diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm index 553016400ad..6e5605cd232 100644 --- a/code/game/machinery/machinery.dm +++ b/code/game/machinery/machinery.dm @@ -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) diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index 33a2e2840ac..56ac1bc3f6a 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -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, "You insert the [I] into the [src]") 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, "It does nothing.") else if(panel_open) @@ -281,21 +279,18 @@ 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 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, "There is something already inserted!") 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, "[I] is stuck to your hand, you can't seem to put it down!") return - user.unEquip(I) inserted_item = I I.forceMove(src) to_chat(user, "You insert [I] into [src].") 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, "You successfully pull the coin out before the [src] could swallow it.") + to_chat(user, "You successfully pull the coin out before [src] could swallow it.") else to_chat(user, "You weren't able to pull the coin out fast enough, the machine ate it, string and all.") 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, "You stock the [src] with \a [R.product_name]") 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("[src] launches [throw_item.name] at [target.name]!") - 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, "[I] is not compatible with this machine.") - return FALSE if(!I.is_open_container()) - to_chat(user, "You need to open [I] before you insert it.") + to_chat(user, "You need to open [I] before inserting it.") 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) diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm index 246fc5df75d..572495b503f 100644 --- a/code/game/objects/obj_defense.dm +++ b/code/game/objects/obj_defense.dm @@ -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("[src] is hit by \a [P]!") - 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