Skip to content

Commit

Permalink
Nightshift v2 (#6207)
Browse files Browse the repository at this point in the history
Co-authored-by: silicons <no@you.cat>
  • Loading branch information
silicons and silicons authored Dec 19, 2023
1 parent 34791f2 commit 2c75047
Show file tree
Hide file tree
Showing 17 changed files with 316 additions and 84 deletions.
1 change: 1 addition & 0 deletions citadel.dme
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@
#include "code\__DEFINES\mining\legacy.dm"
#include "code\__DEFINES\misc\attack_animations.dm"
#include "code\__DEFINES\misc\message_ranges.dm"
#include "code\__DEFINES\misc\nightshift.dm"
#include "code\__DEFINES\mobs\actions.dm"
#include "code\__DEFINES\mobs\characteristics.dm"
#include "code\__DEFINES\mobs\grab.dm"
Expand Down
15 changes: 13 additions & 2 deletions code/__DEFINES/color/lights.dm
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
//Some defines to generalise colours used in lighting.
//* Some defines to generalise colours used in lighting.
//* This file also contains powers/ranges, because power really does matter for lighting.

//! ## GENERAL COLORS
//? Important note on colors. Colors can end up significantly different from the basic html picture, especially when saturated!
#define LIGHT_COLOR_WHITE "#FFFFFF" // rgb(255, 255, 255) Pure white.
Expand Down Expand Up @@ -34,4 +36,13 @@
#define LIGHT_COLOR_INCANDESCENT_TUBE "#E0EFF0" // rgb(224, 239, 240) Slightly blueish white.
#define LIGHT_COLOR_INCANDESCENT_BULB "#FFFEB8" // rgb(255, 254, 184) Slightly yellowish white.
#define LIGHT_COLOR_INCANDESCENT_FLASHLIGHT "#FFCC66" // rgb(255, 204, 102) Slightly yellowish white.
#define LIGHT_COLOR_NIGHTSHIFT "#616191" // rgb(97, 97, 145) Dark blue.

/// Nightshift Light Color
/// Used on full-strength light tubes.
#define LIGHT_COLOR_NIGHTSHIFT "#c7c7ff"
/// Nightshift Light Power
/// Used on full-strength light tubes.
#define LIGHT_POWER_NIGHTSHIFT 0.435
/// Nightshift Light Range
/// Used on full-strength light tubes.
#define LIGHT_RANGE_NIGHTSHIFT 7
32 changes: 32 additions & 0 deletions code/__DEFINES/misc/nightshift.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//* This file is explicitly licensed under the MIT license. *//
//* Copyright (c) 2023 Citadel Station developers. *//

//* nightshift flags

#define NIGHTSHIFT_LEVEL_UNSET (1<<0)

#define NIGHTSHIFT_LEVEL_PUBLIC_HALLWAYS (1<<1)
#define NIGHTSHIFT_LEVEL_PUBLIC_FACILITIES (1<<2)

#define NIGHTSHIFT_LEVEL_DEPARTMENT_HALLWAYS (1<<3)
#define NIGHTSHIFT_LEVEL_DEPARTMENT_FACILITIES (1<<4)
#define NIGHTSHIFT_LEVEL_DEPARTMENT_SENSITIVE (1<<5)
#define NIGHTSHIFT_LEVEL_DEPARTMENT_LEISURE (1<<6)

#define NIGHTSHIFT_LEVEL_COMMAND_HALLWAYS (1<<7)
#define NIGHTSHIFT_LEVEL_COMMAND_FACILITIES (1<<8)
#define NIGHTSHIFT_LEVEL_COMMAND_SENSITIVE (1<<9)

//* Do not randomly change this, it is used for configuration. *//
DEFINE_BITFIELD(nightshift_level, list(
BITFIELD_NAMED("Unset", NIGHTSHIFT_LEVEL_UNSET),
BITFIELD_NAMED("PublicHalls", NIGHTSHIFT_LEVEL_PUBLIC_HALLWAYS),
BITFIELD_NAMED("PublicAreas", NIGHTSHIFT_LEVEL_PUBLIC_FACILITIES),
BITFIELD_NAMED("DepartmentHalls", NIGHTSHIFT_LEVEL_DEPARTMENT_HALLWAYS),
BITFIELD_NAMED("DepartmentAreas", NIGHTSHIFT_LEVEL_DEPARTMENT_FACILITIES),
BITFIELD_NAMED("DepartmentSecure", NIGHTSHIFT_LEVEL_DEPARTMENT_SENSITIVE),
BITFIELD_NAMED("DepartmentLeisure", NIGHTSHIFT_LEVEL_DEPARTMENT_LEISURE),
BITFIELD_NAMED("CommandHalls", NIGHTSHIFT_LEVEL_COMMAND_HALLWAYS),
BITFIELD_NAMED("CommandAreas", NIGHTSHIFT_LEVEL_COMMAND_FACILITIES),
BITFIELD_NAMED("CommandSecure", NIGHTSHIFT_LEVEL_COMMAND_SENSITIVE),
))
119 changes: 71 additions & 48 deletions code/__HELPERS/datastructs/priority_queue.dm
Original file line number Diff line number Diff line change
@@ -1,66 +1,89 @@
//* This file is explicitly licensed under the MIT license. *//
//* Copyright (c) 2023 Citadel Station developers. *//

/**
* array-backed priority heap
* An array-backed priority queue.
*
* not written in house, cloned from oldish polaris/bay (?)
* The "front" of the queue is popped first; check comparators.dm for what this means.
*/
/datum/priority_queue
var/list/queue
var/comparison_function
/// comparaison function
var/procpath/comparison
/// internal array
var/list/array = list()

/datum/priority_queue/New(compare)
queue = list()
comparison_function = compare
/datum/priority_queue/New(cmp)
src.comparison = cmp
array = list()

/datum/priority_queue/proc/is_empty()
return !queue.len

/datum/priority_queue/proc/enqueue(data)
queue.Add(data)
var/index = queue.len
return length(array) == 0

//From what I can tell, this automagically sorts the added data into the correct location.
while(index > 2 && call(comparison_function)(queue[index / 2], queue[index]) > 0)
queue.Swap(index, index / 2)
index /= 2
/datum/priority_queue/proc/enqueue(entry)
array += entry
bubble_up(length(array))

/datum/priority_queue/proc/dequeue()
if(!queue.len)
return 0
return remove(1)
if(length(array) == 0)
return null
. = array[1]
array.Swap(1, length(array))
--array.len
bubble_down(1)

/datum/priority_queue/proc/remove(index)
if(index > queue.len)
return 0
/datum/priority_queue/proc/peek()
return length(array)? array[1] : null

var/thing = queue[index]
queue.Swap(index, queue.len)
--queue.len
if(index < queue.len)
fix_queue(index)
return thing

/datum/priority_queue/proc/fix_queue(index)
var/child = 2 * index
var/item = queue[index]
// todo: define this
/datum/priority_queue/proc/bubble_up(index)
while(index >= 2 && call(comparison)(array[index], array[index / 2]) < 0)
array.Swap(index, index / 2)
index /= 2

while(child <= queue.len)
if(child < queue.len && call(comparison_function)(queue[child], queue[child + 1]) > 0)
child++
if(call(comparison_function)(item, queue[child]) > 0)
queue[index] = queue[child]
index = child
// todo: define this
/datum/priority_queue/proc/bubble_down(index)
var/length = length(array)
var/next = index * 2
while(next <= length)
// left always exists, right doesn't necessarily exist
if(call(comparison)(array[next], array[index]) < 0)
if(next < length && call(comparison)(array[next], array[next + 1]) > 0)
array.Swap(index, next + 1)
index = next + 1
else
array.Swap(index, next)
index = next
else if(next < length && call(comparison)(array[next + 1], array[index]) < 0)
array.Swap(index, next + 1)
index = next + 1
else
break
child = 2 * index
queue[index] = item
next = index * 2

/datum/priority_queue/proc/clone_list()
return queue.Copy()
/**
* returns copy of list of entries in no particular order
*/
/datum/priority_queue/proc/flattened()
return array.Copy()

/datum/priority_queue/proc/size()
return queue.len
/datum/priority_queue/proc/remove_index(index)
var/length = length(array)
if(!index || index > length)
return
if(index == length)
. = array[index]
--array.len
return
. = array[index]
array.Swap(index, length)
--array.len
bubble_down(index)

/datum/priority_queue/proc/find(entry)
return array.Find(entry)

/datum/priority_queue/proc/remove_item(data)
var/index = queue.Find(data)
if(index)
return remove(index)
/datum/priority_queue/proc/remove_entry(entry)
return remove_index(array.Find(entry))

/datum/priority_queue/proc/size()
return length(array)
6 changes: 3 additions & 3 deletions code/__HELPERS/graphs/astar.dm
Original file line number Diff line number Diff line change
Expand Up @@ -114,15 +114,15 @@
var/datum/graph_astar_node/target = path_node_by_position[datum]
if(target.best_estimated_cost)
if(best_estimated_cost + call(datum, dist)(end) < target.best_estimated_cost)
open.remove_item(target)
open.remove_entry(target)
else
continue

var/datum/graph_astar_node/next_node = new (datum, current, best_estimated_cost, call(datum, dist)(end), current.nodes_traversed + 1)
path_node_by_position[datum] = next_node
open.enqueue(next_node)

if(max_nodes && length(open.queue) > max_nodes)
open.remove(length(open.queue))
if(max_nodes && length(open.array) > max_nodes)
open.remove_index(length(open.array))

return path
4 changes: 2 additions & 2 deletions code/__HELPERS/pathfinding/astar.dm
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ GLOBAL_VAR_INIT(astar_visualization_persist, 3 SECONDS)
start.color = ASTAR_VISUAL_COLOR_OPEN
#endif

while(length(open.queue))
while(length(open.array))
// get best node
var/datum/astar_node/top = open.dequeue()
current = top.pos
Expand Down Expand Up @@ -231,7 +231,7 @@ GLOBAL_VAR_INIT(astar_visualization_persist, 3 SECONDS)
turfs_got_colored[top.pos] = TRUE
#endif

if(length(open.queue) > ASTAR_SANE_NODE_LIMIT)
if(length(open.array) > ASTAR_SANE_NODE_LIMIT)
#ifdef ASTAR_DEBUGGING
astar_wipe_colors_after(turfs_got_colored, GLOB.astar_visualization_persist)
#endif
Expand Down
2 changes: 1 addition & 1 deletion code/__HELPERS/pathfinding/jps.dm
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ GLOBAL_VAR_INIT(jps_visualization_resolve, TRUE)
while(TRUE);
#endif
//* loop
while(length(open.queue))
while(length(open.array))
node_top = open.dequeue()
node_top_pos = node_top.pos
#ifdef JPS_DEBUGGING
Expand Down
6 changes: 5 additions & 1 deletion code/__HELPERS/sorts/comparators.dm
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
/**
* Comparators for use with /datum/sort_instance (or wherever you want)
* They should return negative, zero, or positive numbers for a < b, a == b, and a > b respectively.
*
* They should return negative, zero, or positive numbers for a < b, a == b, and a > b respectively, where
* * neg : a < b = "a should be in front of b",
* * zero: a == b = "a and b are equivalent"
* * pos : a > b = "a should be behind b"
*/

//! Standard Sort
Expand Down
2 changes: 1 addition & 1 deletion code/controllers/configuration/config_entry.dm
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@
continue_check_key = ispath(new_key)
switch(value_mode)
if(VALUE_MODE_FLAG)
new_value = TRUE
new_value = text2num(key_value) != 0 && lowertext(key_value) != "false"
continue_check_value = TRUE
if(VALUE_MODE_NUM)
new_value = text2num(key_value)
Expand Down
34 changes: 31 additions & 3 deletions code/controllers/configuration/entries/game.dm
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@
/datum/config_entry/flag/allow_holidays
default = TRUE

/datum/config_entry/flag/nightshifts_enabled
default = TRUE

/datum/config_entry/string/alert_desc_green
default = "All threats to the station have passed. Security may not have weapons visible, privacy laws are once again fully enforced."

Expand Down Expand Up @@ -81,3 +78,34 @@

/datum/config_entry/flag/almost_everyone_has_maintenance_access
default = TRUE

//* Nightshifts *//

/datum/config_entry/flag/nightshifts_enabled
default = TRUE

/datum/config_entry/keyed_list/nightshift_levels
default = list(
"Unset",
"PublicHalls",
"PublicAreas",
"DepartmentHalls",
"DepartmentLeisure",
"CommandHalls",
)
lowercase = FALSE
key_mode = KEY_MODE_TEXT
value_mode = VALUE_MODE_FLAG

/datum/config_entry/keyed_list/nightshift_levels/ValidateAndSet(str_val)
. = ..()
if(!.)
return
var/datum/bitfield/single/target_bitfield = /datum/bitfield/single/nightshift_level
var/target_bitname = initial(target_bitfield.variable)
var/list/actual_bitfield = GLOB.bitfields[target_bitname]
var/new_flags = NONE
for(var/key in config_entry_value)
if(config_entry_value[key])
new_flags |= actual_bitfield[key]
SSnightshift.nightshift_level = new_flags
7 changes: 6 additions & 1 deletion code/controllers/subsystem/nightshift.dm
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ SUBSYSTEM_DEF(nightshift)
wait = 60 SECONDS
subsystem_flags = SS_NO_TICK_CHECK

/// Set from configuration - enabled nightshift flags.
var/nightshift_level = NONE

//! legacy below

var/nightshift_active = FALSE
var/nightshift_start_time = 19 HOURS + 30 MINUTES //7:30 PM, station time
var/nightshift_end_time = 7 HOURS + 30 MINUTES //7:30 AM, station time
Expand Down Expand Up @@ -64,7 +69,7 @@ SUBSYSTEM_DEF(nightshift)

for(var/obj/machinery/power/apc/apc in GLOB.apcs)
if(apc.z in (LEGACY_MAP_DATUM).station_levels)
apc.set_nightshift(active, TRUE)
apc.set_nightshift(active && (apc.area.nightshift_level & nightshift_level), TRUE)
CHECK_TICK

SSlighting.resume_instant()
Loading

0 comments on commit 2c75047

Please sign in to comment.