diff --git a/SQL/tgstation_schema.sql b/SQL/tgstation_schema.sql
index b7e2e501ce1..4978c514b8f 100644
--- a/SQL/tgstation_schema.sql
+++ b/SQL/tgstation_schema.sql
@@ -2,9 +2,7 @@ SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL';
-CREATE SCHEMA IF NOT EXISTS `mydb` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci ;
CREATE SCHEMA IF NOT EXISTS `tgstation` DEFAULT CHARACTER SET latin1 ;
-USE `mydb` ;
USE `tgstation` ;
-- -----------------------------------------------------
diff --git a/baystation12.dme b/baystation12.dme
index 20aef9156e6..c3c894298ea 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -103,6 +103,7 @@
#define FILE_DIR "code/modules/DetectiveWork"
#define FILE_DIR "code/modules/flufftext"
#define FILE_DIR "code/modules/food"
+#define FILE_DIR "code/modules/icon generation"
#define FILE_DIR "code/modules/maps"
#define FILE_DIR "code/modules/mining"
#define FILE_DIR "code/modules/mob"
@@ -362,12 +363,6 @@
#include "code\defines\sd_procs\constants.dm"
#include "code\defines\sd_procs\direction.dm"
#include "code\defines\sd_procs\math.dm"
-#include "code\FEA\FEA_airgroup.dm"
-#include "code\FEA\FEA_fire.dm"
-#include "code\FEA\FEA_gas_mixture.dm"
-#include "code\FEA\FEA_group_helpers.dm"
-#include "code\FEA\FEA_system.dm"
-#include "code\FEA\FEA_turf_tile.dm"
#include "code\game\algorithm.dm"
#include "code\game\atom_procs.dm"
#include "code\game\cellautomata.dm"
@@ -455,6 +450,7 @@
#include "code\game\gamemodes\sandbox\h_sandbox.dm"
#include "code\game\gamemodes\sandbox\sandbox.dm"
#include "code\game\gamemodes\traitor\traitor.dm"
+#include "code\game\gamemodes\traitor\traitor_info.dm"
#include "code\game\gamemodes\wizard\rightandwrong.dm"
#include "code\game\gamemodes\wizard\soulstone.dm"
#include "code\game\gamemodes\wizard\spellbook.dm"
@@ -593,6 +589,7 @@
#include "code\game\magic\archived_book.dm"
#include "code\game\magic\library.dm"
#include "code\game\magic\musician.dm"
+#include "code\game\magic\Uristrunes.dm"
#include "code\game\magic\cultist\ritual.dm"
#include "code\game\magic\cultist\runes.dm"
#include "code\game\magic\cultist\talisman.dm"
@@ -648,6 +645,7 @@
#include "code\game\objects\tank.dm"
#include "code\game\objects\toys.dm"
#include "code\game\objects\transfer_valve.dm"
+#include "code\game\objects\uplinks.dm"
#include "code\game\objects\washing_machine.dm"
#include "code\game\objects\watercloset.dm"
#include "code\game\objects\weapons.dm"
@@ -773,6 +771,7 @@
#include "code\game\objects\storage\lockbox.dm"
#include "code\game\objects\storage\storage.dm"
#include "code\game\objects\storage\toolbox.dm"
+#include "code\game\objects\storage\uplink_kits.dm"
#include "code\game\objects\tanks\emergency.dm"
#include "code\game\objects\tanks\jetpack.dm"
#include "code\game\objects\tanks\oxygen.dm"
@@ -789,6 +788,7 @@
#include "code\js\byjax.dm"
#include "code\js\menus.dm"
#include "code\modules\admin\admin.dm"
+#include "code\modules\admin\admin_memo.dm"
#include "code\modules\admin\admin_verbs.dm"
#include "code\modules\admin\banjob.dm"
#include "code\modules\admin\create_mob.dm"
@@ -963,6 +963,7 @@
#include "code\modules\mob\living\carbon\human\emote.dm"
#include "code\modules\mob\living\carbon\human\examine.dm"
#include "code\modules\mob\living\carbon\human\hud.dm"
+#include "code\modules\mob\living\carbon\human\hud_overlays.dm"
#include "code\modules\mob\living\carbon\human\human.dm"
#include "code\modules\mob\living\carbon\human\human_attackalien.dm"
#include "code\modules\mob\living\carbon\human\human_attackhand.dm"
@@ -1151,8 +1152,7 @@
#include "code\WorkInProgress\AI_Visibility\minimap.dm"
#include "code\WorkInProgress\AI_Visibility\util.dm"
#include "code\WorkInProgress\animusstation\atm.dm"
-#include "code\WorkInProgress\Cael_Aislinn\BirdMan\bird_transformation.dm"
-#include "code\WorkInProgress\Cael_Aislinn\BirdMan\birdman.dm"
+#include "code\WorkInProgress\Cael_Aislinn\power_monitor.dm"
#include "code\WorkInProgress\Cael_Aislinn\Rust\core_field.dm"
#include "code\WorkInProgress\Cael_Aislinn\Rust\core_gen.dm"
#include "code\WorkInProgress\Cael_Aislinn\Rust\core_monitor.dm"
@@ -1168,24 +1168,9 @@
#include "code\WorkInProgress\Cael_Aislinn\Supermatter\LaserComputer.dm"
#include "code\WorkInProgress\Cael_Aislinn\Supermatter\SuperMatter.dm"
#include "code\WorkInProgress\Cael_Aislinn\Supermatter\ZeroPointLaser.dm"
-#include "code\WorkInProgress\Cael_Aislinn\Tajara\death.dm"
-#include "code\WorkInProgress\Cael_Aislinn\Tajara\emote.dm"
-#include "code\WorkInProgress\Cael_Aislinn\Tajara\examine.dm"
-#include "code\WorkInProgress\Cael_Aislinn\Tajara\hud.dm"
-#include "code\WorkInProgress\Cael_Aislinn\Tajara\life.dm"
-#include "code\WorkInProgress\Cael_Aislinn\Tajara\login.dm"
-#include "code\WorkInProgress\Cael_Aislinn\Tajara\pain.dm"
#include "code\WorkInProgress\Cael_Aislinn\Tajara\say.dm"
#include "code\WorkInProgress\Cael_Aislinn\Tajara\tajara_transformation.dm"
#include "code\WorkInProgress\Cael_Aislinn\Tajara\tajaran.dm"
-#include "code\WorkInProgress\Cael_Aislinn\Tajara\tajaran_algorithm.dm"
-#include "code\WorkInProgress\Cael_Aislinn\Tajara\tajaran_attackalien.dm"
-#include "code\WorkInProgress\Cael_Aislinn\Tajara\tajaran_attackhand.dm"
-#include "code\WorkInProgress\Cael_Aislinn\Tajara\tajaran_attackpaw.dm"
-#include "code\WorkInProgress\Cael_Aislinn\Tajara\tajaran_damage.dm"
-#include "code\WorkInProgress\Cael_Aislinn\Tajara\tajaran_defense.dm"
-#include "code\WorkInProgress\Cael_Aislinn\Tajara\tajaran_movement.dm"
-#include "code\WorkInProgress\Cael_Aislinn\Tajara\tajaran_transform_procs.dm"
#include "code\WorkInProgress\Cael_Aislinn\Tajara\whisper.dm"
#include "code\WorkInProgress\Chinsky\ashtray.dm"
#include "code\WorkInProgress\Mini\atmos_control.dm"
@@ -1193,10 +1178,8 @@
#include "code\WorkInProgress\Mloc\Shortcuts.dm"
#include "code\WorkInProgress\organs\implants.dm"
#include "code\WorkInProgress\organs\organs.dm"
-#include "code\WorkInProgress\Ported\head.dm"
#include "code\WorkInProgress\Ported\policetape.dm"
-#include "code\WorkInProgress\Ported\Abi79\uplink_kits.dm"
-#include "code\WorkInProgress\Ported\Abi79\uplinks.dm"
+#include "code\WorkInProgress\Ported\sql.dm"
#include "code\WorkInProgress\Ported\Bureaucracy\copier.dm"
#include "code\WorkInProgress\Ported\Bureaucracy\filing.dm"
#include "code\WorkInProgress\SkyMarshal\coatrack.dm"
@@ -1222,6 +1205,18 @@
#include "code\WorkInProgress\virus2\monkeydispensor.dm"
#include "code\WorkInProgress\virus2\Prob.dm"
#include "code\WorkInProgress\Wrongnumber\weldbackpack.dm"
+#include "code\ZAS\Airflow.dm"
+#include "code\ZAS\Connection.dm"
+#include "code\ZAS\Creation.dm"
+#include "code\ZAS\Definition.dm"
+#include "code\ZAS\FEA_gas_mixture.dm"
+#include "code\ZAS\FEA_system.dm"
+#include "code\ZAS\FEA_turf_tile.dm"
+#include "code\ZAS\Fire.dm"
+#include "code\ZAS\Functions.dm"
+#include "code\ZAS\Plasma.dm"
+#include "code\ZAS\Processing.dm"
+#include "code\ZAS\Variable Settings.dm"
#include "interface\interface.dm"
#include "interface\skin.dmf"
#include "maps\tgstation.2.0.8.dmm"
diff --git a/code/ATMOSPHERICS/datum_pipeline.dm b/code/ATMOSPHERICS/datum_pipeline.dm
index 1b63e605481..5ade345e08f 100644
--- a/code/ATMOSPHERICS/datum_pipeline.dm
+++ b/code/ATMOSPHERICS/datum_pipeline.dm
@@ -128,28 +128,19 @@ datum/pipeline
var/datum/gas_mixture/air_sample = air.remove_ratio(mingle_volume/air.volume)
air_sample.volume = mingle_volume
- if(istype(target) && target.parent && target.parent.group_processing)
+ if(istype(target) && target.zone)
//Have to consider preservation of group statuses
var/datum/gas_mixture/turf_copy = new
- turf_copy.copy_from(target.parent.air)
- turf_copy.volume = target.parent.air.volume //Copy a good representation of the turf from parent group
+ turf_copy.copy_from(target.zone.air)
+ turf_copy.volume = target.zone.air.volume //Copy a good representation of the turf from parent group
equalize_gases(list(air_sample, turf_copy))
air.merge(air_sample)
- if(target.parent.air.compare(turf_copy))
- //The new turf would be an acceptable group member so permit the integration
+ turf_copy.subtract(target.zone.air)
- turf_copy.subtract(target.parent.air)
-
- target.parent.air.merge(turf_copy)
-
- else
- //Comparison failure so dissemble group and copy turf
-
- target.parent.suspend_group_processing()
- target.air.copy_from(turf_copy)
+ target.zone.air.merge(turf_copy)
else
var/datum/gas_mixture/turf_air = target.return_air()
@@ -187,9 +178,9 @@ datum/pipeline
var/delta_temperature = 0
var/sharer_heat_capacity = 0
- if(modeled_location.parent && modeled_location.parent.group_processing)
- delta_temperature = (air.temperature - modeled_location.parent.air.temperature)
- sharer_heat_capacity = modeled_location.parent.air.heat_capacity()
+ if(modeled_location.zone)
+ delta_temperature = (air.temperature - modeled_location.zone.air.temperature)
+ sharer_heat_capacity = modeled_location.zone.air.heat_capacity()
else
delta_temperature = (air.temperature - modeled_location.air.temperature)
sharer_heat_capacity = modeled_location.air.heat_capacity()
@@ -208,14 +199,8 @@ datum/pipeline
air.temperature += self_temperature_delta
- if(modeled_location.parent && modeled_location.parent.group_processing)
- if((abs(sharer_temperature_delta) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) && (abs(sharer_temperature_delta) > MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND*modeled_location.parent.air.temperature))
- modeled_location.parent.suspend_group_processing()
-
- modeled_location.air.temperature += sharer_temperature_delta
-
- else
- modeled_location.parent.air.temperature += sharer_temperature_delta/modeled_location.parent.air.group_multiplier
+ if(modeled_location.zone)
+ modeled_location.zone.air.temperature += sharer_temperature_delta/modeled_location.zone.air.group_multiplier
else
modeled_location.air.temperature += sharer_temperature_delta
diff --git a/code/FEA/FEA_fire.dm b/code/FEA/FEA_fire.dm
index 14fd727dd92..c37e51ac2ca 100644
--- a/code/FEA/FEA_fire.dm
+++ b/code/FEA/FEA_fire.dm
@@ -1,3 +1,5 @@
+//This file was auto-corrected by findeclaration.exe on 29/05/2012 15:03:04
+
atom
proc/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
//Purpose: Managing temperature exposure.
@@ -67,13 +69,12 @@ obj
layer = TURF_LAYER
- var
- volume = 125
- temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST
+ var/volume = 125
+ var/temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST
- just_spawned = 1
+ var/just_spawned = 1
- bypassing = 0
+ var/bypassing = 0
proc/perform_exposure()
var/turf/simulated/floor/location = loc
@@ -179,4 +180,4 @@ obj
loc = null
- ..()
\ No newline at end of file
+ ..()
diff --git a/code/FEA/FEA_gas_mixture.dm b/code/FEA/FEA_gas_mixture.dm
index 8edefe79d7b..751431ef7b3 100644
--- a/code/FEA/FEA_gas_mixture.dm
+++ b/code/FEA/FEA_gas_mixture.dm
@@ -1,3 +1,5 @@
+//This file was auto-corrected by findeclaration.exe on 29/05/2012 15:03:04
+
/*
What are the archived variables for?
Calculations are done using the archived variables with the results merged into the regular variables.
@@ -22,11 +24,10 @@ datum
volatile_fuel
specific_heat = 30
- var
- moles = 0
- specific_heat = 0
+ var/moles = 0
+ var/specific_heat = 0
- moles_archived = 0
+ var/moles_archived = 0
gas_mixture
var //Holds the "moles" of each of the four gases.
@@ -1006,4 +1007,4 @@ datum
corresponding.moles -= trace_gas.moles
update_values()
- return 1
\ No newline at end of file
+ return 1
diff --git a/code/FEA/FEA_turf_tile.dm b/code/FEA/FEA_turf_tile.dm
index 38083f52ce0..0652fe66163 100644
--- a/code/FEA/FEA_turf_tile.dm
+++ b/code/FEA/FEA_turf_tile.dm
@@ -1,3 +1,5 @@
+//This file was auto-corrected by findeclaration.exe on 29/05/2012 15:03:04
+
atom/movable/var/pressure_resistance = 20
atom/movable/var/last_forced_movement = 0
@@ -91,23 +93,22 @@ turf
var/current_graphic = null
- var/tmp
- datum/gas_mixture/air
+ var/tmp/datum/gas_mixture/air
- processing = 1
- datum/air_group/parent
- group_border = 0
- length_space_border = 0
+ var/tmp/processing = 1
+ var/tmp/datum/air_group/parent
+ var/tmp/group_border = 0
+ var/tmp/length_space_border = 0
- air_check_directions = 0 //Do not modify this, just add turf to air_master.tiles_to_update
+ var/tmp/air_check_directions = 0 //Do not modify this, just add turf to air_master.tiles_to_update
- archived_cycle = 0
- current_cycle = 0
+ var/tmp/archived_cycle = 0
+ var/tmp/current_cycle = 0
- obj/effect/hotspot/active_hotspot
+ var/tmp/obj/effect/hotspot/active_hotspot
- temperature_archived //USED ONLY FOR SOLIDS
- being_superconductive = 0
+ var/tmp/temperature_archived //USED ONLY FOR SOLIDS
+ var/tmp/being_superconductive = 0
proc
@@ -132,9 +133,9 @@ turf
overlays += image('floors.dmi',siding_icon_state)
switch(model.graphic)
- if("plasma")
+ if(1)
overlays.Add(plmaster)
- if("sleeping_agent")
+ if(2)
overlays.Add(slmaster)
diff --git a/code/WorkInProgress/Cael_Aislinn/Tajara/tajara_transformation.dm b/code/WorkInProgress/Cael_Aislinn/Tajara/tajara_transformation.dm
index c8906cf31df..bc1c6750dab 100644
--- a/code/WorkInProgress/Cael_Aislinn/Tajara/tajara_transformation.dm
+++ b/code/WorkInProgress/Cael_Aislinn/Tajara/tajara_transformation.dm
@@ -55,7 +55,7 @@
O.update_body()
O.update_face()
spawn(1)
- O.update_clothing()
+ O.rebuild_appearance()
O << "You are now a Tajara."
spawn(0)//To prevent the proc from returning null.
del(src)
diff --git a/code/WorkInProgress/Cael_Aislinn/Tajara/tajaran.dm b/code/WorkInProgress/Cael_Aislinn/Tajara/tajaran.dm
index 29f4cc2b95d..3541f135f6d 100644
--- a/code/WorkInProgress/Cael_Aislinn/Tajara/tajaran.dm
+++ b/code/WorkInProgress/Cael_Aislinn/Tajara/tajaran.dm
@@ -22,11 +22,17 @@
if(!lying_icon)
lying_icon = new /icon('tajaran.dmi', "body_[g]_l")
icon = stand_icon
- update_clothing()
+ rebuild_appearance()
src << "\blue Your icons have been generated!"
..()
+/mob/living/carbon/human/tajaran/rebuild_appearance()
+ update_clothing()
+
+/mob/living/carbon/human/tajaran/update_body_appearance()
+ update_clothing()
+
/mob/living/carbon/human/tajaran/update_clothing()
// ..()
@@ -303,12 +309,7 @@
if ( istype(wear_suit, /obj/item/clothing/suit/bio_suit) || istype(wear_suit, /obj/item/clothing/suit/bomb_suit) || istype(wear_suit, /obj/item/clothing/suit/space) )
tail_shown = 0
if(tail_shown)
- var/icon/tail_icon = image("icon" = icon('tajaran.dmi', "tail_[gender==FEMALE ? "f" : "m"]_[lying ? "l" : "s"]"), "layer" = MOB_LAYER)
- if (s_tone >= 0)
- tail_icon.Blend(rgb(s_tone, s_tone, s_tone), ICON_ADD)
- else
- tail_icon.Blend(rgb(-s_tone, -s_tone, -s_tone), ICON_SUBTRACT)
- overlays += tail_icon
+ overlays += image("icon" = icon('tajaran.dmi', "tail_[gender==FEMALE ? "f" : "m"]_[lying ? "l" : "s"]"), "layer" = MOB_LAYER)
if (lying)
if (face_lying)
@@ -344,12 +345,7 @@
var/datum/organ/external/head = organs["head"]
if(!head.destroyed)
//if not wearing anything on the head, show the ears
- var/icon/ears_icon = image("icon" = icon('tajaran.dmi', "ears_[gender==FEMALE ? "f" : "m"]_[lying ? "l" : "s"]"), "layer" = MOB_LAYER)
- if (s_tone >= 0)
- ears_icon.Blend(rgb(s_tone, s_tone, s_tone), ICON_ADD)
- else
- ears_icon.Blend(rgb(-s_tone, -s_tone, -s_tone), ICON_SUBTRACT)
- overlays += ears_icon
+ overlays += image("icon" = icon('tajaran.dmi', "ears_[gender==FEMALE ? "f" : "m"]_[lying ? "l" : "s"]"), "layer" = MOB_LAYER)
// Belt
if (belt)
diff --git a/code/WorkInProgress/Cael_Aislinn/Tajara/tajaran.dmi b/code/WorkInProgress/Cael_Aislinn/Tajara/tajaran.dmi
index 6e69669647f..14284506856 100644
Binary files a/code/WorkInProgress/Cael_Aislinn/Tajara/tajaran.dmi and b/code/WorkInProgress/Cael_Aislinn/Tajara/tajaran.dmi differ
diff --git a/code/WorkInProgress/Cael_Aislinn/Tajara/tajaran_face.dmi b/code/WorkInProgress/Cael_Aislinn/Tajara/tajaran_face.dmi
index 440983184db..c101e668feb 100644
Binary files a/code/WorkInProgress/Cael_Aislinn/Tajara/tajaran_face.dmi and b/code/WorkInProgress/Cael_Aislinn/Tajara/tajaran_face.dmi differ
diff --git a/code/WorkInProgress/Mini/ATM.dm b/code/WorkInProgress/Mini/ATM.dm
index 3feb2014916..068211a97c3 100644
--- a/code/WorkInProgress/Mini/ATM.dm
+++ b/code/WorkInProgress/Mini/ATM.dm
@@ -21,7 +21,7 @@ log transactions
/obj/machinery/atm/attackby(obj/item/I as obj, mob/user as mob)
if(ishuman(user))
var/obj/item/weapon/card/id/user_id = src.scan_user(user)
- if(istype(I,/obj/item/weapon/spacecash))
+ if(istype(I,/obj/item/weapon/money))
user_id.money += I:worth
del I
@@ -29,7 +29,7 @@ log transactions
if(istype(user, /mob/living/silicon))
user << "\red Artificial unit recognized. Artificial units do not currently receive monetary compensation, as per NanoTrasen regulation #1005."
return
-
+
var/obj/item/weapon/card/id/user_id = src.scan_user(user)
if(..())
return
@@ -51,21 +51,21 @@ log transactions
//hueg switch for giving moneh out
switch(amount)
if(1)
- new /obj/item/weapon/spacecash(loc)
+ new /obj/item/weapon/money(loc)
if(10)
- new /obj/item/weapon/spacecash/c10(loc)
+ new /obj/item/weapon/money/c10(loc)
if(20)
- new /obj/item/weapon/spacecash/c20(loc)
+ new /obj/item/weapon/money/c20(loc)
if(50)
- new /obj/item/weapon/spacecash/c50(loc)
+ new /obj/item/weapon/money/c50(loc)
if(100)
- new /obj/item/weapon/spacecash/c100(loc)
+ new /obj/item/weapon/money/c100(loc)
if(200)
- new /obj/item/weapon/spacecash/c200(loc)
+ new /obj/item/weapon/money/c200(loc)
if(500)
- new /obj/item/weapon/spacecash/c500(loc)
+ new /obj/item/weapon/money/c500(loc)
if(1000)
- new /obj/item/weapon/spacecash/c1000(loc)
+ new /obj/item/weapon/money/c1000(loc)
else
usr << browse("You don't have that much money!
Back","window=atm")
return
diff --git a/code/WorkInProgress/Mloc/Shortcuts.dm b/code/WorkInProgress/Mloc/Shortcuts.dm
index 8d537d15830..361e647cbc3 100644
--- a/code/WorkInProgress/Mloc/Shortcuts.dm
+++ b/code/WorkInProgress/Mloc/Shortcuts.dm
@@ -7,27 +7,59 @@
if("help")
usr.a_intent = "disarm"
usr.hud_used.action_intent.icon_state = "disarm"
+ usr.hud_used.hurt_intent.icon_state = "harm_small"
+ usr.hud_used.help_intent.icon_state = "help_small"
+ usr.hud_used.grab_intent.icon_state = "grab_small"
+ usr.hud_used.disarm_intent.icon_state = "disarm_small_active"
if("disarm")
usr.a_intent = "hurt"
usr.hud_used.action_intent.icon_state = "harm"
+ usr.hud_used.hurt_intent.icon_state = "harm_small_active"
+ usr.hud_used.help_intent.icon_state = "help_small"
+ usr.hud_used.grab_intent.icon_state = "grab_small"
+ usr.hud_used.disarm_intent.icon_state = "disarm_small"
if("hurt")
usr.a_intent = "grab"
usr.hud_used.action_intent.icon_state = "grab"
+ usr.hud_used.hurt_intent.icon_state = "harm_small"
+ usr.hud_used.help_intent.icon_state = "help_small"
+ usr.hud_used.grab_intent.icon_state = "grab_small_active"
+ usr.hud_used.disarm_intent.icon_state = "disarm_small"
if("grab")
usr.a_intent = "help"
usr.hud_used.action_intent.icon_state = "help"
+ usr.hud_used.hurt_intent.icon_state = "harm_small"
+ usr.hud_used.help_intent.icon_state = "help_small_active"
+ usr.hud_used.grab_intent.icon_state = "grab_small"
+ usr.hud_used.disarm_intent.icon_state = "disarm_small"
else if(changeto == -1)
switch(usr.a_intent)
if("help")
usr.a_intent = "grab"
usr.hud_used.action_intent.icon_state = "grab"
+ usr.hud_used.hurt_intent.icon_state = "harm_small"
+ usr.hud_used.help_intent.icon_state = "help_small"
+ usr.hud_used.grab_intent.icon_state = "grab_small_active"
+ usr.hud_used.disarm_intent.icon_state = "disarm_small"
if("disarm")
usr.a_intent = "help"
usr.hud_used.action_intent.icon_state = "help"
+ usr.hud_used.hurt_intent.icon_state = "harm_small"
+ usr.hud_used.help_intent.icon_state = "help_small_active"
+ usr.hud_used.grab_intent.icon_state = "grab_small"
+ usr.hud_used.disarm_intent.icon_state = "disarm_small"
if("hurt")
usr.a_intent = "disarm"
usr.hud_used.action_intent.icon_state = "disarm"
+ usr.hud_used.hurt_intent.icon_state = "harm_small"
+ usr.hud_used.help_intent.icon_state = "help_small"
+ usr.hud_used.grab_intent.icon_state = "grab_small"
+ usr.hud_used.disarm_intent.icon_state = "disarm_small_active"
if("grab")
usr.a_intent = "hurt"
usr.hud_used.action_intent.icon_state = "harm"
+ usr.hud_used.hurt_intent.icon_state = "harm_small_active"
+ usr.hud_used.help_intent.icon_state = "help_small"
+ usr.hud_used.grab_intent.icon_state = "grab_small"
+ usr.hud_used.disarm_intent.icon_state = "disarm_small"
return
\ No newline at end of file
diff --git a/code/WorkInProgress/Ported/Abi79/uplinks.dm b/code/WorkInProgress/Ported/Abi79/uplinks.dm
index 203cbb77bb7..ae261a85ac1 100644
--- a/code/WorkInProgress/Ported/Abi79/uplinks.dm
+++ b/code/WorkInProgress/Ported/Abi79/uplinks.dm
@@ -175,9 +175,9 @@ A list of items and costs is stored under the datum of every game mode, alongsid
if(text2num(href_list["cost"]) > uses) // Not enough crystals for the item
return 0
- //if(usr:mind && ticker.mode.traitors[usr:mind])
- //var/datum/traitorinfo/info = ticker.mode.traitors[usr:mind]
- //info.spawnlist += href_list["buy_item"]
+ if(usr:mind && ticker.mode.traitors[usr:mind])
+ var/datum/traitorinfo/info = ticker.mode.traitors[usr:mind]
+ info.spawnlist += href_list["buy_item"]
uses -= text2num(href_list["cost"])
@@ -268,7 +268,7 @@ A list of items and costs is stored under the datum of every game mode, alongsid
else
item:loc = get_turf(A)
usr.update_clothing()
- // usr.client.onBought("[item:name]") When we have the stats again, uncomment.
+ usr.client.onBought("[item:name]")
/* if(istype(item, /obj/spawner)) // Spawners need to have del called on them to avoid leaving a marker behind
del item*/
//HEADFINDBACK
@@ -371,7 +371,7 @@ A list of items and costs is stored under the datum of every game mode, alongsid
item:loc = get_turf(A)
/* if(istype(item, /obj/spawner)) // Spawners need to have del called on them to avoid leaving a marker behind
del item*/
- // usr.client.onBought("[item:name]") When we have the stats again, uncomment.
+ usr.client.onBought("[item:name]")
src.attack_self(usr)
return
diff --git a/code/WorkInProgress/Ported/policetape.dm b/code/WorkInProgress/Ported/policetape.dm
index 4a6d1b7c066..e51791050d9 100644
--- a/code/WorkInProgress/Ported/policetape.dm
+++ b/code/WorkInProgress/Ported/policetape.dm
@@ -49,11 +49,19 @@
end = get_turf(locate(end.x+d,end.y,end.z))
dir = "h"
- while (cur!=end)
+ var/can_place = 1
+ while (cur!=end && can_place)
if(cur.density == 1)
- usr << "\blue You can't run [src] through a wall!"
- return
+ can_place = 0
+ else
+ for(var/obj/O in cur)
+ if(O.density)
+ can_place = 0
+ break
cur = get_step_towards(cur,end)
+ if (!can_place)
+ usr << "\blue You can't run \the [src] through that!"
+ return
cur = start
var/tapetest = 0
diff --git a/code/WorkInProgress/Ported/head.dm b/code/WorkInProgress/Ported/sql.dm
similarity index 55%
rename from code/WorkInProgress/Ported/head.dm
rename to code/WorkInProgress/Ported/sql.dm
index d1cac9bc30d..9e0cad90ad5 100644
--- a/code/WorkInProgress/Ported/head.dm
+++ b/code/WorkInProgress/Ported/sql.dm
@@ -1,48 +1,65 @@
-//This looks to be the traitor win tracker code. Gonna comment it out as we lack it currently.
-/*
+//This looks to be the traitor win tracker code.
client/proc/add_roundsjoined()
if(!makejson)
return
+ var/DBConnection/dbcon = new()
+
+ dbcon.Connect("dbi:mysql:[sqldb]:[sqladdress]:[sqlport]","[sqllogin]","[sqlpass]")
+ if(!dbcon.IsConnected()) return
+
var/DBQuery/cquery = dbcon.NewQuery("INSERT INTO `roundsjoined` (`ckey`) VALUES ('[ckey(src.key)]')")
if(!cquery.Execute()) message_admins(cquery.ErrorMsg())
+
client/proc/add_roundssurvived()
if(!makejson)
return
+ var/DBConnection/dbcon = new()
+
+ dbcon.Connect("dbi:mysql:[sqldb]:[sqladdress]:[sqlport]","[sqllogin]","[sqlpass]")
+ if(!dbcon.IsConnected()) return
+
var/DBQuery/cquery = dbcon.NewQuery("INSERT INTO `roundsurvived` (`ckey`) VALUES ('[ckey(src.key)]')")
if(!cquery.Execute()) message_admins(cquery.ErrorMsg())
-client/proc/onDeath(var/mob/A = src.mob)
+
+client/proc/onDeath()
if(!makejson)
return
roundinfo.deaths++
- if(!ismob(A))
+ if(!ismob(mob))
return
- var/ckey = src.ckey
- var/area
+ var/area = get_area(mob)
var/attacker
var/tod = time2text(world.realtime)
var/health
var/last
- if(isturf(A.loc))
- area = A.loc:loc:name
- else
- area = A.loc:name
- if(ishuman(A.lastattacker))
- attacker = A.lastattacker:name
+ if(ishuman(mob.lastattacker))
+ attacker = mob.lastattacker:name
else
attacker = "None"
- health = "Oxy:[A.oxyloss]Brute:[A.bruteloss]Burn:[A.fireloss]Toxins:[A.toxloss]"
- if(A.logs.len >= 1)
- last = A.logs[A.logs.len]
+ health = "Oxy:[mob.oxyloss]Brute:[mob.bruteloss]Burn:[mob.fireloss]Toxins:[mob.toxloss]Brain:[mob.brainloss]"
+ if(mob.attack_log.len >= 1)
+ last = mob.attack_log[mob.attack_log.len]
else
last = "None"
+
+ var/DBConnection/dbcon = new()
+
+ dbcon.Connect("dbi:mysql:[sqldb]:[sqladdress]:[sqlport]","[sqllogin]","[sqlpass]")
+ if(!dbcon.IsConnected()) return
+
var/DBQuery/cquery = dbcon.NewQuery("INSERT INTO `deathlog` (`ckey`,`location`,`lastattacker`,`ToD`,`health`,`lasthit`) VALUES ('[ckey]',[dbcon.Quote(area)],[dbcon.Quote(attacker)],'[tod]','[health]',[dbcon.Quote(last)])")
if(!cquery.Execute()) message_admins(cquery.ErrorMsg())
+
client/proc/onBought(names)
if(!makejson) return
if(!names) return
+ var/DBConnection/dbcon = new()
+
+ dbcon.Connect("dbi:mysql:[sqldb]:[sqladdress]:[sqlport]","[sqllogin]","[sqlpass]")
+ if(!dbcon.IsConnected()) return
+
var/DBQuery/cquery = dbcon.NewQuery("INSERT INTO `traitorbuy` (`type`) VALUES ([dbcon.Quote(names)])")
if(!cquery.Execute()) message_admins(cquery.ErrorMsg())
-*/
datum/roundinfo
var/core = 0
diff --git a/code/WorkInProgress/SkyMarshal/portalathe.dm b/code/WorkInProgress/SkyMarshal/portalathe.dm
index bbd27df919d..9fdc0e757ef 100644
--- a/code/WorkInProgress/SkyMarshal/portalathe.dm
+++ b/code/WorkInProgress/SkyMarshal/portalathe.dm
@@ -1,8 +1,9 @@
//May expand later, but right now it just repairs lights.
/obj/item/device/portalathe
- name = "\improper Portable Autolathe"
- desc = "It blinks and has an antenna on it. It must be advanced."
- icon_state = "t-ray0"
+ name = "portable autolathe"
+ desc = "A device which can repair broken lights instantly. Must be advanced."
+ icon = 'janitor.dmi'
+ icon_state = "portalathe"
afterattack(var/atom/target, mob/user as mob)
if(!target || !user)
@@ -16,5 +17,5 @@
L.status = 0
L.on = 1
L.update()
- user.visible_message("[user] repairs \the [target] on the spot with their [src]!","You repair the lightbulb!")
+ user.visible_message("[user] repairs \the [target] on the spot with their [src]!","You repair the lightbulb!","You hear a soft whiiir-pop noise over the sound of flexing glass, followed by the soft hum of an activated [target].")
return
\ No newline at end of file
diff --git a/code/WorkInProgress/SkyMarshal/traitoritems.dm b/code/WorkInProgress/SkyMarshal/traitoritems.dm
index 19e2d2e9a0d..a2b24f4f5ce 100644
--- a/code/WorkInProgress/SkyMarshal/traitoritems.dm
+++ b/code/WorkInProgress/SkyMarshal/traitoritems.dm
@@ -1,3 +1,5 @@
+//This file was auto-corrected by findeclaration.exe on 29/05/2012 15:03:06
+
/obj/item/weapon/stamperaser
name = "eraser"
desc = "It looks like some kind of eraser."
@@ -15,10 +17,9 @@
var/on = 0
flags = FPRINT|TABLEPASS
w_class = 1
- var
- list/obj/item/device/radio/Old = list()
- list/obj/item/device/radio/Curr = list()
- time_remaining = 5
+ var/list/obj/item/device/radio/Old = list()
+ var/list/obj/item/device/radio/Curr = list()
+ var/time_remaining = 5
/obj/item/device/jammer/New()
..()
@@ -72,4 +73,4 @@
icon_state = "t-ray0"
sleep(2)
- */
\ No newline at end of file
+ */
diff --git a/code/WorkInProgress/SkyMarshal/wardrobes.dm b/code/WorkInProgress/SkyMarshal/wardrobes.dm
index 56b7f4d36fb..f8fa93cef3f 100755
--- a/code/WorkInProgress/SkyMarshal/wardrobes.dm
+++ b/code/WorkInProgress/SkyMarshal/wardrobes.dm
@@ -1,3 +1,5 @@
+//This file was auto-corrected by findeclaration.exe on 29/05/2012 15:03:06
+
/obj/item/wardrobe
name = "\improper Wardrobe"
desc = "A standard-issue bag for clothing and equipment. Usually comes sealed, stocked with everything you need for a particular job."
@@ -6,9 +8,8 @@
item_state = "wardrobe"
w_class = 4
layer = 2.99
- var
- descriptor = "various clothing"
- seal_torn = 0
+ var/descriptor = "various clothing"
+ var/seal_torn = 0
attack_self(mob/user)
if(!contents.len)
diff --git a/code/WorkInProgress/animusstation/atm.dm b/code/WorkInProgress/animusstation/atm.dm
index cbb61e6e79c..71235421cec 100644
--- a/code/WorkInProgress/animusstation/atm.dm
+++ b/code/WorkInProgress/animusstation/atm.dm
@@ -1,3 +1,5 @@
+//This file was auto-corrected by findeclaration.exe on 29/05/2012 15:03:06
+
/*
TODO:
@@ -15,15 +17,14 @@ log transactions
anchored = 1
use_power = 1
idle_power_usage = 10
- var
- obj/item/weapon/card/id/card
- obj/item/weapon/spacecash/cashes = list()
- inserted = 0
- accepted = 0
- pincode = 0
+ var/obj/item/weapon/card/id/card
+ var/obj/item/weapon/money/cashes = list()
+ var/inserted = 0
+ var/accepted = 0
+ var/pincode = 0
attackby(var/obj/A, var/mob/user)
- if(istype(A,/obj/item/weapon/spacecash))
+ if(istype(A,/obj/item/weapon/money))
cashes += A
user.drop_item()
A.loc = src
@@ -100,21 +101,21 @@ log transactions
card.money -= amount
switch(amount)
if(1)
- new /obj/item/weapon/spacecash(loc)
+ new /obj/item/weapon/money(loc)
if(10)
- new /obj/item/weapon/spacecash/c10(loc)
+ new /obj/item/weapon/money/c10(loc)
if(20)
- new /obj/item/weapon/spacecash/c20(loc)
+ new /obj/item/weapon/money/c20(loc)
if(50)
- new /obj/item/weapon/spacecash/c50(loc)
+ new /obj/item/weapon/money/c50(loc)
if(100)
- new /obj/item/weapon/spacecash/c100(loc)
+ new /obj/item/weapon/money/c100(loc)
if(200)
- new /obj/item/weapon/spacecash/c200(loc)
+ new /obj/item/weapon/money/c200(loc)
if(500)
- new /obj/item/weapon/spacecash/c500(loc)
+ new /obj/item/weapon/money/c500(loc)
if(1000)
- new /obj/item/weapon/spacecash/c1000(loc)
+ new /obj/item/weapon/money/c1000(loc)
else
user << "\red Error: Insufficient funds."
return
@@ -143,7 +144,7 @@ log transactions
if (usr.machine==src && get_dist(src, usr) <= 1 || istype(usr, /mob/living/silicon/ai))
if(href_list["eca"])
if(accepted)
- for(var/obj/item/weapon/spacecash/M in cashes)
+ for(var/obj/item/weapon/money/M in cashes)
M.loc = loc
inserted = 0
if(!cashes)
@@ -154,6 +155,8 @@ log transactions
if(accepted)
card.money += inserted
inserted = 0
+ if(cashes)
+ cashes = null
if(href_list["lock"])
card = null
accepted = 0
diff --git a/code/WorkInProgress/virus2/antibodies.dm b/code/WorkInProgress/virus2/antibodies.dm
index 31de7c02ba9..5c12beb9482 100644
--- a/code/WorkInProgress/virus2/antibodies.dm
+++ b/code/WorkInProgress/virus2/antibodies.dm
@@ -1,3 +1,5 @@
+//This file was auto-corrected by findeclaration.exe on 29/05/2012 15:03:06
+
// pure concentrated antibodies
datum/reagent/antibodies
data = new/list("antibodies"=0)
@@ -16,20 +18,19 @@ datum/reagent/antibodies
return
// reserving some numbers for later special antigens
-var/global/const
- ANTIGEN_A = 1
- ANTIGEN_B = 2
- ANTIGEN_RH = 4
- ANTIGEN_Q = 8
- ANTIGEN_U = 16
- ANTIGEN_V = 32
- ANTIGEN_X = 64
- ANTIGEN_Y = 128
- ANTIGEN_Z = 256
- ANTIGEN_M = 512
- ANTIGEN_N = 1024
- ANTIGEN_P = 2048
- ANTIGEN_O = 4096
+var/global/const/ANTIGEN_A = 1
+var/global/const/ANTIGEN_B = 2
+var/global/const/ANTIGEN_RH = 4
+var/global/const/ANTIGEN_Q = 8
+var/global/const/ANTIGEN_U = 16
+var/global/const/ANTIGEN_V = 32
+var/global/const/ANTIGEN_X = 64
+var/global/const/ANTIGEN_Y = 128
+var/global/const/ANTIGEN_Z = 256
+var/global/const/ANTIGEN_M = 512
+var/global/const/ANTIGEN_N = 1024
+var/global/const/ANTIGEN_P = 2048
+var/global/const/ANTIGEN_O = 4096
var/global/list/ANTIGENS = list("[ANTIGEN_A]" = "A", "[ANTIGEN_B]" = "B", "[ANTIGEN_RH]" = "RH", "[ANTIGEN_Q]" = "Q",
"[ANTIGEN_U]" = "U", "[ANTIGEN_V]" = "V", "[ANTIGEN_Z]" = "Z", "[ANTIGEN_M]" = "M",
@@ -53,4 +54,4 @@ var/global/list/ANTIGENS = list("[ANTIGEN_A]" = "A", "[ANTIGEN_B]" = "B", "[ANTI
// iterate over the list of antigens and see what matches
var/code = ""
for(var/V in ANTIGENS) if(text2num(V) & M.antibodies) code += ANTIGENS[V]
- user << text("\blue [src] The antibody scanner displays a cryptic set of data: [code]")
\ No newline at end of file
+ user << text("\blue [src] The antibody scanner displays a cryptic set of data: [code]")
diff --git a/code/WorkInProgress/virus2/base.dm b/code/WorkInProgress/virus2/base.dm
index 4bd30bf08ca..01cadec2aa3 100644
--- a/code/WorkInProgress/virus2/base.dm
+++ b/code/WorkInProgress/virus2/base.dm
@@ -47,10 +47,6 @@ proc/airborne_can_reach(turf/source, turf/target)
return
if(!disease)
return
- //immunity
- /*for(var/iii = 1, iii <= M.immunevirus2.len, iii++)
- if(disease.issame(M.immunevirus2[iii]))
- return*/
// if one of the antibodies in the mob's body matches one of the disease's antigens, don't infect
if(M.antibodies & disease.antigen != 0) return
@@ -266,7 +262,6 @@ proc/airborne_can_reach(turf/source, turf/target)
proc/getcopy()
-// world << "getting copy"
var/datum/disease2/disease/disease = new /datum/disease2/disease
disease.infectionchance = infectionchance
disease.spreadtype = spreadtype
@@ -274,7 +269,6 @@ proc/airborne_can_reach(turf/source, turf/target)
disease.antigen = antigen
disease.uniqueID = uniqueID
for(var/datum/disease2/effectholder/holder in effects)
- // world << "adding effects"
var/datum/disease2/effectholder/newholder = new /datum/disease2/effectholder
newholder.effect = new holder.effect.type
newholder.chance = holder.chance
@@ -283,8 +277,6 @@ proc/airborne_can_reach(turf/source, turf/target)
newholder.happensonce = holder.happensonce
newholder.stage = holder.stage
disease.effects += newholder
- // world << "[newholder.effect.name]"
- // world << "[disease]"
return disease
proc/spread_airborne(var/mob/living/carbon/mob)
@@ -298,9 +290,17 @@ proc/airborne_can_reach(turf/source, turf/target)
var/name = "Blanking effect"
var/stage = 4
var/maxm = 1
+ var/happensalways = 0
proc/activate(var/mob/living/carbon/mob,var/multiplier)
proc/deactivate(var/mob/living/carbon/mob)
+// ================================
+// ======= DISEASE SYMPTOMS =======
+// ================================
+
+// Special diseases
+// --------------------------------
+
/datum/disease2/effect/alien
name = "Unidentified Foreign Body"
stage = 4
@@ -317,11 +317,68 @@ proc/airborne_can_reach(turf/source, turf/target)
mob:gib()
del D
-/datum/disease2/effect/greater/gibbingtons
- name = "Gibbingtons Syndrome"
- stage = 4
+// Greater Diseases, Stage 1
+// --------------------------------
+
+
+/datum/disease2/effect/greater/gunck
+ name = "Flemmingtons"
+ stage = 1
activate(var/mob/living/carbon/mob,var/multiplier)
- mob.gib()
+ mob << "\red Mucous runs down the back of your throat."
+
+
+// Greater Diseases, Stage 2
+// --------------------------------
+
+/datum/disease2/effect/greater/cough
+ name = "Anima Syndrome"
+ stage = 2
+ activate(var/mob/living/carbon/mob,var/multiplier)
+ mob.say("*cough")
+ if(mob.virus2) mob.virus2.spread_airborne(mob)
+ if(mob.virus2) mob.virus2.spread_airborne(mob)
+ if(prob(2))
+ var/obj/effect/decal/cleanable/mucus/this = new(mob.loc)
+ this.virus2 = mob.virus2
+
+/datum/disease2/effect/greater/vomit
+ name = "Bad Stomach Syndrome"
+ stage = 2
+ activate(var/mob/living/carbon/mob,var/multiplier)
+ if(prob(20) && mob.nutrition > 200)
+ mob.vomit()
+
+
+/datum/disease2/effect/greater/sneeze
+ name = "Coldingtons Effect"
+ stage = 2
+ activate(var/mob/living/carbon/mob,var/multiplier)
+ mob.say("*sneeze")
+ if(mob.virus2) mob.virus2.spread_airborne(mob)
+ if(mob.virus2) mob.virus2.spread_airborne(mob)
+ if(prob(5))
+ var/obj/effect/decal/cleanable/mucus/this = new(mob.loc)
+ this.anchored = 0
+ step(this, mob.dir)
+ this.anchored = 1
+ this.virus2 = mob.virus2
+
+// Greater Diseases, Stage 3
+// --------------------------------
+
+/datum/disease2/effect/greater/sleepy
+ name = "Resting syndrome"
+ stage = 3
+ activate(var/mob/living/carbon/mob,var/multiplier)
+ mob.say("*collapse")
+
+/datum/disease2/effect/greater/mind
+ name = "Lazy mind syndrome"
+ stage = 3
+ activate(var/mob/living/carbon/mob,var/multiplier)
+ mob.setBrainLoss(50)
+
/datum/disease2/effect/greater/hallucinations
name = "Hallucinational Syndrome"
@@ -329,12 +386,6 @@ proc/airborne_can_reach(turf/source, turf/target)
activate(var/mob/living/carbon/mob,var/multiplier)
mob.hallucination += 25
-/datum/disease2/effect/greater/radian
- name = "Radian's syndrome"
- stage = 4
- maxm = 2
- activate(var/mob/living/carbon/mob,var/multiplier)
- mob.radiation += (20*multiplier)
/datum/disease2/effect/greater/toxins
name = "Hyperacid Syndrome"
@@ -356,6 +407,38 @@ proc/airborne_can_reach(turf/source, turf/target)
activate(var/mob/living/carbon/mob,var/multiplier)
shake_camera(mob,5*multiplier)
+
+/datum/disease2/effect/greater/telepathic
+ name = "Telepathy Syndrome"
+ stage = 3
+ activate(var/mob/living/carbon/mob,var/multiplier)
+ mob.mutations |= 512
+
+// Greater Diseases, Stage 4
+// --------------------------------
+
+/datum/disease2/effect/greater/gibbingtons
+ name = "Gibbingtons Syndrome"
+ stage = 4
+ activate(var/mob/living/carbon/mob,var/multiplier)
+ mob.gib()
+
+
+/datum/disease2/effect/greater/blood_fountain
+ name = "Blood Fountain Syndrome"
+ stage = 4
+ activate(var/mob/living/carbon/mob,var/multiplier)
+ if(prob(20))
+ mob.visible_message("\red You see a fountain of blood erupt from [mob.name].","\red Something wet is leaking from you.","You hear a loud splash.")
+ mob.drip(50)
+
+/datum/disease2/effect/greater/radian
+ name = "Radian's syndrome"
+ stage = 4
+ maxm = 2
+ activate(var/mob/living/carbon/mob,var/multiplier)
+ mob.radiation += (20*multiplier)
+
/datum/disease2/effect/greater/fever
name = "Fever syndrome"
stage = 4
@@ -363,6 +446,7 @@ proc/airborne_can_reach(turf/source, turf/target)
activate(var/mob/living/carbon/mob,var/multiplier)
mob.adjustFireLoss(10 * multiplier)
+
/datum/disease2/effect/greater/weak_bones
name = "Bone Density Syndrome"
stage = 4
@@ -371,7 +455,7 @@ proc/airborne_can_reach(turf/source, turf/target)
var/name = pick(mob.organs)
var/datum/organ/external/organ = mob.organs[name]
- if(!organ.broken)
+ if(!organ.broken && !organ.robot)
mob.adjustBruteLoss(10)
mob.visible_message("\red You hear a loud cracking sound coming from [mob.name].","\red Something feels like it shattered in your [organ.display_name]!","You hear a sickening crack.")
mob.emote("scream")
@@ -379,17 +463,6 @@ proc/airborne_can_reach(turf/source, turf/target)
organ.wound = pick("broken","fracture","hairline fracture") //Randomise in future. Edit: Randomized. --SkyMarshal
organ.perma_injury = 10
-/datum/disease2/effect/invisible
- name = "Waiting Syndrome"
- stage = 1
- activate(var/mob/living/carbon/mob,var/multiplier)
- return
-
-/datum/disease2/effect/greater/telepathic
- name = "Telepathy Syndrome"
- stage = 3
- activate(var/mob/living/carbon/mob,var/multiplier)
- mob.mutations |= 512
/datum/disease2/effect/greater/monkey
name = "Monkism syndrome"
@@ -399,37 +472,6 @@ proc/airborne_can_reach(turf/source, turf/target)
var/mob/living/carbon/human/h = mob
h.monkeyize()
-/datum/disease2/effect/greater/sneeze
- name = "Coldingtons Effect"
- stage = 2
- activate(var/mob/living/carbon/mob,var/multiplier)
- mob.say("*sneeze")
- if(mob.virus2) mob.virus2.spread_airborne(mob)
- if(mob.virus2) mob.virus2.spread_airborne(mob)
- if(prob(5))
- var/obj/effect/decal/cleanable/mucus/this = new(mob.loc)
- this.anchored = 0
- step(this, mob.dir)
- this.anchored = 1
- this.virus2 = mob.virus2
-
-
-/datum/disease2/effect/greater/cough
- name = "Anima Syndrome"
- stage = 2
- activate(var/mob/living/carbon/mob,var/multiplier)
- mob.say("*cough")
- if(mob.virus2) mob.virus2.spread_airborne(mob)
- if(mob.virus2) mob.virus2.spread_airborne(mob)
- if(prob(2))
- var/obj/effect/decal/cleanable/mucus/this = new(mob.loc)
- this.virus2 = mob.virus2
-
-/datum/disease2/effect/greater/gunck
- name = "Flemmingtons"
- stage = 1
- activate(var/mob/living/carbon/mob,var/multiplier)
- mob << "\red Mucous runs down the back of your throat."
/datum/disease2/effect/greater/killertoxins
name = "Toxification syndrome"
@@ -437,36 +479,9 @@ proc/airborne_can_reach(turf/source, turf/target)
activate(var/mob/living/carbon/mob,var/multiplier)
mob.adjustToxLoss(15)
-/datum/disease2/effect/greater/sleepy
- name = "Resting syndrome"
- stage = 3
- activate(var/mob/living/carbon/mob,var/multiplier)
- mob.say("*collapse")
-/datum/disease2/effect/greater/mind
- name = "Lazy mind syndrome"
- stage = 3
- activate(var/mob/living/carbon/mob,var/multiplier)
- mob.setBrainLoss(50)
-
-// lesser syndromes, partly just copypastes
-/datum/disease2/effect/lesser/hallucinations
- name = "Hallucinational Syndrome"
- stage = 3
- activate(var/mob/living/carbon/mob,var/multiplier)
- mob.hallucination += 5
-
-/datum/disease2/effect/lesser/mind
- name = "Lazy mind syndrome"
- stage = 3
- activate(var/mob/living/carbon/mob,var/multiplier)
- mob.setBrainLoss(20)
-
-/datum/disease2/effect/lesser/deaf
- name = "Hard of hearing syndrome"
- stage = 3
- activate(var/mob/living/carbon/mob,var/multiplier)
- mob.ear_deaf = 5
+// Lesser Diseases, Stage 1
+// --------------------------------
/datum/disease2/effect/lesser/gunck
name = "Flemmingtons"
@@ -474,13 +489,30 @@ proc/airborne_can_reach(turf/source, turf/target)
activate(var/mob/living/carbon/mob,var/multiplier)
mob << "\red Mucous runs down the back of your throat."
-/datum/disease2/effect/lesser/radian
- name = "Radian's syndrome"
- stage = 4
- maxm = 3
+/datum/disease2/effect/lesser/fridge
+ name = "Refridgerator Syndrome"
+ stage = 1
activate(var/mob/living/carbon/mob,var/multiplier)
- mob.radiation += 1
+ if(prob(10)) mob << "\blue You feel extremely cold."
+
+/datum/disease2/effect/lesser/pale
+ name = "Ghost Effect"
+ stage = 1
+ activate(var/mob/living/carbon/mob,var/multiplier)
+ mob << "\blue If you had a mirror, your reflection would probably look very pale.."
+
+/datum/disease2/effect/lesser/hoarse
+ name = "Hoarse Throat"
+ stage = 1
+ happensalways = 1 // the mob will have a permanently sore throat
+ activate(var/mob/living/carbon/mob,var/multiplier)
+ mob.disease_symptoms |= DISEASE_HOARSE
+ if(prob(3)) mob << "\blue Your throat feels very sore.."
+
+
+// Lesser Diseases, Stage 2
+// --------------------------------
/datum/disease2/effect/lesser/sneeze
name = "Coldingtons Effect"
stage = 2
@@ -506,19 +538,49 @@ proc/airborne_can_reach(turf/source, turf/target)
var/obj/effect/decal/cleanable/mucus/this = new(mob.loc)
this.virus2 = mob.virus2
-/*/datum/disease2/effect/lesser/arm
- name = "Disarming Syndrome"
- stage = 4
+
+/datum/disease2/effect/lesser/nosebleed
+ name = "Nosebleed Effect"
+ stage = 2
activate(var/mob/living/carbon/mob,var/multiplier)
- var/datum/organ/external/org = mob.organs["r_arm"]
- org.take_damage(3,0,0,0)
- mob << "\red You feel a sting in your right arm."*/
+ if(prob(30))
+ mob.drip(1)
+
+// Lesser Diseases, Stage 3
+// --------------------------------
+
+/datum/disease2/effect/lesser/vomit
+ name = "Bad Stomach Syndrome"
+ stage = 3
+ activate(var/mob/living/carbon/mob,var/multiplier)
+ if(prob(5) && mob.nutrition > 200)
+ mob.vomit()
+
+
+// lesser syndromes, partly just copypastes
+/datum/disease2/effect/lesser/hallucinations
+ name = "Hallucinational Syndrome"
+ stage = 3
+ activate(var/mob/living/carbon/mob,var/multiplier)
+ mob.hallucination += 5
+
+/datum/disease2/effect/lesser/mind
+ name = "Lazy mind syndrome"
+ stage = 3
+ activate(var/mob/living/carbon/mob,var/multiplier)
+ mob.setBrainLoss(20)
+
+/datum/disease2/effect/lesser/deaf
+ name = "Hard of hearing syndrome"
+ stage = 3
+ activate(var/mob/living/carbon/mob,var/multiplier)
+ mob.ear_deaf = 5
/datum/disease2/effect/lesser/hungry
name = "Appetiser Effect"
- stage = 3
+ stage = 2
activate(var/mob/living/carbon/mob,var/multiplier)
- mob.nutrition = max(0, mob.nutrition - 3)
+ mob.nutrition = max(0, mob.nutrition - 1)
/datum/disease2/effect/lesser/groan
name = "Groaning Syndrome"
@@ -526,24 +588,12 @@ proc/airborne_can_reach(turf/source, turf/target)
activate(var/mob/living/carbon/mob,var/multiplier)
mob.say("*groan")
-/datum/disease2/effect/lesser/fridge
- name = "Refridgerator Syndrome"
- stage = 1
- activate(var/mob/living/carbon/mob,var/multiplier)
- mob.say("*shiver")
-
/datum/disease2/effect/lesser/twitch
name = "Twitcher"
stage = 3
activate(var/mob/living/carbon/mob,var/multiplier)
- mob.say("*twitch")
-
-/datum/disease2/effect/lesser/pale
- name = "Ghost Effect"
- stage = 1
- activate(var/mob/living/carbon/mob,var/multiplier)
- if(prob(10))
- mob.emote("me",1,"looks very pale.")
+ if(prob(5)) mob.say("*twitch")
+ if(prob(20)) mob << "\blue Your muscles feel twitchy.."
/datum/disease2/effect/lesser/stumble
name = "Poor Balance Syndrome"
@@ -556,11 +606,32 @@ proc/airborne_can_reach(turf/source, turf/target)
step(mob, pick(cardinal))
mob.emote("me",1,"stumbles over their own feet.")
-/datum/disease2/effect/lesser/hoarse
- name = "Hoarse Throat"
+
+// Lesser Diseases, Stage 4
+// --------------------------------
+
+
+/datum/disease2/effect/lesser/radian
+ name = "Radian's syndrome"
+ stage = 4
+ maxm = 3
+ activate(var/mob/living/carbon/mob,var/multiplier)
+ mob.radiation += 1
+
+// ============
+// END SYMPTOMS
+// ============
+
+
+
+
+
+/datum/disease2/effect/invisible
+ name = "Waiting Syndrome"
stage = 1
activate(var/mob/living/carbon/mob,var/multiplier)
- mob.disease_symptoms |= DISEASE_HOARSE
+ return
+
var/global/const/DISEASE_HOARSE = 2
var/global/const/DISEASE_WHISPER = 4
@@ -579,7 +650,7 @@ var/global/const/DISEASE_WHISPER = 4
var/stage = 0
proc/runeffect(var/mob/living/carbon/human/mob,var/stage)
- if(happensonce > -1 && effect.stage <= stage && prob(chance))
+ if(effect.stage <= stage) if(effect.happensalways || (happensonce > -1 && prob(chance)))
effect.activate(mob)
if(happensonce == 1)
happensonce = -1
diff --git a/code/ZAS/Airflow.dm b/code/ZAS/Airflow.dm
index a3cb01eb7ee..bd3109f4a05 100644
--- a/code/ZAS/Airflow.dm
+++ b/code/ZAS/Airflow.dm
@@ -12,31 +12,16 @@ atom/movable/airflow_speed
The speed (1-15) at which a flying object is traveling to airflow_dest. Decays over time.
-CALLABLE PROCS:
-
-AirflowRepel(turf/T, n, per)
- Causes objects to fly away from a point within a single zone.
- Called manually by air releasers. T is the location of the expanding gas.
- n is the pressure released. per indicates that n is a percent value if nonzero.
- RETURNS: Null
-
-AirflowAttract(turf/T, n, per)
- Causes objects to fly to a point within a single zone.
- Called manually by air consumers. T is the location of the attractor.
- n is the pressure consumed. per indicates that n is a percent value if nonzero.
- RETURNS: Null
-
-
OVERLOADABLE PROCS:
mob/airflow_stun()
Contains checks for and results of being stunned by airflow.
- Called when airflow quantities exceed AF_HUMAN_STUN_THRESHOLD.
+ Called when airflow quantities exceed airflow_medium_pressure.
RETURNS: Null
atom/movable/check_airflow_movable(n)
Contains checks for moving any object due to airflow.
- n is the percent of 1 Atmosphere that is flowing.
+ n is the pressure that is flowing.
RETURNS: 1 if the object moves under the air conditions, 0 if it stays put.
atom/movable/airflow_hit(atom/A)
@@ -47,10 +32,9 @@ atom/movable/airflow_hit(atom/A)
AUTOMATIC PROCS:
-Airflow(zone/A, zone/B, n)
+Airflow(zone/A, zone/B)
Causes objects to fly along a pressure gradient.
Called by zone updates. A and B are two connected zones.
- n is the pressure difference between them.
AirflowSpace(zone/A)
Causes objects to fly into space.
@@ -64,115 +48,17 @@ atom/movable/RepelAirflowDest(n)
*/
-var/tick_multiplier = 2
vs_control/var
- zone_update_delay = 10
- zone_update_delay_NAME = "Zone Update Delay"
- zone_update_delay_DESC = "The delay in ticks between updates of zones. Increase if lag is bad seemingly because of air."
+ airflow_lightest_pressure = 15
+ airflow_light_pressure = 30
+ airflow_medium_pressure = 45
+ airflow_heavy_pressure = 60
+ airflow_heaviest_pressure = 100
- zone_share_percent = 2
- zone_share_percent_NAME = "Zone Connection Transfer %"
- zone_share_percent_DESC = "Percent of gas per connected tile that is shared between zones."
-
- //Used in /mob/carbon/human/life
- OXYGEN_LOSS = 2
- OXYGEN_LOSS_NAME = "Damage - Oxygen Loss"
- OXYGEN_LOSS_DESC = "A multiplier for damage due to lack of air, CO2 poisoning, and vacuum. Does not affect oxyloss\
- from being incapacitated or dying."
- TEMP_DMG = 2
- TEMP_DMG_NAME = "Damage - Temperature"
- TEMP_DMG_DESC = "A multiplier for damage due to body temperature irregularities."
- BURN_DMG = 6
- BURN_DMG_NAME = "Damage - Fire"
- BURN_DMG_DESC = "A multiplier for damage due to direct fire exposure."
-
- AF_TINY_MOVEMENT_THRESHOLD = 50 //% difference to move tiny items.
- AF_TINY_MOVEMENT_THRESHOLD_NAME = "Airflow - Tiny Movement Threshold %"
- AF_TINY_MOVEMENT_THRESHOLD_DESC = "Percent of 1 Atm. at which items with the tiny weight class will move."
- AF_SMALL_MOVEMENT_THRESHOLD = 70 //% difference to move small items.
- AF_SMALL_MOVEMENT_THRESHOLD_NAME = "Airflow - Small Movement Threshold %"
- AF_SMALL_MOVEMENT_THRESHOLD_DESC = "Percent of 1 Atm. at which items with the small weight class will move."
- AF_NORMAL_MOVEMENT_THRESHOLD = 90 //% difference to move normal items.
- AF_NORMAL_MOVEMENT_THRESHOLD_NAME = "Airflow - Normal Movement Threshold %"
- AF_NORMAL_MOVEMENT_THRESHOLD_DESC = "Percent of 1 Atm. at which items with the normal weight class will move."
- AF_LARGE_MOVEMENT_THRESHOLD = 100 //% difference to move large and huge items.
- AF_LARGE_MOVEMENT_THRESHOLD_NAME = "Airflow - Large Movement Threshold %"
- AF_LARGE_MOVEMENT_THRESHOLD_DESC = "Percent of 1 Atm. at which items with the large or huge weight class will move."
- AF_DENSE_MOVEMENT_THRESHOLD = 120 //% difference to move dense crap and mobs.
- AF_DENSE_MOVEMENT_THRESHOLD_NAME = "Airflow - Dense Movement Threshold %"
- AF_DENSE_MOVEMENT_THRESHOLD_DESC = "Percent of 1 Atm. at which dense objects (canisters, etc.) will be shifted by airflow."
- AF_MOB_MOVEMENT_THRESHOLD = 175
- AF_MOB_MOVEMENT_THRESHOLD_NAME = "Airflow - Human Movement Threshold %"
- AF_MOB_MOVEMENT_THRESHOLD_DESC = "Percent of 1 Atm. at which mobs will be shifted by airflow."
-
- AF_HUMAN_STUN_THRESHOLD = 130
- AF_HUMAN_STUN_THRESHOLD_NAME = "Airflow - Human Stun Threshold %"
- AF_HUMAN_STUN_THRESHOLD_DESC = "Percent of 1 Atm. at which living things are stunned or knocked over."
-
- AF_PERCENT_OF = ONE_ATMOSPHERE
- AF_PERCENT_OF_NAME = "Airflow - 100% Pressure"
- AF_PERCENT_OF_DESC = "Normally set to 1 Atm. in kPa, this indicates what pressure is considered 100% by the system."
-
- AF_SPEED_MULTIPLIER = 4 //airspeed per movement threshold value crossed.
- AF_SPEED_MULTIPLIER_NAME = "Airflow - Speed Increase per 10%"
- AF_SPEED_MULTIPLIER_DESC = "Velocity increase of shifted items per 10% of airflow."
- AF_DAMAGE_MULTIPLIER = 5 //Amount of damage applied per airflow_speed.
- AF_DAMAGE_MULTIPLIER_NAME = "Airflow - Damage Per Velocity"
- AF_DAMAGE_MULTIPLIER_DESC = "Amount of damage applied per unit of speed (1-15 units) at which mobs are thrown."
- AF_STUN_MULTIPLIER = 1.5 //Seconds of stun applied per airflow_speed.
- AF_STUN_MULTIPLIER_NAME = "Airflow - Stun Per Velocity"
- AF_STUN_MULTIPLIER_DESC = "Amount of stun effect applied per unit of speed (1-15 units) at which mobs are thrown."
- AF_SPEED_DECAY = 0.5 //Amount that flow speed will decay with time.
- AF_SPEED_DECAY_NAME = "Airflow - Velocity Lost per Tick"
- AF_SPEED_DECAY_DESC = "Amount of airflow speed lost per tick on a moving object."
- AF_SPACE_MULTIPLIER = 2 //Increasing this will make space connections more DRAMATIC!
- AF_SPACE_MULTIPLIER_NAME = "Airflow - Space Airflow Multiplier"
- AF_SPACE_MULTIPLIER_DESC = "Increasing this multiplier will cause more powerful airflow to space."
- AF_CANISTER_MULTIPLIER = 0.25
- AF_CANISTER_MULTIPLIER_NAME = "Airflow - Canister Airflow Multiplier"
- AF_CANISTER_MULTIPLIER_DESC = "Increasing this multiplier will cause more powerful airflow from single-tile sources like canisters."
-
-mob/proc
- Change_Airflow_Constants()
- set category = "Debug"
-
- var/choice = input("Which constant will you modify?","Change Airflow Constants")\
- as null|anything in list("Movement Threshold","Speed Multiplier","Damage Multiplier","Stun Multiplier","Speed Decay")
-
- var/n
-
- switch(choice)
- if("Movement Threshold")
- n = input("What will you change it to","Change Airflow Constants",vsc.AF_DENSE_MOVEMENT_THRESHOLD) as num
- n = max(1,n)
- vsc.AF_DENSE_MOVEMENT_THRESHOLD = n
- world.log << "vsc.AF_DENSE_MOVEMENT_THRESHOLD set to [n]."
- if("Speed Multiplier")
- n = input("What will you change it to","Change Airflow Constants",vsc.AF_SPEED_MULTIPLIER) as num
- n = max(1,n)
- vsc.AF_SPEED_MULTIPLIER = n
- world.log << "vsc.AF_SPEED_MULTIPLIER set to [n]."
- if("Damage Multiplier")
- n = input("What will you change it to","Change Airflow Constants",vsc.AF_DAMAGE_MULTIPLIER) as num
- vsc.AF_DAMAGE_MULTIPLIER = n
- world.log << "AF_DAMAGE_MULTIPLIER set to [n]."
- if("Stun Multiplier")
- n = input("What will you change it to","Change Airflow Constants",vsc.AF_STUN_MULTIPLIER) as num
- vsc.AF_STUN_MULTIPLIER = n
- world.log << "AF_STUN_MULTIPLIER set to [n]."
- if("Speed Decay")
- n = input("What will you change it to","Change Airflow Constants",vsc.AF_SPEED_DECAY) as num
- vsc.AF_SPEED_DECAY = n
- world.log << "AF_SPEED_DECAY set to [n]."
- if("Space Flow Multiplier")
- n = input("What will you change it to","Change Airflow Constants",vsc.AF_SPEED_DECAY) as num
- vsc.AF_SPEED_DECAY = n
- world.log << "AF_SPEED_DECAY set to [n]."
-
-
-//The main airflow code. Called by zone updates.
-//Zones A and B are air zones. n represents the amount of air moved.
+ airflow_damage = 0.3
+ airflow_stun = 0.15
+ airflow_speed_decay = 1
mob/proc/airflow_stun()
if(weakened <= 0) src << "\red The sudden rush of air knocks you over!"
@@ -197,8 +83,7 @@ atom/movable/proc/check_airflow_movable(n)
if(anchored && !ismob(src)) return 0
- if(!istype(src,/obj/item) && n < vsc.AF_DENSE_MOVEMENT_THRESHOLD) return 0
- if(ismob(src) && n < vsc.AF_MOB_MOVEMENT_THRESHOLD) return 0
+ if(!istype(src,/obj/item) && n < vsc.airflow_heavy_pressure) return 0
return 1
@@ -213,177 +98,125 @@ obj/item/check_airflow_movable(n)
. = ..()
switch(w_class)
if(2)
- if(n < vsc.AF_SMALL_MOVEMENT_THRESHOLD) return 0
+ if(n < vsc.airflow_lightest_pressure) return 0
if(3)
- if(n < vsc.AF_NORMAL_MOVEMENT_THRESHOLD) return 0
+ if(n < vsc.airflow_light_pressure) return 0
if(4,5)
- if(n < vsc.AF_LARGE_MOVEMENT_THRESHOLD) return 0
+ if(n < vsc.airflow_medium_pressure) return 0
-proc/Airflow(zone/A,zone/B,n)
+//The main airflow code. Called by zone updates.
+//Zones A and B are air zones. n represents the amount of air moved.
- //Now n is a percent of one atm.
- n = round((n/vsc.AF_PERCENT_OF)*100,0.1)
+proc/Airflow(zone/A,zone/B)
+
+ var/n = B.air.pressure - A.air.pressure
//Don't go any further if n is lower than the lowest value needed for airflow.
- if(abs(n) < vsc.AF_TINY_MOVEMENT_THRESHOLD) return
+ if(abs(n) < vsc.airflow_lightest_pressure) return
//These turfs are the midway point between A and B, and will be the destination point for thrown objects.
var/list/connected_turfs = A.connections[B]
//Get lists of things that can be thrown across the room for each zone.
- var/list/pplz = A.movables()
- var/list/otherpplz = B.movables()
+ var/list/pplz = A.movable_objects
+ var/list/otherpplz = B.movable_objects
for(var/atom/movable/M in pplz)
+ if(M.last_airflow > world.time - 150) continue
+
//Check for knocking people over
- if(ismob(M) && n > vsc.AF_HUMAN_STUN_THRESHOLD)
+ if(ismob(M) && n > vsc.airflow_medium_pressure)
if(M:nodamage) continue
M:airflow_stun()
if(M.check_airflow_movable(n))
//Check for things that are in range of the midpoint turfs.
- var/fail = 1
+ var/list/close_turfs = list()
for(var/turf/U in connected_turfs)
- if(M in range(U)) fail = 0
- if(fail) continue
+ if(M in range(U)) close_turfs += U
+ if(!close_turfs.len) continue
//If they're already being tossed, don't do it again.
if(!M.airflow_speed)
- M.airflow_dest = pick(connected_turfs) //Pick a random midpoint to fly towards.
+ M.airflow_dest = pick(close_turfs) //Pick a random midpoint to fly towards.
- spawn M.GotoAirflowDest(abs(n) * (vsc.AF_SPEED_MULTIPLIER/10))
- //Send the object flying at a speed determined by n and AF_SPEED_MULTIPLIER.
+ spawn M.GotoAirflowDest(abs(n)/5)
//Do it again for the stuff in the other zone, making it fly away.
for(var/atom/movable/M in otherpplz)
- if(ismob(M) && abs(n) > vsc.AF_HUMAN_STUN_THRESHOLD)
+ if(M.last_airflow > world.time - 150) continue
+
+ if(ismob(M) && abs(n) > vsc.airflow_medium_pressure)
if(M:nodamage) continue
M:airflow_stun()
if(M.check_airflow_movable(abs(n)))
- var/fail = 1
+ var/list/close_turfs = list()
for(var/turf/U in connected_turfs)
- if(M in range(U)) fail = 0
- if(fail) continue
+ if(M in range(U)) close_turfs += U
+ if(!close_turfs.len) continue
- if(M && !M.airflow_speed)
+ //If they're already being tossed, don't do it again.
+ if(!M.airflow_speed)
- M.airflow_dest = pick(connected_turfs)
+ M.airflow_dest = pick(close_turfs) //Pick a random midpoint to fly towards.
- spawn M.RepelAirflowDest(abs(n) * (vsc.AF_SPEED_MULTIPLIER/10))
+ spawn M.RepelAirflowDest(abs(n)/5)
proc/AirflowSpace(zone/A)
//The space version of the Airflow(A,B,n) proc.
- var/n = (A.air.oxygen + A.air.nitrogen + A.air.carbon_dioxide)*vsc.AF_SPACE_MULTIPLIER
- //Here, n is determined by the space multiplier constant and the zone's air.
+ var/n = A.air.pressure
+ //Here, n is determined by only the pressure in the room.
- n = round((n/vsc.AF_PERCENT_OF)*100,0.1)
-
- if(n < vsc.AF_TINY_MOVEMENT_THRESHOLD) return
+ if(n < vsc.airflow_lightest_pressure) return
var/list/connected_turfs = A.space_tiles //The midpoints are now all the space connections.
- var/list/pplz = A.movables() //We only need to worry about things in the zone, not things in space.
+ var/list/pplz = A.movable_objects //We only need to worry about things in the zone, not things in space.
for(var/atom/movable/M in pplz)
- if(ismob(M) && n > vsc.AF_HUMAN_STUN_THRESHOLD)
+ if(M.last_airflow > world.time - 150) continue
+
+ if(ismob(M) && n > vsc.airflow_medium_pressure)
if(M:nodamage) continue
M:airflow_stun()
if(M.check_airflow_movable(n))
- var/fail = 1
+ var/list/close_turfs = list()
for(var/turf/U in connected_turfs)
- if(M in range(U)) fail = 0
- if(fail) continue
+ if(M in range(U)) close_turfs += U
+ if(!close_turfs.len) continue
+ //If they're already being tossed, don't do it again.
if(!M.airflow_speed)
- M.airflow_dest = pick(connected_turfs)
+
+ M.airflow_dest = pick(close_turfs) //Pick a random midpoint to fly towards.
spawn
- if(M) M.GotoAirflowDest(n * (vsc.AF_SPEED_MULTIPLIER/10))
+ if(M) M.GotoAirflowDest(n/20)
//Sometimes shit breaks, and M isn't there after the spawn.
-proc/AirflowRepel(turf/T,n,per = 0)
-
- //This one is used for air escaping from canisters.
- var/zone/A = T.zone
- if(!A) return
-
- n *= vsc.AF_CANISTER_MULTIPLIER
-
- if(!per)
- n = round((n/vsc.AF_PERCENT_OF) * 100,0.1)
-
- if(n < 0) return
- if(abs(n) > vsc.AF_TINY_MOVEMENT_THRESHOLD)
-
- var/list/pplz = A.movables()
-
- for(var/atom/movable/M in pplz)
- var/relative_n = n / max(1,get_dist(T,M)/2)
- if(ismob(M) && relative_n > vsc.AF_HUMAN_STUN_THRESHOLD)
- if(M:nodamage) continue
- M:airflow_stun()
-
- if(M.check_airflow_movable(relative_n))
-
- if(!(M in range(T))) continue //Recall that T is the center of the repelling force.
-
- if(!M.airflow_speed)
- M.airflow_dest = T
- spawn M.RepelAirflowDest(relative_n * (vsc.AF_SPEED_MULTIPLIER/10))
-
-proc/AirflowAttract(turf/T,n,per=0)
-
- //Same as above, but attracts objects to the target.
-
- var/zone/A = T.zone
- if(!A) return
-
- n *= vsc.AF_CANISTER_MULTIPLIER
-
- if(!per)
- n = round((n/vsc.AF_PERCENT_OF) * 100,0.1)
-
- if(n < 0) return
- if(abs(n) > vsc.AF_TINY_MOVEMENT_THRESHOLD)
- //world << "Airflow!"
- var/list/pplz = A.movables()
- for(var/atom/movable/M in pplz)
- //world << "[M] / \..."
-
- var/relative_n = n / max(1,get_dist(T,M)/2)
-
- if(ismob(M) && relative_n > vsc.AF_HUMAN_STUN_THRESHOLD)
- if(M:nodamage) continue
- M:airflow_stun()
-
- if(M.check_airflow_movable(relative_n))
-
- if(!(M in range(T))) continue
-
- if(!M.airflow_speed)
- M.airflow_dest = T
- spawn M.GotoAirflowDest(relative_n * (vsc.AF_SPEED_MULTIPLIER/10))
-
atom/movable
var/turf/airflow_dest
var/airflow_speed = 0
var/airflow_time = 0
+ var/last_airflow = 0
proc/GotoAirflowDest(n)
if(!airflow_dest) return
if(airflow_speed < 0) return
+ if(last_airflow > world.time - 150) return
if(airflow_speed)
- airflow_speed = n
+ airflow_speed = n/max(get_dist(src,airflow_dest),1)
return
+ last_airflow = world.time
if(airflow_dest == loc)
step_away(src,loc)
if(ismob(src))
@@ -408,7 +241,7 @@ atom/movable
while(airflow_speed > 0)
if(airflow_speed <= 0) return
airflow_speed = min(airflow_speed,15)
- airflow_speed -= vsc.AF_SPEED_DECAY
+ airflow_speed -= vsc.airflow_speed_decay
if(airflow_speed > 7)
if(airflow_time++ >= airflow_speed - 7)
sleep(1 * tick_multiplier)
@@ -421,17 +254,18 @@ atom/movable
step_towards(src, src.airflow_dest)
if(ismob(src) && src:client) src:client:move_delay = world.time + 10
airflow_dest = null
- airflow_speed = -1
- spawn(150 * tick_multiplier) airflow_speed = 0
+ airflow_speed = 0
if(od)
density = 0
proc/RepelAirflowDest(n)
if(!airflow_dest) return
if(airflow_speed < 0) return
+ if(last_airflow > world.time - 150) return
if(airflow_speed)
- airflow_speed = n
+ airflow_speed = n/max(get_dist(src,airflow_dest),1)
return
+ last_airflow = world.time
if(airflow_dest == loc)
step_away(src,loc)
if(ismob(src))
@@ -456,7 +290,7 @@ atom/movable
while(airflow_speed > 0)
if(airflow_speed <= 0) return
airflow_speed = min(airflow_speed,15)
- airflow_speed -= vsc.AF_SPEED_DECAY
+ airflow_speed -= vsc.airflow_speed_decay
if(airflow_speed > 7)
if(airflow_time++ >= airflow_speed - 7)
sleep(1 * tick_multiplier)
@@ -469,8 +303,7 @@ atom/movable
step_towards(src, src.airflow_dest)
if(ismob(src) && src:client) src:client:move_delay = world.time + 10
airflow_dest = null
- airflow_speed = -1
- spawn(150 * tick_multiplier) airflow_speed = 0
+ airflow_speed = 0
if(od)
density = 0
@@ -482,8 +315,7 @@ atom/movable
. = ..()
atom/movable/proc/airflow_hit(atom/A)
- airflow_speed = -1
- spawn(50 * tick_multiplier) airflow_speed = 0
+ airflow_speed = 0
airflow_dest = null
mob/airflow_hit(atom/A)
@@ -499,8 +331,7 @@ obj/airflow_hit(atom/A)
. = ..()
obj/item/airflow_hit(atom/A)
- airflow_speed = -1
- spawn(50 * tick_multiplier) airflow_speed = 0
+ airflow_speed = 0
airflow_dest = null
mob/living/carbon/human/airflow_hit(atom/A)
@@ -512,76 +343,43 @@ mob/living/carbon/human/airflow_hit(atom/A)
src.wear_suit.add_blood(src)
if (src.w_uniform)
src.w_uniform.add_blood(src)
- var/b_loss = airflow_speed * vsc.AF_DAMAGE_MULTIPLIER
- for(var/organ in src:organs)
- var/datum/organ/external/temp = src:organs["[organ]"]
- if (istype(temp, /datum/organ/external))
- switch(temp.name)
- if("head")
- temp.take_damage(b_loss * 0.2, 0)
- if("chest")
- temp.take_damage(b_loss * 0.4, 0)
- if("diaper")
- temp.take_damage(b_loss * 0.1, 0)
- spawn UpdateDamageIcon()
+ var/b_loss = airflow_speed * vsc.airflow_damage
+
+ var/blocked = run_armor_check("head","melee")
+ apply_damage(b_loss/3, BRUTE, "head", blocked, 0, "Airflow")
+
+ blocked = run_armor_check("chest","melee")
+ apply_damage(b_loss/3, BRUTE, "chest", blocked, 0, "Airflow")
+
+ blocked = run_armor_check("groin","melee")
+ apply_damage(b_loss/3, BRUTE, "groin", blocked, 0, "Airflow")
+
if(airflow_speed > 10)
- paralysis += round(airflow_speed * vsc.AF_STUN_MULTIPLIER)
+ paralysis += round(airflow_speed * vsc.airflow_stun)
stunned = max(stunned,paralysis + 3)
else
- stunned += round(airflow_speed * vsc.AF_STUN_MULTIPLIER/2)
+ stunned += round(airflow_speed * vsc.airflow_stun/2)
. = ..()
-zone/proc/movables()
- . = list()
- for(var/turf/T in contents)
- for(var/atom/A in T)
- . += A
+turf/simulated/Entered(atom/A)
+ . = ..()
+ if(istype(A,/atom/movable) && zone)
+ zone.movable_objects += A
-proc/Get_Dir(atom/S,atom/T) //Shamelessly stolen from AJX.AdvancedGetDir
- var/GDist=get_dist(S,T)
- var/GDir=get_dir(S,T)
- if(GDist<=3)
- if(GDist==0) return 0
- if(GDist==1)
- return GDir
+turf/simulated/Exited(atom/A)
+ . = ..()
+ if(istype(A,/atom/movable) && zone)
+ zone.movable_objects -= A
+atom/movable/New(turf/simulated/T)
+ . = ..()
+ if(istype(T))
+ if(T.zone)
+ T.zone.movable_objects += src
- var/X1=S.x*10
- var/X2=T.x*10
- var/Y1=S.y*10
- var/Y2=T.y*10
- var/Ref
- if(GDir==NORTHEAST)
- Ref=(X2/X1)*Y1
- if(Ref-1>Y2) .=EAST
- else if(Ref+1Y2) .=WEST
- else if(Ref+1Y2) .=SOUTH
- else if(Ref+1Y2) .=SOUTH
- else if(Ref+1> vsc
- del F
- world.log << "TWEAKS: Airflow, Plasma and Damage settings loaded."
\ No newline at end of file
+atom/movable/Del()
+ var/turf/simulated/T = loc
+ if(istype(T))
+ if(T.zone)
+ T.zone.movable_objects -= src
+ . = ..()
\ No newline at end of file
diff --git a/code/ZAS/Connection.dm b/code/ZAS/Connection.dm
index bf43f90d1c0..3092352bd0f 100644
--- a/code/ZAS/Connection.dm
+++ b/code/ZAS/Connection.dm
@@ -1,3 +1,8 @@
+/*
+This object is contained within zone/var/connections. It's generated whenever two turfs from different zones are linked.
+Indirect connections will not merge the two zones after they reach equilibrium.
+*/
+
connection
var
turf //The turfs involved in the connection.
@@ -5,6 +10,7 @@ connection
B
indirect = 0 //If the connection is purely indirect, the zones should not join.
last_updated //The tick at which this was last updated.
+ no_zone_count = 0
New(turf/T,turf/O)
A = T
B = O
@@ -31,6 +37,8 @@ connection
B.zone.connected_zones[A.zone] = 1
else
B.zone.connected_zones[A.zone]++
+ else
+ world.log << "Attempted to create connection object for non-zone tiles: [T] -> [O]"
Del()
if(A.zone && A.zone.connections)
A.zone.connections -= src
@@ -57,5 +65,14 @@ connection
. = ..()
proc/Cleanup()
- if(A.zone == B.zone) del src
- if(!A.zone || !B.zone) del src
\ No newline at end of file
+ if(!A || !B)
+ //world.log << "Connection removed: [A] or [B] missing entirely."
+ del src
+ if(A.zone == B.zone)
+ //world.log << "Connection removed: Zones now merged."
+ del src
+ if(!A.zone || !B.zone)
+ no_zone_count++
+ if(no_zone_count >= 5)
+ //world.log << "Connection removed: [A] or [B] missing a zone."
+ del src
\ No newline at end of file
diff --git a/code/ZAS/Creation.dm b/code/ZAS/Creation.dm
index 5f256767fd3..10508e0aa2f 100644
--- a/code/ZAS/Creation.dm
+++ b/code/ZAS/Creation.dm
@@ -1,13 +1,19 @@
zone
New(turf/start)
+ //Get the turfs that are part of the zone using a floodfill method
if(istype(start,/list))
contents = start
else
contents = FloodFill(start)
+
+ //Change all the zone vars of the turfs, check for space to be added to space_tiles.
for(var/turf/T in contents)
T.zone = src
if(istype(T,/turf/space))
AddSpace(T)
+
+ //Generate the gas_mixture for use in this zone by using the average of the gases
+ //defined at startup.
air = new
var/members = contents.len
for(var/turf/simulated/T in contents)
@@ -17,8 +23,13 @@ zone
air.toxins += T.toxins / members
air.temperature += T.temperature / members
air.group_multiplier = contents.len
+ air.update_values()
+
+ //Add this zone to the global list.
zones += src
+
Del()
+ //Ensuring the zone list doesn't get clogged with null values.
zones -= src
. = ..()
@@ -30,17 +41,23 @@ proc/FloodFill(turf/start)
while(open.len)
for(var/turf/T in open)
+ //Stop if there's a door, even if it's open. These are handled by indirect connection.
if(!T.HasDoor())
+
for(var/d in cardinal)
var/turf/O = get_step(T,d)
+ //Simple pass check.
if(O.ZCanPass(T) && !(O in open) && !(O in closed))
open += O
+
open -= T
closed += T
return closed
turf/proc/ZCanPass(turf/T)
+ //Fairly standard pass checks for turfs, objects and directional windows. Also stops at the edge of space.
+
if(istype(T,/turf/space)) return 0
else
if(T.blocks_air||blocks_air)
@@ -51,6 +68,7 @@ turf/proc/ZCanPass(turf/T)
continue
if(!obstacle.CanPass(0, T, 0, 1))
return 0
+
for(var/obj/obstacle in T)
if(istype(obstacle,/obj/machinery/door) && !istype(obstacle,/obj/machinery/door/window))
continue
diff --git a/code/ZAS/Debug.dm b/code/ZAS/Debug.dm
index 28fc3caef53..7a0285cc1e1 100644
--- a/code/ZAS/Debug.dm
+++ b/code/ZAS/Debug.dm
@@ -1,5 +1,5 @@
-client/proc/Zone_Info(turf/T as null|turf)
+client/verb/Zone_Info(turf/T as null|turf)
set category = "Debug"
if(T)
if(T.zone)
@@ -28,9 +28,11 @@ zone/proc
M << "Plasma: [air.toxins]"
M << "Carbon Dioxide: [air.carbon_dioxide]"
M << "Temperature: [air.temperature]"
- M << "Heat Energy: [air.thermal_energy()]"
+ M << "Heat Energy: [air.temperature * air.heat_capacity()]"
M << "Pressure: [air.return_pressure()]"
M << ""
+ M << "Space Tiles: [length(space_tiles)]"
+ M << "Movable Objects: [length(movable_objects)]"
M << "Connections: [length(connections)]"
for(var/connection/C in connections)
@@ -40,6 +42,9 @@ zone/proc
spawn(50)
C.A.overlays -= 'debug_connect.dmi'
C.B.overlays -= 'debug_connect.dmi'
+ for(var/C in connections)
+ if(!istype(C,/connection))
+ M << "[C] (Not Connection!)"
else
dbg_output = 0
diff --git a/code/ZAS/Definition.dm b/code/ZAS/Definition.dm
index 729d19841fc..cdf411fe68c 100644
--- a/code/ZAS/Definition.dm
+++ b/code/ZAS/Definition.dm
@@ -1,34 +1,17 @@
turf/var/zone/zone
var/list/zones = list()
-var/zone_controller/zone_master = new
-
-zone_controller
- var
- current_tick = 0
- proc
- start()
- set background = 1
- while(1)
- current_tick++
- for(var/zone/Z in zones)
- if(Z.last_update < current_tick)
- Z.process()
- if(Z) Z.last_update = current_tick
- for(var/obj/fire/F)
- F.process()
- //for(var/obj/z_hotspot/H in z_hotspots)
- // H.process()
- sleep(max(5,vsc.zone_update_delay*tick_multiplier))
zone
var
dbg_output = 0 //Enables debug output.
- rebuild = 0 //If 1, zone will be rebuilt on next process.
+ rebuild = 0 //If 1, zone will be rebuilt on next process. Not sure if used.
datum/gas_mixture/air //The air contents of the zone.
list/contents //All the tiles that are contained in this zone.
list/connections // /connection objects which refer to connections with other zones, e.g. through a door.
list/connected_zones //Parallels connections, but lists zones to which this one is connected and the number
//of points they're connected at.
list/space_tiles // Any space tiles in this list will cause air to flow out.
- last_update = 0
\ No newline at end of file
+ last_update = 0
+
+ list/movable_objects = list() //All the things that can be tossed by airflow.
\ No newline at end of file
diff --git a/code/ZAS/FEA_gas_mixture.dm b/code/ZAS/FEA_gas_mixture.dm
new file mode 100644
index 00000000000..d6a0cf36ab2
--- /dev/null
+++ b/code/ZAS/FEA_gas_mixture.dm
@@ -0,0 +1,1008 @@
+/*
+What are the archived variables for?
+ Calculations are done using the archived variables with the results merged into the regular variables.
+ This prevents race conditions that arise based on the order of tile processing.
+*/
+
+datum
+ gas //These are used for the "Trace Gases" stuff, but is buggy.
+ sleeping_agent
+ specific_heat = 40
+
+ volatile_fuel
+ specific_heat = 30
+
+ var
+ moles = 0
+ specific_heat = 0
+
+ moles_archived = 0
+
+ gas_mixture
+ var //Holds the "moles" of each of the four gases.
+ oxygen = 0
+ carbon_dioxide = 0
+ nitrogen = 0
+ toxins = 0
+ total_moles = 0 //Updated when a reaction occurs.
+ pressure = 0
+
+ volume = CELL_VOLUME
+
+ temperature = 0 //in Kelvin, use calculate_temperature() to modify
+
+ group_multiplier = 1
+ //Size of the group this gas_mixture is representing.
+ //=1 for singletons
+
+ graphic
+
+ list/datum/gas/trace_gases = list() //Seemed to be a good idea that was abandoned
+
+ tmp //These are variables for use with the archived data
+ oxygen_archived
+ carbon_dioxide_archived
+ nitrogen_archived
+ toxins_archived
+
+ temperature_archived
+
+ graphic_archived = 0
+ fuel_burnt = 0
+
+//FOR THE LOVE OF GOD PLEASE USE THIS PROC
+//Call it with negative numbers to remove gases.
+
+ proc/adjustGases(o2 = 0, co2 = 0, n2 = 0, tx = 0, list/datum/gas/traces = list())
+ //Purpose: Adjusting the gases within a airmix
+ //Called by: Nothing, yet!
+ //Inputs: The values of the gases to adjust
+ //Outputs: null
+
+ oxygen = max(0, oxygen + o2)
+ carbon_dioxide = max(0, carbon_dioxide + co2)
+ nitrogen = max(0, nitrogen + n2)
+ toxins = max(0, toxins + tx)
+
+ //handle trace gasses
+ for(var/datum/gas/G in traces)
+ var/datum/gas/T = locate(G.type) in trace_gases
+ if(T)
+ T.moles = max(G.moles + T.moles, 0)
+ else if(G.moles > 0)
+ trace_gases |= G
+ update_values()
+ return
+
+///////////////////////////////
+//PV=nRT - related procedures//
+///////////////////////////////
+
+
+ proc/heat_capacity()
+ //Purpose: Returning the heat capacity of the gas mix
+ //Called by: UNKNOWN
+ //Inputs: None
+ //Outputs: Heat capacity
+
+ var/heat_capacity = HEAT_CAPACITY_CALCULATION(oxygen,carbon_dioxide,nitrogen,toxins)
+
+ if(trace_gases.len)
+ for(var/datum/gas/trace_gas in trace_gases)
+ heat_capacity += trace_gas.moles*trace_gas.specific_heat
+
+ return max(MINIMUM_HEAT_CAPACITY,heat_capacity)
+
+ proc/heat_capacity_archived()
+ //Purpose: Returning the archived heat capacity of the gas mix
+ //Called by: UNKNOWN
+ //Inputs: None
+ //Outputs: Archived heat capacity
+
+ var/heat_capacity_archived = HEAT_CAPACITY_CALCULATION(oxygen_archived,carbon_dioxide_archived,nitrogen_archived,toxins_archived)
+
+ if(trace_gases.len)
+ for(var/datum/gas/trace_gas in trace_gases)
+ heat_capacity_archived += trace_gas.moles_archived*trace_gas.specific_heat
+
+ return max(MINIMUM_HEAT_CAPACITY,heat_capacity_archived)
+
+ proc/return_pressure()
+ //Purpose: Calculating Current Pressure
+ //Called by:
+ //Inputs: None
+ //Outputs: Gas pressure.
+
+ if(volume>0)
+ return total_moles*R_IDEAL_GAS_EQUATION*temperature/volume
+ return 0
+
+// proc/return_temperature()
+ //Purpose:
+ //Inputs:
+ //Outputs:
+
+// return temperature
+
+// proc/return_volume()
+ //Purpose:
+ //Inputs:
+ //Outputs:
+
+// return max(0, volume)
+
+// proc/thermal_energy()
+ //Purpose:
+ //Inputs:
+ //Outputs:
+
+// return temperature*heat_capacity()
+
+ proc/update_values()
+ //Purpose: Calculating and storing values which were normally called CONSTANTLY
+ //Called by: Anything that changes values within a gas mix.
+ //Inputs: None
+ //Outputs: None
+
+ total_moles = oxygen + carbon_dioxide + nitrogen + toxins
+
+ if(trace_gases.len)
+ for(var/datum/gas/trace_gas in trace_gases)
+ total_moles += trace_gas.moles
+
+ if(volume)
+ pressure = total_moles*R_IDEAL_GAS_EQUATION*temperature/volume
+ else
+ pressure = 0
+ return
+
+////////////////////////////////////////////
+//Procedures used for very specific events//
+////////////////////////////////////////////
+
+
+ proc/check_tile_graphic()
+ //Purpose: Calculating the graphic for a tile
+ //Called by: Turfs updating
+ //Inputs: None
+ //Outputs: 1 if graphic changed, 0 if unchanged
+
+ graphic = 0
+ if(toxins > MOLES_PLASMA_VISIBLE)
+ graphic = 1
+ else if(length(trace_gases))
+ var/datum/gas/sleeping_agent = locate(/datum/gas/sleeping_agent) in trace_gases
+ if(sleeping_agent && (sleeping_agent.moles > 1))
+ graphic = 2
+ else
+ graphic = 0
+
+ return graphic != graphic_archived
+
+ proc/react(atom/dump_location)
+ //Purpose: Calculating if it is possible for a fire to occur in the airmix
+ //Called by: Air mixes updating?
+ //Inputs: None
+ //Outputs: If a fire occured
+
+ var/reacting = 0 //set to 1 if a notable reaction occured (used by pipe_network)
+
+ if(temperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST)
+ if(zburn(null) > 0)
+ reacting = 1
+
+ return reacting
+
+ proc/fire()
+ //Purpose: Calculating any fire reactions.
+ //Called by: react() (See above)
+ //Inputs: None
+ //Outputs: How much fuel burned
+
+ return zburn(null)
+
+ /*var/energy_released = 0
+ var/old_heat_capacity = heat_capacity()
+
+ var/datum/gas/volatile_fuel/fuel_store = locate(/datum/gas/volatile_fuel) in trace_gases
+ if(fuel_store) //General volatile gas burn
+ var/burned_fuel = 0
+
+ if(oxygen < fuel_store.moles)
+ burned_fuel = oxygen
+ fuel_store.moles -= burned_fuel
+ oxygen = 0
+ else
+ burned_fuel = fuel_store.moles
+ oxygen -= fuel_store.moles
+ del(fuel_store)
+
+ energy_released += FIRE_CARBON_ENERGY_RELEASED * burned_fuel
+ carbon_dioxide += burned_fuel
+ fuel_burnt += burned_fuel
+
+ //Handle plasma burning
+ if(toxins > MINIMUM_HEAT_CAPACITY)
+ var/plasma_burn_rate = 0
+ var/oxygen_burn_rate = 0
+ //more plasma released at higher temperatures
+ var/temperature_scale
+ if(temperature > PLASMA_UPPER_TEMPERATURE)
+ temperature_scale = 1
+ else
+ temperature_scale = (temperature-PLASMA_MINIMUM_BURN_TEMPERATURE)/(PLASMA_UPPER_TEMPERATURE-PLASMA_MINIMUM_BURN_TEMPERATURE)
+ if(temperature_scale > 0)
+ oxygen_burn_rate = 1.4 - temperature_scale
+ if(oxygen > toxins*PLASMA_OXYGEN_FULLBURN)
+ plasma_burn_rate = (toxins*temperature_scale)/4
+ else
+ plasma_burn_rate = (temperature_scale*(oxygen/PLASMA_OXYGEN_FULLBURN))/4
+ if(plasma_burn_rate > MINIMUM_HEAT_CAPACITY)
+ toxins -= plasma_burn_rate
+ oxygen -= plasma_burn_rate*oxygen_burn_rate
+ carbon_dioxide += plasma_burn_rate
+
+ energy_released += FIRE_PLASMA_ENERGY_RELEASED * (plasma_burn_rate)
+
+ fuel_burnt += (plasma_burn_rate)*(1+oxygen_burn_rate)
+
+ if(energy_released > 0)
+ var/new_heat_capacity = heat_capacity()
+ if(new_heat_capacity > MINIMUM_HEAT_CAPACITY)
+ temperature = (temperature*old_heat_capacity + energy_released)/new_heat_capacity
+ update_values()
+
+ return fuel_burnt*/
+
+//////////////////////////////////////////////
+//Procs for general gas spread calculations.//
+//////////////////////////////////////////////
+
+
+ proc/archive()
+ //Purpose: Archives the current gas values
+ //Called by: UNKNOWN
+ //Inputs: None
+ //Outputs: 1
+
+ oxygen_archived = oxygen
+ carbon_dioxide_archived = carbon_dioxide
+ nitrogen_archived = nitrogen
+ toxins_archived = toxins
+
+ if(trace_gases.len)
+ for(var/datum/gas/trace_gas in trace_gases)
+ trace_gas.moles_archived = trace_gas.moles
+
+ temperature_archived = temperature
+
+ graphic_archived = graphic
+
+ return 1
+
+ proc/check_then_merge(datum/gas_mixture/giver)
+ //Purpose: Similar to merge(...) but first checks to see if the amount of air assumed is small enough
+ // that group processing is still accurate for source (aborts if not)
+ //Called by: airgroups/machinery expelling air, ?
+ //Inputs: The gas to try and merge
+ //Outputs: 1 on successful merge. 0 otherwise.
+
+ if(!giver)
+ return 0
+ if(((giver.oxygen > MINIMUM_AIR_TO_SUSPEND) && (giver.oxygen >= oxygen*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((giver.carbon_dioxide > MINIMUM_AIR_TO_SUSPEND) && (giver.carbon_dioxide >= carbon_dioxide*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((giver.nitrogen > MINIMUM_AIR_TO_SUSPEND) && (giver.nitrogen >= nitrogen*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((giver.toxins > MINIMUM_AIR_TO_SUSPEND) && (giver.toxins >= toxins*MINIMUM_AIR_RATIO_TO_SUSPEND)))
+ return 0
+ if(abs(giver.temperature - temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND)
+ return 0
+
+ if(giver.trace_gases.len)
+ for(var/datum/gas/trace_gas in giver.trace_gases)
+ var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases
+ if((trace_gas.moles > MINIMUM_AIR_TO_SUSPEND) && (!corresponding || (trace_gas.moles >= corresponding.moles*MINIMUM_AIR_RATIO_TO_SUSPEND)))
+ return 0
+
+ return merge(giver)
+
+ proc/merge(datum/gas_mixture/giver)
+ //Purpose: Merges all air from giver into self. Deletes giver.
+ //Called by: Machinery expelling air, check_then_merge, ?
+ //Inputs: The gas to merge.
+ //Outputs: 1
+
+ if(!giver)
+ return 0
+
+ if(abs(temperature-giver.temperature)>MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
+ var/self_heat_capacity = heat_capacity()*group_multiplier
+ var/giver_heat_capacity = giver.heat_capacity()*giver.group_multiplier
+ var/combined_heat_capacity = giver_heat_capacity + self_heat_capacity
+ if(combined_heat_capacity != 0)
+ temperature = (giver.temperature*giver_heat_capacity + temperature*self_heat_capacity)/combined_heat_capacity
+
+ if((group_multiplier>1)||(giver.group_multiplier>1))
+ oxygen += giver.oxygen*giver.group_multiplier/group_multiplier
+ carbon_dioxide += giver.carbon_dioxide*giver.group_multiplier/group_multiplier
+ nitrogen += giver.nitrogen*giver.group_multiplier/group_multiplier
+ toxins += giver.toxins*giver.group_multiplier/group_multiplier
+ else
+ oxygen += giver.oxygen
+ carbon_dioxide += giver.carbon_dioxide
+ nitrogen += giver.nitrogen
+ toxins += giver.toxins
+
+ if(giver.trace_gases.len)
+ for(var/datum/gas/trace_gas in giver.trace_gases)
+ var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases
+ if(!corresponding)
+ corresponding = new trace_gas.type()
+ trace_gases += corresponding
+ corresponding.moles += trace_gas.moles*giver.group_multiplier/group_multiplier
+ update_values()
+
+ del(giver)
+ return 1
+
+ proc/remove(amount)
+ //Purpose: Removes a certain number of moles from the air.
+ //Called by: ?
+ //Inputs: How many moles to remove.
+ //Outputs: Removed air.
+
+ var/sum = total_moles
+ amount = min(amount,sum) //Can not take more air than tile has!
+ if(amount <= 0)
+ return null
+
+ var/datum/gas_mixture/removed = new
+
+
+ removed.oxygen = QUANTIZE((oxygen/sum)*amount)
+ removed.nitrogen = QUANTIZE((nitrogen/sum)*amount)
+ removed.carbon_dioxide = QUANTIZE((carbon_dioxide/sum)*amount)
+ removed.toxins = QUANTIZE((toxins/sum)*amount)
+
+ oxygen -= removed.oxygen/group_multiplier
+ nitrogen -= removed.nitrogen/group_multiplier
+ carbon_dioxide -= removed.carbon_dioxide/group_multiplier
+ toxins -= removed.toxins/group_multiplier
+
+ if(trace_gases.len)
+ for(var/datum/gas/trace_gas in trace_gases)
+ var/datum/gas/corresponding = new trace_gas.type()
+ removed.trace_gases += corresponding
+
+ corresponding.moles = (trace_gas.moles/sum)*amount
+ trace_gas.moles -= corresponding.moles/group_multiplier
+
+ removed.temperature = temperature
+ update_values()
+ removed.update_values()
+
+ return removed
+
+ proc/remove_ratio(ratio)
+ //Purpose: Removes a certain ratio of the air.
+ //Called by: ?
+ //Inputs: Percentage to remove.
+ //Outputs: Removed air.
+
+ if(ratio <= 0)
+ return null
+
+ ratio = min(ratio, 1)
+
+ var/datum/gas_mixture/removed = new
+
+ removed.oxygen = QUANTIZE(oxygen*ratio)
+ removed.nitrogen = QUANTIZE(nitrogen*ratio)
+ removed.carbon_dioxide = QUANTIZE(carbon_dioxide*ratio)
+ removed.toxins = QUANTIZE(toxins*ratio)
+
+ oxygen -= removed.oxygen/group_multiplier
+ nitrogen -= removed.nitrogen/group_multiplier
+ carbon_dioxide -= removed.carbon_dioxide/group_multiplier
+ toxins -= removed.toxins/group_multiplier
+
+ if(trace_gases.len)
+ for(var/datum/gas/trace_gas in trace_gases)
+ var/datum/gas/corresponding = new trace_gas.type()
+ removed.trace_gases += corresponding
+
+ corresponding.moles = trace_gas.moles*ratio
+ trace_gas.moles -= corresponding.moles/group_multiplier
+
+ removed.temperature = temperature
+ update_values()
+ removed.update_values()
+
+ return removed
+
+ proc/check_then_remove(amount)
+ //Purpose: Similar to remove(...) but first checks to see if the amount of air removed is small enough
+ // that group processing is still accurate for source (aborts if not)
+ //Called by: ?
+ //Inputs: Number of moles to remove
+ //Outputs: Removed air or 0 if it can remove air or not.
+
+ amount = min(amount,total_moles) //Can not take more air than tile has!
+
+ if((amount > MINIMUM_AIR_RATIO_TO_SUSPEND) && (amount > total_moles*MINIMUM_AIR_RATIO_TO_SUSPEND))
+ return 0
+
+ return remove(amount)
+
+ proc/copy_from(datum/gas_mixture/sample)
+ //Purpose: Duplicates the sample air mixture.
+ //Called by: airgroups splitting, ?
+ //Inputs: Gas to copy
+ //Outputs: 1
+
+ oxygen = sample.oxygen
+ carbon_dioxide = sample.carbon_dioxide
+ nitrogen = sample.nitrogen
+ toxins = sample.toxins
+ total_moles = sample.total_moles
+
+ trace_gases.len=null
+ if(sample.trace_gases.len > 0)
+ for(var/datum/gas/trace_gas in sample.trace_gases)
+ var/datum/gas/corresponding = new trace_gas.type()
+ trace_gases += corresponding
+
+ corresponding.moles = trace_gas.moles
+
+ temperature = sample.temperature
+
+ return 1
+
+ proc/check_gas_mixture(datum/gas_mixture/sharer)
+ //Purpose: Telling if one or both airgroups needs to disable group processing.
+ //Called by: Airgroups sharing air, checking if group processing needs disabled.
+ //Inputs: Gas to compare from other airgroup
+ //Outputs: 0 if the self-check failed (local airgroup breaks?)
+ // then -1 if sharer-check failed (sharing airgroup breaks?)
+ // then 1 if both checks pass (share succesful?)
+ if(!istype(sharer))
+ return
+
+ var/delta_oxygen = QUANTIZE(oxygen_archived - sharer.oxygen_archived)/TRANSFER_FRACTION
+ var/delta_carbon_dioxide = QUANTIZE(carbon_dioxide_archived - sharer.carbon_dioxide_archived)/TRANSFER_FRACTION
+ var/delta_nitrogen = QUANTIZE(nitrogen_archived - sharer.nitrogen_archived)/TRANSFER_FRACTION
+ var/delta_toxins = QUANTIZE(toxins_archived - sharer.toxins_archived)/TRANSFER_FRACTION
+
+ var/delta_temperature = (temperature_archived - sharer.temperature_archived)
+
+ if(((abs(delta_oxygen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_oxygen) >= oxygen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((abs(delta_carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_carbon_dioxide) >= carbon_dioxide_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= nitrogen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= toxins_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)))
+ return 0
+
+ if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND)
+ return 0
+
+ if(sharer.trace_gases.len)
+ for(var/datum/gas/trace_gas in sharer.trace_gases)
+ if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND*4)
+ var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases
+ if(corresponding)
+ if(trace_gas.moles_archived >= corresponding.moles_archived*MINIMUM_AIR_RATIO_TO_SUSPEND*4)
+ return 0
+ else
+ return 0
+
+ if(trace_gases.len)
+ for(var/datum/gas/trace_gas in trace_gases)
+ if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND*4)
+ if(!locate(trace_gas.type) in sharer.trace_gases)
+ return 0
+
+ if(((abs(delta_oxygen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_oxygen) >= sharer.oxygen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((abs(delta_carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_carbon_dioxide) >= sharer.carbon_dioxide_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= sharer.nitrogen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= sharer.toxins_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)))
+ return -1
+
+ if(trace_gases.len)
+ for(var/datum/gas/trace_gas in trace_gases)
+ if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND*4)
+ var/datum/gas/corresponding = locate(trace_gas.type) in sharer.trace_gases
+ if(corresponding)
+ if(trace_gas.moles_archived >= corresponding.moles_archived*MINIMUM_AIR_RATIO_TO_SUSPEND*4)
+ return -1
+ else
+ return -1
+
+ return 1
+
+ proc/check_turf(turf/model)
+ //Purpose: Used to compare the gases in an unsimulated turf with the gas in a simulated one.
+ //Called by: Sharing air (mimicing) with adjacent unsimulated turfs
+ //Inputs: Unsimulated turf
+ //Outputs: 1 if safe to mimic, 0 if needs to break airgroup.
+
+ var/delta_oxygen = (oxygen_archived - model.oxygen)/TRANSFER_FRACTION
+ var/delta_carbon_dioxide = (carbon_dioxide_archived - model.carbon_dioxide)/TRANSFER_FRACTION
+ var/delta_nitrogen = (nitrogen_archived - model.nitrogen)/TRANSFER_FRACTION
+ var/delta_toxins = (toxins_archived - model.toxins)/TRANSFER_FRACTION
+
+ var/delta_temperature = (temperature_archived - model.temperature)
+
+ if(((abs(delta_oxygen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_oxygen) >= oxygen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((abs(delta_carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_carbon_dioxide) >= carbon_dioxide_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= nitrogen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= toxins_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)))
+ return 0
+ if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND)
+ return 0
+
+ if(trace_gases.len)
+ for(var/datum/gas/trace_gas in trace_gases)
+ if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND*4)
+ return 0
+
+ return 1
+
+ proc/share(datum/gas_mixture/sharer)
+ //Purpose: Used to transfer gas from a more pressurised tile to a less presurised tile
+ // (Two directional, if the other tile is more pressurised, air travels to current tile)
+ //Called by: Sharing air with adjacent simulated turfs
+ //Inputs: Air datum to share with
+ //Outputs: Amount of gas exchanged (Negative if lost air, positive if gained.)
+
+
+ if(!istype(sharer))
+ return
+
+ var/delta_oxygen = QUANTIZE(oxygen_archived - sharer.oxygen_archived)/TRANSFER_FRACTION
+ var/delta_carbon_dioxide = QUANTIZE(carbon_dioxide_archived - sharer.carbon_dioxide_archived)/TRANSFER_FRACTION
+ var/delta_nitrogen = QUANTIZE(nitrogen_archived - sharer.nitrogen_archived)/TRANSFER_FRACTION
+ var/delta_toxins = QUANTIZE(toxins_archived - sharer.toxins_archived)/TRANSFER_FRACTION
+
+ var/delta_temperature = (temperature_archived - sharer.temperature_archived)
+
+ var/old_self_heat_capacity = 0
+ var/old_sharer_heat_capacity = 0
+
+ var/heat_self_to_sharer = 0
+ var/heat_capacity_self_to_sharer = 0
+ var/heat_sharer_to_self = 0
+ var/heat_capacity_sharer_to_self = 0
+
+ if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
+
+ var/delta_air = delta_oxygen+delta_nitrogen
+ if(delta_air)
+ var/air_heat_capacity = SPECIFIC_HEAT_AIR*delta_air
+ if(delta_air > 0)
+ heat_self_to_sharer += air_heat_capacity*temperature_archived
+ heat_capacity_self_to_sharer += air_heat_capacity
+ else
+ heat_sharer_to_self -= air_heat_capacity*sharer.temperature_archived
+ heat_capacity_sharer_to_self -= air_heat_capacity
+
+ if(delta_carbon_dioxide)
+ var/carbon_dioxide_heat_capacity = SPECIFIC_HEAT_CDO*delta_carbon_dioxide
+ if(delta_carbon_dioxide > 0)
+ heat_self_to_sharer += carbon_dioxide_heat_capacity*temperature_archived
+ heat_capacity_self_to_sharer += carbon_dioxide_heat_capacity
+ else
+ heat_sharer_to_self -= carbon_dioxide_heat_capacity*sharer.temperature_archived
+ heat_capacity_sharer_to_self -= carbon_dioxide_heat_capacity
+
+ if(delta_toxins)
+ var/toxins_heat_capacity = SPECIFIC_HEAT_TOXIN*delta_toxins
+ if(delta_toxins > 0)
+ heat_self_to_sharer += toxins_heat_capacity*temperature_archived
+ heat_capacity_self_to_sharer += toxins_heat_capacity
+ else
+ heat_sharer_to_self -= toxins_heat_capacity*sharer.temperature_archived
+ heat_capacity_sharer_to_self -= toxins_heat_capacity
+
+ old_self_heat_capacity = heat_capacity()*group_multiplier
+ old_sharer_heat_capacity = sharer.heat_capacity()*sharer.group_multiplier
+
+ oxygen -= delta_oxygen/group_multiplier
+ sharer.oxygen += delta_oxygen/sharer.group_multiplier
+
+ carbon_dioxide -= delta_carbon_dioxide/group_multiplier
+ sharer.carbon_dioxide += delta_carbon_dioxide/sharer.group_multiplier
+
+ nitrogen -= delta_nitrogen/group_multiplier
+ sharer.nitrogen += delta_nitrogen/sharer.group_multiplier
+
+ toxins -= delta_toxins/group_multiplier
+ sharer.toxins += delta_toxins/sharer.group_multiplier
+
+ var/moved_moles = (delta_oxygen + delta_carbon_dioxide + delta_nitrogen + delta_toxins)
+
+ var/list/trace_types_considered = list()
+
+ if(trace_gases.len)
+ for(var/datum/gas/trace_gas in trace_gases)
+
+ var/datum/gas/corresponding = locate(trace_gas.type) in sharer.trace_gases
+ var/delta = 0
+
+ if(corresponding)
+ delta = QUANTIZE(trace_gas.moles_archived - corresponding.moles_archived)/TRANSFER_FRACTION
+ else
+ corresponding = new trace_gas.type()
+ sharer.trace_gases += corresponding
+
+ delta = trace_gas.moles_archived/TRANSFER_FRACTION
+
+ trace_gas.moles -= delta/group_multiplier
+ corresponding.moles += delta/sharer.group_multiplier
+
+ if(delta)
+ var/individual_heat_capacity = trace_gas.specific_heat*delta
+ if(delta > 0)
+ heat_self_to_sharer += individual_heat_capacity*temperature_archived
+ heat_capacity_self_to_sharer += individual_heat_capacity
+ else
+ heat_sharer_to_self -= individual_heat_capacity*sharer.temperature_archived
+ heat_capacity_sharer_to_self -= individual_heat_capacity
+
+ moved_moles += delta
+
+ trace_types_considered += trace_gas.type
+
+
+ if(sharer.trace_gases.len)
+ for(var/datum/gas/trace_gas in sharer.trace_gases)
+ if(trace_gas.type in trace_types_considered) continue
+ else
+ var/datum/gas/corresponding
+ var/delta = 0
+
+ corresponding = new trace_gas.type()
+ trace_gases += corresponding
+
+ delta = trace_gas.moles_archived/TRANSFER_FRACTION
+
+ trace_gas.moles -= delta/sharer.group_multiplier
+ corresponding.moles += delta/group_multiplier
+
+ //Guaranteed transfer from sharer to self
+ var/individual_heat_capacity = trace_gas.specific_heat*delta
+ heat_sharer_to_self += individual_heat_capacity*sharer.temperature_archived
+ heat_capacity_sharer_to_self += individual_heat_capacity
+
+ moved_moles += -delta
+ update_values()
+ sharer.update_values()
+
+ if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
+ var/new_self_heat_capacity = old_self_heat_capacity + heat_capacity_sharer_to_self - heat_capacity_self_to_sharer
+ var/new_sharer_heat_capacity = old_sharer_heat_capacity + heat_capacity_self_to_sharer - heat_capacity_sharer_to_self
+
+ if(new_self_heat_capacity > MINIMUM_HEAT_CAPACITY)
+ temperature = (old_self_heat_capacity*temperature - heat_capacity_self_to_sharer*temperature_archived + heat_capacity_sharer_to_self*sharer.temperature_archived)/new_self_heat_capacity
+
+ if(new_sharer_heat_capacity > MINIMUM_HEAT_CAPACITY)
+ sharer.temperature = (old_sharer_heat_capacity*sharer.temperature-heat_capacity_sharer_to_self*sharer.temperature_archived + heat_capacity_self_to_sharer*temperature_archived)/new_sharer_heat_capacity
+
+ if(abs(old_sharer_heat_capacity) > MINIMUM_HEAT_CAPACITY)
+ if(abs(new_sharer_heat_capacity/old_sharer_heat_capacity - 1) < 0.10) // <10% change in sharer heat capacity
+ temperature_share(sharer, OPEN_HEAT_TRANSFER_COEFFICIENT)
+
+ if((delta_temperature > MINIMUM_TEMPERATURE_TO_MOVE) || abs(moved_moles) > MINIMUM_MOLES_DELTA_TO_MOVE)
+ var/delta_pressure = temperature_archived*(total_moles + moved_moles) - sharer.temperature_archived*(sharer.total_moles - moved_moles)
+ return delta_pressure*R_IDEAL_GAS_EQUATION/volume
+
+ else
+ return 0
+
+ proc/mimic(turf/model, border_multiplier)
+ //Purpose: Used transfer gas from a more pressurised tile to a less presurised unsimulated tile.
+ //Called by: "sharing" from unsimulated to simulated turfs.
+ //Inputs: Unsimulated turf, Multiplier for gas transfer (optional)
+ //Outputs: Amount of gas exchanged
+
+ var/delta_oxygen = QUANTIZE(oxygen_archived - model.oxygen)/TRANSFER_FRACTION
+ var/delta_carbon_dioxide = QUANTIZE(carbon_dioxide_archived - model.carbon_dioxide)/TRANSFER_FRACTION
+ var/delta_nitrogen = QUANTIZE(nitrogen_archived - model.nitrogen)/TRANSFER_FRACTION
+ var/delta_toxins = QUANTIZE(toxins_archived - model.toxins)/TRANSFER_FRACTION
+
+ var/delta_temperature = (temperature_archived - model.temperature)
+
+ var/heat_transferred = 0
+ var/old_self_heat_capacity = 0
+ var/heat_capacity_transferred = 0
+
+ if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
+
+ var/delta_air = delta_oxygen+delta_nitrogen
+ if(delta_air)
+ var/air_heat_capacity = SPECIFIC_HEAT_AIR*delta_air
+ heat_transferred -= air_heat_capacity*model.temperature
+ heat_capacity_transferred -= air_heat_capacity
+
+ if(delta_carbon_dioxide)
+ var/carbon_dioxide_heat_capacity = SPECIFIC_HEAT_CDO*delta_carbon_dioxide
+ heat_transferred -= carbon_dioxide_heat_capacity*model.temperature
+ heat_capacity_transferred -= carbon_dioxide_heat_capacity
+
+ if(delta_toxins)
+ var/toxins_heat_capacity = SPECIFIC_HEAT_TOXIN*delta_toxins
+ heat_transferred -= toxins_heat_capacity*model.temperature
+ heat_capacity_transferred -= toxins_heat_capacity
+
+ old_self_heat_capacity = heat_capacity()*group_multiplier
+
+ if(border_multiplier)
+ oxygen -= delta_oxygen*border_multiplier/group_multiplier
+ carbon_dioxide -= delta_carbon_dioxide*border_multiplier/group_multiplier
+ nitrogen -= delta_nitrogen*border_multiplier/group_multiplier
+ toxins -= delta_toxins*border_multiplier/group_multiplier
+ else
+ oxygen -= delta_oxygen/group_multiplier
+ carbon_dioxide -= delta_carbon_dioxide/group_multiplier
+ nitrogen -= delta_nitrogen/group_multiplier
+ toxins -= delta_toxins/group_multiplier
+
+ var/moved_moles = (delta_oxygen + delta_carbon_dioxide + delta_nitrogen + delta_toxins)
+
+ if(trace_gases.len)
+ for(var/datum/gas/trace_gas in trace_gases)
+ var/delta = 0
+
+ delta = trace_gas.moles_archived/TRANSFER_FRACTION
+
+ if(border_multiplier)
+ trace_gas.moles -= delta*border_multiplier/group_multiplier
+ else
+ trace_gas.moles -= delta/group_multiplier
+
+ var/heat_cap_transferred = delta*trace_gas.specific_heat
+ heat_transferred += heat_cap_transferred*temperature_archived
+ heat_capacity_transferred += heat_cap_transferred
+ moved_moles += delta
+ update_values()
+
+ if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
+ var/new_self_heat_capacity = old_self_heat_capacity - heat_capacity_transferred
+ if(new_self_heat_capacity > MINIMUM_HEAT_CAPACITY)
+ if(border_multiplier)
+ temperature = (old_self_heat_capacity*temperature - heat_capacity_transferred*border_multiplier*temperature_archived)/new_self_heat_capacity
+ else
+ temperature = (old_self_heat_capacity*temperature - heat_capacity_transferred*border_multiplier*temperature_archived)/new_self_heat_capacity
+
+ temperature_mimic(model, model.thermal_conductivity, border_multiplier)
+
+ if((delta_temperature > MINIMUM_TEMPERATURE_TO_MOVE) || abs(moved_moles) > MINIMUM_MOLES_DELTA_TO_MOVE)
+ var/delta_pressure = temperature_archived*(total_moles + moved_moles) - model.temperature*(model.oxygen+model.carbon_dioxide+model.nitrogen+model.toxins)
+ return delta_pressure*R_IDEAL_GAS_EQUATION/volume
+ else
+ return 0
+
+ proc/check_both_then_temperature_share(datum/gas_mixture/sharer, conduction_coefficient)
+ var/delta_temperature = (temperature_archived - sharer.temperature_archived)
+
+ var/self_heat_capacity = heat_capacity_archived()
+ var/sharer_heat_capacity = sharer.heat_capacity_archived()
+
+ var/self_temperature_delta = 0
+ var/sharer_temperature_delta = 0
+
+ if((sharer_heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY))
+ var/heat = conduction_coefficient*delta_temperature* \
+ (self_heat_capacity*sharer_heat_capacity/(self_heat_capacity+sharer_heat_capacity))
+
+ self_temperature_delta = -heat/(self_heat_capacity*group_multiplier)
+ sharer_temperature_delta = heat/(sharer_heat_capacity*sharer.group_multiplier)
+ else
+ return 1
+
+ if((abs(self_temperature_delta) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) \
+ && (abs(self_temperature_delta) > MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND*temperature_archived))
+ return 0
+
+ if((abs(sharer_temperature_delta) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) \
+ && (abs(sharer_temperature_delta) > MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND*sharer.temperature_archived))
+ return -1
+
+ temperature += self_temperature_delta
+ sharer.temperature += sharer_temperature_delta
+
+ return 1
+ //Logic integrated from: temperature_share(sharer, conduction_coefficient) for efficiency
+
+ proc/check_me_then_temperature_share(datum/gas_mixture/sharer, conduction_coefficient)
+ var/delta_temperature = (temperature_archived - sharer.temperature_archived)
+
+ var/self_heat_capacity = heat_capacity_archived()
+ var/sharer_heat_capacity = sharer.heat_capacity_archived()
+
+ var/self_temperature_delta = 0
+ var/sharer_temperature_delta = 0
+
+ if((sharer_heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY))
+ var/heat = conduction_coefficient*delta_temperature* \
+ (self_heat_capacity*sharer_heat_capacity/(self_heat_capacity+sharer_heat_capacity))
+
+ self_temperature_delta = -heat/(self_heat_capacity*group_multiplier)
+ sharer_temperature_delta = heat/(sharer_heat_capacity*sharer.group_multiplier)
+ else
+ return 1
+
+ if((abs(self_temperature_delta) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) \
+ && (abs(self_temperature_delta) > MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND*temperature_archived))
+ return 0
+
+ temperature += self_temperature_delta
+ sharer.temperature += sharer_temperature_delta
+
+ return 1
+ //Logic integrated from: temperature_share(sharer, conduction_coefficient) for efficiency
+
+ proc/check_me_then_temperature_turf_share(turf/simulated/sharer, conduction_coefficient)
+ var/delta_temperature = (temperature_archived - sharer.temperature)
+
+ var/self_temperature_delta = 0
+ var/sharer_temperature_delta = 0
+
+ if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
+ var/self_heat_capacity = heat_capacity_archived()
+
+ if((sharer.heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY))
+ var/heat = conduction_coefficient*delta_temperature* \
+ (self_heat_capacity*sharer.heat_capacity/(self_heat_capacity+sharer.heat_capacity))
+
+ self_temperature_delta = -heat/(self_heat_capacity*group_multiplier)
+ sharer_temperature_delta = heat/sharer.heat_capacity
+ else
+ return 1
+
+ if((abs(self_temperature_delta) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) \
+ && (abs(self_temperature_delta) > MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND*temperature_archived))
+ return 0
+
+ temperature += self_temperature_delta
+ sharer.temperature += sharer_temperature_delta
+
+ return 1
+ //Logic integrated from: temperature_turf_share(sharer, conduction_coefficient) for efficiency
+
+ proc/check_me_then_temperature_mimic(turf/model, conduction_coefficient)
+ var/delta_temperature = (temperature_archived - model.temperature)
+ var/self_temperature_delta = 0
+
+ if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
+ var/self_heat_capacity = heat_capacity_archived()
+
+ if((model.heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY))
+ var/heat = conduction_coefficient*delta_temperature* \
+ (self_heat_capacity*model.heat_capacity/(self_heat_capacity+model.heat_capacity))
+
+ self_temperature_delta = -heat/(self_heat_capacity*group_multiplier)
+
+ if((abs(self_temperature_delta) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) \
+ && (abs(self_temperature_delta) > MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND*temperature_archived))
+ return 0
+
+ temperature += self_temperature_delta
+
+ return 1
+ //Logic integrated from: temperature_mimic(model, conduction_coefficient) for efficiency
+
+ proc/temperature_share(datum/gas_mixture/sharer, conduction_coefficient)
+
+ var/delta_temperature = (temperature_archived - sharer.temperature_archived)
+ if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
+ var/self_heat_capacity = heat_capacity_archived()
+ var/sharer_heat_capacity = sharer.heat_capacity_archived()
+ if(!group_multiplier)
+ message_admins("Error! The gas mixture (ref \ref[src]) has no group multiplier!")
+ return
+
+ if((sharer_heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY))
+ var/heat = conduction_coefficient*delta_temperature* \
+ (self_heat_capacity*sharer_heat_capacity/(self_heat_capacity+sharer_heat_capacity))
+
+ temperature -= heat/(self_heat_capacity*group_multiplier)
+ sharer.temperature += heat/(sharer_heat_capacity*sharer.group_multiplier)
+
+ proc/temperature_mimic(turf/model, conduction_coefficient, border_multiplier)
+ var/delta_temperature = (temperature - model.temperature)
+ if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
+ var/self_heat_capacity = heat_capacity()//_archived()
+ if(!group_multiplier)
+ message_admins("Error! The gas mixture (ref \ref[src]) has no group multiplier!")
+ return
+
+ if((model.heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY))
+ var/heat = conduction_coefficient*delta_temperature* \
+ (self_heat_capacity*model.heat_capacity/(self_heat_capacity+model.heat_capacity))
+
+ if(border_multiplier)
+ temperature -= heat*border_multiplier/(self_heat_capacity*group_multiplier)
+ else
+ temperature -= heat/(self_heat_capacity*group_multiplier)
+
+ proc/temperature_turf_share(turf/simulated/sharer, conduction_coefficient)
+ var/delta_temperature = (temperature_archived - sharer.temperature)
+ if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
+ var/self_heat_capacity = heat_capacity()
+
+ if((sharer.heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY))
+ var/heat = conduction_coefficient*delta_temperature* \
+ (self_heat_capacity*sharer.heat_capacity/(self_heat_capacity+sharer.heat_capacity))
+
+ temperature -= heat/(self_heat_capacity*group_multiplier)
+ sharer.temperature += heat/sharer.heat_capacity
+
+ proc/compare(datum/gas_mixture/sample)
+ //Purpose: Compares sample to self to see if within acceptable ranges that group processing may be enabled
+ //Called by: Airgroups trying to rebuild
+ //Inputs: Gas mix to compare
+ //Outputs: 1 if can rebuild, 0 if not.
+ if(!sample) return 0
+
+ if((abs(oxygen-sample.oxygen) > MINIMUM_AIR_TO_SUSPEND) && \
+ ((oxygen < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.oxygen) || (oxygen > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.oxygen)))
+ return 0
+ if((abs(nitrogen-sample.nitrogen) > MINIMUM_AIR_TO_SUSPEND) && \
+ ((nitrogen < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.nitrogen) || (nitrogen > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.nitrogen)))
+ return 0
+ if((abs(carbon_dioxide-sample.carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && \
+ ((carbon_dioxide < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.carbon_dioxide) || (oxygen > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.carbon_dioxide)))
+ return 0
+ if((abs(toxins-sample.toxins) > MINIMUM_AIR_TO_SUSPEND) && \
+ ((toxins < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.toxins) || (toxins > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.toxins)))
+ return 0
+
+ if(total_moles > MINIMUM_AIR_TO_SUSPEND)
+ if((abs(temperature-sample.temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) && \
+ ((temperature < (1-MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND)*sample.temperature) || (temperature > (1+MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND)*sample.temperature)))
+ //world << "temp fail [temperature] & [sample.temperature]"
+ return 0
+
+ if(sample.trace_gases.len)
+ for(var/datum/gas/trace_gas in sample.trace_gases)
+ if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND)
+ var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases
+ if(corresponding)
+ if((abs(trace_gas.moles - corresponding.moles) > MINIMUM_AIR_TO_SUSPEND) && \
+ ((corresponding.moles < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*trace_gas.moles) || (corresponding.moles > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*trace_gas.moles)))
+ return 0
+ else
+ return 0
+
+ if(trace_gases.len)
+ for(var/datum/gas/trace_gas in trace_gases)
+ if(trace_gas.moles > MINIMUM_AIR_TO_SUSPEND)
+ var/datum/gas/corresponding = locate(trace_gas.type) in sample.trace_gases
+ if(corresponding)
+ if((abs(trace_gas.moles - corresponding.moles) > MINIMUM_AIR_TO_SUSPEND) && \
+ ((trace_gas.moles < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*corresponding.moles) || (trace_gas.moles > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*corresponding.moles)))
+ return 0
+ else
+ return 0
+ return 1
+
+
+ proc/subtract(datum/gas_mixture/right_side)
+ //Purpose: Subtracts right_side from air_mixture. Used to help turfs mingle
+ //Called by: Pipelines ending in a break (or something)
+ //Inputs: Gas mix to remove
+ //Outputs: 1
+
+ oxygen -= right_side.oxygen
+ carbon_dioxide -= right_side.carbon_dioxide
+ nitrogen -= right_side.nitrogen
+ toxins -= right_side.toxins
+
+ if((trace_gases.len > 0)||(right_side.trace_gases.len > 0))
+ for(var/datum/gas/trace_gas in right_side.trace_gases)
+ var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases
+ if(!corresponding)
+ corresponding = new trace_gas.type()
+ trace_gases += corresponding
+
+ corresponding.moles -= trace_gas.moles
+ update_values()
+ return 1
\ No newline at end of file
diff --git a/code/ZAS/FEA_system.dm b/code/ZAS/FEA_system.dm
new file mode 100644
index 00000000000..dd2fca6ef21
--- /dev/null
+++ b/code/ZAS/FEA_system.dm
@@ -0,0 +1,178 @@
+/*
+Overview:
+ The air_master global variable is the workhorse for the system.
+
+Why are you archiving data before modifying it?
+ The general concept with archiving data and having each tile keep track of when they were last updated is to keep everything symmetric
+ and totally independent of the order they are read in an update cycle.
+ This prevents abnormalities like air/fire spreading rapidly in one direction and super slowly in the other.
+
+Why not just archive everything and then calculate?
+ Efficiency. While a for-loop that goes through all tils and groups to archive their information before doing any calculations seems simple, it is
+ slightly less efficient than the archive-before-modify/read method.
+
+Why is there a cycle check for calculating data as well?
+ This ensures that every connection between group-tile, tile-tile, and group-group is only evaluated once per loop.
+
+
+
+
+Important variables:
+ air_master.groups_to_rebuild (list)
+ A list of air groups that have had their geometry occluded and thus may need to be split in half.
+ A set of adjacent groups put in here will join together if validly connected.
+ This is done before air system calculations for a cycle.
+ air_master.tiles_to_update (list)
+ Turfs that are in this list have their border data updated before the next air calculations for a cycle.
+ Place turfs in this list rather than call the proc directly to prevent race conditions
+
+ turf/simulated.archive() and datum/air_group.archive()
+ This stores all data for.
+ If you modify, make sure to update the archived_cycle to prevent race conditions and maintain symmetry
+
+ atom/CanPass(atom/movable/mover, turf/target, height, air_group)
+ returns 1 for allow pass and 0 for deny pass
+ Turfs automatically call this for all objects/mobs in its turf.
+ This is called both as source.CanPass(target, height, air_group)
+ and target.CanPass(source, height, air_group)
+
+ Cases for the parameters
+ 1. This is called with args (mover, location, height>0, air_group=0) for normal objects.
+ 2. This is called with args (null, location, height=0, air_group=0) for flowing air.
+ 3. This is called with args (null, location, height=?, air_group=1) for determining group boundaries.
+
+ Cases 2 and 3 would be different for doors or other objects open and close fairly often.
+ (Case 3 would return 0 always while Case 2 would return 0 only when the door is open)
+ This prevents the necessity of re-evaluating group geometry every time a door opens/closes.
+
+
+Important Procedures
+ air_master.process()
+ This first processes the air_master update/rebuild lists then processes all groups and tiles for air calculations
+
+
+*/
+
+var/kill_air = 0
+var/tick_multiplier = 2
+
+atom/proc/CanPass(atom/movable/mover, turf/target, height=1.5, air_group = 0)
+ //Purpose: Determines if the object (or airflow) can pass this atom.
+ //Called by: Movement, airflow.
+ //Inputs: The moving atom (optional), target turf, "height" and air group
+ //Outputs: Boolean if can pass.
+
+ return (!density || !height || air_group)
+
+turf
+ CanPass(atom/movable/mover, turf/target, height=1.5,air_group=0)
+ if(!target) return 0
+
+ if(istype(mover)) // turf/Enter(...) will perform more advanced checks
+ return !density
+
+ else // Now, doing more detailed checks for air movement and air group formation
+ if(target.blocks_air||blocks_air)
+ return 0
+
+ for(var/obj/obstacle in src)
+ if(!obstacle.CanPass(mover, target, height, air_group))
+ return 0
+ for(var/obj/obstacle in target)
+ if(!obstacle.CanPass(mover, src, height, air_group))
+ return 0
+
+ return 1
+
+
+var/global/datum/controller/air_system/air_master
+
+datum
+ controller
+ air_system
+ //Geoemetry lists
+ var/list/turf/simulated/active_singletons = list()
+
+ //Special functions lists
+ var/list/turf/simulated/active_super_conductivity = list()
+ var/list/turf/simulated/high_pressure_delta = list()
+
+ //Geometry updates lists
+ var/list/turf/simulated/tiles_to_update = list()
+ var/list/turf/simulated/groups_to_rebuild = list()
+
+ var/current_cycle = 0
+ var/update_delay = 5 //How long between check should it try to process atmos again.
+ var/failed_ticks = 0 //How many ticks have runtimed?
+
+
+/* process()
+ //Call this to process air movements for a cycle
+
+ process_rebuild_select_groups()
+ //Used by process()
+ //Warning: Do not call this
+
+ rebuild_group(datum/air_group)
+ //Used by process_rebuild_select_groups()
+ //Warning: Do not call this, add the group to air_master.groups_to_rebuild instead
+ */
+
+
+ proc/setup()
+ //Purpose: Call this at the start to setup air groups geometry
+ // (Warning: Very processor intensive but only must be done once per round)
+ //Called by: Gameticker/Master controller
+ //Inputs: None.
+ //Outputs: None.
+
+ set background = 1
+ world << "\red \b Processing Geometry..."
+ sleep(-1)
+
+ var/start_time = world.timeofday
+
+ for(var/turf/simulated/S in world)
+ if(S.z < 5)
+ if(!S.blocks_air && !S.zone && S.z < 5) // Added last check to force skipping asteroid z-levels -- TLE
+ new/zone(S)
+
+ S.update_air_properties()
+
+ world << "\red \b Geometry processed in [time2text(world.timeofday-start_time, "mm:ss")] minutes!"
+ spawn start()
+
+ proc/start()
+ //Purpose: This is kicked off by the master controller, and controls the processing of all atmosphere.
+ //Called by: Master controller
+ //Inputs: None.
+ //Outputs: None.
+
+ set background = 1
+ while(1)
+ if(!kill_air)
+ current_cycle++
+ var/success = tick() //Changed so that a runtime does not crash the ticker.
+ if(!success) //Runtimed.
+ failed_ticks++
+ if(failed_ticks > 20)
+ world << "ERROR IN ATMOS TICKER. Killing air simulation!"
+ kill_air = 1
+ sleep(max(5,update_delay*tick_multiplier))
+
+ proc/tick()
+
+ if(tiles_to_update.len > 0) //If there are tiles to update, do so.
+ for(var/turf/simulated/T in tiles_to_update)
+ spawn T.update_air_properties()
+ tiles_to_update = list()
+
+ for(var/zone/Z in zones)
+ if(Z.last_update < current_cycle)
+ Z.process()
+ if(Z) Z.last_update = current_cycle
+
+ for(var/obj/fire/F)
+ F.process()
+
+ return 1
\ No newline at end of file
diff --git a/code/ZAS/FEA_turf_tile.dm b/code/ZAS/FEA_turf_tile.dm
new file mode 100644
index 00000000000..c8dda862530
--- /dev/null
+++ b/code/ZAS/FEA_turf_tile.dm
@@ -0,0 +1,205 @@
+atom/var/pressure_resistance = ONE_ATMOSPHERE
+turf
+ assume_air(datum/gas_mixture/giver) //use this for machines to adjust air
+ del(giver)
+ return 0
+
+ return_air()
+ //Create gas mixture to hold data for passing
+ var/datum/gas_mixture/GM = new
+
+ GM.oxygen = oxygen
+ GM.carbon_dioxide = carbon_dioxide
+ GM.nitrogen = nitrogen
+ GM.toxins = toxins
+
+ GM.temperature = temperature
+ GM.update_values()
+
+ return GM
+
+ remove_air(amount as num)
+ var/datum/gas_mixture/GM = new
+
+ var/sum = oxygen + carbon_dioxide + nitrogen + toxins
+ if(sum>0)
+ GM.oxygen = (oxygen/sum)*amount
+ GM.carbon_dioxide = (carbon_dioxide/sum)*amount
+ GM.nitrogen = (nitrogen/sum)*amount
+ GM.toxins = (toxins/sum)*amount
+
+ GM.temperature = temperature
+ GM.update_values()
+
+ return GM
+
+
+turf
+ simulated
+
+ var/current_graphic = null
+
+ var/tmp
+ datum/gas_mixture/air
+
+ processing = 1
+ group_border = 0
+ length_space_border = 0
+
+ air_check_directions = 0 //Do not modify this, just add turf to air_master.tiles_to_update
+
+ archived_cycle = 0
+ current_cycle = 0
+
+ obj/fire/active_hotspot
+
+ temperature_archived //USED ONLY FOR SOLIDS
+ being_superconductive = 0
+
+
+ proc
+ process_cell()
+ update_air_properties()
+ archive()
+
+ mimic_air_with_tile(turf/model)
+ share_air_with_tile(turf/simulated/sharer)
+
+ mimic_temperature_with_tile(turf/model)
+ share_temperature_with_tile(turf/simulated/sharer)
+
+
+ super_conduct()
+
+ update_visuals()
+ overlays = null
+
+ var/siding_icon_state = return_siding_icon_state()
+ if(siding_icon_state)
+ overlays += image('floors.dmi',siding_icon_state)
+ var/datum/gas_mixture/model = return_air()
+ switch(model.graphic)
+ if("plasma")
+ overlays.Add(plmaster)
+ if("sleeping_agent")
+ overlays.Add(slmaster)
+
+
+
+ New()
+ ..()
+
+ if(!blocks_air)
+ air = new
+
+ air.oxygen = oxygen
+ air.carbon_dioxide = carbon_dioxide
+ air.nitrogen = nitrogen
+ air.toxins = toxins
+
+ air.temperature = temperature
+ air.update_values()
+
+ if(air_master)
+ air_master.tiles_to_update.Add(src)
+
+ find_zone()
+
+// air.parent = src //TODO DEBUG REMOVE
+
+ else
+ if(air_master)
+ for(var/direction in cardinal)
+ var/turf/simulated/floor/target = get_step(src,direction)
+ if(istype(target))
+ air_master.tiles_to_update.Add(target)
+
+ Del()
+ if(active_hotspot)
+ del(active_hotspot)
+ if(blocks_air)
+ for(var/direction in list(NORTH, SOUTH, EAST, WEST))
+ var/turf/simulated/tile = get_step(src,direction)
+ if(istype(tile) && !tile.blocks_air)
+ air_master.tiles_to_update.Add(tile)
+ ..()
+
+ assume_air(datum/gas_mixture/giver)
+ if(!giver) return 0
+ if(zone)
+ zone.air.merge(giver)
+ return 1
+ else
+ return ..()
+
+ archive()
+ if(air) //For open space like floors
+ air.archive()
+
+ temperature_archived = temperature
+ archived_cycle = air_master.current_cycle
+
+ share_air_with_tile(turf/simulated/T)
+ return air.share(T.air)
+
+ mimic_air_with_tile(turf/T)
+ return air.mimic(T)
+
+ return_air()
+ if(zone)
+ return zone.air
+ else if(air)
+ return air
+
+ else
+ return ..()
+
+ remove_air(amount as num)
+ if(zone)
+ var/datum/gas_mixture/removed = null
+ removed = zone.air.remove(amount)
+ return removed
+ else if(air)
+ var/datum/gas_mixture/removed = null
+ removed = air.remove(amount)
+
+ if(air.check_tile_graphic())
+ update_visuals(air)
+ return removed
+
+ else
+ return ..()
+
+ update_air_properties()//OPTIMIZE
+ air_check_directions = 0
+
+ for(var/direction in cardinal)
+ if(CanPass(null, get_step(src,direction), 0, 0))
+ air_check_directions |= direction
+
+ if(zone)
+ for(var/direction in cardinal)
+ if(air_check_directions&direction)
+
+ var/turf/simulated/T = get_step(src,direction)
+ if(T)
+ ZConnect(src,T)
+ else
+ var/turf/simulated/T = get_step(src,direction)
+ if(T)
+ ZDisconnect(src,T)
+ else
+
+ for(var/direction in cardinal)
+ if(air_check_directions&direction)
+ var/turf/simulated/T = get_step(src,direction)
+ if(T.zone)
+ T.zone.AddTurf(src)
+ break
+ if(!zone)
+ new/zone(src)
+
+ if(air_check_directions)
+ processing = 1
+ else
+ processing = 0
\ No newline at end of file
diff --git a/code/ZAS/Fire.dm b/code/ZAS/Fire.dm
index f265c45877a..7c2d2292a2a 100644
--- a/code/ZAS/Fire.dm
+++ b/code/ZAS/Fire.dm
@@ -1,13 +1,16 @@
vs_control/var/IgnitionLevel = 10 //Moles of oxygen+plasma - co2 needed to burn.
-#define OXYGEN
+//Some legacy definitions so fires can be started.
atom/proc/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
return null
+
turf/proc/hotspot_expose(exposed_temperature, exposed_volume, soh = 0)
+
+
turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh)
- if(fire_protection) return
+ if(fire_protection > world.time-300) return
var/datum/gas_mixture/air_contents = return_air(1)
if(!air_contents)
return 0
@@ -25,19 +28,11 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh)
return 1
var/datum/gas/volatile_fuel/fuel = locate() in air_contents.trace_gases
var/obj/liquid_fuel/liquid = locate() in src
- var/fuel_level = 0
- var/liquid_level = 0
- if(fuel) fuel_level = fuel.moles
- if(liquid) liquid_level = liquid.amount
- var/total_fuel = air_contents.toxins + fuel_level + liquid_level
- if((air_contents.oxygen + air_contents.toxins + fuel_level*1.5 + liquid_level*1.5) - (air_contents.carbon_dioxide*0.25) > vsc.IgnitionLevel && total_fuel > 0.5)
+ if(air_contents.calculate_firelevel(liquid) > vsc.IgnitionLevel && (fuel || liquid || air_contents.toxins > 0.5))
igniting = 1
if(air_contents.oxygen < 0.5)
return 0
- if(parent&&parent.group_processing)
- parent.suspend_group_processing()
-
if(! (locate(/obj/fire) in src))
var/obj/fire/F = new(src,1000)
F.temperature = exposed_temperature
@@ -48,112 +43,9 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh)
return igniting
-obj/effect/hotspot
- //Icon for fire on turfs, also helps for nurturing small fires until they are full tile
-
- anchored = 1
-
- mouse_opacity = 0
-
- //luminosity = 3
-
- icon = 'fire.dmi'
- icon_state = "1"
-
- layer = TURF_LAYER
-
- var
- volume = 125
- temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST
-
- just_spawned = 1
-
- bypassing = 0
-
-obj/effect/hotspot/proc/perform_exposure()
- var/turf/simulated/floor/location = loc
- if(!istype(location))
- return 0
-
- if(volume > CELL_VOLUME*0.95)
- bypassing = 1
- else bypassing = 0
-
- if(bypassing)
- if(!just_spawned)
- volume = location.air.fuel_burnt*FIRE_GROWTH_RATE
- temperature = location.air.temperature
- else
- var/datum/gas_mixture/affected = location.air.remove_ratio(volume/location.air.volume)
-
- affected.temperature = temperature
-
- affected.react()
-
- temperature = affected.temperature
- volume = affected.fuel_burnt*FIRE_GROWTH_RATE
-
- location.assume_air(affected)
-
- for(var/atom/item in loc)
- item.temperature_expose(null, temperature, volume)
-
-obj/effect/hotspot/process(turf/simulated/list/possible_spread)
- if(just_spawned)
- just_spawned = 0
- return 0
-
- var/turf/simulated/floor/location = loc
- if(!istype(location))
- del(src)
-
- if((temperature < FIRE_MINIMUM_TEMPERATURE_TO_EXIST) || (volume <= 1))
- del(src)
-
- if(location.air.toxins < 0.5 || location.air.oxygen < 0.5)
- del(src)
-
-
- perform_exposure()
-
- if(location.wet) location.wet = 0
-
- if(bypassing)
- icon_state = "3"
- location.burn_tile()
-
- //Possible spread due to radiated heat
- if(location.air.temperature > FIRE_MINIMUM_TEMPERATURE_TO_SPREAD)
- var/radiated_temperature = location.air.temperature*FIRE_SPREAD_RADIOSITY_SCALE
-
- for(var/turf/simulated/possible_target in possible_spread)
- if(!locate(/obj/effect/hotspot) in possible_target)
- possible_target.hotspot_expose(radiated_temperature, CELL_VOLUME/4)
-
- else
- if(volume > CELL_VOLUME*0.4)
- icon_state = "2"
- else
- icon_state = "1"
-
- return 1
-
-obj/effect/hotspot/New()
- ..()
- dir = pick(cardinal)
- sd_SetLuminosity(3)
-
-obj/effect/hotspot/Del()
- src.sd_SetLuminosity(0)
- loc = null
- ..()
-
-var
- fire_ratio_1 = 0.05
-
obj
fire
- //Icon for fire on turfs, also helps for nurturing small fires until they are full tile
+ //Icon for fire on turfs.
anchored = 1
mouse_opacity = 0
@@ -168,84 +60,82 @@ obj
var
volume = CELL_VOLUME
temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST
- firelevel = 10000
+ firelevel = 10000 //Calculated by gas_mixture.calculate_firelevel()
archived_firelevel = 0
process()
+
if(firelevel > vsc.IgnitionLevel)
+
var/turf/simulated/floor/S = loc
- if(!S.zone) del src
- //src.temperature += (src.firelevel/FireTempDivider+FireOffset - src.temperature) / FireRate
+ if(!S.zone) del src //Cannot exist where zones are broken.
+
if(istype(S,/turf/simulated/floor))
var
datum/gas_mixture/air_contents = S.return_air()
+ //Get whatever trace fuels are in the area
datum/gas/volatile_fuel/fuel = locate(/datum/gas/volatile_fuel/) in air_contents.trace_gases
- fuel_level = 0
+ //Also get liquid fuels on the ground.
obj/liquid_fuel/liquid = locate() in S
- liquid_level = 0
- if(fuel) fuel_level = fuel.moles
- if(liquid)
- liquid_level = liquid.amount
- if(liquid.amount <= 0)
- del liquid
- liquid_level = 0
+ firelevel = air_contents.calculate_firelevel(liquid)
- firelevel = (air_contents.oxygen + air_contents.toxins + fuel_level*1.5 + liquid_level*1.5) - (air_contents.carbon_dioxide*0.25)
+ //Ensure that there is an appropriate amount of fuel and O2 here.
+ if(firelevel > 25 && (air_contents.toxins || fuel || liquid))
- firelevel = min(firelevel,vsc.IgnitionLevel*5)
-
- if(firelevel > vsc.IgnitionLevel * 1.5 && (air_contents.toxins || fuel_level || liquid_level))
for(var/direction in cardinal)
if(S.air_check_directions&direction) //Grab all valid bordering tiles
- var/turf/simulated/enemy_tile = get_step(S, direction)
- if(istype(enemy_tile))
- if(enemy_tile.fire_protection)
- firelevel -= vsc.IgnitionLevel
- continue
- if(!(locate(/obj/fire) in enemy_tile))
- if( prob( firelevel/(vsc.IgnitionLevel*0.1) ) )
- new/obj/fire(enemy_tile,firelevel)
- // else
- // world << "Spread Probability: [firelevel/(vsc.IgnitionLevel*0.1)]%."
- // else
- // world << "There's a fire there bitch."
- // else
- // world << "[enemy_tile] cannot be spread to."
- //else
- // world << "Not enough firelevel to spread: [firelevel]/[vsc.IgnitionLevel*1.5]"
- var/datum/gas_mixture/flow = air_contents.remove_ratio(0.5)
- //n = PV/RT, taking the volume of a single tile from the gas.
+ var/turf/simulated/enemy_tile = get_step(S, direction)
+
+ if(istype(enemy_tile))
+ //If extinguisher mist passed over the turf it's trying to spread to, don't spread and
+ //reduce firelevel.
+ if(enemy_tile.fire_protection > world.time-30)
+ firelevel -= 150
+ continue
+
+ //Spread the fire.
+ if(!(locate(/obj/fire) in enemy_tile))
+ if( prob( firelevel/2.5 ) )
+ new/obj/fire(enemy_tile,firelevel)
+
+ var/datum/gas_mixture/flow = air_contents.remove_ratio(0.5) //Take half the air from the room I guess.
if(flow)
- if(flow.oxygen > 0.3 && (flow.toxins || fuel_level || liquid))
+ //Ensure adequate oxygen and fuel.
+ if(flow.oxygen > 0.3 && (flow.toxins || fuel || liquid))
+ //Change icon depending on the fuel, and thus temperature.
icon_state = "1"
- if(firelevel > vsc.IgnitionLevel * 2)
+ if(firelevel > 25)
icon_state = "2"
- if(firelevel > vsc.IgnitionLevel * 3.5)
+ if(firelevel > 100)
icon_state = "3"
+
+ //Ensure flow temperature is higher than minimum fire temperatures.
flow.temperature = max(PLASMA_MINIMUM_BURN_TEMPERATURE+0.1,flow.temperature)
+
+ //Burn the gas mixture.
flow.zburn(liquid)
else
+
del src
- S.assume_air(flow)
+ S.assume_air(flow) //Then put it back where you found it.
+
else
- //world << "No air at all."
del src
else
del src
else
- //world << "Insufficient fire level for ignition: [firelevel]/[IgnitionLevel]"
del src
for(var/mob/living/carbon/human/M in loc)
- M.FireBurn(firelevel/(vsc.IgnitionLevel*10))
+ M.FireBurn(min(max(0.1,firelevel / 20),10)) //Burn the humans!
New(newLoc,fl)
@@ -254,7 +144,7 @@ obj
sd_SetLuminosity(3)
firelevel = fl
for(var/mob/living/carbon/human/M in loc)
- M.FireBurn(firelevel/(vsc.IgnitionLevel*10))
+ M.FireBurn(min(max(0.1,firelevel / 20),10)) //Burn the humans!
Del()
if (istype(loc, /turf/simulated))
@@ -265,74 +155,162 @@ obj
..()
obj/liquid_fuel
- icon = 'effects.dmi'
- icon_state = "slube"
+ //Liquid fuel is used for things that used to rely on volatile fuels or plasma being contained to a couple tiles.
+ icon = 'icons/effects/effects.dmi'
+ icon_state = "fuel"
layer = TURF_LAYER+0.2
anchored = 1
- var/amount = 1
+ var/amount = 1 //Basically moles.
- New(newLoc)
+ New(newLoc,amt=1)
+ src.amount = amt
+
+ //Be absorbed by any other liquid fuel in the tile.
for(var/obj/liquid_fuel/other in newLoc)
if(other != src)
other.amount += src.amount
+ spawn other.Spread()
del src
+ return
+
+ Spread()
. = ..()
-vs_control/var/switch_fire = 1
+ proc/Spread()
+ //Allows liquid fuels to sometimes flow into other tiles.
+ if(amount < 0.5) return
+ var/turf/simulated/S = loc
+ if(!istype(S)) return
+ for(var/d in cardinal)
+ if(S.air_check_directions & d)
+ if(rand(25))
+ var/turf/simulated/O = get_step(src,d)
+ new/obj/liquid_fuel(O,amount*0.25)
+ amount *= 0.75
-turf/simulated/var/fire_protection = 0
+ flamethrower_fuel
+ icon_state = "mustard"
+ anchored = 0
+ New(newLoc, amt = 1, d = 0)
+ dir = d //Setting this direction means you won't get torched by your own flamethrower.
+ . = ..()
+ Spread()
+ //The spread for flamethrower fuel is much more precise, to create a wide fire pattern.
+ if(amount < 0.1) return
+ var/turf/simulated/S = loc
+ if(!istype(S)) return
+
+ for(var/d in list(turn(dir,90),turn(dir,-90)))
+ if(S.air_check_directions & d)
+ var/turf/simulated/O = get_step(S,d)
+ new/obj/liquid_fuel/flamethrower_fuel(O,amount*0.25,d)
+ O.hotspot_expose((T20C*2) + 380,500) //Light flamethrower fuel on fire immediately.
+
+ amount *= 0.5
+
+
+turf/simulated/var/fire_protection = 0 //Protects newly extinguished tiles from being overrun again.
+turf/proc/apply_fire_protection()
+turf/simulated/apply_fire_protection()
+ fire_protection = world.time
datum/gas_mixture/proc/zburn(obj/liquid_fuel/liquid)
- if(vsc.switch_fire)
- . = fire()
- if(liquid && liquid.amount > 0)
- oxygen -= fire_ratio_1
- liquid.amount = max(liquid.amount-fire_ratio_1,0)
- carbon_dioxide += fire_ratio_1
- if(liquid.amount <= 0)
- del liquid
- return
+ //This proc is similar to fire(), but uses a simple logarithm to calculate temp, and is thus more stable with ZAS.
if(temperature > PLASMA_MINIMUM_BURN_TEMPERATURE)
var
- fuel_level = 0
+ total_fuel = toxins
+ fuel_sources = 0 //We'll divide by this later so that fuel is consumed evenly.
datum/gas/volatile_fuel/fuel = locate() in trace_gases
- liquid_level = 0
- if(fuel) fuel_level = fuel.moles
- if(liquid) liquid_level = liquid.amount
- if(liquid && liquid_level <= 0)
- del liquid
- liquid_level = 0
- if(oxygen > 0.3 && (toxins || fuel_level || liquid_level))
- if(toxins && temperature < PLASMA_UPPER_TEMPERATURE)
- temperature += (FIRE_PLASMA_ENERGY_RELEASED*fire_ratio_1) / heat_capacity()
- if((fuel_level || liquid_level) && temperature < PLASMA_UPPER_TEMPERATURE)
- temperature += (FIRE_CARBON_ENERGY_RELEASED*fire_ratio_1) / heat_capacity()
+ if(fuel)
+ //Volatile Fuel
+ total_fuel += fuel.moles
+ fuel_sources++
- if(toxins > fire_ratio_1)
- oxygen -= vsc.plc.OXY_TO_PLASMA*fire_ratio_1
- toxins -= fire_ratio_1
- carbon_dioxide += fire_ratio_1
- else if(toxins)
- oxygen -= toxins * vsc.plc.OXY_TO_PLASMA
- carbon_dioxide += toxins
- toxins = 0
+ if(liquid)
+ //Liquid Fuel
+ if(liquid.amount <= 0)
+ del liquid
+ else
+ total_fuel += liquid.amount
+ fuel_sources++
- if(fuel_level > fire_ratio_1/1.5)
- oxygen -= vsc.plc.OXY_TO_PLASMA*fire_ratio_1
- fuel.moles -= fire_ratio_1
- carbon_dioxide += fire_ratio_1
+ //Toxins
+ if(toxins > 0.3) fuel_sources++
- else if(fuel_level)
- oxygen -= fuel.moles * vsc.plc.OXY_TO_PLASMA
- carbon_dioxide += fuel.moles
- fuel.moles = 0
+ if(!fuel_sources) return 0 //If there's no fuel, there's no burn. Can't divide by zero anyway.
- if(liquid_level > 0)
- oxygen -= fire_ratio_1
- liquid.amount = max(liquid.amount-fire_ratio_1,0)
- carbon_dioxide += fire_ratio_1
- if(liquid.amount <= 0)
- del liquid
- return 1
- return 0
\ No newline at end of file
+ if(oxygen > 0.3)
+
+ //Calculate the firelevel.
+ var/firelevel = calculate_firelevel(liquid)
+
+ //Reaches a maximum practical temperature of around 2750.
+
+ temperature = 1000*log(0.016*firelevel + 1.45)
+
+ //Consume some gas.
+ var/consumed_gas = min(oxygen,0.002*firelevel,total_fuel) / fuel_sources
+
+ oxygen -= consumed_gas
+
+ toxins = max(0,toxins-consumed_gas)
+
+ if(fuel)
+ fuel.moles -= consumed_gas
+ if(fuel.moles <= 0) del fuel
+
+ if(liquid)
+ liquid.amount -= consumed_gas
+ if(liquid.amount <= 0) del liquid
+
+ update_values()
+ return consumed_gas*fuel_sources
+ return 0
+
+datum/gas_mixture/proc/calculate_firelevel(obj/liquid_fuel/liquid)
+ //Calculates the firelevel based on one equation instead of having to do this multiple times in different areas.
+ var
+ datum/gas/volatile_fuel/fuel = locate() in trace_gases
+ fuel_level = 0
+ liquid_level = 0
+
+ if(fuel) fuel_level = fuel.moles
+ if(liquid) liquid_level = liquid.amount
+ return oxygen + toxins + liquid_level*15 + fuel_level*5
+
+/mob/living/carbon/human/proc/FireBurn(mx as num)
+ //Burns mobs due to fire. Respects heat transfer coefficients on various body parts.
+
+ var
+ head_exposure = 1
+ chest_exposure = 1
+ groin_exposure = 1
+ legs_exposure = 1
+ arms_exposure = 1
+
+ //Get heat transfer coefficients for clothing.
+ for(var/obj/item/clothing/C in src)
+ if(l_hand == C || r_hand == C) continue
+ if(C.body_parts_covered & HEAD)
+ head_exposure *= C.heat_transfer_coefficient
+ if(C.body_parts_covered & UPPER_TORSO)
+ chest_exposure *= C.heat_transfer_coefficient
+ if(C.body_parts_covered & LOWER_TORSO)
+ groin_exposure *= C.heat_transfer_coefficient
+ if(C.body_parts_covered & LEGS)
+ legs_exposure *= C.heat_transfer_coefficient
+ if(C.body_parts_covered & ARMS)
+ arms_exposure *= C.heat_transfer_coefficient
+
+ //Always check these damage procs first if fire damage isn't working. They're probably what's wrong.
+
+ apply_damage(2.5*mx*head_exposure, BURN, "head", 0, 0, "Fire")
+ apply_damage(2.5*mx*chest_exposure, BURN, "chest", 0, 0, "Fire")
+ apply_damage(2.0*mx*groin_exposure, BURN, "groin", 0, 0, "Fire")
+ apply_damage(0.6*mx*legs_exposure, BURN, "l_leg", 0, 0, "Fire")
+ apply_damage(0.6*mx*legs_exposure, BURN, "r_leg", 0, 0, "Fire")
+ apply_damage(0.4*mx*arms_exposure, BURN, "l_arm", 0, 0, "Fire")
+ apply_damage(0.4*mx*arms_exposure, BURN, "r_arm", 0, 0, "Fire")
+
+ flash_pain()
\ No newline at end of file
diff --git a/code/ZAS/Functions.dm b/code/ZAS/Functions.dm
index ab52842dd1f..b9d88a84f22 100644
--- a/code/ZAS/Functions.dm
+++ b/code/ZAS/Functions.dm
@@ -1,43 +1,34 @@
zone
proc
AddTurf(turf/T)
+ //Adds the turf to contents, increases the size of the zone, and sets the zone var.
if(T in contents) return
contents += T
air.group_multiplier++
T.zone = src
RemoveTurf(turf/T)
+ //Same, but in reverse.
if(!(T in contents)) return
contents -= T
air.group_multiplier--
T.zone = null
- DivideAir(ratio)
- ratio = min(1,max(0,ratio))
- air.oxygen *= ratio
- air.oxygen = QUANTIZE(air.oxygen)
- air.nitrogen *= ratio
- air.nitrogen = QUANTIZE(air.nitrogen)
- air.toxins *= ratio
- air.toxins = QUANTIZE(air.toxins)
- air.carbon_dioxide *= ratio
- air.carbon_dioxide = QUANTIZE(air.carbon_dioxide)
- if(air.trace_gases.len)
- for(var/datum/gas/trace_gas in air.trace_gases)
- trace_gas.moles *= ratio
- trace_gas.moles = QUANTIZE(trace_gas.moles)
- air.temperature = air.temperature*ratio + TCMB*(1-ratio)
- air.temperature = QUANTIZE(air.temperature)
-
AddSpace(turf/space/S)
+ //Adds a space tile to the list, and creates the list if null.
if(istype(S,/turf/space))
if(!space_tiles) space_tiles = list()
space_tiles += S
+
RemoveSpace(turf/space/S)
+ //Removes a space tile from the list, and deletes the list if length is 0.
if(space_tiles)
space_tiles -= S
if(!space_tiles.len) space_tiles = null
turf/proc/HasDoor(turf/O)
+ //Checks for the presence of doors, used for zone spreading and connection.
+ //A positive numerical argument checks only for closed doors.
+ //Another turf as an argument checks for windoors between here and there.
for(var/obj/machinery/door/D in src)
if(isnum(O) && O)
if(!D.density) continue
@@ -48,110 +39,155 @@ turf/proc/HasDoor(turf/O)
return 1
turf/proc/find_zone()
+ //Allows newly generated turfs to join up with a nearby zone.
+ if(world.time < 10) return
for(var/d in cardinal)
var/turf/T = get_step(src,d)
- if(!T || !T.zone) continue
+ if(!T || !T.zone || !T.ZCanPass(src)) continue
if(!zone)
zone = T.zone
zone.AddTurf(src)
else if(T.zone != zone)
ZConnect(src,T)
+turf/proc/check_connections()
+ //Checks for new connections that can be made.
+ for(var/d in cardinal)
+ var/turf/T = get_step(src,d)
+ if(!T || !T.zone || !T.CanPass(0,src,0,0)) continue
+ if(T.zone != zone)
+ ZConnect(src,T)
+
+turf/proc/check_for_space()
+ //Checks for space around the turf.
+ for(var/d in cardinal)
+ var/turf/T = get_step(src,d)
+ if(istype(T,/turf/space) && T.CanPass(0,src,0,0))
+ zone.AddSpace(T)
+
proc
ZMerge(zone/A,zone/B)
- //world << "Merge occured."
+ //Merges two zones so that they are one.
var
a_size = A.air.group_multiplier
b_size = B.air.group_multiplier
c_size = a_size + b_size
new_contents = A.contents + B.contents
+ //Set air multipliers to one so air represents gas per tile.
A.air.group_multiplier = 1
B.air.group_multiplier = 1
+ //Remove some air proportional to the size of this zone.
A.air.remove_ratio(a_size/c_size)
B.air.remove_ratio(b_size/c_size)
+
+ //Merge the gases and set the multiplier to the sum of the old ones.
A.air.merge(B.air)
A.air.group_multiplier = c_size
+ //Check for connections to merge into the new zone.
for(var/connection/C in B.connections)
if((C.A in new_contents) && (C.B in new_contents))
del C
continue
+ if(!A.connections) A.connections = list()
A.connections += C
+
+ //Add space tiles.
A.space_tiles += B.space_tiles
+
+ //Add contents.
A.contents = new_contents
+
+ //Set all the zone vars.
for(var/turf/T in B.contents)
T.zone = A
+
del B
ZConnect(turf/A,turf/B)
+ //Connects two zones by forming a connection object representing turfs A and B.
+
+ //Make sure that if it's space, it gets added to space_tiles instead.
if(istype(B,/turf/space))
if(A.zone)
A.zone.AddSpace(B)
- //world << "Space added."
return
if(istype(A,/turf/space))
if(B.zone)
- B.zone.AddSpace(B)
- //world << "Space added."
+ B.zone.AddSpace(A)
return
+
+ //Make some preliminary checks to see if the connection is valid.
if(!A.zone || !B.zone) return
if(A.zone == B.zone) return
if(!A.CanPass(0,B,0,0)) return
+
+ //Ensure the connection isn't already made.
for(var/connection/C in A.zone.connections)
if((C.A == A && C.B == B) || (C.A == B && C.B == A))
return
- var/connection/C = new(A,B)
- if(A.HasDoor(B) || B.HasDoor(A)) C.indirect = 1
- //world << "Connection Formed: [A] --> [B] [(C.indirect?"Indirect":"Direct")]"
- //A.overlays += 'zone_connection_A.dmi'
- //B.overlays += 'zone_connection_B.dmi'
- //spawn(10)
- // A.overlays -= 'zone_connection_A.dmi'
- // B.overlays -= 'zone_connection_B.dmi'
+ var/connection/C = new(A,B)
+
+ //Ensure zones separated by doors do not merge.
+ if(A.HasDoor(B) || B.HasDoor(A)) C.indirect = 1
ZDisconnect(turf/A,turf/B)
+ //Removes a zone connection. Can split zones in the case of a permanent barrier.
+
+ //If one of them doesn't have a zone, it might be space, so check for that.
if(A.zone && B.zone)
+ //If the two zones are different, just remove a connection.
if(A.zone != B.zone)
for(var/connection/C in A.zone.connections)
if((C.A == A && C.B == B) || (C.A == B && C.B == A))
- //world << "Connection Dissolved: [A] -/-> [B] [(C.indirect?"Indirect":"Direct")]"
- /*A.overlays += 'zone_connection_A.dmi'
- B.overlays += 'zone_connection_B.dmi'
- spawn(10)
- A.overlays -= 'zone_connection_A.dmi'
- B.overlays -= 'zone_connection_B.dmi'*/
del C
- /*else
+ //If they're the same, split the zone at this line.
+ else
+ //Preliminary checks to prevent stupidity.
if(A == B) return
if(A.CanPass(0,B,0,0)) return
if(A.HasDoor(B) || B.HasDoor(A)) return
+
+ //Do a test fill. If turf B is still in the floodfill, then the zone isn't really split.
var/zone/oldzone = A.zone
var/list/test = FloodFill(A)
if(B in test) return
+
else
- var/zone/Z = new(test,oldzone.air)
+ var/zone/Z = new(test,oldzone.air) //Create a new zone based on the old air and the test fill.
+
+ //Add connections from the old zone.
for(var/connection/C in oldzone.connections)
if((A in Z.contents) || (B in Z.contents))
if(!Z.connections) Z.connections = list()
Z.connections += C
+
+ //Check for space.
+ for(var/turf/T in test)
+ T.check_for_space()
+
+ //Make a new, identical air mixture for the other zone.
var/datum/gas_mixture/Y_Air = new
Y_Air.copy_from(oldzone.air)
- var/zone/Y = new(B,Y_Air)
+
+ var/zone/Y = new(B,Y_Air) //Make a new zone starting at B and using Y_Air.
+
+ //Add relevant connections from old zone.
for(var/connection/C in oldzone.connections)
if((A in Y.contents) || (B in Y.contents))
if(!Y.connections) Y.connections = list()
Y.connections += C
+
+ //Add the remaining space tiles to this zone.
+ for(var/turf/space/T in oldzone.space_tiles)
+ if(!(T in Z.space_tiles))
+ Y.AddSpace(T)
+
oldzone.air = null
del oldzone
- world << "Zone Split: [A] / [B]"
- A.overlays += 'zone_connection_A.dmi'
- B.overlays += 'zone_connection_B.dmi'
- spawn(10)
- A.overlays -= 'zone_connection_A.dmi'
- B.overlays -= 'zone_connection_B.dmi'*/
else
if(istype(A,/turf/space) && B.zone)
B.zone.RemoveSpace(A)
diff --git a/code/ZAS/Plasma.dm b/code/ZAS/Plasma.dm
index df25a974578..858799a2729 100644
--- a/code/ZAS/Plasma.dm
+++ b/code/ZAS/Plasma.dm
@@ -1,252 +1,139 @@
pl_control/var
PLASMA_DMG = 3
- PLASMA_DMG_NAME = "Plasma Damage Multiplier"
- PLASMA_DMG_DESC = "Multiplier on how much damage inhaling plasma can do."
- OXY_TO_PLASMA = 1
- OXY_TO_PLASMA_NAME = "O2/Plasma Ratio"
- OXY_TO_PLASMA_DESC = "Multiplier for the ratio of oxygen to plasma required in fires."
+ CLOTH_CONTAMINATION = 0 //If this is on, plasma does damage by getting into cloth.
- CLOTH_CONTAMINATION = 1 //If this is on, plasma does damage by getting into cloth.
- CLOTH_CONTAMINATION_NAME = "Plasma - Cloth Contamination"
- CLOTH_CONTAMINATION_RANDOM = 60
- CLOTH_CONTAMINATION_METHOD = "Toggle"
- CLOTH_CONTAMINATION_DESC = "If set to nonzero, plasma will contaminate cloth items (uniforms, backpacks, etc.)\
- and cause a small amount of damage over time to anyone carrying or wearing them. Contamination can be detected\
- with a Health Analyzer, and washed off in the washer."
-
- ALL_ITEM_CONTAMINATION = 0 //If this is on, any item can be contaminated, so suits and tools must be discarded or
- //decontaminated.
- ALL_ITEM_CONTAMINATION_NAME = "Plasma - Full Contamination"
- ALL_ITEM_CONTAMINATION_RANDOM = 10
- ALL_ITEM_CONTAMINATION_METHOD = "Toggle"
- ALL_ITEM_CONTAMINATION_DESC = "Like Cloth Contamination, but all item types are susceptible."
-
- PLASMAGUARD_ONLY = 0
- PLASMAGUARD_ONLY_NAME = "Plasma - Biosuits/Spacesuits Only"
- PLASMAGUARD_ONLY_RANDOM = 20
- PLASMAGUARD_ONLY_METHOD = "Toggle"
- PLASMAGUARD_ONLY_DESC = "If on, any suits that are not biosuits or space suits will not protect against contamination."
-
- //CANISTER_CORROSION = 0 //If this is on, plasma must be stored in orange tanks and canisters,
- //CANISTER_CORROSION_RANDOM = 20 //or it will corrode the tank.
- //CANISTER_CORROSION_METHOD = "Toggle"
+ PLASMAGUARD_ONLY = 0 //If this is on, only biosuits and spacesuits protect against contamination and ill effects.
GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 10,000.
- GENETIC_CORRUPTION_NAME = "Plasma - Genetic Corruption"
- GENETIC_CORRUPTION_RANDOM = "PROB10/3d6"
- GENETIC_CORRUPTION_METHOD = "Numeric"
- GENETIC_CORRUPTION_DESC = "When set to a probability in 1000, any humans in plasma will have this chance to develop a random mutation."
SKIN_BURNS = 1 //Plasma has an effect similar to mustard gas on the un-suited.
- SKIN_BURNS_NAME = "Plasma - Skin Burns"
- SKIN_BURNS_RANDOM = 10
- SKIN_BURNS_METHOD = "Toggle"
- SKIN_BURNS_DESC = "When toggled, humans with exposed skin will suffer burns (similar to mustard gas) in plasma."
- //PLASMA_INJECTS_TOXINS = 0 //Plasma damage injects the toxins chemical to do damage over time.
- //PLASMA_INJECTS_TOXINS_RANDOM = 30
- //PLASMA_INJECTS_TOXINS_METHOD = "Toggle"
+ EYE_BURNS = 1 //Plasma burns the eyes of anyone not wearing eye protection.
- EYE_BURNS = 0 //Plasma burns the eyes of anyone not wearing eye protection.
- EYE_BURNS_NAME = "Plasma - Eye Burns"
- EYE_BURNS_RANDOM = 30
- EYE_BURNS_METHOD = "Toggle"
- EYE_BURNS_DESC = "When toggled, humans without masks that cover the eyes will suffer temporary blurriness and sight loss,\
- and may need glasses to see again if exposed for long durations."
+ CONTAMINATION_LOSS = 0.01
- //N2O_REACTION = 0 //Plasma can react with N2O, making sparks and starting a fire if levels are high.
- //N2O_REACTION_RANDOM = 5
+ PLASMA_HALLUCINATION = 0
- //PLASMA_COLOR = "onturf" //Plasma can change colors yaaaay!
- //PLASMA_COLOR_RANDOM = "PICKonturf,onturf"
-
- //PLASMA_DMG_OFFSET = 1
- //PLASMA_DMG_OFFSET_RANDOM = "1d5"
- //PLASMA_DMG_QUOTIENT = 10
- //PLASMA_DMG_QUOTIENT_RANDOM = "1d10+4"
-
- CONTAMINATION_LOSS = 0.1
- _NAME = "Plasma - Contamination Damage"
- CONTAMINATION_LOSS_DESC = "A number representing the damage done per life cycle by contaminated items."
-
- PLASMA_HALLUCINATION = 1
- PLASMA_HALLUCINATION_NAME = "Plasma - Hallucination"
- PLASMA_HALLUCINATION_METHOD = "Toggle"
- PLASMA_HALLUCINATION_DESC = "If toggled, uses the remnants of the hallucination code to induce visions in those\
- who breathe plasma."
N2O_HALLUCINATION = 1
- N2O_HALLUCINATION_NAME = "Nitrous Oxide - Hallucination"
- N2O_HALLUCINATION_METHOD = "Toggle"
- N2O_HALLUCINATION_DESC = "If toggled, uses the remnants of the hallucination code to induce visions in those\
- who breathe N2O."
- //CONTAMINATION_LOSS_RANDOM = "5d5"
-//Plasma has a chance to be a different color.
+
obj/var/contaminated = 0
obj/item/proc
can_contaminate()
+ //Clothing and backpacks can be contaminated.
if(flags & PLASMAGUARD) return 0
- if((flags & SUITSPACE) && !vsc.plc.PLASMAGUARD_ONLY) return 1
- if(vsc.plc.ALL_ITEM_CONTAMINATION) return 1
+ if(flags & SUITSPACE) return 0
else if(istype(src,/obj/item/clothing)) return 1
else if(istype(src,/obj/item/weapon/storage/backpack)) return 1
-/mob/living/carbon/human/proc/contaminate()
+ contaminate()
+ //Do a contamination overlay? Temporary measure to keep contamination less deadly than it was.
+ if(!contaminated)
+ contaminated = 1
+ overlays += 'icons/effects/contamination.dmi'
+
+ decontaminate()
+ contaminated = 0
+ overlays -= 'icons/effects/contamination.dmi'
+
+/mob/proc/contaminate()
+
+/mob/living/carbon/human/contaminate()
+ //See if anything can be contaminated.
+
if(!pl_suit_protected())
suit_contamination()
- else if(vsc.plc.PLASMAGUARD_ONLY)
- if(!wear_suit.flags & PLASMAGUARD) wear_suit.contaminated = 1
-
-
if(!pl_head_protected())
- if(wear_mask) wear_mask.contaminated = 1
if(prob(1)) suit_contamination() //Plasma can sometimes get through such an open suit.
- else if(vsc.plc.PLASMAGUARD_ONLY)
- if(!head.flags & PLASMAGUARD) head.contaminated = 1
- if(istype(back,/obj/item/weapon/storage/backpack) || vsc.plc.ALL_ITEM_CONTAMINATION)
- back.contaminated = 1
+ if(istype(back,/obj/item/weapon/storage/backpack))
+ back.contaminate()
- if(l_hand)
- if(l_hand.can_contaminate()) l_hand.contaminated = 1
- if(r_hand)
- if(r_hand.can_contaminate()) r_hand.contaminated = 1
- if(belt)
- if(belt.can_contaminate()) belt.contaminated = 1
- if(wear_id && !pl_suit_protected())
- if(wear_id.can_contaminate()) wear_id.contaminated = 1
- if(l_ear && !pl_head_protected())
- if(l_ear.can_contaminate()) l_ear.contaminated = 1
- if(r_ear && !pl_head_protected())
- if(r_ear.can_contaminate()) r_ear.contaminated = 1
+/mob/proc/pl_effects()
-/mob/living/carbon/human/proc/pl_effects()
+/mob/living/carbon/human/pl_effects()
+ //Handles all the bad things plasma can do.
+
+ //Contamination
+ if(vsc.plc.CLOTH_CONTAMINATION) contaminate()
+
+ //Anything else requires them to not be dead.
if(stat >= 2)
return
+
+ //Burn skin if exposed.
if(vsc.plc.SKIN_BURNS)
if(!pl_head_protected() || !pl_suit_protected())
burn_skin(0.75)
- if (coughedtime != 1)
- coughedtime = 1
- emote("gasp")
- spawn (20)
- coughedtime = 0
+ if(prob(20)) src << "\red Your skin burns!"
updatehealth()
- if(vsc.plc.EYE_BURNS && !pl_head_protected())
- if(!wear_mask)
- if(prob(20)) usr << "\red Your eyes burn!"
- eye_stat += 2.5
- eye_blurry += 1.5
- if (eye_stat >= 20 && !(disabilities & 1))
- src << "\red Your eyes start to burn badly!"
- disabilities |= 1
- if (prob(max(0,eye_stat - 20) + 1))
- src << "\red You are blinded!"
- eye_blind += 20
- eye_stat = max(eye_stat-25,0)
+
+ //Burn eyes if exposed.
+ if(vsc.plc.EYE_BURNS)
+ if(!head)
+ if(!wear_mask)
+ burn_eyes()
+ else
+ if(!(wear_mask.flags & MASKCOVERSEYES))
+ burn_eyes()
else
- if(!(wear_mask.flags & MASKCOVERSEYES))
- if(prob(20)) usr << "\red Your eyes burn!"
- eye_stat += 2.5
- eye_blurry = min(eye_blurry+1.5,50)
- if (eye_stat >= 20 && !(disabilities & 1))
- src << "\red Your eyes start to burn badly!"
- disabilities |= 1
- if (prob(max(0,eye_stat - 20) + 1) &&!eye_blind)
- src << "\red You are blinded!"
- eye_blind += 20
- eye_stat = 0
+ if(!(head.flags & HEADCOVERSEYES))
+ if(!wear_mask)
+ burn_eyes()
+ else
+ if(!(wear_mask.flags & MASKCOVERSEYES))
+ burn_eyes()
+
+ //Genetic Corruption
if(vsc.plc.GENETIC_CORRUPTION)
- if(rand(1,1000) < vsc.plc.GENETIC_CORRUPTION)
+ if(rand(1,10000) < vsc.plc.GENETIC_CORRUPTION)
randmutb(src)
src << "\red High levels of toxins cause you to spontaneously mutate."
domutcheck(src,null)
-/mob/living/carbon/human/proc/FireBurn(mx as num)
- //NO! NOT INTO THE PIT! IT BURRRRRNS!
- mx *= vsc.BURN_DMG
-
- var
- head_exposure = 1
- chest_exposure = 1
- groin_exposure = 1
- legs_exposure = 1
- feet_exposure = 1
- arms_exposure = 1
- hands_exposure = 1
- for(var/obj/item/clothing/C in src)
- if(l_hand == C || r_hand == C) continue
- if(C.body_parts_covered & HEAD)
- head_exposure *= C.heat_transfer_coefficient
- if(C.body_parts_covered & UPPER_TORSO)
- chest_exposure *= C.heat_transfer_coefficient
- if(C.body_parts_covered & LOWER_TORSO)
- groin_exposure *= C.heat_transfer_coefficient
- if(C.body_parts_covered & LEGS)
- legs_exposure *= C.heat_transfer_coefficient
- if(C.body_parts_covered & FEET)
- feet_exposure *= C.heat_transfer_coefficient
- if(C.body_parts_covered & ARMS)
- arms_exposure *= C.heat_transfer_coefficient
- if(C.body_parts_covered & HANDS)
- arms_exposure *= C.heat_transfer_coefficient
-
- mx *= 10
-
- apply_damage("head", 0, 2.5*mx*head_exposure)
- apply_damage("chest", 0, 2.5*mx*chest_exposure)
- apply_damage("groin", 0, 2.0*mx*groin_exposure)
- apply_damage("l_leg", 0, 0.6*mx*legs_exposure)
- apply_damage("r_leg", 0, 0.6*mx*legs_exposure)
- apply_damage("l_arm", 0, 0.4*mx*arms_exposure)
- apply_damage("r_arm", 0, 0.4*mx*arms_exposure)
- apply_damage("l_foot", 0, 0.25*mx*feet_exposure)
- apply_damage("r_foot", 0, 0.25*mx*feet_exposure)
- apply_damage("l_hand", 0, 0.25*mx*hands_exposure)
- apply_damage("r_hand", 0, 0.25*mx*hands_exposure)
-
-/mob/living/carbon/human/proc/suit_interior()
- . = list()
- if(!pl_suit_protected())
- for(var/obj/item/I in src)
- . += I
- return .
- . += wear_mask
- . += w_uniform
- . += shoes
- . += gloves
- if(!pl_head_protected())
- . += head
+/mob/living/carbon/human/proc/burn_eyes()
+ //The proc that handles eye burning.
+ if(prob(20)) src << "\red Your eyes burn!"
+ eye_stat += 2.5
+ eye_blurry = min(eye_blurry+1.5,50)
+ if (prob(max(0,eye_stat - 20) + 1) &&!eye_blind)
+ src << "\red You are blinded!"
+ eye_blind += 20
+ eye_stat = 0
/mob/living/carbon/human/proc/pl_head_protected()
+ //Checks if the head is adequately sealed.
if(head)
- if(head.flags & PLASMAGUARD || head.flags & HEADSPACE) return 1
+ if(vsc.plc.PLASMAGUARD_ONLY)
+ if(head.flags & PLASMAGUARD || head.flags & HEADSPACE) return 1
+ else
+ if(head.flags & HEADCOVERSEYES) return 1
return 0
/mob/living/carbon/human/proc/pl_suit_protected()
+ //Checks if the suit is adequately sealed.
if(wear_suit)
- if(wear_suit.flags & PLASMAGUARD || wear_suit.flags & SUITSPACE) return 1
+ if(vsc.plc.PLASMAGUARD_ONLY)
+ if(wear_suit.flags & PLASMAGUARD || wear_suit.flags & SUITSPACE) return 1
+ else
+ if(wear_suit.flags_inv & HIDEJUMPSUIT) return 1
return 0
/mob/living/carbon/human/proc/suit_contamination()
- if(vsc.plc.ALL_ITEM_CONTAMINATION)
- for(var/obj/item/I in src)
- I.contaminated = 1
- else
- if(wear_suit) wear_suit.contaminated = 1
- if(w_uniform) w_uniform.contaminated = 1
- if(shoes) shoes.contaminated = 1
- if(gloves) gloves.contaminated = 1
- if(wear_mask) wear_mask.contaminated = 1
+ //Runs over the things that can be contaminated and does so.
+ if(w_uniform) w_uniform.contaminate()
+ if(shoes) shoes.contaminate()
+ if(gloves) gloves.contaminate()
turf/Entered(obj/item/I)
. = ..()
- if(istype(I))
+ //Items that are in plasma, but not on a mob, can still be contaminated.
+ if(istype(I) && vsc.plc.CLOTH_CONTAMINATION)
var/datum/gas_mixture/env = return_air(1)
- if(env.toxins > 0.35)
+ if(env.toxins > MOLES_PLASMA_VISIBLE + 1)
if(I.can_contaminate())
- I.contaminated = 1
\ No newline at end of file
+ I.contaminate()
\ No newline at end of file
diff --git a/code/ZAS/Processing.dm b/code/ZAS/Processing.dm
index 4de6c939860..48e51767eb1 100644
--- a/code/ZAS/Processing.dm
+++ b/code/ZAS/Processing.dm
@@ -1,20 +1,28 @@
#define QUANTIZE(variable) (round(variable,0.0001))
var/explosion_halt = 0
+var/zone_share_percent = 1
zone
proc/process()
+ //Does rebuilding stuff. Not sure if used.
if(rebuild)
+ //Deletes zone if empty.
if(!contents.len)
del src
return 0
+
+ //Choose a random turf and regenerate the zone from it.
var
turf/sample = pick(contents)
list/new_contents = FloodFill(sample)
problem = 0
+
+ //If something isn't carried over, there was a complication.
for(var/turf/T in contents)
if(!(T in new_contents))
problem = 1
if(problem)
+ //Build some new zones for stuff that wasn't included.
var/list/rebuild_turfs = list()
for(var/turf/T in contents - new_contents)
contents -= T
@@ -26,74 +34,190 @@ zone
Z.air.copy_from(air)
rebuild = 0
- var/total_space = 0
- var/turf/space/space
+ //Sometimes explosions will cause the air to be deleted for some reason.
+ if(!air)
+ air = new()
+ air.adjustGases(MOLES_O2STANDARD, 0, MOLES_N2STANDARD, 0, list())
+ world.log << "Air object lost in zone. Regenerating."
- if(length(connected_zones))
- for(var/zone/Z in connected_zones)
- total_space += length(Z.space_tiles)
- if(length(Z.space_tiles))
- space = Z.space_tiles[1]
+ //Counting up space.
+ var/total_space = 0
if(space_tiles)
for(var/T in space_tiles)
if(!istype(T,/turf/space)) space_tiles -= T
- total_space += length(space_tiles)
- if(length(space_tiles))
- space = space_tiles[1]
+ total_space++
- if(total_space && space)
- var/old_pressure = air.return_pressure()
- air.temperature_mimic(space,OPEN_HEAT_TRANSFER_COEFFICIENT,total_space)
- air.remove(MOLES_CELLSTANDARD * (air.group_multiplier/40) * total_space)
- if(dbg_output) world << "Space removed [MOLES_CELLSTANDARD*(air.group_multiplier/40)*total_space] moles of air."
- var/p_diff = old_pressure - air.return_pressure()
- if(p_diff > vsc.AF_TINY_MOVEMENT_THRESHOLD) AirflowSpace(src,p_diff)
+ //Add checks to ensure that we're not sucking air out of an empty room.
+ if(total_space && air.total_moles > 0.1 && air.temperature > TCMB+0.5)
+ //If there is space, air should flow out of the zone.
+ if(abs(air.pressure) > vsc.airflow_lightest_pressure)
+ AirflowSpace(src)
+ ShareSpace(air,total_space*(zone_share_percent/100))
- air.react(null,0)
- var/check = air.check_tile_graphic()
- for(var/turf/T in contents)
- if(T.zone && T.zone != src)
- RemoveTurf(T)
- if(dbg_output) world << "Removed invalid turf."
- if(air.group_multiplier <= 0) // No more turfs belong to this zone, so we can get rid of it
- del(src)
- else // Turf was valid, so we can handle it
- if(!T.zone)
- T.zone = src
+ //React the air here.
+ //air.react(null,0)
- if(istype(T,/turf/simulated))
- var/turf/simulated/S = T
- if(S.fire_protection) S.fire_protection--
- if(check)
- if(S.HasDoor(1))
- S.update_visuals()
- else
- S.update_visuals(air)
+ //Check the graphic.
- if(air.temperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST)
- for(var/atom/movable/item in S)
- item.temperature_expose(air, air.temperature, CELL_VOLUME)
- S.temperature_expose(air, air.temperature, CELL_VOLUME)
+ air.graphic = 0
+ if(air.toxins > MOLES_PLASMA_VISIBLE)
+ air.graphic = 1
+ else if(air.trace_gases.len)
+ var/datum/gas/sleeping_agent = locate(/datum/gas/sleeping_agent) in air.trace_gases
+ if(sleeping_agent && (sleeping_agent.moles > 1))
+ air.graphic = 2
+ else
+ air.graphic = 0
+ //Only run through the individual turfs if there's reason to.
+ if(air.graphic != air.graphic_archived || air.temperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST)
+
+ for(var/turf/simulated/S in contents)
+ //Update overlays.
+ if(air.graphic != air.graphic_archived)
+ if(S.HasDoor(1))
+ S.update_visuals()
+ else
+ S.update_visuals(air)
+
+ //Expose stuff to extreme heat.
+ if(air.temperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST)
+ for(var/atom/movable/item in S)
+ item.temperature_expose(air, air.temperature, CELL_VOLUME)
+ S.temperature_expose(air, air.temperature, CELL_VOLUME)
+
+ //Archive graphic so we can know if it's different.
air.graphic_archived = air.graphic
+ //Ensure temperature does not reach absolute zero.
air.temperature = max(TCMB,air.temperature)
+ //Handle connections to other zones.
if(length(connections))
for(var/connection/C in connections)
+ //Check if the connection is valid first.
C.Cleanup()
- if(C && !C.indirect)
- if(C.A.zone.air.compare(C.B.zone.air))
+ //Do merging if conditions are met. Specifically, if there's a non-door connection
+ //to somewhere with space, the zones are merged regardless of equilibrium, to speed
+ //up spacing in areas with double-plated windows.
+ if(C && !C.indirect && C.A.zone && C.B.zone)
+ if(C.A.zone.air.compare(C.B.zone.air) || total_space)
ZMerge(C.A.zone,C.B.zone)
+
+ //Share some
for(var/zone/Z in connected_zones)
- var/p_diff = (air.return_pressure()-Z.air.return_pressure())*connected_zones[Z]*(vsc.zone_share_percent/100)
- if(p_diff > vsc.AF_TINY_MOVEMENT_THRESHOLD) Airflow(src,Z,p_diff)
- air.share_ratio(Z.air,connected_zones[Z]*(vsc.zone_share_percent/100))
+ //Ensure we're not doing pointless calculations on equilibrium zones.
+ if(abs(air.total_moles - Z.air.total_moles) > 0.1 || abs(air.temperature - Z.air.temperature) > 0.1)
+ if(abs(Z.air.pressure - air.pressure) > vsc.airflow_lightest_pressure)
+ Airflow(src,Z)
+ ShareRatio(air,Z.air,connected_zones[Z]*(zone_share_percent/100))
+
+proc/ShareRatio(datum/gas_mixture/A, datum/gas_mixture/B, ratio)
+ //Shares a specific ratio of gas between mixtures using simple weighted averages.
+ var
+ size = max(1,A.group_multiplier)
+ share_size = max(1,B.group_multiplier)
+
+ full_oxy = A.oxygen * size
+ full_nitro = A.nitrogen * size
+ full_co2 = A.carbon_dioxide * size
+ full_plasma = A.toxins * size
+
+ full_heat_capacity = A.heat_capacity() * size
+
+ s_full_oxy = B.oxygen * share_size
+ s_full_nitro = B.nitrogen * share_size
+ s_full_co2 = B.carbon_dioxide * share_size
+ s_full_plasma = B.toxins * share_size
+
+ s_full_heat_capacity = B.heat_capacity() * share_size
+
+ oxy_avg = (full_oxy + s_full_oxy) / (size + share_size)
+ nit_avg = (full_nitro + s_full_nitro) / (size + share_size)
+ co2_avg = (full_co2 + s_full_co2) / (size + share_size)
+ plasma_avg = (full_plasma + s_full_plasma) / (size + share_size)
+
+ temp_avg = (A.temperature * full_heat_capacity + B.temperature * s_full_heat_capacity) / (full_heat_capacity + s_full_heat_capacity)
+
+ A.oxygen = (A.oxygen - oxy_avg) * (1-ratio) + oxy_avg
+ A.nitrogen = (A.nitrogen - nit_avg) * (1-ratio) + nit_avg
+ A.carbon_dioxide = (A.carbon_dioxide - co2_avg) * (1-ratio) + co2_avg
+ A.toxins = (A.toxins - plasma_avg) * (1-ratio) + plasma_avg
+
+ A.temperature = (A.temperature - temp_avg) * (1-ratio) + temp_avg
+
+ B.oxygen = (B.oxygen - oxy_avg) * (1-ratio) + oxy_avg
+ B.nitrogen = (B.nitrogen - nit_avg) * (1-ratio) + nit_avg
+ B.carbon_dioxide = (B.carbon_dioxide - co2_avg) * (1-ratio) + co2_avg
+ B.toxins = (B.toxins - plasma_avg) * (1-ratio) + plasma_avg
+
+ B.temperature = (B.temperature - temp_avg) * (1-ratio) + temp_avg
+
+ for(var/datum/gas/G in A.trace_gases)
+ var/datum/gas/H = locate(G.type) in B.trace_gases
+ if(H)
+ var/G_avg = (G.moles*size + H.moles*share_size) / (size+share_size)
+ G.moles = (G.moles - G_avg) * (1-ratio) + G_avg
+ H.moles = (H.moles - G_avg) * (1-ratio) + G_avg
+ else
+ H = new G.type
+ B.trace_gases += H
+ var/G_avg = (G.moles*size) / (size+share_size)
+ G.moles = (G.moles - G_avg) * (1-ratio) + G_avg
+ H.moles = (H.moles - G_avg) * (1-ratio) + G_avg
+
+ A.update_values()
+ B.update_values()
+
+ if(A.compare(B)) return 1
+ else return 0
+
+proc/ShareSpace(datum/gas_mixture/A, ratio)
+ //A modified version of ShareRatio for spacing gas at the same rate as if it were going into a large airless room.
+ var
+ size = max(1,A.group_multiplier)
+ share_size = max(1,A.group_multiplier)
+
+ full_oxy = A.oxygen * size
+ full_nitro = A.nitrogen * size
+ full_co2 = A.carbon_dioxide * size
+ full_plasma = A.toxins * size
+
+ full_heat_capacity = A.heat_capacity() * size
+
+ space_heat_capacity = MINIMUM_HEAT_CAPACITY * share_size
+
+ oxy_avg = (full_oxy) / (size + share_size)
+ nit_avg = (full_nitro) / (size + share_size)
+ co2_avg = (full_co2) / (size + share_size)
+ plasma_avg = (full_plasma) / (size + share_size)
+
+ temp_avg = (A.temperature * full_heat_capacity + TCMB * space_heat_capacity) / (full_heat_capacity + space_heat_capacity)
+
+ A.oxygen = (A.oxygen - oxy_avg) * (1-ratio) + oxy_avg
+ A.nitrogen = (A.nitrogen - nit_avg) * (1-ratio) + nit_avg
+ A.carbon_dioxide = (A.carbon_dioxide - co2_avg) * (1-ratio) + co2_avg
+ A.toxins = (A.toxins - plasma_avg) * (1-ratio) + plasma_avg
+
+ A.temperature = (A.temperature - temp_avg) * (1-ratio) + temp_avg
+
+ //833 * 0.9 + 833 =
+ //(5000/3) = 1666
+ //(5000/6) = 833
+
+ for(var/datum/gas/G in A.trace_gases)
+ var/G_avg = (G.moles*size + 0) / (size+share_size)
+ G.moles = (G.moles - G_avg) * (1-ratio) + G_avg
+
+ A.update_values()
+
+ return 1
zone/proc
connected_zones()
+ //A legacy proc for getting connected zones.
. = list()
for(var/connection/C in connections)
var/zone/Z
diff --git a/code/ZAS/Variable Settings.dm b/code/ZAS/Variable Settings.dm
index 188f885ae9b..70f186613b2 100644
--- a/code/ZAS/Variable Settings.dm
+++ b/code/ZAS/Variable Settings.dm
@@ -119,8 +119,6 @@ vs_control
if("Original")
plc.CLOTH_CONTAMINATION = 0 //If this is on, plasma does damage by getting into cloth.
- plc.ALL_ITEM_CONTAMINATION = 0 //If this is on, any item can be contaminated, so suits and tools must be discarded or
-
plc.PLASMAGUARD_ONLY = 0
//plc.CANISTER_CORROSION = 0 //If this is on, plasma must be stored in orange tanks and canisters,
@@ -133,6 +131,8 @@ vs_control
plc.EYE_BURNS = 0 //Plasma burns the eyes of anyone not wearing eye protection.
+ plc.PLASMA_HALLUCINATION = 0
+
//plc.N2O_REACTION = 0 //Plasma can react with N2O, making sparks and starting a fire if levels are high.
//plc.PLASMA_COLOR = "onturf" //Plasma can change colors yaaaay!
@@ -141,10 +141,8 @@ vs_control
//plc.PLASMA_DMG_QUOTIENT = 10
plc.CONTAMINATION_LOSS = 0
- if("Hazard-Low")
- plc.CLOTH_CONTAMINATION = 1 //If this is on, plasma does damage by getting into cloth.
-
- plc.ALL_ITEM_CONTAMINATION = 0 //If this is on, any item can be contaminated, so suits and tools must be discarded or
+ if("Hazard - Low")
+ plc.CLOTH_CONTAMINATION = 0 //If this is on, plasma does damage by getting into cloth.
plc.PLASMAGUARD_ONLY = 0
@@ -152,7 +150,7 @@ vs_control
plc.GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 1000.
- plc.SKIN_BURNS = 0 //Plasma has an effect similar to mustard gas on the un-suited.
+ plc.SKIN_BURNS = 1 //Plasma has an effect similar to mustard gas on the un-suited.
// plc.PLASMA_INJECTS_TOXINS = 0 //Plasma damage injects the toxins chemical to do damage over time.
@@ -168,27 +166,22 @@ vs_control
//plc.PLASMA_DMG_OFFSET = 1.5
//plc.PLASMA_DMG_QUOTIENT = 8
- plc.CONTAMINATION_LOSS = 0.01
+ plc.CONTAMINATION_LOSS = 0
- var/s = pick(plc.settings)
- plc.Randomize(s)
-
- if("Hazard-High")
+ if("Hazard - High")
plc.CLOTH_CONTAMINATION = 1 //If this is on, plasma does damage by getting into cloth.
- plc.ALL_ITEM_CONTAMINATION = 0 //If this is on, any item can be contaminated, so suits and tools must be discarded or
-
plc.PLASMAGUARD_ONLY = 0
// plc.CANISTER_CORROSION = 1 //If this is on, plasma must be stored in orange tanks and canisters,
plc.GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 1000.
- plc.SKIN_BURNS = 0 //Plasma has an effect similar to mustard gas on the un-suited.
+ plc.SKIN_BURNS = 1 //Plasma has an effect similar to mustard gas on the un-suited.
// plc.PLASMA_INJECTS_TOXINS = 0 //Plasma damage injects the toxins chemical to do damage over time.
- plc.EYE_BURNS = 0 //Plasma burns the eyes of anyone not wearing eye protection.
+ plc.EYE_BURNS = 1 //Plasma burns the eyes of anyone not wearing eye protection.
// plc.N2O_REACTION = 0 //Plasma can react with N2O, making sparks and starting a fire if levels are high.
@@ -197,17 +190,9 @@ vs_control
//plc.PLASMA_DMG_OFFSET = 3
//plc.PLASMA_DMG_QUOTIENT = 5
- plc.CONTAMINATION_LOSS = 0.05
-
- for(var/i = rand(3,5),i>0,i--)
- var/s = pick(plc.settings)
- plc.Randomize(s)
-
- if("Everything")
+ if("Oh Shit!")
plc.CLOTH_CONTAMINATION = 1 //If this is on, plasma does damage by getting into cloth.
- plc.ALL_ITEM_CONTAMINATION = 1 //If this is on, any item can be contaminated, so suits and tools must be discarded or ELSE
-
plc.PLASMAGUARD_ONLY = 1
// plc.CANISTER_CORROSION = 1 //If this is on, plasma must be stored in orange tanks and canisters,
@@ -227,7 +212,6 @@ vs_control
//plc.PLASMA_DMG_OFFSET = 3
//plc.PLASMA_DMG_QUOTIENT = 5
- plc.CONTAMINATION_LOSS = 0.02
/////world << "Plasma color updated."
pl_control
diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm
index c39421ea81c..2040d874324 100644
--- a/code/datums/datumvars.dm
+++ b/code/datums/datumvars.dm
@@ -392,6 +392,21 @@ client
//All BYOND links pass through client/Topic() FIRST and are then directed to [hsrc]/Topic() by the ..() call at the end.
client/Topic(href, href_list, hsrc)
+ file("topic_log") << "[time2text(world.realtime, "DDD MMM DD YYYY")] at [time2text(world.timeofday, "hh:mm:ss")], [ckey], \"[url_encode(href)]\""
+ // build some more useful info
+ var/references = ""
+ for(var/href_key in href_list)
+ var/href_val = locate(href_list[href_key])
+ references += "[href_key] = [href_val]("
+ if(istype(href_val,/datum))
+ references += "[href_val:type]"
+ if(istype(href_val,/atom))
+ references += " at [href_val:x],[href_val:y],[href_val:z]"
+
+ references += "); "
+ file("topic_log") << references
+
+ sleep(3)
//search the href for script injection //This is a temporary measure
if( findtext(href,"