
Safe Codes
"
/obj/item/paper/safe_code/Initialize(mapload)
+ ..()
return INITIALIZE_HINT_LATELOAD
/obj/item/paper/safe_code/LateInitialize(mapload)
diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm
index 5acd4f7d8a3..bdab5ca2466 100644
--- a/code/game/objects/structures/tables_racks.dm
+++ b/code/game/objects/structures/tables_racks.dm
@@ -128,7 +128,7 @@
/obj/structure/table/CanAStarPass(ID, dir, caller)
. = !density
- if(ismovableatom(caller))
+ if(ismovable(caller))
var/atom/movable/mover = caller
. = . || mover.checkpass(PASSTABLE)
@@ -224,8 +224,8 @@
if(!click_params || !click_params["icon-x"] || !click_params["icon-y"])
return
//Clamp it so that the icon never moves more than 16 pixels in either direction (thus leaving the table turf)
- I.pixel_x = Clamp(text2num(click_params["icon-x"]) - 16, -(world.icon_size/2), world.icon_size/2)
- I.pixel_y = Clamp(text2num(click_params["icon-y"]) - 16, -(world.icon_size/2), world.icon_size/2)
+ I.pixel_x = clamp(text2num(click_params["icon-x"]) - 16, -(world.icon_size/2), world.icon_size/2)
+ I.pixel_y = clamp(text2num(click_params["icon-y"]) - 16, -(world.icon_size/2), world.icon_size/2)
item_placed(I)
else
return ..()
@@ -666,7 +666,7 @@
/obj/structure/rack/CanAStarPass(ID, dir, caller)
. = !density
- if(ismovableatom(caller))
+ if(ismovable(caller))
var/atom/movable/mover = caller
. = . || mover.checkpass(PASSTABLE)
diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm
index 87107f97abe..1a5b275bc01 100644
--- a/code/game/objects/structures/watercloset.dm
+++ b/code/game/objects/structures/watercloset.dm
@@ -403,75 +403,7 @@
L.ExtinguishMob()
L.adjust_fire_stacks(-20) //Douse ourselves with water to avoid fire more easily
to_chat(L, "
You've been drenched in water!")
- if(iscarbon(O))
- var/mob/living/carbon/M = O
- if(M.r_hand)
- M.r_hand.clean_blood()
- if(M.l_hand)
- M.l_hand.clean_blood()
- if(M.back)
- if(M.back.clean_blood())
- M.update_inv_back()
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- var/washgloves = 1
- var/washshoes = 1
- var/washmask = 1
- var/washears = 1
- var/washglasses = 1
-
- if(H.wear_suit)
- washgloves = !(H.wear_suit.flags_inv & HIDEGLOVES)
- washshoes = !(H.wear_suit.flags_inv & HIDESHOES)
-
- if(H.head)
- washmask = !(H.head.flags_inv & HIDEMASK)
- washglasses = !(H.head.flags_inv & HIDEEYES)
- washears = !(H.head.flags_inv & HIDEEARS)
-
- if(H.wear_mask)
- if(washears)
- washears = !(H.wear_mask.flags_inv & HIDEEARS)
- if(washglasses)
- washglasses = !(H.wear_mask.flags_inv & HIDEEYES)
-
- if(H.head)
- if(H.head.clean_blood())
- H.update_inv_head()
- if(H.wear_suit)
- if(H.wear_suit.clean_blood())
- H.update_inv_wear_suit()
- else if(H.w_uniform)
- if(H.w_uniform.clean_blood())
- H.update_inv_w_uniform()
- if(H.gloves && washgloves)
- if(H.gloves.clean_blood())
- H.update_inv_gloves()
- if(H.shoes && washshoes)
- if(H.shoes.clean_blood())
- H.update_inv_shoes()
- if(H.wear_mask && washmask)
- if(H.wear_mask.clean_blood())
- H.update_inv_wear_mask()
- if(H.glasses && washglasses)
- if(H.glasses.clean_blood())
- H.update_inv_glasses()
- if(H.l_ear && washears)
- if(H.l_ear.clean_blood())
- H.update_inv_ears()
- if(H.r_ear && washears)
- if(H.r_ear.clean_blood())
- H.update_inv_ears()
- if(H.belt)
- if(H.belt.clean_blood())
- H.update_inv_belt()
- else
- if(M.wear_mask) //if the mob is not human, it cleans the mask without asking for bitflags
- if(M.wear_mask.clean_blood())
- M.update_inv_wear_mask()
-
- else
- O.clean_blood()
+ L.clean_blood()
if(isturf(loc))
var/turf/tile = loc
diff --git a/code/game/turfs/simulated.dm b/code/game/turfs/simulated.dm
index 19717991593..6bc1c4ba142 100644
--- a/code/game/turfs/simulated.dm
+++ b/code/game/turfs/simulated.dm
@@ -8,12 +8,6 @@
nitrogen = MOLES_N2STANDARD
var/to_be_destroyed = 0 //Used for fire, if a melting temperature was reached, it will be destroyed
var/max_fire_temperature_sustained = 0 //The max temperature of the fire which it was subjected to
- var/dirtoverlay = null
-
-/turf/simulated/New()
- ..()
- levelupdate()
- visibilityChanged()
/turf/simulated/proc/break_tile()
return
diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm
index 2d886f44bfd..614b8232b0b 100644
--- a/code/game/turfs/simulated/floor.dm
+++ b/code/game/turfs/simulated/floor.dm
@@ -27,24 +27,16 @@ GLOBAL_LIST_INIT(icons_to_ignore_at_floor_init, list("damaged1","damaged2","dama
var/burnt = 0
var/current_overlay = null
var/floor_tile = null //tile that this floor drops
- var/obj/item/stack/tile/builtin_tile = null //needed for performance reasons when the singularity rips off floor tiles
var/list/broken_states = list("damaged1", "damaged2", "damaged3", "damaged4", "damaged5")
var/list/burnt_states = list("floorscorched1", "floorscorched2")
var/list/prying_tool_list = list(TOOL_CROWBAR) //What tool/s can we use to pry up the tile?
-/turf/simulated/floor/New()
- ..()
+/turf/simulated/floor/Initialize(mapload)
+ . = ..()
if(icon_state in GLOB.icons_to_ignore_at_floor_init) //so damaged/burned tiles or plating icons aren't saved as the default
icon_regular_floor = "floor"
else
icon_regular_floor = icon_state
- if(floor_tile)
- builtin_tile = new floor_tile
-
-/turf/simulated/floor/Destroy()
- QDEL_NULL(builtin_tile)
- return ..()
-
//turf/simulated/floor/CanPass(atom/movable/mover, turf/target, height=0)
// if((istype(mover, /obj/machinery/vehicle) && !(src.burnt)))
@@ -209,30 +201,26 @@ GLOBAL_LIST_INIT(icons_to_ignore_at_floor_init, list("damaged1","damaged2","dama
else
if(user && !silent)
to_chat(user, "
You remove the floor tile.")
- if(builtin_tile && make_tile)
- builtin_tile.forceMove(src)
- builtin_tile = null
+ if(floor_tile && make_tile)
+ new floor_tile(src)
return make_plating()
/turf/simulated/floor/singularity_pull(S, current_size)
..()
if(current_size == STAGE_THREE)
if(prob(30))
- if(builtin_tile)
- builtin_tile.loc = src
- builtin_tile = null
+ if(floor_tile)
+ new floor_tile(src)
make_plating()
else if(current_size == STAGE_FOUR)
if(prob(50))
- if(builtin_tile)
- builtin_tile.loc = src
- builtin_tile = null
+ if(floor_tile)
+ new floor_tile(src)
make_plating()
else if(current_size >= STAGE_FIVE)
- if(builtin_tile)
+ if(floor_tile)
if(prob(70))
- builtin_tile.loc = src
- builtin_tile = null
+ new floor_tile(src)
make_plating()
else if(prob(50))
ReplaceWithLattice()
diff --git a/code/game/turfs/simulated/floor/asteroid.dm b/code/game/turfs/simulated/floor/asteroid.dm
index 6d5d95dff0e..6118885a921 100644
--- a/code/game/turfs/simulated/floor/asteroid.dm
+++ b/code/game/turfs/simulated/floor/asteroid.dm
@@ -227,7 +227,7 @@ GLOBAL_LIST_INIT(megafauna_spawn_list, list(/mob/living/simple_animal/hostile/me
break
var/list/L = list(45)
- if(IsOdd(dir2angle(dir))) // We're going at an angle and we want thick angled tunnels.
+ if(ISODD(dir2angle(dir))) // We're going at an angle and we want thick angled tunnels.
L += -45
// Expand the edges of our tunnel
diff --git a/code/game/turfs/simulated/floor/fancy_floor.dm b/code/game/turfs/simulated/floor/fancy_floor.dm
index 3ab424e69cc..bfbfa70331e 100644
--- a/code/game/turfs/simulated/floor/fancy_floor.dm
+++ b/code/game/turfs/simulated/floor/fancy_floor.dm
@@ -31,9 +31,8 @@
if(make_tile)
if(user && !silent)
to_chat(user, "
You unscrew the planks.")
- if(builtin_tile)
- builtin_tile.forceMove(src)
- builtin_tile = null
+ if(floor_tile)
+ new floor_tile(src)
else
if(user && !silent)
to_chat(user, "
You forcefully pry off the planks, destroying them in the process.")
@@ -50,9 +49,9 @@
floor_tile = /obj/item/stack/tile/grass
broken_states = list("sand")
-/turf/simulated/floor/grass/Initialize()
+/turf/simulated/floor/grass/Initialize(mapload)
+ . = ..()
update_icon()
- ..()
/turf/simulated/floor/grass/update_icon()
icon_state = "grass[pick("1","2","3","4")]"
@@ -81,10 +80,9 @@
)
-/turf/simulated/floor/carpet/New()
- ..()
- if(broken || burnt)
- make_plating()
+/turf/simulated/floor/carpet/Initialize(mapload)
+ . = ..()
+ update_icon()
/turf/simulated/floor/carpet/update_icon()
if(!..())
@@ -120,18 +118,18 @@
broken_states = list("damaged")
plane = PLANE_SPACE
-/turf/simulated/floor/fakespace/New()
- ..()
- icon_state = "[rand(0,25)]"
-
-/turf/simulated/floor/carpet/arcade
- icon = 'icons/goonstation/turf/floor.dmi'
- icon_state = "arcade"
- floor_tile = /obj/item/stack/tile/arcade_carpet
- smooth = SMOOTH_FALSE
+/turf/simulated/floor/fakespace/Initialize(mapload)
+ . = ..()
+ icon_state = SPACE_ICON_STATE
/turf/simulated/floor/fakespace/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir)
underlay_appearance.icon = 'icons/turf/space.dmi'
underlay_appearance.icon_state = SPACE_ICON_STATE
underlay_appearance.plane = PLANE_SPACE
return TRUE
+
+/turf/simulated/floor/carpet/arcade
+ icon = 'icons/goonstation/turf/floor.dmi'
+ icon_state = "arcade"
+ floor_tile = /obj/item/stack/tile/arcade_carpet
+ smooth = SMOOTH_FALSE
diff --git a/code/game/turfs/simulated/floor/lava.dm b/code/game/turfs/simulated/floor/lava.dm
index aa1be2200fa..14a08639132 100644
--- a/code/game/turfs/simulated/floor/lava.dm
+++ b/code/game/turfs/simulated/floor/lava.dm
@@ -8,9 +8,6 @@
light_power = 0.75
light_color = LIGHT_COLOR_LAVA
-/turf/simulated/floor/plating/lava/New()
- ..()
-
/turf/simulated/floor/plating/lava/ex_act()
return
@@ -80,8 +77,8 @@
O.resistance_flags |= FLAMMABLE //Even fireproof things burn up in lava
if(O.resistance_flags & FIRE_PROOF)
O.resistance_flags &= ~FIRE_PROOF
- if(O.armor["fire"] > 50) //obj with 100% fire armor still get slowly burned away.
- O.armor["fire"] = 50
+ if(O.armor.getRating("fire") > 50) //obj with 100% fire armor still get slowly burned away.
+ O.armor = O.armor.setRating(fire_value = 50)
O.fire_act(10000, 1000)
else if(isliving(thing))
diff --git a/code/game/turfs/simulated/floor/light_floor.dm b/code/game/turfs/simulated/floor/light_floor.dm
index 332cf745a4c..8276c0de33f 100644
--- a/code/game/turfs/simulated/floor/light_floor.dm
+++ b/code/game/turfs/simulated/floor/light_floor.dm
@@ -20,8 +20,8 @@
var/state = LIGHTFLOOR_ON
var/can_modify_colour = TRUE
-/turf/simulated/floor/light/New()
- ..()
+/turf/simulated/floor/light/Initialize(mapload)
+ . = ..()
update_icon()
/turf/simulated/floor/light/update_icon()
@@ -77,14 +77,13 @@
/turf/simulated/floor/light/attackby(obj/item/C, mob/user, params)
if(istype(C,/obj/item/light/bulb)) //only for light tiles
- if(istype(builtin_tile, /obj/item/stack/tile/light))
- if(!state)
- qdel(C)
- state = LIGHTFLOOR_ON
- update_icon()
- to_chat(user, "
You replace the light bulb.")
- else
- to_chat(user, "
The light bulb seems fine, no need to replace it.")
+ if(!state)
+ qdel(C)
+ state = LIGHTFLOOR_ON
+ update_icon()
+ to_chat(user, "
You replace the light bulb.")
+ else
+ to_chat(user, "
The light bulb seems fine, no need to replace it.")
else
return ..()
diff --git a/code/game/turfs/simulated/floor/mineral.dm b/code/game/turfs/simulated/floor/mineral.dm
index ffb1cce0b5c..dd975dc80d9 100644
--- a/code/game/turfs/simulated/floor/mineral.dm
+++ b/code/game/turfs/simulated/floor/mineral.dm
@@ -14,8 +14,8 @@
icon_state = ""
var/list/icons = list()
-/turf/simulated/floor/mineral/New()
- ..()
+/turf/simulated/floor/mineral/Initialize(mapload)
+ . = ..()
broken_states = list("[initial(icon_state)]_dam")
/turf/simulated/floor/mineral/update_icon()
@@ -97,24 +97,24 @@
broken_states = list("titanium_dam1","titanium_dam2","titanium_dam3","titanium_dam4","titanium_dam5")
/turf/simulated/floor/mineral/titanium/airless
- oxygen = 0.01
- nitrogen = 0.01
+ oxygen = 0
+ nitrogen = 0
temperature = TCMB
/turf/simulated/floor/mineral/titanium/blue
icon_state = "titanium_blue"
/turf/simulated/floor/mineral/titanium/blue/airless
- oxygen = 0.01
- nitrogen = 0.01
+ oxygen = 0
+ nitrogen = 0
temperature = TCMB
/turf/simulated/floor/mineral/titanium/yellow
icon_state = "titanium_yellow"
/turf/simulated/floor/mineral/titanium/yellow/airless
- oxygen = 0.01
- nitrogen = 0.01
+ oxygen = 0
+ nitrogen = 0
temperature = TCMB
/turf/simulated/floor/mineral/titanium/purple
@@ -122,8 +122,8 @@
floor_tile = /obj/item/stack/tile/mineral/titanium/purple
/turf/simulated/floor/mineral/titanium/purple/airless
- oxygen = 0.01
- nitrogen = 0.01
+ oxygen = 0
+ nitrogen = 0
temperature = TCMB
//PLASTITANIUM (syndieshuttle)
@@ -137,8 +137,8 @@
icon_state = "plastitanium_red"
/turf/simulated/floor/mineral/plastitanium/red/airless
- oxygen = 0.01
- nitrogen = 0.01
+ oxygen = 0
+ nitrogen = 0
temperature = TCMB
/turf/simulated/floor/mineral/plastitanium/red/brig
@@ -179,8 +179,8 @@
spam_flag = world.time + 10
/turf/simulated/floor/mineral/bananium/airless
- oxygen = 0.01
- nitrogen = 0.01
+ oxygen = 0
+ nitrogen = 0
temperature = TCMB
@@ -254,8 +254,8 @@
floor_tile = /obj/item/stack/tile/mineral/abductor
icons = list("alienpod1", "alienpod2", "alienpod3", "alienpod4", "alienpod5", "alienpod6", "alienpod7", "alienpod8", "alienpod9")
-/turf/simulated/floor/mineral/abductor/New()
- ..()
+/turf/simulated/floor/mineral/abductor/Initialize(mapload)
+ . = ..()
icon_state = "alienpod[rand(1,9)]"
/turf/simulated/floor/mineral/abductor/break_tile()
diff --git a/code/game/turfs/simulated/floor/misc_floor.dm b/code/game/turfs/simulated/floor/misc_floor.dm
index 0ca6494497c..83835cd947f 100644
--- a/code/game/turfs/simulated/floor/misc_floor.dm
+++ b/code/game/turfs/simulated/floor/misc_floor.dm
@@ -3,23 +3,23 @@
icon_state = "rockvault"
smooth = SMOOTH_FALSE
-/turf/simulated/floor/vault/New(location, vtype)
- ..()
- icon_state = "[vtype]vault"
-
/turf/simulated/wall/vault
icon = 'icons/turf/walls.dmi'
icon_state = "rockvault"
smooth = SMOOTH_FALSE
-/turf/simulated/wall/vault/New(location, vtype)
- ..()
- icon_state = "[vtype]vault"
-
/turf/simulated/floor/bluegrid
icon = 'icons/turf/floors.dmi'
icon_state = "bcircuit"
+/turf/simulated/floor/bluegrid/telecomms
+ nitrogen = 100
+ oxygen = 0
+ temperature = 80
+
+/turf/simulated/floor/bluegrid/telecomms/server
+ name = "server base"
+
/turf/simulated/floor/greengrid
icon = 'icons/turf/floors.dmi'
icon_state = "gcircuit"
@@ -27,12 +27,12 @@
/turf/simulated/floor/greengrid/airless
icon_state = "gcircuit"
name = "airless floor"
- oxygen = 0.01
- nitrogen = 0.01
+ oxygen = 0
+ nitrogen = 0
temperature = TCMB
-/turf/simulated/floor/greengrid/airless/New()
- ..()
+/turf/simulated/floor/greengrid/airless/Initialize(mapload)
+ . = ..()
name = "floor"
/turf/simulated/floor/redgrid
@@ -70,8 +70,8 @@
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
var/obj/machinery/poolcontroller/linkedcontroller = null
-/turf/simulated/floor/beach/water/New()
- ..()
+/turf/simulated/floor/beach/water/Initialize(mapload)
+ . = ..()
var/image/overlay_image = image('icons/misc/beach.dmi', icon_state = "water5", layer = ABOVE_MOB_LAYER)
overlay_image.plane = GAME_PLANE
overlays += overlay_image
diff --git a/code/game/turfs/simulated/floor/plasteel_floor.dm b/code/game/turfs/simulated/floor/plasteel_floor.dm
index d36396aaa5f..116d57dc1ef 100644
--- a/code/game/turfs/simulated/floor/plasteel_floor.dm
+++ b/code/game/turfs/simulated/floor/plasteel_floor.dm
@@ -12,12 +12,12 @@
/turf/simulated/floor/plasteel/airless
name = "airless floor"
- oxygen = 0.01
- nitrogen = 0.01
+ oxygen = 0
+ nitrogen = 0
temperature = TCMB
-/turf/simulated/floor/plasteel/airless/New()
- ..()
+/turf/simulated/floor/plasteel/airless/Initialize(mapload)
+ . = ..()
name = "floor"
/turf/simulated/floor/plasteel/airless/indestructible // For bomb testing range
@@ -41,6 +41,11 @@
/turf/simulated/floor/plasteel/dark
icon_state = "darkfull"
+/turf/simulated/floor/plasteel/dark/telecomms
+ nitrogen = 100
+ oxygen = 0
+ temperature = 80
+
/turf/simulated/floor/plasteel/freezer
icon_state = "freezerfloor"
diff --git a/code/game/turfs/simulated/floor/plating.dm b/code/game/turfs/simulated/floor/plating.dm
index 588a8387474..a6dbe0de281 100644
--- a/code/game/turfs/simulated/floor/plating.dm
+++ b/code/game/turfs/simulated/floor/plating.dm
@@ -14,17 +14,17 @@
"xeno" = list('sound/effects/footstep/plating_xeno.ogg')
)
-/turf/simulated/floor/plating/New()
- ..()
+/turf/simulated/floor/plating/Initialize(mapload)
+ . = ..()
icon_plating = icon_state
update_icon()
-/turf/simulated/floor/plating/damaged/New()
- ..()
+/turf/simulated/floor/plating/damaged/Initialize(mapload)
+ . = ..()
break_tile()
-/turf/simulated/floor/plating/burnt/New()
- ..()
+/turf/simulated/floor/plating/burnt/Initialize(mapload)
+ . = ..()
burn_tile()
/turf/simulated/floor/plating/update_icon()
@@ -113,12 +113,12 @@
/turf/simulated/floor/plating/airless
icon_state = "plating"
name = "airless plating"
- oxygen = 0.01
- nitrogen = 0.01
+ oxygen = 0
+ nitrogen = 0
temperature = TCMB
-/turf/simulated/floor/plating/airless/New()
- ..()
+/turf/simulated/floor/plating/airless/Initialize(mapload)
+ . = ..()
name = "plating"
/turf/simulated/floor/engine
@@ -190,8 +190,8 @@
name = "engraved floor"
icon_state = "cult"
-/turf/simulated/floor/engine/cult/New()
- ..()
+/turf/simulated/floor/engine/cult/Initialize(mapload)
+ . = ..()
if(SSticker.mode)//only do this if the round is going..otherwise..fucking asteroid..
icon_state = SSticker.cultdat.cult_floor_icon_state
@@ -205,16 +205,41 @@
color = "#FAE48C"
animate(src, color = previouscolor, time = 8)
-/turf/simulated/floor/engine/n20/New()
- ..()
- var/datum/gas_mixture/adding = new
- var/datum/gas/sleeping_agent/trace_gas = new
+//air filled floors; used in atmos pressure chambers
- trace_gas.moles = 6000
- adding.trace_gases += trace_gas
- adding.temperature = T20C
+/turf/simulated/floor/engine/n20
+ name = "\improper N2O floor"
+ sleeping_agent = 6000
+ oxygen = 0
+ nitrogen = 0
+
+/turf/simulated/floor/engine/co2
+ name = "\improper CO2 floor"
+ carbon_dioxide = 50000
+ oxygen = 0
+ nitrogen = 0
+
+/turf/simulated/floor/engine/plasma
+ name = "plasma floor"
+ toxins = 70000
+ oxygen = 0
+ nitrogen = 0
+
+/turf/simulated/floor/engine/o2
+ name = "\improper O2 floor"
+ oxygen = 100000
+ nitrogen = 0
+
+/turf/simulated/floor/engine/n2
+ name = "\improper N2 floor"
+ nitrogen = 100000
+ oxygen = 0
+
+/turf/simulated/floor/engine/air
+ name = "air floor"
+ oxygen = 2644
+ nitrogen = 10580
- assume_air(adding)
/turf/simulated/floor/engine/singularity_pull(S, current_size)
..()
@@ -250,8 +275,8 @@
icon = 'icons/turf/floors/ironsand.dmi'
icon_state = "ironsand1"
-/turf/simulated/floor/plating/ironsand/New()
- ..()
+/turf/simulated/floor/plating/ironsand/Initialize(mapload)
+ . = ..()
icon_state = "ironsand[rand(1,15)]"
/turf/simulated/floor/plating/ironsand/remove_plating()
@@ -334,8 +359,8 @@
name = "alien floor"
icon_state = "alienpod1"
-/turf/simulated/floor/plating/abductor/New()
- ..()
+/turf/simulated/floor/plating/abductor/Initialize(mapload)
+ . = ..()
icon_state = "alienpod[rand(1,9)]"
/turf/simulated/floor/plating/ice
diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm
index c18acf19d0a..23d0c9789bd 100644
--- a/code/game/turfs/simulated/walls.dm
+++ b/code/game/turfs/simulated/walls.dm
@@ -34,7 +34,6 @@
var/sheet_type = /obj/item/stack/sheet/metal
var/sheet_amount = 2
var/girder_type = /obj/structure/girder
- var/obj/item/stack/sheet/builtin_sheet = null
canSmoothWith = list(
/turf/simulated/wall,
@@ -46,10 +45,6 @@
/turf/simulated/wall/r_wall/coated)
smooth = SMOOTH_TRUE
-/turf/simulated/wall/New()
- ..()
- builtin_sheet = new sheet_type
-
/turf/simulated/wall/BeforeChange()
for(var/obj/effect/overlay/wall_rot/WR in src)
qdel(WR)
diff --git a/code/game/turfs/simulated/walls_misc.dm b/code/game/turfs/simulated/walls_misc.dm
index d2d7f8386ee..56908a7ecae 100644
--- a/code/game/turfs/simulated/walls_misc.dm
+++ b/code/game/turfs/simulated/walls_misc.dm
@@ -3,15 +3,14 @@
desc = "A cold metal wall engraved with indecipherable symbols. Studying them causes your head to pound."
icon = 'icons/turf/walls/cult_wall.dmi'
icon_state = "cult"
- builtin_sheet = null
canSmoothWith = null
smooth = SMOOTH_FALSE
sheet_type = /obj/item/stack/sheet/runed_metal
sheet_amount = 1
girder_type = /obj/structure/girder/cult
-/turf/simulated/wall/cult/New()
- ..()
+/turf/simulated/wall/cult/Initialize(mapload)
+ . = ..()
if(SSticker.mode)//game hasn't started offically don't do shit..
new /obj/effect/temp_visual/cult/turf(src)
icon_state = SSticker.cultdat.cult_wall_icon_state
@@ -73,10 +72,7 @@
realappearance.linked = src
/turf/simulated/wall/clockwork/Destroy()
- if(realappearance)
- qdel(realappearance)
- realappearance = null
-
+ QDEL_NULL(realappearance)
return ..()
/turf/simulated/wall/clockwork/ReplaceWithLattice()
diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm
index f78f520cfd3..1a8ccdae550 100644
--- a/code/game/turfs/space/space.dm
+++ b/code/game/turfs/space/space.dm
@@ -21,6 +21,11 @@
/turf/space/Initialize(mapload)
if(!istype(src, /turf/space/transit))
icon_state = SPACE_ICON_STATE
+ vis_contents.Cut() //removes inherited overlays
+
+ if(initialized)
+ stack_trace("Warning: [src]([type]) initialized multiple times!")
+ initialized = TRUE
var/area/A = loc
if(!IS_DYNAMIC_LIGHTING(src) && IS_DYNAMIC_LIGHTING(A))
@@ -34,12 +39,6 @@
return INITIALIZE_HINT_NORMAL
-/turf/space/Destroy(force)
- if(force)
- . = ..()
- else
- return QDEL_HINT_LETMELIVE
-
/turf/space/BeforeChange()
..()
var/datum/space_level/S = GLOB.space_manager.get_zlev(z)
diff --git a/code/game/turfs/space/transit.dm b/code/game/turfs/space/transit.dm
index 2a14230d467..a96cbae1269 100644
--- a/code/game/turfs/space/transit.dm
+++ b/code/game/turfs/space/transit.dm
@@ -125,9 +125,9 @@
/turf/space/transit/attackby()
return
-/turf/space/transit/New()
+/turf/space/transit/Initialize(mapload)
+ . = ..()
update_icon()
- ..()
/turf/space/transit/proc/update_icon()
var/p = 9
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index defd6720e7d..e174634123d 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -3,15 +3,18 @@
level = 1
luminosity = 1
- var/intact = 1
+ var/intact = TRUE
var/turf/baseturf = /turf/space
var/slowdown = 0 //negative for faster, positive for slower
- //Properties for open tiles (/floor)
+ ///Properties for open tiles (/floor)
+ /// All the gas vars, on the turf, are meant to be utilized for initializing a gas datum and setting its first gas values; the turf vars are never further modified at runtime; it is never directly used for calculations by the atmospherics system.
var/oxygen = 0
var/carbon_dioxide = 0
var/nitrogen = 0
var/toxins = 0
+ var/sleeping_agent = 0
+ var/agent_b = 0
//Properties for airtight tiles (/wall)
var/thermal_conductivity = 0.05
@@ -28,21 +31,29 @@
var/image/obscured //camerachunks
+ var/changing_turf = FALSE
+
var/list/blueprint_data //for the station blueprints, images of objects eg: pipes
- var/list/footstep_sounds = list()
+ var/list/footstep_sounds
var/shoe_running_volume = 50
var/shoe_walking_volume = 20
-/turf/New()
- ..()
+/turf/Initialize(mapload)
+ if(initialized)
+ stack_trace("Warning: [src]([type]) initialized multiple times!")
+ initialized = TRUE
+
+ // by default, vis_contents is inherited from the turf that was here before
+ vis_contents.Cut()
+
+ levelupdate()
+ if(smooth)
+ queue_smooth(src)
+ visibilityChanged()
+
for(var/atom/movable/AM in src)
Entered(AM)
- if(smooth && SSticker && SSticker.current_state == GAME_STATE_PLAYING)
- queue_smooth(src)
-
-/turf/Initialize(mapload)
- . = ..()
var/area/A = loc
if(!IS_DYNAMIC_LIGHTING(src) && IS_DYNAMIC_LIGHTING(A))
@@ -51,9 +62,11 @@
if(light_power && light_range)
update_light()
- if (opacity)
+ if(opacity)
has_opaque_atom = TRUE
+ return INITIALIZE_HINT_NORMAL
+
/hook/startup/proc/smooth_world()
var/watch = start_watch()
log_startup_progress("Smoothing atoms...")
@@ -65,24 +78,37 @@
if(AA.smooth)
queue_smooth(AA)
log_startup_progress(" Smoothed atoms in [stop_watch(watch)]s.")
- return 1
+ return TRUE
-/turf/Destroy()
-// Adds the adjacent turfs to the current atmos processing
- if(SSair)
- for(var/direction in GLOB.cardinal)
- if(atmos_adjacent_turfs & direction)
- var/turf/simulated/T = get_step(src, direction)
- if(istype(T))
- SSair.add_to_active(T)
+/turf/Destroy(force)
+ . = QDEL_HINT_IWILLGC
+ if(!changing_turf)
+ stack_trace("Incorrect turf deletion")
+ changing_turf = FALSE
+ if(force)
+ ..()
+ //this will completely wipe turf state
+ var/turf/B = new world.turf(src)
+ for(var/A in B.contents)
+ qdel(A)
+ return
+ // Adds the adjacent turfs to the current atmos processing
+ for(var/direction in GLOB.cardinal)
+ if(atmos_adjacent_turfs & direction)
+ var/turf/simulated/T = get_step(src, direction)
+ if(istype(T))
+ SSair.add_to_active(T)
+ SSair.remove_from_active(src)
+ visibilityChanged()
+ QDEL_LIST(blueprint_data)
+ initialized = FALSE
..()
- return QDEL_HINT_HARDDEL_NOW
/turf/attack_hand(mob/user as mob)
user.Move_Pulled(src)
/turf/ex_act(severity)
- return 0
+ return FALSE
/turf/rpd_act(mob/user, obj/item/rpd/our_rpd) //This is the default turf behaviour for the RPD; override it as required
if(our_rpd.mode == RPD_ATMOS_MODE)
@@ -100,55 +126,53 @@
else if(our_rpd.mode == RPD_DELETE_MODE)
our_rpd.delete_all_pipes(user, src)
-/turf/bullet_act(var/obj/item/projectile/Proj)
- if(istype(Proj ,/obj/item/projectile/beam/pulse))
+/turf/bullet_act(obj/item/projectile/Proj)
+ if(istype(Proj, /obj/item/projectile/beam/pulse))
src.ex_act(2)
..()
- return 0
+ return FALSE
-/turf/bullet_act(var/obj/item/projectile/Proj)
- if(istype(Proj ,/obj/item/projectile/bullet/gyro))
+/turf/bullet_act(obj/item/projectile/Proj)
+ if(istype(Proj, /obj/item/projectile/bullet/gyro))
explosion(src, -1, 0, 2)
..()
- return 0
+ return FALSE
-/turf/Enter(atom/movable/mover as mob|obj, atom/forget as mob|obj|turf|area)
+/turf/Enter(atom/movable/mover as mob|obj, atom/forget)
if(!mover)
- return 1
-
+ return TRUE
// First, make sure it can leave its square
if(isturf(mover.loc))
// Nothing but border objects stop you from leaving a tile, only one loop is needed
for(var/obj/obstacle in mover.loc)
if(!obstacle.CheckExit(mover, src) && obstacle != mover && obstacle != forget)
- mover.Bump(obstacle, 1)
- return 0
+ mover.Bump(obstacle, TRUE)
+ return FALSE
var/list/large_dense = list()
//Next, check objects to block entry that are on the border
for(var/atom/movable/border_obstacle in src)
- if(border_obstacle.flags&ON_BORDER)
- if(!border_obstacle.CanPass(mover, mover.loc, 1, 0) && (forget != border_obstacle))
- mover.Bump(border_obstacle, 1)
- return 0
+ if(border_obstacle.flags & ON_BORDER)
+ if(!border_obstacle.CanPass(mover, mover.loc, 1) && (forget != border_obstacle))
+ mover.Bump(border_obstacle, TRUE)
+ return FALSE
else
large_dense += border_obstacle
//Then, check the turf itself
if(!src.CanPass(mover, src))
- mover.Bump(src, 1)
- return 0
+ mover.Bump(src, TRUE)
+ return FALSE
//Finally, check objects/mobs to block entry that are not on the border
for(var/atom/movable/obstacle in large_dense)
- if(!obstacle.CanPass(mover, mover.loc, 1, 0) && (forget != obstacle))
- mover.Bump(obstacle, 1)
- return 0
- return 1 //Nothing found to block so return success!
+ if(!obstacle.CanPass(mover, mover.loc, 1) && (forget != obstacle))
+ mover.Bump(obstacle, TRUE)
+ return FALSE
+ return TRUE //Nothing found to block so return success!
-
-/turf/Entered(atom/movable/M, atom/OL, ignoreRest = 0)
+/turf/Entered(atom/movable/M, atom/OL, ignoreRest = FALSE)
..()
if(ismob(M))
var/mob/O = M
@@ -161,7 +185,7 @@
if(loopsanity == 0)
break
loopsanity--
- A.HasProximity(M, 1)
+ A.HasProximity(M)
// If an opaque movable atom moves around we need to potentially update visibility.
if(M.opacity)
@@ -177,7 +201,7 @@
/turf/space/levelupdate()
for(var/obj/O in src)
if(O.level == 1)
- O.hide(0)
+ O.hide(FALSE)
// Removes all signs of lattice on the pos of the turf -Donkieyo
/turf/proc/RemoveLattice()
@@ -208,10 +232,10 @@
var/old_corners = corners
BeforeChange()
- if(SSair)
- SSair.remove_from_active(src)
var/old_baseturf = baseturf
+ changing_turf = TRUE
+ qdel(src) //Just get the side effects and call Destroy
var/turf/W = new path(src)
W.baseturf = old_baseturf
@@ -224,7 +248,6 @@
if(SSlighting.initialized)
recalc_atom_opacity()
lighting_object = old_lighting_object
-
affecting_lights = old_affecting_lights
corners = old_corners
if(old_opacity != opacity || dynamic_lighting != old_dynamic_lighting)
@@ -247,7 +270,7 @@
return
// I'm including `ignore_air` because BYOND lacks positional-only arguments
-/turf/proc/AfterChange(ignore_air, keep_cabling = FALSE) //called after a turf has been replaced in ChangeTurf()
+/turf/proc/AfterChange(ignore_air = FALSE, keep_cabling = FALSE) //called after a turf has been replaced in ChangeTurf()
levelupdate()
CalculateAdjacentTurfs()
@@ -258,7 +281,7 @@
for(var/obj/structure/cable/C in contents)
qdel(C)
-/turf/simulated/AfterChange(ignore_air, keep_cabling = FALSE)
+/turf/simulated/AfterChange(ignore_air = FALSE, keep_cabling = FALSE)
..()
RemoveLattice()
if(!ignore_air)
@@ -267,32 +290,38 @@
//////Assimilate Air//////
/turf/simulated/proc/Assimilate_Air()
if(air)
- var/aoxy = 0//Holders to assimilate air from nearby turfs
+ var/aoxy = 0 //Holders to assimilate air from nearby turfs
var/anitro = 0
var/aco = 0
var/atox = 0
+ var/asleep = 0
+ var/ab = 0
var/atemp = 0
var/turf_count = 0
for(var/direction in GLOB.cardinal)//Only use cardinals to cut down on lag
- var/turf/T = get_step(src,direction)
- if(istype(T,/turf/space))//Counted as no air
+ var/turf/T = get_step(src, direction)
+ if(istype(T, /turf/space))//Counted as no air
turf_count++//Considered a valid turf for air calcs
continue
- else if(istype(T,/turf/simulated/floor))
+ else if(istype(T, /turf/simulated/floor))
var/turf/simulated/S = T
if(S.air)//Add the air's contents to the holders
aoxy += S.air.oxygen
anitro += S.air.nitrogen
aco += S.air.carbon_dioxide
atox += S.air.toxins
+ asleep += S.air.sleeping_agent
+ ab += S.air.agent_b
atemp += S.air.temperature
turf_count++
- air.oxygen = (aoxy/max(turf_count,1))//Averages contents of the turfs, ignoring walls and the like
- air.nitrogen = (anitro/max(turf_count,1))
- air.carbon_dioxide = (aco/max(turf_count,1))
- air.toxins = (atox/max(turf_count,1))
- air.temperature = (atemp/max(turf_count,1))//Trace gases can get bant
+ air.oxygen = (aoxy / max(turf_count, 1)) //Averages contents of the turfs, ignoring walls and the like
+ air.nitrogen = (anitro / max(turf_count, 1))
+ air.carbon_dioxide = (aco / max(turf_count, 1))
+ air.toxins = (atox / max(turf_count, 1))
+ air.sleeping_agent = (asleep / max(turf_count, 1))
+ air.agent_b = (ab / max(turf_count, 1))
+ air.temperature = (atemp / max(turf_count, 1))
if(SSair)
SSair.add_to_active(src)
@@ -306,12 +335,11 @@
/turf/proc/kill_creatures(mob/U = null)//Will kill people/creatures and damage mechs./N
//Useful to batch-add creatures to the list.
for(var/mob/living/M in src)
- if(M==U) continue//Will not harm U. Since null != M, can be excluded to kill everyone.
- spawn(0)
- M.gib()
+ if(M == U)
+ continue//Will not harm U. Since null != M, can be excluded to kill everyone.
+ INVOKE_ASYNC(M, /mob/.proc/gib)
for(var/obj/mecha/M in src)//Mecha are not gibbed but are damaged.
- spawn(0)
- M.take_damage(100, "brute")
+ INVOKE_ASYNC(M, /obj/mecha/.proc/take_damage, 100, "brute")
/turf/proc/Bless()
flags |= NOJAUNT
@@ -368,11 +396,11 @@
// Returns the surrounding simulated turfs with open links
// Including through doors openable with the ID
-/turf/proc/AdjacentTurfsWithAccess(var/obj/item/card/id/ID = null,var/list/closed)//check access if one is passed
+/turf/proc/AdjacentTurfsWithAccess(obj/item/card/id/ID = null, list/closed)//check access if one is passed
var/list/L = new()
var/turf/simulated/T
- for(var/dir in list(NORTHWEST,NORTHEAST,SOUTHEAST,SOUTHWEST,NORTH,EAST,SOUTH,WEST)) //arbitrarily ordered list to favor non-diagonal moves in case of ties
- T = get_step(src,dir)
+ for(var/dir in GLOB.alldirs2) //arbitrarily ordered list to favor non-diagonal moves in case of ties
+ T = get_step(src, dir)
if(T in closed) //turf already proceeded in A*
continue
if(istype(T) && !T.density)
@@ -381,11 +409,11 @@
return L
//Idem, but don't check for ID and goes through open doors
-/turf/proc/AdjacentTurfs(var/list/closed)
+/turf/proc/AdjacentTurfs(list/closed)
var/list/L = new()
var/turf/simulated/T
- for(var/dir in list(NORTHWEST,NORTHEAST,SOUTHEAST,SOUTHWEST,NORTH,EAST,SOUTH,WEST)) //arbitrarily ordered list to favor non-diagonal moves in case of ties
- T = get_step(src,dir)
+ for(var/dir in GLOB.alldirs2) //arbitrarily ordered list to favor non-diagonal moves in case of ties
+ T = get_step(src, dir)
if(T in closed) //turf already proceeded by A*
continue
if(istype(T) && !T.density)
@@ -394,11 +422,11 @@
return L
// check for all turfs, including unsimulated ones
-/turf/proc/AdjacentTurfsSpace(var/obj/item/card/id/ID = null, var/list/closed)//check access if one is passed
+/turf/proc/AdjacentTurfsSpace(obj/item/card/id/ID = null, list/closed)//check access if one is passed
var/list/L = new()
var/turf/T
- for(var/dir in list(NORTHWEST,NORTHEAST,SOUTHEAST,SOUTHWEST,NORTH,EAST,SOUTH,WEST)) //arbitrarily ordered list to favor non-diagonal moves in case of ties
- T = get_step(src,dir)
+ for(var/dir in GLOB.alldirs2) //arbitrarily ordered list to favor non-diagonal moves in case of ties
+ T = get_step(src, dir)
if(T in closed) //turf already proceeded by A*
continue
if(istype(T) && !T.density)
@@ -415,20 +443,21 @@
//////////////////////////////
//Distance associates with all directions movement
-/turf/proc/Distance(var/turf/T)
- return get_dist(src,T)
+/turf/proc/Distance(turf/T)
+ return get_dist(src, T)
// This Distance proc assumes that only cardinal movement is
// possible. It results in more efficient (CPU-wise) pathing
// for bots and anything else that only moves in cardinal dirs.
/turf/proc/Distance_cardinal(turf/T)
- if(!src || !T) return 0
+ if(!src || !T)
+ return 0
return abs(src.x - T.x) + abs(src.y - T.y)
////////////////////////////////////////////////////
/turf/acid_act(acidpwr, acid_volume)
- . = 1
+ . = TRUE
var/acid_type = /obj/effect/acid
if(acidpwr >= 200) //alien acid power
acid_type = /obj/effect/acid/alien
@@ -453,7 +482,7 @@
if(!forced)
return
if(has_gravity(src))
- playsound(src, "bodyfall", 50, 1)
+ playsound(src, "bodyfall", 50, TRUE)
/turf/singularity_act()
if(intact)
@@ -463,7 +492,7 @@
if(O.invisibility == INVISIBILITY_MAXIMUM)
O.singularity_act()
ChangeTurf(baseturf)
- return(2)
+ return 2
/turf/proc/visibilityChanged()
if(SSticker)
@@ -474,25 +503,25 @@
if(istype(I, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/C = I
for(var/obj/structure/cable/LC in src)
- if(LC.d1 == 0 || LC.d2==0)
- LC.attackby(C,user)
+ if(LC.d1 == 0 || LC.d2 == 0)
+ LC.attackby(C, user)
return
C.place_turf(src, user)
- return 1
+ return TRUE
else if(istype(I, /obj/item/twohanded/rcl))
var/obj/item/twohanded/rcl/R = I
if(R.loaded)
for(var/obj/structure/cable/LC in src)
- if(LC.d1 == 0 || LC.d2==0)
+ if(LC.d1 == 0 || LC.d2 == 0)
LC.attackby(R, user)
return
R.loaded.place_turf(src, user)
R.is_empty(user)
- return 0
+ return FALSE
/turf/proc/can_have_cabling()
- return 1
+ return TRUE
/turf/proc/can_lay_cable()
return can_have_cabling() & !intact
@@ -517,18 +546,15 @@
I.appearance = AM.appearance
I.appearance_flags = RESET_COLOR|RESET_ALPHA|RESET_TRANSFORM
I.loc = src
- I.dir = AM.dir
+ I.setDir(AM.dir)
I.alpha = 128
-
- if(!blueprint_data)
- blueprint_data = list()
- blueprint_data += I
+ LAZYADD(blueprint_data, I)
/turf/proc/add_blueprints_preround(atom/movable/AM)
if(!SSticker || SSticker.current_state != GAME_STATE_PLAYING)
add_blueprints(AM)
-/turf/proc/empty(turf_type=/turf/space)
+/turf/proc/empty(turf_type = /turf/space)
// Remove all atoms except observers, landmarks, docking ports, and (un)`simulated` atoms (lighting overlays)
var/turf/T0 = src
for(var/X in T0.GetAllContents())
@@ -541,13 +567,13 @@
continue
if(istype(A, /obj/docking_port))
continue
- qdel(A, force=TRUE)
+ qdel(A, force = TRUE)
T0.ChangeTurf(turf_type)
SSair.remove_from_active(T0)
T0.CalculateAdjacentTurfs()
- SSair.add_to_active(T0,1)
+ SSair.add_to_active(T0, TRUE)
/turf/AllowDrop()
return TRUE
diff --git a/code/game/turfs/unsimulated.dm b/code/game/turfs/unsimulated.dm
index 688dc778ce3..02af9173e2b 100644
--- a/code/game/turfs/unsimulated.dm
+++ b/code/game/turfs/unsimulated.dm
@@ -40,6 +40,6 @@
nitrogen = 0
temperature = TCMB
-/turf/unsimulated/floor/plating/airless/New()
- ..()
+/turf/unsimulated/floor/plating/airless/Initialize(mapload)
+ . = ..()
name = "plating"
diff --git a/code/game/turfs/unsimulated/beach.dm b/code/game/turfs/unsimulated/beach.dm
index f6a3a62c324..a7c73971e99 100644
--- a/code/game/turfs/unsimulated/beach.dm
+++ b/code/game/turfs/unsimulated/beach.dm
@@ -3,9 +3,9 @@
icon = 'icons/misc/beach.dmi'
var/water_overlay_image = null
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
-
-/turf/unsimulated/beach/New()
- ..()
+
+/turf/unsimulated/beach/Initialize(mapload)
+ . = ..()
if(water_overlay_image)
var/image/overlay_image = image('icons/misc/beach.dmi', icon_state = water_overlay_image, layer = ABOVE_MOB_LAYER)
overlay_image.plane = GAME_PLANE
@@ -15,10 +15,10 @@
name = "Sand"
icon_state = "desert"
mouse_opacity = MOUSE_OPACITY_ICON
-
-/turf/unsimulated/beach/sand/New() //adds some aesthetic randomness to the beach sand
+
+/turf/unsimulated/beach/sand/Initialize(mapload)
+ . = ..() //adds some aesthetic randomness to the beach sand
icon_state = pick("desert", "desert0", "desert1", "desert2", "desert3", "desert4")
- ..()
/turf/unsimulated/beach/sand/dense //for boundary "walls"
density = 1
@@ -42,7 +42,7 @@
/turf/unsimulated/beach/water/Entered(atom/movable/AM, atom/OldLoc)
. = ..()
if(!linkedcontroller)
- return
+ return
if(ismob(AM))
linkedcontroller.mobinpool += AM
@@ -79,8 +79,8 @@
/turf/unsimulated/beach/water/edge_drop)
var/obj/effect/beach_drop_overlay/water_overlay
-/turf/unsimulated/beach/water/drop/New()
- ..()
+/turf/unsimulated/beach/water/drop/Initialize(mapload)
+ . = ..()
water_overlay = new(src)
/turf/unsimulated/beach/water/drop/Destroy()
diff --git a/code/game/turfs/unsimulated/floor.dm b/code/game/turfs/unsimulated/floor.dm
index 28f4e359223..750ebe015ae 100644
--- a/code/game/turfs/unsimulated/floor.dm
+++ b/code/game/turfs/unsimulated/floor.dm
@@ -7,8 +7,8 @@
name = "grass patch"
icon_state = "grass1"
-/turf/unsimulated/floor/grass/New()
- ..()
+/turf/unsimulated/floor/grass/Initialize(mapload)
+ . = ..()
icon_state = "grass[rand(1,4)]"
/turf/unsimulated/floor/snow
@@ -20,8 +20,8 @@
name = "alien floor"
icon_state = "alienpod1"
-/turf/unsimulated/floor/abductor/New()
- ..()
+/turf/unsimulated/floor/abductor/Initialize(mapload)
+ . = ..()
icon_state = "alienpod[rand(1,9)]"
/turf/unsimulated/floor/vox
diff --git a/code/game/verbs/who.dm b/code/game/verbs/who.dm
index 2683e236269..95b11353b86 100644
--- a/code/game/verbs/who.dm
+++ b/code/game/verbs/who.dm
@@ -27,7 +27,7 @@
entry += " -
Observing"
else
entry += " -
DEAD"
- else if(istype(C.mob, /mob/new_player))
+ else if(isnewplayer(C.mob))
entry += " -
New Player"
else
entry += " -
DEAD"
@@ -90,7 +90,7 @@
if(isobserver(C.mob))
msg += " - Observing"
- else if(istype(C.mob,/mob/new_player))
+ else if(isnewplayer(C.mob))
msg += " - Lobby"
else
msg += " - Playing"
@@ -106,7 +106,7 @@
if(isobserver(C.mob))
modmsg += " - Observing"
- else if(istype(C.mob,/mob/new_player))
+ else if(isnewplayer(C.mob))
modmsg += " - Lobby"
else
modmsg += " - Playing"
diff --git a/code/game/world.dm b/code/game/world.dm
index dd9711515f8..355c6280aaf 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -1,5 +1,3 @@
-#define RECOMMENDED_VERSION 510
-
GLOBAL_LIST_INIT(map_transition_config, MAP_TRANSITION_CONFIG)
/world/New()
@@ -11,8 +9,11 @@ GLOBAL_LIST_INIT(map_transition_config, MAP_TRANSITION_CONFIG)
enable_debugger() // Enable the extools debugger
log_world("World loaded at [time_stamp()]")
log_world("[GLOB.vars.len - GLOB.gvars_datum_in_built_vars.len] global variables")
+ #ifdef UNIT_TESTS
+ log_world("Unit Tests Are Enabled!")
+ #endif
- if(byond_version < RECOMMENDED_VERSION)
+ if(byond_version < MIN_COMPILER_VERSION || byond_build < MIN_COMPILER_BUILD)
log_world("Your server's byond version does not meet the recommended requirements for this code. Please update BYOND")
if(config && config.server_name != null && config.server_suffix && world.port > 0)
@@ -35,8 +36,9 @@ GLOBAL_LIST_INIT(map_transition_config, MAP_TRANSITION_CONFIG)
Master.Initialize(10, FALSE)
-
-#undef RECOMMENDED_VERSION
+ #ifdef UNIT_TESTS
+ HandleTestRun()
+ #endif
return
@@ -230,7 +232,7 @@ GLOBAL_VAR_INIT(world_topic_spam_protect_time, world.timeofday)
if(!C)
return "No client with that name on server"
- del(C)
+ qdel(C)
return "Kick Successful"
@@ -315,6 +317,11 @@ GLOBAL_VAR_INIT(world_topic_spam_protect_time, world.timeofday)
GLOB.dbcon.Disconnect() // DCs cleanly from the database
shutdown_logging() // Past this point, no logging procs can be used, at risk of data loss.
+ #ifdef UNIT_TESTS
+ FinishTestRun()
+ return
+ #endif
+
for(var/client/C in GLOB.clients)
if(config.server) //if you set a server location in config.txt, it sends you there instead of trying to reconnect to the same world address. -- NeoFite
C << link("byond://[config.server]")
@@ -418,10 +425,12 @@ GLOBAL_VAR_INIT(failed_old_db_connections, 0)
GLOB.world_runtime_log = "[GLOB.log_directory]/runtime.log"
GLOB.world_qdel_log = "[GLOB.log_directory]/qdel.log"
GLOB.world_asset_log = "[GLOB.log_directory]/asset.log"
+ GLOB.tgui_log = "[GLOB.log_directory]/tgui.log"
start_log(GLOB.world_game_log)
start_log(GLOB.world_href_log)
start_log(GLOB.world_runtime_log)
start_log(GLOB.world_qdel_log)
+ start_log(GLOB.tgui_log)
// This log follows a special format and this path should NOT be used for anything else
GLOB.runtime_summary_log = "data/logs/runtime_summary.log"
diff --git a/code/modules/admin/DB ban/functions.dm b/code/modules/admin/DB ban/functions.dm
index 21b59586bfd..25693b58f47 100644
--- a/code/modules/admin/DB ban/functions.dm
+++ b/code/modules/admin/DB ban/functions.dm
@@ -146,7 +146,7 @@ datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration =
if(kickbannedckey)
if(banned_mob && banned_mob.client && banned_mob.client.ckey == banckey)
- del(banned_mob.client)
+ qdel(banned_mob.client)
if(isjobban)
jobban_client_fullban(ckey, job)
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index df156c5b0df..1eed8083a97 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -72,7 +72,7 @@ GLOBAL_VAR_INIT(nologevent, 0)
body += "\[
[M.client.holder ? M.client.holder.rank : "Player"]\] "
body += "\[
" + M.client.get_exp_type(EXP_TYPE_CREW) + " as [EXP_TYPE_CREW]\]"
- if(istype(M, /mob/new_player))
+ if(isnewplayer(M))
body += "
Hasn't Entered Game "
else
body += " \[
Heal\] "
@@ -147,7 +147,7 @@ GLOBAL_VAR_INIT(nologevent, 0)
body += {" |
Cryo "}
if(M.client)
- if(!istype(M, /mob/new_player))
+ if(!isnewplayer(M))
body += "
"
body += "
Transformation:"
body += "
"
@@ -1004,13 +1004,13 @@ GLOBAL_VAR_INIT(gamma_ship_location, 1) // 0 = station , 1 = space
/proc/kick_clients_in_lobby(message, kick_only_afk = 0)
var/list/kicked_client_names = list()
for(var/client/C in GLOB.clients)
- if(istype(C.mob, /mob/new_player))
+ if(isnewplayer(C.mob))
if(kick_only_afk && !C.is_afk()) //Ignore clients who are not afk
continue
if(message)
to_chat(C, message)
kicked_client_names.Add("[C.ckey]")
- del(C)
+ qdel(C)
return kicked_client_names
//returns 1 to let the dragdrop code know we are trapping this event
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 4e3d2d65f30..80a60957c75 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -337,7 +337,7 @@ GLOBAL_LIST_INIT(admin_verbs_ticket, list(
ghost.reenter_corpse()
log_admin("[key_name(usr)] re-entered their body")
feedback_add_details("admin_verb","P") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
- else if(istype(mob,/mob/new_player))
+ else if(isnewplayer(mob))
to_chat(src, "
Error: Aghost: Can't admin-ghost whilst in the lobby. Join or observe first.")
else
//ghostize
@@ -542,7 +542,7 @@ GLOBAL_LIST_INIT(admin_verbs_ticket, list(
message_admins("[key_name_admin(src)] has warned [key_name_admin(C)] resulting in a [AUTOBANTIME] minute ban")
log_admin("[key_name(src)] has warned [key_name(C)] resulting in a [AUTOBANTIME] minute ban")
to_chat(C, "
You have been autobanned due to a warning by [ckey].
This is a temporary ban, it will be removed in [AUTOBANTIME] minutes.")
- del(C)
+ qdel(C)
else
message_admins("[key_name_admin(src)] has warned [warned_ckey] resulting in a [AUTOBANTIME] minute ban")
log_admin("[key_name(src)] has warned [warned_ckey] resulting in a [AUTOBANTIME] minute ban")
diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm
index efb5ac32f97..e89b829f421 100644
--- a/code/modules/admin/player_panel.dm
+++ b/code/modules/admin/player_panel.dm
@@ -268,7 +268,7 @@
else
M_job = "Living"
- else if(istype(M,/mob/new_player))
+ else if(isnewplayer(M))
M_job = "New player"
else if(isobserver(M))
@@ -356,7 +356,7 @@
dat += "[M.real_name] | "
else if(istype(M, /mob/living/silicon/pai))
dat += "
pAI | "
- else if(istype(M, /mob/new_player))
+ else if(isnewplayer(M))
dat += "
New Player | "
else if(isobserver(M))
dat += "
Ghost | "
diff --git a/code/modules/admin/sql_notes.dm b/code/modules/admin/sql_notes.dm
index 238c380f417..a438a43eaec 100644
--- a/code/modules/admin/sql_notes.dm
+++ b/code/modules/admin/sql_notes.dm
@@ -186,9 +186,13 @@
var/err = query_list_notes.ErrorMsg()
log_game("SQL ERROR obtaining ckey from notes table. Error : \[[err]\]\n")
return
+ to_chat(usr, "
Started regex note search for [search]. Please wait for results...")
+ message_admins("[usr.ckey] has started a note search with the following regex: [search] | CPU usage may be higher.")
while(query_list_notes.NextRow())
index_ckey = query_list_notes.item[1]
output += "
[index_ckey]"
+ CHECK_TICK
+ message_admins("The note search started by [usr.ckey] has complete. CPU should return to normal.")
else
output += "
\[Add Note\]"
output += ruler
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 1a040d46e90..ac8adc5fdf0 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -909,7 +909,7 @@
log_admin("[key_name(usr)] booted [key_name(M)].")
message_admins("
[key_name_admin(usr)] booted [key_name_admin(M)].", 1)
//M.client = null
- del(M.client)
+ qdel(M.client)
//Player Notes
else if(href_list["addnote"])
@@ -1011,8 +1011,7 @@
log_admin("[key_name(usr)] has banned [M.ckey].\nReason: [reason]\nThis will be removed in [mins] minutes.")
message_admins("
[key_name_admin(usr)] has banned [M.ckey].\nReason: [reason]\nThis will be removed in [mins] minutes.")
- del(M.client)
- //qdel(M) // See no reason why to delete mob. Important stuff can be lost. And ban can be lifted before round ends.
+ qdel(M.client)
if("No")
var/reason = input(usr,"Please state the reason","Reason") as message|null
if(!reason)
@@ -1032,8 +1031,7 @@
feedback_inc("ban_perma",1)
DB_ban_record(BANTYPE_PERMA, M, -1, reason)
- del(M.client)
- //qdel(M)
+ qdel(M.client)
if("Cancel")
return
@@ -1507,7 +1505,7 @@
if(!check_rights(R_SPAWN)) return
var/mob/M = locateUID(href_list["makeanimal"])
- if(istype(M, /mob/new_player))
+ if(isnewplayer(M))
to_chat(usr, "This cannot be used on instances of type /mob/new_player")
return
if(alert(usr, "Confirm make animal?",, "Yes", "No") != "Yes")
diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2.dm b/code/modules/admin/verbs/SDQL2/SDQL_2.dm
index e2da701cf4d..018b45422c5 100644
--- a/code/modules/admin/verbs/SDQL2/SDQL_2.dm
+++ b/code/modules/admin/verbs/SDQL2/SDQL_2.dm
@@ -430,7 +430,7 @@
else if(expression[start + 1] == "\[" && islist(v))
var/list/L = v
var/index = SDQL_expression(source, expression[start + 2])
- if(isnum(index) && (!IsInteger(index) || L.len < index))
+ if(isnum(index) && (!ISINTEGER(index) || L.len < index))
to_chat(world, "
Invalid list index: [index]")
return null
return L[index]
diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm
index 164d499e04a..dba9a5c26aa 100644
--- a/code/modules/admin/verbs/adminpm.dm
+++ b/code/modules/admin/verbs/adminpm.dm
@@ -19,7 +19,7 @@
var/list/client/targets[0]
for(var/client/T)
if(T.mob)
- if(istype(T.mob, /mob/new_player))
+ if(isnewplayer(T.mob))
targets["(New Player) - [T]"] = T
else if(istype(T.mob, /mob/dead/observer))
targets["[T.mob.name](Ghost) - [T]"] = T
@@ -42,7 +42,7 @@
var/list/client/targets[0]
for(var/client/T)
if(T.mob)
- if(istype(T.mob, /mob/new_player))
+ if(isnewplayer(T.mob))
targets["[T] - (New Player)"] = T
else if(istype(T.mob, /mob/dead/observer))
targets["[T] - [T.mob.name](Ghost)"] = T
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index 329efb8e067..c58f33cc4ce 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -251,7 +251,7 @@ GLOBAL_PROTECT(AdminProcCaller)
alert("That mob doesn't seem to exist, close the panel and try again.")
return
- if(istype(M, /mob/new_player))
+ if(isnewplayer(M))
alert("The mob must not be a new_player.")
return
@@ -382,7 +382,7 @@ GLOBAL_PROTECT(AdminProcCaller)
if(!check_rights(R_DEBUG))
return
- //This gets a confirmation check because it's way easier to accidentally hit this and delete things than it is with del-all
+ //This gets a confirmation check because it's way easier to accidentally hit this and delete things than it is with qdel-all
var/confirm = alert("This will delete ALL Singularities and Tesla orbs except for any that are on away mission z-levels or the centcomm z-level. Are you sure you want to delete them?", "Confirm Panic Button", "Yes", "No")
if(confirm != "Yes")
return
@@ -816,21 +816,6 @@ GLOBAL_PROTECT(AdminProcCaller)
else
alert("Invalid mob")
-/client/proc/reload_nanoui_resources()
- set category = "Debug"
- set name = "Reload NanoUI Resources"
- set desc = "Force the client to redownload NanoUI Resources"
-
- // Close open NanoUIs.
- SSnanoui.close_user_uis(usr)
-
- // Re-load the assets.
- var/datum/asset/assets = get_asset_datum(/datum/asset/nanoui)
- assets.register()
-
- // Clear the user's cache so they get resent.
- usr.client.cache = list()
-
/client/proc/view_runtimes()
set category = "Debug"
set name = "View Runtimes"
diff --git a/code/modules/admin/verbs/diagnostics.dm b/code/modules/admin/verbs/diagnostics.dm
index ce10383ca4e..78f2647e429 100644
--- a/code/modules/admin/verbs/diagnostics.dm
+++ b/code/modules/admin/verbs/diagnostics.dm
@@ -15,9 +15,7 @@
if(T.active_hotspot)
burning = 1
- to_chat(usr, "
@[target.x],[target.y]: O:[GM.oxygen] T:[GM.toxins] N:[GM.nitrogen] C:[GM.carbon_dioxide] w [GM.temperature] Kelvin, [GM.return_pressure()] kPa [(burning)?("BURNING"):(null)]")
- for(var/datum/gas/trace_gas in GM.trace_gases)
- to_chat(usr, "[trace_gas.type]: [trace_gas.moles]")
+ to_chat(usr, "
@[target.x],[target.y]: O:[GM.oxygen] T:[GM.toxins] N:[GM.nitrogen] C:[GM.carbon_dioxide] N2O: [GM.sleeping_agent] Agent B: [GM.agent_b] w [GM.temperature] Kelvin, [GM.return_pressure()] kPa [(burning)?("BURNING"):(null)]")
message_admins("[key_name_admin(usr)] has checked the air status of [target]")
log_admin("[key_name(usr)] has checked the air status of [target]")
diff --git a/code/modules/admin/verbs/onlyoneteam.dm b/code/modules/admin/verbs/onlyoneteam.dm
index 9575cc5b340..974b65e05d2 100644
--- a/code/modules/admin/verbs/onlyoneteam.dm
+++ b/code/modules/admin/verbs/onlyoneteam.dm
@@ -73,9 +73,11 @@
..()
if((ishuman(hit_atom)))
var/mob/living/carbon/human/H = hit_atom
- if(H.r_hand == src) return
- if(H.l_hand == src) return
- var/mob/A = H.LAssailant
+ if(H.r_hand == src)
+ return
+ if(H.l_hand == src)
+ return
+ var/mob/A = thrownby
if((H in GLOB.team_alpha) && (A in GLOB.team_alpha))
to_chat(A, "
He's on your team!")
return
@@ -89,4 +91,3 @@
playsound(src, 'sound/items/dodgeball.ogg', 50, 1)
visible_message("
[H] HAS BEEN ELIMINATED!")
H.melt()
- return
diff --git a/code/modules/admin/verbs/toggledebugverbs.dm b/code/modules/admin/verbs/toggledebugverbs.dm
index 216f5c3e4b0..328b5176e9a 100644
--- a/code/modules/admin/verbs/toggledebugverbs.dm
+++ b/code/modules/admin/verbs/toggledebugverbs.dm
@@ -18,7 +18,6 @@ GLOBAL_LIST_INIT(admin_verbs_show_debug_verbs, list(
/client/proc/print_jobban_old_filter,
/client/proc/forceEvent,
/client/proc/nanomapgen_DumpImage,
- /client/proc/reload_nanoui_resources,
/client/proc/admin_redo_space_transitions,
/client/proc/make_turf_space_map,
/client/proc/vv_by_ref
diff --git a/code/modules/alarm/alarm.dm b/code/modules/alarm/alarm.dm
index 798c5176770..752d3232d23 100644
--- a/code/modules/alarm/alarm.dm
+++ b/code/modules/alarm/alarm.dm
@@ -50,7 +50,7 @@
sources_assoc[source] = AS
// Currently only non-0 durations can be altered (normal alarms VS EMP blasts)
if(AS.duration)
- duration = SecondsToTicks(duration)
+ duration = duration SECONDS
AS.duration = duration
AS.severity = severity
diff --git a/code/modules/arcade/mob_hunt/battle_computer.dm b/code/modules/arcade/mob_hunt/battle_computer.dm
index 94337a5cfac..cb144c99f01 100644
--- a/code/modules/arcade/mob_hunt/battle_computer.dm
+++ b/code/modules/arcade/mob_hunt/battle_computer.dm
@@ -80,7 +80,7 @@
/obj/machinery/computer/mob_battle_terminal/proc/eject_card(override = 0)
if(!override)
if(ready && SSmob_hunt.battle_turn != team)
- audible_message("You can't recall on your rival's turn!", null, 2)
+ atom_say("You can't recall on your rival's turn!")
return
card.mob_data = mob_info
mob_info = null
@@ -202,7 +202,7 @@
start_battle()
else if(option == 2)
ready = 0
- audible_message("[team] Player cancels their battle challenge.", null, 5)
+ atom_say("[team] Player cancels their battle challenge.")
updateUsrDialog()
@@ -246,7 +246,7 @@
var/message = "[mob_info.mob_name] attacks!"
if(mob_info.nickname)
message = "[mob_info.nickname] attacks!"
- audible_message(message, null, 5)
+ atom_say(message)
SSmob_hunt.launch_attack(team, mob_info.get_raw_damage(), mob_info.get_attack_type())
/obj/machinery/computer/mob_battle_terminal/proc/start_battle()
@@ -255,7 +255,7 @@
if(!card) //don't do anything if there isn't a card inserted
return
ready = 1
- audible_message("[team] Player is ready for battle! Waiting for rival...", null, 5)
+ atom_say("[team] Player is ready for battle! Waiting for rival...")
SSmob_hunt.start_check()
/obj/machinery/computer/mob_battle_terminal/proc/receive_attack(raw_damage, datum/mob_type/attack_type)
@@ -268,7 +268,7 @@
SSmob_hunt.end_turn()
/obj/machinery/computer/mob_battle_terminal/proc/surrender()
- audible_message("[team] Player surrenders the battle!", null, 5)
+ atom_say("[team] Player surrenders the battle!")
SSmob_hunt.end_battle(team, 1)
//////////////////////////////
diff --git a/code/modules/arcade/mob_hunt/mob_avatar.dm b/code/modules/arcade/mob_hunt/mob_avatar.dm
index 89eda41be7c..d1077bc81e1 100644
--- a/code/modules/arcade/mob_hunt/mob_avatar.dm
+++ b/code/modules/arcade/mob_hunt/mob_avatar.dm
@@ -55,7 +55,7 @@
var/datum/data/pda/app/mob_hunter_game/client = P.current_app
var/total_catch_mod = client.catch_mod + catch_mod //negative values decrease the chance of the mob running, positive values makes it more likely to flee
if(!client.connected) //must be connected to attempt captures
- P.audible_message("[bicon(P)] No server connection. Capture aborted.", null, 4)
+ P.atom_say("No server connection. Capture aborted.")
return
if(mob_info.is_trap) //traps work even if you ran into them before, which is why this is before the clients_encountered check
@@ -79,7 +79,7 @@
return
else //deal with the new hunter by either running away or getting caught
clients_encountered += client
- var/message = "[bicon(P)] "
+ var/message = null
var/effective_run_chance = mob_info.run_chance + total_catch_mod
if((effective_run_chance > 0) && prob(effective_run_chance))
message += "Capture failed! [name] escaped [P.owner ? "from [P.owner]" : "from this hunter"]!"
@@ -91,7 +91,7 @@
else
message += "Capture error! Try again."
clients_encountered -= client //if the capture registration failed somehow, let them have another chance with this mob
- P.audible_message(message, null, 4)
+ P.atom_say(message)
/obj/effect/nanomob/proc/despawn()
if(SSmob_hunt)
diff --git a/code/modules/arcade/mob_hunt/mob_datums.dm b/code/modules/arcade/mob_hunt/mob_datums.dm
index a50fab183e6..25a4569ede9 100644
--- a/code/modules/arcade/mob_hunt/mob_datums.dm
+++ b/code/modules/arcade/mob_hunt/mob_datums.dm
@@ -139,7 +139,7 @@
for(var/areapath in typesof(A))
possible_areas[areapath] -= 2
//removes "bad areas" which shouldn't be on-station but are subtypes of station areas. probably should the unused ones and consider repathing the rest
- var/list/bad_areas = list(subtypesof(/area/construction), /area/solar/derelict_starboard, /area/solar/derelict_aft, /area/solar/constructionsite)
+ var/list/bad_areas = list(subtypesof(/area/construction), /area/solar/derelict_starboard, /area/solar/derelict_aft)
for(var/A in bad_areas)
possible_areas -= A
//weight check, remove negative or zero weight areas from the list, then return the list.
diff --git a/code/modules/assembly/assembly.dm b/code/modules/assembly/assembly.dm
index 827e7893396..5fea7baa019 100644
--- a/code/modules/assembly/assembly.dm
+++ b/code/modules/assembly/assembly.dm
@@ -59,8 +59,7 @@
cooldown--
if(cooldown <= 0)
return FALSE
- spawn(10)
- process_cooldown()
+ addtimer(CALLBACK(src, .proc/process_cooldown), 10)
return TRUE
/obj/item/assembly/Destroy()
@@ -94,8 +93,7 @@
if(!secured || cooldown > 0)
return FALSE
cooldown = 2
- spawn(10)
- process_cooldown()
+ addtimer(CALLBACK(src, .proc/process_cooldown), 10)
return TRUE
/obj/item/assembly/toggle_secure()
diff --git a/code/modules/assembly/health.dm b/code/modules/assembly/health.dm
index a83df5501c9..a0a7c43a7a9 100644
--- a/code/modules/assembly/health.dm
+++ b/code/modules/assembly/health.dm
@@ -55,7 +55,7 @@
health_scan = M.health
if(health_scan <= alarm_health)
pulse()
- audible_message("[bicon(src)] *beep* *beep*", "*beep* *beep*")
+ audible_message("[bicon(src)] *beep* *beep*")
toggle_scan()
return
return
diff --git a/code/modules/assembly/infrared.dm b/code/modules/assembly/infrared.dm
index 19263e010ab..9de2f32ed6f 100644
--- a/code/modules/assembly/infrared.dm
+++ b/code/modules/assembly/infrared.dm
@@ -127,13 +127,12 @@
/obj/item/assembly/infra/proc/trigger_beam()
if(!secured || !on || cooldown > 0)
return FALSE
- pulse(0)
- audible_message("[bicon(src)] *beep* *beep*", null, 3)
+ cooldown = 2
+ pulse(FALSE)
+ audible_message("[bicon(src)] *beep* *beep*", hearing_distance = 3)
if(first)
qdel(first)
- cooldown = 2
- spawn(10)
- process_cooldown()
+ addtimer(CALLBACK(src, .proc/process_cooldown), 10)
/obj/item/assembly/infra/interact(mob/user)//TODO: change this this to the wire control panel
if(!secured) return
diff --git a/code/modules/assembly/proximity.dm b/code/modules/assembly/proximity.dm
index 7e777f235b1..caefabcb1f8 100644
--- a/code/modules/assembly/proximity.dm
+++ b/code/modules/assembly/proximity.dm
@@ -47,11 +47,10 @@
/obj/item/assembly/prox_sensor/proc/sense()
if(!secured || !scanning || cooldown > 0)
return FALSE
- pulse(0)
- visible_message("[bicon(src)] *beep* *beep*", "*beep* *beep*")
cooldown = 2
- spawn(10)
- process_cooldown()
+ pulse(FALSE)
+ visible_message("[bicon(src)] *beep* *beep*", "*beep* *beep*")
+ addtimer(CALLBACK(src, .proc/process_cooldown), 10)
/obj/item/assembly/prox_sensor/process()
if(timing && (time >= 0))
diff --git a/code/modules/assembly/signaler.dm b/code/modules/assembly/signaler.dm
index f774d28921f..2759d12c21a 100644
--- a/code/modules/assembly/signaler.dm
+++ b/code/modules/assembly/signaler.dm
@@ -41,8 +41,7 @@
if(cooldown > 0)
return FALSE
cooldown = 2
- spawn(10)
- process_cooldown()
+ addtimer(CALLBACK(src, .proc/process_cooldown), 10)
signal()
return TRUE
diff --git a/code/modules/assembly/timer.dm b/code/modules/assembly/timer.dm
index cab132ab747..5bbd9a26538 100644
--- a/code/modules/assembly/timer.dm
+++ b/code/modules/assembly/timer.dm
@@ -39,12 +39,11 @@
/obj/item/assembly/timer/proc/timer_end()
if(!secured || cooldown > 0)
return FALSE
- pulse(0)
+ cooldown = 2
+ pulse(FALSE)
if(loc)
loc.visible_message("[bicon(src)] *beep* *beep*", "*beep* *beep*")
- cooldown = 2
- spawn(10)
- process_cooldown()
+ addtimer(CALLBACK(src, .proc/process_cooldown), 10)
/obj/item/assembly/timer/process()
if(timing && (time > 0))
diff --git a/code/modules/awaymissions/mission_code/centcomAway.dm b/code/modules/awaymissions/mission_code/centcomAway.dm
index bd9890aa43a..92fa90891e0 100644
--- a/code/modules/awaymissions/mission_code/centcomAway.dm
+++ b/code/modules/awaymissions/mission_code/centcomAway.dm
@@ -7,32 +7,32 @@
/area/awaymission/centcomAway/general
name = "XCC-P5831"
- music = "music/ambigen3.ogg"
+ ambientsounds = list('sound/ambience/ambigen3.ogg')
/area/awaymission/centcomAway/maint
name = "XCC-P5831 Maintenance"
icon_state = "away1"
- music = "music/ambisin1.ogg"
+ ambientsounds = list('sound/ambience/ambisin1.ogg')
/area/awaymission/centcomAway/thunderdome
name = "XCC-P5831 Thunderdome"
icon_state = "away2"
- music = "music/ambisin2.ogg"
+ ambientsounds = list('sound/ambience/ambisin2.ogg')
/area/awaymission/centcomAway/cafe
name = "XCC-P5831 Kitchen Arena"
icon_state = "away3"
- music = "music/ambisin3.ogg"
+ ambientsounds = list('sound/ambience/ambisin3.ogg')
/area/awaymission/centcomAway/courtroom
name = "XCC-P5831 Courtroom"
icon_state = "away4"
- music = "music/ambisin4.ogg"
+ ambientsounds = list('sound/ambience/ambisin4.ogg')
/area/awaymission/centcomAway/hangar
name = "XCC-P5831 Hangars"
icon_state = "away4"
- music = "music/ambigen5.ogg"
+ ambientsounds = list('sound/ambience/ambigen5.ogg')
//centcomAway items
diff --git a/code/modules/awaymissions/mission_code/ruins/oldstation.dm b/code/modules/awaymissions/mission_code/ruins/oldstation.dm
index 4d3c54f8f4b..9489ddec45b 100644
--- a/code/modules/awaymissions/mission_code/ruins/oldstation.dm
+++ b/code/modules/awaymissions/mission_code/ruins/oldstation.dm
@@ -321,6 +321,7 @@
name = "Beta Station Atmospherics"
icon_state = "red"
has_gravity = FALSE
+ ambientsounds = ENGINEERING_SOUNDS
/area/ruin/space/ancientstation/betanorth
name = "Beta Station North Corridor"
@@ -333,6 +334,7 @@
/area/ruin/space/ancientstation/engi
name = "Charlie Station Engineering"
icon_state = "engine"
+ ambientsounds = ENGINEERING_SOUNDS
/area/ruin/space/ancientstation/comm
name = "Charlie Station Command"
diff --git a/code/modules/buildmode/effects/line.dm b/code/modules/buildmode/effects/line.dm
index b49d35af095..5cc88309e56 100644
--- a/code/modules/buildmode/effects/line.dm
+++ b/code/modules/buildmode/effects/line.dm
@@ -12,7 +12,7 @@
var/matrix/mat = matrix()
mat.Translate(0, 16)
mat.Scale(1, sqrt((x_offset * x_offset) + (y_offset * y_offset)) / 32)
- mat.Turn(90 - Atan2(x_offset, y_offset)) // So... You pass coords in order x,y to this version of atan2. It should be called acsc2.
+ mat.Turn(90 - ATAN2(x_offset, y_offset)) // So... You pass coords in order x,y to this version of atan2. It should be called acsc2.
mat.Translate(atom_a.pixel_x, atom_a.pixel_y)
transform = mat
diff --git a/code/modules/buildmode/submodes/atmos.dm b/code/modules/buildmode/submodes/atmos.dm
index b3a07374846..ac840acbead 100644
--- a/code/modules/buildmode/submodes/atmos.dm
+++ b/code/modules/buildmode/submodes/atmos.dm
@@ -9,6 +9,7 @@
var/plasma = 0
var/cdiox = 0
var/nitrox = 0
+ var/agentbx = 0
/datum/buildmode_mode/atmos/show_help(mob/user)
@@ -29,6 +30,7 @@
plasma = input(user, "Plasma ratio", "Input", 0) as num|null
cdiox = input(user, "CO2 ratio", "Input", 0) as num|null
nitrox = input(user, "N2O ratio", "Input", 0) as num|null
+ agentbx = input(user, "Agent B ratio", "Input", 0) as num|null
/datum/buildmode_mode/atmos/proc/ppratio_to_moles(ppratio)
// ideal gas equation: Pressure * Volume = Moles * r * Temperature
@@ -52,11 +54,8 @@
S.air.nitrogen = ppratio_to_moles(nitrogen)
S.air.toxins = ppratio_to_moles(plasma)
S.air.carbon_dioxide = ppratio_to_moles(cdiox)
- S.air.trace_gases.Cut()
- if(nitrox)
- var/datum/gas/TG = new /datum/gas/sleeping_agent
- TG.moles = ppratio_to_moles(nitrox)
- S.air.trace_gases += TG
+ S.air.sleeping_agent = ppratio_to_moles(nitrox)
+ S.air.agent_b = ppratio_to_moles(agentbx)
S.update_visuals()
S.air_update_turf()
else if(ctrl_click) // overwrite "default" unsimulated air
@@ -65,7 +64,8 @@
T.nitrogen = ppratio_to_moles(nitrogen)
T.toxins = ppratio_to_moles(plasma)
T.carbon_dioxide = ppratio_to_moles(cdiox)
- // no interface for trace gases on unsim turfs
+ T.sleeping_agent = ppratio_to_moles(nitrox)
+ T.agent_b = ppratio_to_moles(agentbx)
T.air_update_turf()
// admin log
diff --git a/code/modules/buildmode/submodes/copy.dm b/code/modules/buildmode/submodes/copy.dm
index 48cbb2c3cf0..95d8eee8b87 100644
--- a/code/modules/buildmode/submodes/copy.dm
+++ b/code/modules/buildmode/submodes/copy.dm
@@ -22,6 +22,6 @@
if(stored)
DuplicateObject(stored, perfectcopy=1, sameloc=0,newloc=T)
else if(right_click)
- if(ismovableatom(object)) // No copying turfs for now.
+ if(ismovable(object)) // No copying turfs for now.
to_chat(user, "
[object] set as template.")
stored = object
diff --git a/code/modules/client/asset_cache.dm b/code/modules/client/asset_cache.dm
index e1e68bd0617..8ca8bf0fbb1 100644
--- a/code/modules/client/asset_cache.dm
+++ b/code/modules/client/asset_cache.dm
@@ -177,6 +177,12 @@ GLOBAL_LIST_EMPTY(asset_datums)
//DEFINITIONS FOR ASSET DATUMS START HERE.
+/datum/asset/simple/tgui
+ assets = list(
+ "tgui.bundle.js" = 'tgui/packages/tgui/public/tgui.bundle.js',
+ "tgui.bundle.css" = 'tgui/packages/tgui/public/tgui.bundle.css'
+)
+
/datum/asset/simple/paper
assets = list(
"large_stamp-clown.png" = 'icons/paper_icons/large_stamp-clown.png',
@@ -344,3 +350,15 @@ GLOBAL_LIST_EMPTY(asset_datums)
/datum/asset/mob_hunt/send(client)
send_asset_list(client, assets, verify)
+
+// Fontawesome
+/datum/asset/simple/fontawesome
+ verify = FALSE
+ assets = list(
+ "fa-regular-400.eot" = 'html/font-awesome/webfonts/fa-regular-400.eot',
+ "fa-regular-400.woff" = 'html/font-awesome/webfonts/fa-regular-400.woff',
+ "fa-solid-900.eot" = 'html/font-awesome/webfonts/fa-solid-900.eot',
+ "fa-solid-900.woff" = 'html/font-awesome/webfonts/fa-solid-900.woff',
+ "font-awesome.css" = 'html/font-awesome/css/all.min.css',
+ "v4shim.css" = 'html/font-awesome/css/v4-shims.min.css'
+ )
diff --git a/code/modules/client/client defines.dm b/code/modules/client/client defines.dm
index 3cd6458afdf..72537f8ccc3 100644
--- a/code/modules/client/client defines.dm
+++ b/code/modules/client/client defines.dm
@@ -59,10 +59,6 @@
var/karma = 0
var/karma_spent = 0
var/karma_tab = 0
- /////////////////////////////////////////////
- // /vg/: MEDIAAAAAAAA
- // Set on login.
- var/datum/media_manager/media = null
var/topic_debugging = 0 //if set to true, allows client to see nanoUI errors -- yes i realize this is messy but it'll make live testing infinitely easier
@@ -85,10 +81,10 @@
// If set to true, this client can interact with atoms such as buttons and doors on top of regular machinery interaction
var/advanced_admin_interaction = FALSE
- // Has the client been varedited by an admin? [Inherits from datum now]
- // var/var_edited = FALSE
-
var/client_keysend_amount = 0
var/next_keysend_reset = 0
var/next_keysend_trip_reset = 0
var/keysend_tripped = FALSE
+
+ // Last world.time that the player tried to request their resources.
+ var/last_ui_resource_send = 0
diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm
index 561b0b48149..ae503be111b 100644
--- a/code/modules/client/client procs.dm
+++ b/code/modules/client/client procs.dm
@@ -432,7 +432,13 @@
//////////////
//DISCONNECT//
//////////////
+
/client/Del()
+ if(!gc_destroyed)
+ Destroy() //Clean up signals and timers.
+ return ..()
+
+/client/Destroy()
if(holder)
holder.owner = null
GLOB.admins -= src
@@ -442,7 +448,8 @@
movingmob.client_mobs_in_contents -= mob
UNSETEMPTY(movingmob.client_mobs_in_contents)
Master.UpdateTickRate()
- return ..()
+ ..() //Even though we're going to be hard deleted there are still some things that want to know the destroy is happening
+ return QDEL_HINT_HARDDEL_NOW
/client/proc/donator_check()
@@ -556,7 +563,7 @@
if(GLOB.panic_bunker_enabled)
var/threshold = config.panic_bunker_threshold
src << "Server is not accepting connections from never-before-seen players until player count is less than [threshold]. Please try again later."
- del(src)
+ qdel(src)
return // Dont insert or they can just go in again
var/DBQuery/query_insert = GLOB.dbcon.NewQuery("INSERT INTO [format_table_name("player")] (id, ckey, firstseen, lastseen, ip, computerid, lastadminrank) VALUES (null, '[ckey]', Now(), Now(), '[sql_ip]', '[sql_computerid]', '[sql_admin_rank]')")
@@ -906,3 +913,35 @@
return TRUE
#undef SSD_WARNING_TIMER
+
+/client/verb/resend_ui_resources()
+ set name = "Reload UI Resources"
+ set desc = "Reload your UI assets if they are not working"
+ set category = "Special Verbs"
+
+ if(last_ui_resource_send > world.time)
+ to_chat(usr, "
You requested your UI resource files too quickly. Please try again in [(last_ui_resource_send - world.time)/10] seconds.")
+ return
+
+ var/choice = alert(usr, "This will reload your NanoUI and TGUI resources. If you have any open UIs this may break them. Are you sure?", "Resource Reloading", "Yes", "No")
+ if(choice == "Yes")
+ // 600 deciseconds = 1 minute
+ last_ui_resource_send = world.time + 60 SECONDS
+
+ // Close their open UIs
+ SSnanoui.close_user_uis(usr)
+ SStgui.close_user_uis(usr)
+
+ // Resend the resources
+ var/datum/asset/nano_assets = get_asset_datum(/datum/asset/nanoui)
+ nano_assets.register()
+
+ var/datum/asset/tgui_assets = get_asset_datum(/datum/asset/simple/tgui)
+ tgui_assets.register()
+
+ // Clear the user's cache so they get resent.
+ // This is not fully clearing their BYOND cache, just their assets sent from the server this round
+ cache = list()
+
+ to_chat(usr, "
UI resource files resent successfully. If you are still having issues, please try manually clearing your BYOND cache. This can be achieved by opening your BYOND launcher, pressing the cog in the top right, selecting preferences, going to the Games tab, and pressing 'Clear Cache'.")
+
diff --git a/code/modules/client/preference/preferences_mysql.dm b/code/modules/client/preference/preferences_mysql.dm
index 5052a5b315d..c13864c6758 100644
--- a/code/modules/client/preference/preferences_mysql.dm
+++ b/code/modules/client/preference/preferences_mysql.dm
@@ -96,7 +96,7 @@
UI_style_alpha='[UI_style_alpha]',
be_role='[sanitizeSQL(list2params(be_special))]',
default_slot='[default_slot]',
- toggles='[num2text(toggles, Ceiling(log(10, (TOGGLES_TOTAL))))]',
+ toggles='[num2text(toggles, CEILING(log(10, (TOGGLES_TOTAL)), 1))]',
atklog='[atklog]',
sound='[sound]',
randomslot='[randomslot]',
diff --git a/code/modules/clothing/head/soft_caps.dm b/code/modules/clothing/head/soft_caps.dm
index d34584ff425..7ac87e5d5bc 100644
--- a/code/modules/clothing/head/soft_caps.dm
+++ b/code/modules/clothing/head/soft_caps.dm
@@ -113,7 +113,7 @@
/obj/item/clothing/head/soft/sec/corp
name = "corporate security cap"
- desc = "It's baseball hat in corpotate colours."
+ desc = "It's a baseball hat in corporate colours."
icon_state = "corpsoft"
item_color = "corp"
diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm
index 5a01c9f6f55..1198792c980 100644
--- a/code/modules/clothing/spacesuits/hardsuit.dm
+++ b/code/modules/clothing/spacesuits/hardsuit.dm
@@ -531,7 +531,7 @@
/obj/item/clothing/suit/space/hardsuit/shielded/process()
if(world.time > recharge_cooldown && current_charges < max_charges)
- current_charges = Clamp((current_charges + recharge_rate), 0, max_charges)
+ current_charges = clamp((current_charges + recharge_rate), 0, max_charges)
playsound(loc, 'sound/magic/charge.ogg', 50, TRUE)
if(current_charges == max_charges)
playsound(loc, 'sound/machines/ding.ogg', 50, TRUE)
diff --git a/code/modules/clothing/spacesuits/rig/rig.dm b/code/modules/clothing/spacesuits/rig/rig.dm
index cd4ac697406..0d106a874a7 100644
--- a/code/modules/clothing/spacesuits/rig/rig.dm
+++ b/code/modules/clothing/spacesuits/rig/rig.dm
@@ -155,9 +155,8 @@
if(piece.siemens_coefficient > siemens_coefficient) //So that insulated gloves keep their insulation.
piece.siemens_coefficient = siemens_coefficient
piece.permeability_coefficient = permeability_coefficient
- if(islist(armor))
- var/list/L = armor
- piece.armor = L.Copy()
+ if(armor)
+ piece.armor = armor
update_icon(1)
@@ -286,7 +285,7 @@
if(helmet)
helmet.update_light(wearer)
- correct_piece.armor["bio"] = 100
+ correct_piece.armor = correct_piece.armor.setRating(bio_value = 100)
sealing = FALSE
@@ -389,7 +388,7 @@
if(helmet)
helmet.update_light(wearer)
- correct_piece.armor["bio"] = armor["bio"]
+ correct_piece.armor = correct_piece.armor.setRating(bio_value = armor.getRating("bio"))
sealing = FALSE
@@ -553,7 +552,7 @@
data["charge"] = cell ? round(cell.charge,1) : 0
data["maxcharge"] = cell ? cell.maxcharge : 0
- data["chargestatus"] = cell ? Floor((cell.charge/cell.maxcharge)*50) : 0
+ data["chargestatus"] = cell ? FLOOR((cell.charge/cell.maxcharge)*50, 1) : 0
data["emagged"] = subverted
data["coverlock"] = locked
diff --git a/code/modules/clothing/spacesuits/rig/rig_armormod.dm b/code/modules/clothing/spacesuits/rig/rig_armormod.dm
index 68daec45b5a..c04270aa97b 100644
--- a/code/modules/clothing/spacesuits/rig/rig_armormod.dm
+++ b/code/modules/clothing/spacesuits/rig/rig_armormod.dm
@@ -9,13 +9,22 @@
multi *= (100 - chest.damage) / 100 //If we have some breaches, lower the armor value.
//TODO check for other armor mods, likely modules, which need to be coded.
+ if(!armor) //Did we even give them some armor, if this is the case, the list should be initialized from New()
+ return
+ var/datum/armor/A = armor
for(var/obj/item/piece in list(gloves, helmet, boots, chest))
if(!istype(piece)) //Do we have the piece
continue
- if(islist(armor)) //Did we even give them some armor, if this is the case, the list should be initialized from New()
- var/list/L = armor
- for(var/armortype in L)
- piece.armor[armortype] = L[armortype]*multi
+
+ piece.armor = piece.armor.setRating(melee_value = A.getRating("melee") * multi,
+ bullet_value = A.getRating("bullet") * multi,
+ laser_value = A.getRating("laser") * multi,
+ energy_value = A.getRating("energy") * multi,
+ bomb_value = A.getRating("bomb") * multi,
+ bio_value = A.getRating("bio") * multi,
+ rad_value = A.getRating("rad") * multi,
+ fire_value = A.getRating("fire") * multi,
+ acid_value = A.getRating("acidd") * multi)
//Perfect place to also add something like shield modules, or any other hit_reaction modules check.
diff --git a/code/modules/clothing/under/accessories/accessory.dm b/code/modules/clothing/under/accessories/accessory.dm
index b417df89426..76bcd87921d 100644
--- a/code/modules/clothing/under/accessories/accessory.dm
+++ b/code/modules/clothing/under/accessories/accessory.dm
@@ -37,8 +37,13 @@
var/mob/M = has_suit.loc
A.Grant(M)
- for(var/armor_type in armor)
- has_suit.armor[armor_type] += armor[armor_type]
+ if (islist(has_suit.armor) || isnull(has_suit.armor)) // This proc can run before /obj/Initialize has run for U and src,
+ has_suit.armor = getArmor(arglist(has_suit.armor)) // we have to check that the armor list has been transformed into a datum before we try to call a proc on it
+ // This is safe to do as /obj/Initialize only handles setting up the datum if actually needed.
+ if (islist(armor) || isnull(armor))
+ armor = getArmor(arglist(armor))
+
+ has_suit.armor = has_suit.armor.attachArmor(armor)
if(user)
to_chat(user, "
You attach [src] to [has_suit].")
@@ -56,8 +61,7 @@
var/mob/M = has_suit.loc
A.Remove(M)
- for(var/armor_type in armor)
- has_suit.armor[armor_type] -= armor[armor_type]
+ has_suit.armor = has_suit.armor.detachArmor(armor)
has_suit = null
if(user)
@@ -314,6 +318,36 @@
if(isliving(user))
user.visible_message("
[user] invades [M]'s personal space, thrusting [src] into [M.p_their()] face insistently.","
You invade [M]'s personal space, thrusting [src] into [M.p_their()] face insistently. You are the law.")
+//////////////
+//OBJECTION!//
+//////////////
+
+/obj/item/clothing/accessory/lawyers_badge
+ name = "attorney's badge"
+ desc = "Fills you with the conviction of JUSTICE. Lawyers tend to want to show it to everyone they meet."
+ icon_state = "lawyerbadge"
+ item_state = "lawyerbadge"
+ item_color = "lawyerbadge"
+ var/cached_bubble_icon = null
+
+/obj/item/clothing/accessory/lawyers_badge/attack_self(mob/user)
+ if(prob(1))
+ user.say("The testimony contradicts the evidence!")
+ user.visible_message("
[user] shows [user.p_their()] attorney's badge.", "
You show your attorney's badge.")
+
+/obj/item/clothing/accessory/lawyers_badge/on_attached(obj/item/clothing/under/S, mob/user)
+ ..()
+ if(has_suit && ismob(has_suit.loc))
+ var/mob/M = has_suit.loc
+ cached_bubble_icon = M.bubble_icon
+ M.bubble_icon = "lawyer"
+
+/obj/item/clothing/accessory/lawyers_badge/on_removed(mob/user)
+ if(has_suit && ismob(has_suit.loc))
+ var/mob/M = has_suit.loc
+ M.bubble_icon = cached_bubble_icon
+ ..()
+
///////////
//SCARVES//
///////////
diff --git a/code/modules/crafting/craft.dm b/code/modules/crafting/craft.dm
index a9c47e760e7..a0d6823fe80 100644
--- a/code/modules/crafting/craft.dm
+++ b/code/modules/crafting/craft.dm
@@ -128,7 +128,7 @@
continue main_loop
return FALSE
for(var/obj/item/T in tools_used)
- if(!T.tool_start_check(user, 0)) //Check if all our tools are valid for their use
+ if(!T.tool_start_check(null, user, 0)) //Check if all our tools are valid for their use
return FALSE
return TRUE
diff --git a/code/modules/customitems/item_defines.dm b/code/modules/customitems/item_defines.dm
index f8d2029651d..1a5da52ffce 100644
--- a/code/modules/customitems/item_defines.dm
+++ b/code/modules/customitems/item_defines.dm
@@ -48,7 +48,7 @@
var/mob/living/carbon/human/target = M
- if(ismachine(target))
+ if(ismachineperson(target))
to_chat(user, "
[target] has no skin, how do you expect to tattoo [target.p_them()]?")
return
diff --git a/code/modules/detective_work/footprints_and_rag.dm b/code/modules/detective_work/footprints_and_rag.dm
index 2646d03fb0f..bfc9d0aa824 100644
--- a/code/modules/detective_work/footprints_and_rag.dm
+++ b/code/modules/detective_work/footprints_and_rag.dm
@@ -18,7 +18,6 @@
amount_per_transfer_from_this = 5
possible_transfer_amounts = list(5)
volume = 5
- can_be_placed_into = null
flags = NOBLUDGEON
container_type = OPENCONTAINER
has_lid = FALSE
diff --git a/code/modules/economy/Accounts_DB.dm b/code/modules/economy/Accounts_DB.dm
index 6995e260500..aafc91cb849 100644
--- a/code/modules/economy/Accounts_DB.dm
+++ b/code/modules/economy/Accounts_DB.dm
@@ -159,7 +159,7 @@ GLOBAL_VAR(current_date_string)
var/account_name = href_list["holder_name"]
var/starting_funds = max(text2num(href_list["starting_funds"]), 0)
- starting_funds = Clamp(starting_funds, 0, GLOB.station_account.money) // Not authorized to put the station in debt.
+ starting_funds = clamp(starting_funds, 0, GLOB.station_account.money) // Not authorized to put the station in debt.
starting_funds = min(starting_funds, fund_cap) // Not authorized to give more than the fund cap.
var/datum/money_account/M = create_account(account_name, starting_funds, src)
diff --git a/code/modules/events/anomaly_pyro.dm b/code/modules/events/anomaly_pyro.dm
index 79e7c7b8434..0a5dc14bc3a 100644
--- a/code/modules/events/anomaly_pyro.dm
+++ b/code/modules/events/anomaly_pyro.dm
@@ -15,7 +15,7 @@
if(!newAnomaly)
kill()
return
- if(IsMultiple(activeFor, 5))
+ if(ISMULTIPLE(activeFor, 5))
newAnomaly.anomalyEffect()
/datum/event/anomaly/anomaly_pyro/end()
diff --git a/code/modules/events/brand_intelligence.dm b/code/modules/events/brand_intelligence.dm
index d3b7cf012b8..8d91635c458 100644
--- a/code/modules/events/brand_intelligence.dm
+++ b/code/modules/events/brand_intelligence.dm
@@ -55,12 +55,12 @@
kill()
return
- if(IsMultiple(activeFor, 4))
+ if(ISMULTIPLE(activeFor, 4))
var/obj/machinery/vending/rebel = pick(vendingMachines)
vendingMachines.Remove(rebel)
infectedMachines.Add(rebel)
rebel.shut_up = 0
rebel.shoot_inventory = 1
- if(IsMultiple(activeFor, 8))
+ if(ISMULTIPLE(activeFor, 8))
originMachine.speak(pick(rampant_speeches))
diff --git a/code/modules/events/communications_blackout.dm b/code/modules/events/communications_blackout.dm
index 2d83372d625..52baf0fe05c 100644
--- a/code/modules/events/communications_blackout.dm
+++ b/code/modules/events/communications_blackout.dm
@@ -17,7 +17,7 @@
/datum/event/communications_blackout/start()
// This only affects the cores, relays should be unaffected imo
for(var/obj/machinery/tcomms/core/T in GLOB.tcomms_machines)
- T.disable_machine()
+ T.start_ion()
// Bring it back sometime between 3-5 minutes. This uses deciseconds, so 1800 and 3000 respecticely.
- // Note that because this is a strict enable not a toggle, the crew or AI can re-enable the machine themselves
- addtimer(CALLBACK(T, /obj/machinery/tcomms.proc/enable_machine), rand(1800, 3000))
+ // The AI cannot disable this, it must be waited for
+ addtimer(CALLBACK(T, /obj/machinery/tcomms.proc/end_ion), rand(1800, 3000))
diff --git a/code/modules/events/dust.dm b/code/modules/events/dust.dm
index 563ef98697d..a11ef107a8f 100644
--- a/code/modules/events/dust.dm
+++ b/code/modules/events/dust.dm
@@ -16,7 +16,7 @@
density = 1
anchored = 1
var/strength = 2 //ex_act severity number
- var/life = 2 //how many things we hit before del(src)
+ var/life = 2 //how many things we hit before qdel(src)
var/atom/goal = null
/obj/effect/space_dust/weak
diff --git a/code/modules/events/ion_storm.dm b/code/modules/events/ion_storm.dm
index 90718ef2928..2c718580d2c 100644
--- a/code/modules/events/ion_storm.dm
+++ b/code/modules/events/ion_storm.dm
@@ -493,7 +493,7 @@
/proc/generate_static_ion_law()
var/list/players = list()
for(var/mob/living/carbon/human/player in GLOB.player_list)
- if( !player.mind || player.mind.assigned_role == player.mind.special_role || player.client.inactivity > MinutesToTicks(10))
+ if( !player.mind || player.mind.assigned_role == player.mind.special_role || player.client.inactivity > 10 MINUTES)
continue
players += player.real_name
var/random_player = "The Captain"
diff --git a/code/modules/food_and_drinks/drinks/drinks/bottle.dm b/code/modules/food_and_drinks/drinks/drinks/bottle.dm
index 90929175eba..4515a62d86b 100644
--- a/code/modules/food_and_drinks/drinks/drinks/bottle.dm
+++ b/code/modules/food_and_drinks/drinks/drinks/bottle.dm
@@ -72,8 +72,8 @@
if(istype(H.head, /obj/item/clothing/head) && affecting == "head")
// If their head has an armor value, assign headarmor to it, else give it 0.
- if(H.head.armor["melee"])
- headarmor = H.head.armor["melee"]
+ if(H.head.armor.getRating("melee"))
+ headarmor = H.head.armor.getRating("melee")
else
headarmor = 0
else
@@ -115,7 +115,7 @@
//The reagents in the bottle splash all over the target, thanks for the idea Nodrak
SplashReagents(target)
- //Finally, smash the bottle. This kills (del) the bottle.
+ //Finally, smash the bottle. This kills (qdel) the bottle.
smash(target, user)
/obj/item/reagent_containers/food/drinks/bottle/proc/SplashReagents(mob/M)
diff --git a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
index 7d17ac07720..db078675db1 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
@@ -278,11 +278,6 @@
if(!UserOverride)
add_attack_logs(user, occupant, "Gibbed in [src]", !!occupant.ckey ? ATKLOG_FEW : ATKLOG_ALL)
- if(!iscarbon(user))
- occupant.LAssailant = null
- else
- occupant.LAssailant = user
-
else //this looks ugly but it's better than a copy-pasted startgibbing proc override
occupant.create_attack_log("Was gibbed by
an autogibber (\the [src])")
add_attack_logs(src, occupant, "gibbed")
diff --git a/code/modules/games/cards.dm b/code/modules/games/cards.dm
index 7be44052729..9a7c8cca075 100644
--- a/code/modules/games/cards.dm
+++ b/code/modules/games/cards.dm
@@ -438,7 +438,7 @@
overlays += I
return
- var/offset = Floor(20/cards.len + 1)
+ var/offset = FLOOR(20/cards.len + 1, 1)
var/matrix/M = matrix()
if(direction)
diff --git a/code/modules/hydroponics/biogenerator.dm b/code/modules/hydroponics/biogenerator.dm
index c1b5e471315..bb25025cb7f 100644
--- a/code/modules/hydroponics/biogenerator.dm
+++ b/code/modules/hydroponics/biogenerator.dm
@@ -327,7 +327,7 @@
else if(href_list["create"])
var/amount = (text2num(href_list["amount"]))
//Can't be outside these (if you change this keep a sane limit)
- amount = Clamp(amount, 1, 10)
+ amount = clamp(amount, 1, 10)
var/datum/design/D = locate(href_list["create"])
create_product(D, amount)
updateUsrDialog()
diff --git a/code/modules/hydroponics/gene_modder.dm b/code/modules/hydroponics/gene_modder.dm
index d39a0168f14..7ce64f40b20 100644
--- a/code/modules/hydroponics/gene_modder.dm
+++ b/code/modules/hydroponics/gene_modder.dm
@@ -71,7 +71,7 @@
for(var/obj/item/stock_parts/micro_laser/ML in component_parts)
var/wratemod = ML.rating * 2.5
- min_wrate = Floor(10-wratemod) // 7,5,2,0 Clamps at 0 and 10 You want this low
+ min_wrate = FLOOR(10-wratemod, 1) // 7,5,2,0 Clamps at 0 and 10 You want this low
min_wchance = 67-(ML.rating*16) // 48,35,19,3 Clamps at 0 and 67 You want this low
for(var/obj/item/circuitboard/plantgenes/vaultcheck in component_parts)
if(istype(vaultcheck, /obj/item/circuitboard/plantgenes/vault)) // TRAIT_DUMB BOTANY TUTS
diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm
index f4a6a18e417..a3b522187e2 100644
--- a/code/modules/hydroponics/grown.dm
+++ b/code/modules/hydroponics/grown.dm
@@ -40,7 +40,7 @@
for(var/datum/plant_gene/trait/T in seed.genes)
T.on_new(src, newloc)
seed.prepare_result(src)
- transform *= TransformUsingVariable(seed.potency, 100, 0.5) //Makes the resulting produce's sprite larger or smaller based on potency!
+ transform *= TRANSFORM_USING_VARIABLE(seed.potency, 100) + 0.5 //Makes the resulting produce's sprite larger or smaller based on potency!
add_juice()
/obj/item/reagent_containers/food/snacks/grown/Destroy()
@@ -154,12 +154,6 @@
T.on_consume(src, usr)
..()
-/obj/item/reagent_containers/food/snacks/grown/Crossed(atom/movable/AM, oldloc)
- if(seed)
- for(var/datum/plant_gene/trait/T in seed.genes)
- T.on_cross(src, AM)
- ..()
-
/obj/item/reagent_containers/food/snacks/grown/after_slip(mob/living/carbon/human/H)
if(!seed)
return
@@ -190,3 +184,4 @@
D.consume(src)
else
return ..()
+
diff --git a/code/modules/hydroponics/growninedible.dm b/code/modules/hydroponics/growninedible.dm
index 13263b4cc75..f10b286469a 100644
--- a/code/modules/hydroponics/growninedible.dm
+++ b/code/modules/hydroponics/growninedible.dm
@@ -28,7 +28,7 @@
if(istype(src, seed.product)) // no adding reagents if it is just a trash item
seed.prepare_result(src)
- transform *= TransformUsingVariable(seed.potency, 100, 0.5)
+ transform *= TRANSFORM_USING_VARIABLE(seed.potency, 100) + 0.5
add_juice()
/obj/item/grown/Destroy()
@@ -50,13 +50,6 @@
return 1
return 0
-
-/obj/item/grown/Crossed(atom/movable/AM, oldloc)
- if(seed)
- for(var/datum/plant_gene/trait/T in seed.genes)
- T.on_cross(src, AM)
- ..()
-
/obj/item/grown/after_slip(mob/living/carbon/human/H)
if(!seed)
return
diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm
index 0f41ba4b602..1be8f11527d 100644
--- a/code/modules/hydroponics/hydroponics.dm
+++ b/code/modules/hydroponics/hydroponics.dm
@@ -888,7 +888,7 @@
/obj/machinery/hydroponics/wrench_act(mob/user, obj/item/I)
. = TRUE
- if(!I.tool_start_check(user, 0))
+ if(!I.tool_start_check(src, user, 0))
return
if(wrenchable)
if(using_irrigation)
@@ -949,36 +949,36 @@
/// Tray Setters - The following procs adjust the tray or plants variables, and make sure that the stat doesn't go out of bounds.///
/obj/machinery/hydroponics/proc/adjustNutri(adjustamt)
- nutrilevel = Clamp(nutrilevel + adjustamt, 0, maxnutri)
+ nutrilevel = clamp(nutrilevel + adjustamt, 0, maxnutri)
plant_hud_set_nutrient()
/obj/machinery/hydroponics/proc/adjustWater(adjustamt)
- waterlevel = Clamp(waterlevel + adjustamt, 0, maxwater)
+ waterlevel = clamp(waterlevel + adjustamt, 0, maxwater)
plant_hud_set_water()
if(adjustamt>0)
adjustToxic(-round(adjustamt/4))//Toxicity dilutation code. The more water you put in, the lesser the toxin concentration.
/obj/machinery/hydroponics/proc/adjustHealth(adjustamt)
if(myseed && !dead)
- plant_health = Clamp(plant_health + adjustamt, 0, myseed.endurance)
+ plant_health = clamp(plant_health + adjustamt, 0, myseed.endurance)
plant_hud_set_health()
/obj/machinery/hydroponics/proc/adjustToxic(adjustamt)
- toxic = Clamp(toxic + adjustamt, 0, 100)
+ toxic = clamp(toxic + adjustamt, 0, 100)
plant_hud_set_toxin()
/obj/machinery/hydroponics/proc/adjustPests(adjustamt)
- pestlevel = Clamp(pestlevel + adjustamt, 0, 10)
+ pestlevel = clamp(pestlevel + adjustamt, 0, 10)
plant_hud_set_pest()
/obj/machinery/hydroponics/proc/adjustWeeds(adjustamt)
- weedlevel = Clamp(weedlevel + adjustamt, 0, 10)
+ weedlevel = clamp(weedlevel + adjustamt, 0, 10)
plant_hud_set_weed()
/obj/machinery/hydroponics/proc/spawnplant() // why would you put strange reagent in a hydro tray you monster I bet you also feed them blood
var/list/livingplants = list(/mob/living/simple_animal/hostile/tree, /mob/living/simple_animal/hostile/killertomato)
var/chosen = pick(livingplants)
- var/mob/living/simple_animal/hostile/C = new chosen
+ var/mob/living/simple_animal/hostile/C = new chosen(get_turf(src))
C.faction = list("plants")
/obj/machinery/hydroponics/proc/become_self_sufficient() // Ambrosia Gaia effect
diff --git a/code/modules/hydroponics/plant_genes.dm b/code/modules/hydroponics/plant_genes.dm
index 19209a680ad..a4c6fe7280d 100644
--- a/code/modules/hydroponics/plant_genes.dm
+++ b/code/modules/hydroponics/plant_genes.dm
@@ -175,9 +175,6 @@
/datum/plant_gene/trait/proc/on_consume(obj/item/reagent_containers/food/snacks/grown/G, mob/living/carbon/target)
return
-/datum/plant_gene/trait/proc/on_cross(obj/item/reagent_containers/food/snacks/grown/G, atom/target)
- return
-
/datum/plant_gene/trait/proc/on_slip(obj/item/reagent_containers/food/snacks/grown/G, mob/living/carbon/target)
return
diff --git a/code/modules/hydroponics/seeds.dm b/code/modules/hydroponics/seeds.dm
index 8cfc9b7d5f0..08ccac07062 100644
--- a/code/modules/hydroponics/seeds.dm
+++ b/code/modules/hydroponics/seeds.dm
@@ -182,7 +182,7 @@
/// Setters procs ///
/obj/item/seeds/proc/adjust_yield(adjustamt)
if(yield != -1) // Unharvestable shouldn't suddenly turn harvestable
- yield = Clamp(yield + adjustamt, 0, 10)
+ yield = clamp(yield + adjustamt, 0, 10)
if(yield <= 0 && get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism))
yield = 1 // Mushrooms always have a minimum yield of 1.
@@ -191,39 +191,39 @@
C.value = yield
/obj/item/seeds/proc/adjust_lifespan(adjustamt)
- lifespan = Clamp(lifespan + adjustamt, 10, 100)
+ lifespan = clamp(lifespan + adjustamt, 10, 100)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/lifespan)
if(C)
C.value = lifespan
/obj/item/seeds/proc/adjust_endurance(adjustamt)
- endurance = Clamp(endurance + adjustamt, 10, 100)
+ endurance = clamp(endurance + adjustamt, 10, 100)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/endurance)
if(C)
C.value = endurance
/obj/item/seeds/proc/adjust_production(adjustamt)
if(yield != -1)
- production = Clamp(production + adjustamt, 1, 10)
+ production = clamp(production + adjustamt, 1, 10)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/production)
if(C)
C.value = production
/obj/item/seeds/proc/adjust_potency(adjustamt)
if(potency != -1)
- potency = Clamp(potency + adjustamt, 0, 100)
+ potency = clamp(potency + adjustamt, 0, 100)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/potency)
if(C)
C.value = potency
/obj/item/seeds/proc/adjust_weed_rate(adjustamt)
- weed_rate = Clamp(weed_rate + adjustamt, 0, 10)
+ weed_rate = clamp(weed_rate + adjustamt, 0, 10)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/weed_rate)
if(C)
C.value = weed_rate
/obj/item/seeds/proc/adjust_weed_chance(adjustamt)
- weed_chance = Clamp(weed_chance + adjustamt, 0, 67)
+ weed_chance = clamp(weed_chance + adjustamt, 0, 67)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/weed_chance)
if(C)
C.value = weed_chance
@@ -232,7 +232,7 @@
/obj/item/seeds/proc/set_yield(adjustamt)
if(yield != -1) // Unharvestable shouldn't suddenly turn harvestable
- yield = Clamp(adjustamt, 0, 10)
+ yield = clamp(adjustamt, 0, 10)
if(yield <= 0 && get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism))
yield = 1 // Mushrooms always have a minimum yield of 1.
@@ -241,39 +241,39 @@
C.value = yield
/obj/item/seeds/proc/set_lifespan(adjustamt)
- lifespan = Clamp(adjustamt, 10, 100)
+ lifespan = clamp(adjustamt, 10, 100)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/lifespan)
if(C)
C.value = lifespan
/obj/item/seeds/proc/set_endurance(adjustamt)
- endurance = Clamp(adjustamt, 10, 100)
+ endurance = clamp(adjustamt, 10, 100)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/endurance)
if(C)
C.value = endurance
/obj/item/seeds/proc/set_production(adjustamt)
if(yield != -1)
- production = Clamp(adjustamt, 1, 10)
+ production = clamp(adjustamt, 1, 10)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/production)
if(C)
C.value = production
/obj/item/seeds/proc/set_potency(adjustamt)
if(potency != -1)
- potency = Clamp(adjustamt, 0, 100)
+ potency = clamp(adjustamt, 0, 100)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/potency)
if(C)
C.value = potency
/obj/item/seeds/proc/set_weed_rate(adjustamt)
- weed_rate = Clamp(adjustamt, 0, 10)
+ weed_rate = clamp(adjustamt, 0, 10)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/weed_rate)
if(C)
C.value = weed_rate
/obj/item/seeds/proc/set_weed_chance(adjustamt)
- weed_chance = Clamp(adjustamt, 0, 67)
+ weed_chance = clamp(adjustamt, 0, 67)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/weed_chance)
if(C)
C.value = weed_chance
diff --git a/code/modules/library/computers/checkout.dm b/code/modules/library/computers/checkout.dm
index 31eebc5d05c..f9aae71b2a5 100644
--- a/code/modules/library/computers/checkout.dm
+++ b/code/modules/library/computers/checkout.dm
@@ -95,7 +95,7 @@
dat += "
ERROR: Unable to contact External Archive. Please contact your system administrator for assistance."
else
num_results = src.get_num_results()
- num_pages = Ceiling(num_results/LIBRARY_BOOKS_PER_PAGE)
+ num_pages = CEILING(num_results/LIBRARY_BOOKS_PER_PAGE, 1)
dat += {"
"}
@@ -207,7 +207,7 @@
var/obj/item/barcodescanner/scanner = W
scanner.computer = src
to_chat(user, "[scanner]'s associated machine has been set to [src].")
- audible_message("[src] lets out a low, short blip.", 2)
+ audible_message("[src] lets out a low, short blip.", hearing_distance = 2)
return 1
else
return ..()
@@ -224,13 +224,13 @@
else
var/pn = text2num(href_list["pagenum"])
if(!isnull(pn))
- page_num = Clamp(pn, 1, num_pages)
+ page_num = clamp(pn, 1, num_pages)
if(href_list["page"])
if(num_pages == 0)
page_num = 1
else
- page_num = Clamp(text2num(href_list["page"]), 1, num_pages)
+ page_num = clamp(text2num(href_list["page"]), 1, num_pages)
if(href_list["settitle"])
var/newtitle = input("Enter a title to search for:") as text|null
if(newtitle)
@@ -252,7 +252,7 @@
if(href_list["search"])
num_results = src.get_num_results()
- num_pages = Ceiling(num_results/LIBRARY_BOOKS_PER_PAGE)
+ num_pages = CEILING(num_results/LIBRARY_BOOKS_PER_PAGE, 1)
page_num = 1
screenstate = 4
@@ -413,7 +413,7 @@
return
if(bibledelay)
- audible_message("
[src]'s monitor flashes, \"Printer unavailable. Please allow a short time before attempting to print.\"")
+ visible_message("
[src]'s monitor flashes, \"Printer unavailable. Please allow a short time before attempting to print.\"")
else
bibledelay = 1
spawn(60)
diff --git a/code/modules/library/computers/public.dm b/code/modules/library/computers/public.dm
index f94369b11b7..3c5116bc074 100644
--- a/code/modules/library/computers/public.dm
+++ b/code/modules/library/computers/public.dm
@@ -75,7 +75,7 @@
else
var/pn = text2num(href_list["pagenum"])
if(!isnull(pn))
- page_num = Clamp(pn, 1, num_pages)
+ page_num = clamp(pn, 1, num_pages)
if(href_list["settitle"])
var/newtitle = input("Enter a title to search for:") as text|null
@@ -100,11 +100,11 @@
if(num_pages == 0)
page_num = 1
else
- page_num = Clamp(text2num(href_list["page"]), 1, num_pages)
+ page_num = clamp(text2num(href_list["page"]), 1, num_pages)
if(href_list["search"])
num_results = src.get_num_results()
- num_pages = Ceiling(num_results/LIBRARY_BOOKS_PER_PAGE)
+ num_pages = CEILING(num_results/LIBRARY_BOOKS_PER_PAGE, 1)
page_num = 1
screenstate = 1
diff --git a/code/modules/lighting/lighting_atom.dm b/code/modules/lighting/lighting_atom.dm
index ff4bc517979..fa848700557 100644
--- a/code/modules/lighting/lighting_atom.dm
+++ b/code/modules/lighting/lighting_atom.dm
@@ -38,7 +38,7 @@
if(!light_power || !light_range) // We won't emit light anyways, destroy the light source.
QDEL_NULL(light)
else
- if(!ismovableatom(loc)) // We choose what atom should be the top atom of the light here.
+ if(!ismovable(loc)) // We choose what atom should be the top atom of the light here.
. = src
else
. = loc
diff --git a/code/modules/lighting/lighting_source.dm b/code/modules/lighting/lighting_source.dm
index 7b0b782bdca..9398bd9683c 100644
--- a/code/modules/lighting/lighting_source.dm
+++ b/code/modules/lighting/lighting_source.dm
@@ -220,13 +220,14 @@
var/oldlum = source_turf.luminosity
source_turf.luminosity = CEILING(light_range, 1)
for(T in view(CEILING(light_range, 1), source_turf))
- if((!IS_DYNAMIC_LIGHTING(T) && !T.light_sources) || T.has_opaque_atom)
+ if((!IS_DYNAMIC_LIGHTING(T) && !T.light_sources))
continue
- if(!T.lighting_corners_initialised)
- T.generate_missing_corners()
- for(thing in T.corners)
- C = thing
- corners[C] = 0
+ if(!T.has_opaque_atom)
+ if(!T.lighting_corners_initialised)
+ T.generate_missing_corners()
+ for(thing in T.corners)
+ C = thing
+ corners[C] = 0
turfs += T
source_turf.luminosity = oldlum
diff --git a/code/modules/martial_arts/martial.dm b/code/modules/martial_arts/martial.dm
index 882da0a9387..8969463be1d 100644
--- a/code/modules/martial_arts/martial.dm
+++ b/code/modules/martial_arts/martial.dm
@@ -195,6 +195,9 @@
icon = 'icons/obj/library.dmi'
icon_state = "cqcmanual"
+/obj/item/CQC_manual/chef
+ desc = "A small, black manual. Written on the back it says: Bringing the home advantage with you."
+
/obj/item/CQC_manual/attack_self(mob/living/carbon/human/user)
if(!istype(user) || !user)
return
diff --git a/code/modules/mining/lavaland/loot/ashdragon_loot.dm b/code/modules/mining/lavaland/loot/ashdragon_loot.dm
index e9728bc7901..a0ea3eb7639 100644
--- a/code/modules/mining/lavaland/loot/ashdragon_loot.dm
+++ b/code/modules/mining/lavaland/loot/ashdragon_loot.dm
@@ -81,7 +81,7 @@
var/mob/dead/observer/current_spirits = list()
for(var/mob/dead/observer/O in GLOB.player_list)
- if((O.following in contents))
+ if((O.orbiting in contents))
ghost_counter++
O.invisibility = 0
current_spirits |= O
@@ -97,13 +97,13 @@
force = 0
var/ghost_counter = ghost_check()
- force = Clamp((ghost_counter * 4), 0, 75)
+ force = clamp((ghost_counter * 4), 0, 75)
user.visible_message("
[user] strikes with the force of [ghost_counter] vengeful spirits!")
..()
/obj/item/melee/ghost_sword/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
var/ghost_counter = ghost_check()
- final_block_chance += Clamp((ghost_counter * 5), 0, 75)
+ final_block_chance += clamp((ghost_counter * 5), 0, 75)
owner.visible_message("
[owner] is protected by a ring of [ghost_counter] ghosts!")
return ..()
diff --git a/code/modules/mining/lavaland/loot/hierophant_loot.dm b/code/modules/mining/lavaland/loot/hierophant_loot.dm
index a3f6e738380..fc81e6399ae 100644
--- a/code/modules/mining/lavaland/loot/hierophant_loot.dm
+++ b/code/modules/mining/lavaland/loot/hierophant_loot.dm
@@ -93,7 +93,7 @@
blast_range = initial(blast_range)
if(isliving(user))
var/mob/living/L = user
- var/health_percent = L.health / L.maxHealth
+ var/health_percent = max(L.health / L.maxHealth, 0) // Don't go negative
chaser_cooldown += round(health_percent * 20) //two tenths of a second for each missing 10% of health
cooldown_time += round(health_percent * 10) //one tenth of a second for each missing 10% of health
chaser_speed = max(chaser_speed + health_percent, 0.5) //one tenth of a second faster for each missing 10% of health
diff --git a/code/modules/mining/machine_redemption.dm b/code/modules/mining/machine_redemption.dm
index 7f1b520e7f8..9630395e0cd 100644
--- a/code/modules/mining/machine_redemption.dm
+++ b/code/modules/mining/machine_redemption.dm
@@ -221,7 +221,7 @@
. = TRUE
if(!powered())
return
- if(!I.tool_start_check(user, 0))
+ if(!I.tool_start_check(src, user, 0))
return
input_dir = turn(input_dir, -90)
output_dir = turn(output_dir, -90)
diff --git a/code/modules/mining/minebot.dm b/code/modules/mining/minebot.dm
index 1198e2fb9d3..dbaa24fef34 100644
--- a/code/modules/mining/minebot.dm
+++ b/code/modules/mining/minebot.dm
@@ -101,7 +101,7 @@
if(user.a_intent != INTENT_HELP)
return
. = TRUE
- if(!I.tool_start_check(user, 0))
+ if(!I.tool_start_check(src, user, 0))
return
I.melee_attack_chain(user, stored_gun)
diff --git a/code/modules/mining/mint.dm b/code/modules/mining/mint.dm
index c6d23a1bbde..9cabe4ac486 100644
--- a/code/modules/mining/mint.dm
+++ b/code/modules/mining/mint.dm
@@ -70,7 +70,7 @@
if(materials.materials[href_list["choose"]])
chosen = href_list["choose"]
if(href_list["chooseAmt"])
- coinsToProduce = Clamp(coinsToProduce + text2num(href_list["chooseAmt"]), 0, 1000)
+ coinsToProduce = clamp(coinsToProduce + text2num(href_list["chooseAmt"]), 0, 1000)
if(href_list["makeCoins"])
var/temp_coins = coinsToProduce
processing = TRUE
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index 8bff776c176..997920c8e23 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -23,7 +23,6 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
//If you died in the game and are a ghsot - this will remain as null.
//Note that this is not a reliable way to determine if admins started as observers, since they change mobs a lot.
universal_speak = TRUE
- var/atom/movable/following = null
var/image/ghostimage = null //this mobs ghost image, for deleting and stuff
var/ghostvision = TRUE //is the ghost able to see things humans can't?
var/seedarkness = TRUE
@@ -230,7 +229,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
/mob/dead/observer/Move(NewLoc, direct)
update_parallax_contents()
- following = null
setDir(direct)
ghostimage.setDir(dir)
@@ -412,7 +410,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
forceMove(pick(L))
update_parallax_contents()
- following = null
/mob/dead/observer/verb/follow()
set category = "Ghost"
@@ -424,7 +421,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
A.on_close(CALLBACK(src, .proc/ManualFollow))
// This is the ghost's follow verb with an argument
-/mob/dead/observer/proc/ManualFollow(var/atom/movable/target)
+/mob/dead/observer/proc/ManualFollow(atom/movable/target)
if(!target || !isobserver(usr))
return
@@ -432,7 +429,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
return
if(target != src)
- if(following && following == target)
+ if(orbiting && orbiting == target)
return
var/icon/I = icon(target.icon,target.icon_state,target.dir)
@@ -458,7 +455,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
else //Circular
rot_seg = 36 //360/10 bby, smooth enough aproximation of a circle
- following = target
to_chat(src, "
Now following [target]")
orbit(target,orbitsize, FALSE, 20, rot_seg)
@@ -485,7 +481,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if(T && isturf(T)) //Make sure the turf exists, then move the source to that destination.
A.forceMove(T)
M.update_parallax_contents()
- following = null
return
to_chat(A, "This mob is not located in the game world.")
@@ -642,7 +637,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if(!client)
return
forceMove(T)
- following = null
if(href_list["reenter"])
reenter_corpse()
diff --git a/code/modules/mob/emote.dm b/code/modules/mob/emote.dm
index 5f18a27adc9..99e0af0ca6a 100644
--- a/code/modules/mob/emote.dm
+++ b/code/modules/mob/emote.dm
@@ -135,7 +135,7 @@
if(message)
for(var/mob/M in GLOB.player_list)
- if(istype(M, /mob/new_player))
+ if(isnewplayer(M))
continue
if(check_rights(R_ADMIN|R_MOD, 0, M) && M.get_preference(CHAT_DEAD)) // Show the emote to admins/mods
diff --git a/code/modules/mob/language.dm b/code/modules/mob/language.dm
index 7f3a7049558..a46268daf50 100644
--- a/code/modules/mob/language.dm
+++ b/code/modules/mob/language.dm
@@ -33,7 +33,7 @@
for(var/i = 0;i
0;x--)
+ for(var/x = rand(FLOOR(syllable_count/2, 1),syllable_count);x>0;x--)
new_name += pick(syllables)
full_name += " [capitalize(lowertext(new_name))]"
@@ -767,17 +767,6 @@
desc = "Bark bark bark."
key = "vu"
-/datum/language/zombie
- name = "Zombie"
- desc = "BRAAAAAAINS!"
- speech_verb = "moans"
- whisper_verb = "mutters"
- exclaim_verb = "wails"
- colour = "zombie"
- key = "zom"
- flags = RESTRICTED
- syllables = list("BRAAAAAAAAAAAAAAAAINS", "BRAAINS", "BRAINS")
-
/mob/proc/grant_all_babel_languages()
for(var/la in GLOB.all_languages)
var/datum/language/new_language = GLOB.all_languages[la]
diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm
index 247e0bcbab2..f6354b61940 100644
--- a/code/modules/mob/living/carbon/alien/alien.dm
+++ b/code/modules/mob/living/carbon/alien/alien.dm
@@ -2,6 +2,7 @@
name = "alien"
voice_name = "alien"
speak_emote = list("hisses")
+ bubble_icon = "alien"
icon = 'icons/mob/alien.dmi'
gender = NEUTER
dna = null
@@ -226,7 +227,7 @@ Des: Removes all infected images from the alien.
/mob/living/carbon/alien/handle_footstep(turf/T)
if(..())
- if(T.footstep_sounds["xeno"])
+ if(T.footstep_sounds && T.footstep_sounds["xeno"])
var/S = pick(T.footstep_sounds["xeno"])
if(S)
if(m_intent == MOVE_INTENT_RUN)
diff --git a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm
index fec3012529e..58bdb3a9ecc 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm
@@ -136,14 +136,11 @@ Doesn't work on other aliens/AI.*/
set category = "Alien"
if(powerc())
- if(stomach_contents.len)
+ if(LAZYLEN(stomach_contents))
for(var/mob/M in src)
- if(M in stomach_contents)
- stomach_contents.Remove(M)
- M.forceMove(loc)
- //Paralyse(10)
- src.visible_message("[src] hurls out the contents of [p_their()] stomach!")
- return
+ LAZYREMOVE(stomach_contents, M)
+ M.forceMove(drop_location())
+ visible_message("[src] hurls out the contents of [p_their()] stomach!")
/mob/living/carbon/proc/getPlasma()
var/obj/item/organ/internal/xenos/plasmavessel/vessel = get_int_organ(/obj/item/organ/internal/xenos/plasmavessel)
diff --git a/code/modules/mob/living/carbon/alien/humanoid/empress.dm b/code/modules/mob/living/carbon/alien/humanoid/empress.dm
index 63514686f3d..a28b3f33a53 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/empress.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/empress.dm
@@ -6,6 +6,7 @@
icon_state = "alienq_s"
status_flags = CANPARALYSE
mob_size = MOB_SIZE_LARGE
+ bubble_icon = "alienroyal"
large = 1
ventcrawler = 0
diff --git a/code/modules/mob/living/carbon/alien/humanoid/humanoid_defense.dm b/code/modules/mob/living/carbon/alien/humanoid/humanoid_defense.dm
index e7f783acd72..3174879caac 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/humanoid_defense.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/humanoid_defense.dm
@@ -55,7 +55,7 @@
playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
visible_message("[M] has attempted to disarm [src]!")
-/mob/living/carbon/alien/humanoid/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect, end_pixel_y)
+/mob/living/carbon/alien/humanoid/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
if(!no_effect && !visual_effect_icon)
visual_effect_icon = ATTACK_EFFECT_CLAW
..()
diff --git a/code/modules/mob/living/carbon/alien/larva/larva_defense.dm b/code/modules/mob/living/carbon/alien/larva/larva_defense.dm
index 69e12b6ae19..d13dab884b2 100644
--- a/code/modules/mob/living/carbon/alien/larva/larva_defense.dm
+++ b/code/modules/mob/living/carbon/alien/larva/larva_defense.dm
@@ -31,7 +31,7 @@
step_away(src, user, 15)
return TRUE
-/mob/living/carbon/alien/larva/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect, end_pixel_y)
+/mob/living/carbon/alien/larva/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
if(!no_effect && !visual_effect_icon)
visual_effect_icon = ATTACK_EFFECT_BITE
..()
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 0466c1c0be0..98585262518 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -2,6 +2,10 @@
var/canEnterVentWith = "/obj/item/implant=0&/obj/item/clothing/mask/facehugger=0&/obj/item/radio/borg=0&/obj/machinery/camera=0"
var/datum/middleClickOverride/middleClickOverride = null
+/mob/living/carbon/Initialize(mapload)
+ . = ..()
+ GLOB.carbon_list += src
+
/mob/living/carbon/Destroy()
// This clause is here due to items falling off from limb deletion
for(var/obj/item in get_all_slots())
@@ -14,11 +18,11 @@
if(B)
B.leave_host()
qdel(B)
+ GLOB.carbon_list -= src
return ..()
/mob/living/carbon/handle_atom_del(atom/A)
- if(A in processing_patches)
- processing_patches -= A
+ LAZYREMOVE(processing_patches, A)
return ..()
/mob/living/carbon/blob_act(obj/structure/blob/B)
@@ -46,41 +50,40 @@
/mob/living/carbon/var/last_stomach_attack //defining this here because no one would look in carbon_defines for it
-/mob/living/carbon/relaymove(var/mob/user, direction)
- if(user in src.stomach_contents)
- if(last_stomach_attack + STOMACH_ATTACK_DELAY > world.time) return
+/mob/living/carbon/relaymove(mob/user, direction)
+ if(LAZYLEN(stomach_contents))
+ if(user in stomach_contents)
+ if(last_stomach_attack + STOMACH_ATTACK_DELAY > world.time)
+ return
- last_stomach_attack = world.time
- for(var/mob/M in hearers(4, src))
- if(M.client)
- M.show_message(text("You hear something rumbling inside [src]'s stomach..."), 2)
-
- var/obj/item/I = user.get_active_hand()
- if(I && I.force)
- var/d = rand(round(I.force / 4), I.force)
-
- if(istype(src, /mob/living/carbon/human))
- var/mob/living/carbon/human/H = src
- var/obj/item/organ/external/organ = H.get_organ("chest")
- if(istype(organ))
- if(organ.receive_damage(d, 0))
- H.UpdateDamageIcon()
-
- H.updatehealth("stomach attack")
-
- else
- src.take_organ_damage(d)
-
- for(var/mob/M in viewers(user, null))
+ last_stomach_attack = world.time
+ for(var/mob/M in hearers(4, src))
if(M.client)
- M.show_message(text("[user] attacks [src]'s stomach wall with the [I.name]!"), 2)
- playsound(user.loc, 'sound/effects/attackblob.ogg', 50, 1)
+ M.show_message(text("You hear something rumbling inside [src]'s stomach..."), 2)
- if(prob(src.getBruteLoss() - 50))
- for(var/atom/movable/A in stomach_contents)
- A.forceMove(drop_location())
- stomach_contents.Remove(A)
- src.gib()
+ var/obj/item/I = user.get_active_hand()
+ if(I && I.force)
+ var/d = rand(round(I.force / 4), I.force)
+
+ if(istype(src, /mob/living/carbon/human))
+ var/mob/living/carbon/human/H = src
+ var/obj/item/organ/external/organ = H.get_organ("chest")
+ if(istype(organ))
+ if(organ.receive_damage(d, 0))
+ H.UpdateDamageIcon()
+
+ H.updatehealth("stomach attack")
+
+ else
+ take_organ_damage(d)
+
+ for(var/mob/M in viewers(user, null))
+ if(M.client)
+ M.show_message(text("[user] attacks [src]'s stomach wall with the [I.name]!"), 2)
+ playsound(user.loc, 'sound/effects/attackblob.ogg', 50, 1)
+
+ if(prob(getBruteLoss() - 50))
+ gib()
#undef STOMACH_ATTACK_DELAY
@@ -135,9 +138,8 @@
I.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1,3),5)
for(var/mob/M in src)
- if(M in src.stomach_contents)
- src.stomach_contents.Remove(M)
- M.forceMove(get_turf(src))
+ LAZYREMOVE(stomach_contents, M)
+ M.forceMove(drop_location())
visible_message("[M] bursts out of [src]!")
/mob/living/carbon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = FALSE, override = FALSE, tesla_shock = FALSE, illusion = FALSE, stun = TRUE)
@@ -1064,10 +1066,6 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, list(/obj/machinery/atmospherics/unary/ven
/mob/living/carbon/proc/forceFedAttackLog(var/obj/item/reagent_containers/food/toEat, mob/user)
add_attack_logs(user, src, "Fed [toEat]. Reagents: [toEat.reagents.log_list(toEat)]", toEat.reagents.harmless_helper() ? ATKLOG_ALMOSTALL : null)
- if(!iscarbon(user))
- LAssailant = null
- else
- LAssailant = user
/*TO DO - If/when stomach organs are introduced, override this at the human level sending the item to the stomach
@@ -1200,3 +1198,18 @@ so that different stomachs can handle things in different ways VB*/
I.acid_level = 0 //washes off the acid on our clothes
I.extinguish() //extinguishes our clothes
..()
+
+/mob/living/carbon/clean_blood(clean_hands = TRUE, clean_mask = TRUE, clean_feet = TRUE)
+ if(head)
+ if(head.clean_blood())
+ update_inv_head()
+ if(head.flags_inv & HIDEMASK)
+ clean_mask = FALSE
+ if(wear_suit)
+ if(wear_suit.clean_blood())
+ update_inv_wear_suit()
+ if(wear_suit.flags_inv & HIDESHOES)
+ clean_feet = FALSE
+ if(wear_suit.flags_inv & HIDEGLOVES)
+ clean_hands = FALSE
+ ..(clean_hands, clean_mask, clean_feet)
diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
index 75bd6d2664a..e0cba0b0281 100644
--- a/code/modules/mob/living/carbon/carbon_defense.dm
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -12,7 +12,7 @@
visible_message("[src] catches [AM]!")
throw_mode_off()
return TRUE
- ..()
+ return ..()
/mob/living/carbon/water_act(volume, temperature, source, method = REAGENT_TOUCH)
. = ..()
diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm
index 97ecf4dd08b..667fd86204e 100644
--- a/code/modules/mob/living/carbon/carbon_defines.dm
+++ b/code/modules/mob/living/carbon/carbon_defines.dm
@@ -1,11 +1,10 @@
/mob/living/carbon
gender = MALE
pressure_resistance = 15
- var/list/stomach_contents = list()
- var/list/processing_patches = list()
+ var/list/stomach_contents
+ var/list/processing_patches
var/list/internal_organs = list()
var/list/internal_organs_slot = list() //Same as above, but stores "slot ID" - "organ" pairs for easy access.
- var/antibodies = 0
var/life_tick = 0 // The amount of life ticks that have processed on this mob.
diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm
index 6b7a0a2b15d..d213ee7206f 100644
--- a/code/modules/mob/living/carbon/human/death.dm
+++ b/code/modules/mob/living/carbon/human/death.dm
@@ -6,7 +6,7 @@
canmove = 0
icon = null
invisibility = 101
- if(!isSynthetic())
+ if(!ismachineperson(src))
animation = new(loc)
animation.icon_state = "blank"
animation.icon = 'icons/mob/mob.dmi'
@@ -32,12 +32,11 @@
E.droplimb(DROPLIMB_SHARP)
for(var/mob/M in src)
- if(M in stomach_contents)
- stomach_contents.Remove(M)
- M.forceMove(get_turf(src))
+ LAZYREMOVE(stomach_contents, M)
+ M.forceMove(drop_location())
visible_message("[M] bursts out of [src]!")
- if(!isSynthetic())
+ if(!ismachineperson(src))
flick("gibbed-h", animation)
hgibs(loc, dna)
else
@@ -106,11 +105,6 @@
//Handle species-specific deaths.
dna.species.handle_death(gibbed, src)
- if(ishuman(LAssailant))
- var/mob/living/carbon/human/H=LAssailant
- if(H.mind)
- H.mind.kills += "[key_name(src)]"
-
if(SSticker && SSticker.mode)
// log_world("k")
sql_report_death(src)
diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm
index a34f02bc868..10c2ac8f119 100644
--- a/code/modules/mob/living/carbon/human/emote.dm
+++ b/code/modules/mob/living/carbon/human/emote.dm
@@ -34,7 +34,7 @@
//Cooldown-inducing emotes
if("ping", "pings", "buzz", "buzzes", "beep", "beeps", "yes", "no", "buzz2")
var/found_machine_head = FALSE
- if(ismachine(src)) //Only Machines can beep, ping, and buzz, yes, no, and make a silly sad trombone noise.
+ if(ismachineperson(src)) //Only Machines can beep, ping, and buzz, yes, no, and make a silly sad trombone noise.
on_CD = handle_emote_CD() //proc located in code\modules\mob\emote.dm
found_machine_head = TRUE
else
@@ -139,10 +139,18 @@
//WHO THE FUCK THOUGHT THAT WAS A GOOD FUCKING IDEA!?!?
if("howl", "howls")
- var/M = handle_emote_param(param) //Check to see if the param is valid (mob with the param name is in view).
- message = "[src] howls[M ? " at [M]" : ""]!"
- playsound(loc, 'sound/goonstation/voice/howl.ogg', 100, 1, 10, frequency = get_age_pitch())
- m_type = 2
+ var/M = handle_emote_param(param)
+ if(miming)
+ message = "[src] acts out a howl[M ? " at [M]" : ""]!"
+ m_type = 1
+ else
+ if(!muzzled)
+ message = "[src] howls[M ? " at [M]" : ""]!"
+ playsound(loc, 'sound/goonstation/voice/howl.ogg', 100, 1, 10, frequency = get_age_pitch())
+ m_type = 2
+ else
+ message = "[src] makes a very loud noise[M ? " at [M]" : ""]."
+ m_type = 2
if("growl", "growls")
var/M = handle_emote_param(param)
@@ -939,7 +947,7 @@
if("Skrell")
emotelist += "\nSkrell specific emotes :- warble(s)"
- if(ismachine(src))
+ if(ismachineperson(src))
emotelist += "\nMachine specific emotes :- beep(s)-(none)/mob, buzz(es)-none/mob, no-(none)/mob, ping(s)-(none)/mob, yes-(none)/mob, buzz2-(none)/mob"
else
var/obj/item/organ/external/head/H = get_organ("head") // If you have a robotic head, you can make beep-boop noises
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index b67e01924c8..31825ea3765 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -208,7 +208,7 @@
if(!E)
wound_flavor_text["[organ_tag]"] = "[p_they(TRUE)] [p_are()] missing [p_their()] [organ_descriptor].\n"
else
- if(!isSynthetic())
+ if(!ismachineperson(src))
if(E.is_robotic())
wound_flavor_text["[E.limb_name]"] = "[p_they(TRUE)] [p_have()] a robotic [E.name]!\n"
@@ -252,7 +252,7 @@
var/temp = getBruteLoss() //no need to calculate each of these twice
if(temp)
- var/brute_message = !isSynthetic() ? "bruising" : "denting"
+ var/brute_message = !ismachineperson(src) ? "bruising" : "denting"
if(temp < 30)
msg += "[p_they(TRUE)] [p_have()] minor [brute_message ].\n"
else
@@ -301,13 +301,13 @@
else if(nutrition >= NUTRITION_LEVEL_FAT)
msg += "[p_they(TRUE)] [p_are()] quite chubby.\n"
- if(!isSynthetic() && blood_volume < BLOOD_VOLUME_SAFE)
+ if(!ismachineperson(src) && blood_volume < BLOOD_VOLUME_SAFE)
msg += "[p_they(TRUE)] [p_have()] pale skin.\n"
if(bleedsuppress)
msg += "[p_they(TRUE)] [p_are()] bandaged with something.\n"
else if(bleed_rate)
- var/bleed_message = !isSynthetic() ? "bleeding" : "leaking"
+ var/bleed_message = !ismachineperson(src) ? "bleeding" : "leaking"
msg += "[p_they(TRUE)] [p_are()] [bleed_message]!\n"
if(reagents.has_reagent("teslium"))
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 828dc25322c..16f1738d2f6 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -18,7 +18,7 @@
dna = new /datum/dna(null)
// Species name is handled by set_species()
- ..()
+ . = ..()
set_species(new_species, 1, delay_icon_update = 1, skip_same_check = TRUE)
@@ -41,6 +41,7 @@
sync_organ_dna(1)
UpdateAppearance()
+ GLOB.human_list += src
/mob/living/carbon/human/OpenCraftingMenu()
handcrafting.ui_interact(src)
@@ -60,61 +61,62 @@
SSmobs.cubemonkeys -= src
QDEL_LIST(bodyparts)
splinted_limbs.Cut()
+ GLOB.human_list -= src
/mob/living/carbon/human/dummy
real_name = "Test Dummy"
status_flags = GODMODE|CANPUSH
/mob/living/carbon/human/skrell/Initialize(mapload)
- ..(mapload, /datum/species/skrell)
+ . = ..(mapload, /datum/species/skrell)
/mob/living/carbon/human/tajaran/Initialize(mapload)
- ..(mapload, /datum/species/tajaran)
+ . = ..(mapload, /datum/species/tajaran)
/mob/living/carbon/human/vulpkanin/Initialize(mapload)
- ..(mapload, /datum/species/vulpkanin)
+ . = ..(mapload, /datum/species/vulpkanin)
/mob/living/carbon/human/unathi/Initialize(mapload)
- ..(mapload, /datum/species/unathi)
+ . = ..(mapload, /datum/species/unathi)
/mob/living/carbon/human/vox/Initialize(mapload)
- ..(mapload, /datum/species/vox)
+ . = ..(mapload, /datum/species/vox)
/mob/living/carbon/human/voxarmalis/Initialize(mapload)
- ..(mapload, /datum/species/vox/armalis)
+ . = ..(mapload, /datum/species/vox/armalis)
/mob/living/carbon/human/skeleton/Initialize(mapload)
- ..(mapload, /datum/species/skeleton)
+ . = ..(mapload, /datum/species/skeleton)
/mob/living/carbon/human/kidan/Initialize(mapload)
- ..(mapload, /datum/species/kidan)
+ . = ..(mapload, /datum/species/kidan)
/mob/living/carbon/human/plasma/Initialize(mapload)
- ..(mapload, /datum/species/plasmaman)
+ . = ..(mapload, /datum/species/plasmaman)
/mob/living/carbon/human/slime/Initialize(mapload)
- ..(mapload, /datum/species/slime)
+ . = ..(mapload, /datum/species/slime)
/mob/living/carbon/human/grey/Initialize(mapload)
- ..(mapload, /datum/species/grey)
+ . = ..(mapload, /datum/species/grey)
/mob/living/carbon/human/abductor/Initialize(mapload)
- ..(mapload, /datum/species/abductor)
+ . = ..(mapload, /datum/species/abductor)
/mob/living/carbon/human/diona/Initialize(mapload)
- ..(mapload, /datum/species/diona)
+ . = ..(mapload, /datum/species/diona)
/mob/living/carbon/human/pod_diona/Initialize(mapload)
- ..(mapload, /datum/species/diona/pod)
+ . = ..(mapload, /datum/species/diona/pod)
/mob/living/carbon/human/machine/Initialize(mapload)
- ..(mapload, /datum/species/machine)
+ . = ..(mapload, /datum/species/machine)
/mob/living/carbon/human/machine/created
name = "Integrated Robotic Chassis"
/mob/living/carbon/human/machine/created/Initialize(mapload)
- ..()
+ . = ..()
rename_character(null, "Integrated Robotic Chassis ([rand(1, 9999)])")
update_dna()
for(var/obj/item/organ/external/E in bodyparts)
@@ -127,34 +129,34 @@
death()
/mob/living/carbon/human/shadow/Initialize(mapload)
- ..(mapload, /datum/species/shadow)
+ . = ..(mapload, /datum/species/shadow)
/mob/living/carbon/human/golem/Initialize(mapload)
- ..(mapload, /datum/species/golem)
+ . = ..(mapload, /datum/species/golem)
/mob/living/carbon/human/wryn/Initialize(mapload)
- ..(mapload, /datum/species/wryn)
+ . = ..(mapload, /datum/species/wryn)
/mob/living/carbon/human/nucleation/Initialize(mapload)
- ..(mapload, /datum/species/nucleation)
+ . = ..(mapload, /datum/species/nucleation)
/mob/living/carbon/human/drask/Initialize(mapload)
- ..(mapload, /datum/species/drask)
+ . = ..(mapload, /datum/species/drask)
/mob/living/carbon/human/monkey/Initialize(mapload)
- ..(mapload, /datum/species/monkey)
+ . = ..(mapload, /datum/species/monkey)
/mob/living/carbon/human/farwa/Initialize(mapload)
- ..(mapload, /datum/species/monkey/tajaran)
+ . = ..(mapload, /datum/species/monkey/tajaran)
/mob/living/carbon/human/wolpin/Initialize(mapload)
- ..(mapload, /datum/species/monkey/vulpkanin)
+ . = ..(mapload, /datum/species/monkey/vulpkanin)
/mob/living/carbon/human/neara/Initialize(mapload)
- ..(mapload, /datum/species/monkey/skrell)
+ . = ..(mapload, /datum/species/monkey/skrell)
/mob/living/carbon/human/stok/Initialize(mapload)
- ..(mapload, /datum/species/monkey/unathi)
+ . = ..(mapload, /datum/species/monkey/unathi)
/mob/living/carbon/human/Stat()
..()
@@ -1160,18 +1162,6 @@
custom_pain("You feel a stabbing pain in your chest!")
L.damage = L.min_bruised_damage
-//returns 1 if made bloody, returns 0 otherwise
-
-/mob/living/carbon/human/clean_blood(var/clean_feet)
- .=..()
- if(clean_feet && !shoes && istype(feet_blood_DNA, /list) && feet_blood_DNA.len)
- feet_blood_color = null
- qdel(feet_blood_DNA)
- bloody_feet = list(BLOOD_STATE_HUMAN = 0, BLOOD_STATE_XENO = 0, BLOOD_STATE_NOT_BLOODY = 0)
- blood_state = BLOOD_STATE_NOT_BLOODY
- update_inv_shoes()
- return 1
-
/mob/living/carbon/human/cuff_resist(obj/item/I)
if(HULK in mutations)
say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ))
@@ -1699,14 +1689,14 @@ Eyes need to have significantly high darksight to shine unless the mob has the X
/mob/living/carbon/human/forceFed(var/obj/item/reagent_containers/food/toEat, mob/user, fullness)
if(!check_has_mouth())
- if(!((istype(toEat, /obj/item/reagent_containers/food/drinks) && (ismachine(src)))))
+ if(!((istype(toEat, /obj/item/reagent_containers/food/drinks) && (ismachineperson(src)))))
to_chat(user, "Where do you intend to put \the [toEat]? \The [src] doesn't have a mouth!")
return 0
return ..()
/mob/living/carbon/human/selfDrink(var/obj/item/reagent_containers/food/drinks/toDrink)
if(!check_has_mouth())
- if(!ismachine(src))
+ if(!ismachineperson(src))
to_chat(src, "Where do you intend to put \the [src]? You don't have a mouth!")
return 0
else
diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm
index 89aa7854264..f9058065fb0 100644
--- a/code/modules/mob/living/carbon/human/human_damage.dm
+++ b/code/modules/mob/living/carbon/human/human_damage.dm
@@ -30,7 +30,7 @@
if(dna.species && amount > 0)
if(use_brain_mod)
amount = amount * dna.species.brain_mod
- sponge.damage = Clamp(sponge.damage + amount, 0, 120)
+ sponge.damage = clamp(sponge.damage + amount, 0, 120)
if(sponge.damage >= 120)
visible_message("[src] goes limp, [p_their()] facial expression utterly blank.")
death()
@@ -48,7 +48,7 @@
if(dna.species && amount > 0)
if(use_brain_mod)
amount = amount * dna.species.brain_mod
- sponge.damage = Clamp(amount, 0, 120)
+ sponge.damage = clamp(amount, 0, 120)
if(sponge.damage >= 120)
visible_message("[src] goes limp, [p_their()] facial expression utterly blank.")
death()
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 82b61a04391..21a3e8bf274 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -84,7 +84,7 @@ emp_act
E.heal_damage(rembrute,0,0,1)
rembrute = nrembrute
user.visible_message("[user] patches some dents on [src]'s [E.name] with [I].")
- if(bleed_rate && isSynthetic())
+ if(bleed_rate && ismachineperson(src))
bleed_rate = 0
user.visible_message("[user] patches some leaks on [src] with [I].")
if(IgniteMob())
@@ -134,7 +134,7 @@ emp_act
if(bp && istype(bp ,/obj/item/clothing))
var/obj/item/clothing/C = bp
if(C.body_parts_covered & def_zone.body_part)
- protection += C.armor[type]
+ protection += C.armor.getRating(type)
return protection
@@ -185,19 +185,19 @@ emp_act
var/block_chance_modifier = round(damage / -3)
if(l_hand && !istype(l_hand, /obj/item/clothing))
- var/final_block_chance = l_hand.block_chance - (Clamp((armour_penetration-l_hand.armour_penetration)/2,0,100)) + block_chance_modifier //So armour piercing blades can still be parried by other blades, for example
+ var/final_block_chance = l_hand.block_chance - (clamp((armour_penetration-l_hand.armour_penetration)/2,0,100)) + block_chance_modifier //So armour piercing blades can still be parried by other blades, for example
if(l_hand.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
return 1
if(r_hand && !istype(r_hand, /obj/item/clothing))
- var/final_block_chance = r_hand.block_chance - (Clamp((armour_penetration-r_hand.armour_penetration)/2,0,100)) + block_chance_modifier //Need to reset the var so it doesn't carry over modifications between attempts
+ var/final_block_chance = r_hand.block_chance - (clamp((armour_penetration-r_hand.armour_penetration)/2,0,100)) + block_chance_modifier //Need to reset the var so it doesn't carry over modifications between attempts
if(r_hand.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
return 1
if(wear_suit)
- var/final_block_chance = wear_suit.block_chance - (Clamp((armour_penetration-wear_suit.armour_penetration)/2,0,100)) + block_chance_modifier
+ var/final_block_chance = wear_suit.block_chance - (clamp((armour_penetration-wear_suit.armour_penetration)/2,0,100)) + block_chance_modifier
if(wear_suit.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
return 1
if(w_uniform)
- var/final_block_chance = w_uniform.block_chance - (Clamp((armour_penetration-w_uniform.armour_penetration)/2,0,100)) + block_chance_modifier
+ var/final_block_chance = w_uniform.block_chance - (clamp((armour_penetration-w_uniform.armour_penetration)/2,0,100)) + block_chance_modifier
if(w_uniform.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
return 1
return 0
@@ -387,11 +387,6 @@ emp_act
to_chat(user, "You hack off a chunk of meat from [name]")
if(!meatleft)
add_attack_logs(user, src, "Chopped up into meat")
- if(!iscarbon(user))
- LAssailant = null
- else
- LAssailant = user
-
qdel(src)
var/obj/item/organ/external/affecting = get_organ(ran_zone(user.zone_selected))
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index 60b6da987dd..3d365afa940 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -37,7 +37,6 @@ GLOBAL_DATUM_INIT(default_martial_art, /datum/martial_art, new())
var/obj/item/s_store = null
var/icon/stand_icon = null
- var/icon/lying_icon = null
var/voice = "" //Instead of new say code calling GetVoice() over and over and over, we're just going to ask this variable, which gets updated in Life()
diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm
index 85bf001a206..5e1b5163a24 100644
--- a/code/modules/mob/living/carbon/human/human_movement.dm
+++ b/code/modules/mob/living/carbon/human/human_movement.dm
@@ -81,7 +81,7 @@
/mob/living/carbon/human/handle_footstep(turf/T)
if(..())
- if(T.footstep_sounds["human"])
+ if(T.footstep_sounds && T.footstep_sounds["human"])
var/S = pick(T.footstep_sounds["human"])
if(S)
if(m_intent == MOVE_INTENT_RUN)
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index c74340d0901..90653a6750b 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -197,7 +197,7 @@
if(!(RADIMMUNE in dna.species.species_traits))
if(radiation)
- radiation = Clamp(radiation, 0, 200)
+ radiation = clamp(radiation, 0, 200)
var/autopsy_damage = 0
switch(radiation)
@@ -635,7 +635,7 @@
else
overeatduration -= 2
- if(!ismachine(src) && nutrition < NUTRITION_LEVEL_HYPOGLYCEMIA) //Gosh damn snowflakey IPCs
+ if(!ismachineperson(src) && nutrition < NUTRITION_LEVEL_HYPOGLYCEMIA) //Gosh damn snowflakey IPCs
var/datum/disease/D = new /datum/disease/critical/hypoglycemia
ForceContractDisease(D)
@@ -697,7 +697,7 @@
alcohol_strength /= sober_str
var/obj/item/organ/internal/liver/L
- if(!isSynthetic())
+ if(!ismachineperson(src))
L = get_int_organ(/obj/item/organ/internal/liver)
if(L)
alcohol_strength *= L.alcohol_intensity
@@ -719,7 +719,7 @@
AdjustConfused(3 / sober_str)
if(alcohol_strength >= blur_start) //blurry eyes
EyeBlurry(10 / sober_str)
- if(!isSynthetic()) //stuff only for non-synthetics
+ if(!ismachineperson(src)) //stuff only for non-synthetics
if(alcohol_strength >= vomit_start) //vomiting
if(prob(8))
fakevomit()
diff --git a/code/modules/mob/living/carbon/human/npcs.dm b/code/modules/mob/living/carbon/human/npcs.dm
index 41c108dadb9..9dcf83f2e9a 100644
--- a/code/modules/mob/living/carbon/human/npcs.dm
+++ b/code/modules/mob/living/carbon/human/npcs.dm
@@ -7,7 +7,7 @@
species_exception = list(/datum/species/monkey)
/mob/living/carbon/human/monkey/punpun/Initialize(mapload)
- ..()
+ . = ..()
name = "Pun Pun"
real_name = name
equip_to_slot(new /obj/item/clothing/under/punpun(src), slot_w_uniform)
diff --git a/code/modules/mob/living/carbon/human/species/_species.dm b/code/modules/mob/living/carbon/human/species/_species.dm
index 21695e25e78..f65cefff49d 100644
--- a/code/modules/mob/living/carbon/human/species/_species.dm
+++ b/code/modules/mob/living/carbon/human/species/_species.dm
@@ -53,7 +53,6 @@
var/stun_mod = 1 // If a species is more/less impacated by stuns/weakens/paralysis
var/speed_mod = 0 // this affects the race's speed. positive numbers make it move slower, negative numbers make it move faster
var/blood_damage_type = OXY //What type of damage does this species take if it's low on blood?
- var/obj/item/mutanthands
var/total_health = 100
var/punchdamagelow = 0 //lowest possible punch damage
var/punchdamagehigh = 9 //highest possible punch damage
@@ -352,21 +351,6 @@
if(organ.receive_damage(damage, 0, sharp, used_weapon))
H.UpdateDamageIcon()
- if(H.LAssailant && ishuman(H.LAssailant)) //superheros still get the comical hit markers
- var/mob/living/carbon/human/A = H.LAssailant
- if(A.mind && (A.mind in (SSticker.mode.superheroes) || SSticker.mode.supervillains || SSticker.mode.greyshirts))
- var/list/attack_bubble_recipients = list()
- var/mob/living/user
- for(var/mob/O in viewers(user, src))
- if(O.client && O.has_vision(information_only=TRUE))
- attack_bubble_recipients.Add(O.client)
- spawn(0)
- var/image/dmgIcon = image('icons/effects/hit_blips.dmi', src, "dmg[rand(1,2)]",MOB_LAYER+1)
- dmgIcon.pixel_x = (!H.lying) ? rand(-3,3) : rand(-11,12)
- dmgIcon.pixel_y = (!H.lying) ? rand(-11,9) : rand(-10,1)
- flick_overlay(dmgIcon, attack_bubble_recipients, 9)
-
-
if(BURN)
H.damageoverlaytemp = 20
damage = damage * burn_mod
@@ -443,6 +427,9 @@
else
target.LAssailant = user
+ target.lastattacker = user.real_name
+ target.lastattackerckey = user.ckey
+
var/damage = rand(user.dna.species.punchdamagelow, user.dna.species.punchdamagehigh)
damage += attack.damage
if(!damage)
diff --git a/code/modules/mob/living/carbon/human/species/zombies.dm b/code/modules/mob/living/carbon/human/species/zombies.dm
deleted file mode 100644
index 1f1c4d979b7..00000000000
--- a/code/modules/mob/living/carbon/human/species/zombies.dm
+++ /dev/null
@@ -1,102 +0,0 @@
-#define REGENERATION_DELAY 60 // After taking damage, how long it takes for automatic regeneration to begin
-
-/datum/species/zombie
- // 1spooky
- name = "High-Functioning Zombie"
- name_plural = "High-Functioning Zombies"
- icobase = 'icons/mob/human_races/r_zombie.dmi'
- deform = 'icons/mob/human_races/r_def_zombie.dmi'
- dies_at_threshold = TRUE
- language = "Zombie"
- species_traits = list(NO_BLOOD, NOZOMBIE, NOTRANSSTING, NO_BREATHE, RADIMMUNE, NO_SCAN)
- var/static/list/spooks = list('sound/hallucinations/growl1.ogg','sound/hallucinations/growl2.ogg','sound/hallucinations/growl3.ogg','sound/hallucinations/veryfar_noise.ogg','sound/hallucinations/wail.ogg')
- warning_low_pressure = -1
- hazard_low_pressure = -1
- hazard_high_pressure = 999999999
- warning_high_pressure = 999999999
- cold_level_1 = -1
- cold_level_2 = -1
- cold_level_3 = -1
- tox_mod = 0
- flesh_color = "#00FF00" // for green examine text
- bodyflags = HAS_SKIN_COLOR
- dietflags = DIET_CARN
- has_organ = list(
- "heart" = /obj/item/organ/internal/heart,
- "lungs" = /obj/item/organ/internal/lungs,
- "liver" = /obj/item/organ/internal/liver,
- "kidneys" = /obj/item/organ/internal/kidneys,
- "brain" = /obj/item/organ/internal/brain,
- "appendix" = /obj/item/organ/internal/appendix,
- "eyes" = /obj/item/organ/internal/eyes,
- "ears" = /obj/item/organ/internal/ears)
-
-
-/datum/species/zombie/infectious
- name = "Infectious Zombie"
- mutanthands = /obj/item/zombie_hand
- icobase = 'icons/mob/human_races/r_zombie.dmi'
- deform = 'icons/mob/human_races/r_def_zombie.dmi'
- brute_mod = 0.8 // 120 damage to KO a zombie, which kills it
- burn_mod = 0.8
- clone_mod = 0.8
- brain_mod = 0.8
- stamina_mod = 0.8
- speed_mod = 1.6
- default_language = "Zombie"
- var/heal_rate = 1
- var/regen_cooldown = 0
-
-/datum/species/zombie/infectious/spec_stun(mob/living/carbon/human/H, amount)
- . = min(20, amount)
-
-/datum/species/zombie/infectious/apply_damage(damage = 0, damagetype = BRUTE, def_zone = null, blocked = 0, sharp = 0, obj/used_weapon = null)
- . = ..()
- if(damage)
- regen_cooldown = world.time + REGENERATION_DELAY
-
-/datum/species/zombie/infectious/handle_life(mob/living/carbon/human/H)
- . = ..()
- H.a_intent = INTENT_HARM // THE SUFFERING MUST FLOW
-
- //Zombies never actually die, they just fall down until they regenerate enough to rise back up.
- //They must be restrained, beheaded or gibbed to stop being a threat.
- if(regen_cooldown < world.time)
- var/heal_amt = heal_rate
- if(H.InCritical())
- heal_amt *= 2
- H.heal_overall_damage(heal_amt,heal_amt)
- H.adjustToxLoss(-heal_amt)
- if(!H.InCritical() && prob(4))
- playsound(H, pick(spooks), 50, TRUE, 10)
-
-//Congrats you somehow died so hard you stopped being a zombie
-/datum/species/zombie/infectious/handle_death(gibbed, mob/living/carbon/C)
- . = ..()
- var/obj/item/organ/internal/zombie_infection/infection
- infection = C.get_organ_slot("zombie_infection")
- if(infection)
- qdel(infection)
-
-/datum/species/zombie/infectious/on_species_gain(mob/living/carbon/human/H, datum/species/old_species)
- . = ..()
- // Deal with the source of this zombie corruption
- // Infection organ needs to be handled separately from mutant_organs
- // because it persists through species transitions
- if(mutanthands)
- H.drop_l_hand()
- H.drop_r_hand()
- H.put_in_hands(new mutanthands())
- H.put_in_hands(new mutanthands())
- var/obj/item/organ/internal/zombie_infection/infection
- infection = H.get_organ_slot("zombie_infection")
- if(!infection)
- infection = new()
- infection.insert(H)
-
-/datum/species/zombie/infectious/on_species_loss(mob/living/carbon/human/C, datum/species/old_species)
- QDEL_NULL(C.r_hand)
- QDEL_NULL(C.l_hand)
- return ..()
-
-#undef REGENERATION_DELAY
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index 2cce48d51c2..81907ba516f 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -376,7 +376,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
//base icons
var/icon/hair_standing = new /icon('icons/mob/human_face.dmi',"bald_s")
- if(head_organ.h_style && !(head && (head.flags & BLOCKHEADHAIR) && !(isSynthetic())))
+ if(head_organ.h_style && !(head && (head.flags & BLOCKHEADHAIR) && !(ismachineperson(src))))
var/datum/sprite_accessory/hair/hair_style = GLOB.hair_styles_full_list[head_organ.h_style]
if(hair_style && hair_style.species_allowed)
if((head_organ.dna.species.name in hair_style.species_allowed) || (head_organ.dna.species.bodyflags & ALL_RPARTS)) //If the head's species is in the list of allowed species for the hairstyle, or the head's species is one flagged to have bodies comprised wholly of cybernetics...
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index 66e2e60f144..c11eaca5293 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -11,6 +11,10 @@
if(stat != DEAD)
handle_organs()
+ //stuff in the stomach
+ if(LAZYLEN(stomach_contents))
+ handle_stomach(times_fired)
+
. = ..()
if(QDELETED(src))
@@ -122,7 +126,7 @@
var/O2_partialpressure = (breath.oxygen/breath.total_moles())*breath_pressure
var/Toxins_partialpressure = (breath.toxins/breath.total_moles())*breath_pressure
var/CO2_partialpressure = (breath.carbon_dioxide/breath.total_moles())*breath_pressure
-
+ var/SA_partialpressure = (breath.sleeping_agent/breath.total_moles())*breath_pressure
//OXYGEN
if(O2_partialpressure < safe_oxy_min) //Not enough oxygen
@@ -162,22 +166,20 @@
//TOXINS/PLASMA
if(Toxins_partialpressure > safe_tox_max)
var/ratio = (breath.toxins/safe_tox_max) * 10
- adjustToxLoss(Clamp(ratio, MIN_TOXIC_GAS_DAMAGE, MAX_TOXIC_GAS_DAMAGE))
+ adjustToxLoss(clamp(ratio, MIN_TOXIC_GAS_DAMAGE, MAX_TOXIC_GAS_DAMAGE))
throw_alert("too_much_tox", /obj/screen/alert/too_much_tox)
else
clear_alert("too_much_tox")
//TRACE GASES
- if(breath.trace_gases.len)
- for(var/datum/gas/sleeping_agent/SA in breath.trace_gases)
- var/SA_partialpressure = (SA.moles/breath.total_moles())*breath_pressure
- if(SA_partialpressure > SA_para_min)
- Paralyse(3)
- if(SA_partialpressure > SA_sleep_min)
- AdjustSleeping(2, bound_lower = 0, bound_upper = 10)
- else if(SA_partialpressure > 0.01)
- if(prob(20))
- emote(pick("giggle","laugh"))
+ if(breath.sleeping_agent)
+ if(SA_partialpressure > SA_para_min)
+ Paralyse(3)
+ if(SA_partialpressure > SA_sleep_min)
+ AdjustSleeping(2, bound_lower = 0, bound_upper = 10)
+ else if(SA_partialpressure > 0.01)
+ if(prob(20))
+ emote(pick("giggle","laugh"))
//BREATH TEMPERATURE
handle_breath_temperature(breath)
@@ -245,7 +247,7 @@
adjustToxLoss(3)
updatehealth("handle mutations and radiation(75-100)")
- radiation = Clamp(radiation, 0, 100)
+ radiation = clamp(radiation, 0, 100)
/mob/living/carbon/handle_chemicals_in_body()
@@ -256,14 +258,15 @@
if(times_fired % 20==2) //dry off a bit once every 20 ticks or so
wetlevel = max(wetlevel - 1,0)
-/mob/living/carbon/handle_stomach(times_fired)
- for(var/mob/living/M in stomach_contents)
+/mob/living/carbon/proc/handle_stomach(times_fired)
+ for(var/thing in stomach_contents)
+ var/mob/living/M = thing
if(M.loc != src)
- stomach_contents.Remove(M)
+ LAZYREMOVE(stomach_contents, M)
continue
if(stat != DEAD)
if(M.stat == DEAD)
- stomach_contents.Remove(M)
+ LAZYREMOVE(stomach_contents, M)
qdel(M)
continue
if(times_fired % 3 == 1)
@@ -478,7 +481,7 @@
P.reagents.remove_any(applied_amount * 0.5)
else
if(!P.reagents || P.reagents.total_volume <= 0)
- processing_patches -= P
+ LAZYREMOVE(processing_patches, P)
qdel(P)
/mob/living/carbon/proc/handle_germs()
diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm
index 6d020ccdad1..3062ef461f9 100644
--- a/code/modules/mob/living/life.dm
+++ b/code/modules/mob/living/life.dm
@@ -58,9 +58,6 @@
handle_fire()
- //stuff in the stomach
- handle_stomach(times_fired)
-
update_gravity(mob_has_gravity())
if(pulling)
@@ -117,9 +114,6 @@
/mob/living/proc/handle_environment(datum/gas_mixture/environment)
return
-/mob/living/proc/handle_stomach(times_fired)
- return
-
/mob/living/proc/update_pulling()
if(incapacitated())
stop_pulling()
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index dfa4bb61c9d..f3d23ca3f51 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -682,9 +682,6 @@
*/////////////////////
/mob/living/proc/resist_grab()
var/resisting = 0
- for(var/obj/O in requests)
- qdel(O)
- resisting++
for(var/X in grabbed_by)
var/obj/item/grab/G = X
resisting++
@@ -740,7 +737,8 @@
clear_alert("weightless")
else
throw_alert("weightless", /obj/screen/alert/weightless)
- float(!has_gravity)
+ if(!flying)
+ float(!has_gravity)
/mob/living/proc/float(on)
if(throwing)
@@ -825,8 +823,7 @@
spawn_dust()
gib()
-/mob/living/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect, end_pixel_y)
- end_pixel_y = get_standard_pixel_y_offset(lying)
+/mob/living/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
if(!used_item)
used_item = get_active_hand()
..()
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index 604fd47de16..b38f1819524 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -79,9 +79,9 @@
/obj/item/proc/get_volume_by_throwforce_and_or_w_class()
if(throwforce && w_class)
- return Clamp((throwforce + w_class) * 5, 30, 100)// Add the item's throwforce to its weight class and multiply by 5, then clamp the value between 30 and 100
+ return clamp((throwforce + w_class) * 5, 30, 100)// Add the item's throwforce to its weight class and multiply by 5, then clamp the value between 30 and 100
else if(w_class)
- return Clamp(w_class * 8, 20, 100) // Multiply the item's weight class by 8, then clamp the value between 20 and 100
+ return clamp(w_class * 8, 20, 100) // Multiply the item's weight class by 8, then clamp the value between 20 and 100
else
return 0
@@ -175,7 +175,7 @@
return
/mob/living/proc/adjust_fire_stacks(add_fire_stacks) //Adjusting the amount of fire_stacks we have on person
- fire_stacks = Clamp(fire_stacks + add_fire_stacks, -20, 20)
+ fire_stacks = clamp(fire_stacks + add_fire_stacks, -20, 20)
if(on_fire && fire_stacks <= 0)
ExtinguishMob()
@@ -260,8 +260,6 @@
add_attack_logs(user, src, "Grabbed passively", ATKLOG_ALL)
var/obj/item/grab/G = new /obj/item/grab(user, src)
- if(buckled)
- to_chat(user, "You cannot grab [src]; [p_they()] [p_are()] buckled in!")
if(!G) //the grab will delete itself in New if src is anchored
return 0
user.put_in_active_hand(G)
diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm
index c272952b6bf..630b2223321 100644
--- a/code/modules/mob/living/say.dm
+++ b/code/modules/mob/living/say.dm
@@ -61,7 +61,7 @@ proc/get_radio_key_from_channel(var/channel)
return default_language
/mob/living/proc/handle_speech_problems(list/message_pieces, var/verb)
- var/robot = isSynthetic()
+ var/robot = ismachineperson(src)
for(var/datum/multilingual_say_piece/S in message_pieces)
if(S.speaking && S.speaking.flags & NO_STUTTER)
continue
@@ -269,12 +269,12 @@ proc/get_radio_key_from_channel(var/channel)
M.hear_say(message_pieces, verb, italics, src, speech_sound, sound_vol, sound_frequency)
if(M.client)
speech_bubble_recipients.Add(M.client)
- spawn(0)
- if(loc && !isturf(loc))
- var/atom/A = loc //Non-turf, let it handle the speech bubble
- A.speech_bubble("hR[speech_bubble_test]", A, speech_bubble_recipients)
- else //Turf, leave speech bubbles to the mob
- speech_bubble("h[speech_bubble_test]", src, speech_bubble_recipients)
+
+ if(loc && !isturf(loc))
+ var/atom/A = loc //Non-turf, let it handle the speech bubble
+ A.speech_bubble("[A.bubble_icon][speech_bubble_test]", A, speech_bubble_recipients)
+ else //Turf, leave speech bubbles to the mob
+ speech_bubble("[bubble_icon][speech_bubble_test]", src, speech_bubble_recipients)
for(var/obj/O in listening_obj)
spawn(0)
@@ -336,7 +336,8 @@ proc/get_radio_key_from_channel(var/channel)
var/datum/multilingual_say_piece/S = message_pieces // Yay BYOND's hilarious typecasting
S.speaking.broadcast(src, S.message)
return 1
-
+ // Log it here since it skips the default way say handles it
+ create_log(SAY_LOG, "(whisper) '[message]'")
whisper_say(message_pieces)
// for weird circumstances where you're inside an atom that is also you, like pai's
@@ -461,10 +462,7 @@ proc/get_radio_key_from_channel(var/channel)
if(M.client)
speech_bubble_recipients.Add(M.client)
- spawn(0)
- var/image/I = image('icons/mob/talk.dmi', src, "h[speech_bubble_test]", MOB_LAYER + 1)
- I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
- flick_overlay(I, speech_bubble_recipients, 30)
+ speech_bubble("[bubble_icon][speech_bubble_test]", src, speech_bubble_recipients)
if(watching.len)
var/rendered = "[name] [not_heard]."
@@ -473,7 +471,7 @@ proc/get_radio_key_from_channel(var/channel)
return 1
-/mob/living/speech_bubble(var/bubble_state = "",var/bubble_loc = src, var/list/bubble_recipients = list())
- var/image/I = image('icons/mob/talk.dmi', bubble_loc, bubble_state, MOB_LAYER + 1)
+/mob/living/speech_bubble(bubble_state = "", bubble_loc = src, list/bubble_recipients = list())
+ var/image/I = image('icons/mob/talk.dmi', bubble_loc, bubble_state, FLY_LAYER)
I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
- flick_overlay(I, bubble_recipients, 30)
+ INVOKE_ASYNC(GLOBAL_PROC, /.proc/flick_overlay, I, bubble_recipients, 30)
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 85c4ceac427..1c232f9f43c 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -243,7 +243,8 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
/mob/living/silicon/ai/proc/show_borg_info()
stat(null, text("Connected cyborgs: [connected_robots.len]"))
- for(var/mob/living/silicon/robot/R in connected_robots)
+ for(var/thing in connected_robots)
+ var/mob/living/silicon/robot/R = thing
var/robot_status = "Nominal"
if(R.stat || !R.client)
robot_status = "OFFLINE"
@@ -251,8 +252,9 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
robot_status = "DEPOWERED"
// Name, Health, Battery, Module, Area, and Status! Everything an AI wants to know about its borgies!
var/area/A = get_area(R)
+ var/area_name = A ? sanitize(A.name) : "Unknown"
stat(null, text("[R.name] | S.Integrity: [R.health]% | Cell: [R.cell ? "[R.cell.charge] / [R.cell.maxcharge]" : "Empty"] | \
- Module: [R.designation] | Loc: [sanitize(A.name)] | Status: [robot_status]"))
+ Module: [R.designation] | Loc: [area_name] | Status: [robot_status]"))
/mob/living/silicon/ai/rename_character(oldname, newname)
if(!..(oldname, newname))
diff --git a/code/modules/mob/living/silicon/robot/component.dm b/code/modules/mob/living/silicon/robot/component.dm
index 26b5683d1a3..99d135df93b 100644
--- a/code/modules/mob/living/silicon/robot/component.dm
+++ b/code/modules/mob/living/silicon/robot/component.dm
@@ -253,7 +253,7 @@ proc/robot_healthscan(mob/user, mob/living/M)
to_chat(user, "You can't analyze non-robotic things!")
return
-
+
switch(scan_type)
if("robot")
var/BU = M.getFireLoss() > 50 ? "[M.getFireLoss()]" : M.getFireLoss()
@@ -269,7 +269,7 @@ proc/robot_healthscan(mob/user, mob/living/M)
to_chat(user, "Localized Damage:")
if(!LAZYLEN(damaged) && !LAZYLEN(missing))
to_chat(user, "\t Components are OK.")
- else
+ else
if(LAZYLEN(damaged))
for(var/datum/robot_component/org in damaged)
user.show_message(text("\t []: [][] - [] - [] - []", \
@@ -282,7 +282,7 @@ proc/robot_healthscan(mob/user, mob/living/M)
if(LAZYLEN(missing))
for(var/datum/robot_component/org in missing)
user.show_message("\t [capitalize(org.name)]: MISSING")
-
+
if(H.emagged && prob(5))
to_chat(user, "\t ERROR: INTERNAL SYSTEMS COMPROMISED")
@@ -313,7 +313,7 @@ proc/robot_healthscan(mob/user, mob/living/M)
if(!organ_found)
to_chat(user, "No prosthetics located.")
- if(H.isSynthetic())
+ if(ismachineperson(H))
to_chat(user, "Internal Fluid Level:[H.blood_volume]/[H.max_blood]")
if(H.bleed_rate)
to_chat(user, "Warning:External component leak detected!")
diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm
index 39bedc78c77..ff7f7fba084 100644
--- a/code/modules/mob/living/silicon/robot/drone/drone.dm
+++ b/code/modules/mob/living/silicon/robot/drone/drone.dm
@@ -6,6 +6,7 @@
icon_state = "repairbot"
maxHealth = 35
health = 35
+ bubble_icon = "machine"
universal_speak = 0
universal_understand = 1
gender = NEUTER
@@ -13,6 +14,7 @@
braintype = "Robot"
lawupdate = 0
density = 0
+ has_camera = FALSE
req_one_access = list(ACCESS_ENGINE, ACCESS_ROBOTICS)
ventcrawler = 2
magpulse = 1
diff --git a/code/modules/mob/living/silicon/robot/drone/drone_items.dm b/code/modules/mob/living/silicon/robot/drone/drone_items.dm
index 7958f983805..8f2b9fee6ae 100644
--- a/code/modules/mob/living/silicon/robot/drone/drone_items.dm
+++ b/code/modules/mob/living/silicon/robot/drone/drone_items.dm
@@ -64,7 +64,7 @@
..()
can_hold = typecacheof(can_hold)
-/obj/item/gripper/verb/drop_item()
+/obj/item/gripper/verb/drop_item_gripped()
set name = "Drop Gripped Item"
set desc = "Release an item from your magnetic gripper."
set category = "Drone"
diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm
index afdab2f5649..07080e694bf 100644
--- a/code/modules/mob/living/silicon/robot/life.dm
+++ b/code/modules/mob/living/silicon/robot/life.dm
@@ -36,7 +36,7 @@
if(is_component_functioning("power cell") && cell.charge)
if(cell.charge <= 100)
uneq_all()
- var/amt = Clamp((lamp_intensity - 2) * 2,1,cell.charge) //Always try to use at least one charge per tick, but allow it to completely drain the cell.
+ var/amt = clamp((lamp_intensity - 2) * 2,1,cell.charge) //Always try to use at least one charge per tick, but allow it to completely drain the cell.
cell.use(amt) //Usage table: 1/tick if off/lowest setting, 4 = 4/tick, 6 = 8/tick, 8 = 12/tick, 10 = 16/tick
else
uneq_all()
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 2eb1e4669ab..d0452293927 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -9,6 +9,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
icon_state = "robot"
maxHealth = 100
health = 100
+ bubble_icon = "robot"
universal_understand = 1
deathgasp_on_death = TRUE
@@ -16,8 +17,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
var/custom_name = ""
var/custom_sprite = 0 //Due to all the sprites involved, a var for our custom borgs may be best
-//Hud stuff
-
+ //Hud stuff
var/obj/screen/inv1 = null
var/obj/screen/inv2 = null
var/obj/screen/inv3 = null
@@ -27,7 +27,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
var/shown_robot_modules = 0 //Used to determine whether they have the module menu shown or not
var/obj/screen/robot_modules_background
-//3 Modules can be activated at any one time.
+ //3 Modules can be activated at any one time.
var/obj/item/robot_module/module = null
var/module_active = null
var/module_state_1 = null
@@ -57,6 +57,9 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
var/is_emaggable = TRUE
var/eye_protection = 0
var/ear_protection = 0
+ var/damage_protection = 0
+ var/emp_protection = FALSE
+ var/xeno_disarm_chance = 85
var/list/force_modules = list()
var/allow_rename = TRUE
@@ -82,11 +85,11 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
var/lockcharge //Used when locking down a borg to preserve cell charge
var/speed = 0 //Cause sec borgs gotta go fast //No they dont!
var/scrambledcodes = 0 // Used to determine if a borg shows up on the robotics console. Setting to one hides them.
+ var/has_camera = TRUE
var/pdahide = 0 //Used to hide the borg from the messenger list
var/tracking_entities = 0 //The number of known entities currently accessing the internal camera
var/braintype = "Cyborg"
var/base_icon = ""
- var/crisis = 0
var/modules_break = TRUE
var/lamp_max = 10 //Maximum brightness of a borg lamp. Set as a var for easy adjusting.
@@ -97,6 +100,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
hud_possible = list(SPECIALROLE_HUD, DIAG_STAT_HUD, DIAG_HUD, DIAG_BATT_HUD)
+ var/default_cell_type = /obj/item/stock_parts/cell/high
var/magpulse = 0
var/ionpulse = 0 // Jetpack-like effect.
var/ionpulse_on = 0 // Jetpack-like effect.
@@ -132,7 +136,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
init()
- if(!scrambledcodes && !camera)
+ if(has_camera && !camera)
camera = new /obj/machinery/camera(src)
camera.c_tag = real_name
camera.network = list("SS13","Robots")
@@ -144,7 +148,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
mmi.icon_state = "boris"
if(!cell) // Make sure a new cell gets created *before* executing initialize_components(). The cell component needs an existing cell for it to get set up properly
- cell = new /obj/item/stock_parts/cell/high(src)
+ cell = new default_cell_type(src)
initialize_components()
//if(!unfinished)
@@ -288,12 +292,9 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
/mob/living/silicon/robot/proc/pick_module()
if(module)
return
- var/list/modules = list("Standard", "Engineering", "Medical", "Miner", "Janitor", "Service", "Security")
+ var/list/modules = list("Generalist", "Engineering", "Medical", "Miner", "Janitor", "Service", "Security")
if(islist(force_modules) && force_modules.len)
modules = force_modules.Copy()
- if(GLOB.security_level == (SEC_LEVEL_GAMMA || SEC_LEVEL_EPSILON) || crisis)
- to_chat(src, "Crisis mode active. The combat module is now available.")
- modules += "Combat"
if(mmi != null && mmi.alien)
modules = list("Hunter")
modtype = input("Please, select a module!", "Robot", null, null) as null|anything in modules
@@ -306,9 +307,9 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
return
switch(modtype)
- if("Standard")
+ if("Generalist")
module = new /obj/item/robot_module/standard(src)
- module.channels = list("Service" = 1)
+ module.channels = list("Engineering" = 1, "Medical" = 1, "Security" = 1, "Service" = 1)
module_sprites["Basic"] = "robot_old"
module_sprites["Android"] = "droid"
module_sprites["Default"] = "Standard"
@@ -337,6 +338,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
module_sprites["Standard"] = "Standard-Mine"
module_sprites["Noble-DIG"] = "Noble-DIG"
module_sprites["Cricket"] = "Cricket-MINE"
+ module_sprites["Lavaland"] = "lavaland"
if("Medical")
module = new /obj/item/robot_module/medical(src)
@@ -353,6 +355,17 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
status_flags &= ~CANPUSH
if("Security")
+ if(!weapons_unlock)
+ var/count_secborgs = 0
+ for(var/mob/living/silicon/robot/R in GLOB.alive_mob_list)
+ if(R && R.stat != DEAD && R.module && istype(R.module, /obj/item/robot_module/security))
+ count_secborgs++
+ var/max_secborgs = 2
+ if(GLOB.security_level == SEC_LEVEL_GREEN)
+ max_secborgs = 1
+ if(count_secborgs >= max_secborgs)
+ to_chat(src, "There are too many Security cyborgs active. Please choose another module.")
+ return
module = new /obj/item/robot_module/security(src)
module.channels = list("Security" = 1)
module_sprites["Basic"] = "secborg"
@@ -387,10 +400,16 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
module_sprites["Noble-CLN"] = "Noble-CLN"
module_sprites["Cricket"] = "Cricket-JANI"
- if("Combat")
- module = new /obj/item/robot_module/combat(src)
+ if("Destroyer") // Rolling Borg
+ module = new /obj/item/robot_module/destroyer(src)
module.channels = list("Security" = 1)
icon_state = "droidcombat"
+ status_flags &= ~CANPUSH
+
+ if("Combat") // Gamma ERT
+ module = new /obj/item/robot_module/combat(src)
+ icon_state = "ertgamma"
+ status_flags &= ~CANPUSH
if("Hunter")
module = new /obj/item/robot_module/alien/hunter(src)
@@ -442,6 +461,8 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
ionpulse = FALSE
magpulse = FALSE
add_language("Robot Talk", 1)
+ if("lava" in weather_immunities) // Remove the lava-immunity effect given by a printable upgrade
+ weather_immunities -= "lava"
status_flags |= CANPUSH
@@ -916,7 +937,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
return 0
/mob/living/silicon/robot/update_icons()
-
overlays.Cut()
if(stat != DEAD && !(paralysis || stunned || IsWeakened() || low_power_mode)) //Not dead, not stunned.
if(custom_panel in custom_eye_names)
@@ -925,36 +945,24 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
overlays += "eyes-[icon_state]"
else
overlays -= "eyes"
-
if(opened)
var/panelprefix = "ov"
if(custom_sprite) //Custom borgs also have custom panels, heh
panelprefix = "[ckey]"
-
if(custom_panel in custom_panel_names) //For default borgs with different panels
panelprefix = custom_panel
-
if(wiresexposed)
overlays += "[panelprefix]-openpanel +w"
else if(cell)
overlays += "[panelprefix]-openpanel +c"
else
overlays += "[panelprefix]-openpanel -c"
-
- var/combat = list("Combat")
- if(modtype in combat)
- if(base_icon == "")
- base_icon = icon_state
- if(module_active && istype(module_active,/obj/item/borg/combat/mobility))
- icon_state = "[base_icon]-roll"
- else
- icon_state = base_icon
- if(module)
- for(var/obj/item/borg/combat/shield/S in module.modules)
- if(activated(S))
- overlays += "[base_icon]-shield"
+ borg_icons()
update_fire()
+/mob/living/silicon/robot/proc/borg_icons() // Exists so that robot/destroyer can override it
+ return
+
/mob/living/silicon/robot/proc/installed_modules()
if(weapon_lock)
to_chat(src, "Weapon lock active, unable to use modules! Count:[weaponlock_time]")
@@ -1309,56 +1317,52 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
..()
update_module_icon()
+/mob/living/silicon/robot/emp_act(severity)
+ if(emp_protection)
+ return
+ ..()
+ switch(severity)
+ if(1)
+ disable_component("comms", 160)
+ if(2)
+ disable_component("comms", 60)
+
/mob/living/silicon/robot/deathsquad
base_icon = "nano_bloodhound"
icon_state = "nano_bloodhound"
designation = "SpecOps"
lawupdate = 0
scrambledcodes = 1
+ has_camera = FALSE
req_one_access = list(ACCESS_CENT_SPECOPS)
ionpulse = 1
magpulse = 1
pdahide = 1
eye_protection = 2 // Immunity to flashes and the visual part of flashbangs
ear_protection = 1 // Immunity to the audio part of flashbangs
+ damage_protection = 10 // Reduce all incoming damage by this number
+ xeno_disarm_chance = 20
allow_rename = FALSE
modtype = "Commando"
faction = list("nanotrasen")
is_emaggable = FALSE
-
-/mob/living/silicon/robot/deathsquad/New(loc)
- ..()
- cell = new /obj/item/stock_parts/cell/hyper(src)
+ default_cell_type = /obj/item/stock_parts/cell/bluespace
/mob/living/silicon/robot/deathsquad/init()
laws = new /datum/ai_laws/deathsquad
module = new /obj/item/robot_module/deathsquad(src)
-
aiCamera = new/obj/item/camera/siliconcam/robot_camera(src)
radio = new /obj/item/radio/borg/deathsquad(src)
radio.recalculateChannels()
-
playsound(loc, 'sound/mecha/nominalsyndi.ogg', 75, 0)
-/mob/living/silicon/robot/combat
- base_icon = "droidcombat"
- icon_state = "droidcombat"
- modtype = "Combat"
- designation = "Combat"
+/mob/living/silicon/robot/deathsquad/bullet_act(var/obj/item/projectile/P)
+ if(istype(P) && P.is_reflectable && P.starting)
+ visible_message("The [P.name] gets reflected by [src]!", "The [P.name] gets reflected by [src]!")
+ P.reflect_back(src)
+ return -1
+ return ..(P)
-/mob/living/silicon/robot/combat/init()
- ..()
- module = new /obj/item/robot_module/combat(src)
- module.channels = list("Security" = 1)
- //languages
- module.add_languages(src)
- //subsystems
- module.add_subsystems_and_actions(src)
-
- status_flags &= ~CANPUSH
-
- radio.config(module.channels)
- notify_ai(2)
/mob/living/silicon/robot/ert
designation = "ERT"
@@ -1366,11 +1370,12 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
scrambledcodes = 1
req_one_access = list(ACCESS_CENT_SPECOPS)
ionpulse = 1
-
force_modules = list("Engineering", "Medical", "Security")
static_radio_channels = 1
allow_rename = FALSE
weapons_unlock = TRUE
+ default_cell_type = /obj/item/stock_parts/cell/super
+ var/eprefix = "Amber"
/mob/living/silicon/robot/ert/init()
@@ -1379,11 +1384,10 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
radio.recalculateChannels()
aiCamera = new/obj/item/camera/siliconcam/robot_camera(src)
-/mob/living/silicon/robot/ert/New(loc, cyborg_unlock)
+/mob/living/silicon/robot/ert/New(loc)
..(loc)
- cell = new /obj/item/stock_parts/cell/hyper(src)
var/rnum = rand(1,1000)
- var/borgname = "ERT [rnum]"
+ var/borgname = "[eprefix] ERT [rnum]"
name = borgname
custom_name = borgname
real_name = name
@@ -1392,22 +1396,64 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
mind.original = src
mind.assigned_role = SPECIAL_ROLE_ERT
mind.special_role = SPECIAL_ROLE_ERT
- if(cyborg_unlock)
- crisis = 1
if(!(mind in SSticker.minds))
SSticker.minds += mind
SSticker.mode.ert += mind
-/mob/living/silicon/robot/ert/gamma
- crisis = 1
-/mob/living/silicon/robot/emp_act(severity)
+/mob/living/silicon/robot/ert/red
+ eprefix = "Red"
+ default_cell_type = /obj/item/stock_parts/cell/hyper
+
+/mob/living/silicon/robot/ert/gamma
+ default_cell_type = /obj/item/stock_parts/cell/bluespace
+ force_modules = list("Combat", "Engineering", "Medical")
+ damage_protection = 5 // Reduce all incoming damage by this number
+ eprefix = "Gamma"
+ magpulse = 1
+ xeno_disarm_chance = 40
+
+
+/mob/living/silicon/robot/destroyer
+ // admin-only borg, the seraph / special ops officer of borgs
+ base_icon = "droidcombat"
+ icon_state = "droidcombat"
+ modtype = "Destroyer"
+ designation = "Destroyer"
+ lawupdate = 0
+ scrambledcodes = 1
+ has_camera = FALSE
+ req_one_access = list(ACCESS_CENT_SPECOPS)
+ ionpulse = 1
+ magpulse = 1
+ pdahide = 1
+ eye_protection = 2 // Immunity to flashes and the visual part of flashbangs
+ ear_protection = 1 // Immunity to the audio part of flashbangs
+ emp_protection = TRUE // Immunity to EMP, due to heavy shielding
+ damage_protection = 20 // Reduce all incoming damage by this number. Very high in the case of /destroyer borgs, since it is an admin-only borg.
+ xeno_disarm_chance = 10
+ default_cell_type = /obj/item/stock_parts/cell/bluespace
+
+/mob/living/silicon/robot/destroyer/init()
..()
- switch(severity)
- if(1)
- disable_component("comms", 160)
- if(2)
- disable_component("comms", 60)
+ module = new /obj/item/robot_module/destroyer(src)
+ module.add_languages(src)
+ module.add_subsystems_and_actions(src)
+ status_flags &= ~CANPUSH
+ if(radio)
+ qdel(radio)
+ radio = new /obj/item/radio/borg/ert/specops(src)
+ radio.recalculateChannels()
+
+/mob/living/silicon/robot/destroyer/borg_icons()
+ if(base_icon == "")
+ base_icon = icon_state
+ if(module_active && istype(module_active,/obj/item/borg/destroyer/mobility))
+ icon_state = "[base_icon]-roll"
+ else
+ icon_state = base_icon
+ overlays += "[base_icon]-shield"
+
/mob/living/silicon/robot/extinguish_light()
update_headlamp(1, 150)
diff --git a/code/modules/mob/living/silicon/robot/robot_damage.dm b/code/modules/mob/living/silicon/robot/robot_damage.dm
index f4290d764d6..b7b81ed40b7 100644
--- a/code/modules/mob/living/silicon/robot/robot_damage.dm
+++ b/code/modules/mob/living/silicon/robot/robot_damage.dm
@@ -76,29 +76,6 @@
if(!LAZYLEN(components))
return
- //Combat shielding absorbs a percentage of damage directly into the cell.
- var/obj/item/borg/combat/shield/shield
- if(module_state_1 && istype(module_state_1, /obj/item/borg/combat/shield))
- shield = module_state_1
- else if(module_state_2 && istype(module_state_2, /obj/item/borg/combat/shield))
- shield = module_state_2
- else if(module_state_3 && istype(module_state_3, /obj/item/borg/combat/shield))
- shield = module_state_3
- if(shield)
- //Shields absorb a certain percentage of damage based on their power setting.
- var/absorb_brute = brute * shield.shield_level
- var/absorb_burn = burn * shield.shield_level
- var/cost = (absorb_brute+absorb_burn) * 100
-
- cell.charge -= cost
- if(cell.charge <= 0)
- cell.charge = 0
- to_chat(src, "Your shield has overloaded!")
- else
- brute -= absorb_brute
- burn -= absorb_burn
- to_chat(src, "Your shield absorbs some of the impact!")
-
var/datum/robot_component/armour/A = get_armour()
if(A)
A.take_damage(brute, burn, sharp, updating_health)
@@ -127,32 +104,15 @@
updatehealth("heal overall damage")
/mob/living/silicon/robot/take_overall_damage(brute = 0, burn = 0, updating_health = TRUE, used_weapon = null, sharp = 0)
- if(status_flags & GODMODE) return //godmode
+ if(status_flags & GODMODE)
+ return
+
+ if(damage_protection)
+ brute = clamp(brute - damage_protection, 0, brute)
+ burn = clamp(burn - damage_protection, 0, burn)
+
var/list/datum/robot_component/parts = get_damageable_components()
- //Combat shielding absorbs a percentage of damage directly into the cell.
- var/obj/item/borg/combat/shield/shield
- if(module_state_1 && istype(module_state_1, /obj/item/borg/combat/shield))
- shield = module_state_1
- else if(module_state_2 && istype(module_state_2, /obj/item/borg/combat/shield))
- shield = module_state_2
- else if(module_state_3 && istype(module_state_3, /obj/item/borg/combat/shield))
- shield = module_state_3
- if(shield)
- //Shields absorb a certain percentage of damage based on their power setting.
- var/absorb_brute = brute * shield.shield_level
- var/absorb_burn = burn * shield.shield_level
- var/cost = (absorb_brute+absorb_burn) * 100
-
- cell.charge -= cost
- if(cell.charge <= 0)
- cell.charge = 0
- to_chat(src, "Your shield has overloaded!")
- else
- brute -= absorb_brute
- burn -= absorb_burn
- to_chat(src, "Your shield absorbs some of the impact!")
-
var/datum/robot_component/armour/A = get_armour()
if(A)
A.take_damage(brute, burn, sharp)
diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm
index 9b4f1089f46..8445a399582 100644
--- a/code/modules/mob/living/silicon/robot/robot_defense.dm
+++ b/code/modules/mob/living/silicon/robot/robot_defense.dm
@@ -2,7 +2,7 @@
if(M.a_intent == INTENT_DISARM)
if(!lying)
M.do_attack_animation(src, ATTACK_EFFECT_DISARM)
- if(prob(85))
+ if(prob(xeno_disarm_chance))
Stun(7)
step(src, get_dir(M,src))
spawn(5)
diff --git a/code/modules/mob/living/silicon/robot/robot_items.dm b/code/modules/mob/living/silicon/robot/robot_items.dm
index 92115986b2e..b1abb49d2ef 100644
--- a/code/modules/mob/living/silicon/robot/robot_items.dm
+++ b/code/modules/mob/living/silicon/robot/robot_items.dm
@@ -73,24 +73,7 @@
/obj/item/borg
var/powerneeded // Percentage of power remaining required to run item
-/obj/item/borg/combat/shield
- name = "personal shielding"
- desc = "A powerful experimental module that turns aside or absorbs incoming attacks at the cost of charge."
- icon = 'icons/obj/decals.dmi'
- icon_state = "shock"
- powerneeded = 25
- var/shield_level = 0.5 //Percentage of damage absorbed by the shield.
-
-/obj/item/borg/combat/shield/verb/set_shield_level()
- set name = "Set shield level"
- set category = "Object"
- set src in range(0)
-
- var/N = input("How much damage should the shield absorb?") in list("5","10","25","50","75","100")
- if(N)
- shield_level = text2num(N)/100
-
-/obj/item/borg/combat/mobility
+/obj/item/borg/destroyer/mobility
name = "mobility module"
desc = "By retracting limbs and tucking in its head, a combat android can roll at high speeds."
icon = 'icons/obj/decals.dmi'
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index 3260775c674..8e8c67693c5 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -118,20 +118,48 @@
return
/obj/item/robot_module/standard
- name = "standard robot module"
+ // if station is fine, assist with constructing station goal room, cleaning, and repairing cables chewed by rats
+ // if medical crisis, assist by providing basic healthcare, retrieving corpses, and monitoring crew lifesigns
+ // if eng crisis, assist by helping repair hull breaches
+ // if sec crisis, assist by opening doors for sec and providing backup zipties on patrols
+ name = "generalist robot module"
module_type = "Standard"
+ subsystems = list(/mob/living/silicon/proc/subsystem_power_monitor, /mob/living/silicon/proc/subsystem_crew_monitor)
+ stacktypes = list(
+ /obj/item/stack/sheet/metal/cyborg = 50,
+ /obj/item/stack/cable_coil/cyborg = 50,
+ /obj/item/stack/rods/cyborg = 60,
+ /obj/item/stack/tile/plasteel = 20
+ )
/obj/item/robot_module/standard/New()
..()
- modules += new /obj/item/melee/baton/loaded(src)
- modules += new /obj/item/extinguisher(src)
- modules += new /obj/item/wrench/cyborg(src)
+ // sec
+ modules += new /obj/item/restraints/handcuffs/cable/zipties/cyborg(src)
+ // janitorial
+ modules += new /obj/item/soap/nanotrasen(src)
+ modules += new /obj/item/lightreplacer/cyborg(src)
+ // eng
modules += new /obj/item/crowbar/cyborg(src)
+ modules += new /obj/item/wrench/cyborg(src)
+ modules += new /obj/item/extinguisher(src) // for firefighting, and propulsion in space
+ modules += new /obj/item/weldingtool/largetank/cyborg(src)
+ // mining
+ modules += new /obj/item/pickaxe(src)
+ modules += new /obj/item/t_scanner/adv_mining_scanner(src)
+ modules += new /obj/item/storage/bag/ore/cyborg(src)
+ // med
modules += new /obj/item/healthanalyzer(src)
+ modules += new /obj/item/reagent_containers/borghypo/basic(src)
+ modules += new /obj/item/roller_holder(src) // for taking the injured to medbay without worsening their injuries or leaving a blood trail the whole way
emag = new /obj/item/melee/energy/sword/cyborg(src)
-
+ for(var/G in stacktypes)
+ var/obj/item/stack/sheet/M = new G(src)
+ M.amount = stacktypes[G]
+ modules += M
fix_modules()
+
/obj/item/robot_module/medical
name = "medical robot module"
module_type = "Medical"
@@ -259,6 +287,7 @@
modules += new /obj/item/mop/advanced/cyborg(src)
modules += new /obj/item/lightreplacer/cyborg(src)
modules += new /obj/item/holosign_creator(src)
+ modules += new /obj/item/extinguisher/mini(src)
emag = new /obj/item/reagent_containers/spray(src)
emag.reagents.add_reagent("lube", 250)
@@ -483,25 +512,44 @@
fix_modules()
-/obj/item/robot_module/combat
- name = "combat robot module"
+/obj/item/robot_module/destroyer
+ name = "destroyer robot module"
module_type = "Malf"
module_actions = list(
/datum/action/innate/robot_sight/thermal,
)
+/obj/item/robot_module/destroyer/New()
+ ..()
+
+ modules += new /obj/item/gun/energy/immolator/multi/cyborg(src) // See comments on /robot_module/combat below
+ modules += new /obj/item/melee/baton/loaded(src) // secondary weapon, for things immune to burn, immune to ranged weapons, or for arresting low-grade threats
+ modules += new /obj/item/restraints/handcuffs/cable/zipties/cyborg(src)
+ modules += new /obj/item/pickaxe/drill/jackhammer(src) // for breaking walls to execute flanking moves
+ modules += new /obj/item/borg/destroyer/mobility(src)
+ emag = null
+ fix_modules()
+
+
+/obj/item/robot_module/combat
+ name = "combat robot module"
+ module_type = "Malf"
+ module_actions = list()
+
/obj/item/robot_module/combat/New()
..()
+ modules += new /obj/item/gun/energy/immolator/multi/cyborg(src) // primary weapon, strong at close range (ie: against blob/terror/xeno), but consumes a lot of energy per shot.
+ // Borg gets 40 shots of this weapon. Gamma Sec ERT gets 10.
+ // So, borg has way more burst damage, but also takes way longer to recharge / get back in the fight once depleted. Has to find a borg recharger and sit in it for ages.
+ // Organic gamma sec ERT carries alternate weapons, including a box of flashbangs, and can load up on a huge number of guns from science. Borg cannot do either.
+ // Overall, gamma borg has higher skill floor but lower skill ceiling.
+ modules += new /obj/item/melee/baton/loaded(src) // secondary weapon, for things immune to burn, immune to ranged weapons, or for arresting low-grade threats
modules += new /obj/item/restraints/handcuffs/cable/zipties/cyborg(src)
- modules += new /obj/item/gun/energy/gun/cyborg(src)
- modules += new /obj/item/pickaxe/drill/jackhammer(src)
- modules += new /obj/item/borg/combat/shield(src)
- modules += new /obj/item/borg/combat/mobility(src)
- modules += new /obj/item/wrench/cyborg(src)
- emag = new /obj/item/gun/energy/lasercannon/cyborg(src)
-
+ modules += new /obj/item/pickaxe/drill/jackhammer(src) // for breaking walls to execute flanking moves
+ emag = null
fix_modules()
+
/obj/item/robot_module/alien/hunter
name = "alien hunter module"
module_type = "Standard"
diff --git a/code/modules/mob/living/silicon/robot/robot_movement.dm b/code/modules/mob/living/silicon/robot/robot_movement.dm
index 4b645b02849..1d3e1cade6d 100644
--- a/code/modules/mob/living/silicon/robot/robot_movement.dm
+++ b/code/modules/mob/living/silicon/robot/robot_movement.dm
@@ -9,7 +9,7 @@
/mob/living/silicon/robot/movement_delay()
. = ..()
. += speed
- if(module_active && istype(module_active,/obj/item/borg/combat/mobility))
+ if(module_active && istype(module_active,/obj/item/borg/destroyer/mobility))
. -= 3
. += config.robot_delay
diff --git a/code/modules/mob/living/silicon/robot/syndicate.dm b/code/modules/mob/living/silicon/robot/syndicate.dm
index f5ac3e5532b..0d1968b3e7a 100644
--- a/code/modules/mob/living/silicon/robot/syndicate.dm
+++ b/code/modules/mob/living/silicon/robot/syndicate.dm
@@ -3,8 +3,10 @@
icon_state = "syndie_bloodhound"
lawupdate = 0
scrambledcodes = 1
+ has_camera = FALSE
pdahide = 1
faction = list("syndicate")
+ bubble_icon = "syndibot"
designation = "Syndicate Assault"
modtype = "Syndicate"
req_access = list(ACCESS_SYNDICATE)
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index 6457afc87d4..c923e0912b7 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -2,7 +2,9 @@
gender = NEUTER
robot_talk_understand = 1
voice_name = "synthesized voice"
+ bubble_icon = "machine"
has_unlimited_silicon_privilege = 1
+ weather_immunities = list("ash")
var/syndicate = 0
var/const/MAIN_CHANNEL = "Main Frequency"
var/lawchannel = MAIN_CHANNEL // Default channel on which to state laws
@@ -283,7 +285,7 @@
/mob/living/silicon/proc/receive_alarm(var/datum/alarm_handler/alarm_handler, var/datum/alarm/alarm, was_raised)
if(!next_alarm_notice)
- next_alarm_notice = world.time + SecondsToTicks(10)
+ next_alarm_notice = world.time + 10 SECONDS
var/list/alarms = queued_alarms[alarm_handler]
if(was_raised)
diff --git a/code/modules/mob/living/silicon/subsystems.dm b/code/modules/mob/living/silicon/subsystems.dm
index 5f00beff1e4..d18d41a40cf 100644
--- a/code/modules/mob/living/silicon/subsystems.dm
+++ b/code/modules/mob/living/silicon/subsystems.dm
@@ -2,7 +2,7 @@
var/register_alarms = 1
var/datum/nano_module/alarm_monitor/all/alarm_monitor
var/datum/nano_module/atmos_control/atmos_control
- var/datum/nano_module/crew_monitor/crew_monitor
+ var/datum/tgui_module/crew_monitor/crew_monitor
var/datum/nano_module/law_manager/law_manager
var/datum/nano_module/power_monitor/silicon/power_monitor
@@ -71,8 +71,7 @@
/mob/living/silicon/proc/subsystem_crew_monitor()
set category = "Subsystems"
set name = "Crew Monitor"
-
- crew_monitor.ui_interact(usr, state = GLOB.self_state)
+ crew_monitor.tgui_interact(usr, state = GLOB.tgui_self_state)
/****************
* Law Manager *
diff --git a/code/modules/mob/living/simple_animal/animal_defense.dm b/code/modules/mob/living/simple_animal/animal_defense.dm
index 2cfc5e746dc..b42f3275997 100644
--- a/code/modules/mob/living/simple_animal/animal_defense.dm
+++ b/code/modules/mob/living/simple_animal/animal_defense.dm
@@ -118,7 +118,7 @@
/mob/living/simple_animal/blob_act(obj/structure/blob/B)
adjustBruteLoss(20)
-/mob/living/simple_animal/do_attack_animation(atom/A, visual_effect_icon, used_item, no_effect, end_pixel_y)
+/mob/living/simple_animal/do_attack_animation(atom/A, visual_effect_icon, used_item, no_effect)
if(!no_effect && !visual_effect_icon && melee_damage_upper)
if(melee_damage_upper < 10)
visual_effect_icon = ATTACK_EFFECT_PUNCH
diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm
index 962b4722f39..cb45fd98e8b 100644
--- a/code/modules/mob/living/simple_animal/bot/bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/bot.dm
@@ -18,7 +18,7 @@
speak_emote = list("states")
friendly = "boops"
-
+ bubble_icon = "machine"
faction = list("neutral", "silicon")
var/obj/machinery/bot_core/bot_core = null
@@ -63,6 +63,7 @@
var/new_destination // pending new destination (waiting for beacon response)
var/destination // destination description tag
var/next_destination // the next destination in the patrol route
+ var/ignorelistcleanuptimer = 1 // This ticks up every automated action, at 300 we clean the ignore list
var/robot_arm = /obj/item/robot_parts/r_arm
var/blockcount = 0 //number of times retried a blocked path
@@ -254,6 +255,15 @@
/mob/living/simple_animal/bot/handle_automated_action()
diag_hud_set_botmode()
+ if(ignorelistcleanuptimer % 300 == 0) // Every 300 actions, clean up the ignore list from old junk
+ for(var/uid in ignore_list)
+ var/atom/referredatom = locateUID(uid)
+ if(!referredatom || QDELETED(referredatom))
+ ignore_list -= uid
+ ignorelistcleanuptimer = 1
+ else
+ ignorelistcleanuptimer++
+
if(!on)
return
@@ -439,14 +449,15 @@ Example usage: patient = scan(/mob/living/carbon/human, oldpatient, 1)
The proc would return a human next to the bot to be set to the patient var.
Pass the desired type path itself, declaring a temporary var beforehand is not required.
*/
-/mob/living/simple_animal/bot/proc/scan(scan_type, old_target, scan_range = DEFAULT_SCAN_RANGE)
+/mob/living/simple_animal/bot/proc/scan(atom/scan_type, atom/old_target, scan_range = DEFAULT_SCAN_RANGE)
var/final_result
for(var/scan in shuffle(view(scan_range, src))) //Search for something in range!
- if(!istype(scan, scan_type)) //Check that the thing we found is the type we want!
+ var/atom/A = scan
+ if(!istype(A, scan_type)) //Check that the thing we found is the type we want!
continue //If not, keep searching!
- if( (scan in ignore_list) || (scan == old_target) ) //Filter for blacklisted elements, usually unreachable or previously processed oness
+ if((A.UID() in ignore_list) || (A == old_target) ) //Filter for blacklisted elements, usually unreachable or previously processed oness
continue
- var/scan_result = process_scan(scan) //Some bots may require additional processing when a result is selected.
+ var/scan_result = process_scan(A) //Some bots may require additional processing when a result is selected.
if(scan_result)
final_result = scan_result
else
@@ -454,17 +465,16 @@ Pass the desired type path itself, declaring a temporary var beforehand is not r
return final_result
//When the scan finds a target, run bot specific processing to select it for the next step. Empty by default.
-/mob/living/simple_animal/bot/proc/process_scan(scan_target)
+/mob/living/simple_animal/bot/proc/process_scan(atom/scan_target)
return scan_target
-/mob/living/simple_animal/bot/proc/add_to_ignore(subject)
+/mob/living/simple_animal/bot/proc/add_to_ignore(atom/A)
if(ignore_list.len < 50) //This will help keep track of them, so the bot is always trying to reach a blocked spot.
- ignore_list |= subject
- else if(ignore_list.len >= subject) //If the list is full, insert newest, delete oldest.
- ignore_list -= ignore_list[1]
- ignore_list |= subject
-
+ ignore_list |= A.UID()
+ else //If the list is full, insert newest, delete oldest.
+ ignore_list.Cut(1, 2)
+ ignore_list |= A.UID()
/*
Movement proc for stepping a bot through a path generated through A-star.
Pass a positive integer as an argument to override a bot's default speed.
diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm
index f9747238138..4cb4a532d6b 100644
--- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm
@@ -50,7 +50,7 @@
/mob/living/simple_animal/bot/cleanbot/bot_reset()
..()
- ignore_list = list() //Allows the bot to clean targets it previously ignored due to being unreachable.
+ ignore_list.Cut() //Allows the bot to clean targets it previously ignored due to being unreachable.
target = null
oldloc = null
@@ -106,7 +106,7 @@
audible_message("[src] makes an excited beeping booping sound!")
if(!target) //Search for cleanables it can see.
- target = scan(/obj/effect/decal/cleanable/)
+ target = scan(/obj/effect/decal/cleanable)
if(!target && auto_patrol) //Search for cleanables it can see.
if(mode == BOT_IDLE || mode == BOT_START_PATROL)
diff --git a/code/modules/mob/living/simple_animal/bot/floorbot.dm b/code/modules/mob/living/simple_animal/bot/floorbot.dm
index 5b0ea28a72a..df96cae3b6b 100644
--- a/code/modules/mob/living/simple_animal/bot/floorbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/floorbot.dm
@@ -56,7 +56,7 @@
..()
target = null
oldloc = null
- ignore_list = list()
+ ignore_list.Cut()
nagged = 0
anchored = FALSE
update_icon()
@@ -270,7 +270,7 @@
return 1
//Floorbots, having several functions, need sort out special conditions here.
-/mob/living/simple_animal/bot/floorbot/process_scan(scan_target)
+/mob/living/simple_animal/bot/floorbot/process_scan(atom/scan_target)
var/result
var/turf/simulated/floor/F
switch(process_type)
diff --git a/code/modules/mob/living/simple_animal/bot/honkbot.dm b/code/modules/mob/living/simple_animal/bot/honkbot.dm
index d9097a82d2e..62c133fffd7 100644
--- a/code/modules/mob/living/simple_animal/bot/honkbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/honkbot.dm
@@ -33,7 +33,7 @@
/obj/machinery/bot_core/honkbot
req_one_access = list(ACCESS_CLOWN, ACCESS_ROBOTICS, ACCESS_MIME)
-/mob/living/simple_animal/bot/honkbot/Initialize()
+/mob/living/simple_animal/bot/honkbot/Initialize(mapload)
. = ..()
update_icon()
auto_patrol = TRUE
diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm
index 728b050dd54..f1278918898 100644
--- a/code/modules/mob/living/simple_animal/bot/mulebot.dm
+++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm
@@ -323,13 +323,13 @@
/mob/living/simple_animal/bot/mulebot/proc/buzz(type)
switch(type)
if(SIGH)
- audible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.")
+ audible_message("[src] makes a sighing buzz.")
playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
if(ANNOYED)
- audible_message("[src] makes an annoyed buzzing sound.", "You hear an electronic buzzing sound.")
+ audible_message("[src] makes an annoyed buzzing sound.")
playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0)
if(DELIGHT)
- audible_message("[src] makes a delighted ping!", "You hear a ping.")
+ audible_message("[src] makes a delighted ping!")
playsound(loc, 'sound/machines/ping.ogg', 50, 0)
@@ -601,7 +601,7 @@
/mob/living/simple_animal/bot/mulebot/proc/at_target()
if(!reached_target)
radio_channel = "Supply" //Supply channel
- audible_message("[src] makes a chiming sound!", "You hear a chime.")
+ audible_message("[src] makes a chiming sound!")
playsound(loc, 'sound/machines/chime.ogg', 50, 0)
reached_target = 1
diff --git a/code/modules/mob/living/simple_animal/corpse.dm b/code/modules/mob/living/simple_animal/corpse.dm
index 10460d11e65..8d0ad5d0e2b 100644
--- a/code/modules/mob/living/simple_animal/corpse.dm
+++ b/code/modules/mob/living/simple_animal/corpse.dm
@@ -103,9 +103,9 @@
name = "Space Wizard Corpse"
outfit = /datum/outfit/wizardcorpse
-/obj/effect/mob_spawn/human/corpse/clownoff/Initialize()
+/obj/effect/mob_spawn/human/corpse/clownoff/Initialize(mapload)
mob_name = "[pick(GLOB.wizard_first)], [pick(GLOB.wizard_second)]"
- ..()
+ . = ..()
/datum/outfit/wizardcorpse
name = "Space Wizard Corpse"
diff --git a/code/modules/mob/living/simple_animal/damage_procs.dm b/code/modules/mob/living/simple_animal/damage_procs.dm
index 6ba69de6a61..fdcbf95216b 100644
--- a/code/modules/mob/living/simple_animal/damage_procs.dm
+++ b/code/modules/mob/living/simple_animal/damage_procs.dm
@@ -3,7 +3,7 @@
if(status_flags & GODMODE)
return FALSE
var/oldbruteloss = bruteloss
- bruteloss = Clamp(bruteloss + amount, 0, maxHealth)
+ bruteloss = clamp(bruteloss + amount, 0, maxHealth)
if(oldbruteloss == bruteloss)
updating_health = FALSE
. = STATUS_UPDATE_NONE
diff --git a/code/modules/mob/living/simple_animal/friendly/dog.dm b/code/modules/mob/living/simple_animal/friendly/dog.dm
index 4b29e703116..07a21af8a0b 100644
--- a/code/modules/mob/living/simple_animal/friendly/dog.dm
+++ b/code/modules/mob/living/simple_animal/friendly/dog.dm
@@ -153,16 +153,16 @@
if(def_zone)
if(def_zone == "head")
if(inventory_head)
- armorval = inventory_head.armor[type]
+ armorval = inventory_head.armor.getRating(type)
else
if(inventory_back)
- armorval = inventory_back.armor[type]
+ armorval = inventory_back.armor.getRating(type)
return armorval
else
if(inventory_head)
- armorval += inventory_head.armor[type]
+ armorval += inventory_head.armor.getRating(type)
if(inventory_back)
- armorval += inventory_back.armor[type]
+ armorval += inventory_back.armor.getRating(type)
return armorval * 0.5
/mob/living/simple_animal/pet/dog/corgi/attackby(obj/item/O, mob/user, params)
diff --git a/code/modules/mob/living/simple_animal/hostile/alien.dm b/code/modules/mob/living/simple_animal/hostile/alien.dm
index 038b3b3d221..7c7b4dd6a2f 100644
--- a/code/modules/mob/living/simple_animal/hostile/alien.dm
+++ b/code/modules/mob/living/simple_animal/hostile/alien.dm
@@ -20,6 +20,7 @@
melee_damage_upper = 25
attacktext = "slashes"
speak_emote = list("hisses")
+ bubble_icon = "alien"
a_intent = INTENT_HARM
attack_sound = 'sound/weapons/bladeslice.ogg'
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
@@ -127,6 +128,7 @@
icon_state = "queen_s"
icon_living = "queen_s"
icon_dead = "queen_dead"
+ bubble_icon = "alienroyal"
move_to_delay = 4
maxHealth = 400
health = 400
@@ -153,7 +155,7 @@
icon_dead = "maid_dead"
/mob/living/simple_animal/hostile/alien/maid/AttackingTarget()
- if(ismovableatom(target))
+ if(ismovable(target))
if(istype(target, /obj/effect/decal/cleanable))
visible_message("\The [src] cleans up \the [target].")
qdel(target)
diff --git a/code/modules/mob/living/simple_animal/hostile/bees.dm b/code/modules/mob/living/simple_animal/hostile/bees.dm
index c1e7548d9a3..3276416fe7f 100644
--- a/code/modules/mob/living/simple_animal/hostile/bees.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bees.dm
@@ -60,6 +60,7 @@
/mob/living/simple_animal/hostile/poison/bees/New()
..()
generate_bee_visuals()
+ AddComponent(/datum/component/swarming)
/mob/living/simple_animal/hostile/poison/bees/Destroy()
beegent = null
diff --git a/code/modules/mob/living/simple_animal/hostile/headcrab.dm b/code/modules/mob/living/simple_animal/hostile/headcrab.dm
index 8d2ba52709f..08eb7128055 100644
--- a/code/modules/mob/living/simple_animal/hostile/headcrab.dm
+++ b/code/modules/mob/living/simple_animal/hostile/headcrab.dm
@@ -25,7 +25,7 @@
var/list/human_overlays = list()
/mob/living/simple_animal/hostile/headcrab/Life(seconds, times_fired)
- if(..())
+ if(..() && !stat)
if(!is_zombie && isturf(src.loc))
for(var/mob/living/carbon/human/H in oview(src, 1)) //Only for corpse right next to/on same tile
if(H.stat == DEAD || (!H.check_death_method() && H.health <= HEALTH_THRESHOLD_DEAD))
@@ -35,7 +35,7 @@
if(cycles >= 4)
for(var/mob/living/simple_animal/K in oview(src, 1)) //Only for corpse right next to/on same tile
if(K.stat == DEAD || (!K.check_death_method() && K.health <= HEALTH_THRESHOLD_DEAD))
- visible_message("[src] consumes [target] whole!")
+ visible_message("[src] consumes [K] whole!")
if(health < maxHealth)
health += 10
qdel(K)
@@ -62,8 +62,8 @@
is_zombie = TRUE
if(H.wear_suit)
var/obj/item/clothing/suit/armor/A = H.wear_suit
- if(A.armor && A.armor["melee"])
- maxHealth += A.armor["melee"] //That zombie's got armor, I want armor!
+ if(A.armor && A.armor.getRating("melee"))
+ maxHealth += A.armor.getRating("melee") //That zombie's got armor, I want armor!
maxHealth += 200
health = maxHealth
name = "zombie"
diff --git a/code/modules/mob/living/simple_animal/hostile/headslug.dm b/code/modules/mob/living/simple_animal/hostile/headslug.dm
index 801514a3256..6800598fc7f 100644
--- a/code/modules/mob/living/simple_animal/hostile/headslug.dm
+++ b/code/modules/mob/living/simple_animal/hostile/headslug.dm
@@ -72,7 +72,7 @@
/obj/item/organ/internal/body_egg/changeling_egg/proc/Pop()
var/mob/living/carbon/human/monkey/M = new(owner)
- owner.stomach_contents += M
+ LAZYADD(owner.stomach_contents, M)
for(var/obj/item/organ/internal/I in src)
I.insert(M, 1)
diff --git a/code/modules/mob/living/simple_animal/hostile/hivebot.dm b/code/modules/mob/living/simple_animal/hostile/hivebot.dm
index d2a97949c8e..c6f3ac845e3 100644
--- a/code/modules/mob/living/simple_animal/hostile/hivebot.dm
+++ b/code/modules/mob/living/simple_animal/hostile/hivebot.dm
@@ -25,6 +25,7 @@
gold_core_spawnable = HOSTILE_SPAWN
loot = list(/obj/effect/decal/cleanable/blood/gibs/robot)
deathmessage = "blows apart!"
+ bubble_icon = "machine"
del_on_death = 1
/mob/living/simple_animal/hostile/hivebot/range
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
index c9139ea7bfd..469ff0cc7e1 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
@@ -116,8 +116,8 @@ Difficulty: Hard
if(charging)
return
- anger_modifier = Clamp(((maxHealth - health)/60),0,20)
- enrage_time = initial(enrage_time) * Clamp(anger_modifier / 20, 0.5, 1)
+ anger_modifier = clamp(((maxHealth - health)/60),0,20)
+ enrage_time = initial(enrage_time) * clamp(anger_modifier / 20, 0.5, 1)
ranged_cooldown = world.time + 50
if(client)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
index 7f1b3942d94..b8c72d7cf84 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
@@ -83,7 +83,7 @@ Difficulty: Very Hard
chosen_attack_num = 4
/mob/living/simple_animal/hostile/megafauna/colossus/OpenFire()
- anger_modifier = Clamp(((maxHealth - health)/50),0,20)
+ anger_modifier = clamp(((maxHealth - health)/50),0,20)
ranged_cooldown = world.time + 120
if(client)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
index e97b7671b67..50531f976e9 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
@@ -103,7 +103,7 @@ Difficulty: Medium
if(swooping)
return
- anger_modifier = Clamp(((maxHealth - health)/50),0,20)
+ anger_modifier = clamp(((maxHealth - health)/50),0,20)
ranged_cooldown = world.time + ranged_cooldown_time
if(client)
@@ -254,7 +254,7 @@ Difficulty: Medium
/mob/living/simple_animal/hostile/megafauna/dragon/proc/line_target(var/offset, var/range, var/atom/at = target)
if(!at)
return
- var/angle = Atan2(at.x - src.x, at.y - src.y) + offset
+ var/angle = ATAN2(at.x - src.x, at.y - src.y) + offset
var/turf/T = get_turf(src)
for(var/i in 1 to range)
var/turf/check = locate(src.x + cos(angle) * i, src.y + sin(angle) * i, src.z)
@@ -344,10 +344,10 @@ Difficulty: Medium
//ensure swoop direction continuity.
if(negative)
- if(IsInRange(x, initial_x + 1, initial_x + DRAKE_SWOOP_DIRECTION_CHANGE_RANGE))
+ if(ISINRANGE(x, initial_x + 1, initial_x + DRAKE_SWOOP_DIRECTION_CHANGE_RANGE))
negative = FALSE
else
- if(IsInRange(x, initial_x - DRAKE_SWOOP_DIRECTION_CHANGE_RANGE, initial_x - 1))
+ if(ISINRANGE(x, initial_x - DRAKE_SWOOP_DIRECTION_CHANGE_RANGE, initial_x - 1))
negative = TRUE
new /obj/effect/temp_visual/dragon_flight/end(loc, negative)
new /obj/effect/temp_visual/dragon_swoop(loc)
@@ -534,7 +534,7 @@ obj/effect/temp_visual/fireball
duration = 9
pixel_z = 270
-/obj/effect/temp_visual/fireball/Initialize()
+/obj/effect/temp_visual/fireball/Initialize(mapload)
. = ..()
animate(src, pixel_z = 0, time = duration)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
index 716f5436223..65d056188a8 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
@@ -452,6 +452,7 @@ Difficulty: Hard
else
burst_range = 3
INVOKE_ASYNC(src, .proc/burst, get_turf(src), 0.25) //melee attacks on living mobs cause it to release a fast burst if on cooldown
+ OpenFire()
else
devour(L)
else
@@ -481,7 +482,7 @@ Difficulty: Hard
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/calculate_rage() //how angry we are overall
did_reset = FALSE //oh hey we're doing SOMETHING, clearly we might need to heal if we recall
- anger_modifier = Clamp(((maxHealth - health) / 42),0,50)
+ anger_modifier = clamp(((maxHealth - health) / 42),0,50)
burst_range = initial(burst_range) + round(anger_modifier * 0.08)
beam_range = initial(beam_range) + round(anger_modifier * 0.12)
diff --git a/code/modules/mob/living/simple_animal/hostile/mimic.dm b/code/modules/mob/living/simple_animal/hostile/mimic.dm
index 848a285abf4..fbf65ccfa9b 100644
--- a/code/modules/mob/living/simple_animal/hostile/mimic.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mimic.dm
@@ -48,8 +48,8 @@
var/attempt_open = 0
// Pickup loot
-/mob/living/simple_animal/hostile/mimic/crate/Initialize()
- ..()
+/mob/living/simple_animal/hostile/mimic/crate/Initialize(mapload)
+ . = ..()
for(var/obj/item/I in loc)
I.loc = src
diff --git a/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm b/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm
index ca9b632e06a..a5248e98bb6 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm
@@ -90,6 +90,7 @@
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/Initialize(mapload)
. = ..()
addtimer(CALLBACK(src, .proc/death), 100)
+ AddComponent(/datum/component/swarming)
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood
diff --git a/code/modules/mob/living/simple_animal/hostile/netherworld.dm b/code/modules/mob/living/simple_animal/hostile/netherworld.dm
index e8ce4027b4e..89164167005 100644
--- a/code/modules/mob/living/simple_animal/hostile/netherworld.dm
+++ b/code/modules/mob/living/simple_animal/hostile/netherworld.dm
@@ -31,7 +31,7 @@
deathmessage = "wails as its form turns into a pulpy mush."
death_sound = 'sound/voice/hiss6.ogg'
-/mob/living/simple_animal/hostile/netherworld/migo/Initialize()
+/mob/living/simple_animal/hostile/netherworld/migo/Initialize(mapload)
. = ..()
migo_sounds = list('sound/items/bubblewrap.ogg', 'sound/items/change_jaws.ogg', 'sound/items/crowbar.ogg', 'sound/items/drink.ogg', 'sound/items/deconstruct.ogg', 'sound/items/change_drill.ogg', 'sound/items/dodgeball.ogg', 'sound/items/eatfood.ogg', 'sound/items/screwdriver.ogg', 'sound/items/weeoo1.ogg', 'sound/items/wirecutter.ogg', 'sound/items/welder.ogg', 'sound/items/zip.ogg', 'sound/items/rped.ogg', 'sound/items/ratchet.ogg', 'sound/items/polaroid1.ogg', 'sound/items/pshoom.ogg', 'sound/items/airhorn.ogg', 'sound/voice/bcreep.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/ed209_20sec.ogg', 'sound/voice/hiss3.ogg', 'sound/voice/hiss6.ogg', 'sound/voice/mpatchedup.ogg', 'sound/voice/mfeelbetter.ogg', 'sound/weapons/sear.ogg', 'sound/ambience/antag/tatoralert.ogg', 'sound/mecha/nominal.ogg', 'sound/mecha/weapdestr.ogg', 'sound/mecha/critdestr.ogg', 'sound/mecha/imag_enh.ogg', 'sound/effects/adminhelp.ogg', 'sound/effects/alert.ogg', 'sound/effects/attackblob.ogg', 'sound/effects/bamf.ogg', 'sound/effects/blobattack.ogg', 'sound/effects/break_stone.ogg', 'sound/effects/bubbles.ogg', 'sound/effects/bubbles2.ogg', 'sound/effects/clang.ogg', 'sound/effects/clownstep2.ogg', 'sound/effects/dimensional_rend.ogg', 'sound/effects/doorcreaky.ogg', 'sound/effects/empulse.ogg', 'sound/effects/explosionfar.ogg', 'sound/effects/explosion1.ogg', 'sound/effects/grillehit.ogg', 'sound/effects/genetics.ogg', 'sound/effects/heartbeat.ogg', 'sound/effects/hyperspace_begin.ogg', 'sound/effects/hyperspace_end.ogg', 'sound/goonstation/effects/screech.ogg', 'sound/effects/phasein.ogg', 'sound/effects/picaxe1.ogg', 'sound/effects/sparks1.ogg', 'sound/effects/smoke.ogg', 'sound/effects/splat.ogg', 'sound/effects/snap.ogg', 'sound/effects/tendril_destroyed.ogg', 'sound/effects/supermatter.ogg', 'sound/misc/desceration-01.ogg', 'sound/misc/desceration-02.ogg', 'sound/misc/desceration-03.ogg', 'sound/misc/bloblarm.ogg', 'sound/goonstation/misc/airraid_loop.ogg', 'sound/misc/interference.ogg', 'sound/misc/notice1.ogg', 'sound/misc/notice2.ogg', 'sound/misc/sadtrombone.ogg', 'sound/misc/slip.ogg', 'sound/weapons/armbomb.ogg', 'sound/weapons/chainsaw.ogg', 'sound/weapons/emitter.ogg', 'sound/weapons/emitter2.ogg', 'sound/weapons/blade1.ogg', 'sound/weapons/bladeslice.ogg', 'sound/weapons/blastcannon.ogg', 'sound/weapons/blaster.ogg', 'sound/weapons/bulletflyby3.ogg', 'sound/weapons/circsawhit.ogg', 'sound/weapons/cqchit2.ogg', 'sound/weapons/drill.ogg', 'sound/weapons/genhit1.ogg', 'sound/weapons/gunshots/gunshot_silenced.ogg', 'sound/weapons/gunshots/gunshot.ogg', 'sound/weapons/handcuffs.ogg', 'sound/weapons/homerun.ogg', 'sound/weapons/kenetic_accel.ogg', 'sound/machines/fryer/deep_fryer_emerge.ogg', 'sound/machines/airlock_alien_prying.ogg', 'sound/machines/airlock_close.ogg', 'sound/machines/airlockforced.ogg', 'sound/machines/airlock_open.ogg', 'sound/machines/alarm.ogg', 'sound/machines/blender.ogg', 'sound/machines/boltsdown.ogg', 'sound/machines/boltsup.ogg', 'sound/machines/buzz-sigh.ogg', 'sound/machines/buzz-two.ogg', 'sound/machines/chime.ogg', 'sound/machines/defib_charge.ogg', 'sound/machines/defib_failed.ogg', 'sound/machines/defib_ready.ogg', 'sound/machines/defib_zap.ogg', 'sound/machines/deniedbeep.ogg', 'sound/machines/ding.ogg', 'sound/machines/disposalflush.ogg', 'sound/machines/door_close.ogg', 'sound/machines/door_open.ogg', 'sound/machines/engine_alert1.ogg', 'sound/machines/engine_alert2.ogg', 'sound/machines/hiss.ogg', 'sound/machines/honkbot_evil_laugh.ogg', 'sound/machines/juicer.ogg', 'sound/machines/ping.ogg', 'sound/ambience/signal.ogg', 'sound/machines/synth_no.ogg', 'sound/machines/synth_yes.ogg', 'sound/machines/terminal_alert.ogg', 'sound/machines/twobeep.ogg', 'sound/machines/ventcrawl.ogg', 'sound/machines/warning-buzzer.ogg', 'sound/ai/outbreak5.ogg', 'sound/ai/outbreak7.ogg', 'sound/ai/poweroff.ogg', 'sound/ai/radiation.ogg', 'sound/ai/shuttlecalled.ogg', 'sound/ai/shuttledock.ogg', 'sound/ai/shuttlerecalled.ogg', 'sound/ai/aimalf.ogg', 'sound/ambience/ambigen1.ogg', 'sound/ambience/ambigen3.ogg', 'sound/ambience/ambigen4.ogg', 'sound/ambience/ambigen5.ogg', 'sound/ambience/ambigen6.ogg', 'sound/ambience/ambigen10.ogg', 'sound/hallucinations/over_here1.ogg', 'sound/hallucinations/over_here2.ogg', 'sound/hallucinations/over_here3.ogg') //hahahaha fuck you code divers
@@ -82,14 +82,14 @@
/obj/structure/spawner/nether/examine(mob/user)
. = ..()
- if(isskeleton(user) || iszombie(user))
+ if(isskeleton(user))
. += "A direct link to another dimension full of creatures very happy to see you. You can see your house from here!"
else
. += "A direct link to another dimension full of creatures not very happy to see you. Entering the link would be a very bad idea."
/obj/structure/spawner/nether/attack_hand(mob/user)
. = ..()
- if(isskeleton(user) || iszombie(user))
+ if(isskeleton(user))
to_chat(user, "You don't feel like going home yet...")
else
user.visible_message("[user] is violently pulled into the link!", \
diff --git a/code/modules/mob/living/simple_animal/hostile/spaceworms.dm b/code/modules/mob/living/simple_animal/hostile/spaceworms.dm
index fd569984920..07f26031ed5 100644
--- a/code/modules/mob/living/simple_animal/hostile/spaceworms.dm
+++ b/code/modules/mob/living/simple_animal/hostile/spaceworms.dm
@@ -335,7 +335,7 @@
//Jiggle the whole worm forwards towards the next segment
-/mob/living/simple_animal/hostile/spaceWorm/do_attack_animation(atom/A, visual_effect_icon, used_item, no_effect, end_pixel_y)
+/mob/living/simple_animal/hostile/spaceWorm/do_attack_animation(atom/A, visual_effect_icon, used_item, no_effect)
..()
if(previousWorm)
previousWorm.do_attack_animation(src)
diff --git a/code/modules/mob/living/simple_animal/hostile/syndicate.dm b/code/modules/mob/living/simple_animal/hostile/syndicate.dm
index 23970e88826..decfc7146cf 100644
--- a/code/modules/mob/living/simple_animal/hostile/syndicate.dm
+++ b/code/modules/mob/living/simple_animal/hostile/syndicate.dm
@@ -260,7 +260,7 @@
alert_on_shield_breach = TRUE
/mob/living/simple_animal/hostile/syndicate/melee/autogib/depot/armory/Initialize(mapload)
- ..()
+ . = ..()
if(prob(50))
// 50% chance of switching to extremely dangerous ranged variant
melee_damage_lower = 10
@@ -349,7 +349,8 @@
icon = 'icons/mob/critter.dmi'
icon_state = "viscerator_attack"
icon_living = "viscerator_attack"
- pass_flags = PASSTABLE
+ pass_flags = PASSTABLE | PASSMOB
+ a_intent = INTENT_HARM
health = 15
maxHealth = 15
obj_damage = 0
@@ -362,6 +363,11 @@
minbodytemp = 0
mob_size = MOB_SIZE_TINY
flying = 1
+ bubble_icon = "syndibot"
gold_core_spawnable = HOSTILE_SPAWN
del_on_death = 1
deathmessage = "is smashed into pieces!"
+
+/mob/living/simple_animal/hostile/viscerator/Initialize(mapload)
+ . = ..()
+ AddComponent(/datum/component/swarming)
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen.dm
index 241cceb3d2c..bf3c98bb86a 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen.dm
@@ -168,7 +168,7 @@
neststep = 4
else
spider_lastspawn = world.time
- var/spiders_left_to_spawn = Clamp( (spider_max_per_nest - CountSpiders()), 1, 10)
+ var/spiders_left_to_spawn = clamp( (spider_max_per_nest - CountSpiders()), 1, 10)
DoLayTerrorEggs(pick(spider_types_standard), spiders_left_to_spawn)
if(4)
// Nest should be full. Otherwise, start replenishing nest (stage 5).
diff --git a/code/modules/mob/living/simple_animal/posessed_object.dm b/code/modules/mob/living/simple_animal/posessed_object.dm
index bde995d8edb..c3cb61d5970 100644
--- a/code/modules/mob/living/simple_animal/posessed_object.dm
+++ b/code/modules/mob/living/simple_animal/posessed_object.dm
@@ -27,7 +27,7 @@
. += "[src] appears to be having trouble staying afloat!"
-/mob/living/simple_animal/possessed_object/do_attack_animation(atom/A, visual_effect_icon, used_item, no_effect, end_pixel_y)
+/mob/living/simple_animal/possessed_object/do_attack_animation(atom/A, visual_effect_icon, used_item, no_effect)
..()
animate_ghostly_presence(src, -1, 20, 1) // Restart the floating animation after the attack animation, as it will be cancelled.
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index ada8ed9896b..7d31b5d523b 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -144,7 +144,7 @@
/mob/living/simple_animal/updatehealth(reason = "none given")
..(reason)
- health = Clamp(health, 0, maxHealth)
+ health = clamp(health, 0, maxHealth)
med_hud_set_health()
/mob/living/simple_animal/StartResting(updating = 1)
diff --git a/code/modules/mob/living/simple_animal/slime/powers.dm b/code/modules/mob/living/simple_animal/slime/powers.dm
index bd9d001f12f..3f978abbfbb 100644
--- a/code/modules/mob/living/simple_animal/slime/powers.dm
+++ b/code/modules/mob/living/simple_animal/slime/powers.dm
@@ -190,7 +190,7 @@
step_away(M,src)
M.Friends = Friends.Copy()
babies += M
- M.mutation_chance = Clamp(mutation_chance+(rand(5,-5)),0,100)
+ M.mutation_chance = clamp(mutation_chance+(rand(5,-5)),0,100)
feedback_add_details("slime_babies_born", "slimebirth_[replacetext(M.colour," ","_")]")
var/mob/living/simple_animal/slime/new_slime = pick(babies)
diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm
index 8c7d14b23f4..15f483bef76 100644
--- a/code/modules/mob/living/simple_animal/slime/slime.dm
+++ b/code/modules/mob/living/simple_animal/slime/slime.dm
@@ -17,6 +17,7 @@
response_harm = "stomps on"
emote_see = list("jiggles", "bounces in place")
speak_emote = list("blorbles")
+ bubble_icon = "slime"
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
diff --git a/code/modules/mob/logout.dm b/code/modules/mob/logout.dm
index 8bdb0d89332..91bf5f0ab9c 100644
--- a/code/modules/mob/logout.dm
+++ b/code/modules/mob/logout.dm
@@ -1,5 +1,6 @@
/mob/Logout()
SSnanoui.user_logout(src) // this is used to clean up (remove) this user's Nano UIs
+ SStgui.on_logout(src) // Cleanup any TGUIs the user has open
unset_machine()
GLOB.player_list -= src
log_access_out(src)
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index b3d985ac4e4..3b86faeb7e6 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -20,10 +20,10 @@
AA.viewers -= src
viewing_alternate_appearances = null
logs.Cut()
- ..()
- return QDEL_HINT_HARDDEL
+ LAssailant = null
+ return ..()
-/mob/Initialize()
+/mob/Initialize(mapload)
GLOB.mob_list += src
if(stat == DEAD)
GLOB.dead_mob_list += src
@@ -31,7 +31,7 @@
GLOB.alive_mob_list += src
set_focus(src)
prepare_huds()
- ..()
+ . = ..()
/atom/proc/prepare_huds()
hud_list = list()
@@ -65,8 +65,8 @@
t+= "Oxygen: [environment.oxygen] \n"
t+= "Plasma : [environment.toxins] \n"
t+= "Carbon Dioxide: [environment.carbon_dioxide] \n"
- for(var/datum/gas/trace_gas in environment.trace_gases)
- to_chat(usr, "[trace_gas.type]: [trace_gas.moles] \n")
+ t+= "N2O: [environment.sleeping_agent] \n"
+ t+= "Agent B: [environment.agent_b] \n"
usr.show_message(t, 1)
@@ -127,14 +127,12 @@
// self_message (optional) is what the src mob hears.
// deaf_message (optional) is what deaf people will see.
// hearing_distance (optional) is the range, how many tiles away the message can be heard.
-/mob/audible_message(var/message, var/deaf_message, var/hearing_distance, var/self_message)
+/mob/audible_message(message, deaf_message, hearing_distance)
var/range = 7
if(hearing_distance)
range = hearing_distance
var/msg = message
for(var/mob/M in get_mobs_in_view(range, src))
- if(self_message && M == src)
- msg = self_message
M.show_message(msg, 2, deaf_message, 1)
// based on say code
@@ -156,12 +154,12 @@
// message is the message output to anyone who can hear.
// deaf_message (optional) is what deaf people will see.
// hearing_distance (optional) is the range, how many tiles away the message can be heard.
-/atom/proc/audible_message(var/message, var/deaf_message, var/hearing_distance)
+/atom/proc/audible_message(message, deaf_message, hearing_distance)
var/range = 7
if(hearing_distance)
range = hearing_distance
for(var/mob/M in get_mobs_in_view(range, src))
- M.show_message( message, 2, deaf_message, 1)
+ M.show_message(message, 2, deaf_message, 1)
/mob/proc/findname(msg)
for(var/mob/M in GLOB.mob_list)
@@ -754,7 +752,7 @@ GLOBAL_LIST_INIT(slot_equipment_priority, list( \
if(client.holder && (client.holder.rights & R_ADMIN))
is_admin = 1
- else if(stat != DEAD || istype(src, /mob/new_player))
+ else if(stat != DEAD || isnewplayer(src))
to_chat(usr, "You must be observing to use this!")
return
@@ -1299,8 +1297,6 @@ GLOBAL_LIST_INIT(slot_equipment_priority, list( \
.["Add Organ"] = "?_src_=vars;addorgan=[UID()]"
.["Remove Organ"] = "?_src_=vars;remorgan=[UID()]"
- .["Fix NanoUI"] = "?_src_=vars;fix_nano=[UID()]"
-
.["Add Verb"] = "?_src_=vars;addverb=[UID()]"
.["Remove Verb"] = "?_src_=vars;remverb=[UID()]"
@@ -1390,3 +1386,29 @@ GLOBAL_LIST_INIT(slot_equipment_priority, list( \
///Force set the mob nutrition
/mob/proc/set_nutrition(change)
nutrition = max(0, change)
+
+/mob/clean_blood(clean_hands = TRUE, clean_mask = TRUE, clean_feet = TRUE)
+ . = ..()
+ if(bloody_hands && clean_hands)
+ bloody_hands = 0
+ update_inv_gloves()
+ if(l_hand)
+ if(l_hand.clean_blood())
+ update_inv_l_hand()
+ if(r_hand)
+ if(r_hand.clean_blood())
+ update_inv_r_hand()
+ if(back)
+ if(back.clean_blood())
+ update_inv_back()
+ if(wear_mask && clean_mask)
+ if(wear_mask.clean_blood())
+ update_inv_wear_mask()
+ if(clean_feet)
+ feet_blood_color = null
+ qdel(feet_blood_DNA)
+ bloody_feet = list(BLOOD_STATE_HUMAN = 0, BLOOD_STATE_XENO = 0, BLOOD_STATE_NOT_BLOODY = 0)
+ blood_state = BLOOD_STATE_NOT_BLOODY
+ update_inv_shoes()
+ update_icons() //apply the now updated overlays to the mob
+
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index dc77610b97e..1477be47d89 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -31,8 +31,8 @@
var/use_me = 1 //Allows all mobs to use the me verb by default, will have to manually specify they cannot
var/damageoverlaytemp = 0
var/computer_id = null
- var/lastattacker = null
- var/lastattacked = null
+ var/lastattacker = null // real name of the person doing the attacking
+ var/lastattackerckey = null // their ckey
var/list/attack_log_old = list( )
var/list/debug_log = null
@@ -50,7 +50,6 @@
var/med_record = ""
var/sec_record = ""
var/gen_record = ""
- var/bhunger = 0 //Carbon
var/lying = 0
var/lying_prev = 0
var/lastpuke = 0
@@ -61,8 +60,7 @@
var/emote_type = 1 // Define emote default type, 1 for seen emotes, 2 for heard emotes
var/name_archive //For admin things like possession
- var/timeofdeath = 0.0//Living
-
+ var/timeofdeath = 0 //Living
var/bodytemperature = 310.055 //98.7 F
var/flying = 0
@@ -71,22 +69,22 @@
var/hunger_drain = HUNGER_FACTOR // how quickly the mob gets hungry; largely utilized by species.
var/overeatduration = 0 // How long this guy is overeating //Carbon
- var/intent = null//Living
+ var/intent = null //Living
var/shakecamera = 0
- var/a_intent = INTENT_HELP//Living
- var/m_intent = MOVE_INTENT_RUN//Living
+ var/a_intent = INTENT_HELP //Living
+ var/m_intent = MOVE_INTENT_RUN //Living
var/lastKnownIP = null
/// movable atoms buckled to this mob
- var/atom/movable/buckled = null//Living
+ var/atom/movable/buckled = null //Living
/// movable atom we are buckled to
var/atom/movable/buckling
- var/obj/item/l_hand = null//Living
- var/obj/item/r_hand = null//Living
- var/obj/item/back = null//Human/Monkey
- var/obj/item/tank/internal = null//Human/Monkey
- var/obj/item/storage/s_active = null//Carbon
- var/obj/item/clothing/mask/wear_mask = null//Carbon
+ var/obj/item/l_hand = null //Living
+ var/obj/item/r_hand = null //Living
+ var/obj/item/back = null //Human
+ var/obj/item/tank/internal = null //Human
+ var/obj/item/storage/s_active = null //Carbon
+ var/obj/item/clothing/mask/wear_mask = null //Carbon
var/datum/hud/hud_used = null
@@ -95,7 +93,6 @@
var/research_scanner = 0 //For research scanner equipped mobs. Enable to show research data when examining.
var/list/grabbed_by = list()
- var/list/requests = list()
var/lighting_alpha = LIGHTING_PLANE_ALPHA_VISIBLE
var/list/mapobjs = list()
@@ -103,9 +100,9 @@
var/emote_cd = 0 // Used to supress emote spamming. 1 if on CD, 2 if disabled by admin (manually set), else 0
- var/job = null//Living
+ var/job = null //Living
- var/datum/dna/dna = null//Carbon
+ var/datum/dna/dna = null //Carbon
var/radiation = 0 //Carbon
var/list/mutations = list() //Carbon -- Doohl
@@ -179,8 +176,6 @@
var/turf/listed_turf = null //the current turf being examined in the stat panel
var/list/shouldnt_see = list() //list of objects that this mob shouldn't see in the stat panel. this silliness is needed because of AI alt+click and cult blood runes
- var/kills = 0
-
var/stance_damage = 0 //Whether this mob's ability to stand has been affected
var/list/active_genes = list()
diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm
index f595f6b4839..37e116b4376 100644
--- a/code/modules/mob/mob_grab.dm
+++ b/code/modules/mob/mob_grab.dm
@@ -53,12 +53,11 @@
hud.master = src
//check if assailant is grabbed by victim as well
- if(assailant.grabbed_by)
- for(var/obj/item/grab/G in assailant.grabbed_by)
- if(G.assailant == affecting && G.affecting == assailant)
- G.dancing = 1
- G.adjust_position()
- dancing = 1
+ for(var/obj/item/grab/G in assailant.grabbed_by)
+ if(G.assailant == affecting && G.affecting == assailant)
+ G.dancing = 1
+ G.adjust_position()
+ dancing = 1
clean_grabbed_by(assailant, affecting)
adjust_position()
@@ -276,7 +275,7 @@
assailant.visible_message("[assailant] has reinforced [assailant.p_their()] grip on [affecting] (now neck)!")
state = GRAB_NECK
icon_state = "grabbed+1"
- assailant.setDir(get_dir(assailant, affecting))
+
add_attack_logs(assailant, affecting, "Neck grabbed", ATKLOG_ALL)
if(!iscarbon(assailant))
affecting.LAssailant = null
@@ -296,7 +295,7 @@
assailant.next_move = world.time + 10
if(!affecting.get_organ_slot("breathing_tube"))
affecting.AdjustLoseBreath(1)
- affecting.setDir(WEST)
+
adjust_position()
//This is used to make sure the victim hasn't managed to yackety sax away before using the grab.
@@ -409,7 +408,7 @@
add_attack_logs(attacker, affecting, "Devoured")
affecting.forceMove(user)
- attacker.stomach_contents.Add(affecting)
+ LAZYADD(attacker.stomach_contents, affecting)
qdel(src)
/obj/item/grab/proc/checkvalid(var/mob/attacker, var/mob/prey) //does all the checking for the attack proc to see if a mob can eat another with the grab
@@ -433,9 +432,10 @@
/obj/item/grab/Destroy()
if(affecting)
- affecting.pixel_x = 0
- affecting.pixel_y = 0 //used to be an animate, not quick enough for del'ing
- affecting.layer = initial(affecting.layer)
+ if(!affecting.buckled)
+ affecting.pixel_x = 0
+ affecting.pixel_y = 0 //used to be an animate, not quick enough for qdel'ing
+ affecting.layer = initial(affecting.layer)
affecting.grabbed_by -= src
affecting = null
if(assailant)
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index df2a39c0930..5fb5bcb06c8 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -12,14 +12,6 @@
return 1
return 0
-/mob/proc/isSynthetic()
- return 0
-
-/mob/living/carbon/human/isSynthetic()
- if(ismachine(src))
- return TRUE
- return FALSE
-
/mob/proc/get_screen_colour()
/mob/proc/update_client_colour(var/time = 10) //Update the mob's client.color with an animation the specified time in length.
@@ -467,7 +459,7 @@ GLOBAL_LIST_INIT(intents, list(INTENT_HELP,INTENT_DISARM,INTENT_GRAB,INTENT_HARM
name = realname
for(var/mob/M in GLOB.player_list)
- if(M.client && ((!istype(M, /mob/new_player) && M.stat == DEAD) || check_rights(R_ADMIN|R_MOD,0,M)) && M.get_preference(CHAT_DEAD))
+ if(M.client && ((!isnewplayer(M) && M.stat == DEAD) || check_rights(R_ADMIN|R_MOD,0,M)) && M.get_preference(CHAT_DEAD))
var/follow
var/lname
if(subject)
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index 471ddc42557..4797c685fe1 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -26,25 +26,6 @@
else
to_chat(usr, "This mob type cannot throw items.")
-
-/client/verb/drop_item()
- set hidden = 1
- if(!isrobot(mob))
- mob.drop_item_v()
- return
-
-
-/* /client/Center()
- /* No 3D movement in 2D spessman game. dir 16 is Z Up
- if(isobj(mob.loc))
- var/obj/O = mob.loc
- if(mob.canmove)
- return O.relaymove(mob, 16)
- */
- return
- */
-
-
/client/proc/Move_object(direct)
if(mob && mob.control_object)
if(mob.control_object.density)
@@ -186,7 +167,7 @@
if(newdir)
direct = newdir
n = get_step(mob, direct)
-
+
. = mob.SelfMove(n, direct, delay)
mob.setDir(direct)
diff --git a/code/modules/mob/mob_transformation_simple.dm b/code/modules/mob/mob_transformation_simple.dm
index c3ec68c9793..1e704ea3449 100644
--- a/code/modules/mob/mob_transformation_simple.dm
+++ b/code/modules/mob/mob_transformation_simple.dm
@@ -4,7 +4,7 @@
//Note that this proc does NOT do MMI related stuff!
/mob/proc/change_mob_type(var/new_type = null, var/turf/location = null, var/new_name = null as text, var/delete_old_mob = 0 as num, var/forcekey = 0)
- if(istype(src,/mob/new_player))
+ if(isnewplayer(src))
to_chat(usr, "cannot convert players who have not entered yet.")
return
diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm
index af3d439df59..f53daba6626 100644
--- a/code/modules/mob/new_player/new_player.dm
+++ b/code/modules/mob/new_player/new_player.dm
@@ -12,8 +12,13 @@
stat = 2
canmove = 0
-/mob/new_player/New()
+/mob/new_player/Initialize(mapload)
+ SHOULD_CALL_PARENT(FALSE)
+ if(initialized)
+ stack_trace("Warning: [src]([type]) initialized multiple times!")
+ initialized = TRUE
GLOB.mob_list += src
+ return INITIALIZE_HINT_NORMAL
/mob/new_player/verb/new_player_panel()
set src = usr
@@ -205,6 +210,7 @@
if(!client.holder && !config.antag_hud_allowed) // For new ghosts we remove the verb from even showing up if it's not allowed.
observer.verbs -= /mob/dead/observer/verb/toggle_antagHUD // Poor guys, don't know what they are missing!
observer.key = key
+ QDEL_NULL(mind)
GLOB.respawnable_list += observer
qdel(src)
return 1
diff --git a/code/modules/mob/new_player/sprite_accessories/sprite_accessories.dm b/code/modules/mob/new_player/sprite_accessories/sprite_accessories.dm
index 476861861a3..d4834eccc80 100644
--- a/code/modules/mob/new_player/sprite_accessories/sprite_accessories.dm
+++ b/code/modules/mob/new_player/sprite_accessories/sprite_accessories.dm
@@ -48,7 +48,7 @@
var/gender = NEUTER //Determines if the accessory will be skipped or included in random hair generations
// Restrict some styles to specific species
- var/list/species_allowed = list("Human", "Slime People", "Infectious Zombie", "High-Functioning Zombie")
+ var/list/species_allowed = list("Human", "Slime People")
var/list/sprite_sheets = list() //For accessories common across species but need to use 'fitted' sprites (like underwear). e.g. list("Vox" = 'icons/mob/species/vox/iconfile.dmi')
var/list/models_allowed = list() //Specifies which, if any, hairstyles or markings can be accessed by which prosthetics. Should equal the manufacturing company name in robolimbs.dm.
var/list/heads_allowed = null //Specifies which, if any, alt heads a head marking, hairstyle or facial hair style is compatible with.
diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm
index 81d22e40a0b..0417e28f546 100644
--- a/code/modules/mob/say.dm
+++ b/code/modules/mob/say.dm
@@ -114,7 +114,7 @@
return get_turf(src)
-/mob/proc/say_test(var/text)
+/proc/say_test(text)
var/ending = copytext(text, length(text))
if(ending == "?")
return "1"
diff --git a/code/modules/mob/status_procs.dm b/code/modules/mob/status_procs.dm
index b61ce171194..3a053e74e16 100644
--- a/code/modules/mob/status_procs.dm
+++ b/code/modules/mob/status_procs.dm
@@ -207,4 +207,4 @@
/mob/proc/adjust_bodytemperature(amount, min_temp = 0, max_temp = INFINITY)
if(bodytemperature >= min_temp && bodytemperature <= max_temp)
- bodytemperature = Clamp(bodytemperature + amount, min_temp, max_temp)
+ bodytemperature = clamp(bodytemperature + amount, min_temp, max_temp)
diff --git a/code/modules/mob/typing_indicator.dm b/code/modules/mob/typing_indicator.dm
index 4dfbddc2d84..a2ca226147c 100644
--- a/code/modules/mob/typing_indicator.dm
+++ b/code/modules/mob/typing_indicator.dm
@@ -5,31 +5,32 @@ mob/var/typing
mob/var/last_typed
mob/var/last_typed_time
-GLOBAL_DATUM(typing_indicator, /image)
+GLOBAL_LIST_EMPTY(typing_indicator)
-/mob/proc/set_typing_indicator(var/state)
+/mob/proc/set_typing_indicator(state)
- if(!GLOB.typing_indicator)
- GLOB.typing_indicator = image('icons/mob/talk.dmi', null, "typing", MOB_LAYER + 1)
- GLOB.typing_indicator.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
+ if(!GLOB.typing_indicator[bubble_icon])
+ GLOB.typing_indicator[bubble_icon] = image('icons/mob/talk.dmi', null, "[bubble_icon]typing", FLY_LAYER)
+ var/image/I = GLOB.typing_indicator[bubble_icon]
+ I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
if(ishuman(src))
var/mob/living/carbon/human/H = src
if((MUTE in H.mutations) || H.silent)
- overlays -= GLOB.typing_indicator
+ overlays -= GLOB.typing_indicator[bubble_icon]
return
if(client)
if((client.prefs.toggles & SHOW_TYPING) || stat != CONSCIOUS || is_muzzled())
- overlays -= GLOB.typing_indicator
+ overlays -= GLOB.typing_indicator[bubble_icon]
else
if(state)
if(!typing)
- overlays += GLOB.typing_indicator
+ overlays += GLOB.typing_indicator[bubble_icon]
typing = 1
else
if(typing)
- overlays -= GLOB.typing_indicator
+ overlays -= GLOB.typing_indicator[bubble_icon]
typing = 0
return state
diff --git a/code/modules/modular_computers/file_system/programs/engineering/sm_monitor.dm b/code/modules/modular_computers/file_system/programs/engineering/sm_monitor.dm
index 379e71ba484..0045b36f30e 100644
--- a/code/modules/modular_computers/file_system/programs/engineering/sm_monitor.dm
+++ b/code/modules/modular_computers/file_system/programs/engineering/sm_monitor.dm
@@ -84,9 +84,7 @@
data["SM_ambienttemp"] = air.temperature
data["SM_ambientpressure"] = air.return_pressure()
//data["SM_EPR"] = round((air.total_moles / air.group_multiplier) / 23.1, 0.01)
- var/other_moles = 0.0
- for(var/datum/gas/G in air.trace_gases)
- other_moles+=G.moles
+ var/other_moles = air.total_trace_moles()
var/TM = air.total_moles()
if(TM)
data["SM_gas_O2"] = round(100*air.oxygen/TM,0.01)
@@ -94,7 +92,7 @@
data["SM_gas_N2"] = round(100*air.nitrogen/TM,0.01)
data["SM_gas_PL"] = round(100*air.toxins/TM,0.01)
if(other_moles)
- data["SM_gas_OTHER"] = round(100*other_moles/TM,0.01)
+ data["SM_gas_OTHER"] = round(100 * other_moles / TM, 0.01)
else
data["SM_gas_OTHER"] = 0
else
diff --git a/code/modules/nano/modules/crew_monitor.dm b/code/modules/nano/modules/crew_monitor.dm
deleted file mode 100644
index 4ed7fc03de1..00000000000
--- a/code/modules/nano/modules/crew_monitor.dm
+++ /dev/null
@@ -1,41 +0,0 @@
-/datum/nano_module/crew_monitor
- name = "Crew monitor"
-
-/datum/nano_module/crew_monitor/Topic(href, href_list)
- if(..())
- return 1
- var/turf/T = get_turf(nano_host())
- if(!T || !is_level_reachable(T.z))
- to_chat(usr, "Unable to establish a connection: You're too far away from the station!")
- return 0
- if(href_list["track"])
- if(isAI(usr))
- var/mob/living/silicon/ai/AI = usr
- var/mob/living/carbon/human/H = locate(href_list["track"]) in GLOB.mob_list
- if(hassensorlevel(H, SUIT_SENSOR_TRACKING))
- AI.ai_actual_track(H)
- return 1
-
-/datum/nano_module/crew_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state)
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
- if(!ui)
- ui = new(user, src, ui_key, "crew_monitor.tmpl", "Crew Monitoring Computer", 900, 800)
-
- // adding a template with the key "mapContent" enables the map ui functionality
- ui.add_template("mapContent", "crew_monitor_map_content.tmpl")
- // adding a template with the key "mapHeader" replaces the map header content
- ui.add_template("mapHeader", "crew_monitor_map_header.tmpl")
-
- ui.open()
-
- // should make the UI auto-update; doesn't seem to?
- ui.set_auto_update(1)
-
-/datum/nano_module/crew_monitor/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
- var/data[0]
- var/turf/T = get_turf(nano_host())
-
- data["isAI"] = isAI(user)
- data["crewmembers"] = GLOB.crew_repository.health_data(T)
-
- return data
diff --git a/code/modules/nano/modules/law_manager.dm b/code/modules/nano/modules/law_manager.dm
index f2423e57c2f..64850ea954d 100644
--- a/code/modules/nano/modules/law_manager.dm
+++ b/code/modules/nano/modules/law_manager.dm
@@ -99,7 +99,7 @@
if(href_list["change_supplied_law_position"])
var/new_position = input(usr, "Enter new supplied law position between 1 and [MAX_SUPPLIED_LAW_NUMBER], inclusive. Inherent laws at the same index as a supplied law will not be stated.", "Law Position", supplied_law_position) as num|null
if(isnum(new_position) && can_still_topic())
- supplied_law_position = Clamp(new_position, 1, MAX_SUPPLIED_LAW_NUMBER)
+ supplied_law_position = clamp(new_position, 1, MAX_SUPPLIED_LAW_NUMBER)
return 1
if(href_list["edit_law"])
diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm
index 5ca53396253..d5cbbdc0ad6 100644
--- a/code/modules/paperwork/photocopier.dm
+++ b/code/modules/paperwork/photocopier.dm
@@ -340,7 +340,7 @@
return 0
else
playsound(loc, 'sound/machines/ping.ogg', 50, 0)
- atom_say("Attention: Posterior Placed on Printing Plaque!")
+ atom_say("Attention: Posterior Placed on Printing Plaque!")
return 1
/obj/machinery/photocopier/emag_act(user as mob)
diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm
index 1134f7a0752..0cb571d576c 100644
--- a/code/modules/paperwork/photography.dm
+++ b/code/modules/paperwork/photography.dm
@@ -237,7 +237,7 @@ GLOBAL_LIST_INIT(SpookyGhosts, list("ghost","shade","shade2","ghost-narsie","hor
if(A.invisibility)
if(see_ghosts && istype(A,/mob/dead/observer))
var/mob/dead/observer/O = A
- if(O.following)
+ if(O.orbiting)
continue
if(user.mind && !(user.mind.assigned_role == "Chaplain"))
atoms.Add(image('icons/mob/mob.dmi', O.loc, pick(GLOB.SpookyGhosts), 4, SOUTH))
@@ -297,7 +297,7 @@ GLOBAL_LIST_INIT(SpookyGhosts, list("ghost","shade","shade2","ghost-narsie","hor
if(M.invisibility)
if(see_ghosts && istype(M,/mob/dead/observer))
var/mob/dead/observer/O = M
- if(O.following)
+ if(O.orbiting)
continue
if(!mob_detail)
mob_detail = "You can see a g-g-g-g-ghooooost! "
@@ -562,13 +562,13 @@ GLOBAL_LIST_INIT(SpookyGhosts, list("ghost","shade","shade2","ghost-narsie","hor
talk_into(M, msg)
for(var/obj/machinery/computer/security/telescreen/T in GLOB.machines)
if(T.watchers[M] == camera)
- T.audible_message("(Newscaster) [M] says, '[msg]'", hearing_distance = 2)
+ T.atom_say(msg)
/obj/item/videocam/hear_message(mob/M as mob, msg)
if(camera && on)
for(var/obj/machinery/computer/security/telescreen/T in GLOB.machines)
if(T.watchers[M] == camera)
- T.audible_message("(Newscaster) [M] [msg]", hearing_distance = 2)
+ T.atom_say(msg)
///hauntings, like hallucinations but more spooky
diff --git a/code/modules/pda/cart_apps.dm b/code/modules/pda/cart_apps.dm
index 6c03241a096..d47f4184daf 100644
--- a/code/modules/pda/cart_apps.dm
+++ b/code/modules/pda/cart_apps.dm
@@ -366,6 +366,7 @@
JaniData["user_loc"] = list("x" = cl.x, "y" = cl.y)
else
JaniData["user_loc"] = list("x" = 0, "y" = 0)
+
var/MopData[0]
for(var/obj/item/mop/M in GLOB.janitorial_equipment)
var/turf/ml = get_turf(M)
@@ -375,10 +376,6 @@
var/direction = get_dir(pda, M)
MopData[++MopData.len] = list ("x" = ml.x, "y" = ml.y, "dir" = uppertext(dir2text(direction)), "status" = M.reagents.total_volume ? "Wet" : "Dry")
- if(!MopData.len)
- MopData[++MopData.len] = list("x" = 0, "y" = 0, dir=null, status = null)
-
-
var/BucketData[0]
for(var/obj/structure/mopbucket/B in GLOB.janitorial_equipment)
var/turf/bl = get_turf(B)
@@ -386,13 +383,10 @@
if(bl.z != cl.z)
continue
var/direction = get_dir(pda,B)
- BucketData[++BucketData.len] = list ("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = B.reagents.total_volume/100)
-
- if(!BucketData.len)
- BucketData[++BucketData.len] = list("x" = 0, "y" = 0, dir=null, status = null)
+ BucketData[++BucketData.len] = list ("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "volume" = B.reagents.total_volume, "max_volume" = B.reagents.maximum_volume)
var/CbotData[0]
- for(var/mob/living/simple_animal/bot/cleanbot/B in GLOB.simple_animals)
+ for(var/mob/living/simple_animal/bot/cleanbot/B in GLOB.bots_list)
var/turf/bl = get_turf(B)
if(bl)
if(bl.z != cl.z)
@@ -400,9 +394,6 @@
var/direction = get_dir(pda,B)
CbotData[++CbotData.len] = list("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = B.on ? "Online" : "Offline")
-
- if(!CbotData.len)
- CbotData[++CbotData.len] = list("x" = 0, "y" = 0, dir=null, status = null)
var/CartData[0]
for(var/obj/structure/janitorialcart/B in GLOB.janitorial_equipment)
var/turf/bl = get_turf(B)
@@ -410,12 +401,10 @@
if(bl.z != cl.z)
continue
var/direction = get_dir(pda,B)
- CartData[++CartData.len] = list("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = B.reagents.total_volume/100)
- if(!CartData.len)
- CartData[++CartData.len] = list("x" = 0, "y" = 0, dir=null, status = null)
+ CartData[++CartData.len] = list("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "volume" = B.reagents.total_volume, "max_volume" = B.reagents.maximum_volume)
- JaniData["mops"] = MopData
- JaniData["buckets"] = BucketData
- JaniData["cleanbots"] = CbotData
- JaniData["carts"] = CartData
+ JaniData["mops"] = MopData.len ? MopData : null
+ JaniData["buckets"] = BucketData.len ? BucketData : null
+ JaniData["cleanbots"] = CbotData.len ? CbotData : null
+ JaniData["carts"] = CartData.len ? CartData : null
data["janitor"] = JaniData
diff --git a/code/modules/pda/mob_hunt_game_app.dm b/code/modules/pda/mob_hunt_game_app.dm
index c48ebdd4e9e..c72aa6d0d41 100644
--- a/code/modules/pda/mob_hunt_game_app.dm
+++ b/code/modules/pda/mob_hunt_game_app.dm
@@ -47,7 +47,7 @@
SSmob_hunt.connected_clients += src
connected = 1
if(pda)
- pda.audible_message("[bicon(pda)] Connection established. Capture all of the mobs, [pda.owner ? pda.owner : "hunter"]!", null, 2)
+ pda.atom_say("Connection established. Capture all of the mobs, [pda.owner ? pda.owner : "hunter"]!")
return 1
/datum/data/pda/app/mob_hunter_game/proc/get_player()
@@ -67,7 +67,7 @@
connected = 0
//show a disconnect message if we were disconnected involuntarily (reason argument provided)
if(pda && reason)
- pda.audible_message("[bicon(pda)] Disconnected from server. Reason: [reason].", null, 2)
+ pda.atom_say("Disconnected from server. Reason: [reason].")
/datum/data/pda/app/mob_hunter_game/program_process()
if(!SSmob_hunt || !connected)
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index 234b885284e..56e38d31935 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -70,7 +70,6 @@
var/locked = 1
var/coverlocked = 1
var/aidisabled = 0
- var/tdir = null
var/obj/machinery/power/terminal/terminal = null
var/lastused_light = 0
var/lastused_equip = 0
@@ -147,7 +146,7 @@
if(terminal)
terminal.connect_to_network()
-/obj/machinery/power/apc/New(turf/loc, ndir, building = 0)
+/obj/machinery/power/apc/New(turf/loc, direction, building = 0)
if(!armor)
armor = list("melee" = 20, "bullet" = 20, "laser" = 10, "energy" = 100, "bomb" = 30, "bio" = 100, "rad" = 100, "fire" = 90, "acid" = 50)
..()
@@ -155,16 +154,12 @@
GLOB.apcs = sortAtom(GLOB.apcs)
wires = new(src)
- // offset 24 pixels in direction of dir
- // this allows the APC to be embedded in a wall, yet still inside an area
- if(building)
- setDir(ndir)
- tdir = dir // to fix Vars bug
- setDir(SOUTH)
- pixel_x = (src.tdir & 3)? 0 : (src.tdir == 4 ? 24 : -24)
- pixel_y = (src.tdir & 3)? (src.tdir ==1 ? 24 : -24) : 0
if(building)
+ // Offset 24 pixels in direction of dir. This allows the APC to be embedded in a wall, yet still inside an area
+ setDir(direction) // This is only used for pixel offsets, and later terminal placement. APC dir doesn't affect its sprite since it only has one orientation.
+ set_pixel_offsets_from_dir(24, -24, 24, -24)
+
area = get_area(src)
area.apc |= src
opened = 1
@@ -177,7 +172,7 @@
/obj/machinery/power/apc/Destroy()
GLOB.apcs -= src
if(malfai && operating)
- malfai.malf_picker.processing_time = Clamp(malfai.malf_picker.processing_time - 10,0,1000)
+ malfai.malf_picker.processing_time = clamp(malfai.malf_picker.processing_time - 10,0,1000)
area.power_light = 0
area.power_equip = 0
area.power_environ = 0
@@ -194,8 +189,8 @@
/obj/machinery/power/apc/proc/make_terminal()
// create a terminal object at the same position as original turf loc
// wires will attach to this
- terminal = new/obj/machinery/power/terminal(src.loc)
- terminal.setDir(tdir)
+ terminal = new/obj/machinery/power/terminal(get_turf(src))
+ terminal.setDir(dir)
terminal.master = src
/obj/machinery/power/apc/Initialize(mapload)
@@ -545,7 +540,7 @@
/obj/machinery/power/apc/crowbar_act(mob/living/user, obj/item/I)
. = TRUE
- if(!I.tool_start_check(user, 0))
+ if(!I.tool_start_check(src, user, 0))
return
if(opened) // a) on open apc
if(has_electronics==1)
@@ -1333,7 +1328,7 @@
/obj/machinery/power/apc/proc/set_broken()
if(malfai && operating)
- malfai.malf_picker.processing_time = Clamp(malfai.malf_picker.processing_time - 10,0,1000)
+ malfai.malf_picker.processing_time = clamp(malfai.malf_picker.processing_time - 10,0,1000)
stat |= BROKEN
operating = 0
if(occupier)
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index 0dc2fe0a129..b6c65d979cf 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -125,7 +125,7 @@ By design, d1 is the smallest direction and d2 is the highest
/obj/structure/cable/proc/surplus()
if(powernet)
- return Clamp(powernet.avail-powernet.load, 0, powernet.avail)
+ return clamp(powernet.avail-powernet.load, 0, powernet.avail)
else
return 0
@@ -141,7 +141,7 @@ By design, d1 is the smallest direction and d2 is the highest
/obj/structure/cable/proc/delayed_surplus()
if(powernet)
- return Clamp(powernet.newavail - powernet.delayedload, 0, powernet.newavail)
+ return clamp(powernet.newavail - powernet.delayedload, 0, powernet.newavail)
else
return 0
diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm
index 24f55d34454..b92b456890f 100644
--- a/code/modules/power/cell.dm
+++ b/code/modules/power/cell.dm
@@ -160,7 +160,7 @@
/obj/item/stock_parts/cell/proc/get_electrocute_damage()
if(charge >= 1000)
- return Clamp(20 + round(charge / 25000), 20, 195) + rand(-5, 5)
+ return clamp(20 + round(charge / 25000), 20, 195) + rand(-5, 5)
else
return 0
diff --git a/code/modules/power/power.dm b/code/modules/power/power.dm
index b4cc25bf390..ff4074d045e 100644
--- a/code/modules/power/power.dm
+++ b/code/modules/power/power.dm
@@ -42,7 +42,7 @@
/obj/machinery/power/proc/surplus()
if(powernet)
- return Clamp(powernet.avail-powernet.load, 0, powernet.avail)
+ return clamp(powernet.avail-powernet.load, 0, powernet.avail)
else
return 0
@@ -58,7 +58,7 @@
/obj/machinery/power/proc/delayed_surplus()
if(powernet)
- return Clamp(powernet.newavail - powernet.delayedload, 0, powernet.newavail)
+ return clamp(powernet.newavail - powernet.delayedload, 0, powernet.newavail)
else
return 0
diff --git a/code/modules/power/powernet.dm b/code/modules/power/powernet.dm
index a4ab64a2099..f73498cff2c 100644
--- a/code/modules/power/powernet.dm
+++ b/code/modules/power/powernet.dm
@@ -97,6 +97,6 @@
/datum/powernet/proc/get_electrocute_damage()
if(avail >= 1000)
- return Clamp(20 + round(avail / 25000), 20, 195) + rand(-5, 5)
+ return clamp(20 + round(avail / 25000), 20, 195) + rand(-5, 5)
else
return 0
diff --git a/code/modules/power/singularity/particle_accelerator/particle_control.dm b/code/modules/power/singularity/particle_accelerator/particle_control.dm
index f1a7f130592..b8ba53ae432 100644
--- a/code/modules/power/singularity/particle_accelerator/particle_control.dm
+++ b/code/modules/power/singularity/particle_accelerator/particle_control.dm
@@ -24,6 +24,7 @@
wires = new(src)
connected_parts = list()
update_icon()
+ use_log = list()
/obj/machinery/particle_accelerator/control_box/Destroy()
if(active)
diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm
index 7e1d4f59267..d3f5f76303c 100644
--- a/code/modules/power/supermatter/supermatter.dm
+++ b/code/modules/power/supermatter/supermatter.dm
@@ -218,7 +218,7 @@
damage = max(0, damage + between(-DAMAGE_RATE_LIMIT, (removed.temperature - CRITICAL_TEMPERATURE) / 150, damage_inc_limit))
//Maxes out at 100% oxygen pressure
- oxygen = Clamp((removed.oxygen - (removed.nitrogen * NITROGEN_RETARDATION_FACTOR)) / removed.total_moles(), 0, 1)
+ oxygen = clamp((removed.oxygen - (removed.nitrogen * NITROGEN_RETARDATION_FACTOR)) / removed.total_moles(), 0, 1)
var/temp_factor
var/equilibrium_power
diff --git a/code/modules/power/tesla/energy_ball.dm b/code/modules/power/tesla/energy_ball.dm
index 60b2a30dc34..d9b20c9d075 100644
--- a/code/modules/power/tesla/energy_ball.dm
+++ b/code/modules/power/tesla/energy_ball.dm
@@ -51,7 +51,7 @@
pixel_x = -32
pixel_y = -32
for(var/ball in orbiting_balls)
- var/range = rand(1, Clamp(orbiting_balls.len, 3, 7))
+ var/range = rand(1, clamp(orbiting_balls.len, 3, 7))
tesla_zap(ball, range, TESLA_MINI_POWER/7*range, TRUE)
else
energy = 0 // ensure we dont have miniballs of miniballs
@@ -271,7 +271,7 @@
closest_grounding_rod.tesla_act(power, explosive)
else if(closest_mob)
- var/shock_damage = Clamp(round(power/400), 10, 90) + rand(-5, 5)
+ var/shock_damage = clamp(round(power/400), 10, 90) + rand(-5, 5)
closest_mob.electrocute_act(shock_damage, source, 1, tesla_shock = TRUE)
if(issilicon(closest_mob))
var/mob/living/silicon/S = closest_mob
diff --git a/code/modules/power/treadmill.dm b/code/modules/power/treadmill.dm
index 39c5d732128..6fd72d0ae9c 100644
--- a/code/modules/power/treadmill.dm
+++ b/code/modules/power/treadmill.dm
@@ -50,7 +50,7 @@
update_icon()
return
- speed = Clamp(speed - friction, 0, MAX_SPEED)
+ speed = clamp(speed - friction, 0, MAX_SPEED)
for(var/A in (loc.contents - src))
var/atom/movable/AM = A
if(AM.anchored)
diff --git a/code/modules/procedural_mapping/mapGeneratorModules/helpers.dm b/code/modules/procedural_mapping/mapGeneratorModules/helpers.dm
index 3e43c5638d1..5a933251872 100644
--- a/code/modules/procedural_mapping/mapGeneratorModules/helpers.dm
+++ b/code/modules/procedural_mapping/mapGeneratorModules/helpers.dm
@@ -18,6 +18,8 @@
T.air.nitrogen = T.nitrogen
T.air.carbon_dioxide = T.carbon_dioxide
T.air.toxins = T.toxins
+ T.air.sleeping_agent = T.sleeping_agent
+ T.air.agent_b = T.agent_b
T.air.temperature = T.temperature
SSair.add_to_active(T)
diff --git a/code/modules/projectiles/ammunition/energy.dm b/code/modules/projectiles/ammunition/energy.dm
index e0eb509aa9d..bcadfc62e08 100644
--- a/code/modules/projectiles/ammunition/energy.dm
+++ b/code/modules/projectiles/ammunition/energy.dm
@@ -12,7 +12,7 @@
select_name = "kill"
/obj/item/ammo_casing/energy/laser/cyborg //to balance cyborg energy cost seperately
- e_cost = 250
+ e_cost = 250
/obj/item/ammo_casing/energy/lasergun
projectile_type = /obj/item/projectile/beam/laser
@@ -75,6 +75,10 @@
e_cost = 125
select_name = "precise"
+/obj/item/ammo_casing/energy/immolator/strong/cyborg
+ // Used by gamma ERT borgs
+ e_cost = 1000 // 5x that of the standard laser, for 2.25x the damage (if 1/1 shots hit) plus ignite. Not energy-efficient, but can be used for sniping.
+
/obj/item/ammo_casing/energy/immolator/scatter
projectile_type = /obj/item/projectile/beam/immolator/weak
e_cost = 125
@@ -82,6 +86,10 @@
variance = 25
select_name = "scatter"
+/obj/item/ammo_casing/energy/immolator/scatter/cyborg
+ // Used by gamma ERT borgs
+ e_cost = 1000 // 5x that of the standard laser, for 7.5x the damage (if 6/6 shots hit) plus ignite. Efficient only if you hit with at least 4/6 of the shots.
+
/obj/item/ammo_casing/energy/electrode
projectile_type = /obj/item/projectile/energy/electrode
select_name = "stun"
diff --git a/code/modules/projectiles/ammunition/magazines.dm b/code/modules/projectiles/ammunition/magazines.dm
index 5890110b635..8cb48f8e36a 100644
--- a/code/modules/projectiles/ammunition/magazines.dm
+++ b/code/modules/projectiles/ammunition/magazines.dm
@@ -383,7 +383,7 @@
/obj/item/ammo_box/magazine/m12g/update_icon()
..()
- icon_state = "[initial(icon_state)]-[Ceiling(ammo_count(0)/8)*8]"
+ icon_state = "[initial(icon_state)]-[CEILING(ammo_count(0)/8, 1)*8]"
/obj/item/ammo_box/magazine/m12g/buckshot
name = "shotgun magazine (12g buckshot slugs)"
@@ -494,7 +494,7 @@
/obj/item/ammo_box/magazine/laser/update_icon()
..()
- icon_state = "[initial(icon_state)]-[Ceiling(ammo_count(0)/20)*20]"
+ icon_state = "[initial(icon_state)]-[CEILING(ammo_count(0)/20, 1)*20]"
/obj/item/ammo_box/magazine/toy/smgm45
name = "donksoft SMG magazine"
diff --git a/code/modules/projectiles/firing.dm b/code/modules/projectiles/firing.dm
index d1e549dbdb0..869feae8f97 100644
--- a/code/modules/projectiles/firing.dm
+++ b/code/modules/projectiles/firing.dm
@@ -96,7 +96,7 @@
var/ox = round(screenview/2) //"origin" x
var/oy = round(screenview/2) //"origin" y
- var/angle = Atan2(y - oy, x - ox)
+ var/angle = ATAN2(y - oy, x - ox)
Angle = angle
if(spread)
Angle += spread
diff --git a/code/modules/projectiles/guns/dartgun.dm b/code/modules/projectiles/guns/dartgun.dm
index 0a50b844f4a..8c46e542b4a 100644
--- a/code/modules/projectiles/guns/dartgun.dm
+++ b/code/modules/projectiles/guns/dartgun.dm
@@ -175,11 +175,6 @@
for(var/datum/reagent/A in D.reagents.reagent_list)
R += A.id + " ("
R += num2text(A.volume) + "),"
- if(istype(M, /mob))
- if(!iscarbon(user))
- M.LAssailant = null
- else
- M.LAssailant = user
add_attack_logs(user, M, "Shot with dartgun containing [R]")
diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm
index d071ad236d1..ce0abc8cc69 100644
--- a/code/modules/projectiles/guns/energy.dm
+++ b/code/modules/projectiles/guns/energy.dm
@@ -136,7 +136,7 @@
/obj/item/gun/energy/update_icon()
overlays.Cut()
- var/ratio = Ceiling((cell.charge / cell.maxcharge) * charge_sections)
+ var/ratio = CEILING((cell.charge / cell.maxcharge) * charge_sections, 1)
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
var/iconState = "[icon_state]_charge"
var/itemState = null
diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
index ecf5eeed77e..19316cb9540 100644
--- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
+++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
@@ -253,7 +253,7 @@
icon = 'icons/obj/objects.dmi'
icon_state = "modkit"
origin_tech = "programming=2;materials=2;magnets=4"
- require_module = 1
+ require_module = TRUE
module_type = /obj/item/robot_module/miner
usesound = 'sound/items/screwdriver.ogg'
var/denied_type = null
diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm
index 9d4cfaee3d4..3e9c882458e 100644
--- a/code/modules/projectiles/guns/energy/laser.dm
+++ b/code/modules/projectiles/guns/energy/laser.dm
@@ -139,6 +139,12 @@
var/append = shot.select_name
overlays += image(icon = icon, icon_state = "multilensimmolator-[append]")
+
+/obj/item/gun/energy/immolator/multi/cyborg
+ name = "cyborg immolator cannon"
+ ammo_type = list(/obj/item/ammo_casing/energy/immolator/scatter/cyborg, /obj/item/ammo_casing/energy/immolator/strong/cyborg) // scatter is default, because it is more useful
+
+
////////Laser Tag////////////////////
/obj/item/gun/energy/laser/tag
diff --git a/code/modules/projectiles/guns/magic/staff.dm b/code/modules/projectiles/guns/magic/staff.dm
index 9196596c8b5..72d128178a6 100644
--- a/code/modules/projectiles/guns/magic/staff.dm
+++ b/code/modules/projectiles/guns/magic/staff.dm
@@ -58,8 +58,6 @@
ammo_type = /obj/item/ammo_casing/magic/slipping
icon_state = "staffofslipping"
item_state = "staffofslipping"
- max_charges = 10
- recharge_rate = 2
fire_sound = 'sound/items/bikehorn.ogg'
/obj/item/gun/magic/staff/slipping/honkmother
diff --git a/code/modules/projectiles/guns/magic/wand.dm b/code/modules/projectiles/guns/magic/wand.dm
index 7a013f3083c..5823e69b39a 100644
--- a/code/modules/projectiles/guns/magic/wand.dm
+++ b/code/modules/projectiles/guns/magic/wand.dm
@@ -12,9 +12,9 @@
/obj/item/gun/magic/wand/New()
if(prob(75) && variable_charges) //25% chance of listed max charges, 50% chance of 1/2 max charges, 25% chance of 1/3 max charges
if(prob(33))
- max_charges = Ceiling(max_charges / 3)
+ max_charges = CEILING(max_charges / 3, 1)
else
- max_charges = Ceiling(max_charges / 2)
+ max_charges = CEILING(max_charges / 2, 1)
..()
/obj/item/gun/magic/wand/examine(mob/user)
diff --git a/code/modules/projectiles/guns/projectile/automatic.dm b/code/modules/projectiles/guns/projectile/automatic.dm
index f2ce54bbd52..17a20f82d59 100644
--- a/code/modules/projectiles/guns/projectile/automatic.dm
+++ b/code/modules/projectiles/guns/projectile/automatic.dm
@@ -112,7 +112,7 @@
/obj/item/gun/projectile/automatic/c20r/update_icon()
..()
- icon_state = "c20r[magazine ? "-[Ceiling(get_ammo(0)/4)*4]" : ""][chambered ? "" : "-e"][suppressed ? "-suppressed" : ""]"
+ icon_state = "c20r[magazine ? "-[CEILING(get_ammo(0)/4, 1)*4]" : ""][chambered ? "" : "-e"][suppressed ? "-suppressed" : ""]"
//WT550//
/obj/item/gun/projectile/automatic/wt550
@@ -134,7 +134,7 @@
/obj/item/gun/projectile/automatic/wt550/update_icon()
..()
- icon_state = "wt550[magazine ? "-[Ceiling(get_ammo(0)/4)*4]" : ""]"
+ icon_state = "wt550[magazine ? "-[CEILING(get_ammo(0)/4, 1)*4]" : ""]"
//Type-U3 Uzi//
/obj/item/gun/projectile/automatic/mini_uzi
@@ -194,8 +194,8 @@
overlays += "[initial(icon_state)]gren"
icon_state = "[initial(icon_state)][magazine ? "" : "-e"]"
if(magazine)
- overlays += image(icon = icon, icon_state = "m90-[Ceiling(get_ammo(0)/6)*6]")
- item_state = "m90-[Ceiling(get_ammo(0)/7.5)]"
+ overlays += image(icon = icon, icon_state = "m90-[CEILING(get_ammo(0)/6, 1)*6]")
+ item_state = "m90-[CEILING(get_ammo(0)/7.5, 1)]"
else
item_state = "m90-0"
return
@@ -303,4 +303,4 @@
/obj/item/gun/projectile/automatic/lasercarbine/update_icon()
..()
- icon_state = "lasercarbine[magazine ? "-[Ceiling(get_ammo(0)/5)*5]" : ""]"
+ icon_state = "lasercarbine[magazine ? "-[CEILING(get_ammo(0)/5, 1)*5]" : ""]"
diff --git a/code/modules/projectiles/guns/projectile/saw.dm b/code/modules/projectiles/guns/projectile/saw.dm
index 5b70f2b3282..3c25bc30f93 100644
--- a/code/modules/projectiles/guns/projectile/saw.dm
+++ b/code/modules/projectiles/guns/projectile/saw.dm
@@ -23,7 +23,7 @@
update_icon()
/obj/item/gun/projectile/automatic/l6_saw/update_icon()
- icon_state = "l6[cover_open ? "open" : "closed"][magazine ? Ceiling(get_ammo(0)/12.5)*25 : "-empty"][suppressed ? "-suppressed" : ""]"
+ icon_state = "l6[cover_open ? "open" : "closed"][magazine ? CEILING(get_ammo(0)/12.5, 1)*25 : "-empty"][suppressed ? "-suppressed" : ""]"
item_state = "l6[cover_open ? "openmag" : "closedmag"]"
/obj/item/gun/projectile/automatic/l6_saw/afterattack(atom/target as mob|obj|turf, mob/living/user as mob|obj, flag, params) //what I tried to do here is just add a check to see if the cover is open or not and add an icon_state change because I can't figure out how c-20rs do it with overlays
diff --git a/code/modules/projectiles/guns/throw/crossbow.dm b/code/modules/projectiles/guns/throw/crossbow.dm
index dc03a76fb48..7613c335141 100644
--- a/code/modules/projectiles/guns/throw/crossbow.dm
+++ b/code/modules/projectiles/guns/throw/crossbow.dm
@@ -132,13 +132,13 @@
switch(choice)
if(XBOW_TENSION_20)
- drawtension = Ceiling(0.2 * maxtension)
+ drawtension = CEILING(0.2 * maxtension, 1)
if(XBOW_TENSION_40)
- drawtension = Ceiling(0.4 * maxtension)
+ drawtension = CEILING(0.4 * maxtension, 1)
if(XBOW_TENSION_60)
- drawtension = Ceiling(0.6 * maxtension)
+ drawtension = CEILING(0.6 * maxtension, 1)
if(XBOW_TENSION_80)
- drawtension = Ceiling(0.8 * maxtension)
+ drawtension = CEILING(0.8 * maxtension, 1)
if(XBOW_TENSION_FULL)
drawtension = maxtension
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index 626bcaf05a8..c10d8dec600 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -26,7 +26,6 @@
var/speed = 1 //Amount of deciseconds it takes for projectile to travel
var/Angle = null
var/spread = 0 //amount (in degrees) of projectile spread
- var/legacy = FALSE //legacy projectile system
animate_movement = 0
var/ignore_source_check = FALSE
@@ -175,7 +174,7 @@
/obj/item/projectile/proc/vol_by_damage()
if(damage)
- return Clamp((damage) * 0.67, 30, 100)// Multiply projectile damage by 0.67, then clamp the value between 30 and 100
+ return clamp((damage) * 0.67, 30, 100)// Multiply projectile damage by 0.67, then clamp the value between 30 and 100
else
return 50 //if the projectile doesn't do damage, play its hitsound at 50% volume
@@ -199,7 +198,7 @@
def_zone = ran_zone(def_zone, max(100-(7*distance), 5)) //Lower accurancy/longer range tradeoff. 7 is a balanced number to use.
if(isturf(A) && hitsound_wall)
- var/volume = Clamp(vol_by_damage() + 20, 0, 100)
+ var/volume = clamp(vol_by_damage() + 20, 0, 100)
if(suppressed)
volume = 5
playsound(loc, hitsound_wall, volume, 1, -1)
@@ -232,74 +231,61 @@
return 1 //Bullets don't drift in space
/obj/item/projectile/proc/fire(var/setAngle)
+ set waitfor = FALSE
if(setAngle)
Angle = setAngle
- if(!legacy) //new projectiles
- set waitfor = 0
- while(loc)
- if(!paused)
- if((!( current ) || loc == current))
- current = locate(Clamp(x+xo,1,world.maxx),Clamp(y+yo,1,world.maxy),z)
- if(isnull(Angle))
- Angle=round(Get_Angle(src,current))
- if(spread)
- Angle += (rand() - 0.5) * spread
- var/matrix/M = new
- M.Turn(Angle)
- transform = M
- var/Pixel_x=round(sin(Angle)+16*sin(Angle)*2)
- var/Pixel_y=round(cos(Angle)+16*cos(Angle)*2)
- var/pixel_x_offset = pixel_x + Pixel_x
- var/pixel_y_offset = pixel_y + Pixel_y
- var/new_x = x
- var/new_y = y
+ while(!QDELETED(src))
+ if(!paused)
+ if((!current || loc == current))
+ current = locate(clamp(x + xo, 1, world.maxx), clamp(y + yo, 1, world.maxy), z)
+ if(isnull(Angle))
+ Angle = round(Get_Angle(src, current))
+ if(spread)
+ Angle += (rand() - 0.5) * spread
+ var/matrix/M = new
+ M.Turn(Angle)
+ transform = M
- while(pixel_x_offset > 16)
- pixel_x_offset -= 32
- pixel_x -= 32
- new_x++// x++
- while(pixel_x_offset < -16)
- pixel_x_offset += 32
- pixel_x += 32
- new_x--
+ var/Pixel_x = round(sin(Angle) + 16 * sin(Angle) * 2)
+ var/Pixel_y = round(cos(Angle) + 16 * cos(Angle) * 2)
+ var/pixel_x_offset = pixel_x + Pixel_x
+ var/pixel_y_offset = pixel_y + Pixel_y
+ var/new_x = x
+ var/new_y = y
- while(pixel_y_offset > 16)
- pixel_y_offset -= 32
- pixel_y -= 32
- new_y++
- while(pixel_y_offset < -16)
- pixel_y_offset += 32
- pixel_y += 32
- new_y--
+ while(pixel_x_offset > 16)
+ pixel_x_offset -= 32
+ pixel_x -= 32
+ new_x++ // x++
+ while(pixel_x_offset < -16)
+ pixel_x_offset += 32
+ pixel_x += 32
+ new_x--
- speed = round(speed)
- step_towards(src, locate(new_x, new_y, z))
- if(speed <= 1)
- pixel_x = pixel_x_offset
- pixel_y = pixel_y_offset
- else
- animate(src, pixel_x = pixel_x_offset, pixel_y = pixel_y_offset, time = max(1, (speed <= 3 ? speed - 1 : speed)))
+ while(pixel_y_offset > 16)
+ pixel_y_offset -= 32
+ pixel_y -= 32
+ new_y++
+ while(pixel_y_offset < -16)
+ pixel_y_offset += 32
+ pixel_y += 32
+ new_y--
- if(original && (original.layer>=2.75) || ismob(original))
- if(loc == get_turf(original))
- if(!(original in permutated))
- Bump(original, 1)
- Range()
- sleep(max(1, speed))
- else //old projectile system
- set waitfor = 0
- while(loc)
- if(!paused)
- if((!( current ) || loc == current))
- current = locate(Clamp(x+xo,1,world.maxx),Clamp(y+yo,1,world.maxy),z)
- step_towards(src, current)
- if(original && (original.layer>=2.75) || ismob(original))
- if(loc == get_turf(original))
- if(!(original in permutated))
- Bump(original, 1)
- Range()
- sleep(1)
+ speed = round(speed)
+ step_towards(src, locate(new_x, new_y, z))
+ if(speed <= 1)
+ pixel_x = pixel_x_offset
+ pixel_y = pixel_y_offset
+ else
+ animate(src, pixel_x = pixel_x_offset, pixel_y = pixel_y_offset, time = max(1, (speed <= 3 ? speed - 1 : speed)))
+
+ if(original && (original.layer >= 2.75 || ismob(original)))
+ if(loc == get_turf(original))
+ if(!(original in permutated))
+ Bump(original, TRUE)
+ Range()
+ sleep(max(1, speed))
obj/item/projectile/proc/reflect_back(atom/source, list/position_modifiers = list(0, 0, 0, 0, 0, -1, 1, -2, 2))
if(starting)
@@ -311,7 +297,7 @@ obj/item/projectile/proc/reflect_back(atom/source, list/position_modifiers = lis
firer = source // The reflecting mob will be the new firer
else
firer = null // Reflected by something other than a mob so firer will be null
-
+
// redirect the projectile
original = locate(new_x, new_y, z)
starting = curloc
diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm
index dc70eda9cec..4505d984f84 100644
--- a/code/modules/projectiles/projectile/magic.dm
+++ b/code/modules/projectiles/projectile/magic.dm
@@ -28,7 +28,7 @@
/obj/item/projectile/magic/death/on_hit(mob/living/carbon/C)
. = ..()
if(isliving(C))
- if(ismachine(C)) //speshul snowfleks deserv speshul treetment
+ if(ismachineperson(C)) //speshul snowfleks deserv speshul treetment
C.adjustFireLoss(6969) //remember - slimes love fire
else
C.death()
diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm
index 8811d8f2584..d40c96b5381 100644
--- a/code/modules/reagents/chemistry/holder.dm
+++ b/code/modules/reagents/chemistry/holder.dm
@@ -182,7 +182,7 @@
return amount
/datum/reagents/proc/set_reagent_temp(new_temp = T0C, react = TRUE)
- chem_temp = Clamp(new_temp, temperature_min, temperature_max)
+ chem_temp = clamp(new_temp, temperature_min, temperature_max)
if(react)
temperature_react()
handle_reactions()
@@ -623,7 +623,7 @@
if(total_volume + amount > maximum_volume) amount = (maximum_volume - total_volume) //Doesnt fit in. Make it disappear. Shouldnt happen. Will happen.
if(amount <= 0)
return 0
- chem_temp = Clamp((chem_temp * total_volume + reagtemp * amount) / (total_volume + amount), temperature_min, temperature_max) //equalize with new chems
+ chem_temp = clamp((chem_temp * total_volume + reagtemp * amount) / (total_volume + amount), temperature_min, temperature_max) //equalize with new chems
for(var/A in reagent_list)
diff --git a/code/modules/reagents/chemistry/machinery/chem_heater.dm b/code/modules/reagents/chemistry/machinery/chem_heater.dm
index 79fc47d61a8..39aa91099c0 100644
--- a/code/modules/reagents/chemistry/machinery/chem_heater.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_heater.dm
@@ -118,10 +118,10 @@
if(href_list["adjust_temperature"])
var/val = href_list["adjust_temperature"]
if(isnum(val))
- desired_temp = Clamp(desired_temp+val, 0, 1000)
+ desired_temp = clamp(desired_temp+val, 0, 1000)
else if(val == "input")
var/target = input("Please input the target temperature", name) as num
- desired_temp = Clamp(target, 0, 1000)
+ desired_temp = clamp(target, 0, 1000)
else
return FALSE
. = 1
diff --git a/code/modules/reagents/chemistry/reagents/blob.dm b/code/modules/reagents/chemistry/reagents/blob.dm
index acf244a892d..7600fb25222 100644
--- a/code/modules/reagents/chemistry/reagents/blob.dm
+++ b/code/modules/reagents/chemistry/reagents/blob.dm
@@ -125,7 +125,7 @@
/datum/reagent/blob/proc/reagent_vortex(mob/living/M, setting_type, volume)
var/turf/pull = get_turf(M)
- var/range_power = Clamp(round(volume/5, 1), 1, 5)
+ var/range_power = clamp(round(volume/5, 1), 1, 5)
for(var/atom/movable/X in range(range_power,pull))
if(istype(X, /obj/effect))
continue
diff --git a/code/modules/reagents/chemistry/reagents/drugs.dm b/code/modules/reagents/chemistry/reagents/drugs.dm
index a848330e431..ea110581083 100644
--- a/code/modules/reagents/chemistry/reagents/drugs.dm
+++ b/code/modules/reagents/chemistry/reagents/drugs.dm
@@ -543,7 +543,7 @@
M.AdjustConfused(-5)
update_flags |= M.SetWeakened(0, FALSE)
if(volume >= 70 && prob(25))
- if(M.reagents.has_reagent("thc") <= 20)
+ if(M.reagents.get_reagent_amount("thc") <= 20)
M.Drowsy(10)
if(prob(25))
update_flags |= M.adjustBruteLoss(-2, FALSE)
diff --git a/code/modules/reagents/chemistry/reagents/toxins.dm b/code/modules/reagents/chemistry/reagents/toxins.dm
index dec256ac455..c6ff39aaead 100644
--- a/code/modules/reagents/chemistry/reagents/toxins.dm
+++ b/code/modules/reagents/chemistry/reagents/toxins.dm
@@ -226,37 +226,6 @@
if(B && islist(B.data) && !data)
data = B.data.Copy()
-/datum/reagent/romerol
- name = "romerol"
- // the REAL zombie powder
- id = "romerol"
- description = "Romerol is a highly experimental bioterror agent \
- which causes dormant nodules to be etched into the grey matter of \
- the subject. These nodules only become active upon death of the \
- host, upon which, the secondary structures activate and take control \
- of the host body."
- color = "#123524" // RGB (18, 53, 36)
- metabolization_rate = INFINITY
- can_synth = FALSE
- taste_description = "CAAAARL"
-
-/datum/reagent/romerol/reaction_mob(mob/living/carbon/human/H, method = REAGENT_TOUCH, volume)
- if(!istype(H))
- return
- // Silently add the zombie infection organ to be activated upon death
- if(!H.get_organ_slot("zombie_infection"))
- var/obj/item/organ/internal/zombie_infection/nodamage/ZI = new()
- ZI.insert(H)
- ..()
-
-/datum/reagent/romerol/on_mob_life(mob/living/M)
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- if(!H.get_organ_slot("zombie_infection"))
- var/obj/item/organ/internal/zombie_infection/nodamage/ZI = new()
- ZI.insert(H)
- return ..()
-
/datum/reagent/uranium
name ="Uranium"
id = "uranium"
diff --git a/code/modules/reagents/chemistry/reagents/water.dm b/code/modules/reagents/chemistry/reagents/water.dm
index f975cac7293..186315ecc56 100644
--- a/code/modules/reagents/chemistry/reagents/water.dm
+++ b/code/modules/reagents/chemistry/reagents/water.dm
@@ -83,37 +83,7 @@
M.adjustToxLoss(rand(5, 10))
/datum/reagent/space_cleaner/reaction_mob(mob/living/M, method=REAGENT_TOUCH, volume)
- if(iscarbon(M))
- var/mob/living/carbon/C = M
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- if(H.lip_style)
- H.lip_style = null
- H.update_body()
- if(C.r_hand)
- C.r_hand.clean_blood()
- if(C.l_hand)
- C.l_hand.clean_blood()
- if(C.wear_mask)
- if(C.wear_mask.clean_blood())
- C.update_inv_wear_mask()
- if(ishuman(M))
- var/mob/living/carbon/human/H = C
- if(H.head)
- if(H.head.clean_blood())
- H.update_inv_head()
- if(H.wear_suit)
- if(H.wear_suit.clean_blood())
- H.update_inv_wear_suit()
- else if(H.w_uniform)
- if(H.w_uniform.clean_blood())
- H.update_inv_w_uniform()
- if(H.shoes)
- if(H.shoes.clean_blood())
- H.update_inv_shoes()
- M.clean_blood()
- ..()
-
+ M.clean_blood()
/datum/reagent/blood
data = list("donor"=null,"viruses"=null,"blood_DNA"=null,"blood_type"=null,"blood_colour"="#A10808","resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null,"cloneable"=null,"factions"=null, "dna" = null)
diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm
index a091f65a34c..01a5e6823a5 100644
--- a/code/modules/reagents/reagent_containers.dm
+++ b/code/modules/reagents/reagent_containers.dm
@@ -61,8 +61,9 @@ obj/item/reagent_containers/proc/add_initial_reagents()
update_icon()
return
-/obj/item/reagent_containers/afterattack(obj/target, mob/user , flag)
- return
+/obj/item/reagent_containers/attack(mob/M, mob/user, def_zone)
+ if(user.a_intent == INTENT_HARM)
+ return ..()
/obj/item/reagent_containers/wash(mob/user, atom/source)
if(is_open_container())
diff --git a/code/modules/reagents/reagent_containers/borghydro.dm b/code/modules/reagents/reagent_containers/borghydro.dm
index 1fa4930b0f6..8338253fc6c 100644
--- a/code/modules/reagents/reagent_containers/borghydro.dm
+++ b/code/modules/reagents/reagent_containers/borghydro.dm
@@ -47,7 +47,7 @@
/obj/item/reagent_containers/borghypo/process() //Every [recharge_time] seconds, recharge some reagents for the cyborg
charge_tick++
- if(charge_tick < recharge_time)
+ if(charge_tick < recharge_time)
return FALSE
charge_tick = 0
@@ -97,9 +97,7 @@
var/contained = injected.name
var/trans = R.trans_to(M, amount_per_transfer_from_this)
add_attack_logs(user, M, "Injected with [name] containing [contained], transfered [trans] units", injected.harmless ? ATKLOG_ALMOSTALL : null)
- M.LAssailant = user
to_chat(user, "[trans] units injected. [R.total_volume] units remaining.")
- return
/obj/item/reagent_containers/borghypo/attack_self(mob/user)
playsound(loc, 'sound/effects/pop.ogg', 50, 0) //Change the mode
@@ -126,4 +124,9 @@
if(empty)
. += "It is currently empty. Allow some time for the internal syntheszier to produce more."
+/obj/item/reagent_containers/borghypo/basic
+ name = "Basic Medical Hypospray"
+ desc = "A very basic medical hypospray, capable of providing simple medical treatment in emergencies."
+ reagent_ids = list("salglu_solution", "epinephrine")
+
#undef BORGHYPO_REFILL_VALUE
diff --git a/code/modules/reagents/reagent_containers/bottle.dm b/code/modules/reagents/reagent_containers/bottle.dm
index 61552eae789..6c836988e8b 100644
--- a/code/modules/reagents/reagent_containers/bottle.dm
+++ b/code/modules/reagents/reagent_containers/bottle.dm
@@ -12,11 +12,6 @@
container_type = OPENCONTAINER
volume = 30
-/obj/item/reagent_containers/glass/bottle/romerol
- name = "romerol bottle"
- desc = "A small bottle of Romerol. The REAL zombie powder."
- list_reagents = list("romerol" = 30)
-
/obj/item/reagent_containers/glass/bottle/on_reagent_change()
update_icon()
diff --git a/code/modules/reagents/reagent_containers/glass_containers.dm b/code/modules/reagents/reagent_containers/glass_containers.dm
index 3e9480f166d..1e42899111b 100644
--- a/code/modules/reagents/reagent_containers/glass_containers.dm
+++ b/code/modules/reagents/reagent_containers/glass_containers.dm
@@ -14,38 +14,7 @@
container_type = OPENCONTAINER
has_lid = TRUE
resistance_flags = ACID_PROOF
-
var/label_text = ""
- // the fucking asshole who designed this can go die in a fire - Iamgoofball
- var/list/can_be_placed_into = list(
- /obj/machinery/chem_master/,
- /obj/machinery/chem_heater/,
- /obj/machinery/chem_dispenser/,
- /obj/machinery/reagentgrinder,
- /obj/structure/table,
- /obj/structure/closet,
- /obj/structure/sink,
- /obj/structure/toilet,
- /obj/item/storage,
- /obj/machinery/atmospherics/unary/cryo_cell,
- /obj/machinery/dna_scannernew,
- /obj/item/grenade/chem_grenade,
- /mob/living/simple_animal/bot/medbot,
- /obj/item/storage/secure/safe,
- /obj/machinery/iv_drip,
- /obj/machinery/computer/pandemic,
- /obj/machinery/disposal,
- /mob/living/simple_animal/cow,
- /mob/living/simple_animal/hostile/retaliate/goat,
- /obj/machinery/sleeper,
- /obj/machinery/smartfridge/,
- /obj/machinery/biogenerator,
- /obj/machinery/hydroponics,
- /obj/machinery/constructable_frame,
- /obj/machinery/icemachine,
- /obj/item/bombcore/chemical,
- /obj/machinery/vending,
- /obj/machinery/fishtank)
/obj/item/reagent_containers/glass/New()
..()
@@ -74,10 +43,6 @@
M.visible_message("[user] splashes the contents of [src] onto [M]!", \
"[user] splashes the contents of [src] onto [M]!")
add_attack_logs(user, M, "Splashed with [name] containing [contained]", !!M.ckey ? null : ATKLOG_ALL)
- if(!iscarbon(user))
- M.LAssailant = null
- else
- M.LAssailant = user
reagents.reaction(M, REAGENT_TOUCH)
reagents.clear_reagents()
@@ -98,56 +63,44 @@
reagents.reaction(M, REAGENT_INGEST, fraction)
addtimer(CALLBACK(reagents, /datum/reagents.proc/trans_to, M, 5), 5)
playsound(M.loc,'sound/items/drink.ogg', rand(10,50), 1)
- else
- return ..()
/obj/item/reagent_containers/glass/afterattack(obj/target, mob/user, proximity)
- if(!proximity)
+ if((!proximity) || !check_allowed_items(target,target_self = TRUE))
return
if(!is_open_container())
return
- for(var/type in can_be_placed_into)
- if(istype(target, type))
+ if(target.is_refillable()) //Something like a glass. Player probably wants to transfer TO it.
+ if(!reagents.total_volume)
+ to_chat(user, "[src] is empty!")
return
- if(istype(target, /obj/structure/reagent_dispensers)) //A dispenser. Transfer FROM it TO us.
- if(target.reagents && !target.reagents.total_volume)
+ if(target.reagents.holder_full())
+ to_chat(user, "[target] is full.")
+ return
+
+ var/trans = reagents.trans_to(target, amount_per_transfer_from_this)
+ to_chat(user, "You transfer [trans] unit\s of the solution to [target].")
+
+ else if(target.is_drainable()) //A dispenser. Transfer FROM it TO us.
+ if(!target.reagents.total_volume)
to_chat(user, "[target] is empty and can't be refilled!")
return
- if(reagents.total_volume >= reagents.maximum_volume)
- to_chat(user, "[src] is full.")
+ if(reagents.holder_full())
+ to_chat(user, "[src] is full.")
return
var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this)
to_chat(user, "You fill [src] with [trans] unit\s of the contents of [target].")
- else if(target.is_refillable() && is_drainable()) //Something like a glass. Player probably wants to transfer TO it.
- if(!reagents.total_volume)
- to_chat(user, "[src] is empty.")
- return
-
- if(target.reagents.total_volume >= target.reagents.maximum_volume)
- to_chat(user, "[target] is full.")
- return
-
- var/trans = reagents.trans_to(target, amount_per_transfer_from_this)
- to_chat(user, "You transfer [trans] units of the solution to [target].")
-
- else if(istype(target, /obj/item/reagent_containers/glass) && !target.is_open_container())
- to_chat(user, "You cannot fill [target] while it is sealed.")
- return
-
- else if(istype(target, /obj/effect/decal)) //stops splashing while scooping up fluids
- return
-
- else if(reagents.total_volume && user.a_intent == INTENT_HARM)
- user.visible_message("[user] splashes the contents of [src] onto [target]!", \
- "You splash the contents of [src] onto [target].")
- reagents.reaction(target, REAGENT_TOUCH)
- reagents.clear_reagents()
+ else if(reagents.total_volume)
+ if(user.a_intent == INTENT_HARM)
+ user.visible_message("[user] splashes the contents of [src] onto [target]!", \
+ "You splash the contents of [src] onto [target].")
+ reagents.reaction(target, REAGENT_TOUCH)
+ reagents.clear_reagents()
/obj/item/reagent_containers/glass/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/pen) || istype(I, /obj/item/flashlight/pen))
diff --git a/code/modules/reagents/reagent_containers/patch.dm b/code/modules/reagents/reagent_containers/patch.dm
index 582e157004c..17112901b29 100644
--- a/code/modules/reagents/reagent_containers/patch.dm
+++ b/code/modules/reagents/reagent_containers/patch.dm
@@ -20,7 +20,7 @@
if(M.eat(src, user))
user.drop_item()
forceMove(M)
- M.processing_patches += src
+ LAZYADD(M.processing_patches, src)
return TRUE
return FALSE
diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm
index e87e72d8750..8783d8a8c19 100644
--- a/code/modules/reagents/reagent_containers/syringes.dm
+++ b/code/modules/reagents/reagent_containers/syringes.dm
@@ -149,7 +149,7 @@
cut_overlays()
var/rounded_vol
if(reagents && reagents.total_volume)
- rounded_vol = Clamp(round((reagents.total_volume / volume * 15), 5), 1, 15)
+ rounded_vol = clamp(round((reagents.total_volume / volume * 15), 5), 1, 15)
var/image/filling_overlay = mutable_appearance('icons/obj/reagentfillings.dmi', "syringe[rounded_vol]")
filling_overlay.icon += mix_color_from_reagents(reagents.reagent_list)
add_overlay(filling_overlay)
diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm
index 544deb8d11f..13d88100042 100644
--- a/code/modules/recycling/disposal.dm
+++ b/code/modules/recycling/disposal.dm
@@ -207,7 +207,10 @@
else if(target != user && !user.restrained() && !user.stat && !user.IsWeakened() && !user.stunned && !user.paralysis)
msg = "[user.name] stuffs [target.name] into the [src]!"
to_chat(user, "You stuff [target.name] into the [src]!")
-
+ if(!iscarbon(user))
+ target.LAssailant = null
+ else
+ target.LAssailant = user
add_attack_logs(user, target, "Disposal'ed", !!target.ckey ? null : ATKLOG_ALL)
else
return
@@ -237,10 +240,10 @@
// ai as human but can't flush
/obj/machinery/disposal/attack_ai(mob/user as mob)
src.add_hiddenprint(user)
- ui_interact(user)
+ tgui_interact(user)
/obj/machinery/disposal/attack_ghost(mob/user as mob)
- ui_interact(user)
+ tgui_interact(user)
// human interact with machine
/obj/machinery/disposal/attack_hand(mob/user as mob)
@@ -256,76 +259,68 @@
// Clumsy folks can only flush it.
if(user.IsAdvancedToolUser())
- ui_interact(user)
+ tgui_interact(user)
else
flush = !flush
update()
return
-/obj/machinery/disposal/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/disposal/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
- ui = new(user, src, ui_key, "disposal_bin.tmpl", "Waste Disposal Unit", 395, 250)
+ ui = new(user, src, ui_key, "DisposalBin", name, 300, 250, master_ui, state)
ui.open()
- ui.set_auto_update(1)
-/obj/machinery/disposal/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
- var/data[0]
- var/pressure = Clamp(100* air_contents.return_pressure() / (SEND_PRESSURE), 0, 100)
- var/pressure_round = round(pressure,1)
+/obj/machinery/disposal/tgui_data(mob/user)
+ var/list/data = list()
data["isAI"] = isAI(user)
data["flushing"] = flush
data["mode"] = mode
- if(mode <= 0)
- data["pumpstatus"] = "N/A"
- else if(mode == 1)
- data["pumpstatus"] = "Pressurizing"
- else if(mode == 2)
- data["pumpstatus"] = "Ready"
- else
- data["pumpstatus"] = "Idle"
- data["pressure"] = pressure_round
+ data["pressure"] = round(clamp(100* air_contents.return_pressure() / (SEND_PRESSURE), 0, 100),1)
return data
-/obj/machinery/disposal/Topic(href, href_list)
+/obj/machinery/disposal/tgui_act(action, params)
+ if(..())
+ return
if(usr.loc == src)
to_chat(usr, "You cannot reach the controls from inside.")
return
- if(mode==-1 && !href_list["eject"]) // only allow ejecting if mode is -1
+ if(mode==-1 && action != "eject") // If the mode is -1, only allow ejection
to_chat(usr, "The disposal units power is disabled.")
return
- if(..())
- return
-
if(stat & BROKEN)
return
src.add_fingerprint(usr)
- if(usr.stat || usr.restrained() || src.flushing)
+ if(src.flushing)
return
if(istype(src.loc, /turf))
- if(href_list["pump"])
- if(text2num(href_list["pump"]))
- mode = 1
- else
- mode = 0
+ if(action == "pumpOn")
+ mode = 1
+ update()
+ if(action == "pumpOff")
+ mode = 0
update()
- if(!isAI(usr))
- if(href_list["handle"])
- flush = text2num(href_list["handle"])
+ if(!issilicon(usr))
+ if(action == "engageHandle")
+ flush = 1
+ update()
+ if(action == "disengageHandle")
+ flush = 0
update()
- if(href_list["eject"])
+ if(action == "eject")
eject()
- return
+
+ return TRUE
// eject the contents of the disposal unit
/obj/machinery/disposal/proc/eject()
@@ -794,8 +789,8 @@
return
if(T.intact && istype(T,/turf/simulated/floor)) //intact floor, pop the tile
var/turf/simulated/floor/F = T
- new F.builtin_tile.type(H)
- F.remove_tile(null,TRUE,FALSE)
+ new F.floor_tile(H)
+ F.remove_tile(null, TRUE, FALSE)
if(direction) // direction is specified
if(istype(T, /turf/space)) // if ended in space, then range is unlimited
diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm
index 5b5dba286fd..76eabe46761 100644
--- a/code/modules/research/designs/mechfabricator_designs.dm
+++ b/code/modules/research/designs/mechfabricator_designs.dm
@@ -1081,8 +1081,17 @@
construction_time = 120
category = list("Cyborg Upgrade Modules")
+/datum/design/borg_upgrade_lavaproof
+ name = "Cyborg Upgrade (Lavaproof Chassis)"
+ id = "borg_upgrade_lavaproof"
+ build_type = MECHFAB
+ build_path = /obj/item/borg/upgrade/lavaproof
+ materials = list(MAT_METAL = 10000, MAT_PLASMA = 4000, MAT_TITANIUM = 5000)
+ construction_time = 120
+ category = list("Cyborg Upgrade Modules")
+
/datum/design/borg_syndicate_module
- name = "Cyborg Upgrade (Illegal Modules)"
+ name = "Cyborg Upgrade (Safety Override)"
id = "borg_syndicate_module"
build_type = MECHFAB
req_tech = list("combat" = 4, "syndicate" = 2)
diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm
index e3bbb2f4aec..3dabea7dc6b 100644
--- a/code/modules/research/designs/medical_designs.dm
+++ b/code/modules/research/designs/medical_designs.dm
@@ -371,7 +371,7 @@
name = "X-Ray implant"
desc = "These cybernetic eyes will give you X-ray vision. Blinking is futile."
id = "ci-xray"
- req_tech = list("materials" = 7, "programming" = 5, "biotech" = 7, "magnets" = 5,"plasmatech" = 6)
+ req_tech = list("materials" = 7, "programming" = 5, "biotech" = 8, "magnets" = 5,"plasmatech" = 6)
build_type = PROTOLATHE | MECHFAB
construction_time = 60
materials = list(MAT_METAL = 600, MAT_GLASS = 600, MAT_SILVER = 600, MAT_GOLD = 600, MAT_PLASMA = 1000, MAT_URANIUM = 1000, MAT_DIAMOND = 1000, MAT_BLUESPACE = 1000)
diff --git a/code/modules/research/designs/telecomms_designs.dm b/code/modules/research/designs/telecomms_designs.dm
index 083420d68a4..733d76834e4 100644
--- a/code/modules/research/designs/telecomms_designs.dm
+++ b/code/modules/research/designs/telecomms_designs.dm
@@ -13,7 +13,7 @@
category = list("Subspace Telecomms")
/datum/design/telecomms_relay
- name = "Machine Board (Telecommunications Core)"
+ name = "Machine Board (Telecommunications Relay)"
desc = "Allows for the construction of Telecommunications Relays."
id = "s-relay"
req_tech = list("programming" = 2, "engineering" = 2, "bluespace" = 2)
diff --git a/code/modules/research/message_server.dm b/code/modules/research/message_server.dm
index df3a7945e92..91306d910f1 100644
--- a/code/modules/research/message_server.dm
+++ b/code/modules/research/message_server.dm
@@ -103,12 +103,12 @@ GLOBAL_LIST_EMPTY(message_servers)
if(2)
if(!Console.silent)
playsound(Console.loc, 'sound/machines/twobeep.ogg', 50, 1)
- Console.audible_message(text("[bicon(Console)] *The Requests Console beeps: 'PRIORITY Alert in [sender]'"),,5)
+ Console.atom_say("PRIORITY Alert in [sender]")
Console.message_log += "High Priority message from [sender]
[authmsg]"
else
if(!Console.silent)
playsound(Console.loc, 'sound/machines/twobeep.ogg', 50, 1)
- Console.audible_message(text("[bicon(Console)] *The Requests Console beeps: 'Message from [sender]'"),,4)
+ Console.atom_say("Message from [sender]")
Console.message_log += "Message from [sender]
[authmsg]"
Console.set_light(2)
diff --git a/code/modules/research/research.dm b/code/modules/research/research.dm
index b5fc9e9c879..444a2f9d017 100644
--- a/code/modules/research/research.dm
+++ b/code/modules/research/research.dm
@@ -117,7 +117,7 @@ research holder datum.
AddDesign2Known(PD)
for(var/v in known_tech)
var/datum/tech/T = known_tech[v]
- T.level = Clamp(T.level, 0, 20)
+ T.level = clamp(T.level, 0, 20)
//Refreshes the levels of a given tech.
//Input: Tech's ID and Level; Output: null
diff --git a/code/modules/research/server.dm b/code/modules/research/server.dm
index de9194953da..ab0461a8908 100644
--- a/code/modules/research/server.dm
+++ b/code/modules/research/server.dm
@@ -68,7 +68,7 @@
if(0 to T0C)
health = min(100, health + 1)
if(T0C to (T20C + 20))
- health = Clamp(health, 0, 100)
+ health = clamp(health, 0, 100)
if((T20C + 20) to (T0C + 70))
health = max(0, health - 1)
if(health <= 0)
diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm
index c71c3f6f8d8..7c35730f4aa 100644
--- a/code/modules/research/xenobiology/xenobiology.dm
+++ b/code/modules/research/xenobiology/xenobiology.dm
@@ -319,7 +319,7 @@
return ..()
to_chat(user, "You feed the slime the stabilizer. It is now less likely to mutate.")
- M.mutation_chance = Clamp(M.mutation_chance-15,0,100)
+ M.mutation_chance = clamp(M.mutation_chance-15,0,100)
qdel(src)
/obj/item/slimepotion/slime/mutator
@@ -343,7 +343,7 @@
return ..()
to_chat(user, "You feed the slime the mutator. It is now more likely to mutate.")
- M.mutation_chance = Clamp(M.mutation_chance+12,0,100)
+ M.mutation_chance = clamp(M.mutation_chance+12,0,100)
M.mutator_used = TRUE
qdel(src)
diff --git a/code/modules/response_team/ert.dm b/code/modules/response_team/ert.dm
index 6155c1de6b9..a25be3814a7 100644
--- a/code/modules/response_team/ert.dm
+++ b/code/modules/response_team/ert.dm
@@ -135,8 +135,7 @@ GLOBAL_VAR_INIT(ert_request_answered, FALSE)
/client/proc/create_response_team(new_gender, role, turf/spawn_location)
if(role == "Cyborg")
- var/cyborg_unlock = GLOB.active_team.getCyborgUnlock()
- var/mob/living/silicon/robot/ert/R = new /mob/living/silicon/robot/ert(spawn_location, cyborg_unlock)
+ var/mob/living/silicon/robot/ert/R = new GLOB.active_team.borg_path(spawn_location)
return R
var/mob/living/carbon/human/M = new(null)
@@ -208,7 +207,7 @@ GLOBAL_VAR_INIT(ert_request_answered, FALSE)
var/security_outfit
var/janitor_outfit
var/paranormal_outfit
- var/cyborg_unlock = 0
+ var/borg_path = /mob/living/silicon/robot/ert
/datum/response_team/proc/setSlots(com=1, sec=3, med=3, eng=3, jan=0, par=0, cyb=0)
slots["Commander"] = com
@@ -223,9 +222,6 @@ GLOBAL_VAR_INIT(ert_request_answered, FALSE)
slots[role]--
count++
-/datum/response_team/proc/getCyborgUnlock()
- return cyborg_unlock
-
/datum/response_team/proc/get_slot_list()
RETURN_TYPE(/list)
var/list/slots_available = list()
@@ -285,6 +281,7 @@ GLOBAL_VAR_INIT(ert_request_answered, FALSE)
command_outfit = /datum/outfit/job/centcom/response_team/commander/red
janitor_outfit = /datum/outfit/job/centcom/response_team/janitorial/red
paranormal_outfit = /datum/outfit/job/centcom/response_team/paranormal/red
+ borg_path = /mob/living/silicon/robot/ert/red
/datum/response_team/red/announce_team()
GLOB.event_announcement.Announce("Attention, [station_name()]. We are sending a code RED Emergency Response Team. Standby.", "ERT En-Route")
@@ -298,7 +295,7 @@ GLOBAL_VAR_INIT(ert_request_answered, FALSE)
command_outfit = /datum/outfit/job/centcom/response_team/commander/gamma
janitor_outfit = /datum/outfit/job/centcom/response_team/janitorial/gamma
paranormal_outfit = /datum/outfit/job/centcom/response_team/paranormal/gamma
- cyborg_unlock = 1
+ borg_path = /mob/living/silicon/robot/ert/gamma
/datum/response_team/gamma/announce_team()
GLOB.event_announcement.Announce("Attention, [station_name()]. We are sending a code GAMMA elite Emergency Response Team. Standby.", "ERT En-Route")
diff --git a/code/modules/ruins/ruin_areas.dm b/code/modules/ruins/ruin_areas.dm
index 754f8d44f29..cf3b08aa0f2 100644
--- a/code/modules/ruins/ruin_areas.dm
+++ b/code/modules/ruins/ruin_areas.dm
@@ -5,8 +5,8 @@
icon_state = "away"
has_gravity = TRUE
there_can_be_many = TRUE
- ambientsounds = list('sound/ambience/ambimine.ogg')
dynamic_lighting = DYNAMIC_LIGHTING_FORCED
+ ambientsounds = RUINS_SOUNDS
/area/ruin/unpowered
always_unpowered = FALSE
diff --git a/code/modules/security_levels/security levels.dm b/code/modules/security_levels/security levels.dm
index 0f07107a00b..00c575e53b0 100644
--- a/code/modules/security_levels/security levels.dm
+++ b/code/modules/security_levels/security levels.dm
@@ -31,15 +31,6 @@ GLOBAL_DATUM_INIT(security_announcement_down, /datum/announcement/priority/secur
// Mark down this time to prevent shuttle cheese
SSshuttle.emergency_sec_level_time = world.time
- // Reset gamma borgs if the new security level is lower than Gamma.
- if(level < SEC_LEVEL_GAMMA)
- for(var/M in GLOB.silicon_mob_list)
- if(isrobot(M))
- var/mob/living/silicon/robot/R = M
- if(istype(R.module, /obj/item/robot_module/combat) && !R.crisis)
- R.reset_module()
- to_chat(R, "Crisis mode deactivated. The combat module is no longer available and your module has been reset.")
-
switch(level)
if(SEC_LEVEL_GREEN)
GLOB.security_announcement_down.Announce("All threats to the station have passed. All weapons need to be holstered and privacy laws are once again fully enforced.","Attention! Security level lowered to green.")
diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm
index f82598b1e14..de08d5cdf82 100644
--- a/code/modules/shuttle/emergency.dm
+++ b/code/modules/shuttle/emergency.dm
@@ -178,8 +178,6 @@
continue
if(player.stat == DEAD) // Corpses
continue
- if(iszombie(player)) // Walking corpses
- continue
if(issilicon(player)) //Borgs are technically dead anyways
continue
if(isanimal(player)) //Poly does not own the shuttle
diff --git a/code/modules/shuttle/navigation_computer.dm b/code/modules/shuttle/navigation_computer.dm
index 18db87f6eb7..b73901cf2fa 100644
--- a/code/modules/shuttle/navigation_computer.dm
+++ b/code/modules/shuttle/navigation_computer.dm
@@ -32,8 +32,6 @@
jumpto_ports += list("nav_z1" = 1)
if(access_tcomms)
jumpto_ports += list("nav_z3" = 1)
- if(access_construction)
- jumpto_ports += list("nav_z4" = 1)
if(access_mining)
jumpto_ports += list("nav_z5" = 1)
if(access_derelict)
diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm
index fd4bb0b6ad5..d6645ce6f2b 100644
--- a/code/modules/shuttle/shuttle.dm
+++ b/code/modules/shuttle/shuttle.dm
@@ -463,7 +463,7 @@
var/rotation = dir2angle(S1.dir)-dir2angle(dir)
if((rotation % 90) != 0)
rotation += (rotation % 90) //diagonal rotations not allowed, round up
- rotation = SimplifyDegrees(rotation)
+ rotation = SIMPLIFY_DEGREES(rotation)
//remove area surrounding docking port
if(areaInstance.contents.len)
@@ -863,7 +863,7 @@
desc = "Used to control the White Ship."
circuit = /obj/item/circuitboard/white_ship
shuttleId = "whiteship"
- possible_destinations = "whiteship_away;whiteship_home;whiteship_z4"
+ possible_destinations = "whiteship_away;whiteship_home"
/obj/machinery/computer/shuttle/engineering
name = "Engineering Shuttle Console"
@@ -913,7 +913,7 @@
desc = "Used to control the Golem Ship."
circuit = /obj/item/circuitboard/shuttle/golem_ship
shuttleId = "freegolem"
- possible_destinations = "freegolem_lavaland;freegolem_z5;freegolem_z4;freegolem_z6"
+ possible_destinations = "freegolem_lavaland;freegolem_z5;freegolem_z6"
/obj/machinery/computer/shuttle/golem_ship/attack_hand(mob/user)
if(!isgolem(user) && !isobserver(user))
diff --git a/code/modules/shuttle/supply.dm b/code/modules/shuttle/supply.dm
index 50cf7ff7d28..b1eeb07a6de 100644
--- a/code/modules/shuttle/supply.dm
+++ b/code/modules/shuttle/supply.dm
@@ -487,7 +487,7 @@
var/num_input = input(usr, "Amount:", "How many crates?") as null|num
if(!num_input || ..())
return 1
- crates = Clamp(round(num_input), 1, 20)
+ crates = clamp(round(num_input), 1, 20)
var/timeout = world.time + 600
var/reason = input(usr,"Reason:","Why do you require this item?","") as null|text
@@ -668,7 +668,7 @@
var/num_input = input(usr, "Amount:", "How many crates?") as null|num
if(!num_input || !is_authorized(usr) || ..())
return 1
- crates = Clamp(round(num_input), 1, 20)
+ crates = clamp(round(num_input), 1, 20)
var/timeout = world.time + 600
var/reason = input(usr,"Reason:","Why do you require this item?","") as null|text
diff --git a/code/modules/spacepods/spacepod.dm b/code/modules/spacepods/spacepod.dm
index 2e3c89017ef..56e7f8f96ba 100644
--- a/code/modules/spacepods/spacepod.dm
+++ b/code/modules/spacepods/spacepod.dm
@@ -973,7 +973,7 @@
var/obj/I = pick(true_contents)
if(user.put_in_any_hand_if_possible(I))
src.contents -= I
- to_chat(user, "You find a [I] [pick("under the seat", "under the console", "in the mainenance access")]!")
+ to_chat(user, "You find a [I] [pick("under the seat", "under the console", "in the maintenance access")]!")
else
to_chat(user, "You think you saw something shiny, but you can't reach it!")
else
diff --git a/code/modules/surgery/limb_reattach.dm b/code/modules/surgery/limb_reattach.dm
index db1ad04aef3..c43c3f373d5 100644
--- a/code/modules/surgery/limb_reattach.dm
+++ b/code/modules/surgery/limb_reattach.dm
@@ -32,7 +32,7 @@
if(ishuman(target))
var/mob/living/carbon/human/H = target
var/obj/item/organ/external/affected = H.get_organ(user.zone_selected)
- if(ismachine(target))
+ if(ismachineperson(target))
// RIP bi-centennial man
return 0
if(!affected)
diff --git a/code/modules/surgery/organs/augments_eyes.dm b/code/modules/surgery/organs/augments_eyes.dm
index 53907e86d79..042e911fae9 100644
--- a/code/modules/surgery/organs/augments_eyes.dm
+++ b/code/modules/surgery/organs/augments_eyes.dm
@@ -62,7 +62,7 @@
name = "X-ray implant"
desc = "These cybernetic eye implants will give you X-ray vision. Blinking is futile."
implant_color = "#000000"
- origin_tech = "materials=4;programming=4;biotech=6;magnets=4"
+ origin_tech = "materials=4;programming=4;biotech=7;magnets=4"
vision_flags = SEE_MOBS | SEE_OBJS | SEE_TURFS
see_in_dark = 8
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
diff --git a/code/modules/surgery/organs/blood.dm b/code/modules/surgery/organs/blood.dm
index 63a7f8a3590..b0403d8ae49 100644
--- a/code/modules/surgery/organs/blood.dm
+++ b/code/modules/surgery/organs/blood.dm
@@ -54,7 +54,7 @@
var/obj/item/organ/external/BP = X
var/brutedamage = BP.brute_dam
- if(BP.is_robotic() && !isSynthetic())
+ if(BP.is_robotic() && !ismachineperson(src))
continue
//We want an accurate reading of .len
@@ -72,7 +72,7 @@
bleed_rate = max(bleed_rate - 0.5, temp_bleed)//if no wounds, other bleed effects naturally decreases
- var/additional_bleed = round(Clamp((reagents.get_reagent_amount("heparin") / 10), 0, 2), 1) //Heparin worsens existing bleeding
+ var/additional_bleed = round(clamp((reagents.get_reagent_amount("heparin") / 10), 0, 2), 1) //Heparin worsens existing bleeding
if(internal_bleeding_rate && !(status_flags & FAKEDEATH))
bleed_internal(internal_bleeding_rate + additional_bleed)
diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm
index 782bcbe6ca6..34b83d9fe7f 100644
--- a/code/modules/surgery/organs/lungs.dm
+++ b/code/modules/surgery/organs/lungs.dm
@@ -110,6 +110,7 @@
var/N2_pp = breath.get_breath_partial_pressure(breath.nitrogen)
var/Toxins_pp = breath.get_breath_partial_pressure(breath.toxins)
var/CO2_pp = breath.get_breath_partial_pressure(breath.carbon_dioxide)
+ var/SA_pp = breath.get_breath_partial_pressure(breath.sleeping_agent)
//-- OXY --//
@@ -230,16 +231,14 @@
//-- TRACES --//
- if(breath.trace_gases.len) // If there's some other shit in the air lets deal with it here.
- for(var/datum/gas/sleeping_agent/SA in breath.trace_gases)
- var/SA_pp = breath.get_breath_partial_pressure(SA.moles)
- if(SA_pp > SA_para_min)
- H.Paralyse(3) // 3 gives them one second to wake up and run away a bit!
- if(SA_pp > SA_sleep_min) // Enough to make us sleep as well
- H.AdjustSleeping(8, bound_lower = 0, bound_upper = 10)
- else if(SA_pp > 0.01) // There is sleeping gas in their lungs, but only a little, so give them a bit of a warning
- if(prob(20))
- H.emote(pick("giggle", "laugh"))
+ if(breath.sleeping_agent) // If there's some other shit in the air lets deal with it here.
+ if(SA_pp > SA_para_min)
+ H.Paralyse(3) // 3 gives them one second to wake up and run away a bit!
+ if(SA_pp > SA_sleep_min) // Enough to make us sleep as well
+ H.AdjustSleeping(8, bound_lower = 0, bound_upper = 10)
+ else if(SA_pp > 0.01) // There is sleeping gas in their lungs, but only a little, so give them a bit of a warning
+ if(prob(20))
+ H.emote(pick("giggle", "laugh"))
handle_breath_temperature(breath, H)
diff --git a/code/modules/surgery/organs/organ_icon.dm b/code/modules/surgery/organs/organ_icon.dm
index c2df537e771..2a3b94ca249 100644
--- a/code/modules/surgery/organs/organ_icon.dm
+++ b/code/modules/surgery/organs/organ_icon.dm
@@ -138,7 +138,7 @@ GLOBAL_LIST_EMPTY(limb_icon_cache)
add_overlay(facial_s)
if(h_style)
- if(!owner.isSynthetic() || (owner.isSynthetic() && ((owner.head && (owner.head.flags & BLOCKHEADHAIR)) || (owner.wear_mask && (owner.wear_mask.flags & BLOCKHEADHAIR)))))
+ if(!ismachineperson(owner) || (ismachineperson(owner) && ((owner.head && (owner.head.flags & BLOCKHEADHAIR)) || (owner.wear_mask && (owner.wear_mask.flags & BLOCKHEADHAIR)))))
var/datum/sprite_accessory/hair_style = GLOB.hair_styles_full_list[h_style]
if(hair_style && ((dna.species.name in hair_style.species_allowed) || (dna.species.bodyflags & ALL_RPARTS)))
var/icon/hair_s = new /icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s")
diff --git a/code/modules/telesci/rcs.dm b/code/modules/telesci/rcs.dm
new file mode 100644
index 00000000000..83dbe6cb8f0
--- /dev/null
+++ b/code/modules/telesci/rcs.dm
@@ -0,0 +1,121 @@
+#define RCS_MODE_CALIBRATED 0
+#define RCS_MODE_UNCALIBRATED 1
+
+/obj/item/rcs
+ name = "rapid-crate-sender (RCS)"
+ desc = "A device used to teleport crates and closets to cargo telepads."
+ icon = 'icons/obj/telescience.dmi'
+ icon_state = "rcs"
+ item_state = "rcd"
+ flags = CONDUCT
+ force = 10.0
+ throwforce = 10.0
+ throw_speed = 2
+ throw_range = 5
+ toolspeed = 1
+ usesound = 'sound/machines/click.ogg'
+ var/obj/item/stock_parts/cell/high/rcell = null
+ var/obj/machinery/pad = null
+ var/mode = RCS_MODE_CALIBRATED
+ var/rand_x = 0
+ var/rand_y = 0
+ var/emagged = FALSE
+ var/teleporting = FALSE
+ var/chargecost = 1000
+
+/obj/item/rcs/get_cell()
+ return rcell
+
+/obj/item/rcs/New()
+ ..()
+ rcell = new(src)
+
+/obj/item/rcs/examine(mob/user)
+ . = ..()
+ . += "There are [round(rcell.charge/chargecost)] charge\s left."
+
+/obj/item/rcs/Destroy()
+ QDEL_NULL(rcell)
+ return ..()
+
+/obj/item/rcs/attack_self(mob/user)
+ if(!emagged)
+ return
+ if(mode == RCS_MODE_CALIBRATED)
+ mode = RCS_MODE_UNCALIBRATED
+ playsound(get_turf(src), 'sound/effects/pop.ogg', 50, 0)
+ to_chat(user, "The telepad locator has become uncalibrated.")
+ else
+ mode = RCS_MODE_CALIBRATED
+ playsound(get_turf(src), 'sound/effects/pop.ogg', 50, 0)
+ to_chat(user, "You calibrate the telepad locator.")
+
+/obj/item/rcs/emag_act(user as mob)
+ if(!emagged)
+ emagged = TRUE
+ do_sparks(5, 1, src)
+ to_chat(user, "You emag the RCS. Activate it to toggle between modes.")
+ return
+
+/obj/item/rcs/proc/try_send_container(mob/user, obj/structure/closet/C)
+ if(teleporting)
+ to_chat(user, "You're already using [src]!")
+ return
+ if(user in C.contents) //to prevent self-teleporting.
+ return
+ if(!rcell || (rcell.charge < chargecost))
+ to_chat(user, "Out of charges.")
+ return
+
+ if(!is_level_reachable(C.z))
+ to_chat(user, "The rapid-crate-sender can't locate any telepads!")
+ return
+
+ if(mode == RCS_MODE_CALIBRATED)
+ var/list/L = list()
+ var/list/areaindex = list()
+ for(var/obj/machinery/telepad_cargo/R in GLOB.machines)
+ if(R.stage)
+ continue
+ var/turf/T = get_turf(R)
+ var/tmpname = T.loc.name
+ if(areaindex[tmpname])
+ tmpname = "[tmpname] ([++areaindex[tmpname]])"
+ else
+ areaindex[tmpname] = 1
+ L[tmpname] = R
+
+ var/desc = input("Please select a telepad.", "RCS") in L
+ pad = L[desc]
+ try_teleport(user, C, pad)
+ else
+ rand_x = rand(50,200)
+ rand_y = rand(50,200)
+ var/L = locate(rand_x, rand_y, 6)
+ try_teleport(user, C, L)
+
+/obj/item/rcs/proc/try_teleport(mob/user, obj/structure/closet/C, target)
+ if(!C.Adjacent(user))
+ to_chat(user, "Unable to teleport, too far from [C].")
+ return
+ var/turf/ownTurf = get_turf(src)
+ playsound(ownTurf, usesound, 50, 1)
+ to_chat(user, "Teleporting [C]...")
+ teleporting = TRUE
+ if(!do_after(user, 50 * toolspeed, target = C))
+ teleporting = FALSE
+ return
+ teleporting = FALSE
+ if(user in C.contents)
+ to_chat(user, "Error: User located in container--aborting for safety.")
+ playsound(ownTurf, 'sound/machines/buzz-sigh.ogg', 50, 1)
+ return
+ if(!(rcell && rcell.use(chargecost)))
+ to_chat(user, "Unable to teleport, insufficient charge.")
+ return
+ do_sparks(5, 1, C)
+ do_teleport(C, target)
+ to_chat(user, "Teleport successful. [round(rcell.charge/chargecost)] charge\s left.")
+
+#undef RCS_MODE_CALIBRATED
+#undef RCS_MODE_UNCALIBRATED
diff --git a/code/modules/telesci/telepad.dm b/code/modules/telesci/telepad.dm
index 1ec94634b47..af73f65de87 100644
--- a/code/modules/telesci/telepad.dm
+++ b/code/modules/telesci/telepad.dm
@@ -88,7 +88,7 @@
/obj/machinery/telepad_cargo/wrench_act(mob/user, obj/item/I)
. = TRUE
default_unfasten_wrench(user, I)
-
+
/obj/machinery/telepad_cargo/deconstruct(disassembled = TRUE)
if(!(flags & NODECONSTRUCT))
@@ -113,59 +113,3 @@
playsound(src, 'sound/effects/pop.ogg', 100, 1, 1)
qdel(src)
return
-
-///HANDHELD TELEPAD USER///
-/obj/item/rcs
- name = "rapid-crate-sender (RCS)"
- desc = "A device used to teleport crates and closets to cargo telepads."
- icon = 'icons/obj/telescience.dmi'
- icon_state = "rcs"
- item_state = "rcd"
- flags = CONDUCT
- force = 10.0
- throwforce = 10.0
- throw_speed = 2
- throw_range = 5
- toolspeed = 1
- usesound = 'sound/machines/click.ogg'
- var/obj/item/stock_parts/cell/high/rcell = null
- var/obj/machinery/pad = null
- var/mode = 0
- var/rand_x = 0
- var/rand_y = 0
- var/emagged = 0
- var/teleporting = 0
- var/chargecost = 1000
-
-/obj/item/rcs/get_cell()
- return rcell
-
-/obj/item/rcs/New()
- ..()
- rcell = new(src)
-
-/obj/item/rcs/examine(mob/user)
- . = ..()
- . += "There are [round(rcell.charge/chargecost)] charge\s left."
-
-/obj/item/rcs/Destroy()
- QDEL_NULL(rcell)
- return ..()
-
-/obj/item/rcs/attack_self(mob/user)
- if(emagged)
- if(mode == 0)
- mode = 1
- playsound(src.loc, 'sound/effects/pop.ogg', 50, 0)
- to_chat(user, " The telepad locator has become uncalibrated.")
- else
- mode = 0
- playsound(src.loc, 'sound/effects/pop.ogg', 50, 0)
- to_chat(user, " You calibrate the telepad locator.")
-
-/obj/item/rcs/emag_act(user as mob)
- if(!emagged)
- emagged = 1
- do_sparks(5, 1, src)
- to_chat(user, " You emag the RCS. Activate it to toggle between modes.")
- return
diff --git a/code/modules/telesci/telesci_computer.dm b/code/modules/telesci/telesci_computer.dm
index 9d66758207f..d373e73f77b 100644
--- a/code/modules/telesci/telesci_computer.dm
+++ b/code/modules/telesci/telesci_computer.dm
@@ -169,15 +169,15 @@
if(telepad)
- var/truePower = Clamp(power + power_off, 1, 1000)
+ var/truePower = clamp(power + power_off, 1, 1000)
var/trueRotation = rotation + rotation_off
- var/trueAngle = Clamp(angle, 1, 90)
+ var/trueAngle = clamp(angle, 1, 90)
var/datum/projectile_data/proj_data = projectile_trajectory(telepad.x, telepad.y, trueRotation, trueAngle, truePower)
last_tele_data = proj_data
- var/trueX = Clamp(round(proj_data.dest_x, 1), 1, world.maxx)
- var/trueY = Clamp(round(proj_data.dest_y, 1), 1, world.maxy)
+ var/trueX = clamp(round(proj_data.dest_x, 1), 1, world.maxx)
+ var/trueY = clamp(round(proj_data.dest_y, 1), 1, world.maxy)
var/spawn_time = round(proj_data.time) * 10
var/turf/target = locate(trueX, trueY, z_co)
@@ -291,12 +291,12 @@
return
- var/truePower = Clamp(power + power_off, 1, 1000)
+ var/truePower = clamp(power + power_off, 1, 1000)
var/trueRotation = rotation + rotation_off
- var/trueAngle = Clamp(angle, 1, 90)
+ var/trueAngle = clamp(angle, 1, 90)
var/datum/projectile_data/proj_data = projectile_trajectory(telepad.x, telepad.y, trueRotation, trueAngle, truePower)
- var/turf/target = locate(Clamp(round(proj_data.dest_x, 1), 1, world.maxx), Clamp(round(proj_data.dest_y, 1), 1, world.maxy), z_co)
+ var/turf/target = locate(clamp(round(proj_data.dest_x, 1), 1, world.maxx), clamp(round(proj_data.dest_y, 1), 1, world.maxy), z_co)
var/area/A = get_area(target)
if(A.tele_proof == 1)
@@ -336,14 +336,14 @@
var/new_rot = input("Please input desired bearing in degrees.", name, rotation) as num
if(..()) // Check after we input a value, as they could've moved after they entered something
return
- rotation = Clamp(new_rot, -900, 900)
+ rotation = clamp(new_rot, -900, 900)
rotation = round(rotation, 0.01)
if(href_list["setangle"])
var/new_angle = input("Please input desired elevation in degrees.", name, angle) as num
if(..())
return
- angle = Clamp(round(new_angle, 0.1), 1, 9999)
+ angle = clamp(round(new_angle, 0.1), 1, 9999)
if(href_list["setpower"])
var/index = href_list["setpower"]
@@ -356,7 +356,7 @@
var/new_z = input("Please input desired sector.", name, z_co) as num
if(..())
return
- z_co = Clamp(round(new_z), 1, 10)
+ z_co = clamp(round(new_z), 1, 10)
if(href_list["ejectGPS"])
if(inserted_gps)
diff --git a/code/modules/tgui/external.dm b/code/modules/tgui/external.dm
new file mode 100644
index 00000000000..840f0cd267c
--- /dev/null
+++ b/code/modules/tgui/external.dm
@@ -0,0 +1,155 @@
+/**
+ * tgui external
+ *
+ * Contains all external tgui declarations.
+ */
+
+/**
+ * public
+ *
+ * Used to open and update UIs.
+ * If this proc is not implemented properly, the UI will not update correctly.
+ *
+ * required user mob The mob who opened/is using the UI.
+ * optional ui_key string The ui_key of the UI.
+ * optional ui datum/tgui The UI to be updated, if it exists.
+ * optional force_open bool If the UI should be re-opened instead of updated.
+ * optional master_ui datum/tgui The parent UI.
+ * optional state datum/ui_state The state used to determine status.
+ */
+
+/datum/proc/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
+ return FALSE // Not implemented.
+
+/**
+ * public
+ *
+ * Data to be sent to the UI.
+ * This must be implemented for a UI to work.
+ *
+ * required user mob The mob interacting with the UI.
+ *
+ * return list Data to be sent to the UI.
+ */
+/datum/proc/tgui_data(mob/user)
+ return list() // Not implemented.
+
+/**
+ * public
+ *
+ * Static Data to be sent to the UI.
+ * Static data differs from normal data in that it's large data that should be sent infrequently
+ * This is implemented optionally for heavy uis that would be sending a lot of redundant data
+ * frequently.
+ * Gets squished into one object on the frontend side, but the static part is cached.
+ *
+ * required user mob The mob interacting with the UI.
+ *
+ * return list Statuic Data to be sent to the UI.
+ */
+/datum/proc/tgui_static_data(mob/user)
+ return list()
+
+/**
+ * public
+ *
+ * Forces an update on static data. Should be done manually whenever something happens to change static data.
+ *
+ * required user the mob currently interacting with the ui
+ * optional ui ui to be updated
+ * optional ui_key ui key of ui to be updated
+ */
+/datum/proc/update_tgui_static_data(mob/user, datum/tgui/ui, ui_key = "main")
+ ui = SStgui.try_update_ui(user, src, ui_key, ui)
+ // If there was no ui to update, there's no static data to update either.
+ if(!ui)
+ return
+ ui.push_data(null, tgui_static_data(), TRUE)
+
+/**
+ * public
+ *
+ * Called on a UI when the UI receieves a href.
+ * Think of this as Topic().
+ *
+ * required action string The action/button that has been invoked by the user.
+ * required params list A list of parameters attached to the button.
+ *
+ * return bool If the UI should be updated or not.
+ */
+/datum/proc/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
+ // If UI is not interactive or usr calling Topic is not the UI user, bail.
+ if(!ui || ui.status != STATUS_INTERACTIVE)
+ return TRUE
+
+/**
+ * public
+ *
+ * Called on an object when a tgui object is being created, allowing you to
+ * customise the html
+ * For example: inserting a custom stylesheet that you need in the head
+ *
+ * For this purpose, some tags are available in the html, to be parsed out
+ ^ with replacetext
+ * (customheadhtml) - Additions to the head tag
+ *
+ * required html the html base text
+ */
+/datum/proc/tgui_base_html(html)
+ return html
+
+/**
+ * private
+ *
+ * The UI's host object (usually src_object).
+ * This allows modules/datums to have the UI attached to them,
+ * and be a part of another object.
+ */
+/datum/proc/tgui_host(mob/user)
+ return src // Default src.
+
+/**
+ * global
+ *
+ * Associative list of JSON-encoded shared states that were set by
+ * tgui clients.
+ */
+
+/datum/var/list/tgui_shared_states
+
+/**
+ * global
+ *
+ * Used to track UIs for a mob.
+ */
+/mob/var/list/open_tguis = list()
+/**
+ * public
+ *
+ * Called on a UI's object when the UI is closed, not to be confused with
+ * client/verb/uiclose(), which closes the ui window
+ */
+/datum/proc/tgui_close(mob/user)
+
+/**
+ * verb
+ *
+ * Called by UIs when they are closed.
+ * Must be a verb so winset() can call it.
+ *
+ * required uiref ref The UI that was closed.
+ */
+/client/verb/tguiclose(uid as text)
+ // Name the verb, and hide it from the user panel.
+ set name = "uiclose"
+ set hidden = TRUE
+
+ // Get the UI based on the ref.
+ var/datum/tgui/ui = locateUID(uid)
+
+ // If we found the UI, close it.
+ if(istype(ui))
+ ui.close()
+ // Unset machine just to be sure.
+ if(src && src.mob)
+ src.mob.unset_machine()
diff --git a/code/modules/tgui/modules/_base.dm b/code/modules/tgui/modules/_base.dm
new file mode 100644
index 00000000000..36be6295710
--- /dev/null
+++ b/code/modules/tgui/modules/_base.dm
@@ -0,0 +1,21 @@
+/*
+TGUI MODULES
+
+This allows for datum-based TGUIs that can be hooked into objects.
+This is useful for things such as the power monitor, which needs to exist on a physical console in the world, but also as a virtual device the AI can use
+
+Code is pretty much ripped verbatim from nano modules, but with un-needed stuff removed
+*/
+/datum/tgui_module
+ var/name
+ var/datum/host
+
+/datum/tgui_module/New(var/host)
+ src.host = host
+
+/datum/tgui_module/tgui_host()
+ return host ? host : src
+
+/datum/tgui_module/tgui_close(mob/user)
+ if(host)
+ host.tgui_close(user)
diff --git a/code/modules/tgui/modules/crew_monitor.dm b/code/modules/tgui/modules/crew_monitor.dm
new file mode 100644
index 00000000000..783498542e4
--- /dev/null
+++ b/code/modules/tgui/modules/crew_monitor.dm
@@ -0,0 +1,39 @@
+/datum/tgui_module/crew_monitor
+ name = "Crew monitor"
+
+/datum/tgui_module/crew_monitor/tgui_act(action, params)
+ if(..())
+ return TRUE
+
+ var/turf/T = get_turf(tgui_host())
+ if(!T || !is_level_reachable(T.z))
+ to_chat(usr, "Unable to establish a connection: You're too far away from the station!")
+ return FALSE
+
+ switch(action)
+ if("track")
+ if(isAI(usr))
+ var/mob/living/silicon/ai/AI = usr
+ var/mob/living/carbon/human/H = locate(params["track"]) in GLOB.mob_list
+ if(hassensorlevel(H, SUIT_SENSOR_TRACKING))
+ AI.ai_actual_track(H)
+ return TRUE
+
+
+/datum/tgui_module/crew_monitor/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ if(!ui)
+ // The 557 may seem random, but its the perfectsize for margins on the nanomap
+ ui = new(user, src, ui_key, "CrewMonitor", name, 1400, 557, master_ui, state)
+ ui.autoupdate = TRUE
+ ui.open()
+
+
+/datum/tgui_module/crew_monitor/tgui_data(mob/user)
+ var/data[0]
+ var/turf/T = get_turf(tgui_host())
+
+ data["isAI"] = isAI(user)
+ data["crewmembers"] = GLOB.crew_repository.health_data(T)
+
+ return data
diff --git a/code/modules/tgui/states.dm b/code/modules/tgui/states.dm
new file mode 100644
index 00000000000..81152426d06
--- /dev/null
+++ b/code/modules/tgui/states.dm
@@ -0,0 +1,117 @@
+/**
+ * tgui states
+ *
+ * Base state and helpers for states. Just does some sanity checks, implement a state for in-depth checks.
+ */
+
+/**
+ * public
+ *
+ * Checks the UI state for a mob.
+ *
+ * required user mob The mob who opened/is using the UI.
+ * required state datum/ui_state The state to check.
+ *
+ * return UI_state The state of the UI.
+ */
+/datum/proc/tgui_status(mob/user, datum/tgui_state/state)
+ var/src_object = tgui_host(user)
+ . = STATUS_CLOSE
+ if(!state)
+ return
+
+ if(isobserver(user))
+ // If they turn on ghost AI control, admins can always interact.
+ if(user.client.advanced_admin_interaction)
+ . = max(., STATUS_INTERACTIVE)
+
+ // Regular ghosts can always at least view if in range.
+ var/clientviewlist = getviewsize(user.client.view)
+ if(get_dist(src_object, user) < max(clientviewlist[1],clientviewlist[2]))
+ . = max(., STATUS_UPDATE)
+
+ // Check if the state allows interaction
+ var/result = state.can_use_topic(src_object, user)
+ . = max(., result)
+
+/**
+ * private
+ *
+ * Checks if a user can use src_object's UI, and returns the state.
+ * Can call a mob proc, which allows overrides for each mob.
+ *
+ * required src_object datum The object/datum which owns the UI.
+ * required user mob The mob who opened/is using the UI.
+ *
+ * return UI_state The state of the UI.
+ */
+/datum/tgui_state/proc/can_use_topic(src_object, mob/user)
+ return STATUS_CLOSE // Don't allow interaction by default.
+
+/**
+ * public
+ *
+ * Standard interaction/sanity checks. Different mob types may have overrides.
+ *
+ * return UI_state The state of the UI.
+ */
+/mob/proc/shared_tgui_interaction(src_object)
+ if(!client) // Close UIs if mindless.
+ return STATUS_CLOSE
+ else if(stat) // Disable UIs if unconcious.
+ return STATUS_DISABLED
+ else if(incapacitated()) // Update UIs if incapicitated but concious.
+ return STATUS_UPDATE
+ return STATUS_INTERACTIVE
+
+/mob/living/silicon/ai/shared_tgui_interaction(src_object)
+ if(lacks_power()) // Disable UIs if the AI is unpowered.
+ return STATUS_DISABLED
+ return ..()
+
+/mob/living/silicon/robot/shared_tgui_interaction(src_object)
+ if(!cell || cell.charge <= 0 || lockcharge) // Disable UIs if the Borg is unpowered or locked.
+ return STATUS_DISABLED
+ return ..()
+
+/**
+ * public
+ *
+ * Check the distance for a living mob.
+ * Really only used for checks outside the context of a mob.
+ * Otherwise, use shared_living_ui_distance().
+ *
+ * required src_object The object which owns the UI.
+ * required user mob The mob who opened/is using the UI.
+ *
+ * return UI_state The state of the UI.
+ */
+/atom/proc/contents_tgui_distance(src_object, mob/living/user)
+ return user.shared_living_tgui_distance(src_object) // Just call this mob's check.
+
+/**
+ * public
+ *
+ * Distance versus interaction check.
+ *
+ * required src_object atom/movable The object which owns the UI.
+ *
+ * return UI_state The state of the UI.
+ */
+/mob/living/proc/shared_living_tgui_distance(atom/movable/src_object, viewcheck = TRUE)
+ if(viewcheck && !(src_object in view(src))) // If the object is obscured, close it.
+ return STATUS_CLOSE
+
+ var/dist = get_dist(src_object, src)
+ if(dist <= 1) // Open and interact if 1-0 tiles away.
+ return STATUS_INTERACTIVE
+ else if(dist <= 2) // View only if 2-3 tiles away.
+ return STATUS_UPDATE
+ else if(dist <= 5) // Disable if 5 tiles away.
+ return STATUS_DISABLED
+ return STATUS_CLOSE // Otherwise, we got nothing.
+
+/mob/living/carbon/human/shared_living_tgui_distance(atom/movable/src_object)
+ if((TK in mutations) && (get_dist(src, src_object) <= 2))
+ return STATUS_INTERACTIVE
+ return ..()
diff --git a/code/modules/tgui/states/admin.dm b/code/modules/tgui/states/admin.dm
new file mode 100644
index 00000000000..6d1c680927a
--- /dev/null
+++ b/code/modules/tgui/states/admin.dm
@@ -0,0 +1,12 @@
+ /**
+ * tgui state: admin_state
+ *
+ * Checks that the user is an admin, end-of-story.
+ **/
+
+GLOBAL_DATUM_INIT(tgui_admin_state, /datum/tgui_state/admin_state, new)
+
+/datum/tgui_state/admin_state/can_use_topic(src_object, mob/user)
+ if(check_rights_for(user.client, R_ADMIN))
+ return STATUS_INTERACTIVE
+ return STATUS_CLOSE
diff --git a/code/modules/tgui/states/always.dm b/code/modules/tgui/states/always.dm
new file mode 100644
index 00000000000..30915785442
--- /dev/null
+++ b/code/modules/tgui/states/always.dm
@@ -0,0 +1,11 @@
+
+ /**
+ * tgui state: always_state
+ *
+ * Always grants the user UI_INTERACTIVE. Period.
+ **/
+
+GLOBAL_DATUM_INIT(tgui_always_state, /datum/tgui_state/always_state, new)
+
+/datum/tgui_state/always_state/can_use_topic(src_object, mob/user)
+ return STATUS_INTERACTIVE
diff --git a/code/modules/tgui/states/conscious.dm b/code/modules/tgui/states/conscious.dm
new file mode 100644
index 00000000000..6bc0c7ec031
--- /dev/null
+++ b/code/modules/tgui/states/conscious.dm
@@ -0,0 +1,12 @@
+ /**
+ * tgui state: conscious_state
+ *
+ * Only checks if the user is conscious.
+ **/
+
+GLOBAL_DATUM_INIT(tgui_conscious_state, /datum/tgui_state/conscious_state, new)
+
+/datum/tgui_state/conscious_state/can_use_topic(src_object, mob/user)
+ if(user.stat == CONSCIOUS)
+ return STATUS_INTERACTIVE
+ return STATUS_CLOSE
diff --git a/code/modules/tgui/states/contained.dm b/code/modules/tgui/states/contained.dm
new file mode 100644
index 00000000000..c2fbd0b6b06
--- /dev/null
+++ b/code/modules/tgui/states/contained.dm
@@ -0,0 +1,12 @@
+ /**
+ * tgui state: contained_state
+ *
+ * Checks that the user is inside the src_object.
+ **/
+
+GLOBAL_DATUM_INIT(tgui_contained_state, /datum/tgui_state/contained_state, new)
+
+/datum/tgui_state/contained_state/can_use_topic(atom/src_object, mob/user)
+ if(!src_object.contains(user))
+ return STATUS_CLOSE
+ return user.shared_tgui_interaction(src_object)
diff --git a/code/modules/tgui/states/deep_inventory.dm b/code/modules/tgui/states/deep_inventory.dm
new file mode 100644
index 00000000000..137f262a0ea
--- /dev/null
+++ b/code/modules/tgui/states/deep_inventory.dm
@@ -0,0 +1,12 @@
+ /**
+ * tgui state: deep_inventory_state
+ *
+ * Checks that the src_object is in the user's deep (backpack, box, toolbox, etc) inventory.
+ **/
+
+GLOBAL_DATUM_INIT(tgui_deep_inventory_state, /datum/tgui_state/deep_inventory_state, new)
+
+/datum/tgui_state/deep_inventory_state/can_use_topic(src_object, mob/user)
+ if(!user.contains(src_object))
+ return STATUS_CLOSE
+ return user.shared_tgui_interaction(src_object)
diff --git a/code/modules/tgui/states/default.dm b/code/modules/tgui/states/default.dm
new file mode 100644
index 00000000000..4da729aa7e5
--- /dev/null
+++ b/code/modules/tgui/states/default.dm
@@ -0,0 +1,63 @@
+ /**
+ * tgui state: default_state
+ *
+ * Checks a number of things -- mostly physical distance for humans and view for robots.
+ **/
+
+GLOBAL_DATUM_INIT(tgui_default_state, /datum/tgui_state/default, new)
+
+/datum/tgui_state/default/can_use_topic(src_object, mob/user)
+ return user.default_can_use_tgui_topic(src_object) // Call the individual mob-overridden procs.
+
+/mob/proc/default_can_use_tgui_topic(src_object)
+ return STATUS_CLOSE // Don't allow interaction by default.
+
+/mob/living/default_can_use_tgui_topic(src_object)
+ . = shared_tgui_interaction(src_object)
+ if(. > STATUS_CLOSE && loc)
+ . = min(., loc.contents_tgui_distance(src_object, src)) // Check the distance...
+ if(. == STATUS_INTERACTIVE) // Non-human living mobs can only look, not touch.
+ return STATUS_UPDATE
+
+/mob/living/carbon/human/default_can_use_tgui_topic(src_object)
+ . = shared_tgui_interaction(src_object)
+ if(. > STATUS_CLOSE)
+ . = min(., shared_living_tgui_distance(src_object)) // Check the distance...
+
+/mob/living/silicon/robot/default_can_use_tgui_topic(src_object)
+ . = shared_tgui_interaction(src_object)
+ if(. <= STATUS_DISABLED)
+ return
+
+ // Robots can interact with anything they can see.
+ var/list/clientviewlist = getviewsize(client.view)
+ if((src_object in view(src)) && (get_dist(src, src_object) <= min(clientviewlist[1],clientviewlist[2])))
+ return STATUS_INTERACTIVE
+ return STATUS_DISABLED // Otherwise they can keep the UI open.
+
+/mob/living/silicon/ai/default_can_use_tgui_topic(src_object)
+ . = shared_tgui_interaction(src_object)
+ if(. < STATUS_INTERACTIVE)
+ return
+
+ // The AI can interact with anything it can see nearby, or with cameras while wireless control is enabled.
+ if(!control_disabled && can_see(src_object))
+ return STATUS_INTERACTIVE
+ return STATUS_CLOSE
+
+/mob/living/simple_animal/default_can_use_tgui_topic(src_object)
+ . = shared_tgui_interaction(src_object)
+ if(. > STATUS_CLOSE)
+ . = min(., shared_living_tgui_distance(src_object)) //simple animals can only use things they're near.
+
+/mob/living/silicon/pai/default_can_use_tgui_topic(src_object)
+ // pAIs can only use themselves and the owner's radio.
+ if((src_object == src || src_object == radio) && !stat)
+ return STATUS_INTERACTIVE
+ else
+ return ..()
+
+/mob/dead/observer/default_can_use_tgui_topic()
+ if(can_admin_interact())
+ return STATUS_INTERACTIVE // Admins are more equal
+ return STATUS_UPDATE // Ghosts can view updates
diff --git a/code/modules/tgui/states/hands.dm b/code/modules/tgui/states/hands.dm
new file mode 100644
index 00000000000..6dc1e2fc1a4
--- /dev/null
+++ b/code/modules/tgui/states/hands.dm
@@ -0,0 +1,25 @@
+ /**
+ * tgui state: hands_state
+ *
+ * Checks that the src_object is in the user's hands.
+ **/
+
+GLOBAL_DATUM_INIT(tgui_hands_state, /datum/tgui_state/hands_state, new)
+
+/datum/tgui_state/hands_state/can_use_topic(src_object, mob/user)
+ . = user.shared_tgui_interaction(src_object)
+ if(. > STATUS_CLOSE)
+ return min(., user.hands_can_use_tgui_topic(src_object))
+
+/mob/proc/hands_can_use_tgui_topic(src_object)
+ return STATUS_CLOSE
+
+/mob/living/hands_can_use_tgui_topic(src_object)
+ if(is_in_active_hand(src_object) || is_in_inactive_hand(src_object))
+ return STATUS_INTERACTIVE
+ return STATUS_CLOSE
+
+/mob/living/silicon/robot/hands_can_use_tgui_topic(src_object)
+ if(activated(src_object))
+ return STATUS_INTERACTIVE
+ return STATUS_CLOSE
diff --git a/code/modules/tgui/states/human_adjacent.dm b/code/modules/tgui/states/human_adjacent.dm
new file mode 100644
index 00000000000..8164d5f9cee
--- /dev/null
+++ b/code/modules/tgui/states/human_adjacent.dm
@@ -0,0 +1,17 @@
+
+ /**
+ * tgui state: human_adjacent_state
+ *
+ * In addition to default checks, only allows interaction for a
+ * human adjacent user.
+ **/
+
+GLOBAL_DATUM_INIT(tgui_human_adjacent_state, /datum/tgui_state/human_adjacent_state, new)
+
+/datum/tgui_state/human_adjacent_state/can_use_topic(src_object, mob/user)
+ . = user.default_can_use_tgui_topic(src_object)
+
+ var/dist = get_dist(src_object, user)
+ if((dist > 1) || (!ishuman(user)))
+ // Can't be used unless adjacent and human, even with TK
+ . = min(., STATUS_UPDATE)
diff --git a/code/modules/tgui/states/inventory.dm b/code/modules/tgui/states/inventory.dm
new file mode 100644
index 00000000000..92274cc1f2e
--- /dev/null
+++ b/code/modules/tgui/states/inventory.dm
@@ -0,0 +1,12 @@
+ /**
+ * tgui state: inventory_state
+ *
+ * Checks that the src_object is in the user's top-level (hand, ear, pocket, belt, etc) inventory.
+ **/
+
+GLOBAL_DATUM_INIT(tgui_inventory_state, /datum/tgui_state/inventory_state, new)
+
+/datum/tgui_state/inventory_state/can_use_topic(src_object, mob/user)
+ if(!(src_object in user))
+ return STATUS_CLOSE
+ return user.shared_tgui_interaction(src_object)
diff --git a/code/modules/tgui/states/not_incapacitated.dm b/code/modules/tgui/states/not_incapacitated.dm
new file mode 100644
index 00000000000..1185b516478
--- /dev/null
+++ b/code/modules/tgui/states/not_incapacitated.dm
@@ -0,0 +1,29 @@
+ /**
+ * tgui state: not_incapacitated_state
+ *
+ * Checks that the user isn't incapacitated
+ **/
+
+GLOBAL_DATUM_INIT(tgui_not_incapacitated_state, /datum/tgui_state/not_incapacitated_state, new)
+
+ /**
+ * tgui state: not_incapacitated_turf_state
+ *
+ * Checks that the user isn't incapacitated and that their loc is a turf
+ **/
+
+GLOBAL_DATUM_INIT(tgui_not_incapacitated_turf_state, /datum/tgui_state/not_incapacitated_state, new(no_turfs = TRUE))
+
+/datum/tgui_state/not_incapacitated_state
+ var/turf_check = FALSE
+
+/datum/tgui_state/not_incapacitated_state/New(loc, no_turfs = FALSE)
+ ..()
+ turf_check = no_turfs
+
+/datum/tgui_state/not_incapacitated_state/can_use_topic(src_object, mob/user)
+ if(user.stat)
+ return STATUS_CLOSE
+ if(user.incapacitated() || (turf_check && !isturf(user.loc)))
+ return STATUS_DISABLED
+ return STATUS_INTERACTIVE
diff --git a/code/modules/tgui/states/notcontained.dm b/code/modules/tgui/states/notcontained.dm
new file mode 100644
index 00000000000..01811d427f2
--- /dev/null
+++ b/code/modules/tgui/states/notcontained.dm
@@ -0,0 +1,26 @@
+ /**
+ * tgui state: notcontained_state
+ *
+ * Checks that the user is not inside src_object, and then makes the default checks.
+ **/
+
+GLOBAL_DATUM_INIT(tgui_notcontained_state, /datum/tgui_state/notcontained_state, new)
+
+/datum/tgui_state/notcontained_state/can_use_topic(atom/src_object, mob/user)
+ . = user.shared_tgui_interaction(src_object)
+ if(. > STATUS_CLOSE)
+ return min(., user.notcontained_can_use_tgui_topic(src_object))
+
+/mob/proc/notcontained_can_use_tgui_topic(src_object)
+ return STATUS_CLOSE
+
+/mob/living/notcontained_can_use_tgui_topic(atom/src_object)
+ if(src_object.contains(src))
+ return STATUS_CLOSE // Close if we're inside it.
+ return default_can_use_tgui_topic(src_object)
+
+/mob/living/silicon/notcontained_can_use_tgui_topic(src_object)
+ return default_can_use_tgui_topic(src_object) // Silicons use default bevhavior.
+
+/mob/living/simple_animal/drone/notcontained_can_use_tgui_topic(src_object)
+ return default_can_use_tgui_topic(src_object) // Drones use default bevhavior.
diff --git a/code/modules/tgui/states/observer.dm b/code/modules/tgui/states/observer.dm
new file mode 100644
index 00000000000..bf98f444654
--- /dev/null
+++ b/code/modules/tgui/states/observer.dm
@@ -0,0 +1,15 @@
+ /**
+ * tgui state: observer_state
+ *
+ * Checks that the user is an observer/ghost.
+ **/
+
+GLOBAL_DATUM_INIT(tgui_observer_state, /datum/tgui_state/observer_state, new)
+
+/datum/tgui_state/observer_state/can_use_topic(src_object, mob/user)
+ if(isobserver(user))
+ return STATUS_INTERACTIVE
+ if(check_rights(R_ADMIN, 0, src))
+ return STATUS_INTERACTIVE
+ return STATUS_CLOSE
+
diff --git a/code/modules/tgui/states/physical.dm b/code/modules/tgui/states/physical.dm
new file mode 100644
index 00000000000..a57a321e958
--- /dev/null
+++ b/code/modules/tgui/states/physical.dm
@@ -0,0 +1,24 @@
+ /**
+ * tgui state: physical_state
+ *
+ * Short-circuits the default state to only check physical distance.
+ **/
+
+GLOBAL_DATUM_INIT(tgui_physical_state, /datum/tgui_state/physical, new)
+
+/datum/tgui_state/physical/can_use_topic(src_object, mob/user)
+ . = user.shared_tgui_interaction(src_object)
+ if(. > STATUS_CLOSE)
+ return min(., user.physical_can_use_tgui_topic(src_object))
+
+/mob/proc/physical_can_use_tgui_topic(src_object)
+ return STATUS_CLOSE
+
+/mob/living/physical_can_use_tgui_topic(src_object)
+ return shared_living_tgui_distance(src_object)
+
+/mob/living/silicon/physical_can_use_tgui_topic(src_object)
+ return max(STATUS_UPDATE, shared_living_tgui_distance(src_object)) // Silicons can always see.
+
+/mob/living/silicon/ai/physical_can_use_tgui_topic(src_object)
+ return STATUS_UPDATE // AIs are not physical.
diff --git a/code/modules/tgui/states/self.dm b/code/modules/tgui/states/self.dm
new file mode 100644
index 00000000000..109fd6ae440
--- /dev/null
+++ b/code/modules/tgui/states/self.dm
@@ -0,0 +1,12 @@
+ /**
+ * tgui state: self_state
+ *
+ * Only checks that the user and src_object are the same.
+ **/
+
+GLOBAL_DATUM_INIT(tgui_self_state, /datum/tgui_state/self_state, new)
+
+/datum/tgui_state/self_state/can_use_topic(src_object, mob/user)
+ if(src_object != user)
+ return STATUS_CLOSE
+ return user.shared_tgui_interaction(src_object)
diff --git a/code/modules/tgui/states/zlevel.dm b/code/modules/tgui/states/zlevel.dm
new file mode 100644
index 00000000000..a589a4b64d7
--- /dev/null
+++ b/code/modules/tgui/states/zlevel.dm
@@ -0,0 +1,14 @@
+ /**
+ * tgui state: z_state
+ *
+ * Only checks that the Z-level of the user and src_object are the same.
+ **/
+
+GLOBAL_DATUM_INIT(tgui_z_state, /datum/tgui_state/z_state, new)
+
+/datum/tgui_state/z_state/can_use_topic(src_object, mob/user)
+ var/turf/turf_obj = get_turf(src_object)
+ var/turf/turf_usr = get_turf(user)
+ if(turf_obj && turf_usr && turf_obj.z == turf_usr.z)
+ return STATUS_INTERACTIVE
+ return STATUS_CLOSE
diff --git a/code/modules/tgui/tgui.dm b/code/modules/tgui/tgui.dm
new file mode 100644
index 00000000000..5157d0c9fed
--- /dev/null
+++ b/code/modules/tgui/tgui.dm
@@ -0,0 +1,363 @@
+/**
+ * tgui
+ *
+ * /tg/station user interface library
+ */
+
+/**
+ * tgui datum (represents a UI).
+ */
+/datum/tgui
+ /// The mob who opened/is using the UI.
+ var/mob/user
+ /// The object which owns the UI.
+ var/datum/src_object
+ /// The title of te UI.
+ var/title
+ /// The ui_key of the UI. This allows multiple UIs for one src_object.
+ var/ui_key
+ /// The window_id for browse() and onclose().
+ var/window_id
+ /// The window width.
+ var/width = 0
+ /// The window height
+ var/height = 0
+ /// The interface (template) to be used for this UI.
+ var/interface
+ /// Update the UI every MC tick.
+ var/autoupdate = TRUE
+ /// If the UI has been initialized yet.
+ var/initialized = FALSE
+ /// The data (and datastructure) used to initialize the UI.
+ var/list/initial_data
+ /// The static data used to initialize the UI.
+ var/list/initial_static_data
+ /// Holder for the json string, that is sent during the initial update
+ var/_initial_update
+ /// The status/visibility of the UI.
+ var/status = STATUS_INTERACTIVE
+ /// Topic state used to determine status/interactability.
+ var/datum/tgui_state/state = null
+ /// The parent UI.
+ var/datum/tgui/master_ui
+ /// Children of this UI.
+ var/list/datum/tgui/children = list()
+
+/**
+ * public
+ *
+ * Create a new UI.
+ *
+ * required user mob The mob who opened/is using the UI.
+ * required src_object datum The object or datum which owns the UI.
+ * required ui_key string The ui_key of the UI.
+ * required interface string The interface used to render the UI.
+ * optional title string The title of the UI.
+ * optional width int The window width.
+ * optional height int The window height.
+ * optional master_ui datum/tgui The parent UI.
+ * optional state datum/ui_state The state used to determine status.
+ *
+ * return datum/tgui The requested UI.
+ */
+/datum/tgui/New(mob/user, datum/src_object, ui_key, interface, title, width = 0, height = 0, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
+ src.user = user
+ src.src_object = src_object
+ src.ui_key = ui_key
+ src.window_id = "[src_object.UID()]-[ui_key]"
+ src.interface = interface
+
+ if(title)
+ src.title = sanitize(title)
+ if(width)
+ src.width = width
+ if(height)
+ src.height = height
+
+ src.master_ui = master_ui
+ if(master_ui)
+ master_ui.children += src
+ src.state = state
+
+ var/datum/asset/tgui_assets = get_asset_datum(/datum/asset/simple/tgui)
+ var/datum/asset/fa = get_asset_datum(/datum/asset/simple/fontawesome)
+ tgui_assets.send(user)
+ fa.send(user)
+
+/**
+ * public
+ *
+ * Open this UI (and initialize it with data).
+ */
+/datum/tgui/proc/open()
+ if(!user.client)
+ return // Bail if there is no client.
+
+ update_status(push = FALSE) // Update the window status.
+ if(status < STATUS_UPDATE)
+ return // Bail if we're not supposed to open.
+
+
+
+ // Build window options
+ var/window_options = "can_minimize=0;auto_format=0;"
+ // If we have a width and height, use them.
+ if(width && height)
+ window_options += "size=[width]x[height];"
+
+ // Remove titlebar and resize handles for a fancy window
+ if(user.client.prefs.nanoui_fancy)
+ window_options += "titlebar=0;can_resize=0;"
+ else
+ window_options += "titlebar=1;can_resize=1;"
+
+ // Generate page html
+ var/html
+ html = SStgui.basehtml
+ // Allow the src object to override the html if needed
+ html = src_object.tgui_base_html(html)
+ // Replace template tokens with important UI data
+ html = replacetextEx(html, "\[tgui:ref]", "[src.UID()]")
+
+ // Open the window.
+ user << browse(html, "window=[window_id];[window_options]")
+
+ // Instruct the client to signal UI when the window is closed.
+ // NOTE: Intentional \ref usage; tgui datums can't/shouldn't
+ // be tagged, so this is an effective unwrap
+ winset(user, window_id, "on-close=\"uiclose [UID()]\"")
+
+ // Pre-fetch initial state while browser is still loading in
+ // another thread
+ if(!initial_data)
+ initial_data = src_object.tgui_data(user)
+ if(!initial_static_data)
+ initial_static_data = src_object.tgui_static_data(user)
+ _initial_update = url_encode(get_json(initial_data, initial_static_data))
+
+ SStgui.on_open(src)
+
+/**
+ * public
+ *
+ * Reinitialize the UI.
+ * (Possibly with a new interface and/or data).
+ *
+ * optional template string The name of the new interface.
+ * optional data list The new initial data.
+ */
+/datum/tgui/proc/reinitialize(interface, list/data, list/static_data)
+ if(interface)
+ src.interface = interface
+ if(data)
+ initial_data = data
+ if(static_data)
+ initial_static_data = static_data
+ open()
+
+/**
+ * public
+ *
+ * Close the UI, and all its children.
+ */
+/datum/tgui/proc/close()
+ user << browse(null, "window=[window_id]") // Close the window.
+ src_object.tgui_close(user)
+ SStgui.on_close(src)
+ for(var/datum/tgui/child in children) // Loop through and close all children.
+ child.close()
+ children.Cut()
+ state = null
+ master_ui = null
+ qdel(src)
+
+/**
+ * public
+ *
+ * Enable/disable auto-updating of the UI.
+ *
+ * required state bool Enable/disable auto-updating.
+ */
+/datum/tgui/proc/set_autoupdate(state = TRUE)
+ autoupdate = state
+
+/**
+ * private
+ *
+ * Package the data to send to the UI, as JSON.
+ * This includes the UI data and config_data.
+ *
+ * return string The packaged JSON.
+ */
+/datum/tgui/proc/get_json(list/data, list/static_data)
+ var/list/json_data = list()
+
+ json_data["config"] = list(
+ "title" = title,
+ "status" = status,
+ "interface" = interface,
+ "fancy" = user.client.prefs.nanoui_fancy,
+ "observer" = isobserver(user),
+ "window" = window_id,
+ "map" = (GLOB.using_map && GLOB.using_map.name) ? GLOB.using_map.name : "Unknown",
+
+ "ref" = "[src.UID()]"
+ )
+
+ if(!isnull(data))
+ json_data["data"] = data
+ if(!isnull(static_data))
+ json_data["static_data"] = static_data
+
+ // Send shared states
+ if(src_object.tgui_shared_states)
+ json_data["shared"] = src_object.tgui_shared_states
+
+ // Generate the JSON.
+ var/json = json_encode(json_data)
+ // Strip #255/improper.
+ json = replacetext(json, "\proper", "")
+ json = replacetext(json, "\improper", "")
+ return json
+
+/**
+ * private
+ *
+ * Handle clicks from the UI.
+ * Call the src_object's ui_act() if status is UI_INTERACTIVE.
+ * If the src_object's ui_act() returns 1, update all UIs attacked to it.
+ */
+/datum/tgui/Topic(href, href_list)
+ if(user != usr)
+ return // Something is not right here.
+
+ var/action = href_list["action"]
+ var/params = href_list; params -= "action"
+
+ switch(action)
+ if("tgui:initialize")
+ user << output(_initial_update, "[window_id].browser:update")
+ initialized = TRUE
+ if("tgui:setSharedState")
+ // Update the window state.
+ update_status(push = FALSE)
+ // Bail if UI is not interactive or usr calling Topic
+ // is not the UI user.
+ if(status != STATUS_INTERACTIVE)
+ return
+ var/key = params["key"]
+ var/value = params["value"]
+ if(!src_object.tgui_shared_states)
+ src_object.tgui_shared_states = list()
+ src_object.tgui_shared_states[key] = value
+ SStgui.update_uis(src_object)
+ if("tgui:setFancy")
+ var/value = text2num(params["value"])
+ user.client.prefs.nanoui_fancy = value
+ if("tgui:log")
+ // Force window to show frills on fatal errors
+ if(params["fatal"])
+ winset(user, window_id, "titlebar=1;can-resize=1;size=600x600")
+ log_message(params["log"])
+ if("tgui:link")
+ user << link(params["url"])
+
+ else
+ // Update the window state.
+ update_status(push = FALSE)
+ // Call tgui_act() on the src_object.
+ if(src_object.tgui_act(action, params, src, state))
+ // Update if the object requested it.
+ SStgui.update_uis(src_object)
+
+/**
+ * private
+ *
+ * Update the UI.
+ * Only updates the data if update is true, otherwise only updates the status.
+ *
+ * optional force bool If the UI should be forced to update.
+ */
+/datum/tgui/process(force = FALSE)
+ var/datum/host = src_object.tgui_host(user)
+ if(!src_object || !host || !user) // If the object or user died (or something else), abort.
+ close()
+ return
+
+ if(status && (force || autoupdate))
+ update() // Update the UI if the status and update settings allow it.
+ else
+ update_status(push = TRUE) // Otherwise only update status.
+
+/**
+ * private
+ *
+ * Push data to an already open UI.
+ *
+ * required data list The data to send.
+ * optional force bool If the update should be sent regardless of state.
+ */
+/datum/tgui/proc/push_data(data, static_data, force = FALSE)
+ // Update the window state.
+ update_status(push = FALSE)
+ // Cannot update UI if it is not set up yet.
+ if(!initialized)
+ return
+ // Cannot update UI, we have no visibility.
+ if(status <= STATUS_DISABLED && !force)
+ return
+ // Send the new JSON to the update() Javascript function.
+ user << output(
+ url_encode(get_json(data, static_data)),
+ "[window_id].browser:update")
+
+/**
+ * private
+ *
+ * Updates the UI by interacting with the src_object again, which will hopefully
+ * call try_ui_update on it.
+ *
+ * optional force_open bool If force_open should be passed to ui_interact.
+ */
+/datum/tgui/proc/update(force_open = FALSE)
+ src_object.tgui_interact(user, ui_key, src, force_open, master_ui, state)
+
+/**
+ * private
+ *
+ * Update the status/visibility of the UI for its user.
+ *
+ * optional push bool Push an update to the UI (an update is always sent for UI_DISABLED).
+ */
+/datum/tgui/proc/update_status(push = FALSE)
+ var/status = src_object.tgui_status(user, state)
+ if(master_ui)
+ status = min(status, master_ui.status)
+
+ set_status(status, push)
+ if(status == STATUS_CLOSE)
+ close()
+
+/**
+ * private
+ *
+ * Set the status/visibility of the UI.
+ *
+ * required status int The status to set (UI_CLOSE/UI_DISABLED/UI_UPDATE/UI_INTERACTIVE).
+ * optional push bool Push an update to the UI (an update is always sent for UI_DISABLED).
+ */
+/datum/tgui/proc/set_status(status, push = FALSE)
+ // Only update if status has changed.
+ if(src.status != status)
+ if(src.status == STATUS_DISABLED)
+ src.status = status
+ if(push)
+ update()
+ else
+ src.status = status
+ // Update if the UI just because disabled, or a push is requested.
+ if(status == STATUS_DISABLED || push)
+ push_data(null, force = TRUE)
+
+/datum/tgui/proc/log_message(message)
+ log_tgui("[user] ([user.ckey]) using \"[title]\":\n[message]")
diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm
new file mode 100644
index 00000000000..5b1409af4e7
--- /dev/null
+++ b/code/modules/unit_tests/_unit_tests.dm
@@ -0,0 +1,12 @@
+//include unit test files in this module in this ifdef
+//Keep this sorted alphabetically
+
+#ifdef UNIT_TESTS
+#include "component_tests.dm"
+#include "reagent_id_typos.dm"
+#include "spawn_humans.dm"
+#include "sql.dm"
+#include "subsystem_init.dm"
+#include "timer_sanity.dm"
+#include "unit_test.dm"
+#endif
diff --git a/code/modules/unit_tests/component_tests.dm b/code/modules/unit_tests/component_tests.dm
new file mode 100644
index 00000000000..0099d7508c5
--- /dev/null
+++ b/code/modules/unit_tests/component_tests.dm
@@ -0,0 +1,12 @@
+/datum/unit_test/component_duping/Run()
+ var/list/bad_dms = list()
+ var/list/bad_dts = list()
+ for(var/t in typesof(/datum/component))
+ var/datum/component/comp = t
+ if(!isnum(initial(comp.dupe_mode)))
+ bad_dms += t
+ var/dupe_type = initial(comp.dupe_type)
+ if(dupe_type && !ispath(dupe_type))
+ bad_dts += t
+ if(length(bad_dms) || length(bad_dts))
+ Fail("Components with invalid dupe modes: ([bad_dms.Join(",")]) ||| Components with invalid dupe types: ([bad_dts.Join(",")])")
diff --git a/code/modules/unit_tests/reagent_id_typos.dm b/code/modules/unit_tests/reagent_id_typos.dm
new file mode 100644
index 00000000000..7f45774db0b
--- /dev/null
+++ b/code/modules/unit_tests/reagent_id_typos.dm
@@ -0,0 +1,11 @@
+
+
+/datum/unit_test/reagent_id_typos
+
+/datum/unit_test/reagent_id_typos/Run()
+ for(var/I in GLOB.chemical_reactions_list)
+ for(var/V in GLOB.chemical_reactions_list[I])
+ var/datum/chemical_reaction/R = V
+ for(var/id in (R.required_reagents + R.required_catalysts))
+ if(!GLOB.chemical_reagents_list[id])
+ Fail("Unknown chemical id \"[id]\" in recipe [R.type]")
diff --git a/code/modules/unit_tests/spawn_humans.dm b/code/modules/unit_tests/spawn_humans.dm
new file mode 100644
index 00000000000..ae1f4961b02
--- /dev/null
+++ b/code/modules/unit_tests/spawn_humans.dm
@@ -0,0 +1,8 @@
+/datum/unit_test/spawn_humans/Run()
+ var/locs = block(run_loc_bottom_left, run_loc_top_right)
+
+ for(var/I in 1 to 5)
+ new /mob/living/carbon/human(pick(locs))
+
+ // There is a 5 second delay here so that all the items on the humans have time to initialize and spawn
+ sleep(50)
diff --git a/code/modules/unit_tests/sql.dm b/code/modules/unit_tests/sql.dm
new file mode 100644
index 00000000000..d14bdf11001
--- /dev/null
+++ b/code/modules/unit_tests/sql.dm
@@ -0,0 +1,42 @@
+// Unit test to check SQL version has been updated properly.,
+/datum/unit_test/sql_version/Run()
+ // Check if the SQL version set in the code is equal to the travis DB config
+ if(config.sql_enabled && sql_version != SQL_VERSION)
+ Fail("SQL version error: Game is running V[SQL_VERSION] but config is V[sql_version]. You may need to update tools/travis/dbconfig.txt")
+ // Check if the travis DB config is up to date with the example dbconfig
+ // This proc is a little unclean but it works
+ var/example_db_version
+ var/list/Lines = file2list("config/example/dbconfig.txt")
+ for(var/t in Lines)
+ if(!t) continue
+
+ t = trim(t)
+ if(length(t) == 0)
+ continue
+ else if(copytext(t, 1, 2) == "#")
+ continue
+
+ var/pos = findtext(t, " ")
+ var/name = null
+ var/value = null
+
+ if(pos)
+ name = lowertext(copytext(t, 1, pos))
+ value = copytext(t, pos + 1)
+ else
+ name = lowertext(t)
+
+ if(!name)
+ continue
+
+ switch(name)
+ if("db_version")
+ example_db_version = text2num(value)
+
+ if(!example_db_version)
+ Fail("SQL version error: File config/example/dbconfig.txt does not have a valid SQL version set!")
+
+ if(example_db_version != SQL_VERSION)
+ Fail("SQL version error: Game is running V[SQL_VERSION] but config/example/dbconfig.txt is V[example_db_version].")
+
+
diff --git a/code/modules/unit_tests/subsystem_init.dm b/code/modules/unit_tests/subsystem_init.dm
new file mode 100644
index 00000000000..7d5473bc1bb
--- /dev/null
+++ b/code/modules/unit_tests/subsystem_init.dm
@@ -0,0 +1,7 @@
+/datum/unit_test/subsystem_init/Run()
+ for(var/i in Master.subsystems)
+ var/datum/controller/subsystem/ss = i
+ if(ss.flags & SS_NO_INIT)
+ continue
+ if(!ss.initialized)
+ Fail("[ss]([ss.type]) is a subsystem meant to initialize but doesn't get set as initialized.")
diff --git a/code/modules/unit_tests/timer_sanity.dm b/code/modules/unit_tests/timer_sanity.dm
new file mode 100644
index 00000000000..d92323a5253
--- /dev/null
+++ b/code/modules/unit_tests/timer_sanity.dm
@@ -0,0 +1,3 @@
+/datum/unit_test/timer_sanity/Run()
+ if(SStimer.bucket_count < 0)
+ Fail("SStimer is going into negative bucket count from something")
diff --git a/code/modules/unit_tests/unit_test.dm b/code/modules/unit_tests/unit_test.dm
new file mode 100644
index 00000000000..3a1d39bd133
--- /dev/null
+++ b/code/modules/unit_tests/unit_test.dm
@@ -0,0 +1,102 @@
+/*
+Usage:
+Override /Run() to run your test code
+Call Fail() to fail the test (You should specify a reason)
+You may use /New() and /Destroy() for setup/teardown respectively
+You can use the run_loc_bottom_left and run_loc_top_right to get turfs for testing
+*/
+
+/// VARS FOR UNIT TESTS
+GLOBAL_DATUM(current_test, /datum/unit_test)
+GLOBAL_VAR_INIT(failed_any_test, FALSE)
+GLOBAL_VAR(test_log)
+
+/datum/unit_test
+ //Bit of metadata for the future maybe
+ var/list/procs_tested
+
+ //usable vars
+ var/turf/run_loc_bottom_left
+ var/turf/run_loc_top_right
+
+ //internal shit
+ var/succeeded = TRUE
+ var/list/fail_reasons
+
+/datum/unit_test/New()
+ run_loc_bottom_left = locate(1, 1, 1)
+ run_loc_top_right = locate(5, 5, 1)
+
+/datum/unit_test/Destroy()
+ //clear the test area
+ for(var/atom/movable/AM in block(run_loc_bottom_left, run_loc_top_right))
+ qdel(AM)
+ return ..()
+
+/datum/unit_test/proc/Run()
+ Fail("Run() called parent or not implemented")
+
+/datum/unit_test/proc/Fail(reason = "No reason")
+ succeeded = FALSE
+
+ if(!istext(reason))
+ reason = "FORMATTED: [reason != null ? reason : "NULL"]"
+
+ LAZYADD(fail_reasons, reason)
+
+/proc/RunUnitTests()
+ CHECK_TICK
+
+ for(var/I in subtypesof(/datum/unit_test))
+ var/datum/unit_test/test = new I
+
+ GLOB.current_test = test
+ var/duration = REALTIMEOFDAY
+
+ test.Run()
+
+ duration = REALTIMEOFDAY - duration
+ GLOB.current_test = null
+ GLOB.failed_any_test |= !test.succeeded
+
+ var/list/log_entry = list("[test.succeeded ? "PASS" : "FAIL"]: [I] [duration / 10]s")
+ var/list/fail_reasons = test.fail_reasons
+
+ qdel(test)
+
+ for(var/J in 1 to LAZYLEN(fail_reasons))
+ log_entry += "\tREASON #[J]: [fail_reasons[J]]"
+ log_world(log_entry.Join("\n"))
+
+ CHECK_TICK
+
+ world.Reboot("Unit Test Reboot", "end_test", "tests ended", 0)
+
+
+// OTHER MISC PROCS RELATED TO UNIT TESTS //
+
+/world/proc/HandleTestRun()
+ //trigger things to run the whole process
+ Master.sleep_offline_after_initializations = FALSE
+ // This will have the ticker set the game up
+ // Running the tests is part of the ticker's start function, because I cant think of any better place to put it
+ SSticker.force_start = TRUE
+
+/world/proc/FinishTestRun()
+ set waitfor = FALSE
+ var/list/fail_reasons
+ if(GLOB)
+ if(GLOB.total_runtimes != 0)
+ fail_reasons = list("Total runtimes: [GLOB.total_runtimes]")
+ if(!GLOB.log_directory)
+ LAZYADD(fail_reasons, "Missing GLOB.log_directory!")
+ if(GLOB.failed_any_test)
+ LAZYADD(fail_reasons, "Unit Tests failed!")
+ else
+ fail_reasons = list("Missing GLOB!")
+ if(!fail_reasons)
+ text2file("Success!", "data/clean_run.lk")
+ else
+ log_world("Test run failed!\n[fail_reasons.Join("\n")]")
+ sleep(0) //yes, 0, this'll let Reboot finish and prevent byond memes
+ del(src) //shut it down
diff --git a/code/modules/zombie/items.dm b/code/modules/zombie/items.dm
deleted file mode 100644
index 0f0f85b088b..00000000000
--- a/code/modules/zombie/items.dm
+++ /dev/null
@@ -1,69 +0,0 @@
-/obj/item/zombie_hand
- name = "zombie claw"
- desc = "A zombie's claw is its primary tool, capable of infecting \
- unconscious or dead humans, butchering all other living things to \
- sustain the zombie, forcing open airlock doors and opening \
- child-safe caps on bottles."
- flags = NODROP|ABSTRACT|DROPDEL
- resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
- icon = 'icons/effects/blood.dmi'
- icon_state = "bloodhand_left"
- var/icon_left = "bloodhand_left"
- var/icon_right = "bloodhand_right"
- hitsound = 'sound/hallucinations/growl1.ogg'
- force = 21 // Just enough to break airlocks with melee attacks
- damtype = "brute"
-
-/obj/item/zombie_hand/equipped(mob/user, slot)
- . = ..()
- switch(slot)
- // Yes, these intentionally don't match
- if(slot_l_hand)
- icon_state = icon_right
- if(slot_r_hand)
- icon_state = icon_left
-
-/obj/item/zombie_hand/afterattack(atom/target, mob/user, proximity_flag)
- . = ..()
- if(!proximity_flag)
- return
-
- else if(isliving(target))
- if(ishuman(target))
- try_to_zombie_infect(target)
- else
- check_feast(target, user)
-
-/proc/try_to_zombie_infect(mob/living/carbon/human/target)
- CHECK_DNA_AND_SPECIES(target)
-
- if(NOZOMBIE in target.dna.species.species_traits)
- // cannot infect any NOZOMBIE subspecies (such as high functioning
- // zombies)
- return
-
- var/obj/item/organ/internal/zombie_infection/infection
- infection = target.get_organ_slot("zombie_infection")
- if(!infection)
- infection = new()
- infection.insert(target)
-
-/obj/item/zombie_hand/proc/check_feast(mob/living/target, mob/living/user)
- if(target.stat == DEAD)
- var/hp_gained = target.maxHealth
- target.gib()
- user.adjustBruteLoss(-hp_gained, FALSE)
- user.adjustToxLoss(-hp_gained, FALSE)
- user.adjustFireLoss(-hp_gained, FALSE)
- user.adjustCloneLoss(-hp_gained, FALSE)
- user.adjustBrainLoss(-hp_gained, FALSE) // Zom Bee gibbers "BRAAAAISNSs!1!"
- user.updatehealth()
-
-/obj/item/zombie_hand/suicide_act(mob/living/carbon/human/user)
- user.visible_message("[user] is ripping [user.p_their()] brains out! It looks like [user.p_theyre()] trying to commit suicide!")
- if(ishuman(user))
- var/mob/living/carbon/human/L = user
- var/obj/item/organ/external/O = L.get_organ("head")
- if(O)
- O.droplimb()
- return (BRUTELOSS)
diff --git a/code/modules/zombie/organs.dm b/code/modules/zombie/organs.dm
deleted file mode 100644
index 6ea40c90e96..00000000000
--- a/code/modules/zombie/organs.dm
+++ /dev/null
@@ -1,99 +0,0 @@
-/obj/item/organ/internal/zombie_infection
- name = "festering ooze"
- desc = "A black web of pus and viscera."
- parent_organ = "head"
- slot = "zombie_infection"
- icon_state = "blacktumor"
- var/causes_damage = TRUE
- var/datum/species/old_species = /datum/species/human
- var/living_transformation_time = 30
- var/converts_living = FALSE
-
- var/revive_time_min = 450
- var/revive_time_max = 700
- var/timer_id
-
-/obj/item/organ/internal/zombie_infection/New(mob/living/carbon/holder)
- ..()
- GLOB.zombie_infection_list += src
-
-/obj/item/organ/internal/zombie_infection/Destroy()
- GLOB.zombie_infection_list -= src
- . = ..()
-
-/obj/item/organ/internal/zombie_infection/insert(mob/living/carbon/human/M, special = 0)
- ..()
- START_PROCESSING(SSobj, src)
-
-/obj/item/organ/internal/zombie_infection/remove(mob/living/carbon/human/M, special = 0)
- STOP_PROCESSING(SSobj, src)
- if(iszombie(M) && old_species)
- M.set_species(old_species, retain_damage = TRUE)
- if(timer_id)
- deltimer(timer_id)
- . = ..()
-
-/obj/item/organ/internal/zombie_infection/on_find(mob/living/finder)
- to_chat(finder, "Inside the head is a disgusting black \
- web of pus and viscera, bound tightly around the brain like some \
- biological harness.")
-
-/obj/item/organ/internal/zombie_infection/process()
- if(!owner)
- return
- if(!(src in owner.internal_organs))
- remove(owner)
- if(causes_damage && !iszombie(owner) && owner.stat != DEAD)
- owner.adjustToxLoss(1)
- if (prob(10))
- to_chat(owner, "You feel sick...")
- if(timer_id)
- return
- if(owner.suiciding)
- return
- if(owner.stat != DEAD && !converts_living)
- return
- if(!owner.get_int_organ(/obj/item/organ/internal/brain))
- return
- if(!iszombie(owner))
- to_chat(owner, "You can feel your heart stopping, but something isn't right... \
- life has not abandoned your broken form. You can only feel a deep and immutable hunger that \
- not even death can stop, you will rise again!")
- var/revive_time = rand(revive_time_min, revive_time_max)
- var/flags = TIMER_STOPPABLE
- timer_id = addtimer(CALLBACK(src, .proc/zombify), revive_time, flags)
-
-/obj/item/organ/internal/zombie_infection/proc/zombify()
- timer_id = null
-
- if(!converts_living && owner.stat != DEAD)
- return
-
- if(!iszombie(owner))
- old_species = owner.dna.species.type
- owner.set_species(/datum/species/zombie/infectious)
- for(var/datum/disease/critical/crit in owner.viruses) // cure any new crit viruses
- crit.cure(0)
-
- var/stand_up = (owner.stat == DEAD) || (owner.stat == UNCONSCIOUS)
- //Fully heal the zombie's damage the first time they rise
- owner.setToxLoss(0)
- owner.setOxyLoss(0)
- owner.setBrainLoss(0)
- owner.setCloneLoss(0)
- owner.SetLoseBreath(0)
- owner.heal_overall_damage(INFINITY, INFINITY, TRUE, TRUE, FALSE)
- owner.setStaminaLoss(0)
-
- if(!owner.update_revive())
- return
-
- owner.grab_ghost()
- owner.visible_message("[owner] suddenly convulses, as [owner.p_they()][stand_up ? " stagger to [owner.p_their()] feet and" : ""] gain a ravenous hunger in [owner.p_their()] eyes!", "You HUNGER!")
- playsound(owner.loc, 'sound/hallucinations/far_noise.ogg', 50, TRUE)
- owner.do_jitter_animation(living_transformation_time)
- owner.Stun(living_transformation_time * 0.05)
- to_chat(owner, "You are now a zombie! Do not seek to be cured, do not help any non-zombies in any way, do not harm your zombie brethren and spread the disease by killing others. You are a creature of hunger and violence.")
-
-/obj/item/organ/internal/zombie_infection/nodamage
- causes_damage = FALSE
diff --git a/html/font-awesome/README.MD b/html/font-awesome/README.MD
new file mode 100644
index 00000000000..7d693c36f03
--- /dev/null
+++ b/html/font-awesome/README.MD
@@ -0,0 +1,6 @@
+Due to the fact browse_rsc can't create subdirectories, every time you update font-awesome you'll need to change relative webfont references in all.min.css
+eg ../webfonts/fa-regular-400.ttf => fa-regular-400.ttf (or whatever you call it in asset datum)
+
+Second change is ripping out file types other than woff and eot(ie8) from the css
+
+Finally, removing brand related css.
\ No newline at end of file
diff --git a/html/font-awesome/css/all.min.css b/html/font-awesome/css/all.min.css
new file mode 100644
index 00000000000..e7cdfffe751
--- /dev/null
+++ b/html/font-awesome/css/all.min.css
@@ -0,0 +1,5 @@
+/*!
+ * Font Awesome Free 5.9.0 by @fontawesome - https://fontawesome.com
+ * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
+ */
+.fa,.fab,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{animation:fa-spin 2s infinite linear}.fa-pulse{animation:fa-spin 1s infinite steps(8)}@keyframes fa-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";transform:scaleX(-1)}.fa-flip-vertical{transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:"\f26e"}.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-acquisitions-incorporated:before{content:"\f6af"}.fa-ad:before{content:"\f641"}.fa-address-book:before{content:"\f2b9"}.fa-address-card:before{content:"\f2bb"}.fa-adjust:before{content:"\f042"}.fa-adn:before{content:"\f170"}.fa-adobe:before{content:"\f778"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-air-freshener:before{content:"\f5d0"}.fa-airbnb:before{content:"\f834"}.fa-algolia:before{content:"\f36c"}.fa-align-center:before{content:"\f037"}.fa-align-justify:before{content:"\f039"}.fa-align-left:before{content:"\f036"}.fa-align-right:before{content:"\f038"}.fa-alipay:before{content:"\f642"}.fa-allergies:before{content:"\f461"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-ambulance:before{content:"\f0f9"}.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-amilia:before{content:"\f36d"}.fa-anchor:before{content:"\f13d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-down:before{content:"\f107"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angry:before{content:"\f556"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-ankh:before{content:"\f644"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-alt:before{content:"\f5d1"}.fa-apple-pay:before{content:"\f415"}.fa-archive:before{content:"\f187"}.fa-archway:before{content:"\f557"}.fa-arrow-alt-circle-down:before{content:"\f358"}.fa-arrow-alt-circle-left:before{content:"\f359"}.fa-arrow-alt-circle-right:before{content:"\f35a"}.fa-arrow-alt-circle-up:before{content:"\f35b"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-down:before{content:"\f063"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrows-alt:before{content:"\f0b2"}.fa-arrows-alt-h:before{content:"\f337"}.fa-arrows-alt-v:before{content:"\f338"}.fa-artstation:before{content:"\f77a"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asterisk:before{content:"\f069"}.fa-asymmetrik:before{content:"\f372"}.fa-at:before{content:"\f1fa"}.fa-atlas:before{content:"\f558"}.fa-atlassian:before{content:"\f77b"}.fa-atom:before{content:"\f5d2"}.fa-audible:before{content:"\f373"}.fa-audio-description:before{content:"\f29e"}.fa-autoprefixer:before{content:"\f41c"}.fa-avianex:before{content:"\f374"}.fa-aviato:before{content:"\f421"}.fa-award:before{content:"\f559"}.fa-aws:before{content:"\f375"}.fa-baby:before{content:"\f77c"}.fa-baby-carriage:before{content:"\f77d"}.fa-backspace:before{content:"\f55a"}.fa-backward:before{content:"\f04a"}.fa-bacon:before{content:"\f7e5"}.fa-balance-scale:before{content:"\f24e"}.fa-balance-scale-left:before{content:"\f515"}.fa-balance-scale-right:before{content:"\f516"}.fa-ban:before{content:"\f05e"}.fa-band-aid:before{content:"\f462"}.fa-bandcamp:before{content:"\f2d5"}.fa-barcode:before{content:"\f02a"}.fa-bars:before{content:"\f0c9"}.fa-baseball-ball:before{content:"\f433"}.fa-basketball-ball:before{content:"\f434"}.fa-bath:before{content:"\f2cd"}.fa-battery-empty:before{content:"\f244"}.fa-battery-full:before{content:"\f240"}.fa-battery-half:before{content:"\f242"}.fa-battery-quarter:before{content:"\f243"}.fa-battery-three-quarters:before{content:"\f241"}.fa-battle-net:before{content:"\f835"}.fa-bed:before{content:"\f236"}.fa-beer:before{content:"\f0fc"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-bell:before{content:"\f0f3"}.fa-bell-slash:before{content:"\f1f6"}.fa-bezier-curve:before{content:"\f55b"}.fa-bible:before{content:"\f647"}.fa-bicycle:before{content:"\f206"}.fa-biking:before{content:"\f84a"}.fa-bimobject:before{content:"\f378"}.fa-binoculars:before{content:"\f1e5"}.fa-biohazard:before{content:"\f780"}.fa-birthday-cake:before{content:"\f1fd"}.fa-bitbucket:before{content:"\f171"}.fa-bitcoin:before{content:"\f379"}.fa-bity:before{content:"\f37a"}.fa-black-tie:before{content:"\f27e"}.fa-blackberry:before{content:"\f37b"}.fa-blender:before{content:"\f517"}.fa-blender-phone:before{content:"\f6b6"}.fa-blind:before{content:"\f29d"}.fa-blog:before{content:"\f781"}.fa-blogger:before{content:"\f37c"}.fa-blogger-b:before{content:"\f37d"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-bold:before{content:"\f032"}.fa-bolt:before{content:"\f0e7"}.fa-bomb:before{content:"\f1e2"}.fa-bone:before{content:"\f5d7"}.fa-bong:before{content:"\f55c"}.fa-book:before{content:"\f02d"}.fa-book-dead:before{content:"\f6b7"}.fa-book-medical:before{content:"\f7e6"}.fa-book-open:before{content:"\f518"}.fa-book-reader:before{content:"\f5da"}.fa-bookmark:before{content:"\f02e"}.fa-bootstrap:before{content:"\f836"}.fa-border-all:before{content:"\f84c"}.fa-border-none:before{content:"\f850"}.fa-border-style:before{content:"\f853"}.fa-bowling-ball:before{content:"\f436"}.fa-box:before{content:"\f466"}.fa-box-open:before{content:"\f49e"}.fa-boxes:before{content:"\f468"}.fa-braille:before{content:"\f2a1"}.fa-brain:before{content:"\f5dc"}.fa-bread-slice:before{content:"\f7ec"}.fa-briefcase:before{content:"\f0b1"}.fa-briefcase-medical:before{content:"\f469"}.fa-broadcast-tower:before{content:"\f519"}.fa-broom:before{content:"\f51a"}.fa-brush:before{content:"\f55d"}.fa-btc:before{content:"\f15a"}.fa-buffer:before{content:"\f837"}.fa-bug:before{content:"\f188"}.fa-building:before{content:"\f1ad"}.fa-bullhorn:before{content:"\f0a1"}.fa-bullseye:before{content:"\f140"}.fa-burn:before{content:"\f46a"}.fa-buromobelexperte:before{content:"\f37f"}.fa-bus:before{content:"\f207"}.fa-bus-alt:before{content:"\f55e"}.fa-business-time:before{content:"\f64a"}.fa-buysellads:before{content:"\f20d"}.fa-calculator:before{content:"\f1ec"}.fa-calendar:before{content:"\f133"}.fa-calendar-alt:before{content:"\f073"}.fa-calendar-check:before{content:"\f274"}.fa-calendar-day:before{content:"\f783"}.fa-calendar-minus:before{content:"\f272"}.fa-calendar-plus:before{content:"\f271"}.fa-calendar-times:before{content:"\f273"}.fa-calendar-week:before{content:"\f784"}.fa-camera:before{content:"\f030"}.fa-camera-retro:before{content:"\f083"}.fa-campground:before{content:"\f6bb"}.fa-canadian-maple-leaf:before{content:"\f785"}.fa-candy-cane:before{content:"\f786"}.fa-cannabis:before{content:"\f55f"}.fa-capsules:before{content:"\f46b"}.fa-car:before{content:"\f1b9"}.fa-car-alt:before{content:"\f5de"}.fa-car-battery:before{content:"\f5df"}.fa-car-crash:before{content:"\f5e1"}.fa-car-side:before{content:"\f5e4"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-caret-square-down:before{content:"\f150"}.fa-caret-square-left:before{content:"\f191"}.fa-caret-square-right:before{content:"\f152"}.fa-caret-square-up:before{content:"\f151"}.fa-caret-up:before{content:"\f0d8"}.fa-carrot:before{content:"\f787"}.fa-cart-arrow-down:before{content:"\f218"}.fa-cart-plus:before{content:"\f217"}.fa-cash-register:before{content:"\f788"}.fa-cat:before{content:"\f6be"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-apple-pay:before{content:"\f416"}.fa-cc-diners-club:before{content:"\f24c"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-cc-visa:before{content:"\f1f0"}.fa-centercode:before{content:"\f380"}.fa-centos:before{content:"\f789"}.fa-certificate:before{content:"\f0a3"}.fa-chair:before{content:"\f6c0"}.fa-chalkboard:before{content:"\f51b"}.fa-chalkboard-teacher:before{content:"\f51c"}.fa-charging-station:before{content:"\f5e7"}.fa-chart-area:before{content:"\f1fe"}.fa-chart-bar:before{content:"\f080"}.fa-chart-line:before{content:"\f201"}.fa-chart-pie:before{content:"\f200"}.fa-check:before{content:"\f00c"}.fa-check-circle:before{content:"\f058"}.fa-check-double:before{content:"\f560"}.fa-check-square:before{content:"\f14a"}.fa-cheese:before{content:"\f7ef"}.fa-chess:before{content:"\f439"}.fa-chess-bishop:before{content:"\f43a"}.fa-chess-board:before{content:"\f43c"}.fa-chess-king:before{content:"\f43f"}.fa-chess-knight:before{content:"\f441"}.fa-chess-pawn:before{content:"\f443"}.fa-chess-queen:before{content:"\f445"}.fa-chess-rook:before{content:"\f447"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-down:before{content:"\f078"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-chevron-up:before{content:"\f077"}.fa-child:before{content:"\f1ae"}.fa-chrome:before{content:"\f268"}.fa-chromecast:before{content:"\f838"}.fa-church:before{content:"\f51d"}.fa-circle:before{content:"\f111"}.fa-circle-notch:before{content:"\f1ce"}.fa-city:before{content:"\f64f"}.fa-clinic-medical:before{content:"\f7f2"}.fa-clipboard:before{content:"\f328"}.fa-clipboard-check:before{content:"\f46c"}.fa-clipboard-list:before{content:"\f46d"}.fa-clock:before{content:"\f017"}.fa-clone:before{content:"\f24d"}.fa-closed-captioning:before{content:"\f20a"}.fa-cloud:before{content:"\f0c2"}.fa-cloud-download-alt:before{content:"\f381"}.fa-cloud-meatball:before{content:"\f73b"}.fa-cloud-moon:before{content:"\f6c3"}.fa-cloud-moon-rain:before{content:"\f73c"}.fa-cloud-rain:before{content:"\f73d"}.fa-cloud-showers-heavy:before{content:"\f740"}.fa-cloud-sun:before{content:"\f6c4"}.fa-cloud-sun-rain:before{content:"\f743"}.fa-cloud-upload-alt:before{content:"\f382"}.fa-cloudscale:before{content:"\f383"}.fa-cloudsmith:before{content:"\f384"}.fa-cloudversify:before{content:"\f385"}.fa-cocktail:before{content:"\f561"}.fa-code:before{content:"\f121"}.fa-code-branch:before{content:"\f126"}.fa-codepen:before{content:"\f1cb"}.fa-codiepie:before{content:"\f284"}.fa-coffee:before{content:"\f0f4"}.fa-cog:before{content:"\f013"}.fa-cogs:before{content:"\f085"}.fa-coins:before{content:"\f51e"}.fa-columns:before{content:"\f0db"}.fa-comment:before{content:"\f075"}.fa-comment-alt:before{content:"\f27a"}.fa-comment-dollar:before{content:"\f651"}.fa-comment-dots:before{content:"\f4ad"}.fa-comment-medical:before{content:"\f7f5"}.fa-comment-slash:before{content:"\f4b3"}.fa-comments:before{content:"\f086"}.fa-comments-dollar:before{content:"\f653"}.fa-compact-disc:before{content:"\f51f"}.fa-compass:before{content:"\f14e"}.fa-compress:before{content:"\f066"}.fa-compress-arrows-alt:before{content:"\f78c"}.fa-concierge-bell:before{content:"\f562"}.fa-confluence:before{content:"\f78d"}.fa-connectdevelop:before{content:"\f20e"}.fa-contao:before{content:"\f26d"}.fa-cookie:before{content:"\f563"}.fa-cookie-bite:before{content:"\f564"}.fa-copy:before{content:"\f0c5"}.fa-copyright:before{content:"\f1f9"}.fa-couch:before{content:"\f4b8"}.fa-cpanel:before{content:"\f388"}.fa-creative-commons:before{content:"\f25e"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-creative-commons-zero:before{content:"\f4f3"}.fa-credit-card:before{content:"\f09d"}.fa-critical-role:before{content:"\f6c9"}.fa-crop:before{content:"\f125"}.fa-crop-alt:before{content:"\f565"}.fa-cross:before{content:"\f654"}.fa-crosshairs:before{content:"\f05b"}.fa-crow:before{content:"\f520"}.fa-crown:before{content:"\f521"}.fa-crutch:before{content:"\f7f7"}.fa-css3:before{content:"\f13c"}.fa-css3-alt:before{content:"\f38b"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-cut:before{content:"\f0c4"}.fa-cuttlefish:before{content:"\f38c"}.fa-d-and-d:before{content:"\f38d"}.fa-d-and-d-beyond:before{content:"\f6ca"}.fa-dashcube:before{content:"\f210"}.fa-database:before{content:"\f1c0"}.fa-deaf:before{content:"\f2a4"}.fa-delicious:before{content:"\f1a5"}.fa-democrat:before{content:"\f747"}.fa-deploydog:before{content:"\f38e"}.fa-deskpro:before{content:"\f38f"}.fa-desktop:before{content:"\f108"}.fa-dev:before{content:"\f6cc"}.fa-deviantart:before{content:"\f1bd"}.fa-dharmachakra:before{content:"\f655"}.fa-dhl:before{content:"\f790"}.fa-diagnoses:before{content:"\f470"}.fa-diaspora:before{content:"\f791"}.fa-dice:before{content:"\f522"}.fa-dice-d20:before{content:"\f6cf"}.fa-dice-d6:before{content:"\f6d1"}.fa-dice-five:before{content:"\f523"}.fa-dice-four:before{content:"\f524"}.fa-dice-one:before{content:"\f525"}.fa-dice-six:before{content:"\f526"}.fa-dice-three:before{content:"\f527"}.fa-dice-two:before{content:"\f528"}.fa-digg:before{content:"\f1a6"}.fa-digital-ocean:before{content:"\f391"}.fa-digital-tachograph:before{content:"\f566"}.fa-directions:before{content:"\f5eb"}.fa-discord:before{content:"\f392"}.fa-discourse:before{content:"\f393"}.fa-divide:before{content:"\f529"}.fa-dizzy:before{content:"\f567"}.fa-dna:before{content:"\f471"}.fa-dochub:before{content:"\f394"}.fa-docker:before{content:"\f395"}.fa-dog:before{content:"\f6d3"}.fa-dollar-sign:before{content:"\f155"}.fa-dolly:before{content:"\f472"}.fa-dolly-flatbed:before{content:"\f474"}.fa-donate:before{content:"\f4b9"}.fa-door-closed:before{content:"\f52a"}.fa-door-open:before{content:"\f52b"}.fa-dot-circle:before{content:"\f192"}.fa-dove:before{content:"\f4ba"}.fa-download:before{content:"\f019"}.fa-draft2digital:before{content:"\f396"}.fa-drafting-compass:before{content:"\f568"}.fa-dragon:before{content:"\f6d5"}.fa-draw-polygon:before{content:"\f5ee"}.fa-dribbble:before{content:"\f17d"}.fa-dribbble-square:before{content:"\f397"}.fa-dropbox:before{content:"\f16b"}.fa-drum:before{content:"\f569"}.fa-drum-steelpan:before{content:"\f56a"}.fa-drumstick-bite:before{content:"\f6d7"}.fa-drupal:before{content:"\f1a9"}.fa-dumbbell:before{content:"\f44b"}.fa-dumpster:before{content:"\f793"}.fa-dumpster-fire:before{content:"\f794"}.fa-dungeon:before{content:"\f6d9"}.fa-dyalog:before{content:"\f399"}.fa-earlybirds:before{content:"\f39a"}.fa-ebay:before{content:"\f4f4"}.fa-edge:before{content:"\f282"}.fa-edit:before{content:"\f044"}.fa-egg:before{content:"\f7fb"}.fa-eject:before{content:"\f052"}.fa-elementor:before{content:"\f430"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-ello:before{content:"\f5f1"}.fa-ember:before{content:"\f423"}.fa-empire:before{content:"\f1d1"}.fa-envelope:before{content:"\f0e0"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-text:before{content:"\f658"}.fa-envelope-square:before{content:"\f199"}.fa-envira:before{content:"\f299"}.fa-equals:before{content:"\f52c"}.fa-eraser:before{content:"\f12d"}.fa-erlang:before{content:"\f39d"}.fa-ethereum:before{content:"\f42e"}.fa-ethernet:before{content:"\f796"}.fa-etsy:before{content:"\f2d7"}.fa-euro-sign:before{content:"\f153"}.fa-evernote:before{content:"\f839"}.fa-exchange-alt:before{content:"\f362"}.fa-exclamation:before{content:"\f12a"}.fa-exclamation-circle:before{content:"\f06a"}.fa-exclamation-triangle:before{content:"\f071"}.fa-expand:before{content:"\f065"}.fa-expand-arrows-alt:before{content:"\f31e"}.fa-expeditedssl:before{content:"\f23e"}.fa-external-link-alt:before{content:"\f35d"}.fa-external-link-square-alt:before{content:"\f360"}.fa-eye:before{content:"\f06e"}.fa-eye-dropper:before{content:"\f1fb"}.fa-eye-slash:before{content:"\f070"}.fa-facebook:before{content:"\f09a"}.fa-facebook-f:before{content:"\f39e"}.fa-facebook-messenger:before{content:"\f39f"}.fa-facebook-square:before{content:"\f082"}.fa-fan:before{content:"\f863"}.fa-fantasy-flight-games:before{content:"\f6dc"}.fa-fast-backward:before{content:"\f049"}.fa-fast-forward:before{content:"\f050"}.fa-fax:before{content:"\f1ac"}.fa-feather:before{content:"\f52d"}.fa-feather-alt:before{content:"\f56b"}.fa-fedex:before{content:"\f797"}.fa-fedora:before{content:"\f798"}.fa-female:before{content:"\f182"}.fa-fighter-jet:before{content:"\f0fb"}.fa-figma:before{content:"\f799"}.fa-file:before{content:"\f15b"}.fa-file-alt:before{content:"\f15c"}.fa-file-archive:before{content:"\f1c6"}.fa-file-audio:before{content:"\f1c7"}.fa-file-code:before{content:"\f1c9"}.fa-file-contract:before{content:"\f56c"}.fa-file-csv:before{content:"\f6dd"}.fa-file-download:before{content:"\f56d"}.fa-file-excel:before{content:"\f1c3"}.fa-file-export:before{content:"\f56e"}.fa-file-image:before{content:"\f1c5"}.fa-file-import:before{content:"\f56f"}.fa-file-invoice:before{content:"\f570"}.fa-file-invoice-dollar:before{content:"\f571"}.fa-file-medical:before{content:"\f477"}.fa-file-medical-alt:before{content:"\f478"}.fa-file-pdf:before{content:"\f1c1"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-file-prescription:before{content:"\f572"}.fa-file-signature:before{content:"\f573"}.fa-file-upload:before{content:"\f574"}.fa-file-video:before{content:"\f1c8"}.fa-file-word:before{content:"\f1c2"}.fa-fill:before{content:"\f575"}.fa-fill-drip:before{content:"\f576"}.fa-film:before{content:"\f008"}.fa-filter:before{content:"\f0b0"}.fa-fingerprint:before{content:"\f577"}.fa-fire:before{content:"\f06d"}.fa-fire-alt:before{content:"\f7e4"}.fa-fire-extinguisher:before{content:"\f134"}.fa-firefox:before{content:"\f269"}.fa-first-aid:before{content:"\f479"}.fa-first-order:before{content:"\f2b0"}.fa-first-order-alt:before{content:"\f50a"}.fa-firstdraft:before{content:"\f3a1"}.fa-fish:before{content:"\f578"}.fa-fist-raised:before{content:"\f6de"}.fa-flag:before{content:"\f024"}.fa-flag-checkered:before{content:"\f11e"}.fa-flag-usa:before{content:"\f74d"}.fa-flask:before{content:"\f0c3"}.fa-flickr:before{content:"\f16e"}.fa-flipboard:before{content:"\f44d"}.fa-flushed:before{content:"\f579"}.fa-fly:before{content:"\f417"}.fa-folder:before{content:"\f07b"}.fa-folder-minus:before{content:"\f65d"}.fa-folder-open:before{content:"\f07c"}.fa-folder-plus:before{content:"\f65e"}.fa-font:before{content:"\f031"}.fa-font-awesome:before{content:"\f2b4"}.fa-font-awesome-alt:before{content:"\f35c"}.fa-font-awesome-flag:before{content:"\f425"}.fa-font-awesome-logo-full:before{content:"\f4e6"}.fa-fonticons:before{content:"\f280"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-football-ball:before{content:"\f44e"}.fa-fort-awesome:before{content:"\f286"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-forumbee:before{content:"\f211"}.fa-forward:before{content:"\f04e"}.fa-foursquare:before{content:"\f180"}.fa-free-code-camp:before{content:"\f2c5"}.fa-freebsd:before{content:"\f3a4"}.fa-frog:before{content:"\f52e"}.fa-frown:before{content:"\f119"}.fa-frown-open:before{content:"\f57a"}.fa-fulcrum:before{content:"\f50b"}.fa-funnel-dollar:before{content:"\f662"}.fa-futbol:before{content:"\f1e3"}.fa-galactic-republic:before{content:"\f50c"}.fa-galactic-senate:before{content:"\f50d"}.fa-gamepad:before{content:"\f11b"}.fa-gas-pump:before{content:"\f52f"}.fa-gavel:before{content:"\f0e3"}.fa-gem:before{content:"\f3a5"}.fa-genderless:before{content:"\f22d"}.fa-get-pocket:before{content:"\f265"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-ghost:before{content:"\f6e2"}.fa-gift:before{content:"\f06b"}.fa-gifts:before{content:"\f79c"}.fa-git:before{content:"\f1d3"}.fa-git-alt:before{content:"\f841"}.fa-git-square:before{content:"\f1d2"}.fa-github:before{content:"\f09b"}.fa-github-alt:before{content:"\f113"}.fa-github-square:before{content:"\f092"}.fa-gitkraken:before{content:"\f3a6"}.fa-gitlab:before{content:"\f296"}.fa-gitter:before{content:"\f426"}.fa-glass-cheers:before{content:"\f79f"}.fa-glass-martini:before{content:"\f000"}.fa-glass-martini-alt:before{content:"\f57b"}.fa-glass-whiskey:before{content:"\f7a0"}.fa-glasses:before{content:"\f530"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-globe:before{content:"\f0ac"}.fa-globe-africa:before{content:"\f57c"}.fa-globe-americas:before{content:"\f57d"}.fa-globe-asia:before{content:"\f57e"}.fa-globe-europe:before{content:"\f7a2"}.fa-gofore:before{content:"\f3a7"}.fa-golf-ball:before{content:"\f450"}.fa-goodreads:before{content:"\f3a8"}.fa-goodreads-g:before{content:"\f3a9"}.fa-google:before{content:"\f1a0"}.fa-google-drive:before{content:"\f3aa"}.fa-google-play:before{content:"\f3ab"}.fa-google-plus:before{content:"\f2b3"}.fa-google-plus-g:before{content:"\f0d5"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-wallet:before{content:"\f1ee"}.fa-gopuram:before{content:"\f664"}.fa-graduation-cap:before{content:"\f19d"}.fa-gratipay:before{content:"\f184"}.fa-grav:before{content:"\f2d6"}.fa-greater-than:before{content:"\f531"}.fa-greater-than-equal:before{content:"\f532"}.fa-grimace:before{content:"\f57f"}.fa-grin:before{content:"\f580"}.fa-grin-alt:before{content:"\f581"}.fa-grin-beam:before{content:"\f582"}.fa-grin-beam-sweat:before{content:"\f583"}.fa-grin-hearts:before{content:"\f584"}.fa-grin-squint:before{content:"\f585"}.fa-grin-squint-tears:before{content:"\f586"}.fa-grin-stars:before{content:"\f587"}.fa-grin-tears:before{content:"\f588"}.fa-grin-tongue:before{content:"\f589"}.fa-grin-tongue-squint:before{content:"\f58a"}.fa-grin-tongue-wink:before{content:"\f58b"}.fa-grin-wink:before{content:"\f58c"}.fa-grip-horizontal:before{content:"\f58d"}.fa-grip-lines:before{content:"\f7a4"}.fa-grip-lines-vertical:before{content:"\f7a5"}.fa-grip-vertical:before{content:"\f58e"}.fa-gripfire:before{content:"\f3ac"}.fa-grunt:before{content:"\f3ad"}.fa-guitar:before{content:"\f7a6"}.fa-gulp:before{content:"\f3ae"}.fa-h-square:before{content:"\f0fd"}.fa-hacker-news:before{content:"\f1d4"}.fa-hacker-news-square:before{content:"\f3af"}.fa-hackerrank:before{content:"\f5f7"}.fa-hamburger:before{content:"\f805"}.fa-hammer:before{content:"\f6e3"}.fa-hamsa:before{content:"\f665"}.fa-hand-holding:before{content:"\f4bd"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-hand-holding-usd:before{content:"\f4c0"}.fa-hand-lizard:before{content:"\f258"}.fa-hand-middle-finger:before{content:"\f806"}.fa-hand-paper:before{content:"\f256"}.fa-hand-peace:before{content:"\f25b"}.fa-hand-point-down:before{content:"\f0a7"}.fa-hand-point-left:before{content:"\f0a5"}.fa-hand-point-right:before{content:"\f0a4"}.fa-hand-point-up:before{content:"\f0a6"}.fa-hand-pointer:before{content:"\f25a"}.fa-hand-rock:before{content:"\f255"}.fa-hand-scissors:before{content:"\f257"}.fa-hand-spock:before{content:"\f259"}.fa-hands:before{content:"\f4c2"}.fa-hands-helping:before{content:"\f4c4"}.fa-handshake:before{content:"\f2b5"}.fa-hanukiah:before{content:"\f6e6"}.fa-hard-hat:before{content:"\f807"}.fa-hashtag:before{content:"\f292"}.fa-hat-wizard:before{content:"\f6e8"}.fa-haykal:before{content:"\f666"}.fa-hdd:before{content:"\f0a0"}.fa-heading:before{content:"\f1dc"}.fa-headphones:before{content:"\f025"}.fa-headphones-alt:before{content:"\f58f"}.fa-headset:before{content:"\f590"}.fa-heart:before{content:"\f004"}.fa-heart-broken:before{content:"\f7a9"}.fa-heartbeat:before{content:"\f21e"}.fa-helicopter:before{content:"\f533"}.fa-highlighter:before{content:"\f591"}.fa-hiking:before{content:"\f6ec"}.fa-hippo:before{content:"\f6ed"}.fa-hips:before{content:"\f452"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-history:before{content:"\f1da"}.fa-hockey-puck:before{content:"\f453"}.fa-holly-berry:before{content:"\f7aa"}.fa-home:before{content:"\f015"}.fa-hooli:before{content:"\f427"}.fa-hornbill:before{content:"\f592"}.fa-horse:before{content:"\f6f0"}.fa-horse-head:before{content:"\f7ab"}.fa-hospital:before{content:"\f0f8"}.fa-hospital-alt:before{content:"\f47d"}.fa-hospital-symbol:before{content:"\f47e"}.fa-hot-tub:before{content:"\f593"}.fa-hotdog:before{content:"\f80f"}.fa-hotel:before{content:"\f594"}.fa-hotjar:before{content:"\f3b1"}.fa-hourglass:before{content:"\f254"}.fa-hourglass-end:before{content:"\f253"}.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-start:before{content:"\f251"}.fa-house-damage:before{content:"\f6f1"}.fa-houzz:before{content:"\f27c"}.fa-hryvnia:before{content:"\f6f2"}.fa-html5:before{content:"\f13b"}.fa-hubspot:before{content:"\f3b2"}.fa-i-cursor:before{content:"\f246"}.fa-ice-cream:before{content:"\f810"}.fa-icicles:before{content:"\f7ad"}.fa-icons:before{content:"\f86d"}.fa-id-badge:before{content:"\f2c1"}.fa-id-card:before{content:"\f2c2"}.fa-id-card-alt:before{content:"\f47f"}.fa-igloo:before{content:"\f7ae"}.fa-image:before{content:"\f03e"}.fa-images:before{content:"\f302"}.fa-imdb:before{content:"\f2d8"}.fa-inbox:before{content:"\f01c"}.fa-indent:before{content:"\f03c"}.fa-industry:before{content:"\f275"}.fa-infinity:before{content:"\f534"}.fa-info:before{content:"\f129"}.fa-info-circle:before{content:"\f05a"}.fa-instagram:before{content:"\f16d"}.fa-intercom:before{content:"\f7af"}.fa-internet-explorer:before{content:"\f26b"}.fa-invision:before{content:"\f7b0"}.fa-ioxhost:before{content:"\f208"}.fa-italic:before{content:"\f033"}.fa-itch-io:before{content:"\f83a"}.fa-itunes:before{content:"\f3b4"}.fa-itunes-note:before{content:"\f3b5"}.fa-java:before{content:"\f4e4"}.fa-jedi:before{content:"\f669"}.fa-jedi-order:before{content:"\f50e"}.fa-jenkins:before{content:"\f3b6"}.fa-jira:before{content:"\f7b1"}.fa-joget:before{content:"\f3b7"}.fa-joint:before{content:"\f595"}.fa-joomla:before{content:"\f1aa"}.fa-journal-whills:before{content:"\f66a"}.fa-js:before{content:"\f3b8"}.fa-js-square:before{content:"\f3b9"}.fa-jsfiddle:before{content:"\f1cc"}.fa-kaaba:before{content:"\f66b"}.fa-kaggle:before{content:"\f5fa"}.fa-key:before{content:"\f084"}.fa-keybase:before{content:"\f4f5"}.fa-keyboard:before{content:"\f11c"}.fa-keycdn:before{content:"\f3ba"}.fa-khanda:before{content:"\f66d"}.fa-kickstarter:before{content:"\f3bb"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-kiss:before{content:"\f596"}.fa-kiss-beam:before{content:"\f597"}.fa-kiss-wink-heart:before{content:"\f598"}.fa-kiwi-bird:before{content:"\f535"}.fa-korvue:before{content:"\f42f"}.fa-landmark:before{content:"\f66f"}.fa-language:before{content:"\f1ab"}.fa-laptop:before{content:"\f109"}.fa-laptop-code:before{content:"\f5fc"}.fa-laptop-medical:before{content:"\f812"}.fa-laravel:before{content:"\f3bd"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-laugh:before{content:"\f599"}.fa-laugh-beam:before{content:"\f59a"}.fa-laugh-squint:before{content:"\f59b"}.fa-laugh-wink:before{content:"\f59c"}.fa-layer-group:before{content:"\f5fd"}.fa-leaf:before{content:"\f06c"}.fa-leanpub:before{content:"\f212"}.fa-lemon:before{content:"\f094"}.fa-less:before{content:"\f41d"}.fa-less-than:before{content:"\f536"}.fa-less-than-equal:before{content:"\f537"}.fa-level-down-alt:before{content:"\f3be"}.fa-level-up-alt:before{content:"\f3bf"}.fa-life-ring:before{content:"\f1cd"}.fa-lightbulb:before{content:"\f0eb"}.fa-line:before{content:"\f3c0"}.fa-link:before{content:"\f0c1"}.fa-linkedin:before{content:"\f08c"}.fa-linkedin-in:before{content:"\f0e1"}.fa-linode:before{content:"\f2b8"}.fa-linux:before{content:"\f17c"}.fa-lira-sign:before{content:"\f195"}.fa-list:before{content:"\f03a"}.fa-list-alt:before{content:"\f022"}.fa-list-ol:before{content:"\f0cb"}.fa-list-ul:before{content:"\f0ca"}.fa-location-arrow:before{content:"\f124"}.fa-lock:before{content:"\f023"}.fa-lock-open:before{content:"\f3c1"}.fa-long-arrow-alt-down:before{content:"\f309"}.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-long-arrow-alt-right:before{content:"\f30b"}.fa-long-arrow-alt-up:before{content:"\f30c"}.fa-low-vision:before{content:"\f2a8"}.fa-luggage-cart:before{content:"\f59d"}.fa-lyft:before{content:"\f3c3"}.fa-magento:before{content:"\f3c4"}.fa-magic:before{content:"\f0d0"}.fa-magnet:before{content:"\f076"}.fa-mail-bulk:before{content:"\f674"}.fa-mailchimp:before{content:"\f59e"}.fa-male:before{content:"\f183"}.fa-mandalorian:before{content:"\f50f"}.fa-map:before{content:"\f279"}.fa-map-marked:before{content:"\f59f"}.fa-map-marked-alt:before{content:"\f5a0"}.fa-map-marker:before{content:"\f041"}.fa-map-marker-alt:before{content:"\f3c5"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-markdown:before{content:"\f60f"}.fa-marker:before{content:"\f5a1"}.fa-mars:before{content:"\f222"}.fa-mars-double:before{content:"\f227"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mask:before{content:"\f6fa"}.fa-mastodon:before{content:"\f4f6"}.fa-maxcdn:before{content:"\f136"}.fa-medal:before{content:"\f5a2"}.fa-medapps:before{content:"\f3c6"}.fa-medium:before{content:"\f23a"}.fa-medium-m:before{content:"\f3c7"}.fa-medkit:before{content:"\f0fa"}.fa-medrt:before{content:"\f3c8"}.fa-meetup:before{content:"\f2e0"}.fa-megaport:before{content:"\f5a3"}.fa-meh:before{content:"\f11a"}.fa-meh-blank:before{content:"\f5a4"}.fa-meh-rolling-eyes:before{content:"\f5a5"}.fa-memory:before{content:"\f538"}.fa-mendeley:before{content:"\f7b3"}.fa-menorah:before{content:"\f676"}.fa-mercury:before{content:"\f223"}.fa-meteor:before{content:"\f753"}.fa-microchip:before{content:"\f2db"}.fa-microphone:before{content:"\f130"}.fa-microphone-alt:before{content:"\f3c9"}.fa-microphone-alt-slash:before{content:"\f539"}.fa-microphone-slash:before{content:"\f131"}.fa-microscope:before{content:"\f610"}.fa-microsoft:before{content:"\f3ca"}.fa-minus:before{content:"\f068"}.fa-minus-circle:before{content:"\f056"}.fa-minus-square:before{content:"\f146"}.fa-mitten:before{content:"\f7b5"}.fa-mix:before{content:"\f3cb"}.fa-mixcloud:before{content:"\f289"}.fa-mizuni:before{content:"\f3cc"}.fa-mobile:before{content:"\f10b"}.fa-mobile-alt:before{content:"\f3cd"}.fa-modx:before{content:"\f285"}.fa-monero:before{content:"\f3d0"}.fa-money-bill:before{content:"\f0d6"}.fa-money-bill-alt:before{content:"\f3d1"}.fa-money-bill-wave:before{content:"\f53a"}.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-money-check:before{content:"\f53c"}.fa-money-check-alt:before{content:"\f53d"}.fa-monument:before{content:"\f5a6"}.fa-moon:before{content:"\f186"}.fa-mortar-pestle:before{content:"\f5a7"}.fa-mosque:before{content:"\f678"}.fa-motorcycle:before{content:"\f21c"}.fa-mountain:before{content:"\f6fc"}.fa-mouse-pointer:before{content:"\f245"}.fa-mug-hot:before{content:"\f7b6"}.fa-music:before{content:"\f001"}.fa-napster:before{content:"\f3d2"}.fa-neos:before{content:"\f612"}.fa-network-wired:before{content:"\f6ff"}.fa-neuter:before{content:"\f22c"}.fa-newspaper:before{content:"\f1ea"}.fa-nimblr:before{content:"\f5a8"}.fa-node:before{content:"\f419"}.fa-node-js:before{content:"\f3d3"}.fa-not-equal:before{content:"\f53e"}.fa-notes-medical:before{content:"\f481"}.fa-npm:before{content:"\f3d4"}.fa-ns8:before{content:"\f3d5"}.fa-nutritionix:before{content:"\f3d6"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-oil-can:before{content:"\f613"}.fa-old-republic:before{content:"\f510"}.fa-om:before{content:"\f679"}.fa-opencart:before{content:"\f23d"}.fa-openid:before{content:"\f19b"}.fa-opera:before{content:"\f26a"}.fa-optin-monster:before{content:"\f23c"}.fa-osi:before{content:"\f41a"}.fa-otter:before{content:"\f700"}.fa-outdent:before{content:"\f03b"}.fa-page4:before{content:"\f3d7"}.fa-pagelines:before{content:"\f18c"}.fa-pager:before{content:"\f815"}.fa-paint-brush:before{content:"\f1fc"}.fa-paint-roller:before{content:"\f5aa"}.fa-palette:before{content:"\f53f"}.fa-palfed:before{content:"\f3d8"}.fa-pallet:before{content:"\f482"}.fa-paper-plane:before{content:"\f1d8"}.fa-paperclip:before{content:"\f0c6"}.fa-parachute-box:before{content:"\f4cd"}.fa-paragraph:before{content:"\f1dd"}.fa-parking:before{content:"\f540"}.fa-passport:before{content:"\f5ab"}.fa-pastafarianism:before{content:"\f67b"}.fa-paste:before{content:"\f0ea"}.fa-patreon:before{content:"\f3d9"}.fa-pause:before{content:"\f04c"}.fa-pause-circle:before{content:"\f28b"}.fa-paw:before{content:"\f1b0"}.fa-paypal:before{content:"\f1ed"}.fa-peace:before{content:"\f67c"}.fa-pen:before{content:"\f304"}.fa-pen-alt:before{content:"\f305"}.fa-pen-fancy:before{content:"\f5ac"}.fa-pen-nib:before{content:"\f5ad"}.fa-pen-square:before{content:"\f14b"}.fa-pencil-alt:before{content:"\f303"}.fa-pencil-ruler:before{content:"\f5ae"}.fa-penny-arcade:before{content:"\f704"}.fa-people-carry:before{content:"\f4ce"}.fa-pepper-hot:before{content:"\f816"}.fa-percent:before{content:"\f295"}.fa-percentage:before{content:"\f541"}.fa-periscope:before{content:"\f3da"}.fa-person-booth:before{content:"\f756"}.fa-phabricator:before{content:"\f3db"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-phoenix-squadron:before{content:"\f511"}.fa-phone:before{content:"\f095"}.fa-phone-alt:before{content:"\f879"}.fa-phone-slash:before{content:"\f3dd"}.fa-phone-square:before{content:"\f098"}.fa-phone-square-alt:before{content:"\f87b"}.fa-phone-volume:before{content:"\f2a0"}.fa-photo-video:before{content:"\f87c"}.fa-php:before{content:"\f457"}.fa-pied-piper:before{content:"\f2ae"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-piggy-bank:before{content:"\f4d3"}.fa-pills:before{content:"\f484"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-p:before{content:"\f231"}.fa-pinterest-square:before{content:"\f0d3"}.fa-pizza-slice:before{content:"\f818"}.fa-place-of-worship:before{content:"\f67f"}.fa-plane:before{content:"\f072"}.fa-plane-arrival:before{content:"\f5af"}.fa-plane-departure:before{content:"\f5b0"}.fa-play:before{content:"\f04b"}.fa-play-circle:before{content:"\f144"}.fa-playstation:before{content:"\f3df"}.fa-plug:before{content:"\f1e6"}.fa-plus:before{content:"\f067"}.fa-plus-circle:before{content:"\f055"}.fa-plus-square:before{content:"\f0fe"}.fa-podcast:before{content:"\f2ce"}.fa-poll:before{content:"\f681"}.fa-poll-h:before{content:"\f682"}.fa-poo:before{content:"\f2fe"}.fa-poo-storm:before{content:"\f75a"}.fa-poop:before{content:"\f619"}.fa-portrait:before{content:"\f3e0"}.fa-pound-sign:before{content:"\f154"}.fa-power-off:before{content:"\f011"}.fa-pray:before{content:"\f683"}.fa-praying-hands:before{content:"\f684"}.fa-prescription:before{content:"\f5b1"}.fa-prescription-bottle:before{content:"\f485"}.fa-prescription-bottle-alt:before{content:"\f486"}.fa-print:before{content:"\f02f"}.fa-procedures:before{content:"\f487"}.fa-product-hunt:before{content:"\f288"}.fa-project-diagram:before{content:"\f542"}.fa-pushed:before{content:"\f3e1"}.fa-puzzle-piece:before{content:"\f12e"}.fa-python:before{content:"\f3e2"}.fa-qq:before{content:"\f1d6"}.fa-qrcode:before{content:"\f029"}.fa-question:before{content:"\f128"}.fa-question-circle:before{content:"\f059"}.fa-quidditch:before{content:"\f458"}.fa-quinscape:before{content:"\f459"}.fa-quora:before{content:"\f2c4"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-quran:before{content:"\f687"}.fa-r-project:before{content:"\f4f7"}.fa-radiation:before{content:"\f7b9"}.fa-radiation-alt:before{content:"\f7ba"}.fa-rainbow:before{content:"\f75b"}.fa-random:before{content:"\f074"}.fa-raspberry-pi:before{content:"\f7bb"}.fa-ravelry:before{content:"\f2d9"}.fa-react:before{content:"\f41b"}.fa-reacteurope:before{content:"\f75d"}.fa-readme:before{content:"\f4d5"}.fa-rebel:before{content:"\f1d0"}.fa-receipt:before{content:"\f543"}.fa-recycle:before{content:"\f1b8"}.fa-red-river:before{content:"\f3e3"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-alien:before{content:"\f281"}.fa-reddit-square:before{content:"\f1a2"}.fa-redhat:before{content:"\f7bc"}.fa-redo:before{content:"\f01e"}.fa-redo-alt:before{content:"\f2f9"}.fa-registered:before{content:"\f25d"}.fa-remove-format:before{content:"\f87d"}.fa-renren:before{content:"\f18b"}.fa-reply:before{content:"\f3e5"}.fa-reply-all:before{content:"\f122"}.fa-replyd:before{content:"\f3e6"}.fa-republican:before{content:"\f75e"}.fa-researchgate:before{content:"\f4f8"}.fa-resolving:before{content:"\f3e7"}.fa-restroom:before{content:"\f7bd"}.fa-retweet:before{content:"\f079"}.fa-rev:before{content:"\f5b2"}.fa-ribbon:before{content:"\f4d6"}.fa-ring:before{content:"\f70b"}.fa-road:before{content:"\f018"}.fa-robot:before{content:"\f544"}.fa-rocket:before{content:"\f135"}.fa-rocketchat:before{content:"\f3e8"}.fa-rockrms:before{content:"\f3e9"}.fa-route:before{content:"\f4d7"}.fa-rss:before{content:"\f09e"}.fa-rss-square:before{content:"\f143"}.fa-ruble-sign:before{content:"\f158"}.fa-ruler:before{content:"\f545"}.fa-ruler-combined:before{content:"\f546"}.fa-ruler-horizontal:before{content:"\f547"}.fa-ruler-vertical:before{content:"\f548"}.fa-running:before{content:"\f70c"}.fa-rupee-sign:before{content:"\f156"}.fa-sad-cry:before{content:"\f5b3"}.fa-sad-tear:before{content:"\f5b4"}.fa-safari:before{content:"\f267"}.fa-salesforce:before{content:"\f83b"}.fa-sass:before{content:"\f41e"}.fa-satellite:before{content:"\f7bf"}.fa-satellite-dish:before{content:"\f7c0"}.fa-save:before{content:"\f0c7"}.fa-schlix:before{content:"\f3ea"}.fa-school:before{content:"\f549"}.fa-screwdriver:before{content:"\f54a"}.fa-scribd:before{content:"\f28a"}.fa-scroll:before{content:"\f70e"}.fa-sd-card:before{content:"\f7c2"}.fa-search:before{content:"\f002"}.fa-search-dollar:before{content:"\f688"}.fa-search-location:before{content:"\f689"}.fa-search-minus:before{content:"\f010"}.fa-search-plus:before{content:"\f00e"}.fa-searchengin:before{content:"\f3eb"}.fa-seedling:before{content:"\f4d8"}.fa-sellcast:before{content:"\f2da"}.fa-sellsy:before{content:"\f213"}.fa-server:before{content:"\f233"}.fa-servicestack:before{content:"\f3ec"}.fa-shapes:before{content:"\f61f"}.fa-share:before{content:"\f064"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-share-square:before{content:"\f14d"}.fa-shekel-sign:before{content:"\f20b"}.fa-shield-alt:before{content:"\f3ed"}.fa-ship:before{content:"\f21a"}.fa-shipping-fast:before{content:"\f48b"}.fa-shirtsinbulk:before{content:"\f214"}.fa-shoe-prints:before{content:"\f54b"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-shopping-cart:before{content:"\f07a"}.fa-shopware:before{content:"\f5b5"}.fa-shower:before{content:"\f2cc"}.fa-shuttle-van:before{content:"\f5b6"}.fa-sign:before{content:"\f4d9"}.fa-sign-in-alt:before{content:"\f2f6"}.fa-sign-language:before{content:"\f2a7"}.fa-sign-out-alt:before{content:"\f2f5"}.fa-signal:before{content:"\f012"}.fa-signature:before{content:"\f5b7"}.fa-sim-card:before{content:"\f7c4"}.fa-simplybuilt:before{content:"\f215"}.fa-sistrix:before{content:"\f3ee"}.fa-sitemap:before{content:"\f0e8"}.fa-sith:before{content:"\f512"}.fa-skating:before{content:"\f7c5"}.fa-sketch:before{content:"\f7c6"}.fa-skiing:before{content:"\f7c9"}.fa-skiing-nordic:before{content:"\f7ca"}.fa-skull:before{content:"\f54c"}.fa-skull-crossbones:before{content:"\f714"}.fa-skyatlas:before{content:"\f216"}.fa-skype:before{content:"\f17e"}.fa-slack:before{content:"\f198"}.fa-slack-hash:before{content:"\f3ef"}.fa-slash:before{content:"\f715"}.fa-sleigh:before{content:"\f7cc"}.fa-sliders-h:before{content:"\f1de"}.fa-slideshare:before{content:"\f1e7"}.fa-smile:before{content:"\f118"}.fa-smile-beam:before{content:"\f5b8"}.fa-smile-wink:before{content:"\f4da"}.fa-smog:before{content:"\f75f"}.fa-smoking:before{content:"\f48d"}.fa-smoking-ban:before{content:"\f54d"}.fa-sms:before{content:"\f7cd"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-snowboarding:before{content:"\f7ce"}.fa-snowflake:before{content:"\f2dc"}.fa-snowman:before{content:"\f7d0"}.fa-snowplow:before{content:"\f7d2"}.fa-socks:before{content:"\f696"}.fa-solar-panel:before{content:"\f5ba"}.fa-sort:before{content:"\f0dc"}.fa-sort-alpha-down:before{content:"\f15d"}.fa-sort-alpha-down-alt:before{content:"\f881"}.fa-sort-alpha-up:before{content:"\f15e"}.fa-sort-alpha-up-alt:before{content:"\f882"}.fa-sort-amount-down:before{content:"\f160"}.fa-sort-amount-down-alt:before{content:"\f884"}.fa-sort-amount-up:before{content:"\f161"}.fa-sort-amount-up-alt:before{content:"\f885"}.fa-sort-down:before{content:"\f0dd"}.fa-sort-numeric-down:before{content:"\f162"}.fa-sort-numeric-down-alt:before{content:"\f886"}.fa-sort-numeric-up:before{content:"\f163"}.fa-sort-numeric-up-alt:before{content:"\f887"}.fa-sort-up:before{content:"\f0de"}.fa-soundcloud:before{content:"\f1be"}.fa-sourcetree:before{content:"\f7d3"}.fa-spa:before{content:"\f5bb"}.fa-space-shuttle:before{content:"\f197"}.fa-speakap:before{content:"\f3f3"}.fa-speaker-deck:before{content:"\f83c"}.fa-spell-check:before{content:"\f891"}.fa-spider:before{content:"\f717"}.fa-spinner:before{content:"\f110"}.fa-splotch:before{content:"\f5bc"}.fa-spotify:before{content:"\f1bc"}.fa-spray-can:before{content:"\f5bd"}.fa-square:before{content:"\f0c8"}.fa-square-full:before{content:"\f45c"}.fa-square-root-alt:before{content:"\f698"}.fa-squarespace:before{content:"\f5be"}.fa-stack-exchange:before{content:"\f18d"}.fa-stack-overflow:before{content:"\f16c"}.fa-stackpath:before{content:"\f842"}.fa-stamp:before{content:"\f5bf"}.fa-star:before{content:"\f005"}.fa-star-and-crescent:before{content:"\f699"}.fa-star-half:before{content:"\f089"}.fa-star-half-alt:before{content:"\f5c0"}.fa-star-of-david:before{content:"\f69a"}.fa-star-of-life:before{content:"\f621"}.fa-staylinked:before{content:"\f3f5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-steam-symbol:before{content:"\f3f6"}.fa-step-backward:before{content:"\f048"}.fa-step-forward:before{content:"\f051"}.fa-stethoscope:before{content:"\f0f1"}.fa-sticker-mule:before{content:"\f3f7"}.fa-sticky-note:before{content:"\f249"}.fa-stop:before{content:"\f04d"}.fa-stop-circle:before{content:"\f28d"}.fa-stopwatch:before{content:"\f2f2"}.fa-store:before{content:"\f54e"}.fa-store-alt:before{content:"\f54f"}.fa-strava:before{content:"\f428"}.fa-stream:before{content:"\f550"}.fa-street-view:before{content:"\f21d"}.fa-strikethrough:before{content:"\f0cc"}.fa-stripe:before{content:"\f429"}.fa-stripe-s:before{content:"\f42a"}.fa-stroopwafel:before{content:"\f551"}.fa-studiovinari:before{content:"\f3f8"}.fa-stumbleupon:before{content:"\f1a4"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-subscript:before{content:"\f12c"}.fa-subway:before{content:"\f239"}.fa-suitcase:before{content:"\f0f2"}.fa-suitcase-rolling:before{content:"\f5c1"}.fa-sun:before{content:"\f185"}.fa-superpowers:before{content:"\f2dd"}.fa-superscript:before{content:"\f12b"}.fa-supple:before{content:"\f3f9"}.fa-surprise:before{content:"\f5c2"}.fa-suse:before{content:"\f7d6"}.fa-swatchbook:before{content:"\f5c3"}.fa-swimmer:before{content:"\f5c4"}.fa-swimming-pool:before{content:"\f5c5"}.fa-symfony:before{content:"\f83d"}.fa-synagogue:before{content:"\f69b"}.fa-sync:before{content:"\f021"}.fa-sync-alt:before{content:"\f2f1"}.fa-syringe:before{content:"\f48e"}.fa-table:before{content:"\f0ce"}.fa-table-tennis:before{content:"\f45d"}.fa-tablet:before{content:"\f10a"}.fa-tablet-alt:before{content:"\f3fa"}.fa-tablets:before{content:"\f490"}.fa-tachometer-alt:before{content:"\f3fd"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-tape:before{content:"\f4db"}.fa-tasks:before{content:"\f0ae"}.fa-taxi:before{content:"\f1ba"}.fa-teamspeak:before{content:"\f4f9"}.fa-teeth:before{content:"\f62e"}.fa-teeth-open:before{content:"\f62f"}.fa-telegram:before{content:"\f2c6"}.fa-telegram-plane:before{content:"\f3fe"}.fa-temperature-high:before{content:"\f769"}.fa-temperature-low:before{content:"\f76b"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-tenge:before{content:"\f7d7"}.fa-terminal:before{content:"\f120"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-th:before{content:"\f00a"}.fa-th-large:before{content:"\f009"}.fa-th-list:before{content:"\f00b"}.fa-the-red-yeti:before{content:"\f69d"}.fa-theater-masks:before{content:"\f630"}.fa-themeco:before{content:"\f5c6"}.fa-themeisle:before{content:"\f2b2"}.fa-thermometer:before{content:"\f491"}.fa-thermometer-empty:before{content:"\f2cb"}.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-think-peaks:before{content:"\f731"}.fa-thumbs-down:before{content:"\f165"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbtack:before{content:"\f08d"}.fa-ticket-alt:before{content:"\f3ff"}.fa-times:before{content:"\f00d"}.fa-times-circle:before{content:"\f057"}.fa-tint:before{content:"\f043"}.fa-tint-slash:before{content:"\f5c7"}.fa-tired:before{content:"\f5c8"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-toilet:before{content:"\f7d8"}.fa-toilet-paper:before{content:"\f71e"}.fa-toolbox:before{content:"\f552"}.fa-tools:before{content:"\f7d9"}.fa-tooth:before{content:"\f5c9"}.fa-torah:before{content:"\f6a0"}.fa-torii-gate:before{content:"\f6a1"}.fa-tractor:before{content:"\f722"}.fa-trade-federation:before{content:"\f513"}.fa-trademark:before{content:"\f25c"}.fa-traffic-light:before{content:"\f637"}.fa-train:before{content:"\f238"}.fa-tram:before{content:"\f7da"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-trash:before{content:"\f1f8"}.fa-trash-alt:before{content:"\f2ed"}.fa-trash-restore:before{content:"\f829"}.fa-trash-restore-alt:before{content:"\f82a"}.fa-tree:before{content:"\f1bb"}.fa-trello:before{content:"\f181"}.fa-tripadvisor:before{content:"\f262"}.fa-trophy:before{content:"\f091"}.fa-truck:before{content:"\f0d1"}.fa-truck-loading:before{content:"\f4de"}.fa-truck-monster:before{content:"\f63b"}.fa-truck-moving:before{content:"\f4df"}.fa-truck-pickup:before{content:"\f63c"}.fa-tshirt:before{content:"\f553"}.fa-tty:before{content:"\f1e4"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-tv:before{content:"\f26c"}.fa-twitch:before{content:"\f1e8"}.fa-twitter:before{content:"\f099"}.fa-twitter-square:before{content:"\f081"}.fa-typo3:before{content:"\f42b"}.fa-uber:before{content:"\f402"}.fa-ubuntu:before{content:"\f7df"}.fa-uikit:before{content:"\f403"}.fa-umbrella:before{content:"\f0e9"}.fa-umbrella-beach:before{content:"\f5ca"}.fa-underline:before{content:"\f0cd"}.fa-undo:before{content:"\f0e2"}.fa-undo-alt:before{content:"\f2ea"}.fa-uniregistry:before{content:"\f404"}.fa-universal-access:before{content:"\f29a"}.fa-university:before{content:"\f19c"}.fa-unlink:before{content:"\f127"}.fa-unlock:before{content:"\f09c"}.fa-unlock-alt:before{content:"\f13e"}.fa-untappd:before{content:"\f405"}.fa-upload:before{content:"\f093"}.fa-ups:before{content:"\f7e0"}.fa-usb:before{content:"\f287"}.fa-user:before{content:"\f007"}.fa-user-alt:before{content:"\f406"}.fa-user-alt-slash:before{content:"\f4fa"}.fa-user-astronaut:before{content:"\f4fb"}.fa-user-check:before{content:"\f4fc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-clock:before{content:"\f4fd"}.fa-user-cog:before{content:"\f4fe"}.fa-user-edit:before{content:"\f4ff"}.fa-user-friends:before{content:"\f500"}.fa-user-graduate:before{content:"\f501"}.fa-user-injured:before{content:"\f728"}.fa-user-lock:before{content:"\f502"}.fa-user-md:before{content:"\f0f0"}.fa-user-minus:before{content:"\f503"}.fa-user-ninja:before{content:"\f504"}.fa-user-nurse:before{content:"\f82f"}.fa-user-plus:before{content:"\f234"}.fa-user-secret:before{content:"\f21b"}.fa-user-shield:before{content:"\f505"}.fa-user-slash:before{content:"\f506"}.fa-user-tag:before{content:"\f507"}.fa-user-tie:before{content:"\f508"}.fa-user-times:before{content:"\f235"}.fa-users:before{content:"\f0c0"}.fa-users-cog:before{content:"\f509"}.fa-usps:before{content:"\f7e1"}.fa-ussunnah:before{content:"\f407"}.fa-utensil-spoon:before{content:"\f2e5"}.fa-utensils:before{content:"\f2e7"}.fa-vaadin:before{content:"\f408"}.fa-vector-square:before{content:"\f5cb"}.fa-venus:before{content:"\f221"}.fa-venus-double:before{content:"\f226"}.fa-venus-mars:before{content:"\f228"}.fa-viacoin:before{content:"\f237"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-vial:before{content:"\f492"}.fa-vials:before{content:"\f493"}.fa-viber:before{content:"\f409"}.fa-video:before{content:"\f03d"}.fa-video-slash:before{content:"\f4e2"}.fa-vihara:before{content:"\f6a7"}.fa-vimeo:before{content:"\f40a"}.fa-vimeo-square:before{content:"\f194"}.fa-vimeo-v:before{content:"\f27d"}.fa-vine:before{content:"\f1ca"}.fa-vk:before{content:"\f189"}.fa-vnv:before{content:"\f40b"}.fa-voicemail:before{content:"\f897"}.fa-volleyball-ball:before{content:"\f45f"}.fa-volume-down:before{content:"\f027"}.fa-volume-mute:before{content:"\f6a9"}.fa-volume-off:before{content:"\f026"}.fa-volume-up:before{content:"\f028"}.fa-vote-yea:before{content:"\f772"}.fa-vr-cardboard:before{content:"\f729"}.fa-vuejs:before{content:"\f41f"}.fa-walking:before{content:"\f554"}.fa-wallet:before{content:"\f555"}.fa-warehouse:before{content:"\f494"}.fa-water:before{content:"\f773"}.fa-wave-square:before{content:"\f83e"}.fa-waze:before{content:"\f83f"}.fa-weebly:before{content:"\f5cc"}.fa-weibo:before{content:"\f18a"}.fa-weight:before{content:"\f496"}.fa-weight-hanging:before{content:"\f5cd"}.fa-weixin:before{content:"\f1d7"}.fa-whatsapp:before{content:"\f232"}.fa-whatsapp-square:before{content:"\f40c"}.fa-wheelchair:before{content:"\f193"}.fa-whmcs:before{content:"\f40d"}.fa-wifi:before{content:"\f1eb"}.fa-wikipedia-w:before{content:"\f266"}.fa-wind:before{content:"\f72e"}.fa-window-close:before{content:"\f410"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-windows:before{content:"\f17a"}.fa-wine-bottle:before{content:"\f72f"}.fa-wine-glass:before{content:"\f4e3"}.fa-wine-glass-alt:before{content:"\f5ce"}.fa-wix:before{content:"\f5cf"}.fa-wizards-of-the-coast:before{content:"\f730"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-won-sign:before{content:"\f159"}.fa-wordpress:before{content:"\f19a"}.fa-wordpress-simple:before{content:"\f411"}.fa-wpbeginner:before{content:"\f297"}.fa-wpexplorer:before{content:"\f2de"}.fa-wpforms:before{content:"\f298"}.fa-wpressr:before{content:"\f3e4"}.fa-wrench:before{content:"\f0ad"}.fa-x-ray:before{content:"\f497"}.fa-xbox:before{content:"\f412"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-y-combinator:before{content:"\f23b"}.fa-yahoo:before{content:"\f19e"}.fa-yammer:before{content:"\f840"}.fa-yandex:before{content:"\f413"}.fa-yandex-international:before{content:"\f414"}.fa-yarn:before{content:"\f7e3"}.fa-yelp:before{content:"\f1e9"}.fa-yen-sign:before{content:"\f157"}.fa-yin-yang:before{content:"\f6ad"}.fa-yoast:before{content:"\f2b1"}.fa-youtube:before{content:"\f167"}.fa-youtube-square:before{content:"\f431"}.fa-zhihu:before{content:"\f63f"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:400;font-display:auto;src:url(fa-regular-400.eot);src:url(fa-regular-400.eot?#iefix) format("embedded-opentype"),url(fa-regular-400.woff) format("woff")}.far{font-weight:400}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:900;font-display:auto;src:url(fa-solid-900.eot);src:url(fa-solid-900.eot?#iefix) format("embedded-opentype"),url(fa-solid-900.woff) format("woff")}.fa,.far,.fas{font-family:"Font Awesome 5 Free"}.fa,.fas{font-weight:900}
\ No newline at end of file
diff --git a/html/font-awesome/css/v4-shims.min.css b/html/font-awesome/css/v4-shims.min.css
new file mode 100644
index 00000000000..5f3fdc598c8
--- /dev/null
+++ b/html/font-awesome/css/v4-shims.min.css
@@ -0,0 +1,5 @@
+/*!
+ * Font Awesome Free 5.9.0 by @fontawesome - https://fontawesome.com
+ * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
+ */
+.fa.fa-glass:before{content:"\f000"}.fa.fa-meetup{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-star-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-star-o:before{content:"\f005"}.fa.fa-close:before,.fa.fa-remove:before{content:"\f00d"}.fa.fa-gear:before{content:"\f013"}.fa.fa-trash-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-trash-o:before{content:"\f2ed"}.fa.fa-file-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-o:before{content:"\f15b"}.fa.fa-clock-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-clock-o:before{content:"\f017"}.fa.fa-arrow-circle-o-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-arrow-circle-o-down:before{content:"\f358"}.fa.fa-arrow-circle-o-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-arrow-circle-o-up:before{content:"\f35b"}.fa.fa-play-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-play-circle-o:before{content:"\f144"}.fa.fa-repeat:before,.fa.fa-rotate-right:before{content:"\f01e"}.fa.fa-refresh:before{content:"\f021"}.fa.fa-list-alt{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-dedent:before{content:"\f03b"}.fa.fa-video-camera:before{content:"\f03d"}.fa.fa-picture-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-picture-o:before{content:"\f03e"}.fa.fa-photo{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-photo:before{content:"\f03e"}.fa.fa-image{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-image:before{content:"\f03e"}.fa.fa-pencil:before{content:"\f303"}.fa.fa-map-marker:before{content:"\f3c5"}.fa.fa-pencil-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-pencil-square-o:before{content:"\f044"}.fa.fa-share-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-share-square-o:before{content:"\f14d"}.fa.fa-check-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-check-square-o:before{content:"\f14a"}.fa.fa-arrows:before{content:"\f0b2"}.fa.fa-times-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-times-circle-o:before{content:"\f057"}.fa.fa-check-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-check-circle-o:before{content:"\f058"}.fa.fa-mail-forward:before{content:"\f064"}.fa.fa-eye,.fa.fa-eye-slash{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-warning:before{content:"\f071"}.fa.fa-calendar:before{content:"\f073"}.fa.fa-arrows-v:before{content:"\f338"}.fa.fa-arrows-h:before{content:"\f337"}.fa.fa-bar-chart{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bar-chart:before{content:"\f080"}.fa.fa-bar-chart-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bar-chart-o:before{content:"\f080"}.fa.fa-facebook-square,.fa.fa-twitter-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-gears:before{content:"\f085"}.fa.fa-thumbs-o-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-thumbs-o-up:before{content:"\f164"}.fa.fa-thumbs-o-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-thumbs-o-down:before{content:"\f165"}.fa.fa-heart-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-heart-o:before{content:"\f004"}.fa.fa-sign-out:before{content:"\f2f5"}.fa.fa-linkedin-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-linkedin-square:before{content:"\f08c"}.fa.fa-thumb-tack:before{content:"\f08d"}.fa.fa-external-link:before{content:"\f35d"}.fa.fa-sign-in:before{content:"\f2f6"}.fa.fa-github-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-lemon-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-lemon-o:before{content:"\f094"}.fa.fa-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-square-o:before{content:"\f0c8"}.fa.fa-bookmark-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bookmark-o:before{content:"\f02e"}.fa.fa-facebook,.fa.fa-twitter{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-facebook:before{content:"\f39e"}.fa.fa-facebook-f{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-facebook-f:before{content:"\f39e"}.fa.fa-github{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-credit-card{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-feed:before{content:"\f09e"}.fa.fa-hdd-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hdd-o:before{content:"\f0a0"}.fa.fa-hand-o-right{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-o-right:before{content:"\f0a4"}.fa.fa-hand-o-left{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-o-left:before{content:"\f0a5"}.fa.fa-hand-o-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-o-up:before{content:"\f0a6"}.fa.fa-hand-o-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-o-down:before{content:"\f0a7"}.fa.fa-arrows-alt:before{content:"\f31e"}.fa.fa-group:before{content:"\f0c0"}.fa.fa-chain:before{content:"\f0c1"}.fa.fa-scissors:before{content:"\f0c4"}.fa.fa-files-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-files-o:before{content:"\f0c5"}.fa.fa-floppy-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-floppy-o:before{content:"\f0c7"}.fa.fa-navicon:before,.fa.fa-reorder:before{content:"\f0c9"}.fa.fa-google-plus,.fa.fa-google-plus-square,.fa.fa-pinterest,.fa.fa-pinterest-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-google-plus:before{content:"\f0d5"}.fa.fa-money{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-money:before{content:"\f3d1"}.fa.fa-unsorted:before{content:"\f0dc"}.fa.fa-sort-desc:before{content:"\f0dd"}.fa.fa-sort-asc:before{content:"\f0de"}.fa.fa-linkedin{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-linkedin:before{content:"\f0e1"}.fa.fa-rotate-left:before{content:"\f0e2"}.fa.fa-legal:before{content:"\f0e3"}.fa.fa-dashboard:before,.fa.fa-tachometer:before{content:"\f3fd"}.fa.fa-comment-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-comment-o:before{content:"\f075"}.fa.fa-comments-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-comments-o:before{content:"\f086"}.fa.fa-flash:before{content:"\f0e7"}.fa.fa-clipboard,.fa.fa-paste{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-paste:before{content:"\f328"}.fa.fa-lightbulb-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-lightbulb-o:before{content:"\f0eb"}.fa.fa-exchange:before{content:"\f362"}.fa.fa-cloud-download:before{content:"\f381"}.fa.fa-cloud-upload:before{content:"\f382"}.fa.fa-bell-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bell-o:before{content:"\f0f3"}.fa.fa-cutlery:before{content:"\f2e7"}.fa.fa-file-text-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-text-o:before{content:"\f15c"}.fa.fa-building-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-building-o:before{content:"\f1ad"}.fa.fa-hospital-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hospital-o:before{content:"\f0f8"}.fa.fa-tablet:before{content:"\f3fa"}.fa.fa-mobile-phone:before,.fa.fa-mobile:before{content:"\f3cd"}.fa.fa-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-circle-o:before{content:"\f111"}.fa.fa-mail-reply:before{content:"\f3e5"}.fa.fa-github-alt{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-folder-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-folder-o:before{content:"\f07b"}.fa.fa-folder-open-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-folder-open-o:before{content:"\f07c"}.fa.fa-smile-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-smile-o:before{content:"\f118"}.fa.fa-frown-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-frown-o:before{content:"\f119"}.fa.fa-meh-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-meh-o:before{content:"\f11a"}.fa.fa-keyboard-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-keyboard-o:before{content:"\f11c"}.fa.fa-flag-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-flag-o:before{content:"\f024"}.fa.fa-mail-reply-all:before{content:"\f122"}.fa.fa-star-half-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-star-half-o:before{content:"\f089"}.fa.fa-star-half-empty{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-star-half-empty:before{content:"\f089"}.fa.fa-star-half-full{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-star-half-full:before{content:"\f089"}.fa.fa-code-fork:before{content:"\f126"}.fa.fa-chain-broken:before{content:"\f127"}.fa.fa-shield:before{content:"\f3ed"}.fa.fa-calendar-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-o:before{content:"\f133"}.fa.fa-css3,.fa.fa-html5,.fa.fa-maxcdn{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-ticket:before{content:"\f3ff"}.fa.fa-minus-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-minus-square-o:before{content:"\f146"}.fa.fa-level-up:before{content:"\f3bf"}.fa.fa-level-down:before{content:"\f3be"}.fa.fa-pencil-square:before{content:"\f14b"}.fa.fa-external-link-square:before{content:"\f360"}.fa.fa-compass{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-down:before{content:"\f150"}.fa.fa-toggle-down{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-toggle-down:before{content:"\f150"}.fa.fa-caret-square-o-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-up:before{content:"\f151"}.fa.fa-toggle-up{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-toggle-up:before{content:"\f151"}.fa.fa-caret-square-o-right{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-right:before{content:"\f152"}.fa.fa-toggle-right{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-toggle-right:before{content:"\f152"}.fa.fa-eur:before,.fa.fa-euro:before{content:"\f153"}.fa.fa-gbp:before{content:"\f154"}.fa.fa-dollar:before,.fa.fa-usd:before{content:"\f155"}.fa.fa-inr:before,.fa.fa-rupee:before{content:"\f156"}.fa.fa-cny:before,.fa.fa-jpy:before,.fa.fa-rmb:before,.fa.fa-yen:before{content:"\f157"}.fa.fa-rouble:before,.fa.fa-rub:before,.fa.fa-ruble:before{content:"\f158"}.fa.fa-krw:before,.fa.fa-won:before{content:"\f159"}.fa.fa-bitcoin,.fa.fa-btc{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-bitcoin:before{content:"\f15a"}.fa.fa-file-text:before{content:"\f15c"}.fa.fa-sort-alpha-asc:before{content:"\f15d"}.fa.fa-sort-alpha-desc:before{content:"\f15e"}.fa.fa-sort-amount-asc:before{content:"\f160"}.fa.fa-sort-amount-desc:before{content:"\f161"}.fa.fa-sort-numeric-asc:before{content:"\f162"}.fa.fa-sort-numeric-desc:before{content:"\f163"}.fa.fa-xing,.fa.fa-xing-square,.fa.fa-youtube,.fa.fa-youtube-play,.fa.fa-youtube-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-youtube-play:before{content:"\f167"}.fa.fa-adn,.fa.fa-bitbucket,.fa.fa-bitbucket-square,.fa.fa-dropbox,.fa.fa-flickr,.fa.fa-instagram,.fa.fa-stack-overflow{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-bitbucket-square:before{content:"\f171"}.fa.fa-tumblr,.fa.fa-tumblr-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-long-arrow-down:before{content:"\f309"}.fa.fa-long-arrow-up:before{content:"\f30c"}.fa.fa-long-arrow-left:before{content:"\f30a"}.fa.fa-long-arrow-right:before{content:"\f30b"}.fa.fa-android,.fa.fa-apple,.fa.fa-dribbble,.fa.fa-foursquare,.fa.fa-gittip,.fa.fa-gratipay,.fa.fa-linux,.fa.fa-skype,.fa.fa-trello,.fa.fa-windows{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-gittip:before{content:"\f184"}.fa.fa-sun-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-sun-o:before{content:"\f185"}.fa.fa-moon-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-moon-o:before{content:"\f186"}.fa.fa-pagelines,.fa.fa-renren,.fa.fa-stack-exchange,.fa.fa-vk,.fa.fa-weibo{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-arrow-circle-o-right{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-arrow-circle-o-right:before{content:"\f35a"}.fa.fa-arrow-circle-o-left{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-arrow-circle-o-left:before{content:"\f359"}.fa.fa-caret-square-o-left{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-caret-square-o-left:before{content:"\f191"}.fa.fa-toggle-left{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-toggle-left:before{content:"\f191"}.fa.fa-dot-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-dot-circle-o:before{content:"\f192"}.fa.fa-vimeo-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-try:before,.fa.fa-turkish-lira:before{content:"\f195"}.fa.fa-plus-square-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-plus-square-o:before{content:"\f0fe"}.fa.fa-openid,.fa.fa-slack,.fa.fa-wordpress{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-bank:before,.fa.fa-institution:before{content:"\f19c"}.fa.fa-mortar-board:before{content:"\f19d"}.fa.fa-delicious,.fa.fa-digg,.fa.fa-drupal,.fa.fa-google,.fa.fa-joomla,.fa.fa-pied-piper-alt,.fa.fa-pied-piper-pp,.fa.fa-reddit,.fa.fa-reddit-square,.fa.fa-stumbleupon,.fa.fa-stumbleupon-circle,.fa.fa-yahoo{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-spoon:before{content:"\f2e5"}.fa.fa-behance,.fa.fa-behance-square,.fa.fa-steam,.fa.fa-steam-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-automobile:before{content:"\f1b9"}.fa.fa-cab:before{content:"\f1ba"}.fa.fa-envelope-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-envelope-o:before{content:"\f0e0"}.fa.fa-deviantart,.fa.fa-soundcloud{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-file-pdf-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-pdf-o:before{content:"\f1c1"}.fa.fa-file-word-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-word-o:before{content:"\f1c2"}.fa.fa-file-excel-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-excel-o:before{content:"\f1c3"}.fa.fa-file-powerpoint-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-powerpoint-o:before{content:"\f1c4"}.fa.fa-file-image-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-image-o:before{content:"\f1c5"}.fa.fa-file-photo-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-photo-o:before{content:"\f1c5"}.fa.fa-file-picture-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-picture-o:before{content:"\f1c5"}.fa.fa-file-archive-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-archive-o:before{content:"\f1c6"}.fa.fa-file-zip-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-zip-o:before{content:"\f1c6"}.fa.fa-file-audio-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-audio-o:before{content:"\f1c7"}.fa.fa-file-sound-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-sound-o:before{content:"\f1c7"}.fa.fa-file-video-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-video-o:before{content:"\f1c8"}.fa.fa-file-movie-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-movie-o:before{content:"\f1c8"}.fa.fa-file-code-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-file-code-o:before{content:"\f1c9"}.fa.fa-codepen,.fa.fa-jsfiddle,.fa.fa-vine{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-life-bouy,.fa.fa-life-ring{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-life-bouy:before{content:"\f1cd"}.fa.fa-life-buoy{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-life-buoy:before{content:"\f1cd"}.fa.fa-life-saver{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-life-saver:before{content:"\f1cd"}.fa.fa-support{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-support:before{content:"\f1cd"}.fa.fa-circle-o-notch:before{content:"\f1ce"}.fa.fa-ra,.fa.fa-rebel{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-ra:before{content:"\f1d0"}.fa.fa-resistance{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-resistance:before{content:"\f1d0"}.fa.fa-empire,.fa.fa-ge{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-ge:before{content:"\f1d1"}.fa.fa-git,.fa.fa-git-square,.fa.fa-hacker-news,.fa.fa-y-combinator-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-y-combinator-square:before{content:"\f1d4"}.fa.fa-yc-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-yc-square:before{content:"\f1d4"}.fa.fa-qq,.fa.fa-tencent-weibo,.fa.fa-wechat,.fa.fa-weixin{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-wechat:before{content:"\f1d7"}.fa.fa-send:before{content:"\f1d8"}.fa.fa-paper-plane-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-paper-plane-o:before{content:"\f1d8"}.fa.fa-send-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-send-o:before{content:"\f1d8"}.fa.fa-circle-thin{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-circle-thin:before{content:"\f111"}.fa.fa-header:before{content:"\f1dc"}.fa.fa-sliders:before{content:"\f1de"}.fa.fa-futbol-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-futbol-o:before{content:"\f1e3"}.fa.fa-soccer-ball-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-soccer-ball-o:before{content:"\f1e3"}.fa.fa-slideshare,.fa.fa-twitch,.fa.fa-yelp{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-newspaper-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-newspaper-o:before{content:"\f1ea"}.fa.fa-cc-amex,.fa.fa-cc-discover,.fa.fa-cc-mastercard,.fa.fa-cc-paypal,.fa.fa-cc-stripe,.fa.fa-cc-visa,.fa.fa-google-wallet,.fa.fa-paypal{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-bell-slash-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-bell-slash-o:before{content:"\f1f6"}.fa.fa-trash:before{content:"\f2ed"}.fa.fa-copyright{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-eyedropper:before{content:"\f1fb"}.fa.fa-area-chart:before{content:"\f1fe"}.fa.fa-pie-chart:before{content:"\f200"}.fa.fa-line-chart:before{content:"\f201"}.fa.fa-angellist,.fa.fa-ioxhost,.fa.fa-lastfm,.fa.fa-lastfm-square{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-cc{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-cc:before{content:"\f20a"}.fa.fa-ils:before,.fa.fa-shekel:before,.fa.fa-sheqel:before{content:"\f20b"}.fa.fa-meanpath{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-meanpath:before{content:"\f2b4"}.fa.fa-buysellads,.fa.fa-connectdevelop,.fa.fa-dashcube,.fa.fa-forumbee,.fa.fa-leanpub,.fa.fa-sellsy,.fa.fa-shirtsinbulk,.fa.fa-simplybuilt,.fa.fa-skyatlas{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-diamond{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-diamond:before{content:"\f3a5"}.fa.fa-intersex:before{content:"\f224"}.fa.fa-facebook-official{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-facebook-official:before{content:"\f09a"}.fa.fa-pinterest-p,.fa.fa-whatsapp{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-hotel:before{content:"\f236"}.fa.fa-medium,.fa.fa-viacoin,.fa.fa-y-combinator,.fa.fa-yc{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-yc:before{content:"\f23b"}.fa.fa-expeditedssl,.fa.fa-opencart,.fa.fa-optin-monster{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-battery-4:before,.fa.fa-battery:before{content:"\f240"}.fa.fa-battery-3:before{content:"\f241"}.fa.fa-battery-2:before{content:"\f242"}.fa.fa-battery-1:before{content:"\f243"}.fa.fa-battery-0:before{content:"\f244"}.fa.fa-object-group,.fa.fa-object-ungroup,.fa.fa-sticky-note-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-sticky-note-o:before{content:"\f249"}.fa.fa-cc-diners-club,.fa.fa-cc-jcb{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-clone,.fa.fa-hourglass-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hourglass-o:before{content:"\f254"}.fa.fa-hourglass-1:before{content:"\f251"}.fa.fa-hourglass-2:before{content:"\f252"}.fa.fa-hourglass-3:before{content:"\f253"}.fa.fa-hand-rock-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-rock-o:before{content:"\f255"}.fa.fa-hand-grab-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-grab-o:before{content:"\f255"}.fa.fa-hand-paper-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-paper-o:before{content:"\f256"}.fa.fa-hand-stop-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-stop-o:before{content:"\f256"}.fa.fa-hand-scissors-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-scissors-o:before{content:"\f257"}.fa.fa-hand-lizard-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-lizard-o:before{content:"\f258"}.fa.fa-hand-spock-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-spock-o:before{content:"\f259"}.fa.fa-hand-pointer-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-pointer-o:before{content:"\f25a"}.fa.fa-hand-peace-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-hand-peace-o:before{content:"\f25b"}.fa.fa-registered{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-chrome,.fa.fa-creative-commons,.fa.fa-firefox,.fa.fa-get-pocket,.fa.fa-gg,.fa.fa-gg-circle,.fa.fa-internet-explorer,.fa.fa-odnoklassniki,.fa.fa-odnoklassniki-square,.fa.fa-opera,.fa.fa-safari,.fa.fa-tripadvisor,.fa.fa-wikipedia-w{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-television:before{content:"\f26c"}.fa.fa-500px,.fa.fa-amazon,.fa.fa-contao{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-calendar-plus-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-plus-o:before{content:"\f271"}.fa.fa-calendar-minus-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-minus-o:before{content:"\f272"}.fa.fa-calendar-times-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-times-o:before{content:"\f273"}.fa.fa-calendar-check-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-calendar-check-o:before{content:"\f274"}.fa.fa-map-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-map-o:before{content:"\f279"}.fa.fa-commenting:before{content:"\f4ad"}.fa.fa-commenting-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-commenting-o:before{content:"\f4ad"}.fa.fa-houzz,.fa.fa-vimeo{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-vimeo:before{content:"\f27d"}.fa.fa-black-tie,.fa.fa-edge,.fa.fa-fonticons,.fa.fa-reddit-alien{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-credit-card-alt:before{content:"\f09d"}.fa.fa-codiepie,.fa.fa-fort-awesome,.fa.fa-mixcloud,.fa.fa-modx,.fa.fa-product-hunt,.fa.fa-scribd,.fa.fa-usb{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-pause-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-pause-circle-o:before{content:"\f28b"}.fa.fa-stop-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-stop-circle-o:before{content:"\f28d"}.fa.fa-bluetooth,.fa.fa-bluetooth-b,.fa.fa-envira,.fa.fa-gitlab,.fa.fa-wheelchair-alt,.fa.fa-wpbeginner,.fa.fa-wpforms{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-wheelchair-alt:before{content:"\f368"}.fa.fa-question-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-question-circle-o:before{content:"\f059"}.fa.fa-volume-control-phone:before{content:"\f2a0"}.fa.fa-asl-interpreting:before{content:"\f2a3"}.fa.fa-deafness:before,.fa.fa-hard-of-hearing:before{content:"\f2a4"}.fa.fa-glide,.fa.fa-glide-g{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-signing:before{content:"\f2a7"}.fa.fa-first-order,.fa.fa-google-plus-official,.fa.fa-pied-piper,.fa.fa-snapchat,.fa.fa-snapchat-ghost,.fa.fa-snapchat-square,.fa.fa-themeisle,.fa.fa-viadeo,.fa.fa-viadeo-square,.fa.fa-yoast{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-google-plus-official:before{content:"\f2b3"}.fa.fa-google-plus-circle{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-google-plus-circle:before{content:"\f2b3"}.fa.fa-fa,.fa.fa-font-awesome{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-fa:before{content:"\f2b4"}.fa.fa-handshake-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-handshake-o:before{content:"\f2b5"}.fa.fa-envelope-open-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-envelope-open-o:before{content:"\f2b6"}.fa.fa-linode{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-address-book-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-address-book-o:before{content:"\f2b9"}.fa.fa-vcard:before{content:"\f2bb"}.fa.fa-address-card-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-address-card-o:before{content:"\f2bb"}.fa.fa-vcard-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-vcard-o:before{content:"\f2bb"}.fa.fa-user-circle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-user-circle-o:before{content:"\f2bd"}.fa.fa-user-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-user-o:before{content:"\f007"}.fa.fa-id-badge{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-drivers-license:before{content:"\f2c2"}.fa.fa-id-card-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-id-card-o:before{content:"\f2c2"}.fa.fa-drivers-license-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-drivers-license-o:before{content:"\f2c2"}.fa.fa-free-code-camp,.fa.fa-quora,.fa.fa-telegram{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-thermometer-4:before,.fa.fa-thermometer:before{content:"\f2c7"}.fa.fa-thermometer-3:before{content:"\f2c8"}.fa.fa-thermometer-2:before{content:"\f2c9"}.fa.fa-thermometer-1:before{content:"\f2ca"}.fa.fa-thermometer-0:before{content:"\f2cb"}.fa.fa-bathtub:before,.fa.fa-s15:before{content:"\f2cd"}.fa.fa-window-maximize,.fa.fa-window-restore{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-times-rectangle:before{content:"\f410"}.fa.fa-window-close-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-window-close-o:before{content:"\f410"}.fa.fa-times-rectangle-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-times-rectangle-o:before{content:"\f410"}.fa.fa-bandcamp,.fa.fa-eercast,.fa.fa-etsy,.fa.fa-grav,.fa.fa-imdb,.fa.fa-ravelry{font-family:"Font Awesome 5 Brands";font-weight:400}.fa.fa-eercast:before{content:"\f2da"}.fa.fa-snowflake-o{font-family:"Font Awesome 5 Free";font-weight:400}.fa.fa-snowflake-o:before{content:"\f2dc"}.fa.fa-spotify,.fa.fa-superpowers,.fa.fa-wpexplorer{font-family:"Font Awesome 5 Brands";font-weight:400}
\ No newline at end of file
diff --git a/html/font-awesome/webfonts/fa-regular-400.eot b/html/font-awesome/webfonts/fa-regular-400.eot
new file mode 100644
index 00000000000..d62be2fad88
Binary files /dev/null and b/html/font-awesome/webfonts/fa-regular-400.eot differ
diff --git a/html/font-awesome/webfonts/fa-regular-400.woff b/html/font-awesome/webfonts/fa-regular-400.woff
new file mode 100644
index 00000000000..43b1a9ae49d
Binary files /dev/null and b/html/font-awesome/webfonts/fa-regular-400.woff differ
diff --git a/html/font-awesome/webfonts/fa-solid-900.eot b/html/font-awesome/webfonts/fa-solid-900.eot
new file mode 100644
index 00000000000..c77baa8d46a
Binary files /dev/null and b/html/font-awesome/webfonts/fa-solid-900.eot differ
diff --git a/html/font-awesome/webfonts/fa-solid-900.woff b/html/font-awesome/webfonts/fa-solid-900.woff
new file mode 100644
index 00000000000..77c1786227f
Binary files /dev/null and b/html/font-awesome/webfonts/fa-solid-900.woff differ
diff --git a/icons/effects/hit_blips.dmi b/icons/effects/hit_blips.dmi
deleted file mode 100644
index 49bb109799b..00000000000
Binary files a/icons/effects/hit_blips.dmi and /dev/null differ
diff --git a/icons/mob/human_races/r_def_zombie.dmi b/icons/mob/human_races/r_def_zombie.dmi
deleted file mode 100644
index 007eb3f31f3..00000000000
Binary files a/icons/mob/human_races/r_def_zombie.dmi and /dev/null differ
diff --git a/icons/mob/human_races/r_zombie.dmi b/icons/mob/human_races/r_zombie.dmi
deleted file mode 100644
index 007eb3f31f3..00000000000
Binary files a/icons/mob/human_races/r_zombie.dmi and /dev/null differ
diff --git a/icons/mob/robots.dmi b/icons/mob/robots.dmi
index eb59b0288b3..dcbce35fb27 100644
Binary files a/icons/mob/robots.dmi and b/icons/mob/robots.dmi differ
diff --git a/icons/mob/screen_ghost.dmi b/icons/mob/screen_ghost.dmi
index 6519d00aa97..e0e85a6939c 100644
Binary files a/icons/mob/screen_ghost.dmi and b/icons/mob/screen_ghost.dmi differ
diff --git a/icons/mob/talk.dmi b/icons/mob/talk.dmi
index 4b74a2891e3..961cffec7f6 100644
Binary files a/icons/mob/talk.dmi and b/icons/mob/talk.dmi differ
diff --git a/icons/mob/ties.dmi b/icons/mob/ties.dmi
index bbb986c088e..e399e5e3a8b 100644
Binary files a/icons/mob/ties.dmi and b/icons/mob/ties.dmi differ
diff --git a/icons/obj/clothing/ties.dmi b/icons/obj/clothing/ties.dmi
index 4799e9ad963..7675ec0d51c 100644
Binary files a/icons/obj/clothing/ties.dmi and b/icons/obj/clothing/ties.dmi differ
diff --git a/icons/obj/clothing/ties_overlay.dmi b/icons/obj/clothing/ties_overlay.dmi
index 975059bfeeb..fd3b6023185 100644
Binary files a/icons/obj/clothing/ties_overlay.dmi and b/icons/obj/clothing/ties_overlay.dmi differ
diff --git a/libmariadb.so b/libmariadb.so
old mode 100644
new mode 100755
diff --git a/librust_g.so b/librust_g.so
old mode 100644
new mode 100755
index d70052a39c9..57d9ed9fa57
Binary files a/librust_g.so and b/librust_g.so differ
diff --git a/nano/templates/ame.tmpl b/nano/templates/ame.tmpl
deleted file mode 100644
index 4a86139eda1..00000000000
--- a/nano/templates/ame.tmpl
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
Status:
- {{if data.active}}
-
Injecting
- {{else}}
-
Standby
- {{/if}}
- {{:helper.link("Toggle Status", "gear", {"togglestatus":1},null)}}
-
-{{if !data.fueljar}}
- No fuel jar detected.
-{{else}}
-
-
-
Fuel:
-
{{:data.fueljar.fuel}}/{{:data.fueljar.fuel_max}}
- {{:helper.link("Eject", "eject", {"ejectjar":1},null,'floatRight')}}
-
-
-
Injecting:
-
- {{:helper.link(data.fueljar.injecting+" units", 'arrows-v', {'set_strength': 1})}}
-
-
-
-{{/if}}
-
-
-
Stability:
-
- {{:helper.displayBar(data.stability,0,100,"good")}}
- {{:data.stability}}%
-
-
-
-
Shielding Count:
-
{{:data.linked_shields}}
-
-
-
Cores:
-
{{:data.linked_cores}}
- {{:helper.link("Refresh Parts",null,{"refreshicons" : 1},(data.active?"disabled":null),'floatRight')}}
-
-
-
Current Efficiency:
-
{{:data.efficiency}}
-
-
-
Average Efficiency:
-
{{:data.stability}}
-
-
-
Last Produced:
-
{{:data.stored_power}}
-
-
\ No newline at end of file
diff --git a/nano/templates/botany_editor.tmpl b/nano/templates/botany_editor.tmpl
deleted file mode 100644
index 96cabc4341c..00000000000
--- a/nano/templates/botany_editor.tmpl
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
-{{if data.activity}}
- Scanning...
-{{else}}
- Buffered Genetic Data
- {{if data.disk}}
-
-
- Source:
-
-
- {{:data.sourceName}}
-
-
- Gene decay:
-
-
- {{if data.degradation <= 100}}
- {{:data.degradation}}%
- {{else}}
- FURTHER AMENDMENTS NONVIABLE
- {{/if}}
-
-
- Locus:
-
-
- {{:data.locus}}
-
- {{:helper.link('Eject Disk', 'arrow-circle-right', {'eject_disk' : 1}, null)}}
-
- {{else}}
- No disk loaded.
- {{/if}}
- Loaded Material
- {{if data.loaded}}
-
-
- Target:
-
-
- {{:data.loaded}}
-
- {{if data.degradation <= 100}}
- {{:helper.link('Apply Gene Mods', 'gear', {'apply_gene' : 1}, null)}}
- {{/if}}
- {{:helper.link('Eject Target', 'arrow-circle-right', {'eject_packet' : 1}, null)}}
-
- {{else}}
- No target seed packet loaded
- {{/if}}
-{{/if}}
\ No newline at end of file
diff --git a/nano/templates/botany_isolator.tmpl b/nano/templates/botany_isolator.tmpl
deleted file mode 100644
index a5efbc4a212..00000000000
--- a/nano/templates/botany_isolator.tmpl
+++ /dev/null
@@ -1,73 +0,0 @@
-
-
-{{if data.activity}}
- Scanning...
-{{else}}
- Buffered Genetic Data
- {{if data.hasGenetics}}
-
-
- Source:
-
-
- {{:data.sourceName}}
-
-
- Gene decay:
-
-
- {{:data.degradation}}%
-
-
- {{if data.disk}}
- {{for data.geneMasks}}
-
-
- {{:value}}
-
-
- {{:helper.link('Extract', 'arrow-circle-down', {'get_gene' : value}, null)}}
-
-
- {{empty}}
- Data error. Genetic record corrupt.
- {{/for}}
-
-
- {{:helper.link('Eject Loaded Disk', 'arrow-circle-right', {'eject_disk' : 1}, null)}}
- {{:helper.link('Clear Genetic Buffer', 'gear', {'clear_buffer' : 1}, null)}}
-
- {{else}}
- No disk inserted.
- {{/if}}
- {{else}}
- No data buffered.
- {{if data.disk}}
-
-
- {{:helper.link('Eject Loaded Disk', 'arrow-circle-right', {'eject_disk' : 1}, null)}}
-
- {{else}}
- No disk inserted.
- {{/if}}
- {{/if}}
- Loaded Material
- {{if data.loaded}}
-
-
- Packet loaded:
-
-
- {{:data.loaded}}
-
-
- {{:helper.link('Process Genome', 'gear', {'scan_genome' : 1}, null)}}{{:helper.link('Eject Packet', 'arrow-circle-right', {'eject_packet' : 1}, null)}}
-
-
- {{else}}
- No seeds loaded.
- {{/if}}
-{{/if}}
\ No newline at end of file
diff --git a/nano/templates/code_mirror.tmpl b/nano/templates/code_mirror.tmpl
deleted file mode 100644
index dce1bf6f43b..00000000000
--- a/nano/templates/code_mirror.tmpl
+++ /dev/null
@@ -1,14 +0,0 @@
-HELLO
-
-
diff --git a/nano/templates/crew_monitor.tmpl b/nano/templates/crew_monitor.tmpl
deleted file mode 100644
index 15ad2168808..00000000000
--- a/nano/templates/crew_monitor.tmpl
+++ /dev/null
@@ -1,16 +0,0 @@
-
-{{:helper.link('Show Tracker Map', 'thumb-tack', {'showMap' : 1})}}
-
- {{for data.crewmembers}}
- {{if value.sensor_type == 1}}
- | {{:value.name}} ({{:value.assignment}}) | {{:value.dead ? "Deceased" : "Living"}} | Not Available | {{if data.isAI}}{{:helper.link('Track', null, {}, 'disabled')}} | {{/if}}
- {{else value.sensor_type == 2}}
- | {{:value.name}} ({{:value.assignment}}) | {{:value.dead ? "Deceased" : "Living"}} ({{:value.oxy}}/{{:value.tox}}/{{:value.fire}}/{{:value.brute}}) | Not Available | {{if data.isAI}}{{:helper.link('Track', null, {}, 'disabled')}} | {{/if}}
- {{else value.sensor_type == 3}}
- | {{:value.name}} ({{:value.assignment}}) | {{:value.dead ? "Deceased" : "Living"}} ({{:value.oxy}}/{{:value.tox}}/{{:value.fire}}/{{:value.brute}}) | {{:value.area}}({{:value.x}}, {{:value.y}}) | {{if data.isAI}}{{:helper.link('Track', null, {'track' : value.ref})}} | {{/if}}
- {{/if}}
- {{/for}}
-
\ No newline at end of file
diff --git a/nano/templates/crew_monitor_map_content.tmpl b/nano/templates/crew_monitor_map_content.tmpl
deleted file mode 100644
index c2daaf874bb..00000000000
--- a/nano/templates/crew_monitor_map_content.tmpl
+++ /dev/null
@@ -1,16 +0,0 @@
-
-{{for data.crewmembers}}
- {{if value.sensor_type == 3}}
-
-
- {{:value.name}} ({{:value.assignment}}) ({{:value.dead ? "Deceased" : "Living"}}) ({{:value.oxy}}/{{:value.tox}}/{{:value.fire}}/{{:value.brute}}) ({{:value.area}}: {{:value.x}}, {{:value.y}})
-
-
- {{/if}}
-{{/for}}
-
-
-
\ No newline at end of file
diff --git a/nano/templates/crew_monitor_map_header.tmpl b/nano/templates/crew_monitor_map_header.tmpl
deleted file mode 100644
index c753dbce929..00000000000
--- a/nano/templates/crew_monitor_map_header.tmpl
+++ /dev/null
@@ -1,12 +0,0 @@
-
-{{:helper.link('Show Detail List', 'file-text', {'showMap' : 0})}}
-
-
Zoom Level:
-
x1.0
-
x1.5
-
x2.0
-
x2.5
-
\ No newline at end of file
diff --git a/nano/templates/disease_splicer.tmpl b/nano/templates/disease_splicer.tmpl
deleted file mode 100644
index fb248c0d6ca..00000000000
--- a/nano/templates/disease_splicer.tmpl
+++ /dev/null
@@ -1,108 +0,0 @@
-
-
- {{:helper.link('Close', 'gear', {'close' : 1}, null, 'fixedLeft')}}
-
-
-
-{{if data.busy}}
- The Splicer is currently busy.
-
-
{{:data.busy}}
-
-
- Thank you for your patience!
-
-{{else}}
-
-
Virus Dish
-
-
- {{:helper.link('Eject Dish', 'eject', { 'eject' : 1 }, data.dish_inserted ? null : 'disabled')}}
-
-
-
-
- Growth Density:
-
-
- {{:helper.displayBar(data.growth, 0, 100, (data.growth >= 50) ? 'good' : data.growth >= 25 ? 'average' : 'bad', data.growth + '%' )}}
-
-
-
-
-
- {{if !data.info}}
-
- Symptoms:
-
- {{/if}}
-
- {{if data.info}}
-
{{:data.info}}
- {{else}}
- {{for data.effects}}
-
-
- ({{:value.stage}}) {{:value.name}}
- {{if value.badness > 1}}
- Dangerous
- {{/if}}
-
-
- {{/for}}
- {{/if}}
-
-
- {{if data.affected_species && !data.info}}
-
-
- Affected Species:
-
-
- {{:data.affected_species}}
-
-
- {{/if}}
-
- {{if data.effects}}
-
- CAUTION: Reverse engineering will destroy the viral sample.
-
-
-
- Reverse Engineering:
-
-
- {{for data.effects}}
- {{:helper.link(value.stage, 'exchange', { 'grab' : value.reference })}}
- {{/for}}
-
-
- {{:helper.link('Species', 'exchange', { 'affected_species' : 1 })}}
-
-
- {{/if}}
-
-
-
Storage
-
-
-
-
- Memory Buffer:
-
-
- {{if data.buffer}}
- {{:data.buffer.name}} ({{:data.buffer.stage}})
- {{else}}
- {{if data.species_buffer}}
- {{:data.species_buffer}}
- {{else}}
- Empty
- {{/if}}
- {{/if}}
-
-
- {{:helper.link('Save To Disk', 'floppy-o', { 'disk' : 1 }, (data.buffer || data.species_buffer) ? null : 'disabled')}}
- {{:helper.link('Splice Onto Dish', 'pencil', { 'splice' : 1 }, ((data.buffer || data.species_buffer) && !data.info) ? null : 'disabled')}}
-{{/if}}
diff --git a/nano/templates/dish_incubator.tmpl b/nano/templates/dish_incubator.tmpl
deleted file mode 100644
index c8f9d51014b..00000000000
--- a/nano/templates/dish_incubator.tmpl
+++ /dev/null
@@ -1,123 +0,0 @@
-
-
- {{:helper.link('Close', 'gear', {'close' : '1'}, null, 'fixedLeft')}}
-
-
-
-
-
Environmental Conditions
-
-
-
- Power:
-
-
- {{:helper.link('On', 'power-off', { 'power' : 1 }, !data.dish_inserted ? 'disabled' : data.on ? 'selected' : null)}}{{:helper.link('Off', 'close', { 'power' : 1 }, data.on ? null : 'selected')}}
-
-
-
- {{:helper.link('Add Radiation', 'exclamation-circle', {'rad' : 1})}}
- {{:helper.link('Flush System', 'trash', {'flush' : 1}, data.system_in_use ? null : 'disabled')}}
-
-
-
-
-
- Virus Food:
-
-
- {{:helper.displayBar(data.food_supply, 0, 100, 'good', data.food_supply)}}
-
-
-
-
- Radiation Level:
-
-
- {{:helper.displayBar(data.radiation, 0, 100, (data.radiation >= 50) ? 'bad' : (data.growth >= 25) ? 'average' : 'good')}}
-
- {{:helper.formatNumber(data.radiation * 10000)}}
µSv
-
-
-
-
- Toxicity:
-
-
- {{:helper.displayBar(data.toxins, 0, 100, (data.toxins >= 50) ? 'bad' : (data.toxins >= 25) ? 'average' : 'good', data.toxins + '%')}}
-
-
-
-
-
-
Chemicals
-
-
- {{:helper.link('Eject Chemicals', 'eject', { 'ejectchem' : 1 }, data.chemicals_inserted ? null : 'disabled')}}
- {{:helper.link('Breed Virus', 'arrow-circle-down', { 'virus' : 1 }, data.can_breed_virus ? null : 'disabled')}}
-
-
-{{if data.chemicals_inserted}}
-
-
- Volume:
-
-
- {{:helper.displayBar(data.chemical_volume, 0, data.max_chemical_volume, 'good', data.chemical_volume + ' / ' + data.max_chemical_volume)}}
-
-
-
-
- Breeding Environment:
-
-
-
- {{:!data.dish_inserted ? 'N/A' : data.can_breed_virus ? 'Suitable' : 'No hemolytic samples detected'}}
-
- {{if data.blood_already_infected}}
-
- CAUTION: Viral infection detected in blood sample.
- {{/if}}
-
-
-{{else}}
-
- No chemicals inserted.
-
-{{/if}}
-
-
-
Virus Dish
-
-
- {{:helper.link('Eject Dish', 'eject', {'ejectdish' : 1}, data.dish_inserted ? null : 'disabled')}}
-
-
-{{if data.dish_inserted}}
- {{if data.virus}}
-
-
- Growth Density:
-
-
- {{:helper.displayBar(data.growth, 0, 100, (data.growth >= 50) ? 'good' : (data.growth >= 25) ? 'average' : 'bad', data.growth + '%' )}}
-
-
-
-
- Infection Rate:
-
-
- {{:data.analysed ? data.infection_rate : "Unknown"}}
-
-
- {{else}}
-
- No virus detected.
-
- {{/if}}
-{{else}}
-
- No dish loaded.
-
-{{/if}}
diff --git a/nano/templates/disposal_bin.tmpl b/nano/templates/disposal_bin.tmpl
deleted file mode 100644
index d211b3fbb17..00000000000
--- a/nano/templates/disposal_bin.tmpl
+++ /dev/null
@@ -1,52 +0,0 @@
-
-
-
- Pressure:
-
-
- {{:helper.smoothRound(data.pressure)}}%
-
-
-Controls
-
-
- Disposal Handle:
-
-
- {{if data.isAI}}
- {{:helper.link('Engaged', 'gear', {'handle' : 1}, 'disabled')}}
- {{:helper.link('Disengaged', 'gear', {'handle' : 0}, 'disabled')}}
- {{else}}
- {{:helper.link('Engaged', 'gear', {'handle' : 1}, data.flushing ? 'selected' : '')}}
- {{:helper.link('Disengaged', 'gear', {'handle' : 0}, !data.flushing ? 'selected' : '')}}
- {{/if}}
-
-
-
- Pump:
-
-
- {{:helper.link('On', 'gear', {'pump' : 1}, data.mode > 0 ? 'selected' : '')}}
- {{:helper.link('Off', 'gear', {'pump' : 0}, data.mode <= 0 ? 'selected' : '')}}
-
-
-
-
- Pump Status:
-
-
- {{:data.pumpstatus}}
-
-
-
-
- Contents:
-
-
- {{:helper.link('Eject', 'eject', {'eject' : 1}, data.isAI ? 'disabled' : '')}}
-
-
-
\ No newline at end of file
diff --git a/nano/templates/docking_airlock_console.tmpl b/nano/templates/docking_airlock_console.tmpl
deleted file mode 100644
index 91a9c81cf47..00000000000
--- a/nano/templates/docking_airlock_console.tmpl
+++ /dev/null
@@ -1,96 +0,0 @@
-
-
-
- Docking Port Status:
-
- {{if data.docking_status == "docked"}}
-
- {{if !data.override_enabled}}
- DOCKED
- {{else}}
- DOCKED-OVERRIDE ENABLED
- {{/if}}
-
- {{:helper.link('Override', 'exclamation-triangle', {'command' : 'toggle_override'}, null, data.override_enabled ? 'redButton' : null)}}
-
-
- {{else data.docking_status == "docking"}}
-
- {{if !data.override_enabled}}
- DOCKING
- {{else}}
- DOCKING-OVERRIDE ENABLED
- {{/if}}
-
- {{:helper.link('Override', 'exclamation-triangle', {'command' : 'toggle_override'}, null, data.override_enabled ? 'redButton' : null)}}
-
-
- {{else data.docking_status == "undocking"}}
-
- {{if !data.override_enabled}}
- UNDOCKING
- {{else}}
- UNDOCKING-OVERRIDE ENABLED
- {{/if}}
-
- {{:helper.link('Override', 'exclamation-triangle', {'command' : 'toggle_override'}, null, data.override_enabled ? 'redButton' : null)}}
-
-
- {{else data.docking_status == "undocked"}}
-
- {{if !data.override_enabled}}
- NOT IN USE
- {{else}}
- OVERRIDE ENABLED
- {{/if}}
-
- {{:helper.link('Override', 'exclamation-triangle', {'command' : 'toggle_override'}, null, data.override_enabled ? 'redButton' : null)}}
-
-
- {{else}}
-
ERROR
- {{:helper.link('Override', 'exclamation-triangle', {'command' : 'toggle_override'}, null, data.override_enabled ? 'redButton' : null)}}
- {{/if}}
-
-
-
-
-
- Chamber Pressure:
-
-
- {{:helper.displayBar(data.chamber_pressure, 0, 200, (data.chamber_pressure < 80 || data.chamber_pressure > 120) ? 'bad' : (data.chamber_pressure < 95 || data.chamber_pressure > 110) ? 'average' : 'good')}}
-
- {{:helper.smoothRound(data.chamber_pressure)}} kPa
-
-
-
-
-
-
-
- {{:helper.link('Cycle to Exterior', 'arrow-circle-o-left', {'command' : 'cycle_ext'}, (data.processing || data.airlock_disabled) ? 'disabled' : null)}}
- {{:helper.link('Cycle to Interior', 'arrow-circle-right', {'command' : 'cycle_int'}, (data.processing || data.airlock_disabled) ? 'disabled' : null)}}
-
-
- {{if data.airlock_disabled}}
- {{:helper.link('Force exterior door', 'exclamation-triangle', {'command' : 'force_ext'}, 'disabled', null)}}
- {{:helper.link('Force interior door', 'exclamation-triangle', {'command' : 'force_int'}, 'disabled', null)}}
- {{else}}
- {{if data.interior_status.state == "open"}}
- {{:helper.link('Force exterior door', 'exclamation-triangle', {'command' : 'force_ext'}, null, 'redButton')}}
- {{else}}
- {{:helper.link('Force exterior door', 'exclamation-triangle', {'command' : 'force_ext'}, null, data.processing ? 'yellowButton' : null)}}
- {{/if}}
- {{if data.exterior_status.state == "open"}}
- {{:helper.link('Force interior door', 'exclamation-triangle', {'command' : 'force_int'}, null, 'redButton')}}
- {{else}}
- {{:helper.link('Force interior door', 'exclamation-triangle', {'command' : 'force_int'}, null, data.processing ? 'yellowButton' : null)}}
- {{/if}}
- {{/if}}
-
-
-
- {{:helper.link('Abort', 'ban', {'command' : 'abort'}, (data.processing && !data.airlock_disabled) ? null : 'disabled', (data.processing && !data.airlock_disabled) ? 'redButton' : null)}}
-
-
\ No newline at end of file
diff --git a/nano/templates/engines_control.tmpl b/nano/templates/engines_control.tmpl
deleted file mode 100644
index ae44ff572c0..00000000000
--- a/nano/templates/engines_control.tmpl
+++ /dev/null
@@ -1,84 +0,0 @@
-
- {{:helper.link('Overall status', 'sticky-note', {'state' :'status'}, null, state == 'status' ? 'selected' : null)}}
- {{:helper.link('Details', 'sticky-note', {'state' : 'engines'}, null, state == 'engines' ? 'selected' : null)}}
-
-
-{{if data.state == "engines"}}
- {{if data.engines_info}}
- {{for data.engines_info}}
-
-
- Engine #{{:(index + 1)}}:
-
-
- {{:helper.link(value.eng_on ? 'Shutdown' : 'Power up', 'power-off', { 'toggle' : 1, 'engine' : value.eng_reference }, null, value.eng_on ? 'selected' : null)}}
-
-
-
-
-
- Type:
-
-
- {{:value.eng_type}}
-
-
-
-
- Status:
-
-
- {{:value.eng_on ? 'Online' : 'Offline'}}
- {{:value.eng_status}}
-
-
-
-
- Current thrust:
-
-
- {{:value.eng_thrust}}
-
-
-
-
- Thrust limit:
-
-
- {{:helper.link('', 'plus-circle', { 'limit' : 0.1, 'engine' : value.eng_reference }, null, null)}}
- {{:helper.link(value.eng_thrust_limiter+'%', null, { 'set_limit' : 1, 'engine' : value.eng_reference }, null, null)}}
- {{:helper.link('', 'minus-circle', { 'limit' : -0.1, 'engine' : value.eng_reference }, null, null)}}
-
-
-
- {{/for}}
- {{/if}}
-{{/if}}
-{{if data.state == "status"}}
- {{if data.engines_info}}
- {{for data.engines_info}}
-
-
-
- Engine #{{:(index + 1)}}:
-
-
- {{:helper.link(value.eng_on ? 'Shutdown' : 'Power up', 'power-off', { 'toggle' : 1, 'engine' : value.eng_reference }, null, value.eng_on ? 'selected' : null)}}
-
-
-
-
- Thrust:
-
- Thrust limit:
-
-
- {{:value.eng_thrust}}
-
- {{:value.eng_thrust_limiter}}%
-
-
-
- {{/for}}
- {{/if}}
-{{/if}}
\ No newline at end of file
diff --git a/nano/templates/escape_pod_berth_console.tmpl b/nano/templates/escape_pod_berth_console.tmpl
deleted file mode 100644
index 7bccb3205c4..00000000000
--- a/nano/templates/escape_pod_berth_console.tmpl
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-
- Escape Pod Status:
-
-
- {{if data.docking_status == "docked"}}
- {{if data.armed}}
- ARMED
- {{else}}
- SYSTEMS OK
- {{/if}}
- {{else data.docking_status == "undocking"}}
- EJECTING-STAND CLEAR!
- {{else data.docking_status == "undocked"}}
- POD EJECTED
- {{else data.docking_status == "docking"}}
- INITIALIZING...
- {{else}}
- ERROR
- {{/if}}
-
-
-
-
-
-
- {{if data.armed}}
- {{if data.docking_status == "docked"}}
- {{:helper.link('Force exterior door', 'exclamation-triangle', {'command' : 'force_door'}, data.override_enabled ? null : 'disabled', null)}}
- {{:helper.link('Override', 'exclamation-triangle', {'command' : 'toggle_override'}, null, data.override_enabled ? 'redButton' : null)}}
- {{else}}
- {{:helper.link('Force exterior door', 'exclamation-triangle', {'command' : 'force_door'}, data.override_enabled ? null : 'disabled', data.override_enabled ? 'redButton' : null)}}
- {{:helper.link('Override', 'exclamation-triangle', {'command' : 'toggle_override'}, null, data.override_enabled ? 'redButton' : 'yellowButton')}}
- {{/if}}
- {{else}}
- {{:helper.link('Force exterior door', 'exclamation-triangle', {'command' : 'force_door'}, 'disabled', null)}}
- {{:helper.link('Override', 'exclamation-triangle', {'command' : 'toggle_override'}, 'disabled', null)}}
- {{/if}}
-
-
-
\ No newline at end of file
diff --git a/nano/templates/escape_pod_console.tmpl b/nano/templates/escape_pod_console.tmpl
deleted file mode 100644
index a99cb1e6810..00000000000
--- a/nano/templates/escape_pod_console.tmpl
+++ /dev/null
@@ -1,95 +0,0 @@
-
-
-
- Escape Pod Status:
-
-
- {{if data.docking_status == "docked"}}
- {{if data.is_armed}}
- ARMED
- {{else}}
- SYSTEMS OK
- {{/if}}
- {{else data.docking_status == "undocking"}}
- EJECTING
- {{else data.docking_status == "undocked"}}
- POD EJECTED
- {{else data.docking_status == "docking"}}
- DOCKING
- {{else}}
- ERROR
- {{/if}}
-
-
-
-
-
-
- Docking Hatch:
-
-
- {{if data.docking_status == "docked"}}
- {{if data.door_state == "open"}}
- OPEN
- {{else data.door_state == "closed"}}
- CLOSED
- {{else}}
- ERROR
- {{/if}}
- {{else data.docking_status == "docking"}}
- {{if data.door_state == "open"}}
- OPEN
- {{else data.door_state == "closed" && data.door_lock == "locked"}}
- SECURED
- {{else data.door_state == "closed" && data.door_lock == "unlocked"}}
- UNSECURED
- {{else}}
- ERROR
- {{/if}}
- {{else data.docking_status == "undocking"}}
- {{if data.door_state == "open"}}
- OPEN
- {{else data.door_state == "closed" && data.door_lock == "locked"}}
- SECURED
- {{else data.door_state == "closed" && data.door_lock == "unlocked"}}
- UNSECURED
- {{else}}
- ERROR
- {{/if}}
- {{else data.docking_status == "undocked"}}
- {{if data.door_state == "open"}}
- OPEN
- {{else data.door_state == "closed" && data.door_lock == "locked"}}
- SECURED
- {{else data.door_state == "closed" && data.door_lock == "unlocked"}}
- UNSECURED
- {{else}}
- ERROR
- {{/if}}
- {{else}}
- ERROR
- {{/if}}
-
-
-
-
-
-
- {{if data.docking_status == "docked"}}
- {{:helper.link('Force exterior door', 'exclamation-triangle', {'command' : 'force_door'}, data.override_enabled ? null : 'disabled', null)}}
- {{:helper.link('Override', 'exclamation-triangle', {'command' : 'toggle_override'}, null, data.override_enabled ? 'redButton' : null)}}
- {{else}}
- {{:helper.link('Force exterior door', 'exclamation-triangle', {'command' : 'force_door'}, data.override_enabled ? null : 'disabled', data.override_enabled ? 'redButton' : null)}}
- {{:helper.link('Override', 'exclamation-triangle', {'command' : 'toggle_override'}, null, data.override_enabled ? 'redButton' : 'yellowButton')}}
- {{/if}}
-
-
-
-
-
-
- {{:helper.link('ARM', 'exclamation-triangle', {'command' : 'manual_arm'}, data.is_armed ? 'disabled' : null, data.is_armed ? 'redButton' : 'yellowButton')}}
- {{:helper.link('MANUAL EJECT', 'exclamation-triangle', {'command' : 'force_launch'}, data.can_force ? null : 'disabled', data.can_force ? 'yellowButton' : null)}}
-
-
-
diff --git a/nano/templates/escape_shuttle_control_console.tmpl b/nano/templates/escape_shuttle_control_console.tmpl
deleted file mode 100644
index eab831464a8..00000000000
--- a/nano/templates/escape_shuttle_control_console.tmpl
+++ /dev/null
@@ -1,84 +0,0 @@
-Shuttle Status
-
-
- {{:data.shuttle_status}}
-
-
-
-
-
- Bluespace Drive:
-
-
- {{if data.shuttle_state == "idle"}}
- IDLE
- {{else data.shuttle_state == "warmup"}}
- SPINNING UP
- {{else data.shuttle_state == "in_transit"}}
- ENGAGED
- {{else}}
- ERROR
- {{/if}}
-
-
-
-{{if data.has_docking}}
-
-
-
- Docking Status:
-
-
- {{if data.docking_status == "docked"}}
- DOCKED
- {{else data.docking_status == "docking"}}
- {{if !data.docking_override}}
- DOCKING
- {{else}}
- DOCKING-MANUAL
- {{/if}}
- {{else data.docking_status == "undocking"}}
- {{if !data.docking_override}}
- UNDOCKING
- {{else}}
- UNDOCKING-MANUAL
- {{/if}}
- {{else data.docking_status == "undocked"}}
- UNDOCKED
- {{else}}
- ERROR
- {{/if}}
-
-
-
-{{/if}}
-Shuttle Authorization
-
-
- {{if data.has_auth}}
- Access Granted. Shuttle controls unlocked.
- {{else}}
- Additional authorization required.
- {{/if}}
-
-
-
- {{for data.auth_list}}
- {{if value.auth_hash}}
- {{:helper.link(value.auth_name, 'eject', {'removeid' : value.auth_hash}, null, 'itemContentWide')}}
- {{else}}
- {{:helper.link("", 'eject', {'scanid' : 1}, null, 'itemContentWide')}}
- {{/if}}
- {{/for}}
-
-
-Shuttle Control
-
-
-
- {{:helper.link('Launch Shuttle', 'arrow-circle-right', {'move' : '1'}, data.can_launch ? null : 'disabled' , null)}}
-{{:helper.link('Cancel Launch', 'ban', {'cancel' : '1'}, data.can_cancel ? null : 'disabled' , null)}}
- {{:helper.link('Force Launch', 'exclamation-triangle', {'force' : '1'}, data.can_force ? null : 'disabled' , data.can_force ? 'redButton' : null)}}
-
-
-
\ No newline at end of file
diff --git a/nano/templates/geoscanner.tmpl b/nano/templates/geoscanner.tmpl
deleted file mode 100644
index 4204d6466a8..00000000000
--- a/nano/templates/geoscanner.tmpl
+++ /dev/null
@@ -1,185 +0,0 @@
-
-
-Machine Status
-
-
- {{:helper.link(data.scanning ? 'Halt Scan' : 'Begin Scan', 'signal', {'scanItem' : 1}, null)}}
-
-
- {{:helper.link('Eject item', 'eject', {'ejectItem' : 1}, (data.scanned_item && !data.scanning) ? null : 'disabled')}}
-
-
-
-
-
-
Item:
-
- {{if data.scanned_item}}
- {{:data.scanned_item}}
- {{else}}
- No item inserted
- {{/if}}
-
-
-
-
Heuristic analysis:
-
- {{if data.scanned_item_desc}}
- {{:data.scanned_item_desc}}
- {{/if}}
-
-
-
-
-Scanner
-
-
Scan progress:
-
- {{:helper.displayBar(data.scan_progress, 0, 100, 'good')}}
- {{:helper.smoothRound(data.scan_progress)}} %
-
-
- {{if data.scan_progress >= 100}}
- Scan completed successfully.
- {{/if}}
-
-
-
-
Vacuum seal integrity:
-
- {{:helper.displayBar(data.scanner_seal_integrity, 0, 100, ((data.scanner_seal_integrity < 66) ? ((data.scanner_seal_integrity < 33) ? 'bad' : 'average') : 'good'))}}
- {{:helper.smoothRound(data.scanner_seal_integrity)}} %
-
-
- {{if data.scanner_seal_integrity < 25}}
- Warning! Vacuum seal breach will result in scan failure!
- {{/if}}
-
-
-
-MASER
-
-
MASER Efficiency:
-
- {{:helper.displayBar(data.maser_efficiency, 1, 100, ((data.maser_efficiency < 66) ? ((data.maser_efficiency) < 33 ? 'bad' : 'average') : 'good'))}}
- {{:data.maser_efficiency}} %
-
-
- {{if data.maser_efficiency < 50}}
- Match wavelengths to progress the scan.
- {{/if}}
-
-
-
-
Optimal Wavelength:
-
- {{:helper.displayBar(data.optimal_wavelength, 1, 10000, 'good')}}
- {{:data.optimal_wavelength}} MHz
-
-
-
-
Current Wavelength:
-
- {{:helper.displayBar(data.maser_wavelength, 1, 10000, 'good')}}
- {{:data.maser_wavelength}} MHz
-
-
- {{:helper.link('-2 KHz', null, {'maserWavelength' : -2}, null)}}
- {{:helper.link('-1 KHz', null, {'maserWavelength' : -1}, null)}}
- {{:helper.link('-0.5 KHz', null, {'maserWavelength' : -0.5}, null)}}
-
-
- {{:helper.link('+0.5 KHz', null, {'maserWavelength' : 0.5}, null)}}
- {{:helper.link('+1 KHz', null, {'maserWavelength' : 1}, null)}}
- {{:helper.link('+2 KHz', null, {'maserWavelength' : 2}, null)}}
-
-
-
-Environment / Internal
-
-
Centrifuge speed:
-
- {{:helper.displayBar(data.scanner_rpm, 0, 1000, 'good')}}
- {{:data.scanner_rpm}} RPM
-
-
-
-
Internal temperature:
-
- {{:helper.displayBar(data.scanner_temperature, 0, 1273, (data.scanner_temperature > 250 ? (data.scanner_temperature > 1000 ? 'bad' : 'average') : 'good'))}}
- {{:helper.smoothRound(data.scanner_temperature)}} K
-
-
- {{if data.scanner_temperature > 1000}}
- Warning! Exceeding 1200K will result in scan failure!
- {{/if}}
-
-
-
-Radiation
-
-
Ambient radiation:
-
- {{:helper.displayBar(data.radiation, 0, 100, ((data.radiation > 15) ? ((data.radiation > 65) ? 'bad' : 'average') : 'good'))}}
- {{:helper.smoothRound(data.radiation)}} mSv
-
-
- {{:helper.link(data.rad_shield_on ? 'Disable Radiation Shielding' : 'Enable Radiation Shielding', 'exclamation-circle', {'toggle_rad_shield' : 1}, null)}}
- {{if data.rad_shield_on}}
- Shield blocking scanner.
- {{/if}}
-
-
-
-Cooling
-
-
Coolant remaining:
-
- {{:helper.displayBar(data.unused_coolant_per, 0, 100, ((data.unused_coolant_per < 66) ? ((data.unused_coolant_per < 33) ? 'bad' : 'average') : 'good'))}}
- {{:helper.smoothRound(data.unused_coolant_abs)}} u
-
-
- {{if data.unused_coolant_per < 20}}
- Warning! Coolant stocks low!
- {{/if}}
-
-
-
-
Coolant flow rate:
-
- {{:helper.displayBar(data.coolant_usage_rate, 0, 10, 'good')}}
- {{:helper.smoothRound(data.coolant_usage_rate)}} u/s
-
-
- {{:helper.link('Min u/s', null, {'coolantRate' : -10}, null)}}
- {{:helper.link('-3 u/s', null, {'coolantRate' : -3}, null)}}
- {{:helper.link('-1 u/s', null, {'coolantRate' : -1}, null)}}
-
-
- {{:helper.link('+1 u/s', null, {'coolantRate' : 1}, null)}}
- {{:helper.link('+3 u/s', null, {'coolantRate' : 3}, null)}}
- {{:helper.link('Max u/s', null, {'coolantRate' : 10}, null)}}
-
-
-
-
Coolant purity:
-
- {{:helper.displayBar(data.coolant_purity, 0, 100, ((data.coolant_purity < 66) ? ((data.coolant_purity < 33) ? 'bad' : 'average') : 'good'))}}
- {{:data.coolant_purity}} %
-
-
- {{if data.coolant_purity < 0.5}}
- Warning! Check coolant for contaminants!
- {{/if}}
-
-
-
-Latest Results
-
-
- {{:data.last_scan_data}}
-
-
diff --git a/nano/templates/hardsuit.tmpl b/nano/templates/hardsuit.tmpl
deleted file mode 100644
index 92ab1c0fadf..00000000000
--- a/nano/templates/hardsuit.tmpl
+++ /dev/null
@@ -1,259 +0,0 @@
-
-
-
-
-{{if data.interfacelock || data.malf > 0}}
- -- HARDSUIT INTERFACE OFFLINE --
-{{else}}
- {{if data.aicontrol && data.ai != 1}}
- -- HARDSUIT CONTROL OVERRIDDEN BY AI --
- {{else}}
-
-
-
-
-
-
- Suit status:
-
-
- {{if data.sealing == 1}}
-
PROCESSING
- {{else}}
- {{if data.seals == 1}}
-
INACTIVE
- {{else}}
-
ACTIVE
- {{/if}}
- {{/if}}
-
-
- {{:helper.link('Toggle', 'arrow-circle-down', {'toggle_seals' : 1}, null)}}
-
-
-
-
- Cover status:
-
-
- {{if data.emagged || !data.securitycheck}}
-
ERROR - MAINTENANCE LOCK CONTROL OFFLINE
- {{else}}
- {{if data.coverlock}}
-
LOCKED
- {{else}}
-
UNLOCKED
- {{/if}}
- {{/if}}
-
-
- {{:helper.link('Toggle', 'arrow-circle-down', {'toggle_suit_lock' : 1}, null)}}
-
-
-
-
-
- Hardware
- Suit pieces
-
-
-
-
- Helmet:
-
-
- {{:helper.capitalizeFirstLetter(data.helmet)}}
-
- {{if data.sealing != 1}}
-
- {{:helper.link('Toggle', 'arrow-circle-down', {'toggle_piece' : 'helmet'}, null)}}
-
- {{/if}}
-
-
-
- Gauntlets:
-
-
- {{:helper.capitalizeFirstLetter(data.gauntlets)}}
-
- {{if data.sealing != 1}}
-
- {{:helper.link('Toggle', 'arrow-circle-down', {'toggle_piece' : 'gauntlets'}, null)}}
-
- {{/if}}
-
-
-
- Boots:
-
-
- {{:helper.capitalizeFirstLetter(data.boots)}}
-
- {{if data.sealing != 1}}
-
- {{:helper.link('Toggle', 'arrow-circle-down', {'toggle_piece' : 'boots'}, null)}}
-
- {{/if}}
-
-
-
- Chestpiece:
-
-
- {{:helper.capitalizeFirstLetter(data.chest)}}
-
- {{if data.sealing != 1}}
-
- {{:helper.link('Toggle', 'arrow-circle-down', {'toggle_piece' : 'chest'}, null)}}
-
- {{/if}}
-
-
-
- System modules
- {{if data.seals == 1 || data.sealing == 1}}
- HARDSUIT SYSTEMS OFFLINE
- {{else}}
- Selected primary system:
- {{if data.primarysystem}}
- {{:helper.capitalizeFirstLetter(data.primarysystem)}}
- {{else}}
- None
- {{/if}}
-
- {{if data.modules}}
-
- {{for data.modules}}
-
-
-
-
{{:helper.capitalizeFirstLetter(value.name)}}
- {{if value.damage > 0}}
-
- {{if value.damage == 1}}
- (
damaged
)
- {{else}}
- (
destroyed
)
- {{/if}}
-
- {{/if}}
-
-
- Engage: {{:value.engagecost}}
- Activate: {{:value.activecost}}
- Passive: {{:value.passivecost}}
-
-
- {{:value.desc}}
-
-
- {{if value.can_use == 1}}
-
- {{:helper.link(value.engagestring, 'arrow-circle-down', {'interact_module' : value.index, 'module_mode' : 'engage'}, null)}}
-
- {{/if}}
- {{if value.can_select == 1}}
-
- {{if value.name == data.primarysystem}}
-
SELECTED
- {{else}}
- {{:helper.link('Select', 'arrow-circle-down', {'interact_module' : value.index, 'module_mode' : 'select'}, null)}}
- {{/if}}
-
- {{/if}}
- {{if value.can_toggle == 1}}
-
- {{if value.is_active == 1}}
- {{:helper.link(value.deactivatestring, 'arrow-circle-down', {'interact_module' : value.index, 'module_mode' : 'deactivate'}, null)}}
- {{else}}
- {{:helper.link(value.activatestring, 'arrow-circle-down', {'interact_module' : value.index, 'module_mode' : 'activate'}, null)}}
- {{/if}}
-
- {{/if}}
-
-
-
-
- {{if value.charges}}
-
Stored charges
-
-
Selected:
{{:helper.capitalizeFirstLetter(value.chargetype)}}
-
- {{for value.charges :itemValue:itemIndex}}
-
- {{:helper.link(helper.capitalizeFirstLetter(itemValue.caption), null, {'interact_module' : value.index, 'module_mode' : 'select_charge_type', 'charge_type' : itemValue.index}, null)}}
-
- {{/for}}
- {{/if}}
-
-
-
- {{/for}}
-
- {{else}}
- None.
- {{/if}}
- {{/if}}
- {{/if}}
-{{/if}}
\ No newline at end of file
diff --git a/nano/templates/helm.tmpl b/nano/templates/helm.tmpl
deleted file mode 100644
index 615d4ab46d0..00000000000
--- a/nano/templates/helm.tmpl
+++ /dev/null
@@ -1,115 +0,0 @@
-
-
-
Sector information
-
- {{:data.sector}}
-
- Coordinates: {{:data.s_x}} : {{:data.s_y}}
-
- Additional information: {{:data.s_x}} : {{:data.s_y}}
- {{:data.sector_info}}
-
-
-
-
-
Flight data
-
-
-
- Speed:
-
-
- {{:data.speed}}
-
-
-
-
- Acceleration:
-
-
- {{:data.accel}}
-
-
-
-
- Heading:
-
-
- {{:data.heading}}
-
-
-
-
-
-
-Manual control
-
-
-
-
- {{:helper.link('', 'caret-left fa-rotate-45', { 'move' : 9 }, null, null)}}
- {{:helper.link('', 'caret-up', { 'move' : 1 }, null, null)}}
- {{:helper.link('', 'caret-up fa-rotate-45', { 'move' : 5 }, null, null)}}
-
-
- {{:helper.link('', 'caret-left', { 'move' : 8 }, null, null)}}
- {{:helper.link('', 'circle-close', { 'brake' : 1 }, null, null)}}
- {{:helper.link('', 'caret-right', { 'move' : 4 }, null, null)}}
-
-
- {{:helper.link('', 'caret-down fa-rotate-45', { 'move' : 10 }, null, null)}}
- {{:helper.link('', 'caret-down', { 'move' : 2 }, null, null)}}
- {{:helper.link('', 'caret-right fa-rotate-45', { 'move' : 6 }, null, null)}}
-
-
-
-
-
- Direct control
- {{:helper.link(data.manual_control ? 'Engaged' : 'Disengaged', 'random', { 'manual' : 1 }, data.manual_control ? 'selected' : null, null)}}
-
-
-
-
-
-
-
-
Autopilot
-
-
- {{:helper.link(data.autopilot ? 'Engaged' : 'Disengaged', 'gear', { 'apilot' : 1 }, data.dest ? null : 'disabled', data.autopilot ? 'selected' : null)}}
-
-
-
-
- Target coordinates
-
-
- {{if data.dest}}
- {{:helper.link(data.d_x, null, { 'setx' : 1 }, null, null)}} {{:helper.link(data.d_y, null, { 'sety' : 1 }, null, null)}}
- {{else}}
- {{:helper.link('None', null, { 'sety' : 1, 'setx' : 1 }, null, null)}}
- {{/if}}
-
-
-
-Navigation data
-
- {{:helper.link('Save current position', 'floppy-o', { 'add' : 'current' }, null)}}
- {{:helper.link('Add new entry', 'file', { 'add' : 'new' }, null)}}
-
-
-
- {{if data.locations}}
- {{for data.locations}}
-
- {{:value.name}}:
- {{:value.x}} : {{:value.y}}
-
-
- {{:helper.link('Plot course', 'arrow-right', { 'x' : value.x, 'y' : value.y }, null, null)}}
- {{:helper.link('Remove entry', 'close', { 'remove' : value.reference }, null, null)}}
-
- {{/for}}
- {{/if}}
-
diff --git a/nano/templates/isolation_centrifuge.tmpl b/nano/templates/isolation_centrifuge.tmpl
deleted file mode 100644
index 4ff0272df02..00000000000
--- a/nano/templates/isolation_centrifuge.tmpl
+++ /dev/null
@@ -1,81 +0,0 @@
-
- {{:helper.link('Close', 'gear', {'close' : 1}, null, 'fixedLeft')}}
- {{:helper.link('Print', 'print', { 'print' : 1 }, data.antibodies || data.pathogens ? null : 'disabled', 'fixedLeft')}}
-
-
-{{if data.busy}}
- The Centrifuge is currently busy.
-
-
{{:data.busy}}
-
-
- Thank you for your patience!
-
-{{else}}
-
-
{{:data.is_antibody_sample ? 'Antibody Sample' : 'Blood Sample'}}
-
-
- {{:helper.link('Eject Vial', 'eject', { 'action' : 'sample' }, data.sample_inserted ? null : 'disabled')}}
-
- {{if data.sample_inserted}}
- {{if data.antibodies || data.pathogens}}
-
- {{if data.antibodies}}
-
-
- Antibodies:
-
-
- {{:data.antibodies}}
-
-
- {{/if}}
- {{if data.pathogens}}
-
-
- Pathogens:
-
-
- {{for data.pathogens}}
-
- {{:value.name}} ({{:value.spread_type}})
-
- {{/for}}
-
-
- {{/if}}
-
- {{else}}
-
- No antibodies or viral strains detected.
-
- {{/if}}
- {{else}}
-
- No vial detected.
-
- {{/if}}
- {{if data.antibodies && !data.is_antibody_sample}}
-
-
- Isolate Antibodies:
-
-
- {{:helper.link(data.antibodies, 'pencil', { 'action' : 'antibody' })}}
-
-
- {{/if}}
- {{if data.pathogens}}
-
-
- Isolate Strain:
-
-
- {{for data.pathogens}}
- {{:helper.link(value.name, 'pencil', { 'isolate' : value.reference })}}
- {{/for}}
-
-
- {{/if}}
-{{/if}}
diff --git a/nano/templates/multi_docking_console.tmpl b/nano/templates/multi_docking_console.tmpl
deleted file mode 100644
index 9515799644e..00000000000
--- a/nano/templates/multi_docking_console.tmpl
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
- Docking Port Status:
-
-
- {{if data.docking_status == "docked"}}
- DOCKED
- {{else data.docking_status == "docking"}}
- DOCKING
- {{else data.docking_status == "undocking"}}
- UNDOCKING
- {{else data.docking_status == "undocked"}}
- NOT IN USE
- {{else}}
- ERROR
- {{/if}}
-
-
-
-
-{{for data.airlocks}}
-
-
-
- {{:value.name}}
-
-
- {{if value.override_enabled}}
- OVERRIDE ENABLED
- {{else}}
- STATUS OK
- {{/if}}
-
-
-
-{{/for}}
\ No newline at end of file
diff --git a/nano/templates/pathogenic_isolator.tmpl b/nano/templates/pathogenic_isolator.tmpl
deleted file mode 100644
index 119d5b6b7fe..00000000000
--- a/nano/templates/pathogenic_isolator.tmpl
+++ /dev/null
@@ -1,107 +0,0 @@
-
-
Menu
-
-
- {{if !data.isolating}}
- {{:helper.link('Home', 'home', {'home' : 1}, data.state == 'home' ? 'disabled' : null, 'fixedLeft')}}
- {{:helper.link('List', 'sticky-note', {'list' : 1}, data.state == 'list' ? 'disabled' : null, 'fixedLeft')}}
- {{:helper.link('Pathogen', 'folder-open', {'entry' : 1}, data.state == 'entry' ? 'disabled' : null, 'fixedLeft')}}
- {{/if}}
-
- {{:helper.link('Close', 'gear', {'close' : 1}, null, 'fixedLeft')}}
- {{:helper.link('Print', 'print', { 'print' : 1 }, data.can_print ? null : 'disabled', 'fixedLeft')}}
-
-
-{{if data.isolating}}
- The Isolator is currently busy.
-
-
Isolating pathogens...
-
-
- Thank you for your patience!
-
-{{else}}
- {{if data.state =="home"}}
-
-
Blood Sample
-
-
- {{:helper.link('Eject Syringe', 'eject', { 'eject' : 1 }, data.syringe_inserted ? null : 'disabled')}}
-
-
- {{if data.syringe_inserted}}
-
-
Pathogens:
- {{if data.pathogen_pool}}
- {{for data.pathogen_pool}}
-
- {{:index + 1}}. #{{:value.unique_id}} {{:value.is_in_database ? "(Analysed)" : ""}}
- {{:value.name}}: {{:value.dna}}
-
- {{/for}}
- {{else}}
- No pathogens detected.
- {{/if}}
-
- {{else}}
-
- No syringe loaded.
-
- {{/if}}
- {{if data.pathogen_pool}}
-
-
- Isolate Pathogens:
-
-
- {{for data.pathogen_pool}}
- {{:helper.link('#' + value.unique_id, 'pencil', { 'isolate' : value.reference }, null, 'fixedLeft')}}
- {{/for}}
-
-
-
-
- Database Lookup:
-
-
- {{for data.pathogen_pool}}
- {{if value.is_in_database}}
- {{:helper.link('#' + value.unique_id, 'info', { 'entry' : 1, 'view' : value.record }, null, 'fixedLeft')}}
- {{/if}}
- {{/for}}
-
-
- {{/if}}
- {{else}}
- {{if data.state == "list"}}
-
-
View Database
-
-
- {{if data.database}}
- {{for data.database}}
-
-
{{:data.name}}
- {{:helper.link('Details', 'arrow-circle-down', { 'entry' : 1, 'view' : value.record }, null, 'fixedLeft')}}
-
- {{/for}}
- {{else}}
-
The viral database is empty.
- {{/if}}
-
- {{else}}
- {{if data.state == "entry"}}
- {{if data.entry}}
-
-
{{:data.entry.name}}
-
-
- {{:data.entry.description}}
-
- {{else}}
- No virus selected.
- {{/if}}
- {{/if}}
- {{/if}}
- {{/if}}
-{{/if}}
diff --git a/nano/templates/pda_janitor.tmpl b/nano/templates/pda_janitor.tmpl
index a2fd282ad3f..864692d8a04 100644
--- a/nano/templates/pda_janitor.tmpl
+++ b/nano/templates/pda_janitor.tmpl
@@ -8,43 +8,59 @@
{{/if}}
+ERROR: An Ionspheric overload has occured. Please wait for the machine to reboot. This cannot be manually done.
+
+{{/if}}
{{if data.tab == "CONFIG"}}