diff --git a/baystation12.dme b/baystation12.dme
index 3b2e3409f43..d972490d4bb 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -91,6 +91,7 @@
#define FILE_DIR "code/modules/admin/verbs"
#define FILE_DIR "code/modules/assembly"
#define FILE_DIR "code/modules/chemical"
+#define FILE_DIR "code/modules/client"
#define FILE_DIR "code/modules/clothing"
#define FILE_DIR "code/modules/clothing/glasses"
#define FILE_DIR "code/modules/clothing/head"
@@ -103,6 +104,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"
@@ -308,7 +310,6 @@
#include "code\datums\spells\turf_teleport.dm"
#include "code\datums\spells\wizard.dm"
#include "code\defines\atom.dm"
-#include "code\defines\client.dm"
#include "code\defines\global.dm"
#include "code\defines\hub.dm"
#include "code\defines\obj.dm"
@@ -361,12 +362,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"
@@ -423,6 +418,7 @@
#include "code\game\events\Events\SpaceCarp.dm"
#include "code\game\events\Events\SpaceNinja.dm"
#include "code\game\events\Events\VirusEpidemic.dm"
+#include "code\game\gamemodes\factions.dm"
#include "code\game\gamemodes\game_mode.dm"
#include "code\game\gamemodes\gameticker.dm"
#include "code\game\gamemodes\intercept_report.dm"
@@ -516,7 +512,6 @@
#include "code\game\machinery\scanner.dm"
#include "code\game\machinery\seed_extractor.dm"
#include "code\game\machinery\shieldgen.dm"
-#include "code\game\machinery\sink.dm"
#include "code\game\machinery\Sleeper.dm"
#include "code\game\machinery\spaceheater.dm"
#include "code\game\machinery\status_display.dm"
@@ -649,9 +644,11 @@
#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"
+#include "code\game\objects\windoor_assembly.dm"
#include "code\game\objects\window.dm"
#include "code\game\objects\alien\acid.dm"
#include "code\game\objects\alien\defines.dm"
@@ -661,9 +658,11 @@
#include "code\game\objects\alien\weeds.dm"
#include "code\game\objects\closets\bombsuit.dm"
#include "code\game\objects\closets\emergency.dm"
+#include "code\game\objects\closets\ert.dm"
#include "code\game\objects\closets\extinguisher.dm"
#include "code\game\objects\closets\fireaxe.dm"
#include "code\game\objects\closets\firecloset.dm"
+#include "code\game\objects\closets\fitnesscloset.dm"
#include "code\game\objects\closets\gimmick.dm"
#include "code\game\objects\closets\gmcloset.dm"
#include "code\game\objects\closets\janitor.dm"
@@ -743,11 +742,13 @@
#include "code\game\objects\items\weapons\tiles_wires.dm"
#include "code\game\objects\items\weapons\tools.dm"
#include "code\game\objects\items\weapons\twohanded.dm"
+#include "code\game\objects\items\weapons\wrappingpaper.dm"
#include "code\game\objects\items\weapons\implants\implant.dm"
#include "code\game\objects\items\weapons\implants\implantcase.dm"
#include "code\game\objects\items\weapons\implants\implantchair.dm"
#include "code\game\objects\items\weapons\implants\implanter.dm"
#include "code\game\objects\items\weapons\implants\implantfreedom.dm"
+#include "code\game\objects\items\weapons\implants\implantnanoaug.dm"
#include "code\game\objects\items\weapons\implants\implantpad.dm"
#include "code\game\objects\radio\beacon.dm"
#include "code\game\objects\radio\electropack.dm"
@@ -774,6 +775,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"
@@ -790,11 +792,14 @@
#include "code\js\byjax.dm"
#include "code\js\menus.dm"
#include "code\modules\admin\admin.dm"
+#include "code\modules\admin\admin_investigate.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"
#include "code\modules\admin\create_object.dm"
#include "code\modules\admin\create_turf.dm"
+#include "code\modules\admin\IsBanned.dm"
#include "code\modules\admin\NewBan.dm"
#include "code\modules\admin\newbanjob.dm"
#include "code\modules\admin\player_panel.dm"
@@ -837,6 +842,8 @@
#include "code\modules\chemical\Chemistry-Reagents.dm"
#include "code\modules\chemical\Chemistry-Recipes.dm"
#include "code\modules\chemical\Chemistry-Tools.dm"
+#include "code\modules\client\client defines.dm"
+#include "code\modules\client\client procs.dm"
#include "code\modules\clothing\costume.dm"
#include "code\modules\clothing\ears.dm"
#include "code\modules\clothing\gimmick.dm"
@@ -853,6 +860,8 @@
#include "code\modules\clothing\head\hats.dm"
#include "code\modules\clothing\head\helmets.dm"
#include "code\modules\clothing\spacesuits\captain.dm"
+#include "code\modules\clothing\spacesuits\engineer.dm"
+#include "code\modules\clothing\spacesuits\ert.dm"
#include "code\modules\clothing\spacesuits\miscellaneous.dm"
#include "code\modules\clothing\spacesuits\ninja.dm"
#include "code\modules\clothing\spacesuits\rig.dm"
@@ -878,6 +887,8 @@
#include "code\modules\customitems\item_spawning.dm"
#include "code\modules\DetectiveWork\detective_work.dm"
#include "code\modules\DetectiveWork\evidence.dm"
+#include "code\modules\DetectiveWork\footprints_and_rag.dm"
+#include "code\modules\DetectiveWork\scanner.dm"
#include "code\modules\flufftext\Dreaming.dm"
#include "code\modules\flufftext\Hallucination.dm"
#include "code\modules\flufftext\TextFilters.dm"
@@ -921,6 +932,7 @@
#include "code\modules\mob\living\damage_procs.dm"
#include "code\modules\mob\living\living.dm"
#include "code\modules\mob\living\living_defense.dm"
+#include "code\modules\mob\living\login.dm"
#include "code\modules\mob\living\say.dm"
#include "code\modules\mob\living\blob\blob.dm"
#include "code\modules\mob\living\carbon\carbon.dm"
@@ -964,6 +976,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"
@@ -1035,6 +1048,7 @@
#include "code\modules\mob\living\silicon\robot\say.dm"
#include "code\modules\mob\living\silicon\robot\wires.dm"
#include "code\modules\mob\new_player\hud.dm"
+#include "code\modules\mob\new_player\login.dm"
#include "code\modules\mob\new_player\new_player.dm"
#include "code\modules\mob\new_player\preferences.dm"
#include "code\modules\mob\new_player\preferences_setup.dm"
@@ -1079,6 +1093,7 @@
#include "code\modules\power\singularity\emitter.dm"
#include "code\modules\power\singularity\field_generator.dm"
#include "code\modules\power\singularity\generator.dm"
+#include "code\modules\power\singularity\investigate.dm"
#include "code\modules\power\singularity\singularity.dm"
#include "code\modules\power\singularity\particle_accelerator\particle.dm"
#include "code\modules\power\singularity\particle_accelerator\particle_accelerator.dm"
@@ -1180,8 +1195,6 @@
#include "code\WorkInProgress\organs\organs.dm"
#include "code\WorkInProgress\Ported\policetape.dm"
#include "code\WorkInProgress\Ported\sql.dm"
-#include "code\WorkInProgress\Ported\Abi79\uplink_kits.dm"
-#include "code\WorkInProgress\Ported\Abi79\uplinks.dm"
#include "code\WorkInProgress\Ported\Bureaucracy\copier.dm"
#include "code\WorkInProgress\Ported\Bureaucracy\filing.dm"
#include "code\WorkInProgress\SkyMarshal\coatrack.dm"
@@ -1207,6 +1220,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/ATMOSPHERICS/pipes.dm b/code/ATMOSPHERICS/pipes.dm
index 863923b1023..da9bd52bfcd 100644
--- a/code/ATMOSPHERICS/pipes.dm
+++ b/code/ATMOSPHERICS/pipes.dm
@@ -158,7 +158,7 @@ obj/machinery/atmospherics/pipe
else return 1
proc/burst()
- src.visible_message("\red \bold [src] bursts!");
+ src.visible_message("\red \bold \The [src] bursts!");
playsound(src.loc, 'bang.ogg', 25, 1)
var/datum/effect/effect/system/harmless_smoke_spread/smoke = new
smoke.set_up(1,0, src.loc, 0)
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/BirdMan/birdman.dm b/code/WorkInProgress/Cael_Aislinn/BirdMan/birdman.dm
index 45206ccc9ee..34872f32851 100644
--- a/code/WorkInProgress/Cael_Aislinn/BirdMan/birdman.dm
+++ b/code/WorkInProgress/Cael_Aislinn/BirdMan/birdman.dm
@@ -46,8 +46,8 @@
- var/husk = (mutations & HUSK)
- //var/obese = (mutations & FAT)
+ var/husk = (HUSK in mutations)
+ //var/obese = (FAT in mutation)
stand_icon.Blend(new /icon('birdman.dmi', "chest_[g]_s"), ICON_OVERLAY)
lying_icon.Blend(new /icon('birdman.dmi', "chest_[g]_l"), ICON_OVERLAY)
diff --git a/code/WorkInProgress/Cael_Aislinn/Tajara/say.dm b/code/WorkInProgress/Cael_Aislinn/Tajara/say.dm
index de333045f0b..4ab6c96894b 100644
--- a/code/WorkInProgress/Cael_Aislinn/Tajara/say.dm
+++ b/code/WorkInProgress/Cael_Aislinn/Tajara/say.dm
@@ -184,7 +184,7 @@
var/is_speaking_taj = 0
if(copytext(message, 1, 3) == ":j" || copytext(message, 1, 3) == ":J")
message = copytext(message, 3)
- if(taj_talk_understand)
+ if(taj_talk_understand || universal_speak)
is_speaking_taj = 1
if( !message_mode && (disease_symptoms & DISEASE_WHISPER))
@@ -403,7 +403,7 @@
for (var/mob/M in listening)
//if speaking in tajaran, only let other tajs understand
- if ( M.say_understands(src) && (M.taj_talk_understand || !is_speaking_taj) )
+ if ( M.say_understands(src) && (M.taj_talk_understand || !is_speaking_taj || M.universal_speak) )
heard_a += M
else
heard_b += M
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 1f80c190dd1..048aadd1657 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()
// ..()
@@ -37,19 +43,19 @@
// lol
var/fat = ""
- /*if (mutations & FAT)
+ /*if (FAT in mutation)
fat = "fat"*/
/*
- if (mutations & HULK)
+ if (HULK in mutations)
overlays += image("icon" = 'genetics.dmi', "icon_state" = "hulk[fat][!lying ? "_s" : "_l"]")
*/
- if (mutations & COLD_RESISTANCE)
+ if (COLD_RESISTANCE in mutations)
overlays += image("icon" = 'genetics.dmi', "icon_state" = "fire[fat][!lying ? "_s" : "_l"]")
- if (mutations & TK)
+ if (TK in mutations)
overlays += image("icon" = 'genetics.dmi', "icon_state" = "telekinesishead[fat][!lying ? "_s" : "_l"]")
- if (mutations & LASER)
+ if (LASER in mutations)
overlays += image("icon" = 'genetics.dmi', "icon_state" = "lasereyes[!lying ? "_s" : "_l"]")
if (mutantrace)
@@ -74,6 +80,18 @@
del(stand_icon)
if(lying_icon)
del(lying_icon)
+ if("skrell")
+ body_overlays_standing += image("icon" = 'genetics.dmi', "icon_state" = "[mutantrace]_[gender]_s")
+ body_overlays_lying += image("icon" = 'genetics.dmi', "icon_state" = "[mutantrace]_[gender]_l")
+// This needs to be matched up with humans, but I'm too lazy right now
+// if(face_standing)
+// del(face_standing)
+// if(face_lying)
+// del(face_lying)
+ if(stand_icon)
+ del(stand_icon)
+ if(lying_icon)
+ del(lying_icon)
if("plant")
if(stat != 2) //if not dead, that is
overlays += image("icon" = 'genetics.dmi', "icon_state" = "[mutantrace][fat]_[gender][!lying ? "_s" : "_l"]")
@@ -121,21 +139,21 @@
if (lying)
icon = lying_icon
- overlays += body_lying
+ overlays += damageicon_lying
if (face_lying)
overlays += face_lying
else
icon = stand_icon
- overlays += body_standing
+ overlays += damageicon_standing
if (face_standing)
overlays += face_standing
// Uniform
if(w_uniform)
- /*if (mutations & FAT && !(w_uniform.flags & ONESIZEFITSALL))
+ /*if ((FAT in mutations) && !(w_uniform.flags & ONESIZEFITSALL))
src << "\red You burst out of the [w_uniform.name]!"
var/obj/item/clothing/c = w_uniform
u_equip(c)
@@ -151,7 +169,7 @@
var/t1 = w_uniform.color
if (!t1)
t1 = icon_state
- /*if (mutations & FAT)
+ /*if (FAT in mutations)
overlays += image("icon" = 'uniform_fat.dmi', "icon_state" = "[t1][!lying ? "_s" : "_l"]", "layer" = MOB_LAYER)
else*/
overlays += image("icon" = 'uniform.dmi', "icon_state" = text("[][]",t1, (!(lying) ? "_s" : "_l")), "layer" = MOB_LAYER)
@@ -263,7 +281,7 @@
var/tail_shown = 1
if (wear_suit)
- /*if (mutations & FAT && !(wear_suit.flags & ONESIZEFITSALL))
+ /*if ((FAT in mutations) && !(wear_suit.flags & ONESIZEFITSALL))
src << "\red You burst out of the [wear_suit.name]!"
var/obj/item/clothing/c = wear_suit
u_equip(c)
@@ -457,8 +475,8 @@
- var/husk = (mutations & HUSK)
- //var/obese = (mutations & FAT)
+ var/husk = (HUSK in mutations)
+ //var/obese = (FAT in mutations)
stand_icon.Blend(new /icon('tajaran.dmi', "chest_[g]_s"), ICON_OVERLAY)
lying_icon.Blend(new /icon('tajaran.dmi', "chest_[g]_l"), ICON_OVERLAY)
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/Cael_Aislinn/Tajara/whisper.dm b/code/WorkInProgress/Cael_Aislinn/Tajara/whisper.dm
index e4c91900877..a4315a0ba9f 100644
--- a/code/WorkInProgress/Cael_Aislinn/Tajara/whisper.dm
+++ b/code/WorkInProgress/Cael_Aislinn/Tajara/whisper.dm
@@ -35,7 +35,7 @@
var/is_speaking_taj = 0
if(copytext(message, 1, 4) == ":j ")
message = copytext(message, 4)
- if(taj_talk_understand)
+ if(taj_talk_understand || universal_speak)
is_speaking_taj = 1
if(istype(src.wear_mask, /obj/item/clothing/mask/gas/voice/space_ninja)&&src.wear_mask:voice=="Unknown")
@@ -84,7 +84,7 @@
var/list/heard_b = list() // didn't understand us
for (var/mob/M in listening)
- if ( M.say_understands(src) && (M.taj_talk_understand || !is_speaking_taj) )
+ if ( M.say_understands(src) && (M.taj_talk_understand || !is_speaking_taj || M.universal_speak) )
heard_a += M
else
heard_b += M
diff --git a/code/WorkInProgress/Ported/Abi79/uplinks.dm b/code/WorkInProgress/Ported/Abi79/uplinks.dm
index ae261a85ac1..55cd988af8f 100644
--- a/code/WorkInProgress/Ported/Abi79/uplinks.dm
+++ b/code/WorkInProgress/Ported/Abi79/uplinks.dm
@@ -21,12 +21,17 @@ A list of items and costs is stored under the datum of every game mode, alongsid
var/items // List of items
var/list/ItemList // Parsed list of items
var/uses // Numbers of crystals
+ var/uplink_data // designated uplink items
// List of items not to shove in their hands.
var/list/NotInHand = list(/obj/machinery/singularity_beacon/syndicate)
New()
- welcome = ticker.mode.uplink_welcome
- items = dd_replacetext(ticker.mode.uplink_items, "\n", "") // Getting the text string of items
+ if(!welcome)
+ welcome = ticker.mode.uplink_welcome
+ if(!uplink_data)
+ uplink_data = ticker.mode.uplink_items
+
+ items = dd_replacetext(uplink_data, "\n", "") // Getting the text string of items
ItemList = dd_text2list(src.items, ";") // Parsing the items text string
uses = ticker.mode.uplink_uses
@@ -312,7 +317,8 @@ A list of items and costs is stored under the datum of every game mode, alongsid
var/temp = null //Temporary storage area for a message offering the option to destroy the radio
var/selfdestruct = 0 //Set to 1 while the radio is self destructing itself.
var/obj/item/device/radio/origradio = null
- flags = FPRINT | TABLEPASS | CONDUCT | ONBELT
+ flags = FPRINT | TABLEPASS | CONDUCT
+ slot_flags = SLOT_BELT
w_class = 2.0
item_state = "radio"
throwforce = 5
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/Wrongnumber/weldbackpack.dm b/code/WorkInProgress/Wrongnumber/weldbackpack.dm
index 637ba56d8dd..6fe355e7c08 100644
--- a/code/WorkInProgress/Wrongnumber/weldbackpack.dm
+++ b/code/WorkInProgress/Wrongnumber/weldbackpack.dm
@@ -1,7 +1,7 @@
/obj/item/weapon/weldpack
name = "Welding kit"
desc = "A heavy-duty, portable welding fluid carrier."
- flags = ONBACK
+ slot_flags = SLOT_BACK
icon = 'storage.dmi'
icon_state = "welderpack"
w_class = 4.0
@@ -20,7 +20,7 @@
message_admins("[key_name_admin(user)] triggered a fueltank explosion.")
log_game("[key_name(user)] triggered a fueltank explosion.")
user << "\red That was stupid of you."
- explosion(src.loc,-1,0,2)
+ explosion(get_turf(src),-1,0,2)
if(src)
del(src)
return
diff --git a/code/WorkInProgress/animusstation/atm.dm b/code/WorkInProgress/animusstation/atm.dm
index a6dce70e502..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,12 +17,11 @@ log transactions
anchored = 1
use_power = 1
idle_power_usage = 10
- var
- obj/item/weapon/card/id/card
- obj/item/weapon/money/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/money))
diff --git a/code/WorkInProgress/meteors.dm b/code/WorkInProgress/meteors.dm
index 35c370fb0b0..10cbf714713 100644
--- a/code/WorkInProgress/meteors.dm
+++ b/code/WorkInProgress/meteors.dm
@@ -105,18 +105,17 @@
shake_camera(M, 3, 1)
if (A)
A.meteorhit(src)
- playsound(src.loc, 'meteorimpact.ogg', 40, 1)
+ playsound(get_turf(src), 'meteorimpact.ogg', 40, 1)
if (--src.hits <= 0)
if(prob(15))// && !istype(A, /obj/structure/grille))
- explosion(src.loc, 4, 5, 6, 7, 0)
- playsound(src.loc, "explosion", 50, 1)
+ explosion(get_turf(src), 4, 5, 6, 7, 0)
+ playsound(get_turf(src), "explosion", 50, 1)
del(src)
return
/obj/effect/meteor/ex_act(severity)
-
- if (severity < 4)
+ spawn(0)
del(src)
return
@@ -139,11 +138,11 @@
A.meteorhit(src)
src.hits--
return
- playsound(src.loc, 'meteorimpact.ogg', 40, 1)
+ playsound(get_turf(src), 'meteorimpact.ogg', 40, 1)
if (--src.hits <= 0)
if(prob(15) && !istype(A, /obj/structure/grille))
- explosion(src.loc, 1, 2, 3, 4, 0)
- playsound(src.loc, "explosion", 50, 1)
+ explosion(get_turf(src), 1, 2, 3, 4, 0)
+ playsound(get_turf(src), "explosion", 50, 1)
del(src)
return
diff --git a/code/WorkInProgress/virus2/antibodies.dm b/code/WorkInProgress/virus2/antibodies.dm
index 31de7c02ba9..6495bb4d04d 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",
@@ -43,8 +44,8 @@ var/global/list/ANTIGENS = list("[ANTIGEN_A]" = "A", "[ANTIGEN_B]" = "B", "[ANTI
icon_state = "health"
w_class = 2.0
item_state = "electronic"
- flags = FPRINT | TABLEPASS | ONBELT | CONDUCT | USEDELAY
-
+ flags = FPRINT | TABLEPASS | CONDUCT | USEDELAY
+ slot_flags = SLOT_BELT
/obj/item/device/antibody_scanner/attack(mob/living/carbon/human/M as mob, mob/user as mob)
if(! istype(M, /mob/living/carbon) || !M:antibodies)
@@ -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/ZAS/Airflow.dm b/code/ZAS/Airflow.dm
index a3cb01eb7ee..a6ca0f6a7b4 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,119 +48,28 @@ 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 = 90
- 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
+ airflow_delay = 25 //Time in deciseconds before they can be moved by airflow again.
+ airflow_mob_slowdown = 3 //Time in tenths of a second to add as a delay to each movement by a mob.\
+ Only active if they are fighting the pull of the airflow.
+ airflow_stun_cooldown = 10 //How long, in tenths of a second, to wait before stunning them again.
+mob/var/last_airflow_stun = 0
mob/proc/airflow_stun()
+ if(last_airflow_stun > world.time - vsc.airflow_stun_cooldown) return 0
if(weakened <= 0) src << "\red The sudden rush of air knocks you over!"
weakened = max(weakened,5)
+ last_airflow_stun = world.time
mob/living/silicon/airflow_stun()
return
@@ -185,20 +78,21 @@ mob/living/carbon/metroid/airflow_stun()
return
mob/living/carbon/human/airflow_stun()
+ if(last_airflow_stun > world.time - vsc.airflow_stun_cooldown) return 0
if(buckled) return 0
if(wear_suit)
if(wear_suit.flags & SUITSPACE) return 0
if(shoes)
if(shoes.flags & NOSLIP) return 0
if(weakened <= 0) src << "\red The sudden rush of air knocks you over!"
- weakened = max(weakened,2)
+ weakened = max(weakened,rand(1,5))
+ last_airflow_stun = world.time
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 +107,141 @@ 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.return_pressure() - A.air.return_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]
+ var/list/connection/connections_A = A.connections
+ var/list/turf/connected_turfs = list()
+ for(var/connection/C in connections_A) //Grab the turf that is in the zone we are flowing to (determined by n)
+ if( ( A == C.A.zone || A == C.zone_A ) && ( B == C.B.zone || B == C.zone_B ) )
+ if(n < 0)
+ connected_turfs |= C.B
+ else
+ connected_turfs |= C.A
+ else if( ( A == C.B.zone || A == C.zone_B ) && ( B == C.A.zone || B == C.zone_A ) )
+ if(n < 0)
+ connected_turfs |= C.A
+ else
+ connected_turfs |= C.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 = B.movables()
+ var/list/otherpplz = A.movables()
+ if(n < 0)
+ var/list/temporary_pplz = pplz
+ pplz = otherpplz
+ otherpplz = temporary_pplz
for(var/atom/movable/M in pplz)
+ if(M.last_airflow > world.time - vsc.airflow_delay) continue
+
//Check for knocking people over
- if(ismob(M) && n > vsc.AF_HUMAN_STUN_THRESHOLD)
+ if(ismob(M) && n > vsc.airflow_heaviest_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 - vsc.airflow_delay) 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.return_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.
for(var/atom/movable/M in pplz)
- if(ismob(M) && n > vsc.AF_HUMAN_STUN_THRESHOLD)
+ if(M.last_airflow > world.time - vsc.airflow_delay) 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 - vsc.airflow_delay) 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))
@@ -396,7 +254,7 @@ atom/movable
if(src:shoes)
if(src:shoes.type == /obj/item/clothing/shoes/magboots && src:shoes.flags & NOSLIP) return
src << "\red You are sucked away by airflow!"
- airflow_speed = min(round(n),9)
+ airflow_speed = min(round(n)/max(sqrt(get_dist(src,airflow_dest)),1),9)
var
xo = airflow_dest.x - src.x
yo = airflow_dest.y - src.y
@@ -408,7 +266,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)
@@ -419,19 +277,21 @@ atom/movable
if ((src.x == 1 || src.x == world.maxx || src.y == 1 || src.y == world.maxy))
return
step_towards(src, src.airflow_dest)
- if(ismob(src) && src:client) src:client:move_delay = world.time + 10
+ if(ismob(src) && src:client) src:client:move_delay = world.time + vsc.airflow_mob_slowdown
airflow_dest = null
- airflow_speed = -1
- spawn(150 * tick_multiplier) airflow_speed = 0
+ airflow_speed = 0
+ airflow_time = 0
if(od)
density = 0
proc/RepelAirflowDest(n)
if(!airflow_dest) return
if(airflow_speed < 0) return
+ if(last_airflow > world.time - vsc.airflow_delay) 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))
@@ -442,9 +302,9 @@ atom/movable
if(src:wear_suit)
if(src:wear_suit.flags & SUITSPACE) return
if(src:shoes)
- if(src:shoes.type == /obj/item/clothing/shoes/magboots) return
+ if(src:shoes.type == /obj/item/clothing/shoes/magboots && src:shoes.flags & NOSLIP) return
src << "\red You are pushed away by airflow!"
- airflow_speed = min(round(n),9)
+ airflow_speed = min(round(n)/max(sqrt(get_dist(src,airflow_dest)),1),9)
var
xo = -(airflow_dest.x - src.x)
yo = -(airflow_dest.y - src.y)
@@ -456,7 +316,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)
@@ -467,10 +327,10 @@ atom/movable
if ((src.x == 1 || src.x == world.maxx || src.y == 1 || src.y == world.maxy))
return
step_towards(src, src.airflow_dest)
- if(ismob(src) && src:client) src:client:move_delay = world.time + 10
+ if(ismob(src) && src:client) src:client:move_delay = world.time + vsc.airflow_mob_slowdown
airflow_dest = null
- airflow_speed = -1
- spawn(150 * tick_multiplier) airflow_speed = 0
+ airflow_speed = 0
+ airflow_time = 0
if(od)
density = 0
@@ -479,17 +339,18 @@ atom/movable
airflow_hit(A)
else
airflow_speed = 0
+ airflow_time = 0
. = ..()
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)
for(var/mob/M in hearers(src))
M.show_message("\red [src] slams into [A]!",1,"\red You hear a loud slam!",2)
playsound(src.loc, "smash.ogg", 25, 1, -1)
+ weakened = max(weakened, (A.vars.Find("w_class") ? A:w_class : rand(1,5))) //Heheheh
. = ..()
obj/airflow_hit(atom/A)
@@ -499,89 +360,38 @@ 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)
- for(var/mob/M in hearers(src))
- M.show_message("\red [src] slams into [A]!",1,"\red You hear a loud slam!",2)
+// for(var/mob/M in hearers(src))
+// M.show_message("\red [src] slams into [A]!",1,"\red You hear a loud slam!",2)
playsound(src.loc, "punch", 25, 1, -1)
loc:add_blood(src)
if (src.wear_suit)
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
-
-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
-
-
- 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
+ . += A
\ No newline at end of file
diff --git a/code/ZAS/Connection.dm b/code/ZAS/Connection.dm
index bf43f90d1c0..01f5351f595 100644
--- a/code/ZAS/Connection.dm
+++ b/code/ZAS/Connection.dm
@@ -1,20 +1,52 @@
+/*
+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.
A
B
+ zone
+ zone_A
+ zone_B
+ ref_A
+ ref_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
- if(A.zone)
- if(!A.zone.connections) A.zone.connections = new()
- A.zone.connections += src
- if(B.zone)
- if(!B.zone.connections) B.zone.connections = new()
- B.zone.connections += src
if(A.zone && B.zone)
+ if(!A.zone.connections) A.zone.connections = list()
+ A.zone.connections += src
+ zone_A = A.zone
+ ref_A = "\ref[A]"
+
+ if(!B.zone.connections) B.zone.connections = list()
+ B.zone.connections += src
+ zone_B = B.zone
+ ref_B = "\ref[B]"
+
+ if(!air_master.tiles_with_connections)
+ air_master.tiles_with_connections = list()
+
+ if(air_master.tiles_with_connections[ref_A])
+ var/list/A_connections = air_master.tiles_with_connections[ref_A]
+ A_connections |= src
+ else
+ var/list/A_connections = list(src)
+ air_master.tiles_with_connections[ref_A] = A_connections
+
+ if(air_master.tiles_with_connections[ref_B])
+ var/list/B_connections = air_master.tiles_with_connections[ref_B]
+ B_connections |= src
+ else
+ var/list/B_connections = list(src)
+ air_master.tiles_with_connections[ref_B] = B_connections
+
if(!A.zone.connected_zones)
A.zone.connected_zones = list()
if(!B.zone.connected_zones)
@@ -31,31 +63,265 @@ 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(src)
Del()
- if(A.zone && A.zone.connections)
- A.zone.connections -= src
- if(B.zone && B.zone.connections)
- B.zone.connections -= src
+ if(A)
+ if(A.zone && A.zone.connections)
+ A.zone.connections.Remove(src)
+ if(!A.zone.connections.len)
+ del A.zone.connections
+ if(ref_A in air_master.tiles_with_connections)
+ var/list/A_connections = air_master.tiles_with_connections[ref_A]
+ A_connections -= src
+ if(A_connections && !A_connections.len)
+ del A_connections
+ air_master.tiles_with_connections.Remove(ref_A)
+ if(B)
+ if(B.zone && B.zone.connections)
+ B.zone.connections.Remove(src)
+ if(!B.zone.connections.len)
+ del B.zone.connections
+ if(ref_B in air_master.tiles_with_connections)
+ var/list/B_connections = air_master.tiles_with_connections[ref_B]
+ B_connections -= src
+ if(B_connections && !B_connections.len)
+ del B_connections
+ air_master.tiles_with_connections.Remove(ref_B)
+ if(zone_A)
+ if(zone_A && zone_A.connections)
+ zone_A.connections.Remove(src)
+ if(!zone_A.connections.len)
+ del zone_A.connections
+ if(zone_B)
+ if(zone_B && zone_B.connections)
+ zone_B.connections.Remove(src)
+ if(!zone_B.connections.len)
+ del zone_B.connections
- if(A.zone && B.zone)
-
- if(B.zone in A.zone.connected_zones)
- if(A.zone.connected_zones[B.zone] > 1)
- A.zone.connected_zones[B.zone]--
- else
- A.zone.connected_zones -= B.zone
-
- if(A.zone in B.zone.connected_zones)
- if(B.zone.connected_zones[A.zone] > 1)
- B.zone.connected_zones[A.zone]--
- else
- B.zone.connected_zones -= A.zone
- if(A.zone.connected_zones && !A.zone.connected_zones.len)
- A.zone.connected_zones = null
- if(B.zone.connected_zones && !B.zone.connected_zones.len)
- B.zone.connected_zones = null
+ if(A && A.zone)
+ if(B && B.zone)
+ if(B.zone in A.zone.connected_zones)
+ if(A.zone.connected_zones[B.zone] > 1)
+ A.zone.connected_zones[B.zone]--
+ else
+ A.zone.connected_zones -= B.zone
+ if(A.zone.connected_zones && !A.zone.connected_zones.len)
+ A.zone.connected_zones = null
+ if( zone_B && (!B.zone || zone_B != B.zone) )
+ if(zone_B in A.zone.connected_zones)
+ if(A.zone.connected_zones[zone_B] > 1)
+ A.zone.connected_zones[zone_B]--
+ else
+ A.zone.connected_zones -= zone_B
+ if(A.zone.connected_zones && !A.zone.connected_zones.len)
+ A.zone.connected_zones = null
+ if(zone_A && (!A.zone || zone_A != A.zone))
+ if(B && B.zone)
+ if(B.zone in zone_A.connected_zones)
+ if(zone_A.connected_zones[B.zone] > 1)
+ zone_A.connected_zones[B.zone]--
+ else
+ zone_A.connected_zones -= B.zone
+ if(zone_A.connected_zones && !zone_A.connected_zones.len)
+ zone_A.connected_zones = null
+ if( zone_B && (!B.zone || zone_B != B.zone) )
+ if(zone_B in zone_A.connected_zones)
+ if(zone_A.connected_zones[zone_B] > 1)
+ zone_A.connected_zones[zone_B]--
+ else
+ zone_A.connected_zones -= zone_B
+ if(zone_A.connected_zones && !zone_A.connected_zones.len)
+ zone_A.connected_zones = null
+ if(B && B.zone)
+ if(A && A.zone)
+ if(A.zone in B.zone.connected_zones)
+ if(B.zone.connected_zones[A.zone] > 1)
+ B.zone.connected_zones[A.zone]--
+ else
+ B.zone.connected_zones -= A.zone
+ if(B.zone.connected_zones && !B.zone.connected_zones.len)
+ B.zone.connected_zones = null
+ if( zone_A && (!A.zone || zone_A != A.zone) )
+ if(zone_A in B.zone.connected_zones)
+ if(B.zone.connected_zones[zone_A] > 1)
+ B.zone.connected_zones[zone_A]--
+ else
+ B.zone.connected_zones -= zone_A
+ if(B.zone.connected_zones && !B.zone.connected_zones.len)
+ B.zone.connected_zones = null
+ if(zone_B && (!B.zone || zone_B != B.zone))
+ if(A && A.zone)
+ if(A.zone in zone_B.connected_zones)
+ if(zone_B.connected_zones[A.zone] > 1)
+ zone_B.connected_zones[A.zone]--
+ else
+ zone_B.connected_zones -= A.zone
+ if(zone_B.connected_zones && !zone_B.connected_zones.len)
+ zone_B.connected_zones = null
+ if( zone_A && (!A.zone || zone_A != A.zone) )
+ if(zone_A in zone_B.connected_zones)
+ if(zone_B.connected_zones[zone_A] > 1)
+ zone_B.connected_zones[zone_A]--
+ else
+ zone_B.connected_zones -= zone_A
+ if(zone_B.connected_zones && !zone_B.connected_zones.len)
+ zone_B.connected_zones = null
. = ..()
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(ref_A != "\ref[A]" || ref_B != "\ref[B]")
+ del src
+ if((A.zone && A.zone != zone_A) || (B.zone && B.zone != zone_B))
+ Sanitize()
+ 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
+ return 0
+ return 1
+
+ proc/Sanitize()
+ //If the zones change on connected turfs, update it.
+ if(A.zone && A.zone != zone_A && B.zone && B.zone != zone_B)
+ if(!A.zone || !B.zone)
+ del src
+
+ if(A.zone == zone_B && B.zone == zone_A)
+ var/turf/temp = B
+ B = A
+ A = temp
+ zone_B = B.zone
+ zone_A = A.zone
+ var/temp_ref = ref_A
+ ref_A = ref_B
+ ref_B = temp_ref
+ return
+
+ if(zone_A)
+ if(zone_A.connections)
+ zone_A.connections.Remove(src)
+ if(!zone_A.connections.len)
+ del zone_A.connections
+
+ if(zone_A.connected_zones)
+ if(zone_A.connected_zones[zone_B] > 1)
+ zone_A.connected_zones[zone_B]--
+ else
+ zone_A.connected_zones.Remove(zone_B)
+ if(zone_A.connected_zones && !zone_A.connected_zones.len)
+ zone_A.connected_zones = null
+
+ if(zone_B)
+ if(zone_B.connections)
+ zone_B.connections.Remove(src)
+ if(!zone_B.connections.len)
+ del zone_B.connections
+
+ if(zone_B.connected_zones)
+ if(zone_B.connected_zones[zone_A] > 1)
+ zone_B.connected_zones[zone_A]--
+ else
+ zone_B.connected_zones.Remove(zone_A)
+ if(zone_B.connected_zones && !zone_B.connected_zones.len)
+ zone_B.connected_zones = null
+
+ if(!A.zone.connections)
+ A.zone.connections = list()
+ A.zone.connections |= src
+ if(!B.zone.connections)
+ B.zone.connections = list()
+ B.zone.connections |= src
+
+ if(!A.zone.connected_zones)
+ A.zone.connected_zones = list()
+ if(!(B.zone in A.zone.connected_zones))
+ A.zone.connected_zones += B.zone
+ A.zone.connected_zones[B.zone] = 1
+ else
+ A.zone.connected_zones[B.zone]++
+
+ if(!B.zone.connected_zones)
+ B.zone.connected_zones = list()
+ if(!(A.zone in B.zone.connected_zones))
+ B.zone.connected_zones += A.zone
+ B.zone.connected_zones[A.zone] = 1
+ else
+ B.zone.connected_zones[A.zone]++
+
+ zone_B = B.zone
+
+ zone_A = A.zone
+
+
+ else if(A.zone && A.zone != zone_A)
+ if(zone_A)
+
+ if(zone_A.connections)
+ zone_A.connections.Remove(src)
+ if(!zone_A.connections.len)
+ del zone_A.connections
+ if(!A.zone.connections)
+ A.zone.connections = list()
+ A.zone.connections |= src
+
+ if(zone_A.connected_zones)
+ if(zone_A.connected_zones[zone_B] > 1)
+ zone_A.connected_zones[zone_B]--
+ else
+ zone_A.connected_zones.Remove(zone_B)
+ if(zone_A.connected_zones && !zone_A.connected_zones.len)
+ zone_A.connected_zones = null
+
+ if(!A.zone.connected_zones)
+ A.zone.connected_zones = list()
+ if(!(zone_B in A.zone.connected_zones))
+ A.zone.connected_zones += zone_B
+ A.zone.connected_zones[zone_B] = 1
+ else
+ A.zone.connected_zones[zone_B]++
+
+ zone_A = A.zone
+
+ else
+ del src
+
+ else if(B.zone && B.zone != zone_B)
+ if(zone_B)
+
+ if(zone_B.connections)
+ zone_B.connections.Remove(src)
+ if(!zone_B.connections.len)
+ del zone_B.connections
+ if(!B.zone.connections)
+ B.zone.connections = list()
+ B.zone.connections |= src
+
+ if(zone_B.connected_zones)
+ if(zone_B.connected_zones[zone_A] > 1)
+ zone_B.connected_zones[zone_A]--
+ else
+ zone_B.connected_zones.Remove(zone_A)
+ if(zone_B.connected_zones && !zone_B.connected_zones.len)
+ zone_B.connected_zones = null
+
+ if(!B.zone.connected_zones)
+ B.zone.connected_zones = list()
+ if(!(zone_A in B.zone.connected_zones))
+ B.zone.connected_zones += zone_A
+ B.zone.connected_zones[zone_A] = 1
+ else
+ B.zone.connected_zones[zone_A]++
+
+ zone_B = B.zone
+
+ else
+ del src
\ No newline at end of file
diff --git a/code/ZAS/Creation.dm b/code/ZAS/Creation.dm
index 5f256767fd3..225fc02eff7 100644
--- a/code/ZAS/Creation.dm
+++ b/code/ZAS/Creation.dm
@@ -1,13 +1,21 @@
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)
+ if(T.zone)
+ T.zone.RemoveTurf(T)
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,12 +25,27 @@ 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.
+ for(var/turf/simulated/T in contents)
+ if(T.zone && T.zone == src)
+ T.zone = null
+ for(var/zone/Z in connected_zones)
+ if(src in Z.connected_zones)
+ Z.connected_zones.Remove(src)
+ for(var/connection/C in connections)
+ C.Cleanup()
zones -= src
. = ..()
proc/FloodFill(turf/start)
+ if(!istype(start))
+ return list()
var
list
open = list(start)
@@ -30,17 +53,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)
@@ -49,12 +78,13 @@ turf/proc/ZCanPass(turf/T)
for(var/obj/obstacle in src)
if(istype(obstacle,/obj/machinery/door) && !istype(obstacle,/obj/machinery/door/window))
continue
- if(!obstacle.CanPass(0, T, 0, 1))
+ if(!obstacle.CanPass(0, T, 1.5, 1))
return 0
+
for(var/obj/obstacle in T)
if(istype(obstacle,/obj/machinery/door) && !istype(obstacle,/obj/machinery/door/window))
continue
- if(!obstacle.CanPass(0, src, 0, 1))
+ if(!obstacle.CanPass(0, src, 1.5, 1))
return 0
return 1
\ No newline at end of file
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..90e88a6c613 100644
--- a/code/ZAS/Definition.dm
+++ b/code/ZAS/Definition.dm
@@ -1,30 +1,11 @@
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.
diff --git a/code/ZAS/FEA_gas_mixture.dm b/code/ZAS/FEA_gas_mixture.dm
new file mode 100644
index 00000000000..cb600b08c4d
--- /dev/null
+++ b/code/ZAS/FEA_gas_mixture.dm
@@ -0,0 +1,1003 @@
+/*
+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.
+
+ 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/adjust(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
+
+ 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..6db306d8b59
--- /dev/null
+++ b/code/ZAS/FEA_system.dm
@@ -0,0 +1,182 @@
+/*
+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
+ if(target != src)
+ 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/tiles_with_connections = 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.zone && !S.blocks_air && S.z < 5) // Added last check to force skipping asteroid z-levels -- TLE
+ if(S.CanPass(null, S, 0, 0))
+ new/zone(S)
+
+ tiles_to_update |= S
+
+ 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)
+ 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..275f0c5e935
--- /dev/null
+++ b/code/ZAS/FEA_turf_tile.dm
@@ -0,0 +1,228 @@
+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(1)
+ overlays.Add(plmaster) //TODO: Make invisible plasma an option
+ if(2)
+ 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)
+
+// 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 && CanPass(null, src, 1.5, 1)) //No zone and not a wall, lets add ourself to a zone.
+ 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) //No zone found, new zone!
+ new/zone(src)
+
+ if(!CanPass(null, src, 0, 0) && !CanPass(null, src, 1.5, 1)) //Can't pass, and was updated. Delete zone connections involving this turf.
+ if(air_master.tiles_with_connections["\ref[src]"])
+ var/list/connections = air_master.tiles_with_connections["\ref[src]"]
+ for(var/connection/C in connections)
+ del C
+
+ update_zone_properties() //Update self zone and adjacent zones.
+
+ if(air_check_directions)
+ processing = 1
+ else
+ processing = 0
+
+
+ proc/update_zone_properties()
+ for(var/direction in cardinal)
+ var/turf/simulated/T = get_step(src,direction)
+ if(air_check_directions&direction) //I can connect air in this direction
+ if(!istype(T)) //Space
+ if(!CanPass(null, T, 1.5, 1) && CanPass(src, T, 0, 0)) //Normally would block it, instead lets make a connection to it.
+ if(zone)
+ zone.AddSpace(T)
+ else if(!CanPass(src, T, 0, 0)) //I block the air, disconnect from it if connected.
+ if(zone && T in zone.space_tiles)
+ zone.RemoveSpace(T)
+ else if(zone)
+ zone.rebuild = 1
+ continue
+ else if(!T.CanPass(null, src, 1.5, 1) && !T.CanPass(null, src, 0, 0)) //If I block air, we must look to see if the adjacent turfs need rebuilt.
+ if(T.zone && !T.zone.rebuild)
+ for(var/direction2 in cardinal - direction) //Check all other directions for air that might be connected.
+ var/turf/simulated/NT = get_step(src, direction2)
+ if(NT && NT.zone && NT.zone == T.zone)
+ T.zone.rebuild = 1
+ else if((!T.CanPass(null, src, 1.5, 1) && T.CanPass(null, src, 0, 0)) || (!CanPass(null, T, 1.5, 1) && CanPass(null, T, 0, 0)))
+ if(T.zone != zone)
+ ZConnect(src,T)
+ else if(zone && !zone.rebuild)
+ for(var/direction2 in cardinal - reverse_direction(direction)) //Check all other directions for air that might be connected.
+ var/turf/simulated/NT = get_step(T, direction2)
+ if(NT && NT.zone && NT.zone == zone)
+ zone.rebuild = 1
\ No newline at end of file
diff --git a/code/ZAS/Fire.dm b/code/ZAS/Fire.dm
index f265c45877a..87c9f63648d 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,23 +155,174 @@ 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)
+ //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
+ 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
+
+ if(fuel)
+ //Volatile Fuel
+ total_fuel += fuel.moles
+ fuel_sources++
+
+ if(liquid)
+ //Liquid Fuel
+ if(liquid.amount <= 0)
+ del liquid
+ else
+ total_fuel += liquid.amount
+ fuel_sources++
+
+ //Toxins
+ if(toxins > 0.3) fuel_sources++
+
+ if(!fuel_sources) return 0 //If there's no fuel, there's no burn. Can't divide by zero anyway.
+
+ 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
+
+/*
+OLD FIRE:
+fire()
+ 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 += vsc.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 += vsc.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
+
+ return fuel_burnt
+ OLD ZBURN:
datum/gas_mixture/proc/zburn(obj/liquid_fuel/liquid)
if(vsc.switch_fire)
. = fire()
@@ -299,32 +340,32 @@ datum/gas_mixture/proc/zburn(obj/liquid_fuel/liquid)
liquid_level = 0
if(fuel) fuel_level = fuel.moles
if(liquid) liquid_level = liquid.amount
- if(liquid && liquid_level <= 0)
+ if(liquid.amount <= 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()
+ temperature += (vsc.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()
+ temperature += (vsc.FIRE_CARBON_ENERGY_RELEASED*fire_ratio_1) / heat_capacity()
if(toxins > fire_ratio_1)
- oxygen -= vsc.plc.OXY_TO_PLASMA*fire_ratio_1
+ oxygen -= vsc.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
+ oxygen -= toxins * vsc.OXY_TO_PLASMA
carbon_dioxide += toxins
toxins = 0
if(fuel_level > fire_ratio_1/1.5)
- oxygen -= vsc.plc.OXY_TO_PLASMA*fire_ratio_1
+ oxygen -= vsc.OXY_TO_PLASMA*fire_ratio_1
fuel.moles -= fire_ratio_1
carbon_dioxide += fire_ratio_1
else if(fuel_level)
- oxygen -= fuel.moles * vsc.plc.OXY_TO_PLASMA
+ oxygen -= fuel.moles * vsc.OXY_TO_PLASMA
carbon_dioxide += fuel.moles
fuel.moles = 0
@@ -335,4 +376,51 @@ datum/gas_mixture/proc/zburn(obj/liquid_fuel/liquid)
if(liquid.amount <= 0)
del liquid
return 1
- return 0
\ No newline at end of file
+ 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..7a17ba702b4 100644
--- a/code/ZAS/Functions.dm
+++ b/code/ZAS/Functions.dm
@@ -1,43 +1,37 @@
-zone
- proc
- AddTurf(turf/T)
- if(T in contents) return
- contents += T
- air.group_multiplier++
- T.zone = src
- RemoveTurf(turf/T)
- if(!(T in contents)) return
- contents -= T
- air.group_multiplier--
- T.zone = null
+/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
+ if(T.zone)
+ T.zone.RemoveTurf(T)
+ contents += T
+ air.group_multiplier++
+ T.zone = src
+ proc/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)
+ proc/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
- AddSpace(turf/space/S)
- if(istype(S,/turf/space))
- if(!space_tiles) space_tiles = list()
- space_tiles += S
- RemoveSpace(turf/space/S)
- if(space_tiles)
- space_tiles -= S
- if(!space_tiles.len) space_tiles = null
+ proc/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)
+/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
@@ -47,113 +41,173 @@ turf/proc/HasDoor(turf/O)
else
return 1
-turf/proc/find_zone()
+/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) continue
- if(!zone)
- zone = T.zone
- zone.AddTurf(src)
- else if(T.zone != zone)
+ var/turf/simulated/T = get_step(src,d)
+ if(!istype(T) || !T.zone || !T.CanPass(0,src,0,0))
+ continue
+ if(T.zone != zone)
ZConnect(src,T)
-proc
- ZMerge(zone/A,zone/B)
- //world << "Merge occured."
- 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
+/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)
- A.air.group_multiplier = 1
- B.air.group_multiplier = 1
+proc/ZMerge(zone/A,zone/B)
+ //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
- A.air.remove_ratio(a_size/c_size)
- B.air.remove_ratio(b_size/c_size)
- A.air.merge(B.air)
- A.air.group_multiplier = c_size
+ //Set air multipliers to one so air represents gas per tile.
+ A.air.group_multiplier = 1
+ B.air.group_multiplier = 1
- for(var/connection/C in B.connections)
- if((C.A in new_contents) && (C.B in new_contents))
- del C
- continue
- A.connections += C
- A.space_tiles += B.space_tiles
- A.contents = new_contents
- for(var/turf/T in B.contents)
- T.zone = A
- del B
+ //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)
- ZConnect(turf/A,turf/B)
- 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."
- return
- if(!A.zone || !B.zone) return
- if(A.zone == B.zone) return
- if(!A.CanPass(0,B,0,0)) return
- for(var/connection/C in A.zone.connections)
- if((C.A == A && C.B == B) || (C.A == B && C.B == A))
+ //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/simulated/T in B.contents)
+ T.zone = A
+
+ for(var/connection/C in A.connections)
+ C.Cleanup()
+
+ del B
+
+proc/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)
+ return
+ if(istype(A,/turf/space))
+ if(B.zone)
+ 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) || !B.CanPass(0,A,0,0)) return
+ if(A.CanPass(null, B, 1.5, 1) && B.CanPass(null, A, 1.5, 1))
+ return ZMerge(A.zone, B.zone)
+
+ //Ensure the connection isn't already made.
+ if(air_master.tiles_with_connections["\ref[A]"])
+ var/list/connections = air_master.tiles_with_connections["\ref[A]"]
+ for(var/connection/C in connections)
+ C.Cleanup()
+ if(C.B == B || C.A == B)
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)
- ZDisconnect(turf/A,turf/B)
- if(A.zone && B.zone)
- if(A.zone != B.zone)
+ //Ensure zones separated by doors do not merge.
+ if(A.HasDoor(B) || B.HasDoor(A)) C.indirect = 1
+
+/*
+proc/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))
+ del C
+ if(C)
+ C.Cleanup()
+ //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) //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((C.A in Z.contents) || (C.B in Z.contents))
+ if(!Z.connections) Z.connections = list()
+ Z.connections += C
+ C.Cleanup()
+
+ //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) //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((C.A in Y.contents) || (C.B in Y.contents))
+ if(!Y.connections) Y.connections = list()
+ Y.connections += C
+ C.Cleanup()
+
+ //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
+ else
+ if(B.zone)
+ if(istype(A,/turf/space))
+ B.zone.RemoveSpace(A)
+ else
+ for(var/connection/C in B.zone.connections)
+ if((C.A == A && C.B == B) || (C.A == B && C.B == A))
+ del C
+ if(C)
+ C.Cleanup()
+ if(A.zone)
+ if(istype(B,/turf/space))
+ A.zone.RemoveSpace(B)
+ else
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(A == B) return
- if(A.CanPass(0,B,0,0)) return
- if(A.HasDoor(B) || B.HasDoor(A)) return
- var/zone/oldzone = A.zone
- var/list/test = FloodFill(A)
- if(B in test) return
- else
- var/zone/Z = new(test,oldzone.air)
- 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
- var/datum/gas_mixture/Y_Air = new
- Y_Air.copy_from(oldzone.air)
- var/zone/Y = new(B,Y_Air)
- 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
- 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)
- else if(istype(B,/turf/space) && A.zone)
- A.zone.RemoveSpace(B)
\ No newline at end of file
+ if(C)
+ C.Cleanup()*/
\ No newline at end of file
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..2d001fb97bf 100644
--- a/code/ZAS/Processing.dm
+++ b/code/ZAS/Processing.dm
@@ -1,109 +1,281 @@
#define QUANTIZE(variable) (round(variable,0.0001))
var/explosion_halt = 0
-zone
- proc/process()
- if(rebuild)
- if(!contents.len)
- del src
- return 0
- var
- turf/sample = pick(contents)
- list/new_contents = FloodFill(sample)
- problem = 0
- for(var/turf/T in contents)
- if(!(T in new_contents))
- problem = 1
+var/zone_share_percent = 3.5
+zone/proc/process()
+ //Deletes zone if empty.
+ if(!contents.len)
+ del src
+ return 0
+ //Does rebuilding stuff. Not sure if used.
+ if(rebuild)
- if(problem)
- var/list/rebuild_turfs = list()
- for(var/turf/T in contents - new_contents)
- contents -= T
- rebuild_turfs += T
- T.zone = null
- for(var/turf/T in rebuild_turfs)
- if(!T.zone)
- var/zone/Z = new/zone(T)
- Z.air.copy_from(air)
- rebuild = 0
-
- var/total_space = 0
- var/turf/space/space
-
- 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]
+ //Choose a random turf and regenerate the zone from it.
+ var
+ turf/simulated/sample = pick(contents)
+ list/new_contents
+ problem = 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]
+ del(space_tiles)
- 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)
+ contents.Remove(null) //I can't believe this is needed.
- air.react(null,0)
- var/check = air.check_tile_graphic()
+ if(!contents.len)
+ del src
+
+ var/list/tried_turfs = list()
+ do
+ if(sample)
+ tried_turfs |= sample
+ var/list/turfs_to_consider = contents - tried_turfs
+ if(!turfs_to_consider.len)
+ break
+ sample = pick(turfs_to_consider) //Nor this.
+ while(!istype(sample) || !sample.CanPass(null, sample, 1.5, 1))
+
+ if(!istype(sample) || !sample.CanPass(null, sample, 1.5, 1)) //Not a single valid turf.
+ for(var/turf/simulated/T in contents)
+ air_master.tiles_to_update |= T
+ del src
+
+ new_contents = FloodFill(sample)
+
+ for(var/turf/space/S in new_contents)
+ if(!space_tiles)
+ space_tiles = list()
+ space_tiles |= S
+
+ //If something isn't carried over, there was a complication.
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 in new_contents))
+ problem = 1
+ T.zone = null
+
+ if(problem)
+ //Build some new zones for stuff that wasn't included.
+ var/list/turf/simulated/rebuild_turfs = contents - new_contents
+ var/list/turf/simulated/reconsider_turfs = list()
+ contents = new_contents
+ for(var/turf/T in rebuild_turfs)
+ if(istype(T,/turf/space))
+ air_master.tiles_to_update |= T
+ else if(!T.zone && T.CanPass(null, T, 1.5, 1))
+ var/zone/Z = new /zone(T)
+ Z.air.copy_from(air)
+ else
+ reconsider_turfs |= T
+ for(var/turf/T in reconsider_turfs)
if(!T.zone)
- T.zone = src
+ var/zone/Z = new /zone(T)
+ Z.air.copy_from(air)
+ rebuild = 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)
+ //Sometimes explosions will cause the air to be deleted for some reason.
+ if(!air)
+ air = new()
+ air.adjust(MOLES_O2STANDARD, 0, MOLES_N2STANDARD, 0, list())
+ world.log << "Air object lost in zone. Regenerating."
- 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)
+ //Counting up space.
+ var/total_space = 0
- air.graphic_archived = air.graphic
+ if(space_tiles)
+ for(var/T in space_tiles)
+ if(!istype(T,/turf/space))
+ space_tiles -= T
+ continue
+ total_space++
+ if(space_tiles && !space_tiles.len)
+ del space_tiles
- air.temperature = max(TCMB,air.temperature)
+ //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.return_pressure()) > vsc.airflow_lightest_pressure)
+ AirflowSpace(src)
+ ShareSpace(air,total_space*(zone_share_percent/100))
- if(length(connections))
- for(var/connection/C in connections)
- C.Cleanup()
- if(C && !C.indirect)
- if(C.A.zone.air.compare(C.B.zone.air))
- ZMerge(C.A.zone,C.B.zone)
- 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))
+ if(!(last_update%20)) //every 20 processes.
+ if(connections)
+ connections.Remove(null)
+ if(!connections.len)
+ del connections
+ if(connected_zones)
+ connected_zones.Remove(null)
+ if(!connected_zones.len)
+ del connected_zones
+ //React the air here.
+ //air.react(null,0)
-zone/proc
- connected_zones()
- . = list()
+ //Check the graphic.
+
+ 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
+
+ //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)
- var/zone/Z
- if(C.A.zone == src)
- Z = C.B.zone
- else
- Z = C.A.zone
+ //Check if the connection is valid first.
+ if(!C.Cleanup())
+ continue
+ //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)
- if(Z in .)
- .[Z]++
- else
- . += Z
- .[Z] = 1
\ No newline at end of file
+ //Share some
+ for(var/zone/Z in connected_zones)
+ //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.return_pressure() - air.return_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
+ if(C.A.zone == src)
+ Z = C.B.zone
+ else
+ Z = C.A.zone
+
+ if(Z in .)
+ .[Z]++
+ else
+ . += Z
+ .[Z] = 1
\ No newline at end of file
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/configuration.dm b/code/datums/configuration.dm
index e2a03978603..f0cfee61dfc 100644
--- a/code/datums/configuration.dm
+++ b/code/datums/configuration.dm
@@ -14,6 +14,7 @@
var/log_adminchat = 0 // log admin chat messages
var/log_adminwarn = 0 // log warnings admins get about bomb construction and such
var/log_pda = 0 // log pda messages
+ var/log_hrefs = 0 // logs all links clicked in-game. Could be used for debugging and tracking down exploits
var/sql_enabled = 1 // for sql switching
var/allow_vote_restart = 0 // allow votes to restart
var/allow_vote_mode = 0 // allow votes to change mode
@@ -171,6 +172,9 @@
if ("log_pda")
config.log_pda = 1
+ if ("log_hrefs")
+ config.log_hrefs = 1
+
if ("allow_vote_restart")
config.allow_vote_restart = 1
diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm
index 44f9e1cc50e..2e488ab4271 100644
--- a/code/datums/datumvars.dm
+++ b/code/datums/datumvars.dm
@@ -248,7 +248,6 @@ client
if(ishuman(D))
body += ""
body += ""
- body += ""
body += ""
body += ""
body += ""
@@ -390,419 +389,382 @@ client
return html
-//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]"
+/client/proc/view_var_Topic(href,href_list,hsrc)
+ //This will all be moved over to datum/admins/Topic() ~Carn
+ if( (usr.client == src) && src.holder )
+ . = 1 //default return
+ if (href_list["Vars"])
+ debug_variables(locate(href_list["Vars"]))
- references += "); "
- file("topic_log") << references
+ //~CARN: for renaming mobs (updates their real_name and their ID/PDA if applicable).
+ else if (href_list["rename"])
+ var/new_name = copytext(sanitize(input(usr,"What would you like to name this mob?","Input a name") as text|null),1,MAX_NAME_LEN)
+ if(!new_name) return
+ var/mob/M = locate(href_list["rename"])
+ if(!istype(M)) return
- sleep(3)
+ message_admins("Admin [key_name_admin(usr)] renamed [key_name_admin(M)] to [new_name].", 1)
+ if(istype(M, /mob/living/carbon/human))
+ for(var/obj/item/weapon/card/id/ID in M.contents)
+ if(ID.registered_name == M.real_name)
+ ID.name = "[new_name]'s ID Card ([ID.assignment])"
+ ID.registered_name = new_name
+ break
+ for(var/obj/item/device/pda/PDA in M.contents)
+ if(PDA.owner == M.real_name)
+ PDA.name = "PDA-[new_name] ([PDA.ownjob])"
+ PDA.owner = new_name
+ break
+ M.real_name = new_name
+ M.name = new_name
+ M.original_name = new_name
+ href_list["datumrefresh"] = href_list["rename"]
- //search the href for script injection //This is a temporary measure
- if( findtext(href,"