mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-26 14:31:59 +01:00
Four major fixes. These are all pretty clearly bugs, but the result is a substantial mech nerf (except EMPs against EM armor.) First, EMP armour. EMP armour did nothing, it was partially ported to use TG's Element flag system, this finishes that. Rather than make the EMP armour immune to EMP, it spends power to negate it. The cost is 1000 / severity. Heavy EMP is 1, Light EMP is 2. This is 5% of a basic mech cell for light, 10% for heavy. Also fixes the pilot getting EMP'd twice for every EMP act on the mech. Second, open hatches let attacks hit the pilot. Chance is 80% from the front, 20% from the sides. The chance is mostly so that turrets that always aim torso don't shoot mechs forever, always hitting the pilot inside. Third, cockpit damage actually matters now. Previously shooting the mech in the chest was nearly worthless, no important components were there and destroying it did not destroy the mech. Now if the cockpit is completely destroyed, attacks against it penetrate through to hit the pilot. These attacks still account for the mech's armour. Combined with the hatch getting stuck closed, you can have tense rescues of pilots bleeding out inside their suits. Fourth, the mech running out of power actually stops it doing things. Uranium and Phoron power cores allowed mechs to keep running forever, even at fractional power, because they recharged slightly every tick. Now if the mech ever cannot afford the power cost of an action it shuts down. It can be powered back up immediately if the power core recharges it, but it cannot now do costly actions at single digit power. I fixed mech combat shields. They suck, they use the auras system which does not play nicely with the new projectile code. Recursive calls and spaghetti mess. Works for now but could use a complete rewrite. --------- Signed-off-by: FenodyreeAv <fenodyree.av@gmail.com>
386 lines
12 KiB
Plaintext
386 lines
12 KiB
Plaintext
// Big stompy robots.
|
|
/mob/living/heavy_vehicle
|
|
name = "exosuit"
|
|
density = TRUE
|
|
anchored = TRUE
|
|
status_flags = PASSEMOTES
|
|
a_intent = I_HURT
|
|
mob_size = MOB_LARGE
|
|
mob_push_flags = ALLMOBS
|
|
can_be_buckled = FALSE
|
|
accent = ACCENT_TTS
|
|
appearance_flags = KEEP_TOGETHER | DEFAULT_APPEARANCE_FLAGS | TILE_BOUND | LONG_GLIDE
|
|
pass_flags_self = PASSVEHICLE
|
|
var/decal
|
|
|
|
var/emp_damage = 0
|
|
|
|
// Used to offset a non-32x32 icon appropriately.
|
|
var/offset_x = -8
|
|
var/offset_y = 0
|
|
|
|
var/obj/item/radio/exosuit/radio
|
|
var/obj/structure/machinery/camera/camera
|
|
/// Whether pilots want the external camera to broadcast while its hardware is functional
|
|
var/camera_enabled = TRUE
|
|
|
|
var/wreckage_path = /obj/structure/mech_wreckage
|
|
|
|
// Access updating/container.
|
|
var/obj/item/card/id/mecha/access_card
|
|
|
|
// Mob we're currently paired with or following | the names are saved to prevent metagaming when returning diagnostics
|
|
var/datum/weakref/leader
|
|
var/leader_name
|
|
var/datum/weakref/following
|
|
var/following_name
|
|
|
|
// Orders from our leader
|
|
var/nickname // we'll respond to our name or our nickname
|
|
var/follow_distance = 3
|
|
|
|
// Mob currently piloting the mech.
|
|
var/list/pilots
|
|
var/list/pilot_overlays
|
|
|
|
// Remote control stuff
|
|
var/remote = FALSE // Spawns a robotic pilot to be remote controlled
|
|
var/remote_type = /obj/item/remote_mecha
|
|
var/does_hardpoint_lock = TRUE
|
|
var/mob/living/simple_animal/spiderbot/dummy // The remote controlled dummy
|
|
var/dummy_type = /mob/living/simple_animal/spiderbot
|
|
var/dummy_colour
|
|
|
|
// Visible external components. Not strictly accurately named for non-humanoid machines (submarines) but w/e
|
|
var/obj/item/mech_component/manipulators/arms
|
|
var/obj/item/mech_component/propulsion/legs
|
|
var/obj/item/mech_component/sensors/head
|
|
var/obj/item/mech_component/chassis/body
|
|
|
|
// Equipment tracking vars.
|
|
var/obj/item/mecha_equipment/selected_system
|
|
var/selected_hardpoint
|
|
var/list/hardpoints = list()
|
|
var/hardpoints_locked
|
|
var/maintenance_protocols
|
|
var/lockdown
|
|
var/entry_speed = 30
|
|
var/loudening = FALSE // whether we're increasing the speech volume of our pilot
|
|
|
|
// Material
|
|
var/singleton/material/material
|
|
|
|
// Cockpit access vars.
|
|
var/hatch_closed = FALSE
|
|
var/hatch_locked = FALSE
|
|
var/force_locked = FALSE // Is it possible to unlock the hatch?
|
|
|
|
var/use_air = FALSE
|
|
|
|
// Interface stuff.
|
|
|
|
/// The next world tick that the mech has to wait for before it can change its Throttle (forward and backward movement).
|
|
var/next_mecha_move = 0
|
|
|
|
/// The next world tick that the mech has to wait for before it can turn.
|
|
var/next_mecha_turn = 0
|
|
|
|
/// The next world tick that the mech has to wait for before it can strafe.
|
|
var/next_mecha_strafe = 0
|
|
|
|
var/list/hud_elements = list()
|
|
var/list/hardpoint_hud_elements = list()
|
|
var/atom/movable/screen/mecha/health/hud_health
|
|
var/atom/movable/screen/mecha/toggle/hatch_open/hud_open
|
|
var/atom/movable/screen/mecha/power/hud_power
|
|
var/atom/movable/screen/mecha/toggle/power_control/hud_power_control
|
|
//POWER
|
|
var/power = MECH_POWER_OFF
|
|
|
|
/// Sound effect used for mech ambience.
|
|
var/datum/looping_sound/mech_power/soundloop
|
|
/// Separate tracking of current sound looping so we aren't hammering the sound loop system on every tick.
|
|
var/sound_looping = FALSE
|
|
|
|
/mob/living/heavy_vehicle/Destroy()
|
|
unassign_leader()
|
|
unassign_following()
|
|
|
|
selected_system = null
|
|
|
|
for(var/hardpoint in hardpoints)
|
|
var/obj/item/S = remove_system(hardpoint, force = 1)
|
|
if(S)
|
|
QDEL_NULL(S)
|
|
|
|
hardpoints = null
|
|
|
|
for(var/thing in pilots)
|
|
var/mob/pilot = thing
|
|
if(pilot.client)
|
|
pilot.client.screen -= hud_elements
|
|
pilot.client.images -= hud_elements
|
|
if (!QDELETED(pilot)) // Forcemove doesn't accept QDELETED inputs.
|
|
remove_verb(pilot, /mob/proc/toggle_exosuit_camera)
|
|
remove_verb(pilot, /mob/proc/change_exosuit_camera_network)
|
|
pilot.forceMove(get_turf(src))
|
|
pilots = null
|
|
|
|
QDEL_LIST(hud_elements)
|
|
|
|
if(remote_network)
|
|
SSvirtualreality.remove_mech(src, remote_network)
|
|
|
|
hardpoint_hud_elements = null
|
|
|
|
QDEL_NULL(access_card)
|
|
QDEL_NULL(arms)
|
|
QDEL_NULL(legs)
|
|
QDEL_NULL(head)
|
|
QDEL_NULL(body)
|
|
|
|
QDEL_NULL(hud_health)
|
|
QDEL_NULL(hud_open)
|
|
QDEL_NULL(hud_power)
|
|
QDEL_NULL(hud_power_control)
|
|
|
|
QDEL_NULL(camera)
|
|
QDEL_NULL(radio)
|
|
QDEL_NULL(soundloop)
|
|
. = ..()
|
|
|
|
/mob/living/heavy_vehicle/IsAdvancedToolUser()
|
|
return TRUE
|
|
|
|
/mob/living/heavy_vehicle/get_examine_text(mob/user, distance, is_adjacent, infix, suffix)
|
|
SHOULD_CALL_PARENT(FALSE) //Special snowflake case
|
|
|
|
. = list()
|
|
if(!user || !user.client)
|
|
return TRUE
|
|
. += "That's \a <b>[src]</b>."
|
|
if(desc)
|
|
to_chat(user, desc)
|
|
if(LAZYLEN(pilots) && (!hatch_closed || body.pilot_coverage < 100 || body.transparent_cabin))
|
|
if(length(pilots) == 0)
|
|
. += "It has <b>no pilot</b>."
|
|
else
|
|
for(var/pilot in pilots)
|
|
if(ismob(pilot))
|
|
var/mob/M = pilot
|
|
. += "It is being <b>piloted</b> by <a href='byond://?src=[REF(src)];examine=[REF(M)]'>[M.name]</a>."
|
|
else
|
|
. += "It is being <b>piloted</b> by <b>[pilot]</b>."
|
|
if(hardpoints.len)
|
|
. += SPAN_NOTICE("It has the following hardpoints:")
|
|
for(var/hardpoint in hardpoints)
|
|
var/obj/item/I = hardpoints[hardpoint]
|
|
. += "- <b>[hardpoint]</b>: [istype(I) ? "<a href='byond://?src=[REF(src)];examine=[REF(I)]'>[I.name]</a>" : "nothing"]."
|
|
else
|
|
. += "It has <b>no visible hardpoints</b>."
|
|
|
|
for(var/obj/item/mech_component/thing in list(arms, legs, head, body))
|
|
if(!thing)
|
|
continue
|
|
var/damage_string = ""
|
|
switch(thing.damage_state)
|
|
if(1)
|
|
damage_string = "undamaged"
|
|
if(2)
|
|
damage_string = SPAN_WARNING("damaged")
|
|
if(3)
|
|
damage_string = SPAN_WARNING("badly damaged")
|
|
if(4)
|
|
damage_string = SPAN_DANGER("destroyed")
|
|
. += "Its <b>[thing.name]</b> [thing.gender == PLURAL ? "are" : "is"] [damage_string]."
|
|
|
|
/mob/living/heavy_vehicle/Topic(href,href_list[])
|
|
if (href_list["examine"])
|
|
var/mob/M = locate(href_list["examine"])
|
|
if(!M)
|
|
return
|
|
examinate(usr, M)
|
|
|
|
/mob/living/heavy_vehicle/Initialize(mapload, var/obj/structure/heavy_vehicle_frame/source_frame)
|
|
..()
|
|
|
|
if(!access_card) access_card = new (src)
|
|
|
|
if(offset_x) pixel_x = offset_x
|
|
if(offset_y) pixel_y = offset_y
|
|
radio = new(src)
|
|
|
|
// Grab all the supplied components.
|
|
if(source_frame)
|
|
if(source_frame.set_name)
|
|
name = source_frame.set_name
|
|
if(source_frame.arms)
|
|
source_frame.arms.forceMove(src)
|
|
arms = source_frame.arms
|
|
if(source_frame.legs)
|
|
source_frame.legs.forceMove(src)
|
|
legs = source_frame.legs
|
|
if(legs.hover) //Checks here if hoverthrusters
|
|
pass_flags |= PASSRAILING
|
|
if(source_frame.head)
|
|
source_frame.head.forceMove(src)
|
|
head = source_frame.head
|
|
if(source_frame.body)
|
|
source_frame.body.forceMove(src)
|
|
body = source_frame.body
|
|
if(body.cell)
|
|
RegisterSignal(body.cell, COMSIG_CELL_CHARGE, PROC_REF(handle_cell_charge))
|
|
|
|
updatehealth()
|
|
|
|
// Generate hardpoint list.
|
|
for(var/obj/item/mech_component/thing in list(arms, legs, head, body))
|
|
if(thing && thing.has_hardpoints.len)
|
|
for(var/hardpoint in thing.has_hardpoints)
|
|
hardpoints[hardpoint] = null
|
|
|
|
if(head && head.radio)
|
|
radio = new(src)
|
|
|
|
if(!camera)
|
|
camera = new /obj/structure/machinery/camera(src, 0, TRUE, TRUE)
|
|
camera.c_tag = name
|
|
camera.replace_networks(list(NETWORK_MECHS))
|
|
|
|
// Create HUD.
|
|
instantiate_hud()
|
|
|
|
// Build icon.
|
|
update_icon()
|
|
|
|
add_language(LANGUAGE_TCB)
|
|
default_language = GLOB.all_languages[LANGUAGE_TCB]
|
|
soundloop = new(src)
|
|
. = INITIALIZE_HINT_LATELOAD
|
|
|
|
/mob/living/heavy_vehicle/LateInitialize()
|
|
var/obj/structure/machinery/mech_recharger/MR = locate() in get_turf(src)
|
|
if(MR)
|
|
MR.start_charging(src)
|
|
|
|
/mob/living/heavy_vehicle/return_air()
|
|
return (body && body.pilot_coverage >= 100 && hatch_closed) ? body.cockpit : loc?.return_air()
|
|
|
|
/mob/living/heavy_vehicle/proc/update_emp_protection()
|
|
RemoveElement(/datum/element/empprotection, EMP_PROTECT_ALL)
|
|
if(power == MECH_POWER_ON && body.mech_armor && body.mech_armor.emp_protection)
|
|
if(get_cell().charge > 500)
|
|
AddElement(/datum/element/empprotection, EMP_PROTECT_ALL)
|
|
|
|
/mob/living/heavy_vehicle/GetIdCard()
|
|
return access_card
|
|
|
|
/// Checks if mech can be powered on/off, sends message to pilot if failed
|
|
/// `var/remote` can be set to TRUE to have proc adjust where messages and hud elements are presented
|
|
/// If `remote` is TRUE, messages and other hud elements are called on the exosuit itself to prevent wierdness, and errors are handled in `handle_hear_say()`
|
|
/mob/living/heavy_vehicle/proc/toggle_power(var/mob/user, var/remote = FALSE)
|
|
var/cancelled = FALSE
|
|
var/delay = 0
|
|
SEND_SIGNAL(user, COMSIG_MECH_TOGGLE_POWER, &cancelled, &delay)
|
|
if (cancelled || delay && !do_after(user, delay))
|
|
to_chat(user, SPAN_WARNING("There's just too many buttons! You fail to find the power switch!"))
|
|
return
|
|
|
|
// if remotely called, send these messages to the exosuit, not the person calling this proc
|
|
var/reciever = user
|
|
if(remote)
|
|
reciever = src
|
|
if(power == MECH_POWER_TRANSITION)
|
|
to_chat(reciever, SPAN_NOTICE("Power transition in progress. Please wait."))
|
|
else if(power == MECH_POWER_ON) //Turning it off is instant
|
|
power = MECH_POWER_OFF
|
|
update_emp_protection()
|
|
else if(get_cell(TRUE).check_charge(1000)) //Check if we have enough charge to power on
|
|
//Start power up sequence
|
|
power = MECH_POWER_TRANSITION
|
|
playsound(src, 'sound/mecha/powerup.ogg', 50, 0)
|
|
if(do_after(reciever, 1.5 SECONDS) && power == MECH_POWER_TRANSITION)
|
|
power = MECH_POWER_ON
|
|
update_emp_protection()
|
|
sound_looping = TRUE
|
|
soundloop.start()
|
|
else
|
|
to_chat(reciever, SPAN_WARNING("You abort the powerup sequence."))
|
|
power = MECH_POWER_OFF
|
|
update_emp_protection()
|
|
if(hud_power_control)
|
|
SSicon_update.add_to_queue(hud_power_control)
|
|
else
|
|
to_chat(reciever, SPAN_WARNING("Error: No power cell was detected."))
|
|
|
|
/obj/item/radio/exosuit
|
|
name = "exosuit radio"
|
|
cell = null
|
|
|
|
/obj/item/radio/exosuit/get_cell()
|
|
. = ..()
|
|
if(!.)
|
|
var/mob/living/heavy_vehicle/E = loc
|
|
if(istype(E))
|
|
return E.get_cell()
|
|
|
|
/obj/item/radio/exosuit/ui_host()
|
|
var/mob/living/heavy_vehicle/E = loc
|
|
if(istype(E))
|
|
return E
|
|
return null
|
|
|
|
/obj/item/radio/exosuit/attack_self(var/mob/user)
|
|
var/mob/living/heavy_vehicle/exosuit = loc
|
|
if(istype(exosuit) && exosuit.head && exosuit.head.radio && exosuit.head.radio.is_functional())
|
|
user.set_machine(src)
|
|
interact(user)
|
|
else
|
|
to_chat(user, SPAN_WARNING("The radio is too damaged to function."))
|
|
|
|
/obj/item/radio/exosuit/CanUseTopic()
|
|
. = ..()
|
|
if(.)
|
|
var/mob/living/heavy_vehicle/exosuit = loc
|
|
if(istype(exosuit) && exosuit.head && exosuit.head.radio && exosuit.head.radio.is_functional())
|
|
return ..()
|
|
|
|
/mob/living/heavy_vehicle/proc/become_remote()
|
|
for(var/mob/user in pilots)
|
|
eject(user, FALSE)
|
|
|
|
remote = TRUE
|
|
name = name + " \"[pick("Jaeger", "Reaver", "Templar", "Juggernaut", "Basilisk")]-[rand(0, 999)]\""
|
|
if(camera)
|
|
camera.c_tag = name
|
|
invalidateCameraCache()
|
|
if(!remote_network)
|
|
remote_network = REMOTE_GENERIC_MECH
|
|
SSvirtualreality.add_mech(src, remote_network)
|
|
|
|
if(hatch_closed)
|
|
hatch_closed = FALSE
|
|
|
|
dummy = new dummy_type(get_turf(src))
|
|
dummy.real_name = "Remote-Bot"
|
|
dummy.name = dummy.real_name
|
|
// Give dummy a blank encryption key for later editing if spiderbot
|
|
if(istype(dummy, /mob/living/simple_animal/spiderbot) && !istype(dummy, /mob/living/simple_animal/spiderbot/ai))
|
|
dummy.radio.keyslot = new /obj/item/encryptionkey
|
|
remove_verb(dummy, /mob/living/proc/ventcrawl)
|
|
remove_verb(dummy, /mob/living/proc/hide)
|
|
if(dummy_colour)
|
|
dummy.color = dummy_colour
|
|
enter(dummy, TRUE)
|
|
|
|
if(!hatch_closed)
|
|
hatch_closed = TRUE
|
|
hatch_locked = TRUE
|
|
if(does_hardpoint_lock)
|
|
hardpoints_locked = TRUE
|
|
force_locked = TRUE
|
|
update_icon()
|
|
|
|
/mob/living/heavy_vehicle/is_anti_materiel_vulnerable()
|
|
return TRUE
|