[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:
zxaber
2019-07-27 02:06:33 -07:00
committed by Rob Bailey
parent 7704552a41
commit aaaee29a63
12 changed files with 209 additions and 40 deletions
+4
View File
@@ -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)
+187
View File
@@ -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()
. = ..()
+3 -10
View File
@@ -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
+5 -19
View File
@@ -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"
+2 -4
View File
@@ -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
+1 -1
View File
@@ -91,7 +91,7 @@
<b>Cabin temperature: </b> [internal_tank?"[return_temperature()]&deg;K|[return_temperature() - T0C]&deg;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)
+1
View File
@@ -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.