Files
necromanceranne 8df0c5851d Partially reverts #89619, where I partially reverted #87936; Puts back the mining and damage AOE damage on Mech PKA, but improves the standard modkits as well (#89993)
## About The Pull Request

In #89619, I removed the mech PKA's mining AOE and reduced the damaging
AOE to a fraction of the damage.

I have restored both of these aspects, but I have also applied this
change to the standard PKA's mining and damage AOE. I have also included
the mob biotype limitations as well.

AOE modkits take 10% capacity, now allowing miners to use them in more
setups. However, they conflict with one another. You can only have one
AOE mod until you can get the dual AOE mod from tendrils.

The AOE damage/mining effect is now a 2 tile effect rather than 1 tile
effect.

## Why It's Good For The Game

My intent in the previous PR was to bring mech PKA's down to standard
mining limitations. So, why not improve those standards for everyone
instead? The new state of mining expects you to be dealing with a lot of
mobs at once. Even small vents can, on occasion, decide to spit out
several goliaths back to back. That's a lot of mobs with a lot of
health.

Miners need AOE options more than ever. They have very little that are
actually meaningful, sadly. So my intent here is that this should be an
expectation for our miners to be seeking out and can fit into their
current, standard gameplay.

Certainly I've only felt like shit having to sacrifice a damage or
cooldown mod for an AOE mod, only to get a very minor amount of damage
splash for my efforts. That, and the radius doesn't usually impact most
mobs as they spawn and attack from awkward angles or distances from one
another where they are JUST out of reach of one another. Trying to use
the splash to hit multiple enemies is often not worth it compared to
just hitting one enemy at a time with a lot of damage.

So, let's just go with the standard of 'Good AOE is fundamentally needed
now' and worth from that premise.

## Changelog
🆑
balance: Mech PKA now once again mines turfs and does full damage on its
AOE explosion (still only hitting mining mobs).
balance: The standard PKA AOE mods are now by default 10% capacity. But
they cannot be used with one another.
balance: The standard PKA offensive AOE mod now does the PKA's full
damage in its AOE.
balance: Mining AOEs will affect everything within a 2 tile radius
around the point of impact, up from a 1 tile radius.
/🆑

---------

Co-authored-by: SmArtKar <44720187+SmArtKar@users.noreply.github.com>
2025-03-19 07:57:52 +01:00

181 lines
7.9 KiB
Plaintext

///Earthquake random event.
///Draws a curve of turfs between a high and low point. These turfs will shake and eventually "collapse", forming a cut in the station that drops to the z-level below.
///Much of the actual structural damage is done through the explosions subsystem. Objects, machines, and especially people
///that aren't moved out of the epicenter area (indicated by the wobbly tiles) will not just be thrown down a z-level, but also be destroyed/maimed in the process.
/datum/round_event_control/earthquake
name = "Chasmic Earthquake"
description = "Causes an earthquake, demolishing anything caught in the fault."
typepath = /datum/round_event/earthquake
category = EVENT_CATEGORY_ENGINEERING
min_players = 20
max_occurrences = 3
earliest_start = 35 MINUTES
weight = 7
min_wizard_trigger_potency = 3
max_wizard_trigger_potency = 7
map_flags = EVENT_PLANETARY_ONLY
/datum/round_event_control/earthquake/can_spawn_event(players_amt, allow_magic)
. = ..()
if(!.)
return .
if(!length(GLOB.generic_event_spawns))
return FALSE
/datum/round_event/earthquake
start_when = 1
announce_when = 3
end_when = 25
announce_chance = 25
///The chosen location and center of our earthquake.
var/turf/epicenter
///A list of turfs that will be damaged by this event.
var/list/turfs_to_shred
///A list of turfs directly under turfs_to_shred, for creating a proper chasm to the floor below.
var/list/underbelly = list()
///The edges of our fault line, to receive light damage.
var/list/edges = list()
/datum/round_event/earthquake/setup()
epicenter = get_turf(pick(GLOB.generic_event_spawns))
if(!epicenter)
message_admins("Earthquake event failed to find a turf! generic_event_spawn landmarks may be absent or bugged. Aborting...")
return
// Give a bit of variance so our epicenter isn't always on the landmark.
epicenter = locate(epicenter.x + rand(-10, 10), epicenter.y + rand(-10, 10), epicenter.z)
message_admins("An earthquake event is about to strike the [get_area_name(epicenter)][ADMIN_JMP(epicenter)].")
// Picks two points generally opposite from each other
var/turf/fracture_point_high = locate(epicenter.x + rand(4, 10), epicenter.y + rand(4, 8), epicenter.z)
var/turf/fracture_point_low = locate(epicenter.x - rand(4, 10), epicenter.y - rand(4, 8), epicenter.z)
turfs_to_shred = block(fracture_point_high, fracture_point_low)
// Now, we filter out some of the points that are a certain distance away from a rough approximation of the fault line.
// This should create a pattern more akin to a fracture in the ground, rather than a rectangle-shaped crater of destroyed ground.
var/turf/high_midpoint = TURF_MIDPOINT(fracture_point_high, epicenter)
var/turf/low_midpoint = TURF_MIDPOINT(fracture_point_low, epicenter)
// We populate a list with the midpoints and midpoints of midpoints to create a rough line of turfs to compare distances against.
var/list/turfs_to_compare = list(
fracture_point_high,
fracture_point_low,
high_midpoint,
low_midpoint,
TURF_MIDPOINT(fracture_point_high, high_midpoint),
TURF_MIDPOINT(fracture_point_low, low_midpoint),
TURF_MIDPOINT(high_midpoint, epicenter),
TURF_MIDPOINT(low_midpoint, epicenter),
)
// Find the shortest distance between each turf in the list and the rough fault line we've just established
for(var/turf/turf_to_check in turfs_to_shred)
var/nearest_distance = get_dist(turf_to_check, epicenter)
for(var/turf/turf_to_compare in turfs_to_compare)
nearest_distance = min(get_dist(turf_to_check, turf_to_compare), nearest_distance)
// If the turf is too far from any point on our fault line estimate, we remove it. If it's on the edge, we lightly damage it
if(nearest_distance > 2)
if(nearest_distance == 3)
edges += turf_to_check
turfs_to_shred -= turf_to_check
// Grab a list of turfs below the ones we're going to destroy.
// If we're at the bottom layer, it will just tear up the flooring a bunch (exposing it to LAVA).
for(var/turf/turf_to_quake in turfs_to_shred)
underbelly += GET_TURF_BELOW(turf_to_quake)
/datum/round_event/earthquake/announce(fake)
priority_announce("Planetary monitoring systems indicate a devastating seismic event in the near future.", "Seismic Report")
/datum/round_event/earthquake/start()
notify_ghosts(
"The earthquake's epicenter has been located: [get_area_name(epicenter)]!",
source = epicenter,
header = "Rumble Rumble Rumble!",
)
/datum/round_event/earthquake/tick()
if(ISMULTIPLE(activeFor, 5))
for(var/turf/turf_to_quake in turfs_to_shred)
turf_to_quake.Shake(pixelshiftx = 0.1, pixelshifty = 0.1, duration = 1 SECONDS)
if(ISMULTIPLE(activeFor, 10))
for(var/mob/earthquake_witness as anything in GLOB.player_list)
if(!is_station_level(earthquake_witness.z))
continue
shake_camera(earthquake_witness, 1 SECONDS, 1 + (activeFor % 10))
earthquake_witness.playsound_local(
earthquake_witness,
pick(
'sound/ambience/earth_rumble/earth_rumble_distant1.ogg',
'sound/ambience/earth_rumble/earth_rumble_distant2.ogg',
'sound/ambience/earth_rumble/earth_rumble_distant3.ogg',
'sound/ambience/earth_rumble/earth_rumble_distant4.ogg',
),
75,
)
for(var/turf/turf_to_quake in underbelly)
turf_to_quake.Shake(pixelshiftx = 0.1, pixelshifty = 0.1, duration = 1 SECONDS)
if(activeFor == end_when - 2)
for(var/turf/turf_to_quake in turfs_to_shred)
turf_to_quake.Shake(pixelshiftx = 0.5, pixelshifty = 0.5, duration = 1 SECONDS)
for(var/mob/living/quake_victim in turf_to_quake)
quake_victim.Knockdown(7 SECONDS)
quake_victim.Paralyze(5 SECONDS)
to_chat(quake_victim, span_warning("The ground quakes violently beneath you, throwing you off your feet!"))
for(var/turf/turf_to_quake in underbelly)
turf_to_quake.Shake(pixelshiftx = 0.5, pixelshifty = 0.5, duration = 1 SECONDS)
for(var/mob/living/carbon/quake_victim in turf_to_quake)
to_chat(quake_victim, span_warning("Damn, I wonder what that rumbling noise is?")) ///You're about to find out
// Step one of the destruction, which clears natural tiles out from the underbelly and does a bit of initial damage to the topside.
if(activeFor == end_when - 1)
for(var/turf/turf_to_shred in turfs_to_shred)
if(prob(90))
SSexplosions.lowturf += turf_to_shred
for(var/turf/turf_to_clear in underbelly)
if(ismineralturf(turf_to_clear))
var/turf/closed/mineral/rock_to_clear = turf_to_clear
rock_to_clear.gets_drilled()
for(var/turf/turf_to_quake in edges)
turf_to_quake.Shake(pixelshiftx = 0.5, pixelshifty = 0.5, duration = 1 SECONDS)
playsound(epicenter, 'sound/misc/metal_creak.ogg', 125, TRUE)
/datum/round_event/earthquake/end()
playsound(epicenter, 'sound/ambience/earth_rumble/earth_rumble.ogg', 125)
for(var/mob/earthquake_witness as anything in GLOB.player_list)
if(!is_station_level(earthquake_witness.z) || !is_mining_level(earthquake_witness.z))
continue
shake_camera(earthquake_witness, 2 SECONDS, 4)
earthquake_witness.playsound_local(earthquake_witness, 'sound/effects/explosion/explosionfar.ogg', 75)
// Step two of the destruction, which detonates the turfs in the earthquake zone. There is no actual explosion, meaning stuff around the earthquake zone is perfectly safe.
// All turfs, and everything else that IS in the earthquake zone, however, will behave as if it were bombed.
// If you are caught in the earthquake zone, you will not only die but probably be torn apart in the process.
for(var/turf/turf_to_shred in turfs_to_shred)
if(prob(10))
SSexplosions.medturf += turf_to_shred
else
SSexplosions.highturf += turf_to_shred
if(isasteroidturf(turf_to_shred) && prob(95))
turf_to_shred.ScrapeAway(flags = CHANGETURF_INHERIT_AIR)
for(var/mob/living/carbon/quake_victim in turf_to_shred)
if(quake_victim.client)
quake_victim.client.give_award(/datum/award/achievement/misc/earthquake_victim, quake_victim)
for(var/turf/edge_to_damage in edges)
if(prob(25))
SSexplosions.medturf += edge_to_damage
else
SSexplosions.lowturf += edge_to_damage