diff --git a/code/__defines/_byond_version_compat.dm b/code/__defines/_byond_version_compat.dm
index 61d61853a893..8e843d66d713 100644
--- a/code/__defines/_byond_version_compat.dm
+++ b/code/__defines/_byond_version_compat.dm
@@ -1,5 +1,5 @@
-#define REQUIRED_DM_VERSION 515
+#define REQUIRED_DM_VERSION 516
#if DM_VERSION < REQUIRED_DM_VERSION
-#warn Nebula is not tested on BYOND versions older than 515. The code may not compile, and if it does compile it may have severe problems.
+#warn Nebula is not tested on BYOND versions older than 516. The code may not compile, and if it does compile it may have severe problems.
#endif
\ No newline at end of file
diff --git a/code/__defines/math_physics.dm b/code/__defines/math_physics.dm
index 4edf99ad88af..64dd03e8c1d3 100644
--- a/code/__defines/math_physics.dm
+++ b/code/__defines/math_physics.dm
@@ -27,7 +27,7 @@
#define ATM *ONE_ATMOSPHERE
#define ATMOS_PRECISION 0.0001
-#define QUANTIZE(variable) (round(variable, ATMOS_PRECISION))
+#define QUANTIZE(variable) (NONUNIT_FLOOR(variable, ATMOS_PRECISION))
#define INFINITY 1.#INF
diff --git a/code/_helpers/lists.dm b/code/_helpers/lists.dm
index a39367a43233..0a0c554c5fb0 100644
--- a/code/_helpers/lists.dm
+++ b/code/_helpers/lists.dm
@@ -272,6 +272,13 @@ Checks if a list has the same entries and values as an element of big.
else
.[key] = call(merge_method)(.[key], b_value)
+// Picks a key in an alist. This is awful but hey, what can you do?
+/proc/apick(alist/target_alist)
+ var/index = rand(1, length(target_alist))
+ for(var/key in target_alist)
+ if(--index == 0)
+ return key
+
//Pretends to pick an element based on its weight but really just seems to pick a random element.
/proc/pickweight(list/target_list)
var/total = 0
diff --git a/code/_helpers/serde.dm b/code/_helpers/serde.dm
index 9d50f3fae347..4ff9ff8e3004 100644
--- a/code/_helpers/serde.dm
+++ b/code/_helpers/serde.dm
@@ -51,7 +51,7 @@
if(!area)
area = new load_path(null)
instanced_areas[load_path] = area
- ChangeArea(spawn_loc, area)
+ spawn_loc.ChangeArea(area)
else if(ispath(load_path, /atom))
created_instance = new load_path(spawn_loc)
diff --git a/code/_helpers/turfs.dm b/code/_helpers/turfs.dm
index d74b742f97a5..c39b745f6b03 100644
--- a/code/_helpers/turfs.dm
+++ b/code/_helpers/turfs.dm
@@ -120,9 +120,9 @@
if(target)
if(base_area)
- ChangeArea(target, get_area(source))
+ target.ChangeArea(get_area(source))
. += transport_turf_contents(source, target, ignore_background, translate_air, angle = angle)
- ChangeArea(source, base_area)
+ source.ChangeArea(base_area)
else
. += transport_turf_contents(source, target, ignore_background, translate_air, angle = angle)
//change the old turfs
diff --git a/code/_onclick/hud/hud_types/_hud.dm b/code/_onclick/hud/hud_types/_hud.dm
index 5a64f04f09a9..1e9b6337df0f 100644
--- a/code/_onclick/hud/hud_types/_hud.dm
+++ b/code/_onclick/hud/hud_types/_hud.dm
@@ -220,9 +220,9 @@
mymob.remove_mob_modifier(/decl/mob_modifier/restrained, source = mymob)
if(mymob.current_posture?.prone)
- mymob.add_mob_modifier(/decl/mob_modifier/prone, source = mymob)
+ mymob.add_mob_modifier(/decl/mob_modifier/lying, source = mymob)
else
- mymob.remove_mob_modifier(/decl/mob_modifier/prone, source = mymob)
+ mymob.remove_mob_modifier(/decl/mob_modifier/lying, source = mymob)
for(var/obj/screen/elem as anything in hud_elements_update_in_life)
elem.update_icon()
diff --git a/code/_onclick/hud/screen/_screen.dm b/code/_onclick/hud/screen/_screen.dm
index da0c7b5478af..cf3709acd140 100644
--- a/code/_onclick/hud/screen/_screen.dm
+++ b/code/_onclick/hud/screen/_screen.dm
@@ -71,7 +71,7 @@
/obj/screen/get_color()
return color
-/obj/screen/set_color(new_color)
+/obj/screen/set_color(new_color, skip_update)
if(color != new_color)
color = new_color
return TRUE
diff --git a/code/_onclick/hud/screen/screen_exosuit.dm b/code/_onclick/hud/screen/screen_exosuit.dm
index ad9171ed446d..5aaf6c0c9c8a 100644
--- a/code/_onclick/hud/screen/screen_exosuit.dm
+++ b/code/_onclick/hud/screen/screen_exosuit.dm
@@ -198,6 +198,7 @@
maptext_x = -16
maptext_width = 64
maptext_y = -8
+ screen_loc = "RIGHT-2:28,CENTER+1:22"
/obj/screen/exosuit/toggle
name = "toggle"
@@ -363,9 +364,9 @@
/obj/screen/exosuit/heat
name = "heat probe"
icon_state = "heatprobe"
+ screen_loc = "RIGHT-2:28,CENTER+1:12"
var/celsius = TRUE
var/obj/screen/exosuit/needle/gauge_needle = null
- desc = "TEST"
/obj/screen/exosuit/heat/Initialize(mapload, mob/_owner, ui_style, ui_color, ui_alpha)
. = ..()
@@ -417,6 +418,7 @@
/obj/screen/exosuit/health
name = "exosuit integrity"
icon_state = "health"
+ screen_loc = "RIGHT-2:28,CENTER:12"
/obj/screen/exosuit/health/handle_click(mob/user, params)
if(!..())
diff --git a/code/_onclick/hud/screen/screen_mob_modifier.dm b/code/_onclick/hud/screen/screen_mob_modifier.dm
index d8d32bd3c586..a229d9d7db4b 100644
--- a/code/_onclick/hud/screen/screen_mob_modifier.dm
+++ b/code/_onclick/hud/screen/screen_mob_modifier.dm
@@ -1,5 +1,5 @@
/obj/screen/mob_modifiers
- screen_loc = "CENTER,TOP"
+ screen_loc = "CENTER:8,TOP"
icon_state = "blank"
requires_ui_style = FALSE
diff --git a/code/controllers/subsystems/initialization/robots.dm b/code/controllers/subsystems/initialization/robots.dm
index 75c70a7fe4cc..337f8c14e593 100644
--- a/code/controllers/subsystems/initialization/robots.dm
+++ b/code/controllers/subsystems/initialization/robots.dm
@@ -10,14 +10,11 @@ SUBSYSTEM_DEF(robots)
var/list/robot_alt_titles = list()
var/list/mob_types_by_title = list(
- "cyborg, flying" = /mob/living/silicon/robot/flying,
"robot, flying" = /mob/living/silicon/robot/flying
)
- var/list/mmi_types_by_title = list(
- "cyborg" = /obj/item/organ/internal/brain_interface,
+ var/list/processor_types_by_title = list(
"robot" = /obj/item/organ/internal/brain/robotic,
- "cyborg, flying" = /obj/item/organ/internal/brain_interface,
"robot, flying" = /obj/item/organ/internal/brain/robotic
)
@@ -25,7 +22,7 @@ SUBSYSTEM_DEF(robots)
. = ..()
// This is done via loop instead of just assignment in order to trim associations.
- for(var/title in (mob_types_by_title|mmi_types_by_title))
+ for(var/title in (mob_types_by_title|processor_types_by_title))
robot_alt_titles |= capitalize(title)
sortTim(robot_alt_titles, /proc/cmp_text_asc)
@@ -58,7 +55,7 @@ SUBSYSTEM_DEF(robots)
.[include_override] = modules[include_override]
/datum/controller/subsystem/robots/proc/get_brain_type_by_title(var/check_title)
- . = mmi_types_by_title[lowertext(trim(check_title))] || /obj/item/organ/internal/brain/robotic
+ . = processor_types_by_title[lowertext(trim(check_title))] || /obj/item/organ/internal/brain/robotic
/datum/controller/subsystem/robots/proc/get_mob_type_by_title(var/check_title)
. = mob_types_by_title[lowertext(trim(check_title))] || /mob/living/silicon/robot
\ No newline at end of file
diff --git a/code/datums/extensions/abilities/ability_button.dm b/code/datums/extensions/abilities/ability_button.dm
index 5ab2d44e66b8..7bebb71a1993 100644
--- a/code/datums/extensions/abilities/ability_button.dm
+++ b/code/datums/extensions/abilities/ability_button.dm
@@ -65,7 +65,7 @@
/obj/screen/ability/button/handle_click(mob/user, params)
if(owning_handler.prepared_ability == ability)
owning_handler.cancel_prepared_ability()
- else if(ability.use_ability(user, get_turf(user), owning_handler)) // tmp, needs better/multi-step target selection
+ else if(ability.use_ability(user, user, owning_handler)) // tmp, needs better/multi-step target selection
update_icon()
addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_icon)), ability.get_cooldown_time(ability.get_metadata_for_user(user)) + 1)
diff --git a/code/datums/extensions/abilities/ability_decl.dm b/code/datums/extensions/abilities/ability_decl.dm
index a3cb3726f89f..1c11a89414d4 100644
--- a/code/datums/extensions/abilities/ability_decl.dm
+++ b/code/datums/extensions/abilities/ability_decl.dm
@@ -182,7 +182,7 @@
else
// Otherwise, just apply to the target directly.
- apply_effect(user, target, metadata)
+ apply_ability_effect(user, target, metadata)
if(end_prep_on_cast && handler.prepared_ability == src)
handler.cancel_prepared_ability()
@@ -325,7 +325,7 @@
return TRUE
-/decl/ability/proc/apply_effect(mob/user, atom/hit_target, list/metadata, obj/item/projectile/ability/projectile)
+/decl/ability/proc/apply_ability_effect(mob/user, atom/hit_target, list/metadata, obj/item/projectile/ability/projectile)
SHOULD_CALL_PARENT(TRUE)
if(use_sound)
playsound(get_turf(user), use_sound, use_sound_volume, 1)
@@ -339,7 +339,7 @@
show_ability_cast_msg(user, targets, metadata)
while(length(targets))
var/target = targets[1]
- apply_effect_to(user, target, metadata)
+ apply_ability_effect_to(user, target, metadata)
targets = prune_targets(user, target, targets, metadata)
finish_casting(user, hit_target, metadata)
@@ -366,7 +366,7 @@
ability_overlay.set_density(FALSE)
QDEL_IN(ability_overlay, overlay_lifespan)
-/decl/ability/proc/apply_effect_to(mob/user, atom/target, list/metadata)
+/decl/ability/proc/apply_ability_effect_to(mob/living/user, atom/target, list/metadata)
SHOULD_CALL_PARENT(TRUE)
SHOULD_NOT_SLEEP(TRUE)
apply_visuals(user, target, metadata)
diff --git a/code/datums/extensions/abilities/ability_handler.dm b/code/datums/extensions/abilities/ability_handler.dm
index 0b773cb469d5..d81a8bd023b8 100644
--- a/code/datums/extensions/abilities/ability_handler.dm
+++ b/code/datums/extensions/abilities/ability_handler.dm
@@ -125,7 +125,7 @@
add_screen_element(category_toggle, "toggle", TRUE)
toggle_category_visibility(TRUE)
-/datum/ability_handler/proc/refresh_element_positioning(row = 1, col = 1)
+/datum/ability_handler/proc/refresh_element_positioning(row = 1, col = 0)
if(!LAZYLEN(screen_elements))
return 0
var/button_pos = col
@@ -134,14 +134,14 @@
for(var/ability in screen_elements)
var/obj/screen/element = screen_elements[ability]
if(istype(element, /obj/screen/ability/category))
- element.screen_loc = "RIGHT-[col]:-4,TOP-[row]"
+ element.screen_loc = "RIGHT-[col]:-4,TOP-[row]:-24"
else if(!element.invisibility)
button_pos++
if((button_pos-col) > 5)
button_row++
.++
button_pos = col+1
- element.screen_loc = "RIGHT-[button_pos]:-4,TOP-[button_row]"
+ element.screen_loc = "RIGHT-[button_pos]:-4,TOP-[button_row]:-24"
/datum/ability_handler/proc/toggle_category_visibility(force_state)
showing_abilities = isnull(force_state) ? !showing_abilities : force_state
diff --git a/code/datums/extensions/abilities/ability_item.dm b/code/datums/extensions/abilities/ability_item.dm
index b4838fd41458..666d6d268e36 100644
--- a/code/datums/extensions/abilities/ability_item.dm
+++ b/code/datums/extensions/abilities/ability_item.dm
@@ -54,8 +54,8 @@
// Fire a projectile if that is how this ability works.
ability.fire_projectile_at(user, target, metadata)
else
- // Otherwise, apply to the target. Range checking etc. will be handled in apply_effect().
- ability.apply_effect(user, target, metadata)
+ // Otherwise, apply to the target. Range checking etc. will be handled in apply_ability_effect().
+ ability.apply_ability_effect(user, target, metadata)
// Clean up our item if needed.
if(ability.item_end_on_cast)
diff --git a/code/datums/extensions/abilities/ability_projectile.dm b/code/datums/extensions/abilities/ability_projectile.dm
index 896acba2e95a..5b5f2f10b373 100644
--- a/code/datums/extensions/abilities/ability_projectile.dm
+++ b/code/datums/extensions/abilities/ability_projectile.dm
@@ -22,10 +22,10 @@
/obj/item/projectile/ability/Bump(var/atom/A, forced=0)
if(loc && carried_ability && !expended)
- carried_ability.apply_effect(owner, A, ability_metadata, src)
+ carried_ability.apply_ability_effect(owner, A, ability_metadata, src)
return TRUE
/obj/item/projectile/ability/on_impact(var/atom/A)
if(loc && carried_ability && !expended)
- carried_ability.apply_effect(owner, A, ability_metadata, src)
+ carried_ability.apply_ability_effect(owner, A, ability_metadata, src)
return TRUE
diff --git a/code/datums/extensions/abilities/ability_targeting.dm b/code/datums/extensions/abilities/ability_targeting.dm
index 52f7ee8166c5..e93a59c3a793 100644
--- a/code/datums/extensions/abilities/ability_targeting.dm
+++ b/code/datums/extensions/abilities/ability_targeting.dm
@@ -72,19 +72,35 @@
return FALSE
return TRUE
+/decl/ability_targeting/target_self
+ target_turf = FALSE
+
+/decl/ability_targeting/target_self/validate_target(mob/user, atom/target, list/metadata, decl/ability/ability)
+ return target == user
+
+/decl/ability_targeting/target_self/get_affected(mob/user, atom/hit_target, list/metadata, decl/ability/ability, obj/item/projectile/ability/projectile)
+ return list(user)
+
/decl/ability_targeting/clear_turf
ignore_dense_turfs = TRUE
/decl/ability_targeting/clear_turf/validate_target(mob/user, atom/target, list/metadata, decl/ability/ability)
. = ..() && isturf(target)
if(.)
- var/turf/target_turf = target
- return !target_turf.contains_dense_objects(user)
+ var/turf/turf_to_target = target
+ return !turf_to_target.contains_dense_objects(user)
+
+/decl/ability_targeting/single_atom
+ target_turf = FALSE
+ user_is_immune = TRUE
+
+/decl/ability_targeting/single_atom/can_target_user
+ user_is_immune = FALSE
-/decl/ability_targeting/living_mob
- target_turf = FALSE
+/decl/ability_targeting/single_atom/get_affected(mob/user, atom/hit_target, list/metadata, decl/ability/ability, obj/item/projectile/ability/projectile)
+ return list(hit_target)
-/decl/ability_targeting/living_mob/validate_target(mob/user, atom/target, list/metadata, decl/ability/ability)
+/decl/ability_targeting/single_atom/living_mob/validate_target(mob/user, atom/target, list/metadata, decl/ability/ability)
. = ..() && isliving(target)
if(.)
var/mob/living/victim = target
diff --git a/code/datums/trading/traders/goods.dm b/code/datums/trading/traders/goods.dm
index 81d294268dcd..c497455ab77f 100644
--- a/code/datums/trading/traders/goods.dm
+++ b/code/datums/trading/traders/goods.dm
@@ -247,7 +247,6 @@ Sells devices, odds and ends, and medical stuff
/obj/item/synthesized_instrument/violin = TRADER_THIS_TYPE,
/obj/item/hailer = TRADER_THIS_TYPE,
/obj/item/uv_light = TRADER_THIS_TYPE,
- /obj/item/organ/internal/brain_interface = TRADER_SUBTYPES_ONLY,
/obj/item/robotanalyzer = TRADER_THIS_TYPE,
/obj/item/chems/toner_cartridge = TRADER_THIS_TYPE,
/obj/item/camera_film = TRADER_THIS_TYPE,
diff --git a/code/datums/traits/_traits.dm b/code/datums/traits/_traits.dm
index b3e7103fe9d4..94ce0f5da28d 100644
--- a/code/datums/traits/_traits.dm
+++ b/code/datums/traits/_traits.dm
@@ -106,6 +106,8 @@
var/available_at_map_tech = MAP_TECH_LEVEL_ANY
/// Whether or not a rejuvenation should apply this aspect.
var/reapply_on_rejuvenation = FALSE
+ /// Whether this trait should be copied and applied by mob snapshots.
+ var/is_heritable = TRUE
/// What species can select this trait in chargen?
var/list/permitted_species
/// What species cannot select this trait in chargen?
diff --git a/code/datums/traits/maluses/amputations.dm b/code/datums/traits/maluses/amputations.dm
index 8ce9bc5d4186..5b576e2ef5f8 100644
--- a/code/datums/traits/maluses/amputations.dm
+++ b/code/datums/traits/maluses/amputations.dm
@@ -3,6 +3,7 @@
category = "Missing Limbs"
abstract_type = /decl/trait/malus/amputation
reapply_on_rejuvenation = TRUE
+ is_heritable = FALSE
var/list/apply_to_limbs
var/list/ban_traits_relating_to_limbs
diff --git a/code/datums/traits/prosthetics/prosthetic_limbs.dm b/code/datums/traits/prosthetics/prosthetic_limbs.dm
index a620ebef2942..ace1236f36d4 100644
--- a/code/datums/traits/prosthetics/prosthetic_limbs.dm
+++ b/code/datums/traits/prosthetics/prosthetic_limbs.dm
@@ -6,6 +6,7 @@
available_at_map_tech = MAP_TECH_LEVEL_ANY // the base trait must be available so that wooden prostheses are available
abstract_type = /decl/trait/prosthetic_limb
reapply_on_rejuvenation = TRUE
+ is_heritable = FALSE
var/fullbody_synthetic_only = FALSE
var/replace_children = TRUE
var/check_bodytype
diff --git a/code/datums/traits/prosthetics/prosthetic_organs.dm b/code/datums/traits/prosthetics/prosthetic_organs.dm
index 0ae6ce949569..513da35f6e2d 100644
--- a/code/datums/traits/prosthetics/prosthetic_organs.dm
+++ b/code/datums/traits/prosthetics/prosthetic_organs.dm
@@ -5,6 +5,7 @@
available_at_map_tech = MAP_TECH_LEVEL_SPACE
category = "Prosthetic Organs"
reapply_on_rejuvenation = TRUE
+ is_heritable = FALSE
var/synthetic_bodytype_restricted = FALSE
var/apply_to_organ
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index 2499f40ab471..e59bc1aca7ab 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -137,46 +137,46 @@ var/global/list/areas = list()
..()
return QDEL_HINT_HARDDEL
-// Changes the area of T to A. Do not do this manually.
+// Changes the area of src to A. Do not do this manually.
// Area is expected to be a non-null instance.
-/proc/ChangeArea(var/turf/T, var/area/A)
+/turf/proc/ChangeArea(var/area/A)
if(!istype(A))
CRASH("Area change attempt failed: invalid area supplied.")
- var/old_outside = T.is_outside()
- var/area/old_area = get_area(T)
+ var/old_outside = is_outside()
+ var/area/old_area = get_area(src)
if(old_area == A)
return
var/old_area_ambience = old_area?.interior_ambient_light_modifier
- A.contents.Add(T)
+ A.contents.Add(src)
if(old_area)
- old_area.Exited(T, A)
- for(var/atom/movable/AM as anything in T)
+ old_area.Exited(src, A)
+ for(var/atom/movable/AM as anything in src)
old_area.Exited(AM, A) // Note: this _will_ raise exited events.
- A.Entered(T, old_area)
- for(var/atom/movable/AM as anything in T)
+ A.Entered(src, old_area)
+ for(var/atom/movable/AM as anything in src)
A.Entered(AM, old_area) // Note: this will _not_ raise moved or entered events. If you change this, you must also change everything which uses them.
- for(var/obj/machinery/M in T)
+ for(var/obj/machinery/M in src)
M.area_changed(old_area, A) // They usually get moved events, but this is the one way an area can change without triggering one.
- T.update_registrations_on_adjacent_area_change()
+ update_registrations_on_adjacent_area_change()
for(var/direction in global.cardinal)
- var/turf/adjacent_turf = get_step(T, direction)
+ var/turf/adjacent_turf = get_step(src, direction)
if(adjacent_turf)
adjacent_turf.update_registrations_on_adjacent_area_change()
// Handle updating weather and atmos if the outside status of the turf changed.
- if(T.is_outside == OUTSIDE_AREA)
- T.update_external_atmos_participation() // Refreshes outside status and adds exterior air to turf air if necessary.
+ if(is_outside == OUTSIDE_AREA)
+ update_external_atmos_participation() // Refreshes outside status and adds exterior air to turf air if necessary.
- if(T.is_outside() != old_outside)
- T.update_weather()
+ if(is_outside() != old_outside)
+ update_weather()
if(SSambience.initialized) // if not initialized, we'll loop over all turfs anyway
- AMBIENCE_QUEUE_TURF(T)
+ AMBIENCE_QUEUE_TURF(src)
else if(A.interior_ambient_light_modifier != old_area_ambience && SSambience.initialized)
- AMBIENCE_QUEUE_TURF(T)
+ AMBIENCE_QUEUE_TURF(src)
/turf/proc/update_registrations_on_adjacent_area_change()
for(var/obj/machinery/door/firedoor/door in src)
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index e698467579de..0d0b617fc5a5 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -847,7 +847,7 @@
/* Set the atom colour. This is a stub effectively due to the broad use of direct setting. */
// TODO: implement this everywhere that it should be used instead of direct setting.
-/atom/proc/set_color(var/new_color)
+/atom/proc/set_color(new_color, skip_update)
if(isnull(new_color))
return reset_color()
if(color != new_color)
diff --git a/code/game/machinery/air_sensor.dm b/code/game/machinery/air_sensor.dm
index bfbb9236ed3e..6a4774c0759b 100644
--- a/code/game/machinery/air_sensor.dm
+++ b/code/game/machinery/air_sensor.dm
@@ -46,9 +46,9 @@
if(total_moles <= 0)
return
. = list()
- for(var/gas in air_sample.gas)
- var/decl/material/mat = GET_DECL(gas)
- var/gaspercent = round(air_sample.gas[gas]*100/total_moles,0.01)
+ for(var/gas_type, gas_amount in air_sample.gas)
+ var/decl/material/mat = GET_DECL(gas_type)
+ var/gaspercent = round(gas_amount*100/total_moles,0.01)
var/gas_list = list("symbol" = mat.gas_symbol_html, "percent" = gaspercent)
. += list(gas_list)
diff --git a/code/game/machinery/atmoalter/portable_atmospherics.dm b/code/game/machinery/atmoalter/portable_atmospherics.dm
index 3de7c00f4368..b788ebfe1e8a 100644
--- a/code/game/machinery/atmoalter/portable_atmospherics.dm
+++ b/code/game/machinery/atmoalter/portable_atmospherics.dm
@@ -12,9 +12,9 @@
/obj/machinery/portable_atmospherics/get_single_monetary_worth()
. = ..()
- for(var/gas in air_contents?.gas)
- var/decl/material/gas_data = GET_DECL(gas)
- . += gas_data.get_value() * air_contents.gas[gas] * GAS_WORTH_MULTIPLIER
+ for(var/gas_type, gas_amount in air_contents?.gas)
+ var/decl/material/gas_data = GET_DECL(gas_type)
+ . += gas_data.get_value() * gas_amount * GAS_WORTH_MULTIPLIER
. = max(1, round(.))
/obj/machinery/portable_atmospherics/Initialize()
diff --git a/code/game/machinery/computer/ai_core.dm b/code/game/machinery/computer/ai_core.dm
index 79bb78e9540e..b023cc39b312 100644
--- a/code/game/machinery/computer/ai_core.dm
+++ b/code/game/machinery/computer/ai_core.dm
@@ -51,7 +51,7 @@ var/global/list/empty_playable_ai_cores = list()
if(open_for_latejoin)
empty_playable_ai_cores += D
else
- var/mob/living/silicon/ai/A = new /mob/living/silicon/ai ( loc, laws, brain )
+ var/mob/living/silicon/ai/A = new /mob/living/silicon/ai ( loc, laws, brain.get_brainmob() )
if(A) //if there's no brain, the mob is deleted and a structure/AIcore is created
A.on_mob_init()
A.rename_self("ai", 1)
diff --git a/code/game/machinery/doors/_door.dm b/code/game/machinery/doors/_door.dm
index 3b1aec756003..2aef4698196b 100644
--- a/code/game/machinery/doors/_door.dm
+++ b/code/game/machinery/doors/_door.dm
@@ -465,8 +465,8 @@
close_door_at = 0
do_animate("closing")
- sleep(0.5 SECONDS)
src.set_density(TRUE)
+ sleep(0.5 SECONDS)
update_nearby_tiles()
src.layer = closed_layer
diff --git a/code/game/machinery/turret_control.dm b/code/game/machinery/turret_control.dm
index c91249ac56d6..01fb7b136788 100644
--- a/code/game/machinery/turret_control.dm
+++ b/code/game/machinery/turret_control.dm
@@ -48,6 +48,10 @@
. = ..()
/obj/machinery/turretid/Initialize()
+ . = ..()
+ return INITIALIZE_HINT_LATELOAD // Because areas initialize AFTER these!
+
+/obj/machinery/turretid/LateInitialize()
if(!control_area)
control_area = get_area(src)
else if(istext(control_area))
@@ -55,6 +59,8 @@
if(A.name && A.name==control_area)
control_area = A
break
+ else if(ispath(control_area))
+ control_area = locate(control_area) in global.areas
if(control_area)
var/area/A = control_area
diff --git a/code/game/objects/effects/spawners/bombspawner.dm b/code/game/objects/effects/spawners/bombspawner.dm
index 9528d9d7b556..1716a5662e97 100644
--- a/code/game/objects/effects/spawners/bombspawner.dm
+++ b/code/game/objects/effects/spawners/bombspawner.dm
@@ -75,7 +75,7 @@
OT.master = V
PT.valve_welded = TRUE
- PT.air_contents.gas = list()
+ PT.air_contents.gas = alist()
PT.air_contents.gas[accelerant_type] = accelerant_amount
PT.air_contents.gas[filler_type] = filler_amount
PT.air_contents.total_moles = accelerant_amount + filler_amount
@@ -83,7 +83,7 @@
PT.air_contents.update_values()
OT.valve_welded = TRUE
- OT.air_contents.gas = list()
+ OT.air_contents.gas = alist()
OT.air_contents.gas[oxidizer_type] = oxidizer_amount
OT.air_contents.total_moles = oxidizer_amount
OT.air_contents.temperature = FLAMMABLE_GAS_MINIMUM_BURN_TEMPERATURE+1
diff --git a/code/game/objects/items/__item.dm b/code/game/objects/items/__item.dm
index 2a8d149f734c..1bed5d4cf0f6 100644
--- a/code/game/objects/items/__item.dm
+++ b/code/game/objects/items/__item.dm
@@ -155,13 +155,14 @@
return material.color
return initial(color)
-/obj/item/set_color(new_color)
+/obj/item/set_color(new_color, skip_update)
if(new_color == COLOR_WHITE)
new_color = null
if(paint_color != new_color)
paint_color = new_color
. = TRUE
- refresh_color()
+ if(!skip_update)
+ refresh_color()
/obj/item/refresh_color()
if(paint_color)
diff --git a/code/game/objects/items/devices/inducer.dm b/code/game/objects/items/devices/inducer.dm
index bb84d497a164..1c2cf2ccd90b 100644
--- a/code/game/objects/items/devices/inducer.dm
+++ b/code/game/objects/items/devices/inducer.dm
@@ -47,8 +47,18 @@
return FALSE
/obj/item/inducer/attackby(obj/item/used_item, mob/user)
- if(CannotUse(user) || recharge(used_item, user))
+ var/obj/item/cell/my_cell = get_cell()
+ var/datum/extension/loaded_cell/panel/cell_loaded = get_extension(src, /datum/extension/loaded_cell)
+
+ if(cell_loaded?.has_tool_unload_interaction(used_item))
+ return cell_loaded.try_unload(user, used_item)
+
+ else if(!istype(my_cell) && istype(used_item, /obj/item/cell))
+ return cell_loaded?.try_load(user, used_item)
+
+ else if(CannotUse(user) || recharge(used_item, user))
return TRUE
+
return ..()
/obj/item/inducer/proc/recharge(atom/A, mob/user)
diff --git a/code/game/objects/items/robot/robot_frame.dm b/code/game/objects/items/robot/robot_frame.dm
index 2759cbc834e3..b4edb454766e 100644
--- a/code/game/objects/items/robot/robot_frame.dm
+++ b/code/game/objects/items/robot/robot_frame.dm
@@ -32,6 +32,9 @@
SSstatistics.add_field("cyborg_frames_built",1)
return TRUE
+/obj/item/robot_parts/robot_suit/proc/is_valid_processor(obj/item/used_item)
+ return istype(used_item, /obj/item/organ/internal/brain/robotic)
+
/obj/item/robot_parts/robot_suit/attackby(obj/item/used_item, mob/user)
// Uninstall a robotic part.
@@ -61,28 +64,28 @@
return TRUE
// Install a brain.
- else if(istype(used_item, /obj/item/organ/internal/brain_interface))
+ else if(istype(used_item, /obj/item/organ/internal) && is_valid_processor(used_item))
+ var/obj/item/organ/internal/processor = used_item
if(!isturf(loc))
- to_chat(user, SPAN_WARNING("You can't put \the [used_item] in without the frame being on the ground."))
+ to_chat(user, SPAN_WARNING("You can't put \the [processor] in without the frame being on the ground."))
return TRUE
if(!check_completion())
to_chat(user, SPAN_WARNING("The frame is not ready for the central processor to be installed."))
return TRUE
- var/obj/item/organ/internal/brain_interface/M = used_item
- var/mob/living/brainmob = M?.get_brainmob()
+ var/mob/living/brainmob = processor.get_brainmob()
if(!brainmob)
- to_chat(user, SPAN_WARNING("Sticking an empty [used_item.name] into the frame would sort of defeat the purpose."))
+ to_chat(user, SPAN_WARNING("Sticking an empty [processor.name] into the frame would sort of defeat the purpose."))
return TRUE
if(jobban_isbanned(brainmob, ASSIGNMENT_ROBOT))
- to_chat(user, SPAN_WARNING("\The [used_item] does not seem to fit."))
+ to_chat(user, SPAN_WARNING("\The [processor] does not seem to fit."))
return TRUE
if(brainmob.stat == DEAD)
- to_chat(user, SPAN_WARNING("Sticking a dead [used_item.name] into the frame would sort of defeat the purpose."))
+ to_chat(user, SPAN_WARNING("Sticking a dead [processor.name] into the frame would sort of defeat the purpose."))
return TRUE
var/ghost_can_reenter = 0
@@ -95,10 +98,10 @@
else
ghost_can_reenter = 1
if(!ghost_can_reenter)
- to_chat(user, SPAN_WARNING("\The [used_item] is completely unresponsive; there's no point."))
+ to_chat(user, SPAN_WARNING("\The [processor] is completely unresponsive; there's no point."))
return TRUE
- if(!user.try_unequip(used_item))
+ if(!user.try_unequip(processor))
return TRUE
SSstatistics.add_field("cyborg_frames_built",1)
@@ -106,7 +109,7 @@
if(!O)
return TRUE
- O.central_processor = used_item
+ O.central_processor = processor
O.set_invisibility(INVISIBILITY_NONE)
O.custom_name = created_name
O.updatename("Default")
@@ -120,7 +123,7 @@
var/obj/item/robot_parts/chest/chest = parts[BP_CHEST]
chest.cell.forceMove(O)
- used_item.forceMove(O) //Should fix cybros run time erroring when blown up. It got deleted before, along with the frame.
+ processor.forceMove(O) //Should fix cybros run time erroring when blown up. It got deleted before, along with the frame.
// Since we "magically" installed a cell, we also have to update the correct component.
if(O.cell)
diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm
index 73ae28e1dcc2..b191b55e56da 100644
--- a/code/game/objects/items/weapons/tanks/tanks.dm
+++ b/code/game/objects/items/weapons/tanks/tanks.dm
@@ -80,9 +80,9 @@ var/global/list/global/tank_gauge_cache = list()
/obj/item/tank/get_single_monetary_worth()
. = ..()
- for(var/gas in air_contents?.gas)
- var/decl/material/gas_data = GET_DECL(gas)
- . += gas_data.get_value() * air_contents.gas[gas] * GAS_WORTH_MULTIPLIER
+ for(var/gas_type, gas_amount in air_contents?.gas)
+ var/decl/material/gas_data = GET_DECL(gas_type)
+ . += gas_data.get_value() * gas_amount * GAS_WORTH_MULTIPLIER
. = max(1, round(.))
/obj/item/tank/get_examine_strings(mob/user, distance, infix, suffix)
diff --git a/code/game/objects/structures/__structure.dm b/code/game/objects/structures/__structure.dm
index 27239ec9127b..7184dc4797b4 100644
--- a/code/game/objects/structures/__structure.dm
+++ b/code/game/objects/structures/__structure.dm
@@ -24,13 +24,14 @@
return material.color
return initial(color)
-/obj/structure/set_color(new_color)
+/obj/structure/set_color(new_color, skip_update)
if(new_color == COLOR_WHITE)
new_color = null
if(paint_color != new_color)
paint_color = new_color
. = TRUE
- refresh_color()
+ if(!skip_update)
+ refresh_color()
/obj/structure/refresh_color()
if(paint_color)
diff --git a/code/game/objects/structures/fires.dm b/code/game/objects/structures/fires.dm
index b05b4cfba864..a92571c8a8f0 100644
--- a/code/game/objects/structures/fires.dm
+++ b/code/game/objects/structures/fires.dm
@@ -151,8 +151,8 @@
/obj/structure/fire_source/proc/check_atmos()
var/datum/gas_mixture/GM = loc?.return_air()
- for(var/g in GM?.gas)
- var/decl/material/oxidizer = GET_DECL(g)
+ for(var/gas_type in GM?.gas)
+ var/decl/material/oxidizer = GET_DECL(gas_type)
if(oxidizer.gas_flags & XGM_GAS_OXIDIZER)
return TRUE
diff --git a/code/game/turfs/floors/subtypes/floor_circuit.dm b/code/game/turfs/floors/subtypes/floor_circuit.dm
index 77bb38e13a45..2737352de969 100644
--- a/code/game/turfs/floors/subtypes/floor_circuit.dm
+++ b/code/game/turfs/floors/subtypes/floor_circuit.dm
@@ -29,7 +29,7 @@
temperature = TCMB
/turf/floor/greengrid/nitrogen
- initial_gas = list(/decl/material/gas/nitrogen = MOLES_N2STANDARD)
+ initial_gas = alist(/decl/material/gas/nitrogen = MOLES_N2STANDARD)
/turf/floor/blackgrid
name = "mainframe floor"
diff --git a/code/game/turfs/floors/subtypes/floor_reinforced.dm b/code/game/turfs/floors/subtypes/floor_reinforced.dm
index 551786ed357b..a322fb767ce0 100644
--- a/code/game/turfs/floors/subtypes/floor_reinforced.dm
+++ b/code/game/turfs/floors/subtypes/floor_reinforced.dm
@@ -8,32 +8,32 @@
initial_gas = null
/turf/floor/reinforced/airmix
- initial_gas = list(
+ initial_gas = alist(
/decl/material/gas/oxygen = MOLES_O2ATMOS,
/decl/material/gas/nitrogen = MOLES_N2ATMOS
)
/turf/floor/reinforced/nitrogen
- initial_gas = list(/decl/material/gas/nitrogen = ATMOSTANK_NITROGEN)
+ initial_gas = alist(/decl/material/gas/nitrogen = ATMOSTANK_NITROGEN)
/turf/floor/reinforced/hydrogen
- initial_gas = list(/decl/material/gas/hydrogen = ATMOSTANK_HYDROGEN)
+ initial_gas = alist(/decl/material/gas/hydrogen = ATMOSTANK_HYDROGEN)
/turf/floor/reinforced/oxygen
- initial_gas = list(/decl/material/gas/oxygen = ATMOSTANK_OXYGEN)
+ initial_gas = alist(/decl/material/gas/oxygen = ATMOSTANK_OXYGEN)
/turf/floor/reinforced/nitrogen/engine
name = "engine floor"
- initial_gas = list(/decl/material/gas/nitrogen = MOLES_N2STANDARD)
+ initial_gas = alist(/decl/material/gas/nitrogen = MOLES_N2STANDARD)
/turf/floor/reinforced/hydrogen/fuel
- initial_gas = list(/decl/material/gas/hydrogen = ATMOSTANK_HYDROGEN_FUEL)
+ initial_gas = alist(/decl/material/gas/hydrogen = ATMOSTANK_HYDROGEN_FUEL)
/turf/floor/reinforced/carbon_dioxide
- initial_gas = list(/decl/material/gas/carbon_dioxide = ATMOSTANK_CO2)
+ initial_gas = alist(/decl/material/gas/carbon_dioxide = ATMOSTANK_CO2)
/turf/floor/reinforced/n20
- initial_gas = list(/decl/material/gas/nitrous_oxide = ATMOSTANK_NITROUSOXIDE)
+ initial_gas = alist(/decl/material/gas/nitrous_oxide = ATMOSTANK_NITROUSOXIDE)
/turf/floor/reinforced/airless
name = "vacuum floor"
diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm
index eb63e73c3ccf..21fce02894d7 100644
--- a/code/game/turfs/space/space.dm
+++ b/code/game/turfs/space/space.dm
@@ -60,7 +60,7 @@
/turf/space/LateInitialize()
if(SSmapping.base_floor_area)
var/area/new_area = locate(SSmapping.base_floor_area) || new SSmapping.base_floor_area
- ChangeArea(src, new_area)
+ ChangeArea(new_area)
ChangeTurf(SSmapping.base_floor_type)
/turf/space/proc/toggle_transit(var/direction)
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index b677b30f83c7..28171b7c2394 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -18,7 +18,7 @@
var/turf_flags
/// Either a mapping of material decls to mol amounts, or a reserved initial gas define like GAS_STANDARD_AIRMIX.
- var/list/initial_gas
+ var/alist/initial_gas
//Properties for airtight tiles (/wall)
var/thermal_conductivity = 0.05
diff --git a/code/game/turfs/turf_enter.dm b/code/game/turfs/turf_enter.dm
index cb1849868ab6..f419ff75cc63 100644
--- a/code/game/turfs/turf_enter.dm
+++ b/code/game/turfs/turf_enter.dm
@@ -59,9 +59,9 @@
var/datum/gas_mixture/env = return_air(1)
if(!env)
return
- for(var/g in env.gas)
- var/decl/material/mat = GET_DECL(g)
- if((mat.gas_flags & XGM_GAS_CONTAMINANT) && env.gas[g] > mat.gas_overlay_limit + 1)
+ for(var/gas_type, gas_amount in env.gas)
+ var/decl/material/mat = GET_DECL(gas_type)
+ if((mat.gas_flags & XGM_GAS_CONTAMINANT) && gas_amount > mat.gas_overlay_limit + 1)
I.contaminate()
break
diff --git a/code/game/turfs/walls/_wall.dm b/code/game/turfs/walls/_wall.dm
index 3706a99fcfa1..e73bea10dcb7 100644
--- a/code/game/turfs/walls/_wall.dm
+++ b/code/game/turfs/walls/_wall.dm
@@ -301,9 +301,13 @@ var/global/list/wall_fullblend_objects = list(
addtimer(CALLBACK(wall, TYPE_PROC_REF(/turf/wall, burn), temperature/4), 2)
physically_destroyed()
-/turf/wall/set_color(new_color)
- paint_color = new_color
- update_icon()
+/turf/wall/set_color(new_color, skip_update)
+ if(paint_color != new_color)
+ paint_color = new_color
+ if(!skip_update)
+ update_icon()
+ return TRUE
+ return FALSE
/turf/wall/proc/CheckPenetration(var/base_chance, var/damage)
return round(damage/material.integrity*180)
diff --git a/code/modules/ZAS/Diagnostic.dm b/code/modules/ZAS/Diagnostic.dm
index 71641a66eef1..4892aa15e51b 100644
--- a/code/modules/ZAS/Diagnostic.dm
+++ b/code/modules/ZAS/Diagnostic.dm
@@ -10,8 +10,8 @@
to_chat(mob, "ZONE: No zone here.")
var/datum/gas_mixture/mix = T.return_air()
to_chat(mob, "ZONE: [mix.return_pressure()] kPa [mix.temperature] k")
- for(var/g in mix.gas)
- to_chat(mob, "ZONE GASES: [g]: [mix.gas[g]]\n")
+ for(var/gas_type, gas_amount in mix.gas)
+ to_chat(mob, "ZONE GASES: [gas_type]: [gas_amount]\n")
/client/proc/Test_ZAS_Connection(var/turf/T)
set category = "Debug"
diff --git a/code/modules/ZAS/Fire.dm b/code/modules/ZAS/Fire.dm
index 8e68d92a22f9..d6365ddce8df 100644
--- a/code/modules/ZAS/Fire.dm
+++ b/code/modules/ZAS/Fire.dm
@@ -187,12 +187,12 @@ If it gains pressure too slowly, it may leak or just rupture instead of explodin
var/total_oxidizers = 0
//*** Get the fuel and oxidizer amounts
- for(var/g in gas)
- var/decl/material/mat = GET_DECL(g)
+ for(var/gas_type, gas_amount in gas)
+ var/decl/material/mat = GET_DECL(gas_type)
if(mat.gas_flags & XGM_GAS_FUEL)
- total_fuel += gas[g]
+ total_fuel += gas_amount
if(mat.gas_flags & XGM_GAS_OXIDIZER)
- total_oxidizers += gas[g]
+ total_oxidizers += gas_amount
total_fuel *= group_multiplier
total_oxidizers *= group_multiplier
@@ -233,9 +233,9 @@ If it gains pressure too slowly, it may leak or just rupture instead of explodin
//remove_by_flag() and adjust_gas() handle the group_multiplier for us.
remove_by_flag(XGM_GAS_OXIDIZER, used_oxidizers)
var/datum/gas_mixture/burned_fuel = remove_by_flag(XGM_GAS_FUEL, used_fuel)
- for(var/g in burned_fuel.gas)
- var/decl/material/mat = GET_DECL(g)
- mat.add_burn_product(src, burned_fuel.gas[g])
+ for(var/gas_type, gas_amount in burned_fuel.gas)
+ var/decl/material/mat = GET_DECL(gas_type)
+ mat.add_burn_product(src, gas_amount)
//calculate the energy produced by the reaction and then set the new temperature of the mix
temperature = (starting_energy + vsc.fire_fuel_energy_release * used_fuel) / heat_capacity()
@@ -249,44 +249,32 @@ If it gains pressure too slowly, it may leak or just rupture instead of explodin
return firelevel
/datum/gas_mixture/proc/check_recombustibility()
+ var/const/HAS_OXIDIZER = BITFLAG(0)
+ var/const/HAS_FUEL = BITFLAG(1)
. = 0
- for(var/g in gas)
- if(gas[g] >= 0.1)
- var/decl/material/gas = GET_DECL(g)
+ for(var/gas_type, gas_amount in gas)
+ if(gas_amount >= 0.1)
+ var/decl/material/gas = GET_DECL(gas_type)
if(gas.gas_flags & XGM_GAS_OXIDIZER)
- . = 1
- break
-
- if(!.)
- return 0
-
- . = 0
- for(var/g in gas)
- if(gas[g] >= 0.1)
- var/decl/material/gas = GET_DECL(g)
- if(gas.gas_flags & XGM_GAS_OXIDIZER)
- . = 1
- break
+ . |= HAS_OXIDIZER
+ if(gas.gas_flags & XGM_GAS_FUEL)
+ . |= HAS_FUEL
+ if(. == (HAS_OXIDIZER|HAS_FUEL))
+ return TRUE
/datum/gas_mixture/proc/check_combustibility()
+ var/const/HAS_OXIDIZER = BITFLAG(0)
+ var/const/HAS_FUEL = BITFLAG(1)
. = 0
- for(var/g in gas)
- if(QUANTIZE(gas[g] * vsc.fire_consuption_rate) >= 0.1)
- var/decl/material/gas = GET_DECL(g)
+ for(var/gas_type, gas_amount in gas)
+ if(QUANTIZE(gas_amount * vsc.fire_consuption_rate) >= 0.1)
+ var/decl/material/gas = GET_DECL(gas_type)
if(gas.gas_flags & XGM_GAS_OXIDIZER)
- . = 1
- break
-
- if(!.)
- return 0
-
- . = 0
- for(var/g in gas)
- if(QUANTIZE(gas[g] * vsc.fire_consuption_rate) >= 0.1)
- var/decl/material/gas = GET_DECL(g)
+ . |= HAS_OXIDIZER
if(gas.gas_flags & XGM_GAS_FUEL)
- . = 1
- break
+ . |= HAS_FUEL
+ if(. == (HAS_OXIDIZER|HAS_FUEL))
+ return TRUE
//returns a value between 0 and vsc.fire_firelevel_multiplier
/datum/gas_mixture/proc/calculate_firelevel(total_fuel, total_oxidizers, reaction_limit, gas_volume)
diff --git a/code/modules/ZAS/Turf.dm b/code/modules/ZAS/Turf.dm
index 016d69b4c53e..95f4c9c6f34e 100644
--- a/code/modules/ZAS/Turf.dm
+++ b/code/modules/ZAS/Turf.dm
@@ -223,7 +223,7 @@
return TRUE
return FALSE
-var/global/list/STANDARD_AIRMIX = list(
+var/global/alist/STANDARD_AIRMIX = alist(
/decl/material/gas/oxygen = MOLES_O2STANDARD,
/decl/material/gas/nitrogen = MOLES_N2STANDARD
)
diff --git a/code/modules/ZAS/Zone.dm b/code/modules/ZAS/Zone.dm
index cac84cb69bf5..10fab6f56161 100644
--- a/code/modules/ZAS/Zone.dm
+++ b/code/modules/ZAS/Zone.dm
@@ -180,26 +180,26 @@ Class Procs:
/zone/proc/handle_condensation()
set waitfor = FALSE
condensing = TRUE
- for(var/g in air.gas)
- var/decl/material/mat = GET_DECL(g)
+ for(var/gas_type, gas_amount in air.gas)
+ var/decl/material/mat = GET_DECL(gas_type)
if(!isnull(mat.gas_condensation_point) && (air.temperature <= mat.gas_condensation_point))
var/condensation_area = air.group_multiplier / length(air.gas)
while(condensation_area > 0 && length(contents))
condensation_area--
var/turf/flooding = pick(contents)
- var/condense_amt = min(air.gas[g], rand(1,3))
+ var/condense_amt = min(gas_amount, rand(1,3))
if(condense_amt < 1)
break
- air.adjust_gas(g, -condense_amt)
- flooding.add_to_reagents(g, condense_amt * REAGENT_UNITS_PER_GAS_MOLE)
+ air.adjust_gas(gas_type, -condense_amt)
+ flooding.add_to_reagents(gas_type, condense_amt * REAGENT_UNITS_PER_GAS_MOLE)
CHECK_TICK
condensing = FALSE
/zone/proc/dbg_data(mob/M)
to_chat(M, name)
- for(var/g in air.gas)
- var/decl/material/mat = GET_DECL(g)
- to_chat(M, "[capitalize(mat.gas_name)]: [air.gas[g]]")
+ for(var/gas_type, gas_amount in air.gas)
+ var/decl/material/mat = GET_DECL(gas_type)
+ to_chat(M, "[capitalize(mat.gas_name)]: [gas_amount]")
to_chat(M, "P: [air.return_pressure()] kPa V: [air.total_volume]L T: [air.temperature]°K ([air.temperature - T0C]°C)")
to_chat(M, "O2 per N2: [(air.gas[/decl/material/gas/nitrogen] ? air.gas[/decl/material/gas/oxygen]/air.gas[/decl/material/gas/nitrogen] : "N/A")] Moles: [air.total_moles]")
to_chat(M, "Simulated: [contents.len] ([air.group_multiplier])")
diff --git a/code/modules/admin/buildmode/mode_areas.dm b/code/modules/admin/buildmode/mode_areas.dm
index 4df3b7e41797..92366800d9ad 100644
--- a/code/modules/admin/buildmode/mode_areas.dm
+++ b/code/modules/admin/buildmode/mode_areas.dm
@@ -119,7 +119,7 @@
if(!istype(T) || !istype(area_mode))
return FALSE
if (area_mode.selected_area)
- ChangeArea(T, area_mode.selected_area)
+ T.ChangeArea(area_mode.selected_area)
to_chat(build_mode.user, SPAN_NOTICE("Set area of turf [T.name] to [area_mode.selected_area.proper_name]"))
return TRUE
to_chat(build_mode.user, SPAN_WARNING("Pick or create an area first"))
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index 480a29e13010..c9b324c94e9d 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -16,8 +16,8 @@
var/t = "Coordinates: [T.x],[T.y],[T.z]\n"
t += "Temperature: [env.temperature]\n"
t += "Pressure: [env.return_pressure()]kPa\n"
- for(var/g in env.gas)
- t += "[g]: [env.gas[g]] / [env.gas[g] * R_IDEAL_GAS_EQUATION * env.temperature / env.total_volume]kPa\n"
+ for(var/gas_type, gas_amount in env.gas)
+ t += "[gas_type]: [gas_amount] / [gas_amount * R_IDEAL_GAS_EQUATION * env.temperature / env.total_volume]kPa\n"
usr.show_message(t, 1)
SSstatistics.add_field_details("admin_verb","ASL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
diff --git a/code/modules/atmospherics/atmos_primitives.dm b/code/modules/atmospherics/atmos_primitives.dm
index 6a09490b3251..13a0044acfc6 100644
--- a/code/modules/atmospherics/atmos_primitives.dm
+++ b/code/modules/atmospherics/atmos_primitives.dm
@@ -110,27 +110,28 @@
if (source.total_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing
return -1
- filtering = filtering & source.gas //only filter gasses that are actually there. DO NOT USE &=
+ // this takes the associated values of the left side, e.g. source.gas
+ filtering = source.gas & filtering //only filter gasses that are actually there. DO NOT USE &=
//Determine the specific power of each filterable gas type, and the total amount of filterable gas (gasses selected to be scrubbed)
- var/total_filterable_moles = 0 //the total amount of filterable gas
- var/list/specific_power_gas = list() //the power required to remove one mole of pure gas, for each gas type
- for (var/g in filtering)
- if (source.gas[g] < MINIMUM_MOLES_TO_FILTER)
+ var/total_filterable_moles = 0 //the total amount of filterable gas
+ var/alist/specific_power_gas = alist() //the power required to remove one mole of pure gas, for each gas type
+ ///the power required to scrub one mol of input gas
+ var/power_per_mol = 0
+ for (var/gas_type, gas_amount in filtering)
+ if (gas_amount < MINIMUM_MOLES_TO_FILTER)
continue
- var/specific_power = calculate_specific_power_gas(g, source, sink)/ATMOS_FILTER_EFFICIENCY
- specific_power_gas[g] = specific_power
- total_filterable_moles += source.gas[g]
+ var/specific_power = calculate_specific_power_gas(gas_type, source, sink)/ATMOS_FILTER_EFFICIENCY
+ specific_power_gas[gas_type] = specific_power
+ power_per_mol += gas_amount * specific_power
+ total_filterable_moles += gas_amount
if (total_filterable_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing
return -1
//now that we know the total amount of filterable gas, we can calculate the amount of power needed to scrub one mole of gas
- var/total_specific_power = 0 //the power required to remove one mole of filterable gas
- for (var/g in filtering)
- var/ratio = source.gas[g]/total_filterable_moles //this converts the specific power per mole of pure gas to specific power per mole of scrubbed gas
- total_specific_power += specific_power_gas[g]*ratio
+ power_per_mol /= total_filterable_moles //this converts the specific power per mole of pure gas to specific power per mole of scrubbed gas
//Figure out how much of each gas to filter
if (isnull(total_transfer_moles))
@@ -139,8 +140,8 @@
total_transfer_moles = min(total_transfer_moles, total_filterable_moles)
//limit transfer_moles based on available power
- if (!isnull(available_power) && total_specific_power > 0)
- total_transfer_moles = min(total_transfer_moles, available_power/total_specific_power)
+ if (!isnull(available_power) && power_per_mol > 0)
+ total_transfer_moles = min(total_transfer_moles, available_power/power_per_mol)
if (total_transfer_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing
return -1
@@ -154,16 +155,15 @@
P.last_flow_rate = (total_transfer_moles/source.total_moles)*source.total_volume //group_multiplier gets divided out here
var/power_draw = 0
- for (var/g in filtering)
- var/transfer_moles = source.gas[g]
+ for (var/gas_type, gas_amount in filtering)
//filter gas in proportion to the mole ratio
- transfer_moles = min(transfer_moles, total_transfer_moles*(source.gas[g]/total_filterable_moles))
+ var/transfer_moles = min(gas_amount, total_transfer_moles*(gas_amount/total_filterable_moles))
//use update=0. All the filtered gasses are supposed to be added simultaneously, so we update after the for loop.
- source.adjust_gas(g, -transfer_moles, update=0)
- sink.adjust_gas_temp(g, transfer_moles, source.temperature, update=0)
+ source.adjust_gas(gas_type, -transfer_moles, update=0)
+ sink.adjust_gas_temp(gas_type, transfer_moles, source.temperature, update=0)
- power_draw += specific_power_gas[g]*transfer_moles
+ power_draw += specific_power_gas[gas_type]*transfer_moles
//Remix the resulting gases
sink.update_values()
@@ -181,25 +181,16 @@
if (source.total_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing
return -1
- filtering = filtering & source.gas //only filter gasses that are actually there. DO NOT USE &=
+ filtering = filtering & source.gas //only filter gasses that are actually there. DO NOT USE &=
- var/total_specific_power = 0 //the power required to remove one mole of input gas
- var/total_filterable_moles = 0 //the total amount of filterable gas
- var/total_unfilterable_moles = 0 //the total amount of non-filterable gas
- var/list/specific_power_gas = list() //the power required to remove one mole of pure gas, for each gas type
- for (var/g in source.gas)
- if (source.gas[g] < MINIMUM_MOLES_TO_FILTER)
+ var/power_per_mol = 0
+ for (var/gas_type, gas_amount in source.gas)
+ if (gas_amount < MINIMUM_MOLES_TO_FILTER)
continue
+ //the power required to move all the moles of this gas from source to sink
+ power_per_mol += gas_amount * calculate_specific_power_gas(gas_type, source, (gas_type in filtering) ? sink_filtered : sink_clean)/ATMOS_FILTER_EFFICIENCY
- if (g in filtering)
- specific_power_gas[g] = calculate_specific_power_gas(g, source, sink_filtered)/ATMOS_FILTER_EFFICIENCY
- total_filterable_moles += source.gas[g]
- else
- specific_power_gas[g] = calculate_specific_power_gas(g, source, sink_clean)/ATMOS_FILTER_EFFICIENCY
- total_unfilterable_moles += source.gas[g]
-
- var/ratio = source.gas[g]/source.total_moles //converts the specific power per mole of pure gas to specific power per mole of input gas mix
- total_specific_power += specific_power_gas[g]*ratio
+ power_per_mol /= source.total_moles //converts the sum of specific powers per mole of pure gas to specific power per mole of input gas mix
//Figure out how much of each gas to filter
if (isnull(total_transfer_moles))
@@ -208,8 +199,8 @@
total_transfer_moles = min(total_transfer_moles, source.total_moles)
//limit transfer_moles based on available power
- if (!isnull(available_power) && total_specific_power > 0)
- total_transfer_moles = min(total_transfer_moles, available_power/total_specific_power)
+ if (!isnull(available_power) && power_per_mol > 0)
+ total_transfer_moles = min(total_transfer_moles, available_power/power_per_mol)
if (total_transfer_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing
return -1
@@ -223,28 +214,21 @@
P.last_flow_rate = (total_transfer_moles/source.total_moles)*source.total_volume //group_multiplier gets divided out here
var/datum/gas_mixture/removed = source.remove(total_transfer_moles)
- if (!removed) //Just in case
+ if (!removed?.total_moles) //Just in case
return -1
- var/filtered_power_used = 0 //power used to move filterable gas to sink_filtered
- var/unfiltered_power_used = 0 //power used to move unfilterable gas to sink_clean
- for (var/g in removed.gas)
- var/power_used = specific_power_gas[g]*removed.gas[g]
-
- if (g in filtering)
- //use update=0. All the filtered gasses are supposed to be added simultaneously, so we update after the for loop.
- sink_filtered.adjust_gas_temp(g, removed.gas[g], removed.temperature, update=0)
- removed.adjust_gas(g, -removed.gas[g], update=0)
- filtered_power_used += power_used
- else
- unfiltered_power_used += power_used
+ // total power draw
+ . = power_per_mol * removed.total_moles
+ for (var/gas_type, gas_amount in removed.gas & filtering) // only the filtered gases
+ //use update=0. All the filtered gasses are supposed to be added simultaneously, so we update after the for loop.
+ sink_filtered.adjust_gas_temp(gas_type, gas_amount, removed.temperature, update=0)
+ removed.adjust_gas(gas_type, -gas_amount, update=0)
sink_filtered.update_values()
removed.update_values()
-
sink_clean.merge(removed)
- return filtered_power_used + unfiltered_power_used
+ return .
//For omni devices. Instead filtering is an associative list mapping gasids to gas mixtures.
//I don't like the copypasta, but I decided to keep both versions of gas filtering as filter_gas is slightly faster (doesn't create as many temporary lists, doesn't call update_values() as much)
@@ -253,26 +237,15 @@
if (source.total_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing
return -1
- filtering = filtering & source.gas //only filter gasses that are actually there. DO NOT USE &=
+ filtering = filtering & source.gas //only filter gasses that are actually there. DO NOT USE &=
- var/total_specific_power = 0 //the power required to remove one mole of input gas
- var/total_filterable_moles = 0 //the total amount of filterable gas
- var/total_unfilterable_moles = 0 //the total amount of non-filterable gas
- var/list/specific_power_gas = list() //the power required to remove one mole of pure gas, for each gas type
- for (var/g in source.gas)
- if (source.gas[g] < MINIMUM_MOLES_TO_FILTER)
+ var/power_per_mol = 0
+ for (var/gas_type, gas_amount in source.gas)
+ if (gas_amount < MINIMUM_MOLES_TO_FILTER)
continue
-
- if (g in filtering)
- var/datum/gas_mixture/sink_filtered = filtering[g]
- specific_power_gas[g] = calculate_specific_power_gas(g, source, sink_filtered)/ATMOS_FILTER_EFFICIENCY
- total_filterable_moles += source.gas[g]
- else
- specific_power_gas[g] = calculate_specific_power_gas(g, source, sink_clean)/ATMOS_FILTER_EFFICIENCY
- total_unfilterable_moles += source.gas[g]
-
- var/ratio = source.gas[g]/source.total_moles //converts the specific power per mole of pure gas to specific power per mole of input gas mix
- total_specific_power += specific_power_gas[g]*ratio
+ power_per_mol += gas_amount * (calculate_specific_power_gas(gas_type, source, filtering[gas_type] || sink_clean)/ATMOS_FILTER_EFFICIENCY)
+ //converts the sum of specific powers per mole of pure gas to specific power per mole of input gas mix
+ power_per_mol /= source.total_moles
//Figure out how much of each gas to filter
if (isnull(total_transfer_moles))
@@ -281,8 +254,8 @@
total_transfer_moles = min(total_transfer_moles, source.total_moles)
//limit transfer_moles based on available power
- if (!isnull(available_power) && total_specific_power > 0)
- total_transfer_moles = min(total_transfer_moles, available_power/total_specific_power)
+ if (!isnull(available_power) && power_per_mol > 0)
+ total_transfer_moles = min(total_transfer_moles, available_power/power_per_mol)
if (total_transfer_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing
return -1
@@ -299,27 +272,14 @@
if (!removed) //Just in case
return -1
- var/list/filtered_power_used = list() //power used to move filterable gas to the filtered gas mixes
- var/unfiltered_power_used = 0 //power used to move unfilterable gas to sink_clean
- for (var/g in removed.gas)
- var/power_used = specific_power_gas[g]*removed.gas[g]
-
- if (g in filtering)
- var/datum/gas_mixture/sink_filtered = filtering[g]
- //use update=0. All the filtered gasses are supposed to be added simultaneously, so we update after the for loop.
- sink_filtered.adjust_gas_temp(g, removed.gas[g], removed.temperature, update=1)
- removed.adjust_gas(g, -removed.gas[g], update=0)
- if (power_used)
- filtered_power_used[sink_filtered] = power_used
- else
- unfiltered_power_used += power_used
-
+ // for some reason we used to separate filtered and unfiltered power but then we just added it back up anyway??
+ var/power_draw = power_per_mol * removed.total_moles
+ for (var/gas_type, gas_amount in removed.gas & filtering) // keys in both with the values of the former
+ var/datum/gas_mixture/sink_filtered = filtering[gas_type]
+ //use update=0. All the filtered gasses are supposed to be added simultaneously, so we update after the for loop.
+ sink_filtered.adjust_gas_temp(gas_type, gas_amount, removed.temperature, update=1)
+ removed.adjust_gas(gas_type, -gas_amount, update=FALSE)
removed.update_values()
-
- var/power_draw = unfiltered_power_used
- for (var/datum/gas_mixture/sink_filtered in filtered_power_used)
- power_draw += filtered_power_used[sink_filtered]
-
sink_clean.merge(removed)
return power_draw
diff --git a/code/modules/atmospherics/components/unary/unary_base.dm b/code/modules/atmospherics/components/unary/unary_base.dm
index 6cbe3cb184b6..21734409daa8 100644
--- a/code/modules/atmospherics/components/unary/unary_base.dm
+++ b/code/modules/atmospherics/components/unary/unary_base.dm
@@ -12,9 +12,9 @@
/obj/machinery/atmospherics/unary/get_single_monetary_worth()
. = ..()
- for(var/gas in air_contents?.gas)
- var/decl/material/gas_data = GET_DECL(gas)
- . += gas_data.get_value() * air_contents.gas[gas] * GAS_WORTH_MULTIPLIER
+ for(var/gas_type, gas_amount in air_contents?.gas)
+ var/decl/material/gas_data = GET_DECL(gas_type)
+ . += gas_data.get_value() * gas_amount * GAS_WORTH_MULTIPLIER
. = max(1, round(.))
/obj/machinery/atmospherics/unary/Initialize()
diff --git a/code/modules/atmospherics/he_pipes.dm b/code/modules/atmospherics/he_pipes.dm
index 2a11c6cde77d..d066b446d916 100644
--- a/code/modules/atmospherics/he_pipes.dm
+++ b/code/modules/atmospherics/he_pipes.dm
@@ -63,6 +63,7 @@
// Handle pipe heat exchange.
var/turf/turf = loc
var/datum/gas_mixture/pipe_air = return_air()
+ var/heat_radiated = FALSE
if(istype(loc, /turf/space))
parent.radiate_heat_to_space(surface, 1)
else if(istype(turf) && turf.simulated)
@@ -71,8 +72,13 @@
environment_temperature = turf.temperature
else
var/datum/gas_mixture/environment = turf.return_air()
+ if(environment.get_total_moles() == 0) // We're in a vacuum
+ if(loc.is_outside()) // But we're outside, so we're in space
+ parent.radiate_heat_to_space(surface, 0.5) // Radiate out at half efficiency
+ // Else, we're inside, no gas means no heat capacity. Nothing to do, heat was dealt with either way
+ heat_radiated = TRUE // Skip temperature_interact() either way
environment_temperature = environment?.temperature || 0
- if(abs(environment_temperature-pipe_air.temperature) > minimum_temperature_difference)
+ if(!heat_radiated && abs(environment_temperature-pipe_air.temperature) > minimum_temperature_difference)
parent.temperature_interact(turf, gas_volume, thermal_conductivity)
// Burn mobs buckled to this pipe.
diff --git a/code/modules/atmospherics/pipes.dm b/code/modules/atmospherics/pipes.dm
index 5d7ee7e8cb1f..f31cd7a5c53e 100644
--- a/code/modules/atmospherics/pipes.dm
+++ b/code/modules/atmospherics/pipes.dm
@@ -165,9 +165,13 @@
/obj/machinery/atmospherics/get_color()
return pipe_color
-/obj/machinery/atmospherics/set_color(new_color)
- pipe_color = new_color
- update_icon()
+/obj/machinery/atmospherics/set_color(new_color, skip_update)
+ if(pipe_color != new_color)
+ pipe_color = new_color
+ if(!skip_update)
+ update_icon()
+ return TRUE
+ return FALSE
/obj/machinery/atmospherics/pipe/color_cache_name(var/obj/machinery/atmospherics/node)
if(istype(src, /obj/machinery/atmospherics/unary/tank))
@@ -183,11 +187,12 @@
else
return pipe_color
-/obj/machinery/atmospherics/pipe/set_color(new_color)
- ..()
- //for updating connected atmos device pipes (i.e. vents, manifolds, etc)
- for(var/obj/machinery/atmospherics/node as anything in nodes_to_networks)
- node.update_icon()
+/obj/machinery/atmospherics/pipe/set_color(new_color, skip_update)
+ . = ..()
+ if(. && !skip_update)
+ //for updating connected atmos device pipes (i.e. vents, manifolds, etc)
+ for(var/obj/machinery/atmospherics/node as anything in nodes_to_networks)
+ node.update_icon()
/obj/machinery/atmospherics/pipe/proc/try_leak()
var/missing = FALSE
diff --git a/code/modules/backgrounds/citizenship/_citizenship.dm b/code/modules/backgrounds/citizenship/_citizenship.dm
index e16cc9455ac7..8ff6186f88a3 100644
--- a/code/modules/backgrounds/citizenship/_citizenship.dm
+++ b/code/modules/backgrounds/citizenship/_citizenship.dm
@@ -1,18 +1,10 @@
/decl/background_detail/citizenship
abstract_type = /decl/background_detail/citizenship
category = /decl/background_category/citizenship
- var/ruling_body = "Other Faction"
- var/capital
- var/size_heading = "Systems"
- var/size_value
- var/founded
+ var/issuing_body
/decl/background_detail/citizenship/get_text_details()
. = list()
- if(!isnull(capital))
- . += "Capital: [capital]."
- if(!isnull(size_value) && !isnull(size_heading))
- . += "Extent: [size_value] [size_heading]."
- if(!isnull(founded))
- . += "Founded: [founded]"
+ if(!isnull(issuing_body))
+ . += "Issuing body: [issuing_body]."
. += ..()
diff --git a/code/modules/backgrounds/citizenship/citizenship_other.dm b/code/modules/backgrounds/citizenship/citizenship_other.dm
index cfeed30a29cf..8e9b9ab29408 100644
--- a/code/modules/backgrounds/citizenship/citizenship_other.dm
+++ b/code/modules/backgrounds/citizenship/citizenship_other.dm
@@ -13,7 +13,6 @@
uid = "stateless"
description = "You do not possess any kind of official citizenship."
economic_power = 0
- capital = "None"
/decl/background_detail/citizenship/synthetic
name = "Stateless Drone"
diff --git a/code/modules/bodytype/_bodytype.dm b/code/modules/bodytype/_bodytype.dm
index 600043bdc11b..03aae1595c27 100644
--- a/code/modules/bodytype/_bodytype.dm
+++ b/code/modules/bodytype/_bodytype.dm
@@ -639,7 +639,7 @@ var/global/list/bodytypes_by_category = list()
set_extension(limb, /datum/extension/armor, natural_armour_values)
//fully_replace: If true, all existing organs will be discarded. Useful when doing mob transformations, and not caring about the existing organs
-/decl/bodytype/proc/create_missing_organs(mob/living/human/H, fully_replace = FALSE)
+/decl/bodytype/proc/create_missing_organs(mob/living/human/H, fully_replace = FALSE, datum/mob_snapshot/snapshot_to_use = null)
if(fully_replace)
H.delete_organs()
@@ -659,8 +659,10 @@ var/global/list/bodytypes_by_category = list()
qdel(O)
//Create missing limbs
- var/datum/mob_snapshot/supplied_data = H.get_mob_snapshot()
- supplied_data.root_bodytype = src // This may not have been set on the target mob torso yet.
+ var/datum/mob_snapshot/supplied_data = snapshot_to_use
+ if(!supplied_data)
+ supplied_data = H.get_mob_snapshot()
+ supplied_data.root_bodytype = src // This may not have been set on the target mob torso yet.
for(var/limb_type in has_limbs)
if(GET_EXTERNAL_ORGAN(H, limb_type)) //Skip existing
diff --git a/code/modules/bodytype/bodytype_prosthetic.dm b/code/modules/bodytype/bodytype_prosthetic.dm
index 7423faf51b70..9cc143a05500 100644
--- a/code/modules/bodytype/bodytype_prosthetic.dm
+++ b/code/modules/bodytype/bodytype_prosthetic.dm
@@ -35,7 +35,6 @@
'sound/foley/metal1.ogg'
)
has_organ = list(
- BP_BRAIN = /obj/item/organ/internal/brain_interface,
BP_EYES = /obj/item/organ/internal/eyes,
BP_CELL = /obj/item/organ/internal/cell
)
diff --git a/code/modules/client/preference_setup/general/03_traits.dm b/code/modules/client/preference_setup/general/03_traits.dm
index b61d8b02b201..e2a06b282568 100644
--- a/code/modules/client/preference_setup/general/03_traits.dm
+++ b/code/modules/client/preference_setup/general/03_traits.dm
@@ -39,10 +39,18 @@
else
pref.prune_invalid_traits()
+/datum/category_item/player_setup_item/traits/populate_mob_snapshot(datum/mob_snapshot/snapshot, is_preview_copy)
+ for(var/trait_type in pref.traits)
+ var/decl/trait/trait = GET_DECL(trait_type)
+ if(trait.is_heritable)
+ LAZYSET(snapshot.heritable_traits, trait_type, pref.traits[trait_type] || TRAIT_LEVEL_EXISTS)
+
/datum/category_item/player_setup_item/traits/apply_post_snapshot_preferences(mob/living/human/character, is_preview_copy = FALSE)
- character.clear_extrinsic_traits()
+ // apply non-heritable traits now
for(var/trait_type in pref.traits)
- character.set_trait(trait_type, (pref.traits[trait_type] || TRAIT_LEVEL_EXISTS))
+ var/decl/trait/trait = GET_DECL(trait_type)
+ if(!trait.is_heritable)
+ character.set_trait(trait_type, (pref.traits[trait_type] || TRAIT_LEVEL_EXISTS))
/datum/category_item/player_setup_item/traits/save_character(datum/pref_record_writer/writer)
var/list/trait_ids = list()
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index cdfe05e2c66c..e851c2513908 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -309,6 +309,7 @@ var/global/list/time_prefs_fixed = list()
if(href_list["save"])
save_preferences()
save_character()
+ return TRUE // don't regenerate our preview, that's wasteful
else if(href_list["reload"])
load_preferences()
load_character()
@@ -325,6 +326,8 @@ var/global/list/time_prefs_fixed = list()
if(isnewplayer(client.mob))
var/mob/new_player/M = client.mob
M.show_lobby_menu()
+ update_setup_window(usr)
+ return TRUE // don't do a duplicate icon update
else if(href_list["resetslot"])
if(real_name != input("This will reset the current slot. Enter the character's full name to confirm."))
@@ -339,12 +342,15 @@ var/global/list/time_prefs_fixed = list()
equip_preview_mob ^= text2num(href_list["toggle_preview_value"])
else if(href_list["cycle_bg"])
bgstate = next_in_list(bgstate, global.using_map.char_preview_bgstate_options)
+ update_preview_icon(redress_mob = FALSE)
+ return TRUE
else
return FALSE
+ // this should get hit for reset, reload, load, slot change, and equipment preview toggle
update_preview_icon()
update_setup_window(usr)
- return 1
+ return TRUE
/datum/category_item/player_setup_item/records/character_info/apply_post_snapshot_preferences(mob/living/human/character, is_preview_copy = FALSE)
if(is_preview_copy)
diff --git a/code/modules/clothing/_clothing.dm b/code/modules/clothing/_clothing.dm
index 6ac430b952f5..67483c57d4f8 100644
--- a/code/modules/clothing/_clothing.dm
+++ b/code/modules/clothing/_clothing.dm
@@ -452,11 +452,12 @@
if(get_vitals_sensor())
LAZYADD(., /decl/interaction_handler/clothing_set_sensors)
-/obj/item/clothing/proc/set_markings_color(new_color)
+/obj/item/clothing/proc/set_markings_color(new_color, skip_update)
if(markings_color != new_color)
markings_color = new_color
- update_icon()
- update_clothing_icon()
+ if(!skip_update)
+ update_icon()
+ update_clothing_icon()
return TRUE
return FALSE
diff --git a/code/modules/clothing/spacesuits/rig/modules/computer.dm b/code/modules/clothing/spacesuits/rig/modules/computer.dm
index 673ecb204be0..7b4b78c9dfb3 100644
--- a/code/modules/clothing/spacesuits/rig/modules/computer.dm
+++ b/code/modules/clothing/spacesuits/rig/modules/computer.dm
@@ -59,6 +59,7 @@
var/mob/living/integrated_ai // Direct reference to the actual mob held in the suit.
var/obj/item/ai_card // Reference to the object previously holding the AI.
var/obj/item/ai_verbs/verb_holder
+ var/list/simple_insert_types = list(/obj/item/paicard)
/mob/living
var/get_rig_stats = 0
@@ -133,7 +134,7 @@
return 1
// Okay, it wasn't a terminal being touched, check for all the simple insertions.
- if(input_device.type in list(/obj/item/paicard, /obj/item/organ/internal/brain_interface))
+ if(is_type_in_list(input_device, simple_insert_types))
if(integrated_ai)
integrated_ai.attackby(input_device,user)
// If the transfer was successful, we can clear out our vars.
diff --git a/code/modules/clothing/suits/_suit_hood.dm b/code/modules/clothing/suits/_suit_hood.dm
index ba02cf546900..c4227a0cc66e 100644
--- a/code/modules/clothing/suits/_suit_hood.dm
+++ b/code/modules/clothing/suits/_suit_hood.dm
@@ -3,20 +3,23 @@
/obj/item/clothing/suit/Initialize()
if(ispath(hood))
- hood = new hood(src)
- hood.paint_color = paint_color
- hood.markings_color = markings_color
+ hood = new hood(src, material)
+ hood.canremove = FALSE
+ if(markings_color)
+ hood.set_markings_color(markings_color, skip_update = TRUE)
+ if(paint_color)
+ hood.set_color(paint_color, skip_update = TRUE)
if(isnull(hood.markings_state_modifier))
hood.markings_state_modifier = markings_state_modifier
hood.update_icon()
return ..()
-/obj/item/clothing/suit/set_color(new_color)
+/obj/item/clothing/suit/set_color(new_color, skip_update)
. = ..()
if(. && istype(hood))
- hood.set_color(new_color)
+ hood.set_color(new_color, skip_update)
-/obj/item/clothing/suit/set_markings_color(new_color)
+/obj/item/clothing/suit/set_markings_color(new_color, skip_update)
. = ..()
if(istype(hood))
hood.set_markings_color(new_color)
@@ -48,18 +51,6 @@
if(length(.) && istype(hood)) // this is considered a component rather than a contained item
. -= hood
-/obj/item/clothing/suit/Initialize()
- if(ispath(hood))
- hood = new hood(src, material)
- if(paint_color)
- hood.set_color(paint_color)
- return ..()
-
-/obj/item/clothing/suit/Destroy()
- if(istype(hood))
- QDEL_NULL(hood)
- return ..()
-
/obj/item/clothing/suit/equipped(mob/user, slot)
if(slot != slot_wear_suit_str)
remove_hood()
diff --git a/code/modules/emotes/emote_mob.dm b/code/modules/emotes/emote_mob.dm
index b91444de9608..dd9e49236490 100644
--- a/code/modules/emotes/emote_mob.dm
+++ b/code/modules/emotes/emote_mob.dm
@@ -15,8 +15,8 @@
/mob/living/check_mob_can_emote(var/emote_type)
return ..() && !(HAS_STATUS(src, STAT_SILENCE) && emote_type == AUDIBLE_MESSAGE)
-/mob/living/brain/check_mob_can_emote(var/emote_type)
- return ..() && istype(get_container(), /obj/item/organ/internal/brain_interface)
+/mob/living/brain/check_mob_can_emote(var/emote_type, allow_brain_emote = FALSE)
+ return ..() && allow_brain_emote
#define EMOTE_REFRESH_SPAM_COOLDOWN (5 SECONDS)
/mob/proc/emote(var/act, var/m_type, var/message)
diff --git a/code/modules/fabrication/designs/protolathe/designs_machine_intelligence.dm b/code/modules/fabrication/designs/protolathe/designs_machine_intelligence.dm
index 3b52762f8f94..2dd5145d0b56 100644
--- a/code/modules/fabrication/designs/protolathe/designs_machine_intelligence.dm
+++ b/code/modules/fabrication/designs/protolathe/designs_machine_intelligence.dm
@@ -1,16 +1,10 @@
/datum/fabricator_recipe/protolathe/brains
category = "Machine Intelligence"
- path = /obj/item/organ/internal/brain_interface/empty
+ path = /obj/item/organ/internal/brain/robotic
/datum/fabricator_recipe/protolathe/brains/get_product_name()
. = "intelligence storage ([..()])"
-/datum/fabricator_recipe/protolathe/brains/robotic
- path = /obj/item/organ/internal/brain/robotic
-
-/datum/fabricator_recipe/protolathe/brains/mmi_radio
- path = /obj/item/organ/internal/brain_interface/radio_enabled/empty
-
/datum/fabricator_recipe/protolathe/brains/paicard
path = /obj/item/paicard
diff --git a/code/modules/fusion/core/core_field.dm b/code/modules/fusion/core/core_field.dm
index f9c366bc4960..fdd171b839c2 100644
--- a/code/modules/fusion/core/core_field.dm
+++ b/code/modules/fusion/core/core_field.dm
@@ -100,11 +100,11 @@
var/datum/gas_mixture/uptake_gas = owned_core.loc.return_air()
if(uptake_gas)
uptake_gas = uptake_gas.remove_by_flag(MAT_FLAG_FUSION_FUEL, rand(50,100), TRUE)
- if(uptake_gas && uptake_gas.total_moles)
- for(var/gasname in uptake_gas.gas)
- if(uptake_gas.gas[gasname]*10 > reactants[gasname])
- AddParticles(gasname, uptake_gas.gas[gasname]*10)
- uptake_gas.adjust_gas(gasname, -(uptake_gas.gas[gasname]), update=FALSE)
+ if(uptake_gas?.total_moles)
+ for(var/gas_type, gas_amount in uptake_gas.gas)
+ if(gas_amount*10 > reactants[gas_type])
+ AddParticles(gas_type, gas_amount*10)
+ uptake_gas.adjust_gas(gas_type, -gas_amount, update=FALSE)
added_particles = TRUE
if(added_particles)
uptake_gas.update_values()
diff --git a/code/modules/lights/light_bulbs_tubes.dm b/code/modules/lights/light_bulbs_tubes.dm
index 496ca639c1c4..1c70ad67bb80 100644
--- a/code/modules/lights/light_bulbs_tubes.dm
+++ b/code/modules/lights/light_bulbs_tubes.dm
@@ -31,9 +31,10 @@
/obj/item/light/get_color()
return b_color
-/obj/item/light/set_color(color)
+/obj/item/light/set_color(new_color, skip_update)
b_color = isnull(color) ? COLOR_WHITE : color
- queue_icon_update() // avoid running update_icon before Initialize
+ if(!skip_update)
+ queue_icon_update() // avoid running update_icon before Initialize
/obj/item/light/tube
name = "light tube"
diff --git a/code/modules/lights/light_fixture_base.dm b/code/modules/lights/light_fixture_base.dm
index 0f2f5741a626..1afdd5b1552f 100644
--- a/code/modules/lights/light_fixture_base.dm
+++ b/code/modules/lights/light_fixture_base.dm
@@ -39,9 +39,9 @@
/obj/machinery/light/get_color()
return lightbulb?.get_color()
-/obj/machinery/light/set_color(color)
- . = lightbulb?.set_color(color)
- if(.)
+/obj/machinery/light/set_color(new_color, skip_update)
+ . = lightbulb?.set_color(color, skip_update)
+ if(. && !skip_update)
update_light_status(TRUE)
update_icon()
diff --git a/code/modules/maps/reader.dm b/code/modules/maps/reader.dm
index 9f7dff608187..1704be274b26 100644
--- a/code/modules/maps/reader.dm
+++ b/code/modules/maps/reader.dm
@@ -348,7 +348,7 @@ var/global/dmm_suite/preloader/_preloader = new
instance = new atype(null)
initialized_areas_by_type[atype] = instance
if(crds)
- ChangeArea(crds, instance)
+ crds.ChangeArea(instance)
//then instance the /turf and, if multiple tiles are presents, simulates the DMM underlays piling effect
diff --git a/code/modules/maps/template_types/random_exoplanet/flora_generator.dm b/code/modules/maps/template_types/random_exoplanet/flora_generator.dm
index 75c97b70ffc0..1ee8cf4f83cf 100644
--- a/code/modules/maps/template_types/random_exoplanet/flora_generator.dm
+++ b/code/modules/maps/template_types/random_exoplanet/flora_generator.dm
@@ -71,9 +71,9 @@
S.exude_gasses -= exuded_gases_exclusions
if(length(atmos.gas))
if(S.consume_gasses)
- S.consume_gasses = list(pick(atmos.gas)) // ensure that if the plant consumes a gas, the atmosphere will have it
- for(var/g in atmos.gas)
- var/decl/material/mat = GET_DECL(g)
+ S.consume_gasses = list(apick(atmos.gas)) // ensure that if the plant consumes a gas, the atmosphere will have it
+ for(var/gas_type in atmos.gas)
+ var/decl/material/mat = GET_DECL(gas_type)
if(mat.gas_flags & XGM_GAS_CONTAMINANT)
S.set_trait(TRAIT_TOXINS_TOLERANCE, rand(10,15))
if(prob(50))
diff --git a/code/modules/maps/template_types/random_exoplanet/planetoid_data.dm b/code/modules/maps/template_types/random_exoplanet/planetoid_data.dm
index 95df86b82f93..5591ee519965 100644
--- a/code/modules/maps/template_types/random_exoplanet/planetoid_data.dm
+++ b/code/modules/maps/template_types/random_exoplanet/planetoid_data.dm
@@ -16,8 +16,6 @@
var/width
///Preferred height for all the planet z-levels. Null means it's up to each z-levels. Not reliable for telling the height of the levels under this planet.
var/height
- ///Preferred amount of vertically connected z-levels for this planets. Null means it's up to each z-levels.
- var/tallness = 1
///Topmost level data datum id of the root z stack (ID only, because this datum has an uncontrolled lifetime, and we don't want dangling refs)
var/topmost_level_id
///Level data id for the level that's considered to be the planet's surface. In other words, the topmost firm ground level of the root z stack.
diff --git a/code/modules/materials/_materials.dm b/code/modules/materials/_materials.dm
index ada5e9a86c73..e515e82710ae 100644
--- a/code/modules/materials/_materials.dm
+++ b/code/modules/materials/_materials.dm
@@ -391,6 +391,9 @@ var/global/list/materials_by_gas_symbol = list()
else if(isnull(ignition_point) || (new_temperature_damage_threshold > ignition_point))
temperature_damage_threshold = new_temperature_damage_threshold
+ global.cached_specific_heat[type] = gas_specific_heat
+ global.cached_molar_mass[type] = molar_mass
+
if(!shard_icon)
shard_icon = shard_name
if(!burn_armor)
diff --git a/code/modules/mechs/mech.dm b/code/modules/mechs/_mech.dm
similarity index 98%
rename from code/modules/mechs/mech.dm
rename to code/modules/mechs/_mech.dm
index 25f9ecbf7873..957fe6f236a4 100644
--- a/code/modules/mechs/mech.dm
+++ b/code/modules/mechs/_mech.dm
@@ -68,10 +68,10 @@
var/mob/living/current_user = null
-
-//Pixel projectiles need a client, so we need a way to pass who the last user was for view calcs
-/mob/living/proc/get_effective_gunner()
- return src
+/mob/living/exosuit/carried_mob_intent_changed(mob/user, decl/intent/new_intent)
+ if(user in pilots)
+ return set_intent(new_intent)
+ return ..()
/mob/living/exosuit/get_effective_gunner()
return current_user
@@ -260,4 +260,3 @@
if(current_user)
return FALSE
return ..()
-
diff --git a/code/modules/mechs/components/body.dm b/code/modules/mechs/components/body.dm
index 90890403e105..83869776a9c4 100644
--- a/code/modules/mechs/components/body.dm
+++ b/code/modules/mechs/components/body.dm
@@ -57,8 +57,8 @@
var/datum/gas_mixture/air = loc.return_air()
if(air)
//Essentially at this point its like we created a vacuum, but realistically making a bottle doesnt actually increase volume of a room and neither should a mech
- for(var/g in air.gas)
- cockpit.gas[g] = (air.gas[g] / air.total_volume) * cockpit.total_volume
+ for(var/gas_type, gas_amount in air.gas)
+ cockpit.gas[gas_type] = (gas_amount / air.total_volume) * cockpit.total_volume
cockpit.temperature = air.temperature
cockpit.update_values()
diff --git a/code/modules/mechs/components/frame.dm b/code/modules/mechs/components/frame.dm
index 867a6b831ec7..439d0a28e639 100644
--- a/code/modules/mechs/components/frame.dm
+++ b/code/modules/mechs/components/frame.dm
@@ -18,12 +18,12 @@
var/is_reinforced = 0
var/set_name
-/obj/structure/heavy_vehicle_frame/set_color(new_colour)
+/obj/structure/heavy_vehicle_frame/set_color(new_color, skip_update)
var/painted_component = FALSE
for(var/obj/item/mech_component/comp in list(body, arms, legs, head))
- if(comp.set_color(new_colour))
+ if(comp.set_color(new_color, skip_update))
painted_component = TRUE
- if(painted_component)
+ if(!skip_update && painted_component)
queue_icon_update()
/obj/structure/heavy_vehicle_frame/Destroy()
diff --git a/code/modules/mechs/equipment/_equipment.dm b/code/modules/mechs/equipment/_equipment.dm
index ca8273afd3b2..c98994742c58 100644
--- a/code/modules/mechs/equipment/_equipment.dm
+++ b/code/modules/mechs/equipment/_equipment.dm
@@ -27,26 +27,24 @@
/obj/item/mech_equipment/afterattack(var/atom/target, var/mob/living/user, var/inrange, var/params)
if(require_adjacent)
if(!inrange)
- return 0
+ return FALSE
if (owner && loc == owner && ((user in owner.pilots) || user == owner))
if(target in owner.contents)
- return 0
-
+ return FALSE
if(!(owner.get_cell()?.check_charge(active_power_use * CELLRATE)))
to_chat(user, SPAN_WARNING("The power indicator flashes briefly as you attempt to use \the [src]."))
- return 0
- return 1
- else
- return 0
+ return FALSE
+ return TRUE
+ return FALSE
+// Per base attack_self(), return TRUE on an action performed (ie. no further action done) and FALSE to continue action.
/obj/item/mech_equipment/attack_self(var/mob/user)
- if (owner && loc == owner && ((user in owner.pilots) || user == owner))
- if(!(owner.get_cell()?.check_charge(active_power_use * CELLRATE)))
- to_chat(user, SPAN_WARNING("The power indicator flashes briefly as you attempt to use \the [src]."))
- return 0
- return 1
- else
- return 0
+ if(!owner || loc != owner || (!(user in owner.pilots) && user != owner))
+ return TRUE
+ if(!(owner.get_cell()?.check_charge(active_power_use * CELLRATE)))
+ to_chat(user, SPAN_WARNING("The power indicator flashes briefly as you attempt to use \the [src]."))
+ return TRUE
+ return FALSE
/obj/item/mech_equipment/get_examine_strings(mob/user, distance, infix, suffix)
. = ..()
@@ -89,50 +87,6 @@
//Installed equipment shall not be unequiped.
return FALSE
-/obj/item/mech_equipment/mounted_system
- abstract_type = /obj/item/mech_equipment/mounted_system
- var/obj/item/holding
-
-/obj/item/mech_equipment/mounted_system/attack_self(var/mob/user)
- . = ..()
- if(. && holding)
- return holding.attack_self(user)
-
-/obj/item/mech_equipment/mounted_system/proc/forget_holding()
- if(holding) //It'd be strange for this to be called with this var unset
- events_repository.unregister(/decl/observ/destroyed, holding, src, PROC_REF(forget_holding))
- holding = null
- if(!QDELETED(src))
- qdel(src)
-
-/obj/item/mech_equipment/mounted_system/Initialize()
- . = ..()
- if(ispath(holding))
- holding = new holding(src)
- events_repository.register(/decl/observ/destroyed, holding, src, PROC_REF(forget_holding))
- if(!istype(holding))
- return
- if(!icon_state)
- icon = holding.icon
- icon_state = holding.icon_state
- SetName(holding.name)
- desc = "[holding.desc] This one is suitable for installation on an exosuit."
-
-/obj/item/mech_equipment/mounted_system/Destroy()
- events_repository.unregister(/decl/observ/destroyed, holding, src, PROC_REF(forget_holding))
- if(holding)
- QDEL_NULL(holding)
- . = ..()
-
-/obj/item/mech_equipment/mounted_system/get_effective_obj()
- return (holding ? holding : src)
-
-/obj/item/mech_equipment/mounted_system/get_hardpoint_status_value()
- return (holding ? holding.get_hardpoint_status_value() : null)
-
-/obj/item/mech_equipment/mounted_system/get_hardpoint_maptext()
- return (holding ? holding.get_hardpoint_maptext() : null)
-
/obj/item/proc/get_hardpoint_status_value()
return null
diff --git a/code/modules/mechs/equipment/combat.dm b/code/modules/mechs/equipment/combat.dm
index 750d69df49de..fa7e758282a8 100644
--- a/code/modules/mechs/equipment/combat.dm
+++ b/code/modules/mechs/equipment/combat.dm
@@ -79,8 +79,7 @@
. = ..()
/obj/item/mech_equipment/shields/attack_self(var/mob/user)
- . = ..()
- if(.)
+ if(!(. = ..()))
toggle()
/obj/item/mech_equipment/shields/proc/stop_damage(var/damage)
@@ -246,8 +245,7 @@
do_attack_effect(T, "smash")
/obj/item/mech_equipment/ballistic_shield/attack_self(mob/user)
- . = ..()
- if (.) //FORM A SHIELD WALL!
+ if (!(. = ..())) //FORM A SHIELD WALL!
if (last_max_block + 2 SECONDS < world.time)
owner.visible_message(SPAN_WARNING("\The [owner] raises \the [src], locking it in place!"), blind_message = SPAN_WARNING("You hear the whir of motors and scratching metal!"))
playsound(src ,'sound/effects/bamf.ogg',35,1)
@@ -320,8 +318,7 @@
O.handle_flashed(flash_time, do_stun = FALSE)
/obj/item/mech_equipment/flash/attack_self(mob/user)
- . = ..()
- if(.)
+ if(!(. = ..()))
if(world.time < next_use)
to_chat(user, SPAN_WARNING("\The [src] is recharging!"))
return
diff --git a/code/modules/mechs/equipment/combat_projectile.dm b/code/modules/mechs/equipment/combat_projectile.dm
index f71d5a2a5e59..a717954a893f 100644
--- a/code/modules/mechs/equipment/combat_projectile.dm
+++ b/code/modules/mechs/equipment/combat_projectile.dm
@@ -1,3 +1,11 @@
+/obj/item/mech_equipment/mounted_system/projectile
+ name = "mounted submachine gun"
+ icon_state = "mech_ballistic"
+ holding = /obj/item/gun/projectile/automatic/smg/mech
+ restricted_hardpoints = list(HARDPOINT_LEFT_HAND, HARDPOINT_RIGHT_HAND)
+ restricted_software = list(MECH_SOFTWARE_WEAPONS)
+ origin_tech = @'{"programming":4,"combat":6,"engineering":5}'
+
/obj/item/mech_equipment/mounted_system/projectile/attackby(var/obj/item/used_item, var/mob/user)
var/obj/item/gun/projectile/automatic/A = holding
if(!istype(A))
@@ -10,12 +18,6 @@
to_chat(user, SPAN_NOTICE("You load the ammo magazine into \the [src]."))
return TRUE
-/obj/item/mech_equipment/mounted_system/projectile/attack_self(var/mob/user)
- . = ..()
- if(. && holding)
- var/obj/item/gun/M = holding
- return M.switch_firemodes()
-
/obj/item/gun/projectile/automatic/get_hardpoint_status_value()
if(!isnull(ammo_magazine))
return ammo_magazine.get_stored_ammo_count()
@@ -26,14 +28,6 @@
return 0
//Weapons below this.
-/obj/item/mech_equipment/mounted_system/projectile
- name = "mounted submachine gun"
- icon_state = "mech_ballistic"
- holding = /obj/item/gun/projectile/automatic/smg/mech
- restricted_hardpoints = list(HARDPOINT_LEFT_HAND, HARDPOINT_RIGHT_HAND)
- restricted_software = list(MECH_SOFTWARE_WEAPONS)
- origin_tech = @'{"programming":4,"combat":6,"engineering":5}'
-
/obj/item/gun/projectile/automatic/smg/mech
magazine_type = /obj/item/ammo_magazine/mech/smg_top
allowed_magazines = /obj/item/ammo_magazine/mech/smg_top
@@ -167,4 +161,4 @@
gun.set_autofire(over_object, owner, FALSE)
return
- gun.clear_autofire()
\ No newline at end of file
+ gun.clear_autofire()
diff --git a/code/modules/mechs/equipment/engineering.dm b/code/modules/mechs/equipment/engineering.dm
index 607226f683e0..00ed16ae5e14 100644
--- a/code/modules/mechs/equipment/engineering.dm
+++ b/code/modules/mechs/equipment/engineering.dm
@@ -179,8 +179,7 @@
owner.update_icon()
/obj/item/mech_equipment/atmos_shields/attack_self(mob/user)
- . = ..()
- if(.)
+ if(!(. = ..()))
if(active)
deactivate()
else
diff --git a/code/modules/mechs/equipment/medical.dm b/code/modules/mechs/equipment/medical.dm
index f18d56ea2e0e..15f415cd6478 100644
--- a/code/modules/mechs/equipment/medical.dm
+++ b/code/modules/mechs/equipment/medical.dm
@@ -25,8 +25,7 @@
sleeper?.go_out()
/obj/item/mech_equipment/sleeper/attack_self(var/mob/user)
- . = ..()
- if(.)
+ if(!(. = ..()))
sleeper.ui_interact(user)
/obj/item/mech_equipment/sleeper/attackby(var/obj/item/used_item, var/mob/user)
diff --git a/code/modules/mechs/equipment/mounted_system.dm b/code/modules/mechs/equipment/mounted_system.dm
new file mode 100644
index 000000000000..d8a62f70a8fb
--- /dev/null
+++ b/code/modules/mechs/equipment/mounted_system.dm
@@ -0,0 +1,41 @@
+/obj/item/mech_equipment/mounted_system
+ abstract_type = /obj/item/mech_equipment/mounted_system
+ var/obj/item/holding
+
+/obj/item/mech_equipment/mounted_system/attack_self(var/mob/user)
+ return holding ? holding.attack_self(user) : ..()
+
+/obj/item/mech_equipment/mounted_system/proc/forget_holding()
+ if(holding) //It'd be strange for this to be called with this var unset
+ events_repository.unregister(/decl/observ/destroyed, holding, src, PROC_REF(forget_holding))
+ holding = null
+ if(!QDELETED(src))
+ qdel(src)
+
+/obj/item/mech_equipment/mounted_system/Initialize()
+ . = ..()
+ if(ispath(holding))
+ holding = new holding(src)
+ events_repository.register(/decl/observ/destroyed, holding, src, PROC_REF(forget_holding))
+ if(!istype(holding))
+ return
+ if(!icon_state)
+ icon = holding.icon
+ icon_state = holding.icon_state
+ SetName(holding.name)
+ desc = "[holding.desc] This one is suitable for installation on an exosuit."
+
+/obj/item/mech_equipment/mounted_system/Destroy()
+ events_repository.unregister(/decl/observ/destroyed, holding, src, PROC_REF(forget_holding))
+ if(holding)
+ QDEL_NULL(holding)
+ . = ..()
+
+/obj/item/mech_equipment/mounted_system/get_effective_obj()
+ return (holding ? holding : src)
+
+/obj/item/mech_equipment/mounted_system/get_hardpoint_status_value()
+ return (holding ? holding.get_hardpoint_status_value() : null)
+
+/obj/item/mech_equipment/mounted_system/get_hardpoint_maptext()
+ return (holding ? holding.get_hardpoint_maptext() : null)
diff --git a/code/modules/mechs/equipment/utility.dm b/code/modules/mechs/equipment/utility.dm
index 37b955a8ddfe..81ed2e6b9fe3 100644
--- a/code/modules/mechs/equipment/utility.dm
+++ b/code/modules/mechs/equipment/utility.dm
@@ -135,8 +135,7 @@
owner.visible_message("[owner] pushes [target] out of the way.")
/obj/item/mech_equipment/clamp/attack_self(var/mob/user)
- . = ..()
- if(.)
+ if(!(. = ..()))
drop_carrying(user, TRUE)
/obj/item/mech_equipment/clamp/get_alt_interactions(mob/user)
@@ -221,8 +220,7 @@
update_icon()
/obj/item/mech_equipment/light/attack_self(var/mob/user)
- . = ..()
- if(.)
+ if(!(. = ..()))
toggle()
to_chat(user, "You switch \the [src] [on ? "on" : "off"].")
@@ -276,15 +274,12 @@
else string += "Push"
return string
-
/obj/item/mech_equipment/catapult/attack_self(var/mob/user)
- . = ..()
- if(.)
+ if(!(. = ..()))
mode = mode == CATAPULT_SINGLE ? CATAPULT_AREA : CATAPULT_SINGLE
to_chat(user, SPAN_NOTICE("You set \the [src] to [mode == CATAPULT_SINGLE ? "single" : "multi"]-target mode."))
update_icon()
-
/obj/item/mech_equipment/catapult/afterattack(var/atom/target, var/mob/living/user, var/inrange, var/params)
. = ..()
if(.)
@@ -393,11 +388,9 @@
drill_head = new drill_head(src)
/obj/item/mech_equipment/drill/attack_self(var/mob/user)
- . = ..()
- if(.)
- if(drill_head)
- owner.visible_message(SPAN_WARNING("[owner] revs the [drill_head], menancingly."))
- playsound(src, 'sound/mecha/mechdrill.ogg', 50, 1)
+ if(!(. = ..()) && drill_head)
+ owner.visible_message(SPAN_WARNING("[owner] revs the [drill_head] menancingly."))
+ playsound(src, 'sound/mecha/mechdrill.ogg', 50, 1)
/obj/item/mech_equipment/drill/get_hardpoint_maptext()
if(drill_head)
@@ -615,14 +608,11 @@
return FALSE
/obj/item/mech_equipment/ionjets/attack_self(mob/user)
- . = ..()
- if (!.)
- return
-
- if (active)
- deactivate()
- else
- activate()
+ if(!(. = ..()))
+ if(active)
+ deactivate()
+ else
+ activate()
/obj/item/mech_equipment/ionjets/proc/activate()
passive_power_use = activated_passive_power
@@ -763,8 +753,7 @@
D.ui_interact(user)
/obj/item/mech_equipment/camera/attack_self(mob/user)
- . = ..()
- if(.)
+ if(!(. = ..()))
if(active)
deactivate()
else
diff --git a/code/modules/mechs/interface/_interface.dm b/code/modules/mechs/interface/_interface.dm
index f2985acc7324..a77bc9d53b7a 100644
--- a/code/modules/mechs/interface/_interface.dm
+++ b/code/modules/mechs/interface/_interface.dm
@@ -25,32 +25,28 @@
var/i = 1
for(var/hardpoint in hardpoints)
var/obj/screen/exosuit/hardpoint/H = new(null, src, null, null, null, null, hardpoint)
- H.screen_loc = "LEFT:6,TOP-[i]:-16"
+ H.screen_loc = "LEFT+1:6,TOP-[i]:-16"
hud_elements |= H
hardpoint_hud_elements[hardpoint] = H
i++
if(body && body.pilot_coverage >= 100)
additional_hud_elements += /obj/screen/exosuit/toggle/air
- i = 0
- var/pos = 7
+ i = 16
for(var/additional_hud in additional_hud_elements)
var/obj/screen/exosuit/M = new additional_hud(null, src)
- M.screen_loc = "LEFT:6,BOTTOM+[pos]:[i]"
+ M.screen_loc = "LEFT:6,TOP-1:-[i]"
hud_elements |= M
- i -= M.height
+ i += M.height
hud_health = new /obj/screen/exosuit/health(null, src)
- hud_health.screen_loc = "RIGHT-1:28,CENTER-3:11"
hud_elements |= hud_health
hud_open = locate(/obj/screen/exosuit/toggle/hatch_open) in hud_elements
hud_power = new /obj/screen/exosuit/power(null, src)
- hud_power.screen_loc = "RIGHT-1:28,CENTER-4:25"
hud_elements |= hud_power
hud_power_control = locate(/obj/screen/exosuit/toggle/power_control) in hud_elements
hud_camera = locate(/obj/screen/exosuit/toggle/camera) in hud_elements
hud_heat = new /obj/screen/exosuit/heat(null, src)
- hud_heat.screen_loc = "RIGHT-1:28,CENTER-4"
hud_elements |= hud_heat
refresh_hud()
diff --git a/code/modules/mechs/mech_construction.dm b/code/modules/mechs/mech_construction.dm
index fb4f5f6b705e..41a213d4893a 100644
--- a/code/modules/mechs/mech_construction.dm
+++ b/code/modules/mechs/mech_construction.dm
@@ -61,15 +61,19 @@
/mob/living/exosuit/proc/install_system(var/obj/item/system, var/system_hardpoint, var/mob/user)
set waitfor = FALSE
+
if(hardpoints_locked || hardpoints[system_hardpoint])
+ to_chat(user, SPAN_WARNING("\The [system] could not be installed in that hardpoint, as it is locked or occupied."))
return FALSE
var/obj/item/mech_equipment/ME = system
if(istype(ME))
if(ME.restricted_hardpoints && !(system_hardpoint in ME.restricted_hardpoints))
+ to_chat(user, SPAN_WARNING("\The [system] could not be installed in that hardpoint, as it is restricted."))
return FALSE
if(ME.restricted_software)
if(!head || !head.software)
+ to_chat(user, SPAN_WARNING("\The [system] could not be installed in that hardpoint, as it requires specialist software."))
return FALSE
var/found
for(var/software in ME.restricted_software)
@@ -77,6 +81,7 @@
found = TRUE
break
if(!found)
+ to_chat(user, SPAN_WARNING("\The [system] could not be installed in that hardpoint, as it requires specialist software."))
return FALSE
else
return FALSE
@@ -91,10 +96,10 @@
if(!do_after(user, delay, src) || user.get_active_held_item() != system)
return FALSE
- if(user.try_unequip(system))
- to_chat(user, SPAN_NOTICE("You install \the [system] in \the [src]'s [system_hardpoint]."))
- playsound(user.loc, 'sound/items/Screwdriver.ogg', 100, 1)
- else return FALSE
+ if(!user.try_unequip(system))
+ return FALSE
+ to_chat(user, SPAN_NOTICE("You install \the [system] in \the [src]'s [system_hardpoint]."))
+ playsound(user.loc, 'sound/items/Screwdriver.ogg', 100, 1)
events_repository.register(/decl/observ/destroyed, system, src, PROC_REF(forget_module))
diff --git a/code/modules/mechs/mech_interaction.dm b/code/modules/mechs/mech_interaction.dm
index 8a8e9b671675..eb900899d021 100644
--- a/code/modules/mechs/mech_interaction.dm
+++ b/code/modules/mechs/mech_interaction.dm
@@ -349,8 +349,8 @@
var/to_place = input("Where would you like to install it?") as null|anything in (realThing.restricted_hardpoints & free_hardpoints)
if(!to_place)
to_chat(user, SPAN_WARNING("There is no room to install \the [used_item]."))
- else if(!install_system(used_item, to_place, user))
- to_chat(user, SPAN_WARNING("\The [used_item] could not be installed in that hardpoint."))
+ else
+ install_system(used_item, to_place, user)
return TRUE
// Apply customisation.
diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm
index a565d1e1aae0..8f2f8a2212f0 100644
--- a/code/modules/mob/inventory.dm
+++ b/code/modules/mob/inventory.dm
@@ -389,6 +389,11 @@
for(var/thing in get_held_items())
try_unequip(thing, drop_loc)
+/mob/proc/drop_equipped_items(drop_loc = loc, include_carried = FALSE)
+ SHOULD_CALL_PARENT(TRUE)
+ for(var/thing in get_equipped_items(include_carried))
+ try_unequip(thing, drop_loc)
+
//Returns the item equipped to the specified slot, if any.
/mob/proc/get_equipped_item(var/slot)
SHOULD_CALL_PARENT(TRUE)
diff --git a/code/modules/mob/living/brain/brain.dm b/code/modules/mob/living/brain/brain.dm
index 7fbab9b36654..ea6366c8c7e2 100644
--- a/code/modules/mob/living/brain/brain.dm
+++ b/code/modules/mob/living/brain/brain.dm
@@ -41,18 +41,18 @@
/mob/living/brain/proc/get_container()
return get_recursive_loc_of_type(/obj/item/organ/internal)
+/mob/living/brain/proc/on_container_login(obj/item/organ/internal/container)
+ container.update_icon()
+
/mob/living/brain/Login()
. = ..()
var/obj/item/organ/internal/container = get_container()
if(istype(container))
- var/obj/item/organ/internal/brain_interface/interface = container
- if(istype(interface))
- interface.locked = TRUE
- container.update_icon()
+ on_container_login(container)
/mob/living/brain/proc/is_in_interface()
var/container = get_container()
- return istype(container, /obj/item/organ/internal/brain_interface) || istype(container, /obj/item/organ/internal/brain/robotic)
+ return istype(container, /obj/item/organ/internal/brain/robotic)
/mob/living/brain/can_emote(emote_type, show_message)
return is_in_interface() && ..()
diff --git a/code/modules/mob/living/brain/death.dm b/code/modules/mob/living/brain/death.dm
index 1c185d241c60..ee2313275490 100644
--- a/code/modules/mob/living/brain/death.dm
+++ b/code/modules/mob/living/brain/death.dm
@@ -1,25 +1,12 @@
-/mob/living/brain/get_death_message(gibbed)
- var/obj/item/organ/internal/brain_interface/container = get_container()
- if(!gibbed && istype(container))
- return "beeps shrilly as \the [container] flatlines!"
- return ..()
-
/mob/living/brain/death(gibbed)
var/obj/item/organ/holder = loc
- var/obj/item/organ/internal/brain_interface/container = get_container()
. = ..()
if(.)
if(stat == DEAD && istype(holder))
holder.die()
- if(istype(container) && !QDELETED(container))
- container.update_icon()
/mob/living/brain/gib(do_gibs = TRUE)
- var/obj/item/organ/internal/brain_interface/container = get_container()
var/obj/item/organ/internal/brain/sponge = loc
. = ..()
- if(.)
- if(istype(container) && !QDELETED(container))
- qdel(container)
- if(istype(sponge) && !QDELETED(sponge))
- qdel(sponge)
+ if(. && istype(sponge) && !QDELETED(sponge))
+ qdel(sponge)
diff --git a/code/modules/mob/living/brain/say.dm b/code/modules/mob/living/brain/say.dm
index c2542360968b..98946a423659 100644
--- a/code/modules/mob/living/brain/say.dm
+++ b/code/modules/mob/living/brain/say.dm
@@ -10,7 +10,3 @@
if(radio)
radio.hear_talk(src, sanitize(message), verb, speaking)
-/mob/living/brain/get_radio()
- var/obj/item/organ/internal/brain_interface/container = get_container()
- if(istype(container))
- return container.get_radio()
diff --git a/code/modules/mob/living/human/human.dm b/code/modules/mob/living/human/human.dm
index 00c520947984..4e60c2cc91d8 100644
--- a/code/modules/mob/living/human/human.dm
+++ b/code/modules/mob/living/human/human.dm
@@ -462,7 +462,7 @@
/mob/proc/set_bodytype(var/decl/bodytype/new_bodytype)
return
-/mob/living/human/set_bodytype(var/decl/bodytype/new_bodytype)
+/mob/living/human/set_bodytype(var/decl/bodytype/new_bodytype, var/datum/mob_snapshot/snapshot_to_use = null)
var/decl/bodytype/old_bodytype = get_bodytype()
if(ispath(new_bodytype))
@@ -489,7 +489,7 @@
//set_species should not handle the entirety of initing the mob, and should not trigger deep updates
//It focuses on setting up species-related data, without force applying them uppon organs and the mob's appearance.
// For transforming an existing mob, look at change_species()
-/mob/living/human/set_species(var/new_species_uid, var/new_bodytype = null)
+/mob/living/human/set_species(var/new_species_uid, var/new_bodytype = null, var/datum/mob_snapshot/snapshot_to_use = null)
if(!new_species_uid)
CRASH("set_species on mob '[src]' was passed a null species uid!")
var/decl/species/new_species = decls_repository.get_decl_by_id(new_species_uid)
@@ -518,7 +518,7 @@
//Handle bodytype
if(!new_bodytype)
new_bodytype = species.get_bodytype_by_pronouns(new_pronouns)
- set_bodytype(new_bodytype)
+ set_bodytype(new_bodytype, snapshot_to_use = snapshot_to_use)
available_maneuvers = species.maneuvers.Copy()
@@ -894,20 +894,10 @@
if(!defer_language_update)
update_languages()
-/mob/living/proc/get_background_datum_by_flag(background_flag)
- var/list/all_categories = global.using_map.get_background_categories()
- for(var/cat_type in all_categories)
- var/decl/background_category/background_cat = all_categories[cat_type]
- if(background_cat.background_flags && (background_cat.background_flags & background_flag))
- return get_background_datum(cat_type)
-
-/mob/living/proc/get_background_datum(cat_type)
- return null
-
/mob/living/human/get_background_datum(cat_type)
. = LAZYACCESS(background_info, cat_type)
if(!istype(., /decl/background_detail))
- . = global.using_map.default_background_info[cat_type]
+ . = ..()
PRINT_STACK_TRACE("get_background_datum() tried to return a non-instance value for background category '[cat_type]' - full background list: [json_encode(background_info)] default species culture list: [json_encode(global.using_map.default_background_info)]")
/mob/living/human/get_digestion_product()
@@ -984,7 +974,7 @@
else if(!species_uid)
species_uid = global.using_map.default_species //Humans cannot exist without a species!
- set_species(species_uid, supplied_appearance?.root_bodytype)
+ set_species(species_uid, supplied_appearance?.root_bodytype, snapshot_to_use = supplied_appearance)
var/decl/bodytype/root_bodytype = get_bodytype() // root bodytype is set in set_species
ASSERT((!supplied_appearance?.root_bodytype) || (root_bodytype == supplied_appearance.root_bodytype))
if(!get_skin_colour())
diff --git a/code/modules/mob/living/human/life.dm b/code/modules/mob/living/human/life.dm
index 21aa9577627e..b5588d76bde8 100644
--- a/code/modules/mob/living/human/life.dm
+++ b/code/modules/mob/living/human/life.dm
@@ -157,9 +157,9 @@
var/adjusted_pressure = calculate_affecting_pressure(pressure)
//Check for contaminants before anything else because we don't want to skip it.
- for(var/g in environment.gas)
- var/decl/material/mat = GET_DECL(g)
- if((mat.gas_flags & XGM_GAS_CONTAMINANT) && environment.gas[g] > mat.gas_overlay_limit + 1)
+ for(var/gas_type, gas_amount in environment.gas)
+ var/decl/material/mat = GET_DECL(gas_type)
+ if((mat.gas_flags & XGM_GAS_CONTAMINANT) && gas_amount > mat.gas_overlay_limit + 1)
handle_contaminants()
break
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 24bb4de3f4b9..55e94083cb93 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -2017,3 +2017,6 @@ default behaviour is:
/mob/living/proc/is_tagging_suitable()
return !key && !client
+//Pixel projectiles need a client, so we need a way to pass who the last user was for view calcs
+/mob/living/proc/get_effective_gunner()
+ return src
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index e72e3798f8cc..28beeb784990 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -103,7 +103,7 @@ var/global/list/ai_verbs_default = list(
src.verbs -= ai_verbs_default
src.verbs += /mob/living/verb/ghost
-/mob/living/silicon/ai/Initialize(mapload, var/datum/ai_laws/L, var/obj/item/organ/internal/brain_interface/B, var/safety = 0)
+/mob/living/silicon/ai/Initialize(mapload, var/datum/ai_laws/L, var/mob/living/brain/brainmob, var/safety = 0)
announcement = new()
announcement.title = "A.I. Announcement"
announcement.announcement_type = "A.I. Announcement"
@@ -143,7 +143,6 @@ var/global/list/ai_verbs_default = list(
add_language(/decl/language/sign, 0)
if(!safety)//Only used by AIize() to successfully spawn an AI.
- var/mob/living/brainmob = B?.get_brainmob()
if(!brainmob) // If there is no player/brain inside.
empty_playable_ai_cores += new/obj/structure/aicore/deactivated(loc)//New empty terminal.
. = INITIALIZE_HINT_QDEL
diff --git a/code/modules/mob/living/silicon/pai/software_modules.dm b/code/modules/mob/living/silicon/pai/software_modules.dm
index b113096f13be..53c6a4859bfe 100644
--- a/code/modules/mob/living/silicon/pai/software_modules.dm
+++ b/code/modules/mob/living/silicon/pai/software_modules.dm
@@ -234,11 +234,11 @@
var/t_moles = env.total_moles
var/gases[0]
- for(var/g in env.gas)
+ for(var/gas_type, gas_amount in env.gas)
var/gas[0]
- var/decl/material/mat = GET_DECL(g)
+ var/decl/material/mat = GET_DECL(gas_type)
gas["name"] = capitalize(mat.gas_name)
- gas["percent"] = round((env.gas[g] / t_moles) * 100)
+ gas["percent"] = round((gas_amount / t_moles) * 100)
gases[++gases.len] = gas
data["gas"] = gases
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 969dd3dac640..fa013a27914f 100644
--- a/code/modules/mob/living/silicon/robot/drone/drone_items.dm
+++ b/code/modules/mob/living/silicon/robot/drone/drone_items.dm
@@ -76,7 +76,6 @@
can_hold = list(
/obj/item/cell,
/obj/item/stock_parts,
- /obj/item/organ/internal/brain_interface,
/obj/item/robot_parts,
/obj/item/borg/upgrade,
/obj/item/flash,
diff --git a/code/modules/mob/living/simple_animal/_simple_animal.dm b/code/modules/mob/living/simple_animal/_simple_animal.dm
index 7b62adcc2ed0..7c30f1cfcc6d 100644
--- a/code/modules/mob/living/simple_animal/_simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/_simple_animal.dm
@@ -496,12 +496,11 @@ var/global/list/simplemob_icon_bitflag_cache = list()
if(!level_data.exterior_atmosphere)
return
- for(var/gas in level_data.exterior_atmosphere.gas)
- var/gas_amt = level_data.exterior_atmosphere.gas[gas]
+ for(var/gas_type, gas_amt in level_data.exterior_atmosphere.gas)
if(min_gas)
- min_gas[gas] = round(gas_amt * 0.5)
+ min_gas[gas_type] = round(gas_amt * 0.5)
if(max_gas)
- min_gas[gas] = round(gas_amt * 1.5)
+ min_gas[gas_type] = round(gas_amt * 1.5)
// Simple filler bodytype so animals get offsets for their inventory slots.
/decl/bodytype/animal
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 8d3083ecbf9d..612a4e888b47 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -695,10 +695,10 @@ var/global/const/ACTION_DANGER_ALL = 2
return ..()
/mob/proc/pull_damage()
- return 0
+ return FALSE
/mob/living/human/pull_damage()
- if(!current_posture.prone|| get_damage(BRUTE) + get_damage(BURN) < 100)
+ if(buckled || !current_posture.prone || get_damage(BRUTE) + get_damage(BURN) < 100)
return FALSE
for(var/obj/item/organ/external/e in get_external_organs())
if((e.status & ORGAN_BROKEN) && !e.splinted)
@@ -1603,3 +1603,13 @@ var/global/const/ACTION_DANGER_ALL = 2
// Returns true if the mob is cloaked, otherwise false
/mob/proc/is_cloaked()
return FALSE
+
+/mob/proc/get_background_datum_by_flag(background_flag)
+ var/list/all_categories = global.using_map.get_background_categories()
+ for(var/cat_type in all_categories)
+ var/decl/background_category/background_cat = all_categories[cat_type]
+ if(background_cat.background_flags && (background_cat.background_flags & background_flag))
+ return get_background_datum(cat_type)
+
+/mob/proc/get_background_datum(cat_type)
+ return global.using_map.default_background_info[cat_type]
diff --git a/code/modules/mob/mob_intent.dm b/code/modules/mob/mob_intent.dm
index f9271fb64fec..4eeeaaff9ff4 100644
--- a/code/modules/mob/mob_intent.dm
+++ b/code/modules/mob/mob_intent.dm
@@ -115,10 +115,16 @@
_a_intent = new_intent
if(istype(hud_used))
hud_used.refresh_element(HUD_INTENT)
+ if(ismob(loc))
+ var/mob/holder = loc
+ holder.carried_mob_intent_changed(src, _a_intent)
return TRUE
return FALSE
+/mob/proc/carried_mob_intent_changed(mob/user, decl/intent/new_intent)
+ return
+
/mob/proc/get_intent()
RETURN_TYPE(/decl/intent)
var/list/available_intents = get_available_intents()
diff --git a/code/modules/mob/mob_snapshot.dm b/code/modules/mob/mob_snapshot.dm
index c876a47857c6..271fade652b2 100644
--- a/code/modules/mob/mob_snapshot.dm
+++ b/code/modules/mob/mob_snapshot.dm
@@ -16,6 +16,8 @@
var/list/genetic_conditions
/// Please find a better way to do this. This is done to add tails if we have the tail accessory selected...
var/list/extra_limbs
+ /// A list of trait levels to add. Should contain only 'heritable' traits... whatever that means.
+ var/list/heritable_traits
/datum/mob_snapshot/New(mob/living/donor, genetic_info_only = FALSE)
@@ -74,6 +76,10 @@
else if(istype(root_bodytype) && target.get_bodytype() != root_bodytype)
target.set_bodytype(root_bodytype)
+ // we try to set traits as soon as possible after species set
+ for(var/target_trait in heritable_traits)
+ target.set_trait(target_trait, heritable_traits[target_trait])
+
target.set_fingerprint(fingerprint)
target.set_unique_enzymes(unique_enzymes)
target.set_skin_colour(skin_color)
diff --git a/code/modules/mob/new_player/preferences_setup.dm b/code/modules/mob/new_player/preferences_setup.dm
index 5a8b7f89ecbe..b1104cadc6cf 100644
--- a/code/modules/mob/new_player/preferences_setup.dm
+++ b/code/modules/mob/new_player/preferences_setup.dm
@@ -109,11 +109,12 @@
mannequin.update_icon()
mannequin.compile_overlays()
-/datum/preferences/proc/update_preview_icon()
+/datum/preferences/proc/update_preview_icon(redress_mob = TRUE)
var/mob/living/human/dummy/mannequin/mannequin = get_mannequin(client?.ckey)
if(mannequin)
- mannequin.delete_inventory(TRUE)
- dress_preview_mob(mannequin)
+ if(redress_mob)
+ mannequin.delete_inventory(TRUE)
+ dress_preview_mob(mannequin)
update_character_previews(mannequin)
/datum/preferences/proc/get_random_name()
diff --git a/code/modules/mob/observer/eye/blueprints_eye.dm b/code/modules/mob/observer/eye/blueprints_eye.dm
index c7bae7b5f9c7..6309e82b166d 100644
--- a/code/modules/mob/observer/eye/blueprints_eye.dm
+++ b/code/modules/mob/observer/eye/blueprints_eye.dm
@@ -66,7 +66,7 @@
var/area/A = new
A.SetName(area_name)
for(var/turf/T in selected_turfs)
- ChangeArea(T, A)
+ T.ChangeArea(A)
finalize_area(A)
remove_selection() // Reset the selection for clarity.
@@ -90,7 +90,7 @@
var/datum/level_data/our_level_data = SSmapping.levels_by_z[our_turf.z]
var/area/base_area = our_level_data.get_base_area_instance()
for(var/turf/T in A.contents)
- ChangeArea(T, base_area)
+ T.ChangeArea(base_area)
if(!(locate(/turf) in A))
qdel(A) // uh oh, is this safe?
@@ -316,7 +316,7 @@
var/datum/level_data/our_level_data = SSmapping.levels_by_z[our_turf.z]
var/area/base_area = our_level_data.get_base_area_instance()
for(var/turf/T in A.contents)
- ChangeArea(T, base_area)
+ T.ChangeArea(base_area)
if(!(locate(/turf) in A))
qdel(A) // uh oh, is this safe?
diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm
index bebc25e3b4b5..d358e28ba7d4 100644
--- a/code/modules/mob/transform_procs.dm
+++ b/code/modules/mob/transform_procs.dm
@@ -51,8 +51,8 @@
/mob/living/AIize(move = TRUE)
if (HAS_TRANSFORMATION_MOVEMENT_HANDLER(src))
return
- for(var/t in get_external_organs())
- qdel(t)
+ delete_organs()
+ drop_equipped_items()
for(var/obj/item/thing in src)
drop_from_inventory(thing)
ADD_TRANSFORMATION_MOVEMENT_HANDLER(src)
@@ -65,7 +65,7 @@
sound_to(src, sound(null, repeat = 0, wait = 0, volume = 85, channel = sound_channels.lobby_channel))// stop the jams for AIs
- var/mob/living/silicon/ai/O = new (loc, global.using_map.default_law_type,,1)//No brain but safety is in effect.
+ var/mob/living/silicon/ai/O = new (loc, global.using_map.default_law_type,null,1)//No brain but safety is in effect.
O.set_invisibility(INVISIBILITY_NONE)
O.aiRestorePowerRoutine = 0
if(mind)
@@ -101,28 +101,23 @@
qdel(src)
return O
-//human -> robot
-/mob/living/human/proc/Robotize(var/supplied_robot_type = /mob/living/silicon/robot)
+//living mob -> robot
+/mob/living/proc/Robotize(var/supplied_robot_type = ASSIGNMENT_ROBOT, skip_qdel = FALSE)
if (HAS_TRANSFORMATION_MOVEMENT_HANDLER(src))
return
- QDEL_NULL_LIST(worn_underwear)
- for(var/obj/item/thing in src)
- drop_from_inventory(thing)
- try_refresh_visible_overlays()
ADD_TRANSFORMATION_MOVEMENT_HANDLER(src)
- icon = null
- set_invisibility(INVISIBILITY_ABSTRACT)
- for(var/t in get_external_organs())
- qdel(t)
-
- var/mob/living/silicon/robot/O = new supplied_robot_type( loc )
+ drop_equipped_items()
+ var/robot_type_path = SSrobots.get_mob_type_by_title(supplied_robot_type)
+ var/mob/living/silicon/robot/O = new robot_type_path(loc)
- O.set_gender(gender)
+ O.set_gender(get_gender())
O.set_invisibility(INVISIBILITY_NONE)
if(!mind)
mind_initialize()
mind.assigned_role = ASSIGNMENT_ROBOT
+ if(supplied_robot_type != ASSIGNMENT_ROBOT)
+ mind.role_alt_title = supplied_robot_type
mind.active = TRUE
mind.transfer_to(O)
if(O.mind && O.mind.assigned_role == ASSIGNMENT_ROBOT)
@@ -135,7 +130,8 @@
RAISE_EVENT(/decl/observ/cyborg_created, O)
O.Namepick()
- qdel(src)
+ if(!skip_qdel)
+ qdel(src)
return O
/mob/living/human/proc/corgize()
diff --git a/code/modules/mob_modifiers/definitions/modifiers_prone.dm b/code/modules/mob_modifiers/definitions/modifiers_prone.dm
index caf5b30c53b6..14d04ecac121 100644
--- a/code/modules/mob_modifiers/definitions/modifiers_prone.dm
+++ b/code/modules/mob_modifiers/definitions/modifiers_prone.dm
@@ -1,10 +1,10 @@
-/decl/mob_modifier/prone
- name = "Prone"
- desc = "You are lying prone and may need to stand up before taking action."
+/decl/mob_modifier/lying
+ name = "Lying"
+ desc = "You are lying down and may need to stand up before taking action."
hud_icon_state = "prone"
show_indefinite_duration = FALSE
-/decl/mob_modifier/prone/on_modifier_datum_click(mob/living/_owner, decl/mob_modifier/modifier, params)
+/decl/mob_modifier/lying/on_modifier_datum_click(mob/living/_owner, decl/mob_modifier/modifier, params)
if(_owner.current_posture?.prone)
_owner.lay_down()
return TRUE
diff --git a/code/modules/multiz/level_data.dm b/code/modules/multiz/level_data.dm
index 73f2054e5696..c88b80a285ea 100644
--- a/code/modules/multiz/level_data.dm
+++ b/code/modules/multiz/level_data.dm
@@ -232,7 +232,7 @@
if(change_turf)
T = T.ChangeTurf(picked_turf)
if(change_area)
- ChangeArea(T, A)
+ T.ChangeArea(A)
///Prepare level for being used. Setup borders, lateral z connections, ambient lighting, atmosphere, etc..
/datum/level_data/proc/setup_level_data(var/skip_gen = FALSE)
@@ -410,11 +410,11 @@
exterior_atmosphere.update_values() //Might as well update
exterior_atmosphere.check_tile_graphic()
return
- var/list/exterior_atmos_composition = exterior_atmosphere
+ var/alist/exterior_atmos_composition = exterior_atmosphere
exterior_atmosphere = new
- if(islist(exterior_atmos_composition))
- for(var/gas in exterior_atmos_composition)
- exterior_atmosphere.adjust_gas(gas, exterior_atmos_composition[gas], FALSE)
+ if(istype(exterior_atmos_composition, /alist))
+ for(var/gas, gas_amount in exterior_atmos_composition)
+ exterior_atmosphere.adjust_gas(gas, gas_amount, FALSE)
exterior_atmosphere.temperature = exterior_atmos_temp
exterior_atmosphere.update_values()
exterior_atmosphere.check_tile_graphic()
diff --git a/code/modules/organs/internal/lungs.dm b/code/modules/organs/internal/lungs.dm
index aeea20125422..934534fc6323 100644
--- a/code/modules/organs/internal/lungs.dm
+++ b/code/modules/organs/internal/lungs.dm
@@ -210,9 +210,9 @@
if(!failed_inhale) // Enough gas to tell we're being poisoned via chemical burns or whatever.
var/poison_total = 0
if(poison_types)
- for(var/gname in breath.gas)
- if(poison_types[gname])
- poison_total += breath.gas[gname]
+ for(var/gas_type, gas_amount in breath.gas)
+ if(poison_types[gas_type])
+ poison_total += gas_amount
if(((poison_total/breath.total_moles)*breath_pressure) > safe_toxins_max)
SET_HUD_ALERT(owner, HUD_TOX, 1)
diff --git a/code/modules/overmap/_overmap.dm b/code/modules/overmap/_overmap.dm
index 96d9180a2402..690abc887fc5 100644
--- a/code/modules/overmap/_overmap.dm
+++ b/code/modules/overmap/_overmap.dm
@@ -43,7 +43,7 @@
square = square.ChangeTurf(overmap_edge_type)
else
square = square.ChangeTurf(overmap_turf_type)
- ChangeArea(square, A)
+ square.ChangeArea(A)
/datum/overmap/proc/generate_overmap()
testing("Building overmap [name]...")
diff --git a/code/modules/overmap/planetoids/_planetoids.dm b/code/modules/overmap/planetoids/_planetoids.dm
index 16ea48dfe92b..f28b871ef26b 100644
--- a/code/modules/overmap/planetoids/_planetoids.dm
+++ b/code/modules/overmap/planetoids/_planetoids.dm
@@ -56,9 +56,9 @@
if(atmosphere)
if(user.skill_check(SKILL_SCIENCE, SKILL_EXPERT) || user.skill_check(SKILL_ATMOS, SKILL_EXPERT))
var/list/gases = list()
- for(var/g in atmosphere.gas)
- if(atmosphere.gas[g] > atmosphere.total_moles * 0.05)
- var/decl/material/mat = GET_DECL(g)
+ for(var/gas_type, gas_amount in atmosphere.gas)
+ if(gas_amount > atmosphere.total_moles * 0.05)
+ var/decl/material/mat = GET_DECL(gas_type)
gases += mat.gas_name
. += "Atmosphere composition: [english_list(gases)]
"
var/inaccuracy = rand(8,12)/10
diff --git a/code/modules/overmap/planetoids/planetoid_skybox.dm b/code/modules/overmap/planetoids/planetoid_skybox.dm
index d9528a9bfc38..f0b30e4bc25b 100644
--- a/code/modules/overmap/planetoids/planetoid_skybox.dm
+++ b/code/modules/overmap/planetoids/planetoid_skybox.dm
@@ -27,10 +27,8 @@
var/list/colors = list()
for(var/lvl in map_z)
var/datum/level_data/level_data = SSmapping.levels_by_z[lvl]
- ///#TODO: Check if the z-level is visible from space
- for(var/g in level_data.exterior_atmosphere?.gas)
- var/decl/material/mat = GET_DECL(g)
- colors += mat.color
+ if(level_data.exterior_atmosphere)
+ colors += level_data.exterior_atmosphere.get_overall_color()
if(length(colors))
return MixColors(colors)
diff --git a/code/modules/overmap/ships/device_types/gas_thruster.dm b/code/modules/overmap/ships/device_types/gas_thruster.dm
index 1f09c65b3187..1c9c32381827 100644
--- a/code/modules/overmap/ships/device_types/gas_thruster.dm
+++ b/code/modules/overmap/ships/device_types/gas_thruster.dm
@@ -74,12 +74,12 @@
if(!propellant || !length(propellant.gas) || !propellant.total_moles)
return 0.01 // Divide by zero protection.
- for(var/mat in propellant.gas)
+ for(var/mat, amt in propellant.gas)
var/decl/material/gas/G = GET_DECL(mat)
// 0.08 chosen to get the RATIO of the specific heat, we don't have cV/cP here, so this is a rough approximate.
var/ratio = (G.gas_specific_heat / 25) + 0.8// These numbers are meaningless, just magic numbers to calibrate range.
- ratio_specific_heat += ratio * (propellant.gas[mat] / propellant.total_moles)
- ratio_specific_heat = ratio_specific_heat / length(propellant.gas)
+ ratio_specific_heat += ratio * (amt / propellant.total_moles)
+ ratio_specific_heat /= length(propellant.gas)
if(ratio_specific_heat == 0 || ratio_specific_heat == 1)
// rare case of avoiding a divide by zero error.
ratio_specific_heat += 0.01
diff --git a/code/modules/power/singularity/collector.dm b/code/modules/power/singularity/collector.dm
index cd70fdbc44a5..b271e18090ea 100644
--- a/code/modules/power/singularity/collector.dm
+++ b/code/modules/power/singularity/collector.dm
@@ -64,7 +64,7 @@ var/global/list/rad_collectors = list()
receive_pulse(12.5*(last_rads/max_rads)/(0.3+(last_rads/max_rads)))
if(loaded_tank)
- if(loaded_tank.air_contents.gas[/decl/material/gas/hydrogen] == 0)
+ if(!loaded_tank.air_contents.get_gas(/decl/material/gas/hydrogen))
investigate_log("out of fuel.","singulo")
eject()
else
@@ -85,7 +85,8 @@ var/global/list/rad_collectors = list()
toggle_power()
user.visible_message("[user.name] turns \the [src] [active? "on":"off"].", \
"You turn \the [src] [active? "on":"off"].")
- investigate_log("turned [active?"on":"off"] by [user.key]. [loaded_tank?"Fuel: [round(loaded_tank.air_contents.gas[/decl/material/gas/hydrogen]/0.29)]%":"It is empty"].","singulo")
+ // WHY DOES THIS DIVIDE BY 0.29
+ investigate_log("turned [active?"on":"off"] by [user.key]. [loaded_tank?"Fuel: [round(loaded_tank.air_contents.get_gas(/decl/material/gas/hydrogen)/0.29)]%":"It is empty"].","singulo")
else
to_chat(user, SPAN_WARNING("The controls are locked!"))
@@ -177,7 +178,7 @@ var/global/list/rad_collectors = list()
/obj/machinery/rad_collector/proc/receive_pulse(var/pulse_strength)
if(loaded_tank && active)
var/power_produced = 0
- power_produced = min(100*loaded_tank.air_contents.gas[/decl/material/gas/hydrogen]*pulse_strength*pulse_coeff,max_power)
+ power_produced = min(100*loaded_tank.air_contents.get_gas(/decl/material/gas/hydrogen)*pulse_strength*pulse_coeff,max_power)
generate_power(power_produced)
last_power_new = power_produced
return
diff --git a/code/modules/projectiles/projectile/change.dm b/code/modules/projectiles/projectile/change.dm
index 7e498de80efc..7628644b405a 100644
--- a/code/modules/projectiles/projectile/change.dm
+++ b/code/modules/projectiles/projectile/change.dm
@@ -9,59 +9,57 @@
/obj/item/projectile/change/on_hit(var/atom/change)
wabbajack(change)
-/obj/item/projectile/change/proc/get_random_transformation_options(var/mob/M)
+/obj/item/projectile/change/proc/get_random_transformation_options(var/mob/living/victim)
. = list()
- if(!isrobot(M))
+ if(!isrobot(victim))
. += "robot"
for(var/decl/species/species as anything in decls_repository.get_decls_of_subtype_unassociated(/decl/species))
. += species.uid
- if(ishuman(M))
- var/mob/living/human/H = M
- . -= H.species.uid
+ if(ishuman(victim))
+ var/mob/living/human/human_victim = victim
+ . -= human_victim.species.uid
-/obj/item/projectile/change/proc/apply_transformation(var/mob/M, var/choice)
+/obj/item/projectile/change/proc/make_robot(var/mob/living/victim, robot_title = ASSIGNMENT_ROBOT)
+ return victim.Robotize(robot_title, skip_qdel = TRUE)
+
+/obj/item/projectile/change/proc/apply_transformation(var/mob/living/victim, var/choice)
if(choice == "robot")
- var/mob/living/silicon/robot/robot = new(get_turf(M))
- robot.set_gender(M.get_gender())
- robot.job = ASSIGNMENT_ROBOT
- robot.central_processor = new /obj/item/organ/internal/brain_interface(robot)
- transfer_key_from_mob_to_mob(M, robot)
- return robot
+ return make_robot()
if(decls_repository.get_decl_by_id(choice))
- var/mob/living/human/H = M
- if(!istype(H))
- H = new(get_turf(M))
- H.set_gender(M.get_gender())
- H.name = "unknown" // This will cause set_species() to randomize the mob name.
- H.real_name = H.name
- H.change_species(choice)
- H.universal_speak = TRUE
+ var/mob/living/human/human_victim = victim
+ if(!istype(human_victim))
+ human_victim = new(get_turf(victim))
+ human_victim.set_gender(victim.get_gender())
+ human_victim.name = "unknown" // This will cause set_species() to randomize the mob name.
+ human_victim.real_name = human_victim.name
+ human_victim.change_species(choice)
+ human_victim.universal_speak = TRUE
var/datum/preferences/A = new()
- A.randomize_appearance_and_body_for(H)
- return H
+ A.randomize_appearance_and_body_for(human_victim)
+ return human_victim
-/obj/item/projectile/change/proc/wabbajack(var/mob/M)
+/obj/item/projectile/change/proc/wabbajack(var/mob/living/victim)
- if(!isliving(M) || M.stat == DEAD)
+ if(!isliving(victim) || victim.stat == DEAD)
return
- if(HAS_TRANSFORMATION_MOVEMENT_HANDLER(M))
+ if(HAS_TRANSFORMATION_MOVEMENT_HANDLER(victim))
return
- M.handle_pre_transformation()
- var/choice = pick(get_random_transformation_options(M))
- var/mob/living/new_mob = apply_transformation(M, choice)
+ victim.handle_pre_transformation()
+ var/choice = pick(get_random_transformation_options(victim))
+ var/mob/living/new_mob = apply_transformation(victim, choice)
if(new_mob)
new_mob.set_intent(I_FLAG_HARM)
- new_mob.copy_abilities_from(M)
- transfer_key_from_mob_to_mob(M, new_mob)
+ new_mob.copy_abilities_from(victim)
+ transfer_key_from_mob_to_mob(victim, new_mob)
to_chat(new_mob, "Your form morphs into that of \a [choice].")
else
- new_mob = M
+ new_mob = victim
if(new_mob)
to_chat(new_mob, SPAN_WARNING("Your form morphs into that of \a [choice]."))
- if(new_mob != M && !QDELETED(M))
- qdel(M)
+ if(new_mob != victim && !QDELETED(victim))
+ qdel(victim)
diff --git a/code/modules/random_map/random_map.dm b/code/modules/random_map/random_map.dm
index 10c390dfcd47..c4bce943eefb 100644
--- a/code/modules/random_map/random_map.dm
+++ b/code/modules/random_map/random_map.dm
@@ -175,7 +175,8 @@ var/global/list/map_count = list()
. = (newpath && !istype(T, newpath)) ? T.ChangeTurf(newpath) : T
get_additional_spawns(map[current_cell], ., get_spawn_dir(x, y))
if(use_area)
- ChangeArea(., use_area)
+ T = .
+ T.ChangeArea(use_area)
/datum/random_map/proc/get_spawn_dir()
return 0
diff --git a/code/modules/scanners/gas.dm b/code/modules/scanners/gas.dm
index 397ea46d74bf..3637da7d02e4 100644
--- a/code/modules/scanners/gas.dm
+++ b/code/modules/scanners/gas.dm
@@ -57,14 +57,14 @@
. += "Pressure: [round(pressure,0.01)] kPa"
var/perGas_add_string = ""
- for(var/mix in mixture.gas)
- var/percentage = round(mixture.gas[mix]/total_moles * 100, 0.01)
+ for(var/gas_type, gas_moles in mixture.gas)
+ var/percentage = round(gas_moles/total_moles * 100, 0.01)
if(!percentage)
continue
- var/decl/material/mat = GET_DECL(mix)
+ var/decl/material/mat = GET_DECL(gas_type)
switch(mode)
if(MV_MODE)
- perGas_add_string = ", Moles: [round(mixture.gas[mix], 0.01)]"
+ perGas_add_string = ", Moles: [round(gas_moles, 0.01)]"
if(MAT_TRAIT_MODE)
var/list/traits = list()
if(mat.gas_flags & XGM_GAS_FUEL)
diff --git a/code/modules/turbolift/turbolift_map.dm b/code/modules/turbolift/turbolift_map.dm
index bbea91dd8cc4..d69a39fd5bb8 100644
--- a/code/modules/turbolift/turbolift_map.dm
+++ b/code/modules/turbolift/turbolift_map.dm
@@ -186,8 +186,8 @@ INITIALIZE_IMMEDIATE(/obj/abstract/turbolift_spawner)
var/area_path = areas_to_use[az]
var/area/A = locate(area_path) || new area_path()
- for(var/T in floor_turfs)
- ChangeArea(T, A)
+ for(var/turf/T as anything in floor_turfs)
+ T.ChangeArea(A)
cfloor.set_area_ref("\ref[A]")
// Place exterior doors.
diff --git a/code/modules/xgm/xgm_gas_mixture.dm b/code/modules/xgm/xgm_gas_mixture.dm
index d88010d37564..59b19c52794e 100644
--- a/code/modules/xgm/xgm_gas_mixture.dm
+++ b/code/modules/xgm/xgm_gas_mixture.dm
@@ -1,7 +1,16 @@
+// These variables are used to speed up certain calculations by using dot products.
+var/global/alist/cached_specific_heat = alist()
+var/global/alist/cached_molar_mass = alist()
+var/global/alist/cached_mat_r = alist()
+var/global/alist/cached_mat_g = alist()
+var/global/alist/cached_mat_b = alist()
+var/global/alist/cached_mat_a = alist()
+var/global/alist/cached_mat_color_weight = alist()
+
/datum/gas_mixture
//Associative list of gas moles.
//Gases with 0 moles are not tracked and are pruned by update_values()
- var/list/gas = list()
+ var/alist/gas = alist()
//Temperature in Kelvin of this gas mix.
var/temperature = 0
@@ -86,11 +95,12 @@
temperature = (giver.temperature*giver_heat_capacity + temperature*self_heat_capacity)/combined_heat_capacity
if((group_multiplier != 1)||(giver.group_multiplier != 1))
- for(var/g in giver.gas)
- gas[g] += giver.gas[g] * giver.group_multiplier / group_multiplier
+ var/scale_factor = giver.group_multiplier / group_multiplier
+ for(var/gas_type, gas_amount in giver.gas)
+ gas[gas_type] += gas_amount * scale_factor
else
- for(var/g in giver.gas)
- gas[g] += giver.gas[g]
+ for(var/gas_type, gas_amount in giver.gas)
+ gas[gas_type] += gas_amount
update_values()
return TRUE
@@ -105,11 +115,13 @@
gas.Cut()
sharer.gas.Cut()
- for(var/g in gas|sharer.gas)
- var/comb = gas[g] + sharer.gas[g]
- comb /= total_volume + sharer.total_volume
- gas[g] = comb * total_volume
- sharer.gas[g] = comb * sharer.total_volume
+ var/scale_factor = total_volume + sharer.total_volume
+ var/origin_scale_factor = total_volume / scale_factor
+ var/sharer_scale_factor = sharer.total_volume / scale_factor
+ for(var/gas_type in gas|sharer.gas) // we can only iterate keys here since merging alists doesn't combine values
+ var/comb = gas[gas_type] + sharer.gas[gas_type]
+ gas[gas_type] = comb * origin_scale_factor
+ sharer.gas[gas_type] = comb * sharer_scale_factor
if(our_heatcap + share_heatcap)
temperature = ((temperature * our_heatcap) + (sharer.temperature * share_heatcap)) / (our_heatcap + share_heatcap)
@@ -123,12 +135,7 @@
//Returns the heat capacity of the gas mix based on the specific heat of the gases.
/datum/gas_mixture/proc/heat_capacity()
- . = 0
- for(var/g in gas)
- var/decl/material/mat = GET_DECL(g)
- . += mat.gas_specific_heat * gas[g]
- . *= max(1, group_multiplier)
-
+ return values_dot(gas, global.cached_specific_heat) * max(1, group_multiplier)
//Adds or removes thermal energy. Returns the actual thermal energy change, as in the case of removing energy we can't go below TCMB.
/datum/gas_mixture/proc/add_thermal_energy(var/thermal_energy)
@@ -152,7 +159,6 @@
/datum/gas_mixture/proc/get_thermal_energy_change(var/new_temperature)
return heat_capacity()*(max(new_temperature, 0) - temperature)
-
//Technically vacuum doesn't have a specific entropy. Just use a really big number (infinity would be ideal) here so that it's easy to add gas to vacuum and hard to take gas out.
#define SPECIFIC_ENTROPY_VACUUM 150000
@@ -197,13 +203,8 @@
//Updates the total_moles count and trims any empty gases.
/datum/gas_mixture/proc/update_values()
- total_moles = 0
- for(var/g in gas)
- if(gas[g] <= 0)
- gas -= g
- else
- total_moles += gas[g]
-
+ values_cut_under(gas, ATMOS_PRECISION)
+ total_moles = values_sum(gas)
//Mark the cached color for update
cached_mix_color = null
@@ -222,9 +223,9 @@
var/datum/gas_mixture/removed = new
- for(var/g in gas)
- removed.gas[g] = QUANTIZE((gas[g] / total_moles) * amount)
- gas[g] -= removed.gas[g] / group_multiplier
+ for(var/gas_type, gas_amount in gas)
+ removed.gas[gas_type] = QUANTIZE((gas_amount / total_moles) * amount)
+ gas[gas_type] -= removed.gas[gas_type] / group_multiplier
removed.temperature = temperature
update_values()
@@ -244,9 +245,9 @@
var/datum/gas_mixture/removed = new
removed.group_multiplier = out_group_multiplier
- for(var/g in gas)
- removed.gas[g] = (gas[g] * ratio * group_multiplier / out_group_multiplier)
- gas[g] = gas[g] * (1 - ratio)
+ for(var/gas_type, gas_amount in gas)
+ removed.gas[gas_type] = (gas_amount * ratio * group_multiplier / out_group_multiplier)
+ gas[gas_type] = gas_amount * (1 - ratio)
removed.temperature = temperature
removed.total_volume = total_volume * group_multiplier / out_group_multiplier
@@ -269,18 +270,18 @@
return removed
var/sum = 0
- for(var/g in gas)
- var/decl/material/mat = GET_DECL(g)
- var/list/check = mat_flag ? mat.flags : mat.gas_flags
+ for(var/gas_type, gas_amount in gas)
+ var/decl/material/mat = GET_DECL(gas_type)
+ var/check = mat_flag ? mat.flags : mat.gas_flags
if(check & flag)
- sum += gas[g]
+ sum += gas_amount
- for(var/g in gas)
- var/decl/material/mat = GET_DECL(g)
- var/list/check = mat_flag ? mat.flags : mat.gas_flags
+ for(var/gas_type, gas_amount in gas)
+ var/decl/material/mat = GET_DECL(gas_type)
+ var/check = mat_flag ? mat.flags : mat.gas_flags
if(check & flag)
- removed.gas[g] = QUANTIZE((gas[g] / sum) * amount)
- gas[g] -= removed.gas[g] / group_multiplier
+ removed.gas[gas_type] = QUANTIZE((gas_amount / sum) * amount)
+ gas[gas_type] -= removed.gas[gas_type] / group_multiplier
removed.temperature = temperature
update_values()
@@ -291,10 +292,10 @@
//Returns the amount of gas that has the given flag, in moles
/datum/gas_mixture/proc/get_by_flag(flag)
. = 0
- for(var/g in gas)
- var/decl/material/mat = GET_DECL(g)
+ for(var/gas_type, gas_amount in gas)
+ var/decl/material/mat = GET_DECL(gas_type)
if(mat.gas_flags & flag)
- . += gas[g]
+ . += gas_amount
//Copies gas and temperature from another gas_mixture.
/datum/gas_mixture/proc/copy_from(const/datum/gas_mixture/sample)
@@ -324,22 +325,22 @@
if(total_moles == 0 && sample.total_moles != 0 || sample.total_moles == 0 && total_moles != 0)
return 0
- var/list/marked = list()
- for(var/g in gas)
- if((abs(gas[g] - sample.gas[g]) > MINIMUM_AIR_TO_SUSPEND) && \
- ((gas[g] < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.gas[g]) || \
- (gas[g] > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.gas[g])))
+ var/alist/marked = alist()
+ for(var/gas_type, gas_amount in gas)
+ if((abs(gas_amount - sample.gas[gas_type]) > MINIMUM_AIR_TO_SUSPEND) && \
+ ((gas_amount < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.gas[gas_type]) || \
+ (gas_amount > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.gas[gas_type])))
return 0
- marked[g] = 1
+ marked[gas_type] = 1
if(abs(return_pressure() - sample.return_pressure()) > MINIMUM_PRESSURE_DIFFERENCE_TO_SUSPEND)
return 0
- for(var/g in sample.gas)
- if(!marked[g])
- if((abs(gas[g] - sample.gas[g]) > MINIMUM_AIR_TO_SUSPEND) && \
- ((gas[g] < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.gas[g]) || \
- (gas[g] > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.gas[g])))
+ for(var/sample_type, sample_moles in sample.gas)
+ if(!marked[sample_type])
+ if((abs(gas[sample_type] - sample_moles) > MINIMUM_AIR_TO_SUSPEND) && \
+ ((gas[sample_type] < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample_moles) || \
+ (gas[sample_type] > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample_moles)))
return 0
if(total_moles > MINIMUM_AIR_TO_SUSPEND)
@@ -358,13 +359,13 @@
for(var/obj/effect/gas_overlay/O in graphic)
if(gas[O.material.type] <= O.material.gas_overlay_limit)
LAZYADD(graphic_remove, O)
- for(var/g in gas)
+ for(var/gas_type, gas_amount in gas)
+ var/decl/material/mat = GET_DECL(gas_type)
//Overlay isn't applied for this gas, check if it's valid and needs to be added.
- var/decl/material/mat = GET_DECL(g)
- if(!isnull(mat.gas_overlay_limit) && gas[g] > mat.gas_overlay_limit)
- if(!LAZYACCESS(tile_overlay_cache, g))
- LAZYSET(tile_overlay_cache, g, new /obj/effect/gas_overlay(null, g))
- var/tile_overlay = tile_overlay_cache[g]
+ if(!isnull(mat.gas_overlay_limit) && gas_amount > mat.gas_overlay_limit)
+ if(!LAZYACCESS(tile_overlay_cache, gas_type))
+ LAZYSET(tile_overlay_cache, gas_type, new /obj/effect/gas_overlay(null, gas_type))
+ var/tile_overlay = tile_overlay_cache[gas_type]
if(!(tile_overlay in graphic))
LAZYADD(graphic_add, tile_overlay)
. = FALSE
@@ -413,16 +414,16 @@
var/full_heat_capacity = heat_capacity()
var/s_full_heat_capacity = other.heat_capacity()
- var/list/avg_gas = list()
+ var/alist/avg_gas = alist()
+ var/scale_factor = (size + share_size)
+ var/self_scale_factor = size / scale_factor
+ var/other_scale_factor = share_size / scale_factor
- for(var/g in gas)
- avg_gas[g] += gas[g] * size
+ for(var/gas_type, gas_moles in gas)
+ avg_gas[gas_type] += gas_moles * self_scale_factor
- for(var/g in other.gas)
- avg_gas[g] += other.gas[g] * share_size
-
- for(var/g in avg_gas)
- avg_gas[g] /= (size + share_size)
+ for(var/gas_type, gas_moles in other.gas)
+ avg_gas[gas_type] += gas_moles * other_scale_factor
var/temp_avg = 0
if(full_heat_capacity + s_full_heat_capacity)
@@ -433,10 +434,10 @@
ratio = sharing_lookup_table[connecting_tiles]
//WOOT WOOT DO NOT TOUCH THIS.
- for(var/g in avg_gas)
- gas[g] = max(0, (gas[g] - avg_gas[g]) * (1 - ratio) + avg_gas[g])
+ for(var/gas_type, gas_amount in avg_gas)
+ gas[gas_type] = max(0, (gas[gas_type] - gas_amount) * (1 - ratio) + gas_amount)
if(!one_way)
- other.gas[g] = max(0, (other.gas[g] - avg_gas[g]) * (1 - ratio) + avg_gas[g])
+ other.gas[gas_type] = max(0, (other.gas[gas_type] - gas_amount) * (1 - ratio) + gas_amount)
temperature = max(0, (temperature - temp_avg) * (1-ratio) + temp_avg)
if(!one_way)
@@ -459,14 +460,14 @@
var/total_thermal_energy = 0
var/total_heat_capacity = 0
- var/list/total_gas = list()
+ var/alist/total_gas = alist()
for(var/datum/gas_mixture/gasmix in gases)
total_volume += gasmix.total_volume
var/temp_heatcap = gasmix.heat_capacity()
total_thermal_energy += gasmix.temperature * temp_heatcap
total_heat_capacity += temp_heatcap
- for(var/g in gasmix.gas)
- total_gas[g] += gasmix.gas[g]
+ for(var/gas_type, gas_amount in gasmix.gas)
+ total_gas[gas_type] += gas_amount
if(total_volume > 0)
var/datum/gas_mixture/combined = new(total_volume)
@@ -481,8 +482,7 @@
combined.react()
//Average out the gases
- for(var/g in combined.gas)
- combined.gas[g] /= total_volume
+ combined.divide(total_volume)
//Update individual gas_mixtures
for(var/datum/gas_mixture/gasmix in gases)
@@ -493,10 +493,7 @@
return 1
/datum/gas_mixture/proc/get_mass()
- . = 0
- for(var/g in gas)
- var/decl/material/mat = GET_DECL(g)
- . += gas[g] * mat.molar_mass * group_multiplier
+ return values_dot(gas, global.cached_molar_mass) * group_multiplier
/datum/gas_mixture/proc/specific_mass()
var/M = get_total_moles()
@@ -507,30 +504,23 @@
///Returns a color blended from all materials the gas mixture contains
/datum/gas_mixture/proc/get_overall_color()
if(!cached_mix_color)
- if(!LAZYLEN(gas))
+ if(!length(gas))
cached_mix_color = "#ffffffff"
return cached_mix_color
- if(LAZYLEN(gas) == 1)
- var/decl/material/G = GET_DECL(gas[1])
- cached_mix_color = G.color + num2hex(G.opacity * 255)
+ if(length(gas) == 1)
+ for(var/gas_type in gas)
+ var/decl/material/G = GET_DECL(gas_type)
+ cached_mix_color = G.color + num2hex(G.opacity * 255)
return cached_mix_color
//If we really have to, add up all colors
- var/list/colors = list(0, 0, 0, 0)
- var/total_color_weight = 0
-
- for(var/mat_path in gas)
+ cached_mix_color = rgb(255,255,255,255)
+ for(var/mat_path, mat_moles in gas)
var/decl/material/G = GET_DECL(mat_path)
if(G.color_weight <= 0)
continue
var/hex = uppertext(G.color) + num2hex(G.opacity * 255)
- var/mod = gas[mat_path] * G.color_weight
- colors[1] += HEX_RED(hex) * mod
- colors[2] += HEX_GREEN(hex) * mod
- colors[3] += HEX_BLUE(hex) * mod
- colors[4] += HEX_ALPHA(hex) * mod
- total_color_weight += mod
- cached_mix_color = rgb(colors[1] / total_color_weight, colors[2] / total_color_weight, colors[3] / total_color_weight, colors[4] / total_color_weight)
+ cached_mix_color = BlendHSV(cached_mix_color, hex, (mat_moles * G.color_weight) / total_moles)
return cached_mix_color
diff --git a/code/unit_tests/atmospherics_tests.dm b/code/unit_tests/atmospherics_tests.dm
index e28fcc06a378..ea7ed3b20eb3 100644
--- a/code/unit_tests/atmospherics_tests.dm
+++ b/code/unit_tests/atmospherics_tests.dm
@@ -62,7 +62,7 @@
test_cases = list(
uphill = list(
source = list(
- initial_gas = list(
+ initial_gas = alist(
/decl/material/gas/oxygen = 5,
/decl/material/gas/nitrogen = 10,
/decl/material/gas/carbon_dioxide = 5,
@@ -72,7 +72,7 @@
temperature = T20C - 5,
),
sink = list(
- initial_gas = list(
+ initial_gas = alist(
/decl/material/gas/oxygen = 10,
/decl/material/gas/nitrogen = 20,
/decl/material/gas/carbon_dioxide = 10,
@@ -84,7 +84,7 @@
),
downhill = list(
source = list(
- initial_gas = list(
+ initial_gas = alist(
/decl/material/gas/oxygen = 10,
/decl/material/gas/nitrogen = 20,
/decl/material/gas/carbon_dioxide = 10,
@@ -94,7 +94,7 @@
temperature = T20C + 5,
),
sink = list(
- initial_gas = list(
+ initial_gas = alist(
/decl/material/gas/oxygen = 5,
/decl/material/gas/nitrogen = 10,
/decl/material/gas/carbon_dioxide = 5,
@@ -106,7 +106,7 @@
),
flat = list(
source = list(
- initial_gas = list(
+ initial_gas = alist(
/decl/material/gas/oxygen = 10,
/decl/material/gas/nitrogen = 20,
/decl/material/gas/carbon_dioxide = 10,
@@ -116,7 +116,7 @@
temperature = T20C,
),
sink = list(
- initial_gas = list(
+ initial_gas = alist(
/decl/material/gas/oxygen = 10,
/decl/material/gas/nitrogen = 20,
/decl/material/gas/carbon_dioxide = 10,
@@ -128,7 +128,7 @@
),
vacuum_sink = list(
source = list(
- initial_gas = list(
+ initial_gas = alist(
/decl/material/gas/oxygen = 10,
/decl/material/gas/nitrogen = 20,
/decl/material/gas/carbon_dioxide = 10,
@@ -138,17 +138,17 @@
temperature = T20C,
),
sink = list(
- initial_gas = list(),
+ initial_gas = alist(),
temperature = 0,
),
),
vacuum_source = list(
source = list(
- initial_gas = list(),
+ initial_gas = alist(),
temperature = 0,
),
sink = list(
- initial_gas = list(
+ initial_gas = alist(
/decl/material/gas/oxygen = 10,
/decl/material/gas/nitrogen = 20,
/decl/material/gas/carbon_dioxide = 10,
diff --git a/maps/away/bearcat/bearcat.dm b/maps/away/bearcat/bearcat.dm
index dc13ca07d873..c022e64c5308 100644
--- a/maps/away/bearcat/bearcat.dm
+++ b/maps/away/bearcat/bearcat.dm
@@ -89,16 +89,16 @@
door_color = COLOR_AMBER
/turf/floor/usedup
- initial_gas = list(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD, /decl/material/gas/nitrogen = MOLES_N2STANDARD)
+ initial_gas = alist(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD, /decl/material/gas/nitrogen = MOLES_N2STANDARD)
/turf/floor/tiled/usedup
- initial_gas = list(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD, /decl/material/gas/nitrogen = MOLES_N2STANDARD)
+ initial_gas = alist(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD, /decl/material/gas/nitrogen = MOLES_N2STANDARD)
/turf/floor/tiled/dark/usedup
- initial_gas = list(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD, /decl/material/gas/nitrogen = MOLES_N2STANDARD)
+ initial_gas = alist(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD, /decl/material/gas/nitrogen = MOLES_N2STANDARD)
/turf/floor/tiled/white/usedup
- initial_gas = list(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD, /decl/material/gas/nitrogen = MOLES_N2STANDARD)
+ initial_gas = alist(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD, /decl/material/gas/nitrogen = MOLES_N2STANDARD)
/obj/abstract/landmark/corpse/deadcap
name = "Dead Captain"
diff --git a/maps/exodus/exodus.dm b/maps/exodus/exodus.dm
index a5bb07e061cf..3553f269e878 100644
--- a/maps/exodus/exodus.dm
+++ b/maps/exodus/exodus.dm
@@ -7,6 +7,7 @@
#include "../../mods/content/beekeeping/_beekeeping.dme"
#include "../../mods/content/bigpharma/_bigpharma.dme"
#include "../../mods/content/blob/_blob.dme"
+ #include "../../mods/content/brain_interface/_brain_interface.dme"
#include "../../mods/content/corporate/_corporate.dme"
#include "../../mods/content/government/_government.dme"
#include "../../mods/content/integrated_electronics/_integrated_electronics.dme"
diff --git a/maps/ministation/ministation-0.dmm b/maps/ministation/ministation-0.dmm
index 45af5c6f8e6b..e3f4b0c453f8 100644
--- a/maps/ministation/ministation-0.dmm
+++ b/maps/ministation/ministation-0.dmm
@@ -10255,7 +10255,7 @@
dir = 1
},
/obj/machinery/turretid/stun{
- control_area = "\improper AI Upload Chamber";
+ control_area = /area/ministation/ai_core;
id_tag = "aihome";
pixel_y = -24;
dir = 1
@@ -13371,7 +13371,6 @@
/obj/machinery/turretid/stun{
name = "AI Upload turret control";
id_tag = "upload";
- control_area = "\improper AI Upload Chamber";
pixel_y = -24;
dir = 1
},
diff --git a/maps/ministation/ministation.dm b/maps/ministation/ministation.dm
index a44a244232b9..cf34155e64f2 100644
--- a/maps/ministation/ministation.dm
+++ b/maps/ministation/ministation.dm
@@ -23,6 +23,7 @@ Twice...
#include "../../mods/content/augments/_augments.dme"
#include "../../mods/content/bigpharma/_bigpharma.dme"
#include "../../mods/content/blob/_blob.dme"
+ #include "../../mods/content/brain_interface/_brain_interface.dme"
#include "../../mods/content/corporate/_corporate.dme"
#include "../../mods/content/government/_government.dme"
#include "../../mods/content/integrated_electronics/_integrated_electronics.dme"
diff --git a/maps/modpack_testing/modpack_testing.dm b/maps/modpack_testing/modpack_testing.dm
index d334f4879d6c..aed6b8e3022a 100644
--- a/maps/modpack_testing/modpack_testing.dm
+++ b/maps/modpack_testing/modpack_testing.dm
@@ -12,6 +12,7 @@
#include "../../mods/content/bigpharma/_bigpharma.dme"
#include "../../mods/content/biomods/_biomods.dme"
#include "../../mods/content/blob/_blob.dme"
+ #include "../../mods/content/brain_interface/_brain_interface.dme"
#include "../../mods/content/breath_holding/_breath_holding.dme"
#include "../../mods/content/byond_membership/_byond_membership.dm"
#include "../../mods/content/corporate/_corporate.dme"
diff --git a/maps/planets/test_planet/test_planet.dm b/maps/planets/test_planet/test_planet.dm
index 83c42703e654..9d7d0f324d71 100644
--- a/maps/planets/test_planet/test_planet.dm
+++ b/maps/planets/test_planet/test_planet.dm
@@ -7,7 +7,7 @@
/datum/gas_mixture/atmos_neutralia
temperature = T20C
- gas = list(
+ gas = alist(
/decl/material/gas/oxygen = MOLES_O2STANDARD,
/decl/material/gas/nitrogen = MOLES_N2STANDARD,
)
diff --git a/maps/random_ruins/exoplanet_ruins/lodge/lodge.dm b/maps/random_ruins/exoplanet_ruins/lodge/lodge.dm
index 893ebdb5c648..b92079557e2e 100644
--- a/maps/random_ruins/exoplanet_ruins/lodge/lodge.dm
+++ b/maps/random_ruins/exoplanet_ruins/lodge/lodge.dm
@@ -7,4 +7,4 @@
template_tags = TEMPLATE_TAG_HUMAN|TEMPLATE_TAG_HABITAT
/turf/floor/wood/usedup
- initial_gas = list(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD, /decl/material/gas/nitrogen = MOLES_N2STANDARD)
\ No newline at end of file
+ initial_gas = alist(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD, /decl/material/gas/nitrogen = MOLES_N2STANDARD)
\ No newline at end of file
diff --git a/maps/shaded_hills/levels/_levels.dm b/maps/shaded_hills/levels/_levels.dm
index 411714f57c56..cf7081b88e51 100644
--- a/maps/shaded_hills/levels/_levels.dm
+++ b/maps/shaded_hills/levels/_levels.dm
@@ -9,7 +9,7 @@
ambient_light_level = 1
ambient_light_color = "#f3e6ca"
strata = /decl/strata/shaded_hills
- exterior_atmosphere = list(
+ exterior_atmosphere = alist(
/decl/material/gas/oxygen = MOLES_O2STANDARD,
/decl/material/gas/nitrogen = MOLES_N2STANDARD
)
diff --git a/maps/tradeship/tradeship.dm b/maps/tradeship/tradeship.dm
index 28f3b208c5a1..2101d73bb84f 100644
--- a/maps/tradeship/tradeship.dm
+++ b/maps/tradeship/tradeship.dm
@@ -20,6 +20,7 @@
#include "../../mods/content/beekeeping/_beekeeping.dme"
#include "../../mods/content/bigpharma/_bigpharma.dme"
#include "../../mods/content/blob/_blob.dme"
+ #include "../../mods/content/brain_interface/_brain_interface.dme"
#include "../../mods/content/breath_holding/_breath_holding.dme"
#include "../../mods/content/corporate/_corporate.dme"
#include "../../mods/content/dungeon_loot/_dungeon_loot.dme"
diff --git a/mods/content/biomods/ears_animal.dm b/mods/content/biomods/ears_animal.dm
index 3e39b6567dd1..71785dd8f32f 100644
--- a/mods/content/biomods/ears_animal.dm
+++ b/mods/content/biomods/ears_animal.dm
@@ -19,7 +19,7 @@
icon_state = "fox"
uid = "accessory_ears_fox"
-/decl/sprite_accessory/ears/biomods/antlers
+/decl/sprite_accessory/ears/biomods/animal/antlers
name = "Antlers"
icon_state = "antlers"
uid = "accessory_ears_antlers"
diff --git a/mods/content/brain_interface/_brain_interface.dme b/mods/content/brain_interface/_brain_interface.dme
new file mode 100644
index 000000000000..41d2d720d0d7
--- /dev/null
+++ b/mods/content/brain_interface/_brain_interface.dme
@@ -0,0 +1,11 @@
+#ifndef CONTENT_PACK_BRAIN_INTERFACE
+#define CONTENT_PACK_BRAIN_INTERFACE
+// BEGIN_INCLUDE
+#include "brain_interface.dm"
+#include "brain_interface_organ.dm"
+#include "brainmob_overrides.dm"
+#include "fabricator_recipes.dm"
+#include "interface_radio.dm"
+#include "misc_overrides.dm"
+// END_INCLUDE
+#endif
\ No newline at end of file
diff --git a/mods/content/brain_interface/brain_interface.dm b/mods/content/brain_interface/brain_interface.dm
new file mode 100644
index 000000000000..e861d74778a9
--- /dev/null
+++ b/mods/content/brain_interface/brain_interface.dm
@@ -0,0 +1,3 @@
+/decl/modpack/brain_interface
+ name = "Brain Interface"
+ desc = "Adds brain-computer interfaces, used as organs in full-body prostheses and in cyborgs."
diff --git a/code/modules/brain_interface/_brain_interface.dm b/mods/content/brain_interface/brain_interface_organ.dm
similarity index 98%
rename from code/modules/brain_interface/_brain_interface.dm
rename to mods/content/brain_interface/brain_interface_organ.dm
index abd19c34b0f9..6696cc39b37f 100644
--- a/code/modules/brain_interface/_brain_interface.dm
+++ b/mods/content/brain_interface/brain_interface_organ.dm
@@ -5,7 +5,7 @@
organ_tag = BP_BRAIN
parent_organ = BP_HEAD
origin_tech = @'{"biotech":3}'
- icon = 'icons/obj/items/brain_interface_organic.dmi'
+ icon = 'mods/content/brain_interface/icons/brain_interface_organic.dmi'
icon_state = ICON_STATE_WORLD
req_access = list(access_robotics)
material = /decl/material/solid/metal/steel
diff --git a/mods/content/brain_interface/brainmob_overrides.dm b/mods/content/brain_interface/brainmob_overrides.dm
new file mode 100644
index 000000000000..d01d72a31d91
--- /dev/null
+++ b/mods/content/brain_interface/brainmob_overrides.dm
@@ -0,0 +1,35 @@
+/mob/living/brain/get_radio()
+ var/obj/item/organ/internal/brain_interface/container = get_container()
+ if(istype(container))
+ return container.get_radio()
+
+/mob/living/brain/get_death_message(gibbed)
+ var/obj/item/organ/internal/brain_interface/container = get_container()
+ if(!gibbed && istype(container))
+ return "beeps shrilly as \the [container] flatlines!"
+ return ..()
+
+/mob/living/brain/death(gibbed)
+ var/obj/item/organ/internal/brain_interface/container = get_container()
+ . = ..()
+ if(. && istype(container) && !QDELETED(container))
+ container.update_icon()
+
+/mob/living/brain/gib(do_gibs = TRUE)
+ var/obj/item/organ/internal/brain_interface/container = get_container()
+ . = ..()
+ if(. && istype(container) && !QDELETED(container))
+ qdel(container)
+
+/mob/living/brain/on_container_login(obj/item/organ/internal/container)
+ var/obj/item/organ/internal/brain_interface/interface = container
+ if(istype(interface))
+ interface.locked = TRUE
+ . = ..()
+
+/mob/living/brain/is_in_interface()
+ var/container = get_container()
+ return ..() || istype(container, /obj/item/organ/internal/brain_interface)
+
+/mob/living/brain/check_mob_can_emote(var/emote_type, allow_brain_emote = FALSE)
+ return ..(emote_type, istype(get_container(), /obj/item/organ/internal/brain_interface))
diff --git a/mods/content/brain_interface/fabricator_recipes.dm b/mods/content/brain_interface/fabricator_recipes.dm
new file mode 100644
index 000000000000..9ccce7c6fddc
--- /dev/null
+++ b/mods/content/brain_interface/fabricator_recipes.dm
@@ -0,0 +1,5 @@
+/datum/fabricator_recipe/protolathe/brains/mmi
+ path = /obj/item/organ/internal/brain_interface/empty
+
+/datum/fabricator_recipe/protolathe/brains/mmi_radio
+ path = /obj/item/organ/internal/brain_interface/radio_enabled/empty
\ No newline at end of file
diff --git a/icons/obj/items/brain_interface_organic.dmi b/mods/content/brain_interface/icons/brain_interface_organic.dmi
similarity index 100%
rename from icons/obj/items/brain_interface_organic.dmi
rename to mods/content/brain_interface/icons/brain_interface_organic.dmi
diff --git a/code/modules/brain_interface/interface_radio.dm b/mods/content/brain_interface/interface_radio.dm
similarity index 100%
rename from code/modules/brain_interface/interface_radio.dm
rename to mods/content/brain_interface/interface_radio.dm
diff --git a/mods/content/brain_interface/misc_overrides.dm b/mods/content/brain_interface/misc_overrides.dm
new file mode 100644
index 000000000000..9c11536d62cd
--- /dev/null
+++ b/mods/content/brain_interface/misc_overrides.dm
@@ -0,0 +1,31 @@
+/datum/trader/devices/New()
+ LAZYSET(possible_trading_items, /obj/item/organ/internal/brain_interface, TRADER_SUBTYPES_ONLY)
+ . = ..()
+
+/datum/controller/subsystem/robots/PreInit()
+ . = ..()
+ LAZYSET(mob_types_by_title, "cyborg, flying", /mob/living/silicon/robot/flying)
+ LAZYSET(processor_types_by_title, "cyborg", /obj/item/organ/internal/brain_interface)
+ LAZYSET(processor_types_by_title, "cyborg, flying", /obj/item/organ/internal/brain_interface)
+
+// Override to use MMIs for mobs with brains
+/obj/item/projectile/change/make_robot(var/mob/living/victim, robot_title = ASSIGNMENT_ROBOT)
+ var/obj/item/organ/internal/brain/victim_brain = victim.get_organ(BP_BRAIN, /obj/item/organ/internal/brain)
+ if(istype(victim_brain) && victim_brain.can_use_brain_interface)
+ robot_title = "Cyborg"
+ return ..(victim, robot_title)
+
+/obj/item/robot_parts/robot_suit/is_valid_processor(obj/item/used_item)
+ return ..() || istype(used_item, /obj/item/organ/internal/brain_interface)
+
+/decl/bodytype/prosthetic/Initialize()
+ LAZYSET(has_organ, BP_BRAIN, /obj/item/organ/internal/brain_interface)
+ . = ..()
+
+/obj/item/rig_module/ai_container/Initialize(mapload)
+ simple_insert_types |= /obj/item/organ/internal/brain_interface
+ . = ..()
+
+/obj/item/gripper/research/Initialize(ml, material_key)
+ can_hold += /obj/item/organ/internal/brain_interface
+ . = ..()
diff --git a/mods/content/government/ruins/ec_old_crash/ec_old_crash.dm b/mods/content/government/ruins/ec_old_crash/ec_old_crash.dm
index bc42e4e157af..4942a9d83b02 100644
--- a/mods/content/government/ruins/ec_old_crash/ec_old_crash.dm
+++ b/mods/content/government/ruins/ec_old_crash/ec_old_crash.dm
@@ -43,10 +43,10 @@
external_pressure_bound = 0.25 ATM
/turf/floor/tiled/lowpressure
- initial_gas = list(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD)
+ initial_gas = alist(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD)
/turf/floor/tiled/white/lowpressure
- initial_gas = list(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD)
+ initial_gas = alist(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD)
/obj/item/disk/astrodata
name = "astronomical data disk"
diff --git a/mods/content/integrated_electronics/components/manipulation.dm b/mods/content/integrated_electronics/components/manipulation.dm
index 4148ac842ee5..0a231032e345 100644
--- a/mods/content/integrated_electronics/components/manipulation.dm
+++ b/mods/content/integrated_electronics/components/manipulation.dm
@@ -652,9 +652,11 @@
aicard = null
controlling = null
+/obj/item/integrated_circuit/manipulation/ai/proc/can_load_ai(obj/item/used_item, mob/user)
+ return istype(used_item, /obj/item/aicard) || istype(used_item, /obj/item/paicard) || istype(used_item, /obj/item/organ/internal/brain/robotic)
/obj/item/integrated_circuit/manipulation/ai/attackby(var/obj/item/used_item, var/mob/user)
- if(is_type_in_list(used_item, list(/obj/item/aicard, /obj/item/paicard, /obj/item/organ/internal/brain_interface)))
+ if(can_load_ai(used_item, user))
load_ai(user, used_item)
return TRUE
else return ..()
diff --git a/mods/content/standard_jobs/jobs/synthetics.dm b/mods/content/standard_jobs/jobs/synthetics.dm
index 23f768d4ac62..cbea8c6bf826 100644
--- a/mods/content/standard_jobs/jobs/synthetics.dm
+++ b/mods/content/standard_jobs/jobs/synthetics.dm
@@ -70,7 +70,7 @@
/datum/job/standard/robot/handle_variant_join(var/mob/living/human/H, var/alt_title)
if(H)
- return H.Robotize(SSrobots.get_mob_type_by_title(alt_title || title))
+ return H.Robotize(alt_title || title)
/datum/job/standard/robot/equip_job(var/mob/living/human/H)
return !!H
diff --git a/mods/gamemodes/cult/abilities/construct.dm b/mods/gamemodes/cult/abilities/construct.dm
index 60138eaba356..bbf1a5bc0de3 100644
--- a/mods/gamemodes/cult/abilities/construct.dm
+++ b/mods/gamemodes/cult/abilities/construct.dm
@@ -2,10 +2,9 @@
/decl/ability/cult/construct
name = "Artificer"
desc = "This spell conjures a construct which may be controlled by shades."
- target_selector = /decl/ability_targeting/clear_turf
+ target_selector = /decl/ability_targeting/clear_turf/construct
overlay_icon = 'mods/gamemodes/cult/icons/effects.dmi'
overlay_icon_state = "sparkles"
- target_selector = /decl/ability_targeting/clear_turf/construct
var/summon_type = /obj/structure/constructshell
/decl/ability_targeting/clear_turf/construct/validate_target(mob/user, atom/target, list/metadata, decl/ability/ability)
@@ -14,14 +13,14 @@
return FALSE
return ..() && !istype(target, cult_ability.summon_type) && !(locate(cult_ability.summon_type) in target)
-/decl/ability/cult/construct/apply_effect(mob/user, atom/hit_target, list/metadata, obj/item/projectile/ability/projectile)
+/decl/ability/cult/construct/apply_ability_effect(mob/user, atom/hit_target, list/metadata, obj/item/projectile/ability/projectile)
. = ..()
var/turf/target_turf = get_turf(hit_target)
if(istype(target_turf))
if(ispath(summon_type, /turf))
target_turf = target_turf.ChangeTurf(summon_type, TRUE, FALSE, TRUE, TRUE, FALSE)
if(target_turf) // We reapply effects as target no longer exists.
- apply_effect_to(user, target_turf, metadata)
+ apply_ability_effect_to(user, target_turf, metadata)
else if(ispath(summon_type, /atom))
new summon_type(target_turf)
@@ -87,7 +86,7 @@
return TRUE
return FALSE
-/decl/ability/cult/construct/pylon/apply_effect(mob/user, atom/hit_target, list/metadata, obj/item/projectile/ability/projectile)
+/decl/ability/cult/construct/pylon/apply_ability_effect(mob/user, atom/hit_target, list/metadata, obj/item/projectile/ability/projectile)
for(var/obj/structure/cult/pylon/P in get_turf(hit_target))
if(P.isbroken)
P.repair(user)
diff --git a/mods/gamemodes/cult/abilities/harvest.dm b/mods/gamemodes/cult/abilities/harvest.dm
index 49569d6a25ef..dc8bfc1002ff 100644
--- a/mods/gamemodes/cult/abilities/harvest.dm
+++ b/mods/gamemodes/cult/abilities/harvest.dm
@@ -9,7 +9,7 @@
prepare_message_3p_str = "Space around $USER$ begins to bubble and decay as a terrible vista begins to intrude..."
prepare_message_1p_str = "You bore through space and time, seeking the essence of the Geometer of Blood."
fail_cast_1p_str = "Reality reasserts itself, preventing your return to Nar-Sie."
- target_selector = /decl/ability_targeting/living_mob
+ target_selector = /decl/ability_targeting/single_atom/living_mob
/decl/ability/cult/construct/harvest/can_use_ability(mob/user, list/metadata, silent)
. = ..()
@@ -22,7 +22,7 @@
to_chat(user, SPAN_DANGER("You cannot sense the Geometer of Blood!"))
return FALSE
-/decl/ability/cult/construct/harvest/apply_effect(mob/user, atom/hit_target, list/metadata, obj/item/projectile/ability/projectile)
+/decl/ability/cult/construct/harvest/apply_ability_effect(mob/user, atom/hit_target, list/metadata, obj/item/projectile/ability/projectile)
..()
var/destination = null
for(var/obj/effect/narsie/N in global.narsie_list)
diff --git a/mods/pyrelight/datum/wyrdling/ears.dm b/mods/pyrelight/datum/wyrdling/ears.dm
index 639e675d0684..278dd93c7dba 100644
--- a/mods/pyrelight/datum/wyrdling/ears.dm
+++ b/mods/pyrelight/datum/wyrdling/ears.dm
@@ -1,2 +1,2 @@
/decl/sprite_accessory/ears/biomods/animal
- //required_traits = list(/decl/trait/wyrd/wild)
+ required_traits = list(/decl/trait/wyrd/wild)
diff --git a/mods/pyrelight/datum/wyrdling/tails.dm b/mods/pyrelight/datum/wyrdling/tails.dm
index 3f93a80f1681..44203ca2433d 100644
--- a/mods/pyrelight/datum/wyrdling/tails.dm
+++ b/mods/pyrelight/datum/wyrdling/tails.dm
@@ -1,2 +1,2 @@
/decl/sprite_accessory/tail/biomods
- //required_traits = list(/decl/trait/wyrd/wild)
+ required_traits = list(/decl/trait/wyrd/wild)
diff --git a/mods/species/ascent/turfs/ship.dm b/mods/species/ascent/turfs/ship.dm
index 320a2d8c30e2..03e991d57619 100644
--- a/mods/species/ascent/turfs/ship.dm
+++ b/mods/species/ascent/turfs/ship.dm
@@ -43,7 +43,7 @@
_base_flooring = /decl/flooring/plating/ascent
icon_state = "curvy"
icon = 'icons/turf/flooring/alium.dmi'
- initial_gas = list(
+ initial_gas = alist(
/decl/material/gas/methyl_bromide = MOLES_CELLSTANDARD * 0.5,
/decl/material/gas/oxygen = MOLES_CELLSTANDARD * 0.5
)
@@ -58,7 +58,7 @@
icon_state = "jaggy"
color = COLOR_GRAY40
_flooring = /decl/flooring/tiling_ascent
- initial_gas = list(
+ initial_gas = alist(
/decl/material/gas/methyl_bromide = MOLES_CELLSTANDARD * 0.5,
/decl/material/gas/oxygen = MOLES_CELLSTANDARD * 0.5
)
diff --git a/mods/~compatibility/patches/circuits.dm b/mods/~compatibility/patches/circuits.dm
index afa15ae3f36c..ed8e9ad9b1ef 100644
--- a/mods/~compatibility/patches/circuits.dm
+++ b/mods/~compatibility/patches/circuits.dm
@@ -9,4 +9,8 @@
// Add augment assembly for circuits.
#ifdef CONTENT_PACK_AUGMENTS
#include "circuits/augment_circuits.dm"
+#endif
+// Add support for MMIs to the AI manipulator circuit.
+#ifdef CONTENT_PACK_BRAIN_INTERFACE
+#include "circuits/brain_interface_circuits.dm"
#endif
\ No newline at end of file
diff --git a/mods/~compatibility/patches/circuits/brain_interface_circuits.dm b/mods/~compatibility/patches/circuits/brain_interface_circuits.dm
new file mode 100644
index 000000000000..83d0b5c9c6c9
--- /dev/null
+++ b/mods/~compatibility/patches/circuits/brain_interface_circuits.dm
@@ -0,0 +1,2 @@
+/obj/item/integrated_circuit/manipulation/ai/can_load_ai(obj/item/used_item, mob/user)
+ return ..() || istype(used_item, /obj/item/organ/internal/brain_interface)
\ No newline at end of file
diff --git a/nebula.dme b/nebula.dme
index 0deecff31456..b40eee57081c 100644
--- a/nebula.dme
+++ b/nebula.dme
@@ -1849,8 +1849,6 @@
#include "code\modules\bodytype\bodytype_prosthetic_models.dm"
#include "code\modules\bodytype\bodytype_quadruped.dm"
#include "code\modules\bodytype\bodytype_random.dm"
-#include "code\modules\brain_interface\_brain_interface.dm"
-#include "code\modules\brain_interface\interface_radio.dm"
#include "code\modules\butchery\_butchery.dm"
#include "code\modules\butchery\butchery_data.dm"
#include "code\modules\butchery\butchery_data_animal.dm"
@@ -2772,8 +2770,8 @@
#include "code\modules\materials\stack_types\material_stack_misc.dm"
#include "code\modules\materials\stack_types\material_stack_nail.dm"
#include "code\modules\materials\stack_types\material_stack_ore.dm"
+#include "code\modules\mechs\_mech.dm"
#include "code\modules\mechs\_mech_setup.dm"
-#include "code\modules\mechs\mech.dm"
#include "code\modules\mechs\mech_construction.dm"
#include "code\modules\mechs\mech_damage.dm"
#include "code\modules\mechs\mech_damage_immunity.dm"
@@ -2796,6 +2794,7 @@
#include "code\modules\mechs\equipment\combat_projectile.dm"
#include "code\modules\mechs\equipment\engineering.dm"
#include "code\modules\mechs\equipment\medical.dm"
+#include "code\modules\mechs\equipment\mounted_system.dm"
#include "code\modules\mechs\equipment\utility.dm"
#include "code\modules\mechs\interface\_interface.dm"
#include "code\modules\mechs\premade\_premade.dm"