From 9b9de138e67cac90cd0ab10ba1ceb2bf2044f9f5 Mon Sep 17 00:00:00 2001 From: Neerti Date: Sun, 29 Jan 2017 19:32:20 -0500 Subject: [PATCH] Continues work on new Event System Ports and adds some more events, including dust, meteors, carp, etc. Tweaks meteors, now has a 10 minute warning beforehand and meteors only approach from one direction now. --- code/modules/gamemaster/actions/action.dm | 5 +- .../gamemaster/actions/carp_migration.dm | 65 +++++++++++++++++++ .../gamemaster/actions/comms_blackout.dm | 18 ++++- code/modules/gamemaster/actions/dust.dm | 17 +++++ code/modules/gamemaster/actions/grid_check.dm | 1 + .../gamemaster/actions/meteor_defense.dm | 51 +++++++++++++++ .../gamemaster/actions/shipping_error.dm | 17 +++++ .../actions/surprise_carp_attack.dm | 53 +++++++++++++++ .../gamemaster/actions/surprise_meteor.dm | 17 +++++ code/modules/gamemaster/controller.dm | 16 ++++- code/modules/gamemaster/game_master.dm | 21 ++++-- polaris.dme | 6 ++ 12 files changed, 273 insertions(+), 14 deletions(-) create mode 100644 code/modules/gamemaster/actions/carp_migration.dm create mode 100644 code/modules/gamemaster/actions/dust.dm create mode 100644 code/modules/gamemaster/actions/meteor_defense.dm create mode 100644 code/modules/gamemaster/actions/shipping_error.dm create mode 100644 code/modules/gamemaster/actions/surprise_carp_attack.dm create mode 100644 code/modules/gamemaster/actions/surprise_meteor.dm diff --git a/code/modules/gamemaster/actions/action.dm b/code/modules/gamemaster/actions/action.dm index 82ebd860b5..aa259ccc03 100644 --- a/code/modules/gamemaster/actions/action.dm +++ b/code/modules/gamemaster/actions/action.dm @@ -5,12 +5,9 @@ var/chaotic = 0 // A number showing how chaotic the action may be. If danger is high, the GM will avoid it. 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 -/datum/gm_action/New(var/datum/game_master/new_gm) - ..() - gm = new_gm - /datum/gm_action/proc/set_up() return diff --git a/code/modules/gamemaster/actions/carp_migration.dm b/code/modules/gamemaster/actions/carp_migration.dm new file mode 100644 index 0000000000..520eb0c314 --- /dev/null +++ b/code/modules/gamemaster/actions/carp_migration.dm @@ -0,0 +1,65 @@ +//carp_migration +/datum/gm_action/carp_migration + name = "carp migration" + departments = list(ROLE_SECURITY, ROLE_EVERYONE) + chaotic = 50 + var/list/spawned_carp = list() + var/carp_amount = 0 + length = 20 MINUTES + +/datum/gm_action/carp_migration/get_weight() + var/people_in_space = 0 + for(var/mob/living/L in player_list) + if(!(L.z in config.station_levels)) + continue // Not on the right z-level. + var/turf/T = get_turf(L) + if(istype(T, /turf/space) && istype(T.loc,/area/space)) + people_in_space++ + return 50 + (metric.count_people_in_department(ROLE_SECURITY) * 10) + (people_in_space * 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(ROLE_SECURITY) * 3) + station_strength += (metric.count_people_in_department(ROLE_ENGINEERING) * 2) + station_strength += metric.count_people_in_department(ROLE_MEDICAL) + + // Less active emergency response departments tones the event down. + var/activeness = ((metric.assess_department(ROLE_SECURITY) + metric.assess_department(ROLE_ENGINEERING) + metric.assess_department(ROLE_MEDICAL)) / 3) + activeness = max(activeness, 20) + + carp_amount = Ceiling(station_strength * (activeness / 100) + 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_animal/hostile/carp(spawn_locations[i])) + i++ + message_admins("[spawned_carp.len] carp spawned by event.") + +/datum/gm_action/carp_migration/end() + for(var/mob/living/simple_animal/hostile/carp/C in spawned_carp) + if(!C.stat) + var/turf/T = get_turf(C) + if(istype(T, /turf/space)) + if(!prob(25)) + qdel(C) \ No newline at end of file diff --git a/code/modules/gamemaster/actions/comms_blackout.dm b/code/modules/gamemaster/actions/comms_blackout.dm index 75359085ac..71b172b153 100644 --- a/code/modules/gamemaster/actions/comms_blackout.dm +++ b/code/modules/gamemaster/actions/comms_blackout.dm @@ -1,9 +1,21 @@ -// Comms blackout is, just like grid check, mostly the same as always, yet engineering has an option to get it back sooner. - /datum/gm_action/comms_blackout name = "communications blackout" departments = list(ROLE_ENGINEERING, ROLE_EVERYONE) chaotic = 35 /datum/gm_action/comms_blackout/get_weight() - return 50 + (metric.count_people_in_department(ROLE_ENGINEERING) * 40) \ No newline at end of file + return 50 + (metric.count_people_in_department(ROLE_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) + A << "
" + A << "Ionospheric anomalies detected. Temporary telecommunication failure imminent. Please contact you-BZZT" + A << "
" + +/datum/gm_action/comms_blackout/start() + ..() + for(var/obj/machinery/telecomms/T in telecomms_list) + T.emp_act(1) diff --git a/code/modules/gamemaster/actions/dust.dm b/code/modules/gamemaster/actions/dust.dm new file mode 100644 index 0000000000..caecc51445 --- /dev/null +++ b/code/modules/gamemaster/actions/dust.dm @@ -0,0 +1,17 @@ +/datum/gm_action/dust + name = "dust" + departments = list(ROLE_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(ROLE_ENGINEERING) + var/weight = 30 + (engineers * 25) + return weight + +/datum/gm_action/dust/start() + ..() + dust_swarm("norm") \ No newline at end of file diff --git a/code/modules/gamemaster/actions/grid_check.dm b/code/modules/gamemaster/actions/grid_check.dm index 08c817fdf9..dcf35a230f 100644 --- a/code/modules/gamemaster/actions/grid_check.dm +++ b/code/modules/gamemaster/actions/grid_check.dm @@ -13,6 +13,7 @@ return 50 + (metric.count_people_in_department(ROLE_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) diff --git a/code/modules/gamemaster/actions/meteor_defense.dm b/code/modules/gamemaster/actions/meteor_defense.dm new file mode 100644 index 0000000000..1bae723b00 --- /dev/null +++ b/code/modules/gamemaster/actions/meteor_defense.dm @@ -0,0 +1,51 @@ +// 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(ROLE_ENGINEERING) + chaotic = 50 + var/direction = null + var/dir_text = null + var/waves = 0 + +/datum/gm_action/meteor_defense/get_weight() + var/engineers = metric.count_people_in_department(ROLE_ENGINEERING) + var/weight = (max(engineers - 1, 0) * 25) // If only one engineer exists, no meteors for now. + return weight + +/datum/gm_action/meteor_defense/set_up() + 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 other asteroids have collided near [station_name()]. Chunks of it are expected to approach from the [dir_text] side. ETA to arrival is \ + approximately 10 minutes." + command_announcement.Announce(announcement, "Meteor Alert", new_sound = 'sound/AI/meteors.ogg') + +/datum/gm_action/meteor_defense/start() + ..() + spawn(0) + // sleep(5 MINUTES) + var/announcement = "The incoming debris are expected to approach from the [dir_text] side. ETA to arrival is approximately 5 minutes." + command_announcement.Announce(announcement, "Meteor Alert - Update") + // sleep(5 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 colony has cleared the incoming debris." + command_announcement.Announce(announcement, "Meteor Alert - Update") + message_admins("Meteor defense event has ended.") \ No newline at end of file diff --git a/code/modules/gamemaster/actions/shipping_error.dm b/code/modules/gamemaster/actions/shipping_error.dm new file mode 100644 index 0000000000..affbe94dc9 --- /dev/null +++ b/code/modules/gamemaster/actions/shipping_error.dm @@ -0,0 +1,17 @@ +/datum/gm_action/shipping_error + name = "shipping error" + departments = list(ROLE_CARGO) + reusable = TRUE + +/datum/gm_action/shipping_error/get_weight() + var/cargo = metric.count_people_in_department(ROLE_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_packs[pick(supply_controller.supply_packs)] + O.orderedby = random_name(pick(MALE,FEMALE), species = "Human") + supply_controller.shoppinglist += O \ No newline at end of file diff --git a/code/modules/gamemaster/actions/surprise_carp_attack.dm b/code/modules/gamemaster/actions/surprise_carp_attack.dm new file mode 100644 index 0000000000..c91103c878 --- /dev/null +++ b/code/modules/gamemaster/actions/surprise_carp_attack.dm @@ -0,0 +1,53 @@ +// This event sends a few carp after someone in space. + +/datum/gm_action/surprise_carp_attack + name = "surprise carp attack" + departments = list(ROLE_EVERYONE) + reusable = TRUE + chaotic = 10 + var/mob/living/victim = null + +/datum/gm_action/surprise_carp_attack/get_weight() + var/people_in_space = 0 + for(var/mob/living/L in player_list) + if(!(L.z in config.station_levels)) + continue // Not on the right z-level. + var/turf/T = get_turf(L) + if(istype(T, /turf/space) && istype(T.loc,/area/space)) + people_in_space++ + return people_in_space * 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 config.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) + 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) + var/mob/living/simple_animal/hostile/carp/C = new(spawning_turf) + C.target_mob = victim + C.stance = STANCE_ATTACK + number_of_carp-- \ No newline at end of file diff --git a/code/modules/gamemaster/actions/surprise_meteor.dm b/code/modules/gamemaster/actions/surprise_meteor.dm new file mode 100644 index 0000000000..682a8287a6 --- /dev/null +++ b/code/modules/gamemaster/actions/surprise_meteor.dm @@ -0,0 +1,17 @@ +// This event sends one wave of meteors unannounced. + +/datum/gm_action/surprise_meteors + name = "surprise meteors" + departments = list(ROLE_ENGINEERING) + chaotic = 25 + +/datum/gm_action/surprise_meteors/get_weight() + var/engineers = metric.count_people_in_department(ROLE_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.") \ No newline at end of file diff --git a/code/modules/gamemaster/controller.dm b/code/modules/gamemaster/controller.dm index 079c535164..343f05842d 100644 --- a/code/modules/gamemaster/controller.dm +++ b/code/modules/gamemaster/controller.dm @@ -24,7 +24,7 @@ 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()])
" + HTML += "[action.name] ([english_list(action.departments)]) (weight: [action.get_weight()]) \[Force\]
" HTML += "
" HTML += "All living mobs activity: [metric.assess_all_living_mobs()]%
" @@ -77,4 +77,16 @@ adjust_danger(amount) message_admins("GM danger was adjusted by [amount] by [usr.key].") - interact(usr) // To refresh the UI. \ No newline at end of file + interact(usr) // To refresh the UI. + +/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].") \ No newline at end of file diff --git a/code/modules/gamemaster/game_master.dm b/code/modules/gamemaster/game_master.dm index 180892f4c9..c435e868f6 100644 --- a/code/modules/gamemaster/game_master.dm +++ b/code/modules/gamemaster/game_master.dm @@ -19,6 +19,8 @@ /datum/game_master/New() ..() available_actions = init_subtypes(/datum/gm_action) + for(var/datum/gm_action/action in available_actions) + action.gm = src /datum/game_master/proc/process() if(ticker && ticker.current_state == GAME_STATE_PLAYING && !suspended) @@ -68,17 +70,26 @@ 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.") - choice.set_up() - choice.start() - next_action = world.time + rand(15 MINUTES, 30 MINUTES) - last_department_used = choice.departments[1] - + run_action(choice) +/datum/game_master/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(15 MINUTES, 30 MINUTES) + last_department_used = action.departments[1] /datum/game_master/proc/decide_best_action(var/list/most_active_departments) diff --git a/polaris.dme b/polaris.dme index 17eb4b2ef2..ca0b3b5a6e 100644 --- a/polaris.dme +++ b/polaris.dme @@ -1357,8 +1357,14 @@ #include "code\modules\gamemaster\game_master.dm" #include "code\modules\gamemaster\helpers.dm" #include "code\modules\gamemaster\actions\action.dm" +#include "code\modules\gamemaster\actions\carp_migration.dm" #include "code\modules\gamemaster\actions\comms_blackout.dm" +#include "code\modules\gamemaster\actions\dust.dm" #include "code\modules\gamemaster\actions\grid_check.dm" +#include "code\modules\gamemaster\actions\meteor_defense.dm" +#include "code\modules\gamemaster\actions\shipping_error.dm" +#include "code\modules\gamemaster\actions\surprise_carp_attack.dm" +#include "code\modules\gamemaster\actions\surprise_meteor.dm" #include "code\modules\gamemaster\actions\waste_disposal.dm" #include "code\modules\games\cah.dm" #include "code\modules\games\cah_black_cards.dm"