mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-28 23:58:07 +01:00
Merge remote-tracking branch 'tgstation/master' into upstream-2025-11-29
# Conflicts: # _maps/RandomRuins/SpaceRuins/derelict_sulaco.dmm # _maps/RandomRuins/SpaceRuins/garbagetruck2.dmm # _maps/map_files/CatwalkStation/CatwalkStation_2023.dmm # _maps/map_files/tramstation/tramstation.dmm # code/_onclick/hud/new_player.dm # code/datums/components/squashable.dm # code/datums/diseases/advance/symptoms/heal.dm # code/datums/diseases/chronic_illness.dm # code/datums/status_effects/buffs.dm # code/datums/status_effects/debuffs/drunk.dm # code/datums/status_effects/debuffs/stamcrit.dm # code/game/machinery/computer/crew.dm # code/game/objects/items/devices/scanners/health_analyzer.dm # code/game/objects/items/wall_mounted.dm # code/game/turfs/closed/indestructible.dm # code/modules/admin/view_variables/filterrific.dm # code/modules/antagonists/heretic/influences.dm # code/modules/cargo/orderconsole.dm # code/modules/client/preferences.dm # code/modules/events/space_vines/vine_mutations.dm # code/modules/mob/dead/new_player/new_player.dm # code/modules/mob/living/carbon/human/death.dm # code/modules/mob/living/carbon/human/species_types/jellypeople.dm # code/modules/mob/living/damage_procs.dm # code/modules/mob/living/living.dm # code/modules/mob_spawn/ghost_roles/mining_roles.dm # code/modules/mob_spawn/mob_spawn.dm # code/modules/projectiles/ammunition/energy/laser.dm # code/modules/projectiles/guns/ballistic/launchers.dm # code/modules/projectiles/guns/energy/laser.dm # code/modules/reagents/chemistry/machinery/chem_dispenser.dm # code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm # code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm # code/modules/reagents/chemistry/reagents/medicine_reagents.dm # code/modules/surgery/healing.dm # code/modules/unit_tests/designs.dm # icons/mob/inhands/items_lefthand.dmi # icons/mob/inhands/items_righthand.dmi # tgui/packages/tgui/interfaces/ChemDispenser.tsx
This commit is contained in:
@@ -457,6 +457,9 @@
|
||||
var/c_type = target.type
|
||||
qdel(target)
|
||||
CRASH("Incompatible [c_type] transfer attempt to a [type]!")
|
||||
if(COMPONENT_NOTRANSFER)
|
||||
qdel(target)
|
||||
return
|
||||
|
||||
AddComponent(target)
|
||||
if(!QDELETED(target))
|
||||
|
||||
@@ -395,8 +395,8 @@
|
||||
///Check if an offspring of two fish (or one if self-reproducing) can evolve.
|
||||
/datum/component/aquarium/proc/check_evolution(atom/movable/source, obj/item/fish/fish, obj/item/fish/mate, datum/fish_evolution/evolution)
|
||||
SIGNAL_HANDLER
|
||||
//chances are halved if only one parent has this evolution.
|
||||
var/real_probability = (mate && (evolution.type in mate.evolution_types)) ? evolution.probability : evolution.probability * 0.5
|
||||
//chances are halved if it isn't asexual reproduction and one parent doesn't have the evolution.
|
||||
var/real_probability = (isnull(mate) || (evolution.type in mate.evolution_types)) ? evolution.probability : evolution.probability * 0.5
|
||||
if(HAS_TRAIT(fish, TRAIT_FISH_MUTAGENIC) || (mate && HAS_TRAIT(mate, TRAIT_FISH_MUTAGENIC)))
|
||||
real_probability *= 3
|
||||
if(!prob(real_probability))
|
||||
@@ -697,6 +697,8 @@
|
||||
check_fluid_and_temperature(fish)
|
||||
|
||||
/datum/component/aquarium/proc/admire(atom/movable/source, mob/living/user)
|
||||
if(!isliving(user))
|
||||
return
|
||||
source.balloon_alert(user, "admiring aquarium...")
|
||||
if(!do_after(user, 5 SECONDS, target = source))
|
||||
return
|
||||
|
||||
@@ -128,18 +128,18 @@
|
||||
new /obj/effect/temp_visual/heal(get_turf(candidate), healing_color)
|
||||
|
||||
if (iscarbon(candidate) || issilicon(candidate) || isbasicmob(candidate))
|
||||
candidate.adjustBruteLoss(-brute_heal * seconds_per_tick, updating_health = FALSE)
|
||||
candidate.adjustFireLoss(-burn_heal * seconds_per_tick, updating_health = FALSE)
|
||||
candidate.adjust_brute_loss(-brute_heal * seconds_per_tick, updating_health = FALSE)
|
||||
candidate.adjust_fire_loss(-burn_heal * seconds_per_tick, updating_health = FALSE)
|
||||
|
||||
if (iscarbon(candidate))
|
||||
// Toxin healing is forced for slime people
|
||||
candidate.adjustToxLoss(-toxin_heal * seconds_per_tick, updating_health = FALSE, forced = TRUE)
|
||||
candidate.adjust_tox_loss(-toxin_heal * seconds_per_tick, updating_health = FALSE, forced = TRUE)
|
||||
|
||||
candidate.adjustOxyLoss(-suffocation_heal * seconds_per_tick, updating_health = FALSE)
|
||||
candidate.adjustStaminaLoss(-stamina_heal * seconds_per_tick, updating_stamina = FALSE)
|
||||
candidate.adjust_oxy_loss(-suffocation_heal * seconds_per_tick, updating_health = FALSE)
|
||||
candidate.adjust_stamina_loss(-stamina_heal * seconds_per_tick, updating_stamina = FALSE)
|
||||
|
||||
for (var/organ in organ_healing)
|
||||
candidate.adjustOrganLoss(organ, -organ_healing[organ] * seconds_per_tick)
|
||||
candidate.adjust_organ_loss(organ, -organ_healing[organ] * seconds_per_tick)
|
||||
var/mob/living/carbon/carbidate = candidate
|
||||
for(var/datum/wound/iter_wound as anything in carbidate.all_wounds)
|
||||
iter_wound.adjust_blood_flow(-wound_clotting * seconds_per_tick)
|
||||
@@ -151,8 +151,7 @@
|
||||
var/mob/living/basic/basic_candidate = candidate
|
||||
basic_candidate.adjust_health(-simple_heal * seconds_per_tick, updating_health = FALSE)
|
||||
|
||||
if (candidate.blood_volume < BLOOD_VOLUME_NORMAL)
|
||||
candidate.blood_volume += blood_heal * seconds_per_tick
|
||||
candidate.adjust_blood_volume(blood_heal * seconds_per_tick, maximum = BLOOD_VOLUME_NORMAL)
|
||||
|
||||
candidate.updatehealth()
|
||||
|
||||
|
||||
@@ -49,6 +49,8 @@
|
||||
RegisterSignal(overmind, COMSIG_QDELETING, PROC_REF(overmind_deleted))
|
||||
RegisterSignal(overmind, COMSIG_BLOB_SELECTED_STRAIN, PROC_REF(strain_properties_changed))
|
||||
strain_properties_changed(overmind, overmind.blobstrain)
|
||||
var/mob/living_parent = parent
|
||||
living_parent.pass_flags |= PASSBLOB
|
||||
|
||||
/// Our overmind is gone, uh oh!
|
||||
/datum/component/blob_minion/proc/overmind_deleted()
|
||||
@@ -70,7 +72,6 @@
|
||||
|
||||
/datum/component/blob_minion/RegisterWithParent()
|
||||
var/mob/living/living_parent = parent
|
||||
living_parent.pass_flags |= PASSBLOB
|
||||
living_parent.faction |= ROLE_BLOB
|
||||
ADD_TRAIT(parent, TRAIT_BLOB_ALLY, REF(src))
|
||||
remove_verb(parent, /mob/living/verb/pulled) // No dragging people into the blob
|
||||
@@ -113,6 +114,7 @@
|
||||
COMSIG_HOSTILE_PRE_ATTACKINGTARGET,
|
||||
))
|
||||
GLOB.blob_telepathy_mobs -= parent
|
||||
living_parent.pass_flags &= ~PASSBLOB
|
||||
|
||||
/// Become blobpilled when we gain a mind
|
||||
/datum/component/blob_minion/proc/on_mind_init(mob/living/minion, datum/mind/new_mind)
|
||||
@@ -152,9 +154,9 @@
|
||||
/datum/component/blob_minion/proc/on_burned(mob/living/minion, exposed_temperature, exposed_volume)
|
||||
SIGNAL_HANDLER
|
||||
if(isnull(exposed_temperature))
|
||||
minion.adjustFireLoss(5)
|
||||
minion.adjust_fire_loss(5)
|
||||
return
|
||||
minion.adjustFireLoss(clamp(0.01 * exposed_temperature, 1, 5))
|
||||
minion.adjust_fire_loss(clamp(0.01 * exposed_temperature, 1, 5))
|
||||
|
||||
/// Someone is attempting to move through us, allow it if it is a blob tile
|
||||
/datum/component/blob_minion/proc/on_attempted_pass(mob/living/minion, atom/movable/incoming)
|
||||
|
||||
@@ -12,15 +12,12 @@
|
||||
///List of callback timers, used to clear out mobs listening to boss music after `track_duration`.
|
||||
var/list/music_callbacks = list()
|
||||
|
||||
/datum/component/boss_music/Initialize(
|
||||
boss_track,
|
||||
track_duration,
|
||||
)
|
||||
/datum/component/boss_music/Initialize(boss_track)
|
||||
. = ..()
|
||||
if(!ishostile(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
src.boss_track = boss_track
|
||||
src.track_duration = track_duration
|
||||
track_duration = SSsounds.get_sound_length(boss_track)
|
||||
|
||||
/datum/component/boss_music/Destroy(force)
|
||||
. = ..()
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
RegisterSignal(parent, SIGNAL_ADDTRAIT(TRAIT_CHASM_STOPPED), PROC_REF(on_chasm_stopped))
|
||||
RegisterSignal(parent, SIGNAL_REMOVETRAIT(TRAIT_CHASM_STOPPED), PROC_REF(on_chasm_no_longer_stopped))
|
||||
target_turf = target
|
||||
ADD_TRAIT(parent, TRAIT_AI_AVOID_TURF, REF(src))
|
||||
RegisterSignal(parent, COMSIG_ATOM_ABSTRACT_ENTERED, PROC_REF(entered))
|
||||
RegisterSignal(parent, COMSIG_ATOM_ABSTRACT_EXITED, PROC_REF(exited))
|
||||
RegisterSignal(parent, COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON, PROC_REF(initialized_on))
|
||||
@@ -53,6 +54,7 @@
|
||||
parent.AddComponent(/datum/component/fishing_spot, GLOB.preset_fish_sources[/datum/fish_source/chasm])
|
||||
|
||||
/datum/component/chasm/UnregisterFromParent()
|
||||
REMOVE_TRAIT(parent, TRAIT_AI_AVOID_TURF, REF(src))
|
||||
storage = null
|
||||
|
||||
/datum/component/chasm/proc/entered(datum/source, atom/movable/arrived, atom/old_loc, list/atom/old_locs)
|
||||
@@ -161,7 +163,7 @@
|
||||
if(isliving(dropped_thing))
|
||||
var/mob/living/fallen = dropped_thing
|
||||
fallen.Paralyze(100)
|
||||
fallen.adjustBruteLoss(30)
|
||||
fallen.adjust_brute_loss(30)
|
||||
falling_atoms -= falling_ref
|
||||
return
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
|
||||
/datum/crafting_recipe/xraylaser
|
||||
name = "X-ray Laser Gun"
|
||||
result = /obj/item/gun/energy/xray
|
||||
result = /obj/item/gun/energy/laser/xray
|
||||
reqs = list(
|
||||
/obj/item/gun/energy/laser = 1,
|
||||
/obj/item/weaponcrafting/gunkit/xray = 1,
|
||||
|
||||
@@ -300,12 +300,14 @@
|
||||
return
|
||||
our_turf = get_turf(cultist) //we may have moved. adjust as needed...
|
||||
|
||||
var/can_have_blood = CAN_HAVE_BLOOD(cultist)
|
||||
|
||||
cultist.visible_message(
|
||||
span_warning("[cultist] [cultist.blood_volume ? "cuts open [cultist.p_their()] arm and begins writing in [cultist.p_their()] own blood":"begins sketching out a strange design"]!"),
|
||||
span_cult("You [cultist.blood_volume ? "slice open your arm and ":""]begin drawing a sigil of the Geometer.")
|
||||
span_warning("[cultist] [can_have_blood ? "cuts open [cultist.p_their()] arm and begins writing in [cultist.p_their()] own blood":"begins sketching out a strange design"]!"),
|
||||
span_cult("You [can_have_blood ? "slice open your arm and ":""]begin drawing a sigil of the Geometer.")
|
||||
)
|
||||
|
||||
if(cultist.blood_volume)
|
||||
if(can_have_blood)
|
||||
cultist.apply_damage(initial(rune_to_scribe.scribe_damage), BRUTE, pick(GLOB.arm_zones), wound_bonus = CANT_WOUND) // *cuts arm* *bone explodes* ever have one of those days?
|
||||
|
||||
var/scribe_mod = initial(rune_to_scribe.scribe_delay)
|
||||
@@ -332,7 +334,7 @@
|
||||
return FALSE
|
||||
|
||||
cultist.visible_message(
|
||||
span_warning("[cultist] creates a strange circle[cultist.blood_volume ? " in [cultist.p_their()] own blood":""]."),
|
||||
span_warning("[cultist] creates a strange circle[can_have_blood ? " in [cultist.p_their()] own blood":""]."),
|
||||
span_cult("You finish drawing the arcane markings of the Geometer.")
|
||||
)
|
||||
|
||||
|
||||
@@ -97,13 +97,14 @@
|
||||
/// What effect the damage aura has if it has an owner.
|
||||
/datum/component/damage_aura/proc/owner_effect(mob/living/owner_mob, seconds_per_tick)
|
||||
var/need_mob_update = FALSE
|
||||
need_mob_update += owner_mob.adjustStaminaLoss(-20 * seconds_per_tick, updating_stamina = FALSE)
|
||||
need_mob_update += owner_mob.adjustBruteLoss(-1 * seconds_per_tick, updating_health = FALSE)
|
||||
need_mob_update += owner_mob.adjustFireLoss(-1 * seconds_per_tick, updating_health = FALSE)
|
||||
need_mob_update += owner_mob.adjustToxLoss(-1 * seconds_per_tick, updating_health = FALSE, forced = TRUE)
|
||||
need_mob_update += owner_mob.adjustOxyLoss(-1 * seconds_per_tick, updating_health = FALSE)
|
||||
if (owner_mob.blood_volume < BLOOD_VOLUME_NORMAL)
|
||||
owner_mob.blood_volume += 2 * seconds_per_tick
|
||||
need_mob_update += owner_mob.adjust_stamina_loss(-20 * seconds_per_tick, updating_stamina = FALSE)
|
||||
need_mob_update += owner_mob.adjust_brute_loss(-1 * seconds_per_tick, updating_health = FALSE)
|
||||
need_mob_update += owner_mob.adjust_fire_loss(-1 * seconds_per_tick, updating_health = FALSE)
|
||||
need_mob_update += owner_mob.adjust_tox_loss(-1 * seconds_per_tick, updating_health = FALSE, forced = TRUE)
|
||||
need_mob_update += owner_mob.adjust_oxy_loss(-1 * seconds_per_tick, updating_health = FALSE)
|
||||
|
||||
owner_mob.adjust_blood_volume(2 * seconds_per_tick, maximum = BLOOD_VOLUME_NORMAL)
|
||||
|
||||
if(need_mob_update)
|
||||
owner_mob.updatehealth()
|
||||
|
||||
@@ -134,16 +135,16 @@
|
||||
to_chat(candidate, damage_message)
|
||||
|
||||
if (iscarbon(candidate) || issilicon(candidate) || isbasicmob(candidate))
|
||||
candidate.adjustBruteLoss(brute_damage * seconds_per_tick, updating_health = FALSE)
|
||||
candidate.adjustFireLoss(burn_damage * seconds_per_tick, updating_health = FALSE)
|
||||
candidate.adjust_brute_loss(brute_damage * seconds_per_tick, updating_health = FALSE)
|
||||
candidate.adjust_fire_loss(burn_damage * seconds_per_tick, updating_health = FALSE)
|
||||
|
||||
if (iscarbon(candidate))
|
||||
candidate.adjustToxLoss(toxin_damage * seconds_per_tick, updating_health = FALSE)
|
||||
candidate.adjustOxyLoss(suffocation_damage * seconds_per_tick, updating_health = FALSE)
|
||||
candidate.adjustStaminaLoss(stamina_damage * seconds_per_tick, updating_stamina = FALSE)
|
||||
candidate.adjust_tox_loss(toxin_damage * seconds_per_tick, updating_health = FALSE)
|
||||
candidate.adjust_oxy_loss(suffocation_damage * seconds_per_tick, updating_health = FALSE)
|
||||
candidate.adjust_stamina_loss(stamina_damage * seconds_per_tick, updating_stamina = FALSE)
|
||||
|
||||
for (var/organ in organ_damage)
|
||||
candidate.adjustOrganLoss(organ, organ_damage[organ] * seconds_per_tick)
|
||||
candidate.adjust_organ_loss(organ, organ_damage[organ] * seconds_per_tick)
|
||||
else if (isanimal(candidate))
|
||||
var/mob/living/simple_animal/animal_candidate = candidate
|
||||
animal_candidate.adjustHealth(simple_damage * seconds_per_tick, updating_health = FALSE)
|
||||
@@ -151,8 +152,7 @@
|
||||
var/mob/living/basic/basic_candidate = candidate
|
||||
basic_candidate.adjust_health(simple_damage * seconds_per_tick, updating_health = FALSE)
|
||||
|
||||
if (candidate.blood_volume > BLOOD_VOLUME_SURVIVE)
|
||||
candidate.blood_volume -= blood_damage * seconds_per_tick
|
||||
candidate.adjust_blood_volume(blood_damage * seconds_per_tick, minimum = BLOOD_VOLUME_SURVIVE)
|
||||
|
||||
candidate.updatehealth()
|
||||
|
||||
|
||||
@@ -48,9 +48,9 @@
|
||||
|
||||
if(isliving(parent))
|
||||
var/mob/living/L = parent
|
||||
tox_loss = L.getToxLoss()
|
||||
oxy_loss = L.getOxyLoss()
|
||||
stamina_loss = L.getStaminaLoss()
|
||||
tox_loss = L.get_tox_loss()
|
||||
oxy_loss = L.get_oxy_loss()
|
||||
stamina_loss = L.get_stamina_loss()
|
||||
brain_loss = L.get_organ_loss(ORGAN_SLOT_BRAIN)
|
||||
rewind_type = PROC_REF(rewind_living)
|
||||
|
||||
@@ -99,10 +99,10 @@
|
||||
parent.AddComponent(type, 1, rewind_interval, TRUE)
|
||||
|
||||
var/mob/living/master = parent
|
||||
master.setToxLoss(tox_loss)
|
||||
master.setOxyLoss(oxy_loss)
|
||||
master.setStaminaLoss(stamina_loss)
|
||||
master.setOrganLoss(ORGAN_SLOT_BRAIN, brain_loss)
|
||||
master.set_tox_loss(tox_loss)
|
||||
master.set_oxy_loss(oxy_loss)
|
||||
master.set_stamina_loss(stamina_loss)
|
||||
master.set_organ_loss(ORGAN_SLOT_BRAIN, brain_loss)
|
||||
rewind()
|
||||
|
||||
/datum/component/dejavu/proc/rewind_carbon()
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
///Whenever get_ear_protection() is called, this proc adds 'protection_value' to the wearer's natural ear protection.
|
||||
/datum/component/wearertargeting/earprotection
|
||||
signals = list(COMSIG_LIVING_GET_EAR_PROTECTION)
|
||||
mobtype = /mob/living/carbon
|
||||
proctype = PROC_REF(reducebang)
|
||||
var/reduce_amount = 1
|
||||
//positive amount indicating how much protection this gives
|
||||
var/protection_amount = 1
|
||||
valid_slots = ITEM_SLOT_EARS | ITEM_SLOT_HEAD
|
||||
|
||||
/datum/component/wearertargeting/earprotection/Initialize(reduce_amount = 1)
|
||||
/datum/component/wearertargeting/earprotection/Initialize(protection_amount = EAR_PROTECTION_NORMAL)
|
||||
. = ..()
|
||||
if(reduce_amount)
|
||||
src.reduce_amount = reduce_amount
|
||||
src.protection_amount = protection_amount
|
||||
|
||||
/datum/component/wearertargeting/earprotection/proc/reducebang(datum/source, list/reflist)
|
||||
reflist[EAR_PROTECTION_ARG] -= reduce_amount
|
||||
SIGNAL_HANDLER
|
||||
reflist[EAR_PROTECTION_ARG] += protection_amount
|
||||
|
||||
@@ -106,17 +106,15 @@
|
||||
if(HAS_TRAIT(echolocator, TRAIT_ECHOLOCATION_EXTRA_RANGE))
|
||||
real_echo_range += 2
|
||||
var/list/filtered = list()
|
||||
var/list/seen = dview(real_echo_range, get_turf(echolocator.client?.eye || echolocator), invis_flags = echolocator.see_invisible)
|
||||
if(blinding)
|
||||
for(var/atom/seen_atom as anything in seen)
|
||||
for(var/atom/seen_atom as anything in dview(real_echo_range, get_turf(echolocator.client?.eye || echolocator), invis_flags = echolocator.see_invisible))
|
||||
if(!seen_atom.alpha)
|
||||
continue
|
||||
if(allowed_paths[seen_atom.type])
|
||||
filtered += seen_atom
|
||||
else
|
||||
var/list/ranged_atoms = range(real_echo_range, get_turf(echolocator.client?.eye || echolocator))
|
||||
for(var/atom/possible_atom as anything in ranged_atoms)
|
||||
if(!possible_atom.alpha)
|
||||
for(var/atom/possible_atom as anything in range(real_echo_range, get_turf(echolocator.client?.eye || echolocator)))
|
||||
if(!possible_atom.alpha || possible_atom.invisibility > echolocator.see_invisible)
|
||||
continue
|
||||
if(allowed_paths[possible_atom.type])
|
||||
filtered += possible_atom
|
||||
|
||||
@@ -57,9 +57,9 @@
|
||||
var/t_are = target.p_are()
|
||||
if((visible_info & EMPATH_SEE_COMBAT) && target.combat_mode)
|
||||
examine_list += "[t_They] seem[p_s()] to be on guard."
|
||||
if((visible_info & EMPATH_SEE_OXY) && target.getOxyLoss() >= 10)
|
||||
if((visible_info & EMPATH_SEE_OXY) && target.get_oxy_loss() >= 10)
|
||||
examine_list += "[t_They] seem[p_s()] winded."
|
||||
if((visible_info & EMPATH_SEE_TOX) && target.getToxLoss() >= 10)
|
||||
if((visible_info & EMPATH_SEE_TOX) && target.get_tox_loss() >= 10)
|
||||
examine_list += "[t_They] seem[p_s()] sickly."
|
||||
if((visible_info & EMPATH_SEE_SANITY) && target.mob_mood.sanity <= SANITY_DISTURBED)
|
||||
examine_list += "[t_They] seem[p_s()] distressed."
|
||||
|
||||
@@ -111,11 +111,12 @@
|
||||
/mob/living/simple_animal,
|
||||
)
|
||||
for(var/type in mob_subtype_whitelist)
|
||||
possible_mobtypes += subtypesof(type)
|
||||
possible_mobtypes += valid_subtypesof(type)
|
||||
|
||||
var/list/mob_subtype_blacklist = list(
|
||||
/mob/living/simple_animal/hostile/asteroid/elite,
|
||||
/mob/living/simple_animal/hostile/megafauna,
|
||||
/mob/living/basic/boss,
|
||||
)
|
||||
for(var/type in mob_subtype_blacklist)
|
||||
possible_mobtypes -= subtypesof(type)
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
return
|
||||
|
||||
if (terror_buildup < TERROR_BUILDUP_HEART_ATTACK || !prob(15))
|
||||
owner.adjustOxyLoss(8)
|
||||
owner.adjust_oxy_loss(8)
|
||||
if (terror_buildup < TERROR_BUILDUP_FEAR)
|
||||
to_chat(owner, span_warning("Your heart skips a beat."))
|
||||
else
|
||||
|
||||
@@ -287,7 +287,7 @@ Behavior that's still missing from this component that original food items had t
|
||||
else
|
||||
examine_list += span_notice("[owner] was bitten multiple times!")
|
||||
|
||||
if(GLOB.Debug2)
|
||||
if(GLOB.debugging_enabled)
|
||||
examine_list += span_notice("Reagent purities:")
|
||||
for(var/datum/reagent/reagent as anything in owner.reagents.reagent_list)
|
||||
examine_list += span_notice("- [reagent.name] [reagent.volume]u: [round(reagent.purity * 100)]% pure")
|
||||
@@ -739,6 +739,8 @@ Behavior that's still missing from this component that original food items had t
|
||||
///Ability to feed food to puppers
|
||||
/datum/component/edible/proc/on_entered(datum/source, atom/movable/arrived, atom/old_loc, list/atom/old_locs)
|
||||
SIGNAL_HANDLER
|
||||
if(QDELETED(parent))
|
||||
return
|
||||
SEND_SIGNAL(parent, COMSIG_FOOD_CROSSED, arrived, bitecount)
|
||||
|
||||
///Response to being used to customize something
|
||||
|
||||
@@ -165,14 +165,14 @@
|
||||
/datum/component/healing_touch/proc/has_healable_damage(mob/living/target)
|
||||
if (!isnull(valid_biotypes) && !(valid_biotypes & target.mob_biotypes))
|
||||
return FALSE
|
||||
if (target.getStaminaLoss() > 0 && heal_stamina)
|
||||
if (target.get_stamina_loss() > 0 && heal_stamina)
|
||||
return TRUE
|
||||
if (target.getOxyLoss() > 0 && heal_oxy)
|
||||
if (target.get_oxy_loss() > 0 && heal_oxy)
|
||||
return TRUE
|
||||
if (target.getToxLoss() > 0 && heal_tox)
|
||||
if (target.get_tox_loss() > 0 && heal_tox)
|
||||
return TRUE
|
||||
if (!iscarbon(target))
|
||||
return (target.getBruteLoss() > 0 && heal_brute) || (target.getFireLoss() > 0 && heal_burn)
|
||||
return (target.get_brute_loss() > 0 && heal_brute) || (target.get_fire_loss() > 0 && heal_burn)
|
||||
var/mob/living/carbon/carbon_target = target
|
||||
for (var/obj/item/bodypart/part in carbon_target.bodyparts)
|
||||
if (!(part.brute_dam && heal_brute) && !(part.burn_dam && heal_burn))
|
||||
@@ -207,8 +207,8 @@
|
||||
required_bodytype = required_bodytype,
|
||||
updating_health = FALSE,
|
||||
)
|
||||
healed += target.adjustOxyLoss(-heal_oxy * mult, updating_health = FALSE, required_biotype = valid_biotypes)
|
||||
healed += target.adjustToxLoss(-heal_tox * mult, updating_health = FALSE, required_biotype = valid_biotypes)
|
||||
healed += target.adjust_oxy_loss(-heal_oxy * mult, updating_health = FALSE, required_biotype = valid_biotypes)
|
||||
healed += target.adjust_tox_loss(-heal_tox * mult, updating_health = FALSE, required_biotype = valid_biotypes)
|
||||
if (healed <= 0)
|
||||
return
|
||||
|
||||
|
||||
@@ -111,11 +111,11 @@
|
||||
///Heart eater give also strong healing from hearts.
|
||||
/datum/component/heart_eater/proc/healing_heart(mob/living/carbon/human/eater)
|
||||
for(var/heal_organ in eater.organs)
|
||||
eater.adjustOrganLoss(heal_organ, -50)
|
||||
eater.adjust_organ_loss(heal_organ, -50)
|
||||
for(var/datum/wound/heal_wound in eater.all_wounds)
|
||||
heal_wound.remove_wound()
|
||||
eater.adjustBruteLoss(-50)
|
||||
eater.adjustFireLoss(-50)
|
||||
eater.adjustToxLoss(-50)
|
||||
eater.adjustOxyLoss(-50)
|
||||
eater.adjustStaminaLoss(-50)
|
||||
eater.adjust_brute_loss(-50)
|
||||
eater.adjust_fire_loss(-50)
|
||||
eater.adjust_tox_loss(-50)
|
||||
eater.adjust_oxy_loss(-50)
|
||||
eater.adjust_stamina_loss(-50)
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/// Teleports interactors onto a safe turf randomly picked from a list of z-levels.
|
||||
/datum/component/houlihan_teleport
|
||||
dupe_mode = COMPONENT_DUPE_HIGHLANDER
|
||||
/// Text that will appear in the alert prompt.
|
||||
var/question = "Travel back?"
|
||||
/// List of z-levels that the user can teleport to. By default, this is station z-levels.
|
||||
var/list/zlevels
|
||||
|
||||
/datum/component/houlihan_teleport/Initialize(question, zlevels)
|
||||
. = ..()
|
||||
if(!isstructure(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
if(!isnull(question) && (!istext(question) || !length(question)))
|
||||
stack_trace("received bad question argument, falling back to default")
|
||||
question = null
|
||||
src.question = question || initial(src.question)
|
||||
|
||||
if(!isnull(zlevels) && (!islist(zlevels) || !length(zlevels)))
|
||||
stack_trace("received bad zlevels argument, falling back to default")
|
||||
zlevels = null
|
||||
src.zlevels = zlevels || SSmapping.levels_by_trait(ZTRAIT_STATION)
|
||||
|
||||
/datum/component/houlihan_teleport/RegisterWithParent()
|
||||
RegisterSignals(parent, list(COMSIG_ATOM_ATTACK_ROBOT, COMSIG_ATOM_ATTACK_PAW, COMSIG_ATOM_ATTACK_ANIMAL, COMSIG_ATOM_ATTACK_LARVA), PROC_REF(handle_generic_attack))
|
||||
RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, PROC_REF(handle_attack_hand))
|
||||
RegisterSignal(parent, COMSIG_ATOM_ATTACKBY, PROC_REF(handle_attackby))
|
||||
|
||||
/datum/component/houlihan_teleport/UnregisterFromParent()
|
||||
UnregisterSignal(parent, list(
|
||||
COMSIG_ATOM_ATTACK_ROBOT, COMSIG_ATOM_ATTACK_PAW, COMSIG_ATOM_ATTACK_ANIMAL, COMSIG_ATOM_ATTACK_LARVA, //handle_generic_attack
|
||||
COMSIG_ATOM_ATTACK_HAND, //handle_attack_hand
|
||||
COMSIG_ATOM_ATTACKBY, //handle_attackby
|
||||
))
|
||||
|
||||
/datum/component/houlihan_teleport/proc/get_me_outta_here(obj/structure/source, mob/living/user)
|
||||
var/said_yes = (tgui_alert(user, question, source.name, list("Yes", "No")) == "Yes")
|
||||
if(!said_yes || !source.Adjacent(user))
|
||||
return
|
||||
|
||||
var/turf/destination_turf = zlevels ? find_safe_turf(zlevels) : get_safe_random_station_turf_equal_weight()
|
||||
if(!destination_turf)
|
||||
source.balloon_alert(user, "uh oh...")
|
||||
to_chat(user, span_warning("Nothing happens. You feel like this is a bad sign."))
|
||||
return
|
||||
|
||||
var/turf/user_turf = get_turf(user)
|
||||
var/atom/movable/dragged = user.pulling
|
||||
user.forceMove(destination_turf)
|
||||
user_turf.balloon_alert_to_viewers("(pop)")
|
||||
if(dragged)
|
||||
var/turf/dragged_turf = get_turf(dragged)
|
||||
dragged.forceMove(destination_turf)
|
||||
user.start_pulling(dragged, force = TRUE)
|
||||
dragged_turf.balloon_alert_to_viewers("(pop)")
|
||||
|
||||
to_chat(list(user, dragged), span_notice("You blink and find yourself in <b>[get_area_name(destination_turf)]</b>."))
|
||||
user.emote("blink")
|
||||
astype(dragged, /mob)?.emote("blink") // shhhhh just let it happen
|
||||
|
||||
/datum/component/houlihan_teleport/proc/handle_generic_attack(obj/structure/source, mob/living/user, list/modifiers)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(user.combat_mode)
|
||||
return NONE
|
||||
|
||||
if(iscyborg(user) && !source.Adjacent(user))
|
||||
return NONE
|
||||
|
||||
INVOKE_ASYNC(src, PROC_REF(get_me_outta_here), source, user)
|
||||
return COMPONENT_NO_AFTERATTACK
|
||||
|
||||
/datum/component/houlihan_teleport/proc/handle_attack_hand(obj/structure/source, mob/user, list/modifiers)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!isliving(user))
|
||||
return NONE
|
||||
|
||||
var/mob/living/living_user = user
|
||||
if(living_user.combat_mode)
|
||||
return NONE
|
||||
|
||||
INVOKE_ASYNC(src, PROC_REF(get_me_outta_here), source, living_user)
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/datum/component/houlihan_teleport/proc/handle_attackby(obj/structure/source, obj/item/item, mob/living/user, list/modifiers)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(user.combat_mode)
|
||||
return NONE
|
||||
|
||||
INVOKE_ASYNC(src, PROC_REF(get_me_outta_here), source, user)
|
||||
return COMPONENT_NO_AFTERATTACK
|
||||
@@ -101,7 +101,7 @@
|
||||
return PROCESS_KILL
|
||||
|
||||
var/mob/living/carbon/human/human_parent = parent
|
||||
if (human_parent.getToxLoss() == 0)
|
||||
if (human_parent.get_tox_loss() == 0)
|
||||
qdel(src)
|
||||
return PROCESS_KILL
|
||||
|
||||
@@ -216,7 +216,7 @@
|
||||
|
||||
if (isliving(source))
|
||||
var/mob/living/living_source = source
|
||||
to_chat(user, span_bolddanger("[icon2html(geiger_counter, user)] Subject is irradiated. Contamination traces back to roughly [DisplayTimeText(world.time - beginning_of_irradiation, 5)] ago. Current toxin levels: [living_source.getToxLoss()]."))
|
||||
to_chat(user, span_bolddanger("[icon2html(geiger_counter, user)] Subject is irradiated. Contamination traces back to roughly [DisplayTimeText(world.time - beginning_of_irradiation, 5)] ago. Current toxin levels: [living_source.get_tox_loss()]."))
|
||||
else
|
||||
// In case the green wasn't obvious enough...
|
||||
to_chat(user, span_bolddanger("[icon2html(geiger_counter, user)] Target is irradiated."))
|
||||
|
||||
@@ -31,5 +31,5 @@
|
||||
|
||||
var/mob/living/overlord_to_damage = overlord_mob?.resolve()
|
||||
if(!isnull(overlord_to_damage))
|
||||
overlord_to_damage.adjustBruteLoss(previous_health_count - source.health) ///damage or heal overlord
|
||||
overlord_to_damage.adjust_brute_loss(previous_health_count - source.health) ///damage or heal overlord
|
||||
previous_health_count = source.health
|
||||
|
||||
@@ -95,16 +95,26 @@
|
||||
var/static/list/config_songs
|
||||
if(isnull(config_songs))
|
||||
config_songs = list()
|
||||
var/list/tracks = flist("[global.config.directory]/jukebox_music/sounds/")
|
||||
var/list/tracks = flist(CONFIG_JUKEBOX_SOUNDS)
|
||||
for(var/track_file in tracks)
|
||||
var/datum/track/new_track = new()
|
||||
new_track.song_path = file("[global.config.directory]/jukebox_music/sounds/[track_file]")
|
||||
new_track.song_path = file("[CONFIG_JUKEBOX_SOUNDS][track_file]")
|
||||
var/list/track_data = splittext(track_file, "+")
|
||||
if(length(track_data) < 3 || !IS_SOUND_FILE(new_track.song_path))
|
||||
if(!length(track_data) || !IS_SOUND_FILE_SAFE(new_track.song_path))
|
||||
continue
|
||||
new_track.song_name = track_data[1]
|
||||
new_track.song_length = text2num(track_data[2])
|
||||
new_track.song_beat = text2num(track_data[3])
|
||||
var/track_name = track_data[JUKEBOX_NAME]
|
||||
track_name = strip_filepath_extension(track_name, SSsounds.safe_formats)
|
||||
new_track.song_name = track_name
|
||||
new_track.song_length = SSsounds.get_sound_length(new_track.song_path)
|
||||
if(track_data.len >= 3) // Bandaid for legacy tracks to not use the length for the bpm rather then the actual beats.
|
||||
var/static/logged_to_admins = FALSE
|
||||
log_game("[new_track.song_path] track data seems to be using the legacy format; we will attempt to make it work.")
|
||||
if(!logged_to_admins)
|
||||
message_admins("The jukebox has tracks uploaded in a legacy format. Length is now fetched programmatically, with title and beats being the only required fields.")
|
||||
logged_to_admins = TRUE
|
||||
new_track.song_beat_deciseconds = text2num(track_data[3])
|
||||
else if(track_data.len >= 2)
|
||||
new_track.song_beat_deciseconds = text2num(track_data[JUKEBOX_BEATS])
|
||||
config_songs[new_track.song_name] = new_track
|
||||
|
||||
if(!length(config_songs))
|
||||
@@ -128,7 +138,7 @@
|
||||
UNTYPED_LIST_ADD(songs_data, list( \
|
||||
"name" = song_name, \
|
||||
"length" = DisplayTimeText(one_song.song_length), \
|
||||
"beat" = one_song.song_beat, \
|
||||
"beat" = one_song.song_beat_deciseconds || "Unknown", \
|
||||
))
|
||||
|
||||
data["active"] = !!active_song_sound
|
||||
@@ -399,11 +409,12 @@
|
||||
var/song_length = 0
|
||||
/// How long is a beat of the song in decisconds
|
||||
/// Used to determine time between effects when played
|
||||
var/song_beat = 0
|
||||
/// Do note this is NOT BPM.
|
||||
var/song_beat_deciseconds = 0
|
||||
|
||||
// Default track supplied for testing and also because it's a banger
|
||||
/datum/track/default
|
||||
song_path = 'sound/music/lobby_music/title3.ogg'
|
||||
song_name = "Tintin on the Moon"
|
||||
song_length = 3 MINUTES + 52 SECONDS
|
||||
song_beat = 1 SECONDS
|
||||
song_beat_deciseconds = 1 SECONDS
|
||||
|
||||
@@ -65,13 +65,13 @@
|
||||
amount *= our_mob.get_damage_mod(type)
|
||||
switch (type)
|
||||
if(BRUTE)
|
||||
host.adjustBruteLoss(amount, forced = TRUE)
|
||||
host.adjust_brute_loss(amount, forced = TRUE)
|
||||
if(BURN)
|
||||
host.adjustFireLoss(amount, forced = TRUE)
|
||||
host.adjust_fire_loss(amount, forced = TRUE)
|
||||
if(TOX)
|
||||
host.adjustToxLoss(amount, forced = TRUE)
|
||||
host.adjust_tox_loss(amount, forced = TRUE)
|
||||
if(OXY)
|
||||
host.adjustOxyLoss(amount, forced = TRUE)
|
||||
host.adjust_oxy_loss(amount, forced = TRUE)
|
||||
|
||||
on_passed_damage?.Invoke(our_mob, host, amount)
|
||||
return COMPONENT_IGNORE_CHANGE
|
||||
@@ -80,9 +80,9 @@
|
||||
/datum/component/life_link/proc/on_limb_damage(mob/living/our_mob, limb, brute, burn)
|
||||
SIGNAL_HANDLER
|
||||
if (brute != 0)
|
||||
host.adjustBruteLoss(brute, updating_health = FALSE)
|
||||
host.adjust_brute_loss(brute, updating_health = FALSE)
|
||||
if (burn != 0)
|
||||
host.adjustFireLoss(burn, updating_health = FALSE)
|
||||
host.adjust_fire_loss(burn, updating_health = FALSE)
|
||||
if (brute != 0 || burn != 0)
|
||||
host.updatehealth()
|
||||
on_passed_damage?.Invoke(our_mob, host, brute + burn)
|
||||
|
||||
@@ -49,22 +49,21 @@
|
||||
RegisterSignal(parent, COMSIG_CARBON_LOSE_ORGAN, PROC_REF(check_removed_organ))
|
||||
RegisterSignal(parent, COMSIG_CARBON_GAIN_ORGAN, PROC_REF(check_added_organ))
|
||||
RegisterSignal(parent, COMSIG_HEART_MANUAL_PULSE, PROC_REF(on_pump))
|
||||
RegisterSignals(parent, list(COMSIG_LIVING_DEATH, SIGNAL_ADDTRAIT(TRAIT_NOBLOOD)), PROC_REF(pause))
|
||||
RegisterSignals(parent, list(COMSIG_LIVING_REVIVE, SIGNAL_REMOVETRAIT(TRAIT_NOBLOOD)), PROC_REF(restart))
|
||||
RegisterSignal(parent, COMSIG_LIVING_UPDATE_BLOOD_STATUS, PROC_REF(on_update_blood_status))
|
||||
|
||||
pump_action.cooldown_time = pump_delay - (1 SECONDS) //you can pump up to a second early
|
||||
pump_action.Grant(parent)
|
||||
|
||||
var/mob/living/carbon/carbon_parent = parent
|
||||
var/obj/item/organ/heart/parent_heart = carbon_parent.get_organ_slot(ORGAN_SLOT_HEART)
|
||||
if(parent_heart && !HAS_TRAIT(carbon_parent, TRAIT_NOBLOOD) && carbon_parent.stat != DEAD)
|
||||
if(parent_heart && CAN_HAVE_BLOOD(carbon_parent) && carbon_parent.stat != DEAD)
|
||||
START_PROCESSING(SSdcs, src)
|
||||
COOLDOWN_START(src, heart_timer, pump_delay)
|
||||
|
||||
to_chat(parent, span_userdanger("Your heart no longer beats automatically! You have to pump it manually - otherwise you'll die!"))
|
||||
|
||||
/datum/component/manual_heart/UnregisterFromParent()
|
||||
UnregisterSignal(parent, list(COMSIG_CARBON_GAIN_ORGAN, COMSIG_CARBON_LOSE_ORGAN, COMSIG_HEART_MANUAL_PULSE, COMSIG_LIVING_REVIVE, COMSIG_LIVING_DEATH, SIGNAL_ADDTRAIT(TRAIT_NOBLOOD), SIGNAL_REMOVETRAIT(TRAIT_NOBLOOD)))
|
||||
UnregisterSignal(parent, list(COMSIG_CARBON_GAIN_ORGAN, COMSIG_CARBON_LOSE_ORGAN, COMSIG_HEART_MANUAL_PULSE, COMSIG_LIVING_REVIVE, COMSIG_LIVING_DEATH, COMSIG_LIVING_UPDATE_BLOOD_STATUS))
|
||||
|
||||
to_chat(parent, span_userdanger("You feel your heart start beating normally again!"))
|
||||
var/mob/living/carbon/carbon_parent = parent
|
||||
@@ -95,14 +94,14 @@
|
||||
|
||||
var/mob/living/carbon/carbon_owner = owner
|
||||
|
||||
if(HAS_TRAIT(carbon_owner, TRAIT_NOBLOOD))
|
||||
if(!CAN_HAVE_BLOOD(carbon_owner))
|
||||
return
|
||||
carbon_owner.blood_volume = min(carbon_owner.blood_volume + (blood_loss * 0.5), BLOOD_VOLUME_MAXIMUM)
|
||||
carbon_owner.adjust_blood_volume(blood_loss * 0.5)
|
||||
carbon_owner.remove_client_colour(REF(src))
|
||||
add_colour = TRUE
|
||||
carbon_owner.adjustBruteLoss(-heal_brute)
|
||||
carbon_owner.adjustFireLoss(-heal_burn)
|
||||
carbon_owner.adjustOxyLoss(-heal_oxy)
|
||||
carbon_owner.adjust_brute_loss(-heal_brute)
|
||||
carbon_owner.adjust_fire_loss(-heal_burn)
|
||||
carbon_owner.adjust_oxy_loss(-heal_oxy)
|
||||
|
||||
/datum/component/manual_heart/process()
|
||||
var/mob/living/carbon/carbon_parent = parent
|
||||
@@ -115,13 +114,21 @@
|
||||
if(!COOLDOWN_FINISHED(src, heart_timer))
|
||||
return
|
||||
|
||||
carbon_parent.blood_volume = max(carbon_parent.blood_volume - blood_loss, 0)
|
||||
carbon_parent.adjust_blood_volume(-blood_loss)
|
||||
to_chat(carbon_parent, span_userdanger("You have to keep pumping your blood!"))
|
||||
COOLDOWN_START(src, heart_timer, MANUAL_HEART_GRACE_PERIOD) //give two full seconds before losing more blood
|
||||
if(add_colour)
|
||||
carbon_parent.add_client_colour(/datum/client_colour/manual_heart_blood, REF(src))
|
||||
add_colour = FALSE
|
||||
|
||||
/datum/component/manual_heart/proc/on_update_blood_status(datum/source, had_blood, has_blood, new_blood_volume, old_blood_volume)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if (has_blood)
|
||||
restart()
|
||||
else
|
||||
pause()
|
||||
|
||||
///If a new heart is added, start processing.
|
||||
/datum/component/manual_heart/proc/check_added_organ(mob/organ_owner, obj/item/organ/new_organ)
|
||||
SIGNAL_HANDLER
|
||||
@@ -151,7 +158,7 @@
|
||||
/datum/component/manual_heart/proc/check_valid()
|
||||
var/mob/living/carbon/carbon_parent = parent
|
||||
var/obj/item/organ/heart/parent_heart = carbon_parent.get_organ_slot(ORGAN_SLOT_HEART)
|
||||
return !isnull(parent_heart) && !HAS_TRAIT(carbon_parent, TRAIT_NOBLOOD) && carbon_parent.stat != DEAD
|
||||
return !isnull(parent_heart) && CAN_HAVE_BLOOD(carbon_parent) && carbon_parent.stat != DEAD
|
||||
|
||||
///Action to pump your heart. Cooldown will always be set to 1 second less than the pump delay.
|
||||
/datum/action/cooldown/manual_heart
|
||||
@@ -169,7 +176,7 @@
|
||||
///The action button is only available when you're a living carbon with blood and a heart.
|
||||
/datum/action/cooldown/manual_heart/IsAvailable(feedback = FALSE)
|
||||
var/mob/living/carbon/heart_haver = owner
|
||||
if(!istype(heart_haver) || HAS_TRAIT(heart_haver, TRAIT_NOBLOOD) || heart_haver.stat == DEAD)
|
||||
if(!istype(heart_haver) || !CAN_HAVE_BLOOD(heart_haver) || heart_haver.stat == DEAD)
|
||||
return FALSE
|
||||
var/obj/item/organ/heart/heart_havers_heart = heart_haver.get_organ_slot(ORGAN_SLOT_HEART)
|
||||
if(isnull(heart_havers_heart))
|
||||
|
||||
@@ -171,7 +171,7 @@
|
||||
SIGNAL_HANDLER
|
||||
if (forced)
|
||||
return
|
||||
back?.adjustStaminaLoss(amount, forced = forced)
|
||||
back?.adjust_stamina_loss(amount, forced = forced)
|
||||
|
||||
/// On damage or heal, affect our furthest segment
|
||||
/datum/component/mob_chain/proc/on_adjust_damage(mob/living/our_mob, type, amount, forced)
|
||||
@@ -180,13 +180,13 @@
|
||||
return
|
||||
switch (type)
|
||||
if(BRUTE)
|
||||
back.adjustBruteLoss(amount, forced = forced)
|
||||
back.adjust_brute_loss(amount, forced = forced)
|
||||
if(BURN)
|
||||
back.adjustFireLoss(amount, forced = forced)
|
||||
back.adjust_fire_loss(amount, forced = forced)
|
||||
if(TOX)
|
||||
back.adjustToxLoss(amount, forced = forced)
|
||||
back.adjust_tox_loss(amount, forced = forced)
|
||||
if(OXY) // If all segments are suffocating we pile damage backwards until our ass starts dying forwards
|
||||
back.adjustOxyLoss(amount, forced = forced)
|
||||
back.adjust_oxy_loss(amount, forced = forced)
|
||||
return COMPONENT_IGNORE_CHANGE
|
||||
|
||||
/// Special handling for if damage is delegated to a mob's limbs instead of its overall damage
|
||||
@@ -195,9 +195,9 @@
|
||||
if (isnull(back))
|
||||
return
|
||||
if (brute != 0)
|
||||
back.adjustBruteLoss(brute, updating_health = FALSE)
|
||||
back.adjust_brute_loss(brute, updating_health = FALSE)
|
||||
if (burn != 0)
|
||||
back.adjustFireLoss(burn, updating_health = FALSE)
|
||||
back.adjust_fire_loss(burn, updating_health = FALSE)
|
||||
if (brute != 0 || burn != 0)
|
||||
back.updatehealth()
|
||||
return COMPONENT_PREVENT_LIMB_DAMAGE
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/datum/component/plumbing/automated_iv
|
||||
demand_connects = SOUTH
|
||||
supply_connects = NORTH
|
||||
///Temporary holder to store all the reagents from the iv drip before transferring it to the ducts
|
||||
var/datum/reagents/plumbing/holder
|
||||
|
||||
/datum/component/plumbing/automated_iv/Initialize(start=TRUE, _ducting_layer, _turn_connects=TRUE, datum/reagents/custom_receiver)
|
||||
. = ..()
|
||||
if(!istype(parent, /obj/machinery/iv_drip/plumbing))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
var/obj/machinery/iv_drip/plumbing/drip = parent
|
||||
holder = new(drip.reagents.maximum_volume, drip.reagents.flags)
|
||||
holder.my_atom = drip
|
||||
|
||||
/datum/component/plumbing/automated_iv/Destroy(force)
|
||||
QDEL_NULL(holder)
|
||||
return ..()
|
||||
|
||||
/datum/component/plumbing/automated_iv/can_give(amount, reagent)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
var/obj/machinery/iv_drip/plumbing/drip = parent
|
||||
return drip.mode == 0
|
||||
|
||||
/datum/component/plumbing/automated_iv/send_request(dir)
|
||||
var/obj/machinery/iv_drip/plumbing/drip = parent
|
||||
if(drip.mode == 1)
|
||||
process_request(dir = dir)
|
||||
|
||||
/datum/component/plumbing/automated_iv/transfer_to(datum/component/plumbing/target, amount, reagent, datum/ductnet/net, round_robin = TRUE)
|
||||
reagents.trans_to(holder, reagents.total_volume)
|
||||
reagents = holder
|
||||
. = ..()
|
||||
var/obj/machinery/iv_drip/plumbing/drip = parent
|
||||
reagents = drip.reagents
|
||||
@@ -115,13 +115,13 @@
|
||||
|
||||
var/need_mob_update = FALSE
|
||||
if(brute_per_second)
|
||||
need_mob_update += living_parent.adjustBruteLoss(-1 * heal_mod * brute_per_second * seconds_per_tick, updating_health = FALSE)
|
||||
need_mob_update += living_parent.adjust_brute_loss(-1 * heal_mod * brute_per_second * seconds_per_tick, updating_health = FALSE)
|
||||
if(burn_per_second)
|
||||
need_mob_update += living_parent.adjustFireLoss(-1 * heal_mod * burn_per_second * seconds_per_tick, updating_health = FALSE)
|
||||
need_mob_update += living_parent.adjust_fire_loss(-1 * heal_mod * burn_per_second * seconds_per_tick, updating_health = FALSE)
|
||||
if(tox_per_second)
|
||||
need_mob_update += living_parent.adjustToxLoss(-1 * heal_mod * tox_per_second * seconds_per_tick, updating_health = FALSE)
|
||||
need_mob_update += living_parent.adjust_tox_loss(-1 * heal_mod * tox_per_second * seconds_per_tick, updating_health = FALSE)
|
||||
if(oxy_per_second)
|
||||
need_mob_update += living_parent.adjustOxyLoss(-1 * heal_mod * oxy_per_second * seconds_per_tick, updating_health = FALSE)
|
||||
need_mob_update += living_parent.adjust_oxy_loss(-1 * heal_mod * oxy_per_second * seconds_per_tick, updating_health = FALSE)
|
||||
|
||||
if(heals_wounds && iscarbon(parent))
|
||||
var/mob/living/carbon/carbon_parent = living_parent
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
RegisterSignal(parent, COMSIG_ATOM_ATTACK_GHOST, PROC_REF(on_attack_ghost))
|
||||
if(!(shell_flags & SHELL_FLAG_CIRCUIT_UNMODIFIABLE))
|
||||
RegisterSignal(parent, COMSIG_ATOM_TOOL_ACT(TOOL_MULTITOOL), PROC_REF(on_multitool_act))
|
||||
RegisterSignal(parent, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attack_by))
|
||||
RegisterSignal(parent, COMSIG_ATOM_ITEM_INTERACTION, PROC_REF(on_item_interaction))
|
||||
if(!(shell_flags & SHELL_FLAG_CIRCUIT_UNREMOVABLE))
|
||||
RegisterSignal(parent, COMSIG_ATOM_TOOL_ACT(TOOL_SCREWDRIVER), PROC_REF(on_screwdriver_act))
|
||||
RegisterSignal(parent, COMSIG_OBJ_DECONSTRUCT, PROC_REF(on_object_deconstruct))
|
||||
@@ -91,7 +91,7 @@
|
||||
|
||||
/datum/component/shell/UnregisterFromParent()
|
||||
UnregisterSignal(parent, list(
|
||||
COMSIG_ATOM_ATTACKBY,
|
||||
COMSIG_ATOM_ITEM_INTERACTION,
|
||||
COMSIG_ATOM_TOOL_ACT(TOOL_SCREWDRIVER),
|
||||
COMSIG_ATOM_TOOL_ACT(TOOL_MULTITOOL),
|
||||
COMSIG_OBJ_DECONSTRUCT,
|
||||
@@ -160,55 +160,56 @@
|
||||
attached_circuit?.set_on(source.anchored)
|
||||
|
||||
/**
|
||||
* Called when an item hits the parent. This is the method to add the circuitboard to the component.
|
||||
* Called when interacting with the parent using an item. This is the method to add the circuitboard to the component.
|
||||
*/
|
||||
/datum/component/shell/proc/on_attack_by(atom/source, obj/item/item, mob/living/attacker)
|
||||
/datum/component/shell/proc/on_item_interaction(atom/source, mob/living/user, obj/item/item, list/modifiers)
|
||||
SIGNAL_HANDLER
|
||||
if(!is_authorized(attacker))
|
||||
if(!is_authorized(user))
|
||||
return
|
||||
|
||||
if(istype(item, /obj/item/stock_parts/power_store/cell))
|
||||
source.balloon_alert(attacker, "can't put cell in directly!")
|
||||
source.balloon_alert(user, "can't put cell in directly!")
|
||||
return
|
||||
|
||||
if(istype(item, /obj/item/inducer))
|
||||
var/obj/item/inducer/inducer = item
|
||||
INVOKE_ASYNC(inducer, TYPE_PROC_REF(/obj/item, interact_with_atom), attached_circuit || parent, attacker, list())
|
||||
return COMPONENT_NO_AFTERATTACK
|
||||
INVOKE_ASYNC(inducer, TYPE_PROC_REF(/obj/item, interact_with_atom), attached_circuit || parent, user, list())
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
if(attached_circuit)
|
||||
if(attached_circuit.owner_id && item == attached_circuit.owner_id.resolve())
|
||||
set_locked(!locked)
|
||||
source.balloon_alert(attacker, "[locked ? "locked" : "unlocked"] [source]")
|
||||
return COMPONENT_NO_AFTERATTACK
|
||||
source.balloon_alert(user, "[locked ? "locked" : "unlocked"] [source]")
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
if(!attached_circuit.owner_id && isidcard(item))
|
||||
source.balloon_alert(attacker, "owner id set for [item]")
|
||||
source.balloon_alert(user, "owner id set for [item]")
|
||||
attached_circuit.owner_id = WEAKREF(item)
|
||||
return COMPONENT_NO_AFTERATTACK
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
if(istype(item, /obj/item/circuit_component))
|
||||
attached_circuit.add_component_manually(item, attacker)
|
||||
return COMPONENT_NO_AFTERATTACK
|
||||
if(attached_circuit.add_component_manually(item, user))
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(!istype(item, /obj/item/integrated_circuit))
|
||||
return
|
||||
var/obj/item/integrated_circuit/logic_board = item
|
||||
. = COMPONENT_NO_AFTERATTACK
|
||||
|
||||
if(logic_board.shell) // I'll be surprised if this ever happens
|
||||
return
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(attached_circuit)
|
||||
source.balloon_alert(attacker, "there is already a circuitboard inside!")
|
||||
return
|
||||
source.balloon_alert(user, "there is already a circuitboard inside!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(logic_board.current_size > capacity)
|
||||
source.balloon_alert(attacker, "this is too large to fit into [parent]!")
|
||||
return
|
||||
source.balloon_alert(user, "this is too large to fit into [parent]!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
logic_board.inserter_mind = WEAKREF(attacker.mind)
|
||||
attach_circuit(logic_board, attacker)
|
||||
logic_board.inserter_mind = WEAKREF(user.mind)
|
||||
attach_circuit(logic_board, user)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
/// Sets whether the shell is locked or not
|
||||
/datum/component/shell/proc/set_locked(new_value)
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
var/blood_cost = (cooldown_remaining - new_cooldown ) * COOLDOWN_TO_BLOOD_RATIO
|
||||
|
||||
spell.StartCooldown(new_cooldown)
|
||||
source.blood_volume -= blood_cost
|
||||
source.adjust_blood_volume(-blood_cost)
|
||||
|
||||
var/cost_desc
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
clicked_atom = get_turf_in_angle(tackle_angle, get_turf(user), min_distance)
|
||||
|
||||
user.Knockdown(base_knockdown, ignore_canstun = TRUE)
|
||||
user.adjustStaminaLoss(stamina_cost)
|
||||
user.adjust_stamina_loss(stamina_cost)
|
||||
user.throw_at(clicked_atom, range, speed, user, FALSE)
|
||||
addtimer(CALLBACK(src, PROC_REF(resetTackle)), base_knockdown, TIMER_STOPPABLE)
|
||||
return(COMSIG_MOB_CANCEL_CLICKON)
|
||||
@@ -470,11 +470,11 @@
|
||||
|
||||
if(human_sacker.mob_mood.sanity_level == SANITY_LEVEL_INSANE) //I've gone COMPLETELY INSANE
|
||||
attack_mod += 15
|
||||
human_sacker.adjustStaminaLoss(100) //AHAHAHAHAHAHAHAHA
|
||||
human_sacker.adjust_stamina_loss(100) //AHAHAHAHAHAHAHAHA
|
||||
|
||||
if(HAS_TRAIT(human_sacker, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED)) // tackling with riot specialized armor, like riot armor, is effective but tiring
|
||||
attack_mod += 2
|
||||
human_sacker.adjustStaminaLoss(20)
|
||||
human_sacker.adjust_stamina_loss(20)
|
||||
|
||||
var/randomized_tackle_roll = rand(-3, 3) - defense_mod + attack_mod + skill_mod
|
||||
return randomized_tackle_roll
|
||||
@@ -626,7 +626,7 @@
|
||||
embed.ignore_throwspeed_threshold = initial(embed.ignore_throwspeed_threshold)
|
||||
embed.impact_pain_mult = initial(embed.impact_pain_mult)
|
||||
windscreen_casualty.atom_destruction()
|
||||
user.adjustStaminaLoss(10 * speed)
|
||||
user.adjust_stamina_loss(10 * speed)
|
||||
user.Paralyze(3 SECONDS)
|
||||
user.visible_message(span_danger("[user] smacks into [windscreen_casualty] and shatters it, shredding [user.p_them()]self with glass!"), span_userdanger("You smacks into [windscreen_casualty] and shatter it, shredding yourself with glass!"))
|
||||
|
||||
@@ -635,8 +635,8 @@
|
||||
user.Paralyze(1 SECONDS)
|
||||
user.Knockdown(3 SECONDS)
|
||||
windscreen_casualty.take_damage(30 * speed)
|
||||
user.adjustStaminaLoss(10 * speed, updating_stamina=FALSE)
|
||||
user.adjustBruteLoss(5 * speed)
|
||||
user.adjust_stamina_loss(10 * speed, updating_stamina=FALSE)
|
||||
user.adjust_brute_loss(5 * speed)
|
||||
|
||||
/datum/component/tackler/proc/delayedSmash(obj/structure/window/windscreen_casualty)
|
||||
if(windscreen_casualty)
|
||||
@@ -680,8 +680,8 @@
|
||||
HOW_big_of_a_miss_did_we_just_make = ", making a ginormous mess!" // an extra exclamation point!! for emphasis!!!
|
||||
|
||||
owner.visible_message(span_danger("[owner] trips over [kevved] and slams into it face-first[HOW_big_of_a_miss_did_we_just_make]!"), span_userdanger("You trip over [kevved] and slam into it face-first[HOW_big_of_a_miss_did_we_just_make]!"))
|
||||
owner.adjustStaminaLoss(15 + messes.len * 2, updating_stamina = FALSE)
|
||||
owner.adjustBruteLoss(8 + messes.len, updating_health = FALSE)
|
||||
owner.adjust_stamina_loss(15 + messes.len * 2, updating_stamina = FALSE)
|
||||
owner.adjust_brute_loss(8 + messes.len, updating_health = FALSE)
|
||||
owner.Paralyze(0.4 SECONDS * messes.len) // .4 seconds of paralyze for each thing you knock around
|
||||
owner.Knockdown(2 SECONDS + 0.4 SECONDS * messes.len) // 2 seconds of knockdown after the paralyze
|
||||
owner.updatehealth()
|
||||
|
||||
@@ -276,11 +276,11 @@
|
||||
var/obj/item/item_parent = parent
|
||||
switch(item_parent.damtype)
|
||||
if(STAMINA)
|
||||
user.adjustStaminaLoss(clumsy_damage)
|
||||
user.adjust_stamina_loss(clumsy_damage)
|
||||
if(OXY)
|
||||
user.adjustOxyLoss(clumsy_damage)
|
||||
user.adjust_oxy_loss(clumsy_damage)
|
||||
if(TOX)
|
||||
user.adjustToxLoss(clumsy_damage)
|
||||
user.adjust_tox_loss(clumsy_damage)
|
||||
if(BRUTE)
|
||||
user.take_bodypart_damage(brute=clumsy_damage)
|
||||
if(BURN)
|
||||
|
||||
@@ -11,10 +11,13 @@
|
||||
* assembly code at the bottom of this file
|
||||
*/
|
||||
/datum/component/trapdoor
|
||||
can_transfer = TRUE
|
||||
///assembly tied to this trapdoor
|
||||
var/obj/item/assembly/trapdoor/assembly
|
||||
///path of the turf this should change into when the assembly is pulsed. needed for openspace trapdoors knowing what to turn back into
|
||||
var/trapdoor_turf_path
|
||||
///stack of baseturfs on top of the openspace under this trapdoor
|
||||
var/list/trapdoor_baseturfs = list()
|
||||
/// is this trapdoor "conspicuous" (ie. it gets examine text and overlay added)
|
||||
var/conspicuous
|
||||
/// overlay that makes trapdoors more obvious
|
||||
@@ -32,8 +35,10 @@
|
||||
var/autoclose = TRUE
|
||||
/// Delay before trapdoor shuts close
|
||||
var/autoclose_delay = 5 SECONDS
|
||||
/// Is this trapdoor on a shuttle
|
||||
var/on_shuttle = FALSE
|
||||
|
||||
/datum/component/trapdoor/Initialize(starts_open, trapdoor_turf_path, assembly, conspicuous = TRUE, list/carried_decals = null, autoclose = TRUE)
|
||||
/datum/component/trapdoor/Initialize(starts_open, trapdoor_turf_path, trapdoor_baseturfs, assembly, conspicuous = TRUE, list/carried_decals = null, autoclose = TRUE)
|
||||
if(!isopenturf(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
@@ -46,29 +51,57 @@
|
||||
if(!trapdoor_overlay)
|
||||
trapdoor_overlay = mutable_appearance('icons/turf/overlays.dmi', "border_black", ABOVE_NORMAL_TURF_LAYER)
|
||||
|
||||
var/turf/parent_turf = parent
|
||||
if(SSshuttle.get_containing_shuttle(parent_turf))
|
||||
on_shuttle = TRUE
|
||||
|
||||
if(IS_OPEN(parent))
|
||||
openspace_trapdoor_setup(trapdoor_turf_path, assembly)
|
||||
openspace_trapdoor_setup(trapdoor_turf_path, trapdoor_baseturfs)
|
||||
if(autoclose)
|
||||
addtimer(CALLBACK(src, PROC_REF(try_closing)), autoclose_delay)
|
||||
else
|
||||
tile_trapdoor_setup(trapdoor_turf_path, assembly)
|
||||
tile_trapdoor_setup()
|
||||
|
||||
if(starts_open)
|
||||
try_opening()
|
||||
|
||||
/datum/component/trapdoor/PostTransfer(datum/new_parent)
|
||||
if(!isopenturf(new_parent))
|
||||
if(isatom(new_parent))
|
||||
var/atom/new_parent_atom = new_parent
|
||||
new_parent_atom.visible_message(span_warning("The trapdoor mechanism under [new_parent_atom] is broken!"))
|
||||
return COMPONENT_NOTRANSFER
|
||||
if(SSshuttle.get_containing_shuttle(new_parent))
|
||||
on_shuttle = TRUE
|
||||
else
|
||||
on_shuttle = FALSE
|
||||
|
||||
/datum/component/trapdoor/proc/is_under_shuttle()
|
||||
var/turf/parent_turf = parent
|
||||
var/shuttle_skipover_depth = parent_turf.depth_to_find_baseturf(/turf/baseturf_skipover/shuttle)
|
||||
return shuttle_skipover_depth && parent_turf.depth_to_find_baseturf(/turf/baseturf_skipover/trapdoor) > shuttle_skipover_depth
|
||||
|
||||
///initializing as an opened trapdoor, we need to trust that we were given the data by a closed trapdoor
|
||||
/datum/component/trapdoor/proc/openspace_trapdoor_setup(trapdoor_turf_path)
|
||||
/datum/component/trapdoor/proc/openspace_trapdoor_setup(trapdoor_turf_path, trapdoor_baseturfs)
|
||||
src.trapdoor_turf_path = trapdoor_turf_path
|
||||
src.trapdoor_baseturfs = trapdoor_baseturfs
|
||||
|
||||
///initializing as a closed trapdoor, we need to take data from the tile we're on to give it to the open state to store
|
||||
/datum/component/trapdoor/proc/tile_trapdoor_setup(trapdoor_turf_path)
|
||||
/datum/component/trapdoor/proc/tile_trapdoor_setup()
|
||||
src.trapdoor_turf_path = parent.type
|
||||
insert_trapdoor_skipover()
|
||||
if(stored_decals.len)
|
||||
reapply_all_decals()
|
||||
if(conspicuous)
|
||||
var/turf/parent_turf = parent
|
||||
parent_turf.add_overlay(trapdoor_overlay)
|
||||
|
||||
/datum/component/trapdoor/proc/insert_trapdoor_skipover()
|
||||
var/turf/parent_turf = parent
|
||||
if(parent_turf.depth_to_find_baseturf(/turf/baseturf_skipover/trapdoor))
|
||||
return
|
||||
parent_turf.insert_baseturf((parent_turf.level_to_find_baseturf(/turf/baseturf_skipover/shuttle) || 1) + 1, /turf/baseturf_skipover/trapdoor)
|
||||
|
||||
/datum/component/trapdoor/RegisterWithParent()
|
||||
. = ..()
|
||||
RegisterSignal(parent, COMSIG_TURF_CHANGE, PROC_REF(turf_changed_pre))
|
||||
@@ -84,6 +117,8 @@
|
||||
// SKYRAT EDIT END
|
||||
RegisterSignal(parent, COMSIG_ATOM_TOOL_ACT(TOOL_MULTITOOL), PROC_REF(try_unlink))
|
||||
RegisterSignal(parent, COMSIG_ATOM_ITEM_INTERACTION, PROC_REF(try_link))
|
||||
RegisterSignal(parent, COMSIG_SHUTTLE_TURF_SHOULD_MOVE_SPECIAL, PROC_REF(should_move_special))
|
||||
RegisterSignal(parent, COMSIG_SHUTTLE_TURF_ON_MOVE_SPECIAL, PROC_REF(on_move_special))
|
||||
|
||||
/datum/component/trapdoor/UnregisterFromParent()
|
||||
. = ..()
|
||||
@@ -94,9 +129,13 @@
|
||||
UnregisterSignal(parent, COMSIG_ATOM_EXAMINE)
|
||||
UnregisterSignal(parent, COMSIG_ATOM_TOOL_ACT(TOOL_MULTITOOL))
|
||||
UnregisterSignal(parent, COMSIG_ATOM_ITEM_INTERACTION)
|
||||
UnregisterSignal(parent, COMSIG_SHUTTLE_TURF_SHOULD_MOVE_SPECIAL)
|
||||
UnregisterSignal(parent, COMSIG_SHUTTLE_TURF_ON_MOVE_SPECIAL)
|
||||
|
||||
/datum/component/trapdoor/proc/try_unlink(turf/source, mob/user, obj/item/tool)
|
||||
SIGNAL_HANDLER
|
||||
if(is_under_shuttle())
|
||||
return
|
||||
if(!assembly)
|
||||
return
|
||||
if(IS_OPEN(parent))
|
||||
@@ -108,6 +147,8 @@
|
||||
|
||||
/datum/component/trapdoor/proc/try_link(turf/source, mob/user, obj/item/tool)
|
||||
SIGNAL_HANDLER
|
||||
if(is_under_shuttle())
|
||||
return
|
||||
if(!istype(tool, /obj/item/trapdoor_remote))
|
||||
return
|
||||
var/obj/item/trapdoor_remote/remote = tool
|
||||
@@ -126,6 +167,8 @@
|
||||
/datum/component/trapdoor/proc/async_try_link(turf/source, mob/user, obj/item/trapdoor_remote/remote)
|
||||
if(!do_after(user, 2 SECONDS, target=source))
|
||||
return
|
||||
if(QDELETED(src))
|
||||
return
|
||||
if(IS_OPEN(parent))
|
||||
source.balloon_alert(user, "can't link trapdoor when its open")
|
||||
return
|
||||
@@ -139,6 +182,8 @@
|
||||
/datum/component/trapdoor/proc/async_try_unlink(turf/source, mob/user, obj/item/tool)
|
||||
if(!do_after(user, 5 SECONDS, target=source))
|
||||
return
|
||||
if(QDELETED(src))
|
||||
return
|
||||
if(IS_OPEN(parent))
|
||||
source.balloon_alert(user, "can't unlink trapdoor when its open")
|
||||
return
|
||||
@@ -161,6 +206,8 @@
|
||||
* changing turfs does not bring over decals, so we must perform a little bit of element reapplication.
|
||||
*/
|
||||
/datum/component/trapdoor/proc/reapply_all_decals()
|
||||
if(is_under_shuttle())
|
||||
return
|
||||
for(var/list/element_data as anything in stored_decals)
|
||||
apply_decal(element_data[1], element_data[2], element_data[3], element_data[4])
|
||||
stored_decals = list()
|
||||
@@ -192,12 +239,12 @@
|
||||
try_closing()
|
||||
|
||||
///signal called by turf changing
|
||||
/datum/component/trapdoor/proc/turf_changed_pre(datum/source, path, new_baseturfs, flags, post_change_callbacks)
|
||||
/datum/component/trapdoor/proc/turf_changed_pre(datum/source, path, list/new_baseturfs, flags, post_change_callbacks)
|
||||
SIGNAL_HANDLER
|
||||
var/turf/open/dying_trapdoor = parent
|
||||
if((flags & CHANGETURF_TRAPDOOR_INDUCED) == 0) //not a process of the trapdoor
|
||||
if(!IS_OPEN(parent) && !ispath(path, /turf/closed) && !ispath(path, /turf/open/openspace)) // allow people to place tiles on plating / change tiles without breaking the trapdoor
|
||||
post_change_callbacks += CALLBACK(src, TYPE_PROC_REF(/datum/component/trapdoor, carry_over_trapdoor), path, conspicuous, assembly)
|
||||
if(!IS_OPEN(parent) && !ispath(path, /turf/closed) && islist(new_baseturfs) && new_baseturfs.Find(/turf/baseturf_skipover/trapdoor)) // allow people to place tiles on plating / change tiles without breaking the trapdoor
|
||||
post_change_callbacks += CALLBACK(src, TYPE_PROC_REF(/datum/component/trapdoor, carry_over_trapdoor), path, null, conspicuous, assembly)
|
||||
return
|
||||
// otherwise, break trapdoor
|
||||
dying_trapdoor.visible_message(span_warning("The trapdoor mechanism in [dying_trapdoor] is broken!"))
|
||||
@@ -206,7 +253,7 @@
|
||||
stored_decals.Cut()
|
||||
assembly = null
|
||||
return
|
||||
post_change_callbacks += CALLBACK(src, TYPE_PROC_REF(/datum/component/trapdoor, carry_over_trapdoor), trapdoor_turf_path, conspicuous, assembly)
|
||||
post_change_callbacks += CALLBACK(src, TYPE_PROC_REF(/datum/component/trapdoor, carry_over_trapdoor), trapdoor_turf_path, trapdoor_baseturfs, conspicuous, assembly)
|
||||
|
||||
/**
|
||||
* ## carry_over_trapdoor
|
||||
@@ -214,8 +261,8 @@
|
||||
* applies the trapdoor to the new turf (created by the last trapdoor)
|
||||
* apparently callbacks with arguments on invoke and the callback itself have the callback args go first. interesting!
|
||||
*/
|
||||
/datum/component/trapdoor/proc/carry_over_trapdoor(trapdoor_turf_path, conspicuous, assembly, turf/new_turf)
|
||||
new_turf.AddComponent(/datum/component/trapdoor, FALSE, trapdoor_turf_path, assembly, conspicuous, stored_decals, autoclose)
|
||||
/datum/component/trapdoor/proc/carry_over_trapdoor(trapdoor_turf_path, trapdoor_baseturfs, conspicuous, assembly, turf/new_turf)
|
||||
new_turf.AddComponent(/datum/component/trapdoor, FALSE, trapdoor_turf_path, trapdoor_baseturfs, assembly, conspicuous, stored_decals, autoclose)
|
||||
|
||||
/**
|
||||
* ## on_examine
|
||||
@@ -224,6 +271,8 @@
|
||||
*/
|
||||
/datum/component/trapdoor/proc/on_examine(datum/source, mob/user, list/examine_text)
|
||||
SIGNAL_HANDLER
|
||||
if(is_under_shuttle())
|
||||
return
|
||||
if(conspicuous)
|
||||
examine_text += "There seems to be a tiny gap around this tile with some wires that you might be able to pulse with a <b>multitool</b>."
|
||||
|
||||
@@ -235,12 +284,19 @@
|
||||
*/
|
||||
/datum/component/trapdoor/proc/try_opening()
|
||||
var/turf/open/trapdoor_turf = parent
|
||||
var/opening_depth = trapdoor_turf.depth_to_find_baseturf(/turf/baseturf_skipover/trapdoor)
|
||||
if(!opening_depth)
|
||||
stack_trace("Could not find baseturf skipover for trapdoor")
|
||||
return
|
||||
if(is_under_shuttle())
|
||||
return
|
||||
///we want to save this turf's decals as they were right before deletion, so this is the point where we begin listening
|
||||
if(assembly)
|
||||
RegisterSignal(parent, COMSIG_TURF_DECAL_DETACHED, PROC_REF(decal_detached))
|
||||
playsound(trapdoor_turf, 'sound/machines/trapdoor/trapdoor_open.ogg', 50)
|
||||
trapdoor_baseturfs = trapdoor_turf.get_baseturfs_to_depth(opening_depth)
|
||||
trapdoor_turf.visible_message(span_warning("[trapdoor_turf] swings open!"))
|
||||
trapdoor_turf.ChangeTurf(/turf/open/openspace, flags = CHANGETURF_INHERIT_AIR | CHANGETURF_TRAPDOOR_INDUCED)
|
||||
trapdoor_turf.ScrapeAway(opening_depth, flags = CHANGETURF_INHERIT_AIR | CHANGETURF_TRAPDOOR_INDUCED)
|
||||
|
||||
/**
|
||||
* ## try_closing
|
||||
@@ -256,7 +312,23 @@
|
||||
return
|
||||
playsound(trapdoor_turf, 'sound/machines/trapdoor/trapdoor_shut.ogg', 50)
|
||||
trapdoor_turf.visible_message(span_warning("The trapdoor mechanism in [trapdoor_turf] swings shut!"))
|
||||
trapdoor_turf.ChangeTurf(trapdoor_turf_path, flags = CHANGETURF_INHERIT_AIR | CHANGETURF_TRAPDOOR_INDUCED)
|
||||
var/list/new_baseturfs = list()
|
||||
new_baseturfs += trapdoor_turf.baseturfs
|
||||
new_baseturfs += trapdoor_turf.type
|
||||
if(on_shuttle)
|
||||
new_baseturfs += /turf/baseturf_skipover/shuttle
|
||||
new_baseturfs += trapdoor_baseturfs
|
||||
trapdoor_baseturfs = null
|
||||
trapdoor_turf.ChangeTurf(trapdoor_turf_path, new_baseturfs, flags = CHANGETURF_INHERIT_AIR | CHANGETURF_TRAPDOOR_INDUCED)
|
||||
|
||||
/datum/component/trapdoor/proc/should_move_special(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
var/turf/source_turf = source
|
||||
return IS_OPEN(source_turf) && !is_under_shuttle()
|
||||
|
||||
/datum/component/trapdoor/proc/on_move_special(datum/source, turf/new_turf)
|
||||
SIGNAL_HANDLER
|
||||
new_turf.TakeComponent(src)
|
||||
|
||||
#undef IS_OPEN
|
||||
|
||||
|
||||
@@ -1,50 +1,56 @@
|
||||
// This element should be applied to wall-mounted machines/structures, so that if the wall it's "hanging" from is broken or deconstructed, the wall-hung structure will deconstruct.
|
||||
/datum/component/wall_mounted
|
||||
dupe_mode = COMPONENT_DUPE_ALLOWED
|
||||
/// The wall our object is currently linked to.
|
||||
var/turf/closed/wall/hanging_wall_turf
|
||||
// This element should be applied to wall-mounted machines/structures, so that if the support structure it's "hanging" from is broken or deconstructed, the wall-hung structure will deconstruct.
|
||||
/datum/component/atom_mounted
|
||||
/// The closed turf our object is currently linked to.
|
||||
var/atom/hanging_support_atom
|
||||
|
||||
/datum/component/wall_mounted/Initialize(target_wall, on_drop_callback)
|
||||
/datum/component/atom_mounted/Initialize(target_structure, on_drop_callback)
|
||||
. = ..()
|
||||
if(!isobj(parent) || !iswallturf(target_wall))
|
||||
if(!isobj(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
hanging_wall_turf = target_wall
|
||||
hanging_support_atom = target_structure
|
||||
|
||||
/datum/component/wall_mounted/RegisterWithParent()
|
||||
/datum/component/atom_mounted/RegisterWithParent()
|
||||
ADD_TRAIT(parent, TRAIT_WALLMOUNTED, REF(src))
|
||||
RegisterSignal(hanging_wall_turf, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
|
||||
RegisterSignal(hanging_wall_turf, COMSIG_TURF_CHANGE, PROC_REF(on_turf_changing))
|
||||
RegisterSignal(hanging_support_atom, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
|
||||
if(isclosedturf(hanging_support_atom))
|
||||
RegisterSignal(hanging_support_atom, COMSIG_TURF_CHANGE, PROC_REF(on_turf_changing))
|
||||
else
|
||||
RegisterSignal(hanging_support_atom, COMSIG_QDELETING, PROC_REF(on_structure_delete))
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(on_move))
|
||||
|
||||
/datum/component/wall_mounted/UnregisterFromParent()
|
||||
/datum/component/atom_mounted/UnregisterFromParent()
|
||||
REMOVE_TRAIT(parent, TRAIT_WALLMOUNTED, REF(src))
|
||||
UnregisterSignal(hanging_wall_turf, list(COMSIG_ATOM_EXAMINE, COMSIG_TURF_CHANGE))
|
||||
UnregisterSignal(hanging_support_atom, list(COMSIG_ATOM_EXAMINE))
|
||||
if(isclosedturf(hanging_support_atom))
|
||||
UnregisterSignal(hanging_support_atom, COMSIG_TURF_CHANGE)
|
||||
else
|
||||
UnregisterSignal(hanging_support_atom, COMSIG_QDELETING)
|
||||
UnregisterSignal(parent, COMSIG_MOVABLE_MOVED)
|
||||
hanging_wall_turf = null
|
||||
hanging_support_atom = null
|
||||
|
||||
/**
|
||||
* When the wall is examined, explains that it's supporting the linked object.
|
||||
*/
|
||||
/datum/component/wall_mounted/proc/on_examine(datum/source, mob/user, list/examine_list)
|
||||
/datum/component/atom_mounted/proc/on_examine(datum/source, mob/user, list/examine_list)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if (parent in view(user.client?.view || world.view, user))
|
||||
examine_list += span_notice("\The [hanging_wall_turf] is currently supporting [span_bold("[parent]")]. Deconstruction or excessive damage would cause it to [span_bold("fall to the ground")].")
|
||||
examine_list += span_notice("\The [hanging_support_atom] is currently supporting [span_bold("[parent]")]. Deconstruction or excessive damage would cause it to [span_bold("fall to the ground")].")
|
||||
|
||||
/**
|
||||
* When the type of turf changes, if it is changing into a floor we should drop our contents
|
||||
*/
|
||||
/datum/component/wall_mounted/proc/on_turf_changing(datum/source, path, new_baseturfs, flags, post_change_callbacks)
|
||||
/// When the type of turf changes, if it is changing into a floor we should drop our contents
|
||||
/datum/component/atom_mounted/proc/on_turf_changing(datum/source, path, new_baseturfs, flags, post_change_callbacks)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(ispath(path, /turf/open))
|
||||
drop_wallmount()
|
||||
|
||||
/datum/component/atom_mounted/proc/on_structure_delete(datum/source, force)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
/**
|
||||
* If we get dragged from our wall (by a singulo for instance) we should deconstruct
|
||||
*/
|
||||
/datum/component/wall_mounted/proc/on_move(datum/source, atom/old_loc, dir, forced, list/old_locs)
|
||||
drop_wallmount()
|
||||
|
||||
/// If we get dragged from our wall (by a singulo for instance) we should deconstruct
|
||||
/datum/component/atom_mounted/proc/on_move(datum/source, atom/old_loc, dir, forced, list/old_locs)
|
||||
SIGNAL_HANDLER
|
||||
// If we're having our lighting messed with we're likely to get dragged about
|
||||
// That shouldn't lead to a decon
|
||||
@@ -55,23 +61,62 @@
|
||||
/**
|
||||
* Handles the dropping of the linked object. This is done via deconstruction, as that should be the most sane way to handle it for most objects.
|
||||
* Except for intercoms, which are handled by creating a new wallframe intercom, as they're apparently items.
|
||||
*/
|
||||
/datum/component/wall_mounted/proc/drop_wallmount()
|
||||
*/
|
||||
/datum/component/atom_mounted/proc/drop_wallmount()
|
||||
PRIVATE_PROC(TRUE)
|
||||
|
||||
var/obj/hanging_parent = parent
|
||||
hanging_parent.visible_message(message = span_warning("\The [hanging_parent] falls apart!"), vision_distance = 5)
|
||||
hanging_parent.deconstruct(FALSE)
|
||||
|
||||
/**
|
||||
* Finds an support atom to hang this object on. If you need to mount the object on Late Initialize
|
||||
* then pass TRUE inside Initialize() but not in LateInitialize().
|
||||
* The flag is only applied if no support atom could be found during Initialize() as a last resort
|
||||
*
|
||||
* Arguments
|
||||
* * mark_for_late_init - if TRUE will apply the MOUNT_ON_LATE_INITIALIZE which gets cleared on every call
|
||||
* * late_init - should only be passed as TRUE from inside LateInitialize()
|
||||
*/
|
||||
/obj/proc/find_and_hang_on_atom(mark_for_late_init = FALSE, late_init = FALSE)
|
||||
if(obj_flags & MOUNT_ON_LATE_INITIALIZE)
|
||||
obj_flags &= ~MOUNT_ON_LATE_INITIALIZE
|
||||
else if(late_init)
|
||||
return TRUE
|
||||
|
||||
///Checks object direction and then verifies if there's a wall in that direction. Finally, applies a wall_mounted component to the object.
|
||||
/obj/proc/find_and_hang_on_wall()
|
||||
if(istype(get_area(src), /area/shuttle))
|
||||
return FALSE //For now, we're going to keep the component off of shuttles to avoid the turf changing issue. We'll hit that later really;
|
||||
var/turf/attachable_wall = loc //first attempt to locate a wall in our current turf
|
||||
if(!iswallturf(attachable_wall))
|
||||
attachable_wall = get_step(src, dir) //if no then attempt to locate it in our direction
|
||||
if(!iswallturf(attachable_wall))
|
||||
return FALSE //Nothing to latch onto, or not the right thing.
|
||||
AddComponent(/datum/component/wall_mounted, attachable_wall)
|
||||
return TRUE
|
||||
var/area/location = get_area(src)
|
||||
if(!isarea(location) || istype(location, /area/shuttle))
|
||||
return FALSE
|
||||
|
||||
var/msg
|
||||
if(PERFORM_ALL_TESTS(focus_only/atom_mounted) && !mark_for_late_init)
|
||||
msg = "[type] Could not find attachable object at [location.type] "
|
||||
|
||||
var/list/turf/attachable_turfs = list()
|
||||
attachable_turfs += get_step(src, dir)
|
||||
attachable_turfs += get_turf(src)
|
||||
for(var/turf/target as anything in attachable_turfs)
|
||||
var/atom/attachable_atom
|
||||
if(isclosedturf(target))
|
||||
attachable_atom = target //your usual wallmount
|
||||
else
|
||||
var/static/list/attachables = list(
|
||||
/obj/structure/table,
|
||||
/obj/structure/window,
|
||||
/obj/structure/fence,
|
||||
) //list of structures to mount on
|
||||
for(var/obj/attachable in target)
|
||||
if(is_type_in_list(attachable, attachables))
|
||||
attachable_atom = attachable
|
||||
break
|
||||
if(attachable_atom)
|
||||
AddComponent(/datum/component/atom_mounted, attachable_atom)
|
||||
return TRUE
|
||||
if(msg)
|
||||
msg += "([target.x],[target.y],[target.z]) "
|
||||
if(msg)
|
||||
stack_trace(msg)
|
||||
|
||||
if(mark_for_late_init)
|
||||
obj_flags |= MOUNT_ON_LATE_INITIALIZE
|
||||
return FALSE
|
||||
|
||||
Reference in New Issue
Block a user