[MIRROR] Unlucky trait (#11775)

Co-authored-by: Cameron Lennox <killer65311@gmail.com>
This commit is contained in:
CHOMPStation2StaffMirrorBot
2025-10-04 00:52:24 -07:00
committed by GitHub
parent 6eab8c8408
commit b8fe8fa68d
44 changed files with 1162 additions and 181 deletions

View File

@@ -163,6 +163,11 @@
///from base of atom/attack_paw(): (mob/user) ///from base of atom/attack_paw(): (mob/user)
//This signal return value bitflags can be found in __DEFINES/misc.dm //This signal return value bitflags can be found in __DEFINES/misc.dm
///from base of /obj/structure/stairs/top/use_stairs(var/atom/movable/AM, var/atom/oldloc)
#define COMSIG_MOVED_DOWN_STAIRS "atom_moved_down_stairs"
///from base of /obj/structure/stairs/bottom/use_stairs(var/atom/movable/AM, var/atom/oldloc)
#define COMSIG_MOVED_UP_STAIRS "atom_moved_up_stairs"
///called for each movable in a turf contents on /turf/zImpact(): (atom/movable/A, levels) ///called for each movable in a turf contents on /turf/zImpact(): (atom/movable/A, levels)
#define COMSIG_ATOM_INTERCEPT_Z_FALL "movable_intercept_z_impact" #define COMSIG_ATOM_INTERCEPT_Z_FALL "movable_intercept_z_impact"
///called on a movable (NOT living) when someone starts pulling it (atom/movable/puller, state, force) ///called on a movable (NOT living) when someone starts pulling it (atom/movable/puller, state, force)
@@ -240,6 +245,8 @@
#define COMPONENT_MOVABLE_IMPACT_NEVERMIND (1<<1) //return true if you destroyed whatever it was you're impacting and there won't be anything for hitby() to run on #define COMPONENT_MOVABLE_IMPACT_NEVERMIND (1<<1) //return true if you destroyed whatever it was you're impacting and there won't be anything for hitby() to run on
///from base of mob/living/hitby(): (mob/living/target, hit_zone) ///from base of mob/living/hitby(): (mob/living/target, hit_zone)
#define COMSIG_MOVABLE_IMPACT_ZONE "item_impact_zone" #define COMSIG_MOVABLE_IMPACT_ZONE "item_impact_zone"
///from the base of mob/living/carbon/human/hitby(): (atom/movable/source, speed)
#define COMSIG_HUMAN_ON_CATCH_THROW "human_on_catch_throw"
///from base of atom/movable/buckle_mob(): (mob, force) ///from base of atom/movable/buckle_mob(): (mob, force)
#define COMSIG_MOVABLE_BUCKLE "buckle" #define COMSIG_MOVABLE_BUCKLE "buckle"
///from base of atom/movable/unbuckle_mob(): (mob, force) ///from base of atom/movable/unbuckle_mob(): (mob, force)
@@ -290,6 +297,9 @@
#define COMSIG_MOB_ALTCLICKON "mob_altclickon" #define COMSIG_MOB_ALTCLICKON "mob_altclickon"
#define COMSIG_MOB_CANCEL_CLICKON (1<<0) #define COMSIG_MOB_CANCEL_CLICKON (1<<0)
///from base of /obj/item/dice/proc/rollDice(mob/user as mob, var/silent = 0). Has the arguments of 'src, silent, result'
#define COMSIG_MOB_ROLLED_DICE "mob_rolled_dice" //can give a return value if we want it to make the dice roll a specific number!
///from base of obj/allowed(mob/M): (/obj) returns bool, if TRUE the mob has id access to the obj ///from base of obj/allowed(mob/M): (/obj) returns bool, if TRUE the mob has id access to the obj
#define COMSIG_MOB_ALLOWED "mob_allowed" #define COMSIG_MOB_ALLOWED "mob_allowed"
///from base of mob/anti_magic_check(): (mob/user, magic, holy, tinfoil, chargecost, self, protection_sources) ///from base of mob/anti_magic_check(): (mob/user, magic, holy, tinfoil, chargecost, self, protection_sources)
@@ -406,6 +416,8 @@
#define COMSIG_TAKING_APPLY_EFFECT "applying_effect" #define COMSIG_TAKING_APPLY_EFFECT "applying_effect"
///Return this in response if you don't want the effect to be applied ///Return this in response if you don't want the effect to be applied
#define COMSIG_CANCEL_EFFECT (1<<0) #define COMSIG_CANCEL_EFFECT (1<<0)
///from /mob/living/proc/stun_effect_act(var/stun_amount, var/agony_amount, var/def_zone, var/used_weapon=null, var/electric = FALSE)
#define COMSIG_STUN_EFFECT_ACT "stun_effect_act"
///Misc signal for checking for godmode. Used by /datum/element/godmode ///Misc signal for checking for godmode. Used by /datum/element/godmode
#define COMSIG_CHECK_FOR_GODMODE "check_for_godmode" #define COMSIG_CHECK_FOR_GODMODE "check_for_godmode"
@@ -450,7 +462,8 @@
///called when being electrocuted, from /mob/living/carbon/electrocute_act(shock_damage, source, siemens_coeff, def_zone, stun) ///called when being electrocuted, from /mob/living/carbon/electrocute_act(shock_damage, source, siemens_coeff, def_zone, stun)
#define COMSIG_BEING_ELECTROCUTED "being_electrocuted" #define COMSIG_BEING_ELECTROCUTED "being_electrocuted"
#define COMPONENT_CARBON_CANCEL_ELECTROCUTE (1<<0) //If this is set, the carbon will be not be electrocuted. #define COMPONENT_CARBON_CANCEL_ELECTROCUTE (1<<0) //If this is set, the carbon will be not be electrocuted.
///called when a carbon slipps, from /mob/living/carbon/slip(var/slipped_on,stun_duration=8)
#define COMSIG_ON_CARBON_SLIP "carbon_slip"
// /mob/living/silicon signals // /mob/living/silicon signals
///called when a silicon is emp'd. from /mob/living/silicon/emp_act(severity) ///called when a silicon is emp'd. from /mob/living/silicon/emp_act(severity)
@@ -536,6 +549,8 @@
#define COMSIG_MOB_UNEQUIPPED_ITEM "mob_unequipped_item" #define COMSIG_MOB_UNEQUIPPED_ITEM "mob_unequipped_item"
///from base of obj/item/pickup(): (/mob/taker) ///from base of obj/item/pickup(): (/mob/taker)
#define COMSIG_ITEM_PICKUP "item_pickup" #define COMSIG_ITEM_PICKUP "item_pickup"
///from base of obj/item/pickup(): (/obj/item)
#define COMSIG_PICKED_UP_ITEM "piked_up_item"
///from base of mob/living/carbon/attacked_by(): (mob/living/carbon/target, mob/living/user, hit_zone) ///from base of mob/living/carbon/attacked_by(): (mob/living/carbon/target, mob/living/user, hit_zone)
#define COMSIG_ITEM_ATTACK_ZONE "item_attack_zone" #define COMSIG_ITEM_ATTACK_ZONE "item_attack_zone"
///return a truthy value to prevent ensouling, checked in /obj/effect/proc_holder/spell/targeted/lichdom/cast(): (mob/user) ///return a truthy value to prevent ensouling, checked in /obj/effect/proc_holder/spell/targeted/lichdom/cast(): (mob/user)

View File

@@ -16,6 +16,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
/// Prevents the affected object from opening a loot window via alt click. See atom/AltClick() /// Prevents the affected object from opening a loot window via alt click. See atom/AltClick()
#define TRAIT_ALT_CLICK_BLOCKER "no_alt_click" #define TRAIT_ALT_CLICK_BLOCKER "no_alt_click"
/// Unlucky trait. Given by the 'unlucky' trait in character select. Checked by various things to cause unlucky interactions.
#define TRAIT_UNLUCKY "trait_unlucky"
#define TRAIT_INCAPACITATED "incapacitated" #define TRAIT_INCAPACITATED "incapacitated"
#define TRAIT_NOFIRE "nonflammable" #define TRAIT_NOFIRE "nonflammable"

View File

@@ -370,6 +370,7 @@
old_component.InheritComponent(arglist(arguments)) old_component.InheritComponent(arglist(arguments))
else else
old_component.InheritComponent(new_component, TRUE) old_component.InheritComponent(new_component, TRUE)
QDEL_NULL(new_component)
if(COMPONENT_DUPE_SOURCES) if(COMPONENT_DUPE_SOURCES)
if(source in old_component.sources) if(source in old_component.sources)

View File

@@ -45,7 +45,7 @@
if(G.affecting) if(G.affecting)
G.affecting.electrocute_act(10 * siemens, src, 1.0, BP_TORSO, 0) G.affecting.electrocute_act(10 * siemens, src, 1.0, BP_TORSO, 0)
var/agony = 80 * siemens //Does more than if hit with an electric hand, since grabbing is slower. var/agony = 80 * siemens //Does more than if hit with an electric hand, since grabbing is slower.
G.affecting.stun_effect_act(0, agony, BP_TORSO, src) G.affecting.stun_effect_act(0, agony, BP_TORSO, src, electric = TRUE)
add_attack_logs(src,G.affecting,"Changeling shocked") add_attack_logs(src,G.affecting,"Changeling shocked")

View File

@@ -0,0 +1,544 @@
/**
* Ripped from /tg/ with modifications.
* unlucky.dm: For when you want someone to have a really bad day
*
* When you attach an omen component to someone, they start running the risk of all sorts of bad environmental injuries, like nearby vending machines randomly falling on you (TBI),
* or hitting your head really hard when you slip and fall, or you get shocked by the tram rails at an unfortunate moment.
*
* Omens are removed once the victim is either maimed by one of the possible injuries, or if they receive a blessing (read: bashing with a bible) from the chaplain. (TBI)
*/
/datum/component/omen
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
/// How many incidents are left. If 0 exactly, it will get deleted.
var/incidents_left = INFINITY
/// Base probability of negative events. Cursed are half as unlucky.
var/luck_mod = 1
/// Base damage from negative events. Cursed take 25% of this damage.
var/damage_mod = 1
/// If we want to do more evil events, such as spontaneous combustion
var/evil = TRUE
/// If our codebase has safe disposals or not
var/safe_disposals = FALSE
/// If we have vore interactions or not
var/vorish = TRUE
/datum/component/omen/Initialize(incidents_left, luck_mod, damage_mod, evil, safe_disposals, vorish)
if(!isliving(parent))
return COMPONENT_INCOMPATIBLE
if(!isnull(incidents_left))
src.incidents_left = incidents_left
if(!isnull(luck_mod))
src.luck_mod = luck_mod
if(!isnull(damage_mod))
src.damage_mod = damage_mod
if(!isnull(evil))
src.evil = evil
if(!isnull(safe_disposals))
src.safe_disposals = safe_disposals
if(!isnull(vorish))
src.vorish = vorish
ADD_TRAIT(parent, TRAIT_UNLUCKY, src)
/**
* This is a omen eat omen world! The stronger omen survives.
*/
/datum/component/omen/InheritComponent(
datum/component/omen/new_comp,
i_am_original,
incidents_left,
luck_mod,
damage_mod,
evil,
safe_disposals,
vorish,
)
// If we have more incidents left the new one gets deleted.
if(src.incidents_left > incidents_left)
return
src.incidents_left = incidents_left
// The new omen is weaker than our current omen? Let's split the difference.
if(src.luck_mod > luck_mod)
src.luck_mod += luck_mod * 0.5
if(src.damage_mod > damage_mod)
src.damage_mod += damage_mod * 0.5
// If the new omen has special modifiers, we take them on forever!
if(evil)
src.evil = TRUE
if(safe_disposals)
src.safe_disposals = TRUE
if(vorish)
src.vorish = TRUE
//This means weaker, longing lasting omens will take priority, but have some of the strength of the original.
/datum/component/omen/Destroy(force)
var/mob/living/person = parent
REMOVE_TRAIT(person, TRAIT_UNLUCKY, src)
to_chat(person, span_warning(span_green("You feel a horrible omen lifted off your shoulders!")))
return ..()
/datum/component/omen/RegisterWithParent()
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(check_accident))
RegisterSignal(parent, COMSIG_ON_CARBON_SLIP, PROC_REF(check_slip))
RegisterSignal(parent, COMSIG_MOVED_DOWN_STAIRS, PROC_REF(check_stairs))
RegisterSignal(parent, COMSIG_STUN_EFFECT_ACT, PROC_REF(check_taser))
RegisterSignal(parent, COMSIG_MOB_ROLLED_DICE, PROC_REF(check_roll))
RegisterSignal(parent, COMSIG_HUMAN_ON_CATCH_THROW, PROC_REF(check_throw))
RegisterSignal(parent, COMSIG_PICKED_UP_ITEM, PROC_REF(check_pickup))
/datum/component/omen/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_ON_CARBON_SLIP, COMSIG_MOVABLE_MOVED, COMSIG_STUN_EFFECT_ACT, COMSIG_MOVED_DOWN_STAIRS, COMSIG_MOB_ROLLED_DICE, COMSIG_HUMAN_ON_CATCH_THROW, COMSIG_PICKED_UP_ITEM))
/datum/component/omen/proc/consume_omen()
incidents_left--
if(incidents_left < 1)
qdel(src)
/**
* check_accident() is called each step we take
*
* While we're walking around, roll to see if there's any environmental hazards on one of the adjacent tiles we can trigger.
* We do the prob() at the beginning to A. add some tension for /when/ it will strike, and B. (more importantly) ameliorate the fact that we're checking up to 5 turfs's contents each time
*/
/datum/component/omen/proc/check_accident(atom/movable/our_guy)
SIGNAL_HANDLER
if(!isliving(our_guy) || isbelly(our_guy.loc))
return
var/mob/living/living_guy = our_guy
if(living_guy.is_incorporeal()) //no being unlucky if you don't even exist on the same plane.
return
if(evil && prob(0.0001) && (living_guy.stat != DEAD)) // 1 in a million
living_guy.visible_message(span_danger("[living_guy] suddenly bursts into flames!"), span_danger("You suddenly burst into flames!"))
living_guy.emote("scream")
living_guy.adjust_fire_stacks(20)
living_guy.ignite_mob()
consume_omen()
return
var/effective_luck = luck_mod
// If there's nobody to witness the misfortune, make it less likely.
// This way, we allow for people to be able to get into hilarious situations without making the game nigh unplayable most of the time.
var/has_watchers = FALSE
for(var/mob/viewer in viewers(our_guy, world.view))
if(viewer.client && !viewer.client.is_afk())
has_watchers = TRUE
break
if(!has_watchers)
effective_luck *= 0.5
if(!prob(2 * effective_luck))
return
var/turf/our_guy_pos = get_turf(our_guy)
if(!our_guy_pos)
return
if(evil)
for(var/obj/machinery/door/airlock/darth_airlock in our_guy_pos)
if(darth_airlock.locked || !darth_airlock.arePowerSystemsOn())
continue
to_chat(living_guy, span_warning("The airlock suddenly closes on you!"))
living_guy.Paralyse(1 SECONDS)
slam_airlock(darth_airlock)
consume_omen()
return
for(var/turf/the_turf as anything in our_guy_pos.AdjacentTurfs(check_blockage = FALSE)) //need false so we can check disposal units
if(the_turf.CanZPass(our_guy, DOWN))
to_chat(living_guy, span_warning("You lose your balance and slip towards the edge!"))
living_guy.Weaken(5)
living_guy.throw_at(the_turf, 1, 20)
consume_omen()
return
if(vorish)
for(var/mob/living/living_mob in the_turf)
if(living_mob == our_guy)
continue //Don't do anything to ourselves.
if(living_mob.stat)
continue
if(!living_mob.CanStumbleVore(living_guy) && !living_guy.CanStumbleVore(living_mob)) //Works both ways! Either way, someone's getting eaten!
continue
living_mob.stumble_into(living_guy) //logic reversed here because the game is DUMB. This means that living_guy is stumbling into the target!
living_guy.visible_message(span_danger("[living_guy] loses their balance and slips into [living_mob]!"), span_boldwarning("You lose your balance, slipping into [living_mob]!"))
consume_omen()
return
for(var/obj/machinery/washing_machine/evil_washer in the_turf)
if(evil_washer.state == 1) //Empty and open door
our_guy.visible_message(span_danger("[our_guy] slips near the [evil_washer] and falls in, the door shutting!"), span_boldwarning("You slip on a wet spot near the [evil_washer] and fall in, the door shutting! You're stuck!"))
our_guy.forceMove(evil_washer)
evil_washer.washing += our_guy
evil_washer.state = 4
evil_washer.visible_message(span_danger("[evil_washer] begins its spin cycle!"))
evil_washer.start(TRUE, damage_mod)
consume_omen()
return
if(evil || safe_disposals) //On servers without safe disposals, this is a death sentence. With servers with safe disposals, it's just funny.
for(var/obj/machinery/disposal/evil_disposal in the_turf)
if(evil_disposal.stat & (BROKEN|NOPOWER))
continue
if(evil_disposal.loc == living_guy.loc) //Let's not do a continual loop of them falling into it as soon as they climb out, as funny as that is.
continue
our_guy.visible_message(span_danger("[our_guy] slips on a spill near the [evil_disposal] and falls in!"), span_boldwarning("You slip on a spill near the [evil_disposal] and fall in!"))
living_guy.forceMove(evil_disposal)
evil_disposal.flush = TRUE
evil_disposal.update()
living_guy.Weaken(5)
consume_omen()
return
if(evil && prob(33)) //This has an additional 2 in 3 chance to not happen as there's a LOT of lights on stations. This should be rarer.
for(var/obj/machinery/light/evil_light in the_turf)
if((evil_light.status == LIGHT_BURNED || evil_light.status == LIGHT_BROKEN) || (living_guy.get_shock_protection() == 1)) // we can't do anything :(
to_chat(living_guy, span_warning("[evil_light] sparks weakly for a second."))
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread //this shit is copy pasted all over the code...this needs to just be made into a proc at this point jesus christ
s.set_up(4, FALSE, evil_light)
s.start()
//We don't clear the omen as nothing really happened.
break
to_chat(living_guy, span_warning("[evil_light] glows ominously...")) // ominously
evil_light.visible_message(span_boldwarning("[evil_light] suddenly flares brightly and sparks!"))
//evil_light.broken(skip_sound_and_sparks = FALSE) //Let's not break it actually.
evil_light.Beam(living_guy, icon_state = "lightning[rand(1,12)]", time = 0.5 SECONDS)
living_guy.electrocute_act(35 * (damage_mod * 0.5), evil_light, stun = TRUE) //Stun is binary and scales on damage..Lame.
living_guy.emote("scream")
consume_omen()
return
for(var/obj/machinery/vending/darth_vendor in the_turf)
if(darth_vendor.stat & (BROKEN|NOPOWER))
continue
to_chat(living_guy, span_warning("The delivery chute of [darth_vendor] raises up..."))
darth_vendor.throw_item(living_guy)
consume_omen()
return
for(var/obj/structure/mirror/evil_mirror in the_turf)
to_chat(living_guy, span_warning("You pass by the mirror and glance at it..."))
if(evil_mirror.shattered)
to_chat(living_guy, span_notice("You feel lucky, somehow."))
return
var/mirror_rand
if(evil)
mirror_rand = rand(1,5)
else
mirror_rand = rand(1,3)
switch(mirror_rand)
if(1)
to_chat(living_guy, span_boldwarning("You see your reflection, but it is grinning malevolently and staring directly at you!"))
living_guy.emote("scream")
if(2 to 3)
to_chat(living_guy, span_large(span_cult("Oh god, you can't see your reflection!!")))
living_guy.emote("scream")
if(4 to 5)
to_chat(living_guy, span_warning("The mirror explodes into a million pieces! Wait, does that mean you're even more unlucky?"))
evil_mirror.shatter()
if(prob(50 * effective_luck)) // sometimes
luck_mod += 0.25
damage_mod += 0.25
var/max_health_coefficient = (living_guy.maxHealth * 0.06)
for(var/obj/item/organ/external/limb in living_guy.organs)
living_guy.apply_damage(max_health_coefficient * damage_mod, BRUTE, limb.organ_tag, used_weapon = "glass shrapnel")
living_guy.make_jittery(250)
if(evil && prob(7 * effective_luck))
to_chat(living_guy, span_warning("You are completely shocked by this turn of events!"))
if(ishuman(living_guy))
var/mob/living/carbon/human/human_guy = living_guy
if(human_guy.should_have_organ(O_HEART))
for(var/obj/item/organ/internal/heart/heart in human_guy.internal_organs)
heart.bruise() //Closest thing we have to a heart attack.
to_chat(living_guy, span_boldwarning("You clutch at your heart!"))
consume_omen()
return
if(evil)
for(var/obj/item/reagent_containers/glass/beaker/evil_beaker in the_turf)
if(!evil_beaker.is_open_container() && (evil_beaker.reagents.total_volume > 0)) //A closed beaker is a safe beaker!
continue
living_guy.visible_message(span_danger("[evil_beaker] tilts, spilling its contents on [living_guy]!"), span_bolddanger("[evil_beaker] spills all over you!"))
evil_beaker.balloon_alert_visible("[evil_beaker]'s contents splashes onto [living_guy]!")
evil_beaker.reagents.splash(living_guy, evil_beaker.reagents.total_volume)
consume_omen()
return
for(var/obj/structure/table/evil_table in the_turf)
if(!evil_table.material) //We only want tables, not just table frames.
continue
var/datum/gender/gender = GLOB.gender_datums[living_guy.get_visible_gender()]
living_guy.visible_message(span_danger("[living_guy] stubs [gender.his] toe on [evil_table]!"), span_bolddanger("You stub your toe on [evil_table]!"))
living_guy.apply_damage(2 * damage_mod, BRUTE, pick(BP_L_FOOT, BP_R_FOOT), used_weapon = "blunt force trauma")
living_guy.adjustHalLoss(25) //It REALLY hurts.
living_guy.Weaken(3)
consume_omen()
return
//Ran out of turf options. Let's do more generic options.
if(prob(luck_mod * 5))
// In complete darkness
if(our_guy_pos.get_lumcount() <= LIGHTING_SOFT_THRESHOLD)
living_guy.Blind(5) //10 seconds of 'OH GOD WHAT'S HAPPENING'
living_guy.silent = 5
living_guy.Paralyse(5)
to_chat(living_guy, span_bolddanger("You feel the ground buckle underneath you, falling down, your vision going dark as you feel paralyzed in place!"))
consume_omen()
return
/datum/component/omen/proc/slam_airlock(obj/machinery/door/airlock/darth_airlock)
SIGNAL_HANDLER
. = darth_airlock.close(forced = TRUE, ignore_safties = TRUE, crush_damage = 15) //Not enough to cause any IB or massively injured organs.
if(.)
consume_omen()
/// If we get knocked down, see if we have a really bad slip and bash our head hard
/datum/component/omen/proc/check_slip(mob/living/our_guy, amount)
SIGNAL_HANDLER
if(prob(30)) // AAAA
our_guy.emote("scream")
to_chat(our_guy, span_cult("What a horrible night... To have a curse!"))
if(prob(30 * luck_mod) && our_guy.get_bodypart_name(BP_HEAD)) /// Bonk!
playsound(our_guy, 'sound/effects/tableheadsmash.ogg', 90, TRUE)
var/datum/gender/gender = GLOB.gender_datums[our_guy.get_visible_gender()]
our_guy.visible_message(span_danger("[our_guy] hits [gender.his] head really badly falling down!"), span_bolddanger("You hit your head really badly falling down!"))
var/max_health_coefficient = (our_guy.maxHealth * 0.5)
our_guy.apply_damage(max_health_coefficient * damage_mod, BRUTE, BP_HEAD, used_weapon = "slipping")
if(ishuman(our_guy))
var/mob/living/carbon/human/human_guy = our_guy
if(human_guy.should_have_organ(O_BRAIN))
for(var/obj/item/organ/internal/brain/brain in human_guy.internal_organs)
brain.take_damage(30 * damage_mod) //60 damage kills.
if(human_guy.glasses && human_guy.canUnEquip(human_guy.glasses))
var/turf/T = get_turf(human_guy)
if(T)
var/obj/item/our_glasses = human_guy.glasses
human_guy.unEquip(human_guy.glasses, target = T)
to_chat(human_guy, span_warning("Your glasses fly off as you hit the ground!"))
our_glasses.throw_at_random(FALSE, 3, 2)
consume_omen()
return
/datum/component/omen/proc/check_roll(mob/living/unlucky_soul, var/obj/item/dice/the_dice, silent, result)
SIGNAL_HANDLER
if(prob(20 * luck_mod))
//unlucky_soul.visible_message(span_danger("[unlucky_soul] rolls [the_dice] with it landing on the edge of [result] before tilting over!"), span_boldwarning("You feel dreadfully unlucky as you roll the dice!"))
//I had thought about making this have a notice that it happened.
//However, gaslighting the user by providing no visible notice is MUCH funnier.
return 1 // We override the roll to a 1.
///Returns TRUE and stops us from catching
/datum/component/omen/proc/check_throw(mob/living/unlucky_soul, source, speed)
SIGNAL_HANDLER
if(prob(30 * luck_mod)) //~9% chance
if(istype(source, /obj/item/grenade))
var/obj/item/grenade/bad_grenade = source
if(bad_grenade.active)
unlucky_soul.put_in_active_hand(bad_grenade)
unlucky_soul.visible_message(span_warning("[src] catches [source] as it goes off in their hand!"), span_bolddanger("You catch [source] and it goes off in your hand!"))
unlucky_soul.throw_mode_off()
bad_grenade.detonate()
return TRUE
else
unlucky_soul.visible_message(span_attack("[unlucky_soul] tries to catch [source] and fumbles it, getting thrown back!"))
unlucky_soul.Weaken(5)
return TRUE
/*
* Dynamic injury system for when you pick up objects!
* Some objects might cut, burn, or otherwise injure you if you pick them up!
* Genenerally more of an annoyance than anything.
* Variables that can be changed:
* injury_type, damage_to_inflict, damage_type, injury_verb, is_sharp, is_edge.
*/
/datum/component/omen/proc/check_pickup(mob/living/unlucky_soul, obj/item/item)
SIGNAL_HANDLER
if(prob(3 * luck_mod) && ishuman(unlucky_soul)) // ~3% chance
var/mob/living/carbon/human/unlucky_human = unlucky_soul
///What the injury will show up as on an autopsy.
var/injury_type = "injury"
///How much damage we'll inflect.
var/damage_to_inflict = 0
///What type of damage we'll inflict
var/damage_type = BRUTE
///If the item we get injured on has is sharp.
var/is_sharp = FALSE
///If the item we get injured on has an edge.
var/has_edge = FALSE
///What verb we use to describe the injury.
var/injury_verb = "cuts"
///What hand we are currently using, so we injure the correct one.
var/current_hand = BP_R_HAND
if(unlucky_human.hand)
current_hand = BP_L_HAND
if(istype(item, /obj/item/paper))
injury_verb = "cuts"
injury_type = "paper cut"
damage_to_inflict = 2
else if(istype(item, /obj/item/material/knife))
var/obj/item/material/knife = item
injury_verb = "cuts"
injury_type = "knife"
is_sharp = knife.sharp
has_edge = knife.edge
damage_to_inflict = knife.force
else if(istype(item, /obj/item/material/shard))
var/obj/item/material/shard/shard = item
injury_verb = "cuts"
injury_type = "shard"
is_sharp = shard.sharp
has_edge = shard.edge
damage_to_inflict = shard.force
else if(istype(item, /obj/item/flame/lighter))
var/obj/item/flame/lighter/lighter = item
if(!lighter.lit)
return
injury_verb = "burns"
injury_type = "lighter"
damage_type = BURN
damage_to_inflict = 5
else if(istype(item, /obj/item/tool/transforming/jawsoflife))
var/obj/item/tool/transforming/jawsoflife/jaws = item
injury_verb = "clamps"
injury_type = "industrial tool"
is_sharp = jaws.sharp
has_edge = jaws.edge
damage_to_inflict = jaws.force
else if(istype(item, /obj/item/tool/screwdriver))
var/obj/item/tool/screwdriver/screwdriver = item
injury_verb = "stabs"
injury_type = "industrial tool"
is_sharp = screwdriver.sharp
has_edge = screwdriver.edge
damage_to_inflict = screwdriver.force
else if(istype(item, /obj/item/tool/wirecutters))
var/obj/item/tool/wirecutters/wirecutters = item
injury_verb = "nips"
injury_type = "industrial tool"
is_sharp = wirecutters.sharp
has_edge = wirecutters.edge
damage_to_inflict = wirecutters.force
if(!damage_to_inflict)
return
var/datum/gender/gender = GLOB.gender_datums[unlucky_human.get_visible_gender()]
unlucky_human.visible_message(span_danger("[unlucky_human] accidentally [injury_verb] [gender.his] hand on [item]!"))
unlucky_human.apply_damage(damage_to_inflict * damage_mod, damage_type, current_hand, sharp = is_sharp, edge = has_edge, used_weapon = injury_type)
/datum/component/omen/proc/check_stairs(mob/living/unlucky_soul)
SIGNAL_HANDLER
if(prob(3 * luck_mod)) /// Bonk!
playsound(unlucky_soul, 'sound/effects/tableheadsmash.ogg', 90, TRUE)
unlucky_soul.visible_message(span_danger("One of the stairs give way as [unlucky_soul] steps onto it, tumbling them down to the bottom!"), span_bolddanger("A stair gives way and you trip to the bottom!"))
var/max_health_coefficient = (unlucky_soul.maxHealth * 0.09)
for(var/obj/item/organ/external/limb in unlucky_soul.organs) //In total, you should have 11 limbs (generally, unless you have an amputation). The full omen variant we want to leave you at 1 hp, the trait version less. As of writing, the trait version is 25% of the damage, so you take 24.75 across all limbs.
unlucky_soul.apply_damage(max_health_coefficient * damage_mod, BRUTE, limb.organ_tag, used_weapon = "slipping")
unlucky_soul.Weaken(5)
consume_omen()
/datum/component/omen/proc/check_taser(mob/living/unlucky_soul, stun_amount, agony_amount, def_zone, used_weapon, electric)
SIGNAL_HANDLER
if(!electric || !evil) //If it's not electric we don't care! Likewise, if we don't have the evil variant, don't care!
return
if(!ishuman(unlucky_soul))
return
if(prob(3 * luck_mod))
var/mob/living/carbon/human/human_guy = unlucky_soul
if(human_guy.should_have_organ(O_HEART))
for(var/obj/item/organ/internal/heart/heart in human_guy.internal_organs)
if(heart.robotic)
continue //Robotic hearts are immune to this.
heart.take_damage(10 * stun_amount * damage_mod)
heart.take_damage(0.25 * agony_amount * damage_mod)
playsound(src, 'sound/effects/singlebeat.ogg', 50, FALSE)
to_chat(unlucky_soul, span_bolddanger("You feel as though your heart stopped"))
human_guy.Stun(5)
consume_omen()
return
/**
* The trait omen. Permanent.
* Has only a 30% chance of bad things happening, and takes only 25% of normal damage.
* Evil is false, so you get less dramatic things happening.
*/
/datum/component/omen/trait
incidents_left = INFINITY
dupe_type = /datum/component/omen/trait
luck_mod = 0.3 // 30% chance of bad things happening
damage_mod = 0.25 // 25% of normal damage
evil = FALSE
safe_disposals = FALSE
///Major variant of the trait.
/datum/component/omen/trait/major
evil = TRUE
damage_mod = 0.75 //75% of normal damage
///Variant trait for downstreams that have safe disposals.
/datum/component/omen/trait/safe_disposals
safe_disposals = TRUE
/datum/component/omen/trait/safe_disposals/major
evil = TRUE
damage_mod = 0.75 //75% of normal damage
/**
* The bible omen.
* While it lasts, parent gets a cursed aura filter.
*/
/datum/component/omen/bible
incidents_left = 1
/datum/component/omen/bible/RegisterWithParent()
. = ..()
var/mob/living/living_parent = parent
living_parent.add_filter("omen", 2, list("type" = "drop_shadow", "color" = "#A50824", "alpha" = 0, "size" = 2))
var/filter = living_parent.get_filter("omen")
animate(filter, alpha = 255, time = 2 SECONDS, loop = -1)
animate(alpha = 0, time = 2 SECONDS)
/datum/component/omen/bible/UnregisterFromParent()
. = ..()
var/mob/living/living_parent = parent
living_parent.remove_filter("omen")
/**
* The dice omen.
* Single use omen from rolling a nat 1 on a cursed d20.
*/
/datum/component/omen/dice
incidents_left = 1

View File

@@ -9,6 +9,7 @@
var/loot_left = 0 // When this reaches zero, and loot_depleted is true, you can't obtain anymore loot. var/loot_left = 0 // When this reaches zero, and loot_depleted is true, you can't obtain anymore loot.
var/delete_on_depletion = FALSE // If true, and if the loot gets depleted as above, the pile is deleted. var/delete_on_depletion = FALSE // If true, and if the loot gets depleted as above, the pile is deleted.
var/list/unlucky_loot = list() // Unlucky is the worst tier. Only people with the unlucky trait can get this stuff. Primed grenades, dangerous syringes, etc.
var/list/common_loot = list() // Common is generally less-than-useful junk and filler, at least for maint loot piles. var/list/common_loot = list() // Common is generally less-than-useful junk and filler, at least for maint loot piles.
var/list/uncommon_loot = list() // Uncommon is actually maybe some useful items, usually the reason someone bothers looking inside. var/list/uncommon_loot = list() // Uncommon is actually maybe some useful items, usually the reason someone bothers looking inside.
var/list/rare_loot = list() // Rare is really powerful, or at least unique items. var/list/rare_loot = list() // Rare is really powerful, or at least unique items.
@@ -47,7 +48,17 @@
var/obj/item/loot = null var/obj/item/loot = null
var/span = "notice" // Blue var/span = "notice" // Blue
if(prob(chance_uncommon) && uncommon_loot.len) // You might still get something good. if(HAS_TRAIT(L, TRAIT_UNLUCKY) && unlucky_loot.len) // If you're unlucky, you will always find bad stuff.
loot = produce_unlucky_item(source)
span = "cult" // Purple and bold.
if(prob(1))
to_chat(L, span_danger("You cut your hand on something in the trash!"))
L.apply_damage(2, BRUTE, pick(BP_L_HAND, BP_R_HAND), used_weapon = "sharp object")
var/datum/disease/advance/random/random_disease = new /datum/disease/advance/random()
random_disease.spread_flags |= DISEASE_SPREAD_NON_CONTAGIOUS
L.ForceContractDisease(random_disease)
else if(prob(chance_uncommon) && uncommon_loot.len) // You might still get something good.
loot = produce_uncommon_item(source) loot = produce_uncommon_item(source)
span = "alium" // Green span = "alium" // Green
@@ -96,6 +107,9 @@
if(delete_on_depletion) if(delete_on_depletion)
qdel(source) qdel(source)
/datum/element/lootable/proc/produce_unlucky_item(atom/source)
var/path = pick(unlucky_loot)
return new path(source)
/datum/element/lootable/proc/produce_common_item(atom/source) /datum/element/lootable/proc/produce_common_item(atom/source)
var/path = pick(common_loot) var/path = pick(common_loot)

View File

@@ -1,6 +1,44 @@
// Contains loads of different types of boxes, which may have items inside! // Contains loads of different types of boxes, which may have items inside!
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/datum/element/lootable/boxes /datum/element/lootable/boxes
unlucky_loot = list(
/obj/item/grenade/flashbang/clusterbang/primed,
/obj/item/storage/box/old_syringes,
/obj/item/storage/box/donut/empty,
/obj/item/grenade/smokebomb/primed,
/obj/item/storage/box,
/obj/item/storage/box/cups,
/obj/item/trash/candle,
/obj/item/trash/candy,
/obj/item/trash/candy/proteinbar,
/obj/item/trash/candy/gums,
/obj/item/trash/cheesie,
/obj/item/trash/chips,
/obj/item/trash/chips/bbq,
/obj/item/trash/liquidfood,
/obj/item/trash/pistachios,
/obj/item/trash/plate,
/obj/item/trash/popcorn,
/obj/item/trash/raisins,
/obj/item/trash/semki,
/obj/item/trash/snack_bowl,
/obj/item/trash/sosjerky,
/obj/item/trash/syndi_cakes,
/obj/item/trash/tastybread,
/obj/item/trash/coffee,
/obj/item/trash/tray,
/obj/item/trash/unajerky,
/obj/item/trash/waffles,
/obj/item/spacecash/c1,
/obj/item/card/emag_broken,
/obj/effect/decal/remains/lizard,
/obj/effect/decal/remains/mouse,
/obj/effect/decal/remains/robot,
/obj/item/pizzabox/old,
/obj/item/paper/crumpled
)
common_loot = list( common_loot = list(
/obj/item/storage/box, /obj/item/storage/box,
/obj/item/storage/box/beakers, /obj/item/storage/box/beakers,

View File

@@ -1,6 +1,43 @@
// Has large amounts of possible items, most of which may or may not be useful. // Has large amounts of possible items, most of which may or may not be useful.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/datum/element/lootable/maint/junk /datum/element/lootable/maint/junk
unlucky_loot = list(
/obj/item/grenade/flashbang/clusterbang/primed,
/obj/item/storage/box/old_syringes,
/obj/item/storage/box/donut/empty,
/obj/item/grenade/smokebomb/primed,
/obj/item/storage/box,
/obj/item/storage/box/cups,
/obj/item/trash/candle,
/obj/item/trash/candy,
/obj/item/trash/candy/proteinbar,
/obj/item/trash/candy/gums,
/obj/item/trash/cheesie,
/obj/item/trash/chips,
/obj/item/trash/chips/bbq,
/obj/item/trash/liquidfood,
/obj/item/trash/pistachios,
/obj/item/trash/plate,
/obj/item/trash/popcorn,
/obj/item/trash/raisins,
/obj/item/trash/semki,
/obj/item/trash/snack_bowl,
/obj/item/trash/sosjerky,
/obj/item/trash/syndi_cakes,
/obj/item/trash/tastybread,
/obj/item/trash/coffee,
/obj/item/trash/tray,
/obj/item/trash/unajerky,
/obj/item/trash/waffles,
/obj/item/spacecash/c1,
/obj/item/card/emag_broken,
/obj/effect/decal/remains/lizard,
/obj/effect/decal/remains/mouse,
/obj/effect/decal/remains/robot,
/obj/item/pizzabox/old,
/obj/item/paper/crumpled
)
common_loot = list( common_loot = list(
/obj/item/flashlight/flare, /obj/item/flashlight/flare,
/obj/item/flashlight/glowstick, /obj/item/flashlight/glowstick,
@@ -95,6 +132,43 @@
// Contains mostly useless garbage. // Contains mostly useless garbage.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/datum/element/lootable/maint/trash /datum/element/lootable/maint/trash
unlucky_loot = list(
/obj/item/grenade/flashbang/clusterbang/primed,
/obj/item/storage/box/old_syringes,
/obj/item/storage/box/donut/empty,
/obj/item/grenade/smokebomb/primed,
/obj/item/storage/box,
/obj/item/storage/box/cups,
/obj/item/trash/candle,
/obj/item/trash/candy,
/obj/item/trash/candy/proteinbar,
/obj/item/trash/candy/gums,
/obj/item/trash/cheesie,
/obj/item/trash/chips,
/obj/item/trash/chips/bbq,
/obj/item/trash/liquidfood,
/obj/item/trash/pistachios,
/obj/item/trash/plate,
/obj/item/trash/popcorn,
/obj/item/trash/raisins,
/obj/item/trash/semki,
/obj/item/trash/snack_bowl,
/obj/item/trash/sosjerky,
/obj/item/trash/syndi_cakes,
/obj/item/trash/tastybread,
/obj/item/trash/coffee,
/obj/item/trash/tray,
/obj/item/trash/unajerky,
/obj/item/trash/waffles,
/obj/item/spacecash/c1,
/obj/item/card/emag_broken,
/obj/effect/decal/remains/lizard,
/obj/effect/decal/remains/mouse,
/obj/effect/decal/remains/robot,
/obj/item/pizzabox/old,
/obj/item/paper/crumpled
)
common_loot = list( common_loot = list(
/obj/item/trash/candle, /obj/item/trash/candle,
/obj/item/trash/candy, /obj/item/trash/candy,

View File

@@ -5,6 +5,43 @@
chance_rare = 2 chance_rare = 2
chance_gamma = 1 // Special single drop table chance_gamma = 1 // Special single drop table
unlucky_loot = list(
/obj/item/grenade/flashbang/clusterbang/primed,
/obj/item/storage/box/old_syringes,
/obj/item/storage/box/donut/empty,
/obj/item/grenade/smokebomb/primed,
/obj/item/storage/box,
/obj/item/storage/box/cups,
/obj/item/trash/candle,
/obj/item/trash/candy,
/obj/item/trash/candy/proteinbar,
/obj/item/trash/candy/gums,
/obj/item/trash/cheesie,
/obj/item/trash/chips,
/obj/item/trash/chips/bbq,
/obj/item/trash/liquidfood,
/obj/item/trash/pistachios,
/obj/item/trash/plate,
/obj/item/trash/popcorn,
/obj/item/trash/raisins,
/obj/item/trash/semki,
/obj/item/trash/snack_bowl,
/obj/item/trash/sosjerky,
/obj/item/trash/syndi_cakes,
/obj/item/trash/tastybread,
/obj/item/trash/coffee,
/obj/item/trash/tray,
/obj/item/trash/unajerky,
/obj/item/trash/waffles,
/obj/item/spacecash/c1,
/obj/item/card/emag_broken,
/obj/effect/decal/remains/lizard,
/obj/effect/decal/remains/mouse,
/obj/effect/decal/remains/robot,
/obj/item/pizzabox/old,
/obj/item/paper/crumpled
)
common_loot = list( common_loot = list(
/obj/item/clothing/gloves/rainbow, /obj/item/clothing/gloves/rainbow,
/obj/item/clothing/gloves/white, /obj/item/clothing/gloves/white,

View File

@@ -442,7 +442,7 @@ var/list/mob/living/forced_ambiance_list = list()
if(istype(get_turf(mob), /turf/space)) // Can't fall onto nothing. if(istype(get_turf(mob), /turf/space)) // Can't fall onto nothing.
return return
if(istype(mob,/mob/living/carbon/human/)) if(ishuman(mob))
var/mob/living/carbon/human/H = mob var/mob/living/carbon/human/H = mob
if(H.buckled) if(H.buckled)
return // Being buckled to something solid keeps you in place. return // Being buckled to something solid keeps you in place.
@@ -460,6 +460,11 @@ var/list/mob/living/forced_ambiance_list = list()
H.AdjustStunned(1) // CHOMPedit: No longer a supermassive long stun. H.AdjustStunned(1) // CHOMPedit: No longer a supermassive long stun.
// H.AdjustWeakened(3) // CHOMPedit: No longer weakens. // H.AdjustWeakened(3) // CHOMPedit: No longer weakens.
to_chat(mob, span_notice("The sudden appearance of gravity makes you fall to the floor!")) to_chat(mob, span_notice("The sudden appearance of gravity makes you fall to the floor!"))
if(HAS_TRAIT(H, TRAIT_UNLUCKY) && prob(50) && H.get_bodypart_name(BP_HEAD))
var/datum/gender/gender = GLOB.gender_datums[H.get_visible_gender()]
H.visible_message(span_warning("[H] falls to the ground from the sudden appearance of gravity, smashing [gender.his] head against the ground!"),span_warning("You smash your head into the ground as gravity appears!"))
H.apply_damage(14, BRUTE, BP_HEAD, used_weapon = "blunt force")
playsound(H, 'sound/effects/tableheadsmash.ogg', 90, TRUE)
playsound(mob, "bodyfall", 50, 1) playsound(mob, "bodyfall", 50, 1)
/area/proc/prison_break(break_lights = TRUE, open_doors = TRUE, open_blast_doors = FALSE) //CHOMP Edit set blast doors to FALSE /area/proc/prison_break(break_lights = TRUE, open_doors = TRUE, open_blast_doors = FALSE) //CHOMP Edit set blast doors to FALSE

View File

@@ -75,6 +75,7 @@
anchored = TRUE anchored = TRUE
movement_type = UNSTOPPABLE movement_type = UNSTOPPABLE
var/turf/despawn_loc = null var/turf/despawn_loc = null
var/has_hunted_unlucky = FALSE
/obj/effect/immovablerod/proc/TakeFlight(var/turf/end) /obj/effect/immovablerod/proc/TakeFlight(var/turf/end)
despawn_loc = end despawn_loc = end
@@ -112,8 +113,8 @@
if(despawn_loc != null && (src.x == despawn_loc.x && src.y == despawn_loc.y)) if(despawn_loc != null && (src.x == despawn_loc.x && src.y == despawn_loc.y))
qdel(src) qdel(src)
return return
/* //Used in conjunction with the Unlucky/Cursed trait. NYI.
if(prob(10)) if(prob(10) && !has_hunted_unlucky)
hunt_unlucky() hunt_unlucky()
/obj/effect/immovablerod/proc/hunt_unlucky() /obj/effect/immovablerod/proc/hunt_unlucky()
@@ -132,7 +133,7 @@
/obj/effect/immovablerod/proc/resume_path() /obj/effect/immovablerod/proc/resume_path()
walk(src, 0) walk(src, 0)
walk_towards(src, despawn_loc, 1) walk_towards(src, despawn_loc, 1)
*/
/obj/effect/immovablerod/Destroy() /obj/effect/immovablerod/Destroy()
walk(src, 0) // Because we might have called walk_towards, we must stop the walk loop or BYOND keeps an internal reference to us forever. walk(src, 0) // Because we might have called walk_towards, we must stop the walk loop or BYOND keeps an internal reference to us forever.
return ..() return ..()

View File

@@ -911,13 +911,13 @@ About the new airlock wires panel:
adjustBruteLoss(crush_damage) adjustBruteLoss(crush_damage)
return FALSE return FALSE
/obj/machinery/door/airlock/close(var/forced=0) /obj/machinery/door/airlock/close(var/forced= FALSE, var/ignore_safties = FALSE, var/crush_damage = DOOR_CRUSH_DAMAGE)
if(!can_close(forced)) if(!can_close(forced))
return FALSE return FALSE
hold_open = null //if it passes the can close check, always make sure to clear hold open hold_open = null //if it passes the can close check, always make sure to clear hold open
if(safe) if(safe && !ignore_safties)
for(var/turf/turf in locs) for(var/turf/turf in locs)
for(var/atom/movable/AM in turf) for(var/atom/movable/AM in turf)
if(AM.blocks_airlock()) if(AM.blocks_airlock())
@@ -929,8 +929,8 @@ About the new airlock wires panel:
for(var/turf/turf in locs) for(var/turf/turf in locs)
for(var/atom/movable/AM in turf) for(var/atom/movable/AM in turf)
if(AM.airlock_crush(DOOR_CRUSH_DAMAGE)) if(AM.airlock_crush(crush_damage))
take_damage(DOOR_CRUSH_DAMAGE) take_damage(crush_damage)
use_power(360) //360 W seems much more appropriate for an actuator moving an industrial door capable of crushing people use_power(360) //360 W seems much more appropriate for an actuator moving an industrial door capable of crushing people
has_beeped = 0 has_beeped = 0

View File

@@ -128,9 +128,9 @@
if(!surpress_send) send_status() if(!surpress_send) send_status()
/obj/machinery/door/airlock/close(surpress_send) /obj/machinery/door/airlock/close(var/forced= FALSE, var/ignore_safties = FALSE, var/crush_damage = DOOR_CRUSH_DAMAGE)
. = ..() . = ..()
if(!surpress_send) send_status() if(!forced) send_status()
/obj/machinery/door/airlock/Bumped(atom/AM) /obj/machinery/door/airlock/Bumped(atom/AM)

View File

@@ -527,7 +527,7 @@
open_speed = 15 open_speed = 15
return (normalspeed ? open_speed : 5) return (normalspeed ? open_speed : 5)
/obj/machinery/door/proc/close(var/forced = 0) /obj/machinery/door/proc/close(var/forced = 0, var/ignore_safties = FALSE, var/crush_damage = DOOR_CRUSH_DAMAGE)
if(!can_close(forced)) if(!can_close(forced))
return return
operating = 1 operating = 1

View File

@@ -115,6 +115,50 @@
return return
//CHOMPEdit End //CHOMPEdit End
// Checks to make sure he's not in space doing it, and that the area got proper power.
if(!powered())
to_chat(user, span_warning("\The [src] blinks red as you try to insert [G]!"))
return
if(istype(G, /obj/item/gun/energy))
var/obj/item/gun/energy/E = G
if(E.self_recharge)
to_chat(user, span_notice("\The [E] has no recharge port."))
return
if(istype(G, /obj/item/modular_computer))
var/obj/item/modular_computer/C = G
if(!C.battery_module)
to_chat(user, span_notice("\The [C] does not have a battery installed. "))
return
if(istype(G, /obj/item/flash))
var/obj/item/flash/F = G
if(F.use_external_power)
to_chat(user, span_notice("\The [F] has no recharge port."))
return
if(istype(G, /obj/item/weldingtool/electric))
var/obj/item/weldingtool/electric/EW = G
if(EW.use_external_power)
to_chat(user, span_notice("\The [EW] has no recharge port."))
return
if(!G.get_cell() && !istype(G, /obj/item/ammo_casing/microbattery) && !istype(G, /obj/item/paicard)) //VOREStation Edit: NSFW charging
to_chat(user, "\The [G] does not have a battery installed.")
return
if(istype(G, /obj/item/paicard))
var/obj/item/paicard/ourcard = G
if(ourcard.panel_open)
to_chat(user, span_warning("\The [ourcard] won't fit in the recharger with its panel open."))
return
if(ourcard.pai)
if(ourcard.pai.stat == CONSCIOUS)
to_chat(user, span_warning("\The [ourcard] boops... it doesn't need to be recharged!"))
return
else
to_chat(user, span_warning("\The [ourcard] doesn't have a personality!"))
return
if(HAS_TRAIT(user, TRAIT_UNLUCKY) && prob(10))
user.visible_message("[user] inserts [charging] into [src] backwards!", "You insert [charging] into [src] backwards!")
user.drop_item()
G.loc = get_turf(src)
return
user.drop_item() user.drop_item()
G.loc = src G.loc = src
charging = G charging = G

View File

@@ -1,3 +1,13 @@
#define EMPTY_OPEN 1
#define EMPTY_CLOSED 2
#define FULL_OPEN 3
#define FULL_CLOSED 4
#define RUNNING 5
#define BLOODY_OPEN 6 //Not actually used...
#define BLOODY_CLOSED 7
#define BLOODY_RUNNING 8
/obj/machinery/washing_machine /obj/machinery/washing_machine
name = "Washing Machine" name = "Washing Machine"
desc = "Not a hiding place. Unfit for pets." desc = "Not a hiding place. Unfit for pets."
@@ -9,19 +19,9 @@
clickvol = 40 clickvol = 40
circuit = /obj/item/circuitboard/washing circuit = /obj/item/circuitboard/washing
var/state = 1 var/state = EMPTY_OPEN
//1 = empty, open door var/hacked = TRUE //Bleh, screw hacking, let's have it hacked by default.
//2 = empty, closed door var/gibs_ready = FALSE
//3 = full, open door
//4 = full, closed door
//5 = running
//6 = blood, open door
//7 = blood, closed door
//8 = blood, running
var/hacked = 1 //Bleh, screw hacking, let's have it hacked by default.
//0 = not hacked
//1 = hacked
var/gibs_ready = 0
var/obj/crayon var/obj/crayon
var/list/washing = list() var/list/washing = list()
var/list/disallowed_types = list( var/list/disallowed_types = list(
@@ -34,6 +34,14 @@
default_apply_parts() default_apply_parts()
AddElement(/datum/element/climbable) AddElement(/datum/element/climbable)
/obj/machinery/washing_machine/Destroy()
for(var/atom/movable/washed_items in contents)
washed_items.forceMove(get_turf(src))
washing.Cut()
crayon = null
. = ..()
/obj/machinery/washing_machine/AltClick() /obj/machinery/washing_machine/AltClick()
start() start()
@@ -43,26 +51,27 @@
set src in oview(1) set src in oview(1)
start() start()
/obj/machinery/washing_machine/proc/start() /obj/machinery/washing_machine/proc/start(force, damage_modifier)
if(!isliving(usr)) //ew ew ew usr, but it's the only way to check. if(!isliving(usr) && !force) //ew ew ew usr, but it's the only way to check.
return return
if(!damage_modifier)
if(state != 4) damage_modifier = 0.5
to_chat(usr, "The washing machine cannot run in this state.") if(state != FULL_CLOSED)
visible_message("The washing machine buzzes - it can not run in this state!")
return return
if(locate(/mob,washing)) if(locate(/mob,washing))
state = 8 state = BLOODY_RUNNING
else else
state = 5 state = RUNNING
update_icon() update_icon()
to_chat(usr, "The washing machine starts a cycle.") visible_message("The washing machine starts a cycle.")
playsound(src, 'sound/items/washingmachine.ogg', 50, 1, 1) playsound(src, 'sound/items/washingmachine.ogg', 50, 1, 1)
addtimer(CALLBACK(src, PROC_REF(finish_wash)), 2 SECONDS) addtimer(CALLBACK(src, PROC_REF(finish_wash), damage_modifier), 2 SECONDS)
/obj/machinery/washing_machine/proc/finish_wash() /obj/machinery/washing_machine/proc/finish_wash(damage_modifier)
for(var/atom/A in washing) for(var/atom/A in washing)
A.wash(CLEAN_ALL) A.wash(CLEAN_ALL)
@@ -74,21 +83,49 @@
HH.use(HH.get_amount()) HH.use(HH.get_amount())
washing += WL washing += WL
var/has_mobs = FALSE
for(var/mob/living/mobs in washing)
has_mobs = TRUE
if(ishuman(mobs))
var/mob/living/carbon/human/our_human = mobs
var/max_health_coefficient = (our_human.maxHealth * 0.09) //9 for 100% hp human, 4.5 for 50% hp human (teshari), etc.
for(var/i=0,i<10,i++)
our_human.apply_damage(max_health_coefficient*damage_modifier, BRUTE, used_weapon = "spin cycle") //Let's randomly do damage across the body. One limb might get hurt more than the others. At 100% damge mod, does 90% of max hp in damage.
continue
mobs.stat = DEAD //Kill them so they can't interact anymore.
if(locate(/mob,washing)) if(has_mobs)
state = 7 state = BLOODY_CLOSED
gibs_ready = 1 gibs_ready = TRUE
else else
state = 4 state = FULL_CLOSED
update_icon() update_icon()
/obj/machinery/washing_machine/verb/climb_out() /obj/machinery/washing_machine/verb/climb_out()
set name = "Climb out" set name = "Climb out"
set category = "Object" set category = "Object"
set src in usr.loc set src in usr.loc
user_climb_out(usr)
if((state in list(1,3,6)) && do_after(usr, 2 SECONDS, target = src)) /obj/machinery/washing_machine/proc/user_climb_out(mob/user)
usr.loc = src.loc if(user.loc != src) //Have to be in it to climb out of it.
return
if(state in list(EMPTY_OPEN, FULL_OPEN, BLOODY_OPEN)) //Door is open, we can climb out easily.
visible_message("[user] begins to climb out of the [src]!")
if(do_after(user, 2 SECONDS, target = src))
if(!(state in list(EMPTY_CLOSED, FULL_CLOSED, BLOODY_CLOSED))) //Someone shut the door while we were trying to climb out!
user.forceMove(get_turf(src))
visible_message("[user] climbs out of the [src]!")
else
to_chat(user, "Someone shut the door on you!")
else if(state in list(EMPTY_CLOSED, FULL_CLOSED, BLOODY_CLOSED)) //Door is shut.
visible_message("[src] begins to rattle and shake!")
if(do_after(user, 60 SECONDS, target = src))
visible_message("[user] climbs out of the [src]!")
attack_hand(user, force = TRUE)
/obj/machinery/washing_machine/container_resist(mob/living/escapee)
user_climb_out(escapee)
/obj/machinery/washing_machine/update_icon() /obj/machinery/washing_machine/update_icon()
cut_overlays() cut_overlays()
@@ -97,7 +134,7 @@
add_overlay("panel") add_overlay("panel")
/obj/machinery/washing_machine/attackby(obj/item/W as obj, mob/user as mob) /obj/machinery/washing_machine/attackby(obj/item/W as obj, mob/user as mob)
if(state == 2 && washing.len < 1) if(state == EMPTY_CLOSED && washing.len < 1)
if(default_deconstruction_screwdriver(user, W)) if(default_deconstruction_screwdriver(user, W))
return return
if(default_deconstruction_crowbar(user, W)) if(default_deconstruction_crowbar(user, W))
@@ -108,22 +145,30 @@
panel = !panel panel = !panel
to_chat(user, span_notice("You [panel ? "open" : "close"] the [src]'s maintenance panel"))*/ to_chat(user, span_notice("You [panel ? "open" : "close"] the [src]'s maintenance panel"))*/
if(istype(W,/obj/item/pen/crayon) || istype(W,/obj/item/stamp)) if(istype(W,/obj/item/pen/crayon) || istype(W,/obj/item/stamp))
if(state in list( 1, 3, 6)) if(state in list (EMPTY_OPEN, FULL_OPEN, BLOODY_OPEN))
if(!crayon) if(!crayon)
user.drop_item() user.drop_item()
crayon = W crayon = W
crayon.forceMove(src)
crayon.loc = src crayon.loc = src
else else
..() ..()
else else
..() ..()
else if(istype(W,/obj/item/grab)) else if(istype(W,/obj/item/grab))
if((state == 1) && hacked) if((state == EMPTY_OPEN) && hacked)
var/obj/item/grab/G = W var/obj/item/grab/G = W
if(ishuman(G.assailant) && iscorgi(G.affecting)) if(ishuman(G.assailant) && (iscorgi(G.affecting) || ishuman(G.affecting)))
G.affecting.loc = src user.visible_message("[user] begins stuffing [G.affecting] into the [src]!", "You begin stuffing [G.affecting] into the [src]!")
qdel(G) if(do_after(user, 5 SECONDS, target = src))
state = 3 if(state == EMPTY_OPEN) //Checking to make sure nobody closed it before we shoved em in it.
user.visible_message("[user] stuffs [G.affecting] into the [src] and shuts the door!", "You stuff [G.affecting] into the [src] and shut the door!")
G.affecting.forceMove(src)
washing += G.affecting
qdel(G)
state = FULL_CLOSED
else
to_chat(user, "You can't shove [G.affecting] in unless the washer is empty and open!")
else else
..() ..()
@@ -133,11 +178,11 @@
else if(istype(W, /obj/item/clothing) || istype(W, /obj/item/bedsheet) || istype(W, /obj/item/stack/hairlesshide)) else if(istype(W, /obj/item/clothing) || istype(W, /obj/item/bedsheet) || istype(W, /obj/item/stack/hairlesshide))
if(washing.len < 5) if(washing.len < 5)
if(state in list(1, 3)) if(state in list(EMPTY_OPEN, FULL_OPEN))
user.drop_item() user.drop_item()
W.loc = src W.forceMove(src)
washing += W washing += W
state = 3 state = FULL_OPEN
else else
to_chat(user, span_notice("You can't put the item in right now.")) to_chat(user, span_notice("You can't put the item in right now."))
else else
@@ -146,38 +191,50 @@
..() ..()
update_icon() update_icon()
/obj/machinery/washing_machine/attack_hand(mob/user as mob) /obj/machinery/washing_machine/attack_hand(mob/user, force)
if(user.loc == src && !force)
return //No interacting with it from the inside!
switch(state) switch(state)
if(1) if(EMPTY_OPEN)
state = 2 state = EMPTY_CLOSED
if(2) if(EMPTY_CLOSED)
state = 1 state = EMPTY_OPEN
for(var/atom/movable/O in washing) for(var/atom/movable/O in washing)
O.loc = src.loc O.forceMove(get_turf(src))
washing.Cut() washing.Cut()
if(3) if(FULL_OPEN)
state = 4 state = FULL_CLOSED
if(4) if(FULL_CLOSED)
state = 3
for(var/atom/movable/O in washing) for(var/atom/movable/O in washing)
O.loc = src.loc O.forceMove(get_turf(src))
crayon = null crayon = null
washing.Cut() washing.Cut()
state = 1 state = EMPTY_OPEN
if(5) if(RUNNING)
to_chat(user, span_warning("The [src] is busy.")) if(user)
if(6) to_chat(user, span_warning("The [src] is busy."))
state = 7 if(BLOODY_OPEN)
if(7) state = BLOODY_CLOSED
if(BLOODY_CLOSED)
if(gibs_ready) if(gibs_ready)
gibs_ready = 0 gibs_ready = FALSE
if(locate(/mob,washing)) for(var/mob/living/mobs in washing)
var/mob/M = locate(/mob,washing) if(ishuman(mobs)) //Humans have special handling.
M.gib() continue
mobs.gib()
for(var/atom/movable/O in washing) for(var/atom/movable/O in washing)
O.loc = src.loc O.forceMove(get_turf(src))
crayon = null crayon = null
state = 1 state = EMPTY_OPEN
washing.Cut() washing.Cut()
update_icon() update_icon()
#undef EMPTY_OPEN
#undef EMPTY_CLOSED
#undef FULL_OPEN
#undef FULL_CLOSED
#undef RUNNING
#undef BLOODY_OPEN
#undef BLOODY_CLOSED
#undef BLOODY_RUNNING

View File

@@ -440,6 +440,7 @@
// called just as an item is picked up (loc is not yet changed) // called just as an item is picked up (loc is not yet changed)
/obj/item/proc/pickup(mob/user) /obj/item/proc/pickup(mob/user)
SEND_SIGNAL(src, COMSIG_ITEM_PICKUP, user) SEND_SIGNAL(src, COMSIG_ITEM_PICKUP, user)
SEND_SIGNAL(user, COMSIG_PICKED_UP_ITEM, src)
pixel_x = 0 pixel_x = 0
pixel_y = 0 pixel_y = 0
return return

View File

@@ -389,6 +389,10 @@
return return
H.apply_damage(burn_damage_amt, BURN, BP_TORSO) H.apply_damage(burn_damage_amt, BURN, BP_TORSO)
if(HAS_TRAIT(H, TRAIT_UNLUCKY) && prob(5))
make_announcement("buzzes, \"Unknown error occurred. Please try again.\"", "warning")
playsound(src, 'sound/machines/defib_failed.ogg', 50, FALSE)
return
//set oxyloss so that the patient is just barely in crit, if possible //set oxyloss so that the patient is just barely in crit, if possible
var/barely_in_crit = H.get_crit_point() - 1 var/barely_in_crit = H.get_crit_point() - 1
@@ -437,7 +441,7 @@
playsound(src, 'sound/weapons/egloves.ogg', 100, 1, -1) playsound(src, 'sound/weapons/egloves.ogg', 100, 1, -1)
set_cooldown(cooldowntime) set_cooldown(cooldowntime)
H.stun_effect_act(2, 120, target_zone) H.stun_effect_act(2, 120, target_zone, electric = TRUE)
var/burn_damage = H.electrocute_act(burn_damage_amt*2, src, def_zone = target_zone) var/burn_damage = H.electrocute_act(burn_damage_amt*2, src, def_zone = target_zone)
if(burn_damage > 15 && H.can_feel_pain()) if(burn_damage > 15 && H.can_feel_pain())
H.emote("scream") H.emote("scream")

View File

@@ -162,3 +162,10 @@
walk_away(src,temploc,stepdist) walk_away(src,temploc,stepdist)
addtimer(CALLBACK(src, PROC_REF(detonate)), rand(15, 60), TIMER_DELETE_ME) addtimer(CALLBACK(src, PROC_REF(detonate)), rand(15, 60), TIMER_DELETE_ME)
/obj/item/grenade/flashbang/clusterbang/primed
desc = "This clusterbang seems to have already been activated. Uhoh."
/obj/item/grenade/flashbang/clusterbang/primed/Initialize(mapload)
. = ..()
activate()

View File

@@ -37,3 +37,10 @@
var/new_smoke_color = tgui_color_picker(user, "Choose a color for the smoke:", "Smoke Color", smoke_color) var/new_smoke_color = tgui_color_picker(user, "Choose a color for the smoke:", "Smoke Color", smoke_color)
if(new_smoke_color) if(new_smoke_color)
smoke_color = new_smoke_color smoke_color = new_smoke_color
/obj/item/grenade/smokebomb/primed
desc = "A smoke bomb. This one appears to be already activated!"
/obj/item/grenade/smokebomb/primed/Initialize(mapload)
. = ..()
activate()

View File

@@ -205,7 +205,7 @@
//stun effects //stun effects
if(status) if(status)
target.stun_effect_act(stun, agony, hit_zone, src) target.stun_effect_act(stun, agony, hit_zone, src, electric = TRUE)
msg_admin_attack("[key_name(user)] stunned [key_name(target)] with the [src].") msg_admin_attack("[key_name(user)] stunned [key_name(target)] with the [src].")
if(ishuman(target)) if(ishuman(target))

View File

@@ -216,6 +216,13 @@
user.put_in_hands(stuff) user.put_in_hands(stuff)
else else
stuff.forceMove(drop_location()) stuff.forceMove(drop_location())
//Now here's the kicker
if(HAS_TRAIT(user, TRAIT_UNLUCKY) && prob(5)) //1 in 20 chance for your mail to be rigged with a glitter bomb
to_chat(user, span_bolddanger("You open the mail and - OH SHIT IS THAT A BOMB!"))
var/obj/item/grenade/confetti/confetti_nade = new /obj/item/grenade/confetti()
confetti_nade.name = "Pipebomb"
confetti_nade.desc = span_bolddanger("What the hell are you looking at it for?! RUN!!")
confetti_nade.activate()
playsound(loc, 'sound/items/poster_ripped.ogg', 100, TRUE) playsound(loc, 'sound/items/poster_ripped.ogg', 100, TRUE)
qdel(src) qdel(src)

View File

@@ -22,7 +22,7 @@
/datum/blob_type/energized_jelly/on_attack(obj/structure/blob/B, mob/living/victim, def_zone) /datum/blob_type/energized_jelly/on_attack(obj/structure/blob/B, mob/living/victim, def_zone)
victim.electrocute_act(10, src, 1, def_zone) victim.electrocute_act(10, src, 1, def_zone)
victim.stun_effect_act(0, 40, BP_TORSO, src) victim.stun_effect_act(0, 40, BP_TORSO, src, electric = TRUE)
/datum/blob_type/energized_jelly/on_chunk_tick(obj/item/blobcore_chunk/B) /datum/blob_type/energized_jelly/on_chunk_tick(obj/item/blobcore_chunk/B)
for(var/mob/living/L in oview(world.view, get_turf(B))) for(var/mob/living/L in oview(world.view, get_turf(B)))

View File

@@ -590,6 +590,13 @@ GLOBAL_LIST_EMPTY(vending_products)
addtimer(CALLBACK(src, PROC_REF(delayed_vend), R, user), vend_delay) addtimer(CALLBACK(src, PROC_REF(delayed_vend), R, user), vend_delay)
/obj/machinery/vending/proc/delayed_vend(datum/stored_item/vending_product/R, mob/user) /obj/machinery/vending/proc/delayed_vend(datum/stored_item/vending_product/R, mob/user)
if(HAS_TRAIT(user, TRAIT_UNLUCKY) && prob(10))
visible_message(span_infoplain(span_bold("\The [src]") + " clunks and fails to dispense any item."))
playsound(src, "sound/[vending_sound]", 100, TRUE, 1)
vend_ready = 1
currently_vending = null
SStgui.update_uis(src)
return
R.get_product(get_turf(src)) R.get_product(get_turf(src))
if(has_logs) if(has_logs)
do_logging(R, user, 1) do_logging(R, user, 1)
@@ -715,9 +722,11 @@ GLOBAL_LIST_EMPTY(vending_products)
return return
//Somebody cut an important wire and now we're following a new definition of "pitch." //Somebody cut an important wire and now we're following a new definition of "pitch."
/obj/machinery/vending/proc/throw_item() /obj/machinery/vending/proc/throw_item(forced_target)
var/obj/item/throw_item = null var/obj/item/throw_item = null
var/mob/living/target = locate() in view(7,src) var/mob/living/target = locate() in view(7,src)
if(forced_target && isliving(forced_target))
target = forced_target
if(!target) if(!target)
return 0 return 0

View File

@@ -27,3 +27,16 @@
to_chat(user, span_warning("You need at least one working hand to snap your fingers.")) to_chat(user, span_warning("You need at least one working hand to snap your fingers."))
return FALSE return FALSE
. = ..() . = ..()
/decl/emote/audible/snap/do_extra(mob/user)
. = ..()
if(HAS_TRAIT(user, TRAIT_UNLUCKY) && prob(0.1) && ishuman(user)) //1 in a thousand
var/mob/living/carbon/human/unlucky_human = user
var/datum/component/omen/bad_luck = unlucky_human.GetComponent(/datum/component/omen) //Also going to make sure they got the EVIL version.
if(bad_luck.evil)
unlucky_human.visible_message(span_danger("[unlucky_human] snaps, their hand fading to ash!"), span_danger(span_huge("OH GOD YOUR HAND")))
for(var/limb in list(BP_L_HAND, BP_R_HAND))
var/obj/item/organ/external/L = unlucky_human.get_organ(limb)
if(istype(L) && L.is_usable() && !L.splinted)
L.droplimb(TRUE, DROPLIMB_BURN)
break

View File

@@ -91,10 +91,10 @@
sides = 10 sides = 10
result = 10 result = 10
/obj/item/dice/attack_self(mob/user as mob) /obj/item/dice/attack_self(mob/user)
rollDice(user, 0) rollDice(user, 0)
/obj/item/dice/proc/rollDice(mob/user as mob, var/silent = 0) /obj/item/dice/proc/rollDice(mob/user, silent = FALSE)
result = rand(1, sides) result = rand(1, sides)
if(loaded) if(loaded)
if(cheater) if(cheater)
@@ -103,6 +103,9 @@
else if(prob(75)) //makeshift weighted dice don't always work else if(prob(75)) //makeshift weighted dice don't always work
result = loaded result = loaded
icon_state = "[name][result]" icon_state = "[name][result]"
var/result_override = SEND_SIGNAL(user, COMSIG_MOB_ROLLED_DICE, src, silent, result) //We can override dice rolls!
if(result_override)
result = result_override
if(!silent) if(!silent)
var/comment = "" var/comment = ""
@@ -192,18 +195,18 @@
/obj/item/dice, /obj/item/dice,
) )
/obj/item/storage/dicecup/attack_self(mob/user as mob) /obj/item/storage/dicecup/attack_self(mob/user)
user.visible_message(span_notice("[user] shakes [src]."), \ user.visible_message(span_notice("[user] shakes [src]."), \
span_notice("You shake [src]."), \ span_notice("You shake [src]."), \
span_notice("You hear dice rolling.")) span_notice("You hear dice rolling."))
rollCup(user) rollCup(user)
/obj/item/storage/dicecup/proc/rollCup(mob/user as mob) /obj/item/storage/dicecup/proc/rollCup(mob/user)
for(var/obj/item/dice/I in src.contents) for(var/obj/item/dice/I in src.contents)
var/obj/item/dice/D = I var/obj/item/dice/D = I
D.rollDice(user, 1) D.rollDice(user, 1)
/obj/item/storage/dicecup/proc/revealDice(var/mob/viewer) /obj/item/storage/dicecup/proc/revealDice(mob/viewer)
for(var/obj/item/dice/I in src.contents) for(var/obj/item/dice/I in src.contents)
var/obj/item/dice/D = I var/obj/item/dice/D = I
to_chat(viewer, "The [D.name] shows a [D.result].") to_chat(viewer, "The [D.name] shows a [D.result].")
@@ -230,3 +233,40 @@
. = ..() . = ..()
for(var/i = 1 to 5) for(var/i = 1 to 5)
new /obj/item/dice(src) new /obj/item/dice(src)
/obj/item/dice/d20/cursed
name = "d20"
desc = "A dice with twenty sides."
icon_state = "d2020"
sides = 20
result = 20
///If the dice will apply the major version of unlucky or not.
var/evil = TRUE
/obj/item/dice/d20/cursed/rollDice(mob/user, silent = FALSE)
..()
if(result == 1)
to_chat(user, span_cult("You feel extraordinarily unlucky..."))
if(evil)
user.AddComponent(
/datum/component/omen/dice,\
incidents_left = 1,\
luck_mod = 1,\
damage_mod = 1,\
evil = TRUE,\
safe_disposals = FALSE,\
vorish = TRUE,\
)
else
user.AddComponent(
/datum/component/omen/dice,\
incidents_left = 1,\
luck_mod = 0.3,\
damage_mod = 1,\
evil = FALSE,\
safe_disposals = FALSE,\
vorish = TRUE,\
)

View File

@@ -323,7 +323,7 @@
if(!H.lying || H.handcuffed || arrest_type) if(!H.lying || H.handcuffed || arrest_type)
cuff = FALSE cuff = FALSE
if(!cuff) if(!cuff)
H.stun_effect_act(0, stun_strength, null) H.stun_effect_act(0, stun_strength, null, electric = TRUE)
playsound(src, 'sound/weapons/egloves.ogg', 50, 1, -1) playsound(src, 'sound/weapons/egloves.ogg', 50, 1, -1)
do_attack_animation(H) do_attack_animation(H)
busy = TRUE busy = TRUE

View File

@@ -389,8 +389,9 @@
return return
/mob/living/carbon/slip(var/slipped_on,stun_duration=8) /mob/living/carbon/slip(var/slipped_on,stun_duration=8)
SEND_SIGNAL(src, COMSIG_ON_CARBON_SLIP, slipped_on, stun_duration)
if(buckled) if(buckled)
return 0 return FALSE
stop_pulling() stop_pulling()
to_chat(src, span_warning("You slipped on [slipped_on]!")) to_chat(src, span_warning("You slipped on [slipped_on]!"))
playsound(src, 'sound/misc/slip.ogg', 50, 1, -3) playsound(src, 'sound/misc/slip.ogg', 50, 1, -3)
@@ -399,7 +400,7 @@
src.emote("sflip") src.emote("sflip")
return 1 //CHOMPEdit End return 1 //CHOMPEdit End
Weaken(FLOOR(stun_duration/2, 1)) Weaken(FLOOR(stun_duration/2, 1))
return 1 return TRUE
/mob/living/carbon/proc/add_chemical_effect(var/effect, var/magnitude = 1) /mob/living/carbon/proc/add_chemical_effect(var/effect, var/magnitude = 1)
if(effect in chem_effects) if(effect in chem_effects)

View File

@@ -1506,12 +1506,12 @@
if(lying) if(lying)
playsound(src, 'sound/misc/slip.ogg', 25, 1, -1) playsound(src, 'sound/misc/slip.ogg', 25, 1, -1)
drop_both_hands() drop_both_hands()
return 0 return FALSE
if((species.flags & NO_SLIP && !footcoverage_check) || (shoes && (shoes.item_flags & NOSLIP))) //Footwear negates a species' natural traction. if((species.flags & NO_SLIP && !footcoverage_check) || (shoes && (shoes.item_flags & NOSLIP))) //Footwear negates a species' natural traction.
return 0 return FALSE
if(..(slipped_on,stun_duration)) if(..(slipped_on,stun_duration))
drop_both_hands() drop_both_hands()
return 1 return TRUE
/mob/living/carbon/human/proc/relocate() /mob/living/carbon/human/proc/relocate()
set category = "Object" set category = "Object"

View File

@@ -58,7 +58,7 @@ emp_act
return (..(P , def_zone)) return (..(P , def_zone))
/mob/living/carbon/human/stun_effect_act(var/stun_amount, var/agony_amount, var/def_zone) /mob/living/carbon/human/stun_effect_act(var/stun_amount, var/agony_amount, var/def_zone, var/used_weapon=null, var/electric = FALSE)
var/obj/item/organ/external/affected = get_organ(check_zone(def_zone)) var/obj/item/organ/external/affected = get_organ(check_zone(def_zone))
var/siemens_coeff = get_siemens_coefficient_organ(affected) var/siemens_coeff = get_siemens_coefficient_organ(affected)
if(fire_stacks < 0) // Water makes you more conductive. if(fire_stacks < 0) // Water makes you more conductive.
@@ -87,7 +87,7 @@ emp_act
var/emote_scream = pick("screams in pain and ", "lets out a sharp cry and ", "cries out and ") var/emote_scream = pick("screams in pain and ", "lets out a sharp cry and ", "cries out and ")
automatic_custom_emote(VISIBLE_MESSAGE, "[affected.organ_can_feel_pain() ? "" : emote_scream] drops what they were holding in their [affected.name]!", check_stat = TRUE) automatic_custom_emote(VISIBLE_MESSAGE, "[affected.organ_can_feel_pain() ? "" : emote_scream] drops what they were holding in their [affected.name]!", check_stat = TRUE)
..(stun_amount, agony_amount, def_zone) ..(stun_amount, agony_amount, def_zone, used_weapon, electric)
/mob/living/carbon/human/getarmor(var/def_zone, var/type) /mob/living/carbon/human/getarmor(var/def_zone, var/type)
var/armorval = 0 var/armorval = 0
@@ -433,8 +433,8 @@ emp_act
return return
if(in_throw_mode && speed <= THROWFORCE_SPEED_DIVISOR) //empty active hand and we're in throw mode if(in_throw_mode && speed <= THROWFORCE_SPEED_DIVISOR) //empty active hand and we're in throw mode
if(canmove && !restrained() && !src.is_incorporeal()) if(canmove && !restrained() && !src.is_incorporeal())
if(isturf(O.loc)) if(isturf(O.loc) && can_catch(O))
if(can_catch(O)) if(!SEND_SIGNAL(src, COMSIG_HUMAN_ON_CATCH_THROW, source, speed))
put_in_active_hand(O) put_in_active_hand(O)
visible_message(span_warning("[src] catches [O]!")) visible_message(span_warning("[src] catches [O]!"))
throw_mode_off() throw_mode_off()

View File

@@ -830,3 +830,26 @@
addiction = REAGENT_ID_ASUSTENANCE addiction = REAGENT_ID_ASUSTENANCE
custom_only = FALSE custom_only = FALSE
hidden = TRUE //Disabled on Virgo hidden = TRUE //Disabled on Virgo
/datum/trait/negative/unlucky
name = "Unlucky"
desc = "You are naturally unlucky and ill-events often befall you."
cost = -2
is_genetrait = FALSE
hidden = FALSE
custom_only = FALSE
added_component_path = /datum/component/omen/trait
excludes = list(/datum/trait/negative/unlucky/major)
/datum/trait/negative/unlucky/major
name = "Unlucky, Major"
desc = "Your luck is extremely awful and potentially fatal."
cost = -5
tutorial = "You should avoid disposal bins."
is_genetrait = TRUE
hidden = FALSE
added_component_path = /datum/component/omen/trait/major
excludes = list(/datum/trait/negative/unlucky)
activation_message= span_cult(span_bold("What a terrible night to have a curse!"))
primitive_expression_messages=list("unluckily stubs their toe!")

View File

@@ -117,7 +117,7 @@
// Getting hurt in VR doesn't damage the physical body, but you still got hurt. // Getting hurt in VR doesn't damage the physical body, but you still got hurt.
if(ishuman(vr_holder) && total_damage) if(ishuman(vr_holder) && total_damage)
var/mob/living/carbon/human/V = vr_holder var/mob/living/carbon/human/V = vr_holder
V.stun_effect_act(0, total_damage*2/3, null) // 200 damage leaves the user in paincrit for several seconds, agony reaches 0 after around 2m. V.stun_effect_act(0, total_damage*2/3, null, electric = FALSE) // 200 damage leaves the user in paincrit for several seconds, agony reaches 0 after around 2m.
to_chat(vr_holder, span_warning("Pain from your time in VR lingers.")) // 250 damage leaves the user unconscious for several seconds in addition to paincrit to_chat(vr_holder, span_warning("Pain from your time in VR lingers.")) // 250 damage leaves the user unconscious for several seconds in addition to paincrit
// Maintain a link with the mob, but don't use teleop // Maintain a link with the mob, but don't use teleop

View File

@@ -134,7 +134,7 @@
//Stun Beams //Stun Beams
if(P.taser_effect) if(P.taser_effect)
stun_effect_act(0, P.agony, def_zone, P) stun_effect_act(0, P.agony, def_zone, P, electric = TRUE)
if(!P.nodamage) if(!P.nodamage)
apply_damage(P.damage, P.damage_type, def_zone, absorb, soaked, 0, sharp=proj_sharp, edge=proj_edge, used_weapon=P, projectile=TRUE) apply_damage(P.damage, P.damage_type, def_zone, absorb, soaked, 0, sharp=proj_sharp, edge=proj_edge, used_weapon=P, projectile=TRUE)
qdel(P) qdel(P)
@@ -154,8 +154,9 @@
// return absorb // return absorb
//Handles the effects of "stun" weapons //Handles the effects of "stun" weapons
/mob/living/proc/stun_effect_act(var/stun_amount, var/agony_amount, var/def_zone, var/used_weapon=null) /mob/living/proc/stun_effect_act(var/stun_amount, var/agony_amount, var/def_zone, var/used_weapon=null, var/electric = FALSE)
flash_pain() flash_pain()
SEND_SIGNAL(src, COMSIG_STUN_EFFECT_ACT, stun_amount, agony_amount, def_zone, used_weapon, electric)
if (stun_amount) if (stun_amount)
Stun(stun_amount) Stun(stun_amount)

View File

@@ -91,7 +91,7 @@
to_chat(src, span_danger("Warning: Electromagnetic pulse detected.")) to_chat(src, span_danger("Warning: Electromagnetic pulse detected."))
..() ..()
/mob/living/silicon/stun_effect_act(var/stun_amount, var/agony_amount) /mob/living/silicon/stun_effect_act(var/stun_amount, var/agony_amount, var/def_zone, var/used_weapon=null, var/electric = FALSE)
return //immune return //immune
/mob/living/silicon/electrocute_act(var/shock_damage, var/obj/source, var/siemens_coeff = 0.0, var/def_zone = null, var/stun = 1) /mob/living/silicon/electrocute_act(var/shock_damage, var/obj/source, var/siemens_coeff = 0.0, var/def_zone = null, var/stun = 1)

View File

@@ -190,9 +190,8 @@
. = min(., 1.0) . = min(., 1.0)
// Electricity // Electricity
/mob/living/simple_mob/electrocute_act(var/shock_damage, var/obj/source, var/siemens_coeff = 1.0, var/def_zone = null) /mob/living/simple_mob/electrocute_act(var/shock_damage, var/obj/source, var/siemens_coeff = 1.0, var/def_zone = null, var/stun = 1)
var/zap = min((1-get_shock_protection()), siemens_coeff) shock_damage *= siemens_coeff
shock_damage *= zap
if(shock_damage < 1) if(shock_damage < 1)
return 0 return 0
@@ -217,7 +216,7 @@
. = min(., 1.0) . = min(., 1.0)
// Shot with taser/stunvolver // Shot with taser/stunvolver
/mob/living/simple_mob/stun_effect_act(var/stun_amount, var/agony_amount, var/def_zone, var/used_weapon=null) /mob/living/simple_mob/stun_effect_act(var/stun_amount, var/agony_amount, var/def_zone, var/used_weapon=null, var/electric = FALSE)
if(taser_kill) if(taser_kill)
var/stunDam = 0 var/stunDam = 0
var/agonyDam = 0 var/agonyDam = 0

View File

@@ -44,7 +44,7 @@
adjust_discipline(2) // Justified. adjust_discipline(2) // Justified.
// Shocked grilles don't hurt slimes, and in fact give them charge. // Shocked grilles don't hurt slimes, and in fact give them charge.
/mob/living/simple_mob/slime/xenobio/electrocute_act(shock_damage, obj/source, siemens_coeff = 1.0, def_zone = null) /mob/living/simple_mob/slime/xenobio/electrocute_act(shock_damage, obj/source, siemens_coeff = 1.0, def_zone = null, stun = 1)
power_charge = between(0, power_charge + round(shock_damage / 10), 10) power_charge = between(0, power_charge + round(shock_damage / 10), 10)
to_chat(src, span_notice("\The [source] shocks you, and it charges you.")) to_chat(src, span_notice("\The [source] shocks you, and it charges you."))

View File

@@ -116,8 +116,19 @@
// On-click handling. Turns on the computer if it's off and opens the GUI. // On-click handling. Turns on the computer if it's off and opens the GUI.
/obj/item/modular_computer/attack_self(var/mob/user) /obj/item/modular_computer/attack_self(var/mob/user)
if(enabled && screen_on) if(enabled && screen_on)
if(isliving(user) && HAS_TRAIT(user, TRAIT_UNLUCKY) && prob(5))
var/mob/living/unlucky_soul = user
to_chat(user, span_danger("You interact with \the [src] and are met with a sudden shock!"))
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(5, 1, src)
s.start()
unlucky_soul.electrocute_act(5, src, 1)
return
tgui_interact(user) tgui_interact(user)
else if(!enabled && screen_on) else if(!enabled && screen_on)
if(HAS_TRAIT(user, TRAIT_UNLUCKY) && prob(25))
to_chat(user, "You try to turn on \the [src] but it doesn't respond.")
return
turn_on(user) turn_on(user)
/obj/item/modular_computer/attackby(var/obj/item/W, var/mob/user) /obj/item/modular_computer/attackby(var/obj/item/W, var/mob/user)

View File

@@ -193,7 +193,7 @@
var/mob/living/L = P var/mob/living/L = P
if(L.client) if(L.client)
L.client.Process_Grab() // Update any miscellanous grabs, possibly break grab-chains L.client.Process_Grab() // Update any miscellanous grabs, possibly break grab-chains
SEND_SIGNAL(AM, COMSIG_MOVED_UP_STAIRS, AM, oldloc)
return TRUE return TRUE
/obj/structure/stairs/bottom/use_stairs_instant(var/atom/movable/AM) /obj/structure/stairs/bottom/use_stairs_instant(var/atom/movable/AM)
@@ -231,6 +231,7 @@
L.client.Process_Grab() L.client.Process_Grab()
else else
AM.forceMove(get_turf(top)) AM.forceMove(get_turf(top))
SEND_SIGNAL(AM, COMSIG_MOVED_UP_STAIRS, AM)
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
@@ -452,7 +453,7 @@
var/mob/living/L = P var/mob/living/L = P
if(L.client) if(L.client)
L.client.Process_Grab() // Update any miscellanous grabs, possibly break grab-chains L.client.Process_Grab() // Update any miscellanous grabs, possibly break grab-chains
SEND_SIGNAL(AM, COMSIG_MOVED_DOWN_STAIRS, AM, oldloc)
return TRUE return TRUE
/obj/structure/stairs/top/use_stairs_instant(var/atom/movable/AM) /obj/structure/stairs/top/use_stairs_instant(var/atom/movable/AM)
@@ -489,6 +490,7 @@
L.client.Process_Grab() L.client.Process_Grab()
else else
AM.forceMove(get_turf(bottom)) AM.forceMove(get_turf(bottom))
SEND_SIGNAL(AM, COMSIG_MOVED_DOWN_STAIRS, AM)
// Mapping pieces, placed at the bottommost part of the stairs // Mapping pieces, placed at the bottommost part of the stairs
/obj/structure/stairs/spawner /obj/structure/stairs/spawner

View File

@@ -869,7 +869,7 @@ GLOBAL_LIST_EMPTY(light_type_cache)
// break the light and make sparks if was on // break the light and make sparks if was on
/obj/machinery/light/proc/broken(var/skip_sound_and_sparks = 0) /obj/machinery/light/proc/broken(var/skip_sound_and_sparks = FALSE)
if(status == LIGHT_EMPTY) if(status == LIGHT_EMPTY)
return return

View File

@@ -150,7 +150,7 @@
overlay_above_everything = TRUE overlay_above_everything = TRUE
color = "#3e5064" color = "#3e5064"
/obj/machinery/light/small/fairylights/broken() /obj/machinery/light/small/fairylights/broken(var/skip_sound_and_sparks = FALSE)
return return
/obj/machinery/light/small/fairylights/flicker /obj/machinery/light/small/fairylights/flicker

View File

@@ -273,7 +273,7 @@
target.visible_message(span_danger("[target] has been zapped with [src] by [user]!")) target.visible_message(span_danger("[target] has been zapped with [src] by [user]!"))
playsound(src, 'sound/weapons/egloves.ogg', 50, 1, -1) playsound(src, 'sound/weapons/egloves.ogg', 50, 1, -1)
target.stun_effect_act(0, agony, hit_zone, src) target.stun_effect_act(0, agony, hit_zone, src, electric = TRUE)
msg_admin_attack("[key_name(user)] stunned [key_name(target)] with the [src].") msg_admin_attack("[key_name(user)] stunned [key_name(target)] with the [src].")
if(ishuman(target)) if(ishuman(target))
var/mob/living/carbon/human/H = target var/mob/living/carbon/human/H = target
@@ -495,7 +495,7 @@
else else
target.visible_message(span_danger("[target] has been prodded with [src] by [user]!")) target.visible_message(span_danger("[target] has been prodded with [src] by [user]!"))
playsound(src, 'sound/weapons/egloves.ogg', 50, 1, -1) playsound(src, 'sound/weapons/egloves.ogg', 50, 1, -1)
target.stun_effect_act(stun, agony, hit_zone, src) target.stun_effect_act(stun, agony, hit_zone, src, electric = TRUE)
msg_admin_attack("[key_name(user)] stunned [key_name(target)] with the [src].") msg_admin_attack("[key_name(user)] stunned [key_name(target)] with the [src].")
if(ishuman(target)) if(ishuman(target))
var/mob/living/carbon/human/H = target var/mob/living/carbon/human/H = target

View File

@@ -2,6 +2,14 @@
//The winner of the pull has an effect applied to them. //The winner of the pull has an effect applied to them.
//Crackers do already exist, but these ones are a more memey scene item. //Crackers do already exist, but these ones are a more memey scene item.
#define SHRINKING_CRACKER "shrinking"
#define GROWING_CRACKER "growing"
#define DRUGGED_CRACKER "drugged"
#define INVISIBLE_CRACKER "invisibility"
#define FALLING_CRACKER "knockdown"
#define TELEPORTING_CRACKER "teleport"
#define WEALTHY_CRACKER "wealth"
/obj/item/cracker /obj/item/cracker
name = "bluespace cracker" //I have no idea why this was called shrink ray when this increased and decreased size. name = "bluespace cracker" //I have no idea why this was called shrink ray when this increased and decreased size.
desc = "A celebratory little game with a bluespace twist! Pull it between two people until it snaps, and the person who recieves the larger end gets a prize!" desc = "A celebratory little game with a bluespace twist! Pull it between two people until it snaps, and the person who recieves the larger end gets a prize!"
@@ -13,26 +21,35 @@
) )
item_state = "blue" item_state = "blue"
var/rigged = 0 //So that they can be rigged by varedits to go one way or the other. positive values mean holder always wins, negative values mean target always wins. var/rigged = 0 //So that they can be rigged by varedits to go one way or the other. positive values mean holder always wins, negative values mean target always wins.
var/list/prizes = list("shrinking","growing","drugged","invisibility","knocked over","teleport","wealth") var/prize //What prize we have loaded
var/list/jokes = list( var/joke //What joke we have loaded
"When is a boat just like snow? When it's adrift.",
"What happens to naughty elves? Santa gives them the sack.", /obj/item/cracker/Initialize(mapload)
"What do you call an old snowman? Water.", . = ..()
"Why has Santa been banned from sooty chimneys? Carbon footprints.", var/style = pick("blue","green","yellow","red","heart","hazard")
"What goes down but doesn't come up? A yo.", icon_state = style
"What's green and fuzzy, has four legs and would kill you if it fell from a tree? A pool table.", item_state = style
"Why did the blind man fall into the well? Because he couldn't see that well.", if(!prize)
"What did the pirate get on his report card? Seven Cs", prize = pick(SHRINKING_CRACKER,GROWING_CRACKER,GROWING_CRACKER,INVISIBLE_CRACKER,FALLING_CRACKER,TELEPORTING_CRACKER,WEALTHY_CRACKER)
"What do you call a fish with no eyes? Fsh", if(!joke)
"How do you make an egg roll? You push it.", joke = pick("When is a boat just like snow? When it's adrift.",
"What do you call a deer with no eyes? NO EYED DEER!", "What happens to naughty elves? Santa gives them the sack.",
"What's red, and smells like blue paint? Red paint.", "What do you call an old snowman? Water.",
"Where do cows go to dance? A meat ball.", "Why has Santa been banned from sooty chimneys? Carbon footprints.",
"What do you call a person who steals all your toenail clippings? A cliptoemaniac.", "What goes down but doesn't come up? A yo.",
"What's brown and sticky? A stick.", "What's green and fuzzy, has four legs and would kill you if it fell from a tree? A pool table.",
"What's the best way to kill a circus? Go for the juggler.", "Why did the blind man fall into the well? Because he couldn't see that well.",
"What do you call a cow with no legs? Ground Beef.", "What did the pirate get on his report card? Seven Cs",
"Why'd the scarecrow win the Nobel prize? He was outstanding in his field.") "What do you call a fish with no eyes? Fsh",
"How do you make an egg roll? You push it.",
"What do you call a deer with no eyes? NO EYED DEER!",
"What's red, and smells like blue paint? Red paint.",
"Where do cows go to dance? A meat ball.",
"What do you call a person who steals all your toenail clippings? A cliptoemaniac.",
"What's brown and sticky? A stick.",
"What's the best way to kill a circus? Go for the juggler.",
"What do you call a cow with no legs? Ground Beef.",
"Why'd the scarecrow win the Nobel prize? He was outstanding in his field.")
/obj/item/cracker/attack(atom/A, mob/living/user, adjacent, params) /obj/item/cracker/attack(atom/A, mob/living/user, adjacent, params)
var/mob/living/carbon/human/target = A var/mob/living/carbon/human/target = A
@@ -56,8 +73,6 @@
to_chat(user, span_notice("\The [src] is no longer in-hand!")) to_chat(user, span_notice("\The [src] is no longer in-hand!"))
to_chat(target, span_notice("\The [src] is no longer in-hand!")) to_chat(target, span_notice("\The [src] is no longer in-hand!"))
return return
var/prize = pick(prizes)
var/joke = pick(jokes)
var/mob/living/carbon/human/winner var/mob/living/carbon/human/winner
var/mob/living/carbon/human/loser var/mob/living/carbon/human/loser
if(!rigged) if(!rigged)
@@ -74,46 +89,52 @@
else else
winner = target winner = target
loser = user loser = user
if(HAS_TRAIT(loser, TRAIT_UNLUCKY) && prob(66))
if(prize == (SHRINKING_CRACKER || GROWING_CRACKER || FALLING_CRACKER || TELEPORTING_CRACKER)) //If we're unlucky and the prize is bad, chance for us to get it!
var/former_winner = winner
winner = loser
loser = former_winner
var/spawnloc = get_turf(winner) var/spawnloc = get_turf(winner)
winner.visible_message(span_notice("\The [winner] wins the cracker prize!"),span_notice("You win the cracker prize!")) winner.visible_message(span_notice("\The [winner] wins the cracker prize!"),span_notice("You win the cracker prize!"))
if(prize == "shrinking") switch(prize)
winner.resize(0.25) if(SHRINKING_CRACKER)
winner.visible_message(span_bold("\The [winner]") + " shrinks suddenly!") winner.resize(0.25)
if(prize == "growing") winner.visible_message(span_bold("\The [winner]") + " shrinks suddenly!")
winner.resize(2) if(GROWING_CRACKER)
winner.visible_message(span_bold("\The [winner]") + " grows in height suddenly.") winner.resize(2)
if(prize == "drugged") winner.visible_message(span_bold("\The [winner]") + " grows in height suddenly.")
winner.druggy = max(winner.druggy, 50) if(GROWING_CRACKER)
if(prize == "invisibility") winner.druggy = max(winner.druggy, 50)
if(!winner.cloaked) if(INVISIBLE_CRACKER)
winner.visible_message(span_bold("\The [winner]") + " vanishes from sight.") if(!winner.cloaked)
winner.cloak() winner.visible_message(span_bold("\The [winner]") + " vanishes from sight.")
spawn(600) winner.cloak()
if(winner.cloaked) spawn(600)
winner.uncloak() if(winner.cloaked)
winner.visible_message(span_bold("\The [winner]") + " appears as if from thin air.") winner.uncloak()
if(prize == "knocked over") winner.visible_message(span_bold("\The [winner]") + " appears as if from thin air.")
winner.visible_message(span_bold("\The [winner]") + " is suddenly knocked to the ground.") if(FALLING_CRACKER)
winner.weakened = max(winner.weakened,50) winner.visible_message(span_bold("\The [winner]") + " is suddenly knocked to the ground.")
if(prize == "teleport") winner.weakened = max(winner.weakened,50)
if(loser.can_be_drop_pred && loser.vore_selected) if(TELEPORTING_CRACKER)
if(winner.devourable && winner.can_be_drop_prey) if(loser.can_be_drop_pred && loser.vore_selected)
winner.visible_message(span_bold("\The [winner]") + " is teleported to somewhere nearby...") if(winner.devourable && winner.can_be_drop_prey)
var/datum/effect/effect/system/spark_spread/spk winner.visible_message(span_bold("\The [winner]") + " is teleported to somewhere nearby...")
spk = new(winner) var/datum/effect/effect/system/spark_spread/spk
spk = new(winner)
var/T = get_turf(winner) var/T = get_turf(winner)
spk.set_up(5, 0, winner) spk.set_up(5, 0, winner)
spk.attach(winner) spk.attach(winner)
playsound(T, "sparks", 50, 1) playsound(T, "sparks", 50, 1)
anim(T,winner,'icons/mob/mob.dmi',,"phaseout",,winner.dir) anim(T,winner,'icons/mob/mob.dmi',,"phaseout",,winner.dir)
winner.forceMove(loser.vore_selected) winner.forceMove(loser.vore_selected)
if(prize == "wealth") if(WEALTHY_CRACKER)
new /obj/random/cash/huge(spawnloc) new /obj/random/cash/huge(spawnloc)
new /obj/random/cash/huge(spawnloc) new /obj/random/cash/huge(spawnloc)
winner.visible_message(span_bold("\The [winner]") + " has a whole load of cash fall at their feet!") winner.visible_message(span_bold("\The [winner]") + " has a whole load of cash fall at their feet!")
playsound(user, 'sound/effects/snap.ogg', 50, 1) playsound(user, 'sound/effects/snap.ogg', 50, 1)
user.drop_item(src) user.drop_item(src)
@@ -123,40 +144,33 @@
J.info = joke J.info = joke
qdel(src) qdel(src)
/obj/item/cracker/Initialize(mapload)
var/list/styles = list("blue","green","yellow","red","heart","hazard")
var/style = pick(styles)
icon_state = style
item_state = style
. = ..()
/obj/item/cracker/shrinking /obj/item/cracker/shrinking
name = "shrinking bluespace cracker" name = "shrinking bluespace cracker"
prizes = list("shrinking") prize = SHRINKING_CRACKER
/obj/item/cracker/growing /obj/item/cracker/growing
name = "growing bluespace cracker" name = "growing bluespace cracker"
prizes = list("growing") prize = GROWING_CRACKER
/obj/item/cracker/invisibility /obj/item/cracker/invisibility
name = "cloaking bluespace cracker" name = "cloaking bluespace cracker"
prizes = list("invisibility") prize = INVISIBLE_CRACKER
/obj/item/cracker/drugged /obj/item/cracker/drugged
name = "psychedelic bluespace cracker" name = "psychedelic bluespace cracker"
prizes = list("drugged") prize = GROWING_CRACKER
/obj/item/cracker/knockover /obj/item/cracker/knockover
name = "forceful bluespace cracker" name = "forceful bluespace cracker"
prizes = list("knocked over") prize = FALLING_CRACKER
/obj/item/cracker/vore /obj/item/cracker/vore
name = "teleporting bluespace cracker" name = "teleporting bluespace cracker"
prizes = list("teleport") prize = TELEPORTING_CRACKER
/obj/item/cracker/money /obj/item/cracker/money
name = "fortuitous bluespace cracker" name = "fortuitous bluespace cracker"
prizes = list("wealth") prize = WEALTHY_CRACKER
/obj/item/clothing/head/paper_crown /obj/item/clothing/head/paper_crown
name = "paper crown" name = "paper crown"
@@ -181,3 +195,11 @@
/obj/item/paper/cracker_joke/update_icon() /obj/item/paper/cracker_joke/update_icon()
return return
#undef SHRINKING_CRACKER
#undef GROWING_CRACKER
#undef DRUGGED_CRACKER
#undef INVISIBLE_CRACKER
#undef FALLING_CRACKER
#undef TELEPORTING_CRACKER
#undef WEALTHY_CRACKER

Binary file not shown.

View File

@@ -688,6 +688,7 @@
#include "code\datums\components\traits\gargoyle.dm" #include "code\datums\components\traits\gargoyle.dm"
#include "code\datums\components\traits\nutrition_size_change.dm" #include "code\datums\components\traits\nutrition_size_change.dm"
#include "code\datums\components\traits\photosynth.dm" #include "code\datums\components\traits\photosynth.dm"
#include "code\datums\components\traits\unlucky.dm"
#include "code\datums\components\traits\waddle.dm" #include "code\datums\components\traits\waddle.dm"
#include "code\datums\components\traits\weaver.dm" #include "code\datums\components\traits\weaver.dm"
#include "code\datums\diseases\_disease.dm" #include "code\datums\diseases\_disease.dm"