From 7d53d6e162556ac455df4cbe72ced3861a9a036b Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Mon, 27 Jan 2020 20:24:02 -0700
Subject: [PATCH] s
---
code/__DEFINES/flags.dm | 11 ++--
code/__DEFINES/status_effects.dm | 4 +-
code/datums/status_effects/debuffs.dm | 40 +++++++++++----
.../projectiles/ammunition/energy/stun.dm | 2 +-
code/modules/projectiles/guns/energy.dm | 50 +++++++++++++++++--
code/modules/projectiles/guns/energy/stun.dm | 17 ++++++-
.../projectiles/projectile/energy/stun.dm | 12 ++++-
7 files changed, 111 insertions(+), 25 deletions(-)
diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm
index a7d2670747..317066f673 100644
--- a/code/__DEFINES/flags.dm
+++ b/code/__DEFINES/flags.dm
@@ -56,11 +56,12 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
//Movement Types
-#define GROUND (1<<0)
-#define FLYING (1<<1)
-#define VENTCRAWLING (1<<2)
-#define FLOATING (1<<3)
-#define UNSTOPPABLE (1<<4) //When moving, will Bump()/Cross()/Uncross() everything, but won't be stopped.
+#define GROUND (1<<0)
+#define FLYING (1<<1)
+#define VENTCRAWLING (1<<2)
+#define FLOATING (1<<3)
+#define UNSTOPPABLE (1<<4) //When moving, will Bump()/Cross()/Uncross() everything, but won't be stopped.
+#define CRAWLING (1<<5) //Applied if you're crawling around on the ground/resting.
//Fire and Acid stuff, for resistance_flags
#define LAVA_PROOF (1<<0)
diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm
index 6d52f4640c..f42948f4ae 100644
--- a/code/__DEFINES/status_effects.dm
+++ b/code/__DEFINES/status_effects.dm
@@ -46,7 +46,9 @@
#define STATUS_EFFECT_SLEEPING /datum/status_effect/incapacitating/sleeping //the affected is asleep
-#define STATUS_EFFECT_TASED /datum/status_effect/no_combat_mode/electrode/ //the affected has been tased, preventing fine muscle control
+#define STATUS_EFFECT_TASED_WEAK /datum/status_effect/electrode //not as crippling, just slows down
+
+#define STATUS_EFFECT_TASED /datum/status_effect/electrode/no_combat_mode //the affected has been tased, preventing fine muscle control
#define STATUS_EFFECT_PACIFY /datum/status_effect/pacify //the affected is pacified, preventing direct hostile actions
diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm
index 2e46046a7e..56fbc1659e 100644
--- a/code/datums/status_effects/debuffs.dm
+++ b/code/datums/status_effects/debuffs.dm
@@ -33,7 +33,6 @@
if(owner.getStaminaLoss())
owner.adjustStaminaLoss(-0.3) //reduce stamina loss by 0.3 per tick, 6 per 2 seconds
-
//UNCONSCIOUS
/datum/status_effect/incapacitating/unconscious
id = "unconscious"
@@ -113,10 +112,16 @@
icon = 'icons/mob/actions/bloodsucker.dmi'
icon_state = "power_mez"
-/datum/status_effect/no_combat_mode/electrode
+/datum/status_effect/electrode
id = "tased"
+ var/slowdown = 1.5
+ var/slowdown_priority = 50 //to make sure the stronger effect overrides
+ var/affect_crawl = FALSE
+ var/nextmove_modifier = 1
+ var/stamdmg_per_ds = 1 //a 20 duration would do 20 stamdmg, disablers do 24 or something
+ var/last_tick = 0 //fastprocess processing speed is a goddamn sham, don't trust it.
-/datum/status_effect/no_combat_mode/electrode/on_creation(mob/living/new_owner, set_duration)
+/datum/status_effect/electrode/on_creation(mob/living/new_owner, set_duration)
if(isnum(set_duration)) //TODO, figure out how to grab from subtype
duration = set_duration
. = ..()
@@ -124,20 +129,35 @@
var/mob/living/carbon/C = owner
if(C.combatmode)
C.toggle_combat_mode(TRUE)
- C.add_movespeed_modifier(MOVESPEED_ID_TASED_STATUS, TRUE, override = TRUE, multiplicative_slowdown = 8)
+ C.add_movespeed_modifier("[MOVESPEED_ID_TASED_STATUS]_[id]", TRUE, priority = slowdown_priority, override = TRUE, multiplicative_slowdown = slowdown, blacklisted_movetypes = affected_crawl? NONE : CRAWLING)
-/datum/status_effect/no_combat_mode/electrode/on_remove()
+/datum/status_effect/electrode/on_remove()
if(iscarbon(owner))
var/mob/living/carbon/C = owner
- C.remove_movespeed_modifier(MOVESPEED_ID_TASED_STATUS)
+ C.remove_movespeed_modifier("[MOVESPEED_ID_TASED_STATUS]_[id]")
. = ..()
-/datum/status_effect/no_combat_mode/electrode/tick()
+/datum/status_effect/electrode/tick()
+ var/diff = world.time - last_tick
if(owner)
- owner.adjustStaminaLoss(5) //if you really want to try to stamcrit someone with a taser alone, you can, but it'll take time and good timing.
+ owner.adjustStaminaLoss(max(0, stamdmg_per_ds * diff)) //if you really want to try to stamcrit someone with a taser alone, you can, but it'll take time and good timing.
+ last_tick = world.time
-/datum/status_effect/no_combat_mode/electrode/nextmove_modifier() //why is this a proc. its no big deal since this doesnt get called often at all but literally w h y
- return 2
+/datum/status_effect/electrode/no_combat_mode
+ id = "tased_strong"
+ slowdown = 8
+ slowdown_priority = 100
+ nextmove_modifier = 2
+
+/datum/status_effect/electrode/no_combat_mode/on_creation(mob/living/new_owner, set_duration)
+ . = ..()
+ if(iscarbon(owner))
+ var/mob/living/carbon/C = owner
+ if(C.combatmode)
+ C.toggle_combat_mode(TRUE)
+
+/datum/status_effect/electrode/no_combat_mode/nextmove_modifier() //why is this a proc. its no big deal since this doesnt get called often at all but literally w h y
+ return nextmove_modifier
//OTHER DEBUFFS
/datum/status_effect/his_wrath //does minor damage over time unless holding His Grace
diff --git a/code/modules/projectiles/ammunition/energy/stun.dm b/code/modules/projectiles/ammunition/energy/stun.dm
index 7c2b62c02c..f81064220f 100644
--- a/code/modules/projectiles/ammunition/energy/stun.dm
+++ b/code/modules/projectiles/ammunition/energy/stun.dm
@@ -27,4 +27,4 @@
click_cooldown_override = 3.5
/obj/item/ammo_casing/energy/disabler/secborg
- e_cost = 50
\ No newline at end of file
+ e_cost = 50
diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm
index b56664fe03..d612383a95 100644
--- a/code/modules/projectiles/guns/energy.dm
+++ b/code/modules/projectiles/guns/energy.dm
@@ -20,7 +20,8 @@
var/obj/item/stock_parts/cell/cell //What type of power cell this uses
var/cell_type = /obj/item/stock_parts/cell
var/modifystate = 0
- var/list/ammo_type = list(/obj/item/ammo_casing/energy)
+ /// = TRUE/FALSE decides if the user can switch to it of their own accord
+ var/list/ammo_type = list(/obj/item/ammo_casing/energy = TRUE)
/// The index of the ammo_types/firemodes which we're using right now
var/current_firemode_index = 1
var/can_charge = 1 //Can it be charged in a recharger?
@@ -35,6 +36,9 @@
var/use_cyborg_cell = FALSE //whether the gun drains the cyborg user's cell instead, not to be confused with EGUN_SELFCHARGE_BORG
var/dead_cell = FALSE //set to true so the gun is given an empty cell
+ /// SET THIS TO TRUE IF YOU OVERRIDE altafterattack() or ANY right click action! If this is FALSE, the gun will show in examine its default right click behavior, which is to switch modes.
+ var/right_click_overridden = FALSE
+
/obj/item/gun/energy/emp_act(severity)
. = ..()
if(!(. & EMP_PROTECT_CONTENTS))
@@ -65,6 +69,11 @@
STOP_PROCESSING(SSobj, src)
return ..()
+/obj/item/gun/energy/examine(mob/user)
+ . = ..()
+ if(!right_click_overridden)
+ . += "Right click in combat mode to switch modes."
+
/obj/item/gun/energy/process()
if(selfcharge && cell?.charge < cell.maxcharge)
charge_tick++
@@ -135,11 +144,13 @@
var/obj/item/ammo_casing/energy/C
for(var/i in 1 to length(ammo_type))
var/v = ammo_type[i]
+ var/user_can_select = ammo_type[v]
if(istype(v, /obj/item/ammo_casing/energy)) //already set
- continue
+ ammo_type[v] = isnull(user_can_select)? TRUE : user_can_select
else
C = new v //if you put non energycasing/type stuff in here you deserve the runtime
ammo_type[i] = C
+ ammo_type[C] = isnull(user_can_select)? TRUE : user_can_select
set_firemode_index(initial(current_firemode_index))
/obj/item/gun/energy/proc/set_firemode_index(index, mob/user_for_feedback)
@@ -179,11 +190,37 @@
/// This is the proc used in general for when a user switches firemodes. Just goes to next firemode by default.
/obj/item/gun/energy/proc/select_fire(mob/living/user)
- return set_firemode_to_next(user)
+ return user_set_firemode_to_next(user)
/obj/item/gun/energy/proc/can_select_fire(mob/living/user)
return TRUE
+#define INCREMENT_OR_WRAP(i) i = (i >= length(ammo_type))? 1 : (i + 1)
+#define DECREMENT_OR_WRAP(i) i = (i <= 1)? length(ammo_type) : (i - 1)
+#define IS_VALID_INDEX(i) (ammo_type[ammo_type[i]])
+/obj/item/gun/energy/proc/user_set_firemode_to_next(mob/user_for_feedback)
+ var/current_index = current_firemode_index
+ var/new_index = current_index
+ INCREMENT_OR_WRAP(new_index)
+ if(!IS_VALID_INDEX(new_index))
+ var/initial_index = new_index
+ while(!IS_VALID_INDEX(new_index) && (new_index != initial_index))
+ new_index = INCREMENT_OR_WRAP(new_index)
+ set_firemode_index(new_index, user_for_feedback)
+
+/obj/item/gun/energy/proc/user_set_firemode_to_next(mob/user_for_feedback)
+ var/current_index = current_firemode_index
+ var/new_index = current_index
+ DECREMENT_OR_WRAP(new_index)
+ if(!IS_VALID_INDEX(new_index))
+ var/initial_index = new_index
+ while(!IS_VALID_INDEX(new_index) && (new_index != initial_index))
+ new_index = DECREMENT_OR_WRAP(new_index)
+ set_firemode_index(new_index, user_for_feedback)
+#undef INCREMENT_OR_WRAP
+#undef DECREMENT_OR_WRAP
+#undef IS_VALID_INDEX
+
/obj/item/gun/energy/update_icon(force_update)
if(QDELETED(src))
return
@@ -255,7 +292,6 @@
STOP_PROCESSING(SSobj, src)
. = ..()
-
/obj/item/gun/energy/ignition_effect(atom/A, mob/living/user)
if(!can_shoot() || !ammo_type[current_firemode_index])
shoot_with_empty_chamber()
@@ -283,3 +319,9 @@
playsound(user, BB.hitsound, 50, 1)
cell.use(E.e_cost)
. = "[user] casually lights their [A.name] with [src]. Damn."
+
+/obj/item/gun/energy/altafterattack(atom/target, mob/user, proximity_flags, params)
+ if(!right_click_overridden)
+ select_fire(user)
+ return TRUE
+ return ..()
diff --git a/code/modules/projectiles/guns/energy/stun.dm b/code/modules/projectiles/guns/energy/stun.dm
index 55d11c52d1..1b272bfbaa 100644
--- a/code/modules/projectiles/guns/energy/stun.dm
+++ b/code/modules/projectiles/guns/energy/stun.dm
@@ -18,10 +18,23 @@
/obj/item/gun/energy/e_gun/advtaser
name = "hybrid taser"
- desc = "A dual-mode taser designed to fire both short-range high-power electrodes and long-range disabler beams."
+ desc = "A dual-mode taser designed to fire both short-range high-power electrodes and long-range disabler beams. Right click in combat mode to fire a taser shot with a cooldown.""
icon_state = "advtaser"
- ammo_type = list(/obj/item/ammo_casing/energy/disabler, /obj/item/ammo_casing/energy/electrode)
+ ammo_type = list(/obj/item/ammo_casing/energy/disabler, /obj/item/ammo_casing/energy/electrode = FALSE)
ammo_x_offset = 2
+ // Not enough guns have altfire systems like this yet for this to be a universal framework.
+ var/last_altfire = 0
+ var/altfire_delay = 40
+
+/obj/item/gun/energy/e_gun/advtaser/altafterattack(atom/target, mob/user, proximity_flag, params)
+ if(last_altfire > world.time + altfire_delay)
+ return FALSE
+ var/current_index = current_firemode_index
+ set_firemode_to_type(/obj/item/ammo_casing/energy/electrode)
+ process_afterattack(target, user, proximity_flag, params)
+ set_firemode_index(current_index)
+ last_altfire = world.time
+ return TRUE
/obj/item/gun/energy/e_gun/advtaser/cyborg
name = "cyborg taser"
diff --git a/code/modules/projectiles/projectile/energy/stun.dm b/code/modules/projectiles/projectile/energy/stun.dm
index 88e70154d1..1addfa2001 100644
--- a/code/modules/projectiles/projectile/energy/stun.dm
+++ b/code/modules/projectiles/projectile/energy/stun.dm
@@ -14,6 +14,7 @@
muzzle_type = /obj/effect/projectile/muzzle/stun
impact_type = /obj/effect/projectile/impact/stun
var/tase_duration = 50
+ var/strong_tase = TRUE
/obj/item/projectile/energy/electrode/on_hit(atom/target, blocked = FALSE)
. = ..()
@@ -26,10 +27,17 @@
C.IgniteMob()
if(C.dna && C.dna.check_mutation(HULK))
C.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ), forced = "hulk")
- else if((C.status_flags & CANKNOCKDOWN) && !HAS_TRAIT(C, TRAIT_STUNIMMUNE))
- C.apply_status_effect(STATUS_EFFECT_TASED, tase_duration)
+ else if(tase_duration && (C.status_flags & CANKNOCKDOWN) && !HAS_TRAIT(C, TRAIT_STUNIMMUNE))
+ C.apply_status_effect(strong_tase? STATUS_EFFECT_TASED : STATUS_EFFECT_TASED_WEAK, tase_duration)
addtimer(CALLBACK(C, /mob/living/carbon.proc/do_jitter_animation, jitter), 5)
/obj/item/projectile/energy/electrode/on_range() //to ensure the bolt sparks when it reaches the end of its range if it didn't hit a target yet
do_sparks(1, TRUE, src)
..()
+
+/obj/item/projectile/energy/electrode/security
+ tase_duration = 20
+ knockdown = 0
+ knockdown_stamoverride = 5
+ knockdown_stam_max = 15
+ strong_tase = FALSE