Merge branch 'ParadiseSS13/master' into runtime-fix-2

This commit is contained in:
joep van der velden
2020-03-18 16:59:49 +01:00
1748 changed files with 191532 additions and 184661 deletions
+1 -1
View File
@@ -33,4 +33,4 @@ SUBSYSTEM_DEF(acid)
processing -= O
if(MC_TICK_CHECK)
return
return
+1 -1
View File
@@ -78,4 +78,4 @@ SUBSYSTEM_DEF(afk)
break
#undef AFK_WARNED
#undef AFK_CRYOD
#undef AFK_CRYOD
+1 -1
View File
@@ -382,4 +382,4 @@ SUBSYSTEM_DEF(air)
#undef SSAIR_EXCITEDGROUPS
#undef SSAIR_HIGHPRESSURE
#undef SSAIR_HOTSPOTS
#undef SSAIR_SUPERCONDUCTIVITY
#undef SSAIR_SUPERCONDUCTIVITY
+30 -30
View File
@@ -1,30 +1,30 @@
SUBSYSTEM_DEF(alarms)
name = "Alarms"
init_order = INIT_ORDER_ALARMS // 2
var/datum/alarm_handler/atmosphere/atmosphere_alarm = new()
var/datum/alarm_handler/burglar/burglar_alarm = new()
var/datum/alarm_handler/camera/camera_alarm = new()
var/datum/alarm_handler/fire/fire_alarm = new()
var/datum/alarm_handler/motion/motion_alarm = new()
var/datum/alarm_handler/power/power_alarm = new()
var/list/datum/alarm/all_handlers
/datum/controller/subsystem/alarms/Initialize(start_timeofday)
all_handlers = list(SSalarms.atmosphere_alarm, SSalarms.burglar_alarm, SSalarms.camera_alarm, SSalarms.fire_alarm, SSalarms.motion_alarm, SSalarms.power_alarm)
return ..()
/datum/controller/subsystem/alarms/fire()
for(var/datum/alarm_handler/AH in all_handlers)
AH.process()
/datum/controller/subsystem/alarms/proc/active_alarms()
var/list/all_alarms = new ()
for(var/datum/alarm_handler/AH in all_handlers)
var/list/alarms = AH.alarms
all_alarms += alarms
return all_alarms
/datum/controller/subsystem/alarms/proc/number_of_active_alarms()
var/list/alarms = active_alarms()
return alarms.len
SUBSYSTEM_DEF(alarms)
name = "Alarms"
init_order = INIT_ORDER_ALARMS // 2
var/datum/alarm_handler/atmosphere/atmosphere_alarm = new()
var/datum/alarm_handler/burglar/burglar_alarm = new()
var/datum/alarm_handler/camera/camera_alarm = new()
var/datum/alarm_handler/fire/fire_alarm = new()
var/datum/alarm_handler/motion/motion_alarm = new()
var/datum/alarm_handler/power/power_alarm = new()
var/list/datum/alarm/all_handlers
/datum/controller/subsystem/alarms/Initialize(start_timeofday)
all_handlers = list(SSalarms.atmosphere_alarm, SSalarms.burglar_alarm, SSalarms.camera_alarm, SSalarms.fire_alarm, SSalarms.motion_alarm, SSalarms.power_alarm)
return ..()
/datum/controller/subsystem/alarms/fire()
for(var/datum/alarm_handler/AH in all_handlers)
AH.process()
/datum/controller/subsystem/alarms/proc/active_alarms()
var/list/all_alarms = new ()
for(var/datum/alarm_handler/AH in all_handlers)
var/list/alarms = AH.alarms
all_alarms += alarms
return all_alarms
/datum/controller/subsystem/alarms/proc/number_of_active_alarms()
var/list/alarms = active_alarms()
return alarms.len
+1 -1
View File
@@ -14,4 +14,4 @@ SUBSYSTEM_DEF(assets)
for(var/client/C in GLOB.clients)
addtimer(CALLBACK(GLOBAL_PROC, .proc/getFilesSlow, C, preload, FALSE), 10)
return ..()
return ..()
+3 -2
View File
@@ -11,7 +11,8 @@ SUBSYSTEM_DEF(chat)
/datum/controller/subsystem/chat/fire()
for(var/i in payload)
var/client/C = i
C << output(payload[C], "browseroutput:output")
if(C)
C << output(payload[C], "browseroutput:output")
payload -= C
if(MC_TICK_CHECK)
@@ -62,4 +63,4 @@ SUBSYSTEM_DEF(chat)
C.chatOutput.messageQueue += message
return
payload[C] += twiceEncoded
payload[C] += twiceEncoded
+299 -299
View File
@@ -1,299 +1,299 @@
SUBSYSTEM_DEF(events)
name = "Events"
init_order = INIT_ORDER_EVENTS
runlevels = RUNLEVEL_GAME
// Report events at the end of the rouund
var/report_at_round_end = 0
// UI vars
var/window_x = 700
var/window_y = 600
var/table_options = " align='center'"
var/head_options = " style='font-weight:bold;'"
var/row_options1 = " width='85px'"
var/row_options2 = " width='260px'"
var/row_options3 = " width='150px'"
// Event vars
var/datum/event_container/selected_event_container = null
var/list/active_events = list()
var/list/finished_events = list()
var/list/allEvents
var/list/event_containers = list(
EVENT_LEVEL_MUNDANE = new/datum/event_container/mundane,
EVENT_LEVEL_MODERATE = new/datum/event_container/moderate,
EVENT_LEVEL_MAJOR = new/datum/event_container/major
)
var/datum/event_meta/new_event = new
/datum/controller/subsystem/events/Initialize()
allEvents = subtypesof(/datum/event)
return ..()
/datum/controller/subsystem/events/fire()
for(var/datum/event/E in active_events)
E.process()
for(var/i = EVENT_LEVEL_MUNDANE to EVENT_LEVEL_MAJOR)
var/list/datum/event_container/EC = event_containers[i]
EC.process()
/datum/controller/subsystem/events/proc/event_complete(var/datum/event/E)
if(!E.event_meta) // datum/event is used here and there for random reasons, maintaining "backwards compatibility"
log_debug("Event of '[E.type]' with missing meta-data has completed.")
return
finished_events += E
var/theseverity
if(!E.severity)
theseverity = EVENT_LEVEL_MODERATE
if(!E.severity == EVENT_LEVEL_MUNDANE && !E.severity == EVENT_LEVEL_MODERATE && !E.severity == EVENT_LEVEL_MAJOR)
theseverity = EVENT_LEVEL_MODERATE //just to be careful
if(E.severity)
theseverity = E.severity
// Add the event back to the list of available events
var/datum/event_container/EC = event_containers[theseverity]
var/datum/event_meta/EM = E.event_meta
EC.available_events += EM
log_debug("Event '[EM.name]' has completed at [station_time_timestamp()].")
/datum/controller/subsystem/events/proc/delay_events(var/severity, var/delay)
var/list/datum/event_container/EC = event_containers[severity]
EC.next_event_time += delay
/datum/controller/subsystem/events/proc/Interact(var/mob/living/user)
var/html = GetInteractWindow()
var/datum/browser/popup = new(user, "event_manager", "Event Manager", window_x, window_y)
popup.set_content(html)
popup.open()
/datum/controller/subsystem/events/proc/RoundEnd()
if(!report_at_round_end)
return
to_chat(world, "<br><br><br><font size=3><b>Random Events This Round:</b></font>")
for(var/datum/event/E in active_events|finished_events)
var/datum/event_meta/EM = E.event_meta
if(EM.name == "Nothing")
continue
var/message = "'[EM.name]' began at [station_time_timestamp("hh:mm:ss", E.startedAt)] "
if(E.isRunning)
message += "and is still running."
else
if(E.endedAt - E.startedAt > MinutesToTicks(5)) // Only mention end time if the entire duration was more than 5 minutes
message += "and ended at [station_time_timestamp("hh:mm:ss", E.endedAt)]."
else
message += "and ran to completion."
to_chat(world, message)
/datum/controller/subsystem/events/proc/GetInteractWindow()
var/html = "<A align='right' href='?src=[UID()];refresh=1'>Refresh</A>"
if(selected_event_container)
var/event_time = max(0, selected_event_container.next_event_time - world.time)
html += "<A align='right' href='?src=[UID()];back=1'>Back</A><br>"
html += "Time till start: [round(event_time / 600, 0.1)]<br>"
html += "<div class='block'>"
html += "<h2>Available [severity_to_string[selected_event_container.severity]] Events (queued & running events will not be displayed)</h2>"
html += "<table[table_options]>"
html += "<tr[head_options]><td[row_options2]>Name </td><td>Weight </td><td>MinWeight </td><td>MaxWeight </td><td>OneShot </td><td>Enabled </td><td><span class='alert'>CurrWeight </span></td><td>Remove</td></tr>"
for(var/datum/event_meta/EM in selected_event_container.available_events)
html += "<tr>"
html += "<td>[EM.name]</td>"
html += "<td><A align='right' href='?src=[UID()];set_weight=\ref[EM]'>[EM.weight]</A></td>"
html += "<td>[EM.min_weight]</td>"
html += "<td>[EM.max_weight]</td>"
html += "<td><A align='right' href='?src=[UID()];toggle_oneshot=\ref[EM]'>[EM.one_shot]</A></td>"
html += "<td><A align='right' href='?src=[UID()];toggle_enabled=\ref[EM]'>[EM.enabled]</A></td>"
html += "<td><span class='alert'>[EM.get_weight(number_active_with_role())]</span></td>"
html += "<td><A align='right' href='?src=[UID()];remove=\ref[EM];EC=\ref[selected_event_container]'>Remove</A></td>"
html += "</tr>"
html += "</table>"
html += "</div>"
html += "<div class='block'>"
html += "<h2>Add Event</h2>"
html += "<table[table_options]>"
html += "<tr [head_options]><td[row_options2]>Name</td><td[row_options2]>Type</td><td[row_options1]>Weight</td><td[row_options1]>OneShot</td></tr>"
html += "<tr>"
html += "<td><A align='right' href='?src=[UID()];set_name=\ref[new_event]'>[new_event.name ? new_event.name : "Enter Event"]</A></td>"
html += "<td><A align='right' href='?src=[UID()];set_type=\ref[new_event]'>[new_event.event_type ? new_event.event_type : "Select Type"]</A></td>"
html += "<td><A align='right' href='?src=[UID()];set_weight=\ref[new_event]'>[new_event.weight ? new_event.weight : 0]</A></td>"
html += "<td><A align='right' href='?src=[UID()];toggle_oneshot=\ref[new_event]'>[new_event.one_shot]</A></td>"
html += "</tr>"
html += "</table>"
html += "<A align='right' href='?src=[UID()];add=\ref[selected_event_container]'>Add</A><br>"
html += "</div>"
else
html += "<A align='right' href='?src=[UID()];toggle_report=1'>Round End Report: [report_at_round_end ? "On": "Off"]</A><br>"
html += "<div class='block'>"
html += "<h2>Event Start</h2>"
html += "<table[table_options]>"
html += "<tr[head_options]><td[row_options1]>Severity</td><td[row_options1]>Starts At</td><td[row_options1]>Starts In</td><td[row_options3]>Adjust Start</td><td[row_options1]>Pause</td><td[row_options1]>Interval Mod</td></tr>"
for(var/severity = EVENT_LEVEL_MUNDANE to EVENT_LEVEL_MAJOR)
var/datum/event_container/EC = event_containers[severity]
var/next_event_at = max(0, EC.next_event_time - world.time)
html += "<tr>"
html += "<td>[severity_to_string[severity]]</td>"
html += "<td>[station_time_timestamp("hh:mm:ss", max(EC.next_event_time, world.time))]</td>"
html += "<td>[round(next_event_at / 600, 0.1)]</td>"
html += "<td>"
html += "<A align='right' href='?src=[UID()];dec_timer=2;event=\ref[EC]'>--</A>"
html += "<A align='right' href='?src=[UID()];dec_timer=1;event=\ref[EC]'>-</A>"
html += "<A align='right' href='?src=[UID()];inc_timer=1;event=\ref[EC]'>+</A>"
html += "<A align='right' href='?src=[UID()];inc_timer=2;event=\ref[EC]'>++</A>"
html += "</td>"
html += "<td>"
html += "<A align='right' href='?src=[UID()];pause=\ref[EC]'>[EC.delayed ? "Resume" : "Pause"]</A>"
html += "</td>"
html += "<td>"
html += "<A align='right' href='?src=[UID()];interval=\ref[EC]'>[EC.delay_modifier]</A>"
html += "</td>"
html += "</tr>"
html += "</table>"
html += "</div>"
html += "<div class='block'>"
html += "<h2>Next Event</h2>"
html += "<table[table_options]>"
html += "<tr[head_options]><td[row_options1]>Severity</td><td[row_options2]>Name</td><td[row_options3]>Event Rotation</td><td>Clear</td></tr>"
for(var/severity = EVENT_LEVEL_MUNDANE to EVENT_LEVEL_MAJOR)
var/datum/event_container/EC = event_containers[severity]
var/datum/event_meta/EM = EC.next_event
html += "<tr>"
html += "<td>[severity_to_string[severity]]</td>"
html += "<td><A align='right' href='?src=[UID()];select_event=\ref[EC]'>[EM ? EM.name : "Random"]</A></td>"
html += "<td><A align='right' href='?src=[UID()];view_events=\ref[EC]'>View</A></td>"
html += "<td><A align='right' href='?src=[UID()];clear=\ref[EC]'>Clear</A></td>"
html += "</tr>"
html += "</table>"
html += "</div>"
html += "<div class='block'>"
html += "<h2>Running Events</h2>"
html += "Estimated times, affected by master controller delays."
html += "<table[table_options]>"
html += "<tr[head_options]><td[row_options1]>Severity</td><td[row_options2]>Name</td><td[row_options1]>Ends At</td><td[row_options1]>Ends In</td><td[row_options3]>Stop</td></tr>"
for(var/datum/event/E in active_events)
if(!E.event_meta)
continue
var/datum/event_meta/EM = E.event_meta
var/ends_at = E.startedAt + (E.lastProcessAt() * 20) // A best estimate, based on how often the manager processes
var/ends_in = max(0, round((ends_at - world.time) / 600, 0.1))
var/no_end = E.noAutoEnd
html += "<tr>"
html += "<td>[severity_to_string[EM.severity]]</td>"
html += "<td>[EM.name]</td>"
html += "<td>[no_end ? "N/A" : station_time_timestamp("hh:mm:ss", ends_at)]</td>"
html += "<td>[no_end ? "N/A" : ends_in]</td>"
html += "<td><A align='right' href='?src=[UID()];stop=\ref[E]'>Stop</A></td>"
html += "</tr>"
html += "</table>"
html += "</div>"
return html
/datum/controller/subsystem/events/Topic(href, href_list)
if(..())
return
if(href_list["toggle_report"])
report_at_round_end = !report_at_round_end
admin_log_and_message_admins("has [report_at_round_end ? "enabled" : "disabled"] the round end event report.")
else if(href_list["dec_timer"])
var/datum/event_container/EC = locate(href_list["event"])
var/decrease = (60 * RaiseToPower(10, text2num(href_list["dec_timer"])))
EC.next_event_time -= decrease
admin_log_and_message_admins("decreased timer for [severity_to_string[EC.severity]] events by [decrease/600] minute(s).")
else if(href_list["inc_timer"])
var/datum/event_container/EC = locate(href_list["event"])
var/increase = (60 * RaiseToPower(10, text2num(href_list["inc_timer"])))
EC.next_event_time += increase
admin_log_and_message_admins("increased timer for [severity_to_string[EC.severity]] events by [increase/600] minute(s).")
else if(href_list["select_event"])
var/datum/event_container/EC = locate(href_list["select_event"])
var/datum/event_meta/EM = EC.SelectEvent()
if(EM)
admin_log_and_message_admins("has queued the [severity_to_string[EC.severity]] event '[EM.name]'.")
else if(href_list["pause"])
var/datum/event_container/EC = locate(href_list["pause"])
EC.delayed = !EC.delayed
admin_log_and_message_admins("has [EC.delayed ? "paused" : "resumed"] countdown for [severity_to_string[EC.severity]] events.")
else if(href_list["interval"])
var/delay = input("Enter delay modifier. A value less than one means events fire more often, higher than one less often.", "Set Interval Modifier") as num|null
if(delay && delay > 0)
var/datum/event_container/EC = locate(href_list["interval"])
EC.delay_modifier = delay
admin_log_and_message_admins("has set the interval modifier for [severity_to_string[EC.severity]] events to [EC.delay_modifier].")
else if(href_list["stop"])
if(alert("Stopping an event may have unintended side-effects. Continue?","Stopping Event!","Yes","No") != "Yes")
return
var/datum/event/E = locate(href_list["stop"])
var/datum/event_meta/EM = E.event_meta
admin_log_and_message_admins("has stopped the [severity_to_string[EM.severity]] event '[EM.name]'.")
E.kill()
else if(href_list["view_events"])
selected_event_container = locate(href_list["view_events"])
else if(href_list["back"])
selected_event_container = null
else if(href_list["set_name"])
var/name = clean_input("Enter event name.", "Set Name")
if(name)
var/datum/event_meta/EM = locate(href_list["set_name"])
EM.name = name
else if(href_list["set_type"])
var/type = input("Select event type.", "Select") as null|anything in allEvents
if(type)
var/datum/event_meta/EM = locate(href_list["set_type"])
EM.event_type = type
else if(href_list["set_weight"])
var/weight = input("Enter weight. A higher value means higher chance for the event of being selected.", "Set Weight") as num|null
if(weight && weight > 0)
var/datum/event_meta/EM = locate(href_list["set_weight"])
EM.weight = weight
if(EM != new_event)
admin_log_and_message_admins("has changed the weight of the [severity_to_string[EM.severity]] event '[EM.name]' to [EM.weight].")
else if(href_list["toggle_oneshot"])
var/datum/event_meta/EM = locate(href_list["toggle_oneshot"])
EM.one_shot = !EM.one_shot
if(EM != new_event)
admin_log_and_message_admins("has [EM.one_shot ? "set" : "unset"] the oneshot flag for the [severity_to_string[EM.severity]] event '[EM.name]'.")
else if(href_list["toggle_enabled"])
var/datum/event_meta/EM = locate(href_list["toggle_enabled"])
EM.enabled = !EM.enabled
admin_log_and_message_admins("has [EM.enabled ? "enabled" : "disabled"] the [severity_to_string[EM.severity]] event '[EM.name]'.")
else if(href_list["remove"])
if(alert("This will remove the event from rotation. Continue?","Removing Event!","Yes","No") != "Yes")
return
var/datum/event_meta/EM = locate(href_list["remove"])
var/datum/event_container/EC = locate(href_list["EC"])
EC.available_events -= EM
admin_log_and_message_admins("has removed the [severity_to_string[EM.severity]] event '[EM.name]'.")
else if(href_list["add"])
if(!new_event.name || !new_event.event_type)
return
if(alert("This will add a new event to the rotation. Continue?","Add Event!","Yes","No") != "Yes")
return
new_event.severity = selected_event_container.severity
selected_event_container.available_events += new_event
admin_log_and_message_admins("has added \a [severity_to_string[new_event.severity]] event '[new_event.name]' of type [new_event.event_type] with weight [new_event.weight].")
new_event = new
else if(href_list["clear"])
var/datum/event_container/EC = locate(href_list["clear"])
if(EC.next_event)
admin_log_and_message_admins("has dequeued the [severity_to_string[EC.severity]] event '[EC.next_event.name]'.")
EC.next_event = null
Interact(usr)
SUBSYSTEM_DEF(events)
name = "Events"
init_order = INIT_ORDER_EVENTS
runlevels = RUNLEVEL_GAME
// Report events at the end of the rouund
var/report_at_round_end = 0
// UI vars
var/window_x = 700
var/window_y = 600
var/table_options = " align='center'"
var/head_options = " style='font-weight:bold;'"
var/row_options1 = " width='85px'"
var/row_options2 = " width='260px'"
var/row_options3 = " width='150px'"
// Event vars
var/datum/event_container/selected_event_container = null
var/list/active_events = list()
var/list/finished_events = list()
var/list/allEvents
var/list/event_containers = list(
EVENT_LEVEL_MUNDANE = new/datum/event_container/mundane,
EVENT_LEVEL_MODERATE = new/datum/event_container/moderate,
EVENT_LEVEL_MAJOR = new/datum/event_container/major
)
var/datum/event_meta/new_event = new
/datum/controller/subsystem/events/Initialize()
allEvents = subtypesof(/datum/event)
return ..()
/datum/controller/subsystem/events/fire()
for(var/datum/event/E in active_events)
E.process()
for(var/i = EVENT_LEVEL_MUNDANE to EVENT_LEVEL_MAJOR)
var/list/datum/event_container/EC = event_containers[i]
EC.process()
/datum/controller/subsystem/events/proc/event_complete(var/datum/event/E)
if(!E.event_meta) // datum/event is used here and there for random reasons, maintaining "backwards compatibility"
log_debug("Event of '[E.type]' with missing meta-data has completed.")
return
finished_events += E
var/theseverity
if(!E.severity)
theseverity = EVENT_LEVEL_MODERATE
if(!E.severity == EVENT_LEVEL_MUNDANE && !E.severity == EVENT_LEVEL_MODERATE && !E.severity == EVENT_LEVEL_MAJOR)
theseverity = EVENT_LEVEL_MODERATE //just to be careful
if(E.severity)
theseverity = E.severity
// Add the event back to the list of available events
var/datum/event_container/EC = event_containers[theseverity]
var/datum/event_meta/EM = E.event_meta
EC.available_events += EM
log_debug("Event '[EM.name]' has completed at [station_time_timestamp()].")
/datum/controller/subsystem/events/proc/delay_events(var/severity, var/delay)
var/list/datum/event_container/EC = event_containers[severity]
EC.next_event_time += delay
/datum/controller/subsystem/events/proc/Interact(var/mob/living/user)
var/html = GetInteractWindow()
var/datum/browser/popup = new(user, "event_manager", "Event Manager", window_x, window_y)
popup.set_content(html)
popup.open()
/datum/controller/subsystem/events/proc/RoundEnd()
if(!report_at_round_end)
return
to_chat(world, "<br><br><br><font size=3><b>Random Events This Round:</b></font>")
for(var/datum/event/E in active_events|finished_events)
var/datum/event_meta/EM = E.event_meta
if(EM.name == "Nothing")
continue
var/message = "'[EM.name]' began at [station_time_timestamp("hh:mm:ss", E.startedAt)] "
if(E.isRunning)
message += "and is still running."
else
if(E.endedAt - E.startedAt > MinutesToTicks(5)) // Only mention end time if the entire duration was more than 5 minutes
message += "and ended at [station_time_timestamp("hh:mm:ss", E.endedAt)]."
else
message += "and ran to completion."
to_chat(world, message)
/datum/controller/subsystem/events/proc/GetInteractWindow()
var/html = "<A align='right' href='?src=[UID()];refresh=1'>Refresh</A>"
if(selected_event_container)
var/event_time = max(0, selected_event_container.next_event_time - world.time)
html += "<A align='right' href='?src=[UID()];back=1'>Back</A><br>"
html += "Time till start: [round(event_time / 600, 0.1)]<br>"
html += "<div class='block'>"
html += "<h2>Available [severity_to_string[selected_event_container.severity]] Events (queued & running events will not be displayed)</h2>"
html += "<table[table_options]>"
html += "<tr[head_options]><td[row_options2]>Name </td><td>Weight </td><td>MinWeight </td><td>MaxWeight </td><td>OneShot </td><td>Enabled </td><td><span class='alert'>CurrWeight </span></td><td>Remove</td></tr>"
for(var/datum/event_meta/EM in selected_event_container.available_events)
html += "<tr>"
html += "<td>[EM.name]</td>"
html += "<td><A align='right' href='?src=[UID()];set_weight=\ref[EM]'>[EM.weight]</A></td>"
html += "<td>[EM.min_weight]</td>"
html += "<td>[EM.max_weight]</td>"
html += "<td><A align='right' href='?src=[UID()];toggle_oneshot=\ref[EM]'>[EM.one_shot]</A></td>"
html += "<td><A align='right' href='?src=[UID()];toggle_enabled=\ref[EM]'>[EM.enabled]</A></td>"
html += "<td><span class='alert'>[EM.get_weight(number_active_with_role())]</span></td>"
html += "<td><A align='right' href='?src=[UID()];remove=\ref[EM];EC=\ref[selected_event_container]'>Remove</A></td>"
html += "</tr>"
html += "</table>"
html += "</div>"
html += "<div class='block'>"
html += "<h2>Add Event</h2>"
html += "<table[table_options]>"
html += "<tr [head_options]><td[row_options2]>Name</td><td[row_options2]>Type</td><td[row_options1]>Weight</td><td[row_options1]>OneShot</td></tr>"
html += "<tr>"
html += "<td><A align='right' href='?src=[UID()];set_name=\ref[new_event]'>[new_event.name ? new_event.name : "Enter Event"]</A></td>"
html += "<td><A align='right' href='?src=[UID()];set_type=\ref[new_event]'>[new_event.event_type ? new_event.event_type : "Select Type"]</A></td>"
html += "<td><A align='right' href='?src=[UID()];set_weight=\ref[new_event]'>[new_event.weight ? new_event.weight : 0]</A></td>"
html += "<td><A align='right' href='?src=[UID()];toggle_oneshot=\ref[new_event]'>[new_event.one_shot]</A></td>"
html += "</tr>"
html += "</table>"
html += "<A align='right' href='?src=[UID()];add=\ref[selected_event_container]'>Add</A><br>"
html += "</div>"
else
html += "<A align='right' href='?src=[UID()];toggle_report=1'>Round End Report: [report_at_round_end ? "On": "Off"]</A><br>"
html += "<div class='block'>"
html += "<h2>Event Start</h2>"
html += "<table[table_options]>"
html += "<tr[head_options]><td[row_options1]>Severity</td><td[row_options1]>Starts At</td><td[row_options1]>Starts In</td><td[row_options3]>Adjust Start</td><td[row_options1]>Pause</td><td[row_options1]>Interval Mod</td></tr>"
for(var/severity = EVENT_LEVEL_MUNDANE to EVENT_LEVEL_MAJOR)
var/datum/event_container/EC = event_containers[severity]
var/next_event_at = max(0, EC.next_event_time - world.time)
html += "<tr>"
html += "<td>[severity_to_string[severity]]</td>"
html += "<td>[station_time_timestamp("hh:mm:ss", max(EC.next_event_time, world.time))]</td>"
html += "<td>[round(next_event_at / 600, 0.1)]</td>"
html += "<td>"
html += "<A align='right' href='?src=[UID()];dec_timer=2;event=\ref[EC]'>--</A>"
html += "<A align='right' href='?src=[UID()];dec_timer=1;event=\ref[EC]'>-</A>"
html += "<A align='right' href='?src=[UID()];inc_timer=1;event=\ref[EC]'>+</A>"
html += "<A align='right' href='?src=[UID()];inc_timer=2;event=\ref[EC]'>++</A>"
html += "</td>"
html += "<td>"
html += "<A align='right' href='?src=[UID()];pause=\ref[EC]'>[EC.delayed ? "Resume" : "Pause"]</A>"
html += "</td>"
html += "<td>"
html += "<A align='right' href='?src=[UID()];interval=\ref[EC]'>[EC.delay_modifier]</A>"
html += "</td>"
html += "</tr>"
html += "</table>"
html += "</div>"
html += "<div class='block'>"
html += "<h2>Next Event</h2>"
html += "<table[table_options]>"
html += "<tr[head_options]><td[row_options1]>Severity</td><td[row_options2]>Name</td><td[row_options3]>Event Rotation</td><td>Clear</td></tr>"
for(var/severity = EVENT_LEVEL_MUNDANE to EVENT_LEVEL_MAJOR)
var/datum/event_container/EC = event_containers[severity]
var/datum/event_meta/EM = EC.next_event
html += "<tr>"
html += "<td>[severity_to_string[severity]]</td>"
html += "<td><A align='right' href='?src=[UID()];select_event=\ref[EC]'>[EM ? EM.name : "Random"]</A></td>"
html += "<td><A align='right' href='?src=[UID()];view_events=\ref[EC]'>View</A></td>"
html += "<td><A align='right' href='?src=[UID()];clear=\ref[EC]'>Clear</A></td>"
html += "</tr>"
html += "</table>"
html += "</div>"
html += "<div class='block'>"
html += "<h2>Running Events</h2>"
html += "Estimated times, affected by master controller delays."
html += "<table[table_options]>"
html += "<tr[head_options]><td[row_options1]>Severity</td><td[row_options2]>Name</td><td[row_options1]>Ends At</td><td[row_options1]>Ends In</td><td[row_options3]>Stop</td></tr>"
for(var/datum/event/E in active_events)
if(!E.event_meta)
continue
var/datum/event_meta/EM = E.event_meta
var/ends_at = E.startedAt + (E.lastProcessAt() * 20) // A best estimate, based on how often the manager processes
var/ends_in = max(0, round((ends_at - world.time) / 600, 0.1))
var/no_end = E.noAutoEnd
html += "<tr>"
html += "<td>[severity_to_string[EM.severity]]</td>"
html += "<td>[EM.name]</td>"
html += "<td>[no_end ? "N/A" : station_time_timestamp("hh:mm:ss", ends_at)]</td>"
html += "<td>[no_end ? "N/A" : ends_in]</td>"
html += "<td><A align='right' href='?src=[UID()];stop=\ref[E]'>Stop</A></td>"
html += "</tr>"
html += "</table>"
html += "</div>"
return html
/datum/controller/subsystem/events/Topic(href, href_list)
if(..())
return
if(href_list["toggle_report"])
report_at_round_end = !report_at_round_end
admin_log_and_message_admins("has [report_at_round_end ? "enabled" : "disabled"] the round end event report.")
else if(href_list["dec_timer"])
var/datum/event_container/EC = locate(href_list["event"])
var/decrease = (60 * RaiseToPower(10, text2num(href_list["dec_timer"])))
EC.next_event_time -= decrease
admin_log_and_message_admins("decreased timer for [severity_to_string[EC.severity]] events by [decrease/600] minute(s).")
else if(href_list["inc_timer"])
var/datum/event_container/EC = locate(href_list["event"])
var/increase = (60 * RaiseToPower(10, text2num(href_list["inc_timer"])))
EC.next_event_time += increase
admin_log_and_message_admins("increased timer for [severity_to_string[EC.severity]] events by [increase/600] minute(s).")
else if(href_list["select_event"])
var/datum/event_container/EC = locate(href_list["select_event"])
var/datum/event_meta/EM = EC.SelectEvent()
if(EM)
admin_log_and_message_admins("has queued the [severity_to_string[EC.severity]] event '[EM.name]'.")
else if(href_list["pause"])
var/datum/event_container/EC = locate(href_list["pause"])
EC.delayed = !EC.delayed
admin_log_and_message_admins("has [EC.delayed ? "paused" : "resumed"] countdown for [severity_to_string[EC.severity]] events.")
else if(href_list["interval"])
var/delay = input("Enter delay modifier. A value less than one means events fire more often, higher than one less often.", "Set Interval Modifier") as num|null
if(delay && delay > 0)
var/datum/event_container/EC = locate(href_list["interval"])
EC.delay_modifier = delay
admin_log_and_message_admins("has set the interval modifier for [severity_to_string[EC.severity]] events to [EC.delay_modifier].")
else if(href_list["stop"])
if(alert("Stopping an event may have unintended side-effects. Continue?","Stopping Event!","Yes","No") != "Yes")
return
var/datum/event/E = locate(href_list["stop"])
var/datum/event_meta/EM = E.event_meta
admin_log_and_message_admins("has stopped the [severity_to_string[EM.severity]] event '[EM.name]'.")
E.kill()
else if(href_list["view_events"])
selected_event_container = locate(href_list["view_events"])
else if(href_list["back"])
selected_event_container = null
else if(href_list["set_name"])
var/name = clean_input("Enter event name.", "Set Name")
if(name)
var/datum/event_meta/EM = locate(href_list["set_name"])
EM.name = name
else if(href_list["set_type"])
var/type = input("Select event type.", "Select") as null|anything in allEvents
if(type)
var/datum/event_meta/EM = locate(href_list["set_type"])
EM.event_type = type
else if(href_list["set_weight"])
var/weight = input("Enter weight. A higher value means higher chance for the event of being selected.", "Set Weight") as num|null
if(weight && weight > 0)
var/datum/event_meta/EM = locate(href_list["set_weight"])
EM.weight = weight
if(EM != new_event)
admin_log_and_message_admins("has changed the weight of the [severity_to_string[EM.severity]] event '[EM.name]' to [EM.weight].")
else if(href_list["toggle_oneshot"])
var/datum/event_meta/EM = locate(href_list["toggle_oneshot"])
EM.one_shot = !EM.one_shot
if(EM != new_event)
admin_log_and_message_admins("has [EM.one_shot ? "set" : "unset"] the oneshot flag for the [severity_to_string[EM.severity]] event '[EM.name]'.")
else if(href_list["toggle_enabled"])
var/datum/event_meta/EM = locate(href_list["toggle_enabled"])
EM.enabled = !EM.enabled
admin_log_and_message_admins("has [EM.enabled ? "enabled" : "disabled"] the [severity_to_string[EM.severity]] event '[EM.name]'.")
else if(href_list["remove"])
if(alert("This will remove the event from rotation. Continue?","Removing Event!","Yes","No") != "Yes")
return
var/datum/event_meta/EM = locate(href_list["remove"])
var/datum/event_container/EC = locate(href_list["EC"])
EC.available_events -= EM
admin_log_and_message_admins("has removed the [severity_to_string[EM.severity]] event '[EM.name]'.")
else if(href_list["add"])
if(!new_event.name || !new_event.event_type)
return
if(alert("This will add a new event to the rotation. Continue?","Add Event!","Yes","No") != "Yes")
return
new_event.severity = selected_event_container.severity
selected_event_container.available_events += new_event
admin_log_and_message_admins("has added \a [severity_to_string[new_event.severity]] event '[new_event.name]' of type [new_event.event_type] with weight [new_event.weight].")
new_event = new
else if(href_list["clear"])
var/datum/event_container/EC = locate(href_list["clear"])
if(EC.next_event)
admin_log_and_message_admins("has dequeued the [severity_to_string[EC.severity]] event '[EC.next_event.name]'.")
EC.next_event = null
Interact(usr)
+1 -1
View File
@@ -432,4 +432,4 @@ SUBSYSTEM_DEF(garbage)
CHECK_TICK
#endif
#endif
#endif
+31 -31
View File
@@ -1,31 +1,31 @@
SUBSYSTEM_DEF(holiday)
name = "Holiday"
init_order = INIT_ORDER_HOLIDAY // 3
flags = SS_NO_FIRE
var/list/holidays
/datum/controller/subsystem/holiday/Initialize(start_timeofday)
if(!config.allow_holidays)
return ..() //Holiday stuff was not enabled in the config!
var/YY = text2num(time2text(world.timeofday, "YY")) // get the current year
var/MM = text2num(time2text(world.timeofday, "MM")) // get the current month
var/DD = text2num(time2text(world.timeofday, "DD")) // get the current day
for(var/H in subtypesof(/datum/holiday))
var/datum/holiday/holiday = new H()
if(holiday.shouldCelebrate(DD, MM, YY))
holiday.celebrate()
if(!holidays)
holidays = list()
holidays[holiday.name] = holiday
if(holidays)
holidays = shuffle(holidays)
world.update_status()
for(var/datum/holiday/H in holidays)
if(H.eventChance)
if(prob(H.eventChance))
H.handle_event()
return ..()
SUBSYSTEM_DEF(holiday)
name = "Holiday"
init_order = INIT_ORDER_HOLIDAY // 3
flags = SS_NO_FIRE
var/list/holidays
/datum/controller/subsystem/holiday/Initialize(start_timeofday)
if(!config.allow_holidays)
return ..() //Holiday stuff was not enabled in the config!
var/YY = text2num(time2text(world.timeofday, "YY")) // get the current year
var/MM = text2num(time2text(world.timeofday, "MM")) // get the current month
var/DD = text2num(time2text(world.timeofday, "DD")) // get the current day
for(var/H in subtypesof(/datum/holiday))
var/datum/holiday/holiday = new H()
if(holiday.shouldCelebrate(DD, MM, YY))
holiday.celebrate()
if(!holidays)
holidays = list()
holidays[holiday.name] = holiday
if(holidays)
holidays = shuffle(holidays)
world.update_status()
for(var/datum/holiday/H in holidays)
if(H.eventChance)
if(prob(H.eventChance))
H.handle_event()
return ..()
+2 -1
View File
@@ -29,6 +29,7 @@ SUBSYSTEM_DEF(idlenpcpool)
var/mob/living/simple_animal/SA = currentrun[currentrun.len]
--currentrun.len
if(!SA)
log_debug("idlenpcpool encountered an invalid entry, resumed: [resumed], SA [SA], type of SA [SA?.type], null [SA == null], qdelled [QDELETED(SA)], SA in AI_IDLE list: [SA in GLOB.simple_animals[AI_IDLE]]")
GLOB.simple_animals[AI_IDLE] -= SA
continue
@@ -38,4 +39,4 @@ SUBSYSTEM_DEF(idlenpcpool)
if(SA.stat != DEAD)
SA.consider_wakeup()
if(MC_TICK_CHECK)
return
return
+7 -4
View File
@@ -389,8 +389,11 @@ SUBSYSTEM_DEF(jobs)
// Antags, who have to get in, come first
for(var/mob/new_player/player in unassigned)
if(player.mind.special_role)
GiveRandomJob(player)
if(player in unassigned)
if(player.client.prefs.alternate_option != BE_ASSISTANT)
GiveRandomJob(player)
if(player in unassigned)
AssignRole(player, "Civilian")
else
AssignRole(player, "Civilian")
// Then we assign what we can to everyone else.
@@ -439,7 +442,7 @@ SUBSYSTEM_DEF(jobs)
if(job.is_security)
to_chat(H, "<b>As a member of Security, you are to know <a href=\"https://www.paradisestation.org/wiki/index.php/Space_law\">Space Law</a>, <a href=\"https://www.paradisestation.org/wiki/index.php/Legal_Standard_Operating_Procedure\">Legal Standard Operating Procedure</a>, as well as your <a href=\"https://www.paradisestation.org/wiki/index.php/Standard_Operating_Procedure_&#40;Security&#41\">Department SOP</a></b>")
if(job.req_admin_notify)
to_chat(H, "<b>You are playing a job that is important for the game progression. If you have to disconnect, please notify the admins via adminhelp.</b>")
to_chat(H, "<b>You are playing a job that is important for the game progression. If you have to disconnect, please go to cryo and inform command. If you are unable to do so, please notify the admins via adminhelp.</b>")
return H
/datum/controller/subsystem/jobs/proc/EquipRank(mob/living/carbon/human/H, rank, joined_late = 0) // Equip and put them in an area
@@ -690,4 +693,4 @@ SUBSYSTEM_DEF(jobs)
.++
new_id_change_records["[id_change_counter]"] = thisrecord
id_change_counter++
id_change_records = new_id_change_records
id_change_records = new_id_change_records
+1 -1
View File
@@ -84,4 +84,4 @@ SUBSYSTEM_DEF(lighting)
/datum/controller/subsystem/lighting/Recover()
initialized = SSlighting.initialized
..()
..()
+1 -1
View File
@@ -33,4 +33,4 @@ SUBSYSTEM_DEF(mapping)
return ..()
/datum/controller/subsystem/mapping/Recover()
flags |= SS_NO_INIT
flags |= SS_NO_INIT
+1 -1
View File
@@ -83,4 +83,4 @@ SUBSYSTEM_DEF(medals)
/datum/controller/subsystem/medals/proc/ClearScore(client/player)
if(isnull(world.SetScores(player.ckey, "", config.medal_hub_address, config.medal_hub_password)))
log_game("MEDAL ERROR: Could not contact hub to clear scores for [player.ckey].")
message_admins("Error! Failed to contact hub to clear scores for [player.ckey]!")
message_admins("Error! Failed to contact hub to clear scores for [player.ckey]!")
+1 -1
View File
@@ -33,4 +33,4 @@ SUBSYSTEM_DEF(mobs)
else
GLOB.mob_list.Remove(M)
if(MC_TICK_CHECK)
return
return
+5 -1
View File
@@ -21,6 +21,10 @@ SUBSYSTEM_DEF(npcpool)
while(currentrun.len)
var/mob/living/simple_animal/SA = currentrun[currentrun.len]
--currentrun.len
if(!SA)
log_debug("npcpool encountered an invalid entry, resumed: [resumed], SA [SA], type of SA [SA?.type], null [SA == null], qdelled [QDELETED(SA)], SA in AI_ON list: [SA in GLOB.simple_animals[AI_ON]]")
GLOB.simple_animals[AI_ON] -= SA
continue
if(!SA.ckey && !SA.notransform)
if(SA.stat != DEAD)
@@ -30,4 +34,4 @@ SUBSYSTEM_DEF(npcpool)
if(SA.stat != DEAD)
SA.handle_automated_speech()
if(MC_TICK_CHECK)
return
return
@@ -3,4 +3,4 @@
PROCESSING_SUBSYSTEM_DEF(fastprocess)
name = "Fast Processing"
wait = 2
stat_tag = "FP"
stat_tag = "FP"
+1 -1
View File
@@ -2,4 +2,4 @@ PROCESSING_SUBSYSTEM_DEF(obj)
name = "Objects"
priority = FIRE_PRIORITY_OBJ
flags = SS_NO_INIT
wait = 20
wait = 20
@@ -34,4 +34,4 @@ SUBSYSTEM_DEF(processing)
/datum/proc/process()
set waitfor = 0
return PROCESS_KILL
return PROCESS_KILL
+99 -99
View File
@@ -1,99 +1,99 @@
SUBSYSTEM_DEF(radio)
name = "Radio"
flags = SS_NO_INIT | SS_NO_FIRE
var/list/radiochannels = list(
"Common" = PUB_FREQ,
"Science" = SCI_FREQ,
"Command" = COMM_FREQ,
"Medical" = MED_FREQ,
"Engineering" = ENG_FREQ,
"Security" = SEC_FREQ,
"Response Team" = ERT_FREQ,
"Special Ops" = DTH_FREQ,
"Syndicate" = SYND_FREQ,
"SyndTeam" = SYNDTEAM_FREQ,
"Supply" = SUP_FREQ,
"Service" = SRV_FREQ,
"AI Private" = AI_FREQ,
"Medical(I)" = MED_I_FREQ,
"Security(I)" = SEC_I_FREQ
)
var/list/CENT_FREQS = list(ERT_FREQ, DTH_FREQ)
var/list/ANTAG_FREQS = list(SYND_FREQ, SYNDTEAM_FREQ)
var/list/DEPT_FREQS = list(AI_FREQ, COMM_FREQ, ENG_FREQ, MED_FREQ, SEC_FREQ, SCI_FREQ, SRV_FREQ, SUP_FREQ)
var/list/datum/radio_frequency/frequencies = list()
// This is fucking disgusting and needs to die
/datum/controller/subsystem/radio/proc/frequency_span_class(var/frequency)
// Antags!
if(frequency in ANTAG_FREQS)
return "syndradio"
// centcomm channels (deathsquid and ert)
if(frequency in CENT_FREQS)
return "centradio"
// This switch used to be a shit tonne of if statements. I am gonna find who made this and give them a kind talking to
switch(frequency)
if(COMM_FREQ)
return "comradio"
if(AI_FREQ)
return "airadio"
if(SEC_FREQ)
return "secradio"
if(ENG_FREQ)
return "engradio"
if(SCI_FREQ)
return "sciradio"
if(MED_FREQ)
return "medradio"
if(SUP_FREQ)
return "supradio"
if(SRV_FREQ)
return "srvradio"
// If the above switch somehow failed. And it needs the SSradio. part otherwise it fails to compile
if(frequency in DEPT_FREQS)
return "deptradio"
// If its none of the others
return "radio"
/datum/controller/subsystem/radio/proc/add_object(obj/device as obj, var/new_frequency as num, var/filter = null as text|null)
var/f_text = num2text(new_frequency)
var/datum/radio_frequency/frequency = frequencies[f_text]
if(!frequency)
frequency = new
frequency.frequency = new_frequency
frequencies[f_text] = frequency
frequency.add_listener(device, filter)
return frequency
/datum/controller/subsystem/radio/proc/remove_object(obj/device, old_frequency)
var/f_text = num2text(old_frequency)
var/datum/radio_frequency/frequency = frequencies[f_text]
if(frequency)
frequency.remove_listener(device)
if(frequency.devices.len == 0)
qdel(frequency)
frequencies -= f_text
return 1
/datum/controller/subsystem/radio/proc/return_frequency(var/new_frequency as num)
var/f_text = num2text(new_frequency)
var/datum/radio_frequency/frequency = frequencies[f_text]
if(!frequency)
frequency = new
frequency.frequency = new_frequency
frequencies[f_text] = frequency
return frequency
// ALL THE SHIT BELOW THIS LINE ISNT PART OF THE SUBSYSTEM AND REALLY NEEDS ITS OWN FILE
SUBSYSTEM_DEF(radio)
name = "Radio"
flags = SS_NO_INIT | SS_NO_FIRE
var/list/radiochannels = list(
"Common" = PUB_FREQ,
"Science" = SCI_FREQ,
"Command" = COMM_FREQ,
"Medical" = MED_FREQ,
"Engineering" = ENG_FREQ,
"Security" = SEC_FREQ,
"Response Team" = ERT_FREQ,
"Special Ops" = DTH_FREQ,
"Syndicate" = SYND_FREQ,
"SyndTeam" = SYNDTEAM_FREQ,
"Supply" = SUP_FREQ,
"Service" = SRV_FREQ,
"AI Private" = AI_FREQ,
"Medical(I)" = MED_I_FREQ,
"Security(I)" = SEC_I_FREQ
)
var/list/CENT_FREQS = list(ERT_FREQ, DTH_FREQ)
var/list/ANTAG_FREQS = list(SYND_FREQ, SYNDTEAM_FREQ)
var/list/DEPT_FREQS = list(AI_FREQ, COMM_FREQ, ENG_FREQ, MED_FREQ, SEC_FREQ, SCI_FREQ, SRV_FREQ, SUP_FREQ)
var/list/datum/radio_frequency/frequencies = list()
// This is fucking disgusting and needs to die
/datum/controller/subsystem/radio/proc/frequency_span_class(var/frequency)
// Antags!
if(frequency in ANTAG_FREQS)
return "syndradio"
// centcomm channels (deathsquid and ert)
if(frequency in CENT_FREQS)
return "centradio"
// This switch used to be a shit tonne of if statements. I am gonna find who made this and give them a kind talking to
switch(frequency)
if(COMM_FREQ)
return "comradio"
if(AI_FREQ)
return "airadio"
if(SEC_FREQ)
return "secradio"
if(ENG_FREQ)
return "engradio"
if(SCI_FREQ)
return "sciradio"
if(MED_FREQ)
return "medradio"
if(SUP_FREQ)
return "supradio"
if(SRV_FREQ)
return "srvradio"
// If the above switch somehow failed. And it needs the SSradio. part otherwise it fails to compile
if(frequency in DEPT_FREQS)
return "deptradio"
// If its none of the others
return "radio"
/datum/controller/subsystem/radio/proc/add_object(obj/device as obj, var/new_frequency as num, var/filter = null as text|null)
var/f_text = num2text(new_frequency)
var/datum/radio_frequency/frequency = frequencies[f_text]
if(!frequency)
frequency = new
frequency.frequency = new_frequency
frequencies[f_text] = frequency
frequency.add_listener(device, filter)
return frequency
/datum/controller/subsystem/radio/proc/remove_object(obj/device, old_frequency)
var/f_text = num2text(old_frequency)
var/datum/radio_frequency/frequency = frequencies[f_text]
if(frequency)
frequency.remove_listener(device)
if(frequency.devices.len == 0)
qdel(frequency)
frequencies -= f_text
return 1
/datum/controller/subsystem/radio/proc/return_frequency(var/new_frequency as num)
var/f_text = num2text(new_frequency)
var/datum/radio_frequency/frequency = frequencies[f_text]
if(!frequency)
frequency = new
frequency.frequency = new_frequency
frequencies[f_text] = frequency
return frequency
// ALL THE SHIT BELOW THIS LINE ISNT PART OF THE SUBSYSTEM AND REALLY NEEDS ITS OWN FILE
+1 -1
View File
@@ -311,4 +311,4 @@ SUBSYSTEM_DEF(shuttle)
QDEL_LIST(remove_images)
#undef CALL_SHUTTLE_REASON_LENGTH
#undef CALL_SHUTTLE_REASON_LENGTH
+1 -1
View File
@@ -39,4 +39,4 @@ SUBSYSTEM_DEF(sun)
if(!SC.powernet)
solars.Remove(SC)
continue
SC.update()
SC.update()
+1 -1
View File
@@ -518,4 +518,4 @@ SUBSYSTEM_DEF(timer)
#undef BUCKET_LEN
#undef BUCKET_POS
#undef TIMER_MAX
#undef TIMER_ID_MAX
#undef TIMER_ID_MAX
+401 -401
View File
@@ -1,401 +1,401 @@
SUBSYSTEM_DEF(vote)
name = "Vote"
wait = 10
flags = SS_KEEP_TIMING|SS_NO_INIT
runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
var/initiator = null
var/started_time = null
var/time_remaining = 0
var/mode = null
var/question = null
var/list/choices = list()
var/list/voted = list()
var/list/voting = list()
var/list/current_votes = list()
var/list/round_voters = list()
var/auto_muted = 0
/datum/controller/subsystem/vote/fire()
if(mode)
// No more change mode votes after the game has started.
if(mode == "gamemode" && SSticker.current_state >= GAME_STATE_SETTING_UP)
to_chat(world, "<b>Voting aborted due to game start.</b>")
reset()
return
// Calculate how much time is remaining by comparing current time, to time of vote start,
// plus vote duration
time_remaining = round((started_time + config.vote_period - world.time)/10)
if(time_remaining < 0)
result()
for(var/client/C in voting)
if(C)
C << browse(null,"window=vote")
reset()
else
for(var/client/C in voting)
update_panel(C)
CHECK_TICK
/datum/controller/subsystem/vote/proc/autotransfer()
initiate_vote("crew_transfer","the server")
/datum/controller/subsystem/vote/proc/reset()
initiator = null
time_remaining = 0
mode = null
question = null
choices.Cut()
voted.Cut()
voting.Cut()
current_votes.Cut()
if(auto_muted && !config.ooc_allowed)
auto_muted = 0
config.ooc_allowed = !( config.ooc_allowed )
to_chat(world, "<b>The OOC channel has been automatically enabled due to vote end.</b>")
log_admin("OOC was toggled automatically due to vote end.")
message_admins("OOC has been toggled on automatically.")
/datum/controller/subsystem/vote/proc/get_result()
var/greatest_votes = 0
var/total_votes = 0
var/list/sorted_choices = list()
var/sorted_highest
var/sorted_votes = -1
//get the highest number of votes, while also sorting the list
while(choices.len)
// This is a very inefficient sorting method, but that's okay
for(var/option in choices)
var/votes = choices[option]
if(sorted_votes < votes)
sorted_highest = option
sorted_votes = votes
if(votes > greatest_votes)
greatest_votes = votes
sorted_votes = -1
total_votes += choices[sorted_highest]
sorted_choices[sorted_highest] = choices[sorted_highest] || 0
choices -= sorted_highest
choices = sorted_choices
//default-vote for everyone who didn't vote
if(!config.vote_no_default && choices.len)
var/non_voters = (GLOB.clients.len - total_votes)
if(non_voters > 0)
if(mode == "restart")
choices["Continue Playing"] += non_voters
if(choices["Continue Playing"] >= greatest_votes)
greatest_votes = choices["Continue Playing"]
else if(mode == "gamemode")
if(master_mode in choices)
choices[master_mode] += non_voters
if(choices[master_mode] >= greatest_votes)
greatest_votes = choices[master_mode]
else if(mode == "crew_transfer")
var/factor = 0.5
switch(world.time / (10 * 60)) // minutes
if(0 to 60)
factor = 0.5
if(61 to 120)
factor = 0.8
if(121 to 240)
factor = 1
if(241 to 300)
factor = 1.2
else
factor = 1.4
choices["Initiate Crew Transfer"] = round(choices["Initiate Crew Transfer"] * factor)
to_chat(world, "<font color='purple'>Crew Transfer Factor: [factor]</font>")
greatest_votes = max(choices["Initiate Crew Transfer"], choices["Continue The Round"])
//get all options with that many votes and return them in a list
. = list()
if(greatest_votes)
for(var/option in choices)
if(choices[option] == greatest_votes)
. += option
return .
/datum/controller/subsystem/vote/proc/announce_result()
var/list/winners = get_result()
var/text
if(winners.len > 0)
if(winners.len > 1)
if(mode != "gamemode" || SSticker.hide_mode == 0) // Here we are making sure we don't announce potential game modes
text = "<b>Vote Tied Between:</b>\n"
for(var/option in winners)
text += "\t[option]\n"
. = pick(winners)
for(var/key in current_votes)
if(choices[current_votes[key]] == .)
round_voters += key // Keep track of who voted for the winning round.
if(mode == "gamemode" && (. == "extended" || SSticker.hide_mode == 0)) // Announce Extended gamemode, but not other gamemodes
text += "<b>Vote Result: [.] ([choices[.]] vote\s)</b>"
else
if(mode == "custom")
// Completely replace text to show all results in custom votes
text = "<b><span style='text-decoration: underline;'>[question]</span></b>\n"
for(var/option in winners)
text += "\t<b>[option]: [choices[option]] vote\s</b>\n"
for(var/option in (choices-winners))
text += "\t[option]: [choices[option]] vote\s\n"
else if(mode != "gamemode")
text += "<b>Vote Result: [.] ([choices[.]] vote\s)</b>"
else
text += "<b>The vote has ended.</b>" // What will be shown if it is a gamemode vote that isn't extended
else
text += "<b>Vote Result: Inconclusive - No Votes!</b>"
log_vote(text)
to_chat(world, "<font color='purple'>[text]</font>")
return .
/datum/controller/subsystem/vote/proc/result()
. = announce_result()
var/restart = 0
if(.)
switch(mode)
if("restart")
if(. == "Restart Round")
restart = 1
if("gamemode")
if(master_mode != .)
world.save_mode(.)
if(SSticker && SSticker.mode)
restart = 1
else
master_mode = .
if(!going)
going = 1
to_chat(world, "<font color='red'><b>The round will start soon.</b></font>")
if("crew_transfer")
if(. == "Initiate Crew Transfer")
init_shift_change(null, 1)
if(restart)
world.Reboot("Restart vote successful.", "end_error", "restart vote")
return .
/datum/controller/subsystem/vote/proc/submit_vote(var/ckey, var/vote)
if(mode)
if(config.vote_no_dead && usr.stat == DEAD && !usr.client.holder)
return 0
if(current_votes[ckey])
choices[choices[current_votes[ckey]]]--
if(vote && 1<=vote && vote<=choices.len)
voted += usr.ckey
choices[choices[vote]]++ //check this
current_votes[ckey] = vote
return vote
return 0
/datum/controller/subsystem/vote/proc/initiate_vote(var/vote_type, var/initiator_key)
if(!mode)
if(started_time != null && !check_rights(R_ADMIN))
var/next_allowed_time = (started_time + config.vote_delay)
if(next_allowed_time > world.time)
return 0
reset()
switch(vote_type)
if("restart")
choices.Add("Restart Round","Continue Playing")
if("gamemode")
if(SSticker.current_state >= 2)
return 0
choices.Add(config.votable_modes)
if("crew_transfer")
if(check_rights(R_ADMIN|R_MOD))
if(SSticker.current_state <= 2)
return 0
question = "End the shift?"
choices.Add("Initiate Crew Transfer", "Continue The Round")
else
if(SSticker.current_state <= 2)
return 0
question = "End the shift?"
choices.Add("Initiate Crew Transfer", "Continue The Round")
if("custom")
question = html_encode(input(usr,"What is the vote for?") as text|null)
if(!question) return 0
for(var/i=1,i<=10,i++)
var/option = capitalize(html_encode(input(usr,"Please enter an option or hit cancel to finish") as text|null))
if(!option || mode || !usr.client) break
choices.Add(option)
else
return 0
mode = vote_type
initiator = initiator_key
started_time = world.time
var/text = "[capitalize(mode)] vote started by [initiator]."
if(mode == "custom")
text += "\n[question]"
if(usr)
log_admin("[capitalize(mode)] ([question]) vote started by [key_name(usr)].")
else if(usr)
log_admin("[capitalize(mode)] vote started by [key_name(usr)].")
log_vote(text)
to_chat(world, {"<font color='purple'><b>[text]</b>
<a href='?src=[UID()];vote=open'>Click here or type vote to place your vote.</a>
You have [config.vote_period/10] seconds to vote.</font>"})
switch(vote_type)
if("crew_transfer")
world << sound('sound/ambience/alarm4.ogg')
if("gamemode")
world << sound('sound/ambience/alarm4.ogg')
if("custom")
world << sound('sound/ambience/alarm4.ogg')
if(mode == "gamemode" && going)
going = 0
to_chat(world, "<font color='red'><b>Round start has been delayed.</b></font>")
if(mode == "crew_transfer" && config.ooc_allowed)
auto_muted = 1
config.ooc_allowed = !( config.ooc_allowed )
to_chat(world, "<b>The OOC channel has been automatically disabled due to a crew transfer vote.</b>")
log_admin("OOC was toggled automatically due to crew_transfer vote.")
message_admins("OOC has been toggled off automatically.")
if(mode == "gamemode" && config.ooc_allowed)
auto_muted = 1
config.ooc_allowed = !( config.ooc_allowed )
to_chat(world, "<b>The OOC channel has been automatically disabled due to the gamemode vote.</b>")
log_admin("OOC was toggled automatically due to gamemode vote.")
message_admins("OOC has been toggled off automatically.")
if(mode == "custom" && config.ooc_allowed)
auto_muted = 1
config.ooc_allowed = !( config.ooc_allowed )
to_chat(world, "<b>The OOC channel has been automatically disabled due to a custom vote.</b>")
log_admin("OOC was toggled automatically due to custom vote.")
message_admins("OOC has been toggled off automatically.")
time_remaining = round(config.vote_period/10)
return 1
return 0
/datum/controller/subsystem/vote/proc/browse_to(var/client/C)
if(!C)
return
var/admin = check_rights(R_ADMIN, 0, user = C.mob)
voting |= C
var/dat = {"<script>
function update_vote_div(new_content) {
var votediv = document.getElementById("vote_div");
if(votediv) {
votediv.innerHTML = new_content;
}
}
</script>"}
if(mode)
dat += "<div id='vote_div'>[vote_html(C)]</div><hr>"
if(admin)
dat += "(<a href='?src=[UID()];vote=cancel'>Cancel Vote</a>) "
else
dat += "<div id='vote_div'><h2>Start a vote:</h2><hr><ul><li>"
//restart
if(admin || config.allow_vote_restart)
dat += "<a href='?src=[UID()];vote=restart'>Restart</a>"
else
dat += "<font color='grey'>Restart (Disallowed)</font>"
dat += "</li><li>"
if(admin || config.allow_vote_restart)
dat += "<a href='?src=[UID()];vote=crew_transfer'>Crew Transfer</a>"
else
dat += "<font color='grey'>Crew Transfer (Disallowed)</font>"
if(admin)
dat += "\t(<a href='?src=[UID()];vote=toggle_restart'>[config.allow_vote_restart?"Allowed":"Disallowed"]</a>)"
dat += "</li><li>"
//gamemode
if(admin || config.allow_vote_mode)
dat += "<a href='?src=[UID()];vote=gamemode'>GameMode</a>"
else
dat += "<font color='grey'>GameMode (Disallowed)</font>"
if(admin)
dat += "\t(<a href='?src=[UID()];vote=toggle_gamemode'>[config.allow_vote_mode?"Allowed":"Disallowed"]</a>)"
dat += "</li>"
//custom
if(admin)
dat += "<li><a href='?src=[UID()];vote=custom'>Custom</a></li>"
dat += "</ul></div><hr>"
var/datum/browser/popup = new(C.mob, "vote", "Voting Panel", nref=src)
popup.set_content(dat)
popup.open()
/datum/controller/subsystem/vote/proc/update_panel(var/client/C)
C << output(url_encode(vote_html(C)), "vote.browser:update_vote_div")
/datum/controller/subsystem/vote/proc/vote_html(var/client/C)
. = ""
if(question)
. += "<h2>Vote: '[question]'</h2>"
else
. += "<h2>Vote: [capitalize(mode)]</h2>"
. += "Time Left: [time_remaining] s<hr><ul>"
for(var/i = 1, i <= choices.len, i++)
var/votes = choices[choices[i]]
if(!votes)
votes = 0
if(current_votes[C.ckey] == i)
. += "<li><b><a href='?src=[UID()];vote=[i]'>[choices[i]] ([votes] vote\s)</a></b></li>"
else
. += "<li><a href='?src=[UID()];vote=[i]'>[choices[i]] ([votes] vote\s)</a></li>"
. += "</ul>"
/datum/controller/subsystem/vote/Topic(href,href_list[],hsrc)
if(!usr || !usr.client)
return //not necessary but meh...just in-case somebody does something stupid
var/admin = check_rights(R_ADMIN,0)
if(href_list["close"])
voting -= usr.client
return
switch(href_list["vote"])
if("open")
// vote proc will automatically get called after this switch ends
if("cancel")
if(admin && mode)
var/votedesc = capitalize(mode)
if(mode == "custom")
votedesc += " ([question])"
admin_log_and_message_admins("cancelled the running [votedesc] vote.")
reset()
if("toggle_restart")
if(admin)
config.allow_vote_restart = !config.allow_vote_restart
if("toggle_gamemode")
if(admin)
config.allow_vote_mode = !config.allow_vote_mode
if("restart")
if(config.allow_vote_restart || admin)
initiate_vote("restart",usr.key)
if("gamemode")
if(config.allow_vote_mode || admin)
initiate_vote("gamemode",usr.key)
if("crew_transfer")
if(config.allow_vote_restart || admin)
initiate_vote("crew_transfer",usr.key)
if("custom")
if(admin)
initiate_vote("custom",usr.key)
else
submit_vote(usr.ckey, round(text2num(href_list["vote"])))
update_panel(usr.client)
return
usr.vote()
/mob/verb/vote()
set category = "OOC"
set name = "Vote"
if(SSvote)
SSvote.browse_to(client)
SUBSYSTEM_DEF(vote)
name = "Vote"
wait = 10
flags = SS_KEEP_TIMING|SS_NO_INIT
runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
var/initiator = null
var/started_time = null
var/time_remaining = 0
var/mode = null
var/question = null
var/list/choices = list()
var/list/voted = list()
var/list/voting = list()
var/list/current_votes = list()
var/list/round_voters = list()
var/auto_muted = 0
/datum/controller/subsystem/vote/fire()
if(mode)
// No more change mode votes after the game has started.
if(mode == "gamemode" && SSticker.current_state >= GAME_STATE_SETTING_UP)
to_chat(world, "<b>Voting aborted due to game start.</b>")
reset()
return
// Calculate how much time is remaining by comparing current time, to time of vote start,
// plus vote duration
time_remaining = round((started_time + config.vote_period - world.time)/10)
if(time_remaining < 0)
result()
for(var/client/C in voting)
if(C)
C << browse(null,"window=vote")
reset()
else
for(var/client/C in voting)
update_panel(C)
CHECK_TICK
/datum/controller/subsystem/vote/proc/autotransfer()
initiate_vote("crew_transfer","the server")
/datum/controller/subsystem/vote/proc/reset()
initiator = null
time_remaining = 0
mode = null
question = null
choices.Cut()
voted.Cut()
voting.Cut()
current_votes.Cut()
if(auto_muted && !config.ooc_allowed && !(config.auto_toggle_ooc_during_round && SSticker.current_state == GAME_STATE_PLAYING))
auto_muted = 0
config.ooc_allowed = !( config.ooc_allowed )
to_chat(world, "<b>The OOC channel has been automatically enabled due to vote end.</b>")
log_admin("OOC was toggled automatically due to vote end.")
message_admins("OOC has been toggled on automatically.")
/datum/controller/subsystem/vote/proc/get_result()
var/greatest_votes = 0
var/total_votes = 0
var/list/sorted_choices = list()
var/sorted_highest
var/sorted_votes = -1
//get the highest number of votes, while also sorting the list
while(choices.len)
// This is a very inefficient sorting method, but that's okay
for(var/option in choices)
var/votes = choices[option]
if(sorted_votes < votes)
sorted_highest = option
sorted_votes = votes
if(votes > greatest_votes)
greatest_votes = votes
sorted_votes = -1
total_votes += choices[sorted_highest]
sorted_choices[sorted_highest] = choices[sorted_highest] || 0
choices -= sorted_highest
choices = sorted_choices
//default-vote for everyone who didn't vote
if(!config.vote_no_default && choices.len)
var/non_voters = (GLOB.clients.len - total_votes)
if(non_voters > 0)
if(mode == "restart")
choices["Continue Playing"] += non_voters
if(choices["Continue Playing"] >= greatest_votes)
greatest_votes = choices["Continue Playing"]
else if(mode == "gamemode")
if(master_mode in choices)
choices[master_mode] += non_voters
if(choices[master_mode] >= greatest_votes)
greatest_votes = choices[master_mode]
else if(mode == "crew_transfer")
var/factor = 0.5
switch(world.time / (10 * 60)) // minutes
if(0 to 60)
factor = 0.5
if(61 to 120)
factor = 0.8
if(121 to 240)
factor = 1
if(241 to 300)
factor = 1.2
else
factor = 1.4
choices["Initiate Crew Transfer"] = round(choices["Initiate Crew Transfer"] * factor)
to_chat(world, "<font color='purple'>Crew Transfer Factor: [factor]</font>")
greatest_votes = max(choices["Initiate Crew Transfer"], choices["Continue The Round"])
//get all options with that many votes and return them in a list
. = list()
if(greatest_votes)
for(var/option in choices)
if(choices[option] == greatest_votes)
. += option
return .
/datum/controller/subsystem/vote/proc/announce_result()
var/list/winners = get_result()
var/text
if(winners.len > 0)
if(winners.len > 1)
if(mode != "gamemode" || SSticker.hide_mode == 0) // Here we are making sure we don't announce potential game modes
text = "<b>Vote Tied Between:</b>\n"
for(var/option in winners)
text += "\t[option]\n"
. = pick(winners)
for(var/key in current_votes)
if(choices[current_votes[key]] == .)
round_voters += key // Keep track of who voted for the winning round.
if(mode == "gamemode" && (. == "extended" || SSticker.hide_mode == 0)) // Announce Extended gamemode, but not other gamemodes
text += "<b>Vote Result: [.] ([choices[.]] vote\s)</b>"
else
if(mode == "custom")
// Completely replace text to show all results in custom votes
text = "<b><span style='text-decoration: underline;'>[question]</span></b>\n"
for(var/option in winners)
text += "\t<b>[option]: [choices[option]] vote\s</b>\n"
for(var/option in (choices-winners))
text += "\t[option]: [choices[option]] vote\s\n"
else if(mode != "gamemode")
text += "<b>Vote Result: [.] ([choices[.]] vote\s)</b>"
else
text += "<b>The vote has ended.</b>" // What will be shown if it is a gamemode vote that isn't extended
else
text += "<b>Vote Result: Inconclusive - No Votes!</b>"
log_vote(text)
to_chat(world, "<font color='purple'>[text]</font>")
return .
/datum/controller/subsystem/vote/proc/result()
. = announce_result()
var/restart = 0
if(.)
switch(mode)
if("restart")
if(. == "Restart Round")
restart = 1
if("gamemode")
if(master_mode != .)
world.save_mode(.)
if(SSticker && SSticker.mode)
restart = 1
else
master_mode = .
if(!going)
going = 1
to_chat(world, "<font color='red'><b>The round will start soon.</b></font>")
if("crew_transfer")
if(. == "Initiate Crew Transfer")
init_shift_change(null, 1)
if(restart)
world.Reboot("Restart vote successful.", "end_error", "restart vote")
return .
/datum/controller/subsystem/vote/proc/submit_vote(var/ckey, var/vote)
if(mode)
if(config.vote_no_dead && usr.stat == DEAD && !usr.client.holder)
return 0
if(current_votes[ckey])
choices[choices[current_votes[ckey]]]--
if(vote && 1<=vote && vote<=choices.len)
voted += usr.ckey
choices[choices[vote]]++ //check this
current_votes[ckey] = vote
return vote
return 0
/datum/controller/subsystem/vote/proc/initiate_vote(var/vote_type, var/initiator_key)
if(!mode)
if(started_time != null && !check_rights(R_ADMIN))
var/next_allowed_time = (started_time + config.vote_delay)
if(next_allowed_time > world.time)
return 0
reset()
switch(vote_type)
if("restart")
choices.Add("Restart Round","Continue Playing")
if("gamemode")
if(SSticker.current_state >= 2)
return 0
choices.Add(config.votable_modes)
if("crew_transfer")
if(check_rights(R_ADMIN|R_MOD))
if(SSticker.current_state <= 2)
return 0
question = "End the shift?"
choices.Add("Initiate Crew Transfer", "Continue The Round")
else
if(SSticker.current_state <= 2)
return 0
question = "End the shift?"
choices.Add("Initiate Crew Transfer", "Continue The Round")
if("custom")
question = html_encode(input(usr,"What is the vote for?") as text|null)
if(!question) return 0
for(var/i=1,i<=10,i++)
var/option = capitalize(html_encode(input(usr,"Please enter an option or hit cancel to finish") as text|null))
if(!option || mode || !usr.client) break
choices.Add(option)
else
return 0
mode = vote_type
initiator = initiator_key
started_time = world.time
var/text = "[capitalize(mode)] vote started by [initiator]."
if(mode == "custom")
text += "\n[question]"
if(usr)
log_admin("[capitalize(mode)] ([question]) vote started by [key_name(usr)].")
else if(usr)
log_admin("[capitalize(mode)] vote started by [key_name(usr)].")
log_vote(text)
to_chat(world, {"<font color='purple'><b>[text]</b>
<a href='?src=[UID()];vote=open'>Click here or type vote to place your vote.</a>
You have [config.vote_period/10] seconds to vote.</font>"})
switch(vote_type)
if("crew_transfer")
world << sound('sound/ambience/alarm4.ogg')
if("gamemode")
world << sound('sound/ambience/alarm4.ogg')
if("custom")
world << sound('sound/ambience/alarm4.ogg')
if(mode == "gamemode" && going)
going = 0
to_chat(world, "<font color='red'><b>Round start has been delayed.</b></font>")
if(mode == "crew_transfer" && config.ooc_allowed)
auto_muted = 1
config.ooc_allowed = !( config.ooc_allowed )
to_chat(world, "<b>The OOC channel has been automatically disabled due to a crew transfer vote.</b>")
log_admin("OOC was toggled automatically due to crew_transfer vote.")
message_admins("OOC has been toggled off automatically.")
if(mode == "gamemode" && config.ooc_allowed)
auto_muted = 1
config.ooc_allowed = !( config.ooc_allowed )
to_chat(world, "<b>The OOC channel has been automatically disabled due to the gamemode vote.</b>")
log_admin("OOC was toggled automatically due to gamemode vote.")
message_admins("OOC has been toggled off automatically.")
if(mode == "custom" && config.ooc_allowed)
auto_muted = 1
config.ooc_allowed = !( config.ooc_allowed )
to_chat(world, "<b>The OOC channel has been automatically disabled due to a custom vote.</b>")
log_admin("OOC was toggled automatically due to custom vote.")
message_admins("OOC has been toggled off automatically.")
time_remaining = round(config.vote_period/10)
return 1
return 0
/datum/controller/subsystem/vote/proc/browse_to(var/client/C)
if(!C)
return
var/admin = check_rights(R_ADMIN, 0, user = C.mob)
voting |= C
var/dat = {"<script>
function update_vote_div(new_content) {
var votediv = document.getElementById("vote_div");
if(votediv) {
votediv.innerHTML = new_content;
}
}
</script>"}
if(mode)
dat += "<div id='vote_div'>[vote_html(C)]</div><hr>"
if(admin)
dat += "(<a href='?src=[UID()];vote=cancel'>Cancel Vote</a>) "
else
dat += "<div id='vote_div'><h2>Start a vote:</h2><hr><ul><li>"
//restart
if(admin || config.allow_vote_restart)
dat += "<a href='?src=[UID()];vote=restart'>Restart</a>"
else
dat += "<font color='grey'>Restart (Disallowed)</font>"
dat += "</li><li>"
if(admin || config.allow_vote_restart)
dat += "<a href='?src=[UID()];vote=crew_transfer'>Crew Transfer</a>"
else
dat += "<font color='grey'>Crew Transfer (Disallowed)</font>"
if(admin)
dat += "\t(<a href='?src=[UID()];vote=toggle_restart'>[config.allow_vote_restart?"Allowed":"Disallowed"]</a>)"
dat += "</li><li>"
//gamemode
if(admin || config.allow_vote_mode)
dat += "<a href='?src=[UID()];vote=gamemode'>GameMode</a>"
else
dat += "<font color='grey'>GameMode (Disallowed)</font>"
if(admin)
dat += "\t(<a href='?src=[UID()];vote=toggle_gamemode'>[config.allow_vote_mode?"Allowed":"Disallowed"]</a>)"
dat += "</li>"
//custom
if(admin)
dat += "<li><a href='?src=[UID()];vote=custom'>Custom</a></li>"
dat += "</ul></div><hr>"
var/datum/browser/popup = new(C.mob, "vote", "Voting Panel", nref=src)
popup.set_content(dat)
popup.open()
/datum/controller/subsystem/vote/proc/update_panel(var/client/C)
C << output(url_encode(vote_html(C)), "vote.browser:update_vote_div")
/datum/controller/subsystem/vote/proc/vote_html(var/client/C)
. = ""
if(question)
. += "<h2>Vote: '[question]'</h2>"
else
. += "<h2>Vote: [capitalize(mode)]</h2>"
. += "Time Left: [time_remaining] s<hr><ul>"
for(var/i = 1, i <= choices.len, i++)
var/votes = choices[choices[i]]
if(!votes)
votes = 0
if(current_votes[C.ckey] == i)
. += "<li><b><a href='?src=[UID()];vote=[i]'>[choices[i]] ([votes] vote\s)</a></b></li>"
else
. += "<li><a href='?src=[UID()];vote=[i]'>[choices[i]] ([votes] vote\s)</a></li>"
. += "</ul>"
/datum/controller/subsystem/vote/Topic(href,href_list[],hsrc)
if(!usr || !usr.client)
return //not necessary but meh...just in-case somebody does something stupid
var/admin = check_rights(R_ADMIN,0)
if(href_list["close"])
voting -= usr.client
return
switch(href_list["vote"])
if("open")
// vote proc will automatically get called after this switch ends
if("cancel")
if(admin && mode)
var/votedesc = capitalize(mode)
if(mode == "custom")
votedesc += " ([question])"
admin_log_and_message_admins("cancelled the running [votedesc] vote.")
reset()
if("toggle_restart")
if(admin)
config.allow_vote_restart = !config.allow_vote_restart
if("toggle_gamemode")
if(admin)
config.allow_vote_mode = !config.allow_vote_mode
if("restart")
if(config.allow_vote_restart || admin)
initiate_vote("restart",usr.key)
if("gamemode")
if(config.allow_vote_mode || admin)
initiate_vote("gamemode",usr.key)
if("crew_transfer")
if(config.allow_vote_restart || admin)
initiate_vote("crew_transfer",usr.key)
if("custom")
if(admin)
initiate_vote("custom",usr.key)
else
submit_vote(usr.ckey, round(text2num(href_list["vote"])))
update_panel(usr.client)
return
usr.vote()
/mob/verb/vote()
set category = "OOC"
set name = "Vote"
if(SSvote)
SSvote.browse_to(client)
+1 -1
View File
@@ -80,4 +80,4 @@ SUBSYSTEM_DEF(weather)
if((z in W.impacted_z_levels) && W.area_type == active_area.type)
A = W
break
return A
return A