mirror of
https://github.com/PolarisSS13/Polaris.git
synced 2026-01-05 23:12:26 +00:00
Cleans up stuff.
This commit is contained in:
@@ -1,6 +0,0 @@
|
||||
/datum/controller/process/game_master/setup()
|
||||
name = "\improper GM controller"
|
||||
schedule_interval = 600 // every 60 seconds
|
||||
|
||||
/datum/controller/process/game_master/doWork()
|
||||
game_master.process()
|
||||
@@ -1,402 +0,0 @@
|
||||
// This is a sort of successor to the various event systems created over the years. It is designed to be just a tad smarter than the
|
||||
// previous ones, checking various things like player count, department size and composition, individual player activity,
|
||||
// individual player (IC) skill, and such, in order to try to choose the best actions to take in order to add spice or variety to
|
||||
// the round.
|
||||
|
||||
SUBSYSTEM_DEF(game_master_old)
|
||||
name = "Events (Game Master)"
|
||||
wait = 2 SECONDS
|
||||
init_order = INIT_ORDER_GAME_MASTER
|
||||
flags = SS_KEEP_TIMING
|
||||
runlevels = RUNLEVEL_GAME
|
||||
|
||||
// List of `/datum/event2/event`s that are currently active, and receiving process() ticks.
|
||||
var/list/active_events = list()
|
||||
|
||||
// List of `/datum/event2/event`s that finished, and are here for showing at roundend, if that's desired.
|
||||
var/list/finished_events = list()
|
||||
|
||||
// List of `/datum/event2/meta`s that hold meta-information about events.
|
||||
var/list/all_meta_events = list()
|
||||
|
||||
var/list/available_actions = list() // A list of 'actions' that the GM has access to, to spice up a round, such as events.
|
||||
var/danger = 0 // The GM's best guess at how chaotic the round is. High danger makes it hold back.
|
||||
var/staleness = -20 // Determines liklihood of the GM doing something, increases over time.
|
||||
|
||||
// Multiplier for how much 'danger' is accumulated. Higer generally makes it possible for more dangerous events to be picked.
|
||||
var/danger_modifier = 1.0
|
||||
|
||||
// Ditto. Higher numbers generally result in more events occuring in a round.
|
||||
var/staleness_modifier = 1.0
|
||||
|
||||
// If an event was done for a specific department, it is written here, so it doesn't do it again.
|
||||
var/last_department_used = null
|
||||
|
||||
var/next_action = 0 // Minimum amount of time of nothingness until the GM can pick something again.
|
||||
var/decision_cooldown_lower_bound = 5 MINUTES // Lower bound for how long to wait until -the potential- for another action being decided.
|
||||
var/decision_cooldown_upper_bound = 20 MINUTES // Same, but upper bound.
|
||||
|
||||
var/ignore_time_restrictions = FALSE// Useful for debugging without needing to wait 20 minutes each time.
|
||||
var/ignore_round_chaos = FALSE // If true, the system will happily choose back to back intense events like meteors and blobs, Dwarf Fortress style.
|
||||
|
||||
/datum/controller/subsystem/game_master/Initialize()
|
||||
// available_actions = init_subtypes(/datum/gm_action)
|
||||
// for(var/A in available_actions)
|
||||
// var/datum/gm_action/action = A
|
||||
// action.gm = src
|
||||
|
||||
var/list/subtypes = subtypesof(/datum/event2/meta)
|
||||
for(var/T in subtypes)
|
||||
var/datum/event2/meta/M = new T(src)
|
||||
all_meta_events += M
|
||||
|
||||
if(config && !config.enable_game_master)
|
||||
can_fire = FALSE
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/game_master/fire(resumed)
|
||||
// Process active events.
|
||||
for(var/E in active_events)
|
||||
var/datum/event2/event/event = E
|
||||
event.process()
|
||||
if(event.finished)
|
||||
event_finished(event)
|
||||
|
||||
// Decide if a new event is a good idea, and if so, which one.
|
||||
if(times_fired % (1 MINUTE / wait) == 0) // Run once a minute, even if `wait` gets changed in the future or something.
|
||||
adjust_staleness(1)
|
||||
adjust_danger(-1)
|
||||
|
||||
var/global_afk = metric.assess_all_living_mobs()
|
||||
global_afk = abs(global_afk - 100)
|
||||
global_afk = round(global_afk / 100, 0.1)
|
||||
adjust_staleness(global_afk) // Staleness increases faster if more people are less active.
|
||||
|
||||
if(ignore_time_restrictions || next_action < world.time)
|
||||
if(prob(staleness) && pre_action_checks())
|
||||
log_debug("Game Master is going to start something.")
|
||||
start_action()
|
||||
|
||||
/datum/controller/subsystem/game_master/proc/event_started(datum/event2/event/E)
|
||||
active_events += E
|
||||
|
||||
/datum/controller/subsystem/game_master/proc/event_finished(datum/event2/event/E)
|
||||
active_events -= E
|
||||
finished_events += E
|
||||
|
||||
|
||||
// These are ran before committing to an action or event.
|
||||
// Returns TRUE if the system is allowed to procede, otherwise returns FALSE.
|
||||
/datum/controller/subsystem/game_master/proc/pre_action_checks(quiet = FALSE)
|
||||
if(!ticker || ticker.current_state != GAME_STATE_PLAYING)
|
||||
if(!quiet)
|
||||
log_debug("Game Master unable to start event: Ticker is nonexistant, or the game is not ongoing.")
|
||||
return FALSE
|
||||
if(ignore_time_restrictions)
|
||||
return TRUE
|
||||
if(next_action > world.time) // Sanity.
|
||||
if(!quiet)
|
||||
log_debug("Game Master unable to start event: Time until next action is approximately [round((next_action - world.time) / (1 MINUTE))] minute(s)")
|
||||
return FALSE
|
||||
|
||||
// Last minute antagging is bad for humans to do, so the GM will respect the start and end of the round.
|
||||
var/mills = round_duration_in_ticks
|
||||
var/mins = round((mills % 36000) / 600)
|
||||
var/hours = round(mills / 36000)
|
||||
|
||||
// if(hours < 1 && mins <= 20) // Don't do anything for the first twenty minutes of the round.
|
||||
// if(!quiet)
|
||||
// log_debug("Game Master unable to start event: It is too early.")
|
||||
// return FALSE
|
||||
if(hours >= 2 && mins >= 40) // Don't do anything in the last twenty minutes of the round, as well.
|
||||
if(!quiet)
|
||||
log_debug("Game Master unable to start event: It is too late.")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/controller/subsystem/game_master/proc/start_action()
|
||||
log_debug("Game Master now starting action decision.")
|
||||
|
||||
var/list/most_active_departments = metric.assess_all_departments(3, list(last_department_used))
|
||||
var/list/best_actions = decide_best_action(most_active_departments)
|
||||
|
||||
if(best_actions && best_actions.len)
|
||||
var/list/weighted_actions = list()
|
||||
|
||||
for(var/A in best_actions)
|
||||
var/datum/gm_action/action = A
|
||||
if(danger >= action.chaos_threshold)
|
||||
continue // We skip dangerous events when bad stuff is already occuring.
|
||||
weighted_actions[action] = action.get_weight()
|
||||
|
||||
var/datum/gm_action/choice = pickweight(weighted_actions)
|
||||
|
||||
if(choice)
|
||||
log_debug("[choice.name] was chosen by the Game Master, and is now being ran.")
|
||||
run_action(choice)
|
||||
|
||||
/datum/controller/subsystem/game_master/proc/run_action(datum/gm_action/action)
|
||||
log_debug("[action.name] is being ran.")
|
||||
action.set_up()
|
||||
action.start()
|
||||
action.announce()
|
||||
if(action.chaotic)
|
||||
danger += action.chaotic
|
||||
|
||||
next_action = world.time + rand(decision_cooldown_lower_bound, decision_cooldown_upper_bound)
|
||||
last_department_used = LAZYACCESS(action.departments, 1)
|
||||
|
||||
/datum/controller/subsystem/game_master/proc/decide_best_action(list/most_active_departments)
|
||||
if(!LAZYLEN(most_active_departments))// Server's empty?
|
||||
log_debug("Game Master failed to find any active departments.")
|
||||
return list()
|
||||
|
||||
var/list/best_actions = list() // List of actions which involve the most active departments.
|
||||
if(most_active_departments.len >= 2)
|
||||
for(var/A in available_actions)
|
||||
var/datum/gm_action/action = A
|
||||
if(!action.enabled)
|
||||
continue
|
||||
// Try to incorporate an action with the top two departments first.
|
||||
if(most_active_departments[1] in action.departments && most_active_departments[2] in action.departments)
|
||||
best_actions.Add(action)
|
||||
log_debug("[action.name] is being considered because both most active departments are involved.")
|
||||
|
||||
if(best_actions.len) // We found something for those two, let's do it.
|
||||
return best_actions
|
||||
|
||||
// Otherwise we probably couldn't find something for the second highest group, so let's ignore them.
|
||||
for(var/A in available_actions)
|
||||
var/datum/gm_action/action = A
|
||||
if(!action.enabled)
|
||||
continue
|
||||
if(most_active_departments[1] in action.departments)
|
||||
best_actions.Add(action)
|
||||
log_debug("[action.name] is being considered because the most active department is involved.")
|
||||
|
||||
if(best_actions.len) // Found something for the one guy.
|
||||
return best_actions
|
||||
|
||||
// At this point we should expand our horizons.
|
||||
for(var/A in available_actions)
|
||||
var/datum/gm_action/action = A
|
||||
if(!action.enabled)
|
||||
continue
|
||||
if(DEPARTMENT_EVERYONE in action.departments)
|
||||
best_actions.Add(action)
|
||||
log_debug("[action.name] is being considered because it involves everyone.")
|
||||
|
||||
if(best_actions.len) // Finally, perhaps?
|
||||
return best_actions
|
||||
|
||||
// Just give a random event if for some reason it still can't make up its mind.
|
||||
for(var/A in available_actions)
|
||||
var/datum/gm_action/action = A
|
||||
if(!action.enabled)
|
||||
continue
|
||||
best_actions.Add(action)
|
||||
log_debug("[action.name] is being considered because everything else failed.")
|
||||
|
||||
if(best_actions.len) // Finally, perhaps?
|
||||
return best_actions
|
||||
|
||||
log_debug("Game Master failed to find a suitable event, something very wrong is going on.")
|
||||
return list()
|
||||
|
||||
|
||||
// Tell the game master that something dangerous happened, e.g. someone dying, station explosions.
|
||||
/datum/controller/subsystem/game_master/proc/adjust_danger(amount)
|
||||
amount *= danger_modifier
|
||||
danger = round(between(0, danger + amount, 1000), 0.1)
|
||||
|
||||
// Tell the game master that things are getting boring if positive, or something interesting if negative..
|
||||
/datum/controller/subsystem/game_master/proc/adjust_staleness(amount)
|
||||
amount *= staleness_modifier
|
||||
staleness = round( between(-20, staleness + amount, 100), 0.1)
|
||||
|
||||
|
||||
/*
|
||||
Admin UI
|
||||
*/
|
||||
|
||||
/client/proc/show_gm_status()
|
||||
set category = "Debug"
|
||||
set name = "Show GM Status"
|
||||
set desc = "Shows you what the GM is thinking. If only that existed in real life..."
|
||||
|
||||
if(check_rights(R_ADMIN|R_EVENT|R_DEBUG))
|
||||
SSgame_master.interact(usr)
|
||||
else
|
||||
to_chat(usr, span("warning", "You do not have sufficent rights to view the GM panel, sorry."))
|
||||
|
||||
/datum/controller/subsystem/game_master/proc/interact(var/client/user)
|
||||
if(!user)
|
||||
return
|
||||
|
||||
// Using lists for string tree conservation.
|
||||
var/list/dat = list("<html><head><title>Automated Game Master Event System</title></head><body>")
|
||||
|
||||
// Makes the system turn on or off.
|
||||
dat += href(src, list("toggle" = 1), "\[Toggle GM\]")
|
||||
dat += " | "
|
||||
|
||||
// Makes the system not care about staleness or being near round-end.
|
||||
dat += href(src, list("toggle_time_restrictions" = 1), "\[Toggle Time Restrictions\]")
|
||||
dat += " | "
|
||||
|
||||
// Makes the system not care about how chaotic the round might be.
|
||||
dat += href(src, list("toggle_chaos_throttle" = 1), "\[Toggle Chaos Throttling\]")
|
||||
dat += " | "
|
||||
|
||||
// Makes the system immediately choose an event, while still bound to factors like danger, weights, and department staffing.
|
||||
dat += href(src, list("force_choose_event" = 1), "\[Force Event Decision\]")
|
||||
dat += "<br>"
|
||||
|
||||
dat += "State: [can_fire ? "Active": "Inactive"]<br>"
|
||||
dat += "Status: [pre_action_checks(TRUE) ? "Ready" : "Suppressed"]<br><br>"
|
||||
|
||||
dat += "Staleness: [staleness] "
|
||||
dat += href(src, list("set_staleness" = 1), "\[Set\]")
|
||||
dat += "<br>"
|
||||
dat += "<i>Staleness is an estimate of how boring the round might be, and if an event should be done. It is increased passively over time, \
|
||||
and increases faster if people are AFK. It deceases when events and certain 'interesting' things happen in the round.</i><br>"
|
||||
|
||||
dat += "Danger: [danger] "
|
||||
dat += href(src, list("set_danger" = 1), "\[Set\]")
|
||||
dat += "<br>"
|
||||
dat += "<i>Danger is an estimate of how chaotic the round has been so far. It is decreased passively over time, and is increased by having \
|
||||
certain chaotic events be selected, or chaotic things happen in the round. A sufficently high amount of danger will make the system \
|
||||
avoid using destructive events, to avoid pushing the station over the edge.</i><br>"
|
||||
|
||||
dat += "<h2>Player Activity:</h2>"
|
||||
|
||||
dat += "<table border='1' style='width:100%'>"
|
||||
dat += "<tr>"
|
||||
dat += "<th>Category</th>"
|
||||
dat += "<th>Activity Percentage</th>"
|
||||
dat += "</tr>"
|
||||
|
||||
dat += "<tr>"
|
||||
dat += "<td>All Living Mobs</td>"
|
||||
dat += "<td>[metric.assess_all_living_mobs()]%</td>"
|
||||
dat += "</tr>"
|
||||
|
||||
dat += "<tr>"
|
||||
dat += "<td>All Ghosts</td>"
|
||||
dat += "<td>[metric.assess_all_dead_mobs()]%</td>"
|
||||
dat += "</tr>"
|
||||
|
||||
dat += "<tr>"
|
||||
dat += "<th colspan='2'>Departments</td>"
|
||||
dat += "</tr>"
|
||||
|
||||
for(var/D in metric.departments)
|
||||
dat += "<tr>"
|
||||
dat += "<td>[D]</td>"
|
||||
dat += "<td>[metric.assess_department(D)]%</td>"
|
||||
dat += "</tr>"
|
||||
|
||||
dat += "<tr>"
|
||||
dat += "<th colspan='2'>Players</td>"
|
||||
dat += "</tr>"
|
||||
|
||||
for(var/P in player_list)
|
||||
var/mob/M = P
|
||||
dat += "<tr>"
|
||||
dat += "<td>[M] ([M.ckey])</td>"
|
||||
dat += "<td>[metric.assess_player_activity(M)]%</td>"
|
||||
dat += "</tr>"
|
||||
|
||||
dat += "</table>"
|
||||
|
||||
dat += "<h2>Actions available:</h2>"
|
||||
dat += "<table border='1' style='width:100%'>"
|
||||
|
||||
dat += "<tr>"
|
||||
dat += "<th>Action Name</th>"
|
||||
dat += "<th>Involved Departments</th>"
|
||||
dat += "<th>Chaos</th>"
|
||||
dat += "<th>Current Weight</th>"
|
||||
dat += "<th>Buttons</th>"
|
||||
dat += "</tr>"
|
||||
|
||||
for(var/A in available_actions)
|
||||
var/datum/gm_action/action = A
|
||||
dat += "<tr>"
|
||||
dat += "<td>[action.name]</td>"
|
||||
dat += "<td>[english_list(action.departments)]</td>"
|
||||
dat += "<td>[action.chaotic]</td>"
|
||||
dat += "<td>[action.get_weight()]</td>"
|
||||
dat += "<td>[href(action, list("force" = 1), "\[Force\]")] [href(action, list("toggle" = 1), "\[Toggle\]")]</td>"
|
||||
dat += "</tr>"
|
||||
|
||||
dat += "</table>"
|
||||
|
||||
dat += "</body></html>"
|
||||
|
||||
var/datum/browser/popup = new(user, "game_master_debug", "Automated Game Master Event System", 800, 500, src)
|
||||
popup.set_content(dat.Join())
|
||||
popup.open()
|
||||
|
||||
// HTML += "Actions available;<br>"
|
||||
// for(var/datum/gm_action/action in available_actions)
|
||||
// if(action.enabled == FALSE)
|
||||
// continue
|
||||
// HTML += "[action.name] ([english_list(action.departments)]) (weight: [action.get_weight()]) <a href='?src=\ref[action];force=1'>\[Force\]</a> <br>"
|
||||
|
||||
// HTML += "<br>"
|
||||
// HTML += "All living mobs activity: [metric.assess_all_living_mobs()]%<br>"
|
||||
// HTML += "All ghost activity: [metric.assess_all_dead_mobs()]%<br>"
|
||||
//
|
||||
// HTML += "<br>"
|
||||
// HTML += "Departmental activity;<br>"
|
||||
// for(var/department in metric.departments)
|
||||
// HTML += " [department] : [metric.assess_department(department)]%<br>"
|
||||
//
|
||||
// HTML += "<br>"
|
||||
// HTML += "Activity of players;<br>"
|
||||
// for(var/mob/player in player_list)
|
||||
// HTML += " [player] ([player.key]) : [metric.assess_player_activity(player)]%<br>"
|
||||
//
|
||||
// HTML +="</body></html>"
|
||||
// user << browse(HTML, "window=log;size=400x450;border=1;can_resize=1;can_close=1;can_minimize=1")
|
||||
|
||||
|
||||
/datum/controller/subsystem/game_master/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
|
||||
if(!check_rights(R_ADMIN|R_EVENT|R_DEBUG))
|
||||
message_admins("[usr] has attempted to modify the Game Master values without being an admin.")
|
||||
return
|
||||
|
||||
if(href_list["toggle"])
|
||||
can_fire = !can_fire
|
||||
message_admins("GM was [!can_fire ? "dis" : "en"]abled by [usr.key].")
|
||||
|
||||
if(href_list["toggle_time_restrictions"])
|
||||
ignore_time_restrictions = !ignore_time_restrictions
|
||||
message_admins("GM event time restrictions was [ignore_time_restrictions ? "dis" : "en"]abled by [usr.key].")
|
||||
|
||||
if(href_list["toggle_chaos_throttle"])
|
||||
ignore_round_chaos = !ignore_round_chaos
|
||||
message_admins("GM event chaos restrictions was [ignore_round_chaos ? "dis" : "en"]abled by [usr.key].")
|
||||
|
||||
if(href_list["force_choose_event"])
|
||||
start_action()
|
||||
message_admins("[usr.key] forced the Game Master to choose an event immediately.")
|
||||
|
||||
if(href_list["set_staleness"])
|
||||
var/amount = input(usr, "How much staleness should there be?", "Game Master") as null|num
|
||||
if(!isnull(amount))
|
||||
staleness = amount
|
||||
message_admins("GM staleness was set to [amount] by [usr.key].")
|
||||
|
||||
if(href_list["set_danger"])
|
||||
var/amount = input(usr, "How much danger should there be?", "Game Master") as null|num
|
||||
if(!isnull(amount))
|
||||
danger = amount
|
||||
message_admins("GM danger was set to [amount] by [usr.key].")
|
||||
|
||||
interact(usr) // To refresh the UI.
|
||||
@@ -107,7 +107,6 @@ var/gravity_is_on = 1
|
||||
|
||||
var/join_motd = null
|
||||
|
||||
var/datum/game_master/game_master = new() // Game Master, an AI for choosing events.
|
||||
var/datum/metric/metric = new() // Metric datum, used to keep track of the round.
|
||||
|
||||
var/list/awaydestinations = list() // Away missions. A list of landmarks that the warpgate can take you to.
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
/datum/gm_action
|
||||
var/name = "no name" // Simple name, for organization.
|
||||
var/enabled = TRUE // If not enabled, this action is never taken.
|
||||
var/departments = list() // What kinds of departments are affected by this action. Multiple departments can be listed.
|
||||
var/chaotic = 0 // A number showing how chaotic the action may be. If danger is high, the GM will avoid it.
|
||||
var/chaos_threshold = 0 // If the GM's danger score is at this number or higher, the event won't get picked.
|
||||
var/reusable = FALSE // If true, the event does not become disabled upon being used. Should be used sparingly.
|
||||
var/observers_used = FALSE // Determines if the GM should check if ghosts are available before using this.
|
||||
var/length = 0 // Determines how long the event lasts, until end() is called.
|
||||
var/datum/game_master/gm = null
|
||||
var/severity = 1 // The severity of the action. This is here to prevent continued future defining of this var on actions, un-used.
|
||||
|
||||
/datum/gm_action/proc/set_up()
|
||||
return
|
||||
|
||||
/datum/gm_action/proc/get_weight()
|
||||
return
|
||||
|
||||
/datum/gm_action/proc/start()
|
||||
if(!reusable)
|
||||
enabled = FALSE
|
||||
return
|
||||
|
||||
/datum/gm_action/proc/end()
|
||||
return
|
||||
|
||||
/datum/gm_action/proc/announce()
|
||||
return
|
||||
|
||||
/datum/gm_action/proc/should_end()
|
||||
return TRUE
|
||||
|
||||
/datum/gm_action/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
|
||||
if(!is_admin(usr))
|
||||
message_admins("[usr] has attempted to force an event without being an admin.")
|
||||
return
|
||||
|
||||
if(href_list["force"])
|
||||
// gm.run_action(src)
|
||||
message_admins("GM event [name] was forced by [usr.key].")
|
||||
|
||||
if(href_list["toggle"])
|
||||
enabled = !enabled
|
||||
message_admins("GM event [name] was toggled [enabled ? "on" : "off"] by [usr.key].")
|
||||
|
||||
SSgame_master.interact(usr) // To refresh the UI.
|
||||
@@ -1,77 +0,0 @@
|
||||
/datum/gm_action/atmos_leak
|
||||
name = "atmospherics leak"
|
||||
departments = list(DEPARTMENT_ENGINEERING, DEPARTMENT_SYNTHETIC)
|
||||
var/area/target_area // Chosen target area
|
||||
var/area/target_turf // Chosen target turf in target_area
|
||||
var/gas_type // Chosen gas to release
|
||||
// Exclude these types and sub-types from targeting eligibilty
|
||||
var/list/area/excluded = list(
|
||||
/area/submap,
|
||||
/area/shuttle,
|
||||
/area/crew_quarters,
|
||||
/area/holodeck,
|
||||
/area/engineering/engine_room
|
||||
)
|
||||
|
||||
severity
|
||||
|
||||
// Decide which area will be targeted!
|
||||
/datum/gm_action/atmos_leak/set_up()
|
||||
severity = pickweight(EVENT_LEVEL_MUNDANE = 8,
|
||||
EVENT_LEVEL_MODERATE = 5,
|
||||
EVENT_LEVEL_MAJOR = 3
|
||||
)
|
||||
|
||||
var/gas_choices = list("carbon_dioxide", "sleeping_agent") // Annoying
|
||||
if(severity >= EVENT_LEVEL_MODERATE)
|
||||
gas_choices += "phoron" // Dangerous
|
||||
if(severity >= EVENT_LEVEL_MAJOR)
|
||||
gas_choices += "volatile_fuel" // Dangerous and no default atmos setup!
|
||||
gas_type = pick(gas_choices)
|
||||
|
||||
var/list/area/grand_list_of_areas = get_station_areas(excluded)
|
||||
|
||||
// Okay, now lets try and pick a target! Lets try 10 times, otherwise give up
|
||||
for(var/i in 1 to 10)
|
||||
var/area/A = pick(grand_list_of_areas)
|
||||
if(is_area_occupied(A))
|
||||
log_debug("atmos_leak event: Rejected [A] because it is occupied.")
|
||||
continue
|
||||
// A good area, great! Lets try and pick a turf
|
||||
var/list/turfs = list()
|
||||
for(var/turf/simulated/floor/F in A)
|
||||
if(!check_density(F))
|
||||
turfs += F
|
||||
if(turfs.len == 0)
|
||||
log_debug("atmos_leak event: Rejected [A] because it has no clear turfs.")
|
||||
continue
|
||||
target_area = A
|
||||
target_turf = pick(turfs)
|
||||
|
||||
// If we can't find a good target, give up
|
||||
if(!target_area)
|
||||
log_debug("atmos_leak event: Giving up after too many failures to pick target area")
|
||||
return
|
||||
|
||||
/datum/gm_action/atmos_leak/announce()
|
||||
if(target_area)
|
||||
command_announcement.Announce("Warning, hazardous [gas_data.name[gas_type]] gas leak detected in \the [target_area], evacuate the area.", "Hazard Alert")
|
||||
|
||||
/datum/gm_action/atmos_leak/start()
|
||||
if(!target_turf)
|
||||
return
|
||||
..()
|
||||
spawn(rand(0, 600))
|
||||
// Okay, time to actually put the gas in the room!
|
||||
// TODO - Would be nice to break a waste pipe perhaps?
|
||||
// TODO - Maybe having it released from a single point and thus causing airflow to blow stuff around
|
||||
|
||||
// Fow now just add a bunch of it to the air
|
||||
var/datum/gas_mixture/air_contents = new
|
||||
air_contents.temperature = T20C + ((severity - 1) * rand(-50, 50))
|
||||
air_contents.gas[gas_type] = 10 * MOLES_CELLSTANDARD
|
||||
target_turf.assume_air(air_contents)
|
||||
playsound(target_turf, 'sound/effects/smoke.ogg', 50, 1)
|
||||
|
||||
/datum/gm_action/atmos_leak/get_weight()
|
||||
return 15 + (metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 10 + metric.count_people_in_department(DEPARTMENT_SYNTHETIC) * 30) // Synthetics are counted in higher value because they can wirelessly connect to alarms.
|
||||
@@ -1,74 +0,0 @@
|
||||
/datum/gm_action/blob
|
||||
name = "blob infestation"
|
||||
departments = list(DEPARTMENT_ENGINEERING, DEPARTMENT_SECURITY, DEPARTMENT_MEDICAL)
|
||||
chaotic = 25
|
||||
|
||||
var/list/area/excluded = list(
|
||||
/area/submap,
|
||||
/area/shuttle,
|
||||
/area/crew_quarters,
|
||||
/area/holodeck,
|
||||
/area/engineering/engine_room
|
||||
)
|
||||
|
||||
var/area/target_area // Chosen target area
|
||||
var/turf/target_turf // Chosen target turf in target_area
|
||||
|
||||
var/obj/structure/blob/core/Blob
|
||||
var/spawn_blob_type = /obj/structure/blob/core/random_medium
|
||||
|
||||
/datum/gm_action/blob/set_up()
|
||||
severity = pickweight(EVENT_LEVEL_MUNDANE = 4,
|
||||
EVENT_LEVEL_MODERATE = 2,
|
||||
EVENT_LEVEL_MAJOR = 1
|
||||
)
|
||||
|
||||
var/list/area/grand_list_of_areas = get_station_areas(excluded)
|
||||
|
||||
for(var/i in 1 to 10)
|
||||
var/area/A = pick(grand_list_of_areas)
|
||||
if(is_area_occupied(A))
|
||||
log_debug("Blob infestation event: Rejected [A] because it is occupied.")
|
||||
continue
|
||||
var/list/turfs = list()
|
||||
for(var/turf/simulated/floor/F in A)
|
||||
if(!check_density(F))
|
||||
turfs += F
|
||||
if(turfs.len == 0)
|
||||
log_debug("Blob infestation event: Rejected [A] because it has no clear turfs.")
|
||||
continue
|
||||
target_area = A
|
||||
target_turf = pick(turfs)
|
||||
|
||||
if(!target_area)
|
||||
log_debug("Blob infestation event: Giving up after too many failures to pick target area")
|
||||
|
||||
/datum/gm_action/blob/start()
|
||||
..()
|
||||
var/turf/T
|
||||
|
||||
if(severity == EVENT_LEVEL_MUNDANE || !target_area || !target_turf)
|
||||
T = pick(blobstart)
|
||||
else if(severity == EVENT_LEVEL_MODERATE)
|
||||
T = target_turf
|
||||
else
|
||||
T = target_turf
|
||||
spawn_blob_type = /obj/structure/blob/core/random_hard
|
||||
|
||||
Blob = new spawn_blob_type(T)
|
||||
|
||||
/datum/gm_action/blob/announce()
|
||||
spawn(rand(600, 3000)) // 1-5 minute leeway for the blob to go un-detected.
|
||||
command_announcement.Announce("Confirmed outbreak of level 7 biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", new_sound = 'sound/AI/outbreak7.ogg')
|
||||
|
||||
/datum/gm_action/blob/get_weight()
|
||||
var/engineers = metric.count_people_in_department(DEPARTMENT_ENGINEERING)
|
||||
var/security = metric.count_people_in_department(DEPARTMENT_SECURITY)
|
||||
var/medical = metric.count_people_in_department(DEPARTMENT_MEDICAL)
|
||||
|
||||
var/assigned_staff = engineers + security
|
||||
if(engineers || security) // Medical only counts if one of the other two exists, and even then they count as half.
|
||||
assigned_staff += round(medical / 2)
|
||||
|
||||
var/weight = (max(assigned_staff - 2, 0) * 20) // An assigned staff count of 2 must be had to spawn a blob.
|
||||
return weight
|
||||
@@ -1,69 +0,0 @@
|
||||
/datum/gm_action/brand_intelligence
|
||||
name = "rampant vending machines"
|
||||
length = 30 MINUTES
|
||||
departments = list(DEPARTMENT_ENGINEERING, DEPARTMENT_EVERYONE)
|
||||
|
||||
var/list/obj/machinery/vending/vendingMachines = list()
|
||||
var/list/obj/machinery/vending/infectedVendingMachines = list()
|
||||
var/obj/machinery/vending/originMachine
|
||||
var/start_time = 0
|
||||
|
||||
var/active = FALSE // Are we currently infecting?
|
||||
|
||||
/datum/gm_action/brand_intelligence/announce()
|
||||
if(prob(90))
|
||||
command_announcement.Announce("An ongoing mass upload of malware for vendors has been detected onboard [station_name()], which appears to transmit \
|
||||
to other nearby vendors. The original infected machine is believed to be \a [originMachine.name].", "Vendor Service Alert")
|
||||
|
||||
/datum/gm_action/brand_intelligence/set_up()
|
||||
vendingMachines.Cut()
|
||||
infectedVendingMachines.Cut()
|
||||
|
||||
for(var/obj/machinery/vending/V in machines)
|
||||
if(isNotStationLevel(V.z)) continue
|
||||
vendingMachines.Add(V)
|
||||
|
||||
if(!vendingMachines.len)
|
||||
length = 0
|
||||
return
|
||||
|
||||
originMachine = pick(vendingMachines)
|
||||
vendingMachines.Remove(originMachine)
|
||||
originMachine.shut_up = 0
|
||||
originMachine.shoot_inventory = 1
|
||||
|
||||
start_time = world.time
|
||||
active = TRUE
|
||||
|
||||
/datum/gm_action/brand_intelligence/start()
|
||||
..()
|
||||
while(originMachine || active)
|
||||
if(!vendingMachines.len || !originMachine || originMachine.shut_up) //if every machine is infected, or if the original vending machine is missing or has it's voice switch flipped
|
||||
end()
|
||||
return
|
||||
|
||||
if(ISMULTIPLE(world.time - start_time, 5))
|
||||
if(prob(15))
|
||||
var/obj/machinery/vending/infectedMachine = pick(vendingMachines)
|
||||
vendingMachines.Remove(infectedMachine)
|
||||
infectedVendingMachines.Add(infectedMachine)
|
||||
infectedMachine.shut_up = 0
|
||||
infectedMachine.shoot_inventory = 1
|
||||
|
||||
if(ISMULTIPLE(world.time - start_time, 12))
|
||||
originMachine.speak(pick("Try our aggressive new marketing strategies!", \
|
||||
"You should buy products to feed your lifestyle obsession!", \
|
||||
"Consume!", \
|
||||
"Your money can buy happiness!", \
|
||||
"Engage direct marketing!", \
|
||||
"Advertising is legalized lying! But don't let that put you off our great deals!", \
|
||||
"You don't want to buy anything? Yeah, well I didn't want to buy your mom either."))
|
||||
|
||||
/datum/gm_action/brand_intelligence/end()
|
||||
active = FALSE
|
||||
for(var/obj/machinery/vending/infectedMachine in infectedVendingMachines)
|
||||
infectedMachine.shut_up = 1
|
||||
infectedMachine.shoot_inventory = 0
|
||||
|
||||
/datum/gm_action/brand_intelligence/get_weight()
|
||||
return 60 + (metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 20)
|
||||
@@ -1,52 +0,0 @@
|
||||
/datum/gm_action/camera_damage
|
||||
name = "random camera damage"
|
||||
reusable = TRUE
|
||||
departments = list(DEPARTMENT_SYNTHETIC, DEPARTMENT_ENGINEERING)
|
||||
|
||||
/datum/gm_action/camera_damage/start()
|
||||
var/obj/machinery/camera/C = acquire_random_camera()
|
||||
if(!C)
|
||||
return
|
||||
..()
|
||||
|
||||
var/severity_range = 0
|
||||
severity = pickweight(EVENT_LEVEL_MUNDANE = 10,
|
||||
EVENT_LEVEL_MODERATE = 5,
|
||||
EVENT_LEVEL_MAJOR = 1
|
||||
)
|
||||
|
||||
switch(severity)
|
||||
if(EVENT_LEVEL_MUNDANE)
|
||||
severity_range = 0
|
||||
if(EVENT_LEVEL_MODERATE)
|
||||
severity_range = 7
|
||||
if(EVENT_LEVEL_MAJOR)
|
||||
severity_range = 15
|
||||
|
||||
for(var/obj/machinery/camera/cam in range(severity_range,C))
|
||||
if(is_valid_camera(cam))
|
||||
if(prob(2*severity))
|
||||
cam.destroy()
|
||||
else
|
||||
cam.wires.UpdateCut(CAMERA_WIRE_POWER, 0)
|
||||
if(prob(5*severity))
|
||||
cam.wires.UpdateCut(CAMERA_WIRE_ALARM, 0)
|
||||
|
||||
/datum/gm_action/camera_damage/proc/acquire_random_camera(var/remaining_attempts = 5)
|
||||
if(!cameranet.cameras.len)
|
||||
return
|
||||
if(!remaining_attempts)
|
||||
return
|
||||
|
||||
var/obj/machinery/camera/C = pick(cameranet.cameras)
|
||||
if(is_valid_camera(C))
|
||||
return C
|
||||
return acquire_random_camera(remaining_attempts--)
|
||||
|
||||
/datum/gm_action/camera_damage/proc/is_valid_camera(var/obj/machinery/camera/C)
|
||||
// Only return a functional camera, not installed in a silicon/hardsuit/circuit/etc, and that exists somewhere players have access
|
||||
var/turf/T = get_turf(C)
|
||||
return T && C.can_use() && istype(C.loc, /turf) && (T.z in using_map.player_levels)
|
||||
|
||||
/datum/gm_action/camera_damage/get_weight()
|
||||
return 40 + (metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 20) + (metric.count_people_in_department(DEPARTMENT_SYNTHETIC) * 40)
|
||||
@@ -1,24 +0,0 @@
|
||||
//
|
||||
// This event chooses a random canister on player levels and breaks it, releasing its contents!
|
||||
//
|
||||
|
||||
/datum/gm_action/canister_leak
|
||||
name = "Canister Leak"
|
||||
departments = list(DEPARTMENT_ENGINEERING)
|
||||
chaotic = 20
|
||||
|
||||
/datum/gm_action/canister_leak/get_weight()
|
||||
return metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 30
|
||||
|
||||
/datum/gm_action/canister_leak/start()
|
||||
..()
|
||||
// List of all non-destroyed canisters on station levels
|
||||
var/list/all_canisters = list()
|
||||
for(var/obj/machinery/portable_atmospherics/canister/C in machines)
|
||||
if(!C.destroyed && (C.z in using_map.station_levels) && C.air_contents.total_moles >= MOLES_CELLSTANDARD)
|
||||
all_canisters += C
|
||||
var/obj/machinery/portable_atmospherics/canister/C = pick(all_canisters)
|
||||
log_debug("canister_leak event: Canister [C] ([C.x],[C.y],[C.z]) destroyed.")
|
||||
C.health = 0
|
||||
C.healthcheck()
|
||||
return
|
||||
@@ -1,58 +0,0 @@
|
||||
//carp_migration
|
||||
/datum/gm_action/carp_migration
|
||||
name = "carp migration"
|
||||
departments = list(DEPARTMENT_SECURITY, DEPARTMENT_EVERYONE)
|
||||
chaotic = 50
|
||||
var/list/spawned_carp = list()
|
||||
var/carp_amount = 0
|
||||
length = 20 MINUTES
|
||||
|
||||
/datum/gm_action/carp_migration/get_weight()
|
||||
return 50 + (metric.count_people_in_department(DEPARTMENT_SECURITY) * 10) + (metric.count_all_space_mobs() * 20)
|
||||
|
||||
/datum/gm_action/carp_migration/announce()
|
||||
var/announcement = "Unknown biological entities have been detected near [station_name()], please stand-by."
|
||||
command_announcement.Announce(announcement, "Lifesign Alert")
|
||||
|
||||
/datum/gm_action/carp_migration/set_up()
|
||||
// Higher filled roles means more groups of fish.
|
||||
var/station_strength = 0
|
||||
station_strength += (metric.count_people_in_department(DEPARTMENT_SECURITY) * 3)
|
||||
station_strength += (metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 2)
|
||||
station_strength += metric.count_people_in_department(DEPARTMENT_MEDICAL)
|
||||
|
||||
// Less active emergency response departments tones the event down.
|
||||
var/activeness = ((metric.assess_department(DEPARTMENT_SECURITY) + metric.assess_department(DEPARTMENT_ENGINEERING) + metric.assess_department(DEPARTMENT_MEDICAL)) / 3)
|
||||
activeness = max(activeness, 20)
|
||||
|
||||
carp_amount = CEILING(station_strength * (activeness / 100) + 1, 1)
|
||||
|
||||
/datum/gm_action/carp_migration/start()
|
||||
..()
|
||||
var/list/spawn_locations = list()
|
||||
|
||||
var/group_size_min = 3
|
||||
var/group_size_max = 5
|
||||
|
||||
for(var/obj/effect/landmark/C in landmarks_list)
|
||||
if(C.name == "carpspawn")
|
||||
spawn_locations.Add(C.loc)
|
||||
|
||||
spawn_locations = shuffle(spawn_locations)
|
||||
carp_amount = min(carp_amount, spawn_locations.len)
|
||||
|
||||
var/i = 1
|
||||
while (i <= carp_amount)
|
||||
var/group_size = rand(group_size_min, group_size_max)
|
||||
for (var/j = 1, j <= group_size, j++)
|
||||
spawned_carp.Add(new /mob/living/simple_mob/animal/space/carp/event(spawn_locations[i]))
|
||||
i++
|
||||
message_admins("[spawned_carp.len] carp spawned by event.")
|
||||
|
||||
/datum/gm_action/carp_migration/end()
|
||||
for(var/mob/living/simple_mob/animal/space/carp/C in spawned_carp)
|
||||
if(!C.stat)
|
||||
var/turf/T = get_turf(C)
|
||||
if(istype(T, /turf/space))
|
||||
if(!prob(25))
|
||||
qdel(C)
|
||||
@@ -1,21 +0,0 @@
|
||||
/datum/gm_action/comms_blackout
|
||||
name = "communications blackout"
|
||||
departments = list(DEPARTMENT_ENGINEERING, DEPARTMENT_EVERYONE)
|
||||
chaotic = 35
|
||||
|
||||
/datum/gm_action/comms_blackout/get_weight()
|
||||
return 50 + (metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 40)
|
||||
|
||||
/datum/gm_action/comms_blackout/announce()
|
||||
if(prob(33))
|
||||
command_announcement.Announce("Ionospheric anomalies detected. Temporary telecommunication failure imminent. Please contact you-BZZT", new_sound = 'sound/misc/interference.ogg')
|
||||
// AIs will always know if there's a comm blackout, rogue AIs could then lie about comm blackouts in the future while they shutdown comms
|
||||
for(var/mob/living/silicon/ai/A in player_list)
|
||||
to_chat(A, "<br>")
|
||||
to_chat(A, "<span class='warning'><b>Ionospheric anomalies detected. Temporary telecommunication failure imminent. Please contact you-BZZT</b></span>")
|
||||
to_chat(A, "<br>")
|
||||
|
||||
/datum/gm_action/comms_blackout/start()
|
||||
..()
|
||||
for(var/obj/machinery/telecomms/T in telecomms_list)
|
||||
T.emp_act(1)
|
||||
@@ -1,17 +0,0 @@
|
||||
/datum/gm_action/dust
|
||||
name = "dust"
|
||||
departments = list(DEPARTMENT_ENGINEERING)
|
||||
chaotic = 10
|
||||
reusable = TRUE
|
||||
|
||||
/datum/gm_action/dust/announce()
|
||||
command_announcement.Announce("Debris resulting from activity on another nearby asteroid is approaching your colony.", "Dust Alert")
|
||||
|
||||
/datum/gm_action/dust/get_weight()
|
||||
var/engineers = metric.count_people_in_department(DEPARTMENT_ENGINEERING)
|
||||
var/weight = 30 + (engineers * 25)
|
||||
return weight
|
||||
|
||||
/datum/gm_action/dust/start()
|
||||
..()
|
||||
dust_swarm("norm")
|
||||
@@ -1,33 +0,0 @@
|
||||
/datum/gm_action/electrical_storm
|
||||
name = "electrical storm"
|
||||
departments = list(DEPARTMENT_EVERYONE)
|
||||
reusable = TRUE
|
||||
var/lightsoutAmount = 1
|
||||
var/lightsoutRange = 25
|
||||
|
||||
/datum/gm_action/electrical_storm/announce()
|
||||
command_announcement.Announce("An electrical issue has been detected in your area, please repair potential electronic overloads.", "Electrical Alert")
|
||||
|
||||
/datum/gm_action/electrical_storm/start()
|
||||
..()
|
||||
var/list/epicentreList = list()
|
||||
|
||||
for(var/i=1, i <= lightsoutAmount, i++)
|
||||
var/list/possibleEpicentres = list()
|
||||
for(var/obj/effect/landmark/newEpicentre in landmarks_list)
|
||||
if(newEpicentre.name == "lightsout" && !(newEpicentre in epicentreList))
|
||||
possibleEpicentres += newEpicentre
|
||||
if(possibleEpicentres.len)
|
||||
epicentreList += pick(possibleEpicentres)
|
||||
else
|
||||
break
|
||||
|
||||
if(!epicentreList.len)
|
||||
return
|
||||
|
||||
for(var/obj/effect/landmark/epicentre in epicentreList)
|
||||
for(var/obj/machinery/power/apc/apc in range(epicentre,lightsoutRange))
|
||||
apc.overload_lighting()
|
||||
|
||||
/datum/gm_action/electrical_storm/get_weight()
|
||||
return 30 + (metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 15) + (metric.count_people_in_department(DEPARTMENT_EVERYONE) * 5)
|
||||
@@ -1,75 +0,0 @@
|
||||
/datum/gm_action/electrified_door
|
||||
name = "airlock short-circuit"
|
||||
departments = list(DEPARTMENT_ENGINEERING, DEPARTMENT_MEDICAL)
|
||||
chaotic = 10
|
||||
var/obj/machinery/door/airlock/chosen_door
|
||||
var/area/target_area
|
||||
var/list/area/excluded = list(
|
||||
/area/submap,
|
||||
/area/shuttle,
|
||||
/area/crew_quarters
|
||||
)
|
||||
|
||||
/datum/gm_action/electrified_door/set_up()
|
||||
var/list/area/grand_list_of_areas = get_station_areas(excluded)
|
||||
|
||||
severity = pickweight(EVENT_LEVEL_MUNDANE = 10,
|
||||
EVENT_LEVEL_MODERATE = 5,
|
||||
EVENT_LEVEL_MAJOR = 1
|
||||
)
|
||||
|
||||
//try 10 times
|
||||
for(var/i in 1 to 10)
|
||||
target_area = pick(grand_list_of_areas)
|
||||
var/list/obj/machinery/door/airlock/target_doors = list()
|
||||
for(var/obj/machinery/door/airlock/target_door in target_area.contents)
|
||||
target_doors += target_door
|
||||
target_doors = shuffle(target_doors)
|
||||
|
||||
for(var/obj/machinery/door/airlock/target_door in target_doors)
|
||||
if(!target_door.isElectrified() && target_door.arePowerSystemsOn() && target_door.maxhealth == target_door.health)
|
||||
chosen_door = target_door
|
||||
return
|
||||
|
||||
/datum/gm_action/electrified_door/start()
|
||||
..()
|
||||
if(!chosen_door)
|
||||
return
|
||||
command_announcement.Announce("An electrical issue has been detected in your area, please repair potential electronic overloads.", "Electrical Alert")
|
||||
chosen_door.visible_message("<span class='danger'>\The [chosen_door]'s panel sparks!</span>")
|
||||
chosen_door.set_safeties(0)
|
||||
playsound(get_turf(chosen_door), 'sound/machines/buzz-sigh.ogg', 50, 1)
|
||||
if(severity >= EVENT_LEVEL_MODERATE)
|
||||
chosen_door.electrify(-1)
|
||||
spawn(rand(10 SECONDS, 2 MINUTES))
|
||||
if(chosen_door && chosen_door.arePowerSystemsOn() && prob(25 + 25 * severity))
|
||||
command_announcement.Announce("Overload has been localized to \the [target_area].", "Electrical Alert")
|
||||
|
||||
if(severity >= EVENT_LEVEL_MAJOR) // New Major effect. Hydraulic boom.
|
||||
spawn()
|
||||
chosen_door.visible_message("<span class='warning'>\The [chosen_door] buzzes.</span>")
|
||||
playsound(get_turf(chosen_door), 'sound/machines/buzz-sigh.ogg', 50, 1)
|
||||
sleep(rand(10 SECONDS, 3 MINUTES))
|
||||
if(!chosen_door || !chosen_door.arePowerSystemsOn())
|
||||
return
|
||||
chosen_door.visible_message("<span class='warning'>\The [chosen_door]'s hydraulics creak.</span>")
|
||||
playsound(get_turf(chosen_door), 'sound/machines/airlock_creaking.ogg', 50, 1)
|
||||
sleep(rand(30 SECONDS, 10 MINUTES))
|
||||
if(!chosen_door || !chosen_door.arePowerSystemsOn())
|
||||
return
|
||||
chosen_door.visible_message("<span class='danger'>\The [chosen_door] emits a hydraulic shriek!</span>")
|
||||
playsound(get_turf(chosen_door), 'sound/machines/airlock.ogg', 80, 1)
|
||||
spawn(rand(5 SECONDS, 30 SECONDS))
|
||||
if(!chosen_door || !chosen_door.arePowerSystemsOn())
|
||||
return
|
||||
chosen_door.visible_message("<span class='critical'>\The [chosen_door]'s hydraulics detonate!</span>")
|
||||
chosen_door.fragmentate(get_turf(chosen_door), rand(5, 10), rand(3, 5), list(/obj/item/projectile/bullet/pellet/fragment/tank/small))
|
||||
explosion(get_turf(chosen_door),-1,-1,2,3)
|
||||
|
||||
chosen_door.lock()
|
||||
chosen_door.health = chosen_door.maxhealth / 6
|
||||
chosen_door.aiControlDisabled = 1
|
||||
chosen_door.update_icon()
|
||||
|
||||
/datum/gm_action/electrified_door/get_weight()
|
||||
return 10 + (metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 5 + metric.count_people_in_department(DEPARTMENT_MEDICAL) * 10)
|
||||
@@ -1,36 +0,0 @@
|
||||
/datum/gm_action/gravity
|
||||
name = "gravity failure"
|
||||
departments = list(DEPARTMENT_EVERYONE)
|
||||
length = 600
|
||||
var/list/zLevels
|
||||
|
||||
/datum/gm_action/gravity/set_up()
|
||||
length = rand(length, length * 5)
|
||||
// Setup which levels we will disrupt gravit on.
|
||||
zLevels = using_map.station_levels.Copy()
|
||||
for(var/datum/planet/P in SSplanets.planets)
|
||||
zLevels -= P.expected_z_levels
|
||||
|
||||
/datum/gm_action/gravity/announce()
|
||||
command_announcement.Announce("Feedback surge detected in mass-distributions systems. Artificial gravity has been disabled whilst the system \
|
||||
reinitializes. Please stand by while the gravity system reinitializes.", "Gravity Failure")
|
||||
|
||||
/datum/gm_action/gravity/start()
|
||||
..()
|
||||
gravity_is_on = 0
|
||||
for(var/area/A in all_areas)
|
||||
if(A.z in zLevels)
|
||||
A.gravitychange(gravity_is_on, A)
|
||||
|
||||
/datum/gm_action/gravity/end()
|
||||
if(!gravity_is_on)
|
||||
gravity_is_on = 1
|
||||
|
||||
for(var/area/A in all_areas)
|
||||
if(A.z in zLevels)
|
||||
A.gravitychange(gravity_is_on, A)
|
||||
|
||||
command_announcement.Announce("Gravity generators are again functioning within normal parameters. Sorry for any inconvenience.", "Gravity Restored")
|
||||
|
||||
/datum/gm_action/gravity/get_weight()
|
||||
return 30 + (metric.count_people_in_department(DEPARTMENT_EVERYONE) * 20)
|
||||
@@ -1,23 +0,0 @@
|
||||
// New grid check event:
|
||||
// Very similar to the old one, power goes out in most of the colony, however the new feature is the ability for engineering to
|
||||
// get power back on sooner, if they are able to reach a special machine and initiate a manual reboot. If no one is able to do so,
|
||||
// it will reboot itself after a few minutes, just like the old one. Bad things happen if there is no grid checker machine protecting
|
||||
// the powernet when this event fires.
|
||||
|
||||
/datum/gm_action/grid_check
|
||||
name = "grid check"
|
||||
departments = list(DEPARTMENT_ENGINEERING, DEPARTMENT_EVERYONE)
|
||||
chaotic = 20
|
||||
|
||||
/datum/gm_action/grid_check/get_weight()
|
||||
return 50 + (metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 30)
|
||||
|
||||
/datum/gm_action/grid_check/start()
|
||||
..()
|
||||
// This sets off a chain of events that lead to the actual grid check (or perhaps worse).
|
||||
// First, the Supermatter engine makes a power spike.
|
||||
for(var/obj/machinery/power/generator/engine in machines)
|
||||
engine.power_spike()
|
||||
break // Just one engine, please.
|
||||
// After that, the engine checks if a grid checker exists on the same powernet, and if so, it triggers a blackout.
|
||||
// If not, lots of stuff breaks. See code/modules/power/generator.dm for that piece of code.
|
||||
@@ -1,116 +0,0 @@
|
||||
#define LOC_KITCHEN 0
|
||||
#define LOC_ATMOS 1
|
||||
#define LOC_CHAPEL 2
|
||||
#define LOC_LIBRARY 3
|
||||
#define LOC_HYDRO 4
|
||||
#define LOC_VAULT 5
|
||||
#define LOC_CONSTR 6
|
||||
#define LOC_TECH 7
|
||||
#define LOC_GARDEN 8
|
||||
|
||||
#define VERM_MICE 0
|
||||
#define VERM_LIZARDS 1
|
||||
#define VERM_SPIDERS 2
|
||||
|
||||
/datum/gm_action/infestation
|
||||
name = "animal infestation"
|
||||
departments = list(DEPARTMENT_EVERYONE)
|
||||
var/location
|
||||
var/locstring
|
||||
var/vermin
|
||||
var/vermstring
|
||||
|
||||
var/list/turf/simulated/floor/turfs = list()
|
||||
|
||||
var/spawn_types
|
||||
var/max_number
|
||||
|
||||
/datum/gm_action/infestation/set_up()
|
||||
location = rand(0,8)
|
||||
turfs.Cut()
|
||||
var/spawn_area_type
|
||||
switch(location)
|
||||
if(LOC_KITCHEN)
|
||||
spawn_area_type = /area/crew_quarters/kitchen
|
||||
locstring = "the kitchen"
|
||||
if(LOC_ATMOS)
|
||||
spawn_area_type = /area/engineering/atmos
|
||||
locstring = "atmospherics"
|
||||
if(LOC_CHAPEL)
|
||||
spawn_area_type = /area/chapel/main
|
||||
locstring = "the chapel"
|
||||
if(LOC_LIBRARY)
|
||||
spawn_area_type = /area/library
|
||||
locstring = "the library"
|
||||
if(LOC_HYDRO)
|
||||
spawn_area_type = /area/hydroponics
|
||||
locstring = "hydroponics"
|
||||
if(LOC_VAULT)
|
||||
spawn_area_type = /area/security/nuke_storage
|
||||
locstring = "the vault"
|
||||
if(LOC_CONSTR)
|
||||
spawn_area_type = /area/construction
|
||||
locstring = "the construction area"
|
||||
if(LOC_TECH)
|
||||
spawn_area_type = /area/storage/tech
|
||||
locstring = "technical storage"
|
||||
if(LOC_GARDEN)
|
||||
spawn_area_type = /area/hydroponics/garden
|
||||
locstring = "the public garden"
|
||||
|
||||
for(var/areapath in typesof(spawn_area_type))
|
||||
var/area/A = locate(areapath)
|
||||
for(var/turf/simulated/floor/F in A.contents)
|
||||
if(turf_clear(F))
|
||||
turfs += F
|
||||
|
||||
spawn_types = list()
|
||||
max_number = 0
|
||||
vermin = rand(0,2)
|
||||
switch(vermin)
|
||||
if(VERM_MICE)
|
||||
spawn_types = list(/mob/living/simple_mob/animal/passive/mouse/gray, /mob/living/simple_mob/animal/passive/mouse/brown, /mob/living/simple_mob/animal/passive/mouse/white, /mob/living/simple_mob/animal/passive/mouse/rat)
|
||||
max_number = 12
|
||||
vermstring = "mice"
|
||||
if(VERM_LIZARDS)
|
||||
spawn_types = list(/mob/living/simple_mob/animal/passive/lizard, /mob/living/simple_mob/animal/passive/lizard, /mob/living/simple_mob/animal/passive/lizard/large, /mob/living/simple_mob/animal/passive/lizard/large/defensive)
|
||||
max_number = 6
|
||||
vermstring = "lizards"
|
||||
if(VERM_SPIDERS)
|
||||
spawn_types = list(/obj/effect/spider/spiderling)
|
||||
max_number = 3
|
||||
vermstring = "spiders"
|
||||
|
||||
/datum/gm_action/infestation/start()
|
||||
spawn()
|
||||
var/num = rand(2,max_number)
|
||||
while(turfs.len > 0 && num > 0)
|
||||
var/turf/simulated/floor/T = pick(turfs)
|
||||
turfs.Remove(T)
|
||||
num--
|
||||
|
||||
if(vermin == VERM_SPIDERS)
|
||||
var/obj/effect/spider/spiderling/S = new(T)
|
||||
S.amount_grown = -1
|
||||
else
|
||||
var/spawn_type = pick(spawn_types)
|
||||
new spawn_type(T)
|
||||
|
||||
/datum/gm_action/infestation/announce()
|
||||
command_announcement.Announce("Bioscans indicate that [vermstring] have been breeding in [locstring]. Clear them out, before this starts to affect productivity.", "Vermin infestation")
|
||||
|
||||
/datum/gm_action/infestation/get_weight()
|
||||
return 5 + (metric.count_people_in_department(DEPARTMENT_EVERYONE) * 20)
|
||||
|
||||
#undef LOC_KITCHEN
|
||||
#undef LOC_ATMOS
|
||||
#undef LOC_CHAPEL
|
||||
#undef LOC_LIBRARY
|
||||
#undef LOC_HYDRO
|
||||
#undef LOC_VAULT
|
||||
#undef LOC_TECH
|
||||
#undef LOC_GARDEN
|
||||
|
||||
#undef VERM_MICE
|
||||
#undef VERM_LIZARDS
|
||||
#undef VERM_SPIDERS
|
||||
@@ -1,50 +0,0 @@
|
||||
/datum/gm_action/ionstorm
|
||||
name = "ion storm"
|
||||
departments = list(DEPARTMENT_SYNTHETIC)
|
||||
var/botEmagChance = 0.5
|
||||
var/list/players = list()
|
||||
var/active = FALSE
|
||||
length = 1 MINUTE
|
||||
|
||||
/datum/gm_action/ionstorm/set_up()
|
||||
length = rand(length, length * 10)
|
||||
// command_alert("The station has entered an ion storm. Monitor all electronic equipment for malfunctions", "Anomaly Alert")
|
||||
for (var/mob/living/carbon/human/player in player_list)
|
||||
if( !player.mind || player_is_antag(player.mind, only_offstation_roles = 1) || player.client.inactivity > MinutesToTicks(10))
|
||||
continue
|
||||
players += player.real_name
|
||||
|
||||
for (var/mob/living/silicon/ai/target in silicon_mob_list)
|
||||
var/law = target.generate_ion_law()
|
||||
to_chat(target, "<font color='red'><b>You have detected a change in your laws information:</b></font>")
|
||||
to_chat(target,law)
|
||||
target.add_ion_law(law)
|
||||
target.show_laws()
|
||||
|
||||
/datum/gm_action/ionstorm/announce()
|
||||
if(message_servers)
|
||||
for (var/obj/machinery/message_server/MS in message_servers)
|
||||
MS.spamfilter.Cut()
|
||||
var/i
|
||||
for (i = 1, i <= MS.spamfilter_limit, i++)
|
||||
MS.spamfilter += pick("kitty","HONK","rev","malf","liberty","freedom","drugs", "[using_map.station_short]", \
|
||||
"admin","ponies","heresy","meow","Pun Pun","monkey","Ian","moron","pizza","message","spam",\
|
||||
"director", "Hello", "Hi!"," ","nuke","crate","dwarf","xeno")
|
||||
|
||||
/datum/gm_action/ionstorm/start()
|
||||
while(active)
|
||||
sleep(1)
|
||||
if(botEmagChance)
|
||||
for(var/mob/living/bot/bot in mob_list)
|
||||
if(prob(botEmagChance))
|
||||
bot.emag_act(1)
|
||||
|
||||
/datum/gm_action/ionstorm/end()
|
||||
spawn(rand(5000,8000))
|
||||
if(prob(50))
|
||||
ion_storm_announcement()
|
||||
|
||||
/datum/gm_action/ionstorm/get_weight()
|
||||
var/bots = metric.count_people_in_department(DEPARTMENT_SYNTHETIC)
|
||||
var/weight = 5 + (bots * 20)
|
||||
return weight
|
||||
@@ -1,52 +0,0 @@
|
||||
/datum/gm_action/manifest_malfunction
|
||||
name = "manifest malfunction"
|
||||
enabled = TRUE
|
||||
departments = list(DEPARTMENT_SECURITY, DEPARTMENT_SYNTHETIC, DEPARTMENT_EVERYONE)
|
||||
chaotic = 3
|
||||
reusable = FALSE
|
||||
length = 0
|
||||
|
||||
var/recordtype
|
||||
|
||||
/datum/gm_action/manifest_malfunction/set_up()
|
||||
severity = pickweight(EVENT_LEVEL_MUNDANE = 6,
|
||||
EVENT_LEVEL_MODERATE = 2,
|
||||
EVENT_LEVEL_MAJOR = 1
|
||||
)
|
||||
|
||||
recordtype = pickweight("medical" = 10,"security" = (severity * 15))
|
||||
|
||||
return
|
||||
|
||||
/datum/gm_action/manifest_malfunction/get_weight()
|
||||
. = -10
|
||||
|
||||
var/security = metric.count_people_in_department(DEPARTMENT_SECURITY)
|
||||
|
||||
if(security && data_core)
|
||||
. += (metric.count_people_in_department(DEPARTMENT_EVERYONE) * 5) - (metric.count_people_in_department(DEPARTMENT_SYNTHETIC) * 5)
|
||||
|
||||
return .
|
||||
|
||||
/datum/gm_action/manifest_malfunction/start()
|
||||
..()
|
||||
|
||||
var/manifest_cut_count = 1 * severity
|
||||
|
||||
for(var/I = 1 to manifest_cut_count)
|
||||
var/datum/data/record/R
|
||||
|
||||
switch(recordtype)
|
||||
if("security")
|
||||
R = pick(data_core.security)
|
||||
|
||||
if("medical")
|
||||
R = pick(data_core.medical)
|
||||
|
||||
qdel(R)
|
||||
|
||||
/datum/gm_action/manifest_malfunction/announce()
|
||||
if(prob(30 * severity))
|
||||
spawn(rand(5 MINUTES, 10 MINUTES))
|
||||
command_announcement.Announce("An ongoing mass upload of malware for [recordtype] record cores has been detected onboard [station_name()]", "Data Breach Alert")
|
||||
return
|
||||
@@ -1,71 +0,0 @@
|
||||
// This event gives the station an advance warning about meteors, so that they can prepare in various ways.
|
||||
|
||||
/datum/gm_action/meteor_defense
|
||||
name = "meteor defense"
|
||||
departments = list(DEPARTMENT_ENGINEERING, DEPARTMENT_CARGO)
|
||||
chaotic = 50
|
||||
var/direction = null
|
||||
var/dir_text = null
|
||||
var/waves = 0
|
||||
|
||||
var/meteor_types
|
||||
|
||||
/datum/gm_action/meteor_defense/get_weight()
|
||||
var/engineers = metric.count_people_in_department(DEPARTMENT_ENGINEERING)
|
||||
var/cargo = metric.count_people_in_department(DEPARTMENT_CARGO)
|
||||
var/bots = metric.count_people_in_department(DEPARTMENT_SYNTHETIC)
|
||||
var/weight = (max(engineers - 1, 0) * 20) // If only one engineer exists, no meteors for now.
|
||||
|
||||
if(engineers >= 2)
|
||||
weight += ((cargo - 1) * 10)
|
||||
weight += (bots * 15)
|
||||
|
||||
return weight
|
||||
|
||||
/datum/gm_action/meteor_defense/set_up()
|
||||
severity = pickweight(EVENT_LEVEL_MUNDANE = 10,
|
||||
EVENT_LEVEL_MODERATE = 3
|
||||
)
|
||||
|
||||
switch(severity)
|
||||
if(EVENT_LEVEL_MUNDANE)
|
||||
meteor_types = meteors_threatening.Copy()
|
||||
|
||||
if(EVENT_LEVEL_MODERATE)
|
||||
meteor_types = meteors_catastrophic.Copy()
|
||||
|
||||
direction = pick(cardinal) // alldirs doesn't work with current meteor code unfortunately.
|
||||
waves = rand(5, 8)
|
||||
switch(direction)
|
||||
if(NORTH)
|
||||
dir_text = "aft" // For some reason this is needed.
|
||||
if(SOUTH)
|
||||
dir_text = "fore"
|
||||
if(EAST)
|
||||
dir_text = "port"
|
||||
if(WEST)
|
||||
dir_text = "starboard"
|
||||
|
||||
/datum/gm_action/meteor_defense/announce()
|
||||
var/announcement = "Alert! Two asteroids have collided near [station_name()]. Chunks of it are expected to approach from the [dir_text] side. ETA to arrival is \
|
||||
approximately [round(5 * severity * 2)] minutes."
|
||||
command_announcement.Announce(announcement, "Meteor Alert", new_sound = 'sound/AI/meteors.ogg')
|
||||
|
||||
/datum/gm_action/meteor_defense/start()
|
||||
..()
|
||||
spawn(0)
|
||||
sleep(round(5 * severity) MINUTES)
|
||||
var/announcement = "The incoming debris are expected to approach from the [dir_text] side. ETA to arrival is approximately [round(5 * severity)] minutes."
|
||||
command_announcement.Announce(announcement, "Meteor Alert - Update")
|
||||
sleep(round(5 * severity) MINUTES)
|
||||
announcement = "Incoming debris approaches from the [dir_text] side!"
|
||||
command_announcement.Announce(announcement, "Meteor Alert - Update")
|
||||
while(waves)
|
||||
message_admins("[waves] more wave\s of meteors remain.")
|
||||
spawn(1) // Dir is reversed because the direction describes where meteors are going, not what side it's gonna hit.
|
||||
spawn_meteors(rand(8, 12), meteors_threatening, reverse_dir[direction])
|
||||
waves--
|
||||
sleep(30 SECONDS)
|
||||
announcement = "The station has cleared the incoming debris."
|
||||
command_announcement.Announce(announcement, "Meteor Alert - Update")
|
||||
message_admins("Meteor defense event has ended.")
|
||||
@@ -1,79 +0,0 @@
|
||||
/var/global/account_hack_attempted = 0
|
||||
|
||||
/datum/gm_action/money_hacker
|
||||
name = "bank account hacker"
|
||||
departments = list(DEPARTMENT_EVERYONE)
|
||||
reusable = TRUE
|
||||
var/datum/money_account/affected_account
|
||||
var/active
|
||||
var/activeFor
|
||||
var/end_time
|
||||
|
||||
/datum/gm_action/money_hacker/set_up()
|
||||
active = TRUE
|
||||
end_time = world.time + 6000
|
||||
if(all_money_accounts.len)
|
||||
affected_account = pick(all_money_accounts)
|
||||
|
||||
account_hack_attempted = 1
|
||||
|
||||
/datum/gm_action/money_hacker/announce()
|
||||
var/message = "A brute force hack has been detected (in progress since [stationtime2text()]). The target of the attack is: Financial account #[affected_account.account_number], \
|
||||
without intervention this attack will succeed in approximately 10 minutes. Required intervention: temporary suspension of affected accounts until the attack has ceased. \
|
||||
Notifications will be sent as updates occur.<br>"
|
||||
var/my_department = "[station_name()] firewall subroutines"
|
||||
|
||||
for(var/obj/machinery/message_server/MS in machines)
|
||||
if(!MS.active) continue
|
||||
MS.send_rc_message("Head of Personnel's Desk", my_department, message, "", "", 2)
|
||||
|
||||
|
||||
/datum/gm_action/money_hacker/start()
|
||||
..()
|
||||
spawn(0)
|
||||
while(active)
|
||||
sleep(1)
|
||||
activeFor++
|
||||
if(world.time >= end_time)
|
||||
length = activeFor
|
||||
else
|
||||
length = activeFor + 10
|
||||
|
||||
/datum/gm_action/money_hacker/end()
|
||||
active = FALSE
|
||||
var/message
|
||||
if(affected_account && !affected_account.suspended)
|
||||
//hacker wins
|
||||
message = "The hack attempt has succeeded."
|
||||
|
||||
//subtract the money
|
||||
var/lost = affected_account.money * 0.8 + (rand(2,4) - 2) / 10
|
||||
affected_account.money -= lost
|
||||
|
||||
//create a taunting log entry
|
||||
var/datum/transaction/T = new()
|
||||
T.target_name = pick("","yo brotha from anotha motha","el Presidente","chieF smackDowN","Nobody")
|
||||
T.purpose = pick("Ne$ ---ount fu%ds init*&lisat@*n","PAY BACK YOUR MUM","Funds withdrawal","pWnAgE","l33t hax","liberationez","Hit","Nothing")
|
||||
T.amount = pick("","([rand(0,99999)])","alla money","9001$","HOLLA HOLLA GET DOLLA","([lost])")
|
||||
var/date1 = "31 December, 1999"
|
||||
var/date2 = "[num2text(rand(1,31))] [pick("January","February","March","April","May","June","July","August","September","October","November","December")], [rand(1000,3000)]"
|
||||
T.date = pick("", current_date_string, date1, date2,"Nowhen")
|
||||
var/time1 = rand(0, 99999999)
|
||||
var/time2 = "[round(time1 / 36000)+12]:[(time1 / 600 % 60) < 10 ? add_zero(time1 / 600 % 60, 1) : time1 / 600 % 60]"
|
||||
T.time = pick("", stationtime2text(), time2, "Never")
|
||||
T.source_terminal = pick("","[pick("Biesel","New Gibson")] GalaxyNet Terminal #[rand(111,999)]","your mums place","nantrasen high CommanD","Angessa's Pearl","Nowhere")
|
||||
|
||||
affected_account.transaction_log.Add(T)
|
||||
|
||||
else
|
||||
//crew wins
|
||||
message = "The attack has ceased, the affected accounts can now be brought online."
|
||||
|
||||
var/my_department = "[station_name()] firewall subroutines"
|
||||
|
||||
for(var/obj/machinery/message_server/MS in machines)
|
||||
if(!MS.active) continue
|
||||
MS.send_rc_message("Head of Personnel's Desk", my_department, message, "", "", 2)
|
||||
|
||||
/datum/gm_action/money_hacker/get_weight()
|
||||
return 30 * all_money_accounts.len
|
||||
@@ -1,39 +0,0 @@
|
||||
/datum/gm_action/money_lotto
|
||||
name = "lottery win"
|
||||
departments = list(DEPARTMENT_EVERYONE)
|
||||
var/winner_name = "John Smith"
|
||||
var/winner_sum = 0
|
||||
var/deposit_success = 0
|
||||
|
||||
/datum/gm_action/money_lotto/start()
|
||||
..()
|
||||
winner_sum = pick(5000, 10000, 50000, 100000, 500000, 1000000, 1500000)
|
||||
if(all_money_accounts.len)
|
||||
var/datum/money_account/D = pick(all_money_accounts)
|
||||
winner_name = D.owner_name
|
||||
if(!D.suspended)
|
||||
D.money += winner_sum
|
||||
|
||||
var/datum/transaction/T = new()
|
||||
T.target_name = "The [using_map.starsys_name] Times Grand Slam -Stellar- Lottery"
|
||||
T.purpose = "Winner!"
|
||||
T.amount = winner_sum
|
||||
T.date = current_date_string
|
||||
T.time = stationtime2text()
|
||||
T.source_terminal = "Sif TCD Terminal #[rand(111,333)]"
|
||||
D.transaction_log.Add(T)
|
||||
|
||||
deposit_success = 1
|
||||
|
||||
/datum/gm_action/money_lotto/announce()
|
||||
var/author = "[using_map.company_name] Editor"
|
||||
var/channel = "The [using_map.starsys_name] Times"
|
||||
|
||||
var/body = "The [using_map.starsys_name] Times wishes to congratulate <b>[winner_name]</b> for recieving the [using_map.starsys_name] Stellar Slam Lottery, and receiving the out of this world sum of [winner_sum] credits!"
|
||||
if(!deposit_success)
|
||||
body += "<br>Unfortunately, we were unable to verify the account details provided, so we were unable to transfer the money. Send a cheque containing the sum of 5000 Thalers to ND 'Stellar Slam' office on the The [using_map.starsys_name] Times gateway containing updated details, and your winnings'll be re-sent within the month."
|
||||
|
||||
news_network.SubmitArticle(body, author, channel, null, 1)
|
||||
|
||||
/datum/gm_action/money_lotto/get_weight()
|
||||
return 25 * metric.count_people_in_department(DEPARTMENT_EVERYONE)
|
||||
@@ -1,129 +0,0 @@
|
||||
/datum/gm_action/pda_spam
|
||||
name = "PDA spam"
|
||||
departments = list(DEPARTMENT_EVERYONE)
|
||||
reusable = TRUE
|
||||
var/last_spam_time = 0
|
||||
var/obj/machinery/message_server/useMS
|
||||
var/obj/machinery/exonet_node/node
|
||||
|
||||
/datum/gm_action/pda_spam/set_up()
|
||||
last_spam_time = world.time
|
||||
pick_message_server()
|
||||
|
||||
/datum/gm_action/pda_spam/proc/pick_message_server()
|
||||
if(message_servers)
|
||||
for (var/obj/machinery/message_server/MS in message_servers)
|
||||
if(MS.active)
|
||||
useMS = MS
|
||||
break
|
||||
|
||||
/datum/gm_action/pda_spam/start()
|
||||
..()
|
||||
while(world.time < last_spam_time + 3000)
|
||||
if(!node)
|
||||
node = get_exonet_node()
|
||||
|
||||
if(!node || !node.on || !node.allow_external_PDAs)
|
||||
return
|
||||
|
||||
if(!useMS || !useMS.active)
|
||||
useMS = null
|
||||
pick_message_server()
|
||||
|
||||
if(useMS)
|
||||
if(prob(5))
|
||||
// /obj/machinery/message_server/proc/send_pda_message(var/recipient = "",var/sender = "",var/message = "")
|
||||
var/obj/item/device/pda/P
|
||||
var/list/viables = list()
|
||||
for(var/obj/item/device/pda/check_pda in sortAtom(PDAs))
|
||||
if (!check_pda.owner||check_pda.toff||check_pda == src||check_pda.hidden)
|
||||
continue
|
||||
viables.Add(check_pda)
|
||||
|
||||
if(!viables.len)
|
||||
return
|
||||
P = pick(viables)
|
||||
|
||||
var/sender
|
||||
var/message
|
||||
switch(pick(1,2,3,4,5,6,7))
|
||||
if(1)
|
||||
sender = pick("MaxBet","MaxBet Online Casino","There is no better time to register","I'm excited for you to join us")
|
||||
message = pick("Triple deposits are waiting for you at MaxBet Online when you register to play with us.",\
|
||||
"You can qualify for a 200% Welcome Bonus at MaxBet Online when you sign up today.",\
|
||||
"Once you are a player with MaxBet, you will also receive lucrative weekly and monthly promotions.",\
|
||||
"You will be able to enjoy over 450 top-flight casino games at MaxBet.")
|
||||
if(2)
|
||||
sender = pick(300;"QuickDatingSystem",200;"Find your russian bride",50;"Tajaran beauties are waiting",50;"Find your secret skrell crush",50;"Beautiful unathi brides")
|
||||
message = pick("Your profile caught my attention and I wanted to write and say hello (QuickDating).",\
|
||||
"If you will write to me on my email [pick(first_names_female)]@[pick(last_names)].[pick("ru","ck","tj","ur","nt")] I shall necessarily send you a photo (QuickDating).",\
|
||||
"I want that we write each other and I hope, that you will like my profile and you will answer me (QuickDating).",\
|
||||
"You have (1) new message!",\
|
||||
"You have (2) new profile views!")
|
||||
if(3)
|
||||
sender = pick("Galactic Payments Association","Better Business Bureau","[using_map.starsys_name] E-Payments","NAnoTransen Finance Deparmtent","Luxury Replicas")
|
||||
message = pick("Luxury watches for Blowout sale prices!",\
|
||||
"Watches, Jewelry & Accessories, Bags & Wallets !",\
|
||||
"Deposit 100$ and get 300$ totally free!",\
|
||||
" 100K NT.|WOWGOLD <20>nly $89 <HOT>",\
|
||||
"We have been filed with a complaint from one of your customers in respect of their business relations with you.",\
|
||||
"We kindly ask you to open the COMPLAINT REPORT (attached) to reply on this complaint..")
|
||||
if(4)
|
||||
sender = pick("Buy Dr. Maxman","Having dysfuctional troubles?")
|
||||
message = pick("DR MAXMAN: REAL Doctors, REAL Science, REAL Results!",\
|
||||
"Dr. Maxman was created by George Acuilar, M.D, a [using_map.boss_short] Certified Urologist who has treated over 70,000 patients sector wide with 'male problems'.",\
|
||||
"After seven years of research, Dr Acuilar and his team came up with this simple breakthrough male enhancement formula.",\
|
||||
"Men of all species report AMAZING increases in length, width and stamina.")
|
||||
if(5)
|
||||
sender = pick("Dr","Crown prince","King Regent","Professor","Captain")
|
||||
sender += " " + pick("Robert","Alfred","Josephat","Kingsley","Sehi","Zbahi")
|
||||
sender += " " + pick("Mugawe","Nkem","Gbatokwia","Nchekwube","Ndim","Ndubisi")
|
||||
message = pick("YOUR FUND HAS BEEN MOVED TO [pick("Salusa","Segunda","Cepheus","Andromeda","Gruis","Corona","Aquila","ARES","Asellus")] DEVELOPMENTARY BANK FOR ONWARD REMITTANCE.",\
|
||||
"We are happy to inform you that due to the delay, we have been instructed to IMMEDIATELY deposit all funds into your account",\
|
||||
"Dear fund beneficiary, We have please to inform you that overdue funds payment has finally been approved and released for payment",\
|
||||
"Due to my lack of agents I require an off-world financial account to immediately deposit the sum of 1 POINT FIVE MILLION credits.",\
|
||||
"Greetings sir, I regretfully to inform you that as I lay dying here due to my lack ofheirs I have chosen you to recieve the full sum of my lifetime savings of 1.5 billion credits")
|
||||
if(6)
|
||||
sender = pick("[using_map.company_name] Morale Divison","Feeling Lonely?","Bored?","www.wetskrell.nt")
|
||||
message = pick("The [using_map.company_name] Morale Division wishes to provide you with quality entertainment sites.",\
|
||||
"WetSkrell.nt is a xenophillic website endorsed by NT for the use of male crewmembers among it's many stations and outposts.",\
|
||||
"Wetskrell.nt only provides the higest quality of male entertaiment to [using_map.company_name] Employees.",\
|
||||
"Simply enter your [using_map.company_name] Bank account system number and pin. With three easy steps this service could be yours!")
|
||||
if(7)
|
||||
sender = pick("You have won free tickets!","Click here to claim your prize!","You are the 1000th vistor!","You are our lucky grand prize winner!")
|
||||
message = pick("You have won tickets to the newest ACTION JAXSON MOVIE!",\
|
||||
"You have won tickets to the newest crime drama DETECTIVE MYSTERY IN THE CLAMITY CAPER!",\
|
||||
"You have won tickets to the newest romantic comedy 16 RULES OF LOVE!",\
|
||||
"You have won tickets to the newest thriller THE CULT OF THE SLEEPING ONE!")
|
||||
|
||||
if (useMS.send_pda_message("[P.owner]", sender, message)) //Message been filtered by spam filter.
|
||||
return
|
||||
|
||||
last_spam_time = world.time
|
||||
|
||||
if (prob(50)) //Give the AI an increased chance to intercept the message
|
||||
for(var/mob/living/silicon/ai/ai in mob_list)
|
||||
// Allows other AIs to intercept the message but the AI won't intercept their own message.
|
||||
if(ai.aiPDA != P && ai.aiPDA != src)
|
||||
ai.show_message("<i>Intercepted message from <b>[sender]</b></i> (Unknown / spam?) <i>to <b>[P:owner]</b>: [message]</i>")
|
||||
|
||||
//Commented out because we don't send messages like this anymore. Instead it will just popup in their chat window.
|
||||
//P.tnote += "<i><b>← From [sender] (Unknown / spam?):</b></i><br>[message]<br>"
|
||||
|
||||
if (!P.message_silent)
|
||||
playsound(P.loc, 'sound/machines/twobeep.ogg', 50, 1)
|
||||
for (var/mob/O in hearers(3, P.loc))
|
||||
if(!P.message_silent) O.show_message(text("\icon[P] *[P.ttone]*"))
|
||||
//Search for holder of the PDA.
|
||||
var/mob/living/L = null
|
||||
if(P.loc && isliving(P.loc))
|
||||
L = P.loc
|
||||
//Maybe they are a pAI!
|
||||
else
|
||||
L = get(P, /mob/living/silicon)
|
||||
|
||||
if(L)
|
||||
to_chat(L, "\icon[P] <b>Message from [sender] (Unknown / spam?), </b>\"[message]\" (Unable to Reply)")
|
||||
|
||||
/datum/gm_action/pda_spam/get_weight()
|
||||
return 25 * metric.count_people_in_department(DEPARTMENT_EVERYONE)
|
||||
@@ -1,33 +0,0 @@
|
||||
/datum/gm_action/planet_weather_shift
|
||||
name = "sudden weather shift"
|
||||
enabled = TRUE
|
||||
departments = list(DEPARTMENT_EVERYONE)
|
||||
reusable = TRUE
|
||||
var/datum/planet/target_planet
|
||||
|
||||
var/list/banned_weathers = list(
|
||||
/datum/weather/sif/ash_storm,
|
||||
/datum/weather/sif/emberfall,
|
||||
/datum/weather/sif/blood_moon,
|
||||
/datum/weather/sif/fallout)
|
||||
var/list/possible_weathers = list()
|
||||
|
||||
/datum/gm_action/planet_weather_shift/set_up()
|
||||
if(!target_planet || isnull(target_planet))
|
||||
target_planet = pick(SSplanets.planets)
|
||||
possible_weathers |= target_planet.weather_holder.allowed_weather_types
|
||||
possible_weathers -= banned_weathers
|
||||
return
|
||||
|
||||
/datum/gm_action/planet_weather_shift/get_weight()
|
||||
return max(0, -15 + (metric.count_all_outdoor_mobs() * 20))
|
||||
|
||||
/datum/gm_action/planet_weather_shift/start()
|
||||
..()
|
||||
var/new_weather = pick(possible_weathers)
|
||||
target_planet.weather_holder.change_weather(new_weather)
|
||||
|
||||
/datum/gm_action/planet_weather_shift/announce()
|
||||
spawn(rand(3 SECONDS, 2 MINUTES))
|
||||
command_announcement.Announce("Local weather patterns on [target_planet.name] suggest that a sudden atmospheric fluctuation has occurred. All groundside personnel should be wary of rapidly deteriorating conditions.", "Weather Alert")
|
||||
return
|
||||
@@ -1,93 +0,0 @@
|
||||
/datum/gm_action/prison_break
|
||||
name = "prison break"
|
||||
departments = list(DEPARTMENT_SECURITY, DEPARTMENT_SYNTHETIC)
|
||||
|
||||
var/start_time = 0
|
||||
var/active = FALSE // Are we doing stuff?
|
||||
var/releaseWhen = 60 // The delay for the breakout to occur.
|
||||
var/list/area/areas = list() // List of areas to affect. Filled by start()
|
||||
|
||||
var/eventDept = "Security" // Department name in announcement
|
||||
var/list/areaName = list("Brig") // Names of areas mentioned in AI and Engineering announcements
|
||||
var/list/areaType = list(/area/security/prison, /area/security/brig) // Area types to include.
|
||||
var/list/areaNotType = list() // Area types to specifically exclude.
|
||||
|
||||
/datum/gm_action/prison_break/get_weight()
|
||||
var/afflicted_staff = 0
|
||||
var/assigned_staff = metric.count_people_in_department(DEPARTMENT_ENGINEERING)
|
||||
for(var/department in departments)
|
||||
afflicted_staff += round(metric.count_people_in_department(department) / 2)
|
||||
|
||||
var/weight = 20 + (assigned_staff * 10)
|
||||
|
||||
if(assigned_staff)
|
||||
weight += afflicted_staff
|
||||
|
||||
return weight
|
||||
|
||||
/datum/gm_action/prison_break/virology
|
||||
name = "virology breakout"
|
||||
departments = list(DEPARTMENT_MEDICAL, DEPARTMENT_SYNTHETIC)
|
||||
eventDept = "Medical"
|
||||
areaName = list("Virology")
|
||||
areaType = list(/area/medical/virology, /area/medical/virologyaccess)
|
||||
|
||||
/datum/gm_action/prison_break/xenobiology
|
||||
name = "xenobiology breakout"
|
||||
departments = list(DEPARTMENT_RESEARCH, DEPARTMENT_SYNTHETIC)
|
||||
eventDept = "Science"
|
||||
areaName = list("Xenobiology")
|
||||
areaType = list(/area/rnd/xenobiology)
|
||||
areaNotType = list(/area/rnd/xenobiology/xenoflora, /area/rnd/xenobiology/xenoflora_storage)
|
||||
|
||||
/datum/gm_action/prison_break/station
|
||||
name = "station-wide breakout"
|
||||
departments = list(DEPARTMENT_SECURITY, DEPARTMENT_MEDICAL, DEPARTMENT_RESEARCH, DEPARTMENT_SYNTHETIC)
|
||||
eventDept = "Station"
|
||||
areaName = list("Brig","Virology","Xenobiology")
|
||||
areaType = list(/area/security/prison, /area/security/brig, /area/medical/virology, /area/medical/virologyaccess, /area/rnd/xenobiology)
|
||||
areaNotType = list(/area/rnd/xenobiology/xenoflora, /area/rnd/xenobiology/xenoflora_storage)
|
||||
|
||||
/datum/gm_action/prison_break/set_up()
|
||||
releaseWhen = rand(60, 90)
|
||||
start_time = world.time
|
||||
active = TRUE
|
||||
length = releaseWhen + 1 SECOND
|
||||
|
||||
/datum/gm_action/prison_break/announce()
|
||||
if(areas && areas.len > 0)
|
||||
command_announcement.Announce("[pick("Gr3y.T1d3 virus","Malignant trojan")] detected in [station_name()] [(eventDept == "Security")? "imprisonment":"containment"] subroutines. Secure any compromised areas immediately. Station AI involvement is recommended.", "[eventDept] Alert")
|
||||
|
||||
/datum/gm_action/prison_break/start()
|
||||
..()
|
||||
for(var/area/A in all_areas)
|
||||
if(is_type_in_list(A,areaType) && !is_type_in_list(A,areaNotType))
|
||||
areas += A
|
||||
|
||||
if(areas && areas.len > 0)
|
||||
var/my_department = "[station_name()] firewall subroutines"
|
||||
var/rc_message = "An unknown malicious program has been detected in the [english_list(areaName)] lighting and airlock control systems at [stationtime2text()]. Systems will be fully compromised within approximately three minutes. Direct intervention is required immediately.<br>"
|
||||
for(var/obj/machinery/message_server/MS in machines)
|
||||
MS.send_rc_message("Engineering", my_department, rc_message, "", "", 2)
|
||||
for(var/mob/living/silicon/ai/A in player_list)
|
||||
to_chat(A, "<span class='danger'>Malicious program detected in the [english_list(areaName)] lighting and airlock control systems by [my_department].</span>")
|
||||
|
||||
else
|
||||
to_world_log("ERROR: Could not initate grey-tide. Unable to find suitable containment area.")
|
||||
|
||||
if(areas && areas.len > 0)
|
||||
spawn()
|
||||
while(active)
|
||||
sleep(1)
|
||||
if(world.time >= releaseWhen + start_time)
|
||||
var/obj/machinery/power/apc/theAPC = null
|
||||
for(var/area/A in areas)
|
||||
theAPC = A.get_apc()
|
||||
if(theAPC.operating) //If the apc's off, it's a little hard to overload the lights.
|
||||
for(var/obj/machinery/light/L in A)
|
||||
L.flicker(10)
|
||||
|
||||
/datum/gm_action/prison_break/end()
|
||||
active = FALSE
|
||||
for(var/area/A in shuffle(areas))
|
||||
A.prison_break()
|
||||
@@ -1,67 +0,0 @@
|
||||
/datum/gm_action/radiation_storm
|
||||
name = "radiation storm"
|
||||
departments = list(DEPARTMENT_EVERYONE)
|
||||
reusable = TRUE
|
||||
|
||||
var/enterBelt = 30
|
||||
var/radIntervall = 5
|
||||
var/leaveBelt = 80
|
||||
var/revokeAccess = 165
|
||||
var/activeFor = 0
|
||||
var/postStartTicks = 0
|
||||
var/active = FALSE
|
||||
|
||||
/datum/gm_action/radiation_storm/announce()
|
||||
command_announcement.Announce("High levels of radiation detected near \the [station_name()]. Please evacuate into one of the shielded maintenance tunnels.", "Anomaly Alert", new_sound = 'sound/AI/radiation.ogg')
|
||||
|
||||
/datum/gm_action/radiation_storm/set_up()
|
||||
active = TRUE
|
||||
|
||||
/datum/gm_action/radiation_storm/start()
|
||||
..()
|
||||
make_maint_all_access()
|
||||
|
||||
while(active)
|
||||
sleep(1 SECOND)
|
||||
activeFor ++
|
||||
if(activeFor == enterBelt)
|
||||
command_announcement.Announce("The station has entered the radiation belt. Please remain in a sheltered area until we have passed the radiation belt.", "Anomaly Alert")
|
||||
radiate()
|
||||
|
||||
if(activeFor >= enterBelt && activeFor <= leaveBelt)
|
||||
postStartTicks++
|
||||
|
||||
if(postStartTicks == radIntervall)
|
||||
postStartTicks = 0
|
||||
radiate()
|
||||
|
||||
else if(activeFor == leaveBelt)
|
||||
command_announcement.Announce("The station has passed the radiation belt. Please allow for up to one minute while radiation levels dissipate, and report to medbay if you experience any unusual symptoms. Maintenance will lose all access again shortly.", "Anomaly Alert")
|
||||
|
||||
/datum/gm_action/radiation_storm/proc/radiate()
|
||||
var/radiation_level = rand(15, 35)
|
||||
for(var/z in using_map.station_levels)
|
||||
SSradiation.z_radiate(locate(1, 1, z), radiation_level, 1)
|
||||
|
||||
for(var/mob/living/carbon/C in living_mob_list)
|
||||
var/area/A = get_area(C)
|
||||
if(!A)
|
||||
continue
|
||||
if(A.flags & RAD_SHIELDED)
|
||||
continue
|
||||
if(istype(C,/mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = C
|
||||
if(prob(5))
|
||||
if (prob(75))
|
||||
randmutb(H) // Applies bad mutation
|
||||
domutcheck(H,null,MUTCHK_FORCED)
|
||||
else
|
||||
randmutg(H) // Applies good mutation
|
||||
domutcheck(H,null,MUTCHK_FORCED)
|
||||
|
||||
/datum/gm_action/radiation_storm/end()
|
||||
spawn(revokeAccess SECONDS)
|
||||
revoke_maint_all_access()
|
||||
|
||||
/datum/gm_action/radiation_storm/get_weight()
|
||||
return 20 + (metric.count_people_in_department(DEPARTMENT_MEDICAL) * 10) + (metric.count_all_space_mobs() * 40) + (metric.count_people_in_department(DEPARTMENT_EVERYONE) * 20)
|
||||
@@ -1,23 +0,0 @@
|
||||
// The random spawn proc on the antag datum will handle announcing the spawn and whatnot.
|
||||
/datum/gm_action/random_antag
|
||||
name = "random antagonist"
|
||||
departments = list(DEPARTMENT_EVERYONE)
|
||||
chaotic = 30
|
||||
reusable = TRUE
|
||||
|
||||
/datum/gm_action/random_antag/start()
|
||||
..()
|
||||
var/list/valid_types = list()
|
||||
for(var/antag_type in all_antag_types)
|
||||
var/datum/antagonist/antag = all_antag_types[antag_type]
|
||||
if(antag.flags & ANTAG_RANDSPAWN)
|
||||
valid_types |= antag
|
||||
if(valid_types.len)
|
||||
var/datum/antagonist/antag = pick(valid_types)
|
||||
antag.attempt_random_spawn()
|
||||
|
||||
/datum/gm_action/random_antag/get_weight()
|
||||
. = ..()
|
||||
if(gm)
|
||||
var/weight = max(0, (metric.count_people_in_department(DEPARTMENT_SECURITY) * 20) + (metric.count_people_in_department(DEPARTMENT_EVERYONE) * 5) + gm.staleness)
|
||||
return weight
|
||||
@@ -1,21 +0,0 @@
|
||||
/datum/gm_action/security_drill
|
||||
name = "security drills"
|
||||
departments = list(DEPARTMENT_SECURITY, DEPARTMENT_EVERYONE)
|
||||
chaos_threshold = 20 // To avoid CentCom from mandating a drill while people are dying left and right.
|
||||
|
||||
/datum/gm_action/security_drill/announce()
|
||||
command_announcement.Announce("[pick("A NanoTrasen security director", "A Vir-Gov correspondant", "Local Sif authoritiy")] \
|
||||
has advised the enactment of [pick("a rampant wildlife", "a fire", "a hostile boarding", "a nonstandard", \
|
||||
"a bomb", "an emergent intelligence")] drill with the personnel onboard \the [station_name()].", "Security Advisement")
|
||||
|
||||
/datum/gm_action/security_drill/get_weight()
|
||||
var/sec = metric.count_people_in_department(DEPARTMENT_SECURITY)
|
||||
var/everyone = metric.count_people_in_department(DEPARTMENT_EVERYONE)
|
||||
|
||||
if(!sec) // If there's no security, then there is no drill.
|
||||
return 0
|
||||
if(everyone - sec < 0) // If there's no non-sec, then there is no drill.
|
||||
return 0
|
||||
|
||||
// Each security player adds +5 weight, while non-security adds +1.5.
|
||||
return (sec * 5) + ((everyone - sec) * 1.5)
|
||||
@@ -1,66 +0,0 @@
|
||||
/datum/gm_action/rogue_drone
|
||||
name = "rogue drones"
|
||||
departments = list(DEPARTMENT_SECURITY)
|
||||
chaotic = 20
|
||||
chaos_threshold = EVENT_CHAOS_THRESHOLD_MEDIUM_IMPACT
|
||||
length = 20 MINUTES
|
||||
var/list/drones_list = list()
|
||||
|
||||
/datum/gm_action/rogue_drone/start()
|
||||
..()
|
||||
//spawn them at the same place as carp
|
||||
var/list/possible_spawns = list()
|
||||
for(var/obj/effect/landmark/C in landmarks_list)
|
||||
if(C.name == "carpspawn")
|
||||
possible_spawns.Add(C)
|
||||
|
||||
//25% chance for this to be a false alarm
|
||||
var/num
|
||||
if(prob(25))
|
||||
num = 0
|
||||
else
|
||||
num = rand(2,6)
|
||||
for(var/i=0, i<num, i++)
|
||||
var/mob/living/simple_mob/mechanical/combat_drone/event/D = new(get_turf(pick(possible_spawns)))
|
||||
drones_list.Add(D)
|
||||
|
||||
/datum/gm_action/rogue_drone/announce()
|
||||
var/msg
|
||||
var/rng = rand(1,5)
|
||||
switch(rng)
|
||||
if(1)
|
||||
msg = "A combat drone wing operating in close orbit above Sif has failed to return from a anti-piracy sweep. If any are sighted, \
|
||||
approach with caution."
|
||||
if(2)
|
||||
msg = "Contact has been lost with a combat drone wing in Sif orbit. If any are sighted in the area, approach with \
|
||||
caution."
|
||||
if(3)
|
||||
msg = "Unidentified hackers have targeted a combat drone wing deployed around Sif. If any are sighted in the area, approach with caution."
|
||||
if(4)
|
||||
msg = "A passing derelict ship's drone defense systems have just activated. If any are sighted in the area, use caution."
|
||||
if(5)
|
||||
msg = "We're detecting a swarm of small objects approaching your station. Most likely a bunch of drones. Please exercise caution if you see any."
|
||||
|
||||
command_announcement.Announce(msg, "Rogue drone alert")
|
||||
|
||||
/datum/gm_action/rogue_drone/end()
|
||||
var/num_recovered = 0
|
||||
for(var/mob/living/simple_mob/mechanical/combat_drone/D in drones_list)
|
||||
var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread()
|
||||
sparks.set_up(3, 0, D.loc)
|
||||
sparks.start()
|
||||
D.z = using_map.admin_levels[1]
|
||||
D.loot_list = list()
|
||||
|
||||
qdel(D)
|
||||
num_recovered++
|
||||
|
||||
if(num_recovered > drones_list.len * 0.75)
|
||||
command_announcement.Announce("The drones that were malfunctioning have been recovered safely.", "Rogue drone alert")
|
||||
else
|
||||
command_announcement.Announce("We're disappointed at the loss of the drones, but the survivors have been recovered.", "Rogue drone alert")
|
||||
|
||||
/datum/gm_action/rogue_drone/get_weight()
|
||||
. = 20 // Start with a base weight of 20, since this event does provide some value even if no sec is around.
|
||||
. += metric.count_people_in_department(DEPARTMENT_SECURITY) * 10 // Each sec adds 10.
|
||||
. += metric.count_all_space_mobs() * 30 // Each player currently EVA adds 30.
|
||||
@@ -1,59 +0,0 @@
|
||||
/datum/gm_action/spider_infestation
|
||||
name = "spider infestation"
|
||||
departments = list(DEPARTMENT_SECURITY, DEPARTMENT_MEDICAL, DEPARTMENT_EVERYONE)
|
||||
chaotic = 30
|
||||
chaos_threshold = EVENT_CHAOS_THRESHOLD_MEDIUM_IMPACT
|
||||
|
||||
severity = 1
|
||||
|
||||
var/spawncount = 1
|
||||
|
||||
var/spawntype = /obj/effect/spider/spiderling
|
||||
|
||||
/datum/gm_action/spider_infestation/set_up()
|
||||
severity = pickweight(EVENT_LEVEL_MUNDANE = max(1,(12 - (3 * metric.count_people_in_department(DEPARTMENT_SECURITY)))),
|
||||
EVENT_LEVEL_MODERATE = (7 + (2 * metric.count_people_in_department(DEPARTMENT_SECURITY))),
|
||||
EVENT_LEVEL_MAJOR = (1 + (2 * metric.count_people_in_department(DEPARTMENT_SECURITY)))
|
||||
)
|
||||
|
||||
switch(severity)
|
||||
if(EVENT_LEVEL_MUNDANE)
|
||||
spawntype = /obj/effect/spider/spiderling/stunted
|
||||
if(EVENT_LEVEL_MODERATE)
|
||||
spawntype = /obj/effect/spider/spiderling
|
||||
if(EVENT_LEVEL_MAJOR)
|
||||
spawntype = /obj/effect/spider/spiderling
|
||||
|
||||
spawncount = rand(4 * severity, 6 * severity)
|
||||
|
||||
/datum/gm_action/spider_infestation/announce()
|
||||
command_announcement.Announce("Unidentified lifesigns detected coming aboard [station_name()]. \
|
||||
Secure any exterior access, including ducting and ventilation.", "Lifesign Alert", new_sound = 'sound/AI/aliens.ogg')
|
||||
|
||||
if(severity >= EVENT_LEVEL_MAJOR)
|
||||
spawn(rand(600, 3000))
|
||||
command_announcement.Announce("Unidentified lifesigns previously detected coming aboard [station_name()] \
|
||||
have been classified as a swarm of arachnids. Extreme caution is advised.", "Arachnid Alert")
|
||||
|
||||
/datum/gm_action/spider_infestation/start()
|
||||
..()
|
||||
var/list/vents = list()
|
||||
for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in machines)
|
||||
if(!temp_vent.welded && temp_vent.network && temp_vent.loc.z in using_map.station_levels)
|
||||
if(temp_vent.network.normal_members.len > 50)
|
||||
vents += temp_vent
|
||||
|
||||
while((spawncount >= 1) && vents.len)
|
||||
var/obj/vent = pick(vents)
|
||||
new /obj/effect/spider/spiderling(vent.loc)
|
||||
vents -= vent
|
||||
spawncount--
|
||||
|
||||
/datum/gm_action/spider_infestation/get_weight()
|
||||
var/security = metric.count_people_in_department(DEPARTMENT_SECURITY)
|
||||
var/medical = metric.count_people_in_department(DEPARTMENT_MEDICAL)
|
||||
var/engineering = metric.count_people_in_department(DEPARTMENT_ENGINEERING)
|
||||
|
||||
var/assigned_staff = security + round(medical / 2) + round(engineering / 2)
|
||||
|
||||
return 10 + (assigned_staff * 15)
|
||||
@@ -1,49 +0,0 @@
|
||||
/datum/gm_action/security_screening
|
||||
name = "security screening"
|
||||
departments = list(DEPARTMENT_SECURITY, DEPARTMENT_EVERYONE)
|
||||
|
||||
var/list/species_weights = list(
|
||||
SPECIES_SKRELL = 9,
|
||||
SPECIES_UNATHI = 15,
|
||||
SPECIES_HUMAN_VATBORN = 6,
|
||||
SPECIES_TESHARI = 2,
|
||||
SPECIES_TAJ = 3,
|
||||
SPECIES_DIONA = 1,
|
||||
SPECIES_ZADDAT = 25,
|
||||
SPECIES_HUMAN = 3,
|
||||
SPECIES_PROMETHEAN = 30
|
||||
)
|
||||
|
||||
var/list/synth_weights = list(
|
||||
"Cybernetic" = 15,
|
||||
"Drone" = 30,
|
||||
"Positronic" = 25
|
||||
)
|
||||
|
||||
var/list/end_weights = list()
|
||||
|
||||
/datum/gm_action/security_screening/set_up()
|
||||
for(var/species_name in species_weights)
|
||||
var/giveweight = 0
|
||||
|
||||
for(var/datum/data/record/R in data_core.general)
|
||||
if(R.fields["species"] == species_name)
|
||||
giveweight += species_weights[species_name]
|
||||
|
||||
end_weights[species_name] = giveweight
|
||||
|
||||
for(var/bottype in synth_weights)
|
||||
var/giveweight = 0
|
||||
|
||||
for(var/datum/data/record/R in data_core.general)
|
||||
if(R.fields["brain_type"] == bottype)
|
||||
giveweight += synth_weights[bottype]
|
||||
|
||||
end_weights[bottype] = giveweight
|
||||
|
||||
/datum/gm_action/security_screening/announce()
|
||||
spawn(rand(1 MINUTE, 2 MINUTES))
|
||||
command_announcement.Announce("[pick("A nearby Navy vessel", "A Solar official", "A Vir-Gov official", "A NanoTrasen board director")] has requested the screening of [pick("every other", "every", "suspicious", "willing")] [pickweight(end_weights)] personnel onboard \the [station_name()].", "Security Advisement")
|
||||
|
||||
/datum/gm_action/security_screening/get_weight()
|
||||
return max(-20, 10 + round(gm.staleness * 1.5) - (gm.danger * 2)) + (metric.count_people_in_department(DEPARTMENT_SECURITY) * 10) + (metric.count_people_in_department(DEPARTMENT_EVERYONE) * 1.5)
|
||||
@@ -1,17 +0,0 @@
|
||||
/datum/gm_action/shipping_error
|
||||
name = "shipping error"
|
||||
departments = list(DEPARTMENT_CARGO)
|
||||
reusable = TRUE
|
||||
|
||||
/datum/gm_action/shipping_error/get_weight()
|
||||
var/cargo = metric.count_people_in_department(DEPARTMENT_CARGO)
|
||||
var/weight = (cargo * 40)
|
||||
return weight
|
||||
|
||||
/datum/gm_action/shipping_error/start()
|
||||
..()
|
||||
var/datum/supply_order/O = new /datum/supply_order()
|
||||
O.ordernum = supply_controller.ordernum
|
||||
O.object = supply_controller.supply_pack[pick(supply_controller.supply_pack)]
|
||||
O.ordered_by = random_name(pick(MALE,FEMALE), species = "Human")
|
||||
supply_controller.shoppinglist += O
|
||||
@@ -1,56 +0,0 @@
|
||||
/datum/gm_action/solar_storm
|
||||
name = "solar storm"
|
||||
var/rad_interval = 1 SECOND
|
||||
var/base_solar_gen_rate
|
||||
length = 3 MINUTES
|
||||
var/duration // Duration for the storm
|
||||
var/start_time = 0
|
||||
|
||||
reusable = TRUE
|
||||
|
||||
/datum/gm_action/solar_storm/set_up()
|
||||
start_time = world.time
|
||||
duration = length
|
||||
duration += rand(-1 * 1 MINUTE, 1 MINUTE)
|
||||
|
||||
/datum/gm_action/solar_storm/announce()
|
||||
command_announcement.Announce("A solar storm has been detected approaching \the [station_name()]. Please halt all EVA activites immediately and return to the interior of the station.", "Anomaly Alert", new_sound = 'sound/AI/radiation.ogg')
|
||||
adjust_solar_output(1.5)
|
||||
|
||||
/datum/gm_action/solar_storm/proc/adjust_solar_output(var/mult = 1)
|
||||
if(isnull(base_solar_gen_rate)) base_solar_gen_rate = GLOB.solar_gen_rate
|
||||
GLOB.solar_gen_rate = mult * base_solar_gen_rate
|
||||
|
||||
/datum/gm_action/solar_storm/start()
|
||||
..()
|
||||
length = duration
|
||||
command_announcement.Announce("The solar storm has reached the station. Please refain from EVA and remain inside the station until it has passed.", "Anomaly Alert")
|
||||
adjust_solar_output(5)
|
||||
|
||||
var/start_time = world.time
|
||||
|
||||
spawn()
|
||||
while(world.time <= start_time + duration)
|
||||
sleep(rad_interval)
|
||||
radiate()
|
||||
|
||||
/datum/gm_action/solar_storm/get_weight()
|
||||
return 20 + (metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 10) + (metric.count_all_space_mobs() * 30)
|
||||
|
||||
/datum/gm_action/solar_storm/proc/radiate()
|
||||
// Note: Too complicated to be worth trying to use the radiation system for this. Its only in space anyway, so we make an exception in this case.
|
||||
for(var/mob/living/L in player_list)
|
||||
var/turf/T = get_turf(L)
|
||||
if(!T)
|
||||
continue
|
||||
|
||||
if(!istype(T.loc,/area/space) && !istype(T,/turf/space)) //Make sure you're in a space area or on a space turf
|
||||
continue
|
||||
|
||||
//Todo: Apply some burn damage from the heat of the sun. Until then, enjoy some moderate radiation.
|
||||
L.rad_act(rand(15, 30))
|
||||
|
||||
/datum/gm_action/solar_storm/end()
|
||||
command_announcement.Announce("The solar storm has passed the station. It is now safe to resume EVA activities. Please report to medbay if you experience any unusual symptoms. ", "Anomaly Alert")
|
||||
adjust_solar_output()
|
||||
length = initial(length)
|
||||
@@ -1,14 +0,0 @@
|
||||
/datum/gm_action/spacevine
|
||||
name = "space-vine infestation"
|
||||
departments = list(DEPARTMENT_ENGINEERING)
|
||||
chaotic = 2
|
||||
|
||||
/datum/gm_action/spacevine/start()
|
||||
..()
|
||||
spacevine_infestation()
|
||||
|
||||
/datum/gm_action/spacevine/announce()
|
||||
level_seven_announcement()
|
||||
|
||||
/datum/gm_action/spacevine/get_weight()
|
||||
return 20 + (metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 20) + (metric.count_people_in_department(DEPARTMENT_EVERYONE) * 10)
|
||||
@@ -1,13 +0,0 @@
|
||||
/datum/gm_action/spontaneous_appendicitis
|
||||
name = "appendicitis"
|
||||
departments = list(DEPARTMENT_MEDICAL, DEPARTMENT_EVERYONE)
|
||||
chaotic = 1
|
||||
|
||||
/datum/gm_action/spontaneous_appendicitis/start()
|
||||
..()
|
||||
for(var/mob/living/carbon/human/H in shuffle(living_mob_list))
|
||||
if(H.client && !player_is_antag(H.mind) && H.appendicitis())
|
||||
break
|
||||
|
||||
/datum/gm_action/spontaneous_appendicitis/get_weight()
|
||||
return max(0, -5 + (metric.count_people_in_department(DEPARTMENT_MEDICAL) * 10))
|
||||
@@ -1,14 +0,0 @@
|
||||
/datum/gm_action/station_fund_raise
|
||||
name = "local funding drive"
|
||||
departments = list(DEPARTMENT_SECURITY, DEPARTMENT_CARGO, DEPARTMENT_EVERYONE)
|
||||
|
||||
/datum/gm_action/station_fund_raise/announce()
|
||||
spawn(rand(1 MINUTE, 2 MINUTES))
|
||||
command_announcement.Announce("Due to [pick("recent", "unfortunate", "possible future")] budget [pick("changes", "issues")], in-system stations are now advised to increase funding income.", "Security & Supply Advisement")
|
||||
|
||||
/datum/gm_action/station_fund_raise/get_weight()
|
||||
var/weight_modifier = 0.5
|
||||
if(station_account.money <= 80000)
|
||||
weight_modifier = 1
|
||||
|
||||
return (max(-20, 10 + gm.staleness) + ((metric.count_people_in_department(DEPARTMENT_SECURITY) + (metric.count_people_in_department(DEPARTMENT_CARGO))) * 5) + (metric.count_people_in_department(DEPARTMENT_EVERYONE) * 3)) * weight_modifier
|
||||
@@ -1,80 +0,0 @@
|
||||
/datum/gm_action/stowaway
|
||||
name = "stowaway pod"
|
||||
departments = list(DEPARTMENT_EVERYONE, DEPARTMENT_SECURITY)
|
||||
chaotic = 10
|
||||
observers_used = TRUE
|
||||
var/area/target_area // Chosen target area
|
||||
var/area/target_turf // Chosen target turf in target_area
|
||||
var/list/area/excluded = list(
|
||||
/area/submap,
|
||||
/area/shuttle,
|
||||
/area/crew_quarters,
|
||||
/area/holodeck,
|
||||
/area/engineering/engine_room
|
||||
)
|
||||
|
||||
var/list/area/included = list(
|
||||
/area/maintenance
|
||||
)
|
||||
|
||||
/datum/gm_action/stowaway/set_up()
|
||||
severity = pickweight(EVENT_LEVEL_MUNDANE = 20,
|
||||
EVENT_LEVEL_MODERATE = 5,
|
||||
EVENT_LEVEL_MAJOR = 1
|
||||
)
|
||||
|
||||
var/list/area/grand_list_of_areas = get_station_areas(excluded)
|
||||
|
||||
for(var/area/Incl in included)
|
||||
for(var/area/A in grand_list_of_areas)
|
||||
if(!istype(A, Incl))
|
||||
grand_list_of_areas -= A
|
||||
|
||||
// Okay, now lets try and pick a target! Lets try 10 times, otherwise give up
|
||||
for(var/i in 1 to 10)
|
||||
var/area/A = pick(grand_list_of_areas)
|
||||
if(is_area_occupied(A))
|
||||
log_debug("[name] event: Rejected [A] because it is occupied.")
|
||||
continue
|
||||
// A good area, great! Lets try and pick a turf
|
||||
var/list/turfs = list()
|
||||
for(var/turf/simulated/floor/F in A)
|
||||
if(turf_clear(F))
|
||||
turfs += F
|
||||
if(turfs.len == 0)
|
||||
log_debug("[name] event: Rejected [A] because it has no clear turfs.")
|
||||
continue
|
||||
target_area = A
|
||||
target_turf = pick(turfs)
|
||||
|
||||
if(!target_area)
|
||||
log_debug("[name] event: Giving up after too many failures to pick target area")
|
||||
return
|
||||
|
||||
/datum/gm_action/stowaway/start()
|
||||
if(!target_turf)
|
||||
return
|
||||
..()
|
||||
|
||||
var/obj/structure/ghost_pod/ghost_activated/human/HP = new (target_turf)
|
||||
|
||||
if(severity == EVENT_LEVEL_MUNDANE || istype(ticker.mode, /datum/game_mode/extended))
|
||||
HP.make_antag = MODE_STOWAWAY
|
||||
|
||||
else if(severity == EVENT_LEVEL_MODERATE)
|
||||
HP.make_antag = MODE_RENEGADE
|
||||
HP.occupant_type = "renegade [HP.occupant_type]"
|
||||
|
||||
else if(severity == EVENT_LEVEL_MAJOR)
|
||||
HP.make_antag = MODE_INFILTRATOR
|
||||
HP.occupant_type = "volatile [HP.occupant_type]"
|
||||
|
||||
say_dead_object("A <span class='notice'>[HP.occupant_type]</span> pod is now available in \the [target_area].", HP)
|
||||
|
||||
/datum/gm_action/stowaway/get_weight()
|
||||
return -20 + (metric.count_people_in_department(DEPARTMENT_SECURITY) * 15 + metric.count_people_in_department(DEPARTMENT_SYNTHETIC) * 5 + metric.count_people_in_department(DEPARTMENT_EVERYONE) * 1)
|
||||
|
||||
/datum/gm_action/stowaway/announce()
|
||||
spawn(rand(15 MINUTES, 30 MINUTES))
|
||||
if(prob(20) && severity >= EVENT_LEVEL_MODERATE && atc && !atc.squelched)
|
||||
atc.msg("Attention civilian vessels in [using_map.starsys_name] shipping lanes, caution is advised as [pick("an unidentified vessel", "a known criminal's vessel", "a derelict vessel")] has been detected passing multiple local stations.")
|
||||
@@ -1,65 +0,0 @@
|
||||
/datum/gm_action/nanotrasen_budget_allocation
|
||||
name = "supply point to cargo budget"
|
||||
enabled = TRUE
|
||||
departments = list(DEPARTMENT_CARGO)
|
||||
chaotic = 0
|
||||
reusable = TRUE
|
||||
|
||||
var/datum/controller/supply/SC
|
||||
var/running = FALSE
|
||||
var/last_run
|
||||
|
||||
var/thaler_earned
|
||||
|
||||
/datum/gm_action/nanotrasen_budget_allocation/New()
|
||||
..()
|
||||
SC = supply_controller
|
||||
|
||||
/datum/gm_action/nanotrasen_budget_allocation/set_up()
|
||||
running = TRUE
|
||||
return
|
||||
|
||||
/datum/gm_action/nanotrasen_budget_allocation/get_weight()
|
||||
. = round(SC.points / 15)
|
||||
|
||||
var/cargo = metric.count_people_in_department(DEPARTMENT_CARGO)
|
||||
var/personnel = metric.count_people_in_department(DEPARTMENT_EVERYONE)
|
||||
if(cargo)
|
||||
. = round(SC.points / (10 + personnel)) + cargo * 10
|
||||
|
||||
if(running || ( world.time < (last_run + 30 MINUTES)))
|
||||
. = 0
|
||||
|
||||
return .
|
||||
|
||||
/datum/gm_action/nanotrasen_budget_allocation/start()
|
||||
. = ..()
|
||||
|
||||
last_run = world.time
|
||||
|
||||
var/point_difference = SC.points
|
||||
|
||||
if(SC.points >= 1000)
|
||||
SC.points = round(SC.points / 3)
|
||||
point_difference -= SC.points
|
||||
|
||||
else if(SC.points >= 500)
|
||||
SC.points -= 100 * (rand(5, 20) / 10)
|
||||
point_difference -= SC.points
|
||||
|
||||
else
|
||||
SC.points = round(SC.points / 1.25)
|
||||
point_difference -= SC.points
|
||||
|
||||
if(point_difference > 0)
|
||||
thaler_earned = round(point_difference / SC.points_per_money)
|
||||
|
||||
/datum/gm_action/nanotrasen_budget_allocation/end()
|
||||
spawn(5 MINUTES)
|
||||
running = FALSE
|
||||
return
|
||||
|
||||
/datum/gm_action/nanotrasen_budget_allocation/announce()
|
||||
spawn(rand(1 MINUTE, 5 MINUTES))
|
||||
command_announcement.Announce("[station_name()] Supply Department has earned a converted thaler budget of [thaler_earned] due to their backlogged daily requisition tokens.", "Supply Budget Conversion")
|
||||
return
|
||||
@@ -1,11 +0,0 @@
|
||||
/datum/gm_action/request
|
||||
name = "general request"
|
||||
departments = list(DEPARTMENT_CARGO)
|
||||
|
||||
/datum/gm_action/request/announce()
|
||||
spawn(rand(1 MINUTE, 2 MINUTES))
|
||||
command_announcement.Announce("[pick("A nearby vessel", "A Solar contractor", "A Skrellian contractor", "A NanoTrasen board director")] has requested the delivery of [pick("one","two","three","several")] [pick("medical","engineering","research","civilian")] supply packages. The [station_name()] has been tasked with completing this request.", "Supply Request")
|
||||
|
||||
/datum/gm_action/request/get_weight()
|
||||
return max(15, 15 + round(gm.staleness / 2) - gm.danger) + (metric.count_people_in_department(DEPARTMENT_CARGO) * 10)
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
// This event sends a few carp after someone in space.
|
||||
|
||||
/datum/gm_action/surprise_carp_attack
|
||||
name = "surprise carp attack"
|
||||
departments = list(DEPARTMENT_EVERYONE)
|
||||
reusable = TRUE
|
||||
chaotic = 10
|
||||
var/mob/living/victim = null
|
||||
|
||||
/datum/gm_action/surprise_carp_attack/get_weight()
|
||||
return metric.count_all_space_mobs() * 50
|
||||
|
||||
/datum/gm_action/surprise_carp_attack/set_up()
|
||||
var/list/potential_victims = list()
|
||||
victim = null
|
||||
for(var/mob/living/L in player_list)
|
||||
if(!(L.z in using_map.station_levels))
|
||||
continue // Not on the right z-level.
|
||||
if(L.stat)
|
||||
continue // Don't want dead people.
|
||||
var/turf/T = get_turf(L)
|
||||
if(istype(T, /turf/space) && istype(T.loc,/area/space))
|
||||
potential_victims.Add(L)
|
||||
if(potential_victims.len)
|
||||
victim = pick(potential_victims)
|
||||
|
||||
|
||||
/datum/gm_action/surprise_carp_attack/start()
|
||||
..()
|
||||
if(!victim)
|
||||
message_admins("Surprise carp attack failed to find a target.")
|
||||
return
|
||||
var/number_of_carp = rand(1, 2)
|
||||
message_admins("Sending [number_of_carp] carp\s after [victim].")
|
||||
while(number_of_carp)
|
||||
var/turf/spawning_turf = null
|
||||
var/list/nearby_things = oview(10, victim)
|
||||
for(var/turf/space/space in nearby_things)
|
||||
if(get_dist(space, victim) <= 7)
|
||||
continue
|
||||
spawning_turf = space
|
||||
break
|
||||
if(spawning_turf)
|
||||
new /mob/living/simple_mob/animal/space/carp(spawning_turf)
|
||||
number_of_carp--
|
||||
@@ -1,17 +0,0 @@
|
||||
// This event sends one wave of meteors unannounced.
|
||||
|
||||
/datum/gm_action/surprise_meteors
|
||||
name = "surprise meteors"
|
||||
departments = list(DEPARTMENT_ENGINEERING)
|
||||
chaotic = 25
|
||||
|
||||
/datum/gm_action/surprise_meteors/get_weight()
|
||||
var/engineers = metric.count_people_in_department(DEPARTMENT_ENGINEERING)
|
||||
var/weight = (max(engineers - 1, 0) * 25) // If only one engineer exists, no meteors for now.
|
||||
return weight
|
||||
|
||||
/datum/gm_action/surprise_meteors/start()
|
||||
..()
|
||||
spawn(1)
|
||||
spawn_meteors(rand(4, 8), meteors_normal, pick(cardinal))
|
||||
message_admins("Surprise meteors event has ended.")
|
||||
@@ -1,75 +0,0 @@
|
||||
/datum/gm_action/swarm_boarder
|
||||
name = "swarmer shell"
|
||||
departments = list(DEPARTMENT_EVERYONE, DEPARTMENT_SECURITY, DEPARTMENT_ENGINEERING)
|
||||
chaotic = 60
|
||||
observers_used = TRUE
|
||||
var/area/target_area // Chosen target area
|
||||
var/area/target_turf // Chosen target turf in target_area
|
||||
var/list/area/excluded = list(
|
||||
/area/submap,
|
||||
/area/shuttle,
|
||||
/area/crew_quarters,
|
||||
/area/holodeck,
|
||||
/area/engineering/engine_room
|
||||
)
|
||||
|
||||
var/list/area/included = list(
|
||||
/area/maintenance
|
||||
)
|
||||
|
||||
/datum/gm_action/swarm_boarder/set_up()
|
||||
severity = pickweight(EVENT_LEVEL_MUNDANE = 30,
|
||||
EVENT_LEVEL_MODERATE = 10,
|
||||
EVENT_LEVEL_MAJOR = 1
|
||||
)
|
||||
|
||||
var/list/area/grand_list_of_areas = get_station_areas(excluded)
|
||||
|
||||
for(var/area/Incl in included)
|
||||
for(var/area/A in grand_list_of_areas)
|
||||
if(!istype(A, Incl))
|
||||
grand_list_of_areas -= A
|
||||
|
||||
// Okay, now lets try and pick a target! Lets try 10 times, otherwise give up
|
||||
for(var/i in 1 to 10)
|
||||
var/area/A = pick(grand_list_of_areas)
|
||||
if(is_area_occupied(A))
|
||||
log_debug("[name] event: Rejected [A] because it is occupied.")
|
||||
continue
|
||||
// A good area, great! Lets try and pick a turf
|
||||
var/list/turfs = list()
|
||||
for(var/turf/simulated/floor/F in A)
|
||||
if(turf_clear(F))
|
||||
turfs += F
|
||||
if(turfs.len == 0)
|
||||
log_debug("[name] event: Rejected [A] because it has no clear turfs.")
|
||||
continue
|
||||
target_area = A
|
||||
target_turf = pick(turfs)
|
||||
|
||||
if(!target_area)
|
||||
log_debug("[name] event: Giving up after too many failures to pick target area")
|
||||
return
|
||||
|
||||
/datum/gm_action/swarm_boarder/start()
|
||||
if(!target_turf)
|
||||
return
|
||||
..()
|
||||
|
||||
var/swarmertype = /obj/structure/ghost_pod/ghost_activated/swarm_drone/event
|
||||
|
||||
if(severity == EVENT_LEVEL_MODERATE)
|
||||
swarmertype = /obj/structure/ghost_pod/ghost_activated/swarm_drone/event/melee
|
||||
|
||||
if(severity == EVENT_LEVEL_MAJOR)
|
||||
swarmertype = /obj/structure/ghost_pod/ghost_activated/swarm_drone/event/gunner
|
||||
|
||||
new swarmertype(target_turf)
|
||||
|
||||
/datum/gm_action/swarm_boarder/get_weight()
|
||||
return max(0, -60 + (metric.count_people_in_department(DEPARTMENT_SECURITY) * 10 + metric.count_people_in_department(DEPARTMENT_SYNTHETIC) * 5))
|
||||
|
||||
/datum/gm_action/swarm_boarder/announce()
|
||||
spawn(rand(5 MINUTES, 15 MINUTES))
|
||||
if(prob(80) && severity >= EVENT_LEVEL_MODERATE && atc && !atc.squelched)
|
||||
atc.msg("Attention civilian vessels in [using_map.starsys_name] shipping lanes, caution is advised as [pick("an unidentified vessel", "a known criminal's vessel", "a derelict vessel")] has been detected passing multiple local stations.")
|
||||
@@ -1,83 +0,0 @@
|
||||
/var/global/list/event_viruses = list() // so that event viruses are kept around for admin logs, rather than being GCed
|
||||
|
||||
/datum/gm_action/viral_infection
|
||||
name = "viral infection"
|
||||
departments = list(DEPARTMENT_MEDICAL)
|
||||
chaotic = 5
|
||||
var/list/viruses = list()
|
||||
severity = 1
|
||||
|
||||
/datum/gm_action/viral_infection/set_up()
|
||||
severity = pickweight(EVENT_LEVEL_MUNDANE = 20,
|
||||
EVENT_LEVEL_MODERATE = 10,
|
||||
EVENT_LEVEL_MAJOR = 3
|
||||
)
|
||||
|
||||
//generate 1-3 viruses. This way there's an upper limit on how many individual diseases need to be cured if many people are initially infected
|
||||
var/num_diseases = rand(1,3)
|
||||
for (var/i=0, i < num_diseases, i++)
|
||||
var/datum/disease2/disease/D = new /datum/disease2/disease
|
||||
|
||||
var/strength = 1 //whether the disease is of the greater or lesser variety
|
||||
if (severity >= EVENT_LEVEL_MAJOR && prob(75))
|
||||
strength = 2
|
||||
D.makerandom(strength)
|
||||
viruses += D
|
||||
|
||||
/datum/gm_action/viral_infection/announce()
|
||||
var/level
|
||||
if (severity == EVENT_LEVEL_MUNDANE)
|
||||
return
|
||||
else if (severity == EVENT_LEVEL_MODERATE)
|
||||
level = pick("one", "two", "three", "four")
|
||||
else
|
||||
level = "five"
|
||||
|
||||
spawn(rand(0, 3000))
|
||||
if(severity == EVENT_LEVEL_MAJOR || prob(60))
|
||||
command_announcement.Announce("Confirmed outbreak of level [level] biohazard aboard \the [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", new_sound = 'sound/AI/outbreak5.ogg')
|
||||
|
||||
/datum/gm_action/viral_infection/start()
|
||||
if(!viruses.len) return
|
||||
|
||||
..()
|
||||
|
||||
var/list/candidates = list() //list of candidate keys
|
||||
for(var/mob/living/carbon/human/G in player_list)
|
||||
if(G.mind && G.stat != DEAD && G.is_client_active(5) && !player_is_antag(G.mind))
|
||||
var/turf/T = get_turf(G)
|
||||
if(T.z in using_map.station_levels)
|
||||
candidates += G
|
||||
if(!candidates.len) return
|
||||
candidates = shuffle(candidates)//Incorporating Donkie's list shuffle
|
||||
|
||||
var/list/used_viruses = list()
|
||||
var/list/used_candidates = list()
|
||||
severity = max(EVENT_LEVEL_MUNDANE, severity - 1)
|
||||
var/actual_severity = severity * rand(1, 3)
|
||||
while(actual_severity > 0 && candidates.len)
|
||||
var/datum/disease2/disease/D = pick(viruses)
|
||||
infect_mob(candidates[1], D.getcopy())
|
||||
used_candidates += candidates[1]
|
||||
candidates.Remove(candidates[1])
|
||||
actual_severity--
|
||||
used_viruses |= D
|
||||
|
||||
event_viruses |= used_viruses
|
||||
var/list/used_viruses_links = list()
|
||||
var/list/used_viruses_text = list()
|
||||
for(var/datum/disease2/disease/D in used_viruses)
|
||||
used_viruses_links += "<a href='?src=\ref[D];info=1'>[D.name()]</a>"
|
||||
used_viruses_text += D.name()
|
||||
|
||||
var/list/used_candidates_links = list()
|
||||
var/list/used_candidates_text = list()
|
||||
for(var/mob/M in used_candidates)
|
||||
used_candidates_links += key_name_admin(M)
|
||||
used_candidates_text += key_name(M)
|
||||
|
||||
log_admin("Virus event affecting [english_list(used_candidates_text)] started; Viruses: [english_list(used_viruses_text)]")
|
||||
message_admins("Virus event affecting [english_list(used_candidates_links)] started; Viruses: [english_list(used_viruses_links)]")
|
||||
|
||||
/datum/gm_action/viral_infection/get_weight()
|
||||
return (metric.count_people_in_department(DEPARTMENT_MEDICAL) * 20)
|
||||
@@ -1,44 +0,0 @@
|
||||
/datum/gm_action/viral_outbreak
|
||||
name = "viral outbreak"
|
||||
departments = list(DEPARTMENT_MEDICAL, DEPARTMENT_EVERYONE)
|
||||
chaotic = 30
|
||||
severity = 1
|
||||
var/list/candidates = list()
|
||||
|
||||
/datum/gm_action/viral_outbreak/set_up()
|
||||
candidates.Cut() // Incase we somehow get run twice.
|
||||
severity = rand(2, 4)
|
||||
for(var/mob/living/carbon/human/G in player_list)
|
||||
if(G.client && G.stat != DEAD)
|
||||
candidates += G
|
||||
if(!candidates.len) return
|
||||
candidates = shuffle(candidates)//Incorporating Donkie's list shuffle
|
||||
|
||||
/datum/gm_action/viral_outbreak/announce()
|
||||
command_announcement.Announce("Confirmed outbreak of level 7 biohazard aboard \the [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", new_sound = 'sound/AI/outbreak7.ogg')
|
||||
|
||||
/datum/gm_action/viral_outbreak/start()
|
||||
..()
|
||||
while(severity > 0 && candidates.len)
|
||||
if(prob(33))
|
||||
infect_mob_random_lesser(candidates[1])
|
||||
else
|
||||
infect_mob_random_greater(candidates[1])
|
||||
|
||||
candidates.Remove(candidates[1])
|
||||
severity--
|
||||
|
||||
/datum/gm_action/viral_outbreak/get_weight()
|
||||
var/medical = metric.count_people_in_department(DEPARTMENT_MEDICAL)
|
||||
var/security = metric.count_people_in_department(DEPARTMENT_SECURITY)
|
||||
var/everyone = metric.count_people_in_department(DEPARTMENT_EVERYONE)
|
||||
|
||||
var/assigned_staff = medical + round(security / 2)
|
||||
|
||||
if(!medical) // No docs, no staff.
|
||||
assigned_staff = 0
|
||||
|
||||
if(assigned_staff < round(everyone / 6) - assigned_staff) // A doc or half an officer per roughly six people. Any less, and assigned staff is halved.
|
||||
assigned_staff /= 2
|
||||
|
||||
return (assigned_staff * 10)
|
||||
@@ -1,43 +0,0 @@
|
||||
/datum/gm_action/wallrot
|
||||
name = "wall rot"
|
||||
departments = list(DEPARTMENT_ENGINEERING)
|
||||
reusable = TRUE
|
||||
var/turf/simulated/wall/center
|
||||
severity = 1
|
||||
|
||||
/datum/gm_action/wallrot/set_up()
|
||||
severity = rand(1,3)
|
||||
center = null
|
||||
// 100 attempts
|
||||
for(var/i=0, i<100, i++)
|
||||
var/turf/candidate = locate(rand(1, world.maxx), rand(1, world.maxy), 1)
|
||||
if(istype(candidate, /turf/simulated/wall))
|
||||
center = candidate
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/gm_action/wallrot/announce()
|
||||
if(center && prob(min(90,40 * severity)))
|
||||
command_announcement.Announce("Harmful fungi detected on \the [station_name()] nearby [center.loc.name]. Station structures may be contaminated.", "Biohazard Alert")
|
||||
|
||||
/datum/gm_action/wallrot/start()
|
||||
..()
|
||||
spawn()
|
||||
if(center)
|
||||
// Make sure at least one piece of wall rots!
|
||||
center.rot()
|
||||
|
||||
// Have a chance to rot lots of other walls.
|
||||
var/rotcount = 0
|
||||
var/actual_severity = severity * rand(5, 10)
|
||||
for(var/turf/simulated/wall/W in range(5, center))
|
||||
if(prob(50))
|
||||
W.rot()
|
||||
rotcount++
|
||||
|
||||
// Only rot up to severity walls
|
||||
if(rotcount >= actual_severity)
|
||||
break
|
||||
|
||||
/datum/gm_action/wallrot/get_weight()
|
||||
return 60 + (metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 35)
|
||||
@@ -1,9 +0,0 @@
|
||||
// A shuttle full of junk docks, and cargo is tasked with sifting through it all to find valuables, or just dispose of it.
|
||||
|
||||
/datum/gm_action/waste_disposal
|
||||
name = "waste disposal"
|
||||
departments = list(DEPARTMENT_CARGO)
|
||||
chaotic = 0
|
||||
|
||||
/datum/gm_action/waste_disposal/get_weight()
|
||||
return metric.count_people_in_department(DEPARTMENT_CARGO) * 50
|
||||
@@ -1,78 +0,0 @@
|
||||
/datum/gm_action/window_break
|
||||
name = "window breach"
|
||||
departments = list(DEPARTMENT_ENGINEERING)
|
||||
chaotic = 5
|
||||
var/obj/structure/window/chosen_window
|
||||
var/list/obj/structure/window/collateral_windows
|
||||
var/turf/chosen_location
|
||||
var/list/area/excluded = list(
|
||||
/area/shuttle,
|
||||
/area/crew_quarters
|
||||
)
|
||||
|
||||
/datum/gm_action/window_break/set_up()
|
||||
var/list/area/grand_list_of_areas = get_station_areas(excluded)
|
||||
//try 10 times
|
||||
for(var/i in 1 to 10)
|
||||
var/area/A = pick(grand_list_of_areas)
|
||||
var/list/obj/structure/window/possible_target_windows = list()
|
||||
for(var/obj/structure/window/target_window in A.contents)
|
||||
possible_target_windows += target_window
|
||||
possible_target_windows = shuffle(possible_target_windows)
|
||||
|
||||
for(var/obj/structure/window/target_window in possible_target_windows)
|
||||
//if() don't have any conditions, for isn't strictly necessary
|
||||
chosen_window = target_window
|
||||
chosen_location = chosen_window.loc
|
||||
collateral_windows = gather_collateral_windows(chosen_window)
|
||||
return
|
||||
|
||||
//TL;DR: breadth first search for all connected turfs with windows
|
||||
/datum/gm_action/window_break/proc/gather_collateral_windows(var/obj/structure/window/target_window)
|
||||
var/list/turf/frontier_set = list(target_window.loc)
|
||||
var/list/obj/structure/window/result_set = list()
|
||||
var/list/turf/explored_set = list()
|
||||
|
||||
while(frontier_set.len > 0)
|
||||
var/turf/current = frontier_set[1]
|
||||
frontier_set -= current
|
||||
explored_set += current
|
||||
|
||||
var/contains_windows = 0
|
||||
for(var/obj/structure/window/to_add in current.contents)
|
||||
contains_windows = 1
|
||||
result_set += to_add
|
||||
|
||||
if(contains_windows)
|
||||
//add adjacent turfs to be checked for windows as well
|
||||
var/turf/neighbor = locate(current.x + 1, current.y, current.z)
|
||||
if(!(neighbor in frontier_set) && !(neighbor in explored_set))
|
||||
frontier_set += neighbor
|
||||
neighbor = locate(current.x - 1, current.y, current.z)
|
||||
if(!(neighbor in frontier_set) && !(neighbor in explored_set))
|
||||
frontier_set += neighbor
|
||||
neighbor = locate(current.x, current.y + 1, current.z)
|
||||
if(!(neighbor in frontier_set) && !(neighbor in explored_set))
|
||||
frontier_set += neighbor
|
||||
neighbor = locate(current.x, current.y - 1, current.z)
|
||||
if(!(neighbor in frontier_set) && !(neighbor in explored_set))
|
||||
frontier_set += neighbor
|
||||
return result_set
|
||||
|
||||
/datum/gm_action/window_break/start()
|
||||
if(!chosen_window)
|
||||
return
|
||||
..()
|
||||
chosen_window.shatter(0)
|
||||
|
||||
spawn()
|
||||
for(var/obj/structure/window/current_collateral in collateral_windows)
|
||||
sleep(rand(1,20))
|
||||
current_collateral.take_damage(current_collateral.health - (current_collateral.maxhealth / 5)) //set to 1/5th health
|
||||
|
||||
/datum/gm_action/window_break/announce()
|
||||
if(chosen_window)
|
||||
command_announcement.Announce("Structural integrity of windows at [chosen_location.loc.name] is failing. Immediate repair or replacement is advised.", "Structural Alert")
|
||||
|
||||
/datum/gm_action/window_break/get_weight()
|
||||
return 20 * metric.count_people_in_department(DEPARTMENT_ENGINEERING)
|
||||
@@ -1,23 +0,0 @@
|
||||
/datum/gm_action/wormholes
|
||||
name = "space-time anomalies"
|
||||
chaotic = 70
|
||||
length = 12 MINUTES
|
||||
departments = list(DEPARTMENT_EVERYONE)
|
||||
severity = 1
|
||||
|
||||
/datum/gm_action/wormholes/set_up() // 1 out of 5 will be full-duration wormholes, meaning up to a minute long.
|
||||
severity = pickweight(list(
|
||||
3 = 5,
|
||||
2 = 7,
|
||||
1 = 13
|
||||
))
|
||||
|
||||
/datum/gm_action/wormholes/start()
|
||||
..()
|
||||
wormhole_event(length / 2, (severity / 3))
|
||||
|
||||
/datum/gm_action/wormholes/get_weight()
|
||||
return 10 + max(0, -30 + (metric.count_people_in_department(DEPARTMENT_EVERYONE) * 5) + (metric.count_people_in_department(DEPARTMENT_ENGINEERING) + 10) + (metric.count_people_in_department(DEPARTMENT_MEDICAL) * 20))
|
||||
|
||||
/datum/gm_action/wormholes/end()
|
||||
command_announcement.Announce("There are no more space-time anomalies detected on the station.", "Anomaly Alert")
|
||||
@@ -1,5 +1,3 @@
|
||||
#define EVENT_BASELINE_WEIGHT 200
|
||||
|
||||
#define EVENT_CHAOS_THRESHOLD_HIGH_IMPACT 25
|
||||
#define EVENT_CHAOS_THRESHOLD_MEDIUM_IMPACT 50
|
||||
#define EVENT_CHAOS_THRESHOLD_LOW_IMPACT 100
|
||||
@@ -98,84 +98,3 @@
|
||||
|
||||
/datum/event2/event/airlock_failure/shock/break_door(obj/machinery/door/airlock/door)
|
||||
door.electrify(-1)
|
||||
|
||||
|
||||
|
||||
/*
|
||||
/datum/gm_action/electrified_door
|
||||
name = "airlock short-circuit"
|
||||
departments = list(DEPARTMENT_ENGINEERING, DEPARTMENT_MEDICAL)
|
||||
chaotic = 10
|
||||
var/obj/machinery/door/airlock/chosen_door
|
||||
var/area/target_area
|
||||
var/list/area/excluded = list(
|
||||
/area/submap,
|
||||
/area/shuttle,
|
||||
/area/crew_quarters
|
||||
)
|
||||
|
||||
/datum/gm_action/electrified_door/set_up()
|
||||
var/list/area/grand_list_of_areas = get_station_areas(excluded)
|
||||
|
||||
severity = pickweight(EVENT_LEVEL_MUNDANE = 10,
|
||||
EVENT_LEVEL_MODERATE = 5,
|
||||
EVENT_LEVEL_MAJOR = 1
|
||||
)
|
||||
|
||||
//try 10 times
|
||||
for(var/i in 1 to 10)
|
||||
target_area = pick(grand_list_of_areas)
|
||||
var/list/obj/machinery/door/airlock/target_doors = list()
|
||||
for(var/obj/machinery/door/airlock/target_door in target_area.contents)
|
||||
target_doors += target_door
|
||||
target_doors = shuffle(target_doors)
|
||||
|
||||
for(var/obj/machinery/door/airlock/target_door in target_doors)
|
||||
if(!target_door.isElectrified() && target_door.arePowerSystemsOn() && target_door.maxhealth == target_door.health)
|
||||
chosen_door = target_door
|
||||
return
|
||||
|
||||
/datum/gm_action/electrified_door/start()
|
||||
..()
|
||||
if(!chosen_door)
|
||||
return
|
||||
command_announcement.Announce("An electrical issue has been detected in your area, please repair potential electronic overloads.", "Electrical Alert")
|
||||
chosen_door.visible_message("<span class='danger'>\The [chosen_door]'s panel sparks!</span>")
|
||||
chosen_door.set_safeties(0)
|
||||
playsound(get_turf(chosen_door), 'sound/machines/buzz-sigh.ogg', 50, 1)
|
||||
if(severity >= EVENT_LEVEL_MODERATE)
|
||||
chosen_door.electrify(-1)
|
||||
spawn(rand(10 SECONDS, 2 MINUTES))
|
||||
if(chosen_door && chosen_door.arePowerSystemsOn() && prob(25 + 25 * severity))
|
||||
command_announcement.Announce("Overload has been localized to \the [target_area].", "Electrical Alert")
|
||||
|
||||
if(severity >= EVENT_LEVEL_MAJOR) // New Major effect. Hydraulic boom.
|
||||
spawn()
|
||||
chosen_door.visible_message("<span class='warning'>\The [chosen_door] buzzes.</span>")
|
||||
playsound(get_turf(chosen_door), 'sound/machines/buzz-sigh.ogg', 50, 1)
|
||||
sleep(rand(10 SECONDS, 3 MINUTES))
|
||||
if(!chosen_door || !chosen_door.arePowerSystemsOn())
|
||||
return
|
||||
chosen_door.visible_message("<span class='warning'>\The [chosen_door]'s hydraulics creak.</span>")
|
||||
playsound(get_turf(chosen_door), 'sound/machines/airlock_creaking.ogg', 50, 1)
|
||||
sleep(rand(30 SECONDS, 10 MINUTES))
|
||||
if(!chosen_door || !chosen_door.arePowerSystemsOn())
|
||||
return
|
||||
chosen_door.visible_message("<span class='danger'>\The [chosen_door] emits a hydraulic shriek!</span>")
|
||||
playsound(get_turf(chosen_door), 'sound/machines/airlock.ogg', 80, 1)
|
||||
spawn(rand(5 SECONDS, 30 SECONDS))
|
||||
if(!chosen_door || !chosen_door.arePowerSystemsOn())
|
||||
return
|
||||
chosen_door.visible_message("<span class='critical'>\The [chosen_door]'s hydraulics detonate!</span>")
|
||||
chosen_door.fragmentate(get_turf(chosen_door), rand(5, 10), rand(3, 5), list(/obj/item/projectile/bullet/pellet/fragment/tank/small))
|
||||
explosion(get_turf(chosen_door),-1,-1,2,3)
|
||||
|
||||
chosen_door.lock()
|
||||
chosen_door.health = chosen_door.maxhealth / 6
|
||||
chosen_door.aiControlDisabled = 1
|
||||
chosen_door.update_icon()
|
||||
|
||||
/datum/gm_action/electrified_door/get_weight()
|
||||
return 10 + (metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 5 + metric.count_people_in_department(DEPARTMENT_MEDICAL) * 10)
|
||||
|
||||
*/
|
||||
@@ -80,7 +80,6 @@
|
||||
/area/engineering/engine_room
|
||||
)
|
||||
var/list/open_turfs = list()
|
||||
var/area/target_area = null
|
||||
var/spawn_blob_type = /obj/structure/blob/core/random_medium
|
||||
var/number_of_blobs = 1
|
||||
var/list/blobs = list() // A list containing weakrefs to blob cores created. Weakrefs mean this event won't interfere with qdel.
|
||||
@@ -97,27 +96,10 @@
|
||||
number_of_blobs = 16 // Someday maybe we can get this to specifically spawn every blob.
|
||||
|
||||
/datum/event2/event/blob/set_up()
|
||||
var/list/area/grand_list_of_areas = get_station_areas(excluded)
|
||||
if(grand_list_of_areas.len)
|
||||
for(var/i in 1 to 10)
|
||||
var/area/A = pick(grand_list_of_areas)
|
||||
if(is_area_occupied(A))
|
||||
log_debug("Blob infestation event: Rejected [A] because it is occupied.")
|
||||
continue
|
||||
var/list/turfs = list()
|
||||
for(var/turf/simulated/floor/F in A)
|
||||
if(!F.check_density())
|
||||
turfs += F
|
||||
if(turfs.len < 5 + number_of_blobs)
|
||||
log_debug("Blob infestation event: Rejected [A] because it has too little clear turfs.")
|
||||
continue
|
||||
open_turfs = turfs.Copy()
|
||||
target_area = A
|
||||
log_debug("Blob infestation event: Going to place blob at [A].")
|
||||
break
|
||||
open_turfs = find_random_turfs(5 + number_of_blobs)
|
||||
|
||||
if(!open_turfs.len)
|
||||
log_debug("Blob infestation event: Giving up after too many failures to pick a blob spot.")
|
||||
log_debug("Blob infestation event: Giving up after failure to find blob spots.")
|
||||
abort()
|
||||
|
||||
/datum/event2/event/blob/start()
|
||||
@@ -171,88 +153,11 @@
|
||||
lines += "The biohazard[multiblob ? "s have": " has"] been identified as [english_list(blob_type_names)]."
|
||||
|
||||
if(danger_level >= BLOB_DIFFICULTY_HARD) // If it's really hard then tell them where it is so the response occurs faster.
|
||||
lines += "[multiblob ? "It is": "They are"] suspected to have originated from \the [target_area]."
|
||||
var/turf/T = open_turfs[1]
|
||||
var/area/A = T.loc
|
||||
lines += "[multiblob ? "It is": "They are"] suspected to have originated from \the [A]."
|
||||
|
||||
if(danger_level >= BLOB_DIFFICULTY_SUPERHARD)
|
||||
lines += "Extreme caution is advised."
|
||||
|
||||
command_announcement.Announce(lines.Join("\n"), "Biohazard Alert", new_sound = 'sound/AI/outbreak7.ogg')
|
||||
|
||||
/*
|
||||
/datum/gm_action/blob
|
||||
name = "blob infestation"
|
||||
departments = list(DEPARTMENT_ENGINEERING, DEPARTMENT_SECURITY, DEPARTMENT_MEDICAL)
|
||||
chaotic = 25
|
||||
|
||||
var/list/area/excluded = list(
|
||||
/area/submap,
|
||||
/area/shuttle,
|
||||
/area/crew_quarters,
|
||||
/area/holodeck,
|
||||
/area/engineering/engine_room
|
||||
)
|
||||
|
||||
var/area/target_area // Chosen target area
|
||||
var/turf/target_turf // Chosen target turf in target_area
|
||||
|
||||
var/obj/structure/blob/core/Blob
|
||||
var/spawn_blob_type = /obj/structure/blob/core/random_medium
|
||||
|
||||
/datum/gm_action/blob/set_up()
|
||||
severity = pickweight(EVENT_LEVEL_MUNDANE = 4,
|
||||
EVENT_LEVEL_MODERATE = 2,
|
||||
EVENT_LEVEL_MAJOR = 1
|
||||
)
|
||||
|
||||
var/list/area/grand_list_of_areas = get_station_areas(excluded)
|
||||
|
||||
for(var/i in 1 to 10)
|
||||
var/area/A = pick(grand_list_of_areas)
|
||||
if(is_area_occupied(A))
|
||||
log_debug("Blob infestation event: Rejected [A] because it is occupied.")
|
||||
continue
|
||||
var/list/turfs = list()
|
||||
for(var/turf/simulated/floor/F in A)
|
||||
if(turf_clear(F))
|
||||
turfs += F
|
||||
if(turfs.len == 0)
|
||||
log_debug("Blob infestation event: Rejected [A] because it has no clear turfs.")
|
||||
continue
|
||||
target_area = A
|
||||
target_turf = pick(turfs)
|
||||
|
||||
if(!target_area)
|
||||
log_debug("Blob infestation event: Giving up after too many failures to pick target area")
|
||||
|
||||
/datum/gm_action/blob/start()
|
||||
..()
|
||||
var/turf/T
|
||||
|
||||
if(severity == EVENT_LEVEL_MUNDANE || !target_area || !target_turf)
|
||||
T = pick(blobstart)
|
||||
else if(severity == EVENT_LEVEL_MODERATE)
|
||||
T = target_turf
|
||||
else
|
||||
T = target_turf
|
||||
spawn_blob_type = /obj/structure/blob/core/random_hard
|
||||
|
||||
Blob = new spawn_blob_type(T)
|
||||
|
||||
/datum/gm_action/blob/announce()
|
||||
spawn(rand(600, 3000)) // 1-5 minute leeway for the blob to go un-detected.
|
||||
command_announcement.Announce("Confirmed outbreak of level 7 biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", new_sound = 'sound/AI/outbreak7.ogg')
|
||||
|
||||
/datum/gm_action/blob/get_weight()
|
||||
var/engineers = metric.count_people_in_department(DEPARTMENT_ENGINEERING)
|
||||
var/security = metric.count_people_in_department(DEPARTMENT_SECURITY)
|
||||
var/medical = metric.count_people_in_department(DEPARTMENT_MEDICAL)
|
||||
|
||||
var/assigned_staff = engineers + security
|
||||
if(engineers || security) // Medical only counts if one of the other two exists, and even then they count as half.
|
||||
assigned_staff += round(medical / 2)
|
||||
|
||||
var/weight = (max(assigned_staff - 2, 0) * 20) // An assigned staff count of 2 must be had to spawn a blob.
|
||||
return weight
|
||||
|
||||
*/
|
||||
|
||||
|
||||
@@ -135,134 +135,3 @@
|
||||
/datum/event2/event/pda_spam/proc/pick_message_server()
|
||||
if(LAZYLEN(message_servers))
|
||||
return pick(message_servers)
|
||||
|
||||
|
||||
/*
|
||||
/datum/event/pda_spam
|
||||
endWhen = 36000
|
||||
var/last_spam_time = 0
|
||||
var/obj/machinery/message_server/useMS
|
||||
var/obj/machinery/exonet_node/node
|
||||
|
||||
/datum/event/pda_spam/setup()
|
||||
last_spam_time = world.time
|
||||
pick_message_server()
|
||||
|
||||
/datum/event/pda_spam/proc/pick_message_server()
|
||||
if(message_servers)
|
||||
for (var/obj/machinery/message_server/MS in message_servers)
|
||||
if(MS.active)
|
||||
useMS = MS
|
||||
break
|
||||
|
||||
/datum/event/pda_spam/tick()
|
||||
if(world.time > last_spam_time + 3000)
|
||||
//if there's no spam managed to get to receiver for five minutes, give up
|
||||
kill()
|
||||
return
|
||||
if(!node)
|
||||
node = get_exonet_node()
|
||||
|
||||
if(!node || !node.on || !node.allow_external_PDAs)
|
||||
return
|
||||
|
||||
if(!useMS || !useMS.active)
|
||||
useMS = null
|
||||
pick_message_server()
|
||||
|
||||
if(useMS)
|
||||
if(prob(5))
|
||||
// /obj/machinery/message_server/proc/send_pda_message(var/recipient = "",var/sender = "",var/message = "")
|
||||
var/obj/item/device/pda/P
|
||||
var/list/viables = list()
|
||||
for(var/obj/item/device/pda/check_pda in sortAtom(PDAs))
|
||||
if (!check_pda.owner||check_pda.toff||check_pda == src||check_pda.hidden)
|
||||
continue
|
||||
viables.Add(check_pda)
|
||||
|
||||
if(!viables.len)
|
||||
return
|
||||
P = pick(viables)
|
||||
|
||||
var/sender
|
||||
var/message
|
||||
switch(pick(1,2,3,4,5,6,7))
|
||||
if(1)
|
||||
sender = pick("MaxBet","MaxBet Online Casino","There is no better time to register","I'm excited for you to join us")
|
||||
message = pick("Triple deposits are waiting for you at MaxBet Online when you register to play with us.",\
|
||||
"You can qualify for a 200% Welcome Bonus at MaxBet Online when you sign up today.",\
|
||||
"Once you are a player with MaxBet, you will also receive lucrative weekly and monthly promotions.",\
|
||||
"You will be able to enjoy over 450 top-flight casino games at MaxBet.")
|
||||
if(2)
|
||||
sender = pick(300;"QuickDatingSystem",200;"Find your russian bride",50;"Tajaran beauties are waiting",50;"Find your secret skrell crush",50;"Beautiful unathi brides")
|
||||
message = pick("Your profile caught my attention and I wanted to write and say hello (QuickDating).",\
|
||||
"If you will write to me on my email [pick(first_names_female)]@[pick(last_names)].[pick("ru","ck","tj","ur","nt")] I shall necessarily send you a photo (QuickDating).",\
|
||||
"I want that we write each other and I hope, that you will like my profile and you will answer me (QuickDating).",\
|
||||
"You have (1) new message!",\
|
||||
"You have (2) new profile views!")
|
||||
if(3)
|
||||
sender = pick("Galactic Payments Association","Better Business Bureau","[using_map.starsys_name] E-Payments","NAnoTransen Finance Deparmtent","Luxury Replicas")
|
||||
message = pick("Luxury watches for Blowout sale prices!",\
|
||||
"Watches, Jewelry & Accessories, Bags & Wallets !",\
|
||||
"Deposit 100$ and get 300$ totally free!",\
|
||||
" 100K NT.|WOWGOLD <20>nly $89 <HOT>",\
|
||||
"We have been filed with a complaint from one of your customers in respect of their business relations with you.",\
|
||||
"We kindly ask you to open the COMPLAINT REPORT (attached) to reply on this complaint..")
|
||||
if(4)
|
||||
sender = pick("Buy Dr. Maxman","Having dysfuctional troubles?")
|
||||
message = pick("DR MAXMAN: REAL Doctors, REAL Science, REAL Results!",\
|
||||
"Dr. Maxman was created by George Acuilar, M.D, a [using_map.boss_short] Certified Urologist who has treated over 70,000 patients sector wide with 'male problems'.",\
|
||||
"After seven years of research, Dr Acuilar and his team came up with this simple breakthrough male enhancement formula.",\
|
||||
"Men of all species report AMAZING increases in length, width and stamina.")
|
||||
if(5)
|
||||
sender = pick("Dr","Crown prince","King Regent","Professor","Captain")
|
||||
sender += " " + pick("Robert","Alfred","Josephat","Kingsley","Sehi","Zbahi")
|
||||
sender += " " + pick("Mugawe","Nkem","Gbatokwia","Nchekwube","Ndim","Ndubisi")
|
||||
message = pick("YOUR FUND HAS BEEN MOVED TO [pick("Salusa","Segunda","Cepheus","Andromeda","Gruis","Corona","Aquila","ARES","Asellus")] DEVELOPMENTARY BANK FOR ONWARD REMITTANCE.",\
|
||||
"We are happy to inform you that due to the delay, we have been instructed to IMMEDIATELY deposit all funds into your account",\
|
||||
"Dear fund beneficiary, We have please to inform you that overdue funds payment has finally been approved and released for payment",\
|
||||
"Due to my lack of agents I require an off-world financial account to immediately deposit the sum of 1 POINT FIVE MILLION credits.",\
|
||||
"Greetings sir, I regretfully to inform you that as I lay dying here due to my lack ofheirs I have chosen you to recieve the full sum of my lifetime savings of 1.5 billion credits")
|
||||
if(6)
|
||||
sender = pick("[using_map.company_name] Morale Divison","Feeling Lonely?","Bored?","www.wetskrell.nt")
|
||||
message = pick("The [using_map.company_name] Morale Division wishes to provide you with quality entertainment sites.",\
|
||||
"WetSkrell.nt is a xenophillic website endorsed by NT for the use of male crewmembers among it's many stations and outposts.",\
|
||||
"Wetskrell.nt only provides the higest quality of male entertaiment to [using_map.company_name] Employees.",\
|
||||
"Simply enter your [using_map.company_name] Bank account system number and pin. With three easy steps this service could be yours!")
|
||||
if(7)
|
||||
sender = pick("You have won free tickets!","Click here to claim your prize!","You are the 1000th vistor!","You are our lucky grand prize winner!")
|
||||
message = pick("You have won tickets to the newest ACTION JAXSON MOVIE!",\
|
||||
"You have won tickets to the newest crime drama DETECTIVE MYSTERY IN THE CLAMITY CAPER!",\
|
||||
"You have won tickets to the newest romantic comedy 16 RULES OF LOVE!",\
|
||||
"You have won tickets to the newest thriller THE CULT OF THE SLEEPING ONE!")
|
||||
|
||||
if (useMS.send_pda_message("[P.owner]", sender, message)) //Message been filtered by spam filter.
|
||||
return
|
||||
|
||||
last_spam_time = world.time
|
||||
|
||||
if (prob(50)) //Give the AI an increased chance to intercept the message
|
||||
for(var/mob/living/silicon/ai/ai in mob_list)
|
||||
// Allows other AIs to intercept the message but the AI won't intercept their own message.
|
||||
if(ai.aiPDA != P && ai.aiPDA != src)
|
||||
ai.show_message("<i>Intercepted message from <b>[sender]</b></i> (Unknown / spam?) <i>to <b>[P:owner]</b>: [message]</i>")
|
||||
|
||||
//Commented out because we don't send messages like this anymore. Instead it will just popup in their chat window.
|
||||
//P.tnote += "<i><b>← From [sender] (Unknown / spam?):</b></i><br>[message]<br>"
|
||||
|
||||
if (!P.message_silent)
|
||||
playsound(P.loc, 'sound/machines/twobeep.ogg', 50, 1)
|
||||
for (var/mob/O in hearers(3, P.loc))
|
||||
if(!P.message_silent) O.show_message(text("\icon[P] *[P.ttone]*"))
|
||||
//Search for holder of the PDA.
|
||||
var/mob/living/L = null
|
||||
if(P.loc && isliving(P.loc))
|
||||
L = P.loc
|
||||
//Maybe they are a pAI!
|
||||
else
|
||||
L = get(P, /mob/living/silicon)
|
||||
|
||||
if(L)
|
||||
to_chat(L, "\icon[P] <b>Message from [sender] (Unknown / spam?), </b>\"[message]\" (Unable to Reply)")
|
||||
|
||||
*/
|
||||
@@ -43,40 +43,3 @@
|
||||
var/new_weather = pickweight(new_weather_weights)
|
||||
log_debug("Sudden weather shift event is now changing [chosen_planet.name]'s weather to [new_weather].")
|
||||
chosen_planet.weather_holder.change_weather(new_weather)
|
||||
|
||||
/*
|
||||
/datum/gm_action/planet_weather_shift
|
||||
name = "sudden weather shift"
|
||||
enabled = TRUE
|
||||
departments = list(DEPARTMENT_EVERYONE)
|
||||
reusable = TRUE
|
||||
var/datum/planet/target_planet
|
||||
|
||||
var/list/banned_weathers = list(
|
||||
/datum/weather/sif/ash_storm,
|
||||
/datum/weather/sif/emberfall,
|
||||
/datum/weather/sif/blood_moon,
|
||||
/datum/weather/sif/fallout)
|
||||
var/list/possible_weathers = list()
|
||||
|
||||
/datum/gm_action/planet_weather_shift/set_up()
|
||||
if(!target_planet || isnull(target_planet))
|
||||
target_planet = pick(SSplanets.planets)
|
||||
possible_weathers |= target_planet.weather_holder.allowed_weather_types
|
||||
possible_weathers -= banned_weathers
|
||||
return
|
||||
|
||||
/datum/gm_action/planet_weather_shift/get_weight()
|
||||
return max(0, -15 + (metric.count_all_outdoor_mobs() * 20))
|
||||
|
||||
/datum/gm_action/planet_weather_shift/start()
|
||||
..()
|
||||
var/new_weather = pick(possible_weathers)
|
||||
target_planet.weather_holder.change_weather(new_weather)
|
||||
|
||||
/datum/gm_action/planet_weather_shift/announce()
|
||||
spawn(rand(3 SECONDS, 2 MINUTES))
|
||||
command_announcement.Announce("Local weather patterns on [target_planet.name] suggest that a sudden atmospheric fluctuation has occurred. All groundside personnel should be wary of rapidly deteriorating conditions.", "Weather Alert")
|
||||
return
|
||||
|
||||
*/
|
||||
@@ -1,160 +0,0 @@
|
||||
// This is a sort of successor to the various event systems created over the years. It is designed to be just a tad smarter than the
|
||||
// previous ones, checking various things like player count, department size and composition, individual player activity,
|
||||
// individual player (IC) skill, and such, in order to try to choose the best actions to take in order to add spice or variety to
|
||||
// the round.
|
||||
|
||||
/datum/game_master_old
|
||||
var/suspended = TRUE // If true, it will not do anything.
|
||||
var/ignore_time_restrictions = FALSE// Useful for debugging without needing to wait 20 minutes each time.
|
||||
var/list/available_actions = list() // A list of 'actions' that the GM has access to, to spice up a round, such as events.
|
||||
var/danger = 0 // The GM's best guess at how chaotic the round is. High danger makes it hold back.
|
||||
var/staleness = -20 // Determines liklihood of the GM doing something, increases over time.
|
||||
var/danger_modifier = 1 // Multiplier for how much 'danger' is accumulated.
|
||||
var/staleness_modifier = 1 // Ditto. Higher numbers generally result in more events occuring in a round.
|
||||
var/ticks_completed = 0 // Counts amount of ticks completed. Note that this ticks once a minute.
|
||||
var/next_action = 0 // Minimum amount of time of nothingness until the GM can pick something again.
|
||||
var/last_department_used = null // If an event was done for a specific department, it is written here, so it doesn't do it again.
|
||||
|
||||
/datum/game_master_old/New()
|
||||
..()
|
||||
available_actions = init_subtypes(/datum/gm_action)
|
||||
for(var/datum/gm_action/action in available_actions)
|
||||
action.gm = src
|
||||
|
||||
var/config_setup_delay = TRUE
|
||||
spawn(0)
|
||||
while(config_setup_delay)
|
||||
if(config)
|
||||
config_setup_delay = FALSE
|
||||
if(config.enable_game_master)
|
||||
suspended = FALSE
|
||||
next_action = world.time + rand(15 MINUTES, 25 MINUTES)
|
||||
else
|
||||
sleep(30 SECONDS)
|
||||
|
||||
/datum/game_master_old/process()
|
||||
if(ticker && ticker.current_state == GAME_STATE_PLAYING && !suspended)
|
||||
adjust_staleness(1)
|
||||
adjust_danger(-1)
|
||||
ticks_completed++
|
||||
|
||||
var/global_afk = metric.assess_all_living_mobs()
|
||||
global_afk -= 100
|
||||
global_afk = abs(global_afk)
|
||||
global_afk = round(global_afk / 100, 0.1)
|
||||
adjust_staleness(global_afk) // Staleness increases faster if more people are less active.
|
||||
|
||||
if(world.time < next_action && prob(staleness * 2) )
|
||||
log_debug("Game Master going to start something.")
|
||||
start_action()
|
||||
|
||||
// This is run before committing to an action/event.
|
||||
/datum/game_master_old/proc/pre_action_checks()
|
||||
if(!ticker || ticker.current_state != GAME_STATE_PLAYING)
|
||||
log_debug("Game Master unable to start event: Ticker is nonexistant, or the game is not ongoing.")
|
||||
return FALSE
|
||||
if(suspended)
|
||||
return FALSE
|
||||
if(ignore_time_restrictions)
|
||||
return TRUE
|
||||
if(world.time < next_action) // Sanity.
|
||||
log_debug("Game Master unable to start event: Time until next action is approximately [round((next_action - world.time) / (1 MINUTE))] minute(s)")
|
||||
return FALSE
|
||||
// Last minute antagging is bad for humans to do, so the GM will respect the start and end of the round.
|
||||
var/mills = round_duration_in_ticks
|
||||
var/mins = round((mills % 36000) / 600)
|
||||
var/hours = round(mills / 36000)
|
||||
|
||||
if(hours < 1 && mins <= 20) // Don't do anything for the first twenty minutes of the round.
|
||||
log_debug("Game Master unable to start event: It is too early.")
|
||||
return FALSE
|
||||
if(hours >= 2 && mins >= 40) // Don't do anything in the last twenty minutes of the round, as well.
|
||||
log_debug("Game Master unable to start event: It is too late.")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/game_master_old/proc/start_action()
|
||||
if(!pre_action_checks()) // Make sure we're not doing last minute events, or early events.
|
||||
return
|
||||
log_debug("Game Master now starting action decision.")
|
||||
var/list/most_active_departments = metric.assess_all_departments(3, list(last_department_used))
|
||||
var/list/best_actions = decide_best_action(most_active_departments)
|
||||
|
||||
if(best_actions && best_actions.len)
|
||||
var/list/weighted_actions = list()
|
||||
for(var/datum/gm_action/action in best_actions)
|
||||
if(action.chaotic > danger)
|
||||
continue // We skip dangerous events when bad stuff is already occuring.
|
||||
weighted_actions[action] = action.get_weight()
|
||||
|
||||
var/datum/gm_action/choice = pickweight(weighted_actions)
|
||||
if(choice)
|
||||
log_debug("[choice.name] was chosen by the Game Master, and is now being ran.")
|
||||
run_action(choice)
|
||||
|
||||
/datum/game_master_old/proc/run_action(var/datum/gm_action/action)
|
||||
action.set_up()
|
||||
action.start()
|
||||
action.announce()
|
||||
if(action.chaotic)
|
||||
danger += action.chaotic
|
||||
if(action.length)
|
||||
spawn(action.length)
|
||||
action.end()
|
||||
next_action = world.time + rand(5 MINUTES, 20 MINUTES)
|
||||
last_department_used = action.departments[1]
|
||||
|
||||
|
||||
/datum/game_master_old/proc/decide_best_action(var/list/most_active_departments)
|
||||
if(!most_active_departments.len) // Server's empty?
|
||||
log_debug("Game Master failed to find any active departments.")
|
||||
return list()
|
||||
|
||||
var/list/best_actions = list() // List of actions which involve the most active departments.
|
||||
if(most_active_departments.len >= 2)
|
||||
for(var/datum/gm_action/action in available_actions)
|
||||
if(!action.enabled)
|
||||
continue
|
||||
// Try to incorporate an action with the top two departments first.
|
||||
if(most_active_departments[1] in action.departments && most_active_departments[2] in action.departments)
|
||||
best_actions.Add(action)
|
||||
log_debug("[action.name] is being considered because both most active departments are involved.")
|
||||
|
||||
if(best_actions.len) // We found something for those two, let's do it.
|
||||
return best_actions
|
||||
|
||||
// Otherwise we probably couldn't find something for the second highest group, so let's ignore them.
|
||||
for(var/datum/gm_action/action in available_actions)
|
||||
if(!action.enabled)
|
||||
continue
|
||||
if(most_active_departments[1] in action.departments)
|
||||
best_actions.Add(action)
|
||||
log_debug("[action.name] is being considered because the most active department is involved.")
|
||||
|
||||
if(best_actions.len) // Found something for the one guy.
|
||||
return best_actions
|
||||
|
||||
// At this point we should expand our horizons.
|
||||
for(var/datum/gm_action/action in available_actions)
|
||||
if(!action.enabled)
|
||||
continue
|
||||
if(DEPARTMENT_EVERYONE in action.departments)
|
||||
best_actions.Add(action)
|
||||
log_debug("[action.name] is being considered because it involves everyone.")
|
||||
|
||||
if(best_actions.len) // Finally, perhaps?
|
||||
return best_actions
|
||||
|
||||
// Just give a random event if for some reason it still can't make up its mind.
|
||||
for(var/datum/gm_action/action in available_actions)
|
||||
if(!action.enabled)
|
||||
continue
|
||||
best_actions.Add(action)
|
||||
log_debug("[action.name] is being considered because everything else failed.")
|
||||
|
||||
if(best_actions.len) // Finally, perhaps?
|
||||
return best_actions
|
||||
else
|
||||
log_debug("Game Master failed to find a suitable event, something very wrong is going on.")
|
||||
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
// Tell the game master that something dangerous happened, e.g. someone dying.
|
||||
/datum/game_master_old/proc/adjust_danger(var/amt)
|
||||
amt = amt * danger_modifier
|
||||
danger = round( CLAMP(danger + amt, 0, 1000), 0.1)
|
||||
|
||||
// Tell the game master that something interesting happened.
|
||||
/datum/game_master_old/proc/adjust_staleness(var/amt)
|
||||
amt = amt * staleness_modifier
|
||||
staleness = round( CLAMP(staleness + amt, -50, 200), 0.1)
|
||||
Reference in New Issue
Block a user