Files
evilew 10ef9e374a Nanotrasen to GATO - comments
I know it's a mess, but the least I can do is add comments anywhere I can
2024-11-19 01:59:28 +01:00

242 lines
9.1 KiB
Plaintext

/obj/vehicle/sealed/mecha/combat/durand
desc = "An aging combat exosuit utilized by the GATO corporation. Originally developed to combat hostile alien lifeforms." //GS13 - Nanotrasen to GATO
name = "\improper Durand"
icon_state = "durand"
movedelay = 4
dir_in = 1 //Facing North.
max_integrity = 400
deflect_chance = 20
armor = list(MELEE = 40, BULLET = 35, LASER = 15, ENERGY = 10, BOMB = 20, BIO = 0, RAD = 50, FIRE = 100, ACID = 100)
max_temperature = 30000
force = 40
wreckage = /obj/structure/mecha_wreckage/durand
var/obj/durand_shield/shield
/obj/vehicle/sealed/mecha/combat/durand/Initialize(mapload)
. = ..()
shield = new /obj/durand_shield(loc, src, layer, dir)
RegisterSignal(src, COMSIG_MECHA_ACTION_TRIGGER, PROC_REF(relay))
RegisterSignal(src, COMSIG_PROJECTILE_PREHIT, PROC_REF(prehit))
/obj/vehicle/sealed/mecha/combat/durand/Destroy()
if(shield)
QDEL_NULL(shield)
return ..()
/obj/vehicle/sealed/mecha/combat/durand/generate_actions()
. = ..()
initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/mech_defense_mode)
/obj/vehicle/sealed/mecha/combat/durand/process()
. = ..()
if(defense_mode && !use_power(100)) //Defence mode can only be on with a occupant so we check if one of them can toggle it and toggle
for(var/O in occupants)
var/mob/living/occupant = O
var/datum/action/action = LAZYACCESSASSOC(occupant_actions, occupant, /datum/action/vehicle/sealed/mecha/mech_defense_mode)
if(action)
INVOKE_ASYNC(action, TYPE_PROC_REF(/datum/action, Trigger))
break
/obj/vehicle/sealed/mecha/combat/durand/Move(direction)
. = ..()
if(shield)
shield.forceMove(loc)
shield.setDir(dir)
/obj/vehicle/sealed/mecha/combat/durand/forceMove(turf/T)
. = ..()
shield.forceMove(T)
/obj/vehicle/sealed/mecha/combat/durand/mob_exit(mob/M, silent, randomstep, forced)
if(defense_mode)
var/datum/action/action = LAZYACCESSASSOC(occupant_actions, M, /datum/action/vehicle/sealed/mecha/mech_defense_mode)
if(action)
INVOKE_ASYNC(action, TYPE_PROC_REF(/datum/action, Trigger), FALSE)
return ..()
///Relays the signal from the action button to the shield, and creates a new shield if the old one is MIA.
/obj/vehicle/sealed/mecha/combat/durand/proc/relay(datum/source, mob/owner, list/signal_args)
SIGNAL_HANDLER
if(!shield) //if the shield somehow got deleted
stack_trace("Durand triggered relay without a shield")
shield = new /obj/durand_shield(loc, src, layer)
shield.setDir(dir)
SEND_SIGNAL(shield, COMSIG_MECHA_ACTION_TRIGGER, owner, signal_args)
//Redirects projectiles to the shield if defense_check decides they should be blocked and returns true.
/obj/vehicle/sealed/mecha/combat/durand/proc/prehit(obj/item/projectile/source, list/signal_args)
if(defense_check(source.loc) && shield)
signal_args[2] = shield
/**Checks if defense mode is enabled, and if the attacker is standing in an area covered by the shield.
Expects a turf. Returns true if the attack should be blocked, false if not.*/
/obj/vehicle/sealed/mecha/combat/durand/proc/defense_check(turf/aloc)
if (!defense_mode || !shield || shield.switching)
return FALSE
. = FALSE
switch(dir)
if (1)
if(abs(x - aloc.x) <= (y - aloc.y) * -2)
. = TRUE
if (2)
if(abs(x - aloc.x) <= (y - aloc.y) * 2)
. = TRUE
if (4)
if(abs(y - aloc.y) <= (x - aloc.x) * -2)
. = TRUE
if (8)
if(abs(y - aloc.y) <= (x - aloc.x) * 2)
. = TRUE
return
/obj/vehicle/sealed/mecha/combat/durand/attack_generic(mob/user, damage_amount = 0, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, armor_penetration = 0)
if(defense_check(user.loc))
log_message("Attack absorbed by defense field. Attacker - [user].", LOG_MECHA, color="orange")
shield.attack_generic(user, damage_amount, damage_type, damage_flag, sound_effect, armor_penetration)
else
. = ..()
/obj/vehicle/sealed/mecha/combat/durand/blob_act(obj/structure/blob/B)
if(defense_check(B.loc))
log_message("Attack by blob. Attacker - [B].", LOG_MECHA, color="red")
log_message("Attack absorbed by defense field.", LOG_MECHA, color="orange")
shield.blob_act(B)
else
. = ..()
/obj/vehicle/sealed/mecha/combat/durand/attackby(obj/item/W as obj, mob/user as mob, params)
if(defense_check(user.loc))
log_message("Attack absorbed by defense field. Attacker - [user], with [W]", LOG_MECHA, color="orange")
shield.attackby(W, user, params)
else
. = ..()
/obj/vehicle/sealed/mecha/combat/durand/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
if(defense_check(AM.loc))
log_message("Impact with [AM] absorbed by defense field.", LOG_MECHA, color="orange")
shield.hitby(AM, skipcatch, hitpush, blocked, throwingdatum)
else
. = ..()
////////////////////////////
///// Shield processing ////
////////////////////////////
/**An object to take the hit for us when using the Durand's defense mode.
It is spawned in during the durand's initilization, and always stays on the same tile.
Normally invisible, until defense mode is actvated. When the durand detects an attack that should be blocked, the
attack is passed to the shield. The shield takes the damage, uses it to calculate charge cost, and then sets its
own integrity back to max. Shield is automatically dropped if we run out of power or the user gets out.*/
/obj/durand_shield //projectiles get passed to this when defense mode is enabled
name = "defense grid"
icon = 'icons/mecha/durand_shield.dmi'
icon_state = "shield_null"
invisibility = INVISIBILITY_MAXIMUM //no showing on right-click
pixel_y = 4
max_integrity = 10000
obj_integrity = 10000
anchored = TRUE
light_range = MINIMUM_USEFUL_LIGHT_RANGE
light_power = 5
light_color = COLOR_CYAN
///Our link back to the durand
var/obj/vehicle/sealed/mecha/combat/durand/chassis
///To keep track of things during the animation
var/switching = FALSE
var/currentuser
/obj/durand_shield/Initialize(mapload, _chassis, _layer, _dir)
. = ..()
chassis = _chassis
layer = _layer
setDir(_dir)
RegisterSignal(src, COMSIG_MECHA_ACTION_TRIGGER, PROC_REF(activate))
/obj/durand_shield/Destroy()
if(chassis)
chassis.shield = null
chassis = null
return ..()
/**
*Handles activating and deactivating the shield. This proc is called by a signal sent from the mech's action button
*and relayed by the mech itself. The "forced" variabe, signal_args[1], will skip the to-pilot text and is meant for when
*the shield is disabled by means other than the action button (like running out of power)
* Arguments:
* * source: the shield
* * owner: mob that activated the shield
* * signal_args: whether it's forced
*/
/obj/durand_shield/proc/activate(datum/source, mob/owner, list/signal_args)
SIGNAL_HANDLER
currentuser = owner
if(!LAZYLEN(chassis?.occupants))
return
if(switching && !signal_args[1])
return
if(!chassis.defense_mode && (!chassis.cell || chassis.cell.charge < 100)) //If it's off, and we have less than 100 units of power
to_chat(currentuser, "[icon2html(src, currentuser)]<span class='warn'>Insufficient power; cannot activate defense mode.</span>")
return
switching = TRUE
chassis.defense_mode = !chassis.defense_mode
if(!signal_args[1])
to_chat(currentuser, "[icon2html(src, currentuser)]<span class='notice'>Defense mode [chassis.defense_mode?"enabled":"disabled"].</span>")
chassis.log_message("User has toggled defense mode -- now [chassis.defense_mode?"enabled":"disabled"].", LOG_MECHA)
else
chassis.log_message("defense mode state changed -- now [chassis.defense_mode?"enabled":"disabled"].", LOG_MECHA)
for(var/occupant in chassis.occupants)
var/datum/action/button = chassis.occupant_actions[occupant][/datum/action/vehicle/sealed/mecha/mech_defense_mode]
button.button_icon_state = "mech_defense_mode_[chassis.defense_mode ? "on" : "off"]"
button.UpdateButtons()
set_light(light_range, light_power, light_color)
if(chassis.defense_mode)
invisibility = 0
flick("shield_raise", src)
playsound(src, 'sound/mecha/mech_shield_raise.ogg', 50, FALSE)
set_light(l_range = MINIMUM_USEFUL_LIGHT_RANGE , l_power = 5, l_color = "#00FFFF")
icon_state = "shield"
RegisterSignal(chassis, COMSIG_ATOM_DIR_CHANGE, PROC_REF(resetdir))
else
flick("shield_drop", src)
playsound(src, 'sound/mecha/mech_shield_drop.ogg', 50, FALSE)
set_light(0)
icon_state = "shield_null"
invisibility = INVISIBILITY_MAXIMUM //no showing on right-click
UnregisterSignal(chassis, COMSIG_ATOM_DIR_CHANGE)
switching = FALSE
/obj/durand_shield/proc/resetdir(datum/source, olddir, newdir)
setDir(newdir)
/obj/durand_shield/take_damage()
if(!chassis)
qdel(src)
return
if(!chassis.defense_mode) //if defense mode is disabled, we're taking damage that we shouldn't be taking
return
. = ..()
flick("shield_impact", src)
if(!chassis.use_power((max_integrity - obj_integrity) * 100))
chassis.cell?.charge = 0
for(var/O in chassis.occupants)
var/mob/living/occupant = O
var/datum/action/action = LAZYACCESSASSOC(chassis.occupant_actions, occupant, /datum/action/vehicle/sealed/mecha/mech_defense_mode)
action.Trigger(FALSE)
obj_integrity = 10000
/obj/durand_shield/play_attack_sound()
playsound(src, 'sound/mecha/mech_shield_deflect.ogg', 100, TRUE)
/obj/durand_shield/bullet_act()
play_attack_sound()
. = ..()