mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-08-29 15:08:34 +01:00
Whitespace Standardization [MDB IGNORE] (#15748)
* Update settings * Whitespace changes * Comment out merger hooks in gitattributes Corrupt maps would have to be resolved in repo before hooks could be updated * Revert "Whitespace changes" This reverts commitafbdd1d844. * Whitespace again minus example * Gitignore example changelog * Restore changelog merge setting * Keep older dmi hook attribute until hooks can be updated * update vscode settings too * Renormalize remaining * Revert "Gitignore example changelog" This reverts commitde22ad375d. * Attempt to normalize example.yml (and another file I guess) * Try again
This commit is contained in:
@@ -1,105 +1,105 @@
|
||||
/datum/event2/meta/airlock_failure
|
||||
event_class = "airlock failure"
|
||||
departments = list(DEPARTMENT_ENGINEERING, DEPARTMENT_MEDICAL)
|
||||
chaos = 15
|
||||
chaotic_threshold = EVENT_CHAOS_THRESHOLD_MEDIUM_IMPACT
|
||||
event_type = /datum/event2/event/airlock_failure
|
||||
var/needs_medical = FALSE
|
||||
|
||||
/datum/event2/meta/airlock_failure/emag
|
||||
name = "airlock failure - emag"
|
||||
event_type = /datum/event2/event/airlock_failure/emag
|
||||
|
||||
/datum/event2/meta/airlock_failure/door_crush
|
||||
name = "airlock failure - crushing"
|
||||
event_type = /datum/event2/event/airlock_failure/door_crush
|
||||
needs_medical = TRUE
|
||||
|
||||
/datum/event2/meta/airlock_failure/shock
|
||||
name = "airlock failure - shock"
|
||||
chaos = 30
|
||||
event_type = /datum/event2/event/airlock_failure/shock
|
||||
needs_medical = TRUE
|
||||
|
||||
|
||||
/datum/event2/meta/airlock_failure/get_weight()
|
||||
var/engineering = metric.count_people_in_department(DEPARTMENT_ENGINEERING)
|
||||
|
||||
// Synths are good both for fixing the doors and getting blamed for the doors zapping people.
|
||||
var/synths = metric.count_people_in_department(DEPARTMENT_SYNTHETIC)
|
||||
if(!engineering && !synths) // Nobody's around to fix the door.
|
||||
return 0
|
||||
|
||||
// Medical might be needed for some of the more violent airlock failures.
|
||||
var/medical = metric.count_people_in_department(DEPARTMENT_MEDICAL)
|
||||
if(!medical && needs_medical)
|
||||
return 0
|
||||
|
||||
return (engineering * 20) + (medical * 20) + (synths * 20)
|
||||
|
||||
|
||||
|
||||
/datum/event2/event/airlock_failure
|
||||
announce_delay_lower_bound = 20 SECONDS
|
||||
announce_delay_upper_bound = 40 SECONDS
|
||||
var/announce_odds = 0
|
||||
var/doors_to_break = 1
|
||||
var/list/affected_areas = list()
|
||||
|
||||
/datum/event2/event/airlock_failure/emag
|
||||
announce_odds = 10 // To make people wonder if the emagged door was from a baddie or from this event.
|
||||
doors_to_break = 2 // Replacing emagged doors really sucks for engineering so don't overdo it.
|
||||
|
||||
/datum/event2/event/airlock_failure/door_crush
|
||||
announce_odds = 30
|
||||
doors_to_break = 5
|
||||
|
||||
/datum/event2/event/airlock_failure/shock
|
||||
announce_odds = 70
|
||||
|
||||
/datum/event2/event/airlock_failure/start()
|
||||
var/list/areas = find_random_areas()
|
||||
if(!LAZYLEN(areas))
|
||||
log_debug("Airlock Failure event could not find any areas. Aborting.")
|
||||
abort()
|
||||
return
|
||||
|
||||
while(areas.len)
|
||||
var/area/area = pick(areas)
|
||||
areas -= area
|
||||
|
||||
for(var/obj/machinery/door/airlock/door in area.contents)
|
||||
if(can_break_door(door))
|
||||
addtimer(CALLBACK(src, PROC_REF(break_door), door), 1) // Emagging proc is actually a blocking proc and that's bad for the ticker.
|
||||
door.visible_message(span("danger", "\The [door]'s panel sparks!"))
|
||||
playsound(door, "sparks", 50, 1)
|
||||
log_debug("Airlock Failure event has broken \the [door] airlock in [area].")
|
||||
affected_areas |= area
|
||||
doors_to_break--
|
||||
|
||||
if(doors_to_break <= 0)
|
||||
return
|
||||
|
||||
/datum/event2/event/airlock_failure/announce()
|
||||
if(prob(announce_odds))
|
||||
command_announcement.Announce("An electrical issue has been detected in the airlock grid at [english_list(affected_areas)]. \
|
||||
Some airlocks may require servicing by a qualified technician.", "Electrical Alert")
|
||||
|
||||
|
||||
/datum/event2/event/airlock_failure/proc/can_break_door(obj/machinery/door/airlock/door)
|
||||
if(istype(door, /obj/machinery/door/airlock/lift))
|
||||
return FALSE
|
||||
return door.arePowerSystemsOn()
|
||||
|
||||
// Override this for door busting.
|
||||
/datum/event2/event/airlock_failure/proc/break_door(obj/machinery/door/airlock/door)
|
||||
|
||||
/datum/event2/event/airlock_failure/emag/break_door(obj/machinery/door/airlock/door)
|
||||
door.emag_act(1)
|
||||
|
||||
/datum/event2/event/airlock_failure/door_crush/break_door(obj/machinery/door/airlock/door)
|
||||
door.normalspeed = FALSE
|
||||
door.safe = FALSE
|
||||
|
||||
/datum/event2/event/airlock_failure/shock/break_door(obj/machinery/door/airlock/door)
|
||||
door.electrify(-1)
|
||||
/datum/event2/meta/airlock_failure
|
||||
event_class = "airlock failure"
|
||||
departments = list(DEPARTMENT_ENGINEERING, DEPARTMENT_MEDICAL)
|
||||
chaos = 15
|
||||
chaotic_threshold = EVENT_CHAOS_THRESHOLD_MEDIUM_IMPACT
|
||||
event_type = /datum/event2/event/airlock_failure
|
||||
var/needs_medical = FALSE
|
||||
|
||||
/datum/event2/meta/airlock_failure/emag
|
||||
name = "airlock failure - emag"
|
||||
event_type = /datum/event2/event/airlock_failure/emag
|
||||
|
||||
/datum/event2/meta/airlock_failure/door_crush
|
||||
name = "airlock failure - crushing"
|
||||
event_type = /datum/event2/event/airlock_failure/door_crush
|
||||
needs_medical = TRUE
|
||||
|
||||
/datum/event2/meta/airlock_failure/shock
|
||||
name = "airlock failure - shock"
|
||||
chaos = 30
|
||||
event_type = /datum/event2/event/airlock_failure/shock
|
||||
needs_medical = TRUE
|
||||
|
||||
|
||||
/datum/event2/meta/airlock_failure/get_weight()
|
||||
var/engineering = metric.count_people_in_department(DEPARTMENT_ENGINEERING)
|
||||
|
||||
// Synths are good both for fixing the doors and getting blamed for the doors zapping people.
|
||||
var/synths = metric.count_people_in_department(DEPARTMENT_SYNTHETIC)
|
||||
if(!engineering && !synths) // Nobody's around to fix the door.
|
||||
return 0
|
||||
|
||||
// Medical might be needed for some of the more violent airlock failures.
|
||||
var/medical = metric.count_people_in_department(DEPARTMENT_MEDICAL)
|
||||
if(!medical && needs_medical)
|
||||
return 0
|
||||
|
||||
return (engineering * 20) + (medical * 20) + (synths * 20)
|
||||
|
||||
|
||||
|
||||
/datum/event2/event/airlock_failure
|
||||
announce_delay_lower_bound = 20 SECONDS
|
||||
announce_delay_upper_bound = 40 SECONDS
|
||||
var/announce_odds = 0
|
||||
var/doors_to_break = 1
|
||||
var/list/affected_areas = list()
|
||||
|
||||
/datum/event2/event/airlock_failure/emag
|
||||
announce_odds = 10 // To make people wonder if the emagged door was from a baddie or from this event.
|
||||
doors_to_break = 2 // Replacing emagged doors really sucks for engineering so don't overdo it.
|
||||
|
||||
/datum/event2/event/airlock_failure/door_crush
|
||||
announce_odds = 30
|
||||
doors_to_break = 5
|
||||
|
||||
/datum/event2/event/airlock_failure/shock
|
||||
announce_odds = 70
|
||||
|
||||
/datum/event2/event/airlock_failure/start()
|
||||
var/list/areas = find_random_areas()
|
||||
if(!LAZYLEN(areas))
|
||||
log_debug("Airlock Failure event could not find any areas. Aborting.")
|
||||
abort()
|
||||
return
|
||||
|
||||
while(areas.len)
|
||||
var/area/area = pick(areas)
|
||||
areas -= area
|
||||
|
||||
for(var/obj/machinery/door/airlock/door in area.contents)
|
||||
if(can_break_door(door))
|
||||
addtimer(CALLBACK(src, PROC_REF(break_door), door), 1) // Emagging proc is actually a blocking proc and that's bad for the ticker.
|
||||
door.visible_message(span("danger", "\The [door]'s panel sparks!"))
|
||||
playsound(door, "sparks", 50, 1)
|
||||
log_debug("Airlock Failure event has broken \the [door] airlock in [area].")
|
||||
affected_areas |= area
|
||||
doors_to_break--
|
||||
|
||||
if(doors_to_break <= 0)
|
||||
return
|
||||
|
||||
/datum/event2/event/airlock_failure/announce()
|
||||
if(prob(announce_odds))
|
||||
command_announcement.Announce("An electrical issue has been detected in the airlock grid at [english_list(affected_areas)]. \
|
||||
Some airlocks may require servicing by a qualified technician.", "Electrical Alert")
|
||||
|
||||
|
||||
/datum/event2/event/airlock_failure/proc/can_break_door(obj/machinery/door/airlock/door)
|
||||
if(istype(door, /obj/machinery/door/airlock/lift))
|
||||
return FALSE
|
||||
return door.arePowerSystemsOn()
|
||||
|
||||
// Override this for door busting.
|
||||
/datum/event2/event/airlock_failure/proc/break_door(obj/machinery/door/airlock/door)
|
||||
|
||||
/datum/event2/event/airlock_failure/emag/break_door(obj/machinery/door/airlock/door)
|
||||
door.emag_act(1)
|
||||
|
||||
/datum/event2/event/airlock_failure/door_crush/break_door(obj/machinery/door/airlock/door)
|
||||
door.normalspeed = FALSE
|
||||
door.safe = FALSE
|
||||
|
||||
/datum/event2/event/airlock_failure/shock/break_door(obj/machinery/door/airlock/door)
|
||||
door.electrify(-1)
|
||||
|
||||
@@ -1,160 +1,160 @@
|
||||
/datum/event2/meta/blob
|
||||
name = "blob"
|
||||
departments = list(DEPARTMENT_ENGINEERING, DEPARTMENT_SECURITY, DEPARTMENT_MEDICAL)
|
||||
chaos = 30
|
||||
chaotic_threshold = EVENT_CHAOS_THRESHOLD_HIGH_IMPACT
|
||||
event_class = "blob" // This makes it so there is no potential for multiple blob events of different types happening in the same round.
|
||||
event_type = /datum/event2/event/blob
|
||||
// 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.
|
||||
|
||||
/datum/event2/meta/blob/hard
|
||||
name = "harder blob"
|
||||
chaos = 40
|
||||
event_type = /datum/event2/event/blob/hard_blob
|
||||
required_fighters = 3
|
||||
|
||||
/datum/event2/meta/blob/multi_blob
|
||||
name = "multi blob"
|
||||
chaos = 60
|
||||
event_type = /datum/event2/event/blob/multi_blob
|
||||
required_fighters = 4
|
||||
required_support = 2
|
||||
|
||||
// For bussing only.
|
||||
/datum/event2/meta/blob/omni_blob
|
||||
name = "omni blob"
|
||||
chaos = 200
|
||||
event_type = /datum/event2/event/blob/omni_blob
|
||||
enabled = FALSE
|
||||
|
||||
/datum/event2/meta/blob/get_weight()
|
||||
// Count the 'fighters'.
|
||||
var/list/engineers = metric.get_people_in_department(DEPARTMENT_ENGINEERING)
|
||||
var/list/security = metric.get_people_in_department(DEPARTMENT_SECURITY)
|
||||
|
||||
if(engineers.len + security.len < required_fighters)
|
||||
return 0
|
||||
|
||||
// Now count the 'support'.
|
||||
var/list/medical = metric.get_people_in_department(DEPARTMENT_MEDICAL)
|
||||
var/need_medical = FALSE
|
||||
|
||||
var/list/robotics = metric.get_people_with_job(/datum/job/roboticist)
|
||||
var/need_robotics = FALSE
|
||||
|
||||
// Determine what kind of support might be needed.
|
||||
for(var/mob/living/L in engineers|security)
|
||||
if(L.isSynthetic())
|
||||
need_robotics = TRUE
|
||||
else
|
||||
need_medical = TRUE
|
||||
|
||||
// Medical is more important than robotics, since robits tend to not suffer slow deaths if there isn't a roboticist.
|
||||
if(medical.len < required_support && need_medical)
|
||||
return 0
|
||||
|
||||
// Engineers can sometimes fill in as robotics. This is done in the interest of the event having a chance of not being super rare.
|
||||
// In the uncertain future, a mechanical skill system check could replace this check here.
|
||||
if(robotics.len + engineers.len < required_support && need_robotics)
|
||||
return 0
|
||||
|
||||
var/fighter_weight = (engineers.len + security.len) * 20
|
||||
var/support_weight = (medical.len + robotics.len) * 10 // Not counting engineers as support so they don't cause 30 weight each.
|
||||
var/chaos_weight = chaos / 2 // Chaos is added as a weight in order to make more chaotic variants be preferred if they are allowed to be picked.
|
||||
|
||||
return fighter_weight + support_weight + chaos_weight
|
||||
|
||||
|
||||
|
||||
/datum/event2/event/blob
|
||||
announce_delay_lower_bound = 1 MINUTE
|
||||
announce_delay_upper_bound = 5 MINUTES
|
||||
// This could be made into a GLOB accessible list for reuse if needed.
|
||||
var/list/area/excluded = list(
|
||||
/area/submap,
|
||||
/area/shuttle,
|
||||
/area/crew_quarters,
|
||||
/area/holodeck,
|
||||
/area/engineering/engine_room
|
||||
)
|
||||
var/list/open_turfs = list()
|
||||
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.
|
||||
|
||||
/datum/event2/event/blob/hard_blob
|
||||
spawn_blob_type = /obj/structure/blob/core/random_hard
|
||||
|
||||
/datum/event2/event/blob/multi_blob
|
||||
spawn_blob_type = /obj/structure/blob/core/random_hard // Lethargic blobs are boring.
|
||||
number_of_blobs = 2
|
||||
|
||||
// For adminbus only.
|
||||
/datum/event2/event/blob/omni_blob
|
||||
number_of_blobs = 16 // Someday maybe we can get this to specifically spawn every blob.
|
||||
|
||||
/datum/event2/event/blob/set_up()
|
||||
open_turfs = find_random_turfs(5 + number_of_blobs)
|
||||
|
||||
if(!open_turfs.len)
|
||||
log_debug("Blob infestation event: Giving up after failure to find blob spots.")
|
||||
abort()
|
||||
|
||||
/datum/event2/event/blob/start()
|
||||
for(var/i = 1 to number_of_blobs)
|
||||
var/turf/T = pick(open_turfs)
|
||||
var/obj/structure/blob/core/new_blob = new spawn_blob_type(T)
|
||||
blobs += WEAKREF(new_blob)
|
||||
open_turfs -= T // So we can't put two cores on the same tile if doing multiblob.
|
||||
log_debug("Spawned [new_blob.overmind.blob_type.name] blob at [get_area(new_blob)].")
|
||||
|
||||
/datum/event2/event/blob/should_end()
|
||||
for(var/datum/weakref/weakref as anything in blobs)
|
||||
if(weakref.resolve()) // If the weakref is resolvable, that means the blob hasn't been deleted yet.
|
||||
return FALSE
|
||||
return TRUE // Only end if all blobs die.
|
||||
|
||||
// Normally this does nothing, but is useful if aborted by an admin.
|
||||
/datum/event2/event/blob/end()
|
||||
for(var/datum/weakref/weakref as anything in blobs)
|
||||
var/obj/structure/blob/core/B = weakref.resolve()
|
||||
if(istype(B))
|
||||
qdel(B)
|
||||
|
||||
/datum/event2/event/blob/announce()
|
||||
if(!ended) // Don't announce if the blobs die early.
|
||||
var/danger_level = 0
|
||||
var/list/blob_type_names = list()
|
||||
var/multiblob = FALSE
|
||||
for(var/datum/weakref/weakref as anything in blobs)
|
||||
var/obj/structure/blob/core/B = weakref.resolve()
|
||||
if(!istype(B))
|
||||
continue
|
||||
var/datum/blob_type/blob_type = B.overmind.blob_type
|
||||
|
||||
blob_type_names += blob_type.name
|
||||
if(danger_level > blob_type.difficulty) // The highest difficulty is used, if multiple blobs are present.
|
||||
danger_level = blob_type.difficulty
|
||||
|
||||
if(blob_type_names.len > 1) // More than one blob is harder.
|
||||
danger_level += blob_type_names.len
|
||||
multiblob = TRUE
|
||||
|
||||
var/list/lines = list()
|
||||
lines += "Confirmed outbreak of level [7 + danger_level] biohazard[multiblob ? "s": ""] \
|
||||
aboard [location_name()]. All personnel must contain the outbreak."
|
||||
|
||||
if(danger_level >= BLOB_DIFFICULTY_MEDIUM) // Tell them what kind of blob it is if it's tough.
|
||||
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.
|
||||
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/event2/meta/blob
|
||||
name = "blob"
|
||||
departments = list(DEPARTMENT_ENGINEERING, DEPARTMENT_SECURITY, DEPARTMENT_MEDICAL)
|
||||
chaos = 30
|
||||
chaotic_threshold = EVENT_CHAOS_THRESHOLD_HIGH_IMPACT
|
||||
event_class = "blob" // This makes it so there is no potential for multiple blob events of different types happening in the same round.
|
||||
event_type = /datum/event2/event/blob
|
||||
// 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.
|
||||
|
||||
/datum/event2/meta/blob/hard
|
||||
name = "harder blob"
|
||||
chaos = 40
|
||||
event_type = /datum/event2/event/blob/hard_blob
|
||||
required_fighters = 3
|
||||
|
||||
/datum/event2/meta/blob/multi_blob
|
||||
name = "multi blob"
|
||||
chaos = 60
|
||||
event_type = /datum/event2/event/blob/multi_blob
|
||||
required_fighters = 4
|
||||
required_support = 2
|
||||
|
||||
// For bussing only.
|
||||
/datum/event2/meta/blob/omni_blob
|
||||
name = "omni blob"
|
||||
chaos = 200
|
||||
event_type = /datum/event2/event/blob/omni_blob
|
||||
enabled = FALSE
|
||||
|
||||
/datum/event2/meta/blob/get_weight()
|
||||
// Count the 'fighters'.
|
||||
var/list/engineers = metric.get_people_in_department(DEPARTMENT_ENGINEERING)
|
||||
var/list/security = metric.get_people_in_department(DEPARTMENT_SECURITY)
|
||||
|
||||
if(engineers.len + security.len < required_fighters)
|
||||
return 0
|
||||
|
||||
// Now count the 'support'.
|
||||
var/list/medical = metric.get_people_in_department(DEPARTMENT_MEDICAL)
|
||||
var/need_medical = FALSE
|
||||
|
||||
var/list/robotics = metric.get_people_with_job(/datum/job/roboticist)
|
||||
var/need_robotics = FALSE
|
||||
|
||||
// Determine what kind of support might be needed.
|
||||
for(var/mob/living/L in engineers|security)
|
||||
if(L.isSynthetic())
|
||||
need_robotics = TRUE
|
||||
else
|
||||
need_medical = TRUE
|
||||
|
||||
// Medical is more important than robotics, since robits tend to not suffer slow deaths if there isn't a roboticist.
|
||||
if(medical.len < required_support && need_medical)
|
||||
return 0
|
||||
|
||||
// Engineers can sometimes fill in as robotics. This is done in the interest of the event having a chance of not being super rare.
|
||||
// In the uncertain future, a mechanical skill system check could replace this check here.
|
||||
if(robotics.len + engineers.len < required_support && need_robotics)
|
||||
return 0
|
||||
|
||||
var/fighter_weight = (engineers.len + security.len) * 20
|
||||
var/support_weight = (medical.len + robotics.len) * 10 // Not counting engineers as support so they don't cause 30 weight each.
|
||||
var/chaos_weight = chaos / 2 // Chaos is added as a weight in order to make more chaotic variants be preferred if they are allowed to be picked.
|
||||
|
||||
return fighter_weight + support_weight + chaos_weight
|
||||
|
||||
|
||||
|
||||
/datum/event2/event/blob
|
||||
announce_delay_lower_bound = 1 MINUTE
|
||||
announce_delay_upper_bound = 5 MINUTES
|
||||
// This could be made into a GLOB accessible list for reuse if needed.
|
||||
var/list/area/excluded = list(
|
||||
/area/submap,
|
||||
/area/shuttle,
|
||||
/area/crew_quarters,
|
||||
/area/holodeck,
|
||||
/area/engineering/engine_room
|
||||
)
|
||||
var/list/open_turfs = list()
|
||||
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.
|
||||
|
||||
/datum/event2/event/blob/hard_blob
|
||||
spawn_blob_type = /obj/structure/blob/core/random_hard
|
||||
|
||||
/datum/event2/event/blob/multi_blob
|
||||
spawn_blob_type = /obj/structure/blob/core/random_hard // Lethargic blobs are boring.
|
||||
number_of_blobs = 2
|
||||
|
||||
// For adminbus only.
|
||||
/datum/event2/event/blob/omni_blob
|
||||
number_of_blobs = 16 // Someday maybe we can get this to specifically spawn every blob.
|
||||
|
||||
/datum/event2/event/blob/set_up()
|
||||
open_turfs = find_random_turfs(5 + number_of_blobs)
|
||||
|
||||
if(!open_turfs.len)
|
||||
log_debug("Blob infestation event: Giving up after failure to find blob spots.")
|
||||
abort()
|
||||
|
||||
/datum/event2/event/blob/start()
|
||||
for(var/i = 1 to number_of_blobs)
|
||||
var/turf/T = pick(open_turfs)
|
||||
var/obj/structure/blob/core/new_blob = new spawn_blob_type(T)
|
||||
blobs += WEAKREF(new_blob)
|
||||
open_turfs -= T // So we can't put two cores on the same tile if doing multiblob.
|
||||
log_debug("Spawned [new_blob.overmind.blob_type.name] blob at [get_area(new_blob)].")
|
||||
|
||||
/datum/event2/event/blob/should_end()
|
||||
for(var/datum/weakref/weakref as anything in blobs)
|
||||
if(weakref.resolve()) // If the weakref is resolvable, that means the blob hasn't been deleted yet.
|
||||
return FALSE
|
||||
return TRUE // Only end if all blobs die.
|
||||
|
||||
// Normally this does nothing, but is useful if aborted by an admin.
|
||||
/datum/event2/event/blob/end()
|
||||
for(var/datum/weakref/weakref as anything in blobs)
|
||||
var/obj/structure/blob/core/B = weakref.resolve()
|
||||
if(istype(B))
|
||||
qdel(B)
|
||||
|
||||
/datum/event2/event/blob/announce()
|
||||
if(!ended) // Don't announce if the blobs die early.
|
||||
var/danger_level = 0
|
||||
var/list/blob_type_names = list()
|
||||
var/multiblob = FALSE
|
||||
for(var/datum/weakref/weakref as anything in blobs)
|
||||
var/obj/structure/blob/core/B = weakref.resolve()
|
||||
if(!istype(B))
|
||||
continue
|
||||
var/datum/blob_type/blob_type = B.overmind.blob_type
|
||||
|
||||
blob_type_names += blob_type.name
|
||||
if(danger_level > blob_type.difficulty) // The highest difficulty is used, if multiple blobs are present.
|
||||
danger_level = blob_type.difficulty
|
||||
|
||||
if(blob_type_names.len > 1) // More than one blob is harder.
|
||||
danger_level += blob_type_names.len
|
||||
multiblob = TRUE
|
||||
|
||||
var/list/lines = list()
|
||||
lines += "Confirmed outbreak of level [7 + danger_level] biohazard[multiblob ? "s": ""] \
|
||||
aboard [location_name()]. All personnel must contain the outbreak."
|
||||
|
||||
if(danger_level >= BLOB_DIFFICULTY_MEDIUM) // Tell them what kind of blob it is if it's tough.
|
||||
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.
|
||||
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')
|
||||
|
||||
@@ -1,90 +1,90 @@
|
||||
/datum/event2/meta/brand_intelligence
|
||||
name = "vending machine malware"
|
||||
departments = list(DEPARTMENT_ENGINEERING, DEPARTMENT_EVERYONE)
|
||||
chaos = 10
|
||||
chaotic_threshold = EVENT_CHAOS_THRESHOLD_LOW_IMPACT
|
||||
event_type = /datum/event2/event/brand_intelligence
|
||||
|
||||
/datum/event2/meta/brand_intelligence/get_weight()
|
||||
return 10 + (metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 20)
|
||||
|
||||
|
||||
|
||||
/datum/event2/event/brand_intelligence
|
||||
var/malware_spread_cooldown = 30 SECONDS
|
||||
|
||||
var/list/vending_machines = list() // List of venders that can potentially be infected.
|
||||
var/list/infected_vending_machines = list() // List of venders that have been infected.
|
||||
var/obj/machinery/vending/vender_zero = null // The first vending machine infected. If that one gets fixed, all other infected machines will be cured.
|
||||
var/last_malware_spread_time = null
|
||||
|
||||
/datum/event2/event/brand_intelligence/set_up()
|
||||
for(var/obj/machinery/vending/V in machines)
|
||||
if(!(V.z in using_map.station_levels))
|
||||
continue
|
||||
vending_machines += V
|
||||
|
||||
if(!vending_machines.len)
|
||||
log_debug("Could not find any vending machines on station Z levels. Aborting.")
|
||||
abort()
|
||||
return
|
||||
|
||||
vender_zero = pick(vending_machines)
|
||||
|
||||
/datum/event2/event/brand_intelligence/announce()
|
||||
if(prob(90))
|
||||
command_announcement.Announce("An ongoing mass upload of malware for vendors has been detected onboard \the [location_name()], \
|
||||
which appears to transmit to nearby vendors. The original infected machine is believed to be \a [vender_zero].", "Vendor Service Alert")
|
||||
|
||||
/datum/event2/event/brand_intelligence/start()
|
||||
infect_vender(vender_zero)
|
||||
|
||||
/datum/event2/event/brand_intelligence/event_tick()
|
||||
if(last_malware_spread_time + malware_spread_cooldown > world.time)
|
||||
return // Still on cooldown.
|
||||
last_malware_spread_time = world.time
|
||||
|
||||
if(vending_machines.len)
|
||||
var/next_victim = pick(vending_machines)
|
||||
infect_vender(next_victim)
|
||||
|
||||
// Every time Vender Zero infects, it says something.
|
||||
vender_zero.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/event2/event/brand_intelligence/should_end()
|
||||
if(!vending_machines.len)
|
||||
return TRUE
|
||||
if(!can_propagate(vender_zero))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/event2/event/brand_intelligence/end()
|
||||
if(can_propagate(vender_zero)) // The crew failed and all the machines are infected!
|
||||
return
|
||||
// Otherwise Vender Zero was taken out in some form.
|
||||
if(vender_zero)
|
||||
vender_zero.visible_message(span("notice", "\The [vender_zero]'s network activity light flickers wildly \
|
||||
for a few seconds as a small screen reads: 'Rolling out firmware reset to networked machines'."))
|
||||
for(var/obj/machinery/vending/vender in infected_vending_machines)
|
||||
cure_vender(vender)
|
||||
|
||||
/datum/event2/event/brand_intelligence/proc/infect_vender(obj/machinery/vending/V)
|
||||
vending_machines -= V
|
||||
infected_vending_machines += V
|
||||
V.shut_up = FALSE
|
||||
V.shoot_inventory = TRUE
|
||||
|
||||
/datum/event2/event/brand_intelligence/proc/cure_vender(obj/machinery/vending/V)
|
||||
infected_vending_machines -= V
|
||||
V.shut_up = TRUE
|
||||
V.shoot_inventory = FALSE
|
||||
|
||||
/datum/event2/event/brand_intelligence/proc/can_propagate(obj/machinery/vending/V)
|
||||
return V && V.shut_up == FALSE
|
||||
/datum/event2/meta/brand_intelligence
|
||||
name = "vending machine malware"
|
||||
departments = list(DEPARTMENT_ENGINEERING, DEPARTMENT_EVERYONE)
|
||||
chaos = 10
|
||||
chaotic_threshold = EVENT_CHAOS_THRESHOLD_LOW_IMPACT
|
||||
event_type = /datum/event2/event/brand_intelligence
|
||||
|
||||
/datum/event2/meta/brand_intelligence/get_weight()
|
||||
return 10 + (metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 20)
|
||||
|
||||
|
||||
|
||||
/datum/event2/event/brand_intelligence
|
||||
var/malware_spread_cooldown = 30 SECONDS
|
||||
|
||||
var/list/vending_machines = list() // List of venders that can potentially be infected.
|
||||
var/list/infected_vending_machines = list() // List of venders that have been infected.
|
||||
var/obj/machinery/vending/vender_zero = null // The first vending machine infected. If that one gets fixed, all other infected machines will be cured.
|
||||
var/last_malware_spread_time = null
|
||||
|
||||
/datum/event2/event/brand_intelligence/set_up()
|
||||
for(var/obj/machinery/vending/V in machines)
|
||||
if(!(V.z in using_map.station_levels))
|
||||
continue
|
||||
vending_machines += V
|
||||
|
||||
if(!vending_machines.len)
|
||||
log_debug("Could not find any vending machines on station Z levels. Aborting.")
|
||||
abort()
|
||||
return
|
||||
|
||||
vender_zero = pick(vending_machines)
|
||||
|
||||
/datum/event2/event/brand_intelligence/announce()
|
||||
if(prob(90))
|
||||
command_announcement.Announce("An ongoing mass upload of malware for vendors has been detected onboard \the [location_name()], \
|
||||
which appears to transmit to nearby vendors. The original infected machine is believed to be \a [vender_zero].", "Vendor Service Alert")
|
||||
|
||||
/datum/event2/event/brand_intelligence/start()
|
||||
infect_vender(vender_zero)
|
||||
|
||||
/datum/event2/event/brand_intelligence/event_tick()
|
||||
if(last_malware_spread_time + malware_spread_cooldown > world.time)
|
||||
return // Still on cooldown.
|
||||
last_malware_spread_time = world.time
|
||||
|
||||
if(vending_machines.len)
|
||||
var/next_victim = pick(vending_machines)
|
||||
infect_vender(next_victim)
|
||||
|
||||
// Every time Vender Zero infects, it says something.
|
||||
vender_zero.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/event2/event/brand_intelligence/should_end()
|
||||
if(!vending_machines.len)
|
||||
return TRUE
|
||||
if(!can_propagate(vender_zero))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/event2/event/brand_intelligence/end()
|
||||
if(can_propagate(vender_zero)) // The crew failed and all the machines are infected!
|
||||
return
|
||||
// Otherwise Vender Zero was taken out in some form.
|
||||
if(vender_zero)
|
||||
vender_zero.visible_message(span("notice", "\The [vender_zero]'s network activity light flickers wildly \
|
||||
for a few seconds as a small screen reads: 'Rolling out firmware reset to networked machines'."))
|
||||
for(var/obj/machinery/vending/vender in infected_vending_machines)
|
||||
cure_vender(vender)
|
||||
|
||||
/datum/event2/event/brand_intelligence/proc/infect_vender(obj/machinery/vending/V)
|
||||
vending_machines -= V
|
||||
infected_vending_machines += V
|
||||
V.shut_up = FALSE
|
||||
V.shoot_inventory = TRUE
|
||||
|
||||
/datum/event2/event/brand_intelligence/proc/cure_vender(obj/machinery/vending/V)
|
||||
infected_vending_machines -= V
|
||||
V.shut_up = TRUE
|
||||
V.shoot_inventory = FALSE
|
||||
|
||||
/datum/event2/event/brand_intelligence/proc/can_propagate(obj/machinery/vending/V)
|
||||
return V && V.shut_up == FALSE
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
/datum/event2/meta/camera_damage
|
||||
name = "random camera damage"
|
||||
departments = list(DEPARTMENT_SYNTHETIC, DEPARTMENT_ENGINEERING)
|
||||
chaos = 5
|
||||
chaotic_threshold = EVENT_CHAOS_THRESHOLD_LOW_IMPACT
|
||||
reusable = TRUE
|
||||
event_type = /datum/event2/event/camera_damage
|
||||
|
||||
/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)
|
||||
|
||||
/datum/event2/event/camera_damage
|
||||
var/camera_range = 7
|
||||
|
||||
/datum/event2/event/camera_damage/start()
|
||||
var/obj/machinery/camera/C = acquire_random_camera()
|
||||
if(!C)
|
||||
return
|
||||
|
||||
for(var/obj/machinery/camera/cam in range(camera_range, C))
|
||||
if(is_valid_camera(cam))
|
||||
cam.wires.cut(WIRE_MAIN_POWER1)
|
||||
if(prob(25))
|
||||
cam.wires.cut(WIRE_CAM_ALARM)
|
||||
|
||||
/datum/event2/event/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
|
||||
// It is very important to use --var and not var-- for recursive calls, as var-- will cause an infinite loop.
|
||||
return acquire_random_camera(--remaining_attempts)
|
||||
|
||||
/datum/event2/event/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)
|
||||
/datum/event2/meta/camera_damage
|
||||
name = "random camera damage"
|
||||
departments = list(DEPARTMENT_SYNTHETIC, DEPARTMENT_ENGINEERING)
|
||||
chaos = 5
|
||||
chaotic_threshold = EVENT_CHAOS_THRESHOLD_LOW_IMPACT
|
||||
reusable = TRUE
|
||||
event_type = /datum/event2/event/camera_damage
|
||||
|
||||
/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)
|
||||
|
||||
/datum/event2/event/camera_damage
|
||||
var/camera_range = 7
|
||||
|
||||
/datum/event2/event/camera_damage/start()
|
||||
var/obj/machinery/camera/C = acquire_random_camera()
|
||||
if(!C)
|
||||
return
|
||||
|
||||
for(var/obj/machinery/camera/cam in range(camera_range, C))
|
||||
if(is_valid_camera(cam))
|
||||
cam.wires.cut(WIRE_MAIN_POWER1)
|
||||
if(prob(25))
|
||||
cam.wires.cut(WIRE_CAM_ALARM)
|
||||
|
||||
/datum/event2/event/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
|
||||
// It is very important to use --var and not var-- for recursive calls, as var-- will cause an infinite loop.
|
||||
return acquire_random_camera(--remaining_attempts)
|
||||
|
||||
/datum/event2/event/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)
|
||||
@@ -1,26 +1,26 @@
|
||||
//
|
||||
// This event chooses a random canister on player levels and breaks it, releasing its contents!
|
||||
//
|
||||
|
||||
/datum/event2/meta/canister_leak
|
||||
name = "canister leak"
|
||||
departments = list(DEPARTMENT_ENGINEERING)
|
||||
chaos = 10
|
||||
chaotic_threshold = EVENT_CHAOS_THRESHOLD_LOW_IMPACT
|
||||
reusable = TRUE
|
||||
event_type = /datum/event2/event/canister_leak
|
||||
|
||||
/datum/event2/meta/canister_leak/get_weight()
|
||||
return metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 30
|
||||
|
||||
/datum/event2/event/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()
|
||||
|
||||
//
|
||||
// This event chooses a random canister on player levels and breaks it, releasing its contents!
|
||||
//
|
||||
|
||||
/datum/event2/meta/canister_leak
|
||||
name = "canister leak"
|
||||
departments = list(DEPARTMENT_ENGINEERING)
|
||||
chaos = 10
|
||||
chaotic_threshold = EVENT_CHAOS_THRESHOLD_LOW_IMPACT
|
||||
reusable = TRUE
|
||||
event_type = /datum/event2/event/canister_leak
|
||||
|
||||
/datum/event2/meta/canister_leak/get_weight()
|
||||
return metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 30
|
||||
|
||||
/datum/event2/event/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()
|
||||
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
/datum/event2/meta/dust
|
||||
name = "dust"
|
||||
departments = list(DEPARTMENT_ENGINEERING)
|
||||
chaos = 10
|
||||
chaotic_threshold = EVENT_CHAOS_THRESHOLD_LOW_IMPACT
|
||||
reusable = TRUE
|
||||
event_type = /datum/event2/event/dust
|
||||
|
||||
/datum/event2/meta/dust/get_weight()
|
||||
return metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 20
|
||||
|
||||
|
||||
|
||||
/datum/event2/event/dust/announce()
|
||||
if(prob(33))
|
||||
command_announcement.Announce("Dust has been detected on a collision course with \the [location_name()].")
|
||||
|
||||
/datum/event2/event/dust/start()
|
||||
dust_swarm("norm")
|
||||
/datum/event2/meta/dust
|
||||
name = "dust"
|
||||
departments = list(DEPARTMENT_ENGINEERING)
|
||||
chaos = 10
|
||||
chaotic_threshold = EVENT_CHAOS_THRESHOLD_LOW_IMPACT
|
||||
reusable = TRUE
|
||||
event_type = /datum/event2/event/dust
|
||||
|
||||
/datum/event2/meta/dust/get_weight()
|
||||
return metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 20
|
||||
|
||||
|
||||
|
||||
/datum/event2/event/dust/announce()
|
||||
if(prob(33))
|
||||
command_announcement.Announce("Dust has been detected on a collision course with \the [location_name()].")
|
||||
|
||||
/datum/event2/event/dust/start()
|
||||
dust_swarm("norm")
|
||||
|
||||
@@ -1,47 +1,47 @@
|
||||
/datum/event2/meta/gas_leak
|
||||
name = "gas leak"
|
||||
departments = list(DEPARTMENT_ENGINEERING, DEPARTMENT_SYNTHETIC)
|
||||
chaos = 10
|
||||
chaotic_threshold = EVENT_CHAOS_THRESHOLD_LOW_IMPACT
|
||||
reusable = TRUE
|
||||
event_type = /datum/event2/event/gas_leak
|
||||
|
||||
/datum/event2/meta/gas_leak/get_weight()
|
||||
// Synthetics are counted in higher value because they can wirelessly connect to alarms.
|
||||
var/engineering_factor = metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 10
|
||||
var/synthetic_factor = metric.count_people_in_department(DEPARTMENT_SYNTHETIC) * 30
|
||||
return (15 + engineering_factor + synthetic_factor) / (times_ran + 1)
|
||||
|
||||
|
||||
|
||||
/datum/event2/event/gas_leak
|
||||
var/potential_gas_choices = list("carbon_dioxide", "nitrous_oxide", "phoron", "volatile_fuel")
|
||||
var/chosen_gas = null
|
||||
var/turf/chosen_turf = null
|
||||
|
||||
/datum/event2/event/gas_leak/set_up()
|
||||
chosen_gas = pick(potential_gas_choices)
|
||||
|
||||
var/list/turfs = find_random_turfs()
|
||||
if(!turfs.len)
|
||||
log_debug("Gas Leak event failed to find any available turfs to leak into. Aborting.")
|
||||
abort()
|
||||
return
|
||||
chosen_turf = pick(turfs)
|
||||
|
||||
/datum/event2/event/gas_leak/announce()
|
||||
if(chosen_turf)
|
||||
command_announcement.Announce("Warning, hazardous [lowertext(gas_data.name[chosen_gas])] gas leak detected in \the [chosen_turf.loc], evacuate the area.", "Hazard Alert")
|
||||
|
||||
/datum/event2/event/gas_leak/start()
|
||||
// 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 + rand(-50, 50)
|
||||
air_contents.gas[chosen_gas] = 10 * MOLES_CELLSTANDARD
|
||||
chosen_turf.assume_air(air_contents)
|
||||
/datum/event2/meta/gas_leak
|
||||
name = "gas leak"
|
||||
departments = list(DEPARTMENT_ENGINEERING, DEPARTMENT_SYNTHETIC)
|
||||
chaos = 10
|
||||
chaotic_threshold = EVENT_CHAOS_THRESHOLD_LOW_IMPACT
|
||||
reusable = TRUE
|
||||
event_type = /datum/event2/event/gas_leak
|
||||
|
||||
/datum/event2/meta/gas_leak/get_weight()
|
||||
// Synthetics are counted in higher value because they can wirelessly connect to alarms.
|
||||
var/engineering_factor = metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 10
|
||||
var/synthetic_factor = metric.count_people_in_department(DEPARTMENT_SYNTHETIC) * 30
|
||||
return (15 + engineering_factor + synthetic_factor) / (times_ran + 1)
|
||||
|
||||
|
||||
|
||||
/datum/event2/event/gas_leak
|
||||
var/potential_gas_choices = list("carbon_dioxide", "nitrous_oxide", "phoron", "volatile_fuel")
|
||||
var/chosen_gas = null
|
||||
var/turf/chosen_turf = null
|
||||
|
||||
/datum/event2/event/gas_leak/set_up()
|
||||
chosen_gas = pick(potential_gas_choices)
|
||||
|
||||
var/list/turfs = find_random_turfs()
|
||||
if(!turfs.len)
|
||||
log_debug("Gas Leak event failed to find any available turfs to leak into. Aborting.")
|
||||
abort()
|
||||
return
|
||||
chosen_turf = pick(turfs)
|
||||
|
||||
/datum/event2/event/gas_leak/announce()
|
||||
if(chosen_turf)
|
||||
command_announcement.Announce("Warning, hazardous [lowertext(gas_data.name[chosen_gas])] gas leak detected in \the [chosen_turf.loc], evacuate the area.", "Hazard Alert")
|
||||
|
||||
/datum/event2/event/gas_leak/start()
|
||||
// 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 + rand(-50, 50)
|
||||
air_contents.gas[chosen_gas] = 10 * MOLES_CELLSTANDARD
|
||||
chosen_turf.assume_air(air_contents)
|
||||
playsound(chosen_turf, 'sound/effects/smoke.ogg', 75, 1)
|
||||
@@ -1,50 +1,50 @@
|
||||
// New grid check event:
|
||||
// Very similar to the old one, power goes out in most of the station, 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/event2/meta/grid_check
|
||||
name = "grid check"
|
||||
departments = list(DEPARTMENT_ENGINEERING, DEPARTMENT_EVERYONE)
|
||||
chaos = 10
|
||||
chaotic_threshold = EVENT_CHAOS_THRESHOLD_LOW_IMPACT
|
||||
reusable = TRUE
|
||||
event_type = /datum/event2/event/grid_check
|
||||
|
||||
// Having the turbines be way over their rated limit makes grid checks more likely.
|
||||
/datum/event2/meta/grid_check/proc/get_overpower()
|
||||
var/highest_overpower = 0
|
||||
for(var/obj/machinery/power/generator/turbine as anything in GLOB.all_turbines)
|
||||
var/overpower = max((turbine.effective_gen / turbine.max_power) - 1, 0)
|
||||
if(overpower > highest_overpower)
|
||||
highest_overpower = overpower
|
||||
return highest_overpower
|
||||
|
||||
/datum/event2/meta/grid_check/get_weight()
|
||||
var/population_factor = metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 10
|
||||
var/overpower_factor = 50 * get_overpower() // Will be 0 if not overloaded at all, and 50 if turbines are outputting twice as much as rated.
|
||||
return (20 + population_factor + overpower_factor) / (times_ran + 1)
|
||||
|
||||
|
||||
|
||||
/datum/event2/event/grid_check
|
||||
var/obj/machinery/power/generator/engine // The turbine that will send a power spike.
|
||||
|
||||
/datum/event2/event/grid_check/set_up()
|
||||
// Find the turbine being pushed the most.
|
||||
var/obj/machinery/power/generator/most_stressed_turbine = null
|
||||
for(var/obj/machinery/power/generator/turbine as anything in GLOB.all_turbines)
|
||||
if(!most_stressed_turbine)
|
||||
most_stressed_turbine = turbine
|
||||
else if(turbine.effective_gen > most_stressed_turbine.effective_gen)
|
||||
most_stressed_turbine = turbine
|
||||
engine = most_stressed_turbine
|
||||
|
||||
/datum/event2/event/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.
|
||||
if(engine)
|
||||
engine.power_spike()
|
||||
// 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.
|
||||
// New grid check event:
|
||||
// Very similar to the old one, power goes out in most of the station, 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/event2/meta/grid_check
|
||||
name = "grid check"
|
||||
departments = list(DEPARTMENT_ENGINEERING, DEPARTMENT_EVERYONE)
|
||||
chaos = 10
|
||||
chaotic_threshold = EVENT_CHAOS_THRESHOLD_LOW_IMPACT
|
||||
reusable = TRUE
|
||||
event_type = /datum/event2/event/grid_check
|
||||
|
||||
// Having the turbines be way over their rated limit makes grid checks more likely.
|
||||
/datum/event2/meta/grid_check/proc/get_overpower()
|
||||
var/highest_overpower = 0
|
||||
for(var/obj/machinery/power/generator/turbine as anything in GLOB.all_turbines)
|
||||
var/overpower = max((turbine.effective_gen / turbine.max_power) - 1, 0)
|
||||
if(overpower > highest_overpower)
|
||||
highest_overpower = overpower
|
||||
return highest_overpower
|
||||
|
||||
/datum/event2/meta/grid_check/get_weight()
|
||||
var/population_factor = metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 10
|
||||
var/overpower_factor = 50 * get_overpower() // Will be 0 if not overloaded at all, and 50 if turbines are outputting twice as much as rated.
|
||||
return (20 + population_factor + overpower_factor) / (times_ran + 1)
|
||||
|
||||
|
||||
|
||||
/datum/event2/event/grid_check
|
||||
var/obj/machinery/power/generator/engine // The turbine that will send a power spike.
|
||||
|
||||
/datum/event2/event/grid_check/set_up()
|
||||
// Find the turbine being pushed the most.
|
||||
var/obj/machinery/power/generator/most_stressed_turbine = null
|
||||
for(var/obj/machinery/power/generator/turbine as anything in GLOB.all_turbines)
|
||||
if(!most_stressed_turbine)
|
||||
most_stressed_turbine = turbine
|
||||
else if(turbine.effective_gen > most_stressed_turbine.effective_gen)
|
||||
most_stressed_turbine = turbine
|
||||
engine = most_stressed_turbine
|
||||
|
||||
/datum/event2/event/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.
|
||||
if(engine)
|
||||
engine.power_spike()
|
||||
// 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,83 +1,83 @@
|
||||
// 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
|
||||
|
||||
/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")
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/datum/event2/meta/spacevine
|
||||
name = "space-vine infestation"
|
||||
departments = list(DEPARTMENT_ENGINEERING)
|
||||
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
|
||||
|
||||
/datum/event2/meta/spacevine/get_weight()
|
||||
return 20 + (metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 10) + (metric.count_people_in_department(DEPARTMENT_EVERYONE) * 5)
|
||||
|
||||
|
||||
|
||||
/datum/event2/event/spacevine/announce()
|
||||
level_seven_announcement()
|
||||
|
||||
/datum/event2/event/spacevine/start()
|
||||
spacevine_infestation()
|
||||
/datum/event2/meta/spacevine
|
||||
name = "space-vine infestation"
|
||||
departments = list(DEPARTMENT_ENGINEERING)
|
||||
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
|
||||
|
||||
/datum/event2/meta/spacevine/get_weight()
|
||||
return 20 + (metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 10) + (metric.count_people_in_department(DEPARTMENT_EVERYONE) * 5)
|
||||
|
||||
|
||||
|
||||
/datum/event2/event/spacevine/announce()
|
||||
level_seven_announcement()
|
||||
|
||||
/datum/event2/event/spacevine/start()
|
||||
spacevine_infestation()
|
||||
|
||||
@@ -1,46 +1,46 @@
|
||||
/datum/event2/meta/wallrot
|
||||
name = "wall-rot"
|
||||
departments = list(DEPARTMENT_ENGINEERING)
|
||||
reusable = TRUE
|
||||
event_type = /datum/event2/event/wallrot
|
||||
|
||||
/datum/event2/meta/wallrot/get_weight()
|
||||
return (10 + metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 10) / (times_ran + 1)
|
||||
|
||||
|
||||
|
||||
|
||||
/datum/event2/event/wallrot
|
||||
var/turf/simulated/wall/origin = null
|
||||
|
||||
/datum/event2/event/wallrot/set_up()
|
||||
for(var/i = 1 to 100)
|
||||
var/turf/candidate = locate(rand(1, world.maxx), rand(1, world.maxy), pick(get_location_z_levels()) )
|
||||
if(istype(candidate, /turf/simulated/wall))
|
||||
origin = candidate
|
||||
log_debug("Wall-rot event has chosen \the [origin] ([origin.loc]) as the origin for the wallrot infestation.")
|
||||
return
|
||||
|
||||
log_debug("Wall-rot event failed to find a valid wall after one hundred tries. Aborting.")
|
||||
abort()
|
||||
|
||||
/datum/event2/event/wallrot/announce()
|
||||
if(origin && prob(80))
|
||||
command_announcement.Announce("Harmful fungi detected on \the [location_name()], near \the [origin.loc]. \
|
||||
Station structural integrity may be compromised.", "Biohazard Alert")
|
||||
|
||||
/datum/event2/event/wallrot/start()
|
||||
if(origin)
|
||||
origin.rot()
|
||||
|
||||
var/rot_count = 0
|
||||
var/target_rot = rand(5, 20)
|
||||
for(var/turf/simulated/wall/W in range(7, origin))
|
||||
if(prob(50))
|
||||
if(W.rot())
|
||||
rot_count++
|
||||
if(rot_count >= target_rot)
|
||||
break
|
||||
|
||||
|
||||
|
||||
/datum/event2/meta/wallrot
|
||||
name = "wall-rot"
|
||||
departments = list(DEPARTMENT_ENGINEERING)
|
||||
reusable = TRUE
|
||||
event_type = /datum/event2/event/wallrot
|
||||
|
||||
/datum/event2/meta/wallrot/get_weight()
|
||||
return (10 + metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 10) / (times_ran + 1)
|
||||
|
||||
|
||||
|
||||
|
||||
/datum/event2/event/wallrot
|
||||
var/turf/simulated/wall/origin = null
|
||||
|
||||
/datum/event2/event/wallrot/set_up()
|
||||
for(var/i = 1 to 100)
|
||||
var/turf/candidate = locate(rand(1, world.maxx), rand(1, world.maxy), pick(get_location_z_levels()) )
|
||||
if(istype(candidate, /turf/simulated/wall))
|
||||
origin = candidate
|
||||
log_debug("Wall-rot event has chosen \the [origin] ([origin.loc]) as the origin for the wallrot infestation.")
|
||||
return
|
||||
|
||||
log_debug("Wall-rot event failed to find a valid wall after one hundred tries. Aborting.")
|
||||
abort()
|
||||
|
||||
/datum/event2/event/wallrot/announce()
|
||||
if(origin && prob(80))
|
||||
command_announcement.Announce("Harmful fungi detected on \the [location_name()], near \the [origin.loc]. \
|
||||
Station structural integrity may be compromised.", "Biohazard Alert")
|
||||
|
||||
/datum/event2/event/wallrot/start()
|
||||
if(origin)
|
||||
origin.rot()
|
||||
|
||||
var/rot_count = 0
|
||||
var/target_rot = rand(5, 20)
|
||||
for(var/turf/simulated/wall/W in range(7, origin))
|
||||
if(prob(50))
|
||||
if(W.rot())
|
||||
rot_count++
|
||||
if(rot_count >= target_rot)
|
||||
break
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,148 +1,148 @@
|
||||
// This event causes a random window near space to become damaged.
|
||||
// If that window is not fixed in a certain amount of time,
|
||||
// that window and nearby windows will shatter, causing a breach.
|
||||
|
||||
/datum/event2/meta/window_break
|
||||
name = "window break"
|
||||
departments = list(DEPARTMENT_ENGINEERING)
|
||||
chaos = 10
|
||||
reusable = TRUE
|
||||
chaotic_threshold = EVENT_CHAOS_THRESHOLD_MEDIUM_IMPACT
|
||||
event_type = /datum/event2/event/window_break
|
||||
|
||||
/datum/event2/meta/window_break/get_weight()
|
||||
return (metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 20) / (times_ran + 1)
|
||||
|
||||
|
||||
|
||||
/datum/event2/event/window_break
|
||||
announce_delay_lower_bound = 10 SECONDS
|
||||
announce_delay_upper_bound = 20 SECONDS
|
||||
length_lower_bound = 8 MINUTES
|
||||
length_upper_bound = 12 MINUTES
|
||||
var/turf/chosen_turf_with_windows = null
|
||||
var/obj/structure/window/chosen_window = null
|
||||
var/list/collateral_windows = list()
|
||||
|
||||
/datum/event2/event/window_break/set_up()
|
||||
var/list/areas = find_random_areas()
|
||||
if(!LAZYLEN(areas))
|
||||
log_debug("Window Break event could not find any areas. Aborting.")
|
||||
abort()
|
||||
return
|
||||
|
||||
while(areas.len)
|
||||
var/area/area = pick(areas)
|
||||
areas -= area
|
||||
|
||||
for(var/obj/structure/window/W in area.contents)
|
||||
if(!is_window_to_space(W))
|
||||
continue
|
||||
chosen_turf_with_windows = get_turf(W)
|
||||
collateral_windows = gather_collateral_windows(W)
|
||||
break // Break out of the inner loop.
|
||||
|
||||
if(chosen_turf_with_windows)
|
||||
log_debug("Window Break event has chosen turf '[chosen_turf_with_windows.name]' in [chosen_turf_with_windows.loc].")
|
||||
break // Then the outer loop.
|
||||
|
||||
if(!chosen_turf_with_windows)
|
||||
log_debug("Window Break event could not find a turf with valid windows to break. Aborting.")
|
||||
abort()
|
||||
return
|
||||
|
||||
/datum/event2/event/window_break/announce()
|
||||
if(chosen_window)
|
||||
command_announcement.Announce("Structural integrity of space-facing windows at \the [get_area(chosen_turf_with_windows)] are failing. \
|
||||
Repair of the damaged window is advised. Personnel without EVA suits in the area should leave until repairs are complete.", "Structural Alert")
|
||||
|
||||
/datum/event2/event/window_break/start()
|
||||
if(!chosen_turf_with_windows)
|
||||
return
|
||||
|
||||
for(var/obj/structure/window/W in chosen_turf_with_windows.contents)
|
||||
if(W.is_fulltile()) // Full tile windows are simple and can always be used.
|
||||
chosen_window = W
|
||||
break
|
||||
else // Otherwise we only want the window that is on the inside side of the station.
|
||||
var/turf/T = get_step(W, W.dir)
|
||||
if(T.is_space())
|
||||
continue
|
||||
if(T.check_density())
|
||||
continue
|
||||
chosen_window = W
|
||||
break
|
||||
|
||||
if(!chosen_window)
|
||||
return
|
||||
|
||||
chosen_window.take_damage(chosen_window.maxhealth * 0.8)
|
||||
playsound(chosen_window, 'sound/effects/Glasshit.ogg', 100, 1)
|
||||
chosen_window.visible_message(span("danger", "\The [chosen_window] suddenly begins to crack!"))
|
||||
|
||||
/datum/event2/event/window_break/should_end()
|
||||
. = ..()
|
||||
if(!.) // If the timer didn't expire, we can still end it early if someone messes up.
|
||||
if(!chosen_window || !chosen_window.anchored || chosen_window.health == chosen_window.maxhealth)
|
||||
// If the window got deconstructed/moved/etc, immediately end and make the breach happen.
|
||||
// Also end early if it was repaired.
|
||||
return TRUE
|
||||
|
||||
/datum/event2/event/window_break/end()
|
||||
// If someone fixed the window, then everything is fine.
|
||||
if(chosen_window && chosen_window.anchored && chosen_window.health == chosen_window.maxhealth)
|
||||
log_debug("Window Break event ended with window repaired.")
|
||||
return
|
||||
|
||||
// Otherwise a bunch of windows shatter.
|
||||
chosen_window?.shatter()
|
||||
|
||||
var/windows_to_shatter = min(rand(4, 10), collateral_windows.len)
|
||||
for(var/i = 1 to windows_to_shatter)
|
||||
var/obj/structure/window/W = collateral_windows[i]
|
||||
W?.shatter()
|
||||
|
||||
log_debug("Window Break event ended with [windows_to_shatter] shattered windows and a breach.")
|
||||
|
||||
// Checks if a window is adjacent to a space tile, and also that the opposite direction is open.
|
||||
// This is done to avoid getting caught in corner parts of windows.
|
||||
/datum/event2/event/window_break/proc/is_window_to_space(obj/structure/window/W)
|
||||
for(var/direction in GLOB.cardinal)
|
||||
var/turf/T = get_step(W, direction)
|
||||
if(T.is_space())
|
||||
var/turf/opposite_T = get_step(W, GLOB.reverse_dir[direction])
|
||||
if(!opposite_T.check_density())
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
//TL;DR: breadth first search for all connected turfs with windows
|
||||
/datum/event2/event/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
|
||||
// This event causes a random window near space to become damaged.
|
||||
// If that window is not fixed in a certain amount of time,
|
||||
// that window and nearby windows will shatter, causing a breach.
|
||||
|
||||
/datum/event2/meta/window_break
|
||||
name = "window break"
|
||||
departments = list(DEPARTMENT_ENGINEERING)
|
||||
chaos = 10
|
||||
reusable = TRUE
|
||||
chaotic_threshold = EVENT_CHAOS_THRESHOLD_MEDIUM_IMPACT
|
||||
event_type = /datum/event2/event/window_break
|
||||
|
||||
/datum/event2/meta/window_break/get_weight()
|
||||
return (metric.count_people_in_department(DEPARTMENT_ENGINEERING) * 20) / (times_ran + 1)
|
||||
|
||||
|
||||
|
||||
/datum/event2/event/window_break
|
||||
announce_delay_lower_bound = 10 SECONDS
|
||||
announce_delay_upper_bound = 20 SECONDS
|
||||
length_lower_bound = 8 MINUTES
|
||||
length_upper_bound = 12 MINUTES
|
||||
var/turf/chosen_turf_with_windows = null
|
||||
var/obj/structure/window/chosen_window = null
|
||||
var/list/collateral_windows = list()
|
||||
|
||||
/datum/event2/event/window_break/set_up()
|
||||
var/list/areas = find_random_areas()
|
||||
if(!LAZYLEN(areas))
|
||||
log_debug("Window Break event could not find any areas. Aborting.")
|
||||
abort()
|
||||
return
|
||||
|
||||
while(areas.len)
|
||||
var/area/area = pick(areas)
|
||||
areas -= area
|
||||
|
||||
for(var/obj/structure/window/W in area.contents)
|
||||
if(!is_window_to_space(W))
|
||||
continue
|
||||
chosen_turf_with_windows = get_turf(W)
|
||||
collateral_windows = gather_collateral_windows(W)
|
||||
break // Break out of the inner loop.
|
||||
|
||||
if(chosen_turf_with_windows)
|
||||
log_debug("Window Break event has chosen turf '[chosen_turf_with_windows.name]' in [chosen_turf_with_windows.loc].")
|
||||
break // Then the outer loop.
|
||||
|
||||
if(!chosen_turf_with_windows)
|
||||
log_debug("Window Break event could not find a turf with valid windows to break. Aborting.")
|
||||
abort()
|
||||
return
|
||||
|
||||
/datum/event2/event/window_break/announce()
|
||||
if(chosen_window)
|
||||
command_announcement.Announce("Structural integrity of space-facing windows at \the [get_area(chosen_turf_with_windows)] are failing. \
|
||||
Repair of the damaged window is advised. Personnel without EVA suits in the area should leave until repairs are complete.", "Structural Alert")
|
||||
|
||||
/datum/event2/event/window_break/start()
|
||||
if(!chosen_turf_with_windows)
|
||||
return
|
||||
|
||||
for(var/obj/structure/window/W in chosen_turf_with_windows.contents)
|
||||
if(W.is_fulltile()) // Full tile windows are simple and can always be used.
|
||||
chosen_window = W
|
||||
break
|
||||
else // Otherwise we only want the window that is on the inside side of the station.
|
||||
var/turf/T = get_step(W, W.dir)
|
||||
if(T.is_space())
|
||||
continue
|
||||
if(T.check_density())
|
||||
continue
|
||||
chosen_window = W
|
||||
break
|
||||
|
||||
if(!chosen_window)
|
||||
return
|
||||
|
||||
chosen_window.take_damage(chosen_window.maxhealth * 0.8)
|
||||
playsound(chosen_window, 'sound/effects/Glasshit.ogg', 100, 1)
|
||||
chosen_window.visible_message(span("danger", "\The [chosen_window] suddenly begins to crack!"))
|
||||
|
||||
/datum/event2/event/window_break/should_end()
|
||||
. = ..()
|
||||
if(!.) // If the timer didn't expire, we can still end it early if someone messes up.
|
||||
if(!chosen_window || !chosen_window.anchored || chosen_window.health == chosen_window.maxhealth)
|
||||
// If the window got deconstructed/moved/etc, immediately end and make the breach happen.
|
||||
// Also end early if it was repaired.
|
||||
return TRUE
|
||||
|
||||
/datum/event2/event/window_break/end()
|
||||
// If someone fixed the window, then everything is fine.
|
||||
if(chosen_window && chosen_window.anchored && chosen_window.health == chosen_window.maxhealth)
|
||||
log_debug("Window Break event ended with window repaired.")
|
||||
return
|
||||
|
||||
// Otherwise a bunch of windows shatter.
|
||||
chosen_window?.shatter()
|
||||
|
||||
var/windows_to_shatter = min(rand(4, 10), collateral_windows.len)
|
||||
for(var/i = 1 to windows_to_shatter)
|
||||
var/obj/structure/window/W = collateral_windows[i]
|
||||
W?.shatter()
|
||||
|
||||
log_debug("Window Break event ended with [windows_to_shatter] shattered windows and a breach.")
|
||||
|
||||
// Checks if a window is adjacent to a space tile, and also that the opposite direction is open.
|
||||
// This is done to avoid getting caught in corner parts of windows.
|
||||
/datum/event2/event/window_break/proc/is_window_to_space(obj/structure/window/W)
|
||||
for(var/direction in GLOB.cardinal)
|
||||
var/turf/T = get_step(W, direction)
|
||||
if(T.is_space())
|
||||
var/turf/opposite_T = get_step(W, GLOB.reverse_dir[direction])
|
||||
if(!opposite_T.check_density())
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
//TL;DR: breadth first search for all connected turfs with windows
|
||||
/datum/event2/event/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
|
||||
|
||||
Reference in New Issue
Block a user