mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-23 03:57:13 +01:00
Custom, crew-buildable vendors (#28009)
* Buildable vendors. * Lint. * I think this is right? * It's already IN their hands. * Lint, re-check item after prompting for price. * Fixes. * Review fixes, working dissassembly again. * Apply suggestions from code review Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com> Signed-off-by: Charlie Nolan <funnyman3595@gmail.com> * Restrict appearance to buildable vendor sprites. * tyop fix --------- Signed-off-by: Charlie Nolan <funnyman3595@gmail.com> Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com>
This commit is contained in:
@@ -318,7 +318,8 @@ to destroy them and players will be able to make replacements.
|
||||
"HydroDrobe" = /obj/machinery/economy/vending/hydrodrobe,
|
||||
"JaniDrobe" = /obj/machinery/economy/vending/janidrobe,
|
||||
"LawDrobe" = /obj/machinery/economy/vending/lawdrobe,
|
||||
"TrainDrobe" = /obj/machinery/economy/vending/traindrobe)
|
||||
"TrainDrobe" = /obj/machinery/economy/vending/traindrobe,
|
||||
"CrewVend 3000" = /obj/machinery/economy/vending/custom)
|
||||
var/static/list/unique_vendors = list(
|
||||
"ShadyCigs Ultra" = /obj/machinery/economy/vending/cigarette/beach,
|
||||
"SyndiMed Plus" = /obj/machinery/economy/vending/wallmed/syndicate)
|
||||
@@ -338,7 +339,10 @@ to destroy them and players will be able to make replacements.
|
||||
build_path = typepath
|
||||
board_name = "[type] Vendor"
|
||||
format_board_name()
|
||||
req_components = list(initial(typepath.refill_canister) = 1)
|
||||
if(initial(typepath.refill_canister))
|
||||
req_components = list(initial(typepath.refill_canister) = 1)
|
||||
else
|
||||
req_components = list()
|
||||
|
||||
/obj/item/circuitboard/slot_machine
|
||||
board_name = "Slot Machine"
|
||||
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/obj/machinery/economy/vending/custom
|
||||
name = "\improper CrewVend 3000"
|
||||
refill_canister = null
|
||||
always_deconstruct = TRUE
|
||||
var/obj/item/eftpos/linked_pos
|
||||
|
||||
/obj/machinery/economy/vending/custom/Destroy()
|
||||
if(!isnull(linked_pos))
|
||||
linked_pos.linked_vendors -= src
|
||||
linked_pos = null
|
||||
return ..()
|
||||
|
||||
/obj/machinery/economy/vending/custom/locked()
|
||||
return isnull(linked_pos) || linked_pos.transaction_locked
|
||||
|
||||
/obj/machinery/economy/vending/custom/get_vendor_account()
|
||||
return linked_pos?.linked_account || ..()
|
||||
|
||||
/obj/machinery/economy/vending/custom/item_interaction(mob/living/user, obj/item/used, list/modifiers)
|
||||
if(istype(used, /obj/item/eftpos))
|
||||
visible_message("<span class='notice'>[src] beeps as [user] links it to [used].</span>", "<span class='notice'>You hear something beep.</span>")
|
||||
if(!isnull(linked_pos))
|
||||
linked_pos.linked_vendors -= src
|
||||
linked_pos = used
|
||||
var/obj/item/eftpos/pos = used
|
||||
pos.linked_vendors += src
|
||||
return ITEM_INTERACT_COMPLETE
|
||||
else if(isnull(linked_pos))
|
||||
to_chat(user, "<span class='warning'>You need to link a point of sale device first!</span>")
|
||||
return ITEM_INTERACT_COMPLETE
|
||||
else if(locked())
|
||||
return ..()
|
||||
if(!user.canUnEquip(used, FALSE))
|
||||
to_chat(user, "<span class='warning'>\The [used] is stuck to your hand!</span>")
|
||||
return ITEM_INTERACT_COMPLETE
|
||||
|
||||
for(var/datum/data/vending_product/physical/record in physical_product_records)
|
||||
if(record.get_amount_left() == 0)
|
||||
physical_product_records -= record
|
||||
qdel(record)
|
||||
else if(isitem(record.items[1]))
|
||||
var/obj/item/existing = record.items[1]
|
||||
if(existing.should_stack_with(used))
|
||||
record.items += used
|
||||
user.unequip(used)
|
||||
used.moveToNullspace()
|
||||
user.visible_message("<span class='notice'>[user] puts [used] into [src].</span>", "<span class='notice>'You put [used] into [src].</span>")
|
||||
return ITEM_INTERACT_COMPLETE
|
||||
|
||||
var/price = tgui_input_number(user, "How much do you want to sell [used] for?")
|
||||
if(!isnum(price))
|
||||
return ITEM_INTERACT_COMPLETE
|
||||
if(!Adjacent(user))
|
||||
to_chat(user, "<span class='warning'>You can't reach [src] from here!</span>")
|
||||
return ITEM_INTERACT_COMPLETE
|
||||
if(!user.is_holding(used))
|
||||
to_chat(user, "<span class='warning'>\The [used] isn't in your hand anymore!</span>")
|
||||
return ITEM_INTERACT_COMPLETE
|
||||
if(!user.canUnEquip(used, FALSE))
|
||||
to_chat(user, "<span class='warning'>\The [used] is stuck to your hand!</span>")
|
||||
return ITEM_INTERACT_COMPLETE
|
||||
|
||||
var/datum/data/vending_product/physical/record = new(used.name, used.icon, used.icon_state)
|
||||
record.items += used
|
||||
record.price = price
|
||||
physical_product_records += record
|
||||
SStgui.update_uis(src, TRUE)
|
||||
user.unequip(used)
|
||||
used.moveToNullspace()
|
||||
user.visible_message("[user] puts [used] into [src].", "You put [used] into [src].")
|
||||
return ITEM_INTERACT_COMPLETE
|
||||
|
||||
/obj/machinery/economy/vending/custom/crowbar_act(mob/user, obj/item/I)
|
||||
if(!isnull(linked_pos) && linked_pos.transaction_locked)
|
||||
user.visible_message("<span class='notice'>[user] tries to pry [src] apart, but fails.</span>", "<span class='notice'>The lock on [src] resists your efforts to pry it apart.</span>")
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/obj/machinery/economy/vending/custom/delayed_vend(datum/data/vending_product/R, mob/user)
|
||||
. = ..()
|
||||
if(istype(R, /datum/data/vending_product/physical) && R.get_amount_left() == 0)
|
||||
physical_product_records -= R
|
||||
physical_hidden_records -= R
|
||||
SStgui.update_uis(src, TRUE)
|
||||
+3
-18
@@ -156,30 +156,15 @@
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/economy/vending/coffee/do_vend(datum/data/vending_product/R, mob/user)
|
||||
if(..())
|
||||
var/obj/item/reagent_containers/drinks/vended = ..()
|
||||
if(!istype(vended))
|
||||
return
|
||||
var/obj/item/reagent_containers/drinks/vended = new R.product_path()
|
||||
|
||||
if(istype(vended, /obj/item/reagent_containers/drinks/mug))
|
||||
var/put_on_turf = TRUE
|
||||
if(user && iscarbon(user) && user.Adjacent(src))
|
||||
if(user.put_in_hands(vended))
|
||||
put_on_turf = FALSE
|
||||
if(put_on_turf)
|
||||
var/turf/T = get_turf(src)
|
||||
vended.forceMove(T)
|
||||
return
|
||||
|
||||
vended.reagents.trans_to(inserted_item, vended.reagents.total_volume)
|
||||
if(vended.reagents.total_volume)
|
||||
var/put_on_turf = TRUE
|
||||
if(user && iscarbon(user) && user.Adjacent(src))
|
||||
if(user.put_in_hands(vended))
|
||||
put_on_turf = FALSE
|
||||
if(put_on_turf)
|
||||
var/turf/T = get_turf(src)
|
||||
vended.forceMove(T)
|
||||
else
|
||||
if(!vended.reagents.total_volume)
|
||||
qdel(vended)
|
||||
|
||||
|
||||
|
||||
+179
-95
@@ -2,15 +2,98 @@
|
||||
* Datum used to hold information about a product in a vending machine
|
||||
*/
|
||||
/datum/data/vending_product
|
||||
name = "generic"
|
||||
name = "the idea of vending something"
|
||||
/// Price to buy one
|
||||
var/price = 0
|
||||
|
||||
/datum/data/vending_product/proc/get_amount_full()
|
||||
CRASH("Abstract vending product used.")
|
||||
|
||||
/datum/data/vending_product/proc/get_amount_left()
|
||||
CRASH("Abstract vending product used.")
|
||||
|
||||
/datum/data/vending_product/proc/get_icon()
|
||||
CRASH("Abstract vending product used.")
|
||||
|
||||
/datum/data/vending_product/proc/get_icon_state()
|
||||
CRASH("Abstract vending product used.")
|
||||
|
||||
/datum/data/vending_product/proc/get_name()
|
||||
CRASH("Abstract vending product used.")
|
||||
|
||||
/datum/data/vending_product/proc/vend(turf/where)
|
||||
CRASH("Abstract vending product used.")
|
||||
|
||||
/datum/data/vending_product/from_path
|
||||
name = "a magically-created vending product"
|
||||
|
||||
///Typepath of the product that is created when this record "sells"
|
||||
var/product_path = null
|
||||
var/atom/movable/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
|
||||
/// Price to buy one
|
||||
var/price = 0
|
||||
|
||||
/datum/data/vending_product/from_path/get_amount_full()
|
||||
return max_amount
|
||||
|
||||
/datum/data/vending_product/from_path/get_amount_left()
|
||||
return amount
|
||||
|
||||
/datum/data/vending_product/from_path/get_icon()
|
||||
return initial(product_path.icon)
|
||||
|
||||
/datum/data/vending_product/from_path/get_icon_state()
|
||||
return initial(product_path.icon_state)
|
||||
|
||||
/datum/data/vending_product/from_path/get_name()
|
||||
return initial(product_path.name)
|
||||
|
||||
/datum/data/vending_product/from_path/vend(turf/where)
|
||||
amount--
|
||||
return new product_path(where)
|
||||
|
||||
/datum/data/vending_product/physical
|
||||
name = "a physical vending product"
|
||||
|
||||
/// The items available.
|
||||
var/list/items = list()
|
||||
/// What should they be called?
|
||||
var/display_name
|
||||
/// What icon should they use?
|
||||
var/display_icon
|
||||
/// What icon state should they use?
|
||||
var/display_icon_state
|
||||
|
||||
/datum/data/vending_product/physical/New(name, icon, icon_state)
|
||||
display_name = name
|
||||
display_icon = icon
|
||||
display_icon_state = icon_state
|
||||
|
||||
/datum/data/vending_product/physical/get_amount_full()
|
||||
return 1
|
||||
|
||||
/datum/data/vending_product/physical/get_amount_left()
|
||||
return length(items)
|
||||
|
||||
/datum/data/vending_product/physical/get_icon()
|
||||
return display_icon
|
||||
|
||||
/datum/data/vending_product/physical/get_icon_state()
|
||||
return display_icon_state
|
||||
|
||||
/datum/data/vending_product/physical/get_name()
|
||||
return display_name
|
||||
|
||||
/datum/data/vending_product/physical/vend(turf/where)
|
||||
var/atom/movable/vended = items[length(items)]
|
||||
items.len--
|
||||
vended.forceMove(where)
|
||||
return vended
|
||||
|
||||
/datum/data/vending_product/physical/proc/on_deconstruct(turf/where)
|
||||
while(length(items))
|
||||
vend(where)
|
||||
|
||||
/obj/machinery/economy/vending
|
||||
name = "\improper Vendomat"
|
||||
@@ -63,7 +146,9 @@
|
||||
|
||||
// List of vending_product items available.
|
||||
var/list/product_records = list()
|
||||
var/list/physical_product_records = list()
|
||||
var/list/hidden_records = list()
|
||||
var/list/physical_hidden_records = list()
|
||||
|
||||
/// Unimplemented list of ads that are meant to show up somewhere, but don't.
|
||||
var/list/ads_list = list()
|
||||
@@ -82,6 +167,8 @@
|
||||
|
||||
//The type of refill canisters used by this machine.
|
||||
var/obj/item/vending_refill/refill_canister
|
||||
/// Should we always be able to deconstruct this into components, even if it has no refill_canister?
|
||||
var/always_deconstruct = FALSE
|
||||
|
||||
// Things that can go wrong
|
||||
/// Allows people to access a vendor that's normally access restricted.
|
||||
@@ -110,9 +197,6 @@
|
||||
/// do I look unpowered, even when powered?
|
||||
var/force_no_power_icon_state = FALSE
|
||||
|
||||
///the money account that is tethered to this vendor
|
||||
var/datum/money_account/vendor_account
|
||||
|
||||
/// If this vending machine can be tipped or not
|
||||
var/tiltable = TRUE
|
||||
/// If this vendor is currently tipped
|
||||
@@ -149,6 +233,10 @@
|
||||
var/build_inv = FALSE
|
||||
if(!refill_canister)
|
||||
build_inv = TRUE
|
||||
if(always_deconstruct)
|
||||
var/obj/item/circuitboard/vendor/V = new
|
||||
V.set_type(replacetext(initial(name), "\improper", ""))
|
||||
component_parts = list(V)
|
||||
else
|
||||
component_parts = list()
|
||||
var/obj/item/circuitboard/vendor/V = new
|
||||
@@ -168,9 +256,6 @@
|
||||
// so if slogantime is 10 minutes, it will say it at somewhere between 10 and 20 minutes after the machine is created.
|
||||
last_slogan = world.time + rand(0, slogan_delay)
|
||||
|
||||
if(account_database)
|
||||
vendor_account = account_database.vendor_account
|
||||
|
||||
update_icon(UPDATE_OVERLAYS)
|
||||
reconnect_database()
|
||||
power_change()
|
||||
@@ -263,7 +348,7 @@
|
||||
amount = 0
|
||||
|
||||
var/atom/temp = typepath
|
||||
var/datum/data/vending_product/R = new /datum/data/vending_product()
|
||||
var/datum/data/vending_product/from_path/R = new /datum/data/vending_product/from_path()
|
||||
R.name = initial(temp.name)
|
||||
R.product_path = typepath
|
||||
if(!start_empty)
|
||||
@@ -296,7 +381,7 @@
|
||||
*/
|
||||
/obj/machinery/economy/vending/proc/refill_inventory(list/productlist, list/recordlist)
|
||||
. = 0
|
||||
for(var/datum/data/vending_product/record as anything in recordlist)
|
||||
for(var/datum/data/vending_product/from_path/record as anything in recordlist)
|
||||
var/diff = min(record.max_amount - record.amount, productlist[record.product_path])
|
||||
if(diff)
|
||||
productlist[record.product_path] -= diff
|
||||
@@ -308,7 +393,7 @@
|
||||
* This is used when the machine is deconstructed, so the items aren't "lost"
|
||||
*/
|
||||
/obj/machinery/economy/vending/proc/update_canister()
|
||||
if(!component_parts)
|
||||
if(isnull(refill_canister))
|
||||
return
|
||||
|
||||
var/obj/item/vending_refill/R = locate() in component_parts
|
||||
@@ -323,12 +408,14 @@
|
||||
*/
|
||||
/obj/machinery/economy/vending/proc/unbuild_inventory(list/recordlist)
|
||||
. = list()
|
||||
for(var/datum/data/vending_product/record as anything in recordlist)
|
||||
for(var/datum/data/vending_product/from_path/record in recordlist)
|
||||
.[record.product_path] += record.amount
|
||||
|
||||
/obj/machinery/economy/vending/deconstruct(disassembled = TRUE)
|
||||
eject_item()
|
||||
if(!refill_canister) //the non constructable vendors drop metal instead of a machine frame.
|
||||
for(var/datum/data/vending_product/physical/R in physical_product_records + physical_hidden_records)
|
||||
R.on_deconstruct(loc)
|
||||
if(!component_parts) //the non constructable vendors drop metal instead of a machine frame.
|
||||
new /obj/item/stack/sheet/metal(loc, 3)
|
||||
qdel(src)
|
||||
else
|
||||
@@ -371,9 +458,6 @@
|
||||
return ITEM_INTERACT_COMPLETE
|
||||
|
||||
/obj/machinery/economy/vending/attacked_by(obj/item/attacker, mob/living/user)
|
||||
if(..())
|
||||
return FINISH_ATTACK
|
||||
|
||||
if(tiltable && !tilted && attacker.force)
|
||||
if(resistance_flags & INDESTRUCTIBLE)
|
||||
// no goodies, but also no tilts
|
||||
@@ -404,16 +488,12 @@
|
||||
visible_message("<span class='notice'>[num_freebies] free goodie\s tumble[num_freebies > 1 ? "" : "s"] out of [src]!</span>")
|
||||
|
||||
for(var/i in 1 to num_freebies)
|
||||
for(var/datum/data/vending_product/R in shuffle(product_records))
|
||||
for(var/datum/data/vending_product/R in shuffle(product_records + physical_product_records))
|
||||
|
||||
if(R.amount <= 0)
|
||||
if(R.get_amount_left() <= 0)
|
||||
continue
|
||||
|
||||
var/dump_path = R.product_path
|
||||
if(!dump_path)
|
||||
continue
|
||||
new dump_path(get_turf(src))
|
||||
R.amount--
|
||||
R.vend(loc)
|
||||
break
|
||||
|
||||
/obj/machinery/economy/vending/HasProximity(atom/movable/AM)
|
||||
@@ -609,6 +689,8 @@
|
||||
/obj/machinery/economy/vending/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
|
||||
data["locked"] = locked()
|
||||
data["chargesMoney"] = locked()
|
||||
data["usermoney"] = 0
|
||||
data["inserted_cash"] = cash_transaction
|
||||
data["user"] = null
|
||||
@@ -629,8 +711,8 @@
|
||||
data["user"]["job"] = C.rank ? C.rank : "No Job"
|
||||
|
||||
data["stock"] = list()
|
||||
for(var/datum/data/vending_product/R in product_records + hidden_records)
|
||||
data["stock"][R.name] = R.amount
|
||||
for(var/datum/data/vending_product/R in product_records + physical_product_records + hidden_records + physical_hidden_records)
|
||||
data["stock"][R.get_name()] = R.get_amount_left()
|
||||
data["extended_inventory"] = extended_inventory
|
||||
data["vend_ready"] = vend_ready
|
||||
data["panel_open"] = panel_open ? TRUE : FALSE
|
||||
@@ -642,30 +724,27 @@
|
||||
|
||||
/obj/machinery/economy/vending/ui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["chargesMoney"] = length(prices) > 0 ? TRUE : FALSE
|
||||
data["product_records"] = list()
|
||||
var/i = 1
|
||||
for(var/datum/data/vending_product/R in product_records)
|
||||
var/obj/item = R.product_path
|
||||
for(var/datum/data/vending_product/R in product_records + physical_product_records)
|
||||
var/list/data_pr = list(
|
||||
name = R.name,
|
||||
price = (item in prices) ? prices[item] : 0,
|
||||
icon = item.icon,
|
||||
icon_state = item.icon_state,
|
||||
max_amount = R.max_amount,
|
||||
name = R.get_name(),
|
||||
price = R.price,
|
||||
icon = R.get_icon(),
|
||||
icon_state = R.get_icon_state(),
|
||||
max_amount = R.get_amount_full(),
|
||||
is_hidden = FALSE,
|
||||
inum = i++
|
||||
)
|
||||
data["product_records"] += list(data_pr)
|
||||
data["hidden_records"] = list()
|
||||
for(var/datum/data/vending_product/R in hidden_records)
|
||||
var/obj/item = R.product_path
|
||||
for(var/datum/data/vending_product/R in hidden_records + physical_hidden_records)
|
||||
var/list/data_hr = list(
|
||||
name = R.name,
|
||||
price = (item in prices) ? prices[item] : 0,
|
||||
icon = item.icon,
|
||||
icon_state = item.icon_state,
|
||||
max_amount = R.max_amount,
|
||||
name = R.get_name(),
|
||||
price = R.price,
|
||||
icon = R.get_icon(),
|
||||
icon_state = R.get_icon_state(),
|
||||
max_amount = R.get_amount_full(),
|
||||
is_hidden = TRUE,
|
||||
inum = i++,
|
||||
premium = TRUE
|
||||
@@ -697,6 +776,27 @@
|
||||
if("vend")
|
||||
var/key = text2num(params["inum"])
|
||||
try_vend(key, user)
|
||||
if("rename")
|
||||
if(!locked())
|
||||
var/new_name = tgui_input_text(user, "Rename the vendor to what?", name)
|
||||
if(!isnull(new_name))
|
||||
name = new_name
|
||||
if("change_appearance")
|
||||
if(locked())
|
||||
return
|
||||
var/possible_icons = list()
|
||||
var/icon_lookup = list()
|
||||
var/buildable_vendors = /obj/item/circuitboard/vendor::station_vendors
|
||||
for(var/vendor_name in buildable_vendors)
|
||||
var/obj/machinery/economy/vending/vendor_type = buildable_vendors[vendor_name]
|
||||
possible_icons[vendor_name] = image(icon = initial(vendor_type.icon), icon_state = initial(vendor_type.icon_state))
|
||||
icon_lookup[vendor_name] = list(initial(vendor_type.icon), initial(vendor_type.icon_state))
|
||||
var/choice = show_radial_menu(user, src, possible_icons, radius=48)
|
||||
if(!choice || !(choice in icon_lookup) || user.stat || !in_range(user, src) || QDELETED(src))
|
||||
return
|
||||
icon = icon_lookup[choice][1]
|
||||
icon_state = icon_lookup[choice][2]
|
||||
|
||||
if(.)
|
||||
add_fingerprint(user)
|
||||
|
||||
@@ -708,9 +808,9 @@
|
||||
to_chat(user, "<span class='warning'>The vending machine cannot dispense products while its service panel is open!</span>")
|
||||
return
|
||||
|
||||
var/list/display_records = product_records
|
||||
var/list/display_records = product_records + physical_product_records
|
||||
if(extended_inventory)
|
||||
display_records = product_records + hidden_records
|
||||
display_records = product_records + physical_product_records + hidden_records + physical_hidden_records
|
||||
if(key < 1 || key > length(display_records))
|
||||
log_debug("invalid inum passed to a [name] vendor.</span>")
|
||||
return
|
||||
@@ -718,29 +818,25 @@
|
||||
if(!istype(R))
|
||||
log_debug("player attempted to access an unknown vending_product at a [name] vendor.</span>")
|
||||
return
|
||||
var/list/record_to_check = product_records
|
||||
var/list/record_to_check = product_records + physical_product_records
|
||||
if(extended_inventory)
|
||||
record_to_check = product_records + hidden_records
|
||||
if(!R.product_path)
|
||||
log_debug("player attempted to access an unknown product record at a [name] vendor.</span>")
|
||||
record_to_check = product_records + physical_product_records + hidden_records + physical_hidden_records
|
||||
if(!extended_inventory && ((R in hidden_records) || (R in physical_hidden_records)))
|
||||
// Exploit prevention, stop the user purchasing hidden stuff if they haven't hacked the machine.
|
||||
log_debug("player attempted to access a [name] vendor extended inventory when it was not allowed.</span>")
|
||||
return
|
||||
if(R in hidden_records)
|
||||
if(!extended_inventory)
|
||||
// Exploit prevention, stop the user purchasing hidden stuff if they haven't hacked the machine.
|
||||
log_debug("player attempted to access a [name] vendor extended inventory when it was not allowed.</span>")
|
||||
return
|
||||
else if(!(R in record_to_check))
|
||||
// Exploit prevention, stop the user
|
||||
message_admins("Vending machine exploit attempted by [ADMIN_LOOKUPFLW(user)]!")
|
||||
return
|
||||
if(R.amount <= 0)
|
||||
to_chat(user, "Sold out of [R.name].")
|
||||
if(R.get_amount_left() <= 0)
|
||||
to_chat(user, "Sold out of [R.get_name()].")
|
||||
flick(icon_deny, src)
|
||||
return
|
||||
|
||||
vend_ready = FALSE // From this point onwards, vendor is locked to performing this transaction only, until it is resolved.
|
||||
|
||||
if(!ishuman(user) || R.price <= 0)
|
||||
if(!ishuman(user) || R.price <= 0 || !locked())
|
||||
// Either the purchaser is not human, or the item is free.
|
||||
// Skip all payment logic.
|
||||
vend(R, user)
|
||||
@@ -757,19 +853,20 @@
|
||||
currently_vending = R
|
||||
var/paid = FALSE
|
||||
|
||||
if(cash_transaction < currently_vending.price && GLOB.station_money_database.vendor_account?.suspended)
|
||||
to_chat(user, "Vendor account offline. Unable to process transaction.")
|
||||
var/datum/money_account/vendor_account = get_vendor_account()
|
||||
if(cash_transaction < currently_vending.price && (isnull(vendor_account) || vendor_account.suspended))
|
||||
to_chat(user, "<span class='warning'>Vendor account offline. Unable to process transaction.</span>")
|
||||
flick(icon_deny, src)
|
||||
vend_ready = TRUE
|
||||
return
|
||||
|
||||
if(cash_transaction >= currently_vending.price)
|
||||
paid = pay_with_cash(currently_vending.price, "Vendor Transaction", name, user, GLOB.station_money_database.vendor_account)
|
||||
paid = pay_with_cash(currently_vending.price, "Vendor Transaction", name, user, vendor_account)
|
||||
else if(istype(C, /obj/item/card))
|
||||
// Because this uses H.get_idcard(TRUE), it will attempt to use:
|
||||
// active hand, inactive hand, pda.id, and then wear_id ID in that order
|
||||
// this is important because it lets people buy stuff with someone else's ID by holding it while using the vendor
|
||||
paid = pay_with_card(C, currently_vending.price, "Vendor transaction", name, user, GLOB.station_money_database.vendor_account)
|
||||
paid = pay_with_card(C, currently_vending.price, "Vendor transaction", name, user, vendor_account)
|
||||
else if(user.can_advanced_admin_interact())
|
||||
to_chat(user, "<span class='notice'>Vending object due to admin interaction.</span>")
|
||||
paid = TRUE
|
||||
@@ -794,15 +891,13 @@
|
||||
vend_ready = TRUE
|
||||
return
|
||||
|
||||
if(!R.amount)
|
||||
if(R.get_amount_left() <= 0)
|
||||
to_chat(user, "<span class='warning'>The vending machine has ran out of that product.</span>")
|
||||
vend_ready = TRUE
|
||||
return
|
||||
|
||||
vend_ready = FALSE //One thing at a time!!
|
||||
|
||||
R.amount--
|
||||
|
||||
if(last_reply + vend_delay + 200 <= world.time && vend_reply)
|
||||
speak(vend_reply)
|
||||
last_reply = world.time
|
||||
@@ -819,25 +914,17 @@
|
||||
currently_vending = null
|
||||
|
||||
//override this proc to add handling for what to do with the vended product when you have a inserted item and remember to include a parent call for this generic handling
|
||||
/obj/machinery/economy/vending/proc/do_vend(datum/data/vending_product/R, mob/user)
|
||||
if(!item_slot || !inserted_item)
|
||||
var/put_on_turf = TRUE
|
||||
var/obj/vended = new R.product_path()
|
||||
if(user && iscarbon(user) && user.Adjacent(src))
|
||||
if(user.put_in_hands(vended))
|
||||
put_on_turf = FALSE
|
||||
if(put_on_turf)
|
||||
var/turf/T = get_turf(src)
|
||||
vended.forceMove(T)
|
||||
vended.scatter_atom()
|
||||
return TRUE
|
||||
return FALSE
|
||||
/obj/machinery/economy/vending/proc/do_vend(datum/data/vending_product/R, mob/user, put_in_hands = TRUE)
|
||||
var/vended = R.vend(loc)
|
||||
if(put_in_hands && isliving(user) && istype(vended, /obj/item) && Adjacent(user))
|
||||
user.put_in_hands(vended)
|
||||
return vended
|
||||
|
||||
/* Example override for do_vend proc:
|
||||
/obj/machinery/economy/vending/example/do_vend(datum/data/vending_product/R)
|
||||
if(..())
|
||||
var/obj/item/vended = ..()
|
||||
if(!vended)
|
||||
return
|
||||
var/obj/item/vended = new R.product_path()
|
||||
if(inserted_item.force == initial(inserted_item.force)
|
||||
inserted_item.force += vended.force
|
||||
inserted_item.damtype = vended.damtype
|
||||
@@ -903,20 +990,15 @@
|
||||
var/found_anything = TRUE
|
||||
while(found_anything)
|
||||
found_anything = FALSE
|
||||
for(var/record in shuffle(product_records))
|
||||
var/datum/data/vending_product/R = record
|
||||
if(R.amount <= 0) //Try to use a record that actually has something to dump.
|
||||
for(var/datum/data/vending_product/record in shuffle(product_records))
|
||||
if(record.get_amount_left() <= 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--
|
||||
var/atom/movable/thing = record.vend()
|
||||
// busting open a vendor will destroy some of the contents
|
||||
if(found_anything && prob(80))
|
||||
continue
|
||||
qdel(thing)
|
||||
|
||||
var/obj/O = new dump_path(loc)
|
||||
step(O, pick(GLOB.alldirs))
|
||||
step(thing, pick(GLOB.alldirs))
|
||||
found_anything = TRUE
|
||||
dump_amount++
|
||||
if(dump_amount >= 16)
|
||||
@@ -933,15 +1015,11 @@
|
||||
if(!target)
|
||||
return 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)
|
||||
for(var/datum/data/vending_product/R in product_records + physical_product_records)
|
||||
if(R.get_amount_left() <= 0) //Try to use a record that actually has something to dump.
|
||||
continue
|
||||
|
||||
R.amount--
|
||||
throw_item = new dump_path(loc)
|
||||
throw_item = R.vend(loc)
|
||||
break
|
||||
if(!throw_item)
|
||||
return
|
||||
@@ -1012,6 +1090,12 @@
|
||||
mob_hurt = TRUE
|
||||
return ..()
|
||||
|
||||
/obj/machinery/economy/vending/proc/locked()
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/economy/vending/proc/get_vendor_account()
|
||||
return GLOB.station_money_database.vendor_account
|
||||
|
||||
/*
|
||||
* Vending machine types
|
||||
*/
|
||||
|
||||
@@ -705,6 +705,7 @@
|
||||
/obj/item/clothing/accessory/armband/service = 3,
|
||||
/obj/item/reagent_containers/glass/rag = 3,
|
||||
/obj/item/storage/box/dish_drive = 1,
|
||||
/obj/item/storage/box/crewvend = 1,
|
||||
/obj/item/clothing/head/helmet/space/plasmaman/chef = 2,
|
||||
/obj/item/clothing/under/plasmaman/chef = 2)
|
||||
|
||||
@@ -724,6 +725,7 @@
|
||||
/obj/item/clothing/accessory/armband/service = 20,
|
||||
/obj/item/reagent_containers/glass/rag = 5,
|
||||
/obj/item/storage/box/dish_drive = 100,
|
||||
/obj/item/storage/box/crewvend = 100,
|
||||
/obj/item/clothing/head/helmet/space/plasmaman/chef = 60,
|
||||
/obj/item/clothing/under/plasmaman/chef = 60)
|
||||
|
||||
@@ -751,6 +753,7 @@
|
||||
/obj/item/clothing/accessory/armband/service = 3,
|
||||
/obj/item/reagent_containers/glass/rag = 3,
|
||||
/obj/item/storage/box/dish_drive = 1,
|
||||
/obj/item/storage/box/crewvend = 1,
|
||||
/obj/item/clothing/head/helmet/space/plasmaman/white = 2,
|
||||
/obj/item/clothing/under/plasmaman/enviroslacks = 2)
|
||||
|
||||
@@ -768,6 +771,7 @@
|
||||
/obj/item/clothing/accessory/armband/service = 20,
|
||||
/obj/item/reagent_containers/glass/rag = 5,
|
||||
/obj/item/storage/box/dish_drive = 100,
|
||||
/obj/item/storage/box/crewvend = 100,
|
||||
/obj/item/clothing/head/helmet/space/plasmaman/white = 60,
|
||||
/obj/item/clothing/under/plasmaman/enviroslacks = 60)
|
||||
|
||||
|
||||
@@ -1246,6 +1246,17 @@
|
||||
new /obj/item/stock_parts/matter_bin(src)
|
||||
new /obj/item/screwdriver(src)
|
||||
|
||||
/obj/item/storage/box/crewvend
|
||||
name = "CrewVend 3000 Kit"
|
||||
desc = "Contains everything you need to build your own vending machine!"
|
||||
|
||||
/obj/item/storage/box/crewvend/populate_contents()
|
||||
new /obj/item/stack/sheet/metal/(src, 5)
|
||||
new /obj/item/stack/cable_coil/five(src)
|
||||
var/obj/item/circuitboard/vendor/board = new /obj/item/circuitboard/vendor(src)
|
||||
board.set_type("CrewVend 3000")
|
||||
new /obj/item/screwdriver(src)
|
||||
|
||||
/obj/item/storage/box/hardmode_box
|
||||
name = "box of HRD-MDE project box"
|
||||
desc = "Contains everything needed to get yourself killed for a medal."
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
desc = "A base economy machine."
|
||||
anchored = TRUE
|
||||
density = TRUE
|
||||
new_attack_chain = TRUE
|
||||
|
||||
///Can this machine access restricted money accounts?
|
||||
var/restricted_bypass = FALSE
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
///Is this a portable unit that you can offer with *payme?
|
||||
var/can_offer = TRUE
|
||||
|
||||
///The vendors that are linked to this EFTPOS.
|
||||
var/list/linked_vendors = list()
|
||||
|
||||
/obj/item/eftpos/Initialize(mapload)
|
||||
machine_name = "EFTPOS #[rand(101, 999)]"
|
||||
access_code = rand(1000, 9999)
|
||||
@@ -35,6 +38,16 @@
|
||||
print_reference()
|
||||
return ..()
|
||||
|
||||
/obj/item/eftpos/Destroy()
|
||||
account_database = null
|
||||
linked_account = null
|
||||
for(var/obj/machinery/economy/vending/custom/vendor in linked_vendors)
|
||||
if(vendor.linked_pos == src)
|
||||
vendor.linked_pos = null
|
||||
linked_vendors.Cut()
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/item/eftpos/proc/reconnect_database()
|
||||
account_database = GLOB.station_money_database
|
||||
|
||||
@@ -138,6 +151,9 @@
|
||||
transaction_paid = FALSE
|
||||
else if(linked_account)
|
||||
transaction_locked = TRUE
|
||||
for(var/obj/machinery/economy/vending/custom/vendor in linked_vendors)
|
||||
if(vendor.linked_pos == src)
|
||||
SStgui.update_uis(vendor, TRUE)
|
||||
else
|
||||
to_chat(user, "[bicon(src)]<span class='warning'>No account connected to send transactions to.</span>")
|
||||
if("reset")
|
||||
|
||||
@@ -966,6 +966,7 @@
|
||||
#include "code\game\machinery\tcomms\tcomms_core.dm"
|
||||
#include "code\game\machinery\tcomms\tcomms_presets.dm"
|
||||
#include "code\game\machinery\vendors\contraband_vendors.dm"
|
||||
#include "code\game\machinery\vendors\custom_vendors.dm"
|
||||
#include "code\game\machinery\vendors\departmental_vendors.dm"
|
||||
#include "code\game\machinery\vendors\generic_vendors.dm"
|
||||
#include "code\game\machinery\vendors\tilt_crits.dm"
|
||||
|
||||
@@ -66,6 +66,7 @@ export const Vending = (props, context) => {
|
||||
inserted_item_name,
|
||||
panel_open,
|
||||
speaker,
|
||||
locked,
|
||||
} = data;
|
||||
let inventory;
|
||||
|
||||
@@ -83,6 +84,24 @@ export const Vending = (props, context) => {
|
||||
>
|
||||
<Window.Content scrollable>
|
||||
<Stack fill vertical>
|
||||
{!locked && (
|
||||
<Stack.Item>
|
||||
<Section title="Configuration">
|
||||
<Stack horizontal>
|
||||
<Stack.Item>
|
||||
<Button icon="pen-to-square" content="Rename Vendor" onClick={() => act('rename', {})} />
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
icon="pen-to-square"
|
||||
content="Change Vendor Appearance"
|
||||
onClick={() => act('change_appearance', {})}
|
||||
/>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
)}
|
||||
{!!chargesMoney && (
|
||||
<Stack.Item>
|
||||
<Section
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user