Adds event regions to GameMaster events (#8334)

* Configures gm events to be selectable by "region"

* Configures event regions for existing events

* Configures event selection to filter by region
This commit is contained in:
Atermonera
2022-01-15 23:52:00 -08:00
committed by GitHub
parent ae7f147ea5
commit cff34e64a1
47 changed files with 232 additions and 126 deletions

10
code/__defines/events.dm Normal file
View File

@@ -0,0 +1,10 @@
// Event defines
#define EVENT_REGION_SPACESTATION "near_space" // In space, but easy access
#define EVENT_REGION_DEEPSPACE "overmap" // Deep in space, far from others
#define EVENT_REGION_PLANETSURFACE "planetside" // Somewhere on a planet
#define EVENT_REGION_SUBTERRANEAN "mining" // Somewhere explicitly subterranean, like the mining Z
#define EVENT_REGION_PLAYER_MAIN_AREA "player_main_area" // The main area that players are expected to be in
// Universal events disregard
#define EVENT_REGION_UNIVERSAL "universal"

View File

@@ -238,19 +238,17 @@ This actually tests if they have the same entries and values.
//Pretends to pick an element based on its weight but really just seems to pick a random element.
/proc/pickweight(list/L)
var/total = 0
var/item
for (item in L)
if (!L[item])
for(var/item in L)
if(!L[item])
L[item] = 1
total += L[item]
total = rand(1, total)
for (item in L)
total -=L [item]
if (total <= 0)
for(var/item in L)
total -= L[item]
if(total <= 0)
return item
return null
//Pick a random element from the list and remove it from the list.
/proc/pick_n_take(list/listfrom)

View File

@@ -10,8 +10,12 @@
/datum/game_master/default/choose_event()
log_game_master("Now starting event decision.")
var/list/regions = metric.assess_player_regions()
if(!LAZYLEN(regions))
regions = list(EVENT_REGION_UNIVERSAL = 100)
var/list/most_active_departments = metric.assess_all_departments(3, list(last_department_used))
var/list/best_events = decide_best_events(most_active_departments)
var/list/best_events = decide_best_events(most_active_departments, regions)
if(LAZYLEN(best_events))
log_game_master("Got [best_events.len] choice\s for the next event.")
@@ -32,33 +36,45 @@
last_department_used = LAZYACCESS(choice.departments, 1)
return choice
/datum/game_master/default/proc/decide_best_events(list/most_active_departments)
/datum/game_master/default/proc/decide_best_events(list/most_active_departments, var/list/regions)
if(!LAZYLEN(most_active_departments)) // Server's empty?
log_game_master("Game Master failed to find any active departments.")
return list()
var/list/best_events = list()
// Filter by generic factors
var/list/available_events = filter_events_generic()
// Filter by player regions. Lots of people in the mines = favor subterranean events
var/list/best_events = filter_events_by_region(available_events, pickweight(regions))
if(!LAZYLEN(best_events))
best_events = filter_events_by_region(available_events, EVENT_REGION_UNIVERSAL)
if(!LAZYLEN(best_events))
log_game_master("Game Master failed to find a suitable event, something very wrong is going on.")
return list()
available_events = best_events
// Filter events by department. Lots of engineering = break things on the station
if(most_active_departments.len >= 2)
var/list/top_two = list(most_active_departments[1], most_active_departments[2])
best_events = filter_events_by_departments(top_two)
best_events = filter_events_by_departments(available_events, top_two)
if(LAZYLEN(best_events)) // We found something for those two, let's do it.
return best_events
// Otherwise we probably couldn't find something for the second highest group, so let's ignore them.
best_events = filter_events_by_departments(most_active_departments[1])
best_events = filter_events_by_departments(available_events, list(most_active_departments[1]))
if(LAZYLEN(best_events))
return best_events
// At this point we should expand our horizons.
best_events = filter_events_by_departments(list(DEPARTMENT_EVERYONE))
best_events = filter_events_by_departments(available_events, list(DEPARTMENT_EVERYONE))
if(LAZYLEN(best_events))
return best_events
// Just give a random event if for some reason it still can't make up its mind.
best_events = filter_events_by_departments()
best_events = filter_events_by_departments(available_events)
if(LAZYLEN(best_events))
return best_events
@@ -66,10 +82,8 @@
log_game_master("Game Master failed to find a suitable event, something very wrong is going on.")
return list()
// Filters the available events down to events for specific departments.
// Pass DEPARTMENT_EVERYONE if you want events that target the general population, like gravity failure.
// If no list is passed, all the events will be returned.
/datum/game_master/default/proc/filter_events_by_departments(list/departments)
// Filters events by availability, enable, and chaos
/datum/game_master/default/proc/filter_events_generic()
. = list()
for(var/E in SSgame_master.available_events)
var/datum/event2/meta/event = E
@@ -78,12 +92,21 @@
if(event.chaotic_threshold && !ignore_round_chaos)
if(SSgame_master.danger > event.chaotic_threshold)
continue
. += event
// Filters the available events down to events for specific departments.
// Pass DEPARTMENT_EVERYONE if you want events that target the general population, like gravity failure.
// If no list is passed, all the events will be returned.
/datum/game_master/default/proc/filter_events_by_departments(list/available_events, list/departments)
. = list()
for(var/datum/event2/meta/event in available_events)
// An event has to involve all of these departments to pass.
var/viable = TRUE
if(LAZYLEN(departments))
for(var/department in departments)
if(!LAZYFIND(departments, department))
viable = FALSE
break
if(viable)
if(!LAZYLEN(departments) || (departments ~= (event.departments & departments)))
. += event
// Filters the available events by the region those events target.
/datum/game_master/default/proc/filter_events_by_region(list/available_events, var/target_region)
. = list()
for(var/datum/event2/meta/event in available_events)
if(target_region in event.regions)
. += event

View File

@@ -76,20 +76,13 @@ This allows for events that have their announcement happen after the end itself.
/datum/event2/event/proc/is_planet_z_level(z_level)
var/datum/planet/P = LAZYACCESS(SSplanets.z_to_planet, z_level)
if(!istype(P))
return FALSE
return TRUE
return istype(LAZYACCESS(SSplanets.z_to_planet, z_level), /datum/planet)
// Returns a list of empty turfs in the same area.
/datum/event2/event/proc/find_random_turfs(minimum_free_space = 5, list/specific_areas = list(), ignore_occupancy = FALSE)
var/list/area/grand_list_of_areas = find_random_areas(specific_areas)
if(!LAZYLEN(grand_list_of_areas))
return list()
for(var/thing in grand_list_of_areas)
var/list/A = thing
for(var/area/A in grand_list_of_areas)
var/list/turfs = list()
for(var/turf/T in A)
if(!T.check_density())
@@ -98,7 +91,6 @@ This allows for events that have their announcement happen after the end itself.
if(turfs.len < minimum_free_space)
continue // Not enough free space.
return turfs
return list()
/datum/event2/event/proc/find_random_areas(list/specific_areas = list(), ignore_occupancy = FALSE)
@@ -107,8 +99,7 @@ This allows for events that have their announcement happen after the end itself.
var/list/area/grand_list_of_areas = get_all_existing_areas_of_types(specific_areas)
. = list()
for(var/thing in shuffle(grand_list_of_areas))
var/area/A = thing
for(var/area/A in shuffle(grand_list_of_areas))
if(A.forbid_events)
continue
if(!(A.z in get_location_z_levels()))
@@ -182,7 +173,7 @@ This allows for events that have their announcement happen after the end itself.
return
if(!check_rights(R_ADMIN|R_EVENT|R_DEBUG))
message_admins("[usr] has attempted to manipulate an event without sufficent privilages.")
message_admins("[usr] has attempted to manipulate an event without sufficent privileges.")
return
if(href_list["abort"])

View File

@@ -4,6 +4,7 @@
chaos = -10 // A helpful event.
reusable = TRUE
event_type = /datum/event2/event/shipping_error
regions = list(EVENT_REGION_UNIVERSAL)
/datum/event2/meta/shipping_error/get_weight()
return (metric.count_people_with_job(/datum/job/cargo_tech) + metric.count_people_with_job(/datum/job/qm)) * 30

View File

@@ -4,6 +4,7 @@
chaos = 10
chaotic_threshold = EVENT_CHAOS_THRESHOLD_LOW_IMPACT
event_type = /datum/event2/event/manifest_malfunction
regions = list(EVENT_REGION_UNIVERSAL)
/datum/event2/meta/manifest_malfunction/get_weight()
var/security = metric.count_people_in_department(DEPARTMENT_SECURITY)

View File

@@ -4,6 +4,7 @@
chaos = 10
chaotic_threshold = EVENT_CHAOS_THRESHOLD_LOW_IMPACT
event_type = /datum/event2/event/money_hacker
regions = list(EVENT_REGION_UNIVERSAL)
/datum/event2/meta/money_hacker/get_weight()
var/command = metric.count_people_with_job(/datum/job/hop) + metric.count_people_with_job(/datum/job/captain)

View File

@@ -4,6 +4,7 @@
departments = list(DEPARTMENT_COMMAND, DEPARTMENT_CARGO)
chaotic_threshold = EVENT_CHAOS_THRESHOLD_LOW_IMPACT
event_type = /datum/event2/event/raise_funds
regions = list(EVENT_REGION_UNIVERSAL)
/datum/event2/meta/raise_funds/get_weight()
var/command = metric.count_people_in_department(DEPARTMENT_COMMAND)

View File

@@ -5,6 +5,7 @@
chaotic_threshold = EVENT_CHAOS_THRESHOLD_MEDIUM_IMPACT
event_type = /datum/event2/event/airlock_failure
var/needs_medical = FALSE
regions = list(EVENT_REGION_PLAYER_MAIN_AREA)
/datum/event2/meta/airlock_failure/emag
name = "airlock failure - emag"

View File

@@ -8,6 +8,7 @@
// In the distant future, if a mechanical skill system were to come into being, these vars could be replaced with skill checks so off duty people could count.
var/required_fighters = 2 // Fighters refers to engineering OR security.
var/required_support = 1 // Support refers to doctors AND roboticists, depending on fighter composition.
regions = list(EVENT_REGION_PLAYER_MAIN_AREA)
/datum/event2/meta/blob/hard
name = "harder blob"

View File

@@ -4,6 +4,7 @@
chaos = 10
chaotic_threshold = EVENT_CHAOS_THRESHOLD_LOW_IMPACT
event_type = /datum/event2/event/brand_intelligence
regions = list(EVENT_REGION_UNIVERSAL)
/datum/event2/meta/brand_intelligence/get_weight()
return 10 + (metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 20)

View File

@@ -5,6 +5,7 @@
chaotic_threshold = EVENT_CHAOS_THRESHOLD_LOW_IMPACT
reusable = TRUE
event_type = /datum/event2/event/camera_damage
regions = list(EVENT_REGION_PLAYER_MAIN_AREA)
/datum/event2/meta/camera_damage/get_weight()
return 30 + (metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 20) + (metric.count_people_in_department(DEPARTMENT_SYNTHETIC) * 40)

View File

@@ -9,6 +9,7 @@
chaotic_threshold = EVENT_CHAOS_THRESHOLD_LOW_IMPACT
reusable = TRUE
event_type = /datum/event2/event/canister_leak
regions = list(EVENT_REGION_PLAYER_MAIN_AREA)
/datum/event2/meta/canister_leak/get_weight()
return metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 30

View File

@@ -5,6 +5,7 @@
chaotic_threshold = EVENT_CHAOS_THRESHOLD_LOW_IMPACT
reusable = TRUE
event_type = /datum/event2/event/dust
regions = list(EVENT_REGION_SPACESTATION)
/datum/event2/meta/dust/get_weight()
return metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 20

View File

@@ -5,6 +5,7 @@
chaotic_threshold = EVENT_CHAOS_THRESHOLD_LOW_IMPACT
reusable = TRUE
event_type = /datum/event2/event/gas_leak
regions = list(EVENT_REGION_PLAYER_MAIN_AREA)
/datum/event2/meta/gas_leak/get_weight()
// Synthetics are counted in higher value because they can wirelessly connect to alarms.

View File

@@ -11,6 +11,7 @@
chaotic_threshold = EVENT_CHAOS_THRESHOLD_LOW_IMPACT
reusable = TRUE
event_type = /datum/event2/event/grid_check
regions = list(EVENT_REGION_PLAYER_MAIN_AREA)
// Having the turbines be way over their rated limit makes grid checks more likely.
/datum/event2/meta/grid_check/proc/get_overpower()

View File

@@ -1,83 +1,84 @@
// This event gives the station an advance warning about meteors, so that they can prepare in various ways.
/datum/event2/meta/meteor_defense
name = "meteor defense"
departments = list(DEPARTMENT_ENGINEERING, DEPARTMENT_CARGO)
chaos = 50
chaotic_threshold = EVENT_CHAOS_THRESHOLD_HIGH_IMPACT
event_class = "meteor defense"
event_type = /datum/event2/event/meteor_defense
/datum/event2/meta/meteor_defense/get_weight()
// Engineers count as 20.
var/engineers = metric.count_people_in_department(DEPARTMENT_ENGINEERING)
if(engineers < 3) // There -must- be at least three engineers for this to be possible.
return 0
. = engineers * 20
// Cargo and AI/borgs count as 10.
var/cargo = metric.count_people_with_job(/datum/job/cargo_tech) + metric.count_people_with_job(/datum/job/qm)
var/bots = metric.count_people_in_department(DEPARTMENT_SYNTHETIC)
. += (cargo + bots) * 10
/datum/event2/event/meteor_defense
start_delay_lower_bound = 10 MINUTES
start_delay_upper_bound = 15 MINUTES
var/soon_announced = FALSE
var/direction = null // Actual dir used for which side the meteors come from.
var/dir_text = null // Direction shown in the announcement.
var/list/meteor_types = null
var/waves = null // How many times to send meteors.
var/last_wave_time = null // world.time of latest wave.
var/wave_delay = 10 SECONDS
var/wave_upper_bound = 8 // Max amount of meteors per wave.
var/wave_lower_bound = 4 // Min amount.
/datum/event2/event/meteor_defense/proc/set_meteor_types()
meteor_types = meteors_threatening.Copy()
/datum/event2/event/meteor_defense/set_up()
direction = pick(cardinal) // alldirs doesn't work with current meteor code unfortunately.
waves = rand(3, 6)
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"
set_meteor_types()
/datum/event2/event/meteor_defense/announce()
var/announcement = "Meteors are expected to approach from the [dir_text] side, in approximately [DisplayTimeText(time_to_start - world.time, 60)]."
command_announcement.Announce(announcement, "Meteor Alert", new_sound = 'sound/AI/meteors.ogg')
/datum/event2/event/meteor_defense/wait_tick()
if(!soon_announced)
if((time_to_start - world.time) <= 5 MINUTES)
soon_announced = TRUE
var/announcement = "The incoming meteors are expected to approach from the [dir_text] side. \
ETA to arrival is approximately [DisplayTimeText(time_to_start - world.time, 60)]."
command_announcement.Announce(announcement, "Meteor Alert - Update")
/datum/event2/event/meteor_defense/start()
command_announcement.Announce("Incoming meteors approach from \the [dir_text] side!", "Meteor Alert - Update")
/datum/event2/event/meteor_defense/event_tick()
if(world.time > last_wave_time + wave_delay)
last_wave_time = world.time
waves--
message_admins("[waves] more wave\s of meteors remain.")
// Dir is reversed because the direction describes where meteors are going, not what side it's gonna hit.
spawn_meteors(rand(wave_upper_bound, wave_lower_bound), meteor_types, reverse_dir[direction])
/datum/event2/event/meteor_defense/should_end()
return waves <= 0
/datum/event2/event/meteor_defense/end()
command_announcement.Announce("\The [location_name()] will clear the incoming meteors in a moment.", "Meteor Alert - Update")
// This event gives the station an advance warning about meteors, so that they can prepare in various ways.
/datum/event2/meta/meteor_defense
name = "meteor defense"
departments = list(DEPARTMENT_ENGINEERING, DEPARTMENT_CARGO)
chaos = 50
chaotic_threshold = EVENT_CHAOS_THRESHOLD_HIGH_IMPACT
event_class = "meteor defense"
event_type = /datum/event2/event/meteor_defense
regions = list(EVENT_REGION_SPACESTATION)
/datum/event2/meta/meteor_defense/get_weight()
// Engineers count as 20.
var/engineers = metric.count_people_in_department(DEPARTMENT_ENGINEERING)
if(engineers < 3) // There -must- be at least three engineers for this to be possible.
return 0
. = engineers * 20
// Cargo and AI/borgs count as 10.
var/cargo = metric.count_people_with_job(/datum/job/cargo_tech) + metric.count_people_with_job(/datum/job/qm)
var/bots = metric.count_people_in_department(DEPARTMENT_SYNTHETIC)
. += (cargo + bots) * 10
/datum/event2/event/meteor_defense
start_delay_lower_bound = 10 MINUTES
start_delay_upper_bound = 15 MINUTES
var/soon_announced = FALSE
var/direction = null // Actual dir used for which side the meteors come from.
var/dir_text = null // Direction shown in the announcement.
var/list/meteor_types = null
var/waves = null // How many times to send meteors.
var/last_wave_time = null // world.time of latest wave.
var/wave_delay = 10 SECONDS
var/wave_upper_bound = 8 // Max amount of meteors per wave.
var/wave_lower_bound = 4 // Min amount.
/datum/event2/event/meteor_defense/proc/set_meteor_types()
meteor_types = meteors_threatening.Copy()
/datum/event2/event/meteor_defense/set_up()
direction = pick(cardinal) // alldirs doesn't work with current meteor code unfortunately.
waves = rand(3, 6)
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"
set_meteor_types()
/datum/event2/event/meteor_defense/announce()
var/announcement = "Meteors are expected to approach from the [dir_text] side, in approximately [DisplayTimeText(time_to_start - world.time, 60)]."
command_announcement.Announce(announcement, "Meteor Alert", new_sound = 'sound/AI/meteors.ogg')
/datum/event2/event/meteor_defense/wait_tick()
if(!soon_announced)
if((time_to_start - world.time) <= 5 MINUTES)
soon_announced = TRUE
var/announcement = "The incoming meteors are expected to approach from the [dir_text] side. \
ETA to arrival is approximately [DisplayTimeText(time_to_start - world.time, 60)]."
command_announcement.Announce(announcement, "Meteor Alert - Update")
/datum/event2/event/meteor_defense/start()
command_announcement.Announce("Incoming meteors approach from \the [dir_text] side!", "Meteor Alert - Update")
/datum/event2/event/meteor_defense/event_tick()
if(world.time > last_wave_time + wave_delay)
last_wave_time = world.time
waves--
message_admins("[waves] more wave\s of meteors remain.")
// Dir is reversed because the direction describes where meteors are going, not what side it's gonna hit.
spawn_meteors(rand(wave_upper_bound, wave_lower_bound), meteor_types, reverse_dir[direction])
/datum/event2/event/meteor_defense/should_end()
return waves <= 0
/datum/event2/event/meteor_defense/end()
command_announcement.Announce("\The [location_name()] will clear the incoming meteors in a moment.", "Meteor Alert - Update")

View File

@@ -4,6 +4,7 @@
chaos = 10 // There's a really rare chance of vines getting something awful like phoron atmosphere but thats not really controllable.
chaotic_threshold = EVENT_CHAOS_THRESHOLD_MEDIUM_IMPACT
event_type = /datum/event2/event/spacevine
regions = list(EVENT_REGION_PLAYER_MAIN_AREA)
/datum/event2/meta/spacevine/get_weight()
return 20 + (metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 10) + (metric.count_people_in_department(DEPARTMENT_EVERYONE) * 5)

View File

@@ -3,6 +3,7 @@
departments = list(DEPARTMENT_ENGINEERING)
reusable = TRUE
event_type = /datum/event2/event/wallrot
regions = list(EVENT_REGION_PLAYER_MAIN_AREA)
/datum/event2/meta/wallrot/get_weight()
return (10 + metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 10) / (times_ran + 1)

View File

@@ -9,6 +9,7 @@
reusable = TRUE
chaotic_threshold = EVENT_CHAOS_THRESHOLD_MEDIUM_IMPACT
event_type = /datum/event2/event/window_break
regions = list(EVENT_REGION_PLAYER_MAIN_AREA)
/datum/event2/meta/window_break/get_weight()
return (metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 20) / (times_ran + 1)

View File

@@ -5,6 +5,7 @@
chaotic_threshold = EVENT_CHAOS_THRESHOLD_MEDIUM_IMPACT
reusable = TRUE
event_type = /datum/event2/event/comms_blackout
regions = list(EVENT_REGION_UNIVERSAL)
/datum/event2/meta/comms_blackout/get_weight()
return 50 + metric.count_people_in_department(DEPARTMENT_EVERYONE) * 5

View File

@@ -8,6 +8,7 @@
chaos = 10
chaotic_threshold = EVENT_CHAOS_THRESHOLD_LOW_IMPACT
event_type = /datum/event2/event/electrical_fault
regions = list(EVENT_REGION_PLAYER_MAIN_AREA)
/datum/event2/meta/electrical_fault/get_weight()
return 10 + (metric.count_people_in_department(DEPARTMENT_EVERYONE) * 5)

View File

@@ -5,6 +5,7 @@
chaotic_threshold = EVENT_CHAOS_THRESHOLD_LOW_IMPACT
reusable = TRUE
event_type = /datum/event2/event/gravity
regions = list(EVENT_REGION_SPACESTATION, EVENT_REGION_DEEPSPACE)
/datum/event2/meta/gravity/get_weight()
return (20 + (metric.count_people_in_department(DEPARTMENT_EVERYONE) * 5)) / (times_ran + 1)

View File

@@ -1,6 +1,7 @@
/datum/event2/meta/infestation
event_class = "infestation"
departments = list(DEPARTMENT_EVERYONE)
regions = list(EVENT_REGION_PLAYER_MAIN_AREA)
/datum/event2/meta/infestation/get_weight()
return metric.count_people_in_department(DEPARTMENT_EVERYONE) * 10

View File

@@ -2,6 +2,7 @@
name = "pda spam"
departments = list(DEPARTMENT_EVERYONE)
event_type = /datum/event2/event/pda_spam
regions = list(EVENT_REGION_UNIVERSAL)
/datum/event2/meta/pda_spam/get_weight()
return metric.count_people_in_department(DEPARTMENT_EVERYONE) * 2
@@ -96,7 +97,7 @@
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>",\
" 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)

View File

@@ -4,6 +4,7 @@
chaos = 20
chaotic_threshold = EVENT_CHAOS_THRESHOLD_MEDIUM_IMPACT
event_type = /datum/event2/event/radiation_storm
regions = list(EVENT_REGION_SPACESTATION, EVENT_REGION_DEEPSPACE)
/datum/event2/meta/radiation_storm/get_weight()
var/medical_factor = metric.count_people_in_department(DEPARTMENT_MEDICAL) * 10

View File

@@ -10,6 +10,7 @@
departments = list(DEPARTMENT_EVERYONE)
chaotic_threshold = EVENT_CHAOS_THRESHOLD_MEDIUM_IMPACT
event_type = /datum/event2/event/random_antagonist
regions = list(EVENT_REGION_UNIVERSAL)
// This has an abnormally high weight due to antags being very important for the round,
// however the weight will decay with more antags, and more attempts to add antags.

View File

@@ -2,6 +2,7 @@
name = "solar storm"
reusable = TRUE
event_type = /datum/event2/event/solar_storm
regions = list(EVENT_REGION_SPACESTATION, EVENT_REGION_DEEPSPACE)
/datum/event2/meta/solar_storm/get_weight()
var/population_factor = metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 10

View File

@@ -3,6 +3,7 @@
departments = list(DEPARTMENT_EVERYONE)
reusable = TRUE
event_type = /datum/event2/event/sudden_weather_shift
regions = list(EVENT_REGION_PLANETSURFACE)
/datum/event2/meta/sudden_weather_shift/get_weight()
// The proc name is a bit misleading, it only counts players outside, not all mobs.

View File

@@ -4,6 +4,7 @@
chaos = 40
chaotic_threshold = EVENT_CHAOS_THRESHOLD_MEDIUM_IMPACT
event_type = /datum/event2/event/appendicitis
regions = list(EVENT_REGION_PLAYER_MAIN_AREA)
/datum/event2/meta/appendicitis/get_weight()
var/list/doctors = metric.get_people_with_job(/datum/job/doctor)

View File

@@ -5,6 +5,7 @@
chaos = 40
chaotic_threshold = EVENT_CHAOS_THRESHOLD_HIGH_IMPACT
event_type = /datum/event2/event/virus
regions = list(EVENT_REGION_PLAYER_MAIN_AREA)
/datum/event2/meta/virus/superbug
name = "viral superbug"

View File

@@ -5,6 +5,7 @@
chaos = 30
chaotic_threshold = EVENT_CHAOS_THRESHOLD_MEDIUM_IMPACT
event_type = /datum/event2/event/mob_spawning/carp_migration
regions = list(EVENT_REGION_SPACESTATION, EVENT_REGION_DEEPSPACE)
/datum/event2/meta/carp_migration/get_weight()
return 10 + (metric.count_people_in_department(DEPARTMENT_SECURITY) * 20) + (metric.count_all_space_mobs() * 40)

View File

@@ -3,6 +3,7 @@
departments = list(DEPARTMENT_SECURITY, DEPARTMENT_EVERYONE)
chaotic_threshold = EVENT_CHAOS_THRESHOLD_HIGH_IMPACT // Don't run if we just got hit by meteors.
event_type = /datum/event2/event/security_drill
regions = list(EVENT_REGION_PLAYER_MAIN_AREA)
/datum/event2/meta/security_drill/get_weight()
var/sec = metric.count_people_in_department(DEPARTMENT_SECURITY)

View File

@@ -10,6 +10,7 @@
// the prison area.
var/list/relevant_areas = list()
var/list/irrelevant_areas = list()
regions = list(EVENT_REGION_PLAYER_MAIN_AREA)
/datum/event2/meta/prison_break/get_weight()
// First, don't do this if nobody can fix the doors.

View File

@@ -4,6 +4,7 @@
chaos = 40
chaotic_threshold = EVENT_CHAOS_THRESHOLD_MEDIUM_IMPACT
event_type = /datum/event2/event/mob_spawning/rogue_drones
regions = list(EVENT_REGION_SPACESTATION, EVENT_REGION_DEEPSPACE)
/datum/event2/meta/rogue_drones/get_weight()
. = 10 // Start with a base weight, since this event does provide some value even if no sec is around.

View File

@@ -3,6 +3,7 @@
departments = list(DEPARTMENT_SECURITY, DEPARTMENT_EVERYONE)
chaotic_threshold = EVENT_CHAOS_THRESHOLD_HIGH_IMPACT // So this won't get called in the middle of a crisis.
event_type = /datum/event2/event/security_screening
regions = list(EVENT_REGION_UNIVERSAL)
/datum/event2/meta/security_screening/get_weight()
. = 0

View File

@@ -5,6 +5,7 @@
chaos = 30
chaotic_threshold = EVENT_CHAOS_THRESHOLD_MEDIUM_IMPACT
event_type = /datum/event2/event/spider_infestation
regions = list(EVENT_REGION_PLAYER_MAIN_AREA)
/datum/event2/meta/spider_infestation/weak
name = "weak spider infestation"

View File

@@ -6,6 +6,7 @@
chaotic_threshold = EVENT_CHAOS_THRESHOLD_LOW_IMPACT
event_type = /datum/event2/event/ghost_pod_spawner/stowaway
var/safe_for_extended = FALSE
regions = list(EVENT_REGION_PLAYER_MAIN_AREA)
/datum/event2/meta/stowaway/normal
name = "stowaway - normal"

View File

@@ -6,6 +6,7 @@
chaos = 20
chaotic_threshold = EVENT_CHAOS_THRESHOLD_MEDIUM_IMPACT
event_type = /datum/event2/event/surprise_carp
regions = list(EVENT_REGION_SPACESTATION, EVENT_REGION_DEEPSPACE)
/datum/event2/meta/surprise_carp/get_weight()
return metric.count_all_space_mobs() * 50

View File

@@ -7,6 +7,7 @@
chaotic_threshold = EVENT_CHAOS_THRESHOLD_HIGH_IMPACT
enabled = FALSE // Turns out they are in fact grossly OP.
var/safe_for_extended = FALSE
regions = list(EVENT_REGION_SPACESTATION, EVENT_REGION_DEEPSPACE)
/datum/event2/meta/swarm_boarder/get_weight()
if(istype(ticker.mode, /datum/game_mode/extended) && !safe_for_extended)

View File

@@ -4,6 +4,7 @@
chaos = 40
chaotic_threshold = EVENT_CHAOS_THRESHOLD_MEDIUM_IMPACT
event_type = /datum/event2/event/ion_storm
regions = list(EVENT_REGION_SPACESTATION, EVENT_REGION_DEEPSPACE)
/datum/event2/meta/ion_storm/get_weight()
var/list/bots = metric.get_people_in_department(DEPARTMENT_SYNTHETIC)

View File

@@ -14,6 +14,11 @@
// What departments the event attached might affect.
var/list/departments = list(DEPARTMENT_EVERYONE)
// The region affects by this event
// Affects event weight by a similar metric to department population:
// If everybody is planetside, then a meteor storm on the station doesn't really add as much
var/list/regions = list(EVENT_REGION_UNIVERSAL)
// A guess on how disruptive to a round the event might be. If the action is chosen, the GM's
// 'danger' score is increased by this number.
// Negative numbers could be used to signify helpful events.

View File

@@ -91,3 +91,15 @@
num++
if(num)
. = round(. / num, 0.1)
// Computes activity of players on a per-region basis
/datum/metric/proc/assess_player_regions()
. = list()
for(var/mob/living/L in player_list)
var/activity = assess_player_activity(L)
for(var/region in L.get_player_regions())
.[region] += activity
// To prevent the universal region from being chosen too often, scale it down
// If lots of players are active over a wide set of regions, this should prefer events that cover a wider area
.[EVENT_REGION_UNIVERSAL] = round(.[EVENT_REGION_UNIVERSAL] / 2, 1)

View File

@@ -1136,3 +1136,23 @@
// Each mob does vision a bit differently so this is just for inheritence and also so overrided procs can make the vision apply instantly if they call `..()`.
/mob/living/proc/disable_spoiler_vision()
handle_vision()
/mob/living/proc/get_player_regions()
// A living player is always in a universal region
. = list(EVENT_REGION_UNIVERSAL)
var/turf/T = get_turf(src)
var/obj/effect/overmap/visitable/M = get_overmap_sector(T.z)
if(istype(M))
if(M.in_space)
if(T.z in using_map.station_levels)
. |= EVENT_REGION_SPACESTATION
else
. |= EVENT_REGION_DEEPSPACE
else
. |= EVENT_REGION_PLANETSURFACE
var/datum/map_z_level/zlevel = using_map.zlevels["[T.z]"]
if(istype(zlevel))
. |= zlevel.event_regions

View File

@@ -167,6 +167,7 @@
flags = MAP_LEVEL_STATION|MAP_LEVEL_CONTACT|MAP_LEVEL_PLAYER|MAP_LEVEL_CONSOLES
holomap_legend_x = 220
holomap_legend_y = 160
event_regions = list(EVENT_REGION_SPACESTATION, EVENT_REGION_PLAYER_MAIN_AREA)
/datum/map_z_level/southern_cross/station/station_one
z = Z_LEVEL_STATION_ONE
@@ -197,24 +198,28 @@
name = "Empty"
flags = MAP_LEVEL_PLAYER
transit_chance = 76
event_regions = list(EVENT_REGION_DEEPSPACE)
/datum/map_z_level/southern_cross/surface
z = Z_LEVEL_SURFACE
name = "Plains"
flags = MAP_LEVEL_CONTACT|MAP_LEVEL_PLAYER|MAP_LEVEL_SEALED|MAP_LEVEL_CONSOLES
base_turf = /turf/simulated/floor/outdoors/rocks
event_regions = list(EVENT_REGION_PLANETSURFACE, EVENT_REGION_PLAYER_MAIN_AREA)
/datum/map_z_level/southern_cross/surface_mine
z = Z_LEVEL_SURFACE_MINE
name = "Mountains"
flags = MAP_LEVEL_CONTACT|MAP_LEVEL_PLAYER|MAP_LEVEL_SEALED|MAP_LEVEL_CONSOLES
base_turf = /turf/simulated/floor/outdoors/rocks
event_regions = list(EVENT_REGION_PLANETSURFACE, EVENT_REGION_SUBTERRANEAN)
/datum/map_z_level/southern_cross/surface_wild
z = Z_LEVEL_SURFACE_WILD
name = "Wilderness"
flags = MAP_LEVEL_PLAYER|MAP_LEVEL_SEALED|MAP_LEVEL_CONTACT|MAP_LEVEL_CONSOLES
base_turf = /turf/simulated/floor/outdoors/rocks
event_regions = list(EVENT_REGION_PLANETSURFACE)
/datum/map_z_level/southern_cross/misc
z = Z_LEVEL_MISC

View File

@@ -113,7 +113,7 @@ var/list/all_maps = list()
var/list/unit_test_z_levels //To test more than Z1, set your z-levels to test here.
var/list/planet_datums_to_make = list() // Types of `/datum/planet`s that will be instantiated by SSPlanets.
/datum/map/New()
..()
if(zlevel_datum_type)
@@ -270,15 +270,19 @@ var/list/all_maps = list()
var/turf/base_turf // Type path of the base turf for this z
var/transit_chance = 0 // Percentile chance this z will be chosen for map-edge space transit.
// Holomaps
// Holomaps
var/holomap_offset_x = -1 // Number of pixels to offset the map right (for centering) for this z
var/holomap_offset_y = -1 // Number of pixels to offset the map up (for centering) for this z
var/holomap_legend_x = 96 // x position of the holomap legend for this z
var/holomap_legend_y = 96 // y position of the holomap legend for this z
// Skybox
// Skybox
var/datum/skybox_settings/custom_skybox // Can override skybox type here for this z
// List of regions for GameMaster events
var/list/event_regions = list()
// Default constructor applies itself to the parent map datum
/datum/map_z_level/New(var/datum/map/map)
if(!z) return

View File

@@ -36,6 +36,7 @@
#include "code\__defines\crafting.dm"
#include "code\__defines\damage_organs.dm"
#include "code\__defines\dna.dm"
#include "code\__defines\events.dm"
#include "code\__defines\flags.dm"
#include "code\__defines\gamemode.dm"
#include "code\__defines\holomap.dm"
@@ -1902,7 +1903,7 @@
#include "code\modules\gamemaster\event2\events\engineering\dust.dm"
#include "code\modules\gamemaster\event2\events\engineering\gas_leak.dm"
#include "code\modules\gamemaster\event2\events\engineering\grid_check.dm"
#include "code\modules\gamemaster\event2\events\engineering\meteor_defense.dm"
#include "code\modules\gamemaster\event2\events\engineering\space_meteor_defense.dm"
#include "code\modules\gamemaster\event2\events\engineering\spacevine.dm"
#include "code\modules\gamemaster\event2\events\engineering\wallrot.dm"
#include "code\modules\gamemaster\event2\events\engineering\window_break.dm"