diff --git a/.vscode/settings.json b/.vscode/settings.json
index 6ed819b22e9..0ca4d58b4c6 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,5 +1,5 @@
{
"eslint.workingDirectories": [
- "./tgui-next"
+ "./tgui"
]
}
diff --git a/_maps/map_files/Donutstation/Donutstation_LVL2.dmm b/_maps/map_files/Donutstation/Donutstation_LVL2.dmm
index 69295e59f05..b0ccc744f11 100644
--- a/_maps/map_files/Donutstation/Donutstation_LVL2.dmm
+++ b/_maps/map_files/Donutstation/Donutstation_LVL2.dmm
@@ -371,7 +371,7 @@
/obj/effect/turf_decal/tile/brown{
dir = 1
},
-/obj/item/twohanded/required/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-22"
},
/turf/open/floor/plasteel,
@@ -770,7 +770,7 @@
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
-/obj/item/twohanded/required/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-21";
pixel_x = -3;
pixel_y = 3
@@ -3861,7 +3861,7 @@
/turf/open/floor/carpet/black,
/area/library/printer)
"in" = (
-/obj/item/twohanded/required/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-22"
},
/turf/open/floor/carpet/black,
@@ -4017,7 +4017,7 @@
/turf/open/floor/wood,
/area/library/private)
"iE" = (
-/obj/item/twohanded/required/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-22"
},
/obj/structure/cable,
@@ -4302,7 +4302,7 @@
/turf/open/floor/wood,
/area/library/upper)
"jg" = (
-/obj/item/twohanded/required/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-22"
},
/obj/structure/railing{
@@ -7498,7 +7498,7 @@
/obj/effect/turf_decal/tile/neutral{
dir = 1
},
-/obj/item/twohanded/required/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-21";
pixel_x = -3;
pixel_y = 3
@@ -7972,7 +7972,7 @@
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
-/obj/item/twohanded/required/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-21";
pixel_x = -3;
pixel_y = 3
@@ -8936,7 +8936,7 @@
/turf/open/floor/circuit,
/area/ai_monitored/nuke_storage)
"sX" = (
-/obj/item/twohanded/required/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-21";
pixel_x = -3;
pixel_y = 3
@@ -9168,7 +9168,7 @@
c_tag = "Hallway - Upper Central Northeast 2";
dir = 8
},
-/obj/item/twohanded/required/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-21";
pixel_x = -3;
pixel_y = 3
@@ -11043,7 +11043,7 @@
/turf/open/floor/plating,
/area/crew_quarters/dorms/barracks/male)
"wS" = (
-/obj/item/twohanded/required/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-22"
},
/obj/structure/cable,
@@ -12955,7 +12955,7 @@
/obj/structure/sign/poster/official/random{
pixel_y = -32
},
-/obj/item/twohanded/required/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-10"
},
/turf/open/floor/plasteel,
@@ -14254,7 +14254,7 @@
c_tag = "Hallway - Upper Central West 3";
dir = 4
},
-/obj/item/twohanded/required/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-21";
pixel_x = -3;
pixel_y = 3
@@ -14290,7 +14290,7 @@
/area/engine/atmos/upper)
"Dj" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer3,
-/obj/item/twohanded/required/kirbyplants/photosynthetic,
+/obj/item/kirbyplants/photosynthetic,
/turf/open/floor/plasteel,
/area/ai_monitored/turret_protected/ai_upload_foyer)
"Dk" = (
@@ -16039,7 +16039,7 @@
/obj/effect/turf_decal/tile/neutral{
dir = 1
},
-/obj/item/twohanded/required/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-21";
pixel_x = -3;
pixel_y = 3
@@ -20803,7 +20803,7 @@
/obj/effect/turf_decal/tile/neutral{
dir = 4
},
-/obj/item/twohanded/required/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-21";
pixel_x = -3;
pixel_y = 3
@@ -20814,7 +20814,7 @@
/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer3{
dir = 1
},
-/obj/item/twohanded/required/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-10"
},
/turf/open/floor/plasteel,
@@ -20827,7 +20827,7 @@
dir = 1
},
/obj/effect/turf_decal/tile/neutral,
-/obj/item/twohanded/required/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-21";
pixel_x = -3;
pixel_y = 3
@@ -20842,7 +20842,7 @@
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
-/obj/item/twohanded/required/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-21";
pixel_x = -3;
pixel_y = 3
@@ -20857,7 +20857,7 @@
/obj/effect/turf_decal/tile/neutral{
dir = 1
},
-/obj/item/twohanded/required/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-21";
pixel_x = -3;
pixel_y = 3
@@ -20870,7 +20870,7 @@
dir = 8
},
/obj/effect/turf_decal/tile/neutral,
-/obj/item/twohanded/required/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-21";
pixel_x = -3;
pixel_y = 3
@@ -20885,7 +20885,7 @@
/obj/effect/turf_decal/tile/neutral{
dir = 1
},
-/obj/item/twohanded/required/kirbyplants{
+/obj/item/kirbyplants{
icon_state = "plant-21"
},
/turf/open/floor/plasteel,
diff --git a/code/__DEFINES/MC.dm b/code/__DEFINES/MC.dm
index 161bb21d038..128751bcdf7 100644
--- a/code/__DEFINES/MC.dm
+++ b/code/__DEFINES/MC.dm
@@ -32,17 +32,16 @@
/// (Requires a MC restart to change)
#define SS_NO_FIRE 2
-/** subsystem only runs on spare cpu (after all non-background subsystems have ran that tick) */
-/// SS_BACKGROUND has its own priority bracket
+/** Subsystem only runs on spare cpu (after all non-background subsystems have ran that tick) */
+/// SS_BACKGROUND has its own priority bracket, this overrides SS_TICKER's priority bump
#define SS_BACKGROUND 4
/// subsystem does not tick check, and should not run unless there is enough time (or its running behind (unless background))
#define SS_NO_TICK_CHECK 8
/** Treat wait as a tick count, not DS, run every wait ticks. */
-/// (also forces it to run first in the tick, above even SS_NO_TICK_CHECK subsystems)
+/// (also forces it to run first in the tick (unless SS_BACKGROUND))
/// (implies all runlevels because of how it works)
-/// (overrides SS_BACKGROUND)
/// This is designed for basically anything that works as a mini-mc (like SStimer)
#define SS_TICKER 16
diff --git a/code/controllers/master.dm b/code/controllers/master.dm
index c4c9b07520a..9d89a0d3f0a 100644
--- a/code/controllers/master.dm
+++ b/code/controllers/master.dm
@@ -455,14 +455,15 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
// in those cases, so we just let them run)
if (queue_node_flags & SS_NO_TICK_CHECK)
if (queue_node.tick_usage > TICK_LIMIT_RUNNING - TICK_USAGE && ran_non_ticker)
- queue_node.queued_priority += queue_priority_count * 0.1
- queue_priority_count -= queue_node_priority
- queue_priority_count += queue_node.queued_priority
- current_tick_budget -= queue_node_priority
- queue_node = queue_node.queue_next
+ if (!(queue_node_flags & SS_BACKGROUND))
+ queue_node.queued_priority += queue_priority_count * 0.1
+ queue_priority_count -= queue_node_priority
+ queue_priority_count += queue_node.queued_priority
+ current_tick_budget -= queue_node_priority
+ queue_node = queue_node.queue_next
continue
- if ((queue_node_flags & SS_BACKGROUND) && !bg_calc)
+ if (!bg_calc && (queue_node_flags & SS_BACKGROUND))
current_tick_budget = queue_priority_count_bg
bg_calc = TRUE
@@ -515,7 +516,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
queue_node.paused_ticks = 0
queue_node.paused_tick_usage = 0
- if (queue_node_flags & SS_BACKGROUND) //update our running total
+ if (bg_calc) //update our running total
queue_priority_count_bg -= queue_node_priority
else
queue_priority_count -= queue_node_priority
diff --git a/code/controllers/subsystem.dm b/code/controllers/subsystem.dm
index 05330850fcd..7e9e23bd45f 100644
--- a/code/controllers/subsystem.dm
+++ b/code/controllers/subsystem.dm
@@ -137,7 +137,7 @@
queue_node_flags = queue_node.flags
if (queue_node_flags & SS_TICKER)
- if (!(SS_flags & SS_TICKER))
+ if ((SS_flags & (SS_TICKER|SS_BACKGROUND)) != SS_TICKER)
continue
if (queue_node_priority < SS_priority)
break
diff --git a/code/datums/components/label.dm b/code/datums/components/label.dm
index 5c94adecd19..c6d0c595ebb 100644
--- a/code/datums/components/label.dm
+++ b/code/datums/components/label.dm
@@ -19,18 +19,27 @@
return COMPONENT_INCOMPATIBLE
label_name = _label_name
-
- // Add the label to the name of the object in the format of: "Item name (label)"
- var/atom/owner = parent
- owner.name += " ([label_name])"
+ apply_label()
/datum/component/label/RegisterWithParent()
- RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/RemoveLabel)
+ RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/OnAttackby)
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/Examine)
/datum/component/label/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_PARENT_ATTACKBY, COMSIG_PARENT_EXAMINE))
+/**
+ This proc will fire after the parent is hit by a hand labeler which is trying to apply another label.
+ Since the parent already has a label, it will remove the old one from the parent's name, and apply the new one.
+*/
+/datum/component/label/InheritComponent(datum/component/label/new_comp , i_am_original, _label_name)
+ remove_label()
+ if(new_comp)
+ label_name = new_comp.label_name
+ else
+ label_name = _label_name
+ apply_label()
+
/**
This proc will trigger when any object is used to attack the parent.
@@ -42,18 +51,16 @@
* attacker: The object that is hitting the parent.
* user: The mob who is wielding the attacking object.
*/
-/datum/component/label/proc/RemoveLabel(datum/source, obj/item/attacker, mob/user)
+/datum/component/label/proc/OnAttackby(datum/source, obj/item/attacker, mob/user)
// If the attacking object is not a hand labeler or its mode is 1 (has a label ready to apply), return.
// The hand labeler should be off (mode is 0), in order to remove a label.
var/obj/item/hand_labeler/labeler = attacker
if(!istype(labeler) || labeler.mode)
return
- var/atom/owner = source // Source will be the owner / parent of this component.
- owner.name = replacetext(owner.name, "([label_name])", "") // Remove the label text from the parent's name, wherever it may be.
- owner.name = trim(owner.name) // Shave off any white space from the beginning or end of the parent's name.
- playsound(owner, 'sound/items/poster_ripped.ogg', 20, TRUE)
- to_chat(user, "You remove the label from [owner].")
+ remove_label()
+ playsound(parent, 'sound/items/poster_ripped.ogg', 20, TRUE)
+ to_chat(user, "You remove the label from [parent].")
qdel(src) // Remove the component from the object.
/**
@@ -67,3 +74,14 @@
*/
/datum/component/label/proc/Examine(datum/source, mob/user, list/examine_list)
examine_list += "It has a label with some words written on it. Use a hand labeler to remove it."
+
+/// Applies a label to the name of the parent in the format of: "parent_name (label)"
+/datum/component/label/proc/apply_label()
+ var/atom/owner = parent
+ owner.name += " ([label_name])"
+
+/// Removes the label from the parent's name
+/datum/component/label/proc/remove_label()
+ var/atom/owner = parent
+ owner.name = replacetext(owner.name, "([label_name])", "") // Remove the label text from the parent's name, wherever it's located.
+ owner.name = trim(owner.name) // Shave off any white space from the beginning or end of the parent's name.
diff --git a/code/datums/diseases/advance/symptoms/heal.dm b/code/datums/diseases/advance/symptoms/heal.dm
index de5a5297348..c49a953a9d8 100644
--- a/code/datums/diseases/advance/symptoms/heal.dm
+++ b/code/datums/diseases/advance/symptoms/heal.dm
@@ -259,6 +259,8 @@
/datum/symptom/heal/coma/End(datum/disease/advance/A)
if(!..())
return
+ if(active_coma)
+ uncoma()
REMOVE_TRAIT(A.affected_mob, TRAIT_NOCRITDAMAGE, DISEASE_TRAIT)
/datum/symptom/heal/coma/CanHeal(datum/disease/advance/A)
diff --git a/code/datums/materials/basemats.dm b/code/datums/materials/basemats.dm
index ccbcb6de65f..e06f7a3da66 100644
--- a/code/datums/materials/basemats.dm
+++ b/code/datums/materials/basemats.dm
@@ -176,6 +176,7 @@ Unless you know what you're doing, only use the first three numbers. They're in
color = "#caccd9"
strength_modifier = 0.85
sheet_type = /obj/item/stack/sheet/plastic
+ categories = list(MAT_CATEGORY_RIGID = TRUE)
value_per_unit = 0.0125
beauty_modifier = -0.01
armor_modifiers = list("melee" = 1.5, "bullet" = 1.1, "laser" = 0.3, "energy" = 0.5, "bomb" = 1, "bio" = 1, "rad" = 1, "fire" = 1.1, "acid" = 1)
diff --git a/code/game/gamemodes/clown_ops/clown_ops.dm b/code/game/gamemodes/clown_ops/clown_ops.dm
index 3180e896ab6..255f13520cf 100644
--- a/code/game/gamemodes/clown_ops/clown_ops.dm
+++ b/code/game/gamemodes/clown_ops/clown_ops.dm
@@ -31,7 +31,7 @@
uniform = /obj/item/clothing/under/syndicate
shoes = /obj/item/clothing/shoes/clown_shoes/combat
mask = /obj/item/clothing/mask/gas/clown_hat
- gloves = /obj/item/clothing/gloves/tackler/combat/insulated
+ gloves = /obj/item/clothing/gloves/combat
back = /obj/item/storage/backpack/clown
ears = /obj/item/radio/headset/syndicate/alt
l_pocket = /obj/item/pinpointer/nuke/syndicate
diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm
index a1f5e58c5fa..cdda3590327 100644
--- a/code/game/gamemodes/nuclear/nuclear.dm
+++ b/code/game/gamemodes/nuclear/nuclear.dm
@@ -115,7 +115,7 @@
uniform = /obj/item/clothing/under/syndicate
shoes = /obj/item/clothing/shoes/combat
- gloves = /obj/item/clothing/gloves/tackler/combat/insulated
+ gloves = /obj/item/clothing/gloves/combat
back = /obj/item/storage/backpack/fireproof
ears = /obj/item/radio/headset/syndicate/alt
l_pocket = /obj/item/pinpointer/nuke/syndicate
diff --git a/code/game/objects/items/devices/taperecorder.dm b/code/game/objects/items/devices/taperecorder.dm
index e38a4e05e5c..69541305d1f 100644
--- a/code/game/objects/items/devices/taperecorder.dm
+++ b/code/game/objects/items/devices/taperecorder.dm
@@ -56,13 +56,9 @@
//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/item/taperecorder/attack_hand(mob/user)
- if(loc == user)
- if(mytape)
- if(!user.is_holding(src))
- return ..()
- eject(user)
- else
+ if(loc != user || !mytape || !user.is_holding(src))
return ..()
+ eject(user)
/obj/item/taperecorder/proc/can_use(mob/user)
if(user && ismob(user))
diff --git a/code/game/objects/items/dualsaber.dm b/code/game/objects/items/dualsaber.dm
index 574f62da7e1..e8c99f98f40 100644
--- a/code/game/objects/items/dualsaber.dm
+++ b/code/game/objects/items/dualsaber.dm
@@ -23,6 +23,7 @@
max_integrity = 200
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 70)
resistance_flags = FIRE_PROOF
+ var/two_hand_force = 34
var/hacked = FALSE
var/brightness_on = 6 //TWICE AS BRIGHT AS A REGULAR ESWORD
var/list/possible_colors = list("red", "blue", "green", "purple")
@@ -30,8 +31,7 @@
/obj/item/dualsaber/ComponentInitialize()
. = ..()
- AddComponent(/datum/component/two_handed, force_unwielded=3, force_wielded=34, \
- wieldsound='sound/weapons/saberon.ogg', unwieldsound='sound/weapons/saberoff.ogg')
+ AddComponent(/datum/component/two_handed, force_unwielded=force, force_wielded=two_hand_force, wieldsound='sound/weapons/saberon.ogg', unwieldsound='sound/weapons/saberoff.ogg')
/// Triggered on wield of two handed item
/// Specific hulk checks due to reflection chance for balance issues and switches hitsounds.
diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm
index a427ee54670..d84fdf26ac3 100644
--- a/code/game/objects/items/stacks/medical.dm
+++ b/code/game/objects/items/stacks/medical.dm
@@ -241,7 +241,6 @@
is_open = FALSE
update_icon()
-
/obj/item/stack/medical/mesh/update_icon_state()
if(!is_open)
icon_state = "regen_mesh_closed"
@@ -285,6 +284,57 @@
return
. = ..()
+/obj/item/stack/medical/mesh/advanced
+ name = "advanced regenerative mesh"
+ desc = "An advanced mesh made with aloe extracts and sterilizing chemicals, used to treat burns."
+
+ gender = PLURAL
+ singular_name = "advanced regenerative mesh"
+ icon_state = "aloe_mesh"
+ heal_burn = 15
+ grind_results = list(/datum/reagent/consumable/aloejuice = 1)
+
+/obj/item/stack/medical/mesh/advanced/update_icon_state()
+ if(!is_open)
+ icon_state = "aloe_mesh_closed"
+ else
+ return ..()
+
+/obj/item/stack/medical/aloe
+ name = "aloe cream"
+ desc = "A healing paste you can apply on wounds."
+
+ icon_state = "aloe_paste"
+ self_delay = 20
+ other_delay = 10
+ novariants = TRUE
+ amount = 20
+ max_amount = 20
+ var/heal = 3
+ grind_results = list(/datum/reagent/consumable/aloejuice = 1)
+
+/obj/item/stack/medical/aloe/heal(mob/living/M, mob/user)
+ . = ..()
+ if(M.stat == DEAD)
+ to_chat(user, "[M] is dead! You can not help [M.p_them()].")
+ return FALSE
+ if(iscarbon(M))
+ return heal_carbon(M, user, heal, heal)
+ if(isanimal(M))
+ var/mob/living/simple_animal/critter = M
+ if (!(critter.healable))
+ to_chat(user, "You cannot use \the [src] on [M]!")
+ return FALSE
+ else if (critter.health == critter.maxHealth)
+ to_chat(user, "[M] is at full health.")
+ return FALSE
+ user.visible_message("[user] applies \the [src] on [M].", "You apply \the [src] on [M].")
+ M.heal_bodypart_damage(heal, heal)
+ return TRUE
+
+ to_chat(user, "You can't heal [M] with the \the [src]!")
+
+
/*
The idea is for these medical devices to work like a hybrid of the old brute packs and tend wounds,
they heal a little at a time, have reduced healing density and does not allow for rapid healing while in combat.
diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm
index 09030f10ea9..0fdc3692db8 100644
--- a/code/game/objects/items/toys.dm
+++ b/code/game/objects/items/toys.dm
@@ -394,12 +394,9 @@
throwforce = 0
throw_speed = 3
throw_range = 5
+ two_hand_force = 0
attack_verb = list("attacked", "struck", "hit")
-/obj/item/dualsaber/toy/ComponentInitialize()
- . = ..()
- AddComponent(/datum/component/two_handed, wieldsound='sound/weapons/saberon.ogg', unwieldsound='sound/weapons/saberoff.ogg')
-
/obj/item/dualsaber/toy/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
return 0
diff --git a/code/game/objects/structures/ladders.dm b/code/game/objects/structures/ladders.dm
index 9e572c4c57d..0984d94f2c5 100644
--- a/code/game/objects/structures/ladders.dm
+++ b/code/game/objects/structures/ladders.dm
@@ -88,8 +88,13 @@
if (!is_ghost && !in_range(src, user))
return
+ var/list/tool_list = list(
+ "Up" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "arrow", dir = NORTH),
+ "Down" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "arrow", dir = SOUTH)
+ )
+
if (up && down)
- var/result = alert("Go up or down [src]?", "Ladder", "Up", "Down", "Cancel")
+ var/result = show_radial_menu(user, src, tool_list, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE, tooltips = TRUE)
if (!is_ghost && !in_range(src, user))
return // nice try
switch(result)
@@ -109,6 +114,11 @@
if(!is_ghost)
add_fingerprint(user)
+/obj/structure/ladder/proc/check_menu(mob/user)
+ if(user.incapacitated() || !user.Adjacent(src))
+ return FALSE
+ return TRUE
+
/obj/structure/ladder/attack_hand(mob/user)
. = ..()
if(.)
diff --git a/code/game/turfs/open/openspace.dm b/code/game/turfs/open/openspace.dm
index 2e1dca69271..6d2a5c37211 100644
--- a/code/game/turfs/open/openspace.dm
+++ b/code/game/turfs/open/openspace.dm
@@ -21,6 +21,7 @@ GLOBAL_DATUM_INIT(openspace_backdrop_one_for_all, /atom/movable/openspace_backdr
var/can_cover_up = TRUE
var/can_build_on = TRUE
+ intact = 0
/turf/open/openspace/airless
initial_gas_mix = AIRLESS_ATMOS
@@ -44,6 +45,11 @@ GLOBAL_DATUM_INIT(openspace_backdrop_one_for_all, /atom/movable/openspace_backdr
vis_contents.len = 0
return ..()
+/turf/open/openspace/can_have_cabling()
+ if(locate(/obj/structure/lattice/catwalk, src))
+ return TRUE
+ return FALSE
+
/turf/open/openspace/update_multiz(prune_on_fail = FALSE, init = FALSE)
. = ..()
var/turf/T = below()
diff --git a/code/modules/clothing/gloves/tacklers.dm b/code/modules/clothing/gloves/tacklers.dm
index b86b2697173..59f198d5ef3 100644
--- a/code/modules/clothing/gloves/tacklers.dm
+++ b/code/modules/clothing/gloves/tacklers.dm
@@ -70,7 +70,7 @@
resistance_flags = NONE
/obj/item/clothing/gloves/tackler/combat/insulated
- name = "guerilla gloves"
+ name = "guerrilla gloves"
desc = "Superior quality combative gloves, good for performing tackle takedowns as well as absorbing electrical shocks."
siemens_coefficient = 0
permeability_coefficient = 0.05
diff --git a/code/modules/clothing/head/misc.dm b/code/modules/clothing/head/misc.dm
index 54a1b5c0588..a36236cdbf3 100644
--- a/code/modules/clothing/head/misc.dm
+++ b/code/modules/clothing/head/misc.dm
@@ -152,7 +152,7 @@
to_chat(user, "You can no longer speak like a pirate.")
/obj/item/clothing/head/pirate/captain
- name = "pirate captain"
+ name = "pirate captain hat"
icon_state = "hgpiratecap"
item_state = "hgpiratecap"
diff --git a/code/modules/goonchat/browserassets/js/browserOutput.js b/code/modules/goonchat/browserassets/js/browserOutput.js
index cb384cc7aab..2448bf94ed6 100644
--- a/code/modules/goonchat/browserassets/js/browserOutput.js
+++ b/code/modules/goonchat/browserassets/js/browserOutput.js
@@ -79,12 +79,6 @@ function clamp(val, min, max) {
return Math.max(min, Math.min(val, max))
}
-function outerHTML(el) {
- var wrap = document.createElement('div');
- wrap.appendChild(el.cloneNode(true));
- return wrap.innerHTML;
-}
-
//Polyfill for fucking date now because of course IE8 and below don't support it
if (!Date.now) {
Date.now = function now() {
@@ -183,57 +177,62 @@ function replaceRegex() {
$(this).removeAttr('replaceRegex');
}
-//Actually turns the highlight term match into appropriate html
-function addHighlightMarkup(match) {
+// Get a highlight markup span
+function createHighlightMarkup() {
var extra = '';
if (opts.highlightColor) {
- extra += ' style="background-color: '+opts.highlightColor+'"';
+ extra += ' style="background-color: ' + opts.highlightColor + '"';
}
- return ''+match+'';
+ return '';
}
-//Highlights words based on user settings
+// Get all child text nodes that match a regex pattern
+function getTextNodes(elem, pattern) {
+ var result = $([]);
+ $(elem).contents().each(function(idx, child) {
+ if (child.nodeType === 3 && /\S/.test(child.nodeValue) && pattern.test(child.nodeValue)) {
+ result = result.add(child);
+ }
+ else {
+ result = result.add(getTextNodes(child, pattern));
+ }
+ });
+ return result;
+}
+
+// Highlight all text terms matching the registered regex patterns
function highlightTerms(el) {
- if (el.children.length > 0) {
- for(var h = 0; h < el.children.length; h++){
- highlightTerms(el.children[h]);
- }
- }
+ var pattern = new RegExp("(" + opts.highlightTerms.join('|') + ")", 'gi');
+ var nodes = getTextNodes(el, pattern);
- var hasTextNode = false;
- for (var node = 0; node < el.childNodes.length; node++)
- {
- if (el.childNodes[node].nodeType === 3)
- {
- hasTextNode = true;
- break;
- }
- }
-
- if (hasTextNode) { //If element actually has text
- var newText = '';
- for (var c = 0; c < el.childNodes.length; c++) { //Each child element
- if (el.childNodes[c].nodeType === 3) { //Is it text only?
- var words = el.childNodes[c].data.split(' ');
- for (var w = 0; w < words.length; w++) { //Each word in the text
- var newWord = null;
- for (var i = 0; i < opts.highlightTerms.length; i++) { //Each highlight term
- if (opts.highlightTerms[i] && words[w].toLowerCase().indexOf(opts.highlightTerms[i].toLowerCase()) > -1) { //If a match is found
- newWord = words[w].replace("<", "<").replace(new RegExp(opts.highlightTerms[i], 'gi'), addHighlightMarkup);
- break;
- }
- if (window.console)
- console.log(newWord)
- }
- newText += newWord || words[w].replace("<", "<");
- newText += w >= words.length ? '' : ' ';
- }
- } else { //Every other type of element
- newText += outerHTML(el.childNodes[c]);
+ nodes.each(function (idx, node) {
+ var content = $(node).text();
+ var parent = $(node).parent();
+ var pre = $(node.previousSibling);
+ $(node).remove();
+ content.split(pattern).forEach(function (chunk) {
+ // Get our highlighted span/text node
+ var toInsert = null;
+ if (pattern.test(chunk)) {
+ var tmpElem = $(createHighlightMarkup());
+ tmpElem.text(chunk);
+ toInsert = tmpElem;
}
- }
- el.innerHTML = newText;
- }
+ else {
+ toInsert = document.createTextNode(chunk);
+ }
+
+ // Insert back into our element
+ if (pre.length == 0) {
+ var result = parent.prepend(toInsert);
+ pre = $(result[0].firstChild);
+ }
+ else {
+ pre.after(toInsert);
+ pre = $(pre[0].nextSibling);
+ }
+ });
+ });
}
function iconError(E) {
@@ -421,7 +420,7 @@ function output(message, flag) {
//Actually do the snap
//Stuff we can do after the message shows can go here, in the interests of responsiveness
if (opts.highlightTerms && opts.highlightTerms.length > 0) {
- highlightTerms(entry);
+ highlightTerms($(entry));
}
}
@@ -756,15 +755,11 @@ $(function() {
internalOutput('Loaded ping display of: '+(opts.pingDisabled ? 'hidden' : 'visible')+'', 'internal');
}
if (savedConfig.shighlightTerms) {
- var savedTerms = $.parseJSON(savedConfig.shighlightTerms);
- var actualTerms = '';
- for (var i = 0; i < savedTerms.length; i++) {
- if (savedTerms[i]) {
- actualTerms += savedTerms[i] + ', ';
- }
- }
+ var savedTerms = $.parseJSON(savedConfig.shighlightTerms).filter(function (entry) {
+ return entry !== null && /\S/.test(entry);
+ });
+ var actualTerms = savedTerms.length != 0 ? savedTerms.join(', ') : null;
if (actualTerms) {
- actualTerms = actualTerms.substring(0, actualTerms.length - 2);
internalOutput('Loaded highlight strings of: ' + actualTerms+'', 'internal');
opts.highlightTerms = savedTerms;
}
@@ -1066,20 +1061,12 @@ $(function() {
$('body').on('submit', '#highlightTermForm', function(e) {
e.preventDefault();
- var count = 0;
- while (count < opts.highlightLimit) {
+ opts.highlightTerms = [];
+ for (var count = 0; count < opts.highlightLimit; count++) {
var term = $('#highlightTermInput'+count).val();
- if (term) {
- term = term.trim();
- if (term === '') {
- opts.highlightTerms[count] = null;
- } else {
- opts.highlightTerms[count] = term.toLowerCase();
- }
- } else {
- opts.highlightTerms[count] = null;
+ if (term !== null && /\S/.test(term)) {
+ opts.highlightTerms.push(term.trim().toLowerCase());
}
- count++;
}
var color = $('#highlightColor').val();
diff --git a/code/modules/hydroponics/grown/misc.dm b/code/modules/hydroponics/grown/misc.dm
index 36de8996262..70c2fd5b2da 100644
--- a/code/modules/hydroponics/grown/misc.dm
+++ b/code/modules/hydroponics/grown/misc.dm
@@ -228,3 +228,34 @@
reagents.chem_temp = 1000 //Sets off the gunpowder
reagents.handle_reactions()
+// aloe
+/obj/item/seeds/aloe
+ name = "pack of aloe seeds"
+ desc = "These seeds grow into aloe."
+ icon_state = "seed-aloe"
+ species = "aloe"
+ plantname = "Aloe"
+ product = /obj/item/reagent_containers/food/snacks/grown/aloe
+ lifespan = 60
+ endurance = 25
+ maturation = 4
+ production = 4
+ yield = 6
+ growthstages = 5
+ growing_icon = 'icons/obj/hydroponics/growing_vegetables.dmi'
+ reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.05, /datum/reagent/consumable/nutriment = 0.05)
+
+/obj/item/reagent_containers/food/snacks/grown/aloe
+ seed = /obj/item/seeds/aloe
+ name = "aloe"
+ desc = "Cut leaves from the aloe plant."
+ icon_state = "aloe"
+ filling_color = "#90EE90"
+ bitesize_mod = 5
+ foodtype = VEGETABLES
+ juice_results = list(/datum/reagent/consumable/aloejuice = 0)
+ distill_reagent = /datum/reagent/consumable/ethanol/tequila
+
+/obj/item/reagent_containers/food/snacks/grown/aloe/microwave_act(obj/machinery/microwave/M)
+ new /obj/item/stack/medical/aloe(drop_location(), 2)
+ qdel(src)
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 5892cd52e0b..2ca0f8cc68c 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -1,1289 +1,1289 @@
-/mob/living/carbon/human/Initialize()
- verbs += /mob/living/proc/mob_sleep
- verbs += /mob/living/proc/lay_down
-
- icon_state = "" //Remove the inherent human icon that is visible on the map editor. We're rendering ourselves limb by limb, having it still be there results in a bug where the basic human icon appears below as south in all directions and generally looks nasty.
-
- //initialize limbs first
- create_bodyparts()
-
- setup_human_dna()
-
- if(dna.species)
- set_species(dna.species.type)
-
- //initialise organs
- create_internal_organs() //most of it is done in set_species now, this is only for parent call
- physiology = new()
-
- . = ..()
-
- RegisterSignal(src, COMSIG_COMPONENT_CLEAN_ACT, .proc/clean_blood)
- AddComponent(/datum/component/personal_crafting)
- AddComponent(/datum/component/footstep, FOOTSTEP_MOB_HUMAN, 1, 2)
- GLOB.human_list += src
-
-/mob/living/carbon/human/proc/setup_human_dna()
- //initialize dna. for spawned humans; overwritten by other code
- create_dna(src)
- randomize_human(src)
- dna.initialize_dna()
-
-/mob/living/carbon/human/ComponentInitialize()
- . = ..()
- if(!CONFIG_GET(flag/disable_human_mood))
- AddComponent(/datum/component/mood)
-
-/mob/living/carbon/human/Destroy()
- QDEL_NULL(physiology)
- GLOB.human_list -= src
- return ..()
-
-
-/mob/living/carbon/human/prepare_data_huds()
- //Update med hud images...
- ..()
- //...sec hud images...
- sec_hud_set_ID()
- sec_hud_set_implants()
- sec_hud_set_security_status()
- //...and display them.
- add_to_all_human_data_huds()
-
-/mob/living/carbon/human/Stat()
- ..()
-
- if(statpanel("Status"))
- stat(null, "Intent: [a_intent]")
- stat(null, "Move Mode: [m_intent]")
- if (internal)
- if (!internal.air_contents)
- qdel(internal)
- else
- stat(null, "Internal Atmosphere Info: [internal.name]")
- stat(null, "Tank Pressure: [internal.air_contents.return_pressure()]")
- stat(null, "Distribution Pressure: [internal.distribute_pressure]")
-
- if(mind)
- var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
- if(changeling)
- stat(null, "Chemical Storage: [changeling.chem_charges]/[changeling.chem_storage]")
- stat(null, "Absorbed DNA: [changeling.absorbedcount]")
-
- //NINJACODE
- if(istype(wear_suit, /obj/item/clothing/suit/space/space_ninja)) //Only display if actually a ninja.
- var/obj/item/clothing/suit/space/space_ninja/SN = wear_suit
- if(statpanel("SpiderOS"))
- stat("SpiderOS Status:","[SN.s_initialized ? "Initialized" : "Disabled"]")
- stat("Current Time:", "[station_time_timestamp()]")
- if(SN.s_initialized)
- //Suit gear
- stat("Energy Charge:", "[round(SN.cell.charge/100)]%")
- stat("Smoke Bombs:", "\Roman [SN.s_bombs]")
- //Ninja status
- stat("Fingerprints:", "[md5(dna.uni_identity)]")
- stat("Unique Identity:", "[dna.unique_enzymes]")
- stat("Overall Status:", "[stat > 1 ? "dead" : "[health]% healthy"]")
- stat("Nutrition Status:", "[nutrition]")
- stat("Oxygen Loss:", "[getOxyLoss()]")
- stat("Toxin Levels:", "[getToxLoss()]")
- stat("Burn Severity:", "[getFireLoss()]")
- stat("Brute Trauma:", "[getBruteLoss()]")
- stat("Radiation Levels:","[radiation] rad")
- stat("Body Temperature:","[bodytemperature-T0C] degrees C ([bodytemperature*1.8-459.67] degrees F)")
-
- //Diseases
- if(diseases.len)
- stat("Viruses:", null)
- for(var/thing in diseases)
- var/datum/disease/D = thing
- stat("*", "[D.name], Type: [D.spread_text], Stage: [D.stage]/[D.max_stages], Possible Cure: [D.cure_text]")
-
-
-/mob/living/carbon/human/show_inv(mob/user)
- user.set_machine(src)
- var/has_breathable_mask = istype(wear_mask, /obj/item/clothing/mask)
- var/list/obscured = check_obscured_slots()
- var/list/dat = list()
-
- dat += "
- Close
- "}
-
- var/datum/browser/popup = new(user, "mob[REF(src)]", "[src]", 440, 510)
- popup.set_content(dat.Join())
- popup.open()
-
-// called when something steps onto a human
-// this could be made more general, but for now just handle mulebot
-/mob/living/carbon/human/Crossed(atom/movable/AM)
- var/mob/living/simple_animal/bot/mulebot/MB = AM
- if(istype(MB))
- MB.RunOver(src)
-
- . = ..()
- spreadFire(AM)
-
-/mob/living/carbon/human/Topic(href, href_list)
- if(href_list["embedded_object"] && usr.canUseTopic(src, BE_CLOSE, NO_DEXTERITY))
- var/obj/item/bodypart/L = locate(href_list["embedded_limb"]) in bodyparts
- if(!L)
- return
- var/obj/item/I = locate(href_list["embedded_object"]) in L.embedded_objects
- if(!I || I.loc != src) //no item, no limb, or item is not in limb or in the person anymore
- return
- SEND_SIGNAL(src, COMSIG_HUMAN_EMBED_RIP, I, L)
- return
-
- if(href_list["item"]) //canUseTopic check for this is handled by mob/Topic()
- var/slot = text2num(href_list["item"])
- if(slot in check_obscured_slots(TRUE))
- to_chat(usr, "You can't reach that! Something is covering it.")
- return
-
- if(href_list["pockets"] && usr.canUseTopic(src, BE_CLOSE, NO_DEXTERITY)) //TODO: Make it match (or intergrate it into) strippanel so you get 'item cannot fit here' warnings if mob_can_equip fails
- var/pocket_side = href_list["pockets"] != "right" ? "left" : "right"
- var/pocket_id = (pocket_side == "right" ? ITEM_SLOT_RPOCKET : ITEM_SLOT_LPOCKET)
- var/obj/item/pocket_item = (pocket_id == ITEM_SLOT_RPOCKET ? r_store : l_store)
- var/obj/item/place_item = usr.get_active_held_item() // Item to place in the pocket, if it's empty
-
- var/delay_denominator = 1
- if(pocket_item && !(pocket_item.item_flags & ABSTRACT))
- if(HAS_TRAIT(pocket_item, TRAIT_NODROP))
- to_chat(usr, "You try to empty [src]'s [pocket_side] pocket, it seems to be stuck!")
- to_chat(usr, "You try to empty [src]'s [pocket_side] pocket.")
- else if(place_item && place_item.mob_can_equip(src, usr, pocket_id, 1) && !(place_item.item_flags & ABSTRACT))
- to_chat(usr, "You try to place [place_item] into [src]'s [pocket_side] pocket.")
- delay_denominator = 4
- else
- return
-
- if(do_mob(usr, src, POCKET_STRIP_DELAY/delay_denominator)) //placing an item into the pocket is 4 times faster
- if(pocket_item)
- if(pocket_item == (pocket_id == ITEM_SLOT_RPOCKET ? r_store : l_store)) //item still in the pocket we search
- dropItemToGround(pocket_item)
- else
- if(place_item)
- if(place_item.mob_can_equip(src, usr, pocket_id, FALSE, TRUE))
- usr.temporarilyRemoveItemFromInventory(place_item, TRUE)
- equip_to_slot(place_item, pocket_id, TRUE)
- //do nothing otherwise
- //updating inv screen after handled by living/Topic()
- else
- // Display a warning if the user mocks up
- to_chat(src, "You feel your [pocket_side] pocket being fumbled with!")
-
- if(href_list["toggle_uniform"] && usr.canUseTopic(src, BE_CLOSE, NO_DEXTERITY))
- var/obj/item/clothing/under/U = get_item_by_slot(ITEM_SLOT_ICLOTHING)
- to_chat(src, "[usr.name] is trying to adjust your [U].")
- if(do_mob(usr, src, U.strip_delay/2))
- to_chat(src, "[usr.name] successfully adjusted your [U].")
- U.toggle_jumpsuit_adjust()
- update_inv_w_uniform()
- update_body()
-
-
-///////HUDs///////
- if(href_list["hud"])
- if(!ishuman(usr))
- return
- var/mob/living/carbon/human/H = usr
- var/perpname = get_face_name(get_id_name(""))
- if(!HAS_TRAIT(H, TRAIT_SECURITY_HUD) && !HAS_TRAIT(H, TRAIT_MEDICAL_HUD))
- return
- var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.general)
- if(href_list["photo_front"] || href_list["photo_side"])
- if(!R)
- return
- if(!H.canUseHUD())
- return
- if(!HAS_TRAIT(H, TRAIT_SECURITY_HUD) && !HAS_TRAIT(H, TRAIT_MEDICAL_HUD))
- return
- var/obj/item/photo/P = null
- if(href_list["photo_front"])
- P = R.fields["photo_front"]
- else if(href_list["photo_side"])
- P = R.fields["photo_side"]
- if(P)
- P.show(H)
- return
-
- if(href_list["hud"] == "m")
- if(!HAS_TRAIT(H, TRAIT_MEDICAL_HUD))
- return
- if(href_list["evaluation"])
- if(!getBruteLoss() && !getFireLoss() && !getOxyLoss() && getToxLoss() < 20)
- to_chat(usr, "No external injuries detected.
")
- return
- var/span = "notice"
- var/status = ""
- if(getBruteLoss())
- to_chat(usr, "Physical trauma analysis:")
- for(var/X in bodyparts)
- var/obj/item/bodypart/BP = X
- var/brutedamage = BP.brute_dam
- if(brutedamage > 0)
- status = "received minor physical injuries."
- span = "notice"
- if(brutedamage > 20)
- status = "been seriously damaged."
- span = "danger"
- if(brutedamage > 40)
- status = "sustained major trauma!"
- span = "userdanger"
- if(brutedamage)
- to_chat(usr, "[BP] appears to have [status]")
- if(getFireLoss())
- to_chat(usr, "Analysis of skin burns:")
- for(var/X in bodyparts)
- var/obj/item/bodypart/BP = X
- var/burndamage = BP.burn_dam
- if(burndamage > 0)
- status = "signs of minor burns."
- span = "notice"
- if(burndamage > 20)
- status = "serious burns."
- span = "danger"
- if(burndamage > 40)
- status = "major burns!"
- span = "userdanger"
- if(burndamage)
- to_chat(usr, "[BP] appears to have [status]")
- if(getOxyLoss())
- to_chat(usr, "Patient has signs of suffocation, emergency treatment may be required!")
- if(getToxLoss() > 20)
- to_chat(usr, "Gathered data is inconsistent with the analysis, possible cause: poisoning.")
- if(!H.wear_id) //You require access from here on out.
- to_chat(H, "ERROR: Invalid access")
- return
- var/list/access = H.wear_id.GetAccess()
- if(!(ACCESS_MEDICAL in access))
- to_chat(H, "ERROR: Invalid access")
- return
- if(href_list["p_stat"])
- var/health_status = input(usr, "Specify a new physical status for this person.", "Medical HUD", R.fields["p_stat"]) in list("Active", "Physically Unfit", "*Unconscious*", "*Deceased*", "Cancel")
- if(!R)
- return
- if(!H.canUseHUD())
- return
- if(!HAS_TRAIT(H, TRAIT_MEDICAL_HUD))
- return
- if(health_status && health_status != "Cancel")
- R.fields["p_stat"] = health_status
- return
- if(href_list["m_stat"])
- var/health_status = input(usr, "Specify a new mental status for this person.", "Medical HUD", R.fields["m_stat"]) in list("Stable", "*Watch*", "*Unstable*", "*Insane*", "Cancel")
- if(!R)
- return
- if(!H.canUseHUD())
- return
- if(!HAS_TRAIT(H, TRAIT_MEDICAL_HUD))
- return
- if(health_status && health_status != "Cancel")
- R.fields["m_stat"] = health_status
- return
- return //Medical HUD ends here.
-
- if(href_list["hud"] == "s")
- if(!HAS_TRAIT(H, TRAIT_SECURITY_HUD))
- return
- if(usr.stat || usr == src) //|| !usr.canmove || usr.restrained()) Fluff: Sechuds have eye-tracking technology and sets 'arrest' to people that the wearer looks and blinks at.
- return //Non-fluff: This allows sec to set people to arrest as they get disarmed or beaten
- // Checks the user has security clearence before allowing them to change arrest status via hud, comment out to enable all access
- var/allowed_access = null
- var/obj/item/clothing/glasses/hud/security/G = H.glasses
- if(istype(G) && (G.obj_flags & EMAGGED))
- allowed_access = "@%&ERROR_%$*"
- else //Implant and standard glasses check access
- if(H.wear_id)
- var/list/access = H.wear_id.GetAccess()
- if(ACCESS_SEC_DOORS in access)
- allowed_access = H.get_authentification_name()
-
- if(!allowed_access)
- to_chat(H, "ERROR: Invalid access.")
- return
-
- if(!perpname)
- to_chat(H, "ERROR: Can not identify target.")
- return
- R = find_record("name", perpname, GLOB.data_core.security)
- if(!R)
- to_chat(usr, "ERROR: Unable to locate data core entry for target.")
- return
- if(href_list["status"])
- var/setcriminal = input(usr, "Specify a new criminal status for this person.", "Security HUD", R.fields["criminal"]) in list("None", "*Arrest*", "Incarcerated", "Paroled", "Discharged", "Cancel")
- if(setcriminal != "Cancel")
- if(!R)
- return
- if(!H.canUseHUD())
- return
- if(!HAS_TRAIT(H, TRAIT_SECURITY_HUD))
- return
- investigate_log("[key_name(src)] has been set from [R.fields["criminal"]] to [setcriminal] by [key_name(usr)].", INVESTIGATE_RECORDS)
- R.fields["criminal"] = setcriminal
- sec_hud_set_security_status()
- return
-
- if(href_list["view"])
- if(!H.canUseHUD())
- return
- if(!HAS_TRAIT(H, TRAIT_SECURITY_HUD))
- return
- to_chat(usr, "Name: [R.fields["name"]] Criminal Status: [R.fields["criminal"]]")
- to_chat(usr, "Minor Crimes:")
- for(var/datum/data/crime/c in R.fields["mi_crim"])
- to_chat(usr, "Crime: [c.crimeName]")
- to_chat(usr, "Details: [c.crimeDetails]")
- to_chat(usr, "Added by [c.author] at [c.time]")
- to_chat(usr, "----------")
- to_chat(usr, "Major Crimes:")
- for(var/datum/data/crime/c in R.fields["ma_crim"])
- to_chat(usr, "Crime: [c.crimeName]")
- to_chat(usr, "Details: [c.crimeDetails]")
- to_chat(usr, "Added by [c.author] at [c.time]")
- to_chat(usr, "----------")
- to_chat(usr, "Notes: [R.fields["notes"]]")
- return
-
- if(href_list["add_citation"])
- var/maxFine = CONFIG_GET(number/maxfine)
- var/t1 = stripped_input("Please input citation crime:", "Security HUD", "", null)
- var/fine = FLOOR(input("Please input citation fine, up to [maxFine]:", "Security HUD", 50) as num|null, 1)
- if(!R || !t1 || !fine || !allowed_access)
- return
- if(!H.canUseHUD())
- return
- if(!HAS_TRAIT(H, TRAIT_SECURITY_HUD))
- return
- if(fine < 0)
- to_chat(usr, "You're pretty sure that's not how money works.")
- return
- fine = min(fine, maxFine)
-
- var/crime = GLOB.data_core.createCrimeEntry(t1, "", allowed_access, station_time_timestamp(), fine)
- for (var/obj/item/pda/P in GLOB.PDAs)
- if(P.owner == R.fields["name"])
- var/message = "You have been fined [fine] credits for '[t1]'. Fines may be paid at security."
- var/datum/signal/subspace/messaging/pda/signal = new(src, list(
- "name" = "Security Citation",
- "job" = "Citation Server",
- "message" = message,
- "targets" = list("[P.owner] ([P.ownjob])"),
- "automated" = 1
- ))
- signal.send_to_receivers()
- usr.log_message("(PDA: Citation Server) sent \"[message]\" to [signal.format_target()]", LOG_PDA)
- GLOB.data_core.addCitation(R.fields["id"], crime)
- investigate_log("New Citation: [t1] Fine: [fine] | Added to [R.fields["name"]] by [key_name(usr)]", INVESTIGATE_RECORDS)
- return
-
- if(href_list["add_crime"])
- switch(alert("What crime would you like to add?","Security HUD","Minor Crime","Major Crime","Cancel"))
- if("Minor Crime")
- var/t1 = stripped_input("Please input minor crime names:", "Security HUD", "", null)
- var/t2 = stripped_multiline_input("Please input minor crime details:", "Security HUD", "", null)
- if(!R || !t1 || !t2 || !allowed_access)
- return
- if(!H.canUseHUD())
- return
- if(!HAS_TRAIT(H, TRAIT_SECURITY_HUD))
- return
- var/crime = GLOB.data_core.createCrimeEntry(t1, t2, allowed_access, station_time_timestamp())
- GLOB.data_core.addMinorCrime(R.fields["id"], crime)
- investigate_log("New Minor Crime: [t1]: [t2] | Added to [R.fields["name"]] by [key_name(usr)]", INVESTIGATE_RECORDS)
- to_chat(usr, "Successfully added a minor crime.")
- return
- if("Major Crime")
- var/t1 = stripped_input("Please input major crime names:", "Security HUD", "", null)
- var/t2 = stripped_multiline_input("Please input major crime details:", "Security HUD", "", null)
- if(!R || !t1 || !t2 || !allowed_access)
- return
- if(!H.canUseHUD())
- return
- if(!HAS_TRAIT(H, TRAIT_SECURITY_HUD))
- return
- var/crime = GLOB.data_core.createCrimeEntry(t1, t2, allowed_access, station_time_timestamp())
- GLOB.data_core.addMajorCrime(R.fields["id"], crime)
- investigate_log("New Major Crime: [t1]: [t2] | Added to [R.fields["name"]] by [key_name(usr)]", INVESTIGATE_RECORDS)
- to_chat(usr, "Successfully added a major crime.")
- return
-
- if(href_list["view_comment"])
- if(!H.canUseHUD())
- return
- if(!HAS_TRAIT(H, TRAIT_SECURITY_HUD))
- return
- to_chat(usr, "Comments/Log:")
- var/counter = 1
- while(R.fields[text("com_[]", counter)])
- to_chat(usr, R.fields[text("com_[]", counter)])
- to_chat(usr, "----------")
- counter++
- return
-
- if(href_list["add_comment"])
- var/t1 = stripped_multiline_input("Add Comment:", "Secure. records", null, null)
- if (!R || !t1 || !allowed_access)
- return
- if(!H.canUseHUD())
- return
- if(!HAS_TRAIT(H, TRAIT_SECURITY_HUD))
- return
- var/counter = 1
- while(R.fields[text("com_[]", counter)])
- counter++
- R.fields[text("com_[]", counter)] = text("Made by [] on [] [], []
[]", allowed_access, station_time_timestamp(), time2text(world.realtime, "MMM DD"), GLOB.year_integer+540, t1)
- to_chat(usr, "Successfully added comment.")
- return
-
- ..() //end of this massive fucking chain. TODO: make the hud chain not spooky. - Yeah, great job doing that.
-
-
-/mob/living/carbon/human/proc/canUseHUD()
- return (mobility_flags & MOBILITY_USE)
-
-/mob/living/carbon/human/can_inject(mob/user, error_msg, target_zone, penetrate_thick = 0)
- . = 1 // Default to returning true.
- if(user && !target_zone)
- target_zone = user.zone_selected
- if(HAS_TRAIT(src, TRAIT_PIERCEIMMUNE))
- . = 0
- // If targeting the head, see if the head item is thin enough.
- // If targeting anything else, see if the wear suit is thin enough.
- if (!penetrate_thick)
- if(above_neck(target_zone))
- if(head && istype(head, /obj/item/clothing))
- var/obj/item/clothing/CH = head
- if (CH.clothing_flags & THICKMATERIAL)
- . = 0
- else
- if(wear_suit && istype(wear_suit, /obj/item/clothing))
- var/obj/item/clothing/CS = wear_suit
- if (CS.clothing_flags & THICKMATERIAL)
- . = 0
- if(!. && error_msg && user)
- // Might need re-wording.
- to_chat(user, "There is no exposed flesh or thin material [above_neck(target_zone) ? "on [p_their()] head" : "on [p_their()] body"].")
-
-/mob/living/carbon/human/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null)
- if(judgement_criteria & JUDGE_EMAGGED)
- return 10 //Everyone is a criminal!
-
- var/threatcount = 0
-
- //Lasertag bullshit
- if(lasercolor)
- if(lasercolor == "b")//Lasertag turrets target the opposing team, how great is that? -Sieve
- if(istype(wear_suit, /obj/item/clothing/suit/redtag))
- threatcount += 4
- if(is_holding_item_of_type(/obj/item/gun/energy/laser/redtag))
- threatcount += 4
- if(istype(belt, /obj/item/gun/energy/laser/redtag))
- threatcount += 2
-
- if(lasercolor == "r")
- if(istype(wear_suit, /obj/item/clothing/suit/bluetag))
- threatcount += 4
- if(is_holding_item_of_type(/obj/item/gun/energy/laser/bluetag))
- threatcount += 4
- if(istype(belt, /obj/item/gun/energy/laser/bluetag))
- threatcount += 2
-
- return threatcount
-
- //Check for ID
- var/obj/item/card/id/idcard = get_idcard(FALSE)
- if( (judgement_criteria & JUDGE_IDCHECK) && !idcard && name=="Unknown")
- threatcount += 4
-
- //Check for weapons
- if( (judgement_criteria & JUDGE_WEAPONCHECK) && weaponcheck)
- if(!idcard || !(ACCESS_WEAPONS in idcard.access))
- for(var/obj/item/I in held_items) //if they're holding a gun
- if(weaponcheck.Invoke(I))
- threatcount += 4
- if(weaponcheck.Invoke(belt) || weaponcheck.Invoke(back)) //if a weapon is present in the belt or back slot
- threatcount += 2 //not enough to trigger look_for_perp() on it's own unless they also have criminal status.
-
- //Check for arrest warrant
- if(judgement_criteria & JUDGE_RECORDCHECK)
- var/perpname = get_face_name(get_id_name())
- var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.security)
- if(R && R.fields["criminal"])
- switch(R.fields["criminal"])
- if("*Arrest*")
- threatcount += 5
- if("Incarcerated")
- threatcount += 2
- if("Paroled")
- threatcount += 2
-
- //Check for dresscode violations
- if(istype(head, /obj/item/clothing/head/wizard) || istype(head, /obj/item/clothing/head/helmet/space/hardsuit/wizard))
- threatcount += 2
-
- //Check for nonhuman scum
- if(dna && dna.species.id && dna.species.id != "human")
- threatcount += 1
-
- //mindshield implants imply trustworthyness
- if(HAS_TRAIT(src, TRAIT_MINDSHIELD))
- threatcount -= 1
-
- //Agent cards lower threatlevel.
- if(istype(idcard, /obj/item/card/id/syndicate))
- threatcount -= 5
-
- return threatcount
-
-
-//Used for new human mobs created by cloning/goleming/podding
-/mob/living/carbon/human/proc/set_cloned_appearance()
- if(gender == MALE)
- facial_hairstyle = "Full Beard"
- else
- facial_hairstyle = "Shaved"
- hairstyle = pick("Bedhead", "Bedhead 2", "Bedhead 3")
- underwear = "Nude"
- update_body()
- update_hair()
-
-/mob/living/carbon/human/singularity_pull(S, current_size)
- ..()
- if(current_size >= STAGE_THREE)
- for(var/obj/item/hand in held_items)
- if(prob(current_size * 5) && hand.w_class >= ((11-current_size)/2) && dropItemToGround(hand))
- step_towards(hand, src)
- to_chat(src, "\The [S] pulls \the [hand] from your grip!")
- rad_act(current_size * 3)
-
-/mob/living/carbon/human/proc/do_cpr(mob/living/carbon/C)
- CHECK_DNA_AND_SPECIES(C)
-
- if(C.stat == DEAD || (HAS_TRAIT(C, TRAIT_FAKEDEATH)))
- to_chat(src, "[C.name] is dead!")
- return
- if(is_mouth_covered())
- to_chat(src, "Remove your mask first!")
- return 0
- if(C.is_mouth_covered())
- to_chat(src, "Remove [p_their()] mask first!")
- return 0
-
- if(C.cpr_time < world.time + 30)
- visible_message("[src] is trying to perform CPR on [C.name]!", \
- "You try to perform CPR on [C.name]... Hold still!")
- if(!do_mob(src, C))
- to_chat(src, "You fail to perform CPR on [C]!")
- return 0
-
- var/they_breathe = !HAS_TRAIT(C, TRAIT_NOBREATH)
- var/they_lung = C.getorganslot(ORGAN_SLOT_LUNGS)
-
- if(C.health > C.crit_threshold)
- return
-
- src.visible_message("[src] performs CPR on [C.name]!", "You perform CPR on [C.name].")
- SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "perform_cpr", /datum/mood_event/perform_cpr)
- C.cpr_time = world.time
- log_combat(src, C, "CPRed")
-
- if(they_breathe && they_lung)
- var/suff = min(C.getOxyLoss(), 7)
- C.adjustOxyLoss(-suff)
- C.updatehealth()
- to_chat(C, "You feel a breath of fresh air enter your lungs... It feels good...")
- else if(they_breathe && !they_lung)
- to_chat(C, "You feel a breath of fresh air... but you don't feel any better...")
- else
- to_chat(C, "You feel a breath of fresh air... which is a sensation you don't recognise...")
-
-/mob/living/carbon/human/cuff_resist(obj/item/I)
- if(dna && dna.check_mutation(HULK))
- say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ), forced = "hulk")
- if(..(I, cuff_break = FAST_CUFFBREAK))
- dropItemToGround(I)
- else
- if(..())
- dropItemToGround(I)
-
-/mob/living/carbon/human/proc/clean_blood(datum/source, strength)
- if(strength < CLEAN_STRENGTH_BLOOD)
- return
- if(gloves)
- if(SEND_SIGNAL(gloves, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD))
- update_inv_gloves()
- else
- if(bloody_hands)
- bloody_hands = 0
- update_inv_gloves()
-
-//Turns a mob black, flashes a skeleton overlay
-//Just like a cartoon!
-/mob/living/carbon/human/proc/electrocution_animation(anim_duration)
- //Handle mutant parts if possible
- if(dna && dna.species)
- add_atom_colour("#000000", TEMPORARY_COLOUR_PRIORITY)
- var/static/mutable_appearance/electrocution_skeleton_anim
- if(!electrocution_skeleton_anim)
- electrocution_skeleton_anim = mutable_appearance(icon, "electrocuted_base")
- electrocution_skeleton_anim.appearance_flags |= RESET_COLOR|KEEP_APART
- add_overlay(electrocution_skeleton_anim)
- addtimer(CALLBACK(src, .proc/end_electrocution_animation, electrocution_skeleton_anim), anim_duration)
-
- else //or just do a generic animation
- flick_overlay_view(image(icon,src,"electrocuted_generic",ABOVE_MOB_LAYER), src, anim_duration)
-
-/mob/living/carbon/human/proc/end_electrocution_animation(mutable_appearance/MA)
- remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, "#000000")
- cut_overlay(MA)
-
-/mob/living/carbon/human/canUseTopic(atom/movable/M, be_close=FALSE, no_dexterity=FALSE, no_tk=FALSE)
- if(!(mobility_flags & MOBILITY_UI))
- to_chat(src, "You can't do that right now!")
- return FALSE
- if(!Adjacent(M) && (M.loc != src))
- if((be_close == FALSE) || (!no_tk && (dna.check_mutation(TK) && tkMaxRangeCheck(src, M))))
- return TRUE
- to_chat(src, "You are too far away!")
- return FALSE
- return TRUE
-
-/mob/living/carbon/human/resist_restraints()
- if(wear_suit && wear_suit.breakouttime)
- changeNext_move(CLICK_CD_BREAKOUT)
- last_special = world.time + CLICK_CD_BREAKOUT
- cuff_resist(wear_suit)
- else
- ..()
-
-/mob/living/carbon/human/clear_cuffs(obj/item/I, cuff_break)
- . = ..()
- if(.)
- return
- if(!I.loc || buckled)
- return FALSE
- if(I == wear_suit)
- visible_message("[src] manages to [cuff_break ? "break" : "remove"] [I]!")
- to_chat(src, "You successfully [cuff_break ? "break" : "remove"] [I].")
- return TRUE
-
-/mob/living/carbon/human/replace_records_name(oldname,newname) // Only humans have records right now, move this up if changed.
- for(var/list/L in list(GLOB.data_core.general,GLOB.data_core.medical,GLOB.data_core.security,GLOB.data_core.locked))
- var/datum/data/record/R = find_record("name", oldname, L)
- if(R)
- R.fields["name"] = newname
-
-/mob/living/carbon/human/get_total_tint()
- . = ..()
- if(glasses)
- . += glasses.tint
-
-/mob/living/carbon/human/update_health_hud()
- if(!client || !hud_used)
- return
- if(dna.species.update_health_hud())
- return
- else
- if(hud_used.healths)
- var/health_amount = min(health, maxHealth - getStaminaLoss())
- if(..(health_amount)) //not dead
- switch(hal_screwyhud)
- if(SCREWYHUD_CRIT)
- hud_used.healths.icon_state = "health6"
- if(SCREWYHUD_DEAD)
- hud_used.healths.icon_state = "health7"
- if(SCREWYHUD_HEALTHY)
- hud_used.healths.icon_state = "health0"
- if(hud_used.healthdoll)
- hud_used.healthdoll.cut_overlays()
- if(stat != DEAD)
- hud_used.healthdoll.icon_state = "healthdoll_OVERLAY"
- for(var/X in bodyparts)
- var/obj/item/bodypart/BP = X
- var/damage = BP.burn_dam + BP.brute_dam
- var/comparison = (BP.max_damage/5)
- var/icon_num = 0
- if(damage)
- icon_num = 1
- if(damage > (comparison))
- icon_num = 2
- if(damage > (comparison*2))
- icon_num = 3
- if(damage > (comparison*3))
- icon_num = 4
- if(damage > (comparison*4))
- icon_num = 5
- if(hal_screwyhud == SCREWYHUD_HEALTHY)
- icon_num = 0
- if(icon_num)
- hud_used.healthdoll.add_overlay(mutable_appearance('icons/mob/screen_gen.dmi', "[BP.body_zone][icon_num]"))
- for(var/t in get_missing_limbs()) //Missing limbs
- hud_used.healthdoll.add_overlay(mutable_appearance('icons/mob/screen_gen.dmi', "[t]6"))
- for(var/t in get_disabled_limbs()) //Disabled limbs
- hud_used.healthdoll.add_overlay(mutable_appearance('icons/mob/screen_gen.dmi', "[t]7"))
- else
- hud_used.healthdoll.icon_state = "healthdoll_DEAD"
-
-/mob/living/carbon/human/fully_heal(admin_revive = FALSE)
- dna?.species.spec_fully_heal(src)
- if(admin_revive)
- regenerate_limbs()
- regenerate_organs()
- remove_all_embedded_objects()
- set_heartattack(FALSE)
- drunkenness = 0
- for(var/datum/mutation/human/HM in dna.mutations)
- if(HM.quality != POSITIVE)
- dna.remove_mutation(HM.name)
- ..()
-
-/mob/living/carbon/human/check_weakness(obj/item/weapon, mob/living/attacker)
- . = ..()
- if (dna && dna.species)
- . += dna.species.check_species_weakness(weapon, attacker)
-
-/mob/living/carbon/human/is_literate()
- return TRUE
-
-/mob/living/carbon/human/can_hold_items()
- return TRUE
-
-/mob/living/carbon/human/update_gravity(has_gravity,override = 0)
- if(dna && dna.species) //prevents a runtime while a human is being monkeyfied
- override = dna.species.override_float
- ..()
-
-/mob/living/carbon/human/vomit(lost_nutrition = 10, blood = FALSE, stun = TRUE, distance = 1, message = TRUE, toxic = FALSE, harm = TRUE, force = FALSE, purge = FALSE)
- if(blood && (NOBLOOD in dna.species.species_traits) && !HAS_TRAIT(src, TRAIT_TOXINLOVER))
- if(message)
- visible_message("[src] dry heaves!", \
- "You try to throw up, but there's nothing in your stomach!")
- if(stun)
- Paralyze(200)
- return 1
- ..()
-
-/mob/living/carbon/human/vv_get_dropdown()
- . = ..()
- VV_DROPDOWN_OPTION("", "---------")
- VV_DROPDOWN_OPTION(VV_HK_COPY_OUTFIT, "Copy Outfit")
- VV_DROPDOWN_OPTION(VV_HK_MOD_MUTATIONS, "Add/Remove Mutation")
- VV_DROPDOWN_OPTION(VV_HK_MOD_QUIRKS, "Add/Remove Quirks")
- VV_DROPDOWN_OPTION(VV_HK_MAKE_MONKEY, "Make Monkey")
- VV_DROPDOWN_OPTION(VV_HK_MAKE_CYBORG, "Make Cyborg")
- VV_DROPDOWN_OPTION(VV_HK_MAKE_SLIME, "Make Slime")
- VV_DROPDOWN_OPTION(VV_HK_MAKE_ALIEN, "Make Alien")
- VV_DROPDOWN_OPTION(VV_HK_SET_SPECIES, "Set Species")
- VV_DROPDOWN_OPTION(VV_HK_PURRBATION, "Toggle Purrbation")
-
-/mob/living/carbon/human/vv_do_topic(list/href_list)
- . = ..()
- if(href_list[VV_HK_COPY_OUTFIT])
- if(!check_rights(R_SPAWN))
- return
- copy_outfit()
- if(href_list[VV_HK_MOD_MUTATIONS])
- if(!check_rights(R_SPAWN))
- return
-
- var/list/options = list("Clear"="Clear")
- for(var/x in subtypesof(/datum/mutation/human))
- var/datum/mutation/human/mut = x
- var/name = initial(mut.name)
- options[dna.check_mutation(mut) ? "[name] (Remove)" : "[name] (Add)"] = mut
-
- var/result = input(usr, "Choose mutation to add/remove","Mutation Mod") as null|anything in sortList(options)
- if(result)
- if(result == "Clear")
- dna.remove_all_mutations()
- else
- var/mut = options[result]
- if(dna.check_mutation(mut))
- dna.remove_mutation(mut)
- else
- dna.add_mutation(mut)
- if(href_list[VV_HK_MOD_QUIRKS])
- if(!check_rights(R_SPAWN))
- return
-
- var/list/options = list("Clear"="Clear")
- for(var/x in subtypesof(/datum/quirk))
- var/datum/quirk/T = x
- var/qname = initial(T.name)
- options[has_quirk(T) ? "[qname] (Remove)" : "[qname] (Add)"] = T
-
- var/result = input(usr, "Choose quirk to add/remove","Quirk Mod") as null|anything in sortList(options)
- if(result)
- if(result == "Clear")
- for(var/datum/quirk/q in roundstart_quirks)
- remove_quirk(q.type)
- else
- var/T = options[result]
- if(has_quirk(T))
- remove_quirk(T)
- else
- add_quirk(T,TRUE)
- if(href_list[VV_HK_MAKE_MONKEY])
- if(!check_rights(R_SPAWN))
- return
- if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform")
- return
- usr.client.holder.Topic("vv_override", list("monkeyone"=href_list[VV_HK_TARGET]))
- if(href_list[VV_HK_MAKE_CYBORG])
- if(!check_rights(R_SPAWN))
- return
- if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform")
- return
- usr.client.holder.Topic("vv_override", list("makerobot"=href_list[VV_HK_TARGET]))
- if(href_list[VV_HK_MAKE_ALIEN])
- if(!check_rights(R_SPAWN))
- return
- if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform")
- return
- usr.client.holder.Topic("vv_override", list("makealien"=href_list[VV_HK_TARGET]))
- if(href_list[VV_HK_MAKE_SLIME])
- if(!check_rights(R_SPAWN))
- return
- if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform")
- return
- usr.client.holder.Topic("vv_override", list("makeslime"=href_list[VV_HK_TARGET]))
- if(href_list[VV_HK_SET_SPECIES])
- if(!check_rights(R_SPAWN))
- return
- var/result = input(usr, "Please choose a new species","Species") as null|anything in GLOB.species_list
- if(result)
- var/newtype = GLOB.species_list[result]
- admin_ticket_log("[key_name_admin(usr)] has modified the bodyparts of [src] to [result]")
- set_species(newtype)
- if(href_list[VV_HK_PURRBATION])
- if(!check_rights(R_SPAWN))
- return
- if(!ishumanbasic(src))
- to_chat(usr, "This can only be done to the basic human species at the moment.")
- return
- var/success = purrbation_toggle(src)
- if(success)
- to_chat(usr, "Put [src] on purrbation.")
- log_admin("[key_name(usr)] has put [key_name(src)] on purrbation.")
- var/msg = "[key_name_admin(usr)] has put [key_name(src)] on purrbation."
- message_admins(msg)
- admin_ticket_log(src, msg)
-
- else
- to_chat(usr, "Removed [src] from purrbation.")
- log_admin("[key_name(usr)] has removed [key_name(src)] from purrbation.")
- var/msg = "[key_name_admin(usr)] has removed [key_name(src)] from purrbation."
- message_admins(msg)
- admin_ticket_log(src, msg)
-
-/mob/living/carbon/human/MouseDrop_T(mob/living/target, mob/living/user)
- if(pulling == target && grab_state >= GRAB_AGGRESSIVE && stat == CONSCIOUS)
- //If they dragged themselves and we're currently aggressively grabbing them try to piggyback
- if(user == target && can_piggyback(target))
- piggyback(target)
- return
- //If you dragged them to you and you're aggressively grabbing try to fireman carry them
- else if(user != target && can_be_firemanned(target))
- fireman_carry(target)
- return
- . = ..()
-
-//src is the user that will be carrying, target is the mob to be carried
-/mob/living/carbon/human/proc/can_piggyback(mob/living/carbon/target)
- return (istype(target) && target.stat == CONSCIOUS)
-
-/mob/living/carbon/human/proc/can_be_firemanned(mob/living/carbon/target)
- return (ishuman(target) && !(target.mobility_flags & MOBILITY_STAND))
-
-/mob/living/carbon/human/proc/fireman_carry(mob/living/carbon/target)
- var/carrydelay = 50 //if you have latex you are faster at grabbing
- var/skills_space = "" //cobby told me to do this
- if(HAS_TRAIT(src, TRAIT_QUICKER_CARRY))
- carrydelay = 30
- skills_space = "expertly"
- else if(HAS_TRAIT(src, TRAIT_QUICK_CARRY))
- carrydelay = 40
- skills_space = "quickly"
- if(can_be_firemanned(target) && !incapacitated(FALSE, TRUE))
- visible_message("[src] starts [skills_space] lifting [target] onto their back..",
- //Joe Medic starts quickly/expertly lifting Grey Tider onto their back..
- "[carrydelay < 35 ? "Using your gloves' nanochips, you" : "You"] [skills_space] start to lift [target] onto your back[carrydelay == 40 ? ", while assisted by the nanochips in your gloves.." : "..."]")
- //(Using your gloves' nanochips, you/You) ( /quickly/expertly) start to lift Grey Tider onto your back(, while assisted by the nanochips in your gloves../...)
- if(do_after(src, carrydelay, TRUE, target))
- //Second check to make sure they're still valid to be carried
- if(can_be_firemanned(target) && !incapacitated(FALSE, TRUE))
- buckle_mob(target, TRUE, TRUE, 90, 1, 0)
- return
- visible_message("[src] fails to fireman carry [target]!")
- else
- to_chat(src, "You can't fireman carry [target] while they're standing!")
-
-/mob/living/carbon/human/proc/piggyback(mob/living/carbon/target)
- if(can_piggyback(target))
- visible_message("[target] starts to climb onto [src]...")
- if(do_after(target, 15, target = src))
- if(can_piggyback(target))
- if(target.incapacitated(FALSE, TRUE) || incapacitated(FALSE, TRUE))
- target.visible_message("[target] can't hang onto [src]!")
- return
- buckle_mob(target, TRUE, TRUE, FALSE, 0, 2)
- else
- visible_message("[target] fails to climb onto [src]!")
- else
- to_chat(target, "You can't piggyback ride [src] right now!")
-
-/mob/living/carbon/human/buckle_mob(mob/living/target, force = FALSE, check_loc = TRUE, lying_buckle = FALSE, hands_needed = 0, target_hands_needed = 0)
- if(!force)//humans are only meant to be ridden through piggybacking and special cases
- return
- if(!is_type_in_typecache(target, can_ride_typecache))
- target.visible_message("[target] really can't seem to mount [src]...")
- return
- buckle_lying = lying_buckle
- var/datum/component/riding/human/riding_datum = LoadComponent(/datum/component/riding/human)
- if(target_hands_needed)
- riding_datum.ride_check_rider_restrained = TRUE
- if(buckled_mobs && ((target in buckled_mobs) || (buckled_mobs.len >= max_buckled_mobs)) || buckled)
- return
- var/equipped_hands_self
- var/equipped_hands_target
- if(hands_needed)
- equipped_hands_self = riding_datum.equip_buckle_inhands(src, hands_needed, target)
- if(target_hands_needed)
- equipped_hands_target = riding_datum.equip_buckle_inhands(target, target_hands_needed)
-
- if(hands_needed || target_hands_needed)
- if(hands_needed && !equipped_hands_self)
- src.visible_message("[src] can't get a grip on [target] because their hands are full!",
- "You can't get a grip on [target] because your hands are full!")
- return
- else if(target_hands_needed && !equipped_hands_target)
- target.visible_message("[target] can't get a grip on [src] because their hands are full!",
- "You can't get a grip on [src] because your hands are full!")
- return
-
- stop_pulling()
- riding_datum.handle_vehicle_layer()
- . = ..(target, force, check_loc)
-
-/mob/living/carbon/human/proc/is_shove_knockdown_blocked() //If you want to add more things that block shove knockdown, extend this
- var/list/body_parts = list(head, wear_mask, wear_suit, w_uniform, back, gloves, shoes, belt, s_store, glasses, ears, wear_id) //Everything but pockets. Pockets are l_store and r_store. (if pockets were allowed, putting something armored, gloves or hats for example, would double up on the armor)
- for(var/bp in body_parts)
- if(istype(bp, /obj/item/clothing))
- var/obj/item/clothing/C = bp
- if(C.clothing_flags & BLOCKS_SHOVE_KNOCKDOWN)
- return TRUE
- return FALSE
-
-/mob/living/carbon/human/proc/clear_shove_slowdown()
- remove_movespeed_modifier(/datum/movespeed_modifier/shove)
- var/active_item = get_active_held_item()
- if(is_type_in_typecache(active_item, GLOB.shove_disarming_types))
- visible_message("[src.name] regains their grip on \the [active_item]!", "You regain your grip on \the [active_item]", null, COMBAT_MESSAGE_RANGE)
-
-/mob/living/carbon/human/do_after_coefficent()
- . = ..()
- . *= physiology.do_after_speed
-
-/mob/living/carbon/human/updatehealth()
- . = ..()
- dna?.species.spec_updatehealth(src)
- if(HAS_TRAIT(src, TRAIT_IGNOREDAMAGESLOWDOWN))
- remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown)
- remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying)
- return
- var/health_deficiency = max((maxHealth - health), staminaloss)
- if(health_deficiency >= 40)
- add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown, TRUE, multiplicative_slowdown = health_deficiency / 75)
- add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying, TRUE, multiplicative_slowdown = health_deficiency / 25)
- else
- remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown)
- remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying)
-
-/mob/living/carbon/human/washed(var/atom/washer)
- . = ..()
- if(wear_suit)
- update_inv_wear_suit()
- else if(w_uniform && w_uniform.washed(washer))
- update_inv_w_uniform()
-
- if(!is_mouth_covered())
- lip_style = null
- update_body()
- if(belt && belt.washed(washer))
- update_inv_belt()
-
- var/list/obscured = check_obscured_slots()
-
- if(gloves && !(HIDEGLOVES in obscured) && gloves.washed(washer))
- SEND_SIGNAL(src, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
-
-/mob/living/carbon/human/adjust_nutrition(change) //Honestly FUCK the oldcoders for putting nutrition on /mob someone else can move it up because holy hell I'd have to fix SO many typechecks
- if(HAS_TRAIT(src, TRAIT_NOHUNGER))
- return FALSE
- return ..()
-
-/mob/living/carbon/human/set_nutrition(change) //Seriously fuck you oldcoders.
- if(HAS_TRAIT(src, TRAIT_NOHUNGER))
- return FALSE
- return ..()
-
-/mob/living/carbon/human/species
- var/race = null
-
-/mob/living/carbon/human/species/Initialize()
- . = ..()
- set_species(race)
-
-/mob/living/carbon/human/species/abductor
- race = /datum/species/abductor
-
-/mob/living/carbon/human/species/android
- race = /datum/species/android
-
-/mob/living/carbon/human/species/corporate
- race = /datum/species/corporate
-
-/mob/living/carbon/human/species/dullahan
- race = /datum/species/dullahan
-
-/mob/living/carbon/human/species/felinid
- race = /datum/species/human/felinid
-
-/mob/living/carbon/human/species/fly
- race = /datum/species/fly
-
-/mob/living/carbon/human/species/golem
- race = /datum/species/golem
-
-/mob/living/carbon/human/species/golem/random
- race = /datum/species/golem/random
-
-/mob/living/carbon/human/species/golem/adamantine
- race = /datum/species/golem/adamantine
-
-/mob/living/carbon/human/species/golem/plasma
- race = /datum/species/golem/plasma
-
-/mob/living/carbon/human/species/golem/diamond
- race = /datum/species/golem/diamond
-
-/mob/living/carbon/human/species/golem/gold
- race = /datum/species/golem/gold
-
-/mob/living/carbon/human/species/golem/silver
- race = /datum/species/golem/silver
-
-/mob/living/carbon/human/species/golem/plasteel
- race = /datum/species/golem/plasteel
-
-/mob/living/carbon/human/species/golem/titanium
- race = /datum/species/golem/titanium
-
-/mob/living/carbon/human/species/golem/plastitanium
- race = /datum/species/golem/plastitanium
-
-/mob/living/carbon/human/species/golem/alien_alloy
- race = /datum/species/golem/alloy
-
-/mob/living/carbon/human/species/golem/wood
- race = /datum/species/golem/wood
-
-/mob/living/carbon/human/species/golem/uranium
- race = /datum/species/golem/uranium
-
-/mob/living/carbon/human/species/golem/sand
- race = /datum/species/golem/sand
-
-/mob/living/carbon/human/species/golem/glass
- race = /datum/species/golem/glass
-
-/mob/living/carbon/human/species/golem/bluespace
- race = /datum/species/golem/bluespace
-
-/mob/living/carbon/human/species/golem/bananium
- race = /datum/species/golem/bananium
-
-/mob/living/carbon/human/species/golem/blood_cult
- race = /datum/species/golem/runic
-
-/mob/living/carbon/human/species/golem/cloth
- race = /datum/species/golem/cloth
-
-/mob/living/carbon/human/species/golem/plastic
- race = /datum/species/golem/plastic
-
-/mob/living/carbon/human/species/golem/bronze
- race = /datum/species/golem/bronze
-
-/mob/living/carbon/human/species/golem/cardboard
- race = /datum/species/golem/cardboard
-
-/mob/living/carbon/human/species/golem/leather
- race = /datum/species/golem/leather
-
-/mob/living/carbon/human/species/golem/bone
- race = /datum/species/golem/bone
-
-/mob/living/carbon/human/species/golem/durathread
- race = /datum/species/golem/durathread
-
-/mob/living/carbon/human/species/golem/snow
- race = /datum/species/golem/snow
-
-/mob/living/carbon/human/species/golem/capitalist
- race = /datum/species/golem/capitalist
-
-/mob/living/carbon/human/species/golem/soviet
- race = /datum/species/golem/soviet
-
-/mob/living/carbon/human/species/jelly
- race = /datum/species/jelly
-
-/mob/living/carbon/human/species/jelly/slime
- race = /datum/species/jelly/slime
-
-/mob/living/carbon/human/species/jelly/stargazer
- race = /datum/species/jelly/stargazer
-
-/mob/living/carbon/human/species/jelly/luminescent
- race = /datum/species/jelly/luminescent
-
-/mob/living/carbon/human/species/lizard
- race = /datum/species/lizard
-
-/mob/living/carbon/human/species/ethereal
- race = /datum/species/ethereal
-
-/mob/living/carbon/human/species/lizard/ashwalker
- race = /datum/species/lizard/ashwalker
-
-/mob/living/carbon/human/species/moth
- race = /datum/species/moth
-
-/mob/living/carbon/human/species/mush
- race = /datum/species/mush
-
-/mob/living/carbon/human/species/plasma
- race = /datum/species/plasmaman
-
-/mob/living/carbon/human/species/pod
- race = /datum/species/pod
-
-/mob/living/carbon/human/species/shadow
- race = /datum/species/shadow
-
-/mob/living/carbon/human/species/shadow/nightmare
- race = /datum/species/shadow/nightmare
-
-/mob/living/carbon/human/species/skeleton
- race = /datum/species/skeleton
-
-/mob/living/carbon/human/species/snail
- race = /datum/species/snail
-
-/mob/living/carbon/human/species/synth
- race = /datum/species/synth
-
-/mob/living/carbon/human/species/synth/military
- race = /datum/species/synth/military
-
-/mob/living/carbon/human/species/vampire
- race = /datum/species/vampire
-
-/mob/living/carbon/human/species/zombie
- race = /datum/species/zombie
-
-/mob/living/carbon/human/species/zombie/infectious
- race = /datum/species/zombie/infectious
-
-/mob/living/carbon/human/species/zombie/krokodil_addict
- race = /datum/species/krokodil_addict
+/mob/living/carbon/human/Initialize()
+ verbs += /mob/living/proc/mob_sleep
+ verbs += /mob/living/proc/lay_down
+
+ icon_state = "" //Remove the inherent human icon that is visible on the map editor. We're rendering ourselves limb by limb, having it still be there results in a bug where the basic human icon appears below as south in all directions and generally looks nasty.
+
+ //initialize limbs first
+ create_bodyparts()
+
+ setup_human_dna()
+
+ if(dna.species)
+ set_species(dna.species.type)
+
+ //initialise organs
+ create_internal_organs() //most of it is done in set_species now, this is only for parent call
+ physiology = new()
+
+ . = ..()
+
+ RegisterSignal(src, COMSIG_COMPONENT_CLEAN_ACT, .proc/clean_blood)
+ AddComponent(/datum/component/personal_crafting)
+ AddComponent(/datum/component/footstep, FOOTSTEP_MOB_HUMAN, 1, 2)
+ GLOB.human_list += src
+
+/mob/living/carbon/human/proc/setup_human_dna()
+ //initialize dna. for spawned humans; overwritten by other code
+ create_dna(src)
+ randomize_human(src)
+ dna.initialize_dna()
+
+/mob/living/carbon/human/ComponentInitialize()
+ . = ..()
+ if(!CONFIG_GET(flag/disable_human_mood))
+ AddComponent(/datum/component/mood)
+
+/mob/living/carbon/human/Destroy()
+ QDEL_NULL(physiology)
+ GLOB.human_list -= src
+ return ..()
+
+
+/mob/living/carbon/human/prepare_data_huds()
+ //Update med hud images...
+ ..()
+ //...sec hud images...
+ sec_hud_set_ID()
+ sec_hud_set_implants()
+ sec_hud_set_security_status()
+ //...and display them.
+ add_to_all_human_data_huds()
+
+/mob/living/carbon/human/Stat()
+ ..()
+
+ if(statpanel("Status"))
+ stat(null, "Intent: [a_intent]")
+ stat(null, "Move Mode: [m_intent]")
+ if (internal)
+ if (!internal.air_contents)
+ qdel(internal)
+ else
+ stat(null, "Internal Atmosphere Info: [internal.name]")
+ stat(null, "Tank Pressure: [internal.air_contents.return_pressure()]")
+ stat(null, "Distribution Pressure: [internal.distribute_pressure]")
+
+ if(mind)
+ var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
+ if(changeling)
+ stat(null, "Chemical Storage: [changeling.chem_charges]/[changeling.chem_storage]")
+ stat(null, "Absorbed DNA: [changeling.absorbedcount]")
+
+ //NINJACODE
+ if(istype(wear_suit, /obj/item/clothing/suit/space/space_ninja)) //Only display if actually a ninja.
+ var/obj/item/clothing/suit/space/space_ninja/SN = wear_suit
+ if(statpanel("SpiderOS"))
+ stat("SpiderOS Status:","[SN.s_initialized ? "Initialized" : "Disabled"]")
+ stat("Current Time:", "[station_time_timestamp()]")
+ if(SN.s_initialized)
+ //Suit gear
+ stat("Energy Charge:", "[round(SN.cell.charge/100)]%")
+ stat("Smoke Bombs:", "\Roman [SN.s_bombs]")
+ //Ninja status
+ stat("Fingerprints:", "[md5(dna.uni_identity)]")
+ stat("Unique Identity:", "[dna.unique_enzymes]")
+ stat("Overall Status:", "[stat > 1 ? "dead" : "[health]% healthy"]")
+ stat("Nutrition Status:", "[nutrition]")
+ stat("Oxygen Loss:", "[getOxyLoss()]")
+ stat("Toxin Levels:", "[getToxLoss()]")
+ stat("Burn Severity:", "[getFireLoss()]")
+ stat("Brute Trauma:", "[getBruteLoss()]")
+ stat("Radiation Levels:","[radiation] rad")
+ stat("Body Temperature:","[bodytemperature-T0C] degrees C ([bodytemperature*1.8-459.67] degrees F)")
+
+ //Diseases
+ if(diseases.len)
+ stat("Viruses:", null)
+ for(var/thing in diseases)
+ var/datum/disease/D = thing
+ stat("*", "[D.name], Type: [D.spread_text], Stage: [D.stage]/[D.max_stages], Possible Cure: [D.cure_text]")
+
+
+/mob/living/carbon/human/show_inv(mob/user)
+ user.set_machine(src)
+ var/has_breathable_mask = istype(wear_mask, /obj/item/clothing/mask)
+ var/list/obscured = check_obscured_slots()
+ var/list/dat = list()
+
+ dat += "
+ Close
+ "}
+
+ var/datum/browser/popup = new(user, "mob[REF(src)]", "[src]", 440, 510)
+ popup.set_content(dat.Join())
+ popup.open()
+
+// called when something steps onto a human
+// this could be made more general, but for now just handle mulebot
+/mob/living/carbon/human/Crossed(atom/movable/AM)
+ var/mob/living/simple_animal/bot/mulebot/MB = AM
+ if(istype(MB))
+ MB.RunOver(src)
+
+ . = ..()
+ spreadFire(AM)
+
+/mob/living/carbon/human/Topic(href, href_list)
+ if(href_list["embedded_object"] && usr.canUseTopic(src, BE_CLOSE, NO_DEXTERITY))
+ var/obj/item/bodypart/L = locate(href_list["embedded_limb"]) in bodyparts
+ if(!L)
+ return
+ var/obj/item/I = locate(href_list["embedded_object"]) in L.embedded_objects
+ if(!I || I.loc != src) //no item, no limb, or item is not in limb or in the person anymore
+ return
+ SEND_SIGNAL(src, COMSIG_HUMAN_EMBED_RIP, I, L)
+ return
+
+ if(href_list["item"]) //canUseTopic check for this is handled by mob/Topic()
+ var/slot = text2num(href_list["item"])
+ if(slot in check_obscured_slots(TRUE))
+ to_chat(usr, "You can't reach that! Something is covering it.")
+ return
+
+ if(href_list["pockets"] && usr.canUseTopic(src, BE_CLOSE, NO_DEXTERITY)) //TODO: Make it match (or intergrate it into) strippanel so you get 'item cannot fit here' warnings if mob_can_equip fails
+ var/pocket_side = href_list["pockets"] != "right" ? "left" : "right"
+ var/pocket_id = (pocket_side == "right" ? ITEM_SLOT_RPOCKET : ITEM_SLOT_LPOCKET)
+ var/obj/item/pocket_item = (pocket_id == ITEM_SLOT_RPOCKET ? r_store : l_store)
+ var/obj/item/place_item = usr.get_active_held_item() // Item to place in the pocket, if it's empty
+
+ var/delay_denominator = 1
+ if(pocket_item && !(pocket_item.item_flags & ABSTRACT))
+ if(HAS_TRAIT(pocket_item, TRAIT_NODROP))
+ to_chat(usr, "You try to empty [src]'s [pocket_side] pocket, it seems to be stuck!")
+ to_chat(usr, "You try to empty [src]'s [pocket_side] pocket.")
+ else if(place_item && place_item.mob_can_equip(src, usr, pocket_id, 1) && !(place_item.item_flags & ABSTRACT))
+ to_chat(usr, "You try to place [place_item] into [src]'s [pocket_side] pocket.")
+ delay_denominator = 4
+ else
+ return
+
+ if(do_mob(usr, src, POCKET_STRIP_DELAY/delay_denominator)) //placing an item into the pocket is 4 times faster
+ if(pocket_item)
+ if(pocket_item == (pocket_id == ITEM_SLOT_RPOCKET ? r_store : l_store)) //item still in the pocket we search
+ dropItemToGround(pocket_item)
+ else
+ if(place_item)
+ if(place_item.mob_can_equip(src, usr, pocket_id, FALSE, TRUE))
+ usr.temporarilyRemoveItemFromInventory(place_item, TRUE)
+ equip_to_slot(place_item, pocket_id, TRUE)
+ //do nothing otherwise
+ //updating inv screen after handled by living/Topic()
+ else
+ // Display a warning if the user mocks up
+ to_chat(src, "You feel your [pocket_side] pocket being fumbled with!")
+
+ if(href_list["toggle_uniform"] && usr.canUseTopic(src, BE_CLOSE, NO_DEXTERITY))
+ var/obj/item/clothing/under/U = get_item_by_slot(ITEM_SLOT_ICLOTHING)
+ to_chat(src, "[usr.name] is trying to adjust your [U].")
+ if(do_mob(usr, src, U.strip_delay/2))
+ to_chat(src, "[usr.name] successfully adjusted your [U].")
+ U.toggle_jumpsuit_adjust()
+ update_inv_w_uniform()
+ update_body()
+
+
+///////HUDs///////
+ if(href_list["hud"])
+ if(!ishuman(usr))
+ return
+ var/mob/living/carbon/human/H = usr
+ var/perpname = get_face_name(get_id_name(""))
+ if(!HAS_TRAIT(H, TRAIT_SECURITY_HUD) && !HAS_TRAIT(H, TRAIT_MEDICAL_HUD))
+ return
+ var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.general)
+ if(href_list["photo_front"] || href_list["photo_side"])
+ if(!R)
+ return
+ if(!H.canUseHUD())
+ return
+ if(!HAS_TRAIT(H, TRAIT_SECURITY_HUD) && !HAS_TRAIT(H, TRAIT_MEDICAL_HUD))
+ return
+ var/obj/item/photo/P = null
+ if(href_list["photo_front"])
+ P = R.fields["photo_front"]
+ else if(href_list["photo_side"])
+ P = R.fields["photo_side"]
+ if(P)
+ P.show(H)
+ return
+
+ if(href_list["hud"] == "m")
+ if(!HAS_TRAIT(H, TRAIT_MEDICAL_HUD))
+ return
+ if(href_list["evaluation"])
+ if(!getBruteLoss() && !getFireLoss() && !getOxyLoss() && getToxLoss() < 20)
+ to_chat(usr, "No external injuries detected.
")
+ return
+ var/span = "notice"
+ var/status = ""
+ if(getBruteLoss())
+ to_chat(usr, "Physical trauma analysis:")
+ for(var/X in bodyparts)
+ var/obj/item/bodypart/BP = X
+ var/brutedamage = BP.brute_dam
+ if(brutedamage > 0)
+ status = "received minor physical injuries."
+ span = "notice"
+ if(brutedamage > 20)
+ status = "been seriously damaged."
+ span = "danger"
+ if(brutedamage > 40)
+ status = "sustained major trauma!"
+ span = "userdanger"
+ if(brutedamage)
+ to_chat(usr, "[BP] appears to have [status]")
+ if(getFireLoss())
+ to_chat(usr, "Analysis of skin burns:")
+ for(var/X in bodyparts)
+ var/obj/item/bodypart/BP = X
+ var/burndamage = BP.burn_dam
+ if(burndamage > 0)
+ status = "signs of minor burns."
+ span = "notice"
+ if(burndamage > 20)
+ status = "serious burns."
+ span = "danger"
+ if(burndamage > 40)
+ status = "major burns!"
+ span = "userdanger"
+ if(burndamage)
+ to_chat(usr, "[BP] appears to have [status]")
+ if(getOxyLoss())
+ to_chat(usr, "Patient has signs of suffocation, emergency treatment may be required!")
+ if(getToxLoss() > 20)
+ to_chat(usr, "Gathered data is inconsistent with the analysis, possible cause: poisoning.")
+ if(!H.wear_id) //You require access from here on out.
+ to_chat(H, "ERROR: Invalid access")
+ return
+ var/list/access = H.wear_id.GetAccess()
+ if(!(ACCESS_MEDICAL in access))
+ to_chat(H, "ERROR: Invalid access")
+ return
+ if(href_list["p_stat"])
+ var/health_status = input(usr, "Specify a new physical status for this person.", "Medical HUD", R.fields["p_stat"]) in list("Active", "Physically Unfit", "*Unconscious*", "*Deceased*", "Cancel")
+ if(!R)
+ return
+ if(!H.canUseHUD())
+ return
+ if(!HAS_TRAIT(H, TRAIT_MEDICAL_HUD))
+ return
+ if(health_status && health_status != "Cancel")
+ R.fields["p_stat"] = health_status
+ return
+ if(href_list["m_stat"])
+ var/health_status = input(usr, "Specify a new mental status for this person.", "Medical HUD", R.fields["m_stat"]) in list("Stable", "*Watch*", "*Unstable*", "*Insane*", "Cancel")
+ if(!R)
+ return
+ if(!H.canUseHUD())
+ return
+ if(!HAS_TRAIT(H, TRAIT_MEDICAL_HUD))
+ return
+ if(health_status && health_status != "Cancel")
+ R.fields["m_stat"] = health_status
+ return
+ return //Medical HUD ends here.
+
+ if(href_list["hud"] == "s")
+ if(!HAS_TRAIT(H, TRAIT_SECURITY_HUD))
+ return
+ if(usr.stat || usr == src) //|| !usr.canmove || usr.restrained()) Fluff: Sechuds have eye-tracking technology and sets 'arrest' to people that the wearer looks and blinks at.
+ return //Non-fluff: This allows sec to set people to arrest as they get disarmed or beaten
+ // Checks the user has security clearence before allowing them to change arrest status via hud, comment out to enable all access
+ var/allowed_access = null
+ var/obj/item/clothing/glasses/hud/security/G = H.glasses
+ if(istype(G) && (G.obj_flags & EMAGGED))
+ allowed_access = "@%&ERROR_%$*"
+ else //Implant and standard glasses check access
+ if(H.wear_id)
+ var/list/access = H.wear_id.GetAccess()
+ if(ACCESS_SEC_DOORS in access)
+ allowed_access = H.get_authentification_name()
+
+ if(!allowed_access)
+ to_chat(H, "ERROR: Invalid access.")
+ return
+
+ if(!perpname)
+ to_chat(H, "ERROR: Can not identify target.")
+ return
+ R = find_record("name", perpname, GLOB.data_core.security)
+ if(!R)
+ to_chat(usr, "ERROR: Unable to locate data core entry for target.")
+ return
+ if(href_list["status"])
+ var/setcriminal = input(usr, "Specify a new criminal status for this person.", "Security HUD", R.fields["criminal"]) in list("None", "*Arrest*", "Incarcerated", "Paroled", "Discharged", "Cancel")
+ if(setcriminal != "Cancel")
+ if(!R)
+ return
+ if(!H.canUseHUD())
+ return
+ if(!HAS_TRAIT(H, TRAIT_SECURITY_HUD))
+ return
+ investigate_log("[key_name(src)] has been set from [R.fields["criminal"]] to [setcriminal] by [key_name(usr)].", INVESTIGATE_RECORDS)
+ R.fields["criminal"] = setcriminal
+ sec_hud_set_security_status()
+ return
+
+ if(href_list["view"])
+ if(!H.canUseHUD())
+ return
+ if(!HAS_TRAIT(H, TRAIT_SECURITY_HUD))
+ return
+ to_chat(usr, "Name: [R.fields["name"]] Criminal Status: [R.fields["criminal"]]")
+ to_chat(usr, "Minor Crimes:")
+ for(var/datum/data/crime/c in R.fields["mi_crim"])
+ to_chat(usr, "Crime: [c.crimeName]")
+ to_chat(usr, "Details: [c.crimeDetails]")
+ to_chat(usr, "Added by [c.author] at [c.time]")
+ to_chat(usr, "----------")
+ to_chat(usr, "Major Crimes:")
+ for(var/datum/data/crime/c in R.fields["ma_crim"])
+ to_chat(usr, "Crime: [c.crimeName]")
+ to_chat(usr, "Details: [c.crimeDetails]")
+ to_chat(usr, "Added by [c.author] at [c.time]")
+ to_chat(usr, "----------")
+ to_chat(usr, "Notes: [R.fields["notes"]]")
+ return
+
+ if(href_list["add_citation"])
+ var/maxFine = CONFIG_GET(number/maxfine)
+ var/t1 = stripped_input("Please input citation crime:", "Security HUD", "", null)
+ var/fine = FLOOR(input("Please input citation fine, up to [maxFine]:", "Security HUD", 50) as num|null, 1)
+ if(!R || !t1 || !fine || !allowed_access)
+ return
+ if(!H.canUseHUD())
+ return
+ if(!HAS_TRAIT(H, TRAIT_SECURITY_HUD))
+ return
+ if(fine < 0)
+ to_chat(usr, "You're pretty sure that's not how money works.")
+ return
+ fine = min(fine, maxFine)
+
+ var/crime = GLOB.data_core.createCrimeEntry(t1, "", allowed_access, station_time_timestamp(), fine)
+ for (var/obj/item/pda/P in GLOB.PDAs)
+ if(P.owner == R.fields["name"])
+ var/message = "You have been fined [fine] credits for '[t1]'. Fines may be paid at security."
+ var/datum/signal/subspace/messaging/pda/signal = new(src, list(
+ "name" = "Security Citation",
+ "job" = "Citation Server",
+ "message" = message,
+ "targets" = list("[P.owner] ([P.ownjob])"),
+ "automated" = 1
+ ))
+ signal.send_to_receivers()
+ usr.log_message("(PDA: Citation Server) sent \"[message]\" to [signal.format_target()]", LOG_PDA)
+ GLOB.data_core.addCitation(R.fields["id"], crime)
+ investigate_log("New Citation: [t1] Fine: [fine] | Added to [R.fields["name"]] by [key_name(usr)]", INVESTIGATE_RECORDS)
+ return
+
+ if(href_list["add_crime"])
+ switch(alert("What crime would you like to add?","Security HUD","Minor Crime","Major Crime","Cancel"))
+ if("Minor Crime")
+ var/t1 = stripped_input("Please input minor crime names:", "Security HUD", "", null)
+ var/t2 = stripped_multiline_input("Please input minor crime details:", "Security HUD", "", null)
+ if(!R || !t1 || !t2 || !allowed_access)
+ return
+ if(!H.canUseHUD())
+ return
+ if(!HAS_TRAIT(H, TRAIT_SECURITY_HUD))
+ return
+ var/crime = GLOB.data_core.createCrimeEntry(t1, t2, allowed_access, station_time_timestamp())
+ GLOB.data_core.addMinorCrime(R.fields["id"], crime)
+ investigate_log("New Minor Crime: [t1]: [t2] | Added to [R.fields["name"]] by [key_name(usr)]", INVESTIGATE_RECORDS)
+ to_chat(usr, "Successfully added a minor crime.")
+ return
+ if("Major Crime")
+ var/t1 = stripped_input("Please input major crime names:", "Security HUD", "", null)
+ var/t2 = stripped_multiline_input("Please input major crime details:", "Security HUD", "", null)
+ if(!R || !t1 || !t2 || !allowed_access)
+ return
+ if(!H.canUseHUD())
+ return
+ if(!HAS_TRAIT(H, TRAIT_SECURITY_HUD))
+ return
+ var/crime = GLOB.data_core.createCrimeEntry(t1, t2, allowed_access, station_time_timestamp())
+ GLOB.data_core.addMajorCrime(R.fields["id"], crime)
+ investigate_log("New Major Crime: [t1]: [t2] | Added to [R.fields["name"]] by [key_name(usr)]", INVESTIGATE_RECORDS)
+ to_chat(usr, "Successfully added a major crime.")
+ return
+
+ if(href_list["view_comment"])
+ if(!H.canUseHUD())
+ return
+ if(!HAS_TRAIT(H, TRAIT_SECURITY_HUD))
+ return
+ to_chat(usr, "Comments/Log:")
+ var/counter = 1
+ while(R.fields[text("com_[]", counter)])
+ to_chat(usr, R.fields[text("com_[]", counter)])
+ to_chat(usr, "----------")
+ counter++
+ return
+
+ if(href_list["add_comment"])
+ var/t1 = stripped_multiline_input("Add Comment:", "Secure. records", null, null)
+ if (!R || !t1 || !allowed_access)
+ return
+ if(!H.canUseHUD())
+ return
+ if(!HAS_TRAIT(H, TRAIT_SECURITY_HUD))
+ return
+ var/counter = 1
+ while(R.fields[text("com_[]", counter)])
+ counter++
+ R.fields[text("com_[]", counter)] = text("Made by [] on [] [], []
[]", allowed_access, station_time_timestamp(), time2text(world.realtime, "MMM DD"), GLOB.year_integer+540, t1)
+ to_chat(usr, "Successfully added comment.")
+ return
+
+ ..() //end of this massive fucking chain. TODO: make the hud chain not spooky. - Yeah, great job doing that.
+
+
+/mob/living/carbon/human/proc/canUseHUD()
+ return (mobility_flags & MOBILITY_USE)
+
+/mob/living/carbon/human/can_inject(mob/user, error_msg, target_zone, penetrate_thick = 0)
+ . = 1 // Default to returning true.
+ if(user && !target_zone)
+ target_zone = user.zone_selected
+ if(HAS_TRAIT(src, TRAIT_PIERCEIMMUNE))
+ . = 0
+ // If targeting the head, see if the head item is thin enough.
+ // If targeting anything else, see if the wear suit is thin enough.
+ if (!penetrate_thick)
+ if(above_neck(target_zone))
+ if(head && istype(head, /obj/item/clothing))
+ var/obj/item/clothing/CH = head
+ if (CH.clothing_flags & THICKMATERIAL)
+ . = 0
+ else
+ if(wear_suit && istype(wear_suit, /obj/item/clothing))
+ var/obj/item/clothing/CS = wear_suit
+ if (CS.clothing_flags & THICKMATERIAL)
+ . = 0
+ if(!. && error_msg && user)
+ // Might need re-wording.
+ to_chat(user, "There is no exposed flesh or thin material [above_neck(target_zone) ? "on [p_their()] head" : "on [p_their()] body"].")
+
+/mob/living/carbon/human/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null)
+ if(judgement_criteria & JUDGE_EMAGGED)
+ return 10 //Everyone is a criminal!
+
+ var/threatcount = 0
+
+ //Lasertag bullshit
+ if(lasercolor)
+ if(lasercolor == "b")//Lasertag turrets target the opposing team, how great is that? -Sieve
+ if(istype(wear_suit, /obj/item/clothing/suit/redtag))
+ threatcount += 4
+ if(is_holding_item_of_type(/obj/item/gun/energy/laser/redtag))
+ threatcount += 4
+ if(istype(belt, /obj/item/gun/energy/laser/redtag))
+ threatcount += 2
+
+ if(lasercolor == "r")
+ if(istype(wear_suit, /obj/item/clothing/suit/bluetag))
+ threatcount += 4
+ if(is_holding_item_of_type(/obj/item/gun/energy/laser/bluetag))
+ threatcount += 4
+ if(istype(belt, /obj/item/gun/energy/laser/bluetag))
+ threatcount += 2
+
+ return threatcount
+
+ //Check for ID
+ var/obj/item/card/id/idcard = get_idcard(FALSE)
+ if( (judgement_criteria & JUDGE_IDCHECK) && !idcard && name=="Unknown")
+ threatcount += 4
+
+ //Check for weapons
+ if( (judgement_criteria & JUDGE_WEAPONCHECK) && weaponcheck)
+ if(!idcard || !(ACCESS_WEAPONS in idcard.access))
+ for(var/obj/item/I in held_items) //if they're holding a gun
+ if(weaponcheck.Invoke(I))
+ threatcount += 4
+ if(weaponcheck.Invoke(belt) || weaponcheck.Invoke(back)) //if a weapon is present in the belt or back slot
+ threatcount += 2 //not enough to trigger look_for_perp() on it's own unless they also have criminal status.
+
+ //Check for arrest warrant
+ if(judgement_criteria & JUDGE_RECORDCHECK)
+ var/perpname = get_face_name(get_id_name())
+ var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.security)
+ if(R && R.fields["criminal"])
+ switch(R.fields["criminal"])
+ if("*Arrest*")
+ threatcount += 5
+ if("Incarcerated")
+ threatcount += 2
+ if("Paroled")
+ threatcount += 2
+
+ //Check for dresscode violations
+ if(istype(head, /obj/item/clothing/head/wizard) || istype(head, /obj/item/clothing/head/helmet/space/hardsuit/wizard))
+ threatcount += 2
+
+ //Check for nonhuman scum
+ if(dna && dna.species.id && dna.species.id != "human")
+ threatcount += 1
+
+ //mindshield implants imply trustworthyness
+ if(HAS_TRAIT(src, TRAIT_MINDSHIELD))
+ threatcount -= 1
+
+ //Agent cards lower threatlevel.
+ if(istype(idcard, /obj/item/card/id/syndicate))
+ threatcount -= 5
+
+ return threatcount
+
+
+//Used for new human mobs created by cloning/goleming/podding
+/mob/living/carbon/human/proc/set_cloned_appearance()
+ if(gender == MALE)
+ facial_hairstyle = "Full Beard"
+ else
+ facial_hairstyle = "Shaved"
+ hairstyle = pick("Bedhead", "Bedhead 2", "Bedhead 3")
+ underwear = "Nude"
+ update_body()
+ update_hair()
+
+/mob/living/carbon/human/singularity_pull(S, current_size)
+ ..()
+ if(current_size >= STAGE_THREE)
+ for(var/obj/item/hand in held_items)
+ if(prob(current_size * 5) && hand.w_class >= ((11-current_size)/2) && dropItemToGround(hand))
+ step_towards(hand, src)
+ to_chat(src, "\The [S] pulls \the [hand] from your grip!")
+ rad_act(current_size * 3)
+
+/mob/living/carbon/human/proc/do_cpr(mob/living/carbon/C)
+ CHECK_DNA_AND_SPECIES(C)
+
+ if(C.stat == DEAD || (HAS_TRAIT(C, TRAIT_FAKEDEATH)))
+ to_chat(src, "[C.name] is dead!")
+ return
+ if(is_mouth_covered())
+ to_chat(src, "Remove your mask first!")
+ return 0
+ if(C.is_mouth_covered())
+ to_chat(src, "Remove [p_their()] mask first!")
+ return 0
+
+ if(C.cpr_time < world.time + 30)
+ visible_message("[src] is trying to perform CPR on [C.name]!", \
+ "You try to perform CPR on [C.name]... Hold still!")
+ if(!do_mob(src, C))
+ to_chat(src, "You fail to perform CPR on [C]!")
+ return 0
+
+ var/they_breathe = !HAS_TRAIT(C, TRAIT_NOBREATH)
+ var/they_lung = C.getorganslot(ORGAN_SLOT_LUNGS)
+
+ if(C.health > C.crit_threshold)
+ return
+
+ src.visible_message("[src] performs CPR on [C.name]!", "You perform CPR on [C.name].")
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "perform_cpr", /datum/mood_event/perform_cpr)
+ C.cpr_time = world.time
+ log_combat(src, C, "CPRed")
+
+ if(they_breathe && they_lung)
+ var/suff = min(C.getOxyLoss(), 7)
+ C.adjustOxyLoss(-suff)
+ C.updatehealth()
+ to_chat(C, "You feel a breath of fresh air enter your lungs... It feels good...")
+ else if(they_breathe && !they_lung)
+ to_chat(C, "You feel a breath of fresh air... but you don't feel any better...")
+ else
+ to_chat(C, "You feel a breath of fresh air... which is a sensation you don't recognise...")
+
+/mob/living/carbon/human/cuff_resist(obj/item/I)
+ if(dna && dna.check_mutation(HULK))
+ say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ), forced = "hulk")
+ if(..(I, cuff_break = FAST_CUFFBREAK))
+ dropItemToGround(I)
+ else
+ if(..())
+ dropItemToGround(I)
+
+/mob/living/carbon/human/proc/clean_blood(datum/source, strength)
+ if(strength < CLEAN_STRENGTH_BLOOD)
+ return
+ if(gloves)
+ if(SEND_SIGNAL(gloves, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD))
+ update_inv_gloves()
+ else
+ if(bloody_hands)
+ bloody_hands = 0
+ update_inv_gloves()
+
+//Turns a mob black, flashes a skeleton overlay
+//Just like a cartoon!
+/mob/living/carbon/human/proc/electrocution_animation(anim_duration)
+ //Handle mutant parts if possible
+ if(dna && dna.species)
+ add_atom_colour("#000000", TEMPORARY_COLOUR_PRIORITY)
+ var/static/mutable_appearance/electrocution_skeleton_anim
+ if(!electrocution_skeleton_anim)
+ electrocution_skeleton_anim = mutable_appearance(icon, "electrocuted_base")
+ electrocution_skeleton_anim.appearance_flags |= RESET_COLOR|KEEP_APART
+ add_overlay(electrocution_skeleton_anim)
+ addtimer(CALLBACK(src, .proc/end_electrocution_animation, electrocution_skeleton_anim), anim_duration)
+
+ else //or just do a generic animation
+ flick_overlay_view(image(icon,src,"electrocuted_generic",ABOVE_MOB_LAYER), src, anim_duration)
+
+/mob/living/carbon/human/proc/end_electrocution_animation(mutable_appearance/MA)
+ remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, "#000000")
+ cut_overlay(MA)
+
+/mob/living/carbon/human/canUseTopic(atom/movable/M, be_close=FALSE, no_dexterity=FALSE, no_tk=FALSE)
+ if(!(mobility_flags & MOBILITY_UI))
+ to_chat(src, "You can't do that right now!")
+ return FALSE
+ if(!Adjacent(M) && (M.loc != src))
+ if((be_close == FALSE) || (!no_tk && (dna.check_mutation(TK) && tkMaxRangeCheck(src, M))))
+ return TRUE
+ to_chat(src, "You are too far away!")
+ return FALSE
+ return TRUE
+
+/mob/living/carbon/human/resist_restraints()
+ if(wear_suit && wear_suit.breakouttime)
+ changeNext_move(CLICK_CD_BREAKOUT)
+ last_special = world.time + CLICK_CD_BREAKOUT
+ cuff_resist(wear_suit)
+ else
+ ..()
+
+/mob/living/carbon/human/clear_cuffs(obj/item/I, cuff_break)
+ . = ..()
+ if(.)
+ return
+ if(!I.loc || buckled)
+ return FALSE
+ if(I == wear_suit)
+ visible_message("[src] manages to [cuff_break ? "break" : "remove"] [I]!")
+ to_chat(src, "You successfully [cuff_break ? "break" : "remove"] [I].")
+ return TRUE
+
+/mob/living/carbon/human/replace_records_name(oldname,newname) // Only humans have records right now, move this up if changed.
+ for(var/list/L in list(GLOB.data_core.general,GLOB.data_core.medical,GLOB.data_core.security,GLOB.data_core.locked))
+ var/datum/data/record/R = find_record("name", oldname, L)
+ if(R)
+ R.fields["name"] = newname
+
+/mob/living/carbon/human/get_total_tint()
+ . = ..()
+ if(glasses)
+ . += glasses.tint
+
+/mob/living/carbon/human/update_health_hud()
+ if(!client || !hud_used)
+ return
+ if(dna.species.update_health_hud())
+ return
+ else
+ if(hud_used.healths)
+ var/health_amount = min(health, maxHealth - getStaminaLoss())
+ if(..(health_amount)) //not dead
+ switch(hal_screwyhud)
+ if(SCREWYHUD_CRIT)
+ hud_used.healths.icon_state = "health6"
+ if(SCREWYHUD_DEAD)
+ hud_used.healths.icon_state = "health7"
+ if(SCREWYHUD_HEALTHY)
+ hud_used.healths.icon_state = "health0"
+ if(hud_used.healthdoll)
+ hud_used.healthdoll.cut_overlays()
+ if(stat != DEAD)
+ hud_used.healthdoll.icon_state = "healthdoll_OVERLAY"
+ for(var/X in bodyparts)
+ var/obj/item/bodypart/BP = X
+ var/damage = BP.burn_dam + BP.brute_dam
+ var/comparison = (BP.max_damage/5)
+ var/icon_num = 0
+ if(damage)
+ icon_num = 1
+ if(damage > (comparison))
+ icon_num = 2
+ if(damage > (comparison*2))
+ icon_num = 3
+ if(damage > (comparison*3))
+ icon_num = 4
+ if(damage > (comparison*4))
+ icon_num = 5
+ if(hal_screwyhud == SCREWYHUD_HEALTHY)
+ icon_num = 0
+ if(icon_num)
+ hud_used.healthdoll.add_overlay(mutable_appearance('icons/mob/screen_gen.dmi', "[BP.body_zone][icon_num]"))
+ for(var/t in get_missing_limbs()) //Missing limbs
+ hud_used.healthdoll.add_overlay(mutable_appearance('icons/mob/screen_gen.dmi', "[t]6"))
+ for(var/t in get_disabled_limbs()) //Disabled limbs
+ hud_used.healthdoll.add_overlay(mutable_appearance('icons/mob/screen_gen.dmi', "[t]7"))
+ else
+ hud_used.healthdoll.icon_state = "healthdoll_DEAD"
+
+/mob/living/carbon/human/fully_heal(admin_revive = FALSE)
+ dna?.species.spec_fully_heal(src)
+ if(admin_revive)
+ regenerate_limbs()
+ regenerate_organs()
+ remove_all_embedded_objects()
+ set_heartattack(FALSE)
+ drunkenness = 0
+ for(var/datum/mutation/human/HM in dna.mutations)
+ if(HM.quality != POSITIVE)
+ dna.remove_mutation(HM.name)
+ ..()
+
+/mob/living/carbon/human/check_weakness(obj/item/weapon, mob/living/attacker)
+ . = ..()
+ if (dna && dna.species)
+ . += dna.species.check_species_weakness(weapon, attacker)
+
+/mob/living/carbon/human/is_literate()
+ return TRUE
+
+/mob/living/carbon/human/can_hold_items()
+ return TRUE
+
+/mob/living/carbon/human/update_gravity(has_gravity,override = 0)
+ if(dna && dna.species) //prevents a runtime while a human is being monkeyfied
+ override = dna.species.override_float
+ ..()
+
+/mob/living/carbon/human/vomit(lost_nutrition = 10, blood = FALSE, stun = TRUE, distance = 1, message = TRUE, toxic = FALSE, harm = TRUE, force = FALSE, purge = FALSE)
+ if(blood && (NOBLOOD in dna.species.species_traits) && !HAS_TRAIT(src, TRAIT_TOXINLOVER))
+ if(message)
+ visible_message("[src] dry heaves!", \
+ "You try to throw up, but there's nothing in your stomach!")
+ if(stun)
+ Paralyze(200)
+ return 1
+ ..()
+
+/mob/living/carbon/human/vv_get_dropdown()
+ . = ..()
+ VV_DROPDOWN_OPTION("", "---------")
+ VV_DROPDOWN_OPTION(VV_HK_COPY_OUTFIT, "Copy Outfit")
+ VV_DROPDOWN_OPTION(VV_HK_MOD_MUTATIONS, "Add/Remove Mutation")
+ VV_DROPDOWN_OPTION(VV_HK_MOD_QUIRKS, "Add/Remove Quirks")
+ VV_DROPDOWN_OPTION(VV_HK_MAKE_MONKEY, "Make Monkey")
+ VV_DROPDOWN_OPTION(VV_HK_MAKE_CYBORG, "Make Cyborg")
+ VV_DROPDOWN_OPTION(VV_HK_MAKE_SLIME, "Make Slime")
+ VV_DROPDOWN_OPTION(VV_HK_MAKE_ALIEN, "Make Alien")
+ VV_DROPDOWN_OPTION(VV_HK_SET_SPECIES, "Set Species")
+ VV_DROPDOWN_OPTION(VV_HK_PURRBATION, "Toggle Purrbation")
+
+/mob/living/carbon/human/vv_do_topic(list/href_list)
+ . = ..()
+ if(href_list[VV_HK_COPY_OUTFIT])
+ if(!check_rights(R_SPAWN))
+ return
+ copy_outfit()
+ if(href_list[VV_HK_MOD_MUTATIONS])
+ if(!check_rights(R_SPAWN))
+ return
+
+ var/list/options = list("Clear"="Clear")
+ for(var/x in subtypesof(/datum/mutation/human))
+ var/datum/mutation/human/mut = x
+ var/name = initial(mut.name)
+ options[dna.check_mutation(mut) ? "[name] (Remove)" : "[name] (Add)"] = mut
+
+ var/result = input(usr, "Choose mutation to add/remove","Mutation Mod") as null|anything in sortList(options)
+ if(result)
+ if(result == "Clear")
+ dna.remove_all_mutations()
+ else
+ var/mut = options[result]
+ if(dna.check_mutation(mut))
+ dna.remove_mutation(mut)
+ else
+ dna.add_mutation(mut)
+ if(href_list[VV_HK_MOD_QUIRKS])
+ if(!check_rights(R_SPAWN))
+ return
+
+ var/list/options = list("Clear"="Clear")
+ for(var/x in subtypesof(/datum/quirk))
+ var/datum/quirk/T = x
+ var/qname = initial(T.name)
+ options[has_quirk(T) ? "[qname] (Remove)" : "[qname] (Add)"] = T
+
+ var/result = input(usr, "Choose quirk to add/remove","Quirk Mod") as null|anything in sortList(options)
+ if(result)
+ if(result == "Clear")
+ for(var/datum/quirk/q in roundstart_quirks)
+ remove_quirk(q.type)
+ else
+ var/T = options[result]
+ if(has_quirk(T))
+ remove_quirk(T)
+ else
+ add_quirk(T,TRUE)
+ if(href_list[VV_HK_MAKE_MONKEY])
+ if(!check_rights(R_SPAWN))
+ return
+ if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform")
+ return
+ usr.client.holder.Topic("vv_override", list("monkeyone"=href_list[VV_HK_TARGET]))
+ if(href_list[VV_HK_MAKE_CYBORG])
+ if(!check_rights(R_SPAWN))
+ return
+ if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform")
+ return
+ usr.client.holder.Topic("vv_override", list("makerobot"=href_list[VV_HK_TARGET]))
+ if(href_list[VV_HK_MAKE_ALIEN])
+ if(!check_rights(R_SPAWN))
+ return
+ if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform")
+ return
+ usr.client.holder.Topic("vv_override", list("makealien"=href_list[VV_HK_TARGET]))
+ if(href_list[VV_HK_MAKE_SLIME])
+ if(!check_rights(R_SPAWN))
+ return
+ if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform")
+ return
+ usr.client.holder.Topic("vv_override", list("makeslime"=href_list[VV_HK_TARGET]))
+ if(href_list[VV_HK_SET_SPECIES])
+ if(!check_rights(R_SPAWN))
+ return
+ var/result = input(usr, "Please choose a new species","Species") as null|anything in GLOB.species_list
+ if(result)
+ var/newtype = GLOB.species_list[result]
+ admin_ticket_log("[key_name_admin(usr)] has modified the bodyparts of [src] to [result]")
+ set_species(newtype)
+ if(href_list[VV_HK_PURRBATION])
+ if(!check_rights(R_SPAWN))
+ return
+ if(!ishumanbasic(src))
+ to_chat(usr, "This can only be done to the basic human species at the moment.")
+ return
+ var/success = purrbation_toggle(src)
+ if(success)
+ to_chat(usr, "Put [src] on purrbation.")
+ log_admin("[key_name(usr)] has put [key_name(src)] on purrbation.")
+ var/msg = "[key_name_admin(usr)] has put [key_name(src)] on purrbation."
+ message_admins(msg)
+ admin_ticket_log(src, msg)
+
+ else
+ to_chat(usr, "Removed [src] from purrbation.")
+ log_admin("[key_name(usr)] has removed [key_name(src)] from purrbation.")
+ var/msg = "[key_name_admin(usr)] has removed [key_name(src)] from purrbation."
+ message_admins(msg)
+ admin_ticket_log(src, msg)
+
+/mob/living/carbon/human/MouseDrop_T(mob/living/target, mob/living/user)
+ if(pulling == target && grab_state >= GRAB_AGGRESSIVE && stat == CONSCIOUS)
+ //If they dragged themselves and we're currently aggressively grabbing them try to piggyback
+ if(user == target && can_piggyback(target))
+ piggyback(target)
+ return
+ //If you dragged them to you and you're aggressively grabbing try to fireman carry them
+ else if(user != target && can_be_firemanned(target))
+ fireman_carry(target)
+ return
+ . = ..()
+
+//src is the user that will be carrying, target is the mob to be carried
+/mob/living/carbon/human/proc/can_piggyback(mob/living/carbon/target)
+ return (istype(target) && target.stat == CONSCIOUS)
+
+/mob/living/carbon/human/proc/can_be_firemanned(mob/living/carbon/target)
+ return (ishuman(target) && !(target.mobility_flags & MOBILITY_STAND))
+
+/mob/living/carbon/human/proc/fireman_carry(mob/living/carbon/target)
+ var/carrydelay = 50 //if you have latex you are faster at grabbing
+ var/skills_space = "" //cobby told me to do this
+ if(HAS_TRAIT(src, TRAIT_QUICKER_CARRY))
+ carrydelay = 30
+ skills_space = "expertly"
+ else if(HAS_TRAIT(src, TRAIT_QUICK_CARRY))
+ carrydelay = 40
+ skills_space = "quickly"
+ if(can_be_firemanned(target) && !incapacitated(FALSE, TRUE))
+ visible_message("[src] starts [skills_space] lifting [target] onto their back..",
+ //Joe Medic starts quickly/expertly lifting Grey Tider onto their back..
+ "[carrydelay < 35 ? "Using your gloves' nanochips, you" : "You"] [skills_space] start to lift [target] onto your back[carrydelay == 40 ? ", while assisted by the nanochips in your gloves.." : "..."]")
+ //(Using your gloves' nanochips, you/You) ( /quickly/expertly) start to lift Grey Tider onto your back(, while assisted by the nanochips in your gloves../...)
+ if(do_after(src, carrydelay, TRUE, target))
+ //Second check to make sure they're still valid to be carried
+ if(can_be_firemanned(target) && !incapacitated(FALSE, TRUE))
+ buckle_mob(target, TRUE, TRUE, 90, 1, 0)
+ return
+ visible_message("[src] fails to fireman carry [target]!")
+ else
+ to_chat(src, "You can't fireman carry [target] while they're standing!")
+
+/mob/living/carbon/human/proc/piggyback(mob/living/carbon/target)
+ if(can_piggyback(target))
+ visible_message("[target] starts to climb onto [src]...")
+ if(do_after(target, 15, target = src))
+ if(can_piggyback(target))
+ if(target.incapacitated(FALSE, TRUE) || incapacitated(FALSE, TRUE))
+ target.visible_message("[target] can't hang onto [src]!")
+ return
+ buckle_mob(target, TRUE, TRUE, FALSE, 0, 2)
+ else
+ visible_message("[target] fails to climb onto [src]!")
+ else
+ to_chat(target, "You can't piggyback ride [src] right now!")
+
+/mob/living/carbon/human/buckle_mob(mob/living/target, force = FALSE, check_loc = TRUE, lying_buckle = FALSE, hands_needed = 0, target_hands_needed = 0)
+ if(!force)//humans are only meant to be ridden through piggybacking and special cases
+ return
+ if(!is_type_in_typecache(target, can_ride_typecache))
+ target.visible_message("[target] really can't seem to mount [src]...")
+ return
+ buckle_lying = lying_buckle
+ var/datum/component/riding/human/riding_datum = LoadComponent(/datum/component/riding/human)
+ if(target_hands_needed)
+ riding_datum.ride_check_rider_restrained = TRUE
+ if(buckled_mobs && ((target in buckled_mobs) || (buckled_mobs.len >= max_buckled_mobs)) || buckled)
+ return
+ var/equipped_hands_self
+ var/equipped_hands_target
+ if(hands_needed)
+ equipped_hands_self = riding_datum.equip_buckle_inhands(src, hands_needed, target)
+ if(target_hands_needed)
+ equipped_hands_target = riding_datum.equip_buckle_inhands(target, target_hands_needed)
+
+ if(hands_needed || target_hands_needed)
+ if(hands_needed && !equipped_hands_self)
+ src.visible_message("[src] can't get a grip on [target] because their hands are full!",
+ "You can't get a grip on [target] because your hands are full!")
+ return
+ else if(target_hands_needed && !equipped_hands_target)
+ target.visible_message("[target] can't get a grip on [src] because their hands are full!",
+ "You can't get a grip on [src] because your hands are full!")
+ return
+
+ stop_pulling()
+ riding_datum.handle_vehicle_layer()
+ . = ..(target, force, check_loc)
+
+/mob/living/carbon/human/proc/is_shove_knockdown_blocked() //If you want to add more things that block shove knockdown, extend this
+ var/list/body_parts = list(head, wear_mask, wear_suit, w_uniform, back, gloves, shoes, belt, s_store, glasses, ears, wear_id) //Everything but pockets. Pockets are l_store and r_store. (if pockets were allowed, putting something armored, gloves or hats for example, would double up on the armor)
+ for(var/bp in body_parts)
+ if(istype(bp, /obj/item/clothing))
+ var/obj/item/clothing/C = bp
+ if(C.clothing_flags & BLOCKS_SHOVE_KNOCKDOWN)
+ return TRUE
+ return FALSE
+
+/mob/living/carbon/human/proc/clear_shove_slowdown()
+ remove_movespeed_modifier(/datum/movespeed_modifier/shove)
+ var/active_item = get_active_held_item()
+ if(is_type_in_typecache(active_item, GLOB.shove_disarming_types))
+ visible_message("[src.name] regains their grip on \the [active_item]!", "You regain your grip on \the [active_item]", null, COMBAT_MESSAGE_RANGE)
+
+/mob/living/carbon/human/do_after_coefficent()
+ . = ..()
+ . *= physiology.do_after_speed
+
+/mob/living/carbon/human/updatehealth()
+ . = ..()
+ dna?.species.spec_updatehealth(src)
+ if(HAS_TRAIT(src, TRAIT_IGNOREDAMAGESLOWDOWN))
+ remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown)
+ remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying)
+ return
+ var/health_deficiency = max((maxHealth - health), staminaloss)
+ if(health_deficiency >= 40)
+ add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown, TRUE, multiplicative_slowdown = health_deficiency / 75)
+ add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying, TRUE, multiplicative_slowdown = health_deficiency / 25)
+ else
+ remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown)
+ remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying)
+
+/mob/living/carbon/human/washed(var/atom/washer)
+ . = ..()
+ if(wear_suit)
+ update_inv_wear_suit()
+ else if(w_uniform && w_uniform.washed(washer))
+ update_inv_w_uniform()
+
+ if(!is_mouth_covered())
+ lip_style = null
+ update_body()
+ if(belt && belt.washed(washer))
+ update_inv_belt()
+
+ var/list/obscured = check_obscured_slots()
+
+ if(gloves && !(HIDEGLOVES in obscured) && gloves.washed(washer))
+ SEND_SIGNAL(src, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
+
+/mob/living/carbon/human/adjust_nutrition(change) //Honestly FUCK the oldcoders for putting nutrition on /mob someone else can move it up because holy hell I'd have to fix SO many typechecks
+ if(HAS_TRAIT(src, TRAIT_NOHUNGER))
+ return FALSE
+ return ..()
+
+/mob/living/carbon/human/set_nutrition(change) //Seriously fuck you oldcoders.
+ if(HAS_TRAIT(src, TRAIT_NOHUNGER))
+ return FALSE
+ return ..()
+
+/mob/living/carbon/human/species
+ var/race = null
+
+/mob/living/carbon/human/species/Initialize()
+ . = ..()
+ set_species(race)
+
+/mob/living/carbon/human/species/abductor
+ race = /datum/species/abductor
+
+/mob/living/carbon/human/species/android
+ race = /datum/species/android
+
+/mob/living/carbon/human/species/corporate
+ race = /datum/species/corporate
+
+/mob/living/carbon/human/species/dullahan
+ race = /datum/species/dullahan
+
+/mob/living/carbon/human/species/felinid
+ race = /datum/species/human/felinid
+
+/mob/living/carbon/human/species/fly
+ race = /datum/species/fly
+
+/mob/living/carbon/human/species/golem
+ race = /datum/species/golem
+
+/mob/living/carbon/human/species/golem/random
+ race = /datum/species/golem/random
+
+/mob/living/carbon/human/species/golem/adamantine
+ race = /datum/species/golem/adamantine
+
+/mob/living/carbon/human/species/golem/plasma
+ race = /datum/species/golem/plasma
+
+/mob/living/carbon/human/species/golem/diamond
+ race = /datum/species/golem/diamond
+
+/mob/living/carbon/human/species/golem/gold
+ race = /datum/species/golem/gold
+
+/mob/living/carbon/human/species/golem/silver
+ race = /datum/species/golem/silver
+
+/mob/living/carbon/human/species/golem/plasteel
+ race = /datum/species/golem/plasteel
+
+/mob/living/carbon/human/species/golem/titanium
+ race = /datum/species/golem/titanium
+
+/mob/living/carbon/human/species/golem/plastitanium
+ race = /datum/species/golem/plastitanium
+
+/mob/living/carbon/human/species/golem/alien_alloy
+ race = /datum/species/golem/alloy
+
+/mob/living/carbon/human/species/golem/wood
+ race = /datum/species/golem/wood
+
+/mob/living/carbon/human/species/golem/uranium
+ race = /datum/species/golem/uranium
+
+/mob/living/carbon/human/species/golem/sand
+ race = /datum/species/golem/sand
+
+/mob/living/carbon/human/species/golem/glass
+ race = /datum/species/golem/glass
+
+/mob/living/carbon/human/species/golem/bluespace
+ race = /datum/species/golem/bluespace
+
+/mob/living/carbon/human/species/golem/bananium
+ race = /datum/species/golem/bananium
+
+/mob/living/carbon/human/species/golem/blood_cult
+ race = /datum/species/golem/runic
+
+/mob/living/carbon/human/species/golem/cloth
+ race = /datum/species/golem/cloth
+
+/mob/living/carbon/human/species/golem/plastic
+ race = /datum/species/golem/plastic
+
+/mob/living/carbon/human/species/golem/bronze
+ race = /datum/species/golem/bronze
+
+/mob/living/carbon/human/species/golem/cardboard
+ race = /datum/species/golem/cardboard
+
+/mob/living/carbon/human/species/golem/leather
+ race = /datum/species/golem/leather
+
+/mob/living/carbon/human/species/golem/bone
+ race = /datum/species/golem/bone
+
+/mob/living/carbon/human/species/golem/durathread
+ race = /datum/species/golem/durathread
+
+/mob/living/carbon/human/species/golem/snow
+ race = /datum/species/golem/snow
+
+/mob/living/carbon/human/species/golem/capitalist
+ race = /datum/species/golem/capitalist
+
+/mob/living/carbon/human/species/golem/soviet
+ race = /datum/species/golem/soviet
+
+/mob/living/carbon/human/species/jelly
+ race = /datum/species/jelly
+
+/mob/living/carbon/human/species/jelly/slime
+ race = /datum/species/jelly/slime
+
+/mob/living/carbon/human/species/jelly/stargazer
+ race = /datum/species/jelly/stargazer
+
+/mob/living/carbon/human/species/jelly/luminescent
+ race = /datum/species/jelly/luminescent
+
+/mob/living/carbon/human/species/lizard
+ race = /datum/species/lizard
+
+/mob/living/carbon/human/species/ethereal
+ race = /datum/species/ethereal
+
+/mob/living/carbon/human/species/lizard/ashwalker
+ race = /datum/species/lizard/ashwalker
+
+/mob/living/carbon/human/species/moth
+ race = /datum/species/moth
+
+/mob/living/carbon/human/species/mush
+ race = /datum/species/mush
+
+/mob/living/carbon/human/species/plasma
+ race = /datum/species/plasmaman
+
+/mob/living/carbon/human/species/pod
+ race = /datum/species/pod
+
+/mob/living/carbon/human/species/shadow
+ race = /datum/species/shadow
+
+/mob/living/carbon/human/species/shadow/nightmare
+ race = /datum/species/shadow/nightmare
+
+/mob/living/carbon/human/species/skeleton
+ race = /datum/species/skeleton
+
+/mob/living/carbon/human/species/snail
+ race = /datum/species/snail
+
+/mob/living/carbon/human/species/synth
+ race = /datum/species/synth
+
+/mob/living/carbon/human/species/synth/military
+ race = /datum/species/synth/military
+
+/mob/living/carbon/human/species/vampire
+ race = /datum/species/vampire
+
+/mob/living/carbon/human/species/zombie
+ race = /datum/species/zombie
+
+/mob/living/carbon/human/species/zombie/infectious
+ race = /datum/species/zombie/infectious
+
+/mob/living/carbon/human/species/zombie/krokodil_addict
+ race = /datum/species/krokodil_addict
diff --git a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm
index c134f3d47b2..26bd64d4268 100644
--- a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm
@@ -49,7 +49,7 @@
. = ..()
to_chat(C, "[info_text]")
- C.fully_replace_character_name("[pick(GLOB.nightmare_names)]")
+ C.fully_replace_character_name(null, pick(GLOB.nightmare_names))
/datum/species/shadow/nightmare/bullet_act(obj/projectile/P, mob/living/carbon/human/H)
var/turf/T = H.loc
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index e2a8863e9b5..a4835ac94b9 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -649,12 +649,12 @@ All effects don't start immediately, but rather get worse over time; the rate is
/mob/living/carbon/proc/share_bodytemperature(mob/living/carbon/M)
var/temp_diff = bodytemperature - M.bodytemperature
if(temp_diff > 0) // you are warm share the heat of life
- M.adjust_bodytemperature(temp_diff, use_insulation=TRUE, use_steps=TRUE) // warm up the giver
- adjust_bodytemperature((temp_diff * -1), use_insulation=TRUE, use_steps=TRUE) // cool down the reciver
+ M.adjust_bodytemperature((temp_diff * 0.5), use_insulation=TRUE, use_steps=TRUE) // warm up the giver
+ adjust_bodytemperature((temp_diff * -0.5), use_insulation=TRUE, use_steps=TRUE) // cool down the reciver
else // they are warmer leech from them
- adjust_bodytemperature(temp_diff, use_insulation=TRUE, use_steps=TRUE) // warm up the reciver
- M.adjust_bodytemperature((temp_diff * -1), use_insulation=TRUE, use_steps=TRUE) // cool down the giver
+ adjust_bodytemperature((temp_diff * -0.5) , use_insulation=TRUE, use_steps=TRUE) // warm up the reciver
+ M.adjust_bodytemperature((temp_diff * 0.5), use_insulation=TRUE, use_steps=TRUE) // cool down the giver
/**
* Adjust the body temperature of a mob
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index dab25e3b3e7..cb4f19ac15e 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -521,7 +521,7 @@
if(mob_mask.Height() > world.icon_size || mob_mask.Width() > world.icon_size)
var/health_doll_icon_state = health_doll_icon ? health_doll_icon : "megasprite"
mob_mask = icon('icons/mob/screen_gen.dmi', health_doll_icon_state) //swap to something generic if they have no special doll
- UNLINT(livingdoll.filters += filter(type="alpha", icon = mob_mask))
+ livingdoll.filters += filter(type="alpha", icon = mob_mask)
livingdoll.filters += filter(type="drop_shadow", size = -1)
if(severity > 0)
overlay_fullscreen("brute", /obj/screen/fullscreen/brute, severity)
@@ -529,7 +529,23 @@
clear_fullscreen("brute")
//Proc used to resuscitate a mob, for full_heal see fully_heal()
-/mob/living/proc/revive(full_heal = FALSE, admin_revive = FALSE)
+/mob/living/proc/revive(full_heal = FALSE, admin_revive = FALSE, excess_healing = 0)
+ if(excess_healing)
+ if(iscarbon(src) && excess_healing)
+ var/mob/living/carbon/C = src
+ if(!(C.dna?.species && (NOBLOOD in C.dna.species.species_traits)))
+ C.blood_volume += (excess_healing*2)//1 excess = 10 blood
+
+ for(var/i in C.internal_organs)
+ var/obj/item/organ/O = i
+ if(O.organ_flags & ORGAN_SYNTHETIC)
+ continue
+ O.applyOrganDamage(excess_healing*-1)//1 excess = 5 organ damage healed
+
+ adjustOxyLoss(-20, TRUE)
+ adjustToxLoss(-20, TRUE) //slime friendly
+ updatehealth()
+ grab_ghost()
SEND_SIGNAL(src, COMSIG_LIVING_REVIVE, full_heal, admin_revive)
if(full_heal)
fully_heal(admin_revive = admin_revive)
@@ -548,6 +564,9 @@
for(var/S in mind.spell_list)
var/obj/effect/proc_holder/spell/spell = S
spell.updateButtonIcon()
+ if(excess_healing)
+ emote("gasp")
+ log_combat(src, src, "revived")
/mob/living/proc/remove_CC(should_update_mobility = TRUE)
SetStun(0, FALSE)
diff --git a/code/modules/modular_computers/file_system/programs/arcade.dm b/code/modules/modular_computers/file_system/programs/arcade.dm
index ca19c80a9f2..ea38eca44c2 100644
--- a/code/modules/modular_computers/file_system/programs/arcade.dm
+++ b/code/modules/modular_computers/file_system/programs/arcade.dm
@@ -94,14 +94,14 @@
data["BossID"] = "boss[boss_id].gif"
return data
-/datum/computer_file/program/arcade/ui_act(action, list/params, mob/user)
+/datum/computer_file/program/arcade/ui_act(action, list/params)
if(..())
return TRUE
var/obj/item/computer_hardware/printer/printer
if(computer)
printer = computer.all_components[MC_PRINT]
- var/gamerSkillLevel = user.mind?.get_skill_level(/datum/skill/gaming)
+ var/gamerSkillLevel = usr.mind?.get_skill_level(/datum/skill/gaming)
var/gamerSkill = usr.mind?.get_skill_modifier(/datum/skill/gaming, SKILL_RANDS_MODIFIER)
switch(action)
if("Attack")
@@ -157,11 +157,11 @@
computer.visible_message("\The [computer] prints out paper.")
if(ticket_count >= 1)
new /obj/item/stack/arcadeticket((get_turf(computer)), 1)
- to_chat(user, "[src] dispenses a ticket!")
+ to_chat(usr, "[src] dispenses a ticket!")
ticket_count -= 1
printer.stored_paper -= 1
else
- to_chat(user, "You don't have any stored tickets!")
+ to_chat(usr, "You don't have any stored tickets!")
return TRUE
if("Start_Game")
game_active = TRUE
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index f080a894523..67041349241 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -434,6 +434,8 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list(new/datum/stack_recipe("cable restrain
return TRUE
/obj/item/stack/cable_coil/CtrlClick(mob/living/user)
+ if(loc!=user)
+ return ..()
if(!user)
return
var/list/layer_list = list(
diff --git a/code/modules/reagents/chemistry/reagents/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drink_reagents.dm
index d61266128a6..57d57650883 100644
--- a/code/modules/reagents/chemistry/reagents/drink_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/drink_reagents.dm
@@ -898,3 +898,18 @@
glass_icon_state = "glass_orange"
glass_name = "glass of pruno mixture"
glass_desc = "Fruit, sugar, yeast, and water pulped together into a pungent slurry."
+
+/datum/reagent/consumable/aloejuice
+ name = "Aloe Juice"
+ color = "#A3C48B"
+ description = "A healthy and refreshing juice."
+ taste_description = "vegetable"
+ glass_icon_state = "glass_yellow"
+ glass_name = "glass of aloe juice"
+ glass_desc = "A healthy and refreshing juice."
+
+/datum/reagent/consumable/aloejuice/on_mob_life(mob/living/M)
+ if(M.getToxLoss() && prob(30))
+ M.adjustToxLoss(-1, 0)
+ ..()
+ . = TRUE
diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
index 12600a84ae0..b28e6e97fcd 100644
--- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
@@ -736,33 +736,12 @@
M.visible_message("[M]'s body starts convulsing!")
M.notify_ghost_cloning("Your body is being revived with Strange Reagent!")
M.do_jitter_animation(10)
+ var/excess_healing = 5*(reac_volume-amount_to_revive) //excess reagent will heal blood and organs across the board
addtimer(CALLBACK(M, /mob/living/carbon.proc/do_jitter_animation, 10), 40) //jitter immediately, then again after 4 and 8 seconds
addtimer(CALLBACK(M, /mob/living/carbon.proc/do_jitter_animation, 10), 80)
- addtimer(CALLBACK(src, .proc/do_strange_revive,M,reac_volume,amount_to_revive), 79) //timing is everything!
+ addtimer(CALLBACK(M, /mob/living.proc/revive, FALSE, FALSE, excess_healing), 79)
..()
-/datum/reagent/medicine/strange_reagent/proc/do_strange_revive(mob/living/M,reac_volume,revive_requirement) //we store revive_requirement because if we calculate it now we might have changed our damage numbers.
- var/excess_healing = 5*(reac_volume-revive_requirement) //excess reagent will heal blood and organs across the board
- if(iscarbon(M) && excess_healing)
- var/mob/living/carbon/C = M
- if(!(C.dna?.species && (NOBLOOD in C.dna.species.species_traits)))
- C.blood_volume += (excess_healing*2)//1 excess = 10 blood
-
- for(var/i in C.internal_organs)
- var/obj/item/organ/O = i
- if(O.organ_flags & ORGAN_SYNTHETIC)
- continue
- O.applyOrganDamage(excess_healing*-1)//1 excess = 5 organ damage healed
-
- M.adjustOxyLoss(-20, TRUE)
- M.adjustToxLoss(-20, TRUE) //slime friendly
- M.updatehealth()
- M.grab_ghost()
- if(M.revive(full_heal = FALSE, admin_revive = FALSE))
- M.emote("gasp")
- log_combat(M, M, "revived", src)
-
-
/datum/reagent/medicine/strange_reagent/on_mob_life(mob/living/carbon/M)
var/damage_at_random = rand(0,250)/100 //0 to 2.5
M.adjustBruteLoss(damage_at_random*REM, FALSE)
diff --git a/code/modules/reagents/chemistry/recipes/medicine.dm b/code/modules/reagents/chemistry/recipes/medicine.dm
index ad60d2f6776..2171015ab4f 100644
--- a/code/modules/reagents/chemistry/recipes/medicine.dm
+++ b/code/modules/reagents/chemistry/recipes/medicine.dm
@@ -155,10 +155,17 @@
required_catalysts = list(/datum/reagent/iron = 5)
/datum/chemical_reaction/medsuture
- required_reagents = list(/datum/reagent/cellulose = 10, /datum/reagent/toxin/formaldehyde = 30, /datum/reagent/medicine/polypyr = 30) //This might be a bit much, reagent cost should be reviewed after implementation.
+ required_reagents = list(/datum/reagent/cellulose = 10, /datum/reagent/toxin/formaldehyde = 20, /datum/reagent/medicine/polypyr = 15) //This might be a bit much, reagent cost should be reviewed after implementation.
/datum/chemical_reaction/medsuture/on_reaction(datum/reagents/holder, created_volume)
var/location = get_turf(holder.my_atom)
for(var/i = 1, i <= created_volume, i++)
new /obj/item/stack/medical/suture/medicated(location)
- return
+
+/datum/chemical_reaction/medmesh
+ required_reagents = list(/datum/reagent/cellulose = 20, /datum/reagent/consumable/aloejuice = 20, /datum/reagent/space_cleaner/sterilizine = 10)
+
+/datum/chemical_reaction/medmesh/on_reaction(datum/reagents/holder, created_volume)
+ var/location = get_turf(holder.my_atom)
+ for(var/i = 1, i <= created_volume, i++)
+ new /obj/item/stack/medical/mesh/advanced(location)
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index 23748a32aea..8f8ce9723eb 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -610,7 +610,7 @@
description = "Unlocks new RCD designs."
design_ids = list("rcd_upgrade_silo_link")
prereq_ids = list("rcd_upgrade", "bluespace_travel")
- research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 25000)
+ research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000)
export_price = 5000
/////////////////////////weaponry tech/////////////////////////
diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm
index f69ef52dabd..b8734fc9d43 100644
--- a/code/modules/uplink/uplink_items.dm
+++ b/code/modules/uplink/uplink_items.dm
@@ -1487,6 +1487,13 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
cost = 7
limited_stock = 1
+/datum/uplink_item/device_tools/guerillagloves
+ name = "Guerilla Gloves"
+ desc = "A pair of highly robust combat gripper gloves that excels at performing takedowns at close range, with an added lining of insulation. Careful not to hit a wall!"
+ item = /obj/item/clothing/gloves/tackler/combat/insulated
+ include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
+ cost = 2
+
// Implants
/datum/uplink_item/implants
category = "Implants"
diff --git a/code/modules/vending/megaseed.dm b/code/modules/vending/megaseed.dm
index ab48ccb2921..fb00127c8c5 100644
--- a/code/modules/vending/megaseed.dm
+++ b/code/modules/vending/megaseed.dm
@@ -4,7 +4,8 @@
product_slogans = "THIS'S WHERE TH' SEEDS LIVE! GIT YOU SOME!;Hands down the best seed selection on the station!;Also certain mushroom varieties available, more for experts! Get certified today!"
product_ads = "We like plants!;Grow some crops!;Grow, baby, growww!;Aw h'yeah son!"
icon_state = "seeds"
- products = list(/obj/item/seeds/ambrosia = 3,
+ products = list(/obj/item/seeds/aloe = 3,
+ /obj/item/seeds/ambrosia = 3,
/obj/item/seeds/apple = 3,
/obj/item/seeds/cotton = 3,
/obj/item/seeds/banana = 3,
diff --git a/html/changelog.html b/html/changelog.html
index 91accd899c4..52eb95d5b52 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -51,6 +51,41 @@
-->
+
12 March 2020
+
CDranzer updated:
+
+ - Empty tape recorders no longer get stuck on pocket and belt slots
+
+
Fikou updated:
+
+ - rcd silo link tech node now costs 5000 points instead of 25000
+
+
Ghommie updated:
+
+ - The flying speed slowdown while hurt now actually affects flying mobs and not floating ones.
+
+
RaveRadbury updated:
+
+ - Hugging someone colder than you now warms them correctly.
+
+
SteelSlayer updated:
+
+ - Fixes up the label component's code to work as it was intended to.
+
+
Tlaltecuhtli updated:
+
+ - aloe plant
+ - aloe plant cream (microwaved /bonfired aloe)
+ - advanced healing mesh (made with aloe juice + cellulose + sterilizine)
+ - lowered price of polypypyr suture to require less formaldeyhde and less popolypyyr
+
+
+
11 March 2020
+
LemonInTheDark: applying head to wall, ArcaneDefence: doing the brunt of the debugging and work updated:
+
+ - Fixes Strange Reagent's inconsistent revival.
+
+
10 March 2020
4dplanner updated:
@@ -79,6 +114,15 @@
- Radioactive Microlaser UI now has Syndicate theme.
- You must hold Radioactive Microlaser in your hands in order to use its UI.
+
Arkatos and actionninja updated:
+
+ - AI system integrity restorer now uses tgui.
+
+
Bokkiewokkie updated:
+
+ - Bronze sheets are now just as strong as normal sheets when smacking people.
+ - Nanotrasen have recently discovered a technique to observe what kind of sheet someone is holding in their hand, this has now been integrated in the basic spessman training programme.
+
Cobbtholicism updated:
- Religious Sects are now Added! Religious sects tailor your chaplain experience and reward you for playing in a particular playstyle as a convert/priest/highpriest! (Currently Admin Only, Requires Spawning altar_of_god)
@@ -98,12 +142,26 @@
- Hand Tele try place portal ahead of user now.
- try_move_adjacent can take desirable dir
- Now RCD constructing effect unclickable.
+ - Slimes try don't split while not in suitable container.
+ - On slime split new slimes appears in turf.
+ - On slime death new slime appears in turf.
+ - Now ladders has radial menu
+ - Some effect visuals.
+ - fake plasma flood hallucination no more blocks clicking on things
+ - Now possible place cable over openspace on catwalk
+ - Now you can change cable layer only in hand.
+
+
EdgeLordExe updated:
+
+ - Scientist have found a way to identify ash around you to determine what ores are in it.
Fikou updated:
- hivelord stands are replaced with new mining ones, they spin!
- fixed being able to change your stand name/color on every reconnect
- removed most of the old holopara/guardian spirit sprites except for 2 example ones since they aren't used anymore
+ - renames the pirate captain
+ - you can now put plastic in the autolathe to print sticky tape
Iamgoofball, Robustin, sprites by thatguythere03 updated:
@@ -143,10 +201,15 @@
Qustinnus updated:
- Adds a license press, make those prisoners do something useful!
+ - A wise cow can be found visiting the station sometimes now. Be sure to ask him for advice
Ryll/Shaps updated:
- Adds new special gloves that allow tackling! Actual implementation details to be finalized.
+ - "Holy shit! We just accidentally killed the Captain! Here, uhh... oh god, stuff him in that wheelchair over there, before anyone comes in. Yeah, yeah! Get his sunglasses, cover his face. Oh my god, oh my god, oh my god. No one will be able to tell, he looks sorta fine, right? Right?"
+ - You can now Weekend at Bernies dead people with a wheelchair and tinted glasses.
+ - Operatives no longer receive free Guerrilla Gloves, but can purchase a pair for 2TC.
+ - It's guerrilla not guerilla!
ShizCalev updated:
@@ -167,6 +230,7 @@
XDTM updated:
- Fixed nanite comm remotes not working at all.
+ - Fixed Regenerative Coma being permanent if the virus gets cured during a coma.
bandit updated:
@@ -177,6 +241,7 @@
- Nanotrasen has recently retrofitted all disposal bins with built-in vacuum units, allowing brooms to sweep garbage into them!
- Push brooms can now be manufactured in the service protolathe and any autolathe.
+ - Fixed ability to escape any sanitized string in goonchat
cacogen updated:
@@ -209,6 +274,8 @@
- Martyrdom and HADS are in the pool!
- caltrop component now sends a visible message before damage instead of the other way around
+ - tweaked a few things about emojis. some have more reasonable names, some are no longer blurry, stuff like that.
+ - nightmare name not getting added: FINALLY FIXED
zxaber updated:
@@ -1654,16 +1721,6 @@
- Law 0 for emagged borgs is no longer being suppressed.
-
- 08 January 2020
- Skoglol updated:
-
- - Admin basic disease trigger and custom disease renaming should now work properly.
-
- floyd updated:
-
- - Everything made from glass in the game has a little more tegridy and doesnt break from a single punch
-
GoonStation 13 Development Team
diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml
index 73f495a49bd..8d7e0c16778 100644
--- a/html/changelogs/.all_changelog.yml
+++ b/html/changelogs/.all_changelog.yml
@@ -37634,6 +37634,13 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- tweak: Radioactive Microlaser UI now has Syndicate theme.
- tweak: You must hold Radioactive Microlaser in your hands in order to use its
UI.
+ Arkatos and actionninja:
+ - rscadd: AI system integrity restorer now uses tgui.
+ Bokkiewokkie:
+ - bugfix: Bronze sheets are now just as strong as normal sheets when smacking people.
+ - imageadd: Nanotrasen have recently discovered a technique to observe what kind
+ of sheet someone is holding in their hand, this has now been integrated in the
+ basic spessman training programme.
Cobbtholicism:
- rscadd: Religious Sects are now Added! Religious sects tailor your chaplain experience
and reward you for playing in a particular playstyle as a convert/priest/highpriest!
@@ -37655,11 +37662,24 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- tweak: Hand Tele try place portal ahead of user now.
- tweak: try_move_adjacent can take desirable dir
- tweak: Now RCD constructing effect unclickable.
+ - bugfix: Slimes try don't split while not in suitable container.
+ - bugfix: On slime split new slimes appears in turf.
+ - bugfix: On slime death new slime appears in turf.
+ - rscadd: Now ladders has radial menu
+ - bugfix: Some effect visuals.
+ - bugfix: fake plasma flood hallucination no more blocks clicking on things
+ - bugfix: Now possible place cable over openspace on catwalk
+ - tweak: Now you can change cable layer only in hand.
+ EdgeLordExe:
+ - rscadd: Scientist have found a way to identify ash around you to determine what
+ ores are in it.
Fikou:
- rscadd: hivelord stands are replaced with new mining ones, they spin!
- bugfix: fixed being able to change your stand name/color on every reconnect
- imagedel: removed most of the old holopara/guardian spirit sprites except for
2 example ones since they aren't used anymore
+ - spellcheck: renames the pirate captain
+ - bugfix: you can now put plastic in the autolathe to print sticky tape
Iamgoofball, Robustin, sprites by thatguythere03:
- rscadd: A new gamemode is hitting the station, Families.
- rscadd: In this gamemode, 3 different crime families will be spawned on board
@@ -37703,9 +37723,20 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
a bad enough dude to become a legendary gamer?
Qustinnus:
- rscadd: Adds a license press, make those prisoners do something useful!
+ - rscadd: A wise cow can be found visiting the station sometimes now. Be sure to
+ ask him for advice
Ryll/Shaps:
- rscadd: Adds new special gloves that allow tackling! Actual implementation details
to be finalized.
+ - rscadd: '"Holy shit! We just accidentally killed the Captain! Here, uhh... oh
+ god, stuff him in that wheelchair over there, before anyone comes in. Yeah,
+ yeah! Get his sunglasses, cover his face. Oh my god, oh my god, oh my god. No
+ one will be able to tell, he looks sorta fine, right? Right?"'
+ - rscadd: You can now Weekend at Bernies dead people with a wheelchair and tinted
+ glasses.
+ - tweak: Operatives no longer receive free Guerrilla Gloves, but can purchase a
+ pair for 2TC.
+ - spellcheck: It's guerrilla not guerilla!
ShizCalev:
- bugfix: Added prisoner ID's in Donutstation's gulaging area.
SteelSlayer:
@@ -37722,6 +37753,8 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
Phazon mech's construction.
XDTM:
- bugfix: Fixed nanite comm remotes not working at all.
+ - bugfix: Fixed Regenerative Coma being permanent if the virus gets cured during
+ a coma.
bandit:
- rscadd: The uptick of long-term detainees in Nanotrasen brigs has resulted in
prisoners reviving the ancient, illegal tradition of brewing prison wine from
@@ -37735,6 +37768,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
units, allowing brooms to sweep garbage into them!
- rscadd: Push brooms can now be manufactured in the service protolathe and any
autolathe.
+ - bugfix: Fixed ability to escape any sanitized string in goonchat
cacogen:
- rscadd: Space's big players are more beholden to OSH than one might've thought.
Newly manufactured clothing now comes with a tag listing its protection ratings
@@ -37761,6 +37795,9 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- rscadd: Martyrdom and HADS are in the pool!
- bugfix: caltrop component now sends a visible message before damage instead of
the other way around
+ - tweak: tweaked a few things about emojis. some have more reasonable names, some
+ are no longer blurry, stuff like that.
+ - bugfix: 'nightmare name not getting added: FINALLY FIXED'
zxaber:
- balance: AI Core boards (used to make new AIs) no longer require gold and bluespace
crystals.
@@ -37769,3 +37806,24 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- bugfix: Fixed drones not being equip-able as hats.
- bugfix: Fixed pAIs returning to card form when being held or on someone's head
leaving a phantom chassis behind.
+2020-03-11:
+ 'LemonInTheDark: applying head to wall, ArcaneDefence: doing the brunt of the debugging and work':
+ - bugfix: Fixes Strange Reagent's inconsistent revival.
+2020-03-12:
+ CDranzer:
+ - bugfix: Empty tape recorders no longer get stuck on pocket and belt slots
+ Fikou:
+ - balance: rcd silo link tech node now costs 5000 points instead of 25000
+ Ghommie:
+ - bugfix: The flying speed slowdown while hurt now actually affects flying mobs
+ and not floating ones.
+ RaveRadbury:
+ - bugfix: Hugging someone colder than you now warms them correctly.
+ SteelSlayer:
+ - code_imp: Fixes up the label component's code to work as it was intended to.
+ Tlaltecuhtli:
+ - rscadd: aloe plant
+ - rscadd: aloe plant cream (microwaved /bonfired aloe)
+ - rscadd: advanced healing mesh (made with aloe juice + cellulose + sterilizine)
+ - rscadd: lowered price of polypypyr suture to require less formaldeyhde and less
+ popolypyyr
diff --git a/html/changelogs/AutoChangeLog-pr-49719.yml b/html/changelogs/AutoChangeLog-pr-49719.yml
deleted file mode 100644
index 1e25a41d0c9..00000000000
--- a/html/changelogs/AutoChangeLog-pr-49719.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Qustinnus"
-delete-after: True
-changes:
- - rscadd: "A wise cow can be found visiting the station sometimes now. Be sure to ask him for advice"
diff --git a/html/changelogs/AutoChangeLog-pr-49734.yml b/html/changelogs/AutoChangeLog-pr-49734.yml
deleted file mode 100644
index dfa837ddce4..00000000000
--- a/html/changelogs/AutoChangeLog-pr-49734.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-author: "Dennok"
-delete-after: True
-changes:
- - bugfix: "Slimes try don't split while not in suitable container."
- - bugfix: "On slime split new slimes appears in turf."
- - bugfix: "On slime death new slime appears in turf."
diff --git a/html/changelogs/AutoChangeLog-pr-49746.yml b/html/changelogs/AutoChangeLog-pr-49746.yml
deleted file mode 100644
index 97723076f19..00000000000
--- a/html/changelogs/AutoChangeLog-pr-49746.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "EdgeLordExe"
-delete-after: True
-changes:
- - rscadd: "Scientist have found a way to identify ash around you to determine what ores are in it."
diff --git a/html/changelogs/AutoChangeLog-pr-49749.yml b/html/changelogs/AutoChangeLog-pr-49749.yml
deleted file mode 100644
index 6b717838240..00000000000
--- a/html/changelogs/AutoChangeLog-pr-49749.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "Ryll/Shaps"
-delete-after: True
-changes:
- - rscadd: "\"Holy shit! We just accidentally killed the Captain! Here, uhh... oh god, stuff him in that wheelchair over there, before anyone comes in. Yeah, yeah! Get his sunglasses, cover his face. Oh my god, oh my god, oh my god. No one will be able to tell, he looks sorta fine, right? Right?\""
- - rscadd: "You can now Weekend at Bernies dead people with a wheelchair and tinted glasses."
diff --git a/html/changelogs/AutoChangeLog-pr-49804.yml b/html/changelogs/AutoChangeLog-pr-49804.yml
deleted file mode 100644
index de752accced..00000000000
--- a/html/changelogs/AutoChangeLog-pr-49804.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Dennok"
-delete-after: True
-changes:
- - bugfix: "Some effect visuals."
diff --git a/html/changelogs/AutoChangeLog-pr-49807.yml b/html/changelogs/AutoChangeLog-pr-49807.yml
deleted file mode 100644
index 080518bfc70..00000000000
--- a/html/changelogs/AutoChangeLog-pr-49807.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "tralezab"
-delete-after: True
-changes:
- - tweak: "tweaked a few things about emojis. some have more reasonable names, some are no longer blurry, stuff like that."
diff --git a/html/changelogs/AutoChangeLog-pr-49810.yml b/html/changelogs/AutoChangeLog-pr-49810.yml
deleted file mode 100644
index d60d1383b4b..00000000000
--- a/html/changelogs/AutoChangeLog-pr-49810.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Dennok"
-delete-after: True
-changes:
- - bugfix: "fake plasma flood hallucination no more blocks clicking on things"
diff --git a/html/changelogs/AutoChangeLog-pr-49828.yml b/html/changelogs/AutoChangeLog-pr-49828.yml
deleted file mode 100644
index 7450f7770e4..00000000000
--- a/html/changelogs/AutoChangeLog-pr-49828.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Arkatos and actionninja"
-delete-after: True
-changes:
- - rscadd: "AI system integrity restorer now uses tgui."
diff --git a/html/changelogs/AutoChangeLog-pr-49830.yml b/html/changelogs/AutoChangeLog-pr-49830.yml
deleted file mode 100644
index 2dc7f20c89b..00000000000
--- a/html/changelogs/AutoChangeLog-pr-49830.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "Bokkiewokkie"
-delete-after: True
-changes:
- - bugfix: "Bronze sheets are now just as strong as normal sheets when smacking people."
- - imageadd: "Nanotrasen have recently discovered a technique to observe what kind of sheet someone is holding in their hand, this has now been integrated in the basic spessman training programme."
diff --git a/icons/obj/hydroponics/growing_vegetables.dmi b/icons/obj/hydroponics/growing_vegetables.dmi
index c13ce2d5210..0ea0c14e803 100644
Binary files a/icons/obj/hydroponics/growing_vegetables.dmi and b/icons/obj/hydroponics/growing_vegetables.dmi differ
diff --git a/icons/obj/hydroponics/harvest.dmi b/icons/obj/hydroponics/harvest.dmi
index d92950f95de..a5f92088324 100644
Binary files a/icons/obj/hydroponics/harvest.dmi and b/icons/obj/hydroponics/harvest.dmi differ
diff --git a/icons/obj/hydroponics/seeds.dmi b/icons/obj/hydroponics/seeds.dmi
index e8655e6e94c..c11023d26bd 100644
Binary files a/icons/obj/hydroponics/seeds.dmi and b/icons/obj/hydroponics/seeds.dmi differ
diff --git a/icons/obj/stack_objects.dmi b/icons/obj/stack_objects.dmi
index e4e2f4c0080..c9bc9e00381 100644
Binary files a/icons/obj/stack_objects.dmi and b/icons/obj/stack_objects.dmi differ
diff --git a/icons/turf/floors.dmi b/icons/turf/floors.dmi
index 7f2972ed3f4..27ff0f580d6 100644
Binary files a/icons/turf/floors.dmi and b/icons/turf/floors.dmi differ