Controllerized Planets

Controller with deferrals and SCHECKs to be specific. Won't lag while updating the sun, weather, or temperature.

Also moved some vars around. Namely the planet walls are stored on the planet, not in the weather_holder.

Planets now have their own turfs, the controller 'gives' them to the planets each cycle if there are any unallocated turfs in the global lists, to avoid iterating over other planets' turfs if you have more than one, then cuts the lists if you were crazy and some turf added some invalid type. This saves us type-checking in the for() loops later to make them crunch faster. The former operation should only happen once at the start of the game (and maybe very rarely when turfs are added/removed from a map during the game).

With regards to the temperature updates, rebuilding the zone entirely is an intensive operation. Instead we can use this new cheaty proc to do it from over here. ZAS code outside ZAS oh noooo. Well, the option is to snowflake this case into ZAS which is maybe worse?

Only downside to all this is that if you manually set weather and time it might take between 1-60 seconds for the controller to get around to checking if you wanted to update it. That's not that big a deal. If you really want you can now debug that controller and call doWork on it.
This commit is contained in:
Arokha Sieyes
2017-04-18 19:47:14 -04:00
parent aaeae6695a
commit d00c5941ca
9 changed files with 302 additions and 236 deletions

15
code/__defines/planets.dm Normal file
View File

@@ -0,0 +1,15 @@
#define WEATHER_CLEAR "clear"
#define WEATHER_OVERCAST "overcast"
#define WEATHER_LIGHT_SNOW "light snow"
#define WEATHER_SNOW "snow"
#define WEATHER_BLIZZARD "blizzard"
#define WEATHER_RAIN "rain"
#define WEATHER_STORM "storm"
#define WEATHER_HAIL "hail"
#define WEATHER_WINDY "windy"
#define WEATHER_HOT "hot"
#define WEATHER_BLOOD_MOON "blood moon" // For admin fun or cult later on.
#define PLANET_PROCESS_WEATHER 0x1
#define PLANET_PROCESS_SUN 0x2
#define PLANET_PROCESS_TEMP 0x4

View File

@@ -4,14 +4,68 @@ var/datum/controller/process/planet/planet_controller = null
var/list/planets = list()
/datum/controller/process/planet/setup()
name = "planet"
name = "planet controller"
planet_controller = src
schedule_interval = 600 // every minute
schedule_interval = 1 MINUTE
var/list/planet_datums = typesof(/datum/planet) - /datum/planet
for(var/P in planet_datums)
var/datum/planet/NP = new P()
planets.Add(NP)
allocateTurfs()
/datum/controller/process/planet/proc/allocateTurfs()
for(var/turf/simulated/OT in outdoor_turfs)
for(var/datum/planet/P in planets)
if(OT.z in P.expected_z_levels)
P.planet_floors += OT
break
outdoor_turfs.Cut() //Why were you in there INCORRECTLY?
for(var/turf/unsimulated/wall/planetary/PW in planetary_walls)
for(var/datum/planet/P in planets)
if(PW.type == P.planetary_wall_type)
P.planet_walls += PW
break
planetary_walls.Cut()
/datum/controller/process/planet/doWork()
if(outdoor_turfs.len || planetary_walls.len)
allocateTurfs()
for(var/datum/planet/P in planets)
P.process(schedule_interval / 10)
P.process(schedule_interval / 10)
SCHECK //Your process() really shouldn't take this long...
//Weather style needs redrawing
if(P.needs_work & PLANET_PROCESS_WEATHER)
P.needs_work &= ~PLANET_PROCESS_WEATHER
var/image/new_overlay = image(icon = P.weather_holder.current_weather.icon, icon_state = P.weather_holder.current_weather.icon_state, layer = LIGHTING_LAYER - 1)
//Redraw weather icons
for(var/T in P.planet_floors)
var/turf/simulated/turf = T
turf.overlays -= turf.weather_overlay
turf.weather_overlay = new_overlay
turf.overlays += turf.weather_overlay
SCHECK
//Sun light needs changing
if(P.needs_work & PLANET_PROCESS_SUN)
P.needs_work &= ~PLANET_PROCESS_SUN
//Redraw sun overlay
var/new_range = P.sun["range"]
var/new_brightness = P.sun["brightness"]
var/new_color = P.sun["color"]
for(var/T in P.planet_floors)
var/turf/simulated/turf = T
turf.set_light(new_range, new_brightness, new_color)
SCHECK
//Temperature needs updating
if(P.needs_work & PLANET_PROCESS_TEMP)
P.needs_work &= ~PLANET_PROCESS_TEMP
//Set new temperatures
for(var/W in P.planet_walls)
var/turf/unsimulated/wall/planetary/wall = W
wall.set_temperature(P.weather_holder.temperature)
SCHECK

View File

@@ -25,7 +25,7 @@
usr.client.debug_variables(antag)
message_admins("Admin [key_name_admin(usr)] is debugging the [antag.role_text] template.")
/client/proc/debug_controller(controller in list("Master","Ticker","Ticker Process","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras", "Transfer Controller", "Gas Data","Event","Plants","Alarm","Nano","Chemistry","Vote","Xenobio"))
/client/proc/debug_controller(controller in list("Master","Ticker","Ticker Process","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras", "Transfer Controller", "Gas Data","Event","Plants","Alarm","Nano","Chemistry","Vote","Xenobio","Planets"))
set category = "Debug"
set name = "Debug Controller"
set desc = "Debug the various periodic loop controllers for the game (be careful!)"
@@ -98,5 +98,8 @@
if("Xenobio")
debug_variables(xenobio_controller)
feedback_add_details("admin_verb", "DXenobio")
if("Planets")
debug_variables(planet_controller)
feedback_add_details("admin_verb", "DPlanets")
message_admins("Admin [key_name_admin(usr)] is debugging the [controller] controller.")
return

View File

@@ -34,14 +34,16 @@ var/list/outdoor_turfs = list()
outdoor_turfs.Remove(src)
..()
/turf/simulated/floor/proc/update_icon_edge()
/turf/simulated/proc/update_icon_edge()
if(edge_blending_priority)
for(var/checkdir in cardinal)
var/turf/simulated/T = get_step(src, checkdir)
if(istype(T) && T.edge_blending_priority && edge_blending_priority < T.edge_blending_priority && icon_state != T.icon_state)
var/cache_key = "[T.get_edge_icon_state()]-[checkdir]"
if(!turf_edge_cache[cache_key])
turf_edge_cache[cache_key] = image(icon = 'icons/turf/outdoors_edge.dmi', icon_state = "[T.get_edge_icon_state()]-edge", dir = checkdir)
var/image/I = image(icon = 'icons/turf/outdoors_edge.dmi', icon_state = "[T.get_edge_icon_state()]-edge", dir = checkdir)
I.plane = 0
turf_edge_cache[cache_key] = I
overlays += turf_edge_cache[cache_key]
/turf/simulated/proc/get_edge_icon_state()

View File

@@ -27,6 +27,15 @@ var/list/planetary_walls = list()
planetary_walls.Remove(src)
..()
/turf/unsimulated/wall/planetary/proc/set_temperature(var/new_temperature)
if(new_temperature == temperature)
return
temperature = new_temperature
// Force ZAS to reconsider our connections because our temperature has changed
if(connections)
connections.erase_all()
air_master.mark_for_update(src)
// Normal station/earth air.
/turf/unsimulated/wall/planetary/normal
oxygen = MOLES_O2STANDARD
@@ -55,3 +64,4 @@ var/list/planetary_walls = list()
oxygen = MOLES_O2STANDARD
nitrogen = MOLES_N2STANDARD
temperature = 310.92 // About 37.7C / 100F

View File

@@ -12,8 +12,17 @@
var/datum/weather_holder/weather_holder
var/sun_position = 0 // 0 means midnight, 1 means noon.
var/list/sun = list("range","brightness","color")
var/expected_z_levels = list()
var/turf/unsimulated/wall/planetary/planetary_wall_type = /turf/unsimulated/wall/planetary
var/turf/simulated/floor/planet_floors = list()
var/turf/unsimulated/wall/planetary/planet_walls = list()
var/needs_work = 0 // Bitflags to signal to the planet controller these need (properly deferrable) work. Flags defined in controller.
/datum/planet/New()
..()
weather_holder = new(src)
@@ -31,17 +40,13 @@
/datum/planet/proc/update_sun()
sun_last_process = world.time
/datum/planet/proc/update_weather()
if(weather_holder)
weather_holder.process()
/datum/planet/proc/update_sun_deferred(var/new_range, var/new_brightness, var/new_color)
set background = 1
set waitfor = 0
var/i = 0
for(var/turf/simulated/floor/T in outdoor_turfs)
T.set_light(new_range, new_brightness, new_color)
i++
if(i % 30 == 0)
sleep(1)
sun["range"] = new_range
sun["brightness"] = new_brightness
sun["color"] = new_color
needs_work |= PLANET_PROCESS_SUN

View File

@@ -10,6 +10,7 @@ var/datum/planet/sif/planet_sif = null
Its center of government is the equatorial city and site of first settlement, New Reykjavik." // Ripped straight from the wiki.
current_time = new /datum/time/sif() // 32 hour clocks are nice.
expected_z_levels = list(1) // To be changed when real map is finished.
planetary_wall_type = /turf/unsimulated/wall/planetary/sif
/datum/planet/sif/New()
..()
@@ -104,3 +105,197 @@ var/datum/planet/sif/planet_sif = null
/proc/get_sif_time()
if(planet_sif)
return planet_sif.current_time
//Weather definitions
/datum/weather_holder/sif
temperature = T0C
allowed_weather_types = list(
WEATHER_CLEAR = new /datum/weather/sif/clear(),
WEATHER_OVERCAST = new /datum/weather/sif/overcast(),
WEATHER_LIGHT_SNOW = new /datum/weather/sif/light_snow(),
WEATHER_SNOW = new /datum/weather/sif/snow(),
WEATHER_BLIZZARD = new /datum/weather/sif/blizzard(),
WEATHER_RAIN = new /datum/weather/sif/rain(),
WEATHER_STORM = new /datum/weather/sif/storm(),
WEATHER_HAIL = new /datum/weather/sif/hail(),
WEATHER_BLOOD_MOON = new /datum/weather/sif/blood_moon()
)
roundstart_weather_chances = list(
WEATHER_CLEAR = 30,
WEATHER_OVERCAST = 30,
WEATHER_LIGHT_SNOW = 20,
WEATHER_SNOW = 5,
WEATHER_BLIZZARD = 5,
WEATHER_RAIN = 5,
WEATHER_STORM = 2.5,
WEATHER_HAIL = 2.5
)
datum/weather/sif
name = "sif base"
temp_high = 243.15 // -20c
temp_low = 233.15 // -30c
/datum/weather/sif/clear
name = "clear"
transition_chances = list(
WEATHER_CLEAR = 60,
WEATHER_OVERCAST = 40
)
/datum/weather/sif/overcast
name = "overcast"
light_modifier = 0.8
transition_chances = list(
WEATHER_CLEAR = 25,
WEATHER_OVERCAST = 50,
WEATHER_LIGHT_SNOW = 10,
WEATHER_SNOW = 5,
WEATHER_RAIN = 5,
WEATHER_HAIL = 5
)
/datum/weather/sif/light_snow
name = "light snow"
icon_state = "snowfall_light"
temp_high = 238.15 // -25c
temp_low = 228.15 // -35c
light_modifier = 0.7
transition_chances = list(
WEATHER_OVERCAST = 20,
WEATHER_LIGHT_SNOW = 50,
WEATHER_SNOW = 25,
WEATHER_HAIL = 5
)
/datum/weather/sif/snow
name = "moderate snow"
icon_state = "snowfall_med"
temp_high = 233.15 // -30c
temp_low = 223.15 // -40c
light_modifier = 0.5
transition_chances = list(
WEATHER_LIGHT_SNOW = 20,
WEATHER_SNOW = 50,
WEATHER_BLIZZARD = 20,
WEATHER_HAIL = 5,
WEATHER_OVERCAST = 5
)
/datum/weather/sif/snow/process_effects()
for(var/turf/simulated/floor/outdoors/snow/S in outdoor_turfs)
if(S.z in holder.our_planet.expected_z_levels)
for(var/dir_checked in cardinal)
var/turf/simulated/floor/T = get_step(S, dir_checked)
if(istype(T))
if(istype(T, /turf/simulated/floor/outdoors) && prob(33))
T.chill()
/datum/weather/sif/blizzard
name = "blizzard"
icon_state = "snowfall_heavy"
temp_high = 223.15 // -40c
temp_low = 203.15 // -60c
light_modifier = 0.3
transition_chances = list(
WEATHER_SNOW = 45,
WEATHER_BLIZZARD = 40,
WEATHER_HAIL = 10,
WEATHER_OVERCAST = 5
)
/datum/weather/sif/blizzard/process_effects()
for(var/turf/simulated/floor/outdoors/snow/S in outdoor_turfs)
if(S.z in holder.our_planet.expected_z_levels)
for(var/dir_checked in cardinal)
var/turf/simulated/floor/T = get_step(S, dir_checked)
if(istype(T))
if(istype(T, /turf/simulated/floor/outdoors) && prob(50))
T.chill()
/datum/weather/sif/rain
name = "rain"
icon_state = "rain"
light_modifier = 0.5
transition_chances = list(
WEATHER_OVERCAST = 25,
WEATHER_LIGHT_SNOW = 10,
WEATHER_RAIN = 50,
WEATHER_STORM = 10,
WEATHER_HAIL = 5
)
/datum/weather/sif/rain/process_effects()
for(var/mob/living/L in living_mob_list)
if(L.z in holder.our_planet.expected_z_levels)
var/turf/T = get_turf(L)
if(!T.outdoors)
return // They're indoors, so no need to rain on them.
L.adjust_fire_stacks(-5)
to_chat(L, "<span class='warning'>Rain falls on you.</span>")
/datum/weather/sif/storm
name = "storm"
icon_state = "storm"
temp_high = 233.15 // -30c
temp_low = 213.15 // -50c
light_modifier = 0.3
transition_chances = list(
WEATHER_RAIN = 45,
WEATHER_STORM = 40,
WEATHER_HAIL = 10,
WEATHER_OVERCAST = 5
)
/datum/weather/sif/rain/process_effects()
for(var/mob/living/L in living_mob_list)
if(L.z in holder.our_planet.expected_z_levels)
var/turf/T = get_turf(L)
if(!T.outdoors)
return // They're indoors, so no need to rain on them.
L.adjust_fire_stacks(-10)
to_chat(L, "<span class='warning'>Rain falls on you, drenching you in water.</span>")
/datum/weather/sif/hail
name = "hail"
icon_state = "hail"
temp_high = 233.15 // -30c
temp_low = 213.15 // -50c
light_modifier = 0.3
transition_chances = list(
WEATHER_RAIN = 45,
WEATHER_STORM = 10,
WEATHER_HAIL = 40,
WEATHER_OVERCAST = 5
)
/datum/weather/sif/hail/process_effects()
for(var/mob/living/L in living_mob_list)
if(L.z in holder.our_planet.expected_z_levels)
var/turf/T = get_turf(L)
if(!T.outdoors)
return // They're indoors, so no need to pelt them with ice.
var/target_zone = pick(BP_ALL)
var/amount_blocked = L.run_armor_check(target_zone, "melee")
var/amount_soaked = L.get_armor_soak(target_zone, "melee")
if(amount_blocked >= 100)
return // No need to apply damage.
if(amount_soaked >= 10)
return // No need to apply damage.
L.apply_damage(rand(5, 10), BRUTE, target_zone, amount_blocked, amount_soaked, used_weapon = "hail")
to_chat(L, "<span class='warning'>The hail raining down on you [L.can_feel_pain() ? "hurts" : "damages you"]!</span>")
/datum/weather/sif/blood_moon
name = "blood moon"
light_modifier = 0.5
light_color = "#FF0000"
transition_chances = list(
WEATHER_BLOODMOON = 100
)

View File

@@ -1,15 +1,3 @@
#define WEATHER_CLEAR "clear"
#define WEATHER_OVERCAST "overcast"
#define WEATHER_LIGHT_SNOW "light snow"
#define WEATHER_SNOW "snow"
#define WEATHER_BLIZZARD "blizzard"
#define WEATHER_RAIN "rain"
#define WEATHER_STORM "storm"
#define WEATHER_HAIL "hail"
#define WEATHER_WINDY "windy"
#define WEATHER_HOT "hot"
#define WEATHER_BLOOD_MOON "blood moon" // For admin fun or cult later on.
/datum/weather_holder
var/datum/planet/our_planet = null
var/datum/weather/current_weather = null
@@ -19,7 +7,6 @@
var/list/allowed_weather_types = list()
var/list/roundstart_weather_chances = list()
var/next_weather_shift = null
var/planetary_wall_type = null // Which walls to look for when updating temperature.
/datum/weather_holder/New(var/source)
..()
@@ -54,55 +41,15 @@
current_weather.process_effects()
/datum/weather_holder/proc/update_icon_effects()
set background = 1
set waitfor = 0
if(current_weather)
for(var/turf/simulated/floor/T in outdoor_turfs)
if(T.z in our_planet.expected_z_levels)
T.overlays -= T.weather_overlay
T.weather_overlay = image(icon = current_weather.icon, icon_state = current_weather.icon_state, layer = LIGHTING_LAYER - 1)
T.overlays += T.weather_overlay
our_planet.needs_work |= PLANET_PROCESS_WEATHER
/datum/weather_holder/proc/update_temperature()
temperature = Interpolate(current_weather.temp_low, current_weather.temp_high, weight = our_planet.sun_position)
for(var/turf/unsimulated/wall/planetary/wall in planetary_walls)
if(ispath(wall.type, planetary_wall_type))
wall.temperature = temperature
for(var/dir in cardinal)
var/turf/simulated/T = get_step(wall, dir)
if(istype(T))
if(T.zone)
T.zone.rebuild()
our_planet.needs_work |= PLANET_PROCESS_TEMP
/datum/weather_holder/proc/get_weather_datum(desired_type)
return allowed_weather_types[desired_type]
/datum/weather_holder/sif
temperature = T0C
allowed_weather_types = list(
WEATHER_CLEAR = new /datum/weather/sif/clear(),
WEATHER_OVERCAST = new /datum/weather/sif/overcast(),
WEATHER_LIGHT_SNOW = new /datum/weather/sif/light_snow(),
WEATHER_SNOW = new /datum/weather/sif/snow(),
WEATHER_BLIZZARD = new /datum/weather/sif/blizzard(),
WEATHER_RAIN = new /datum/weather/sif/rain(),
WEATHER_STORM = new /datum/weather/sif/storm(),
WEATHER_HAIL = new /datum/weather/sif/hail(),
WEATHER_BLOOD_MOON = new /datum/weather/sif/blood_moon()
)
planetary_wall_type = /turf/unsimulated/wall/planetary/sif
roundstart_weather_chances = list(
WEATHER_CLEAR = 30,
WEATHER_OVERCAST = 30,
WEATHER_LIGHT_SNOW = 20,
WEATHER_SNOW = 5,
WEATHER_BLIZZARD = 5,
WEATHER_RAIN = 5,
WEATHER_STORM = 2.5,
WEATHER_HAIL = 2.5
)
/datum/weather
var/name = "weather base"
@@ -117,169 +64,3 @@
/datum/weather/proc/process_effects()
return
/datum/weather/sif
name = "sif base"
temp_high = 243.15 // -20c
temp_low = 233.15 // -30c
/datum/weather/sif/clear
name = "clear"
transition_chances = list(
WEATHER_CLEAR = 60,
WEATHER_OVERCAST = 40
)
/datum/weather/sif/overcast
name = "overcast"
light_modifier = 0.8
transition_chances = list(
WEATHER_CLEAR = 25,
WEATHER_OVERCAST = 50,
WEATHER_LIGHT_SNOW = 10,
WEATHER_SNOW = 5,
WEATHER_RAIN = 5,
WEATHER_HAIL = 5
)
/datum/weather/sif/light_snow
name = "light snow"
icon_state = "snowfall_light"
temp_high = 238.15 // -25c
temp_low = 228.15 // -35c
light_modifier = 0.7
transition_chances = list(
WEATHER_OVERCAST = 20,
WEATHER_LIGHT_SNOW = 50,
WEATHER_SNOW = 25,
WEATHER_HAIL = 5
)
/datum/weather/sif/snow
name = "moderate snow"
icon_state = "snowfall_med"
temp_high = 233.15 // -30c
temp_low = 223.15 // -40c
light_modifier = 0.5
transition_chances = list(
WEATHER_LIGHT_SNOW = 20,
WEATHER_SNOW = 50,
WEATHER_BLIZZARD = 20,
WEATHER_HAIL = 5,
WEATHER_OVERCAST = 5
)
/datum/weather/sif/snow/process_effects()
for(var/turf/simulated/floor/outdoors/snow/S in outdoor_turfs)
for(var/dir_checked in cardinal)
var/turf/simulated/floor/T = get_step(S, dir_checked)
if(istype(T))
if(istype(T, /turf/simulated/floor/outdoors) && prob(33))
T.chill()
/datum/weather/sif/blizzard
name = "blizzard"
icon_state = "snowfall_heavy"
temp_high = 223.15 // -40c
temp_low = 203.15 // -60c
light_modifier = 0.3
transition_chances = list(
WEATHER_SNOW = 45,
WEATHER_BLIZZARD = 40,
WEATHER_HAIL = 10,
WEATHER_OVERCAST = 5
)
/datum/weather/sif/blizzard/process_effects()
for(var/turf/simulated/floor/outdoors/snow/S in outdoor_turfs)
for(var/dir_checked in cardinal)
var/turf/simulated/floor/T = get_step(S, dir_checked)
if(istype(T))
if(istype(T, /turf/simulated/floor/outdoors) && prob(50))
T.chill()
/datum/weather/sif/rain
name = "rain"
icon_state = "rain"
light_modifier = 0.5
transition_chances = list(
WEATHER_OVERCAST = 25,
WEATHER_LIGHT_SNOW = 10,
WEATHER_RAIN = 50,
WEATHER_STORM = 10,
WEATHER_HAIL = 5
)
/datum/weather/sif/rain/process_effects()
for(var/mob/living/L in living_mob_list)
if(L.z in holder.our_planet.expected_z_levels)
var/turf/T = get_turf(L)
if(!T.outdoors)
return // They're indoors, so no need to rain on them.
L.adjust_fire_stacks(-5)
to_chat(L, "<span class='warning'>Rain falls on you.</span>")
/datum/weather/sif/storm
name = "storm"
icon_state = "storm"
temp_high = 233.15 // -30c
temp_low = 213.15 // -50c
light_modifier = 0.3
transition_chances = list(
WEATHER_RAIN = 45,
WEATHER_STORM = 40,
WEATHER_HAIL = 10,
WEATHER_OVERCAST = 5
)
/datum/weather/sif/rain/process_effects()
for(var/mob/living/L in living_mob_list)
if(L.z in holder.our_planet.expected_z_levels)
var/turf/T = get_turf(L)
if(!T.outdoors)
return // They're indoors, so no need to rain on them.
L.adjust_fire_stacks(-10)
to_chat(L, "<span class='warning'>Rain falls on you, drenching you in water.</span>")
/datum/weather/sif/hail
name = "hail"
icon_state = "hail"
temp_high = 233.15 // -30c
temp_low = 213.15 // -50c
light_modifier = 0.3
transition_chances = list(
WEATHER_RAIN = 45,
WEATHER_STORM = 10,
WEATHER_HAIL = 40,
WEATHER_OVERCAST = 5
)
/datum/weather/sif/hail/process_effects()
for(var/mob/living/L in living_mob_list)
if(L.z in holder.our_planet.expected_z_levels)
var/turf/T = get_turf(L)
if(!T.outdoors)
return // They're indoors, so no need to pelt them with ice.
var/target_zone = pick(BP_ALL)
var/amount_blocked = L.run_armor_check(target_zone, "melee")
var/amount_soaked = L.get_armor_soak(target_zone, "melee")
if(amount_blocked >= 100)
return // No need to apply damage.
if(amount_soaked >= 10)
return // No need to apply damage.
L.apply_damage(rand(5, 10), BRUTE, target_zone, amount_blocked, amount_soaked, used_weapon = "hail")
to_chat(L, "<span class='warning'>The hail raining down on you [L.can_feel_pain() ? "hurts" : "damages you"]!</span>")
/datum/weather/sif/blood_moon
name = "blood moon"
light_modifier = 0.5
light_color = "#FF0000"
transition_chances = list(
WEATHER_BLOODMOON = 100
)