#define STANDARD_CHARGE 1 #define CONTRABAND_CHARGE 2 #define COIN_CHARGE 3 /* * Vending machine types - Can be found under /code/modules/vending/ */ /* /obj/machinery/vending/[vendors name here] // --vending machine template :) name = "" desc = "" icon = '' icon_state = "" products = list() contraband = list() premium = list() IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY CANISTER CHARGES in vending_items.dm */ /datum/data/vending_product var/product_name = "generic" var/product_path = null var/amount = 0 var/max_amount = 0 var/display_color = "blue" /obj/machinery/vending name = "\improper Vendomat" desc = "A generic vending machine." icon = 'icons/obj/vending.dmi' icon_state = "generic" layer = BELOW_OBJ_LAYER anchored = TRUE density = TRUE verb_say = "beeps" verb_ask = "beeps" verb_exclaim = "beeps" max_integrity = 300 integrity_failure = 100 armor = list("melee" = 20, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 70) circuit = /obj/item/circuitboard/machine/vendor var/active = 1 //No sales pitches if off! var/vend_ready = 1 //Are we ready to vend?? Is it time?? // To be filled out at compile time var/list/products = list() //For each, use the following pattern: var/list/contraband = list() //list(/type/path = amount, /type/path2 = amount2) var/list/premium = list() //No specified amount = only one in stock var/product_slogans = "" //String of slogans separated by semicolons, optional var/product_ads = "" //String of small ad messages in the vending screen - random chance var/list/product_records = list() var/list/hidden_records = list() var/list/coin_records = list() var/list/slogan_list = list() var/list/small_ads = list() //Small ad messages in the vending screen - random chance of popping up whenever you open it var/vend_reply //Thank you for shopping! var/last_reply = 0 var/last_slogan = 0 //When did we last pitch? var/slogan_delay = 6000 //How long until we can pitch again? var/icon_vend //Icon_state when vending! var/icon_deny //Icon_state when vending! var/seconds_electrified = 0 //Shock customers like an airlock. var/shoot_inventory = 0 //Fire items at customers! We're broken! var/shoot_inventory_chance = 2 var/shut_up = 0 //Stop spouting those godawful pitches! var/extended_inventory = 0 //can we access the hidden inventory? var/scan_id = 1 var/obj/item/coin/coin var/obj/item/stack/spacecash/bill var/dish_quants = list() //used by the snack machine's custom compartment to count dishes. var/obj/item/vending_refill/refill_canister = null //The type of refill canisters used by this machine. var/refill_count = 3 //The number of canisters the vending machine uses /obj/machinery/vending/Initialize() var/build_inv = FALSE if(!refill_canister) circuit = null build_inv = TRUE . = ..() wires = new /datum/wires/vending(src) if(build_inv) //non-constructable vending machine build_inventory(products) build_inventory(contraband, 1) build_inventory(premium, 0, 1) slogan_list = splittext(product_slogans, ";") // So not all machines speak at the exact same time. // The first time this machine says something will be at slogantime + this random value, // so if slogantime is 10 minutes, it will say it at somewhere between 10 and 20 minutes after the machine is crated. last_slogan = world.time + rand(0, slogan_delay) power_change() /obj/machinery/vending/Destroy() QDEL_NULL(wires) QDEL_NULL(coin) QDEL_NULL(bill) return ..() /obj/machinery/vending/RefreshParts() //Better would be to make constructable child if(component_parts) product_records = list() hidden_records = list() coin_records = list() build_inventory(products, start_empty = 1) build_inventory(contraband, 1, start_empty = 1) build_inventory(premium, 0, 1, start_empty = 1) for(var/obj/item/vending_refill/VR in component_parts) refill_inventory(VR, product_records, STANDARD_CHARGE) refill_inventory(VR, coin_records, COIN_CHARGE) refill_inventory(VR, hidden_records, CONTRABAND_CHARGE) /obj/machinery/vending/deconstruct(disassembled = TRUE) if(!refill_canister) //the non constructable vendors drop metal instead of a machine frame. if(!(flags_1 & NODECONSTRUCT_1)) new /obj/item/stack/sheet/metal(loc, 3) qdel(src) else ..() /obj/machinery/vending/obj_break(damage_flag) if(!(stat & BROKEN) && !(flags_1 & NODECONSTRUCT_1)) var/dump_amount = 0 for(var/datum/data/vending_product/R in product_records) if(R.amount <= 0) //Try to use a record that actually has something to dump. continue var/dump_path = R.product_path if(!dump_path) continue while(R.amount>0) var/obj/O = new dump_path(loc) step(O, pick(GLOB.alldirs)) //we only drop 20% of the total of each products and spread it R.amount -= 5 //around to not fill the turf with too many objects. dump_amount++ if(dump_amount > 15) //so we don't drop too many items (e.g. ClothesMate) break stat |= BROKEN icon_state = "[initial(icon_state)]-broken" /obj/machinery/vending/proc/build_inventory(list/productlist, hidden=0, req_coin=0, start_empty = null) for(var/typepath in productlist) var/amount = productlist[typepath] if(isnull(amount)) amount = 0 var/atom/temp = typepath var/datum/data/vending_product/R = new /datum/data/vending_product() R.product_name = initial(temp.name) R.product_path = typepath if(!start_empty) R.amount = amount R.max_amount = amount R.display_color = pick("red","blue","green") if(hidden) hidden_records += R else if(req_coin) coin_records += R else product_records += R /obj/machinery/vending/proc/refill_inventory(obj/item/vending_refill/refill, datum/data/vending_product/machine, var/charge_type = STANDARD_CHARGE) var/total = 0 var/to_restock = 0 for(var/datum/data/vending_product/machine_content in machine) if(machine_content.amount == 0 && refill.charges[charge_type] > 0) machine_content.amount++ refill.charges[charge_type]-- total++ to_restock += machine_content.max_amount - machine_content.amount if(to_restock <= refill.charges[charge_type]) for(var/datum/data/vending_product/machine_content in machine) machine_content.amount = machine_content.max_amount refill.charges[charge_type] -= to_restock total += to_restock else var/tmp_charges = refill.charges[charge_type] for(var/datum/data/vending_product/machine_content in machine) if(refill.charges[charge_type] == 0) break var/restock = CEILING(((machine_content.max_amount - machine_content.amount)/to_restock)*tmp_charges, 1) if(restock > refill.charges[charge_type]) restock = refill.charges[charge_type] machine_content.amount += restock refill.charges[charge_type] -= restock total += restock return total /obj/machinery/vending/crowbar_act(mob/living/user, obj/item/I) if(!component_parts) return FALSE default_deconstruction_crowbar(I) return TRUE /obj/machinery/vending/wrench_act(mob/living/user, obj/item/I) if(panel_open) default_unfasten_wrench(user, I, time = 60) return TRUE /obj/machinery/vending/screwdriver_act(mob/living/user, obj/item/I) if(anchored) default_deconstruction_screwdriver(user, icon_state, icon_state, I) cut_overlays() if(panel_open) add_overlay("[initial(icon_state)]-panel") updateUsrDialog() else to_chat(user, "You must first secure [src].") return TRUE /obj/machinery/vending/attackby(obj/item/I, mob/user, params) if(panel_open && is_wire_tool(I)) wires.interact(user) return else if(istype(I, /obj/item/coin)) if(coin) to_chat(user, "[src] already has [coin] inserted") return if(bill) to_chat(user, "[src] already has [bill] inserted") return if(!premium.len) to_chat(user, "[src] doesn't have a coin slot.") return if(!user.transferItemToLoc(I, src)) return coin = I to_chat(user, "You insert [I] into [src].") return else if(istype(I, /obj/item/stack/spacecash)) if(coin) to_chat(user, "[src] already has [coin] inserted") return if(bill) to_chat(user, "[src] already has [bill] inserted") return var/obj/item/stack/S = I if(!premium.len) to_chat(user, "[src] doesn't have a bill slot.") return S.use(1) bill = new S.type(src, 1) to_chat(user, "You insert [I] into [src].") return else if(istype(I, refill_canister) && refill_canister != null) if(stat & (BROKEN|NOPOWER)) to_chat(user, "It does nothing.") else if(panel_open) //if the panel is open we attempt to refill the machine var/obj/item/vending_refill/canister = I if(canister.charges[STANDARD_CHARGE] == 0) to_chat(user, "This [canister.name] is empty!") else var/transfered = refill_inventory(canister,product_records,STANDARD_CHARGE) transfered += refill_inventory(canister,coin_records,COIN_CHARGE) transfered += refill_inventory(canister,hidden_records,CONTRABAND_CHARGE) if(transfered) to_chat(user, "You loaded [transfered] items in \the [name].") else to_chat(user, "The [name] is fully stocked.") return else to_chat(user, "You should probably unscrew the service panel first.") else return ..() /obj/machinery/vending/on_deconstruction() var/product_list = list(product_records, hidden_records, coin_records) for(var/i=1, i<=3, i++) for(var/datum/data/vending_product/machine_content in product_list[i]) while(machine_content.amount !=0) var/safety = 0 //to avoid infinite loop for(var/obj/item/vending_refill/VR in component_parts) safety++ if(VR.charges[i] < VR.init_charges[i]) VR.charges[i]++ machine_content.amount-- if(!machine_content.amount) break else safety-- if(safety <= 0) // all refill canisters are full break ..() /obj/machinery/vending/emag_act(mob/user) if(obj_flags & EMAGGED) return obj_flags |= EMAGGED to_chat(user, "You short out the product lock on [src].") /obj/machinery/vending/_try_interact(mob/user) if(seconds_electrified && !(stat & NOPOWER)) if(shock(user, 100)) return return ..() /obj/machinery/vending/interact(mob/user) var/dat = "" dat += "