Signed-off-by: unknown <Colm@Blue.(none)>
This commit is contained in:
unknown
2012-03-15 22:52:29 +00:00
parent 4861e100be
commit a7bce8a609
13 changed files with 1935 additions and 0 deletions

587
code/ZAS/Airflow.dm Normal file
View File

@@ -0,0 +1,587 @@
/*
CONTAINS:
All AirflowX() procs, all Variable Setting Controls for airflow, save/load variable tweaks for airflow.
VARIABLES:
atom/movable/airflow_dest
The destination turf of a flying object.
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.
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.
RETURNS: 1 if the object moves under the air conditions, 0 if it stays put.
atom/movable/airflow_hit(atom/A)
Contains results of hitting a solid object (A) due to airflow.
A is the dense object hit.
Use airflow_speed to determine how fast the projectile was going.
AUTOMATIC PROCS:
Airflow(zone/A, zone/B, n)
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.
Called by zone updates. A is a zone connected to space.
atom/movable/GotoAirflowDest(n)
atom/movable/RepelAirflowDest(n)
Called by main airflow procs to cause the object to fly to or away from destination at speed n.
Probably shouldn't call this directly unless you know what you're
doing and have set airflow_dest. airflow_hit() will be called if the object collides with an obstacle.
*/
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."
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.
mob/proc/airflow_stun()
if(weakened <= 0) src << "\red The sudden rush of air knocks you over!"
weakened = max(weakened,5)
mob/living/silicon/airflow_stun()
return
mob/living/carbon/metroid/airflow_stun()
return
mob/living/carbon/human/airflow_stun()
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)
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
return 1
mob/dead/observer/check_airflow_movable()
return 0
mob/living/silicon/check_airflow_movable()
return 0
obj/item/check_airflow_movable(n)
. = ..()
switch(w_class)
if(2)
if(n < vsc.AF_SMALL_MOVEMENT_THRESHOLD) return 0
if(3)
if(n < vsc.AF_NORMAL_MOVEMENT_THRESHOLD) return 0
if(4,5)
if(n < vsc.AF_LARGE_MOVEMENT_THRESHOLD) return 0
proc/Airflow(zone/A,zone/B,n)
//Now n is a percent of one atm.
n = round((n/vsc.AF_PERCENT_OF)*100,0.1)
//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
//These turfs are the midway point between A and B, and will be the destination point for thrown objects.
var/list/connected_turfs = A.connections[B]
//Get lists of things that can be thrown across the room for each zone.
var/list/pplz = A.movables()
var/list/otherpplz = B.movables()
for(var/atom/movable/M in pplz)
//Check for knocking people over
if(ismob(M) && n > vsc.AF_HUMAN_STUN_THRESHOLD)
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
for(var/turf/U in connected_turfs)
if(M in range(U)) fail = 0
if(fail) 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.
spawn M.GotoAirflowDest(abs(n) * (vsc.AF_SPEED_MULTIPLIER/10))
//Send the object flying at a speed determined by n and AF_SPEED_MULTIPLIER.
//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:nodamage) continue
M:airflow_stun()
if(M.check_airflow_movable(abs(n)))
var/fail = 1
for(var/turf/U in connected_turfs)
if(M in range(U)) fail = 0
if(fail) continue
if(M && !M.airflow_speed)
M.airflow_dest = pick(connected_turfs)
spawn M.RepelAirflowDest(abs(n) * (vsc.AF_SPEED_MULTIPLIER/10))
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.
n = round((n/vsc.AF_PERCENT_OF)*100,0.1)
if(n < vsc.AF_TINY_MOVEMENT_THRESHOLD) 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:nodamage) continue
M:airflow_stun()
if(M.check_airflow_movable(n))
var/fail = 1
for(var/turf/U in connected_turfs)
if(M in range(U)) fail = 0
if(fail) continue
if(!M.airflow_speed)
M.airflow_dest = pick(connected_turfs)
spawn
if(M) M.GotoAirflowDest(n * (vsc.AF_SPEED_MULTIPLIER/10))
//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
proc/GotoAirflowDest(n)
if(!airflow_dest) return
if(airflow_speed < 0) return
if(airflow_speed)
airflow_speed = n
return
if(airflow_dest == loc)
step_away(src,loc)
if(ismob(src))
if(src:nodamage) return
if(istype(src, /mob/living/carbon/human))
if(istype(src, /mob/living/carbon/human))
if(src:buckled) return
if(src:wear_suit)
if(src:wear_suit.flags & SUITSPACE) return
if(src:shoes)
if(src:shoes.type == /obj/item/clothing/shoes/magboots) return
src << "\red You are sucked away by airflow!"
airflow_speed = min(round(n),9)
var
xo = airflow_dest.x - src.x
yo = airflow_dest.y - src.y
od = 0
airflow_dest = null
if(!density)
density = 1
od = 1
while(airflow_speed > 0)
if(airflow_speed <= 0) return
airflow_speed = min(airflow_speed,15)
airflow_speed -= vsc.AF_SPEED_DECAY
if(airflow_speed > 7)
if(airflow_time++ >= airflow_speed - 7)
sleep(1 * tick_multiplier)
else
sleep(max(1,10-(airflow_speed+3)) * tick_multiplier)
if ((!( src.airflow_dest ) || src.loc == src.airflow_dest))
src.airflow_dest = locate(min(max(src.x + xo, 1), world.maxx), min(max(src.y + yo, 1), world.maxy), src.z)
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
airflow_dest = null
airflow_speed = -1
spawn(150 * tick_multiplier) airflow_speed = 0
if(od)
density = 0
proc/RepelAirflowDest(n)
if(!airflow_dest) return
if(airflow_speed < 0) return
if(airflow_speed)
airflow_speed = n
return
if(airflow_dest == loc)
step_away(src,loc)
if(ismob(src))
if(src:nodamage) return
if(istype(src, /mob/living/carbon/human))
if(istype(src, /mob/living/carbon/human))
if(src:buckled) return
if(src:wear_suit)
if(src:wear_suit.flags & SUITSPACE) return
if(src:shoes)
if(src:shoes.type == /obj/item/clothing/shoes/magboots) return
src << "\red You are pushed away by airflow!"
airflow_speed = min(round(n),9)
var
xo = -(airflow_dest.x - src.x)
yo = -(airflow_dest.y - src.y)
od = 0
airflow_dest = null
if(!density)
density = 1
od = 1
while(airflow_speed > 0)
if(airflow_speed <= 0) return
airflow_speed = min(airflow_speed,15)
airflow_speed -= vsc.AF_SPEED_DECAY
if(airflow_speed > 7)
if(airflow_time++ >= airflow_speed - 7)
sleep(1 * tick_multiplier)
else
sleep(max(1,10-(airflow_speed+3)) * tick_multiplier)
if ((!( src.airflow_dest ) || src.loc == src.airflow_dest))
src.airflow_dest = locate(min(max(src.x + xo, 1), world.maxx), min(max(src.y + yo, 1), world.maxy), src.z)
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
airflow_dest = null
airflow_speed = -1
spawn(150 * tick_multiplier) airflow_speed = 0
if(od)
density = 0
Bump(atom/A)
if(airflow_speed > 0 && airflow_dest)
airflow_hit(A)
else
airflow_speed = 0
. = ..()
atom/movable/proc/airflow_hit(atom/A)
airflow_speed = -1
spawn(50 * tick_multiplier) airflow_speed = 0
airflow_dest = null
mob/airflow_hit(atom/A)
for(var/mob/M in hearers(src))
M.show_message("\red <B>[src] slams into [A]!</B>",1,"\red You hear a loud slam!",2)
playsound(src.loc, "smash.ogg", 25, 1, -1)
. = ..()
obj/airflow_hit(atom/A)
for(var/mob/M in hearers(src))
M.show_message("\red <B>[src] slams into [A]!</B>",1,"\red You hear a loud slam!",2)
playsound(src.loc, "smash.ogg", 25, 1, -1)
. = ..()
obj/item/airflow_hit(atom/A)
airflow_speed = -1
spawn(50 * tick_multiplier) 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 <B>[src] slams into [A]!</B>",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()
if(airflow_speed > 10)
paralysis += round(airflow_speed * vsc.AF_STUN_MULTIPLIER)
stunned = max(stunned,paralysis + 3)
else
stunned += round(airflow_speed * vsc.AF_STUN_MULTIPLIER/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+1<Y2) .=NORTH
else .=NORTHEAST
else if(GDir==NORTHWEST)
Ref=(1+((1-(X2/X1))))*Y1
if(Ref-1>Y2) .=WEST
else if(Ref+1<Y2) .=NORTH
else .=NORTHWEST
else if(GDir==SOUTHEAST)
Ref=(1-((X2/X1)-1))*Y1
if(Ref-1>Y2) .=SOUTH
else if(Ref+1<Y2) .=EAST
else .=SOUTHEAST
else if(GDir==SOUTHWEST)
Ref=(X2/X1)*Y1
if(Ref-1>Y2) .=SOUTH
else if(Ref+1<Y2) .=WEST
else .=SOUTHWEST
else
return GDir
proc/SaveTweaks()
var/savefile/F = new("data/game_settings.sav")
F << vsc
del F
world.log << "TWEAKS: Airflow, Plasma and Damage settings saved."
proc/LoadTweaks()
if(fexists("data/game_settings.sav"))
var/savefile/F = new("data/game_settings.sav")
F >> vsc
del F
world.log << "TWEAKS: Airflow, Plasma and Damage settings loaded."

61
code/ZAS/Connection.dm Normal file
View File

@@ -0,0 +1,61 @@
connection
var
turf //The turfs involved in the connection.
A
B
indirect = 0 //If the connection is purely indirect, the zones should not join.
last_updated //The tick at which this was last updated.
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.connected_zones)
A.zone.connected_zones = list()
if(!B.zone.connected_zones)
B.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(!(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]++
Del()
if(A.zone && A.zone.connections)
A.zone.connections -= src
if(B.zone && B.zone.connections)
B.zone.connections -= src
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
. = ..()
proc/Cleanup()
if(A.zone == B.zone) del src
if(!A.zone || !B.zone) del src

60
code/ZAS/Creation.dm Normal file
View File

@@ -0,0 +1,60 @@
zone
New(turf/start)
if(istype(start,/list))
contents = start
else
contents = FloodFill(start)
for(var/turf/T in contents)
T.zone = src
if(istype(T,/turf/space))
AddSpace(T)
air = new
var/members = contents.len
for(var/turf/simulated/T in contents)
air.oxygen += T.oxygen / members
air.nitrogen += T.nitrogen / members
air.carbon_dioxide += T.carbon_dioxide / members
air.toxins += T.toxins / members
air.temperature += T.temperature / members
air.group_multiplier = contents.len
zones += src
Del()
zones -= src
. = ..()
proc/FloodFill(turf/start)
var
list
open = list(start)
closed = list()
while(open.len)
for(var/turf/T in open)
if(!T.HasDoor())
for(var/d in cardinal)
var/turf/O = get_step(T,d)
if(O.ZCanPass(T) && !(O in open) && !(O in closed))
open += O
open -= T
closed += T
return closed
turf/proc/ZCanPass(turf/T)
if(istype(T,/turf/space)) return 0
else
if(T.blocks_air||blocks_air)
return 0
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))
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))
return 0
return 1

56
code/ZAS/Debug.dm Normal file
View File

@@ -0,0 +1,56 @@
client/proc/Zone_Info(turf/T as null|turf)
set category = "Debug"
if(T)
if(T.zone)
T.zone.DebugDisplay(mob)
else
mob << "No zone here."
else
for(T in world)
T.overlays -= 'debug_space.dmi'
T.overlays -= 'debug_group.dmi'
T.overlays -= 'debug_connect.dmi'
zone/proc
DebugDisplay(mob/M)
if(!dbg_output)
dbg_output = 1 //Don't want to be spammed when someone investigates a zone...
for(var/turf/T in contents)
T.overlays += 'debug_group.dmi'
for(var/turf/space/S in space_tiles)
S.overlays += 'debug_space.dmi'
M << "<u>Zone Air Contents</u>"
M << "Oxygen: [air.oxygen]"
M << "Nitrogen: [air.nitrogen]"
M << "Plasma: [air.toxins]"
M << "Carbon Dioxide: [air.carbon_dioxide]"
M << "Temperature: [air.temperature]"
M << "Heat Energy: [air.thermal_energy()]"
M << "Pressure: [air.return_pressure()]"
M << ""
M << "<u>Connections: [length(connections)]</u>"
for(var/connection/C in connections)
M << "[C.A] --> [C.B] [(C.indirect?"Indirect":"Direct")]"
C.A.overlays += 'debug_connect.dmi'
C.B.overlays += 'debug_connect.dmi'
spawn(50)
C.A.overlays -= 'debug_connect.dmi'
C.B.overlays -= 'debug_connect.dmi'
else
dbg_output = 0
for(var/turf/T in contents)
T.overlays -= 'debug_group.dmi'
for(var/turf/space/S in space_tiles)
S.overlays -= 'debug_space.dmi'
for(var/zone/Z in zones)
if(Z.air == air && Z != src)
var/turf/zloc = pick(Z.contents)
M << "\red Illegal air datum shared by: [zloc.loc.name]"

34
code/ZAS/Definition.dm Normal file
View File

@@ -0,0 +1,34 @@
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.
datum/gas_mixture/air //The air contents of the zone.
list/contents //All the tiles that are contained in this zone.
list/connections // /connection objects which refer to connections with other zones, e.g. through a door.
list/connected_zones //Parallels connections, but lists zones to which this one is connected and the number
//of points they're connected at.
list/space_tiles // Any space tiles in this list will cause air to flow out.
last_update = 0

338
code/ZAS/Fire.dm Normal file
View File

@@ -0,0 +1,338 @@
vs_control/var/IgnitionLevel = 10 //Moles of oxygen+plasma - co2 needed to burn.
#define OXYGEN
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
var/datum/gas_mixture/air_contents = return_air(1)
if(!air_contents)
return 0
/*if(active_hotspot)
if(soh)
if(air_contents.toxins > 0.5 && air_contents.oxygen > 0.5)
if(active_hotspot.temperature < exposed_temperature)
active_hotspot.temperature = exposed_temperature
if(active_hotspot.volume < exposed_volume)
active_hotspot.volume = exposed_volume
return 1*/
var/igniting = 0
if(locate(/obj/fire) in src)
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)
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
F.volume = CELL_VOLUME
//active_hotspot.just_spawned = (current_cycle < air_master.current_cycle)
//remove just_spawned protection if no longer processing this cell
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
anchored = 1
mouse_opacity = 0
//luminosity = 3
icon = 'fire.dmi'
icon_state = "1"
layer = TURF_LAYER
var
volume = CELL_VOLUME
temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST
firelevel = 10000
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(istype(S,/turf/simulated/floor))
var
datum/gas_mixture/air_contents = S.return_air()
datum/gas/volatile_fuel/fuel = locate(/datum/gas/volatile_fuel/) in air_contents.trace_gases
fuel_level = 0
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.oxygen + air_contents.toxins + fuel_level*1.5 + liquid_level*1.5) - (air_contents.carbon_dioxide*0.25)
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.
if(flow)
if(flow.oxygen > 0.3 && (flow.toxins || fuel_level || liquid))
icon_state = "1"
if(firelevel > vsc.IgnitionLevel * 2)
icon_state = "2"
if(firelevel > vsc.IgnitionLevel * 3.5)
icon_state = "3"
flow.temperature = max(PLASMA_MINIMUM_BURN_TEMPERATURE+0.1,flow.temperature)
flow.zburn(liquid)
else
del src
S.assume_air(flow)
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))
New(newLoc,fl)
..()
dir = pick(cardinal)
sd_SetLuminosity(3)
firelevel = fl
for(var/mob/living/carbon/human/M in loc)
M.FireBurn(firelevel/(vsc.IgnitionLevel*10))
Del()
if (istype(loc, /turf/simulated))
src.sd_SetLuminosity(0)
loc = null
..()
obj/liquid_fuel
icon = 'effects.dmi'
icon_state = "slube"
layer = TURF_LAYER+0.2
anchored = 1
var/amount = 1
New(newLoc)
for(var/obj/liquid_fuel/other in newLoc)
if(other != src)
other.amount += src.amount
del src
. = ..()
vs_control/var/switch_fire = 1
turf/simulated/var/fire_protection = 0
datum/gas_mixture/proc/zburn(obj/liquid_fuel/liquid)
if(vsc.switch_fire)
. = fire()
if(liquid && liquid.amount > 0)
oxygen -= fire_ratio_1
liquid.amount = max(liquid.amount-fire_ratio_1,0)
carbon_dioxide += fire_ratio_1
if(liquid.amount <= 0)
del liquid
return
if(temperature > PLASMA_MINIMUM_BURN_TEMPERATURE)
var
fuel_level = 0
datum/gas/volatile_fuel/fuel = locate() in trace_gases
liquid_level = 0
if(fuel) fuel_level = fuel.moles
if(liquid) liquid_level = liquid.amount
if(liquid && liquid_level <= 0)
del liquid
liquid_level = 0
if(oxygen > 0.3 && (toxins || fuel_level || liquid_level))
if(toxins && temperature < PLASMA_UPPER_TEMPERATURE)
temperature += (FIRE_PLASMA_ENERGY_RELEASED*fire_ratio_1) / heat_capacity()
if((fuel_level || liquid_level) && temperature < PLASMA_UPPER_TEMPERATURE)
temperature += (FIRE_CARBON_ENERGY_RELEASED*fire_ratio_1) / heat_capacity()
if(toxins > fire_ratio_1)
oxygen -= vsc.plc.OXY_TO_PLASMA*fire_ratio_1
toxins -= fire_ratio_1
carbon_dioxide += fire_ratio_1
else if(toxins)
oxygen -= toxins * vsc.plc.OXY_TO_PLASMA
carbon_dioxide += toxins
toxins = 0
if(fuel_level > fire_ratio_1/1.5)
oxygen -= vsc.plc.OXY_TO_PLASMA*fire_ratio_1
fuel.moles -= fire_ratio_1
carbon_dioxide += fire_ratio_1
else if(fuel_level)
oxygen -= fuel.moles * vsc.plc.OXY_TO_PLASMA
carbon_dioxide += fuel.moles
fuel.moles = 0
if(liquid_level > 0)
oxygen -= fire_ratio_1
liquid.amount = max(liquid.amount-fire_ratio_1,0)
carbon_dioxide += fire_ratio_1
if(liquid.amount <= 0)
del liquid
return 1
return 0

159
code/ZAS/Functions.dm Normal file
View File

@@ -0,0 +1,159 @@
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
DivideAir(ratio)
ratio = min(1,max(0,ratio))
air.oxygen *= ratio
air.oxygen = QUANTIZE(air.oxygen)
air.nitrogen *= ratio
air.nitrogen = QUANTIZE(air.nitrogen)
air.toxins *= ratio
air.toxins = QUANTIZE(air.toxins)
air.carbon_dioxide *= ratio
air.carbon_dioxide = QUANTIZE(air.carbon_dioxide)
if(air.trace_gases.len)
for(var/datum/gas/trace_gas in air.trace_gases)
trace_gas.moles *= ratio
trace_gas.moles = QUANTIZE(trace_gas.moles)
air.temperature = air.temperature*ratio + TCMB*(1-ratio)
air.temperature = QUANTIZE(air.temperature)
AddSpace(turf/space/S)
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
turf/proc/HasDoor(turf/O)
for(var/obj/machinery/door/D in src)
if(isnum(O) && O)
if(!D.density) continue
if(istype(D,/obj/machinery/door/window))
if(!O) continue
if(D.dir == get_dir(D,O)) return 1
else
return 1
turf/proc/find_zone()
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)
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
A.air.group_multiplier = 1
B.air.group_multiplier = 1
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
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
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))
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'
ZDisconnect(turf/A,turf/B)
if(A.zone && B.zone)
if(A.zone != B.zone)
for(var/connection/C in A.zone.connections)
if((C.A == A && C.B == B) || (C.A == B && C.B == A))
//world << "Connection Dissolved: [A] -/-> [B] [(C.indirect?"Indirect":"Direct")]"
/*A.overlays += 'zone_connection_A.dmi'
B.overlays += 'zone_connection_B.dmi'
spawn(10)
A.overlays -= 'zone_connection_A.dmi'
B.overlays -= 'zone_connection_B.dmi'*/
del C
/*else
if(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)

252
code/ZAS/Plasma.dm Normal file
View File

@@ -0,0 +1,252 @@
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 = 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"
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 = 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."
//N2O_REACTION = 0 //Plasma can react with N2O, making sparks and starting a fire if levels are high.
//N2O_REACTION_RANDOM = 5
//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()
if(flags & PLASMAGUARD) return 0
if((flags & SUITSPACE) && !vsc.plc.PLASMAGUARD_ONLY) return 1
if(vsc.plc.ALL_ITEM_CONTAMINATION) return 1
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()
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(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/living/carbon/human/proc/pl_effects()
if(stat >= 2)
return
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
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)
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(vsc.plc.GENETIC_CORRUPTION)
if(rand(1,1000) < 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/pl_head_protected()
if(head)
if(head.flags & PLASMAGUARD || head.flags & HEADSPACE) return 1
return 0
/mob/living/carbon/human/proc/pl_suit_protected()
if(wear_suit)
if(wear_suit.flags & PLASMAGUARD || wear_suit.flags & SUITSPACE) 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
turf/Entered(obj/item/I)
. = ..()
if(istype(I))
var/datum/gas_mixture/env = return_air(1)
if(env.toxins > 0.35)
if(I.can_contaminate())
I.contaminated = 1

103
code/ZAS/Processing.dm Normal file
View File

@@ -0,0 +1,103 @@
#define QUANTIZE(variable) (round(variable,0.0001))
var/explosion_halt = 0
zone
proc/process()
if(rebuild)
if(!contents) del src
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
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]
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]
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)
air.react(null,0)
var/check = air.check_tile_graphic()
for(var/turf/T in contents)
if(T.zone && T.zone != src)
RemoveTurf(T)
if(dbg_output) world << "Removed invalid turf."
else if(!T.zone)
T.zone = src
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)
if(air.temperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST)
for(var/atom/movable/item in S)
item.temperature_expose(air, air.temperature, CELL_VOLUME)
S.temperature_expose(air, air.temperature, CELL_VOLUME)
air.graphic_archived = air.graphic
air.temperature = max(TCMB,air.temperature)
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))
zone/proc
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

View File

@@ -0,0 +1,285 @@
var/global/vs_control/vsc = new
vs_control
var
list/settings = list()
list/bitflags = list("1","2","4","8","16","32","64","128","256","512","1024")
pl_control/plc = new()
/*RPREV_REQUIRE_HEADS_ALIVE = 0
RPREV_REQUIRE_HEADS_ALIVE_DESC = "Require the heads to be captured alive in RP Rev, rather than either dead or captured."
RPREV_REQUIRE_REVS_ALIVE = 0
RPREV_REQUIRE_REVS_ALIVE_DESC = "Require the rev leaders to be captured alive in RP Rev, rather than either dead or captured."*/
New()
. = ..()
settings = vars.Copy()
var/datum/D = new() //Ensure only unique vars are put through by making a datum and removing all common vars.
for(var/V in D.vars)
settings -= V
for(var/V in settings)
if(findtextEx(V,"_RANDOM") || findtextEx(V,"_DESC") || findtextEx(V,"_METHOD"))
settings -= V
settings -= "settings"
settings -= "bitflags"
settings -= "plc"
proc/ChangeSettingsDialog(mob/user,list/L)
//var/which = input(user,"Choose a setting:") in L
var/dat = ""
for(var/ch in L)
if(findtextEx(ch,"_RANDOM") || findtextEx(ch,"_DESC") || findtextEx(ch,"_METHOD") || findtextEx(ch,"_NAME")) continue
var/vw
var/vw_desc = "No Description."
var/vw_name = ch
if(ch in plc.settings)
vw = plc.vars[ch]
if("[ch]_DESC" in plc.vars) vw_desc = plc.vars["[ch]_DESC"]
if("[ch]_NAME" in plc.vars) vw_name = plc.vars["[ch]_NAME"]
else
vw = vars[ch]
if("[ch]_DESC" in vars) vw_desc = vars["[ch]_DESC"]
if("[ch]_NAME" in plc.vars) vw_name = vars["[ch]_NAME"]
dat += "<b>[vw_name] = [vw]</b> <A href='?src=\ref[src];changevar=[ch]'>\[Change\]</A><br>"
dat += "<i>[vw_desc]</i><br><br>"
user << browse(dat,"window=settings")
Topic(href,href_list)
if("changevar" in href_list)
ChangeSetting(usr,href_list["changevar"])
proc/ChangeSetting(mob/user,ch)
var/vw
var/how = "Text"
if(ch in plc.settings)
vw = plc.vars[ch]
if("[ch]_METHOD" in vars)
how = plc.vars["[ch]_METHOD"]
else
if(isnum(vw))
how = "Numeric"
else
how = "Text"
else
vw = vars[ch]
if("[ch]_METHOD" in vars)
how = vars["[ch]_METHOD"]
else
if(isnum(vw))
how = "Numeric"
else
how = "Text"
var/newvar = vw
switch(how)
if("Numeric")
newvar = input(user,"Enter a number:","Settings",newvar) as num
if("Bit Flag")
var/flag = input(user,"Toggle which bit?","Settings") in bitflags
flag = text2num(flag)
if(newvar & flag)
newvar &= ~flag
else
newvar |= flag
if("Toggle")
newvar = !newvar
if("Text")
newvar = input(user,"Enter a string:","Settings",newvar) as text
if("Long Text")
newvar = input(user,"Enter text:","Settings",newvar) as message
vw = newvar
if(ch in plc.settings)
plc.vars[ch] = vw
else
vars[ch] = vw
if(how == "Toggle")
newvar = (newvar?"ON":"OFF")
world << "\blue <b>[key_name(user)] changed the setting [ch] to [newvar].</b>"
//user << "[which] has been changed to [newvar]."
if(ch in plc.settings)
ChangeSettingsDialog(user,plc.settings)
else
ChangeSettingsDialog(user,settings)
proc/RandomizeWithProbability()
for(var/V in settings)
var/newvalue
if("[V]_RANDOM" in vars)
if(isnum(vars["[V]_RANDOM"]))
newvalue = prob(vars["[V]_RANDOM"])
else if(istext(vars["[V]_RANDOM"]))
newvalue = roll(vars["[V]_RANDOM"])
else
newvalue = vars[V]
V = newvalue
proc/ChangePlasma()
for(var/V in plc.settings)
plc.Randomize(V)
////world << "Plasma randomized."
proc/SetDefault(def)
switch(def)
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,
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.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.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!
//plc.PLASMA_DMG_OFFSET = 1
//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
plc.PLASMAGUARD_ONLY = 0
// plc.CANISTER_CORROSION = 0 //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.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.N2O_REACTION = 0 //Plasma can react with N2O, making sparks and starting a fire if levels are high.
// plc.PLASMA_COLOR = "onturf" //RBPYB
//if(prob(20))
// plc.PLASMA_COLOR = pick("red","yellow","blue","purple")
//plc.PLASMA_DMG_OFFSET = 1.5
//plc.PLASMA_DMG_QUOTIENT = 8
plc.CONTAMINATION_LOSS = 0.01
var/s = pick(plc.settings)
plc.Randomize(s)
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.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.N2O_REACTION = 0 //Plasma can react with N2O, making sparks and starting a fire if levels are high.
// plc.PLASMA_COLOR = "onturf"//pick("red","yellow","blue","purple") //RBPYB
//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")
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,
plc.GENETIC_CORRUPTION = 5 //Chance of genetic corruption as well as toxic damage, X in 1000.
plc.SKIN_BURNS = 1 //Plasma has an effect similar to mustard gas on the un-suited.
// plc.PLASMA_INJECTS_TOXINS = 1 //Plasma damage injects the toxins chemical to do damage over time.
plc.EYE_BURNS = 1 //Plasma burns the eyes of anyone not wearing eye protection.
// plc.N2O_REACTION = 1 //Plasma can react with N2O, making sparks and starting a fire if levels are high.
// plc.PLASMA_COLOR = "onturf" //RBPYB
//plc.PLASMA_DMG_OFFSET = 3
//plc.PLASMA_DMG_QUOTIENT = 5
plc.CONTAMINATION_LOSS = 0.02
/////world << "Plasma color updated."
pl_control
var/list/settings = list()
New()
. = ..()
settings = vars.Copy()
var/datum/D = new() //Ensure only unique vars are put through by making a datum and removing all common vars.
for(var/V in D.vars)
settings -= V
for(var/V in settings)
if(findtextEx(V,"_RANDOM") || findtextEx(V,"_DESC"))
settings -= V
settings -= "settings"
proc/Randomize(V)
//world << "Randomizing [V]"
var/newvalue
if("[V]_RANDOM" in vars)
if(isnum(vars["[V]_RANDOM"]))
newvalue = prob(vars["[V]_RANDOM"])
if(newvalue)
//world << "Probability [vars["[V]_RANDOM"]]%: Success."
else
//world << "Probability [vars["[V]_RANDOM"]]%: Failure."
else if(istext(vars["[V]_RANDOM"]))
var/txt = vars["[V]_RANDOM"]
if(findtextEx(txt,"PROB"))
//world << "Probability/Roll Combo \..."
txt = dd_text2list(txt,"/")
txt[1] = dd_replacetext(txt[1],"PROB","")
var/p = text2num(txt[1])
var/r = txt[2]
//world << "Prob:[p]% Roll:[r]"
if(prob(p))
newvalue = roll(r)
//world << "Success. New value: [newvalue]"
else
newvalue = vars[V]
//world << "Probability check failed."
else if(findtextEx(txt,"PICK"))
txt = dd_replacetext(txt,"PICK","")
//world << "Pick: [txt]"
txt = dd_text2list(txt,",")
newvalue = pick(txt)
//world << "Picked: [newvalue]"
else
newvalue = roll(txt)
//world << "Roll: [txt] - [newvalue]"
else
newvalue = vars[V]
vars[V] = newvalue
////world << "Plasma color updated."

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 B

BIN
icons/misc/debug_group.dmi Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 B

BIN
icons/misc/debug_space.dmi Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 B