Skip to content

Commit

Permalink
[MIRROR] Shapechange health transfer tweaks [MDB IGNORE] (#24590) (#298)
Browse files Browse the repository at this point in the history
* Shapechange health transfer tweaks

* Fix diffs

---------

Co-authored-by: SkyratBot <[email protected]>
Co-authored-by: Jacquerel <[email protected]>
Co-authored-by: Giz <[email protected]>
  • Loading branch information
4 people authored Oct 27, 2023
1 parent 40e0c44 commit 9650cf5
Show file tree
Hide file tree
Showing 13 changed files with 135 additions and 67 deletions.
59 changes: 31 additions & 28 deletions code/datums/actions/action.dm
Original file line number Diff line number Diff line change
Expand Up @@ -79,16 +79,17 @@

/// Grants the action to the passed mob, making it the owner
/datum/action/proc/Grant(mob/grant_to)
if(!grant_to)
if(isnull(grant_to))
Remove(owner)
return
if(owner)
if(owner == grant_to)
return
Remove(owner)
SEND_SIGNAL(src, COMSIG_ACTION_GRANTED, grant_to)
SEND_SIGNAL(grant_to, COMSIG_MOB_GRANTED_ACTION, src)
if(grant_to == owner)
return // We already have it
var/mob/previous_owner = owner
owner = grant_to
if(!isnull(previous_owner))
Remove(previous_owner)
SEND_SIGNAL(src, COMSIG_ACTION_GRANTED, owner)
SEND_SIGNAL(owner, COMSIG_MOB_GRANTED_ACTION, src)
RegisterSignal(owner, COMSIG_QDELETING, PROC_REF(clear_ref), override = TRUE)

// Register some signals based on our check_flags
Expand Down Expand Up @@ -120,27 +121,29 @@
LAZYREMOVE(remove_from?.actions, src) // We aren't always properly inserted into the viewers list, gotta make sure that action's cleared
viewers = list()

if(owner)
SEND_SIGNAL(src, COMSIG_ACTION_REMOVED, owner)
SEND_SIGNAL(owner, COMSIG_MOB_REMOVED_ACTION, src)
UnregisterSignal(owner, COMSIG_QDELETING)

// Clean up our check_flag signals
UnregisterSignal(owner, list(
COMSIG_LIVING_SET_BODY_POSITION,
COMSIG_MOB_STATCHANGE,
SIGNAL_ADDTRAIT(TRAIT_HANDS_BLOCKED),
SIGNAL_ADDTRAIT(TRAIT_IMMOBILIZED),
SIGNAL_ADDTRAIT(TRAIT_INCAPACITATED),
SIGNAL_ADDTRAIT(TRAIT_MAGICALLY_PHASED),
SIGNAL_REMOVETRAIT(TRAIT_HANDS_BLOCKED),
SIGNAL_REMOVETRAIT(TRAIT_IMMOBILIZED),
SIGNAL_REMOVETRAIT(TRAIT_INCAPACITATED),
SIGNAL_REMOVETRAIT(TRAIT_MAGICALLY_PHASED),
))

if(target == owner)
RegisterSignal(target, COMSIG_QDELETING, PROC_REF(clear_ref))
if(isnull(owner))
return
SEND_SIGNAL(src, COMSIG_ACTION_REMOVED, owner)
SEND_SIGNAL(owner, COMSIG_MOB_REMOVED_ACTION, src)
UnregisterSignal(owner, COMSIG_QDELETING)

// Clean up our check_flag signals
UnregisterSignal(owner, list(
COMSIG_LIVING_SET_BODY_POSITION,
COMSIG_MOB_STATCHANGE,
SIGNAL_ADDTRAIT(TRAIT_HANDS_BLOCKED),
SIGNAL_ADDTRAIT(TRAIT_IMMOBILIZED),
SIGNAL_ADDTRAIT(TRAIT_INCAPACITATED),
SIGNAL_ADDTRAIT(TRAIT_MAGICALLY_PHASED),
SIGNAL_REMOVETRAIT(TRAIT_HANDS_BLOCKED),
SIGNAL_REMOVETRAIT(TRAIT_IMMOBILIZED),
SIGNAL_REMOVETRAIT(TRAIT_INCAPACITATED),
SIGNAL_REMOVETRAIT(TRAIT_MAGICALLY_PHASED),
))

if(target == owner)
RegisterSignal(target, COMSIG_QDELETING, PROC_REF(clear_ref))
if (owner == remove_from)
owner = null

/// Actually triggers the effects of the action.
Expand Down
8 changes: 8 additions & 0 deletions code/datums/components/leash.dm
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,14 @@
if (get_dist(parent, owner) <= distance)
return

var/atom/movable/atom_parent = parent
if (isnull(owner.loc))
atom_parent.moveToNullspace() // If our parent is in nullspace I guess we gotta go there too
return
if (isnull(atom_parent.loc))
force_teleport_back("in nullspace") // If we're in nullspace, get outta there
return

SEND_SIGNAL(parent, COMSIG_LEASH_PATH_STARTED)

current_path_tick += 1
Expand Down
2 changes: 1 addition & 1 deletion code/datums/elements/weather_listener.dm
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
/datum/element/weather_listener/proc/handle_z_level_change(datum/source, turf/old_loc, turf/new_loc)
SIGNAL_HANDLER
var/list/fitting_z_levels = SSmapping.levels_by_trait(weather_trait)
if(!(new_loc.z in fitting_z_levels))
if(!(new_loc?.z in fitting_z_levels))
return
var/datum/component/our_comp = source.AddComponent(\
/datum/component/area_sound_manager, \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
desc = "A spell that allows you to take on the form of another eldritch creature, gaining their abilities. \
You can change your choice at any time, and if your form dies, you dont die."
cooldown_time = 20 SECONDS
convert_damage = FALSE
die_with_shapeshifted_form = FALSE
possible_shapes = list(
/mob/living/basic/heretic_summon/ash_spirit,
Expand Down
1 change: 1 addition & 0 deletions code/modules/antagonists/heretic/magic/flesh_ascension.dm
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
invocation_type = INVOCATION_SHOUT
spell_requirements = NONE

convert_damage = FALSE // Functionally meaningless on Armsy, we track how many segments it had instead
possible_shapes = list(/mob/living/basic/heretic_summon/armsy)

/// The length of our new wormy when we shed.
Expand Down
16 changes: 8 additions & 8 deletions code/modules/mob/living/carbon/human/_species.dm
Original file line number Diff line number Diff line change
Expand Up @@ -1422,32 +1422,32 @@ GLOBAL_LIST_EMPTY(features_by_species)
H.damageoverlaytemp = 20
var/damage_amount = forced ? damage : damage * hit_percent * H.physiology.brute_mod
if(BP)
if(BP.receive_damage(damage_amount, 0, wound_bonus = wound_bonus, bare_wound_bonus = bare_wound_bonus, sharpness = sharpness, attack_direction = attack_direction, damage_source = attacking_item))
if(BP.receive_damage(damage_amount, 0, forced = forced, wound_bonus = wound_bonus, bare_wound_bonus = bare_wound_bonus, sharpness = sharpness, attack_direction = attack_direction, damage_source = attacking_item))
H.update_damage_overlays()
else//no bodypart, we deal damage with a more general method.
H.adjustBruteLoss(damage_amount)
H.adjustBruteLoss(damage_amount, forced = forced)
INVOKE_ASYNC(H, TYPE_PROC_REF(/mob/living/carbon/human, adjust_pain), damage_amount) // SKYRAT EDIT ADDITION - ERP Pain
if(BURN)
H.damageoverlaytemp = 20
var/damage_amount = forced ? damage : damage * hit_percent * H.physiology.burn_mod
if(BP)
if(BP.receive_damage(0, damage_amount, wound_bonus = wound_bonus, bare_wound_bonus = bare_wound_bonus, sharpness = sharpness, attack_direction = attack_direction, damage_source = attacking_item))
if(BP.receive_damage(0, damage_amount, forced = forced, wound_bonus = wound_bonus, bare_wound_bonus = bare_wound_bonus, sharpness = sharpness, attack_direction = attack_direction, damage_source = attacking_item))
H.update_damage_overlays()
else
H.adjustFireLoss(damage_amount)
H.adjustFireLoss(damage_amount, forced = forced)
INVOKE_ASYNC(H, TYPE_PROC_REF(/mob/living/carbon/human, adjust_pain), damage_amount) // SKYRAT EDIT ADDITION - ERP Pain
if(TOX)
var/damage_amount = forced ? damage : damage * hit_percent * H.physiology.tox_mod
H.adjustToxLoss(damage_amount)
H.adjustToxLoss(damage_amount, forced = forced)
if(OXY)
var/damage_amount = forced ? damage : damage * hit_percent * H.physiology.oxy_mod
H.adjustOxyLoss(damage_amount)
H.adjustOxyLoss(damage_amount, forced = forced)
if(CLONE)
var/damage_amount = forced ? damage : damage * hit_percent * H.physiology.clone_mod
H.adjustCloneLoss(damage_amount)
H.adjustCloneLoss(damage_amount, forced = forced)
if(STAMINA)
var/damage_amount = forced ? damage : damage * hit_percent * H.physiology.stamina_mod
H.adjustStaminaLoss(damage_amount)
H.adjustStaminaLoss(damage_amount, forced = forced)
if(BRAIN)
var/damage_amount = forced ? damage : damage * hit_percent * H.physiology.brain_mod
H.adjustOrganLoss(ORGAN_SLOT_BRAIN, damage_amount)
Expand Down
4 changes: 4 additions & 0 deletions code/modules/mob/living/damage_procs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@
if(STAMINA)
return getStaminaLoss()

/// return the total damage of all types which update your health
/mob/living/proc/get_total_damage(precision = DAMAGE_PRECISION)
return round(getBruteLoss() + getFireLoss() + getToxLoss() + getOxyLoss() + getCloneLoss(), precision)

/// applies multiple damages at once via [/mob/living/proc/apply_damage]
/mob/living/proc/apply_damages(brute = 0, burn = 0, tox = 0, oxy = 0, clone = 0, def_zone = null, blocked = FALSE, stamina = 0, brain = 0)
if(blocked >= 100)
Expand Down
19 changes: 11 additions & 8 deletions code/modules/mob/living/simple_animal/guardian/guardian.dm
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,9 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
/mob/living/simple_animal/hostile/guardian/proc/cut_summoner(different_person = FALSE)
if(is_deployed())
recall_effects()
forceMove(get_turf(src))
var/summoner_turf = get_turf(src)
if (!isnull(summoner_turf))
forceMove(summoner_turf)
UnregisterSignal(summoner, list(COMSIG_MOVABLE_MOVED, COMSIG_QDELETING, COMSIG_LIVING_DEATH, COMSIG_LIVING_HEALTH_UPDATE, COMSIG_LIVING_ON_WABBAJACKED, COMSIG_LIVING_SHAPESHIFTED, COMSIG_LIVING_UNSHAPESHIFTED))
if(different_person)
summoner.faction -= "[REF(src)]"
Expand Down Expand Up @@ -311,7 +313,8 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
SIGNAL_HANDLER

cut_summoner()
forceMove(source.loc)
if (!isnull(source.loc))
forceMove(source.loc)
to_chat(src, span_danger("Your summoner has died!"))
visible_message(span_bolddanger("\The [src] dies along with its user!"))
source.visible_message(span_bolddanger("[source]'s body is completely consumed by the strain of sustaining [src]!"))
Expand Down Expand Up @@ -346,12 +349,12 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
return
to_chat(src, span_holoparasite("You moved out of range, and were pulled back! You can only move [range] meters from [summoner.real_name]!"))
visible_message(span_danger("\The [src] jumps back to its user."))
if(istype(summoner.loc, /obj/effect))
new /obj/effect/temp_visual/guardian/phase/out(loc)
if(istype(summoner.loc, /obj/effect) || isnull(summoner.loc))
recall(forced = TRUE)
else
new /obj/effect/temp_visual/guardian/phase/out(loc)
forceMove(summoner.loc)
new /obj/effect/temp_visual/guardian/phase(loc)
return
forceMove(summoner.loc)
new /obj/effect/temp_visual/guardian/phase(loc)

/mob/living/simple_animal/hostile/guardian/can_suicide()
return FALSE
Expand Down Expand Up @@ -469,7 +472,7 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
//MANIFEST, RECALL, TOGGLE MODE/LIGHT, SHOW TYPE

/mob/living/simple_animal/hostile/guardian/proc/manifest(forced)
if(is_deployed() || istype(summoner.loc, /obj/effect) || (!COOLDOWN_FINISHED(src, manifest_cooldown) && !forced) || locked)
if(is_deployed() || isnull(summoner.loc) || istype(summoner.loc, /obj/effect) || (!COOLDOWN_FINISHED(src, manifest_cooldown) && !forced) || locked)
return FALSE
forceMove(summoner.loc)
new /obj/effect/temp_visual/guardian/phase(loc)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@

/mob/living/simple_animal/hostile/megafauna/dragon/lesser/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
. = ..()
lava_swoop.enraged = FALSE
lava_swoop?.enraged = FALSE // In case taking damage caused us to start deleting ourselves

/mob/living/simple_animal/hostile/megafauna/dragon/lesser/grant_achievement(medaltype,scoretype)
return
Expand Down
1 change: 0 additions & 1 deletion code/modules/mob/mob_helpers.dm
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@
CRASH("limbs is empty and the chest is blacklisted. this may not be intended!")
return (((chest_blacklisted && !base_zone) || even_weights) ? pick_weight(limbs) : ran_zone(base_zone, base_probability, limbs))


///Would this zone be above the neck
/proc/above_neck(zone)
var/list/zones = list(BODY_ZONE_HEAD, BODY_ZONE_PRECISE_MOUTH, BODY_ZONE_PRECISE_EYES)
Expand Down
27 changes: 16 additions & 11 deletions code/modules/spells/spell_types/shapeshift/_shape_status.dm
Original file line number Diff line number Diff line change
Expand Up @@ -76,20 +76,27 @@
UnregisterSignal(owner, list(COMSIG_LIVING_PRE_WABBAJACKED, COMSIG_LIVING_DEATH))
UnregisterSignal(caster_mob, list(COMSIG_QDELETING, COMSIG_LIVING_DEATH))

caster_mob.forceMove(owner.loc)
REMOVE_TRAIT(caster_mob, TRAIT_NO_TRANSFORM, REF(src))
caster_mob.remove_status_effect(/datum/status_effect/grouped/stasis, STASIS_SHAPECHANGE_EFFECT)
owner.mind?.transfer_to(caster_mob)

var/atom/former_loc = owner.loc
owner.moveToNullspace()
caster_mob.forceMove(former_loc) // This is to avoid crushing our former cockroach body

if(kill_caster_after)
caster_mob.death()

after_unchange()
caster_mob = null

// We're about to remove the status effect and clear owner so we need to cache this
var/mob/living/former_body = owner

// Do this late as it will destroy the status effect we are in and null a bunch of values we are trying to use
owner.mind?.transfer_to(caster_mob)

// Destroy the owner after all's said and done, this will also destroy our status effect (src)
// retore_caster() should never reach this point while either the owner or the effect is being qdeleted
qdel(owner)
qdel(former_body)

/// Effects done after the casting mob has reverted to their human form.
/datum/status_effect/shapechange_mob/proc/after_unchange()
Expand Down Expand Up @@ -154,9 +161,9 @@
source_spell.Grant(owner)

if(source_spell.convert_damage)
var/damage_to_apply = owner.maxHealth * ((caster_mob.maxHealth - caster_mob.health) / caster_mob.maxHealth)
var/damage_to_apply = owner.maxHealth * (caster_mob.get_total_damage() / caster_mob.maxHealth)

owner.apply_damage(damage_to_apply, source_spell.convert_damage_type, forced = TRUE, wound_bonus = CANT_WOUND)
owner.apply_damage(damage_to_apply, source_spell.convert_damage_type, forced = TRUE, spread_damage = TRUE, wound_bonus = CANT_WOUND)
owner.blood_volume = caster_mob.blood_volume

for(var/datum/action/bodybound_action as anything in caster_mob.actions)
Expand Down Expand Up @@ -186,11 +193,9 @@
if(QDELETED(source_spell) || !source_spell.convert_damage)
return

if(caster_mob.stat != DEAD)
caster_mob.revive(HEAL_DAMAGE)

var/damage_to_apply = caster_mob.maxHealth * ((owner.maxHealth - owner.health) / owner.maxHealth)
caster_mob.apply_damage(damage_to_apply, source_spell.convert_damage_type, forced = TRUE, wound_bonus = CANT_WOUND)
caster_mob.fully_heal(HEAL_DAMAGE) // Remove all of our damage before setting our health to a proportion of the former transformed mob's health
var/damage_to_apply = caster_mob.maxHealth * (owner.get_total_damage() / owner.maxHealth)
caster_mob.apply_damage(damage_to_apply, source_spell.convert_damage_type, forced = TRUE, spread_damage = TRUE, wound_bonus = CANT_WOUND)

caster_mob.blood_volume = owner.blood_volume

Expand Down
2 changes: 1 addition & 1 deletion code/modules/surgery/bodyparts/_bodyparts.dm
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@
/obj/item/bodypart/proc/receive_damage(brute = 0, burn = 0, blocked = 0, updating_health = TRUE, forced = FALSE, required_bodytype = null, wound_bonus = 0, bare_wound_bonus = 0, sharpness = NONE, attack_direction = null, damage_source)
SHOULD_CALL_PARENT(TRUE)

var/hit_percent = (100-blocked)/100
var/hit_percent = forced ? 1 : (100-blocked)/100
if((!brute && !burn) || hit_percent <= 0)
return FALSE
if (!forced)
Expand Down
Loading

0 comments on commit 9650cf5

Please sign in to comment.