mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-30 16:47:13 +01:00
[READY] Re-works the Durand ability (#45144)
* Woo shields * reshuffle, adding a sound * Re-organizing * better defines for the signals I had * new stuff * fixes * Replaced all instances of "defence" with defense" and other small changes. * oof * spelling, and a forgotten check * you, upgraded, improved, yes
This commit is contained in:
@@ -253,6 +253,10 @@
|
||||
// /obj/item/projectile signals (sent to the firer)
|
||||
#define COMSIG_PROJECTILE_ON_HIT "projectile_on_hit" // from base of /obj/item/projectile/proc/on_hit(): (atom/movable/firer, atom/target, Angle)
|
||||
#define COMSIG_PROJECTILE_BEFORE_FIRE "projectile_before_fire" // from base of /obj/item/projectile/proc/fire(): (obj/item/projectile, atom/original_target)
|
||||
#define COMSIG_PROJECTILE_PREHIT "com_proj_prehit" // sent to targets during the process_hit proc of projectiles
|
||||
|
||||
// /obj/mecha signals
|
||||
#define COMSIG_MECHA_ACTION_ACTIVATE "mecha_action_activate" //sent from mecha action buttons to the mecha they're linked to
|
||||
|
||||
// /mob/living/carbon/human signals
|
||||
#define COMSIG_HUMAN_MELEE_UNARMED_ATTACK "human_melee_unarmed_attack" //from mob/living/carbon/human/UnarmedAttack(): (atom/target)
|
||||
|
||||
@@ -11,6 +11,20 @@
|
||||
infra_luminosity = 8
|
||||
force = 40
|
||||
wreckage = /obj/structure/mecha_wreckage/durand
|
||||
var/obj/durand_shield/shield
|
||||
|
||||
/obj/mecha/combat/durand/Initialize()
|
||||
shield = new/obj/durand_shield
|
||||
shield.chassis = src
|
||||
shield.layer = layer
|
||||
RegisterSignal(src, COMSIG_MECHA_ACTION_ACTIVATE, .proc/relay)
|
||||
RegisterSignal(src, COMSIG_PROJECTILE_PREHIT, .proc/prehit)
|
||||
. = ..()
|
||||
|
||||
/obj/mecha/combat/durand/Destroy()
|
||||
if(shield)
|
||||
qdel(shield)
|
||||
. = ..()
|
||||
|
||||
/obj/mecha/combat/durand/GrantActions(mob/living/user, human_occupant = 0)
|
||||
..()
|
||||
@@ -20,3 +34,176 @@
|
||||
..()
|
||||
defense_action.Remove(user)
|
||||
|
||||
/obj/mecha/combat/durand/process()
|
||||
. = ..()
|
||||
if(defense_mode && !use_power(100))
|
||||
defense_action.Activate(forced_state = TRUE)
|
||||
|
||||
/obj/mecha/combat/durand/domove(direction)
|
||||
. = ..()
|
||||
if(shield)
|
||||
shield.forceMove(loc)
|
||||
shield.dir = dir
|
||||
|
||||
/obj/mecha/combat/durand/forceMove(var/turf/T)
|
||||
. = ..()
|
||||
shield.forceMove(T)
|
||||
|
||||
/obj/mecha/combat/durand/go_out(forced, atom/newloc = loc)
|
||||
if(defense_mode)
|
||||
defense_action.Activate(forced_state = TRUE)
|
||||
. = ..()
|
||||
|
||||
///Relays the signal from the action button to the shield, and creates a new shield if the old one is MIA.
|
||||
/obj/mecha/combat/durand/proc/relay(datum/source, list/signal_args)
|
||||
if(!shield) //if the shield somehow got deleted
|
||||
shield = new/obj/durand_shield
|
||||
shield.chassis = src
|
||||
shield.layer = layer
|
||||
shield.forceMove(loc)
|
||||
shield.dir = dir
|
||||
SEND_SIGNAL(shield, COMSIG_MECHA_ACTION_ACTIVATE, source, signal_args)
|
||||
|
||||
//Redirects projectiles to the shield if defense_check decides they should be blocked and returns true.
|
||||
/obj/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/mecha/combat/durand/proc/defense_check(var/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/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/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/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/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
|
||||
var/obj/mecha/combat/durand/chassis ///Our link back to the durand
|
||||
var/switching = FALSE ///To keep track of things during the animation
|
||||
|
||||
/obj/durand_shield/Initialize()
|
||||
. = ..()
|
||||
RegisterSignal(src, COMSIG_MECHA_ACTION_ACTIVATE, .proc/activate)
|
||||
|
||||
/obj/durand_shield/Destroy()
|
||||
if(chassis)
|
||||
chassis.shield = null
|
||||
. = ..()
|
||||
|
||||
/**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)*/
|
||||
|
||||
/obj/durand_shield/proc/activate(datum/source, var/datum/action/innate/mecha/mech_defense_mode/button, list/signal_args)
|
||||
if(!chassis || !chassis.occupant)
|
||||
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
|
||||
chassis.occupant_message("<span class='warn'>Insufficient power; cannot activate defense mode.</span>")
|
||||
return
|
||||
switching = TRUE
|
||||
chassis.defense_mode = !chassis.defense_mode
|
||||
chassis.defense_action.button_icon_state = "mech_defense_mode_[chassis.defense_mode ? "on" : "off"]" //This is backwards because we haven't changed the var yet
|
||||
if(!signal_args[1])
|
||||
chassis.occupant_message("<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)
|
||||
chassis.defense_action.UpdateButtonIcon()
|
||||
|
||||
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")
|
||||
sleep(3)
|
||||
icon_state = "shield"
|
||||
else
|
||||
flick("shield_drop", src)
|
||||
playsound(src, 'sound/mecha/mech_shield_drop.ogg', 50, FALSE)
|
||||
sleep(5)
|
||||
set_light(0)
|
||||
icon_state = "shield_null"
|
||||
invisibility = INVISIBILITY_MAXIMUM //no showing on right-click
|
||||
switching = FALSE
|
||||
|
||||
/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
|
||||
chassis.defense_action.Activate(forced_state = TRUE)
|
||||
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()
|
||||
. = ..()
|
||||
@@ -98,7 +98,7 @@
|
||||
var/datum/action/innate/mecha/mech_toggle_lights/lights_action = new
|
||||
var/datum/action/innate/mecha/mech_view_stats/stats_action = new
|
||||
var/datum/action/innate/mecha/mech_toggle_thrusters/thrusters_action = new
|
||||
var/datum/action/innate/mecha/mech_defence_mode/defense_action = new
|
||||
var/datum/action/innate/mecha/mech_defense_mode/defense_action = new
|
||||
var/datum/action/innate/mecha/mech_overload_mode/overload_action = new
|
||||
var/datum/effect_system/smoke_spread/smoke_system = new //not an action, but trigged by one
|
||||
var/datum/action/innate/mecha/mech_smoke/smoke_action = new
|
||||
@@ -109,8 +109,7 @@
|
||||
|
||||
//Action vars
|
||||
var/thrusters_active = FALSE
|
||||
var/defence_mode = FALSE
|
||||
var/defence_mode_deflect_chance = 35
|
||||
var/defense_mode = FALSE
|
||||
var/leg_overload_mode = FALSE
|
||||
var/leg_overload_coeff = 100
|
||||
var/zoom_mode = FALSE
|
||||
@@ -577,11 +576,6 @@
|
||||
return 0
|
||||
if(!has_charge(step_energy_drain))
|
||||
return 0
|
||||
if(defence_mode)
|
||||
if(world.time - last_message > 20)
|
||||
occupant_message("<span class='danger'>Unable to move while in defence mode</span>")
|
||||
last_message = world.time
|
||||
return 0
|
||||
if(zoom_mode)
|
||||
if(world.time - last_message > 20)
|
||||
occupant_message("Unable to move while in zoom mode.")
|
||||
@@ -1100,8 +1094,7 @@ GLOBAL_VAR_INIT(year_integer, text2num(year)) // = 2013???
|
||||
return max(0, cell.charge)
|
||||
|
||||
/obj/mecha/proc/use_power(amount)
|
||||
if(get_charge())
|
||||
cell.use(amount)
|
||||
if(get_charge() && cell.use(amount))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
@@ -164,27 +164,13 @@
|
||||
chassis.log_message("Toggled thrusters.", LOG_MECHA)
|
||||
chassis.occupant_message("<font color='[chassis.thrusters_active ?"blue":"red"]'>Thrusters [chassis.thrusters_active ?"en":"dis"]abled.")
|
||||
|
||||
|
||||
/datum/action/innate/mecha/mech_defence_mode
|
||||
name = "Toggle Defence Mode"
|
||||
/datum/action/innate/mecha/mech_defense_mode
|
||||
name = "Toggle an energy shield that blocks all attacks from the faced direction at a heavy power cost."
|
||||
button_icon_state = "mech_defense_mode_off"
|
||||
var/image/def_overlay
|
||||
|
||||
/datum/action/innate/mecha/mech_defence_mode/Activate(forced_state = null)
|
||||
if(!owner || !chassis || chassis.occupant != owner)
|
||||
return
|
||||
if(!isnull(forced_state))
|
||||
chassis.defence_mode = forced_state
|
||||
else
|
||||
chassis.defence_mode = !chassis.defence_mode
|
||||
button_icon_state = "mech_defense_mode_[chassis.defence_mode ? "on" : "off"]"
|
||||
if(chassis.defence_mode)
|
||||
chassis.deflect_chance = chassis.defence_mode_deflect_chance
|
||||
chassis.occupant_message("<span class='notice'>You enable [chassis] defence mode.</span>")
|
||||
else
|
||||
chassis.deflect_chance = initial(chassis.deflect_chance)
|
||||
chassis.occupant_message("<span class='danger'>You disable [chassis] defence mode.</span>")
|
||||
chassis.log_message("Toggled defence mode.", LOG_MECHA)
|
||||
UpdateButtonIcon()
|
||||
/datum/action/innate/mecha/mech_defense_mode/Activate(forced_state = FALSE)
|
||||
SEND_SIGNAL(chassis, COMSIG_MECHA_ACTION_ACTIVATE, args) ///Signal sent to the mech, to be handed to the shield. See durand.dm for more details
|
||||
|
||||
/datum/action/innate/mecha/mech_overload_mode
|
||||
name = "Toggle leg actuators overload"
|
||||
|
||||
@@ -53,7 +53,6 @@
|
||||
if(.)
|
||||
. *= booster_damage_modifier
|
||||
|
||||
|
||||
/obj/mecha/attack_hand(mob/living/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
@@ -67,7 +66,6 @@
|
||||
/obj/mecha/attack_paw(mob/user as mob)
|
||||
return attack_hand(user)
|
||||
|
||||
|
||||
/obj/mecha/attack_alien(mob/living/user)
|
||||
log_message("Attack by alien. Attacker - [user].", LOG_MECHA, color="red")
|
||||
playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1)
|
||||
@@ -87,8 +85,8 @@
|
||||
if(user.obj_damage)
|
||||
animal_damage = user.obj_damage
|
||||
animal_damage = min(animal_damage, 20*user.environment_smash)
|
||||
attack_generic(user, animal_damage, user.melee_damage_type, "melee", play_soundeffect)
|
||||
log_combat(user, src, "attacked")
|
||||
attack_generic(user, animal_damage, user.melee_damage_type, "melee", play_soundeffect)
|
||||
return 1
|
||||
|
||||
|
||||
@@ -102,6 +100,7 @@
|
||||
log_combat(user, src, "punched", "hulk powers")
|
||||
|
||||
/obj/mecha/blob_act(obj/structure/blob/B)
|
||||
log_message("Attack by blob. Attacker - [B].", LOG_MECHA, color="red")
|
||||
take_damage(30, BRUTE, "melee", 0, get_dir(src, B))
|
||||
|
||||
/obj/mecha/attack_tk()
|
||||
@@ -111,7 +110,6 @@
|
||||
log_message("Hit by [AM].", LOG_MECHA, color="red")
|
||||
. = ..()
|
||||
|
||||
|
||||
/obj/mecha/bullet_act(obj/item/projectile/Proj) //wrapper
|
||||
if (!enclosed && occupant && !silicon_pilot && !Proj.force_hit && (Proj.def_zone == BODY_ZONE_HEAD || Proj.def_zone == BODY_ZONE_CHEST)) //allows bullets to hit the pilot of open-canopy mechs
|
||||
occupant.bullet_act(Proj) //If the sides are open, the occupant can be hit
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
<b>Cabin temperature: </b> [internal_tank?"[return_temperature()]°K|[return_temperature() - T0C]°C":"N/A"]<br>
|
||||
[dna_lock?"<b>DNA-locked:</b><br> <span style='font-size:10px;letter-spacing:-1px;'>[dna_lock]</span> \[<a href='?src=[REF(src)];reset_dna=1'>Reset</a>\]<br>":""]<br>
|
||||
[thrusters_action.owner ? "<b>Thrusters: </b> [thrusters_active ? "Enabled" : "Disabled"]<br>" : ""]
|
||||
[defense_action.owner ? "<b>Defence Mode: </b> [defence_mode ? "Enabled" : "Disabled"]<br>" : ""]
|
||||
[defense_action.owner ? "<b>Defense Mode: </b> [defense_mode ? "Enabled" : "Disabled"]<br>" : ""]
|
||||
[overload_action.owner ? "<b>Leg Actuators Overload: </b> [leg_overload_mode ? "Enabled" : "Disabled"]<br>" : ""]
|
||||
[smoke_action.owner ? "<b>Smoke: </b> [smoke]<br>" : ""]
|
||||
[zoom_action.owner ? "<b>Zoom: </b> [zoom_mode ? "Enabled" : "Disabled"]<br>" : ""]
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
//Vars that control when the pilot uses their mecha's abilities (if the mecha has that ability)
|
||||
var/threat_use_mecha_smoke = 5 //5 mobs is enough to engage crowd control
|
||||
var/defence_mode_chance = 35 //Chance to engage Defence mode when damaged
|
||||
var/defense_mode_chance = 35 //Chance to engage Defense mode when damaged
|
||||
var/smoke_chance = 20 //Chance to deploy smoke for crowd control
|
||||
var/retreat_chance = 40 //Chance to run away
|
||||
|
||||
@@ -226,19 +226,19 @@
|
||||
if(mecha.smoke_action && mecha.smoke_action.owner && mecha.smoke)
|
||||
mecha.smoke_action.Activate()
|
||||
|
||||
//Heavy damage - Defence Power or Retreat
|
||||
//Heavy damage - Defense Power or Retreat
|
||||
if(mecha.obj_integrity < mecha.max_integrity*0.25)
|
||||
if(prob(defence_mode_chance))
|
||||
if(mecha.defense_action && mecha.defense_action.owner && !mecha.defence_mode)
|
||||
if(prob(defense_mode_chance))
|
||||
if(mecha.defense_action && mecha.defense_action.owner && !mecha.defense_mode)
|
||||
mecha.leg_overload_mode = 0
|
||||
mecha.defense_action.Activate(TRUE)
|
||||
addtimer(CALLBACK(mecha.defense_action, /datum/action/innate/mecha/mech_defence_mode.proc/Activate, FALSE), 100) //10 seconds of defence, then toggle off
|
||||
addtimer(CALLBACK(mecha.defense_action, /datum/action/innate/mecha/mech_defense_mode.proc/Activate, FALSE), 100) //10 seconds of defense, then toggle off
|
||||
|
||||
else if(prob(retreat_chance))
|
||||
//Speed boost if possible
|
||||
if(mecha.overload_action && mecha.overload_action.owner && !mecha.leg_overload_mode)
|
||||
mecha.overload_action.Activate(TRUE)
|
||||
addtimer(CALLBACK(mecha.overload_action, /datum/action/innate/mecha/mech_defence_mode.proc/Activate, FALSE), 100) //10 seconds of speeeeed, then toggle off
|
||||
addtimer(CALLBACK(mecha.overload_action, /datum/action/innate/mecha/mech_defense_mode.proc/Activate, FALSE), 100) //10 seconds of speeeeed, then toggle off
|
||||
|
||||
retreat_distance = 50
|
||||
spawn(100)
|
||||
|
||||
@@ -257,6 +257,7 @@
|
||||
permutated |= target //Make sure we're never hitting it again. If we ever run into weirdness with piercing projectiles needing to hit something multiple times.. well.. that's a to-do.
|
||||
if(!prehit(target))
|
||||
return process_hit(T, select_target(T), qdel_self, hit_something) //Hit whatever else we can since that didn't work.
|
||||
SEND_SIGNAL(target, COMSIG_PROJECTILE_PREHIT, args)
|
||||
var/result = target.bullet_act(src, def_zone)
|
||||
if(result == BULLET_ACT_FORCE_PIERCE)
|
||||
if(!CHECK_BITFIELD(movement_type, UNSTOPPABLE))
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 9.1 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user