mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-23 12:07:27 +01:00
Merge pull request #11251 from Fox-McCloud/vending-machine-qol
Vending Machine QOL and Destruction
This commit is contained in:
@@ -407,7 +407,7 @@ Class Procs:
|
||||
if(can_deconstruct)
|
||||
on_deconstruction()
|
||||
if(component_parts && component_parts.len)
|
||||
spawn_frame()
|
||||
spawn_frame(disassembled)
|
||||
for(var/obj/item/I in component_parts)
|
||||
I.forceMove(loc)
|
||||
qdel(src)
|
||||
|
||||
+125
-101
@@ -38,6 +38,8 @@
|
||||
layer = 2.9
|
||||
anchored = 1
|
||||
density = 1
|
||||
max_integrity = 300
|
||||
integrity_failure = 100
|
||||
armor = list(melee = 20, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0)
|
||||
var/icon_vend //Icon_state when vending
|
||||
var/icon_deny //Icon_state when denying access
|
||||
@@ -96,30 +98,27 @@
|
||||
var/item_slot = FALSE
|
||||
var/obj/item/inserted_item = null
|
||||
|
||||
/obj/machinery/vending/New()
|
||||
..()
|
||||
/obj/machinery/vending/Initialize(mapload)
|
||||
. = ..()
|
||||
wires = new(src)
|
||||
spawn(50)
|
||||
if(product_slogans)
|
||||
slogan_list += splittext(product_slogans, ";")
|
||||
if(product_slogans)
|
||||
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)
|
||||
// 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)
|
||||
|
||||
if(product_ads)
|
||||
ads_list += splittext(product_ads, ";")
|
||||
if(product_ads)
|
||||
ads_list += splittext(product_ads, ";")
|
||||
|
||||
build_inventory()
|
||||
power_change()
|
||||
|
||||
return
|
||||
|
||||
return
|
||||
build_inventory()
|
||||
power_change()
|
||||
|
||||
/obj/machinery/vending/Destroy()
|
||||
eject_item()
|
||||
QDEL_NULL(wires)
|
||||
QDEL_NULL(coin)
|
||||
QDEL_NULL(inserted_item)
|
||||
return ..()
|
||||
|
||||
/**
|
||||
@@ -148,34 +147,31 @@
|
||||
|
||||
product_records.Add(product)
|
||||
|
||||
/obj/machinery/vending/Destroy()
|
||||
QDEL_NULL(wires)
|
||||
QDEL_NULL(coin)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/vending/ex_act(severity)
|
||||
/obj/machinery/vending/ex_act(severity) //TO-DO-OBJECT-DAMAGE: Kill off when everything is damageable
|
||||
switch(severity)
|
||||
if(1.0)
|
||||
if(1)
|
||||
obj_integrity = 0
|
||||
qdel(src)
|
||||
return
|
||||
if(2.0)
|
||||
if(prob(50))
|
||||
qdel(src)
|
||||
return
|
||||
if(3.0)
|
||||
if(prob(25))
|
||||
malfunction()
|
||||
if(2)
|
||||
take_damage(rand(100, 250), BRUTE, "bomb", 0)
|
||||
if(3)
|
||||
take_damage(rand(10, 90), BRUTE, "bomb", 0)
|
||||
|
||||
/obj/machinery/vending/RefreshParts() //Better would be to make constructable child
|
||||
if(component_parts)
|
||||
for(var/obj/item/vending_refill/VR in component_parts)
|
||||
refill_inventory(VR, product_records, usr)
|
||||
|
||||
/obj/machinery/vending/blob_act()
|
||||
if(prob(75))
|
||||
malfunction()
|
||||
else
|
||||
/obj/machinery/vending/deconstruct(disassembled = TRUE)
|
||||
eject_item()
|
||||
if(!refill_canister) //the non constructable vendors drop metal instead of a machine frame.
|
||||
new /obj/item/stack/sheet/metal(loc, 3)
|
||||
qdel(src)
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/machinery/vending/blob_act(obj/structure/blob/B) //TO-DO-OBJECT-DAMAGE: Kill off when everything is damageable
|
||||
take_damage(400, BRUTE, "melee", 0, get_dir(src, B))
|
||||
|
||||
/obj/machinery/vending/proc/refill_inventory(obj/item/vending_refill/refill, list/machine, mob/user)
|
||||
var/total = 0
|
||||
@@ -236,7 +232,7 @@
|
||||
if(default_unfasten_wrench(user, I, time = 60))
|
||||
return
|
||||
|
||||
if(istype(I, /obj/item/screwdriver) && anchored)
|
||||
if(isscrewdriver(I) && anchored)
|
||||
playsound(loc, I.usesound, 50, 1)
|
||||
panel_open = !panel_open
|
||||
to_chat(user, "You [panel_open ? "open" : "close"] the maintenance panel.")
|
||||
@@ -247,9 +243,9 @@
|
||||
return
|
||||
|
||||
if(panel_open)
|
||||
if(istype(I, /obj/item/multitool)||istype(I, /obj/item/wirecutters))
|
||||
if(ismultitool(I) || iswirecutter(I))
|
||||
return attack_hand(user)
|
||||
if(component_parts && istype(I, /obj/item/crowbar))
|
||||
if(component_parts && iscrowbar(I))
|
||||
var/datum/data/vending_product/machine = product_records
|
||||
for(var/datum/data/vending_product/machine_content in machine)
|
||||
while(machine_content.amount !=0)
|
||||
@@ -259,15 +255,17 @@
|
||||
if(!machine_content.amount)
|
||||
break
|
||||
default_deconstruction_crowbar(I)
|
||||
if(istype(I, /obj/item/coin) && premium.len > 0)
|
||||
user.drop_item()
|
||||
I.loc = src
|
||||
return
|
||||
if(istype(I, /obj/item/coin) && premium.len)
|
||||
if(!user.drop_item())
|
||||
return
|
||||
I.forceMove(src)
|
||||
coin = I
|
||||
categories |= CAT_COIN
|
||||
to_chat(user, "<span class='notice'>You insert the [I] into the [src]</span>")
|
||||
SSnanoui.update_uis(src)
|
||||
return
|
||||
else if(istype(I, refill_canister) && refill_canister != null)
|
||||
if(istype(I, refill_canister) && refill_canister != null)
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
to_chat(user, "<span class='notice'>It does nothing.</span>")
|
||||
else if(panel_open)
|
||||
@@ -281,21 +279,18 @@
|
||||
to_chat(user, "<span class='notice'>You loaded [transfered] items in \the [name].</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>The [name] is fully stocked.</span>")
|
||||
return;
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You should probably unscrew the service panel first.</span>")
|
||||
else if(item_slot_check(user, I))
|
||||
return
|
||||
if(item_slot_check(user, I))
|
||||
insert_item(user, I)
|
||||
return
|
||||
else
|
||||
return ..()
|
||||
return ..()
|
||||
|
||||
//Override this proc to do per-machine checks on the inserted item, but remember to call the parent to handle these generic checks before your logic!
|
||||
/obj/machinery/vending/proc/item_slot_check(mob/user, obj/item/I)
|
||||
if(!item_slot)
|
||||
return FALSE
|
||||
if(alert(user, "Do you want to attempt to insert [I]?", "","Yes", "No") == "No")
|
||||
return FALSE
|
||||
if(inserted_item)
|
||||
to_chat(user, "<span class='warning'>There is something already inserted!</span>")
|
||||
return FALSE
|
||||
@@ -314,28 +309,32 @@
|
||||
/obj/machinery/vending/proc/insert_item(mob/user, obj/item/I)
|
||||
if(!item_slot || inserted_item)
|
||||
return
|
||||
if(!user.canUnEquip(I))
|
||||
if(!user.drop_item())
|
||||
to_chat(user, "<span class='warning'>[I] is stuck to your hand, you can't seem to put it down!</span>")
|
||||
return
|
||||
|
||||
user.unEquip(I)
|
||||
inserted_item = I
|
||||
I.forceMove(src)
|
||||
|
||||
to_chat(user, "<span class='notice'>You insert [I] into [src].</span>")
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
/obj/machinery/vending/proc/eject_item()
|
||||
/obj/machinery/vending/proc/eject_item(mob/user)
|
||||
if(!item_slot || !inserted_item)
|
||||
return
|
||||
inserted_item.forceMove(get_turf(src))
|
||||
var/put_on_turf = TRUE
|
||||
if(user && iscarbon(user) && user.Adjacent(src))
|
||||
if(user.put_in_hands(inserted_item))
|
||||
put_on_turf = FALSE
|
||||
if(put_on_turf)
|
||||
var/turf/T = get_turf(src)
|
||||
inserted_item.forceMove(T)
|
||||
inserted_item = null
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
/obj/machinery/vending/emag_act(user as mob)
|
||||
emagged = 1
|
||||
emagged = TRUE
|
||||
to_chat(user, "You short out the product lock on [src]")
|
||||
return
|
||||
|
||||
/**
|
||||
* Receive payment with cashmoney.
|
||||
@@ -511,7 +510,7 @@
|
||||
categories &= ~CAT_COIN
|
||||
|
||||
if(href_list["remove_item"])
|
||||
eject_item()
|
||||
eject_item(usr)
|
||||
|
||||
if(href_list["pay"])
|
||||
if(currently_vending && vendor_account && !vendor_account.suspended)
|
||||
@@ -593,7 +592,7 @@
|
||||
return
|
||||
if(coin.string_attached)
|
||||
if(prob(50))
|
||||
to_chat(user, "<span class='notice'>You successfully pull the coin out before the [src] could swallow it.</span>")
|
||||
to_chat(user, "<span class='notice'>You successfully pull the coin out before [src] could swallow it.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You weren't able to pull the coin out fast enough, the machine ate it, string and all.</span>")
|
||||
QDEL_NULL(coin)
|
||||
@@ -605,25 +604,33 @@
|
||||
R.amount--
|
||||
|
||||
if(((last_reply + (vend_delay + 200)) <= world.time) && vend_reply)
|
||||
spawn(0)
|
||||
speak(src.vend_reply)
|
||||
last_reply = world.time
|
||||
speak(src.vend_reply)
|
||||
last_reply = world.time
|
||||
|
||||
use_power(vend_power_usage) //actuators and stuff
|
||||
if(icon_vend) //Show the vending animation if needed
|
||||
flick(icon_vend,src)
|
||||
spawn(vend_delay)
|
||||
do_vend(R)
|
||||
status_message = ""
|
||||
status_error = 0
|
||||
vend_ready = 1
|
||||
currently_vending = null
|
||||
SSnanoui.update_uis(src)
|
||||
flick(icon_vend, src)
|
||||
addtimer(CALLBACK(src, .proc/delayed_vend, R, user), vend_delay)
|
||||
|
||||
/obj/machinery/vending/proc/delayed_vend(datum/data/vending_product/R, mob/user)
|
||||
do_vend(R, user)
|
||||
status_message = ""
|
||||
status_error = 0
|
||||
vend_ready = 1
|
||||
currently_vending = null
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
//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/vending/proc/do_vend(datum/data/vending_product/R)
|
||||
/obj/machinery/vending/proc/do_vend(datum/data/vending_product/R, mob/user)
|
||||
if(!item_slot || !inserted_item)
|
||||
new R.product_path(get_turf(src))
|
||||
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)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -638,7 +645,7 @@
|
||||
qdel(vended)
|
||||
*/
|
||||
|
||||
/obj/machinery/vending/proc/stock(var/datum/data/vending_product/R, var/mob/user)
|
||||
/obj/machinery/vending/proc/stock(datum/data/vending_product/R, mob/user)
|
||||
if(panel_open)
|
||||
to_chat(user, "<span class='notice'>You stock the [src] with \a [R.product_name]</span>")
|
||||
R.amount++
|
||||
@@ -664,8 +671,6 @@
|
||||
if(shoot_inventory && prob(shoot_chance))
|
||||
throw_item()
|
||||
|
||||
return
|
||||
|
||||
/obj/machinery/vending/proc/speak(message)
|
||||
if(stat & NOPOWER)
|
||||
return
|
||||
@@ -686,28 +691,38 @@
|
||||
icon_state = "[initial(icon_state)]-off"
|
||||
stat |= NOPOWER
|
||||
|
||||
//Oh no we're malfunctioning! Dump out some product and break.
|
||||
/obj/machinery/vending/proc/malfunction()
|
||||
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
|
||||
/obj/machinery/vending/obj_break(damage_flag)
|
||||
if(!(stat & BROKEN))
|
||||
stat |= BROKEN
|
||||
icon_state = "[initial(icon_state)]-broken"
|
||||
|
||||
while(R.amount>0)
|
||||
new dump_path(loc)
|
||||
R.amount--
|
||||
break
|
||||
var/dump_amount = 0
|
||||
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.
|
||||
continue
|
||||
var/dump_path = R.product_path
|
||||
if(!dump_path)
|
||||
continue
|
||||
R.amount--
|
||||
// busting open a vendor will destroy some of the contents
|
||||
if(found_anything && prob(80))
|
||||
continue
|
||||
|
||||
stat |= BROKEN
|
||||
icon_state = "[initial(icon_state)]-broken"
|
||||
return
|
||||
var/obj/O = new dump_path(loc)
|
||||
step(O, pick(alldirs))
|
||||
found_anything = TRUE
|
||||
dump_amount++
|
||||
if(dump_amount >= 16)
|
||||
return
|
||||
|
||||
//Somebody cut an important wire and now we're following a new definition of "pitch."
|
||||
/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
|
||||
|
||||
@@ -722,11 +737,9 @@
|
||||
throw_item = new dump_path(loc)
|
||||
break
|
||||
if(!throw_item)
|
||||
return 0
|
||||
spawn(0)
|
||||
throw_item.throw_at(target, 16, 3, src)
|
||||
return
|
||||
throw_item.throw_at(target, 16, 3, src)
|
||||
visible_message("<span class='danger'>[src] launches [throw_item.name] at [target.name]!</span>")
|
||||
return 1
|
||||
|
||||
/*
|
||||
* Vending machine types
|
||||
@@ -840,28 +853,39 @@
|
||||
component_parts += new /obj/item/vending_refill/coffee(0)
|
||||
|
||||
/obj/machinery/vending/coffee/item_slot_check(mob/user, obj/item/I)
|
||||
if(!(istype(I, /obj/item/reagent_containers/glass) || istype(I, /obj/item/reagent_containers/food/drinks)))
|
||||
return FALSE
|
||||
if(!..())
|
||||
return FALSE
|
||||
if(!(istype(I, /obj/item/reagent_containers/glass) || istype(I, /obj/item/reagent_containers/food/drinks)))
|
||||
to_chat(user, "<span class='warning'>[I] is not compatible with this machine.</span>")
|
||||
return FALSE
|
||||
if(!I.is_open_container())
|
||||
to_chat(user, "<span class='warning'>You need to open [I] before you insert it.</span>")
|
||||
to_chat(user, "<span class='warning'>You need to open [I] before inserting it.</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/vending/coffee/do_vend(datum/data/vending_product/R)
|
||||
/obj/machinery/vending/coffee/do_vend(datum/data/vending_product/R, mob/user)
|
||||
if(..())
|
||||
return
|
||||
var/obj/item/reagent_containers/food/drinks/vended = new R.product_path()
|
||||
|
||||
if(istype(vended, /obj/item/reagent_containers/food/drinks/mug))
|
||||
vended.forceMove(get_turf(src))
|
||||
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)
|
||||
vended.forceMove(get_turf(src))
|
||||
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
|
||||
qdel(vended)
|
||||
|
||||
|
||||
@@ -49,13 +49,9 @@
|
||||
tforce = O.throwforce
|
||||
take_damage(tforce, BRUTE, "melee", 1, get_dir(src, AM))
|
||||
|
||||
/obj/ex_act(severity, target)
|
||||
/obj/ex_act(severity)
|
||||
if(resistance_flags & INDESTRUCTIBLE)
|
||||
return
|
||||
if(target == src)
|
||||
obj_integrity = 0
|
||||
qdel(src)
|
||||
return
|
||||
switch(severity)
|
||||
if(1)
|
||||
obj_integrity = 0
|
||||
@@ -69,7 +65,8 @@
|
||||
. = ..()
|
||||
playsound(src, P.hitsound, 50, 1)
|
||||
visible_message("<span class='danger'>[src] is hit by \a [P]!</span>")
|
||||
take_damage(P.damage, P.damage_type, P.flag, 0, turn(P.dir, 180), P.armour_penetration)
|
||||
if(!QDELETED(src)) //Bullet on_hit effect might have already destroyed this object
|
||||
take_damage(P.damage, P.damage_type, P.flag, 0, turn(P.dir, 180), P.armour_penetration)
|
||||
|
||||
/obj/proc/hulk_damage()
|
||||
return 150 //the damage hulks do on punches to this object, is affected by melee armor
|
||||
|
||||
Reference in New Issue
Block a user