From 9a0da404d7ccd4e0e048ff291b7dfa19b0c56b14 Mon Sep 17 00:00:00 2001 From: casperr04 Date: Sat, 8 Feb 2025 15:31:17 +0100 Subject: [PATCH 01/15] Of course we commit 51 files at once --- .../dcs/signals/atom/mob/signals_mob.dm | 6 +- code/__DEFINES/traits.dm | 4 + code/__DEFINES/typecheck/xenos.dm | 2 + code/_onclick/item_attack.dm | 31 +++++ code/datums/ammo/xeno.dm | 10 +- code/datums/diseases/xeno_transformation.dm | 4 +- code/datums/effects/acid.dm | 2 +- code/datums/pain/_pain.dm | 10 +- code/datums/pain/pain_yautja.dm | 2 +- .../tutorial/xenomorph/xenomorph_basic.dm | 10 +- .../objects/effects/effect_system/smoke.dm | 6 +- code/modules/admin/autoreply.dm | 6 +- code/modules/animations/animation_library.dm | 3 +- code/modules/mob/living/carbon/carbon.dm | 117 +++++++++--------- code/modules/mob/living/carbon/human/human.dm | 6 +- .../mob/living/carbon/human/human_defines.dm | 3 + .../mob/living/carbon/xenomorph/Evolution.dm | 4 + .../living/carbon/xenomorph/Facehuggers.dm | 3 +- .../mob/living/carbon/xenomorph/XenoProcs.dm | 117 +++++++++++++++--- .../mob/living/carbon/xenomorph/Xenomorph.dm | 11 +- .../xenomorph/abilities/general_abilities.dm | 8 +- .../abilities/general_ability_macros.dm | 6 +- .../xenomorph/abilities/general_powers.dm | 11 +- .../living/carbon/xenomorph/attack_alien.dm | 5 +- .../living/carbon/xenomorph/castes/Boiler.dm | 2 +- .../carbon/xenomorph/castes/Burrower.dm | 2 +- .../living/carbon/xenomorph/castes/Carrier.dm | 2 +- .../living/carbon/xenomorph/castes/Crusher.dm | 2 +- .../carbon/xenomorph/castes/Defender.dm | 2 +- .../living/carbon/xenomorph/castes/Drone.dm | 2 +- .../carbon/xenomorph/castes/Hellhound.dm | 2 +- .../carbon/xenomorph/castes/Hivelord.dm | 2 +- .../living/carbon/xenomorph/castes/King.dm | 2 +- .../living/carbon/xenomorph/castes/Lurker.dm | 2 +- .../carbon/xenomorph/castes/Praetorian.dm | 2 +- .../carbon/xenomorph/castes/Predalien.dm | 2 +- .../living/carbon/xenomorph/castes/Queen.dm | 10 +- .../living/carbon/xenomorph/castes/Ravager.dm | 2 +- .../living/carbon/xenomorph/castes/Runner.dm | 2 +- .../carbon/xenomorph/castes/Sentinel.dm | 2 +- .../living/carbon/xenomorph/castes/Spitter.dm | 2 +- .../living/carbon/xenomorph/castes/Warrior.dm | 2 +- .../carbon/xenomorph/castes/lesser_drone.dm | 2 +- .../living/carbon/xenomorph/damage_procs.dm | 2 + .../mob/living/carbon/xenomorph/death.dm | 2 + .../living/carbon/xenomorph/hive_status.dm | 4 +- .../mob/living/carbon/xenomorph/life.dm | 24 ++-- .../living/carbon/xenomorph/xeno_helpers.dm | 10 +- code/modules/mob/living/living.dm | 8 +- code/modules/mob/living/living_verbs.dm | 4 +- code/modules/mob/mob_grab.dm | 38 ++---- code/modules/paperwork/paper.dm | 2 +- code/modules/projectiles/gun.dm | 2 + code/modules/projectiles/gun_helpers.dm | 6 +- .../modules/projectiles/guns/flamer/flamer.dm | 5 +- strings/memetips.txt | 2 +- 56 files changed, 342 insertions(+), 200 deletions(-) diff --git a/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm b/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm index f4df347c62db..9d3d7549dca9 100644 --- a/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm +++ b/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm @@ -45,9 +45,9 @@ #define COMSIG_MOB_ATTEMPTING_EQUIP "mob_attempting_equip" #define COMPONENT_MOB_CANCEL_ATTEMPT_EQUIP (1<<0) -/// For when a mob is devoured by a Xeno -#define COMSIG_MOB_DEVOURED "mob_devoured" - #define COMPONENT_CANCEL_DEVOUR (1<<0) +/// For when a mob is hauled by a Xeno +#define COMSIG_MOB_HAULED "mob_hauled" + #define COMPONENT_CANCEL_HAUL (1<<0) // Reserved for tech trees #define COMSIG_MOB_ENTER_TREE "mob_enter_tree" #define COMPONENT_CANCEL_TREE_ENTRY (1<<0) diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index adc76b727914..80aec59c6dea 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -163,6 +163,8 @@ #define TRAIT_TEMPORARILY_MUTED "temporarily_muted" /// Mob wont get hit by stray projectiles #define TRAIT_NO_STRAY "trait_no_stray" +/// We can take out our knife or gun if hauled though we are immobilized, also shielded from most damage. +#define TRAIT_HAULED "hauled" // SPECIES TRAITS /// Knowledge of Yautja technology @@ -436,6 +438,8 @@ GLOBAL_LIST(trait_name_map) #define TRAIT_SOURCE_STRAIN "t_s_strain" ///Status trait coming from being buckled. #define TRAIT_SOURCE_BUCKLE "t_s_buckle" +//Status trait coming from being hauled by a xeno. +#define TRAIT_SOURCE_XENO_HAUL "t_s_xeno_haul" ///Status trait coming from being assigned as [acting] squad leader. #define TRAIT_SOURCE_SQUAD_LEADER "t_s_squad_leader" ///Status trait coming from their job diff --git a/code/__DEFINES/typecheck/xenos.dm b/code/__DEFINES/typecheck/xenos.dm index 34b70ac92f45..bc9dbbadcf15 100644 --- a/code/__DEFINES/typecheck/xenos.dm +++ b/code/__DEFINES/typecheck/xenos.dm @@ -30,6 +30,8 @@ /mob/living/carbon/xenomorph/proc/can_not_harm(mob/living/carbon/attempt_harm_mob) if(!istype(attempt_harm_mob)) return FALSE + if(HAS_TRAIT(attempt_harm_mob, TRAIT_HAULED)) + return TRUE if(!hive) hive = GLOB.hive_datum[hivenumber] diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 1631bc7bd12e..66cda367fab9 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -1,6 +1,8 @@ // Called when the item is in the active hand, and clicked; alternately, there is an 'activate held object' verb or you can hit pagedown. /obj/item/proc/attack_self(mob/user) + if(HAS_TRAIT(user, TRAIT_HAULED)) + return SHOULD_CALL_PARENT(TRUE) SEND_SIGNAL(src, COMSIG_ITEM_ATTACK_SELF, user) SEND_SIGNAL(user, COMSIG_MOB_ITEM_ATTACK_SELF, src) @@ -35,9 +37,35 @@ else if(initiate_surgery_moment(I, src, null, user)) return TRUE */ + if(HAS_TRAIT(user, TRAIT_HAULED)) + if(src == user) // No stabbing ourselves to death + return + if(handle_haul_resist(user, src, I)) + return ATTACKBY_HINT_UPDATE_NEXT_MOVE + return if(istype(I) && ismob(user)) return I.attack(src, user) +/mob/living/proc/handle_haul_resist(mob/living/resister, mob/living/carbon/xenomorph/xeno, obj/item/item) // move this? + if(get_dist(xeno, resister)) // No stabbing xenos next to you REMOVE HUGGING HAULED MOBS + return FALSE + if(item.force) + var/damage_of_item = rand(floor(item.force / 4), item.force) + xeno.take_limb_damage(damage_of_item) + for(var/mob/mobs_in_view as anything in viewers(resister, null)) + if(mobs_in_view.client) + mobs_in_view.show_message(text(SPAN_DANGER("[resister] attacks [xeno]'s carapace with the [item.name]!")), SHOW_MESSAGE_AUDIBLE) + resister.track_hit(initial(item.name)) + playsound(resister.loc, 'sound/weapons/slash.ogg', 25, 1) + if(prob(max(4*(100*xeno.getBruteLoss()/xeno.maxHealth - 75),0))) //4% at 24% health, 80% at 5% health + xeno.last_damage_data = create_cause_data("scuffling", resister) + xeno.gib(last_damage_data) + return TRUE + else + for(var/mob/mobs_can_hear in hearers(4, xeno)) + if(mobs_can_hear.client) + mobs_can_hear.show_message(SPAN_DANGER("You hear [resister] struggling against [xeno]'s grip..."), SHOW_MESSAGE_AUDIBLE) + return TRUE // Proximity_flag is 1 if this afterattack was called on something adjacent, in your square, or on your person. // Click parameters is the params string from byond Click() code, see that documentation. @@ -124,3 +152,6 @@ playsound(loc, hitsound, 25, 1) return (hit|ATTACKBY_HINT_UPDATE_NEXT_MOVE) return (ATTACKBY_HINT_NO_AFTERATTACK|ATTACKBY_HINT_UPDATE_NEXT_MOVE) + + + diff --git a/code/datums/ammo/xeno.dm b/code/datums/ammo/xeno.dm index 653beba573e9..11873a7202d5 100644 --- a/code/datums/ammo/xeno.dm +++ b/code/datums/ammo/xeno.dm @@ -162,7 +162,7 @@ /datum/ammo/xeno/acid/on_hit_mob(mob/M, obj/projectile/P) if(iscarbon(M)) var/mob/living/carbon/C = M - if(C.status_flags & XENO_HOST && HAS_TRAIT(C, TRAIT_NESTED) || C.stat == DEAD) + if(C.status_flags & XENO_HOST && HAS_TRAIT(C, TRAIT_NESTED) || C.stat == DEAD || HAS_TRAIT(C, TRAIT_HAULED)) return FALSE ..() @@ -252,7 +252,7 @@ /datum/ammo/xeno/boiler_gas/on_hit_mob(mob/moob, obj/projectile/proj) if(iscarbon(moob)) var/mob/living/carbon/carbon = moob - if(carbon.status_flags & XENO_HOST && HAS_TRAIT(carbon, TRAIT_NESTED) || carbon.stat == DEAD) + if(carbon.status_flags & XENO_HOST && HAS_TRAIT(carbon, TRAIT_NESTED) || carbon.stat == DEAD || HAS_TRAIT(carbon, TRAIT_HAULED)) return var/datum/effects/neurotoxin/neuro_effect = locate() in moob.effects_list if(!neuro_effect) @@ -302,7 +302,7 @@ /datum/ammo/xeno/boiler_gas/acid/on_hit_mob(mob/moob, obj/projectile/proj) if(iscarbon(moob)) var/mob/living/carbon/carbon = moob - if(carbon.status_flags & XENO_HOST && HAS_TRAIT(carbon, TRAIT_NESTED) || carbon.stat == DEAD) + if(carbon.status_flags & XENO_HOST && HAS_TRAIT(carbon, TRAIT_NESTED) || carbon.stat == DEAD || HAS_TRAIT(carbon, TRAIT_HAULED)) return to_chat(moob,SPAN_HIGHDANGER("Acid covers your body! Oh fuck!")) playsound(moob,"acid_strike",75,1) @@ -330,7 +330,7 @@ /datum/ammo/xeno/bone_chips/on_hit_mob(mob/living/M, obj/projectile/P) if(iscarbon(M)) var/mob/living/carbon/C = M - if((HAS_FLAG(C.status_flags, XENO_HOST) && HAS_TRAIT(C, TRAIT_NESTED)) || C.stat == DEAD) + if((HAS_FLAG(C.status_flags, XENO_HOST) && HAS_TRAIT(C, TRAIT_NESTED)) || C.stat == DEAD || HAS_TRAIT(C, TRAIT_HAULED)) return if(ishuman_strict(M) || isxeno(M)) playsound(M, 'sound/effects/spike_hit.ogg', 25, 1, 1) @@ -360,7 +360,7 @@ /datum/ammo/xeno/bone_chips/spread/runner/on_hit_mob(mob/living/M, obj/projectile/P) if(iscarbon(M)) var/mob/living/carbon/C = M - if((HAS_FLAG(C.status_flags, XENO_HOST) && HAS_TRAIT(C, TRAIT_NESTED)) || C.stat == DEAD) + if((HAS_FLAG(C.status_flags, XENO_HOST) && HAS_TRAIT(C, TRAIT_NESTED)) || C.stat == DEAD || HAS_TRAIT(C, TRAIT_HAULED)) return if(ishuman_strict(M) || isxeno(M)) playsound(M, 'sound/effects/spike_hit.ogg', 25, 1, 1) diff --git a/code/datums/diseases/xeno_transformation.dm b/code/datums/diseases/xeno_transformation.dm index 9bd5b965c2cc..9f49c2f1259a 100644 --- a/code/datums/diseases/xeno_transformation.dm +++ b/code/datums/diseases/xeno_transformation.dm @@ -31,13 +31,13 @@ if (prob(4)) to_chat(affected_mob, SPAN_DANGER("You can feel something move...inside.")) if (prob(5)) - to_chat(affected_mob, "\italic " + pick("Soon we will be one...", "Must... devour...", "Capture...", "We are perfect.")) + to_chat(affected_mob, "\italic " + pick("Soon we will be one...", "Must... evolve...", "Capture...", "We are perfect.")) if(4) if (prob(10)) to_chat(affected_mob, pick(SPAN_DANGER("Your skin feels very tight."), SPAN_DANGER("Your blood boils!"))) affected_mob.take_limb_damage(3) if (prob(5)) - affected_mob.whisper(pick("Soon we will be one...", "Must... devour...", "Capture...", "We are perfect.", "Hsssshhhhh!")) + affected_mob.whisper(pick("Soon we will be one...", "Must... evolve...", "Capture...", "We are perfect.", "Hsssshhhhh!")) if (prob(8)) to_chat(affected_mob, SPAN_DANGER("You can feel... something...inside you.")) if(5) diff --git a/code/datums/effects/acid.dm b/code/datums/effects/acid.dm index d89f7261a223..b7a21a41aa93 100644 --- a/code/datums/effects/acid.dm +++ b/code/datums/effects/acid.dm @@ -41,7 +41,7 @@ if(ishuman(A)) var/mob/living/carbon/human/H = A - if(H.status_flags & XENO_HOST && HAS_TRAIT(H, TRAIT_NESTED) || H.stat == DEAD) + if(H.status_flags & XENO_HOST && HAS_TRAIT(H, TRAIT_NESTED) || H.stat == DEAD || HAS_TRAIT(H, TRAIT_HAULED)) return FALSE . = ..() diff --git a/code/datums/pain/_pain.dm b/code/datums/pain/_pain.dm index 6c494fc65ed2..a648eb8cf427 100644 --- a/code/datums/pain/_pain.dm +++ b/code/datums/pain/_pain.dm @@ -195,7 +195,7 @@ if(new_level >= PAIN_LEVEL_SEVERE && feels_pain) RegisterSignal(source_mob, COMSIG_MOB_DRAGGED, PROC_REF(oxyloss_drag), override = TRUE) - RegisterSignal(source_mob, COMSIG_MOB_DEVOURED, PROC_REF(handle_devour), override = TRUE) + RegisterSignal(source_mob, COMSIG_MOB_HAULED, PROC_REF(handle_haul), override = TRUE) RegisterSignal(source_mob, COMSIG_MOVABLE_PRE_THROW, PROC_REF(oxy_kill), override = TRUE) last_level = new_level @@ -232,7 +232,7 @@ if(new_level < PAIN_LEVEL_SEVERE) UnregisterSignal(source_mob, list( COMSIG_MOB_DRAGGED, - COMSIG_MOB_DEVOURED, + COMSIG_MOB_HAULED, COMSIG_MOVABLE_PRE_THROW )) @@ -294,14 +294,14 @@ if(H.species.flags & HAS_HARDCRIT) source.apply_damage(20, OXY) -/datum/pain/proc/handle_devour(mob/living/source, mob/living/carbon/xenomorph/devourer) +/datum/pain/proc/handle_haul(mob/living/source, mob/living/carbon/xenomorph/hauler) SIGNAL_HANDLER if(source.chestburst) return - if(source.ally_of_hivenumber(devourer.hivenumber)) + if(source.ally_of_hivenumber(hauler.hivenumber)) return oxy_kill(source) - return COMPONENT_CANCEL_DEVOUR + return COMPONENT_CANCEL_HAUL /datum/pain/proc/oxy_kill(mob/living/source) SIGNAL_HANDLER diff --git a/code/datums/pain/pain_yautja.dm b/code/datums/pain/pain_yautja.dm index 94f5e8d33650..e2acce0ea2e4 100644 --- a/code/datums/pain/pain_yautja.dm +++ b/code/datums/pain/pain_yautja.dm @@ -17,7 +17,7 @@ /datum/pain/yautja/oxyloss_drag(mob/living/source, mob/puller) return -/datum/pain/yautja/handle_devour(mob/living/source) +/datum/pain/yautja/handle_haul(mob/living/source) return /datum/pain/yautja/oxy_kill(mob/living/source) diff --git a/code/datums/tutorial/xenomorph/xenomorph_basic.dm b/code/datums/tutorial/xenomorph/xenomorph_basic.dm index ed9a9b810b45..e4b45ba6f2e4 100644 --- a/code/datums/tutorial/xenomorph/xenomorph_basic.dm +++ b/code/datums/tutorial/xenomorph/xenomorph_basic.dm @@ -209,15 +209,15 @@ SIGNAL_HANDLER TUTORIAL_ATOM_FROM_TRACKING(/mob/living/carbon/human, human_dummy) UnregisterSignal(human_dummy, COMSIG_MOVABLE_XENO_START_PULLING) - message_to_player("Well done. Now devour the human by clicking on your character with the grab selected in your hand. You must not move during this process.") - update_objective("Devour the grabbed human by clicking on them with the grab in-hand.") - RegisterSignal(human_dummy, COMSIG_MOB_DEVOURED, PROC_REF(nest_cap_phase_five)) + message_to_player("Well done. Now haul the human by clicking on your character with the grab selected in your hand. You must not move during this process.") + update_objective("Haul the grabbed human by clicking on them with the grab in-hand.") + RegisterSignal(human_dummy, COMSIG_MOB_HAULED, PROC_REF(nest_cap_phase_five)) /datum/tutorial/xenomorph/basic/proc/nest_cap_phase_five() SIGNAL_HANDLER message_to_player("Well done, you can reguritate the human using the new ability you have gained.") message_to_player("Be careful. Real humans may put up a fight and can try to cut out of you from inside!") - give_action(xeno, /datum/action/xeno_action/onclick/regurgitate) + give_action(xeno, /datum/action/xeno_action/onclick/release_haul) addtimer(CALLBACK(src, PROC_REF(nest_cap_phase_six)), 15 SECONDS) /datum/tutorial/xenomorph/basic/proc/nest_cap_phase_six() @@ -227,7 +227,7 @@ /datum/tutorial/xenomorph/basic/proc/nest_cap_phase_seven() TUTORIAL_ATOM_FROM_TRACKING(/mob/living/carbon/human, human_dummy) - UnregisterSignal(human_dummy, COMSIG_MOB_DEVOURED) + UnregisterSignal(human_dummy, COMSIG_MOB_HAULED) RegisterSignal(human_dummy, COMSIG_MOB_NESTED, PROC_REF(on_mob_nested)) message_to_player("Nest the captive human!") update_objective("Nest the captive human!") diff --git a/code/game/objects/effects/effect_system/smoke.dm b/code/game/objects/effects/effect_system/smoke.dm index 4c7752538515..1ad4ed34127a 100644 --- a/code/game/objects/effects/effect_system/smoke.dm +++ b/code/game/objects/effects/effect_system/smoke.dm @@ -543,7 +543,7 @@ return FALSE if(isyautja(affected_mob) && prob(75)) return FALSE - if(HAS_TRAIT(affected_mob, TRAIT_NESTED) && affected_mob.status_flags & XENO_HOST) + if(HAS_TRAIT(affected_mob, TRAIT_NESTED) && affected_mob.status_flags & XENO_HOST || HAS_TRAIT(affected_mob, TRAIT_HAULED)) return FALSE affected_mob.last_damage_data = cause_data @@ -600,7 +600,7 @@ return FALSE if(isyautja(moob)) return FALSE - if(HAS_TRAIT(moob, TRAIT_NESTED) && moob.status_flags & XENO_HOST) + if(HAS_TRAIT(moob, TRAIT_NESTED) && moob.status_flags & XENO_HOST || HAS_TRAIT(moob, TRAIT_HAULED)) return FALSE var/mob/living/carbon/human/human_moob @@ -658,7 +658,7 @@ return FALSE if(isyautja(moob) && prob(75)) return FALSE - if(HAS_TRAIT(moob, TRAIT_NESTED) && moob.status_flags & XENO_HOST) + if(HAS_TRAIT(moob, TRAIT_NESTED) && moob.status_flags & XENO_HOST || HAS_TRAIT(moob, TRAIT_HAULED)) return FALSE var/mob/living/carbon/human/human_moob diff --git a/code/modules/admin/autoreply.dm b/code/modules/admin/autoreply.dm index 24a67256acd8..ee655f86394d 100644 --- a/code/modules/admin/autoreply.dm +++ b/code/modules/admin/autoreply.dm @@ -144,9 +144,9 @@ ON_CONFIG_LOAD(/datum/autoreply/mentor/macros) Rangefinders allow you to get tile coordinates (longitude and latitude) by lasing it while zoomed in (produces a GREEN laser). Ctrl + Click on any open tile to start lasing. Ctrl + Click on your rangefinders to stop lasing without zooming out. Coordinates can be used by Staff Officers to send supply drops or to perform Orbital Bombardment. You also can use them to call mortar fire if there are engineers with a mortar. \ Laser Designators have a second mode (produces a RED laser) that allows highlighting targets for Close Air Support performed by dropship pilots. They also have a fixed ID number that is shown on the pilot's weaponry console. Examine the laser designator to check its ID. Red laser must be maintained as long as needed in order for the dropship pilot to bomb the designated area. To switch between lasing modes, Alt + Click the laser designator. Alternatively, Right + Click it in hand and click \"Toggle Mode\"." -/datum/autoreply/mentor/devour - title = "X: Devour as Xeno" - message = "Devouring is useful to quickly transport incapacitated hosts from one place to another. In order to devour a host as a Xeno, grab the mob (CTRL+Click) and then click on yourself to begin devouring. The host can break out of your stomach, which will result in your death so make sure your target is incapacitated. After approximately 1 minute host will be automatically regurgitated. To release your target voluntary, click 'Regurgitate' on the HUD to throw them back up." +/datum/autoreply/mentor/haul + title = "X: Haul as Xeno" + message = "Hauling is useful to quickly transport incapacitated hosts from one place to another. In order to haul a host as a Xeno, grab the mob (CTRL+Click) and then click on yourself to begin hauling. The host can break out of your grip, which will result in your death so make sure your target is incapacitated. After approximately 1 minute host will be automatically released. To release your target voluntary, click 'Release' on the HUD to throw them back up." /datum/autoreply/mentor/plasma title = "X: No plasma regen" diff --git a/code/modules/animations/animation_library.dm b/code/modules/animations/animation_library.dm index fabd7508b856..4cfdf7ace745 100644 --- a/code/modules/animations/animation_library.dm +++ b/code/modules/animations/animation_library.dm @@ -177,7 +177,7 @@ Can look good elsewhere as well.*/ if(A.clone) if(src.Adjacent(A.clone)) A = A.clone - if(buckled || anchored) return //it would look silly. + if(buckled || anchored || HAS_TRAIT(src, TRAIT_HAULED)) return //it would look silly. var/pixel_x_diff = 0 var/pixel_y_diff = 0 var/direction = get_dir(src, A) @@ -206,7 +206,6 @@ Can look good elsewhere as well.*/ animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff, time = 2, flags = ANIMATION_PARALLEL) animate(pixel_x = initial(pixel_x), pixel_y = initial(pixel_y), time = 2) - /atom/proc/animation_spin(speed = 5, loop_amount = -1, clockwise = TRUE, sections = 3, angular_offset = 0, pixel_fuzz = 0) if(!sections) return diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 3bde39c160d8..55a9d9b68c59 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -37,52 +37,27 @@ if(nutrition && stat != DEAD) nutrition -= HUNGER_FACTOR/5 -/mob/living/carbon/relaymove(mob/user, direction) - if(user.is_mob_incapacitated(TRUE)) return - if(user in src.stomach_contents) - if(user.client) - user.client.next_movement = world.time + 20 - if(prob(30)) - for(var/mob/mobs_can_hear in hearers(4, src)) - if(mobs_can_hear.client) - mobs_can_hear.show_message(SPAN_DANGER("You hear something rumbling inside [src]'s stomach..."), SHOW_MESSAGE_AUDIBLE) - var/obj/item/item_in_hand = user.get_active_hand() - if(item_in_hand && item_in_hand.force) - var/damage_of_item = rand(floor(item_in_hand.force / 4), item_in_hand.force) - if(istype(src, /mob/living/carbon/human)) - var/mob/living/carbon/human/human_mob = src - var/organ = human_mob.get_limb("chest") - if(istype(organ, /obj/limb)) - var/obj/limb/organs_in_human = organ - if(organs_in_human.take_damage(damage_of_item, 0)) - human_mob.UpdateDamageIcon() - human_mob.updatehealth() - else - src.take_limb_damage(damage_of_item) - for(var/mob/mobs_in_view as anything in viewers(user, null)) - if(mobs_in_view.client) - mobs_in_view.show_message(text(SPAN_DANGER("[user] attacks [src]'s stomach wall with the [item_in_hand.name]!")), SHOW_MESSAGE_AUDIBLE) - user.track_hit(initial(item_in_hand.name)) - playsound(user.loc, 'sound/effects/attackblob.ogg', 25, 1) - - if(prob(max(4*(100*getBruteLoss()/maxHealth - 75),0))) //4% at 24% health, 80% at 5% health - last_damage_data = create_cause_data("chestbursting", user) - gib(last_damage_data) - else if(!chestburst && (status_flags & XENO_HOST) && islarva(user)) - var/mob/living/carbon/xenomorph/larva/larva_burst = user - larva_burst.chest_burst(src) - -/mob/living/carbon/ex_act(severity, direction, datum/cause_data/cause_data) + +/mob/living/carbon/ex_act(severity, direction, datum/cause_data/cause_data) // stays here because any carbon can be hauled + last_damage_data = istype(cause_data) ? cause_data : create_cause_data(cause_data) + var/gibbing = FALSE + + if(severity >= health && severity >= EXPLOSION_THRESHOLD_GIB) + gibbing = TRUE if(body_position == LYING_DOWN && direction) severity *= EXPLOSION_PRONE_MULTIPLIER + if(HAS_TRAIT(src, TRAIT_HAULED) && !gibbing) // We still probably wanna gib them as well if they were supposed to be gibbed by the explosion in the first place + visible_message(SPAN_WARNING("[src] is shielded from the blast!"), SPAN_WARNING("You are shielded from the blast!")) + return + if(severity >= 30) flash_eyes() last_damage_data = istype(cause_data) ? cause_data : create_cause_data(cause_data) - if(severity >= health && severity >= EXPLOSION_THRESHOLD_GIB) + if(gibbing) gib(last_damage_data) return @@ -97,23 +72,6 @@ /mob/living/carbon/gib(datum/cause_data/cause = create_cause_data("gibbing", src)) if(legcuffed) drop_inv_item_on_ground(legcuffed) - - var/turf/my_turf = get_turf(src) - - for(var/atom/movable/A in stomach_contents) - stomach_contents.Remove(A) - A.forceMove(my_turf) - A.acid_damage = 0 //Reset the acid damage - if(ismob(A)) - visible_message(SPAN_DANGER("[A] bursts out of [src]!")) - - for(var/atom/movable/A in contents_recursive()) - if(isobj(A)) - var/obj/O = A - if(O.unacidable) - O.forceMove(my_turf) - O.throw_atom(pick(RANGE_TURFS(1, src)), 1, SPEED_FAST) - . = ..(cause) /mob/living/carbon/revive() @@ -158,7 +116,7 @@ . = ..() -/mob/living/carbon/attack_hand(mob/target_mob as mob) +/mob/living/carbon/attack_hand(mob/target_mob as mob) // move it here probably if(!istype(target_mob, /mob/living/carbon)) return if(target_mob.mob_flags & SURGERY_MODE_ON && target_mob.a_intent & (INTENT_HELP|INTENT_DISARM)) @@ -366,8 +324,8 @@ return if(stat || !target) return - if(!istype(loc, /turf)) // In some mob/object (i.e. devoured or tank) - to_chat(src, SPAN_WARNING("You cannot throw anything while inside of \the [loc.name].")) + if(!istype(loc, /turf) || HAS_TRAIT(src, TRAIT_HAULED)) // In some mob/object (i.e. hauled or tank) + to_chat(src, SPAN_WARNING("You cannot throw anything right now.")) return if(target.type == /atom/movable/screen) return @@ -498,6 +456,46 @@ if(!HAS_TRAIT(src, TRAIT_FLOORED)) // just watch this break in the most horrible way possible break +// Adding traits, etc after xeno restrains and hauls us +/mob/living/carbon/human/proc/handle_haul(mob/living/carbon/xenomorph/xeno) + setDir(EAST) + xeno.hauled_mob_change_dir(xeno.dir, src) + ADD_TRAIT(src, TRAIT_HAULED, TRAIT_SOURCE_XENO_HAUL) + ADD_TRAIT(src, TRAIT_NO_STRAY, TRAIT_SOURCE_XENO_HAUL) + ADD_TRAIT(src, TRAIT_FLOORED, TRAIT_SOURCE_XENO_HAUL) + ADD_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_SOURCE_XENO_HAUL) + hauling_xeno = xeno + RegisterSignal(xeno, COMSIG_MOB_DEATH, PROC_REF(release_haul_death)) + RegisterSignal(src, COMSIG_LIVING_PREIGNITION, PROC_REF(haul_fire_shield)) + RegisterSignal(src, list(COMSIG_LIVING_FLAMER_CROSSED, COMSIG_LIVING_FLAMER_FLAMED), PROC_REF(haul_fire_shield_callback)) + layer = LYING_BETWEEN_MOB_LAYER + + +/mob/living/carbon/human/proc/release_haul_death() + SIGNAL_HANDLER + handle_unhaul() + +/mob/living/carbon/human/proc/haul_fire_shield(mob/living/burning_mob) //Stealing it from the pyro spec armor, xenos shield us from fire + SIGNAL_HANDLER + return COMPONENT_CANCEL_IGNITION + + +/mob/living/carbon/human/proc/haul_fire_shield_callback(mob/living/burning_mob) + SIGNAL_HANDLER + . = COMPONENT_NO_IGNITE|COMPONENT_NO_BURN + +// Removing traits and other stuff after xeno releases us from haul +/mob/living/carbon/human/proc/handle_unhaul() + if(!isturf(loc)) + var/location = get_turf(loc) + forceMove(location) + src.remove_traits(list(TRAIT_HAULED, TRAIT_NO_STRAY, TRAIT_FLOORED, TRAIT_IMMOBILIZED), TRAIT_SOURCE_XENO_HAUL) + pixel_y = 0 + pixel_x = 0 + UnregisterSignal(src, list(COMSIG_LIVING_PREIGNITION, COMSIG_LIVING_FLAMER_CROSSED, COMSIG_LIVING_FLAMER_FLAMED)) + UnregisterSignal(hauling_xeno, COMSIG_MOB_DEATH) + hauling_xeno = null + layer = MOB_LAYER /mob/living/carbon/on_stored_atom_del(atom/movable/AM) @@ -563,3 +561,8 @@ set_lying_angle(pick(90, 270)) else set_lying_angle(new_lying_angle) + +/mob/living/carbon/human/setDir(newdir) + if(HAS_TRAIT(src, TRAIT_HAULED)) + return + . = ..() diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 86a903e0ce18..6a1e73e55f4f 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -137,8 +137,6 @@ if(body_position == LYING_DOWN && direction) severity *= EXPLOSION_PRONE_MULTIPLIER - - var/b_loss = 0 var/f_loss = 0 @@ -157,6 +155,10 @@ create_shrapnel(oldloc, rand(5, 9), direction, 45, /datum/ammo/bullet/shrapnel/light/human/var2, last_damage_data) return + if(HAS_TRAIT(src, TRAIT_HAULED)) // We still probably wanna gib them as well if they were supposed to be gibbed by the explosion in the first place + visible_message(SPAN_WARNING("[src] is shielded from the blast!"), SPAN_WARNING("You are shielded from the blast!")) + return + if(!HAS_TRAIT(src, TRAIT_EAR_PROTECTION)) ear_damage += severity * 0.15 AdjustEarDeafness(severity * 0.5) diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 2a2661acc500..0e52eba0db5e 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -176,6 +176,9 @@ // Are we currently using inherent zoom vision? var/is_zoomed = FALSE + // Xenomorph that is hauling us if we are hauled + var/mob/living/carbon/xenomorph/hauling_xeno + /client/var/cached_human_playtime /client/proc/get_total_human_playtime(skip_cache = FALSE) diff --git a/code/modules/mob/living/carbon/xenomorph/Evolution.dm b/code/modules/mob/living/carbon/xenomorph/Evolution.dm index 4f288af48fcf..666e06294ff8 100644 --- a/code/modules/mob/living/carbon/xenomorph/Evolution.dm +++ b/code/modules/mob/living/carbon/xenomorph/Evolution.dm @@ -19,6 +19,10 @@ GLOBAL_LIST_EMPTY(deevolved_ckeys) if (!evolve_checks()) return + var/mob/living/carbon/human/user = hauled_mob?.resolve() + if(user) + to_chat("Release [user] before evolving!") + return var/castes_available = caste.evolves_to.Copy() diff --git a/code/modules/mob/living/carbon/xenomorph/Facehuggers.dm b/code/modules/mob/living/carbon/xenomorph/Facehuggers.dm index 3d7db8b58844..79f4bc40e039 100644 --- a/code/modules/mob/living/carbon/xenomorph/Facehuggers.dm +++ b/code/modules/mob/living/carbon/xenomorph/Facehuggers.dm @@ -471,7 +471,8 @@ /proc/can_hug(mob/living/carbon/M, hivenumber) if(!istype(M) || isxeno(M) || issynth(M) || iszombie(M) || isHellhound(M) || M.stat == DEAD || !M.huggable) return FALSE - + if(HAS_TRAIT(M, TRAIT_HAULED)) + return FALSE if(M.ally_of_hivenumber(hivenumber)) return FALSE diff --git a/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm b/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm index de59fea15d95..29f46a4651aa 100644 --- a/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm +++ b/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm @@ -215,6 +215,24 @@ /mob/living/carbon/xenomorph/proc/gain_armor_percent(value) armor_integrity = min(armor_integrity + value, 100) +/mob/living/carbon/xenomorph/animation_attack_on(atom/A, pixel_offset) + if(hauled_mob?.resolve()) + return + . = ..() + +/mob/living/carbon/xenomorph/Move(NewLoc, direct) + . = ..() + var/mob/user = hauled_mob?.resolve() + if(user) + user.forceMove(src.loc) + //switch(direct) + +/mob/living/carbon/xenomorph/forceMove(atom/destination) + . = ..() + var/mob/user = hauled_mob?.resolve() + if(user) + user.forceMove(src.loc) + //Strip all inherent xeno verbs from your caste. Used in evolution. /mob/living/carbon/xenomorph/proc/remove_inherent_verbs() @@ -392,23 +410,90 @@ else lighting_alpha = LIGHTING_PLANE_ALPHA_VISIBLE update_sight() +// +/mob/living/carbon/xenomorph/proc/haul(mob/living/carbon/human/victim) + src.visible_message(SPAN_WARNING("[src] restrains [victim], hauling them effortlessly!"), + SPAN_WARNING("We fully restrain [victim] and start hauling them!"), null, 5) + log_interact(src, victim, "[key_name(src)] started hauling [key_name(victim)] at [get_area_name(src)]") + playsound(loc, 'sound/weapons/thudswoosh.ogg', 25, 1, 7) + + if(ishuman(victim)) + var/mob/living/carbon/human/pulled_human = victim + pulled_human.disable_lights() + hauled_mob = WEAKREF(victim) + victim.forceMove(src.loc, get_dir(victim.loc, src.loc)) + victim.handle_haul(src) + RegisterSignal(victim, COMSIG_MOB_DEATH, PROC_REF(release_dead_haul)) + RegisterSignal(src, COMSIG_ATOM_DIR_CHANGE, PROC_REF(on_dir_change)) + +/mob/living/carbon/xenomorph/proc/on_dir_change(src, olddir, newdir) + SIGNAL_HANDLER + var/mob/living/carbon/human/hauled = hauled_mob.resolve() + hauled_mob_change_dir(newdir, hauled) -/mob/living/carbon/xenomorph/proc/regurgitate(mob/living/victim, stuns = FALSE) - if(length(stomach_contents)) - if(victim) - stomach_contents.Remove(victim) - victim.acid_damage = 0 - victim.forceMove(get_true_turf(loc)) - - visible_message(SPAN_XENOWARNING("[src] hurls out the contents of their stomach!"), - SPAN_XENOWARNING("We hurl out the contents of our stomach!"), null, 5) - playsound(get_true_location(loc), 'sound/voice/alien_drool2.ogg', 50, 1) - log_interact(src, victim, "[key_name(src)] regurgitated [key_name(victim)] at [get_area_name(loc)]") - - if (stuns) - victim.adjust_effect(2, STUN) - else - to_chat(src, SPAN_WARNING("There's nothing in our belly that needs regurgitating.")) +/mob/living/carbon/xenomorph/proc/hauled_mob_change_dir(direction, mob/living/carbon/human/hauled) + var/matrix/base = matrix() + var/angle + switch(direction) + if(NORTH) + angle = 180 + hauled.pixel_x = 0 + hauled.pixel_y = -13 + if(SOUTH) + angle = 0 + hauled.pixel_x = 0 + hauled.pixel_y = 10 + if(EAST) + angle = 250 + hauled.pixel_x = -13 + hauled.pixel_y = -8 + if(WEST) + angle = 110 + hauled.pixel_x = 12 + hauled.pixel_y = -8 + hauled.apply_transform(base.Turn(angle), 0) + +// Releasing a dead hauled mob +/mob/living/carbon/xenomorph/proc/release_dead_haul() + SIGNAL_HANDLER + var/mob/living/carbon/human/user = hauled_mob?.resolve() + to_chat(src, SPAN_XENOWARNING("[user] is dead. No more use for them now.")) + user.handle_unhaul() + UnregisterSignal(user, COMSIG_MOB_DEATH) + UnregisterSignal(src, COMSIG_ATOM_DIR_CHANGE) + + hauled_mob = null + +// Releasing a hauled mob +/mob/living/carbon/xenomorph/proc/release_haul(stuns = FALSE) + var/mob/living/carbon/human/user = hauled_mob?.resolve() + if(!user) + to_chat(src, SPAN_WARNING("We are not hauling anyone.")) + return + user.handle_unhaul() + visible_message(SPAN_XENOWARNING("[src] releases [user] from their grip!"), + SPAN_XENOWARNING("We release [user] from our grip!"), null, 5) + playsound(get_true_location(loc), 'sound/voice/alien_growl1.ogg', 15) + log_interact(src, user, "[key_name(src)] released [key_name(user)] at [get_area_name(loc)]") + if(stuns) + user.adjust_effect(2, STUN) + UnregisterSignal(user, COMSIG_MOB_DEATH) + UnregisterSignal(src, COMSIG_ATOM_DIR_CHANGE) + hauled_mob = null + // if(length(stomach_contents)) + // if(victim) + // stomach_contents.Remove(victim) + // victim.acid_damage = 0 + // victim.forceMove(get_true_turf(loc)) + + // visible_message(SPAN_XENOWARNING("[src] releases [victim] from their grip!"), + // SPAN_XENOWARNING("We release [victim] from our grip!"), null, 5) + // playsound(get_true_location(loc), 'sound/voice/alien_growl1.ogg', 15) + // log_interact(src, victim, "[key_name(src)] released [key_name(victim)] at [get_area_name(loc)]") + + // if (stuns) + // victim.adjust_effect(2, STUN) + // else /mob/living/carbon/xenomorph/proc/check_alien_construction(turf/current_turf, check_blockers = TRUE, silent = FALSE, check_doors = TRUE, ignore_nest = FALSE) var/has_obstacle diff --git a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm index 65367fdc30d3..8fb05a6ee76c 100644 --- a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm +++ b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm @@ -60,7 +60,8 @@ var/obj/item/clothing/head/head = null var/obj/item/r_store = null var/obj/item/l_store = null - + // Mob we are hauling + var/datum/weakref/hauled_mob var/obj/item/iff_tag/iff_tag = null var/static/list/walking_state_cache = list() @@ -278,8 +279,8 @@ /// 0/FALSE - upright, 1/TRUE - all fours var/agility = FALSE var/ripping_limb = FALSE - /// The world.time at which we will regurgitate our currently-vored victim - var/devour_timer = 0 + /// The world.time at which we will release our currently-restrained victim + var/haul_timer = 0 /// For drones/hivelords. Extends the maximum build range they have var/extra_build_dist = 0 /// tiles from self you can plant eggs. @@ -692,6 +693,10 @@ /mob/living/carbon/xenomorph/Destroy() GLOB.living_xeno_list -= src GLOB.xeno_mob_list -= src + var/mob/living/carbon/human/user = hauled_mob?.resolve() + if(user) + user.handle_unhaul() + hauled_mob = null if(tracked_marker) tracked_marker.xenos_tracking -= src diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm b/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm index 4594e87fb647..8024597ba708 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm @@ -59,12 +59,12 @@ if(X && !X.buckled && !X.is_mob_incapacitated()) return TRUE -// Regurgitate -/datum/action/xeno_action/onclick/regurgitate - name = "Regurgitate" +// release_haul +/datum/action/xeno_action/onclick/release_haul + name = "Release" action_icon_state = "regurgitate" plasma_cost = 0 - macro_path = /datum/action/xeno_action/verb/verb_regurgitate + macro_path = /datum/action/xeno_action/verb/verb_release_haul action_type = XENO_ACTION_CLICK // Choose Resin diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/general_ability_macros.dm b/code/modules/mob/living/carbon/xenomorph/abilities/general_ability_macros.dm index 5e22064cfeb2..ae0736e62c2d 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/general_ability_macros.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/general_ability_macros.dm @@ -30,11 +30,11 @@ var/action_name = "Toggle Spit Type" handle_xeno_macro(src, action_name) -/datum/action/xeno_action/verb/verb_regurgitate() +/datum/action/xeno_action/verb/verb_release_haul() set category = "Alien" - set name = "Regurgitate" + set name = "Release" set hidden = TRUE - var/action_name = "Regurgitate" + var/action_name = "Release" handle_xeno_macro(src, action_name) /datum/action/xeno_action/verb/verb_choose_resin_structure() diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/general_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/general_powers.dm index 7d507d46d8fa..f5b7ca995e80 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/general_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/general_powers.dm @@ -123,19 +123,16 @@ button.overlays += image('icons/mob/hud/actions_xeno.dmi', button, "shift_spit_[X.ammo.icon_state]") return ..() -/datum/action/xeno_action/onclick/regurgitate/use_ability(atom/A) +/datum/action/xeno_action/onclick/release_haul/use_ability(atom/A) var/mob/living/carbon/xenomorph/X = owner if(!X.check_state()) return if(!isturf(X.loc)) - to_chat(X, SPAN_WARNING("We cannot regurgitate here.")) + to_chat(X, SPAN_WARNING("We cannot put them down here.")) return - if(length(X.stomach_contents)) - for(var/mob/living/M in X.stomach_contents) - // Also has good reason to be a proc on all Xenos - X.regurgitate(M, TRUE) + X.release_haul(TRUE) return ..() @@ -925,6 +922,8 @@ /datum/action/xeno_action/activable/tail_stab/use_ability(atom/targetted_atom) var/mob/living/carbon/xenomorph/stabbing_xeno = owner + if(HAS_TRAIT(targetted_atom, TRAIT_HAULED)) + return if(HAS_TRAIT(stabbing_xeno, TRAIT_ABILITY_BURROWED) || stabbing_xeno.is_ventcrawling) to_chat(stabbing_xeno, SPAN_XENOWARNING("We must be above ground to do this.")) diff --git a/code/modules/mob/living/carbon/xenomorph/attack_alien.dm b/code/modules/mob/living/carbon/xenomorph/attack_alien.dm index 2421b68f36d9..10d931dc654c 100644 --- a/code/modules/mob/living/carbon/xenomorph/attack_alien.dm +++ b/code/modules/mob/living/carbon/xenomorph/attack_alien.dm @@ -12,6 +12,10 @@ if(attacking_xeno.fortify || HAS_TRAIT(attacking_xeno, TRAIT_ABILITY_BURROWED)) return XENO_NO_DELAY_ACTION + if(HAS_TRAIT(src, TRAIT_HAULED)) + to_chat(attacking_xeno, SPAN_WARNING("[src] is being hauled, we cannot do anything to them.")) + return + var/intent = attacking_xeno.a_intent if(attacking_xeno.behavior_delegate) @@ -79,7 +83,6 @@ acid_damage += (attacking_xeno.frenzy_aura * FRENZY_DAMAGE_MULTIPLIER) attacking_xeno.animation_attack_on(src) - //Somehow we will deal no damage on this attack if(!damage) playsound(attacking_xeno.loc, 'sound/weapons/alien_claw_swipe.ogg', 25, 1) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Boiler.dm b/code/modules/mob/living/carbon/xenomorph/castes/Boiler.dm index e239e5023e64..ba4aef97a84d 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Boiler.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Boiler.dm @@ -66,7 +66,7 @@ base_actions = list( /datum/action/xeno_action/onclick/xeno_resting, - /datum/action/xeno_action/onclick/regurgitate, + /datum/action/xeno_action/onclick/release_haul, /datum/action/xeno_action/watch_xeno, /datum/action/xeno_action/activable/tail_stab/boiler, /datum/action/xeno_action/activable/corrosive_acid/strong, diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Burrower.dm b/code/modules/mob/living/carbon/xenomorph/castes/Burrower.dm index d83c278ac9cc..b416e0f1136c 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Burrower.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Burrower.dm @@ -56,7 +56,7 @@ base_actions = list( /datum/action/xeno_action/onclick/xeno_resting, - /datum/action/xeno_action/onclick/regurgitate, + /datum/action/xeno_action/onclick/release_haul, /datum/action/xeno_action/watch_xeno, /datum/action/xeno_action/activable/tail_stab, /datum/action/xeno_action/activable/corrosive_acid, diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm b/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm index 08b5a9b28deb..8036c7edd711 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm @@ -62,7 +62,7 @@ base_actions = list( /datum/action/xeno_action/onclick/xeno_resting, - /datum/action/xeno_action/onclick/regurgitate, + /datum/action/xeno_action/onclick/release_haul, /datum/action/xeno_action/watch_xeno, /datum/action/xeno_action/activable/tail_stab, /datum/action/xeno_action/activable/place_construction, diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm b/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm index 3c8caab886a4..84e6b9535526 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm @@ -54,7 +54,7 @@ organ_value = 3000 base_actions = list( /datum/action/xeno_action/onclick/xeno_resting, - /datum/action/xeno_action/onclick/regurgitate, + /datum/action/xeno_action/onclick/release_haul, /datum/action/xeno_action/watch_xeno, /datum/action/xeno_action/activable/tail_stab, /datum/action/xeno_action/activable/pounce/crusher_charge, diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Defender.dm b/code/modules/mob/living/carbon/xenomorph/castes/Defender.dm index 3e1eda829d17..b1e0bb6e093b 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Defender.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Defender.dm @@ -43,7 +43,7 @@ base_actions = list( /datum/action/xeno_action/onclick/xeno_resting, - /datum/action/xeno_action/onclick/regurgitate, + /datum/action/xeno_action/onclick/release_haul, /datum/action/xeno_action/watch_xeno, /datum/action/xeno_action/activable/tail_stab/slam, /datum/action/xeno_action/onclick/toggle_crest, diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Drone.dm b/code/modules/mob/living/carbon/xenomorph/castes/Drone.dm index 26c6943cd5df..ff9b3bc862e5 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Drone.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Drone.dm @@ -58,7 +58,7 @@ old_x = -12 base_actions = list( /datum/action/xeno_action/onclick/xeno_resting, - /datum/action/xeno_action/onclick/regurgitate, + /datum/action/xeno_action/onclick/release_haul, /datum/action/xeno_action/watch_xeno, /datum/action/xeno_action/activable/tail_stab, /datum/action/xeno_action/activable/corrosive_acid/weak, diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Hellhound.dm b/code/modules/mob/living/carbon/xenomorph/castes/Hellhound.dm index 19afb901868f..5ac74ab68dd8 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Hellhound.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Hellhound.dm @@ -57,7 +57,7 @@ base_actions = list( /datum/action/xeno_action/onclick/xeno_resting, - /datum/action/xeno_action/onclick/regurgitate, + /datum/action/xeno_action/onclick/release_haul, /datum/action/xeno_action/onclick/xenohide, /datum/action/xeno_action/activable/pounce/runner, /datum/action/xeno_action/onclick/toggle_long_range/runner, diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Hivelord.dm b/code/modules/mob/living/carbon/xenomorph/castes/Hivelord.dm index e2687c8379f5..03ada4937f4b 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Hivelord.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Hivelord.dm @@ -60,7 +60,7 @@ base_actions = list( /datum/action/xeno_action/onclick/xeno_resting, - /datum/action/xeno_action/onclick/regurgitate, + /datum/action/xeno_action/onclick/release_haul, /datum/action/xeno_action/watch_xeno, /datum/action/xeno_action/activable/tail_stab, /datum/action/xeno_action/activable/corrosive_acid, diff --git a/code/modules/mob/living/carbon/xenomorph/castes/King.dm b/code/modules/mob/living/carbon/xenomorph/castes/King.dm index 55283ea30fcd..88c990d0bdcd 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/King.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/King.dm @@ -49,7 +49,7 @@ base_actions = list( /datum/action/xeno_action/onclick/xeno_resting, - /datum/action/xeno_action/onclick/regurgitate, + /datum/action/xeno_action/onclick/release_haul, /datum/action/xeno_action/watch_xeno, /datum/action/xeno_action/activable/tail_stab, /datum/action/xeno_action/onclick/rend, diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm b/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm index e47e94dc2483..f07b67720e0c 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm @@ -41,7 +41,7 @@ organ_value = 2000 base_actions = list( /datum/action/xeno_action/onclick/xeno_resting, - /datum/action/xeno_action/onclick/regurgitate, + /datum/action/xeno_action/onclick/release_haul, /datum/action/xeno_action/watch_xeno, /datum/action/xeno_action/activable/tail_stab, /datum/action/xeno_action/activable/pounce/lurker, diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Praetorian.dm b/code/modules/mob/living/carbon/xenomorph/castes/Praetorian.dm index b8730fac6f0b..9aeef22f86d1 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Praetorian.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Praetorian.dm @@ -56,7 +56,7 @@ base_actions = list( /datum/action/xeno_action/onclick/xeno_resting, - /datum/action/xeno_action/onclick/regurgitate, + /datum/action/xeno_action/onclick/release_haul, /datum/action/xeno_action/watch_xeno, /datum/action/xeno_action/activable/tail_stab, /datum/action/xeno_action/activable/corrosive_acid, diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Predalien.dm b/code/modules/mob/living/carbon/xenomorph/castes/Predalien.dm index d658d2e83195..379c5c90b8dc 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Predalien.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Predalien.dm @@ -56,7 +56,7 @@ base_actions = list( /datum/action/xeno_action/onclick/xeno_resting, - /datum/action/xeno_action/onclick/regurgitate, + /datum/action/xeno_action/onclick/release_haul, /datum/action/xeno_action/watch_xeno, /datum/action/xeno_action/activable/tail_stab, /datum/action/xeno_action/onclick/feralrush, diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm b/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm index b31575547cca..211d612d51d7 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm @@ -296,7 +296,7 @@ base_actions = list( /datum/action/xeno_action/onclick/xeno_resting, - /datum/action/xeno_action/onclick/regurgitate, + /datum/action/xeno_action/onclick/release_haul, /datum/action/xeno_action/watch_xeno, /datum/action/xeno_action/activable/tail_stab, /datum/action/xeno_action/activable/place_construction/not_primary, //normally fifth macro but not as important for queen @@ -326,7 +326,7 @@ var/list/mobile_abilities = list( /datum/action/xeno_action/onclick/xeno_resting, - /datum/action/xeno_action/onclick/regurgitate, + /datum/action/xeno_action/onclick/release_haul, /datum/action/xeno_action/watch_xeno, /datum/action/xeno_action/activable/tail_stab, /datum/action/xeno_action/activable/place_construction/not_primary, //normally fifth macro but not as important for queen @@ -754,7 +754,9 @@ /mob/living/carbon/xenomorph/queen/proc/queen_gut(atom/target) if(!iscarbon(target)) return FALSE - + if(HAS_TRAIT(target, TRAIT_HAULED)) + to_chat(src, SPAN_XENOWARNING("[target] needs to be released first.")) + return FALSE var/mob/living/carbon/victim = target if(get_dist(src, victim) > 1) @@ -846,7 +848,7 @@ var/list/immobile_abilities = list( // These already have their placement locked in: - /datum/action/xeno_action/onclick/regurgitate, + /datum/action/xeno_action/onclick/release_haul, /datum/action/xeno_action/watch_xeno, /datum/action/xeno_action/activable/place_construction/not_primary, /datum/action/xeno_action/onclick/emit_pheromones, diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Ravager.dm b/code/modules/mob/living/carbon/xenomorph/castes/Ravager.dm index dc5e3532d4b5..2921ad4701f7 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Ravager.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Ravager.dm @@ -53,7 +53,7 @@ organ_value = 3000 base_actions = list( /datum/action/xeno_action/onclick/xeno_resting, - /datum/action/xeno_action/onclick/regurgitate, + /datum/action/xeno_action/onclick/release_haul, /datum/action/xeno_action/watch_xeno, /datum/action/xeno_action/activable/tail_stab, /datum/action/xeno_action/activable/pounce/charge, diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Runner.dm b/code/modules/mob/living/carbon/xenomorph/castes/Runner.dm index 7cbe9e8caef7..5be771cea2df 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Runner.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Runner.dm @@ -53,7 +53,7 @@ base_actions = list( /datum/action/xeno_action/onclick/xeno_resting, - /datum/action/xeno_action/onclick/regurgitate, + /datum/action/xeno_action/onclick/release_haul, /datum/action/xeno_action/watch_xeno, /datum/action/xeno_action/activable/tail_stab, /datum/action/xeno_action/onclick/xenohide, diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Sentinel.dm b/code/modules/mob/living/carbon/xenomorph/castes/Sentinel.dm index 8307b18197ee..7310a76e2bec 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Sentinel.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Sentinel.dm @@ -42,7 +42,7 @@ organ_value = 800 base_actions = list( /datum/action/xeno_action/onclick/xeno_resting, - /datum/action/xeno_action/onclick/regurgitate, + /datum/action/xeno_action/onclick/release_haul, /datum/action/xeno_action/watch_xeno, /datum/action/xeno_action/activable/tail_stab, /datum/action/xeno_action/activable/corrosive_acid/weak, diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Spitter.dm b/code/modules/mob/living/carbon/xenomorph/castes/Spitter.dm index 7a9ecea9c21b..dcd10d06e98b 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Spitter.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Spitter.dm @@ -44,7 +44,7 @@ tier = 2 base_actions = list( /datum/action/xeno_action/onclick/xeno_resting, - /datum/action/xeno_action/onclick/regurgitate, + /datum/action/xeno_action/onclick/release_haul, /datum/action/xeno_action/watch_xeno, /datum/action/xeno_action/activable/tail_stab/spitter, /datum/action/xeno_action/activable/corrosive_acid, diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Warrior.dm b/code/modules/mob/living/carbon/xenomorph/castes/Warrior.dm index 28e22eb71d70..09647bf29b04 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Warrior.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Warrior.dm @@ -46,7 +46,7 @@ organ_value = 2000 base_actions = list( /datum/action/xeno_action/onclick/xeno_resting, - /datum/action/xeno_action/onclick/regurgitate, + /datum/action/xeno_action/onclick/release_haul, /datum/action/xeno_action/watch_xeno, /datum/action/xeno_action/activable/tail_stab, /datum/action/xeno_action/activable/warrior_punch, diff --git a/code/modules/mob/living/carbon/xenomorph/castes/lesser_drone.dm b/code/modules/mob/living/carbon/xenomorph/castes/lesser_drone.dm index 531f7f2d9b14..1ddf4919ae66 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/lesser_drone.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/lesser_drone.dm @@ -59,7 +59,7 @@ acid_blood_damage = 15 base_actions = list( /datum/action/xeno_action/onclick/xeno_resting, - /datum/action/xeno_action/onclick/regurgitate, + /datum/action/xeno_action/onclick/release_haul, /datum/action/xeno_action/watch_xeno, /datum/action/xeno_action/activable/tail_stab, /datum/action/xeno_action/activable/corrosive_acid/weak, diff --git a/code/modules/mob/living/carbon/xenomorph/damage_procs.dm b/code/modules/mob/living/carbon/xenomorph/damage_procs.dm index 11d65d1bb0ff..efeac5dd9eb6 100644 --- a/code/modules/mob/living/carbon/xenomorph/damage_procs.dm +++ b/code/modules/mob/living/carbon/xenomorph/damage_procs.dm @@ -271,6 +271,8 @@ for(var/mob/living/carbon/human/victim in orange(radius, src)) //Loop through all nearby victims, including the tile. splash_chance = 65 - (i * 5) + if(HAS_TRAIT(victim, TRAIT_HAULED)) + continue if(victim.loc == loc) splash_chance += 30 //Same tile? BURN if(victim.species?.acid_blood_dodge_chance) diff --git a/code/modules/mob/living/carbon/xenomorph/death.dm b/code/modules/mob/living/carbon/xenomorph/death.dm index eed7bc704a2b..8fde83c43bd5 100644 --- a/code/modules/mob/living/carbon/xenomorph/death.dm +++ b/code/modules/mob/living/carbon/xenomorph/death.dm @@ -19,6 +19,7 @@ if(pulledby) pulledby.stop_pulling() + if(!gibbed) if(hud_used && hud_used.healths) hud_used.healths.icon_state = "health_dead" @@ -144,6 +145,7 @@ if(!caste) CRASH("CASTE ERROR: gib() was called without a caste. (name: [name], disposed: [QDELETED(src)], health: [health])") + switch(caste.caste_type) if(XENO_CASTE_BOILER) var/mob/living/carbon/xenomorph/boiler/src_boiler = src diff --git a/code/modules/mob/living/carbon/xenomorph/hive_status.dm b/code/modules/mob/living/carbon/xenomorph/hive_status.dm index 324ca3402a80..c10d5b9bdc07 100644 --- a/code/modules/mob/living/carbon/xenomorph/hive_status.dm +++ b/code/modules/mob/living/carbon/xenomorph/hive_status.dm @@ -709,7 +709,7 @@ if(isfacehugger(xeno) || islesserdrone(xeno)) to_chat(xeno, SPAN_XENOANNOUNCE("The Queen has left without you, you quickly find a hiding place to enter hibernation as you lose touch with the hive mind.")) if(length(xeno.stomach_contents)) - xeno.devour_timer = 0 + xeno.haul_timer = 0 xeno.handle_stomach_contents() qdel(xeno) continue @@ -719,7 +719,7 @@ else to_chat(xeno, SPAN_XENOANNOUNCE("The Queen has left without you, you quickly find a hiding place to enter hibernation as you lose touch with the hive mind.")) if(length(xeno.stomach_contents)) - xeno.devour_timer = 0 + xeno.haul_timer = 0 xeno.handle_stomach_contents() qdel(xeno) stored_larva++ diff --git a/code/modules/mob/living/carbon/xenomorph/life.dm b/code/modules/mob/living/carbon/xenomorph/life.dm index 19ef26baabc1..23072e3f3676 100644 --- a/code/modules/mob/living/carbon/xenomorph/life.dm +++ b/code/modules/mob/living/carbon/xenomorph/life.dm @@ -219,22 +219,22 @@ return TRUE /mob/living/carbon/xenomorph/proc/handle_stomach_contents() - //Deal with dissolving/damaging stuff in stomach. + //Deal with dissolving/damaging stuff in stomach. This sucks man. if(length(stomach_contents)) for(var/atom/movable/M in stomach_contents) if(ishuman(M)) - if(world.time > devour_timer - 50 && world.time < devour_timer - 30) - to_chat(src, SPAN_WARNING("We're about to regurgitate [M]...")) - playsound(loc, 'sound/voice/alien_drool1.ogg', 50, 1) + if(world.time > haul_timer - 50 && world.time < haul_timer - 30) + to_chat(src, SPAN_WARNING("We're about to release [M] from our grip..")) + playsound(loc, 'sound/voice/alien_hiss2.ogg', 50) var/mob/living/carbon/human/H = M - if(world.time > devour_timer || (H.stat == DEAD && !H.chestburst)) - regurgitate(H) - - M.acid_damage++ - if(M.acid_damage > 300) - to_chat(src, SPAN_XENODANGER("\The [M] is dissolved in our gut with a gurgle.")) - stomach_contents.Remove(M) - qdel(M) + if(world.time > haul_timer || (H.stat == DEAD && !H.chestburst)) + release_haul(FALSE) + + // M.acid_damage++ + // if(M.acid_damage > 300) + // to_chat(src, SPAN_XENODANGER("\The [M] is dissolved in our gut with a gurgle.")) + // stomach_contents.Remove(M) + // qdel(M) /mob/living/carbon/xenomorph/proc/handle_regular_hud_updates() if(!mind) diff --git a/code/modules/mob/living/carbon/xenomorph/xeno_helpers.dm b/code/modules/mob/living/carbon/xenomorph/xeno_helpers.dm index 2414d077b1c0..fbd9eb895bb2 100644 --- a/code/modules/mob/living/carbon/xenomorph/xeno_helpers.dm +++ b/code/modules/mob/living/carbon/xenomorph/xeno_helpers.dm @@ -2,11 +2,11 @@ return (mob_size < MOB_SIZE_BIG && caste.can_vent_crawl) /mob/living/carbon/xenomorph/ventcrawl_carry() - if(length(stomach_contents)) - for(var/mob/living/carbon/human/H in stomach_contents) - if(!isspeciesmonkey(H)) - to_chat(src, SPAN_XENOWARNING("You cannot ventcrawl with [H] inside you!")) - return FALSE + var/mob/living/carbon/human/user = hauled_mob?.resolve() + if(user) + if(!isspeciesmonkey(user)) + to_chat(src, SPAN_XENOWARNING("You cannot ventcrawl while hauling [user]!")) + return FALSE return TRUE /mob/living/carbon/xenomorph/can_inject() diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 2b9a8cfbc369..4f5d8e96e675 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -677,6 +677,8 @@ /mob/living/update_transform(instant_update = FALSE) + if(HAS_TRAIT(src, TRAIT_HAULED)) + return var/visual_angle = lying_angle if(!rotate_on_lying) return @@ -692,9 +694,11 @@ // legacy procs /mob/living/put_in_l_hand(obj/item/W) if(body_position == LYING_DOWN) - return + if(!HAS_TRAIT(src, TRAIT_HAULED)) + return return ..() /mob/living/put_in_r_hand(obj/item/W) if(body_position == LYING_DOWN) - return + if(!HAS_TRAIT(src, TRAIT_HAULED)) + return return ..() diff --git a/code/modules/mob/living/living_verbs.dm b/code/modules/mob/living/living_verbs.dm index 62c15d12f7f0..c23776d3b1c3 100644 --- a/code/modules/mob/living/living_verbs.dm +++ b/code/modules/mob/living/living_verbs.dm @@ -1,7 +1,7 @@ /mob/living/can_resist() if(next_move > world.time) return FALSE - if(HAS_TRAIT(src, TRAIT_INCAPACITATED)) + if(HAS_TRAIT(src, TRAIT_INCAPACITATED) || HAS_TRAIT(src, TRAIT_HAULED)) return FALSE return TRUE @@ -54,7 +54,7 @@ M.status_flags &= ~PASSEMOTES return - //resisting grabs (as if it helps anyone...) + //resisting grabs (as if it helps anyone...) //FLAG if(!is_mob_restrained(0) && pulledby) visible_message(SPAN_DANGER("[src] resists against [pulledby]'s grip!")) resist_grab() diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm index 93dad80cfbe3..61333c3602da 100644 --- a/code/modules/mob/mob_grab.dm +++ b/code/modules/mob/mob_grab.dm @@ -117,7 +117,7 @@ if(!istype(pulled)) return if(isxeno(pulled) || issynth(pulled)) - to_chat(xeno, SPAN_WARNING("That wouldn't taste very good.")) + to_chat(xeno, SPAN_WARNING("That wouldn't serve a purpose.")) return 0 if(pulled.buckled) to_chat(xeno, SPAN_WARNING("[pulled] is buckled to something.")) @@ -125,45 +125,31 @@ if(pulled.stat == DEAD && !pulled.chestburst) to_chat(xeno, SPAN_WARNING("Ew, [pulled] is already starting to rot.")) return 0 - if(length(xeno.stomach_contents)) //Only one thing in the stomach at a time, please - to_chat(xeno, SPAN_WARNING("We already have something in our stomach, there's no way that will fit.")) + if(xeno.hauled_mob?.resolve()) // We can't carry more than one mob + to_chat(xeno, SPAN_WARNING("You already are carrying something, there's no way that will work.")) return 0 - /* Saving this in case we want to allow devouring of dead bodies UNLESS their client is still online somewhere + /* Saving this in case we want to allow hauling of dead bodies UNLESS their client is still online somewhere if(pulled.client) //The client is still inside the body else // The client is observing for(var/mob/dead/observer/G in player_list) if(ckey(G.mind.original.ckey) == pulled.ckey) - to_chat(src, "You start to devour [pulled] but realize \he is already dead.") + to_chat(src, "You start to haul [pulled] but realize \he is already dead.") return */ if(user.action_busy) to_chat(xeno, SPAN_WARNING("We are already busy with something.")) return SEND_SIGNAL(xeno, COMSIG_MOB_EFFECT_CLOAK_CANCEL) - xeno.visible_message(SPAN_DANGER("[xeno] starts to devour [pulled]!"), - SPAN_DANGER("We start to devour [pulled]!"), null, 5) + xeno.visible_message(SPAN_DANGER("[xeno] starts to restrain [pulled]!"), + SPAN_DANGER("We start restraining [pulled]!"), null, 5) if(HAS_TRAIT(xeno, TRAIT_CLOAKED)) //cloaked don't show the visible message, so we gotta work around - to_chat(pulled, FONT_SIZE_HUGE(SPAN_DANGER("[xeno] is trying to devour you!"))) + to_chat(pulled, FONT_SIZE_HUGE(SPAN_DANGER("[xeno] is trying to restrain you!"))) if(do_after(xeno, 50, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) if(isxeno(pulled.loc) && !length(xeno.stomach_contents)) - to_chat(xeno, SPAN_WARNING("Someone already ate \the [pulled].")) + to_chat(xeno, SPAN_WARNING("Someone already took \the [pulled].")) return 0 if(xeno.pulling == pulled && !pulled.buckled && (pulled.stat != DEAD || pulled.chestburst) && !length(xeno.stomach_contents)) //make sure you've still got them in your claws, and alive - if(SEND_SIGNAL(pulled, COMSIG_MOB_DEVOURED, xeno) & COMPONENT_CANCEL_DEVOUR) + if(SEND_SIGNAL(pulled, COMSIG_MOB_HAULED, xeno) & COMPONENT_CANCEL_HAUL) return FALSE + xeno.haul(pulled) + xeno.stop_pulling() - xeno.visible_message(SPAN_WARNING("[xeno] devours [pulled]!"), - SPAN_WARNING("We devour [pulled]!"), null, 5) - log_interact(xeno, pulled, "[key_name(xeno)] devoured [key_name(pulled)] at [get_area_name(xeno)]") - - if(ishuman(pulled)) - var/mob/living/carbon/human/pulled_human = pulled - pulled_human.disable_lights() - - //Then, we place the mob where it ought to be - xeno.stomach_contents.Add(pulled) - xeno.devour_timer = world.time + 500 + rand(0,200) // 50-70 seconds - pulled.forceMove(xeno) - return TRUE - if(!(pulled in xeno.stomach_contents)) - to_chat(xeno, SPAN_WARNING("We stop devouring [pulled]. They probably tasted gross anyways.")) - return 0 diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index 85a64160d37c..2f5e11cb7459 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -576,7 +576,7 @@ /obj/item/paper/prison_station/test_log name = "paper- 'Test Log'" - info = "

TEST LOG

SPECIMEN: Bioweapon candidate Kappa. Individual 3


\n

-

PROCEDURE: Observation

RESULTS: Specimen paces around cell. Appears agitated. Vocalisations.

-

PROCEDURE: Simian test subject

RESULTS: Devoured by specimen. No significant difference from last simian test.

Note: Time to amp it up

-

PROCEDURE: Human test subject (D-1). Instructed to \"pet it like a dog\"

RESULTS: Specimen and D-1 stare at each other for approximately two seconds. D-1 screams and begins pounding on observation window, begging to be released. Specimen pounces on D-1. Specimen kills D-1 with multiple slashes from its foreclaws.

Note: Promising!

-

PROCEDURE: Two human test subjects (D-2, D-3). Instructed to subdue specimen

RESULTS: D-2 and D-3 slowly approach specimen. D-3 punches specimen on forehead to no noticeable effect. Specimen pounces on D-3, then kills him with multiple slashes from its foreclaws. D-2 screams and begins pounding on observation window. Specimen pounces on D-2, then kills him with multiple slashes from its foreclaws.

Specimen begins slashing at observation access doors. Exhibiting an unexpected amount of strength, it is able to d~

" + info = "

TEST LOG

SPECIMEN: Bioweapon candidate Kappa. Individual 3


\n

-

PROCEDURE: Observation

RESULTS: Specimen paces around cell. Appears agitated. Vocalisations.

-

PROCEDURE: Simian test subject

RESULTS: Nested by specimen. No significant difference from last simian test.

Note: Time to amp it up

-

PROCEDURE: Human test subject (D-1). Instructed to \"pet it like a dog\"

RESULTS: Specimen and D-1 stare at each other for approximately two seconds. D-1 screams and begins pounding on observation window, begging to be released. Specimen pounces on D-1. Specimen kills D-1 with multiple slashes from its foreclaws.

Note: Promising!

-

PROCEDURE: Two human test subjects (D-2, D-3). Instructed to subdue specimen

RESULTS: D-2 and D-3 slowly approach specimen. D-3 punches specimen on forehead to no noticeable effect. Specimen pounces on D-3, then kills him with multiple slashes from its foreclaws. D-2 screams and begins pounding on observation window. Specimen pounces on D-2, then kills him with multiple slashes from its foreclaws.

Specimen begins slashing at observation access doors. Exhibiting an unexpected amount of strength, it is able to d~

" /obj/item/paper/prison_station/interrogation_log name = "paper- 'Test Log'" diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 5b4e1951c6a0..6ff1cf0c45b6 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -1593,6 +1593,8 @@ not all weapons use normal magazines etc. load_into_chamber() itself is designed return TRUE if(user.is_mob_incapacitated()) return + if(HAS_TRAIT(user, TRAIT_HAULED)) + return if(world.time < guaranteed_delay_time) return if((world.time < wield_time || world.time < pull_time) && (delay_style & WEAPON_DELAY_NO_FIRE > 0)) diff --git a/code/modules/projectiles/gun_helpers.dm b/code/modules/projectiles/gun_helpers.dm index 51a5988f2fd0..d0ac0a49ed9e 100644 --- a/code/modules/projectiles/gun_helpers.dm +++ b/code/modules/projectiles/gun_helpers.dm @@ -530,7 +530,7 @@ DEFINES in setup.dm, referenced here. /mob/living/carbon/human/verb/holster_verb(unholster_number_offset = 1 as num) set name = "holster" set hidden = TRUE - if(usr.is_mob_incapacitated(TRUE) || usr.is_mob_restrained() || IsKnockDown() || HAS_TRAIT_FROM(src, TRAIT_UNDENSE, LYING_DOWN_TRAIT)) + if(usr.is_mob_incapacitated(TRUE) || usr.is_mob_restrained() || IsKnockDown() || HAS_TRAIT_FROM(src, TRAIT_UNDENSE, LYING_DOWN_TRAIT) && !HAS_TRAIT(src, TRAIT_HAULED)) to_chat(src, SPAN_WARNING("You can't draw a weapon in your current state.")) return @@ -543,7 +543,7 @@ DEFINES in setup.dm, referenced here. items_in_slot = get_item_by_slot(active_hand.preferred_storage[storage]) else items_in_slot = list(get_item_by_slot(active_hand.preferred_storage[storage])) - + for(var/item_in_slot in items_in_slot) if(istype(item_in_slot, storage)) var/slot = active_hand.preferred_storage[storage] @@ -560,7 +560,7 @@ DEFINES in setup.dm, referenced here. slot = WEAR_IN_HELMET if(WEAR_FEET) slot = WEAR_IN_SHOES - + if(equip_to_slot_if_possible(active_hand, slot, ignore_delay = TRUE, del_on_fail = FALSE, disable_warning = TRUE, redraw_mob = TRUE)) return TRUE if(w_uniform) diff --git a/code/modules/projectiles/guns/flamer/flamer.dm b/code/modules/projectiles/guns/flamer/flamer.dm index 42e42d6d0165..0192f07137d1 100644 --- a/code/modules/projectiles/guns/flamer/flamer.dm +++ b/code/modules/projectiles/guns/flamer/flamer.dm @@ -742,7 +742,10 @@ burn_damage = 0 if(!burn_damage) - to_chat(M, SPAN_DANGER("[isxeno(M) ? "We" : "You"] step over the flames.")) + if(HAS_TRAIT(M, TRAIT_HAULED)) + M.visible_message(SPAN_WARNING("[M] is shielded from the flames!"), SPAN_WARNING("You are shielded from the flames!")) + else + to_chat(M, SPAN_DANGER("[isxeno(M) ? "We" : "You"] step over the flames.")) return M.last_damage_data = weapon_cause_data diff --git a/strings/memetips.txt b/strings/memetips.txt index 1767d8688953..2b7c20d4a807 100644 --- a/strings/memetips.txt +++ b/strings/memetips.txt @@ -4,7 +4,7 @@ One shotgun isn't enough. Take six. Don't do the conga, the queen mother knows all. Jones is very important. Protect him at all costs. Install VSC. -Devouring is useful to quickly transport incapacitated hosts from one place to another. In order to devour a host as a Xeno, grab the mob (CTRL + Click) and then click on yourself to begin devouring. The host can break out of your belly, which will result in your death - so make sure your target is incapacitated! After approximately 1 minute the host will be automatically regurgitated. To release your target voluntarily, click 'Regurgitate' on the HUD to throw them back up. +Hauling is useful to quickly transport incapacitated hosts from one place to another. In order to haul a host as a Xeno, grab the mob (CTRL + Click) and then click on yourself to begin restarining them. The host can break out of your grip, which will result in your death - so make sure your target is incapacitated! After approximately 1 minute the host will be automatically be released. To release your target voluntarily, click 'Release' on the HUD to drop them on the ground. As an MP, remember that staff may give you antagonist objectives to help weaken the marines! There's actually a hidden box of HEFA grenades in Requisitions. It can be reached by having one of your buddies throw you down the ASRS elevator. Don't waste crayons by jamming them up your nose - they make excellent emergency rations in a pinch! From 6417fae0cfff57a9cd9c4156c0cc6e6a6f3261dc Mon Sep 17 00:00:00 2001 From: casperr04 Date: Sat, 8 Feb 2025 15:34:34 +0100 Subject: [PATCH 02/15] Empty lines --- code/_onclick/item_attack.dm | 3 --- 1 file changed, 3 deletions(-) diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 66cda367fab9..96c65fb1b25e 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -152,6 +152,3 @@ playsound(loc, hitsound, 25, 1) return (hit|ATTACKBY_HINT_UPDATE_NEXT_MOVE) return (ATTACKBY_HINT_NO_AFTERATTACK|ATTACKBY_HINT_UPDATE_NEXT_MOVE) - - - From baf54d332e6d6412b8047fa6a20e1c2f06814ab6 Mon Sep 17 00:00:00 2001 From: casperr04 Date: Sun, 9 Feb 2025 07:36:29 +0100 Subject: [PATCH 03/15] no rotation --- code/modules/mob/living/carbon/carbon.dm | 13 ++++----- .../mob/living/carbon/xenomorph/XenoProcs.dm | 29 ------------------- code/modules/mob/living/living.dm | 2 -- 3 files changed, 5 insertions(+), 39 deletions(-) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 55a9d9b68c59..b3949463c892 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -458,18 +458,18 @@ // Adding traits, etc after xeno restrains and hauls us /mob/living/carbon/human/proc/handle_haul(mob/living/carbon/xenomorph/xeno) - setDir(EAST) - xeno.hauled_mob_change_dir(xeno.dir, src) ADD_TRAIT(src, TRAIT_HAULED, TRAIT_SOURCE_XENO_HAUL) ADD_TRAIT(src, TRAIT_NO_STRAY, TRAIT_SOURCE_XENO_HAUL) ADD_TRAIT(src, TRAIT_FLOORED, TRAIT_SOURCE_XENO_HAUL) ADD_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_SOURCE_XENO_HAUL) + hauling_xeno = xeno RegisterSignal(xeno, COMSIG_MOB_DEATH, PROC_REF(release_haul_death)) RegisterSignal(src, COMSIG_LIVING_PREIGNITION, PROC_REF(haul_fire_shield)) RegisterSignal(src, list(COMSIG_LIVING_FLAMER_CROSSED, COMSIG_LIVING_FLAMER_FLAMED), PROC_REF(haul_fire_shield_callback)) layer = LYING_BETWEEN_MOB_LAYER - + add_filter("hauled_shadow", 1, color_matrix_filter(rgb(95, 95, 95))) + pixel_y = -10 /mob/living/carbon/human/proc/release_haul_death() SIGNAL_HANDLER @@ -491,11 +491,12 @@ forceMove(location) src.remove_traits(list(TRAIT_HAULED, TRAIT_NO_STRAY, TRAIT_FLOORED, TRAIT_IMMOBILIZED), TRAIT_SOURCE_XENO_HAUL) pixel_y = 0 - pixel_x = 0 UnregisterSignal(src, list(COMSIG_LIVING_PREIGNITION, COMSIG_LIVING_FLAMER_CROSSED, COMSIG_LIVING_FLAMER_FLAMED)) UnregisterSignal(hauling_xeno, COMSIG_MOB_DEATH) hauling_xeno = null layer = MOB_LAYER + remove_filter("hauled_shadow") + /mob/living/carbon/on_stored_atom_del(atom/movable/AM) @@ -562,7 +563,3 @@ else set_lying_angle(new_lying_angle) -/mob/living/carbon/human/setDir(newdir) - if(HAS_TRAIT(src, TRAIT_HAULED)) - return - . = ..() diff --git a/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm b/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm index 29f46a4651aa..98a4db60505b 100644 --- a/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm +++ b/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm @@ -424,34 +424,6 @@ victim.forceMove(src.loc, get_dir(victim.loc, src.loc)) victim.handle_haul(src) RegisterSignal(victim, COMSIG_MOB_DEATH, PROC_REF(release_dead_haul)) - RegisterSignal(src, COMSIG_ATOM_DIR_CHANGE, PROC_REF(on_dir_change)) - -/mob/living/carbon/xenomorph/proc/on_dir_change(src, olddir, newdir) - SIGNAL_HANDLER - var/mob/living/carbon/human/hauled = hauled_mob.resolve() - hauled_mob_change_dir(newdir, hauled) - -/mob/living/carbon/xenomorph/proc/hauled_mob_change_dir(direction, mob/living/carbon/human/hauled) - var/matrix/base = matrix() - var/angle - switch(direction) - if(NORTH) - angle = 180 - hauled.pixel_x = 0 - hauled.pixel_y = -13 - if(SOUTH) - angle = 0 - hauled.pixel_x = 0 - hauled.pixel_y = 10 - if(EAST) - angle = 250 - hauled.pixel_x = -13 - hauled.pixel_y = -8 - if(WEST) - angle = 110 - hauled.pixel_x = 12 - hauled.pixel_y = -8 - hauled.apply_transform(base.Turn(angle), 0) // Releasing a dead hauled mob /mob/living/carbon/xenomorph/proc/release_dead_haul() @@ -461,7 +433,6 @@ user.handle_unhaul() UnregisterSignal(user, COMSIG_MOB_DEATH) UnregisterSignal(src, COMSIG_ATOM_DIR_CHANGE) - hauled_mob = null // Releasing a hauled mob diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 4f5d8e96e675..05e5cebf3ba7 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -677,8 +677,6 @@ /mob/living/update_transform(instant_update = FALSE) - if(HAS_TRAIT(src, TRAIT_HAULED)) - return var/visual_angle = lying_angle if(!rotate_on_lying) return From 85cce050cd62a165c3c0c89ea96f847708d47c4f Mon Sep 17 00:00:00 2001 From: casperr04 Date: Mon, 10 Feb 2025 10:01:12 +0100 Subject: [PATCH 04/15] nuke stomach_contents() --- code/__DEFINES/traits.dm | 2 +- code/__DEFINES/typecheck/xenos.dm | 6 +- code/_onclick/item_attack.dm | 26 -------- code/modules/mob/living/carbon/carbon.dm | 57 ++++++++++++------ .../mob/living/carbon/xenomorph/Evolution.dm | 2 +- .../mob/living/carbon/xenomorph/XenoProcs.dm | 38 ++++-------- .../mob/living/carbon/xenomorph/Xenomorph.dm | 5 +- .../xenomorph/abilities/general_abilities.dm | 2 +- .../living/carbon/xenomorph/hive_status.dm | 8 +-- code/modules/mob/mob_grab.dm | 4 +- icons/mob/hud/actions_xeno.dmi | Bin 57962 -> 58515 bytes 11 files changed, 66 insertions(+), 84 deletions(-) diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 80aec59c6dea..9a1600012baa 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -163,7 +163,7 @@ #define TRAIT_TEMPORARILY_MUTED "temporarily_muted" /// Mob wont get hit by stray projectiles #define TRAIT_NO_STRAY "trait_no_stray" -/// We can take out our knife or gun if hauled though we are immobilized, also shielded from most damage. +/// When a Xeno hauls us. We can take out our knife or gun if hauled though we are immobilized, also shielded from most damage. #define TRAIT_HAULED "hauled" // SPECIES TRAITS diff --git a/code/__DEFINES/typecheck/xenos.dm b/code/__DEFINES/typecheck/xenos.dm index bc9dbbadcf15..4a6a866b0b77 100644 --- a/code/__DEFINES/typecheck/xenos.dm +++ b/code/__DEFINES/typecheck/xenos.dm @@ -30,8 +30,7 @@ /mob/living/carbon/xenomorph/proc/can_not_harm(mob/living/carbon/attempt_harm_mob) if(!istype(attempt_harm_mob)) return FALSE - if(HAS_TRAIT(attempt_harm_mob, TRAIT_HAULED)) - return TRUE + if(!hive) hive = GLOB.hive_datum[hivenumber] @@ -43,6 +42,9 @@ var/datum/hive_status/corrupted/renegade/renegade_hive = hive return renegade_hive.iff_protection_check(src, attempt_harm_mob) + if(HAS_TRAIT(attempt_harm_mob, TRAIT_HAULED)) + return TRUE + return hive.is_ally(attempt_harm_mob) // need this to set the data for walls/eggs/huggers when they are initialized diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 96c65fb1b25e..297791165098 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -37,35 +37,9 @@ else if(initiate_surgery_moment(I, src, null, user)) return TRUE */ - if(HAS_TRAIT(user, TRAIT_HAULED)) - if(src == user) // No stabbing ourselves to death - return - if(handle_haul_resist(user, src, I)) - return ATTACKBY_HINT_UPDATE_NEXT_MOVE - return if(istype(I) && ismob(user)) return I.attack(src, user) -/mob/living/proc/handle_haul_resist(mob/living/resister, mob/living/carbon/xenomorph/xeno, obj/item/item) // move this? - if(get_dist(xeno, resister)) // No stabbing xenos next to you REMOVE HUGGING HAULED MOBS - return FALSE - if(item.force) - var/damage_of_item = rand(floor(item.force / 4), item.force) - xeno.take_limb_damage(damage_of_item) - for(var/mob/mobs_in_view as anything in viewers(resister, null)) - if(mobs_in_view.client) - mobs_in_view.show_message(text(SPAN_DANGER("[resister] attacks [xeno]'s carapace with the [item.name]!")), SHOW_MESSAGE_AUDIBLE) - resister.track_hit(initial(item.name)) - playsound(resister.loc, 'sound/weapons/slash.ogg', 25, 1) - if(prob(max(4*(100*xeno.getBruteLoss()/xeno.maxHealth - 75),0))) //4% at 24% health, 80% at 5% health - xeno.last_damage_data = create_cause_data("scuffling", resister) - xeno.gib(last_damage_data) - return TRUE - else - for(var/mob/mobs_can_hear in hearers(4, xeno)) - if(mobs_can_hear.client) - mobs_can_hear.show_message(SPAN_DANGER("You hear [resister] struggling against [xeno]'s grip..."), SHOW_MESSAGE_AUDIBLE) - return TRUE // Proximity_flag is 1 if this afterattack was called on something adjacent, in your square, or on your person. // Click parameters is the params string from byond Click() code, see that documentation. diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index b3949463c892..ce98c3c5a5ce 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -15,7 +15,6 @@ remove_all_indicators() /mob/living/carbon/Destroy() - stomach_contents?.Cut() view_change_sources = null active_transfusions = null . = ..() @@ -85,37 +84,68 @@ recalculate_move_delay = TRUE ..() -/mob/living/carbon/human/attackby(obj/item/W, mob/living/user) +/mob/living/carbon/human/attackby(obj/item/weapon, mob/living/user) + if(HAS_TRAIT(user, TRAIT_HAULED)) + if(src == user) // No stabbing ourselves to death + return + if(handle_haul_resist(user, src, weapon)) + return ATTACKBY_HINT_UPDATE_NEXT_MOVE + return if(user.mob_flags & SURGERY_MODE_ON) switch(user.a_intent) if(INTENT_HELP) //Attempt to dig shrapnel first, if any. dig_out_shrapnel_check() will fail if user is not human, which may be possible in future. - if(W.flags_item & CAN_DIG_SHRAPNEL && (locate(/obj/item/shard) in src.embedded_items) && W.dig_out_shrapnel_check(src, user)) + if(weapon.flags_item & CAN_DIG_SHRAPNEL && (locate(/obj/item/shard) in src.embedded_items) && weapon.dig_out_shrapnel_check(src, user)) return TRUE var/datum/surgery/current_surgery = active_surgeries[user.zone_selected] if(current_surgery) - if(current_surgery.attempt_next_step(user, W)) + if(current_surgery.attempt_next_step(user, weapon)) return TRUE //Cancel attack. else var/obj/limb/affecting = get_limb(check_zone(user.zone_selected)) - if(initiate_surgery_moment(W, src, affecting, user)) + if(initiate_surgery_moment(weapon, src, affecting, user)) return TRUE if(INTENT_DISARM) //Same as help but without the shrapnel dig attempt. var/datum/surgery/current_surgery = active_surgeries[user.zone_selected] if(current_surgery) - if(current_surgery.attempt_next_step(user, W)) + if(current_surgery.attempt_next_step(user, weapon)) return TRUE else var/obj/limb/affecting = get_limb(check_zone(user.zone_selected)) - if(initiate_surgery_moment(W, src, affecting, user)) + if(initiate_surgery_moment(weapon, src, affecting, user)) return TRUE - else if(W.flags_item & CAN_DIG_SHRAPNEL && W.dig_out_shrapnel_check(src, user)) + else if(weapon.flags_item & CAN_DIG_SHRAPNEL && weapon.dig_out_shrapnel_check(src, user)) return TRUE . = ..() +/mob/living/carbon/human/proc/handle_haul_resist(mob/living/resister, mob/living/carbon/xenomorph/xeno, obj/item/item) + if(get_dist(xeno, resister)) + return FALSE + if(item.force) + var/damage_of_item = rand(floor(item.force / 4), item.force) + xeno.take_limb_damage(damage_of_item) + for(var/mob/mobs_in_view as anything in viewers(resister, null)) + if(mobs_in_view.client) + mobs_in_view.show_message(text(SPAN_DANGER("[resister] attacks [xeno]'s carapace with the [item.name]!")), SHOW_MESSAGE_AUDIBLE) + resister.track_hit(initial(item.name)) + if(item.sharp) + playsound(resister.loc, 'sound/weapons/slash.ogg', 25, 1) + else + var/hit_sound = pick('sound/weapons/genhit1.ogg', 'sound/weapons/genhit2.ogg', 'sound/weapons/genhit3.ogg') + playsound(resister.loc, hit_sound, 25, 1) + if(prob(max(4*(100*xeno.getBruteLoss()/xeno.maxHealth - 75),0))) //4% at 24% health, 80% at 5% health + xeno.last_damage_data = create_cause_data("scuffling", resister) + xeno.gib(last_damage_data) + return TRUE + else + for(var/mob/mobs_can_hear in hearers(4, xeno)) + if(mobs_can_hear.client) + mobs_can_hear.show_message(SPAN_DANGER("You hear [resister] struggling against [xeno]'s grip..."), SHOW_MESSAGE_AUDIBLE) + return TRUE + /mob/living/carbon/attack_hand(mob/target_mob as mob) // move it here probably if(!istype(target_mob, /mob/living/carbon)) return @@ -458,9 +488,9 @@ // Adding traits, etc after xeno restrains and hauls us /mob/living/carbon/human/proc/handle_haul(mob/living/carbon/xenomorph/xeno) + ADD_TRAIT(src, TRAIT_FLOORED, TRAIT_SOURCE_XENO_HAUL) ADD_TRAIT(src, TRAIT_HAULED, TRAIT_SOURCE_XENO_HAUL) ADD_TRAIT(src, TRAIT_NO_STRAY, TRAIT_SOURCE_XENO_HAUL) - ADD_TRAIT(src, TRAIT_FLOORED, TRAIT_SOURCE_XENO_HAUL) ADD_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_SOURCE_XENO_HAUL) hauling_xeno = xeno @@ -469,7 +499,7 @@ RegisterSignal(src, list(COMSIG_LIVING_FLAMER_CROSSED, COMSIG_LIVING_FLAMER_FLAMED), PROC_REF(haul_fire_shield_callback)) layer = LYING_BETWEEN_MOB_LAYER add_filter("hauled_shadow", 1, color_matrix_filter(rgb(95, 95, 95))) - pixel_y = -10 + pixel_y = -7 /mob/living/carbon/human/proc/release_haul_death() SIGNAL_HANDLER @@ -499,13 +529,6 @@ -/mob/living/carbon/on_stored_atom_del(atom/movable/AM) - ..() - if(length(stomach_contents) && ismob(AM)) - for(var/X in stomach_contents) - if(AM == X) - stomach_contents -= AM - break /mob/living/carbon/proc/extinguish_mob(mob/living/carbon/C) adjust_fire_stacks(-5, min_stacks = 0) diff --git a/code/modules/mob/living/carbon/xenomorph/Evolution.dm b/code/modules/mob/living/carbon/xenomorph/Evolution.dm index 666e06294ff8..fb1cdaf10829 100644 --- a/code/modules/mob/living/carbon/xenomorph/Evolution.dm +++ b/code/modules/mob/living/carbon/xenomorph/Evolution.dm @@ -21,7 +21,7 @@ GLOBAL_LIST_EMPTY(deevolved_ckeys) return var/mob/living/carbon/human/user = hauled_mob?.resolve() if(user) - to_chat("Release [user] before evolving!") + to_chat(src, "Release [user] before evolving!") return var/castes_available = caste.evolves_to.Copy() diff --git a/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm b/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm index 98a4db60505b..f18d64dca28b 100644 --- a/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm +++ b/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm @@ -386,17 +386,6 @@ /mob/living/carbon/xenomorph/proc/pounced_turf_wrapper(turf/T) pounced_turf(T) -//Bleuugh -/mob/living/carbon/xenomorph/proc/empty_gut() - if(length(stomach_contents)) - for(var/atom/movable/S in stomach_contents) - stomach_contents.Remove(S) - S.acid_damage = 0 //Reset the acid damage - S.forceMove(get_true_turf(src)) - - if(length(contents)) //Get rid of anything that may be stuck inside us as well - for(var/atom/movable/A in contents) - A.forceMove(get_true_turf(src)) /mob/living/carbon/xenomorph/proc/toggle_nightvision() see_in_dark = 12 @@ -424,6 +413,16 @@ victim.forceMove(src.loc, get_dir(victim.loc, src.loc)) victim.handle_haul(src) RegisterSignal(victim, COMSIG_MOB_DEATH, PROC_REF(release_dead_haul)) + haul_timer = addtimer(CALLBACK(src, PROC_REF(about_to_release_hauled)), 40 SECONDS + rand(0 SECONDS, 20 SECONDS), TIMER_STOPPABLE) + +/mob/living/carbon/xenomorph/proc/about_to_release_hauled() + var/mob/living/carbon/human/user = hauled_mob?.resolve() + if(!user) + deltimer(haul_timer) + return + to_chat(src, SPAN_XENOWARNING("We feel our grip loosen on [user], we will have to release them soon.")) + playsound(src, 'sound/voice/alien_hiss2.ogg', 15) + haul_timer = addtimer(CALLBACK(src, PROC_REF(release_haul)), 10 SECONDS, TIMER_STOPPABLE) // Releasing a dead hauled mob /mob/living/carbon/xenomorph/proc/release_dead_haul() @@ -434,6 +433,7 @@ UnregisterSignal(user, COMSIG_MOB_DEATH) UnregisterSignal(src, COMSIG_ATOM_DIR_CHANGE) hauled_mob = null + deltimer(haul_timer) // Releasing a hauled mob /mob/living/carbon/xenomorph/proc/release_haul(stuns = FALSE) @@ -444,27 +444,13 @@ user.handle_unhaul() visible_message(SPAN_XENOWARNING("[src] releases [user] from their grip!"), SPAN_XENOWARNING("We release [user] from our grip!"), null, 5) - playsound(get_true_location(loc), 'sound/voice/alien_growl1.ogg', 15) + playsound(src, 'sound/voice/alien_growl1.ogg', 15) log_interact(src, user, "[key_name(src)] released [key_name(user)] at [get_area_name(loc)]") if(stuns) user.adjust_effect(2, STUN) UnregisterSignal(user, COMSIG_MOB_DEATH) UnregisterSignal(src, COMSIG_ATOM_DIR_CHANGE) hauled_mob = null - // if(length(stomach_contents)) - // if(victim) - // stomach_contents.Remove(victim) - // victim.acid_damage = 0 - // victim.forceMove(get_true_turf(loc)) - - // visible_message(SPAN_XENOWARNING("[src] releases [victim] from their grip!"), - // SPAN_XENOWARNING("We release [victim] from our grip!"), null, 5) - // playsound(get_true_location(loc), 'sound/voice/alien_growl1.ogg', 15) - // log_interact(src, victim, "[key_name(src)] released [key_name(victim)] at [get_area_name(loc)]") - - // if (stuns) - // victim.adjust_effect(2, STUN) - // else /mob/living/carbon/xenomorph/proc/check_alien_construction(turf/current_turf, check_blockers = TRUE, silent = FALSE, check_doors = TRUE, ignore_nest = FALSE) var/has_obstacle diff --git a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm index 8fb05a6ee76c..951416c9a0cc 100644 --- a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm +++ b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm @@ -62,6 +62,9 @@ var/obj/item/l_store = null // Mob we are hauling var/datum/weakref/hauled_mob + // Haul timer + var/haul_timer + var/obj/item/iff_tag/iff_tag = null var/static/list/walking_state_cache = list() @@ -279,8 +282,6 @@ /// 0/FALSE - upright, 1/TRUE - all fours var/agility = FALSE var/ripping_limb = FALSE - /// The world.time at which we will release our currently-restrained victim - var/haul_timer = 0 /// For drones/hivelords. Extends the maximum build range they have var/extra_build_dist = 0 /// tiles from self you can plant eggs. diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm b/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm index 8024597ba708..c25b726c99ea 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm @@ -62,7 +62,7 @@ // release_haul /datum/action/xeno_action/onclick/release_haul name = "Release" - action_icon_state = "regurgitate" + action_icon_state = "release_haul" plasma_cost = 0 macro_path = /datum/action/xeno_action/verb/verb_release_haul action_type = XENO_ACTION_CLICK diff --git a/code/modules/mob/living/carbon/xenomorph/hive_status.dm b/code/modules/mob/living/carbon/xenomorph/hive_status.dm index c10d5b9bdc07..5fcb60ef8ad5 100644 --- a/code/modules/mob/living/carbon/xenomorph/hive_status.dm +++ b/code/modules/mob/living/carbon/xenomorph/hive_status.dm @@ -708,9 +708,6 @@ if(get_area(xeno) != hijacked_dropship && xeno.loc && is_ground_level(xeno.loc.z)) if(isfacehugger(xeno) || islesserdrone(xeno)) to_chat(xeno, SPAN_XENOANNOUNCE("The Queen has left without you, you quickly find a hiding place to enter hibernation as you lose touch with the hive mind.")) - if(length(xeno.stomach_contents)) - xeno.haul_timer = 0 - xeno.handle_stomach_contents() qdel(xeno) continue if(xeno.hunter_data.hunted && !isqueen(xeno)) @@ -718,9 +715,8 @@ xeno.set_hive_and_update(XENO_HIVE_FORSAKEN) else to_chat(xeno, SPAN_XENOANNOUNCE("The Queen has left without you, you quickly find a hiding place to enter hibernation as you lose touch with the hive mind.")) - if(length(xeno.stomach_contents)) - xeno.haul_timer = 0 - xeno.handle_stomach_contents() + if(xeno.hauled_mob?.resolve()) + xeno.release_haul(hauled_mob.resolve()) qdel(xeno) stored_larva++ continue diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm index 61333c3602da..c97bdbbc2deb 100644 --- a/code/modules/mob/mob_grab.dm +++ b/code/modules/mob/mob_grab.dm @@ -144,10 +144,10 @@ if(HAS_TRAIT(xeno, TRAIT_CLOAKED)) //cloaked don't show the visible message, so we gotta work around to_chat(pulled, FONT_SIZE_HUGE(SPAN_DANGER("[xeno] is trying to restrain you!"))) if(do_after(xeno, 50, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) - if(isxeno(pulled.loc) && !length(xeno.stomach_contents)) + if(isxeno(pulled.loc) && !xeno.hauled_mob) to_chat(xeno, SPAN_WARNING("Someone already took \the [pulled].")) return 0 - if(xeno.pulling == pulled && !pulled.buckled && (pulled.stat != DEAD || pulled.chestburst) && !length(xeno.stomach_contents)) //make sure you've still got them in your claws, and alive + if(xeno.pulling == pulled && !pulled.buckled && (pulled.stat != DEAD || pulled.chestburst) && !xeno.hauled_mob) //make sure you've still got them in your claws, and alive if(SEND_SIGNAL(pulled, COMSIG_MOB_HAULED, xeno) & COMPONENT_CANCEL_HAUL) return FALSE xeno.haul(pulled) diff --git a/icons/mob/hud/actions_xeno.dmi b/icons/mob/hud/actions_xeno.dmi index 578909103c1a76233eae683cf6c9930e789a062a..83113f4fc2bdefd17e32e742a0c92f6d8bbbe393 100644 GIT binary patch delta 14127 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 F{{o~a;THe^ delta 13570 zcmaKSWl&tv(k%|b-GjSBAUHz^gainZ;5Na6yX%4A?ykYz-6cS9cPGH$1REUQ*#RfA;CG|K*d(+8p{FUa}v2BkuOaF_dV z725UKuZ045&K1{dOUf7ZZ_h!p6|qlVQg+=fS=mMVa~Y?-+op6eByF>=Wc15$293+< z7}@=`jfg(69(dWGV#1AF&Li06Hpg6za&RSpX&g_b5}9@0@S(DVgS9`9!l_$|+MYdQ z4oY&Q-BOB>A67S%n6=u)7GjXpG?eU{6~8CQ_BR4(lA2tB!T`_=U+=#Q%EaDgQkzTd zL)8e{PbhpDjQ_~23%accGBM^ zCA}^CIvQojvSt2_Oa#dj$$X0x3TDO;7e2km$VkCvL;4N`=9jh%22kB9aY?PK`-giK z0M&BJJQHDlZC%dRle;kqg`7Lfw3<5wx8tD{@-9uex0g-@)zbdT#bXy91w}TO9F38I zfA%hw50W!=V9u*%B<7M9vyWTv@mjpmMY}YO^jK|XZC%Q{-@SB#@_pV6K_=dyq%Aw% zxj{hxuLuMCy{TE%K}i6Fh=?dX*gvxh%#P~4Tv;z`r&sf*n3r2^Urk9pcRpaTj)kpBCmunATu@l38 z(d4(Wc{@gwXy&9cEf8S-3VVj_Oi)7=Ur<{>Cotl@Yk${JH6PLD^V5k+>+ep5n1o&i z8|S8~c~8B*f0zCBV-P{3@lGF!uGmxR%3GVL9lUuT`&H{Mt;_s}zJ7Y<<}J&OD>p9L z;2VrVs0bwzN+~JnK5F;(WF!Tk!XA7fCgDj1H^)3tdpqCuA)~0SF0nbkrbA2V7i7F} z@0V78dfoiol#yjoRYfw)*B(|U_28s-i9~gI$!bK;HmnN$U@j&+*k^|xI<5 zZq9vNET__A3dQ`|Xgj0)(#5Z6c(nOu`T5s4Vrbo{z%#pGd9qknKftbmsI06k>7A*P zC;@3zIZ;|$md2Onm_gTM%81}?V5_fHXzTMX8-zcO0loYNv%-b^Fc7?*49ovAcFaPlP98GPwFb(nb`nrh!SURDS3 zK>$7}%kFAz@+#6tsvM3VKVx}|r3}=ebRwLbk~~Z7$wp%K0pA+Z(*-vCyR)A zNkP@#@odH*DHmn-OG=V-c&`QQ)4#&>yA5z(tf-LWIauHZ@(ZsRdMpI=^xjJORdP}I z`LQjhwLfeXaA#mhTJ3R+CN>Pa?OnU;F21~SOx_5qsLa~jXF)m69Da7dp0p^VHy;<% zE>+A6pTrlm^&5QLG-j~{{gBJ+^_jx%&b>SG_IM8Y%^-2NqGQ#5NiEw>5}zXJ=EdT= zdQa0Zz(x}Th*GyEM?YVXj8k$laB-1YDsh+Q(9CVC-SMk|$>*XL5MXSwPIbVf+RmE2 z1bRm92LS`7bY=~WI7BT@x#9cFV!V;KdMu4781{~Ji9eG5N}KA-Lvho&bfuF?5gCjc z=3z?)uO|1=iA}TPXBya=8u;zN;q*{?u%>asUtrb48&SFz4 z+Cjl-9>H)XKHoATG%?^}Plq=-(SVCRucF3=4ull_d%Nk7y-c&&j@EP{t6809ybfCJYS6f%RR&&5x&9<@Fyz6 z=rOtIvC?`eX&GLIe2KPtb_cU;+h4Z)rK5i+E|DvHMRd¨tM^hPDsyhO##80PaZv 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 Date: Mon, 10 Feb 2025 11:26:21 +0100 Subject: [PATCH 05/15] inventory stuff --- code/_onclick/human.dm | 2 +- code/_onclick/item_attack.dm | 7 +++++++ .../items/explosives/grenades/grenade.dm | 3 +++ code/game/objects/items/storage/storage.dm | 10 ++++++---- code/modules/mob/inventory.dm | 3 +++ code/modules/mob/living/carbon/carbon.dm | 8 +------- .../mob/living/carbon/carbon_defines.dm | 1 - .../mob/living/carbon/human/inventory.dm | 4 ++++ .../mob/living/carbon/xenomorph/XenoProcs.dm | 3 ++- .../mob/living/carbon/xenomorph/Xenomorph.dm | 3 ++- .../living/carbon/xenomorph/damage_procs.dm | 3 --- .../mob/living/carbon/xenomorph/death.dm | 4 ---- .../living/carbon/xenomorph/hive_status.dm | 2 +- .../mob/living/carbon/xenomorph/life.dm | 19 +------------------ 14 files changed, 31 insertions(+), 41 deletions(-) diff --git a/code/_onclick/human.dm b/code/_onclick/human.dm index 1091eab4b5ba..48d112218933 100644 --- a/code/_onclick/human.dm +++ b/code/_onclick/human.dm @@ -70,7 +70,7 @@ /mob/living/carbon/human/UnarmedAttack(atom/A, proximity, click_parameters) - if(body_position == LYING_DOWN) //No attacks while laying down + if(body_position == LYING_DOWN && !HAS_TRAIT(src, TRAIT_HAULED)) //No attacks while laying down return 0 var/obj/item/clothing/gloves/G = gloves // not typecast specifically enough in defines diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 297791165098..965dad127a0f 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -37,6 +37,13 @@ else if(initiate_surgery_moment(I, src, null, user)) return TRUE */ + if(HAS_TRAIT(user, TRAIT_HAULED)) + var/mob/living/carbon/human/victim = user + if(src == victim) // No stabbing ourselves to death + return + if(victim.handle_haul_resist(user, src, I)) + return ATTACKBY_HINT_UPDATE_NEXT_MOVE + return if(istype(I) && ismob(user)) return I.attack(src, user) diff --git a/code/game/objects/items/explosives/grenades/grenade.dm b/code/game/objects/items/explosives/grenades/grenade.dm index f157d7f8d931..e70a4b0373c6 100644 --- a/code/game/objects/items/explosives/grenades/grenade.dm +++ b/code/game/objects/items/explosives/grenades/grenade.dm @@ -44,6 +44,9 @@ to_chat(user, SPAN_WARNING("Your programming prevents you from using this!")) return FALSE + if(HAS_TRAIT(src, TRAIT_HAULED)) // If somehow they have a grenade in hand while hauled, we don't want them to prime it + return FALSE + return TRUE /obj/item/explosive/grenade/dropped(mob/user) diff --git a/code/game/objects/items/storage/storage.dm b/code/game/objects/items/storage/storage.dm index 9a8b43be53eb..61c00334cbdd 100644 --- a/code/game/objects/items/storage/storage.dm +++ b/code/game/objects/items/storage/storage.dm @@ -404,10 +404,10 @@ GLOBAL_LIST_EMPTY_TYPED(item_storage_box_cache, /datum/item_storage_box) if(cur_stack.amount < cur_stack.max_amount && new_stack.stack_id == cur_stack.stack_id) return TRUE - + if(storage_slots != null && length(contents) < storage_slots) return TRUE //At least one open slot. - + //calculate storage space only for containers that don't have slots if (storage_slots == null) var/sum_storage_cost = W_class_override ? W_class_override : new_item.get_storage_cost() //Takes the override if there is one, the given item otherwise. @@ -510,12 +510,12 @@ user can be null, it refers to the potential mob doing the insertion.**/ if(!istype(cur_item, /obj/item/stack)) continue var/obj/item/stack/cur_stack = cur_item - + if(cur_stack.amount < cur_stack.max_amount && new_stack.stack_id == cur_stack.stack_id) var/amount = min(cur_stack.max_amount - cur_stack.amount, new_stack.amount) new_stack.use(amount) cur_stack.add(amount) - + if(!QDELETED(new_stack) && can_be_inserted(new_stack, user)) if(!user.drop_inv_item_to_loc(new_item, src)) return FALSE @@ -615,6 +615,8 @@ W is always an item. stop_warning prevents messaging. user may be null.**/ return handle_item_insertion(W, prevent_warning, user) /obj/item/storage/attack_hand(mob/user, mods) + if(HAS_TRAIT(user, TRAIT_HAULED)) + return if (loc == user) if((mods && mods["alt"] || storage_flags & STORAGE_USING_DRAWING_METHOD) && ishuman(user) && length(contents)) //Alt mod can reach attack_hand through the clicked() override. var/obj/item/I diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index 286645fc7001..f55c024baf29 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -161,6 +161,9 @@ if(is_mob_incapacitated()) return + if(HAS_TRAIT(src, TRAIT_HAULED)) + return + if(pickup_recent_item_on_turf(user_turf)) return diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index ce98c3c5a5ce..b50c450d0abd 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -85,12 +85,6 @@ ..() /mob/living/carbon/human/attackby(obj/item/weapon, mob/living/user) - if(HAS_TRAIT(user, TRAIT_HAULED)) - if(src == user) // No stabbing ourselves to death - return - if(handle_haul_resist(user, src, weapon)) - return ATTACKBY_HINT_UPDATE_NEXT_MOVE - return if(user.mob_flags & SURGERY_MODE_ON) switch(user.a_intent) if(INTENT_HELP) @@ -125,7 +119,7 @@ if(get_dist(xeno, resister)) return FALSE if(item.force) - var/damage_of_item = rand(floor(item.force / 4), item.force) + var/damage_of_item = rand(floor(item.force / 4), item.force - item.force / 6) xeno.take_limb_damage(damage_of_item) for(var/mob/mobs_in_view as anything in viewers(resister, null)) if(mobs_in_view.client) diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm index 03a8abef22af..f3a1134557a3 100644 --- a/code/modules/mob/living/carbon/carbon_defines.dm +++ b/code/modules/mob/living/carbon/carbon_defines.dm @@ -1,7 +1,6 @@ /mob/living/carbon gender = MALE mobility_flags = MOBILITY_FLAGS_CARBON_DEFAULT - var/list/stomach_contents = list() var/life_tick = 0 // The amount of life ticks that have processed on this mob. diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index 90a2b72653d1..4834abc7440a 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -106,6 +106,10 @@ if(!. || !I) return FALSE + if(HAS_TRAIT(src, TRAIT_HAULED)) + if(!isgun(I) || !isweapon(I)) + return FALSE + if(I == wear_suit) if(s_store && !(s_store.flags_equip_slot & SLOT_SUIT_STORE)) drop_inv_item_on_ground(s_store) diff --git a/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm b/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm index f18d64dca28b..45857f37e2a9 100644 --- a/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm +++ b/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm @@ -427,16 +427,17 @@ // Releasing a dead hauled mob /mob/living/carbon/xenomorph/proc/release_dead_haul() SIGNAL_HANDLER + deltimer(haul_timer) var/mob/living/carbon/human/user = hauled_mob?.resolve() to_chat(src, SPAN_XENOWARNING("[user] is dead. No more use for them now.")) user.handle_unhaul() UnregisterSignal(user, COMSIG_MOB_DEATH) UnregisterSignal(src, COMSIG_ATOM_DIR_CHANGE) hauled_mob = null - deltimer(haul_timer) // Releasing a hauled mob /mob/living/carbon/xenomorph/proc/release_haul(stuns = FALSE) + deltimer(haul_timer) var/mob/living/carbon/human/user = hauled_mob?.resolve() if(!user) to_chat(src, SPAN_WARNING("We are not hauling anyone.")) diff --git a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm index 951416c9a0cc..6f3dcf011a8b 100644 --- a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm +++ b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm @@ -398,7 +398,8 @@ //If we're holding things drop them for(var/obj/item/item in old_xeno.contents) //Drop stuff old_xeno.drop_inv_item_on_ground(item) - old_xeno.empty_gut() + if(old_xeno.hauled_mob?.resolve()) + old_xeno.release_haul(old_xeno.hauled_mob.resolve()) if(old_xeno.iff_tag) iff_tag = old_xeno.iff_tag diff --git a/code/modules/mob/living/carbon/xenomorph/damage_procs.dm b/code/modules/mob/living/carbon/xenomorph/damage_procs.dm index efeac5dd9eb6..7da87d506cfa 100644 --- a/code/modules/mob/living/carbon/xenomorph/damage_procs.dm +++ b/code/modules/mob/living/carbon/xenomorph/damage_procs.dm @@ -54,9 +54,6 @@ last_damage_data = istype(cause_data) ? cause_data : create_cause_data(cause_data) - if(severity > EXPLOSION_THRESHOLD_LOW && length(stomach_contents)) - for(var/mob/M in stomach_contents) - M.ex_act(severity - EXPLOSION_THRESHOLD_LOW, last_damage_data, pierce) var/b_loss = 0 var/f_loss = 0 diff --git a/code/modules/mob/living/carbon/xenomorph/death.dm b/code/modules/mob/living/carbon/xenomorph/death.dm index 8fde83c43bd5..946914f185dc 100644 --- a/code/modules/mob/living/carbon/xenomorph/death.dm +++ b/code/modules/mob/living/carbon/xenomorph/death.dm @@ -103,10 +103,6 @@ if(behavior_delegate) behavior_delegate.handle_death(src) - for(var/atom/movable/A in stomach_contents) - stomach_contents.Remove(A) - A.acid_damage = 0 //Reset the acid damage - A.forceMove(loc) // Banished xeno provide a burrowed larva on death to compensate if(banished && refunds_larva_if_banished) diff --git a/code/modules/mob/living/carbon/xenomorph/hive_status.dm b/code/modules/mob/living/carbon/xenomorph/hive_status.dm index 5fcb60ef8ad5..2ca6fd5fc644 100644 --- a/code/modules/mob/living/carbon/xenomorph/hive_status.dm +++ b/code/modules/mob/living/carbon/xenomorph/hive_status.dm @@ -716,7 +716,7 @@ else to_chat(xeno, SPAN_XENOANNOUNCE("The Queen has left without you, you quickly find a hiding place to enter hibernation as you lose touch with the hive mind.")) if(xeno.hauled_mob?.resolve()) - xeno.release_haul(hauled_mob.resolve()) + xeno.release_haul(xeno.hauled_mob.resolve()) qdel(xeno) stored_larva++ continue diff --git a/code/modules/mob/living/carbon/xenomorph/life.dm b/code/modules/mob/living/carbon/xenomorph/life.dm index 23072e3f3676..749fa1e52691 100644 --- a/code/modules/mob/living/carbon/xenomorph/life.dm +++ b/code/modules/mob/living/carbon/xenomorph/life.dm @@ -22,7 +22,6 @@ handle_xeno_fire() handle_pheromones() handle_regular_status_updates() - handle_stomach_contents() handle_overwatch() // For new Xeno hivewide overwatch - Fourk, 6/24/19 update_icons() handle_luminosity() @@ -218,23 +217,7 @@ return TRUE -/mob/living/carbon/xenomorph/proc/handle_stomach_contents() - //Deal with dissolving/damaging stuff in stomach. This sucks man. - if(length(stomach_contents)) - for(var/atom/movable/M in stomach_contents) - if(ishuman(M)) - if(world.time > haul_timer - 50 && world.time < haul_timer - 30) - to_chat(src, SPAN_WARNING("We're about to release [M] from our grip..")) - playsound(loc, 'sound/voice/alien_hiss2.ogg', 50) - var/mob/living/carbon/human/H = M - if(world.time > haul_timer || (H.stat == DEAD && !H.chestburst)) - release_haul(FALSE) - - // M.acid_damage++ - // if(M.acid_damage > 300) - // to_chat(src, SPAN_XENODANGER("\The [M] is dissolved in our gut with a gurgle.")) - // stomach_contents.Remove(M) - // qdel(M) + /mob/living/carbon/xenomorph/proc/handle_regular_hud_updates() if(!mind) From 292642eeff078f182219b58174bd97e85a921e05 Mon Sep 17 00:00:00 2001 From: casperr04 Date: Mon, 10 Feb 2025 12:16:28 +0100 Subject: [PATCH 06/15] fixes --- code/game/objects/items/explosives/grenades/grenade.dm | 2 +- code/modules/mob/living/carbon/carbon.dm | 2 +- code/modules/mob/mob_grab.dm | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/code/game/objects/items/explosives/grenades/grenade.dm b/code/game/objects/items/explosives/grenades/grenade.dm index e70a4b0373c6..2ddd588890d1 100644 --- a/code/game/objects/items/explosives/grenades/grenade.dm +++ b/code/game/objects/items/explosives/grenades/grenade.dm @@ -44,7 +44,7 @@ to_chat(user, SPAN_WARNING("Your programming prevents you from using this!")) return FALSE - if(HAS_TRAIT(src, TRAIT_HAULED)) // If somehow they have a grenade in hand while hauled, we don't want them to prime it + if(HAS_TRAIT(user, TRAIT_HAULED)) // If somehow they have a grenade in hand while hauled, we don't want them to prime it return FALSE return TRUE diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index b50c450d0abd..5c737e03b1f2 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -119,7 +119,7 @@ if(get_dist(xeno, resister)) return FALSE if(item.force) - var/damage_of_item = rand(floor(item.force / 4), item.force - item.force / 6) + var/damage_of_item = rand(floor(item.force / 6), floor(item.force / 2)) xeno.take_limb_damage(damage_of_item) for(var/mob/mobs_in_view as anything in viewers(resister, null)) if(mobs_in_view.client) diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm index c97bdbbc2deb..5e92e67236ae 100644 --- a/code/modules/mob/mob_grab.dm +++ b/code/modules/mob/mob_grab.dm @@ -147,7 +147,7 @@ if(isxeno(pulled.loc) && !xeno.hauled_mob) to_chat(xeno, SPAN_WARNING("Someone already took \the [pulled].")) return 0 - if(xeno.pulling == pulled && !pulled.buckled && (pulled.stat != DEAD || pulled.chestburst) && !xeno.hauled_mob) //make sure you've still got them in your claws, and alive + if(xeno.pulling == pulled && !pulled.buckled && (pulled.stat != DEAD || pulled.chestburst) && !xeno.hauled_mob?.resolve()) //make sure you've still got them in your claws, and alive if(SEND_SIGNAL(pulled, COMSIG_MOB_HAULED, xeno) & COMPONENT_CANCEL_HAUL) return FALSE xeno.haul(pulled) From 8b0d828d28086a9c1d5dece157a1b13b665f0c40 Mon Sep 17 00:00:00 2001 From: casperr04 Date: Mon, 10 Feb 2025 12:28:14 +0100 Subject: [PATCH 07/15] Tutorial changes and fixes --- code/datums/tutorial/xenomorph/xenomorph_basic.dm | 4 ++-- code/modules/mob/living/carbon/carbon.dm | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/code/datums/tutorial/xenomorph/xenomorph_basic.dm b/code/datums/tutorial/xenomorph/xenomorph_basic.dm index e4b45ba6f2e4..c5e62d543a18 100644 --- a/code/datums/tutorial/xenomorph/xenomorph_basic.dm +++ b/code/datums/tutorial/xenomorph/xenomorph_basic.dm @@ -215,8 +215,8 @@ /datum/tutorial/xenomorph/basic/proc/nest_cap_phase_five() SIGNAL_HANDLER - message_to_player("Well done, you can reguritate the human using the new ability you have gained.") - message_to_player("Be careful. Real humans may put up a fight and can try to cut out of you from inside!") + message_to_player("Well done, you can release the human using the new ability you have gained.") + message_to_player("Be careful. Real humans may put up a fight and can try to cut out of your grip, killing you!") give_action(xeno, /datum/action/xeno_action/onclick/release_haul) addtimer(CALLBACK(src, PROC_REF(nest_cap_phase_six)), 15 SECONDS) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 5c737e03b1f2..bd683e821f17 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -495,6 +495,7 @@ add_filter("hauled_shadow", 1, color_matrix_filter(rgb(95, 95, 95))) pixel_y = -7 + /mob/living/carbon/human/proc/release_haul_death() SIGNAL_HANDLER handle_unhaul() From 9656fad937e694d0ab2da3821cf0ab3db763e8ad Mon Sep 17 00:00:00 2001 From: casperr04 Date: Mon, 10 Feb 2025 12:37:56 +0100 Subject: [PATCH 08/15] culling empty lines --- code/__DEFINES/typecheck/xenos.dm | 1 - code/modules/mob/living/carbon/xenomorph/attack_alien.dm | 1 + code/modules/mob/living/carbon/xenomorph/death.dm | 2 -- strings/memetips.txt | 2 +- 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/code/__DEFINES/typecheck/xenos.dm b/code/__DEFINES/typecheck/xenos.dm index 4a6a866b0b77..c84aa1e30426 100644 --- a/code/__DEFINES/typecheck/xenos.dm +++ b/code/__DEFINES/typecheck/xenos.dm @@ -31,7 +31,6 @@ if(!istype(attempt_harm_mob)) return FALSE - if(!hive) hive = GLOB.hive_datum[hivenumber] diff --git a/code/modules/mob/living/carbon/xenomorph/attack_alien.dm b/code/modules/mob/living/carbon/xenomorph/attack_alien.dm index 10d931dc654c..308c70361084 100644 --- a/code/modules/mob/living/carbon/xenomorph/attack_alien.dm +++ b/code/modules/mob/living/carbon/xenomorph/attack_alien.dm @@ -83,6 +83,7 @@ acid_damage += (attacking_xeno.frenzy_aura * FRENZY_DAMAGE_MULTIPLIER) attacking_xeno.animation_attack_on(src) + //Somehow we will deal no damage on this attack if(!damage) playsound(attacking_xeno.loc, 'sound/weapons/alien_claw_swipe.ogg', 25, 1) diff --git a/code/modules/mob/living/carbon/xenomorph/death.dm b/code/modules/mob/living/carbon/xenomorph/death.dm index 946914f185dc..8ac3a9a14b96 100644 --- a/code/modules/mob/living/carbon/xenomorph/death.dm +++ b/code/modules/mob/living/carbon/xenomorph/death.dm @@ -19,7 +19,6 @@ if(pulledby) pulledby.stop_pulling() - if(!gibbed) if(hud_used && hud_used.healths) hud_used.healths.icon_state = "health_dead" @@ -141,7 +140,6 @@ if(!caste) CRASH("CASTE ERROR: gib() was called without a caste. (name: [name], disposed: [QDELETED(src)], health: [health])") - switch(caste.caste_type) if(XENO_CASTE_BOILER) var/mob/living/carbon/xenomorph/boiler/src_boiler = src diff --git a/strings/memetips.txt b/strings/memetips.txt index 2b7c20d4a807..487236970206 100644 --- a/strings/memetips.txt +++ b/strings/memetips.txt @@ -4,7 +4,7 @@ One shotgun isn't enough. Take six. Don't do the conga, the queen mother knows all. Jones is very important. Protect him at all costs. Install VSC. -Hauling is useful to quickly transport incapacitated hosts from one place to another. In order to haul a host as a Xeno, grab the mob (CTRL + Click) and then click on yourself to begin restarining them. The host can break out of your grip, which will result in your death - so make sure your target is incapacitated! After approximately 1 minute the host will be automatically be released. To release your target voluntarily, click 'Release' on the HUD to drop them on the ground. +Hauling is useful to quickly transport incapacitated hosts from one place to another. In order to haul a host as a Xeno, grab the mob (CTRL + Click) and then click on yourself to begin restraining them. The host can break out of your grip, which will result in your death - so make sure your target is incapacitated! After approximately 1 minute the host will be automatically be released. To release your target voluntarily, click 'Release' on the HUD to drop them on the ground. As an MP, remember that staff may give you antagonist objectives to help weaken the marines! There's actually a hidden box of HEFA grenades in Requisitions. It can be reached by having one of your buddies throw you down the ASRS elevator. Don't waste crayons by jamming them up your nose - they make excellent emergency rations in a pinch! From fd90f6206aeac402259f81f3e70862c17c89eda2 Mon Sep 17 00:00:00 2001 From: casperr04 Date: Mon, 10 Feb 2025 12:43:05 +0100 Subject: [PATCH 09/15] More styling fixes --- code/modules/mob/living/carbon/carbon.dm | 1 - code/modules/mob/living/carbon/xenomorph/XenoProcs.dm | 1 - 2 files changed, 2 deletions(-) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index bd683e821f17..87818b6130b0 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -580,4 +580,3 @@ set_lying_angle(pick(90, 270)) else set_lying_angle(new_lying_angle) - diff --git a/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm b/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm index 45857f37e2a9..5ca7492dfed3 100644 --- a/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm +++ b/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm @@ -233,7 +233,6 @@ if(user) user.forceMove(src.loc) - //Strip all inherent xeno verbs from your caste. Used in evolution. /mob/living/carbon/xenomorph/proc/remove_inherent_verbs() if(inherent_verbs) From ef5738662df35211a48fa2d2b0b8827d8736875d Mon Sep 17 00:00:00 2001 From: casperr04 Date: Mon, 10 Feb 2025 20:33:39 +0100 Subject: [PATCH 10/15] old comment --- code/modules/mob/living/carbon/carbon.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 87818b6130b0..55e6b15a5d1e 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -37,7 +37,7 @@ nutrition -= HUNGER_FACTOR/5 -/mob/living/carbon/ex_act(severity, direction, datum/cause_data/cause_data) // stays here because any carbon can be hauled +/mob/living/carbon/ex_act(severity, direction, datum/cause_data/cause_data) last_damage_data = istype(cause_data) ? cause_data : create_cause_data(cause_data) var/gibbing = FALSE From 124af9a1ba4dfa9c8dd35d2f0a36bc24fe68e324 Mon Sep 17 00:00:00 2001 From: casperr04 Date: Mon, 10 Feb 2025 20:37:35 +0100 Subject: [PATCH 11/15] comment cleanup --- code/modules/mob/living/carbon/xenomorph/XenoProcs.dm | 3 +-- code/modules/mob/living/carbon/xenomorph/Xenomorph.dm | 1 - code/modules/mob/living/living_verbs.dm | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm b/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm index 5ca7492dfed3..d232b1642635 100644 --- a/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm +++ b/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm @@ -225,7 +225,6 @@ var/mob/user = hauled_mob?.resolve() if(user) user.forceMove(src.loc) - //switch(direct) /mob/living/carbon/xenomorph/forceMove(atom/destination) . = ..() @@ -398,7 +397,7 @@ else lighting_alpha = LIGHTING_PLANE_ALPHA_VISIBLE update_sight() -// + /mob/living/carbon/xenomorph/proc/haul(mob/living/carbon/human/victim) src.visible_message(SPAN_WARNING("[src] restrains [victim], hauling them effortlessly!"), SPAN_WARNING("We fully restrain [victim] and start hauling them!"), null, 5) diff --git a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm index 6f3dcf011a8b..6c2c51cfbf23 100644 --- a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm +++ b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm @@ -62,7 +62,6 @@ var/obj/item/l_store = null // Mob we are hauling var/datum/weakref/hauled_mob - // Haul timer var/haul_timer var/obj/item/iff_tag/iff_tag = null diff --git a/code/modules/mob/living/living_verbs.dm b/code/modules/mob/living/living_verbs.dm index c23776d3b1c3..e762b2e02376 100644 --- a/code/modules/mob/living/living_verbs.dm +++ b/code/modules/mob/living/living_verbs.dm @@ -54,7 +54,7 @@ M.status_flags &= ~PASSEMOTES return - //resisting grabs (as if it helps anyone...) //FLAG + //resisting grabs (as if it helps anyone...) if(!is_mob_restrained(0) && pulledby) visible_message(SPAN_DANGER("[src] resists against [pulledby]'s grip!")) resist_grab() From 290db4490317b676cd32b4ba544dc733985f4d35 Mon Sep 17 00:00:00 2001 From: casperr04 Date: Mon, 10 Feb 2025 20:53:04 +0100 Subject: [PATCH 12/15] last random newline --- code/modules/mob/living/carbon/xenomorph/life.dm | 1 - 1 file changed, 1 deletion(-) diff --git a/code/modules/mob/living/carbon/xenomorph/life.dm b/code/modules/mob/living/carbon/xenomorph/life.dm index 749fa1e52691..99e95a39b907 100644 --- a/code/modules/mob/living/carbon/xenomorph/life.dm +++ b/code/modules/mob/living/carbon/xenomorph/life.dm @@ -218,7 +218,6 @@ return TRUE - /mob/living/carbon/xenomorph/proc/handle_regular_hud_updates() if(!mind) return TRUE From 8123c1c44813d02795a34e5db10eb1b6be3d7095 Mon Sep 17 00:00:00 2001 From: casperr04 Date: Mon, 10 Feb 2025 20:59:42 +0100 Subject: [PATCH 13/15] bad comment! --- code/modules/mob/living/carbon/carbon.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 55e6b15a5d1e..7111deed4efa 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -140,7 +140,7 @@ mobs_can_hear.show_message(SPAN_DANGER("You hear [resister] struggling against [xeno]'s grip..."), SHOW_MESSAGE_AUDIBLE) return TRUE -/mob/living/carbon/attack_hand(mob/target_mob as mob) // move it here probably +/mob/living/carbon/attack_hand(mob/target_mob as mob) if(!istype(target_mob, /mob/living/carbon)) return if(target_mob.mob_flags & SURGERY_MODE_ON && target_mob.a_intent & (INTENT_HELP|INTENT_DISARM)) From 3dc29f6a07b39a9401128b30c4b5d54bbbc7f7d1 Mon Sep 17 00:00:00 2001 From: casperr04 Date: Mon, 10 Feb 2025 21:09:48 +0100 Subject: [PATCH 14/15] style --- code/modules/animations/animation_library.dm | 3 ++- code/modules/mob/living/carbon/carbon.dm | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/animations/animation_library.dm b/code/modules/animations/animation_library.dm index 4cfdf7ace745..777fae6977ad 100644 --- a/code/modules/animations/animation_library.dm +++ b/code/modules/animations/animation_library.dm @@ -177,7 +177,8 @@ Can look good elsewhere as well.*/ if(A.clone) if(src.Adjacent(A.clone)) A = A.clone - if(buckled || anchored || HAS_TRAIT(src, TRAIT_HAULED)) return //it would look silly. + if(buckled || anchored || HAS_TRAIT(src, TRAIT_HAULED)) //it would look silly. + return var/pixel_x_diff = 0 var/pixel_y_diff = 0 var/direction = get_dir(src, A) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 6b2c10e7246b..a9ff3cf7fe46 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -37,7 +37,6 @@ nutrition -= HUNGER_FACTOR/5 - /mob/living/carbon/ex_act(severity, direction, datum/cause_data/cause_data) last_damage_data = istype(cause_data) ? cause_data : create_cause_data(cause_data) var/gibbing = FALSE From 1219b9d6a059f42502c64033359aa12ceb317286 Mon Sep 17 00:00:00 2001 From: casperr04 Date: Wed, 12 Feb 2025 03:55:07 +0100 Subject: [PATCH 15/15] fix unable to burst when moving out of body --- code/modules/mob/living/carbon/carbon.dm | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index a9ff3cf7fe46..99a36e35da03 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -36,6 +36,12 @@ if(nutrition && stat != DEAD) nutrition -= HUNGER_FACTOR/5 +/mob/living/carbon/relaymove(mob/user, direction) + if(user.is_mob_incapacitated(TRUE)) + return + if(!chestburst && (status_flags & XENO_HOST) && islarva(user)) + var/mob/living/carbon/xenomorph/larva/larva_burst = user + larva_burst.chest_burst(src) /mob/living/carbon/ex_act(severity, direction, datum/cause_data/cause_data) last_damage_data = istype(cause_data) ? cause_data : create_cause_data(cause_data)