diff --git a/code/__defines/subsystems.dm b/code/__defines/subsystems.dm index 8c546c9135a..75780be3eb8 100644 --- a/code/__defines/subsystems.dm +++ b/code/__defines/subsystems.dm @@ -11,3 +11,5 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_GAME, RUNLEVEL_POSTGAME) #define RUNLEVEL_FLAG_TO_INDEX(flag) (log(2, flag) + 1) // Convert from the runlevel bitfield constants to index in runlevel_flags list + +#define INIT_ORDER_LIGHTING 0 diff --git a/code/controllers/Processes/lighting.dm b/code/controllers/Processes/lighting.dm deleted file mode 100644 index d46cab1d19f..00000000000 --- a/code/controllers/Processes/lighting.dm +++ /dev/null @@ -1,98 +0,0 @@ -/var/lighting_overlays_initialised = FALSE - -/var/list/lighting_update_lights = list() // List of lighting sources queued for update. -/var/list/lighting_update_corners = list() // List of lighting corners queued for update. -/var/list/lighting_update_overlays = list() // List of lighting overlays queued for update. - -/var/list/lighting_update_lights_old = list() // List of lighting sources currently being updated. -/var/list/lighting_update_corners_old = list() // List of lighting corners currently being updated. -/var/list/lighting_update_overlays_old = list() // List of lighting overlays currently being updated. - - -/datum/controller/process/lighting - // Queues of update counts, waiting to be rolled into stats lists - var/list/stats_queues = list( - "Source" = list(), "Corner" = list(), "Overlay" = list()) - // Stats lists - var/list/stats_lists = list( - "Source" = list(), "Corner" = list(), "Overlay" = list()) - var/update_stats_every = (1 SECONDS) - var/next_stats_update = 0 - var/stat_updates_to_keep = 5 - -/datum/controller/process/lighting/setup() - name = "lighting" - - schedule_interval = 0 // run as fast as you possibly can - sleep_interval = 10 // Yield every 10% of a tick - defer_usage = 80 // Defer at 80% of a tick - create_all_lighting_overlays() - lighting_overlays_initialised = TRUE - - // Pre-process lighting once before the round starts. Wait 30 seconds so the away mission has time to load. - spawn(300) - doWork(1) - -/datum/controller/process/lighting/doWork(roundstart) - - lighting_update_lights_old = lighting_update_lights //We use a different list so any additions to the update lists during a delay from scheck() don't cause things to be cut from the list without being updated. - lighting_update_lights = list() - for(var/datum/light_source/L in lighting_update_lights_old) - - if(L.check() || L.destroyed || L.force_update) - L.remove_lum() - if(!L.destroyed) - L.apply_lum() - - else if(L.vis_update) //We smartly update only tiles that became (in) visible to use. - L.smart_vis_update() - - L.vis_update = FALSE - L.force_update = FALSE - L.needs_update = FALSE - - SCHECK - - lighting_update_corners_old = lighting_update_corners //Same as above. - lighting_update_corners = list() - for(var/A in lighting_update_corners_old) - var/datum/lighting_corner/C = A - - C.update_overlays() - - C.needs_update = FALSE - - SCHECK - - lighting_update_overlays_old = lighting_update_overlays //Same as above. - lighting_update_overlays = list() - - for(var/A in lighting_update_overlays_old) - var/atom/movable/lighting_overlay/O = A - O.update_overlay() - O.needs_update = 0 - SCHECK - - stats_queues["Source"] += lighting_update_lights_old.len - stats_queues["Corner"] += lighting_update_corners_old.len - stats_queues["Overlay"] += lighting_update_overlays_old.len - - if(next_stats_update <= world.time) - next_stats_update = world.time + update_stats_every - for(var/stat_name in stats_queues) - var/stat_sum = 0 - var/list/stats_queue = stats_queues[stat_name] - for(var/count in stats_queue) - stat_sum += count - stats_queue.Cut() - - var/list/stats_list = stats_lists[stat_name] - stats_list.Insert(1, stat_sum) - if(stats_list.len > stat_updates_to_keep) - stats_list.Cut(stats_list.len) - -/datum/controller/process/lighting/statProcess() - ..() - stat(null, "[total_lighting_sources] sources, [total_lighting_corners] corners, [total_lighting_overlays] overlays") - for(var/stat_type in stats_lists) - stat(null, "[stat_type] updates: [jointext(stats_lists[stat_type], " | ")]") diff --git a/code/controllers/subsystems/lighting.dm b/code/controllers/subsystems/lighting.dm new file mode 100644 index 00000000000..dd59d0629cd --- /dev/null +++ b/code/controllers/subsystems/lighting.dm @@ -0,0 +1,166 @@ +/* +** Lighting Subsystem - Process the lighting! Do it! +*/ + +#define SSLIGHTING_STAGE_LIGHTS 1 +#define SSLIGHTING_STAGE_CORNERS 2 +#define SSLIGHTING_STAGE_OVERLAYS 3 +#define SSLIGHTING_STAGE_DONE 4 +// This subsystem's fire() method also gets called once during Master.Initialize(). +// During this fire we need to use CHECK_TICK to sleep and continue, but in all other fires we need to use MC_CHECK_TICK to pause and return. +// This leads us to a rather annoying little tidbit of code that I have stuffed into this macro so I don't have to see it. +#define DUAL_TICK_CHECK if (init_tick_checks) { CHECK_TICK; } else if (MC_TICK_CHECK) { return; } + +// Globals +/var/lighting_overlays_initialised = FALSE +/var/list/lighting_update_lights = list() // List of lighting sources queued for update. +/var/list/lighting_update_corners = list() // List of lighting corners queued for update. +/var/list/lighting_update_overlays = list() // List of lighting overlays queued for update. + +SUBSYSTEM_DEF(lighting) + name = "Lighting" + wait = 2 // Ticks, not deciseconds + init_order = INIT_ORDER_LIGHTING + flags = SS_TICKER + + var/list/currentrun = list() + var/stage = null + + var/cost_lights = 0 + var/cost_corners = 0 + var/cost_overlays = 0 + +/datum/controller/subsystem/lighting/Initialize(timeofday) + if(!lighting_overlays_initialised) + // TODO - TG initializes starlight here. + create_all_lighting_overlays() + lighting_overlays_initialised = TRUE + + // Pre-process lighting once before the round starts. + internal_process_lights(FALSE, TRUE) + internal_process_corners(FALSE, TRUE) + internal_process_overlays(FALSE, TRUE) + return ..() + +/datum/controller/subsystem/lighting/fire(resumed = FALSE) + var/timer + if(!resumed) + ASSERT(LAZYLEN(currentrun) == 0) // Santity checks to make sure we don't somehow have items left over from last cycle + ASSERT(stage == null) // Or somehow didn't finish all the steps from last cycle + stage = SSLIGHTING_STAGE_LIGHTS // Start with Step 1 of course + + if(stage == SSLIGHTING_STAGE_LIGHTS) + timer = world.tick_usage + internal_process_lights(resumed) + cost_lights = MC_AVERAGE(cost_lights, TICK_DELTA_TO_MS(world.tick_usage - timer)) + if(state != SS_RUNNING) + return + resumed = 0 + stage = SSLIGHTING_STAGE_CORNERS + + if(stage == SSLIGHTING_STAGE_CORNERS) + timer = world.tick_usage + internal_process_corners(resumed) + cost_corners = MC_AVERAGE(cost_corners, TICK_DELTA_TO_MS(world.tick_usage - timer)) + if(state != SS_RUNNING) + return + resumed = 0 + stage = SSLIGHTING_STAGE_OVERLAYS + + if(stage == SSLIGHTING_STAGE_OVERLAYS) + timer = world.tick_usage + internal_process_overlays(resumed) + cost_overlays = MC_AVERAGE(cost_overlays, TICK_DELTA_TO_MS(world.tick_usage - timer)) + if(state != SS_RUNNING) + return + resumed = 0 + stage = SSLIGHTING_STAGE_DONE + + // Okay, we're done! Woo! Got thru a whole air_master cycle! + ASSERT(LAZYLEN(currentrun) == 0) // Sanity checks to make sure there are really none left + ASSERT(stage == SSLIGHTING_STAGE_DONE) // And that we didn't somehow skip past the last step + currentrun = null + stage = null + +/datum/controller/subsystem/lighting/proc/internal_process_lights(resumed = FALSE, init_tick_checks = FALSE) + if (!resumed) + // We swap out the lists so any additions to the global list during a pause don't make things wierd. + src.currentrun = global.lighting_update_lights + global.lighting_update_lights = list() + + //cache for sanic speed (lists are references anyways) + var/list/currentrun = src.currentrun + while(currentrun.len) + var/datum/light_source/L = currentrun[currentrun.len] + currentrun.len-- + + if(!L) continue + if(L.check() || L.destroyed || L.force_update) + L.remove_lum() + if(!L.destroyed) + L.apply_lum() + + else if(L.vis_update) //We smartly update only tiles that became (in) visible to use. + L.smart_vis_update() + + L.vis_update = FALSE + L.force_update = FALSE + L.needs_update = FALSE + + DUAL_TICK_CHECK + +/datum/controller/subsystem/lighting/proc/internal_process_corners(resumed = FALSE, init_tick_checks = FALSE) + if (!resumed) + // We swap out the lists so any additions to the global list during a pause don't make things wierd. + src.currentrun = global.lighting_update_corners + global.lighting_update_corners = list() + + //cache for sanic speed (lists are references anyways) + var/list/currentrun = src.currentrun + while(currentrun.len) + var/datum/lighting_corner/C = currentrun[currentrun.len] + currentrun.len-- + + if(!C) continue + C.update_overlays() + C.needs_update = FALSE + + DUAL_TICK_CHECK + +/datum/controller/subsystem/lighting/proc/internal_process_overlays(resumed = FALSE, init_tick_checks = FALSE) + if (!resumed) + // We swap out the lists so any additions to the global list during a pause don't make things wierd. + src.currentrun = global.lighting_update_overlays + global.lighting_update_overlays = list() + + //cache for sanic speed (lists are references anyways) + var/list/currentrun = src.currentrun + while(currentrun.len) + var/atom/movable/lighting_overlay/O = currentrun[currentrun.len] + currentrun.len-- + + if(!O) continue + O.update_overlay() + O.needs_update = FALSE + + DUAL_TICK_CHECK + +/datum/controller/subsystem/lighting/stat_entry(msg_prefix) + var/list/msg = list(msg_prefix) + msg += "T:{" + msg += "S [total_lighting_sources] | " + msg += "C [total_lighting_corners] | " + msg += "O [total_lighting_overlays]" + msg += "}" + msg += "C:{" + msg += "S [round(cost_lights, 1)] | " + msg += "C [round(cost_corners, 1)] | " + msg += "O [round(cost_overlays, 1)]" + msg += "}" + ..(msg.Join()) + +#undef DUAL_TICK_CHECK +#undef SSLIGHTING_STAGE_LIGHTS +#undef SSLIGHTING_STAGE_CORNERS +#undef SSLIGHTING_STAGE_OVERLAYS +#undef SSLIGHTING_STAGE_STATS diff --git a/code/modules/lighting/lighting_overlay.dm b/code/modules/lighting/lighting_overlay.dm index 690eba93264..e02f9762810 100644 --- a/code/modules/lighting/lighting_overlay.dm +++ b/code/modules/lighting/lighting_overlay.dm @@ -125,7 +125,7 @@ if (force) total_lighting_overlays-- global.lighting_update_overlays -= src - global.lighting_update_overlays_old -= src + LAZYREMOVE(SSlighting.currentrun, src) var/turf/T = loc if(istype(T)) diff --git a/code/modules/lighting/lighting_setup.dm b/code/modules/lighting/lighting_setup.dm index 981de658649..5d1208f8ef8 100644 --- a/code/modules/lighting/lighting_setup.dm +++ b/code/modules/lighting/lighting_setup.dm @@ -1,16 +1,11 @@ +// Create lighting overlays on all turfs with dynamic lighting in areas with dynamic lighting. /proc/create_all_lighting_overlays() - for(var/zlevel = 1 to world.maxz) - create_lighting_overlays_zlevel(zlevel) - -/proc/create_lighting_overlays_zlevel(var/zlevel) - ASSERT(zlevel) - - for(var/turf/T in block(locate(1, 1, zlevel), locate(world.maxx, world.maxy, zlevel))) - if(!T.dynamic_lighting) - continue - - var/area/A = T.loc + for(var/area/A in world) if(!A.dynamic_lighting) continue - - new /atom/movable/lighting_overlay(T, TRUE) + for(var/turf/T in A) + if(!T.dynamic_lighting) + continue + new /atom/movable/lighting_overlay(T, TRUE) + CHECK_TICK + CHECK_TICK diff --git a/code/modules/vore/appearance/sprite_accessories_vr.dm b/code/modules/vore/appearance/sprite_accessories_vr.dm index 635f7b6bacb..1cda4165034 100644 --- a/code/modules/vore/appearance/sprite_accessories_vr.dm +++ b/code/modules/vore/appearance/sprite_accessories_vr.dm @@ -578,7 +578,13 @@ /datum/sprite_accessory/tail/rosey name = "tritail kitsune tails (Rosey)" desc = "" - icon_state = "rosey" + icon_state = "rosey_three" + ckeys_allowed = list("joey4298") + +/datum/sprite_accessory/tail/rosey2 + name = "pentatail kitsune tails (Rosey)" //I predict seven tails next. ~CK + desc = "" + icon_state = "rosey_five" ckeys_allowed = list("joey4298") /datum/sprite_accessory/tail/scree diff --git a/code/modules/vore/eating/belly_vr.dm b/code/modules/vore/eating/belly_vr.dm index 09d81144adc..b62229bf6a8 100644 --- a/code/modules/vore/eating/belly_vr.dm +++ b/code/modules/vore/eating/belly_vr.dm @@ -183,6 +183,8 @@ var/raw_message = pick(examine_messages) formatted_message = replacetext(raw_message,"%belly",lowertext(name)) + formatted_message = replacetext(formatted_message,"%pred",owner) + formatted_message = replacetext(formatted_message,"%prey",english_list(internal_contents)) return("[formatted_message]
") diff --git a/code/modules/vore/eating/vorepanel_vr.dm b/code/modules/vore/eating/vorepanel_vr.dm index 911f956781c..b73e021eb34 100644 --- a/code/modules/vore/eating/vorepanel_vr.dm +++ b/code/modules/vore/eating/vorepanel_vr.dm @@ -522,7 +522,7 @@ selected.set_messages(new_message,"smi") if("Examine Message (when full)") - var/new_message = input(user,"These are sent to people who examine you when this belly has contents. Write them in 3rd person ('Their %belly is bulging'). Do not use %pred or %prey in this type."+help,"Examine Message (when full)",selected.get_messages("em")) as message + var/new_message = input(user,"These are sent to people who examine you when this belly has contents. Write them in 3rd person ('Their %belly is bulging')."+help,"Examine Message (when full)",selected.get_messages("em")) as message if(new_message) selected.set_messages(new_message,"em") diff --git a/icons/mob/vore/tails_vr.dmi b/icons/mob/vore/tails_vr.dmi index e2def812c6b..b6b1d6e41f1 100644 Binary files a/icons/mob/vore/tails_vr.dmi and b/icons/mob/vore/tails_vr.dmi differ diff --git a/vorestation.dme b/vorestation.dme index a26c0256367..abd0b5fe553 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -171,7 +171,6 @@ #include "code\controllers\Processes\event.dm" #include "code\controllers\Processes\game_master.dm" #include "code\controllers\Processes\inactivity.dm" -#include "code\controllers\Processes\lighting.dm" #include "code\controllers\Processes\machinery.dm" #include "code\controllers\Processes\nanoui.dm" #include "code\controllers\Processes\obj.dm" @@ -188,6 +187,7 @@ #include "code\controllers\ProcessScheduler\core\processScheduler.dm" #include "code\controllers\subsystems\garbage.dm" #include "code\controllers\subsystems\mobs.dm" +#include "code\controllers\subsystems\lighting.dm" #include "code\controllers\subsystems\transcore_vr.dm" #include "code\datums\ai_law_sets.dm" #include "code\datums\ai_laws.dm"