mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-27 22:17:32 +01:00
Tipping vending machines for freebies and/or crushes (#20060)
* Initial commit * Add RNG tip behavior, including free items. * Add some additional checks * Small cleanups * Add squishing, drop normal damage to 40 * Haha, unless? (this is how it is on tg) * Datumizes vendor tips, part one * Datumizing, part 2 * Remove unused * Remove old "key" var * Fix .proc call * double dwarf damage * Update code/game/machinery/vendors/vending.dm Thanks, sean Co-authored-by: S34N <12197162+S34NW@users.noreply.github.com> * Add a warning hit * squish component review * update visible message * remove extra defines * charlie review * Add explosion tilts, some slight cleanups * Review changes - Tweaks self knockover damage slightly to not be the same as crit damage - farie's reviews * Unindent, clean up crit logic * Refactor some code out of main vendor proc also re-adds the head-popping crit lol * making linter happy :) * Removes global list in favor of static one --------- Co-authored-by: S34N <12197162+S34NW@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
#define SHORT_SCALE (5/7)
|
||||
#define TALL_SCALE (7/5)
|
||||
|
||||
/**
|
||||
* squish.dm
|
||||
*
|
||||
* It's an element that squishes things. After the duration passes, it reverses the transformation it squished with, taking into account if they are a different orientation than they started (read: rotationally-fluid)
|
||||
*
|
||||
* Normal squishes apply vertically, as if the target is being squished from above, but you can set reverse to TRUE if you want to squish them from the sides, like if they pancake into a wall from the East or West
|
||||
*/
|
||||
/datum/element/squish
|
||||
element_flags = ELEMENT_DETACH
|
||||
|
||||
/datum/element/squish/Attach(datum/target, duration = 20 SECONDS, reverse = FALSE)
|
||||
. = ..()
|
||||
if(!iscarbon(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
|
||||
var/mob/living/carbon/C = target
|
||||
var/was_lying = C.body_position == LYING_DOWN
|
||||
addtimer(CALLBACK(src, PROC_REF(Detach), C, was_lying, reverse), duration)
|
||||
|
||||
if(reverse)
|
||||
C.transform = C.transform.Scale(SHORT_SCALE, TALL_SCALE)
|
||||
else
|
||||
C.transform = C.transform.Scale(TALL_SCALE, SHORT_SCALE)
|
||||
|
||||
/datum/element/squish/Detach(mob/living/carbon/C, was_lying, reverse)
|
||||
. = ..()
|
||||
if(!istype(C))
|
||||
return
|
||||
var/is_lying = C.body_position == LYING_DOWN
|
||||
|
||||
if(reverse)
|
||||
is_lying = !is_lying
|
||||
|
||||
if(was_lying == is_lying)
|
||||
C.transform = C.transform.Scale(SHORT_SCALE, TALL_SCALE)
|
||||
else
|
||||
C.transform = C.transform.Scale(TALL_SCALE, SHORT_SCALE)
|
||||
|
||||
#undef SHORT_SCALE
|
||||
#undef TALL_SCALE
|
||||
@@ -373,6 +373,7 @@
|
||||
contraband = list(/obj/item/reagent_containers/glass/bottle/wizarditis = 1)
|
||||
armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50)
|
||||
resistance_flags = FIRE_PROOF
|
||||
tiltable = FALSE // don't let a poor wizard screw themselves
|
||||
|
||||
/obj/machinery/economy/vending/autodrobe
|
||||
name = "\improper AutoDrobe"
|
||||
@@ -859,6 +860,7 @@
|
||||
icon_panel = "wallmed"
|
||||
icon_broken = "wallmed"
|
||||
density = FALSE //It is wall-mounted, and thus, not dense. --Superxpdude
|
||||
tiltable = FALSE
|
||||
products = list(/obj/item/stack/medical/bruise_pack = 2, /obj/item/stack/medical/ointment = 2, /obj/item/reagent_containers/hypospray/autoinjector = 4, /obj/item/healthanalyzer = 1)
|
||||
contraband = list(/obj/item/reagent_containers/syringe/charcoal = 4, /obj/item/reagent_containers/syringe/antiviral = 4, /obj/item/reagent_containers/food/pill/tox = 1)
|
||||
armor = list(melee = 50, bullet = 20, laser = 20, energy = 20, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 70)
|
||||
|
||||
+291
-1
@@ -1,3 +1,11 @@
|
||||
// Using these to decide how a vendor crush should be handled after crushing a carbon.
|
||||
/// Just jump ship, the crit handled everything it needs to.
|
||||
#define VENDOR_CRUSH_HANDLED 0
|
||||
/// Throw the vendor at the target's tile.
|
||||
#define VENDOR_THROW_AT_TARGET 1
|
||||
/// Don't actually throw at the target, just tip it in place.
|
||||
#define VENDOR_TIP_IN_PLACE 2
|
||||
|
||||
/**
|
||||
* Datum used to hold information about a product in a vending machine
|
||||
*/
|
||||
@@ -114,6 +122,33 @@
|
||||
///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
|
||||
var/tilted = FALSE
|
||||
/// Amount of damage to deal when tipped
|
||||
var/squish_damage = 40 // yowch
|
||||
/// Factor of extra damage to deal when triggering a crit
|
||||
var/crit_damage_factor = 2
|
||||
/// Factor of extra damage to deal when you knock it over onto yourself
|
||||
var/self_knockover_factor = 1.5
|
||||
/// All possible crits that could be applied. We only need to build this up once
|
||||
var/static/list/all_possible_crits = list()
|
||||
/// Possible crit effects from this vending machine tipping.
|
||||
var/list/possible_crits = list(
|
||||
/datum/vendor_crit/pop_head,
|
||||
/datum/vendor_crit/embed,
|
||||
/datum/vendor_crit/pin,
|
||||
/datum/vendor_crit/shatter,
|
||||
/datum/vendor_crit/lucky
|
||||
)
|
||||
/// number of shards to apply when a crit embeds
|
||||
var/num_shards = 7
|
||||
/// Last time the machine was punched
|
||||
var/last_hit_time = 0
|
||||
/// How long to wait before resetting the warning cooldown
|
||||
var/hit_warning_cooldown_length = 10 SECONDS
|
||||
|
||||
/obj/machinery/economy/vending/Initialize(mapload)
|
||||
. = ..()
|
||||
var/build_inv = FALSE
|
||||
@@ -145,6 +180,11 @@
|
||||
if(account_database)
|
||||
vendor_account = account_database.vendor_account
|
||||
|
||||
|
||||
if(!length(all_possible_crits))
|
||||
for(var/typepath in subtypesof(/datum/vendor_crit))
|
||||
all_possible_crits[typepath] = new typepath()
|
||||
|
||||
reconnect_database()
|
||||
power_change()
|
||||
|
||||
@@ -154,6 +194,13 @@
|
||||
QDEL_NULL(inserted_item)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/economy/vending/examine(mob/user)
|
||||
. = ..()
|
||||
if(tilted)
|
||||
. += "<span class='warning'>It's been tipped over and won't be usable unless it's righted.</span>"
|
||||
if(Adjacent(user))
|
||||
. += "<span class='notice'>You can <b>Alt-Click</b> it to right it.</span>"
|
||||
|
||||
/obj/machinery/economy/vending/RefreshParts() //Better would be to make constructable child
|
||||
if(!component_parts)
|
||||
return
|
||||
@@ -300,7 +347,19 @@
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/machinery/economy/vending/AltClick(mob/user)
|
||||
if(!tilted || !Adjacent(user) || HAS_TRAIT(user, TRAIT_HANDS_BLOCKED))
|
||||
return
|
||||
|
||||
untilt(user)
|
||||
|
||||
/obj/machinery/economy/vending/attackby(obj/item/I, mob/user, params)
|
||||
if(tilted)
|
||||
if(user.a_intent == INTENT_HELP)
|
||||
to_chat(user, "<span class='warning'>[src] is tipped over and non-functional! You'll need to right it first.</span>")
|
||||
return
|
||||
return ..()
|
||||
|
||||
if(isspacecash(I))
|
||||
insert_cash(I, user)
|
||||
return
|
||||
@@ -326,24 +385,72 @@
|
||||
if(item_slot_check(user, I))
|
||||
insert_item(user, I)
|
||||
return
|
||||
return ..()
|
||||
. = ..()
|
||||
if(tiltable && !tilted && I.force)
|
||||
if(resistance_flags & INDESTRUCTIBLE)
|
||||
// no goodies, but also no tilts
|
||||
return
|
||||
var/should_warn = world.time > last_hit_time + hit_warning_cooldown_length
|
||||
last_hit_time = world.time
|
||||
if(should_warn)
|
||||
visible_message("<span class='warning'>[src] seems to sway a bit!</span>")
|
||||
to_chat(user, "<span class='danger'>You might want to think twice about doing that again, [src] looks like it could come crashing down!</span>")
|
||||
return
|
||||
|
||||
switch(rand(1, 100))
|
||||
if(1 to 5)
|
||||
freebie(user, 3)
|
||||
if(6 to 15)
|
||||
freebie(user, 2)
|
||||
if(16 to 25)
|
||||
freebie(user, 1)
|
||||
if(26 to 75)
|
||||
return
|
||||
if(76 to 90)
|
||||
tilt(user)
|
||||
if(91 to 100)
|
||||
tilt(user, crit = TRUE)
|
||||
|
||||
|
||||
/obj/machinery/economy/vending/proc/freebie(mob/user, num_freebies)
|
||||
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))
|
||||
|
||||
if(R.amount <= 0)
|
||||
continue
|
||||
|
||||
var/dump_path = R.product_path
|
||||
if(!dump_path)
|
||||
continue
|
||||
new dump_path(get_turf(src))
|
||||
R.amount--
|
||||
break
|
||||
|
||||
/obj/machinery/economy/vending/crowbar_act(mob/user, obj/item/I)
|
||||
if(!component_parts)
|
||||
return
|
||||
. = TRUE
|
||||
if(tilted)
|
||||
to_chat("<span class='warning'>You'll need to right it first!</span>")
|
||||
return
|
||||
default_deconstruction_crowbar(user, I)
|
||||
|
||||
/obj/machinery/economy/vending/multitool_act(mob/user, obj/item/I)
|
||||
. = TRUE
|
||||
if(tilted)
|
||||
to_chat("<span class='warning'>You'll need to right it first!</span>")
|
||||
return
|
||||
if(!I.use_tool(src, user, 0, volume = I.tool_volume))
|
||||
return
|
||||
wires.Interact(user)
|
||||
|
||||
/obj/machinery/economy/vending/screwdriver_act(mob/user, obj/item/I)
|
||||
. = TRUE
|
||||
if(tilted)
|
||||
to_chat("<span class='warning'>You'll need to right it first!</span>")
|
||||
return
|
||||
if(!I.use_tool(src, user, 0, volume = I.tool_volume))
|
||||
return
|
||||
if(!anchored)
|
||||
@@ -360,11 +467,17 @@
|
||||
|
||||
/obj/machinery/economy/vending/wirecutter_act(mob/user, obj/item/I)
|
||||
. = TRUE
|
||||
if(tilted)
|
||||
to_chat("<span class='warning'>You'll need to right it first!</span>")
|
||||
return
|
||||
if(I.use_tool(src, user, 0, volume = 0))
|
||||
wires.Interact(user)
|
||||
|
||||
/obj/machinery/economy/vending/wrench_act(mob/user, obj/item/I)
|
||||
. = TRUE
|
||||
if(tilted)
|
||||
to_chat("<span class='warning'>The fastening bolts aren't on the ground, you'll need to right it first!</span>")
|
||||
return
|
||||
if(!I.use_tool(src, user, 0, volume = 0))
|
||||
return
|
||||
default_unfasten_wrench(user, I, time = 6 SECONDS)
|
||||
@@ -442,6 +555,22 @@
|
||||
emagged = TRUE
|
||||
to_chat(user, "You short out the product lock on [src]")
|
||||
|
||||
/obj/machinery/economy/vending/ex_act(severity)
|
||||
. = ..()
|
||||
if(QDELETED(src) || (resistance_flags & INDESTRUCTIBLE) || tilted || !tiltable)
|
||||
return
|
||||
var/tilt_prob = 0
|
||||
switch(severity)
|
||||
if(EXPLODE_LIGHT)
|
||||
tilt_prob = 10
|
||||
if(EXPLODE_HEAVY)
|
||||
tilt_prob = 50
|
||||
if(EXPLODE_DEVASTATE)
|
||||
tilt_prob = 80
|
||||
|
||||
if(prob(tilt_prob))
|
||||
tilt()
|
||||
|
||||
/obj/machinery/economy/vending/attack_ai(mob/user)
|
||||
return attack_hand(user)
|
||||
|
||||
@@ -452,6 +581,10 @@
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
return
|
||||
|
||||
if(tilted)
|
||||
to_chat(user, "<span class='warning'>[src] is tipped over and non-functional! You'll need to right it first.</span>")
|
||||
return
|
||||
|
||||
if(seconds_electrified != 0 && shock(user, 100))
|
||||
return
|
||||
|
||||
@@ -799,6 +932,160 @@
|
||||
|
||||
/obj/machinery/economy/vending/onTransitZ()
|
||||
return
|
||||
|
||||
/**
|
||||
* Select a random valid crit.
|
||||
*/
|
||||
/obj/machinery/economy/vending/proc/choose_crit(mob/living/carbon/victim)
|
||||
if(!length(possible_crits))
|
||||
return
|
||||
for(var/crit_path in shuffle(possible_crits))
|
||||
var/datum/vendor_crit/C = all_possible_crits[crit_path]
|
||||
if(C.is_valid(src, victim))
|
||||
return C
|
||||
|
||||
/obj/machinery/economy/vending/proc/handle_squish_carbon(mob/living/carbon/victim, damage_to_deal, crit, from_combat)
|
||||
|
||||
// Damage points to "refund", if a crit already beats the shit out of you we can shelve some of the extra damage.
|
||||
var/crit_rebate = 0
|
||||
|
||||
var/should_throw_at_target = TRUE
|
||||
|
||||
if(HAS_TRAIT(victim, TRAIT_DWARF))
|
||||
// also double damage if you're short
|
||||
damage_to_deal *= 2
|
||||
|
||||
var/datum/vendor_crit/critical_attack = choose_crit(victim)
|
||||
if(!from_combat && crit && critical_attack)
|
||||
crit_rebate = critical_attack.tip_crit_effect(src, victim)
|
||||
if(critical_attack.harmless)
|
||||
tilt_over(critical_attack.fall_towards_mob ? victim : null)
|
||||
return VENDOR_CRUSH_HANDLED
|
||||
|
||||
should_throw_at_target = critical_attack.fall_towards_mob
|
||||
add_attack_logs(null, victim, "critically crushed by [src] causing [critical_attack]")
|
||||
else
|
||||
victim.visible_message(
|
||||
"<span class='danger'>[victim] is crushed by [src]!</span>",
|
||||
"<span class='userdanger'>[src] crushes you!</span>",
|
||||
"<span class='warning'>You hear a loud crunch!</span>"
|
||||
)
|
||||
add_attack_logs(null, victim, "crushed by [src]")
|
||||
|
||||
// 30% chance to spread damage across the entire body, 70% chance to target two limbs in particular
|
||||
damage_to_deal = max(damage_to_deal - crit_rebate, 0)
|
||||
if(prob(30))
|
||||
victim.apply_damage(damage_to_deal, BRUTE, BODY_ZONE_CHEST, spread_damage = TRUE)
|
||||
else
|
||||
var/picked_zone
|
||||
var/num_parts_to_pick = 2
|
||||
for(var/i = 1 to num_parts_to_pick)
|
||||
picked_zone = pick(BODY_ZONE_CHEST, BODY_ZONE_HEAD, BODY_ZONE_L_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_ARM, BODY_ZONE_R_LEG)
|
||||
victim.apply_damage((damage_to_deal) * (1 / num_parts_to_pick), BRUTE, picked_zone)
|
||||
|
||||
victim.AddElement(/datum/element/squish, 80 SECONDS)
|
||||
victim.emote("scream")
|
||||
|
||||
return should_throw_at_target ? VENDOR_THROW_AT_TARGET : VENDOR_TIP_IN_PLACE
|
||||
|
||||
/**
|
||||
* Tilts the machine onto the atom passed in.
|
||||
*
|
||||
* Arguments:
|
||||
* * victim - The thing the machine is falling on top of
|
||||
* * crit - if true, some special damage effects might happen.
|
||||
* * from_combat - If true, hold off on some of the additional damage and extra effects.
|
||||
*/
|
||||
/obj/machinery/economy/vending/proc/tilt(atom/victim, crit = FALSE, from_combat = FALSE)
|
||||
if(QDELETED(src) || !has_gravity(src) || !tiltable || tilted)
|
||||
return
|
||||
|
||||
tilted = TRUE
|
||||
layer = ABOVE_MOB_LAYER
|
||||
|
||||
var/should_throw_at_target = TRUE
|
||||
|
||||
. = FALSE
|
||||
|
||||
if(!victim || !in_range(victim, src))
|
||||
tilt_over()
|
||||
return
|
||||
for(var/mob/living/L in get_turf(victim))
|
||||
// Damage to deal outright
|
||||
var/damage_to_deal = squish_damage
|
||||
if(!from_combat)
|
||||
if(crit)
|
||||
// increase damage if you knock it over onto yourself
|
||||
damage_to_deal *= crit_damage_factor
|
||||
else
|
||||
damage_to_deal *= self_knockover_factor
|
||||
|
||||
if(iscarbon(L))
|
||||
var/throw_spec = handle_squish_carbon(victim, damage_to_deal, crit, from_combat)
|
||||
switch(throw_spec)
|
||||
if(VENDOR_CRUSH_HANDLED)
|
||||
return TRUE
|
||||
if(VENDOR_THROW_AT_TARGET)
|
||||
should_throw_at_target = TRUE
|
||||
if(VENDOR_TIP_IN_PLACE)
|
||||
should_throw_at_target = FALSE
|
||||
else
|
||||
L.visible_message(
|
||||
"<span class='danger'>[L] is crushed by [src]!</span>",
|
||||
"<span class='userdanger'>[src] falls on top of you, crushing you!</span>"
|
||||
)
|
||||
L.apply_damage(damage_to_deal, BRUTE)
|
||||
|
||||
add_attack_logs(null, L, "crushed by [src]")
|
||||
|
||||
. = TRUE
|
||||
L.Weaken(6 SECONDS)
|
||||
L.KnockDown(12 SECONDS)
|
||||
|
||||
playsound(L, "sound/effects/blobattack.ogg", 40, TRUE)
|
||||
playsound(L, "sound/effects/splat.ogg", 50, TRUE)
|
||||
|
||||
tilt_over(should_throw_at_target ? victim : null)
|
||||
|
||||
/obj/machinery/economy/vending/proc/tilt_over(mob/victim)
|
||||
visible_message("<span class='danger'>[src] tips over!</span>", "<span class='danger'>You hear a loud crash!</span>")
|
||||
playsound(src, "sound/effects/bang.ogg", 100, TRUE)
|
||||
var/matrix/M = matrix()
|
||||
M.Turn(pick(90, 270))
|
||||
transform = M
|
||||
if(victim && get_turf(victim) != get_turf(src))
|
||||
throw_at(get_turf(victim), 1, 1, spin = FALSE)
|
||||
|
||||
/obj/machinery/economy/vending/proc/untilt(mob/user)
|
||||
if(!tilted)
|
||||
return
|
||||
|
||||
if(user)
|
||||
user.visible_message(
|
||||
"[user] begins to right [src].",
|
||||
"You begin to right [src]."
|
||||
)
|
||||
if(!do_after(user, 7 SECONDS, TRUE, src))
|
||||
return
|
||||
user.visible_message(
|
||||
"<span class='notice'>[user] rights [src].</span>",
|
||||
"<span class='notice'>You right [src].</span>",
|
||||
"<span class='notice'>You hear a loud clang.</span>"
|
||||
)
|
||||
|
||||
unbuckle_all_mobs(TRUE)
|
||||
|
||||
tilted = FALSE
|
||||
layer = initial(layer)
|
||||
|
||||
var/matrix/M = matrix()
|
||||
M.Turn(0)
|
||||
transform = M
|
||||
|
||||
/obj/machinery/economy/vending/shove_impact(mob/living/target, mob/living/attacker)
|
||||
tilt(target, from_combat = TRUE)
|
||||
return TRUE
|
||||
|
||||
/*
|
||||
* Vending machine types
|
||||
*/
|
||||
@@ -818,3 +1105,6 @@
|
||||
*/
|
||||
|
||||
|
||||
#undef VENDOR_CRUSH_HANDLED
|
||||
#undef VENDOR_THROW_AT_TARGET
|
||||
#undef VENDOR_TIP_IN_PLACE
|
||||
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* Framework for custom vendor crits.
|
||||
*/
|
||||
|
||||
/datum/vendor_crit
|
||||
/// If it'll deal damage or not
|
||||
var/harmless = FALSE
|
||||
/// If we should be thrown against the mob or not.
|
||||
var/fall_towards_mob = TRUE
|
||||
|
||||
/**
|
||||
* Return whether or not the crit selected is valid.
|
||||
*/
|
||||
/datum/vendor_crit/proc/is_valid(obj/machinery/economy/vending/machine, mob/living/carbon/victim)
|
||||
return TRUE
|
||||
|
||||
/***
|
||||
* Perform the tip crit effect on a victim.
|
||||
* Arguments:
|
||||
* * machine - The machine that was tipped over
|
||||
* * user - The unfortunate victim upon whom it was tipped over
|
||||
* Returns: The "crit rebate", or the amount of damage to subtract from the original amount of damage dealt, to soften the blow.
|
||||
*/
|
||||
/datum/vendor_crit/proc/tip_crit_effect(obj/machinery/economy/vending/machine, mob/living/carbon/victim)
|
||||
return 0
|
||||
|
||||
/datum/vendor_crit/shatter
|
||||
|
||||
/datum/vendor_crit/shatter/tip_crit_effect(obj/machinery/economy/vending/machine, mob/living/carbon/victim)
|
||||
victim.bleed(150)
|
||||
var/obj/item/organ/external/leg/right = victim.get_organ(BODY_ZONE_R_LEG)
|
||||
var/obj/item/organ/external/leg/left = victim.get_organ(BODY_ZONE_L_LEG)
|
||||
if(istype(left))
|
||||
left.receive_damage(200)
|
||||
if(istype(right))
|
||||
right.receive_damage(200)
|
||||
|
||||
if(left || right)
|
||||
victim.visible_message(
|
||||
"<span class='danger'>[victim]'s legs shatter with a sickening crunch!</span>",
|
||||
"<span class='userdanger'>Your legs shatter with a sickening crunch!</span>",
|
||||
"<span class='danger'>You hear a sickening crunch!</span>"
|
||||
)
|
||||
|
||||
// that's a LOT of damage, let's rebate most of it.
|
||||
return machine.squish_damage * (5/6)
|
||||
|
||||
/datum/vendor_crit/pin
|
||||
|
||||
/datum/vendor_crit/pin/tip_crit_effect(obj/machinery/economy/vending/machine, mob/living/carbon/victim)
|
||||
machine.forceMove(get_turf(victim))
|
||||
machine.buckle_mob(victim, force=TRUE)
|
||||
victim.visible_message(
|
||||
"<span class='danger'>[victim] gets pinned underneath [machine]!</span>",
|
||||
"<span class='userdanger'>You are pinned down by [machine]!</span>"
|
||||
)
|
||||
|
||||
return 0
|
||||
|
||||
/datum/vendor_crit/embed
|
||||
|
||||
/datum/vendor_crit/embed/is_valid(obj/machinery/economy/vending/machine, mob/living/carbon/victim)
|
||||
. = ..()
|
||||
if(machine.num_shards <= 0)
|
||||
return FALSE
|
||||
|
||||
/datum/vendor_crit/embed/tip_crit_effect(obj/machinery/economy/vending/machine, mob/living/carbon/victim)
|
||||
victim.visible_message(
|
||||
"<span class='danger'>[machine]'s panel shatters against [victim]!</span>",
|
||||
"<span class='userdanger>[machine] lands on you, its panel shattering!</span>"
|
||||
)
|
||||
|
||||
for(var/i in 1 to machine.num_shards)
|
||||
var/obj/item/shard/shard = new /obj/item/shard(get_turf(victim))
|
||||
// do a little dance to force the embeds, but make sure the glass isn't gigapowered afterwards
|
||||
shard.embed_chance = 100
|
||||
shard.embedded_pain_chance = 5
|
||||
shard.embedded_impact_pain_multiplier = 1
|
||||
shard.embedded_ignore_throwspeed_threshold = TRUE
|
||||
victim.hitby(shard, skipcatch = TRUE, hitpush = FALSE)
|
||||
shard.embed_chance = initial(shard.embed_chance)
|
||||
shard.embedded_pain_chance = initial(shard.embedded_pain_chance)
|
||||
shard.embedded_impact_pain_multiplier = initial(shard.embedded_pain_multiplier)
|
||||
shard.embedded_ignore_throwspeed_threshold = initial(shard.embedded_ignore_throwspeed_threshold)
|
||||
|
||||
playsound(machine, "shatter", 50)
|
||||
|
||||
return machine.squish_damage * (3/4)
|
||||
|
||||
/datum/vendor_crit/pop_head
|
||||
|
||||
/datum/vendor_crit/pop_head/tip_crit_effect(obj/machinery/economy/vending/machine, mob/living/carbon/victim)
|
||||
// pop!
|
||||
var/obj/item/organ/external/head/H = victim.get_organ("head")
|
||||
var/obj/item/organ/internal/brain/B = victim.get_int_organ_tag("brain")
|
||||
if(H)
|
||||
victim.visible_message("<span class='danger'>[H] gets crushed under [machine], and explodes in a shower of gore!</span>", "<span class='userdanger'>Oh f-</span>")
|
||||
new /obj/effect/gibspawner/human(get_turf(victim))
|
||||
H.drop_organs()
|
||||
H.droplimb(TRUE)
|
||||
H.disfigure()
|
||||
victim.apply_damage(50, BRUTE, BODY_ZONE_HEAD)
|
||||
else
|
||||
H.visible_message("<span class='danger'>[victim]'s head seems to be crushed under [machine]...but wait, they had none in the first place!</span>")
|
||||
if(B in H)
|
||||
victim.adjustBrainLoss(80)
|
||||
|
||||
return 0
|
||||
|
||||
/datum/vendor_crit/lucky
|
||||
harmless = TRUE
|
||||
|
||||
/datum/vendor_crit/lucky/tip_crit_effect(obj/machinery/economy/vending/machine, mob/living/carbon/victim)
|
||||
victim.visible_message(
|
||||
"<span class='danger'>[src] crashes around [victim], but doesn't seem to crush them!</span>",
|
||||
"<span class='userdanger'>[src] crashes around you, but only around you! You're fine!</span>"
|
||||
)
|
||||
|
||||
return 1000
|
||||
@@ -372,6 +372,7 @@
|
||||
#include "code\datums\components\spawner.dm"
|
||||
#include "code\datums\components\spooky.dm"
|
||||
#include "code\datums\components\squeak.dm"
|
||||
#include "code\datums\components\squish.dm"
|
||||
#include "code\datums\components\surgery_initiator.dm"
|
||||
#include "code\datums\components\swarming.dm"
|
||||
#include "code\datums\discord\discord_manager.dm"
|
||||
@@ -806,6 +807,7 @@
|
||||
#include "code\game\machinery\vendors\departmental_vendors.dm"
|
||||
#include "code\game\machinery\vendors\generic_vendors.dm"
|
||||
#include "code\game\machinery\vendors\vending.dm"
|
||||
#include "code\game\machinery\vendors\vendor_crits.dm"
|
||||
#include "code\game\machinery\vendors\wardrobe_vendors.dm"
|
||||
#include "code\game\magic\Uristrunes.dm"
|
||||
#include "code\game\mecha\mech_bay.dm"
|
||||
|
||||
Reference in New Issue
Block a user