Skip to content

Commit

Permalink
add: Лицехват - моб (#6612) [testmerge][6bb33a1]
Browse files Browse the repository at this point in the history
  • Loading branch information
actions-user committed Mar 9, 2025
1 parent 4ed173f commit e9d8439
Show file tree
Hide file tree
Showing 47 changed files with 886 additions and 196 deletions.
3 changes: 3 additions & 0 deletions code/__DEFINES/dcs/signals.dm
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,9 @@
/// from base of /client/proc/handle_popup_close() : (window_id)
#define COMSIG_POPUP_CLEARED "popup_cleared"

/// from base of /datum/status_effect/Destroy() : (effect_type)
#define COMSIG_MOB_STATUS_EFFECT_ENDED "mob_status_effect_ended"

/// Source: /mob/living/UnarmedAttack (atom/atom, proximity_flag)
#define COMSIG_LIVING_UNARMED_ATTACK "living_unarmed_attack"

Expand Down
1 change: 1 addition & 0 deletions code/__DEFINES/gamemode.dm
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
#define SPECIAL_ROLE_XENOMORPH_DRONE "Xenomorph Drone"
#define SPECIAL_ROLE_XENOMORPH_SENTINEL "Xenomorph Sentinel"
#define SPECIAL_ROLE_XENOMORPH_LARVA "Xenomorph Larva"
#define SPECIAL_ROLE_FACEHUGGER "Facehugger"
#define SPECIAL_ROLE_TERROR_SPIDER "Terror Spider"
#define SPECIAL_ROLE_TERROR_QUEEN "Terror Queen"
#define SPECIAL_ROLE_TERROR_PRINCE "Terror Prince"
Expand Down
5 changes: 5 additions & 0 deletions code/__DEFINES/is_helpers.dm
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
#define isaliensentinel(A) (istype(A, /mob/living/carbon/alien/humanoid/sentinel))

#define isalienqueen(A) (istype(A, /mob/living/carbon/alien/humanoid/queen))
#define isfacehugger(A) (istype(A, /mob/living/simple_animal/hostile/facehugger))
#define isfacehugger_mask(A) (istype(A, /obj/item/clothing/mask/facehugger) && !istype(A, /obj/item/clothing/mask/facehugger/toy))

// Simple animals
// #define issimple_animal(A) (istype(A, /mob/living/simple_animal)) use isanimal(A) instead
Expand Down Expand Up @@ -92,6 +94,8 @@

#define isradio(A) istype(A, /obj/item/radio)

#define isflower(A) istype(A, /obj/item/twohanded/required/kirbyplants)

#define isclothing(A) (istype(A, /obj/item/clothing))

#define is_internal_organ(A) istype(A, /obj/item/organ/internal)
Expand Down Expand Up @@ -153,6 +157,7 @@ GLOBAL_LIST_INIT(glass_sheet_types, typecacheof(list(

//Structures
#define isstructure(A) (istype(A, /obj/structure))
#define istable(A) (istype(A, /obj/structure/table))

// Misc
#define isclient(A) istype(A, /client)
Expand Down
4 changes: 4 additions & 0 deletions code/__DEFINES/obj_flags.dm
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,7 @@
/// Flags for the pod_flags var on /obj/structure/closet/supplypod
#define FIRST_SOUNDS (1<<0) // If it shouldn't play sounds the first time it lands, used for reverse mode


#define HUMAN_HOLDER (1<<0)

#define ALIEN_HOLDER (1<<1)
4 changes: 4 additions & 0 deletions code/__DEFINES/traits/sources.dm
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@
/// Traits applied to a silicon mob by their model.
#define ROBOT_TRAIT "robot_trait"

#define FACEHUGER_TRAIT "facehugger_trait"

/// A trait gained from a mob's leap action, like the leaper
#define LEAPING_TRAIT "leaping"

Expand All @@ -99,6 +101,8 @@
/// Trait associated to lying down (having a [lying_angle] of a different value than zero).
#define LYING_DOWN_TRAIT "lying-down"

#define THROWED_TRAIT "throwed_trait"

#define NO_GRAVITY_TRAIT "no-gravity"
#define NEGATIVE_GRAVITY_TRAIT "negative-gravity"

Expand Down
1 change: 1 addition & 0 deletions code/_globalvars/lists/mobs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ GLOBAL_LIST_EMPTY(mob_list) //List of all mobs, including clientless
GLOBAL_LIST_EMPTY(silicon_mob_list) //List of all silicon mobs, including clientless
GLOBAL_LIST_EMPTY(mob_living_list) //all instances of /mob/living and subtypes
GLOBAL_LIST_EMPTY(carbon_list) //all instances of /mob/living/carbon and subtypes, notably does not contain simple animals
GLOBAL_LIST_EMPTY(aliens_list) //all instances of xenomorph mobs
GLOBAL_LIST_EMPTY(human_list) //all instances of /mob/living/carbon/human and subtypes
GLOBAL_LIST_EMPTY(spirits) //List of all the spirits, including Masks
GLOBAL_LIST_EMPTY(alive_mob_list) //List of all alive mobs, including clientless. Excludes /mob/new_player
Expand Down
19 changes: 17 additions & 2 deletions code/controllers/subsystem/movement/movement_types.dm
Original file line number Diff line number Diff line change
Expand Up @@ -524,10 +524,25 @@
if(!.)
return
var/atom/old_loc = moving.loc
var/turf/next = get_step_to(moving, target)
moving.Move(next, get_dir(moving, next), FALSE, !(flags & MOVEMENT_LOOP_NO_DIR_UPDATE))
var/turf/next = get_next_step()
if(isliving(moving))
var/mob/living/moving_mob = moving
if(!(moving_mob.mobility_flags & MOBILITY_MOVE))
return MOVELOOP_FAILURE
moving?.Move(next, get_dir(moving, next), FALSE, !(flags & MOVEMENT_LOOP_NO_DIR_UPDATE))
return old_loc != moving?.loc ? MOVELOOP_SUCCESS : MOVELOOP_FAILURE

/datum/move_loop/has_target/dist_bound/move_to/proc/get_next_step()
return get_step_to(moving, target)

/datum/controller/subsystem/move_manager/proc/move_to_pathfind(moving, chasing, min_dist, delay, timeout, subsystem, priority, flags, datum/extra_info)
return add_to_loop(moving, subsystem, /datum/move_loop/has_target/dist_bound/move_to/pathfind, priority, flags, extra_info, delay, timeout, chasing, min_dist)

/datum/move_loop/has_target/dist_bound/move_to/pathfind

/datum/move_loop/has_target/dist_bound/move_to/pathfind/get_next_step()
var/list/points = get_path_to(moving, target, skip_first = TRUE)
return (points.len)? points[1] : null

/**
* Wrapper around walk_away()
Expand Down
23 changes: 22 additions & 1 deletion code/datums/components/ghost_direct_control.dm
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
var/ban_type
/// Check Syndicate ban
var/ban_syndicate
/// Check ghost respawnability
var/respawnable_check = TRUE
/// Check antaghud use
var/check_antaghud = TRUE
/// Any extra checks which need to run before we take over
var/datum/callback/extra_control_checks
/// Callback run after someone successfully takes over the body
Expand All @@ -25,6 +29,7 @@
poll_candidates = TRUE,
antag_age_check = TRUE,
check_antaghud = TRUE,
respawnable_check = TRUE,
poll_length = 10 SECONDS,
ban_syndicate = FALSE,
assumed_control_message = null,
Expand All @@ -43,6 +48,8 @@
src.extra_control_checks = extra_control_checks
src.after_assumed_control = after_assumed_control
src.question_text = question_text
src.respawnable_check = respawnable_check
src.check_antaghud = check_antaghud

LAZYADD(GLOB.mob_spawners[format_text("[initial(mob_parent.name)]")], mob_parent)

Expand Down Expand Up @@ -71,6 +78,15 @@
GLOB.mob_spawners -= format_text("[initial(mob_parent.name)]")
return ..()

/datum/component/ghost_direct_control/proc/on_death(datum/source, mob/user, list/examine_text)
SIGNAL_HANDLER
if(!isobserver(user))
return
var/mob/living/our_mob = parent
if(our_mob.stat == DEAD || our_mob.key || awaiting_ghosts)
return
examine_text += span_boldnotice("Вы можете взять под контроль это существо, нажав на него.")

/// Inform ghosts that they can possess this
/datum/component/ghost_direct_control/proc/on_examined(datum/source, mob/user, list/examine_text)
SIGNAL_HANDLER
Expand Down Expand Up @@ -135,13 +151,18 @@
if(new_body.stat == DEAD)
to_chat(harbinger, span_warning("Это тело умерло, оно бесполезно!"))
return
if(respawnable_check && !(harbinger in GLOB.respawnable_list))
to_chat(harbinger, "Вы не можете повторно присоединиться к раунду.")
return
if(respawnable_check && cannotPossess(harbinger))
to_chat(harbinger, "Вы не можете повторно присоединиться к раунду, активировав антаг худ.")
return
if(new_body.key)
to_chat(harbinger, span_warning("[capitalize(new_body.declent_ru(NOMINATIVE))] уже является разумным!"))
qdel(src)
return
if(extra_control_checks && !extra_control_checks.Invoke(harbinger))
return

add_game_logs("took control of [new_body].", harbinger)
// doesn't transfer mind because that transfers antag datum as well
new_body.key = harbinger.key
Expand Down
4 changes: 4 additions & 0 deletions code/datums/spawners_menu.dm
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
this["fluff"] = ""
this["uids"] = list()
for(var/spawner_obj in GLOB.mob_spawners[spawner])//each spawner can contain multiple actual spawners, we use only one desc/info
if(isliving(spawner_obj))
var/mob/living/mob = spawner_obj
if(mob.stat == DEAD)
continue
this["uids"] += "\ref[spawner_obj]"
if(!this["desc"]) //haven't set descriptions yet
if(istype(spawner_obj, /obj/effect/mob_spawn))
Expand Down
2 changes: 1 addition & 1 deletion code/datums/spells/alien_spells/lay_alien_eggs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "Plant alien eggs"
desc = "Allows you to plant alien eggs on your current turf, does not work while in space."
base_cooldown = 1 SECONDS
plasma_cost = 75
plasma_cost = 95
weed_type = /obj/structure/alien/egg
weed_name = "alien egg"
action_icon_state = "alien_egg"
Expand Down
1 change: 1 addition & 0 deletions code/datums/status_effects/status_effect.dm
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
owner.clear_alert(id)
LAZYREMOVE(owner.status_effects, src)
on_remove()
SEND_SIGNAL(owner, COMSIG_MOB_STATUS_EFFECT_ENDED, type)
owner = null
if(linked_alert)
linked_alert.attached_effect = null
Expand Down
1 change: 1 addition & 0 deletions code/game/objects/items.dm
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ GLOBAL_DATUM_INIT(fire_overlay, /mutable_appearance, mutable_appearance('icons/g
var/slot_flags_2 = NONE
/// This flag is used to determine when items in someone's inventory cover others. IE helmets making it so you can't see glasses, etc.
var/flags_inv = NONE
var/holder_flags = NONE
/// These flags will be added/removed (^=) to/from flags_inv in [/proc/check_obscured_slots()]
/// if check_transparent argument is set to `TRUE`. Used in carbon's update icons shenanigans.
/// Example: you can see someone's mask through their transparent visor, but you cannot reach it
Expand Down
2 changes: 1 addition & 1 deletion code/game/objects/obj_defense.dm
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
armor_protection = armor.getRating(damage_flag)
if(armor_protection) //Only apply weak-against-armor/hollowpoint effects if there actually IS armor.
armor_protection = clamp(armor_protection - armour_penetration, min(armor_protection, 0), 100)
return round(damage_amount * (100 - armor_protection)*0.01, DAMAGE_PRECISION)
return round(damage_amount * (100 - armor_protection) * 0.01, DAMAGE_PRECISION)


/// Proc for recovering atom_integrity. Returns the amount repaired by
Expand Down
67 changes: 48 additions & 19 deletions code/game/objects/structures/aliens.dm
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,14 @@
if(user.a_intent == INTENT_HARM)
return ..()

try_switch_state(user)
return try_switch_state(user)

/obj/structure/alien/resin/door/attack_animal(mob/living/simple_animal/M)
if(M.a_intent == INTENT_HARM)
return ..()

return try_switch_state(M)


/obj/structure/alien/resin/door/attack_hand(mob/living/user)
if(!isalien(user))
Expand Down Expand Up @@ -206,18 +212,21 @@

/obj/structure/alien/resin/door/proc/try_switch_state(atom/movable/user)
if(operating)
return
return FALSE

add_fingerprint(user)

if(!isalien(user))
return
if(!isliving(user))
return FALSE
var/mob/living/mob = user
if(!isalien(user) && !("alien" in mob.faction))
return FALSE

var/mob/living/carbon/alien/alien = user
if(alien.incapacitated())
return
return FALSE

switch_state()
return TRUE


/obj/structure/alien/resin/door/proc/switch_state()
Expand Down Expand Up @@ -442,6 +451,7 @@
#define GROWN 3
#define MIN_GROWTH_TIME 1200 //time it takes to grow a hugger
#define MAX_GROWTH_TIME 1800
#define PROXIMITY_RADIUS 5

/obj/structure/alien/egg
name = "egg"
Expand All @@ -468,11 +478,13 @@
update_icon(UPDATE_ICON_STATE)
switch(status)
if(GROWING)
new /obj/item/clothing/mask/facehugger(src)
var/mob/living/simple_animal/hostile/facehugger/hugger = new(src)
hugger.LoseTarget()
addtimer(CALLBACK(src, PROC_REF(Grow)), rand(MIN_GROWTH_TIME, MAX_GROWTH_TIME))
if(GROWN)
new /obj/item/clothing/mask/facehugger(src)
AddComponent(/datum/component/proximity_monitor)
var/mob/living/simple_animal/hostile/facehugger/hugger = new(src)
hugger.LoseTarget()
AddComponent(/datum/component/proximity_monitor, PROXIMITY_RADIUS)
if(BURST)
obj_integrity = integrity_failure

Expand Down Expand Up @@ -512,41 +524,55 @@


/obj/structure/alien/egg/proc/GetFacehugger()
return locate(/obj/item/clothing/mask/facehugger) in contents
return locate(/mob/living/simple_animal/hostile/facehugger) in contents


/obj/structure/alien/egg/proc/Grow()
status = GROWN
update_icon(UPDATE_ICON_STATE)
AddComponent(/datum/component/proximity_monitor)

AddComponent(/datum/component/proximity_monitor, PROXIMITY_RADIUS)

///Need to carry the kill from Burst() to Hatch(), this section handles the alien opening the egg
/obj/structure/alien/egg/proc/Burst(kill = TRUE) //drops and kills the hugger if any is remaining
/obj/structure/alien/egg/proc/Burst(kill = TRUE, atom/movable/trigger) //drops and kills the hugger if any is remaining
if(status == GROWN || status == GROWING)
playsound(get_turf(src), 'sound/creatures/alien/xeno_egg_crack.ogg', 50)
flick("egg_opening", src)
status = BURSTING
qdel(GetComponent(/datum/component/proximity_monitor))
addtimer(CALLBACK(src, PROC_REF(Hatch), kill), 1.5 SECONDS)
addtimer(CALLBACK(src, PROC_REF(Hatch), kill, trigger), 1.5 SECONDS)


///We now check HOW the hugger is hatching, kill carried from Burst() and obj_break()
/obj/structure/alien/egg/proc/Hatch(kill)
/obj/structure/alien/egg/proc/Hatch(kill, atom/movable/trigger)
status = BURST
update_icon(UPDATE_ICON_STATE)
var/obj/item/clothing/mask/facehugger/child = GetFacehugger()
var/mob/living/simple_animal/hostile/facehugger/child = GetFacehugger()

if(!child)
return

child.forceMove(get_turf(src))
child.AddComponent(\
/datum/component/ghost_direct_control,\
ban_type = ROLE_ALIEN,\
poll_candidates = FALSE,\
after_assumed_control = CALLBACK(src, TYPE_PROC_REF(/mob/living/simple_animal/hostile/facehugger, add_datum_if_not_exist)),\
)
if(kill)
child.Die()
child.death()
return

for(var/mob/living/victim in range(1, src))
if(CanHug(victim))
child.Attach(victim)
child.try_hug(victim)
break

if(!CanHug(trigger))
return

child.GiveTarget(trigger)
child.MoveToTarget(list(trigger))


/obj/structure/alien/egg/obj_break(damage_flag)
if(!(obj_flags & NODECONSTRUCT) && status != BURST)
Expand All @@ -567,8 +593,10 @@
var/mob/living/carbon/target = AM
if(iscarbon(target) && target.stat == CONSCIOUS && target.get_int_organ(/obj/item/organ/internal/body_egg/alien_embryo))
return
if(isalien(target))
return

Burst(kill = FALSE)
Burst(kill = FALSE, trigger = AM)


#undef BURST
Expand All @@ -577,6 +605,7 @@
#undef GROWN
#undef MIN_GROWTH_TIME
#undef MAX_GROWTH_TIME
#undef PROXIMITY_RADIUS

#undef ALIEN_RESIN_BURN_MOD
#undef ALIEN_RESIN_BRUTE_MOD
Expand Down
5 changes: 5 additions & 0 deletions code/game/objects/structures/displaycase.dm
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,11 @@
start_showpiece_type = /obj/item/clothing/mask/facehugger/lamarr
req_access = list(ACCESS_RD)

/obj/structure/displaycase/labcage/dump()
var/obj/item/clothing/mask/facehugger/hugger = showpiece
. = ..()
hugger?.check_mob_inside()

/obj/structure/displaycase/stechkin
name = "officer's display case"
desc = "A display case containing a humble stechkin pistol. Never forget your roots."
Expand Down
2 changes: 2 additions & 0 deletions code/game/objects/structures/fence.dm
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
anchored = TRUE
pass_flags_self = PASSFENCE|LETPASSTHROW

can_astar_pass = CANASTARPASS_ALWAYS_PROC

icon = 'icons/obj/fence.dmi'
icon_state = "straight"

Expand Down
1 change: 1 addition & 0 deletions code/game/objects/structures/tables_racks.dm
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
anchored = TRUE
layer = TABLE_LAYER
pass_flags_self = PASSTABLE|LETPASSTHROW
can_astar_pass = CANASTARPASS_ALWAYS_PROC
climbable = TRUE
max_integrity = 100
integrity_failure = 30
Expand Down
Loading

0 comments on commit e9d8439

Please sign in to comment.