Merge pull request #11751 from Arturlang/kills_the_shitty_fix

TGUI Next vendors plus spritesheet port from TG
This commit is contained in:
kevinz000
2020-04-09 03:53:08 -07:00
committed by GitHub
9 changed files with 491 additions and 308 deletions

View File

@@ -39,7 +39,7 @@
//title_image = ntitle_image
/datum/browser/proc/add_stylesheet(name, file)
if (istype(name, /datum/asset/spritesheet))
if(istype(name, /datum/asset/spritesheet))
var/datum/asset/spritesheet/sheet = name
stylesheets["spritesheet_[sheet.name].css"] = "data/spritesheets/[sheet.name]"
else

View File

@@ -706,11 +706,11 @@ CIGARETTE PACKETS ARE IN FANCY.DM
name = "\improper E-Cigarette"
desc = "A classy and highly sophisticated electronic cigarette, for classy and dignified gentlemen. A warning label reads \"Warning: Do not fill with flammable materials.\""//<<< i'd vape to that.
icon = 'icons/obj/clothing/masks.dmi'
icon_state = null
item_state = null
icon_state = "black_vape"
item_state = "black_vape"
w_class = WEIGHT_CLASS_TINY
var/chem_volume = 100
var/vapetime = FALSE //this so it won't puff out clouds every tick
var/vapetime = FALSE //this so it won't puff out clouds every tick
var/screw = FALSE // kinky
var/super = FALSE //for the fattest vapes dude.
@@ -723,11 +723,10 @@ CIGARETTE PACKETS ARE IN FANCY.DM
. = ..()
create_reagents(chem_volume, NO_REACT, NO_REAGENTS_VALUE) // so it doesn't react until you light it
reagents.add_reagent(/datum/reagent/drug/nicotine, 50)
if(!icon_state)
if(!param_color)
param_color = pick("red","blue","black","white","green","purple","yellow","orange")
icon_state = "[param_color]_vape"
item_state = "[param_color]_vape"
if(!param_color)
param_color = pick("red","blue","black","white","green","purple","yellow","orange")
icon_state = "[param_color]_vape"
item_state = "[param_color]_vape"
/obj/item/clothing/mask/vape/attackby(obj/item/O, mob/user, params)
if(O.tool_behaviour == TOOL_SCREWDRIVER)
@@ -1067,4 +1066,4 @@ CIGARETTE PACKETS ARE IN FANCY.DM
name = "coconut bong"
icon_off = "coconut_bong"
icon_on = "coconut_bong_lit"
desc = "A water bong used for smoking dried plants. This one's made out of a coconut and some bamboo."
desc = "A water bong used for smoking dried plants. This one's made out of a coconut and some bamboo."

View File

@@ -704,9 +704,43 @@ GLOBAL_LIST_EMPTY(asset_datums)
Insert(initial(D.id), I)
return ..()
/datum/asset/spritesheet/vending
name = "vending"
/datum/asset/spritesheet/vending/register()
for(var/k in GLOB.vending_products)
var/atom/item = k
if(!ispath(item, /atom))
continue
var/icon_file = initial(item.icon)
var/icon_state = initial(item.icon_state)
var/icon/I
var/icon_states_list = icon_states(icon_file)
if(icon_state in icon_states_list)
I = icon(icon_file, icon_state, SOUTH)
var/c = initial(item.color)
if(!isnull(c) && c != "#FFFFFF")
I.Blend(c, ICON_MULTIPLY)
else
var/icon_states_string
for(var/an_icon_state in icon_states_list)
if(!icon_states_string)
icon_states_string = "[json_encode(an_icon_state)](\ref[an_icon_state])"
else
icon_states_string += ", [json_encode(an_icon_state)](\ref[an_icon_state])"
stack_trace("[item] does not have a valid icon state, icon=[icon_file], icon_state=[json_encode(icon_state)](\ref[icon_state]), icon_states=[icon_states_string]")
I = icon('icons/turf/floors.dmi', "", SOUTH)
var/imgid = replacetext(replacetext("[item]", "/obj/item/", ""), "/", "-")
Insert(imgid, I)
return ..()
/datum/asset/simple/genetics
assets = list(
"dna_discovered.gif" = 'html/dna_discovered.gif',
"dna_undiscovered.gif" = 'html/dna_undiscovered.gif',
"dna_extra.gif" = 'html/dna_extra.gif'
)
)

View File

@@ -187,14 +187,15 @@
/obj/item/clothing/head/wig
name = "wig"
desc = "A bunch of hair without a head attached."
icon_state = ""
item_state = "pwig"
icon = 'icons/mob/human_face.dmi' // default icon for all hairs
icon_state = "hair_vlong"
flags_inv = HIDEHAIR
color = "#000"
var/hair_style = "Very Long Hair"
var/hair_color = "#000"
/obj/item/clothing/head/wig/Initialize(mapload)
. = ..()
icon_state = "" //Shitty hack that i dont know if it is even neccesary to deal with the vendor stack exception
update_icon()
/obj/item/clothing/head/wig/update_icon_state()
@@ -202,14 +203,9 @@
if(!S)
icon = 'icons/obj/clothing/hats.dmi'
icon_state = "pwig"
/obj/item/clothing/head/wig/update_overlays()
. = ..()
var/datum/sprite_accessory/S = GLOB.hair_styles_list[hair_style]
if(S)
var/mutable_appearance/M = mutable_appearance(S.icon, S.icon_state, color = hair_color)
M.appearance_flags |= RESET_COLOR
. += M
else
icon = S.icon
icon_state = S.icon_state
/obj/item/clothing/head/wig/worn_overlays(isinhands = FALSE, icon_file, style_flags = NONE)
. = list()
@@ -219,12 +215,12 @@
return
var/mutable_appearance/M = mutable_appearance(S.icon, S.icon_state,layer = -HAIR_LAYER)
M.appearance_flags |= RESET_COLOR
M.color = hair_color
M.color = color
. += M
/obj/item/clothing/head/wig/random/Initialize(mapload)
hair_style = pick(GLOB.hair_styles_list - "Bald") //Don't want invisible wig
hair_color = "#[random_short_color()]"
color = "#[random_short_color()]"
. = ..()
/obj/item/clothing/head/bronze

View File

@@ -16,12 +16,26 @@
IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY CANISTER CHARGES in vending_items.dm
*/
#define MAX_VENDING_INPUT_AMOUNT 30
/**
* # vending record datum
*
* A datum that represents a product that is vendable
*/
/datum/data/vending_product
name = "generic"
///Typepath of the product that is created when this record "sells"
var/product_path = null
///How many of this product we currently have
var/amount = 0
///How many we can store at maximum
var/max_amount = 0
/**
* # vending machines
*
* Captalism in the year 2525, everything in a vending machine, even love
*/
/obj/machinery/vending
name = "\improper Vendomat"
desc = "A generic vending machine."
@@ -36,43 +50,117 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
integrity_failure = 0.33
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??
light_power = 0.5
light_range = MINIMUM_USEFUL_LIGHT_RANGE
/// Is the machine active (No sales pitches if off)!
var/active = TRUE
///Are we ready to vend?? Is it time??
var/vend_ready = TRUE
///Next world time to send a purchase message
var/purchase_message_cooldown
///Last mob to shop with us
// 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
/**
* List of products this machine sells
*
* form should be list(/type/path = amount, /type/path2 = amount2)
*/
var/list/products = list()
/**
* List of products this machine sells when you hack it
*
* form should be list(/type/path = amount, /type/path2 = amount2)
*/
var/list/contraband = list()
/**
* List of premium products this machine sells
*
* form should be list(/type/path, /type/path2) as there is only ever one in stock
*/
var/list/premium = list()
///String of slogans separated by semicolons, optional
var/product_slogans = ""
///String of small ad messages in the vending screen - random chance
var/product_ads = ""
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/static/vending_cache = list() //used for storing the icons of items being vended
///Small ad messages in the vending screen - random chance of popping up whenever you open it
var/list/small_ads = list()
var/dish_quants = list() //used by the snack machine's custom compartment to count dishes.
///Message sent post vend (Thank you for shopping!)
var/vend_reply
///Last world tick we sent a vent reply
var/last_reply
///Last world tick we sent a slogan message out
var/last_slogan
var/last_shopper
///How many ticks until we can send another
var/slogan_delay = 6000
///Icon when vending an item to the user
var/icon_vend
///Icon to flash when user is denied a vend
var/icon_deny
///World ticks the machine is electified for
var/seconds_electrified = MACHINE_NOT_ELECTRIFIED
///When this is TRUE, we fire items at customers! We're broken!
var/shoot_inventory
///How likely this is to happen (prob 100)
var/shoot_inventory_chance = 2
//Stop spouting those godawful pitches!
var/shut_up
///can we access the hidden inventory?
var/extended_inventory
///Are we checking the users ID
var/scan_id = TRUE
///Coins that we accept?
var/obj/item/coin/coin
///Default price of items if not overridden
/**
* Is this item on station or not
*
* if it doesn't originate from off-station during mapload, everything is free
*/
var/onstation = TRUE //if it doesn't originate from off-station during mapload, everything is free
///A variable to change on a per instance basis on the map that allows the instance to force cost and ID requirements
var/onstation_override = FALSE //change this on the object on the map to override the onstation check. DO NOT APPLY THIS GLOBALLY.
var/obj/item/vending_refill/refill_canister = null //The type of refill canisters used by this machine.
///ID's that can load this vending machine wtih refills
var/list/canload_access_list
/obj/machinery/vending/Initialize()
var/list/vending_machine_input = list()
///Display header on the input view
var/input_display_header = "Custom Vendor"
//The type of refill canisters used by this machine.
var/obj/item/vending_refill/refill_canister = null
/// how many items have been inserted in a vendor
var/loaded_items
///Name of lighting mask for the vending machine
var/light_mask
/obj/item/circuitboard
///determines if the circuit board originated from a vendor off station or not.
var/onstation = TRUE
/**
* Initialize the vending machine
*
* Builds the vending machine inventory, sets up slogans and other such misc work
*
* This also sets the onstation var to:
* * FALSE - if the machine was maploaded on a zlevel that doesn't pass the is_station_level check
* * TRUE - all other cases
*/
/obj/machinery/vending/Initialize(mapload)
var/build_inv = FALSE
if(!refill_canister)
circuit = null
@@ -94,9 +182,11 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
/obj/machinery/vending/Destroy()
QDEL_NULL(wires)
QDEL_NULL(coin)
QDEL_NULL(bill)
return ..()
/obj/machinery/vending/can_speak()
return !shut_up
/obj/machinery/vending/RefreshParts() //Better would be to make constructable child
if(!component_parts)
return
@@ -118,10 +208,31 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
else
..()
/obj/machinery/vending/obj_break(damage_flag)
if(!(stat & BROKEN) && !(flags_1 & NODECONSTRUCT_1))
stat |= BROKEN
/obj/machinery/vending/update_icon_state()
if(stat & BROKEN)
icon_state = "[initial(icon_state)]-broken"
set_light(0)
else if(powered())
icon_state = initial(icon_state)
set_light(1.4)
else
icon_state = "[initial(icon_state)]-off"
set_light(0)
/obj/machinery/vending/update_overlays()
. = ..()
if(!light_mask)
return
SSvis_overlays.remove_vis_overlay(src, managed_vis_overlays)
if(!(stat & BROKEN) && powered())
SSvis_overlays.add_vis_overlay(src, icon, light_mask, EMISSIVE_LAYER, EMISSIVE_PLANE)
/obj/machinery/vending/obj_break(damage_flag)
. = ..()
if(!.)
return
var/dump_amount = 0
var/found_anything = TRUE
@@ -146,6 +257,16 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
if (dump_amount >= 16)
return
GLOBAL_LIST_EMPTY(vending_products)
/**
* Build the inventory of the vending machine from it's product and record lists
*
* This builds up a full set of /datum/data/vending_products from the product list of the vending machine type
* Arguments:
* * productlist - the list of products that need to be converted
* * recordlist - the list containing /datum/data/vending_product datums
* * startempty - should we set vending_product record amount from the product list (so it's prefilled at roundstart)
*/
/obj/machinery/vending/proc/build_inventory(list/productlist, list/recordlist, start_empty = FALSE)
for(var/typepath in productlist)
var/amount = productlist[typepath]
@@ -154,13 +275,21 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
var/atom/temp = typepath
var/datum/data/vending_product/R = new /datum/data/vending_product()
GLOB.vending_products[typepath] = 1
R.name = initial(temp.name)
R.product_path = typepath
if(!start_empty)
R.amount = amount
R.max_amount = amount
recordlist += R
/**
* Refill a vending machine from a refill canister
*
* This takes the products from the refill canister and then fills the products,contraband and premium product categories
*
* Arguments:
* * canister - the vending canister we are refilling from
*/
/obj/machinery/vending/proc/restock(obj/item/vending_refill/canister)
if (!canister.products)
canister.products = products.Copy()
@@ -172,7 +301,13 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
. += refill_inventory(canister.products, product_records)
. += refill_inventory(canister.contraband, hidden_records)
. += refill_inventory(canister.premium, coin_records)
/**
* Refill our inventory from the passed in product list into the record list
*
* Arguments:
* * productlist - list of types -> amount
* * recordlist - existing record datums
*/
/obj/machinery/vending/proc/refill_inventory(list/productlist, list/recordlist)
. = 0
for(var/R in recordlist)
@@ -182,7 +317,11 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
productlist[record.product_path] -= diff
record.amount += diff
. += diff
/**
* Set up a refill canister that matches this machines products
*
* This is used when the machine is deconstructed, so the items aren't "lost"
*/
/obj/machinery/vending/proc/update_canister()
if (!component_parts)
return
@@ -190,12 +329,14 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
var/obj/item/vending_refill/R = locate() in component_parts
if (!R)
CRASH("Constructible vending machine did not have a refill canister")
return
R.products = unbuild_inventory(product_records)
R.contraband = unbuild_inventory(hidden_records)
R.premium = unbuild_inventory(coin_records)
/**
* Given a record list, go through and and return a list of type -> amount
*/
/obj/machinery/vending/proc/unbuild_inventory(list/recordlist)
. = list()
for(var/R in recordlist)
@@ -209,11 +350,14 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
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(..())
return TRUE
if(anchored)
default_deconstruction_screwdriver(user, icon_state, icon_state, I)
cut_overlays()
@@ -232,9 +376,6 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
if(coin)
to_chat(user, "<span class='warning'>[src] already has [coin] inserted</span>")
return
if(bill)
to_chat(user, "<span class='warning'>[src] already has [bill] inserted</span>")
return
if(!premium.len)
to_chat(user, "<span class='warning'>[src] doesn't have a coin slot.</span>")
return
@@ -243,41 +384,87 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
coin = I
to_chat(user, "<span class='notice'>You insert [I] into [src].</span>")
return
else if(istype(I, /obj/item/stack/spacecash))
if(coin)
to_chat(user, "<span class='warning'>[src] already has [coin] inserted</span>")
return
if(bill)
to_chat(user, "<span class='warning'>[src] already has [bill] inserted</span>")
return
var/obj/item/stack/S = I
if(!premium.len)
to_chat(user, "<span class='warning'>[src] doesn't have a bill slot.</span>")
return
S.use(1)
bill = new S.type(src, 1)
to_chat(user, "<span class='notice'>You insert [I] into [src].</span>")
return
else if(refill_canister && istype(I, refill_canister))
if (!panel_open)
to_chat(user, "<span class='notice'>You should probably unscrew the service panel first.</span>")
to_chat(user, "<span class='warning'>You should probably unscrew the service panel first!</span>")
else if (stat & (BROKEN|NOPOWER))
to_chat(user, "<span class='notice'>[src] does not respond.</span>")
else
//if the panel is open we attempt to refill the machine
var/obj/item/vending_refill/canister = I
if(canister.get_part_rating() == 0)
to_chat(user, "<span class='notice'>[canister] is empty!</span>")
to_chat(user, "<span class='warning'>[canister] is empty!</span>")
else
// instantiate canister if needed
var/transferred = restock(canister)
if(transferred)
to_chat(user, "<span class='notice'>You loaded [transferred] items in [src].</span>")
else
to_chat(user, "<span class='notice'>There's nothing to restock!</span>")
to_chat(user, "<span class='warning'>There's nothing to restock!</span>")
return
if(compartmentLoadAccessCheck(user) && user.a_intent != INTENT_HARM)
if(canLoadItem(I))
loadingAttempt(I,user)
updateUsrDialog() //can't put this on the proc above because we spam it below
if(istype(I, /obj/item/storage/bag)) //trays USUALLY
var/obj/item/storage/T = I
var/loaded = 0
var/denied_items = 0
for(var/obj/item/the_item in T.contents)
if(contents.len >= MAX_VENDING_INPUT_AMOUNT) // no more than 30 item can fit inside, legacy from snack vending although not sure why it exists
to_chat(user, "<span class='warning'>[src]'s compartment is full.</span>")
break
if(canLoadItem(the_item) && loadingAttempt(the_item,user))
SEND_SIGNAL(T, COMSIG_TRY_STORAGE_TAKE, the_item, src, TRUE)
loaded++
else
denied_items++
if(denied_items)
to_chat(user, "<span class='warning'>[src] refuses some items!</span>")
if(loaded)
to_chat(user, "<span class='notice'>You insert [loaded] dishes into [src]'s compartment.</span>")
updateUsrDialog()
else
return ..()
. = ..()
/obj/machinery/vending/proc/loadingAttempt(obj/item/I, mob/user)
. = TRUE
if(!user.transferItemToLoc(I, src))
return FALSE
if(vending_machine_input[format_text(I.name)])
vending_machine_input[format_text(I.name)]++
else
vending_machine_input[format_text(I.name)] = 1
to_chat(user, "<span class='notice'>You insert [I] into [src]'s input compartment.</span>")
loaded_items++
/**
* Is the passed in user allowed to load this vending machines compartments
*
* Arguments:
* * user - mob that is doing the loading of the vending machine
*/
/obj/machinery/vending/proc/compartmentLoadAccessCheck(mob/user)
if(!canload_access_list)
return TRUE
else
var/do_you_have_access = FALSE
var/req_access_txt_holder = req_access_txt
for(var/i in canload_access_list)
req_access_txt = i
if(!allowed(user) && !(obj_flags & EMAGGED) && scan_id)
continue
else
do_you_have_access = TRUE
break //you passed don't bother looping anymore
req_access_txt = req_access_txt_holder // revert to normal (before the proc ran)
if(do_you_have_access)
return TRUE
else
to_chat(user, "<span class='warning'>[src]'s input compartment blinks red: Access denied.</span>")
return FALSE
/obj/machinery/vending/exchange_parts(mob/user, obj/item/storage/part_replacer/W)
if(!istype(W))
@@ -297,7 +484,7 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
else
display_parts(user)
if(moved)
to_chat(user, "[moved] items restocked.")
to_chat(user, "<span class='notice'>[moved] items restocked.</span>")
W.play_rped_sound()
return TRUE
@@ -319,188 +506,144 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
return
return ..()
/obj/machinery/vending/ui_interact(mob/user)
var/dat = ""
/obj/machinery/vending/ui_base_html(html)
var/datum/asset/spritesheet/assets = get_asset_datum(/datum/asset/spritesheet/vending)
. = replacetext(html, "<!--customheadhtml-->", assets.css_tag())
dat += "<h3>Select an item</h3>"
dat += "<div class='statusDisplay'>"
if(!product_records.len)
dat += "<font color = 'red'>No product loaded!</font>"
else
var/list/display_records = product_records
if(extended_inventory)
display_records = product_records + hidden_records
if(coin || bill)
display_records = product_records + coin_records
if((coin || bill) && extended_inventory)
display_records = product_records + hidden_records + coin_records
dat += "<table>"
for (var/datum/data/vending_product/R in display_records)
dat += "<tr><td><img src='data:image/jpeg;base64,[GetIconForProduct(R)]'/></td>"
dat += "<td style=\"width: 100%\"><b>[sanitize(R.name)]</b></td>"
if(R.amount > 0)
dat += "<td><b>[R.amount]&nbsp;</b></td><td><a href='byond://?src=[REF(src)];vend=[REF(R)]'>Vend</a></td>"
else
dat += "<td>0&nbsp;</td><td><span class='linkOff'>Vend</span></td>"
dat += "</tr>"
dat += "</table>"
dat += "</div>"
if(premium.len > 0)
dat += "<b>Change Return:</b> "
if (coin || bill)
dat += "[(coin ? coin : "")][(bill ? bill : "")]&nbsp;&nbsp;<a href='byond://?src=[REF(src)];remove_coin=1'>Remove</a>"
else
dat += "<i>No money</i>&nbsp;&nbsp;<span class='linkOff'>Remove</span>"
if(istype(src, /obj/machinery/vending/snack))
dat += "<h3>Chef's Food Selection</h3>"
dat += "<div class='statusDisplay'>"
for (var/O in dish_quants)
if(dish_quants[O] > 0)
var/N = dish_quants[O]
dat += "<a href='byond://?src=[REF(src)];dispense=[sanitize(O)]'>Dispense</A> "
dat += "<B>[capitalize(O)]: [N]</B><br>"
dat += "</div>"
/obj/machinery/vending/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
var/datum/asset/assets = get_asset_datum(/datum/asset/spritesheet/vending)
assets.send(user)
ui = new(user, src, ui_key, "vending", name, 450, 600, master_ui, state)
ui.open()
var/datum/browser/popup = new(user, "vending", (name))
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
popup.open()
/obj/machinery/vending/ui_static_data(mob/user)
. = list()
.["product_records"] = list()
for (var/datum/data/vending_product/R in product_records)
var/list/data = list(
path = replacetext(replacetext("[R.product_path]", "/obj/item/", ""), "/", "-"),
name = R.name,
max_amount = R.max_amount,
ref = REF(R)
)
.["product_records"] += list(data)
.["coin_records"] = list()
for (var/datum/data/vending_product/R in coin_records)
var/list/data = list(
path = replacetext(replacetext("[R.product_path]", "/obj/item/", ""), "/", "-"),
name = R.name,
max_amount = R.max_amount,
ref = REF(R),
premium = TRUE
)
.["coin_records"] += list(data)
.["hidden_records"] = list()
for (var/datum/data/vending_product/R in hidden_records)
var/list/data = list(
path = replacetext(replacetext("[R.product_path]", "/obj/item/", ""), "/", "-"),
name = R.name,
max_amount = R.max_amount,
ref = REF(R),
premium = TRUE
)
.["hidden_records"] += list(data)
/obj/machinery/vending/proc/GetIconForProduct(datum/data/vending_product/P)
if(vending_cache[P.product_path])
return vending_cache[P.product_path]
var/product = new P.product_path()
vending_cache[P.product_path] = icon2base64(getFlatIcon(product, no_anim = TRUE))
qdel(product)
return vending_cache[P.product_path]
/obj/machinery/vending/ui_data(mob/user)
. = list()
.["stock"] = list()
for(var/datum/data/vending_product/R in product_records + coin_records + hidden_records)
.["stock"][R.name] = R.amount
.["extended_inventory"] = extended_inventory
.["coin"] = coin
/obj/machinery/vending/Topic(href, href_list)
if(..())
/obj/machinery/vending/ui_act(action, params)
. = ..()
if(.)
return
if(href_list["remove_coin"])
if(!(coin || bill))
to_chat(usr, "<span class='notice'>There is no money in this machine.</span>")
return
if(coin)
usr.put_in_hands(coin)
to_chat(usr, "<span class='notice'>You remove [coin] from [src].</span>")
coin = null
if(bill)
usr.put_in_hands(bill)
to_chat(usr, "<span class='notice'>You remove [bill] from [src].</span>")
bill = null
usr.set_machine(src)
if((href_list["dispense"]) && (vend_ready))
var/N = href_list["dispense"]
if(dish_quants[N] <= 0) // Sanity check, there are probably ways to press the button when it shouldn't be possible.
return
vend_ready = 0
use_power(5)
dish_quants[N] = max(dish_quants[N] - 1, 0)
for(var/obj/O in contents)
if(O.name == N)
O.forceMove(drop_location())
break
vend_ready = 1
updateUsrDialog()
return
if((href_list["vend"]) && (vend_ready))
if(panel_open)
to_chat(usr, "<span class='notice'>The vending machine cannot dispense products while its service panel is open!</span>")
return
if((!allowed(usr)) && !(obj_flags & EMAGGED) && scan_id) //For SECURE VENDING MACHINES YEAH
to_chat(usr, "<span class='warning'>Access denied.</span>" )
flick(icon_deny,src)
return
vend_ready = 0 //One thing at a time!!
var/datum/data/vending_product/R = locate(href_list["vend"])
if(!R || !istype(R) || !R.product_path)
vend_ready = 1
return
if(R in hidden_records)
if(!extended_inventory)
vend_ready = 1
switch(action)
if("vend")
. = TRUE
if(!vend_ready)
return
else if(R in coin_records)
if(!(coin || bill))
to_chat(usr, "<span class='warning'>You need to insert money to get this item!</span>")
vend_ready = 1
if(panel_open)
to_chat(usr, "<span class='warning'>The vending machine cannot dispense products while its service panel is open!</span>")
return
if(coin && coin.string_attached)
if(prob(50))
if(usr.CanReach(src))
if(usr.put_in_hands(coin))
to_chat(usr, "<span class='notice'>You successfully pull [coin] out before [src] could swallow it.</span>")
coin = null
else
to_chat(usr, "<span class='warning'>You couldn't pull [coin] out because your hands are full!</span>")
QDEL_NULL(coin)
else
if((!allowed(usr)) && !(obj_flags & EMAGGED) && scan_id) //For SECURE VENDING MACHINES YEAH
to_chat(usr, "<span class='warning'>Access denied.</span>" )
flick(icon_deny,src)
return
vend_ready = FALSE //One thing at a time!!
var/datum/data/vending_product/R = locate(params["ref"])
if(!R || !istype(R) || !R.product_path)
vend_ready = TRUE
return
if(R in hidden_records)
if(!extended_inventory)
vend_ready = TRUE
return
else if(R in coin_records)
if(!(coin))
to_chat(usr, "<span class='warning'>You need to a coin to get this item!</span>")
vend_ready = TRUE
return
if(coin && coin.string_attached)
if(!prob(50))
to_chat(usr, "<span class='warning'>You weren't able to pull [coin] out fast enough, the machine ate it, string and all!</span>")
QDEL_NULL(coin)
return
if(!usr.CanReach(src))
to_chat(usr, "<span class='notice'>You successfully pull [coin] out of [src] to the floor.</span>")
coin = null
else
to_chat(usr, "<span class='warning'>You weren't able to pull [coin] out fast enough, the machine ate it, string and all!</span>")
if(!usr.put_in_hands(coin))
to_chat(usr, "<span class='warning'>You couldn't pull [coin] out because your hands are full!</span>")
QDEL_NULL(coin)
to_chat(usr, "<span class='notice'>You successfully pull [coin] out before [src] could swallow it.</span>")
coin = null
QDEL_NULL(coin)
else if(!(R in product_records))
vend_ready = TRUE
message_admins("Vending machine exploit attempted by [ADMIN_LOOKUPFLW(usr)]!")
return
if(R.amount <= 0)
to_chat(usr, "<span class='warning'>Sold out.</span>")
vend_ready = TRUE
return
else
QDEL_NULL(coin)
QDEL_NULL(bill)
else if (!(R in product_records))
vend_ready = 1
message_admins("Vending machine exploit attempted by [ADMIN_LOOKUPFLW(usr)]!")
return
if (R.amount <= 0)
to_chat(usr, "<span class='warning'>Sold out.</span>")
vend_ready = 1
return
else
R.amount--
if(((last_reply + 200) <= world.time) && vend_reply)
speak(vend_reply)
last_reply = world.time
use_power(5)
if(icon_vend) //Show the vending animation if needed
flick(icon_vend,src)
var/vended = new R.product_path(get_turf(src))
if(usr.CanReach(src))
if(usr.put_in_hands(vended))
R.amount--
if(((last_reply + 200) <= world.time) && vend_reply)
speak(vend_reply)
last_reply = world.time
use_power(5)
if(icon_vend) //Show the vending animation if needed
flick(icon_vend,src)
var/vended = new R.product_path(get_turf(src))
if(usr.CanReach(src) && usr.put_in_hands(vended))
to_chat(usr, "<span class='notice'>You take [R.name] out of the slot.</span>")
else
to_chat(usr, "<span class='warning'>[capitalize(R.name)] falls onto the floor!</span>")
else
to_chat(usr, "<span class'warning'>[capitalize(R.name)] falls onto the floor!</span>")
SSblackbox.record_feedback("nested tally", "vending_machine_usage", 1, list("[type]", "[R.product_path]"))
vend_ready = 1
updateUsrDialog()
SSblackbox.record_feedback("nested tally", "vending_machine_usage", 1, list("[type]", "[R.product_path]"))
vend_ready = TRUE
return
if("takeoutcoin")
usr.put_in_hands(coin)
to_chat(usr, "<span class='notice'>You remove [coin] from [src].</span>")
coin = null
return
else if(href_list["togglevoice"] && panel_open)
else if("togglevoice" && panel_open)
shut_up = !shut_up
updateUsrDialog()
/obj/machinery/vending/process()
if(stat & (BROKEN|NOPOWER))
return
return PROCESS_KILL
if(!active)
return
if(seconds_electrified > 0)
if(seconds_electrified > MACHINE_NOT_ELECTRIFIED)
seconds_electrified--
//Pitch to the people! Really sell it!
@@ -511,7 +654,14 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
if(shoot_inventory && prob(shoot_inventory_chance))
throw_item()
/**
* Speak the given message verbally
*
* Checks if the machine is powered and the message exists
*
* Arguments:
* * message - the message to speak
*/
/obj/machinery/vending/proc/speak(message)
if(stat & (BROKEN|NOPOWER))
return
@@ -521,47 +671,61 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
say(message)
/obj/machinery/vending/power_change()
if(stat & BROKEN)
icon_state = "[initial(icon_state)]-broken"
else
if(powered())
icon_state = initial(icon_state)
stat &= ~NOPOWER
else
icon_state = "[initial(icon_state)]-off"
stat |= NOPOWER
. = ..()
if(powered())
START_PROCESSING(SSmachines, src)
//Somebody cut an important wire and now we're following a new definition of "pitch."
/**
* Throw an item from our internal inventory out in front of us
*
* This is called when we are hacked, it selects a random product from the records that has an amount > 0
* This item is then created and tossed out in front of us with a visible message
*/
/obj/machinery/vending/proc/throw_item()
var/obj/throw_item = null
var/mob/living/target = locate() in view(7,src)
var/mob/living/target = locate() in view(7, src)
if(!target)
return 0
return FALSE
for(var/datum/data/vending_product/R in shuffle(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
R.amount--
throw_item = new dump_path(loc)
break
if(!throw_item)
return 0
return FALSE
pre_throw(throw_item)
throw_item.throw_at(target, 16, 3)
visible_message("<span class='danger'>[src] launches [throw_item] at [target]!</span>")
return 1
return TRUE
/**
* A callback called before an item is tossed out
*
* Override this if you need to do any special case handling
*
* Arguments:
* * I - obj/item being thrown
*/
/obj/machinery/vending/proc/pre_throw(obj/item/I)
return
/obj/machinery/vending/proc/shock(mob/user, prb)
if(stat & (BROKEN|NOPOWER)) // unpowered, no shock
/**
* Shock the passed in user
*
* This checks we have power and that the passed in prob is passed, then generates some sparks
* and calls electrocute_mob on the user
*
* Arguments:
* * user - the user to shock
* * prb - probability the shock happens
*/
/obj/machinery/vending/proc/shock(mob/living/user, prb)
if(!istype(user) || stat & (BROKEN|NOPOWER)) // unpowered, no shock
return FALSE
if(!prob(prb))
return FALSE
@@ -571,6 +735,15 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
return TRUE
else
return FALSE
/**
* Are we able to load the item passed in
*
* Arguments:
* * I - the item being loaded
* * user - the user doing the loading
*/
/obj/machinery/vending/proc/canLoadItem(obj/item/I, mob/user)
return FALSE
/obj/machinery/vending/onTransitZ()
return

Binary file not shown.

View File

@@ -9,54 +9,40 @@ export const Vending = props => {
const { ref } = config;
let inventory;
let custom = false;
if (data.vending_machine_input) {
inventory = data.vending_machine_input;
custom = true;
const onstation = true;
if (data.extended_inventory && data.coin) {
inventory = [
...data.product_records,
...data.hidden_records,
...data.coin_records,
];
} else if (data.extended_inventory) {
inventory = [
...data.product_records,
...data.coin_records,
...data.hidden_records,
];
} else if (data.coin) {
inventory = [
...data.product_records,
...data.coin_records,
];
} else {
inventory = [
...data.product_records,
...data.coin_records,
];
}
return (
<Fragment>
{data.onstation && (
<Section title="User">
{data.user && (
<Box>
Welcome, <b>{data.user.name}</b>,
{' '}
<b>{data.user.job || "Unemployed"}</b>!
<br />
Your balance is <b>{data.user.cash} credits</b>.
</Box>
) || (
<Box color="light-gray">
No registered ID card!<br />
Please contact your local HoP!
</Box>
)}
{data.coin && (
<Section title="Coins">
<Button
content={"Take out the coin"}
onClick={() => act(ref, 'takeoutcoin')} />
</Section>
)}
<Section title="Products" >
<Table>
{inventory.map((product => {
const free = (
!data.onstation
|| product.price === 0
|| (
!product.premium
&& data.department
&& data.user
&& data.department === data.user.department
)
);
return (
<Table.Row key={product.name}>
<Table.Cell>
@@ -91,23 +77,13 @@ export const Vending = props => {
<Table.Cell>
{custom && (
<Button
content={data.access ? 'FREE' : product.price + ' cr'}
content={'Vend'}
onClick={() => act(ref, 'dispense', {
'item': product.name,
})} />
) || (
<Button
disabled={(
data.stock[product.namename] === 0
|| (
!free
&& (
!data.user
|| product.price > data.user.cash
)
)
)}
content={free ? 'FREE' : product.price + ' cr'}
content={'Vend'}
onClick={() => act(ref, 'vend', {
'ref': product.ref,
})} />

File diff suppressed because one or more lines are too long

View File

@@ -97,6 +97,7 @@ import { ThermoMachine } from './interfaces/ThermoMachine';
import { TurbineComputer } from './interfaces/TurbineComputer';
import { Uplink } from './interfaces/Uplink';
import { VaultController } from './interfaces/VaultController';
import { Vending } from './interfaces/Vending';
import { Wires } from './interfaces/Wires';
import { AtmosRelief } from './interfaces/AtmosRelief';
@@ -530,6 +531,10 @@ const ROUTES = {
component: () => VaultController,
scrollable: false,
},
vending: {
component: () => Vending,
scrollable: true,
},
wires: {
component: () => Wires,
scrollable: false,