mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-07-16 10:27:14 +01:00
cf585ef505
Makes ship combat significantly more destructive (and a bit deadlier), especially with non-explosive projectiles. **Additions:** - A shell that penetrates a solid (dense) structure will cause spalling. This spall does 2-30 damage, depending on range and has a high embed chance. These embedded chunks are large enough to be ripped out by hand. (But you probably shouldn't). The pilot's suit has 30 ballistic armor, so a prepared bridge crew can survive a lot of spall. - Adds a gun that shoots any ship weapon that admins can spawn. Useful for testing, or for adminbus where they don't want to have to spawn a whole overmap ship. - Made several structures destructible, vending machines, computer frames, grilles (these were just bugged) and watertanks (and their children). These structures could just block infinite shots and were common enough to serve as effective armor for the horizon. These now spawn shrapnel (of their material if it's set), in addition to sheets of steel when destroyed. - Added support for negative maim chance. This allows chosen projectiles to be prevented from decapitating. No more accidentally gibbing the bridge crew's heads. (Unless they get hit with something really really big). **Balance:** - All non-explosive anti ship rounds got significant buffs. Typically 2-3x Anti-Material numbers. - Armour piercing anti-ship rounds got massively increased penetration stats. Typically 4-8 from 1-2. - Doors now get destroyed in less hits, if they are hit by anti-material projectiles. Hits to destroy -= Antimaterial / 2 - Francisca frag shells now shoot less fragments but deal more damage. 394 projectiles for every shot was a bit laggy, now it's only 280. **Shields:** Shields now take more power. 13-14 megawatts for a 10 strength shield. Just inside the ship's generation capacity with both the INDRA and Supermatter running. Instead of deleting any projectile they are hit by, shields now have different failure modes. - Firstly, a piercing projectile has it's penetration reduced by the shield strength. Eg A shot that would go through 10 walls, only penetrates 4 after going through a 6 strength shield. - Secondly, a projectile has it's damage multiplied by 1 - shield strength / 10, then has shield strength subtracted from it's damage. Eg. A damage 100 projectile, hitting a 5 strength shield, has it's damaged reduced to 50, (100 * 0.5), then to 45. (50-5) - Thirdly, an explosive projectile (that does not penetrate per the first step) does not explode, but instead deals it's full damage to the shield. Hits to the shield now also damage the field itself, not just the shield tile. As such, a very big hit on the shield can bring the whole thing down, requiring an engineer to reset it. Shields can now be upgraded with research components. Additionally, shield generators can now support more than one capacitor. The roundstart capacitor on the Horizon is only good enough to support a 6 strength shield. The upgrades increase efficiency, strength loss over time and charge speed. **Overmap Targetting** Previously, shells would spawn within 20 tiles of their target and aim directly forwards. This was bugged for shots with burst, which would instead all aim inwards and mostly miss. This is the reason the Grauwolf (in addition to the explosion bug below) and Fransisca felt so useless, only one of every shell in a burst would hit. Shots now spawn at the map edge, based on the orientation of the projectile and ship. Diagonals are now accounted for. Shots are then aimed directly at the target selected on the console, with 3 degrees of dispersion. **Bugfixes:** - Fixes lots of explosions that didn't pass a turf to the explosions subsystem. This caused the explosion not to happen if the thing hit got qdeled before the subsystem could get the turf to spawn the explosion on. - Embedded shrapnel no longer gets the initial projectile name, this prevents it getting named shrapnelshrapnel. - Fixes a bunch of projectile piercing bugs, mostly with grilles and windows. Shots now go past window frames without hitting them. - Fixes shields not having a click delay when attacked. --------- Signed-off-by: FenodyreeAv <fenodyree.av@gmail.com> Co-authored-by: Matt Atlas <mattiathebest2000@hotmail.it>
410 lines
14 KiB
Plaintext
410 lines
14 KiB
Plaintext
/obj/structure/machinery/ship_weapon/leviathan
|
|
name = "leviathan zero-point artillery"
|
|
desc = "A hulking structure made up of an uncalculable amount of moving parts, components and capacitors. It has no branding other than the \"ZAT\" inscription on the sides."
|
|
icon = 'icons/obj/machinery/ship_guns/leviathan.dmi'
|
|
icon_state = "weapon_off"
|
|
special_firing_mechanism = TRUE
|
|
maxhealth = 10000
|
|
|
|
projectile_type = /obj/projectile/ship_ammo/leviathan
|
|
use_ammunition = FALSE
|
|
heavy_firing_sound = 'sound/weapons/gunshot/ship_weapons/leviathan_fire.ogg'
|
|
caliber = SHIP_CALIBER_ZAT
|
|
firing_effects = FIRING_EFFECT_FLAG_THROW_MOBS|FIRING_EFFECT_FLAG_EXTREMELY_LOUD
|
|
screenshake_type = SHIP_GUN_SCREENSHAKE_ALL_MOBS
|
|
layer = ABOVE_HUMAN_LAYER
|
|
|
|
use_power = POWER_USE_OFF //Start off.
|
|
idle_power_usage = 100 KILO WATTS
|
|
active_power_usage = 20 MEGA WATTS
|
|
var/obj/structure/machinery/power/smes/buildable/smes
|
|
|
|
/obj/structure/machinery/ship_weapon/leviathan/Destroy()
|
|
smes = null
|
|
return ..()
|
|
|
|
/obj/structure/machinery/ship_weapon/leviathan/LateInitialize()
|
|
. = ..()
|
|
couple_to_smes()
|
|
|
|
/obj/structure/machinery/ship_weapon/leviathan/ex_act(severity)
|
|
return //Not happening bro.
|
|
|
|
/obj/structure/machinery/ship_weapon/leviathan/firing_checks()
|
|
if(use_power == POWER_USE_OFF)
|
|
return FALSE
|
|
if(!istype(smes))
|
|
return FALSE
|
|
if(firing)
|
|
return FALSE
|
|
. = ..()
|
|
|
|
/obj/structure/machinery/ship_weapon/leviathan/pre_fire(atom/target, obj/effect/landmark/landmark)
|
|
firing = TRUE
|
|
icon_state = "weapon_on"
|
|
visible_message(SPAN_DANGER("<font size=5>\The [src] begins lighting up with a powerful hum...</font>"))
|
|
var/power_draw = smes.drain_power_simple(active_power_usage)
|
|
if(power_draw >= active_power_usage)
|
|
for(var/mob/M in GLOB.living_mob_list)
|
|
if(AreConnectedZLevels(GET_Z(M), z))
|
|
if(get_area(M) != get_area(src))
|
|
to_chat(M, SPAN_DANGER("<font size=4>The ground below you starts shaking...</font>"))
|
|
sound_to(M, sound('sound/weapons/gunshot/ship_weapons/leviathan_chargeup.ogg'))
|
|
flick("weapon_charge", src)
|
|
sleep(10 SECONDS)
|
|
var/obj/item/ship_ammunition/leviathan/L = new()
|
|
ammunition |= L
|
|
if(!stat)
|
|
visible_message(SPAN_DANGER("<font size=6>\The [src] fires, quaking the ground below you!</font>"))
|
|
for(var/mob/M in GLOB.living_mob_list)
|
|
if(AreConnectedZLevels(M.z, z) && (get_area(M) != get_area(src)))
|
|
to_chat(M, SPAN_DANGER("<font size=4>A gigantic shock courses through the hull of the ship!</font>"))
|
|
. = ..()
|
|
else
|
|
visible_message(SPAN_DANGER("<font size=4>\The [src]'s capacitors fizzle out!</font>"))
|
|
. = FALSE
|
|
disable()
|
|
|
|
/obj/structure/machinery/ship_weapon/leviathan/process()
|
|
if(firing)
|
|
for(var/mob/M in GLOB.living_mob_list)
|
|
if(AreConnectedZLevels(GET_Z(M), z))
|
|
shake_camera(M, 3, 3)
|
|
|
|
/obj/structure/machinery/ship_weapon/leviathan/power_change()
|
|
. = ..()
|
|
if((stat & NOPOWER) && .)
|
|
disable()
|
|
|
|
/obj/structure/machinery/ship_weapon/leviathan/update_use_power(new_use_power)
|
|
. = ..()
|
|
if(new_use_power == POWER_USE_OFF && (use_power != POWER_USE_OFF))
|
|
disable()
|
|
|
|
/obj/structure/machinery/ship_weapon/leviathan/disable()
|
|
firing = FALSE
|
|
if(use_power != POWER_USE_OFF)
|
|
visible_message(SPAN_DANGER("<font size=4>\The [src]'s humming comes to an abrupt halt.</font>"))
|
|
for(var/mob/living/L in GLOB.living_mob_list)
|
|
if(AreConnectedZLevels(L.z, z))
|
|
sound_to(L, 'sound/effects/ship_weapons/leviathan_powerdown.ogg')
|
|
to_chat(L, SPAN_WARNING("The ground below you settles down, no longer vibrating."))
|
|
update_use_power(POWER_USE_OFF)
|
|
icon_state = "weapon_off"
|
|
|
|
/obj/structure/machinery/ship_weapon/leviathan/enable()
|
|
couple_to_smes()
|
|
if(!smes)
|
|
visible_message(SPAN_DANGER("\The [src] doesn't light up at all! Its maintenance display indicates there is no SMES to draw power from."))
|
|
return
|
|
visible_message(SPAN_DANGER("<font size=4>\The [src] lights up with a powerful hum...</font>"))
|
|
for(var/mob/living/L in GLOB.living_mob_list)
|
|
if(AreConnectedZLevels(L.z, z))
|
|
sound_to(L, 'sound/effects/ship_weapons/leviathan_powerup.ogg')
|
|
to_chat(L, SPAN_WARNING("The ground below you starts vibrating with a slight hum..."))
|
|
update_use_power(POWER_USE_IDLE)
|
|
icon_state = "weapon_on"
|
|
|
|
/obj/structure/machinery/ship_weapon/leviathan/proc/couple_to_smes()
|
|
if(smes)
|
|
return
|
|
var/list/obj/structure/machinery/power/smes/candidates = list()
|
|
for(var/obj/structure/machinery/power/smes/S in SSmachinery.machinery)
|
|
if(get_area(S) == get_area(src))
|
|
candidates += S
|
|
for(var/obj/structure/machinery/power/smes/buildable/superconducting/SC in candidates)
|
|
if(istype(SC))
|
|
smes = SC
|
|
return
|
|
for(var/obj/structure/machinery/power/smes/buildable/SM in candidates)
|
|
if(istype(SM))
|
|
smes = SM
|
|
return
|
|
|
|
/obj/item/ship_ammunition/leviathan
|
|
name = "zero-point artillery beam"
|
|
desc = "A beam of pure energy."
|
|
range = OVERMAP_PROJECTILE_RANGE_ULTRAHIGH
|
|
caliber = SHIP_CALIBER_ZAT
|
|
impact_type = SHIP_AMMO_IMPACT_ZAT
|
|
overmap_icon_state = "heavy_pulse"
|
|
|
|
/obj/item/ship_ammunition/leviathan/Initialize()
|
|
. = ..()
|
|
set_light(3, 3, LIGHT_COLOR_PURPLE)
|
|
|
|
/obj/item/ship_ammunition/leviathan/get_speed()
|
|
return 2
|
|
|
|
/obj/projectile/ship_ammo/leviathan
|
|
name = "zero-point artillery beam"
|
|
desc = "A concentrated stream of pure energy."
|
|
icon_state = "pulse"
|
|
damage = 10000
|
|
armor_penetration = 1000
|
|
penetrating = 100
|
|
hitscan = TRUE
|
|
impact_sounds = list(BULLET_IMPACT_MEAT = SOUNDS_LASER_MEAT, BULLET_IMPACT_METAL = SOUNDS_LASER_METAL)
|
|
|
|
muzzle_type = /obj/effect/projectile/muzzle/pulse
|
|
tracer_type = /obj/effect/projectile/tracer/pulse
|
|
impact_type = /obj/effect/projectile/impact/pulse
|
|
|
|
/obj/projectile/ship_ammo/leviathan/on_hit(atom/target, blocked, def_zone, is_landmark_hit)
|
|
. = ..()
|
|
|
|
if(!is_landmark_hit)
|
|
if(ismob(target))
|
|
var/mob/M = target
|
|
M.visible_message(SPAN_DANGER("<font size=6>[M] evaporates as they are engulfed by the beam!</font>"))
|
|
M.dust()
|
|
return
|
|
explosion(get_turf(target), 6, 6, 6)
|
|
else
|
|
target.visible_message(SPAN_DANGER("<font size=6>A giant, purple laser descends from the sky!</font>"))
|
|
explosion(get_turf(target), 30, 30, 30)
|
|
|
|
/obj/structure/machinery/zat_lever
|
|
name = "activation lever"
|
|
desc = "An old-style lever that couples the Leviathan's capacitors. <span class='danger'>Flicking this will result in extreme power usage!</span>"
|
|
icon = 'icons/obj/power.dmi'
|
|
icon_state = "lever1"
|
|
var/obj/structure/machinery/ship_weapon/leviathan/ZAT
|
|
var/toggled = FALSE
|
|
var/cooldown = 0
|
|
|
|
/obj/structure/machinery/zat_lever/Initialize(mapload, d, populate_components, is_internal)
|
|
..()
|
|
return INITIALIZE_HINT_LATELOAD
|
|
|
|
/obj/structure/machinery/zat_lever/LateInitialize()
|
|
. = ..()
|
|
for(var/obj/structure/machinery/ship_weapon/leviathan/cannon in get_area(src))
|
|
ZAT = cannon
|
|
break
|
|
|
|
/obj/structure/machinery/zat_lever/Destroy()
|
|
ZAT = null
|
|
return..()
|
|
|
|
/obj/structure/machinery/zat_lever/attack_hand(mob/user)
|
|
if(!use_check_and_message(user, USE_DISALLOW_SILICONS) && !stat && (cooldown + 10 SECONDS < world.time))
|
|
if(do_after(user, 1 SECOND))
|
|
visible_message(SPAN_DANGER("[user] pulls \the [src] [toggled ? "up" : "down"]!"))
|
|
toggled = !toggled
|
|
switch(toggled)
|
|
if(FALSE)
|
|
flick("lever3", src)
|
|
ZAT.disable()
|
|
sleep(2)
|
|
icon_state = "lever1"
|
|
if(TRUE)
|
|
flick("lever2", src)
|
|
ZAT.enable()
|
|
sleep(2)
|
|
icon_state = "lever_down"
|
|
playsound(src, 'sound/effects/spring.ogg', 100)
|
|
cooldown = world.time
|
|
|
|
/obj/item/leviathan_key
|
|
name = "leviathan activation key"
|
|
desc = "A key made of hardlight used to activate the Leviathan. It is a software-controlled morphing key that uses self-replicating encryption: \
|
|
it cannot be replicated at all. Most importantly, if it is stolen, it can simply be deactivated by the SCC. A marvel of modern technology! \
|
|
If you're vain, you could also probably wear it as a necklace."
|
|
icon = 'icons/obj/machinery/ship_guns/zat_confirmation_terminals.dmi'
|
|
icon_state = "cannon_key"
|
|
item_state = "cannon_key"
|
|
contained_sprite = TRUE
|
|
slot_flags = SLOT_MASK
|
|
|
|
/obj/item/leviathan_case
|
|
name = "leviathan key case"
|
|
desc = "It contains the Leviathan's activation key. The case is made out of authentic ebony wood, while the cushioning on the inside is made of silk."
|
|
icon = 'icons/obj/machinery/ship_guns/zat_confirmation_terminals.dmi'
|
|
icon_state = "key_case"
|
|
var/open = FALSE
|
|
var/obj/item/leviathan_key/LK
|
|
|
|
/obj/item/leviathan_case/Initialize()
|
|
. = ..()
|
|
LK = new(src)
|
|
|
|
/obj/item/leviathan_case/Destroy()
|
|
QDEL_NULL(LK)
|
|
return ..()
|
|
|
|
/obj/item/leviathan_case/attack_self(mob/user)
|
|
if(use_check_and_message(user))
|
|
return
|
|
open = !open
|
|
if(open)
|
|
user.visible_message(SPAN_NOTICE("[user] opens \the [src]."))
|
|
if(LK)
|
|
icon_state = "key_case-o"
|
|
else
|
|
icon_state = "key_case-e"
|
|
else
|
|
user.visible_message(SPAN_NOTICE("[user] closes \the [src]."))
|
|
icon_state = "key_case"
|
|
|
|
/obj/item/leviathan_case/attack_hand(mob/user)
|
|
if(!open || !LK || !ishuman(loc))
|
|
. = ..()
|
|
return
|
|
if(use_check_and_message(user, USE_FORCE_SRC_IN_USER))
|
|
return
|
|
if(LK)
|
|
user.visible_message(SPAN_NOTICE("[user] retrieves \the [LK]."))
|
|
user.put_in_hands(LK)
|
|
LK = null
|
|
icon_state = "key_case-e"
|
|
|
|
/obj/item/leviathan_case/attackby(obj/item/attacking_item, mob/user)
|
|
. = ..()
|
|
if(use_check_and_message(user))
|
|
return
|
|
if(!LK && open)
|
|
if(istype(attacking_item, /obj/item/leviathan_key))
|
|
var/obj/item/leviathan_key/key = attacking_item
|
|
user.visible_message(SPAN_NOTICE("[user] puts \the [key] back into \the [src]."))
|
|
LK = key
|
|
user.drop_from_inventory(key, src)
|
|
icon_state = "key_case-o"
|
|
|
|
/obj/structure/machinery/leviathan_safeguard
|
|
name = "leviathan activation terminal"
|
|
desc = "The terminal used to confirm if you really want to wipe someone out."
|
|
icon = 'icons/obj/machinery/ship_guns/zat_confirmation_terminals.dmi'
|
|
icon_state = "safeguard"
|
|
anchored = TRUE
|
|
density = TRUE
|
|
var/opened = FALSE
|
|
var/locked = FALSE
|
|
var/obj/item/leviathan_key/key
|
|
var/obj/structure/machinery/leviathan_button/button
|
|
|
|
/obj/structure/machinery/leviathan_safeguard/Initialize(mapload, d, populate_components, is_internal)
|
|
..()
|
|
return INITIALIZE_HINT_LATELOAD
|
|
|
|
/obj/structure/machinery/leviathan_safeguard/LateInitialize()
|
|
. = ..()
|
|
if(SSatlas.current_map.use_overmap && !linked)
|
|
var/my_sector = GLOB.map_sectors["[z]"]
|
|
if (istype(my_sector, /obj/effect/overmap/visitable))
|
|
attempt_hook_up(my_sector)
|
|
if(linked)
|
|
ASSERT(isnull(linked.levi_safeguard)) //There should only ever be one
|
|
linked.levi_safeguard = src
|
|
for(var/obj/structure/machinery/leviathan_button/LB in range(3, src))
|
|
if(istype(LB))
|
|
button = LB
|
|
|
|
/obj/structure/machinery/leviathan_safeguard/Destroy()
|
|
if(linked)
|
|
linked.levi_safeguard = null
|
|
|
|
QDEL_NULL(key)
|
|
button = null
|
|
|
|
. = ..()
|
|
|
|
/obj/structure/machinery/leviathan_safeguard/ex_act(severity)
|
|
return
|
|
|
|
/obj/structure/machinery/leviathan_safeguard/emp_act(severity)
|
|
. = ..()
|
|
|
|
return
|
|
|
|
/obj/structure/machinery/leviathan_safeguard/proc/open()
|
|
opened = TRUE
|
|
flick("safeguard_opening", src)
|
|
icon_state = "safeguard_open"
|
|
|
|
/obj/structure/machinery/leviathan_safeguard/attackby(obj/item/attacking_item, mob/user)
|
|
if(!opened || locked)
|
|
return
|
|
if(istype(attacking_item, /obj/item/leviathan_key) && !key && !stat)
|
|
var/obj/item/leviathan_key/LK = attacking_item
|
|
if(use_check_and_message(user))
|
|
return
|
|
if(do_after(user, 1 SECOND))
|
|
visible_message(SPAN_WARNING("[user] places \the [LK] inside \the [src]'s keyhole!"))
|
|
key = LK
|
|
user.drop_from_inventory(attacking_item, src)
|
|
icon_state = "safeguard_open"
|
|
playsound(src, 'sound/effects/ship_weapons/levi_key_insert.ogg', 50)
|
|
|
|
/obj/structure/machinery/leviathan_safeguard/attack_hand(mob/user)
|
|
if(key && !stat && opened && !locked)
|
|
if(use_check_and_message(user))
|
|
return
|
|
if(do_after(user, 1 SECOND))
|
|
visible_message(SPAN_WARNING("[user] twists \the [key]!"))
|
|
flick("safeguard_locking", src)
|
|
icon_state = "safeguard_locked"
|
|
locked = TRUE
|
|
playsound(src, 'sound/effects/ship_weapons/levi_key_twist.ogg', 50)
|
|
button.open()
|
|
|
|
/obj/structure/machinery/leviathan_button
|
|
name = "leviathan fire button"
|
|
desc = "The button that controls the Leviathan's firing mechanism."
|
|
icon = 'icons/obj/machinery/ship_guns/zat_confirmation_terminals.dmi'
|
|
icon_state = "button_closed"
|
|
anchored = TRUE
|
|
var/open = FALSE
|
|
|
|
/obj/structure/machinery/leviathan_button/Initialize()
|
|
..()
|
|
return INITIALIZE_HINT_LATELOAD
|
|
|
|
/obj/structure/machinery/leviathan_button/LateInitialize()
|
|
. = ..()
|
|
if(SSatlas.current_map.use_overmap && !linked)
|
|
var/my_sector = GLOB.map_sectors["[z]"]
|
|
if (istype(my_sector, /obj/effect/overmap/visitable))
|
|
attempt_hook_up(my_sector)
|
|
|
|
/obj/structure/machinery/leviathan_button/ex_act(severity)
|
|
return
|
|
|
|
/obj/structure/machinery/leviathan_button/emp_act(severity)
|
|
. = ..()
|
|
|
|
return
|
|
|
|
/obj/structure/machinery/leviathan_button/proc/open()
|
|
icon_state = "button_open"
|
|
open = TRUE
|
|
|
|
/obj/structure/machinery/leviathan_button/attack_hand(mob/user)
|
|
set waitfor = FALSE
|
|
if(open)
|
|
if(use_check_and_message(user))
|
|
return
|
|
if(linked.targeting)
|
|
var/list/obj/effect/possible_entry_points = list()
|
|
if(istype(linked.targeting, /obj/effect/overmap/visitable))
|
|
var/obj/effect/overmap/visitable/V = linked.targeting
|
|
for(var/obj/effect/O in V.generic_waypoints)
|
|
possible_entry_points[O.name] = O
|
|
for(var/obj/effect/O in V.entry_points)
|
|
possible_entry_points[O.name] = O
|
|
possible_entry_points = sortList(possible_entry_points)
|
|
if(istype(linked.targeting, /obj/effect/overmap/event))
|
|
possible_entry_points += SHIP_HAZARD_TARGET
|
|
var/targeted_landmark = tgui_input_list(user, "Select an entry point.", "Leviathan Control", possible_entry_points)
|
|
if(!targeted_landmark && length(possible_entry_points))
|
|
return
|
|
var/obj/effect/landmark
|
|
if(length(possible_entry_points) && !(targeted_landmark == SHIP_HAZARD_TARGET))
|
|
landmark = possible_entry_points[targeted_landmark]
|
|
if(do_after(user, 1 SECOND) && !use_check_and_message(user))
|
|
playsound(src, 'sound/effects/ship_weapons/levi_button_press.ogg', 50)
|
|
visible_message(SPAN_DANGER("[user] presses \the [src]!"))
|
|
for(var/obj/structure/machinery/ship_weapon/leviathan/LT in linked.ship_weapons)
|
|
if(istype(LT))
|
|
LT.firing_command(linked.targeting, landmark)
|