diff --git a/code/__defines/dcs/signals.dm b/code/__defines/dcs/signals.dm index 7e1dc3c3640..47c531e1580 100644 --- a/code/__defines/dcs/signals.dm +++ b/code/__defines/dcs/signals.dm @@ -185,6 +185,11 @@ ///from base of atom/attack_paw(): (mob/user) //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) #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) @@ -256,6 +261,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 ///from base of mob/living/hitby(): (mob/living/target, hit_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) #define COMSIG_MOVABLE_BUCKLE "buckle" ///from base of atom/movable/unbuckle_mob(): (mob, force) @@ -303,6 +310,9 @@ #define COMSIG_MOB_ALTCLICKON "mob_altclickon" #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 #define COMSIG_MOB_ALLOWED "mob_allowed" ///from base of mob/anti_magic_check(): (mob/user, magic, holy, tinfoil, chargecost, self, protection_sources) @@ -381,6 +391,55 @@ #define COMSIG_LIVING_LIFE "living_life" ///From /living/handle_disabilities(). #define COMSIG_HANDLE_DISABILITIES "handle_disabilities" +<<<<<<< HEAD +======= +///From /living/handle_allergens(). +#define COMSIG_HANDLE_ALLERGENS "handle_allergens" +///From /mob/living/proc/updatehealth(). +#define COMSIG_UPDATE_HEALTH "update_health" + #define COMSIG_UPDATE_HEALTH_GOD_MODE (1<<0) //If this will set health to 100 and stat to conscious. + +// Damage specific signals for /mob/living +///from /mob/living/proc/adjustBrainLoss(amount) and /mob/living/proc/setBrainLoss(amount) +#define COMSIG_TAKING_BRAIN_DAMAGE "taking_brain_damage" +///Return this in response if you don't want brain damage to be dealt via the normal proc. + #define COMSIG_CANCEL_BRAIN_DAMAGE (1<<0) +///from /mob/living/proc/adjustOxyLoss(amount) and /mob/living/proc/setOxyLoss(amount) +#define COMSIG_TAKING_OXY_DAMAGE "taking_oxy_damage" +///Return this in response if you don't want brain damage to be dealt via the normal proc. + #define COMSIG_CANCEL_OXY_DAMAGE (1<<0) +///from /mob/living/proc/adjustToxLoss(amount) and /mob/living/proc/setToxLoss(amount) +#define COMSIG_TAKING_TOX_DAMAGE "taking_tox_damage" +///Return this in response if you don't want tox damage to be dealt via the normal proc. + #define COMSIG_CANCEL_TOX_DAMAGE (1<<0) +///from /mob/living/proc/adjustCloneLoss(amount) and /mob/living/proc/setCloneLoss(amount) +#define COMSIG_TAKING_CLONE_DAMAGE "taking_clone_damage" +///Return this in response if you don't want clone damage to be dealt via the normal proc. + #define COMSIG_CANCEL_CLONE_DAMAGE (1<<0) +///from /mob/living/proc/adjustFireLoss(amount, include_robo) +#define COMSIG_TAKING_FIRE_DAMAGE "taking_fire_damage" +///Return this in response if you don't want fire damage to be dealt via the normal proc. + #define COMSIG_CANCEL_FIRE_DAMAGE (1<<0) +///from /mob/living/proc/adjustBruteLoss(amount, include_robo) and /mob/living/carbon/human/adjustBruteLoss(amount, include_robo) +#define COMSIG_TAKING_BRUTE_DAMAGE "taking_brute_damage" +///Return this in response if you don't want brute damage to be dealt via the normal proc. + #define COMSIG_CANCEL_BRUTE_DAMAGE (1<<0) +///from /mob/living/proc/adjustHalLoss(amount) +#define COMSIG_TAKING_HALO_DAMAGE "taking_halo_damage" +///Return this in response if you don't want halo damage to be dealt via the normal proc. + #define COMSIG_CANCEL_HALO_DAMAGE (1<<0) +///from /mob/living/proc/apply_effect(effect, effecttype, blocked, check_protection) +#define COMSIG_TAKING_APPLY_EFFECT "applying_effect" +///Return this in response if you don't want the effect to be applied + #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 +#define COMSIG_CHECK_FOR_GODMODE "check_for_godmode" +///Returned by /datum/element/godmode if the target is in godmode and whatever we're checking we want to cancel + #define COMSIG_GODMODE_CANCEL (1<<0) +>>>>>>> b8fe8fa68d ([MIRROR] Unlucky trait (#11775)) //ALL OF THESE DO NOT TAKE INTO ACCOUNT WHETHER AMOUNT IS 0 OR LOWER AND ARE SENT REGARDLESS! @@ -417,8 +476,25 @@ #define COMSIG_CARBON_EMBED_RIP "item_embed_start_rip" ///called when removing a given item from a mob, from mob/living/carbon/remove_embedded_object(mob/living/carbon/target, /obj/item) #define COMSIG_CARBON_EMBED_REMOVAL "item_embed_remove_safe" +<<<<<<< HEAD // /obj signals +======= +///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 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 +///called when a silicon is emp'd. from /mob/living/silicon/emp_act(severity) +#define COMSIG_SILICON_EMP_ACT "silicon_emp_act" + #define COMPONENT_BLOCK_EMP (1<<0) //If this is set, the EMP will not go through. Used by other EMP acts as well. + +// /mob/living/silicon/robot signals +///called when a robot is emp'd. from /mob/living/silicon/robot/emp_act(severity) +#define COMSIG_ROBOT_EMP_ACT "robot_emp_act" +>>>>>>> b8fe8fa68d ([MIRROR] Unlucky trait (#11775)) ///from base of obj/deconstruct(): (disassembled) #define COMSIG_OBJ_DECONSTRUCT "obj_deconstruct" @@ -463,6 +539,8 @@ #define COMSIG_ITEM_DROPPED "item_drop" ///from base of obj/item/pickup(): (/mob/taker) #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) #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) diff --git a/code/__defines/traits/declarations.dm b/code/__defines/traits/declarations.dm index 71e358701e7..34fc4e67b8a 100644 --- a/code/__defines/traits/declarations.dm +++ b/code/__defines/traits/declarations.dm @@ -9,3 +9,32 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Trait given to a mob that is currently thinking (giving off the "thinking" icon), used in an IC context #define TRAIT_THINKING_IN_CHARACTER "currently_thinking_IC" +<<<<<<< HEAD +======= + +/// Climbable trait, given and taken by the climbable element when added or removed. Exists to be easily checked via HAS_TRAIT(). +#define TRAIT_CLIMBABLE "trait_climbable" + +/// Prevents the affected object from opening a loot window via alt click. See atom/AltClick() +#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_NOFIRE "nonflammable" +#define TRAIT_NOFIRE_SPREAD "no_fire_spreading" +/// Mobs that have this trait cannot be extinguished +#define TRAIT_NO_EXTINGUISH "no_extinguish" +/// Tells us that the mob urrently has the fire_handler/wet_stacks status effect +#define TRAIT_IS_WET "is_wet" +/// Mobs with this trait stay wet for longer and resist fire decaying wetness +#define TRAIT_WET_FOR_LONGER "wet_for_longer" +/// Mobs with this trait will be immune to slipping while also being slippery themselves when lying on the floor +#define TRAIT_SLIPPERY_WHEN_WET "slippery_when_wet" +/// Stops the mob from slipping on water, or banana peels, or pretty much anything that doesn't have [GALOSHES_DONT_HELP] set +#define TRAIT_NO_SLIP_WATER "noslip_water" +/// Owner will ignore any fire protection when calculating fire damage +#define TRAIT_IGNORE_FIRE_PROTECTION "ignore_fire_protection" +>>>>>>> b8fe8fa68d ([MIRROR] Unlucky trait (#11775)) diff --git a/code/datums/components/_component.dm b/code/datums/components/_component.dm index 0e134ae6063..01c0b824a5e 100644 --- a/code/datums/components/_component.dm +++ b/code/datums/components/_component.dm @@ -368,6 +368,7 @@ old_component.InheritComponent(arglist(arguments)) else old_component.InheritComponent(new_component, TRUE) + QDEL_NULL(new_component) if(COMPONENT_DUPE_SOURCES) if(source in old_component.sources) diff --git a/code/datums/components/traits/unlucky.dm b/code/datums/components/traits/unlucky.dm new file mode 100644 index 00000000000..28ba8000600 --- /dev/null +++ b/code/datums/components/traits/unlucky.dm @@ -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 diff --git a/code/datums/elements/lootable/_lootable.dm b/code/datums/elements/lootable/_lootable.dm new file mode 100644 index 00000000000..b4856b7c537 --- /dev/null +++ b/code/datums/elements/lootable/_lootable.dm @@ -0,0 +1,148 @@ +/datum/element/lootable + var/chance_nothing = 0 // Unlucky people might need to loot multiple spots to find things. + var/chance_uncommon = 10 // Probability of pulling from the uncommon_loot list. + var/chance_rare = 1 // Ditto, but for rare_loot list. + var/chance_gamma = 0 // Singledrop global loot table shared with all piles. + + var/allow_multiple_looting = FALSE // If true, the same person can loot multiple times. Mostly for debugging. + var/loot_depletion = FALSE // If true, loot piles can be 'depleted' after a certain number of searches by different players, where no more loot can be obtained. + 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/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/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. + +/datum/element/lootable/Attach(atom/target) + . = ..() + if(!isatom(target)) + return ELEMENT_INCOMPATIBLE + RegisterSignal(target, COMSIG_LOOT_REWARD, PROC_REF(loot)) + +/datum/element/lootable/Detach(atom/target) + . = ..() + UnregisterSignal(target, COMSIG_LOOT_REWARD) + +/// Calculates and drops loot, the source's turf is where it will be dropped, L is the searching mob, and searched_by is a passed list for storing who has searched a loot pile. +/datum/element/lootable/proc/loot(atom/source,mob/living/L,var/list/searched_by, wake_chance = 0) + SIGNAL_HANDLER + // The loot's all gone. + if(loot_depletion && loot_left <= 0) + to_chat(L, span_warning("\The [source] has been picked clean.")) + return + + // You got unlucky. + if(chance_nothing && prob(chance_nothing)) + to_chat(L, span_warning("Nothing in \the [source] really catches your eye...")) + return + + if(L && islist(searched_by)) // This can handle no mob and no list if you just want to use this as a way to hold drop tables + //You already searched this one + if((L.ckey in searched_by) && !allow_multiple_looting) + to_chat(L, span_warning("You can't find anything else vaguely useful in \the [source]. Another set of eyes might, however.")) + return + searched_by |= L.ckey // List is stored in the caller! + + // You found something! + var/obj/item/loot = null + var/span = "notice" // Blue + + 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) + span = "alium" // Green + + else if(prob(chance_rare) && rare_loot.len) // You won THE GRAND PRIZE! + loot = produce_rare_item(source) + span = "cult" // Purple and bold. + + else if(prob(chance_gamma) && GLOB.unique_gamma_loot.len) // ULTRA GRAND PRIZE + loot = produce_gamma_item(source) + span = "cult" // Purple and bold. + + else // Welp. + loot = produce_common_item(source) + + // Handle randomized items in our tables. + if(istype(loot,/obj/random)) + var/obj/random/randy = loot + var/new_I = randy.spawn_item() + QDEL_SWAP(loot,new_I) + + //We either have an item to hand over or we don't, at this point! + if(!loot) + return + loot.forceMove(get_turf(source)) + var/final_message = "You found \a [loot]!" + switch(span) + if("notice") + final_message = span_notice(final_message) + if("cult") + final_message = span_cult(final_message) + if("alium") + final_message = span_alium(final_message) + to_chat(L, span_info(final_message)) + var/disturbed_sleep = rand(1,100) //spawning of mobs, for now only the trash panda. + if(disturbed_sleep <= wake_chance) + new /mob/living/simple_mob/animal/passive/raccoon(get_turf(source)) + source.visible_message("A raccoon jumps out of the trash!.") + + // Check if we should delete on depletion + if(!loot_depletion) + return + loot_left-- + if(loot_left > 0) + return + to_chat(L, span_warning("You seem to have gotten the last of the spoils in \the [source].")) + if(delete_on_depletion) + 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) + var/path = pick(common_loot) + return new path(source) + +/datum/element/lootable/proc/produce_uncommon_item(atom/source) + var/path = pick(uncommon_loot) + return new path(source) + +/datum/element/lootable/proc/produce_rare_item(atom/source) + var/path = pick(rare_loot) + return new path(source) + +/// These are types that can only spawn once, and then will be removed from this list. +/datum/element/lootable/proc/produce_gamma_item(atom/source) + var/path = pick_n_take(GLOB.unique_gamma_loot) + if(!path) //Tapped out, reallocate? + for(var/P in GLOB.allocated_gamma_loot) + var/datum/weakref/WF = GLOB.allocated_gamma_loot[P] + var/obj/item/I = WF?.resolve() + if(QDELETED(I) || istype(I.loc,/obj/machinery/computer/cryopod)) + restore_gamma_loot(P) + path = P + break + + if(path) + var/obj/item/I = new path(source) + GLOB.allocated_gamma_loot[path] = WEAKREF(I) + return I + + return produce_rare_item(source) + +/// Restores a removed gamma loot item back to the loot table +/proc/restore_gamma_loot(var/w_type) + GLOB.allocated_gamma_loot -= w_type + GLOB.unique_gamma_loot += w_type diff --git a/code/datums/elements/lootable/boxes.dm b/code/datums/elements/lootable/boxes.dm new file mode 100644 index 00000000000..ed5488fe335 --- /dev/null +++ b/code/datums/elements/lootable/boxes.dm @@ -0,0 +1,82 @@ +// Contains loads of different types of boxes, which may have items inside! +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/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( + /obj/item/storage/box, + /obj/item/storage/box/beakers, + /obj/item/storage/box/botanydisk, + /obj/item/storage/box/cups, + /obj/item/storage/box/disks, + /obj/item/storage/box/donkpockets, + /obj/item/storage/box/donut, + /obj/item/storage/box/donut/empty, + /obj/item/storage/box/evidence, + /obj/item/storage/box/lights/mixed, + /obj/item/storage/box/lights/tubes, + /obj/item/storage/box/lights/bulbs, + /obj/item/storage/box/injectors, + /obj/item/storage/box/masks, + /obj/item/storage/box/ids, + /obj/item/storage/box/mousetraps, + /obj/item/storage/box/syringes, + /obj/item/storage/box/survival, + /obj/item/storage/box/gloves, + /obj/item/storage/box/PDAs + ) + + uncommon_loot = list( + /obj/item/storage/box/sinpockets, + /obj/item/ammo_magazine/ammo_box/b12g/practice, + /obj/item/ammo_magazine/ammo_box/b12g/blank, + /obj/item/storage/box/smokes, + /obj/item/storage/box/metalfoam, + /obj/item/storage/box/handcuffs, + /obj/item/storage/box/seccarts, + /obj/item/storage/box/old_syringes, + ) + + rare_loot = list( + /obj/item/storage/box/flashbangs, + /obj/item/storage/box/empslite, + /obj/item/ammo_magazine/ammo_box/b12g/flash, + /obj/item/ammo_magazine/ammo_box/b12g/stunshell, + /obj/item/storage/box/teargas + ) diff --git a/code/datums/elements/lootable/maint.dm b/code/datums/elements/lootable/maint.dm new file mode 100644 index 00000000000..3521a15fd00 --- /dev/null +++ b/code/datums/elements/lootable/maint.dm @@ -0,0 +1,332 @@ +// Has large amounts of possible items, most of which may or may not be useful. +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/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( + /obj/item/flashlight/flare, + /obj/item/flashlight/glowstick, + /obj/item/flashlight/glowstick/blue, + /obj/item/flashlight/glowstick/orange, + /obj/item/flashlight/glowstick/red, + /obj/item/flashlight/glowstick/yellow, + /obj/item/flashlight/pen, + /obj/item/cell, + /obj/item/cell/device, + /obj/item/clothing/mask/gas, + /obj/item/clothing/mask/gas/clear, // CHOMPAdd + /obj/item/clothing/mask/gas/half, + /obj/item/clothing/mask/breath, + /obj/item/reagent_containers/glass/rag, + /obj/item/reagent_containers/food/snacks/liquidfood, + /obj/item/storage/secure/briefcase, + /obj/item/storage/briefcase, + /obj/item/storage/backpack, + /obj/item/storage/backpack/satchel/norm, + /obj/item/storage/backpack/satchel, + /obj/item/storage/backpack/dufflebag, + /obj/item/storage/box, + /obj/item/storage/wallet, + /obj/item/clothing/shoes/galoshes, + /obj/item/clothing/shoes/black, + /obj/item/clothing/shoes/laceup, + /obj/item/clothing/shoes/laceup/grey, + /obj/item/clothing/shoes/laceup/brown, + /obj/item/clothing/gloves/botanic_leather, + /obj/item/clothing/gloves/sterile/latex, + /obj/item/clothing/gloves/white, + /obj/item/clothing/gloves/rainbow, + /obj/item/clothing/gloves/fyellow, + /obj/item/clothing/glasses/sunglasses, + /obj/item/clothing/glasses/meson, + /obj/item/clothing/glasses/meson/prescription, + /obj/item/clothing/glasses/welding, + /obj/item/clothing/head/bio_hood/general, + /obj/item/clothing/head/hardhat, + /obj/item/clothing/head/hardhat/red, + /obj/item/clothing/head/ushanka, + /obj/item/clothing/head/welding, + /obj/item/clothing/suit/storage/hazardvest, + /obj/item/clothing/suit/space/emergency, + /obj/item/clothing/suit/storage/toggle/bomber, + /obj/item/clothing/suit/bio_suit/general, + /obj/item/clothing/suit/storage/toggle/hoodie/black, + /obj/item/clothing/suit/storage/toggle/hoodie/blue, + /obj/item/clothing/suit/storage/toggle/hoodie/red, + /obj/item/clothing/suit/storage/toggle/hoodie/yellow, + /obj/item/clothing/suit/storage/toggle/brown_jacket, + /obj/item/clothing/suit/storage/toggle/leather_jacket, + /obj/item/clothing/suit/storage/apron, + /obj/item/clothing/under/color/grey, + /obj/item/clothing/under/syndicate/tacticool, + /obj/item/clothing/under/pants/camo, + /obj/item/clothing/under/harness, + /obj/item/clothing/accessory/storage/webbing, + /obj/item/spacecash/c1, + /obj/item/spacecash/c5, + /obj/item/spacecash/c10, + /obj/item/spacecash/c20, + /obj/item/camera_assembly, + /obj/item/clothing/suit/caution, + /obj/item/clothing/head/cone, + /obj/item/card/emag_broken, + /obj/item/camera, + /obj/item/pda, + /obj/item/radio/headset, + /obj/item/paicard, + /obj/item/reagent_containers/hypospray/autoinjector/biginjector/glucose, + /obj/item/reagent_containers/syringe/old + ) + + uncommon_loot = list( + /obj/item/clothing/shoes/syndigaloshes, + /obj/item/clothing/gloves/yellow, + /obj/item/clothing/under/tactical, + /obj/item/beartrap, + /obj/item/clothing/suit/storage/vest/press, + /obj/item/material/knife/tacknife, + /obj/item/material/butterfly/switchblade + ) + + rare_loot = list( + /obj/item/clothing/suit/storage/vest/heavy/merc, + /obj/item/clothing/shoes/boots/combat, + ) + + +// Contains mostly useless garbage. +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/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( + /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/reagent_containers/food/snacks/xenomeat/spidermeat, + /obj/item/reagent_containers/food/snacks/mysterysoup, + /obj/item/reagent_containers/food/snacks/old/hotdog, + /obj/item/pizzabox/old, + /obj/item/ammo_casing/spent, + /obj/item/stack/rods{amount = 5}, + /obj/item/stack/material/steel{amount = 5}, + /obj/item/stack/material/cardboard{amount = 5}, + /obj/item/poster, + /obj/item/poster/custom, + /obj/item/newspaper, + /obj/item/paper/crumpled, + /obj/item/paper/crumpled/bloody, + /obj/item/reagent_containers/syringe/old + ) + + uncommon_loot = list( + /obj/item/reagent_containers/syringe/steroid, + /obj/item/storage/pill_bottle/zoom, + /obj/item/storage/pill_bottle/happy, + /obj/item/storage/pill_bottle/paracetamol + ) + + +// One of the more useful maint piles, contains electrical components. +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/datum/element/lootable/maint/technical + common_loot = list( + /obj/item/stock_parts/gear, + /obj/item/stock_parts/console_screen, + /obj/item/stock_parts/spring, + /obj/item/stock_parts/capacitor, + /obj/item/stock_parts/capacitor/adv, + /obj/item/stock_parts/capacitor/super, + /obj/item/stock_parts/manipulator, + /obj/item/stock_parts/manipulator/nano, + /obj/item/stock_parts/manipulator/pico, + /obj/item/stock_parts/matter_bin, + /obj/item/stock_parts/matter_bin/adv, + /obj/item/stock_parts/matter_bin/super, + /obj/item/stock_parts/scanning_module, + /obj/item/stock_parts/scanning_module/adv, + /obj/item/stock_parts/scanning_module/phasic, + /obj/item/stock_parts/subspace/amplifier, + /obj/item/stock_parts/subspace/analyzer, + /obj/item/stock_parts/subspace/ansible, + /obj/item/stock_parts/subspace/crystal, + /obj/item/stock_parts/subspace/sub_filter, + /obj/item/stock_parts/subspace/transmitter, + /obj/item/stock_parts/subspace/treatment, + /obj/item/frame, + /obj/item/broken_device/random, + /obj/item/borg/upgrade/utility/restart, + /obj/item/cell, + /obj/item/cell/high, + /obj/item/cell/device, + /obj/item/circuitboard/broken, + /obj/item/circuitboard/arcade, + /obj/item/circuitboard/autolathe, + /obj/item/circuitboard/atmos_alert, + /obj/item/circuitboard/airalarm, + /obj/item/circuitboard/fax, + /obj/item/circuitboard/jukebox, + /obj/item/circuitboard/batteryrack, + /obj/item/circuitboard/message_monitor, + /obj/item/circuitboard/rcon_console, + /obj/item/smes_coil, + /obj/item/cartridge/engineering, + /obj/item/analyzer, + /obj/item/healthanalyzer, + /obj/item/extrapolator, + /obj/item/gene_scanner, + /obj/item/robotanalyzer, + /obj/item/lightreplacer, + /obj/item/radio, + /obj/item/hailer, + /obj/item/gps, + /obj/item/geiger, + /obj/item/mass_spectrometer, + /obj/item/tool/wrench, + /obj/item/tool/screwdriver, + /obj/item/tool/wirecutters, + /obj/item/mining_scanner/advanced, + /obj/item/multitool, + /obj/item/mecha_parts/mecha_equipment/generator, + /obj/item/mecha_parts/mecha_equipment/tool/cable_layer, + /obj/item/mecha_parts/mecha_equipment/tool/drill, + /obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp, + /obj/item/mecha_parts/mecha_equipment/tool/passenger, + /obj/item/mecha_parts/mecha_equipment/tool/sleeper, + /obj/item/mecha_parts/mecha_equipment/tool/syringe_gun, + /obj/item/robot_parts/robot_component/binary_communication_device, + /obj/item/robot_parts/robot_component/armour, + /obj/item/robot_parts/robot_component/actuator, + /obj/item/robot_parts/robot_component/camera, + /obj/item/robot_parts/robot_component/diagnosis_unit, + /obj/item/robot_parts/robot_component/radio + ) + + uncommon_loot = list( + /obj/item/cell/super, + /obj/item/cell/device/weapon, + /obj/item/circuitboard/security, + /obj/item/circuitboard/crew, + /obj/item/aiModule/reset, + /obj/item/smes_coil/super_capacity, + /obj/item/smes_coil/super_io, + /obj/item/cartridge/captain, + /obj/item/disk/integrated_circuit/upgrade/advanced, + /obj/item/tvcamera, + /obj/item/universal_translator, + /obj/item/aicard, + /obj/item/borg/upgrade/advanced/jetpack, + /obj/item/borg/upgrade/advanced/advhealth, + /obj/item/borg/upgrade/basic/vtec, + /obj/item/borg/upgrade/restricted/tasercooler, + /obj/item/mecha_parts/mecha_equipment/weapon/energy/riggedlaser, + /obj/item/mecha_parts/mecha_equipment/tool/drill/diamonddrill, + /obj/item/rig_module/device/drill, + /obj/item/rig_module/device/plasmacutter, + /obj/item/rig_module/device/healthscanner, + /obj/item/rig_module/device/orescanner, + /obj/item/rig_module/device/anomaly_scanner, + /obj/item/rig_module/datajack, + /obj/item/rig_module/vision/medhud, + /obj/item/rig_module/vision/meson, + /obj/item/rig_module/vision/sechud, + /obj/item/rig_module/sprinter + ) + + rare_loot = list( + /obj/item/cell/hyper, + /obj/item/aiModule/freeform, + /obj/item/aiModule/asimov, + /obj/item/aiModule/paladin, + /obj/item/aiModule/safeguard, + /obj/item/disposable_teleporter, + /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay + ) diff --git a/code/datums/elements/lootable/trash.dm b/code/datums/elements/lootable/trash.dm new file mode 100644 index 00000000000..29679e4971c --- /dev/null +++ b/code/datums/elements/lootable/trash.dm @@ -0,0 +1,200 @@ +// Special loot pile that uses gamma items. These spawn only once! +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/datum/element/lootable/trash_pile + chance_uncommon = 20 + chance_rare = 2 + 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( + /obj/item/clothing/gloves/rainbow, + /obj/item/clothing/gloves/white, + /obj/item/storage/backpack, + /obj/item/storage/backpack/satchel/norm, + /obj/item/storage/box, + // /obj/random/cigarettes, + /obj/item/broken_device/random, + /obj/item/clothing/head/hardhat, + /obj/item/clothing/mask/breath, + /obj/item/clothing/shoes/black, + /obj/item/clothing/shoes/black, + /obj/item/clothing/shoes/laceup, + /obj/item/clothing/shoes/laceup/brown, + /obj/item/clothing/suit/storage/hazardvest, + /obj/item/clothing/under/color/grey, + /obj/item/clothing/suit/caution, + /obj/item/cell, + /obj/item/cell/device, + /obj/item/reagent_containers/food/snacks/liquidfood, + /obj/item/spacecash/c1, + /obj/item/storage/backpack/satchel, + /obj/item/storage/briefcase, + /obj/item/clothing/accessory/storage/webbing, + /obj/item/clothing/glasses/meson, + /obj/item/clothing/gloves/botanic_leather, + /obj/item/clothing/head/hardhat/red, + /obj/item/clothing/mask/gas, + /obj/item/clothing/mask/gas/clear, // CHOMPAdd + /obj/item/clothing/suit/storage/apron, + /obj/item/clothing/suit/storage/toggle/bomber, + /obj/item/clothing/suit/storage/toggle/brown_jacket, + /obj/item/clothing/suit/storage/toggle/hoodie/black, + /obj/item/clothing/suit/storage/toggle/hoodie/blue, + /obj/item/clothing/suit/storage/toggle/hoodie/red, + /obj/item/clothing/suit/storage/toggle/hoodie/yellow, + /obj/item/clothing/suit/storage/toggle/leather_jacket, + /obj/item/pda, + /obj/item/radio/headset, + /obj/item/camera_assembly, + /obj/item/clothing/head/cone, + /obj/item/cell/high, + /obj/item/spacecash/c10, + /obj/item/spacecash/c20, + /obj/item/storage/backpack/dufflebag, + /obj/item/storage/box/donkpockets, + /obj/item/storage/box/mousetraps, + /obj/item/storage/wallet) + + uncommon_loot = list( + /obj/item/clothing/glasses/meson/prescription, + /obj/item/clothing/gloves/fyellow, + /obj/item/clothing/gloves/sterile/latex, + /obj/item/clothing/head/welding, + /obj/item/clothing/mask/gas/half, + /obj/item/clothing/shoes/galoshes, + /obj/item/clothing/under/pants/camo, + /obj/item/clothing/under/syndicate/tacticool, + /obj/item/clothing/under/hyperfiber, + /obj/item/camera, + /obj/item/flashlight/flare, + /obj/item/flashlight/glowstick, + /obj/item/flashlight/glowstick/blue, + /obj/item/card/emag_broken, + /obj/item/cell/super, + /obj/item/poster, + /obj/item/reagent_containers/glass/rag, + /obj/item/storage/box/sinpockets, + /obj/item/storage/secure/briefcase, + /obj/item/clothing/under/fluff/latexmaid, + /obj/item/toy/tennis, + /obj/item/toy/tennis/red, + /obj/item/toy/tennis/yellow, + /obj/item/toy/tennis/green, + /obj/item/toy/tennis/cyan, + /obj/item/toy/tennis/blue, + /obj/item/toy/tennis/purple, + /obj/item/toy/baseball, + /obj/item/storage/box/brainzsnax, + /obj/item/storage/box/brainzsnax/red, + /obj/item/clothing/glasses/sunglasses, + /obj/item/clothing/glasses/sunglasses/bigshot, + /obj/item/clothing/glasses/welding, + /obj/item/clothing/gloves/yellow, + /obj/item/clothing/head/bio_hood/general, + /obj/item/clothing/head/ushanka, + /obj/item/clothing/shoes/syndigaloshes, + /obj/item/clothing/suit/bio_suit/general, + /obj/item/clothing/suit/space/emergency, + /obj/item/clothing/under/harness, + /obj/item/clothing/under/tactical, + /obj/item/clothing/suit/armor/material/makeshift, + /obj/item/flashlight/glowstick/orange, + /obj/item/flashlight/glowstick/red, + /obj/item/flashlight/glowstick/yellow, + /obj/item/flashlight/pen, + /obj/item/paicard, + /obj/item/clothing/accessory/permit/gun, + /obj/item/clothing/mask/gas/voice, + /obj/item/spacecash/c100, + /obj/item/spacecash/c50, + /obj/item/storage/backpack/dufflebag/syndie, + /obj/item/storage/box/cups) + + rare_loot = list( + /obj/item/pizzavoucher, + /obj/item/card/emag, // CHOMPAdd + /obj/item/storage/pill_bottle/paracetamol, + /obj/item/storage/pill_bottle/happy, + /obj/item/storage/pill_bottle/zoom, + /obj/item/seeds/ambrosiavulgarisseed, + /obj/item/gun/energy/sizegun, + /obj/item/slow_sizegun, + /obj/item/clothing/accessory/collar/shock/bluespace, + /obj/item/cracker, + /obj/item/material/butterfly, + /obj/item/material/butterfly/switchblade, + /obj/item/clothing/accessory/knuckledusters, + /obj/item/clothing/gloves/heavy_engineer, + /obj/item/reagent_containers/syringe/drugs, + /obj/item/reagent_containers/syringe/old, + /obj/item/implanter/sizecontrol, + /obj/item/handcuffs/fuzzy, + /obj/item/handcuffs/legcuffs/fuzzy, + /obj/item/storage/box/syndie_kit/spy, + /obj/item/grenade/anti_photon, + /obj/item/clothing/under/hyperfiber/bluespace, + /obj/item/selectable_item/chemistrykit/size, + /obj/item/selectable_item/chemistrykit/gender, + /obj/item/clothing/gloves/bluespace/emagged, + /obj/item/reagent_containers/glass/beaker/vial/sustenance, + /obj/item/clothing/suit/storage/vest/heavy/merc, + /obj/item/nif/bad, + /obj/item/radio_jammer, + /obj/item/sleevemate, + /obj/item/bodysnatcher, + /obj/item/mindbinder, // CHOMPAdd + /obj/item/beartrap, + /obj/item/cell/hyper/empty, + /obj/item/disk/nifsoft/compliance, + /obj/item/implanter/compliance, + /obj/item/material/knife/tacknife, + /obj/item/storage/box/survival/space, + /obj/item/storage/secure/briefcase/trashmoney, + /obj/item/survivalcapsule/popcabin, + /obj/item/reagent_containers/syringe/steroid, + /obj/item/capture_crystal, + /obj/item/perfect_tele/one_beacon, + /obj/item/clothing/gloves/bluespace, + /obj/item/gun/energy/mouseray, + /obj/item/clothing/accessory/collar/shock/bluespace/modified, + /obj/item/gun/energy/sizegun/backfire, + /obj/item/grenade/spawnergrenade/clustaur, // CHOMPAdd + /obj/item/storage/box/monkeycubes, + /obj/item/storage/box/monkeycubes/pets/NT_standard, + /obj/item/storage/box/monkeycubes/pets/NT_special) diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index be4c2c5caab..427d4d72bed 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -441,7 +441,7 @@ var/list/mob/living/forced_ambiance_list = new if(istype(get_turf(mob), /turf/space)) // Can't fall onto nothing. return - if(istype(mob,/mob/living/carbon/human/)) + if(ishuman(mob)) var/mob/living/carbon/human/H = mob if(H.buckled) return // Being buckled to something solid keeps you in place. @@ -459,6 +459,11 @@ var/list/mob/living/forced_ambiance_list = new H.AdjustStunned(1) // CHOMPedit: No longer a supermassive long stun. // H.AdjustWeakened(3) // CHOMPedit: No longer weakens. 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) /area/proc/prison_break(break_lights = TRUE, open_doors = TRUE, open_blast_doors = FALSE) //CHOMP Edit set blast doors to FALSE diff --git a/code/game/gamemodes/changeling/powers/bioelectrogenesis.dm b/code/game/gamemodes/changeling/powers/bioelectrogenesis.dm index bdbebb740de..46a948f8ad9 100644 --- a/code/game/gamemodes/changeling/powers/bioelectrogenesis.dm +++ b/code/game/gamemodes/changeling/powers/bioelectrogenesis.dm @@ -45,7 +45,7 @@ if(G.affecting) 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. - 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") diff --git a/code/game/gamemodes/events/clang.dm b/code/game/gamemodes/events/clang.dm index b55250f523a..06c0aed147d 100644 --- a/code/game/gamemodes/events/clang.dm +++ b/code/game/gamemodes/events/clang.dm @@ -15,10 +15,31 @@ In my current plan for it, 'solid' will be defined as anything with density == 1 throwforce = 100 density = TRUE anchored = TRUE +<<<<<<< HEAD +======= + movement_type = UNSTOPPABLE + var/turf/despawn_loc = null + var/has_hunted_unlucky = FALSE + +/obj/effect/immovablerod/proc/TakeFlight(var/turf/end) + despawn_loc = end + walk_towards(src, despawn_loc, 1) + explosion(loc, 2, 3, 5) // start out with a bang + + // Get steps needed and then await that to despawn + var/despawn_time = sqrt(((end.x - loc.x)**2) + ((end.y - loc.y)**2)) // distance of a line... + QDEL_IN(src, despawn_time + 5 SECONDS) //Give a small extra time before we disappear entirely. +>>>>>>> b8fe8fa68d ([MIRROR] Unlucky trait (#11775)) /obj/effect/immovablerod/Bump(atom/clong) if(istype(clong, /turf/simulated/shuttle)) //Skip shuttles without actually deleting the rod return +<<<<<<< HEAD +======= + + if(prob(10) && !has_hunted_unlucky) + hunt_unlucky() +>>>>>>> b8fe8fa68d ([MIRROR] Unlucky trait (#11775)) else if (istype(clong, /turf) && !istype(clong, /turf/unsimulated)) if(clong.density) @@ -41,6 +62,13 @@ In my current plan for it, 'solid' will be defined as anything with density == 1 if(clong && prob(25)) src.loc = clong.loc +<<<<<<< HEAD +======= +/obj/effect/immovablerod/proc/resume_path() + walk(src, 0) + walk_towards(src, despawn_loc, 1) + +>>>>>>> b8fe8fa68d ([MIRROR] Unlucky trait (#11775)) /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. return ..() diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index d8cd36a4d06..d839f5340ac 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -1419,13 +1419,13 @@ About the new airlock wires panel: adjustBruteLoss(crush_damage) return 0 -/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)) return 0 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/atom/movable/AM in turf) if(AM.blocks_airlock()) @@ -1437,8 +1437,8 @@ About the new airlock wires panel: for(var/turf/turf in locs) for(var/atom/movable/AM in turf) - if(AM.airlock_crush(DOOR_CRUSH_DAMAGE)) - take_damage(DOOR_CRUSH_DAMAGE) + if(AM.airlock_crush(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 has_beeped = 0 diff --git a/code/game/machinery/doors/airlock_control.dm b/code/game/machinery/doors/airlock_control.dm index a66d2bc7729..e7d4559e7aa 100644 --- a/code/game/machinery/doors/airlock_control.dm +++ b/code/game/machinery/doors/airlock_control.dm @@ -128,9 +128,9 @@ 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) diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 597e1384910..1ac7891a3ab 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -437,7 +437,7 @@ open_speed = 15 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)) return operating = 1 diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm index a24c64ea3f0..16e1196a23a 100644 --- a/code/game/machinery/recharger.dm +++ b/code/game/machinery/recharger.dm @@ -115,6 +115,50 @@ return //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() G.loc = src charging = G diff --git a/code/game/machinery/washing_machine.dm b/code/game/machinery/washing_machine.dm index 256dc07f4b1..0d827933566 100644 --- a/code/game/machinery/washing_machine.dm +++ b/code/game/machinery/washing_machine.dm @@ -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 name = "Washing Machine" desc = "Not a hiding place. Unfit for pets." @@ -9,19 +19,9 @@ clickvol = 40 circuit = /obj/item/circuitboard/washing - var/state = 1 - //1 = empty, open door - //2 = empty, closed door - //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/state = EMPTY_OPEN + var/hacked = TRUE //Bleh, screw hacking, let's have it hacked by default. + var/gibs_ready = FALSE var/obj/crayon var/list/washing = list() var/list/disallowed_types = list( @@ -33,6 +33,14 @@ . = ..() default_apply_parts() +/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() start() @@ -42,23 +50,31 @@ set src in oview(1) 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 - - if(state != 4) - to_chat(usr, "The washing machine cannot run in this state.") + if(!damage_modifier) + damage_modifier = 0.5 + if(state != FULL_CLOSED) + visible_message("The washing machine buzzes - it can not run in this state!") return if(locate(/mob,washing)) - state = 8 + state = BLOODY_RUNNING else - state = 5 + state = RUNNING 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) +<<<<<<< HEAD sleep(200) +======= + + addtimer(CALLBACK(src, PROC_REF(finish_wash), damage_modifier), 2 SECONDS) + +/obj/machinery/washing_machine/proc/finish_wash(damage_modifier) +>>>>>>> b8fe8fa68d ([MIRROR] Unlucky trait (#11775)) for(var/atom/A in washing) A.clean_blood() @@ -73,22 +89,55 @@ HH.use(HH.get_amount()) washing += WL - - if(locate(/mob,washing)) - state = 7 - gibs_ready = 1 + 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(has_mobs) + state = BLOODY_CLOSED + gibs_ready = TRUE else - state = 4 + state = FULL_CLOSED update_icon() /obj/machinery/washing_machine/verb/climb_out() set name = "Climb out" set category = "Object" set src in usr.loc + user_climb_out(usr) +<<<<<<< HEAD sleep(20) if(state in list(1,3,6)) usr.loc = src.loc +======= +/obj/machinery/washing_machine/proc/user_climb_out(mob/user) + 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) +>>>>>>> b8fe8fa68d ([MIRROR] Unlucky trait (#11775)) /obj/machinery/washing_machine/update_icon() //VOREStation Edit @@ -99,7 +148,7 @@ //VOREStation Edit End /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)) return if(default_deconstruction_crowbar(user, W)) @@ -110,22 +159,30 @@ panel = !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(state in list( 1, 3, 6)) + if(state in list (EMPTY_OPEN, FULL_OPEN, BLOODY_OPEN)) if(!crayon) user.drop_item() crayon = W + crayon.forceMove(src) crayon.loc = src else ..() else ..() else if(istype(W,/obj/item/grab)) - if((state == 1) && hacked) + if((state == EMPTY_OPEN) && hacked) var/obj/item/grab/G = W - if(ishuman(G.assailant) && iscorgi(G.affecting)) - G.affecting.loc = src - qdel(G) - state = 3 + if(ishuman(G.assailant) && (iscorgi(G.affecting) || ishuman(G.affecting))) + user.visible_message("[user] begins stuffing [G.affecting] into the [src]!", "You begin stuffing [G.affecting] into the [src]!") + if(do_after(user, 5 SECONDS, target = src)) + 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 ..() @@ -135,11 +192,11 @@ else if(istype(W, /obj/item/clothing) || istype(W, /obj/item/bedsheet) || istype(W, /obj/item/stack/hairlesshide)) if(washing.len < 5) - if(state in list(1, 3)) + if(state in list(EMPTY_OPEN, FULL_OPEN)) user.drop_item() - W.loc = src + W.forceMove(src) washing += W - state = 3 + state = FULL_OPEN else to_chat(user, span_notice("You can't put the item in right now.")) else @@ -148,38 +205,50 @@ ..() 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) - if(1) - state = 2 - if(2) - state = 1 + if(EMPTY_OPEN) + state = EMPTY_CLOSED + if(EMPTY_CLOSED) + state = EMPTY_OPEN for(var/atom/movable/O in washing) - O.loc = src.loc + O.forceMove(get_turf(src)) washing.Cut() - if(3) - state = 4 - if(4) - state = 3 + if(FULL_OPEN) + state = FULL_CLOSED + if(FULL_CLOSED) for(var/atom/movable/O in washing) - O.loc = src.loc + O.forceMove(get_turf(src)) crayon = null washing.Cut() - state = 1 - if(5) - to_chat(user, span_warning("The [src] is busy.")) - if(6) - state = 7 - if(7) + state = EMPTY_OPEN + if(RUNNING) + if(user) + to_chat(user, span_warning("The [src] is busy.")) + if(BLOODY_OPEN) + state = BLOODY_CLOSED + if(BLOODY_CLOSED) if(gibs_ready) - gibs_ready = 0 - if(locate(/mob,washing)) - var/mob/M = locate(/mob,washing) - M.gib() + gibs_ready = FALSE + for(var/mob/living/mobs in washing) + if(ishuman(mobs)) //Humans have special handling. + continue + mobs.gib() for(var/atom/movable/O in washing) - O.loc = src.loc + O.forceMove(get_turf(src)) crayon = null - state = 1 + state = EMPTY_OPEN washing.Cut() 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 diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index ceb297cb408..5752cb94a3a 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -398,6 +398,11 @@ // called just as an item is picked up (loc is not yet changed) /obj/item/proc/pickup(mob/user) +<<<<<<< HEAD +======= + SEND_SIGNAL(src, COMSIG_ITEM_PICKUP, user) + SEND_SIGNAL(user, COMSIG_PICKED_UP_ITEM, src) +>>>>>>> b8fe8fa68d ([MIRROR] Unlucky trait (#11775)) pixel_x = 0 pixel_y = 0 return diff --git a/code/game/objects/items/devices/defib.dm b/code/game/objects/items/devices/defib.dm index 15dfbd14e1f..2512fc5df62 100644 --- a/code/game/objects/items/devices/defib.dm +++ b/code/game/objects/items/devices/defib.dm @@ -432,6 +432,10 @@ return 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 var/barely_in_crit = H.get_crit_point() - 1 @@ -480,7 +484,7 @@ playsound(src, 'sound/weapons/egloves.ogg', 100, 1, -1) 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) if(burn_damage > 15 && H.can_feel_pain()) H.emote("scream") diff --git a/code/game/objects/items/weapons/grenades/flashbang.dm b/code/game/objects/items/weapons/grenades/flashbang.dm index 5c80944dad4..f391969bff8 100644 --- a/code/game/objects/items/weapons/grenades/flashbang.dm +++ b/code/game/objects/items/weapons/grenades/flashbang.dm @@ -162,3 +162,10 @@ walk_away(src,temploc,stepdist) 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() diff --git a/code/game/objects/items/weapons/grenades/smokebomb.dm b/code/game/objects/items/weapons/grenades/smokebomb.dm index cd68ca3f3ac..3a012ae99ae 100644 --- a/code/game/objects/items/weapons/grenades/smokebomb.dm +++ b/code/game/objects/items/weapons/grenades/smokebomb.dm @@ -37,3 +37,10 @@ var/new_smoke_color = tgui_color_picker(user, "Choose a color for the smoke:", "Smoke Color", smoke_color) if(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() diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm index 4eef86942aa..644830c8342 100644 --- a/code/game/objects/items/weapons/stunbaton.dm +++ b/code/game/objects/items/weapons/stunbaton.dm @@ -205,7 +205,7 @@ //stun effects 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].") if(ishuman(target)) diff --git a/code/game/objects/mail.dm b/code/game/objects/mail.dm index dc5036bc008..137e399ba66 100644 --- a/code/game/objects/mail.dm +++ b/code/game/objects/mail.dm @@ -216,6 +216,13 @@ user.put_in_hands(stuff) else 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) qdel(src) diff --git a/code/modules/blob2/overmind/types/energized_jelly.dm b/code/modules/blob2/overmind/types/energized_jelly.dm index a73d0f0b9a3..0f715474e8e 100644 --- a/code/modules/blob2/overmind/types/energized_jelly.dm +++ b/code/modules/blob2/overmind/types/energized_jelly.dm @@ -22,7 +22,7 @@ /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.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) for(var/mob/living/L in oview(world.view, get_turf(B))) diff --git a/code/modules/economy/vending.dm b/code/modules/economy/vending.dm index 73bfd7af94c..68f56f51c5e 100644 --- a/code/modules/economy/vending.dm +++ b/code/modules/economy/vending.dm @@ -585,6 +585,13 @@ GLOBAL_LIST_EMPTY(vending_products) 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) + 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)) if(has_logs) do_logging(R, user, 1) @@ -743,9 +750,11 @@ GLOBAL_LIST_EMPTY(vending_products) return //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/mob/living/target = locate() in view(7,src) + if(forced_target && isliving(forced_target)) + target = forced_target if(!target) return 0 diff --git a/code/modules/emotes/definitions/audible_snap.dm b/code/modules/emotes/definitions/audible_snap.dm index 4e9e3140306..04d156078d6 100644 --- a/code/modules/emotes/definitions/audible_snap.dm +++ b/code/modules/emotes/definitions/audible_snap.dm @@ -27,3 +27,16 @@ to_chat(user, span_warning("You need at least one working hand to snap your fingers.")) 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 diff --git a/code/modules/games/dice.dm b/code/modules/games/dice.dm index 7e94bcc4e62..d2d9dc2cc3a 100644 --- a/code/modules/games/dice.dm +++ b/code/modules/games/dice.dm @@ -91,10 +91,10 @@ sides = 10 result = 10 -/obj/item/dice/attack_self(mob/user as mob) +/obj/item/dice/attack_self(mob/user) 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) if(loaded) if(cheater) @@ -103,6 +103,9 @@ else if(prob(75)) //makeshift weighted dice don't always work result = loaded 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) var/comment = "" @@ -165,18 +168,18 @@ /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]."), \ span_notice("You shake [src]."), \ span_notice("You hear dice rolling.")) 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) var/obj/item/dice/D = I 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) var/obj/item/dice/D = I to_chat(viewer, "The [D.name] shows a [D.result].") @@ -203,3 +206,40 @@ . = ..() for(var/i = 1 to 5) 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,\ + ) diff --git a/code/modules/mob/living/bot/secbot.dm b/code/modules/mob/living/bot/secbot.dm index a7edaf539a4..fccf82f7f92 100644 --- a/code/modules/mob/living/bot/secbot.dm +++ b/code/modules/mob/living/bot/secbot.dm @@ -323,7 +323,7 @@ if(!H.lying || H.handcuffed || arrest_type) cuff = FALSE 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) do_attack_animation(H) busy = TRUE diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index bdc7ff56c28..f6c94741d9d 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -379,8 +379,9 @@ return /mob/living/carbon/slip(var/slipped_on,stun_duration=8) + SEND_SIGNAL(src, COMSIG_ON_CARBON_SLIP, slipped_on, stun_duration) if(buckled) - return 0 + return FALSE stop_pulling() to_chat(src, span_warning("You slipped on [slipped_on]!")) playsound(src, 'sound/misc/slip.ogg', 50, 1, -3) @@ -389,7 +390,7 @@ src.emote("sflip") return 1 //CHOMPEdit End Weaken(FLOOR(stun_duration/2, 1)) - return 1 + return TRUE /mob/living/carbon/proc/add_chemical_effect(var/effect, var/magnitude = 1) if(effect in chem_effects) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index e62894ba42c..02f1d1dc03b 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1503,12 +1503,12 @@ if(lying) playsound(src, 'sound/misc/slip.ogg', 25, 1, -1) 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. - return 0 + return FALSE if(..(slipped_on,stun_duration)) drop_both_hands() - return 1 + return TRUE /mob/living/carbon/human/proc/relocate() set category = "Object" diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 73553d27c35..4023405af00 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -58,7 +58,7 @@ emp_act 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/siemens_coeff = get_siemens_coefficient_organ(affected) 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 ") 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) var/armorval = 0 @@ -434,8 +434,8 @@ emp_act return if(in_throw_mode && speed <= THROWFORCE_SPEED_DIVISOR) //empty active hand and we're in throw mode if(canmove && !restrained() && !src.is_incorporeal()) - if(isturf(O.loc)) - if(can_catch(O)) + if(isturf(O.loc) && can_catch(O)) + if(!SEND_SIGNAL(src, COMSIG_HUMAN_ON_CATCH_THROW, source, speed)) put_in_active_hand(O) visible_message(span_warning("[src] catches [O]!")) throw_mode_off() diff --git a/code/modules/mob/living/carbon/human/species/station/traits/negative.dm b/code/modules/mob/living/carbon/human/species/station/traits/negative.dm index d85b1034103..113ae9eda9b 100644 --- a/code/modules/mob/living/carbon/human/species/station/traits/negative.dm +++ b/code/modules/mob/living/carbon/human/species/station/traits/negative.dm @@ -761,3 +761,93 @@ cost = 0 category = 0 custom_only = FALSE +<<<<<<< HEAD +======= + +/datum/trait/negative/photodegeneration + name = "Photodegeneration" + desc = "Without the protection of darkness or a suit your body quickly begins to break down when exposed to light." + cost = -4 + is_genetrait = TRUE // There is no upside, a neat landmine for genetics + hidden = TRUE //Disabled on Virgo + can_take = ORGANICS + added_component_path = /datum/component/burninlight // Literally just Zaddat, but you don't start with any suit. Good luck. + +// Addictions +/datum/trait/neutral/addiction_alcohol + name = "Addiction - Alcohol" + desc = "You have become chemically dependant to any alcoholic drink, and need to regularly consume it or suffer withdrawals." + addiction = REAGENT_ID_ETHANOL + custom_only = FALSE + hidden = TRUE //Disabled on Virgo + +/datum/trait/neutral/addiction_bliss + name = "Addiction - " + REAGENT_BLISS + desc = "You have become chemically dependant to " + REAGENT_BLISS + ", and need to regularly consume it or suffer withdrawals." + addiction = REAGENT_ID_BLISS + custom_only = FALSE + hidden = TRUE //Disabled on Virgo + +/datum/trait/neutral/addiction_coffee + name = "Addiction - " + REAGENT_COFFEE + desc = "You have become chemically dependant to " + REAGENT_COFFEE + ", and need to regularly consume it or suffer withdrawals." + addiction = REAGENT_ID_COFFEE + custom_only = FALSE + +/datum/trait/neutral/addiction_hyper + name = "Addiction - " + REAGENT_HYPERZINE + desc = "You have become chemically dependant to " + REAGENT_HYPERZINE + ", and need to regularly consume it or suffer withdrawals." + addiction = REAGENT_ID_HYPERZINE + custom_only = FALSE + hidden = TRUE //Disabled on Virgo + +/datum/trait/neutral/addiction_nicotine + name = "Addiction - " + REAGENT_NICOTINE + desc = "You have become chemically dependant to " + REAGENT_NICOTINE + ", and need to regularly consume it or suffer withdrawals." + addiction = REAGENT_ID_NICOTINE + custom_only = FALSE + +/datum/trait/neutral/addiction_oxy + name = "Addiction - " + REAGENT_OXYCODONE + desc = "You have become chemically dependant to " + REAGENT_OXYCODONE + ", and need to regularly consume it or suffer withdrawals." + addiction = REAGENT_ID_OXYCODONE + custom_only = FALSE + hidden = TRUE //Disabled on Virgo + +/datum/trait/neutral/addiction_painkiller + name = "Addiction - Pain Killers" + desc = "You have become chemically dependant to " + REAGENT_TRAMADOL + ", and need to regularly consume it or suffer withdrawals." + addiction = REAGENT_ID_TRAMADOL + custom_only = FALSE + hidden = TRUE //Disabled on Virgo + +/datum/trait/neutral/addiction_asustenance + name = "Unstable Vat Grown Body" + desc = "You are chemically dependant to " + REAGENT_ASUSTENANCE + ", and need to regularly consume it or your body decays." + addiction = REAGENT_ID_ASUSTENANCE + custom_only = FALSE + 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!") +>>>>>>> b8fe8fa68d ([MIRROR] Unlucky trait (#11775)) diff --git a/code/modules/mob/living/carbon/human/species/virtual_reality/avatar.dm b/code/modules/mob/living/carbon/human/species/virtual_reality/avatar.dm index e049ce6f781..03a1248d9d6 100644 --- a/code/modules/mob/living/carbon/human/species/virtual_reality/avatar.dm +++ b/code/modules/mob/living/carbon/human/species/virtual_reality/avatar.dm @@ -116,7 +116,7 @@ // Getting hurt in VR doesn't damage the physical body, but you still got hurt. if(ishuman(vr_holder) && total_damage) 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 // Maintain a link with the mob, but don't use teleop diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 5887c3ad9c5..e9357e492ed 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -128,7 +128,7 @@ //Stun Beams 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) 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) @@ -148,8 +148,9 @@ // return absorb //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() + SEND_SIGNAL(src, COMSIG_STUN_EFFECT_ACT, stun_amount, agony_amount, def_zone, used_weapon, electric) if (stun_amount) Stun(stun_amount) diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 7cea3d96974..bdf85f71f30 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -81,7 +81,7 @@ 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 /mob/living/silicon/electrocute_act(var/shock_damage, var/obj/source, var/siemens_coeff = 0.0, var/def_zone = null, var/stun = 1) diff --git a/code/modules/mob/living/simple_mob/defense.dm b/code/modules/mob/living/simple_mob/defense.dm index 4e42d6c7adc..0018539fe97 100644 --- a/code/modules/mob/living/simple_mob/defense.dm +++ b/code/modules/mob/living/simple_mob/defense.dm @@ -190,9 +190,14 @@ . = min(., 1.0) // Electricity +<<<<<<< HEAD /mob/living/simple_mob/electrocute_act(var/shock_damage, var/obj/source, var/siemens_coeff = 1.0, var/def_zone = null) var/zap = min((1-get_shock_protection()), siemens_coeff) //CHOMPEdit - for some reason simple mobs just never properly checked for shock resist? Whatever, take whichever is lower. shock_damage *= zap +======= +/mob/living/simple_mob/electrocute_act(var/shock_damage, var/obj/source, var/siemens_coeff = 1.0, var/def_zone = null, var/stun = 1) + shock_damage *= siemens_coeff +>>>>>>> b8fe8fa68d ([MIRROR] Unlucky trait (#11775)) if(shock_damage < 1) return 0 @@ -217,7 +222,7 @@ . = min(., 1.0) // 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) var/stunDam = 0 var/agonyDam = 0 diff --git a/code/modules/mob/living/simple_mob/subtypes/slime/xenobio/defense.dm b/code/modules/mob/living/simple_mob/subtypes/slime/xenobio/defense.dm index 4de155da2d2..e7d3b53545a 100644 --- a/code/modules/mob/living/simple_mob/subtypes/slime/xenobio/defense.dm +++ b/code/modules/mob/living/simple_mob/subtypes/slime/xenobio/defense.dm @@ -44,7 +44,7 @@ adjust_discipline(2) // Justified. // 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) to_chat(src, span_notice("\The [source] shocks you, and it charges you.")) diff --git a/code/modules/modular_computers/computers/modular_computer/interaction.dm b/code/modules/modular_computers/computers/modular_computer/interaction.dm index 9e9e56156f3..1647bf65ec0 100644 --- a/code/modules/modular_computers/computers/modular_computer/interaction.dm +++ b/code/modules/modular_computers/computers/modular_computer/interaction.dm @@ -116,8 +116,19 @@ // On-click handling. Turns on the computer if it's off and opens the GUI. /obj/item/modular_computer/attack_self(var/mob/user) 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) 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) /obj/item/modular_computer/attackby(var/obj/item/W, var/mob/user) diff --git a/code/modules/multiz/stairs.dm b/code/modules/multiz/stairs.dm index 8ef370ceae6..7e5e34f56eb 100644 --- a/code/modules/multiz/stairs.dm +++ b/code/modules/multiz/stairs.dm @@ -193,7 +193,7 @@ var/mob/living/L = P if(L.client) L.client.Process_Grab() // Update any miscellanous grabs, possibly break grab-chains - + SEND_SIGNAL(AM, COMSIG_MOVED_UP_STAIRS, AM, oldloc) return TRUE /obj/structure/stairs/bottom/use_stairs_instant(var/atom/movable/AM) @@ -231,6 +231,7 @@ L.client.Process_Grab() else AM.forceMove(get_turf(top)) + SEND_SIGNAL(AM, COMSIG_MOVED_UP_STAIRS, AM) ////////////////////////////////////////////////////////////////////// @@ -453,7 +454,7 @@ var/mob/living/L = P if(L.client) L.client.Process_Grab() // Update any miscellanous grabs, possibly break grab-chains - + SEND_SIGNAL(AM, COMSIG_MOVED_DOWN_STAIRS, AM, oldloc) return TRUE /obj/structure/stairs/top/use_stairs_instant(var/atom/movable/AM) @@ -490,6 +491,7 @@ L.client.Process_Grab() else AM.forceMove(get_turf(bottom)) + SEND_SIGNAL(AM, COMSIG_MOVED_DOWN_STAIRS, AM) // Mapping pieces, placed at the bottommost part of the stairs /obj/structure/stairs/spawner diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm index 312bd925cbb..0616a9bba32 100644 --- a/code/modules/power/lighting.dm +++ b/code/modules/power/lighting.dm @@ -869,7 +869,7 @@ var/global/list/light_type_cache = list() // 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) return diff --git a/code/modules/power/lighting_vr.dm b/code/modules/power/lighting_vr.dm index 83b6a308d7a..1d186cfc12d 100644 --- a/code/modules/power/lighting_vr.dm +++ b/code/modules/power/lighting_vr.dm @@ -166,7 +166,7 @@ overlay_above_everything = TRUE color = "#3e5064" -/obj/machinery/light/small/fairylights/broken() +/obj/machinery/light/small/fairylights/broken(var/skip_sound_and_sparks = FALSE) return /obj/machinery/light/small/fairylights/flicker diff --git a/code/modules/projectiles/guns/energy/cyborg.dm b/code/modules/projectiles/guns/energy/cyborg.dm index 7f895cc6600..3d6592d78a3 100644 --- a/code/modules/projectiles/guns/energy/cyborg.dm +++ b/code/modules/projectiles/guns/energy/cyborg.dm @@ -251,7 +251,7 @@ target.visible_message(span_danger("[target] has been zapped with [src] by [user]!")) 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].") if(ishuman(target)) var/mob/living/carbon/human/H = target @@ -417,7 +417,7 @@ else target.visible_message(span_danger("[target] has been prodded with [src] by [user]!")) 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].") if(ishuman(target)) var/mob/living/carbon/human/H = target diff --git a/code/modules/vore/resizing/crackers.dm b/code/modules/vore/resizing/crackers.dm index e27848e15b4..dd75e8faf28 100644 --- a/code/modules/vore/resizing/crackers.dm +++ b/code/modules/vore/resizing/crackers.dm @@ -2,6 +2,14 @@ //The winner of the pull has an effect applied to them. //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 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!" @@ -13,26 +21,35 @@ ) 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/list/prizes = list("shrinking","growing","drugged","invisibility","knocked over","teleport","wealth") - var/list/jokes = list( - "When is a boat just like snow? When it's adrift.", - "What happens to naughty elves? Santa gives them the sack.", - "What do you call an old snowman? Water.", - "Why has Santa been banned from sooty chimneys? Carbon footprints.", - "What goes down but doesn't come up? A yo.", - "What's green and fuzzy, has four legs and would kill you if it fell from a tree? A pool table.", - "Why did the blind man fall into the well? Because he couldn't see that well.", - "What did the pirate get on his report card? Seven Cs", - "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.") + var/prize //What prize we have loaded + var/joke //What joke we have loaded + +/obj/item/cracker/Initialize(mapload) + . = ..() + var/style = pick("blue","green","yellow","red","heart","hazard") + icon_state = style + item_state = style + if(!prize) + prize = pick(SHRINKING_CRACKER,GROWING_CRACKER,GROWING_CRACKER,INVISIBLE_CRACKER,FALLING_CRACKER,TELEPORTING_CRACKER,WEALTHY_CRACKER) + if(!joke) + joke = pick("When is a boat just like snow? When it's adrift.", + "What happens to naughty elves? Santa gives them the sack.", + "What do you call an old snowman? Water.", + "Why has Santa been banned from sooty chimneys? Carbon footprints.", + "What goes down but doesn't come up? A yo.", + "What's green and fuzzy, has four legs and would kill you if it fell from a tree? A pool table.", + "Why did the blind man fall into the well? Because he couldn't see that well.", + "What did the pirate get on his report card? Seven Cs", + "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) 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(target, span_notice("\The [src] is no longer in-hand!")) return - var/prize = pick(prizes) - var/joke = pick(jokes) var/mob/living/carbon/human/winner var/mob/living/carbon/human/loser if(!rigged) @@ -74,46 +89,52 @@ else winner = target 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) winner.visible_message(span_notice("\The [winner] wins the cracker prize!"),span_notice("You win the cracker prize!")) - if(prize == "shrinking") - winner.resize(0.25) - winner.visible_message(span_bold("\The [winner]") + " shrinks suddenly!") - if(prize == "growing") - winner.resize(2) - winner.visible_message(span_bold("\The [winner]") + " grows in height suddenly.") - if(prize == "drugged") - winner.druggy = max(winner.druggy, 50) - if(prize == "invisibility") - if(!winner.cloaked) - winner.visible_message(span_bold("\The [winner]") + " vanishes from sight.") - winner.cloak() - spawn(600) - if(winner.cloaked) - winner.uncloak() - winner.visible_message(span_bold("\The [winner]") + " appears as if from thin air.") - if(prize == "knocked over") - winner.visible_message(span_bold("\The [winner]") + " is suddenly knocked to the ground.") - winner.weakened = max(winner.weakened,50) - if(prize == "teleport") - if(loser.can_be_drop_pred && loser.vore_selected) - if(winner.devourable && winner.can_be_drop_prey) - winner.visible_message(span_bold("\The [winner]") + " is teleported to somewhere nearby...") - var/datum/effect/effect/system/spark_spread/spk - spk = new(winner) - - var/T = get_turf(winner) - spk.set_up(5, 0, winner) - spk.attach(winner) - playsound(T, "sparks", 50, 1) - anim(T,winner,'icons/mob/mob.dmi',,"phaseout",,winner.dir) - winner.forceMove(loser.vore_selected) - if(prize == "wealth") - 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!") + switch(prize) + if(SHRINKING_CRACKER) + winner.resize(0.25) + winner.visible_message(span_bold("\The [winner]") + " shrinks suddenly!") + if(GROWING_CRACKER) + winner.resize(2) + winner.visible_message(span_bold("\The [winner]") + " grows in height suddenly.") + if(GROWING_CRACKER) + winner.druggy = max(winner.druggy, 50) + if(INVISIBLE_CRACKER) + if(!winner.cloaked) + winner.visible_message(span_bold("\The [winner]") + " vanishes from sight.") + winner.cloak() + spawn(600) + if(winner.cloaked) + winner.uncloak() + winner.visible_message(span_bold("\The [winner]") + " appears as if from thin air.") + if(FALLING_CRACKER) + winner.visible_message(span_bold("\The [winner]") + " is suddenly knocked to the ground.") + winner.weakened = max(winner.weakened,50) + if(TELEPORTING_CRACKER) + if(loser.can_be_drop_pred && loser.vore_selected) + if(winner.devourable && winner.can_be_drop_prey) + winner.visible_message(span_bold("\The [winner]") + " is teleported to somewhere nearby...") + var/datum/effect/effect/system/spark_spread/spk + spk = new(winner) + + var/T = get_turf(winner) + spk.set_up(5, 0, winner) + spk.attach(winner) + playsound(T, "sparks", 50, 1) + anim(T,winner,'icons/mob/mob.dmi',,"phaseout",,winner.dir) + winner.forceMove(loser.vore_selected) + if(WEALTHY_CRACKER) + 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!") playsound(user, 'sound/effects/snap.ogg', 50, 1) user.drop_item(src) @@ -123,40 +144,33 @@ J.info = joke 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 name = "shrinking bluespace cracker" - prizes = list("shrinking") + prize = SHRINKING_CRACKER /obj/item/cracker/growing name = "growing bluespace cracker" - prizes = list("growing") + prize = GROWING_CRACKER /obj/item/cracker/invisibility name = "cloaking bluespace cracker" - prizes = list("invisibility") + prize = INVISIBLE_CRACKER /obj/item/cracker/drugged name = "psychedelic bluespace cracker" - prizes = list("drugged") + prize = GROWING_CRACKER /obj/item/cracker/knockover name = "forceful bluespace cracker" - prizes = list("knocked over") + prize = FALLING_CRACKER /obj/item/cracker/vore name = "teleporting bluespace cracker" - prizes = list("teleport") + prize = TELEPORTING_CRACKER /obj/item/cracker/money name = "fortuitous bluespace cracker" - prizes = list("wealth") + prize = WEALTHY_CRACKER /obj/item/clothing/head/paper_crown name = "paper crown" @@ -181,3 +195,11 @@ /obj/item/paper/cracker_joke/update_icon() return + +#undef SHRINKING_CRACKER +#undef GROWING_CRACKER +#undef DRUGGED_CRACKER +#undef INVISIBLE_CRACKER +#undef FALLING_CRACKER +#undef TELEPORTING_CRACKER +#undef WEALTHY_CRACKER diff --git a/sound/effects/tableheadsmash.ogg b/sound/effects/tableheadsmash.ogg new file mode 100644 index 00000000000..1f11344d568 Binary files /dev/null and b/sound/effects/tableheadsmash.ogg differ diff --git a/vorestation.dme b/vorestation.dme index 9eb9c19ab4f..3212353017d 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -551,6 +551,11 @@ #include "code\datums\components\traits\gargoyle.dm" #include "code\datums\components\traits\nutrition_size_change.dm" #include "code\datums\components\traits\photosynth.dm" +<<<<<<< HEAD +======= +#include "code\datums\components\traits\unlucky.dm" +#include "code\datums\components\traits\waddle.dm" +>>>>>>> b8fe8fa68d ([MIRROR] Unlucky trait (#11775)) #include "code\datums\components\traits\weaver.dm" #include "code\datums\diseases\_disease.dm" #include "code\datums\diseases\_MobProcs.dm"