Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inteq Gygax and Durand Paladin shield backlash. Fixes Durand shield blocking bullets from any direction. #3382

Merged
merged 20 commits into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 69 additions & 18 deletions code/game/mecha/combat/durand.dm
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,24 @@
force = 40
wreckage = /obj/structure/mecha_wreckage/durand
var/obj/durand_shield/shield
var/shield_type = /obj/durand_shield
var/shield_passive_drain = 300



/obj/mecha/combat/durand/clip
desc = "An aging combat exosuit appropriated from abandoned Nanotrasen facilities, now supplied to the CMM-BARD anti-xenofauna division."
desc = "An aging combat exosuit appropriated from abandoned Nanotrasen facilities, now supplied to the CMM-BARD anti-xenofauna division. The defence grid has been modified to disperse controlled electric shocks on contact, at the cost of it's ability to block ranged projectiles."
Gristlebee marked this conversation as resolved.
Show resolved Hide resolved
name = "\improper Paladin"
icon_state = "clipdurand"
wreckage = /obj/structure/mecha_wreckage/durand/clip
armor = list("melee" = 40, "bullet" = 35, "laser" = 15, "energy" = 10, "bomb" = 20, "bio" = 0, "rad" = 50, "fire" = 100, "acid" = 100)

//TODO: Custom melee backlash shield with no projectile protection
shield_passive_drain = 0
shield_type = /obj/durand_shield/clip

/obj/mecha/combat/durand/Initialize()
. = ..()
shield = new /obj/durand_shield(loc, src, layer, dir)
shield = new shield_type(loc, src, layer, dir)
RegisterSignal(src, COMSIG_MECHA_ACTION_ACTIVATE, PROC_REF(relay))
RegisterSignal(src, COMSIG_PROJECTILE_PREHIT, PROC_REF(prehit))


/obj/mecha/combat/durand/Destroy()
Expand Down Expand Up @@ -71,22 +72,21 @@

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 = new shield_type(loc, src, layer)
shield.setDir(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/projectile/source, list/signal_args)
SIGNAL_HANDLER

if(defense_check(source.loc) && shield)
signal_args[2] = shield

/obj/mecha/combat/durand/bullet_act(obj/projectile/source)
if(defense_check(source.loc, shield.ranged_pass))
shield.bullet_act(source)
else
. = ..()

/**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(turf/aloc)
if (!defense_mode || !shield || shield.switching)
Expects a turf. Returns true if the attack should be blocked, false if not. Skip defence will make the proc return false and the attack will go through*/
/obj/mecha/combat/durand/proc/defense_check(turf/aloc, skip_defence = FALSE)
if (!defense_mode || !shield || shield.switching || skip_defence)
return FALSE
. = FALSE
switch(dir)
Expand All @@ -105,26 +105,38 @@ Expects a turf. Returns true if the attack should be blocked, false if not.*/
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))
if(defense_check(user.loc, shield.melee_pass))
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/attackby(obj/item/W as obj, mob/user as mob, params)
if(defense_check(user.loc))
if(defense_check(user.loc, shield.melee_pass))
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))
if(defense_check(AM.loc, shield.ranged_pass))
log_message("Impact with [AM] absorbed by defense field.", LOG_MECHA, color="orange")
shield.hitby(AM, skipcatch, hitpush, blocked, throwingdatum)
else
. = ..()

// Walking into the Paladin's shield shocks you.

/obj/mecha/combat/durand/clip/Bump(atom/obstacle)
. = ..()
if(defense_check(obstacle.loc) && isliving(obstacle))
shield.contact(obstacle)

/obj/mecha/combat/durand/clip/Bumped(atom/movable/AM)
. = ..()
if(defense_check(AM.loc) && isliving(AM))
shield.contact(AM)

////////////////////////////
///// Shield processing ////
////////////////////////////
Expand All @@ -151,7 +163,14 @@ own integrity back to max. Shield is automatically dropped if we run out of powe
light_on = FALSE
var/obj/mecha/combat/durand/chassis ///Our link back to the durand
var/switching = FALSE ///To keep track of things during the animation
/// if this shield lets melee attacks pass and hit the mech directly
var/melee_pass = FALSE
/// if this shield lets projectiles pass and hit the mech directly
var/ranged_pass = FALSE

/obj/durand_shield/clip
name = "electric repulsion grid"
ranged_pass = TRUE

/obj/durand_shield/Initialize(mapload, _chassis, _layer, _dir)
. = ..()
Expand Down Expand Up @@ -230,3 +249,35 @@ the shield is disabled by means other than the action button (like running out o
/obj/durand_shield/bullet_act()
play_attack_sound()
. = ..()

/// a mob has bumped into the shield
/obj/durand_shield/proc/contact(mob/living/contactor)
return

/// Clippy shield
/obj/durand_shield/clip/attack_generic(mob/user, damage_amount, damage_type, damage_flag, sound_effect, armor_penetration)
. = ..()
apply_shock(user)

/obj/durand_shield/clip/attackby(obj/item/I, mob/living/user, params)
. = ..()
apply_shock(user)

/obj/durand_shield/clip/contact(mob/living/contactor)
. = ..()
apply_shock(contactor)

/obj/durand_shield/clip/proc/apply_shock(mob/attacker)
var/did_shock = FALSE
if(iscarbon(attacker))
var/mob/living/carbon/victim = attacker
if(electrocute_mob(victim, chassis.cell, src, 1, FALSE, FALSE))
did_shock = TRUE
else if(isliving(attacker))
var/mob/living/victim = attacker
if(victim.apply_damage_type(20,BURN))
to_chat(victim,span_userdanger("You're shocked by \the [src]!"))
did_shock = TRUE
if(did_shock)
visible_message(span_bolddanger("\The [src] repels \the [attacker] on contact, shocking [attacker.p_them()]."))
do_sparks(5,TRUE,src)
16 changes: 16 additions & 0 deletions code/game/mecha/combat/gygax.dm
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@
return
cell = new /obj/item/stock_parts/cell/bluespace(src)

/obj/mecha/combat/gygax/inteq
name = "\improper Pyrnese"
desc = "A lightweight security exosuit, modified to IRMG standards. The leg actuators have been maxed out, allowing for powerful short ranged charges."
icon_state = "inteqgygax"
charge_break_walls = TRUE
charge_toss_structures = TRUE
charge_toss_mobs = TRUE

/obj/mecha/combat/gygax/GrantActions(mob/living/user, human_occupant = 0)
..()
Expand All @@ -67,3 +74,12 @@
/obj/mecha/combat/gygax/RemoveActions(mob/living/user, human_occupant = 0)
..()
overload_action.Remove(user)

/obj/mecha/combat/gygax/inteq/GrantActions(mob/living/user, human_occupant = 0)
..()
overload_action.Remove(user)
charge_action.Grant(user,src)

/obj/mecha/combat/gygax/inteq/RemoveActions(mob/living/user, human_occupant)
. = ..()
charge_action.Remove(user)
7 changes: 7 additions & 0 deletions code/game/mecha/equipment/tools/work_tools.dm
Original file line number Diff line number Diff line change
Expand Up @@ -575,3 +575,10 @@
icon_state = "clipupgrade"
source_mech = list(/obj/mecha/combat/durand)
result_mech = /obj/mecha/combat/durand/clip

/obj/item/mecha_parts/mecha_equipment/conversion_kit/inteq_gygax
name = "IRMG Pyrnese Conversion Kit"
desc = "An IRMG-custom conversion kit for a Gygax combat exosuit, to convert it to the specialized Pyrnese breaching exosuit."
source_mech = list(/obj/mecha/combat/gygax,/obj/mecha/combat/gygax/dark)
result_mech = /obj/mecha/combat/gygax/inteq

60 changes: 60 additions & 0 deletions code/game/mecha/mecha.dm
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@
var/last_user_hud = 1 // used to show/hide the mecha hud while preserving previous preference
var/completely_disabled = FALSE //stops the mech from doing anything

///Vars for mech charges
var/charging = FALSE
var/charge_ready = TRUE
var/charge_cooldown = 50
var/charge_power_consume = 200
var/charge_distance = 5
var/charge_break_walls = FALSE
var/charge_toss_structures = FALSE
var/charge_toss_mobs = FALSE

var/bumpsmash = 0 //Whether or not the mech destroys walls by running into it.
//inner atmos
var/use_internal_tank = 0
Expand Down Expand Up @@ -90,6 +100,7 @@
var/datum/action/innate/mecha/mech_view_stats/stats_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/action/innate/mecha/mech_charge_mode/charge_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
var/datum/action/innate/mecha/mech_zoom/zoom_action = new
Expand Down Expand Up @@ -643,6 +654,7 @@
step_silent = FALSE

/obj/mecha/Bump(atom/obstacle)
var/atom/throw_target = get_edge_target_turf(obstacle, dir)
if(phasing && get_charge() >= phasing_energy_drain && !throwing)
if(!can_move)
return
Expand All @@ -654,6 +666,27 @@
forceMove(get_step(src,dir))
use_power(phasing_energy_drain)
addtimer(VARSET_CALLBACK(src, can_move, TRUE), step_in*3)
else if(charging)
if(charge_break_walls && iswallturf(obstacle))
var/turf/closed/wall/crushed = obstacle
playsound(src, 'sound/effects/meteorimpact.ogg', 100, TRUE)
visible_message(span_danger("[src] smashes through [obstacle]"))
crushed.dismantle_wall(TRUE)
if(isobj(obstacle))
var/obj/object = obstacle
obstacle.mech_melee_attack(src)
if(!(object.resistance_flags & INDESTRUCTIBLE) && charge_toss_structures)
object.throw_at(throw_target, 4, 3)
visible_message(span_danger("[src] crashes into [obstacle]!"))
playsound(src, 'sound/effects/bang.ogg', 50, TRUE)
if(ishuman(obstacle))
var/mob/living/carbon/human/H = obstacle
H.throw_at(throw_target,4,3)
visible_message(span_danger("[src] slams into \the [obstacle], sending [obstacle.p_them()] flying!"))
playsound(H, 'sound/effects/bang.ogg', 100, FALSE, -1)
H.Paralyze(20)
H.adjustStaminaLoss(30)
H.apply_damage(rand(20,35), BRUTE)
else
if(..()) //mech was thrown
return
Expand Down Expand Up @@ -1212,3 +1245,30 @@ GLOBAL_VAR_INIT(year_integer, text2num(year)) // = 2013???
else
to_chat(user, "<span class='notice'>None of the equipment on this exosuit can use this ammo!</span>")
return FALSE


///////////////////////
////// Charging /////
///////////////////////

/obj/mecha/proc/start_charge()
Shake(15, 15, 1 SECONDS)
var/obj/effect/temp_visual/decoy/new_decoy = new /obj/effect/temp_visual/decoy(loc,src)
animate(new_decoy, alpha = 0, color = "#5a5858", transform = matrix()*2, time = 2)
addtimer(CALLBACK(src,PROC_REF(handle_charge)),0.5 SECONDS, TIMER_STOPPABLE)

/obj/mecha/proc/handle_charge()
var/turf/mecha_loc = get_turf(src)
charging = TRUE
var/turf/charge_target = get_ranged_target_turf(mecha_loc,dir,charge_distance)
if(!charge_target)
charging = FALSE
return
cell.use(charge_power_consume)
walk_towards(src, charge_target, 0.7)
sleep(get_dist(src, charge_target) * 0.7)
charge_end()

/obj/mecha/proc/charge_end()
walk(src,0)
charging = FALSE
14 changes: 14 additions & 0 deletions code/game/mecha/mecha_actions.dm
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,20 @@
chassis.occupant_message("<span class='notice'>You disable leg actuators overload.</span>")
UpdateButtonIcon()

/datum/action/innate/mecha/mech_charge_mode
name = "Charge"
button_icon_state = "mech_overload_off"

/datum/action/innate/mecha/mech_charge_mode/Activate()
if(!owner || !chassis || chassis.occupant != owner)
return
if(chassis.charge_ready && !chassis.charging)
chassis.start_charge()
chassis.charge_ready = FALSE
addtimer(VARSET_CALLBACK(chassis, charge_ready, TRUE), chassis.charge_cooldown)
else
chassis.occupant_message(span_warning("The leg actuators are still recharging!"))

/datum/action/innate/mecha/mech_smoke
name = "Smoke"
button_icon_state = "mech_smoke"
Expand Down
3 changes: 2 additions & 1 deletion code/modules/power/power.dm
Original file line number Diff line number Diff line change
Expand Up @@ -377,8 +377,9 @@
//source is an object caused electrocuting (airlock, grille, etc)
//siemens_coeff - layman's terms, conductivity
//dist_check - set to only shock mobs within 1 of source (vendors, airlocks, etc.)
//drain_energy - whether the shock will drain power from the mech. Enabled by default.
//No animations will be performed by this proc.
/proc/electrocute_mob(mob/living/carbon/victim, power_source, obj/source, siemens_coeff = 1, dist_check = FALSE)
/proc/electrocute_mob(mob/living/carbon/victim, power_source, obj/source, siemens_coeff = 1, dist_check = FALSE, drain_energy = TRUE)
if(!istype(victim) || ismecha(victim.loc))
return FALSE //feckin mechs are dumb

Expand Down
Binary file added icons/mecha/inteq_gygax.dmi
Binary file not shown.
Binary file modified icons/mecha/mecha.dmi
Binary file not shown.
10 changes: 5 additions & 5 deletions shiptest.dme
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,10 @@
#include "code\__DEFINES\wires.dm"
#include "code\__DEFINES\dcs\flags.dm"
#include "code\__DEFINES\dcs\helpers.dm"
#include "code\__DEFINES\dcs\signals\signals.dm"
#include "code\__DEFINES\dcs\signals\signals_mod.dm"
#include "code\__DEFINES\dcs\signals\signals_storage.dm"
#include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_carbon.dm"
#include "code\__DEFINES\dcs\signals\signals.dm"
#include "code\__DEFINES\dcs\signals\signals_obj\signals_object.dm"
#include "code\__DEFINES\dcs\signals\signals_obj\signals_item\signals_clothing.dm"
#include "code\__DEFINES\dcs\signals\signals_obj\signals_item\signals_food.dm"
Expand Down Expand Up @@ -2811,6 +2811,10 @@
#include "code\modules\mob\living\simple_animal\slime\slime.dm"
#include "code\modules\mob\living\simple_animal\slime\slime_say.dm"
#include "code\modules\mob\living\simple_animal\slime\subtypes.dm"
#include "code\modules\mob_spawner\burrow.dm"
#include "code\modules\mob_spawner\hivebot.dm"
#include "code\modules\mob_spawner\spawner.dm"
#include "code\modules\mob_spawner\spawner_componet.dm"
#include "code\modules\mod\mod_actions.dm"
#include "code\modules\mod\mod_activation.dm"
#include "code\modules\mod\mod_ai.dm"
Expand All @@ -2835,10 +2839,6 @@
#include "code\modules\mod\modules\modules_storage.dm"
#include "code\modules\mod\modules\modules_supply.dm"
#include "code\modules\mod\modules\modules_visor.dm"
#include "code\modules\mob_spawner\burrow.dm"
#include "code\modules\mob_spawner\hivebot.dm"
#include "code\modules\mob_spawner\spawner.dm"
#include "code\modules\mob_spawner\spawner_componet.dm"
#include "code\modules\modular_computers\laptop_vendor.dm"
#include "code\modules\modular_computers\computers\_modular_computer_shared.dm"
#include "code\modules\modular_computers\computers\item\computer.dm"
Expand Down
Loading