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 e97a1d1a747d..a7e6dd7d0da1 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" +/// 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" // only used by valkyrie #define TRAIT_VALKYRIE_ARMORED "trait_valkyrie_armored" @@ -439,6 +441,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..c84aa1e30426 100644 --- a/code/__DEFINES/typecheck/xenos.dm +++ b/code/__DEFINES/typecheck/xenos.dm @@ -41,6 +41,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/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 1631bc7bd12e..965dad127a0f 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,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/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 8d800ef0bfa0..f98afe012ef4 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..c5e62d543a18 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) + 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) /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/game/objects/items/explosives/grenades/grenade.dm b/code/game/objects/items/explosives/grenades/grenade.dm index f157d7f8d931..2ddd588890d1 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(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 /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 75c067c7f037..64d13d1d98bc 100644 --- a/code/game/objects/items/storage/storage.dm +++ b/code/game/objects/items/storage/storage.dm @@ -616,6 +616,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/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 e7cb49c930d4..777fae6977ad 100644 --- a/code/modules/animations/animation_library.dm +++ b/code/modules/animations/animation_library.dm @@ -177,8 +177,8 @@ 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)) //it would look silly. + return var/pixel_x_diff = 0 var/pixel_y_diff = 0 var/direction = get_dir(src, A) @@ -207,7 +207,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/inventory.dm b/code/modules/mob/inventory.dm index 1ca06f709a9b..0d48bb22186f 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -169,6 +169,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 81199dc11b54..99a36e35da03 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 . = ..() @@ -40,50 +39,30 @@ /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)) + 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) + 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 @@ -98,23 +77,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() @@ -128,37 +90,62 @@ 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(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 / 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) + 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) if(!istype(target_mob, /mob/living/carbon)) return @@ -368,8 +355,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 @@ -502,15 +489,50 @@ 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) + 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_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 = -7 + + +/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 + 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) - ..() - 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/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/human.dm b/code/modules/mob/living/carbon/human/human.dm index 33c02317fb70..adb0459536fa 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/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index b630c63c9b08..521f4293937a 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/Evolution.dm b/code/modules/mob/living/carbon/xenomorph/Evolution.dm index c9882638effa..ca1a385e52cf 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(src, "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 4b37be23fc6c..3fac8948b905 100644 --- a/code/modules/mob/living/carbon/xenomorph/Facehuggers.dm +++ b/code/modules/mob/living/carbon/xenomorph/Facehuggers.dm @@ -474,7 +474,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..d232b1642635 100644 --- a/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm +++ b/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm @@ -215,6 +215,22 @@ /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) + +/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() @@ -368,17 +384,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 @@ -393,22 +398,58 @@ lighting_alpha = LIGHTING_PLANE_ALPHA_VISIBLE update_sight() -/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)]") +/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)) + 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) - if (stuns) - victim.adjust_effect(2, STUN) - else - to_chat(src, SPAN_WARNING("There's nothing in our belly that needs regurgitating.")) +// 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 + +// 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.")) + 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(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 /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..6c2c51cfbf23 100644 --- a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm +++ b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm @@ -60,6 +60,9 @@ 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/haul_timer var/obj/item/iff_tag/iff_tag = null @@ -278,8 +281,6 @@ /// 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 /// For drones/hivelords. Extends the maximum build range they have var/extra_build_dist = 0 /// tiles from self you can plant eggs. @@ -396,7 +397,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 @@ -692,6 +694,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 fe96e5958a13..f3287592954b 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" - action_icon_state = "regurgitate" +// release_haul +/datum/action/xeno_action/onclick/release_haul + name = "Release" + action_icon_state = "release_haul" 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 3f1967429c8c..c51d4f1bc3bd 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 ..() @@ -932,6 +929,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 651071df24ca..f553dc36fce9 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) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Boiler.dm b/code/modules/mob/living/carbon/xenomorph/castes/Boiler.dm index c010ec224b97..7ae9b4d61c88 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 daf98a07849e..a54191e82758 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 6cc976aa4122..ef721c1b1627 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 c264269c1241..d03e23cf08bd 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 cf378b241ea9..7fe89fefbb0d 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 52a38a285abb..1f63f4fb63e9 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Hellhound.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Hellhound.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/onclick/xenohide, /datum/action/xeno_action/activable/pounce/gorge, /datum/action/xeno_action/onclick/sense_owner, diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Hivelord.dm b/code/modules/mob/living/carbon/xenomorph/castes/Hivelord.dm index 6e73a387834a..dc0bec6a9dd8 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 ca16bc1d628a..46aa1ff78699 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 66aeb358b813..e74c162e3927 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 43c7c97c7a1f..808a49233d0c 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 c614ac7d8f5c..b41b750589a6 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm @@ -297,7 +297,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 @@ -327,7 +327,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 @@ -757,7 +757,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) @@ -849,7 +851,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 1c3b62e79997..316380dd99fd 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 599b501e6d42..895f6a806a2c 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 0f2022f38e34..e0990d9c3ed7 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 267d0116bab0..c954f57ac028 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 8103527a5166..f8a5ec5ccef1 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 @@ -275,6 +272,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 1243d3badcdc..3e72aa9fe85d 100644 --- a/code/modules/mob/living/carbon/xenomorph/death.dm +++ b/code/modules/mob/living/carbon/xenomorph/death.dm @@ -107,10 +107,6 @@ GLOBAL_VAR_INIT(total_dead_xenos, 0) 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 ba553d4f10c8..cc6b3c494201 100644 --- a/code/modules/mob/living/carbon/xenomorph/hive_status.dm +++ b/code/modules/mob/living/carbon/xenomorph/hive_status.dm @@ -724,9 +724,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.devour_timer = 0 - xeno.handle_stomach_contents() qdel(xeno) continue if(xeno.hunter_data.hunted && !isqueen(xeno)) @@ -734,9 +731,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.devour_timer = 0 - xeno.handle_stomach_contents() + if(xeno.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 e3df07cbbb19..16ce6f85a3aa 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,6 @@ return TRUE -/mob/living/carbon/xenomorph/proc/handle_stomach_contents() - //Deal with dissolving/damaging stuff in stomach. - 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) - 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) /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 294ea27b6260..2bca2ca224fd 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 9ab85b7c3e9e..7bfc2f963b4d 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -693,9 +693,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..e762b2e02376 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 diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm index 993b4ccfed0f..88259ec38f26 100644 --- a/code/modules/mob/mob_grab.dm +++ b/code/modules/mob/mob_grab.dm @@ -118,7 +118,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.")) @@ -126,45 +126,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].")) + 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(SEND_SIGNAL(pulled, COMSIG_MOB_DEVOURED, xeno) & COMPONENT_CANCEL_DEVOUR) + 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) + 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 316cd795980d..d5bb62715438 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -577,7 +577,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 62e91243c8e3..d99891a44960 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -1609,6 +1609,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 e1446ccb10d5..7e39556e82be 100644 --- a/code/modules/projectiles/gun_helpers.dm +++ b/code/modules/projectiles/gun_helpers.dm @@ -537,7 +537,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 diff --git a/code/modules/projectiles/guns/flamer/flamer.dm b/code/modules/projectiles/guns/flamer/flamer.dm index e9c87c459a27..5d5a59c56af5 100644 --- a/code/modules/projectiles/guns/flamer/flamer.dm +++ b/code/modules/projectiles/guns/flamer/flamer.dm @@ -744,7 +744,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/icons/mob/hud/actions_xeno.dmi b/icons/mob/hud/actions_xeno.dmi index b98194a9cab1..b9605f49fbef 100644 Binary files a/icons/mob/hud/actions_xeno.dmi and b/icons/mob/hud/actions_xeno.dmi differ diff --git a/strings/memetips.txt b/strings/memetips.txt index 1767d8688953..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. -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 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!