mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-29 16:10:02 +01:00
SURPRISE! I hope you all had fun during the Psilence event! It was really fun spending 6 months coding all the infrastructure I required to make that encounter possible. Encountering an entire new enemy type was no doubt incredibly exciting to happen during a big canon round. Well as promised, these critters will start showing up more often now that the big reveal has occured. <img width="982" height="981" alt="image" src="https://github.com/user-attachments/assets/c537afe6-9b97-4913-8572-85650556b871" /> <img width="979" height="981" alt="image" src="https://github.com/user-attachments/assets/1049b564-eb54-45e8-a113-da48f5c4b67b" /> This PR adds new rare random events and overmap hazards for Psirens, allowing the basic varieties of them to appear in normal gameplay. They can also be summoned by technomancers. More to come later. :)
433 lines
14 KiB
Plaintext
433 lines
14 KiB
Plaintext
/var/singleton/overmap_event_handler/overmap_event_handler = new()
|
|
|
|
/singleton/overmap_event_handler
|
|
var/list/hazard_by_turf
|
|
var/list/datum/event/ship_events
|
|
|
|
/singleton/overmap_event_handler/New()
|
|
..()
|
|
hazard_by_turf = list()
|
|
ship_events = list()
|
|
|
|
/singleton/overmap_event_handler/proc/create_events(var/z_level, var/overmap_size, var/number_of_events)
|
|
// Acquire the list of not-yet utilized overmap turfs on this Z-level
|
|
var/list/candidate_turfs = block(locate(OVERMAP_EDGE, OVERMAP_EDGE, z_level),locate(overmap_size - OVERMAP_EDGE, overmap_size - OVERMAP_EDGE,z_level))
|
|
candidate_turfs = where(candidate_turfs, /proc/can_not_locate, /obj/effect/overmap/visitable)
|
|
var/list/available_event_types = get_available_event_types()
|
|
if(!length(available_event_types))
|
|
return
|
|
|
|
for(var/i = 1 to number_of_events)
|
|
if(!candidate_turfs.len)
|
|
break
|
|
var/overmap_event_type = pick(available_event_types)
|
|
var/datum/overmap_event/datum_spawn = new overmap_event_type
|
|
|
|
var/list/event_turfs = acquire_event_turfs(datum_spawn.count, datum_spawn.radius, candidate_turfs, datum_spawn.continuous)
|
|
candidate_turfs -= event_turfs
|
|
|
|
for(var/event_turf in event_turfs)
|
|
var/type = pick(datum_spawn.hazards)
|
|
new type(event_turf)
|
|
|
|
qdel(datum_spawn)//idk help how do I do this better?
|
|
|
|
/singleton/overmap_event_handler/proc/get_available_event_types()
|
|
var/list/available_event_types = list()
|
|
for(var/overmap_event_type in subtypesof(/datum/overmap_event))
|
|
var/datum/overmap_event/datum_spawn = new overmap_event_type
|
|
if(datum_spawn.spawns_in_current_sector())
|
|
available_event_types += overmap_event_type
|
|
qdel(datum_spawn)
|
|
return available_event_types
|
|
|
|
/singleton/overmap_event_handler/proc/acquire_event_turfs(var/number_of_turfs, var/distance_from_origin, var/list/candidate_turfs, var/continuous = TRUE)
|
|
number_of_turfs = min(number_of_turfs, candidate_turfs.len)
|
|
candidate_turfs = candidate_turfs.Copy() // Not this proc's responsibility to adjust the given lists
|
|
|
|
var/origin_turf = pick(candidate_turfs)
|
|
var/list/selected_turfs = list(origin_turf)
|
|
var/list/selection_turfs = list(origin_turf)
|
|
candidate_turfs -= origin_turf
|
|
|
|
while(selection_turfs.len && selected_turfs.len < number_of_turfs)
|
|
var/selection_turf = pick(selection_turfs)
|
|
var/random_neighbour = get_random_neighbour(selection_turf, candidate_turfs, continuous, distance_from_origin)
|
|
|
|
if(random_neighbour)
|
|
candidate_turfs -= random_neighbour
|
|
selected_turfs += random_neighbour
|
|
if(get_dist(origin_turf, random_neighbour) < distance_from_origin)
|
|
selection_turfs += random_neighbour
|
|
else
|
|
selection_turfs -= selection_turf
|
|
|
|
return selected_turfs
|
|
|
|
/singleton/overmap_event_handler/proc/get_random_neighbour(var/turf/origin_turf, var/list/candidate_turfs, var/continuous = TRUE, var/range)
|
|
var/fitting_turfs
|
|
if(continuous)
|
|
fitting_turfs = origin_turf.CardinalTurfs(FALSE)
|
|
else
|
|
fitting_turfs = orange(range, origin_turf)
|
|
fitting_turfs = shuffle(fitting_turfs)
|
|
for(var/turf/T in fitting_turfs)
|
|
if(T in candidate_turfs)
|
|
return T
|
|
|
|
/singleton/overmap_event_handler/proc/start_hazard(var/obj/effect/overmap/visitable/ship/ship, var/obj/effect/overmap/event/hazard)//make these accept both hazards or events
|
|
if(!(ship in ship_events))
|
|
ship_events += ship
|
|
|
|
for(var/event_type in hazard.events)
|
|
if(is_event_active(ship,event_type, hazard.difficulty))//event's already active, don't bother
|
|
continue
|
|
var/datum/event_meta/EM = new(hazard.difficulty, "Overmap event - [hazard.name]", event_type, add_to_queue = FALSE, is_one_shot = TRUE)
|
|
var/datum/event/E = new event_type(EM, FALSE, ship, hazard)
|
|
LAZYADD(ship_events[ship], E)
|
|
|
|
/singleton/overmap_event_handler/proc/stop_hazard(var/obj/effect/overmap/visitable/ship/ship, var/obj/effect/overmap/event/hazard)
|
|
for(var/event_type in hazard.events)
|
|
var/datum/event/E = is_event_active(ship,event_type,hazard.difficulty)
|
|
if(E)
|
|
E.kill()
|
|
LAZYREMOVE(ship_events[ship], E)
|
|
|
|
/singleton/overmap_event_handler/proc/is_event_active(var/ship, var/event_type, var/severity)
|
|
if(!ship_events[ship])
|
|
return
|
|
var/list/active_ship_events = ship_events[ship]
|
|
for(var/datum/event/E as anything in active_ship_events)
|
|
if(E.type == event_type && E.severity == severity)
|
|
return E
|
|
|
|
/singleton/overmap_event_handler/proc/on_turf_entered(var/turf/new_loc, var/obj/effect/overmap/visitable/ship/ship, var/old_loc)
|
|
if(!istype(ship))
|
|
return
|
|
if(new_loc == old_loc)
|
|
return
|
|
|
|
for(var/obj/effect/overmap/event/E in hazard_by_turf[new_loc])
|
|
start_hazard(ship, E)
|
|
|
|
/singleton/overmap_event_handler/proc/on_turf_exited(var/turf/old_loc, var/obj/effect/overmap/visitable/ship/ship, var/new_loc)
|
|
if(!istype(ship))
|
|
return
|
|
if(new_loc == old_loc)
|
|
return
|
|
|
|
for(var/obj/effect/overmap/event/E in hazard_by_turf[old_loc])
|
|
if(is_event_included(hazard_by_turf[new_loc],E))
|
|
continue
|
|
stop_hazard(ship,E)
|
|
|
|
/singleton/overmap_event_handler/proc/update_hazards(var/turf/T)//catch all updater
|
|
if(!istype(T))
|
|
return
|
|
|
|
var/list/active_hazards = list()
|
|
for(var/obj/effect/overmap/event/E in T)
|
|
if(is_event_included(active_hazards, E, TRUE))
|
|
continue
|
|
active_hazards += E
|
|
|
|
if(!active_hazards.len)
|
|
hazard_by_turf -= T
|
|
GLOB.entered_event.unregister(T, src, PROC_REF(on_turf_entered))
|
|
GLOB.exited_event.unregister(T, src, PROC_REF(on_turf_exited))
|
|
else
|
|
hazard_by_turf |= T
|
|
hazard_by_turf[T] = active_hazards
|
|
GLOB.entered_event.register(T, src, PROC_REF(on_turf_entered))
|
|
GLOB.exited_event.register(T, src, PROC_REF(on_turf_exited))
|
|
|
|
for(var/obj/effect/overmap/visitable/ship/ship in T)
|
|
var/list/active_ship_events = ship_events[ship]
|
|
for(var/datum/event/E as anything in active_ship_events)
|
|
if(is_event_in_turf(E,T))
|
|
continue
|
|
E.kill()
|
|
LAZYREMOVE(ship_events[ship], E)
|
|
|
|
for(var/obj/effect/overmap/event/E in active_hazards)
|
|
start_hazard(ship,E)
|
|
|
|
/singleton/overmap_event_handler/proc/is_event_in_turf(var/datum/event/E, var/turf/T)
|
|
for(var/obj/effect/overmap/event/hazard in hazard_by_turf[T])
|
|
if((E in hazard.events) && E.severity == hazard.difficulty)
|
|
return TRUE
|
|
|
|
/singleton/overmap_event_handler/proc/is_event_included(var/list/hazards, var/obj/effect/overmap/event/E, var/equal_or_better)//this proc is only used so it can break out of 2 loops cleanly
|
|
for(var/obj/effect/overmap/event/A in hazards)
|
|
if(istype(A,E.type) || istype(E,A.type))
|
|
if(same_entries(A.events, E.events))
|
|
if(equal_or_better)
|
|
if(A.difficulty >= E.difficulty)
|
|
return TRUE
|
|
else
|
|
hazards -= A
|
|
else
|
|
if(A.difficulty == E.difficulty)
|
|
return TRUE
|
|
|
|
// We don't subtype /obj/effect/overmap/visitable because that'll create sections one can travel to
|
|
// And with them "existing" on the overmap Z-level things quickly get odd.
|
|
/obj/effect/overmap/event
|
|
name = "event"
|
|
icon = 'icons/obj/overmap/overmap_effects.dmi'
|
|
icon_state = "blank"
|
|
opacity = 0
|
|
var/list/events
|
|
var/list/event_icon_states = list("event")
|
|
var/difficulty = EVENT_LEVEL_MODERATE
|
|
/// Basically cached events on which Z level
|
|
var/list/victims
|
|
/// Can this event be destroyed by ship guns?
|
|
var/can_be_destroyed = TRUE
|
|
|
|
/// Events must be detected by sensors, but are otherwise instantly visible.
|
|
requires_contact = TRUE
|
|
instant_contact = TRUE
|
|
|
|
// Vars that determine movability, current moving direction, and moving speed
|
|
/// Whether this event can move or not
|
|
var/movable_event = FALSE
|
|
/// The percentage chance that this event will turn itself into a mobile version
|
|
var/movable_event_chance
|
|
/// In which direction this event is currently planning on moving, will select a random dir if null
|
|
var/moving_dir = null
|
|
/// How many times the event has to process before moving (2 seconds per).
|
|
/// This is automatically randomized to be 1/3 higher or lower on init, so not all events fire simultaneously.
|
|
var/movable_speed = 75
|
|
/// Ticks up each process until move speed is matched, at which point the event will move
|
|
var/move_counter = 0
|
|
/// Percentage chance that the event changes direction
|
|
var/dir_change_chance = 33
|
|
/// How long to delay the next move counter if there's a ship in our loc, this gives bad events some time to happen
|
|
var/ship_delay_time = 10
|
|
/// Ticks up each process until move speed is matched, at which point the event will move
|
|
var/ship_delay_counter = 0
|
|
/// Text that appears in the tooltip.
|
|
var/tooltip_text = "A hazard."
|
|
|
|
/obj/effect/overmap/event/Initialize()
|
|
. = ..()
|
|
icon_state = pick(event_icon_states)
|
|
overmap_event_handler.update_hazards(loc)
|
|
if(movable_event)
|
|
start_moving()
|
|
else if(prob(movable_event_chance))
|
|
make_movable()
|
|
|
|
/obj/effect/overmap/event/proc/make_movable()
|
|
// For a default movable_speed of 60, this could result in a movable speed of anywhere between 40 and 80 (ie. moves every ~1.5-2.5 minutes).
|
|
var/speed_randomness = movable_speed / 3
|
|
movable_speed = movable_speed + rand((0 - speed_randomness), (speed_randomness))
|
|
// Hee hee
|
|
if(prob(1))
|
|
movable_speed = initial(movable_speed) / 4
|
|
start_moving()
|
|
|
|
/obj/effect/overmap/event/proc/start_moving()
|
|
if(!moving_dir) moving_dir = pick(GLOB.alldirs)
|
|
START_PROCESSING(SSprocessing, src)
|
|
|
|
/obj/effect/overmap/event/process()
|
|
if(locate(/obj/effect/overmap/visitable/ship) in loc)
|
|
ship_delay_counter++
|
|
if(ship_delay_counter < ship_delay_time)
|
|
return
|
|
ship_delay_counter = 0
|
|
move_counter++
|
|
if(move_counter >= movable_speed)
|
|
handle_move()
|
|
move_counter = 0
|
|
|
|
/obj/effect/overmap/event/proc/handle_move()
|
|
Move(get_step(src, moving_dir))
|
|
if(prob(dir_change_chance))
|
|
moving_dir = turn(moving_dir, pick(45, -45))
|
|
|
|
/obj/effect/overmap/event/Bump(var/atom/A)
|
|
if(istype(A,/turf/unsimulated/map/edge))
|
|
handle_wraparound()
|
|
..()
|
|
|
|
/obj/effect/overmap/event/Move()
|
|
var/turf/old_loc = loc
|
|
. = ..()
|
|
if(.)
|
|
overmap_event_handler.update_hazards(old_loc)
|
|
overmap_event_handler.update_hazards(loc)
|
|
|
|
/obj/effect/overmap/event/forceMove(atom/destination)
|
|
var/old_loc = loc
|
|
. = ..()
|
|
if(.)
|
|
overmap_event_handler.update_hazards(old_loc)
|
|
overmap_event_handler.update_hazards(loc)
|
|
|
|
/obj/effect/overmap/event/Destroy()//takes a look at this one as well, make sure everything is A-OK
|
|
if(movable_event)
|
|
STOP_PROCESSING(SSprocessing, src)
|
|
var/turf/T = loc
|
|
. = ..()
|
|
overmap_event_handler.update_hazards(T)
|
|
|
|
/obj/effect/overmap/event/meteor
|
|
name = "asteroid field"
|
|
events = list(/datum/event/meteor_wave/overmap)
|
|
opacity = 1
|
|
event_icon_states = list("meteor1", "meteor2", "meteor3", "meteor4")
|
|
difficulty = EVENT_LEVEL_MAJOR
|
|
tooltip_text = "Large rocks and debris traveling at high speed that can destroy entire hull sections."
|
|
|
|
/obj/effect/overmap/event/electric
|
|
name = "electrical storm"
|
|
events = list(/datum/event/electrical_storm)
|
|
event_icon_states = list("electrical1", "electrical2")
|
|
difficulty = EVENT_LEVEL_MAJOR
|
|
can_be_destroyed = FALSE
|
|
tooltip_text = "Electromagnetic storm effects that can damage or disable electrical grids."
|
|
|
|
/obj/effect/overmap/event/dust
|
|
name = "dust cloud"
|
|
events = list(/datum/event/meteor_wave/dust/overmap)
|
|
opacity = 1
|
|
event_icon_states = list("dust1", "dust2", "dust3", "dust4")
|
|
can_be_destroyed = FALSE
|
|
tooltip_text = "Small dust and debris traveling at high speed that can damage or destroy external windows."
|
|
|
|
/obj/effect/overmap/event/ion
|
|
name = "ion cloud"
|
|
events = list(/datum/event/ionstorm)
|
|
event_icon_states = list("ion1", "ion2", "ion3", "ion4")
|
|
difficulty = EVENT_LEVEL_MAJOR
|
|
can_be_destroyed = FALSE
|
|
tooltip_text = "Ionic effects that can damage synthetics like IPCs or AI, as well as disrupt telecommunications."
|
|
|
|
/obj/effect/overmap/event/carp
|
|
name = "carp shoal"
|
|
events = list(/datum/event/carp_migration/overmap)
|
|
difficulty = EVENT_LEVEL_MODERATE
|
|
event_icon_states = list("carp")
|
|
movable_event_chance = 30
|
|
tooltip_text = "Xenofauna: usually hostile."
|
|
|
|
/obj/effect/overmap/event/carp/major
|
|
name = "carp school"
|
|
opacity = 1
|
|
difficulty = EVENT_LEVEL_MAJOR
|
|
movable_event_chance = 15
|
|
|
|
/obj/effect/overmap/event/gravity_anomaly
|
|
name = "gravitic anomaly"
|
|
events = list(/datum/event/gravity_anomaly)
|
|
difficulty = EVENT_LEVEL_MODERATE
|
|
event_icon_states = list("grav1")
|
|
can_be_destroyed = FALSE
|
|
tooltip_text = "Unstable gravitic shear effects detected; wide-field artificial gravity should be powered down before transit."
|
|
|
|
/obj/effect/overmap/event/psiren
|
|
name = "psiren shoal"
|
|
events = list(/datum/event/wandering_psirens/overmap)
|
|
difficulty = EVENT_LEVEL_MODERATE
|
|
event_icon_states = list("carp")
|
|
movable_event_chance = 30
|
|
tooltip_text = "Xenofauna: usually hostile."
|
|
|
|
/obj/effect/overmap/event/psiren/major
|
|
name = "psiren school"
|
|
opacity = 1
|
|
difficulty = EVENT_LEVEL_MAJOR
|
|
movable_event_chance = 15
|
|
|
|
/obj/effect/overmap/event/MouseEntered(location, control, params)
|
|
. = ..()
|
|
openToolTip(usr, src, params, tooltip_text)
|
|
|
|
/obj/effect/overmap/event/MouseExited(location, control, params)
|
|
. = ..()
|
|
closeToolTip(usr)
|
|
|
|
/// These now are basically only used to spawn hazards. Will be useful when we need to spawn group of moving hazards
|
|
/datum/overmap_event
|
|
var/name = "map event"
|
|
var/radius = 2
|
|
var/count = 6
|
|
var/hazards
|
|
var/opacity = 0
|
|
/// If it should form continous blobs, or can have gaps.
|
|
var/continuous = TRUE
|
|
/// If set, this event will only spawn in the named space sectors.
|
|
var/list/sectors = list()
|
|
|
|
/datum/overmap_event/proc/spawns_in_current_sector()
|
|
if(!length(sectors))
|
|
return TRUE
|
|
if(!SSatlas.current_sector)
|
|
return FALSE
|
|
return (SSatlas.current_sector.name in sectors)
|
|
|
|
/datum/overmap_event/meteor
|
|
name = "asteroid field"
|
|
count = 10
|
|
radius = 4
|
|
opacity = 1
|
|
continuous = FALSE
|
|
hazards = /obj/effect/overmap/event/meteor
|
|
|
|
/datum/overmap_event/electric
|
|
name = "electrical storm"
|
|
count = 4
|
|
radius = 2
|
|
hazards = /obj/effect/overmap/event/electric
|
|
|
|
/datum/overmap_event/dust
|
|
name = "dust cloud"
|
|
count = 9
|
|
radius = 3
|
|
opacity = 1
|
|
hazards = /obj/effect/overmap/event/dust
|
|
|
|
/datum/overmap_event/ion
|
|
name = "ion cloud"
|
|
count = 4
|
|
radius = 2
|
|
hazards = /obj/effect/overmap/event/ion
|
|
|
|
/datum/overmap_event/carp
|
|
name = "carp shoal"
|
|
count = 6
|
|
radius = 2
|
|
continuous = FALSE
|
|
hazards = /obj/effect/overmap/event/carp
|
|
|
|
/datum/overmap_event/carp/major
|
|
name = "carp school"
|
|
count = 5
|
|
radius = 3
|
|
opacity = 1
|
|
hazards = /obj/effect/overmap/event/carp/major
|
|
|
|
/datum/overmap_event/gravity
|
|
name = "dark matter influx"
|
|
count = 19
|
|
radius = 12
|
|
hazards = /obj/effect/overmap/event/gravity_anomaly
|
|
sectors = list(SECTOR_LEMURIAN_SEA, SECTOR_LEMURIAN_SEA_FAR)
|
|
|
|
/datum/overmap_event/psiren
|
|
name = "psiren shoal"
|
|
count = 3
|
|
radius = 1
|
|
continuous = FALSE
|
|
hazards = /obj/effect/overmap/event/psiren
|
|
|
|
/datum/overmap_event/psiren/major
|
|
name = "psiren school"
|
|
count = 2
|
|
radius = 2
|
|
opacity = 1
|
|
hazards = /obj/effect/overmap/event/psiren/major
|