From a41f40503d61997bc836e634f13f60d9fe5a4f19 Mon Sep 17 00:00:00 2001
From: Ghom <42542238+Ghommie@users.noreply.github.com>
Date: Wed, 3 Jun 2020 00:22:06 +0200
Subject: [PATCH] More lenient soft stamina combat, decentralized gun
inaccuracy from combat mode. (#12347)
* A more lenient soft stamina crit.
* Yea, your shots are gonna go straight toh.
* accuracy whacks (leaves the bow as is for now).
* Fixing stam penalties calculations, spread the range.
* aaaaaah
* 1.4 seconds delay vs 1.2
* Thanks, linter.
* Missed one.
---
code/__DEFINES/combat.dm | 34 +++++++-
code/__DEFINES/obj_flags.dm | 33 ++++---
code/_onclick/click.dm | 1 +
code/_onclick/item_attack.dm | 86 ++++++++++++-------
code/game/gamemodes/gangs/dominator.dm | 2 +-
.../porta_turret/portable_turret_cover.dm | 2 +-
code/game/mecha/mecha_defense.dm | 2 +-
code/game/objects/items.dm | 9 ++
code/game/objects/items/chrono_eraser.dm | 2 +-
code/game/objects/items/powerfist.dm | 79 +++++++++--------
code/game/objects/items/stunbaton.dm | 4 +-
code/game/objects/items/twohanded.dm | 5 +-
code/modules/antagonists/cult/blood_magic.dm | 2 +-
.../devil/true_devil/_true_devil.dm | 20 +----
code/modules/holodeck/items.dm | 3 -
code/modules/mob/living/living_defines.dm | 2 +
.../hostile/mining_mobs/curse_blob.dm | 1 +
code/modules/projectiles/gun.dm | 79 +++++++++++------
.../projectiles/guns/ballistic/automatic.dm | 2 +-
.../guns/ballistic/laser_gatling.dm | 2 +-
.../projectiles/guns/ballistic/launchers.dm | 4 +-
.../projectiles/guns/ballistic/magweapon.dm | 4 +-
.../projectiles/guns/ballistic/revolver.dm | 4 +-
.../projectiles/guns/ballistic/shotgun.dm | 6 +-
code/modules/projectiles/guns/energy.dm | 4 +-
.../projectiles/guns/energy/dueling.dm | 2 +-
.../projectiles/guns/energy/energy_gun.dm | 2 +-
.../guns/energy/kinetic_accelerator.dm | 14 ++-
code/modules/projectiles/guns/energy/laser.dm | 2 +-
.../projectiles/guns/energy/special.dm | 8 +-
code/modules/projectiles/guns/magic/staff.dm | 2 +-
.../modules/projectiles/guns/misc/chem_gun.dm | 2 +-
.../projectiles/guns/misc/grenade_launcher.dm | 2 +-
code/modules/projectiles/guns/misc/medbeam.dm | 2 +-
.../projectiles/guns/misc/syringe_gun.dm | 4 +-
code/modules/vehicles/cars/car.dm | 4 +-
.../code/modules/projectiles/gun.dm | 11 ---
tgstation.dme | 1 -
38 files changed, 268 insertions(+), 180 deletions(-)
delete mode 100644 modular_citadel/code/modules/projectiles/gun.dm
diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm
index 6e9383326e..eb3c1e32ef 100644
--- a/code/__DEFINES/combat.dm
+++ b/code/__DEFINES/combat.dm
@@ -61,10 +61,18 @@
#define CHECK_STAMCRIT(mob) ((mob.combat_flags & COMBAT_FLAG_HARD_STAMCRIT)? HARD_STAMCRIT : ((mob.combat_flags & COMBAT_FLAG_SOFT_STAMCRIT)? SOFT_STAMCRIT : NOT_STAMCRIT))
//stamina stuff
-#define STAMINA_SOFTCRIT 100 //softcrit for stamina damage. prevents standing up, prevents performing actions that cost stamina, etc, but doesn't force a rest or stop movement
-#define STAMINA_CRIT 140 //crit for stamina damage. forces a rest, and stops movement until stamina goes back to stamina softcrit
-#define STAMINA_SOFTCRIT_TRADITIONAL 0 //same as STAMINA_SOFTCRIT except for the more traditional health calculations
-#define STAMINA_CRIT_TRADITIONAL -40 //ditto, but for STAMINA_CRIT
+///Threshold over which attacks start being hindered.
+#define STAMINA_NEAR_SOFTCRIT 90
+///softcrit for stamina damage. prevents standing up, some actions that cost stamina, etc, but doesn't force a rest or stop movement
+#define STAMINA_SOFTCRIT 100
+///sanity cap to prevent stamina actions (that are still performable) from sending you into crit.
+#define STAMINA_NEAR_CRIT 130
+///crit for stamina damage. forces a rest, and stops movement until stamina goes back to stamina softcrit
+#define STAMINA_CRIT 140
+///same as STAMINA_SOFTCRIT except for the more traditional health calculations
+#define STAMINA_SOFTCRIT_TRADITIONAL 0
+///ditto, but for STAMINA_CRIT
+#define STAMINA_CRIT_TRADITIONAL -40
#define CRAWLUNDER_DELAY 30 //Delay for crawling under a standing mob
@@ -182,6 +190,9 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
#define EGUN_SELFCHARGE 1
#define EGUN_SELFCHARGE_BORG 2
+///Time to spend without clicking on other things required for your shots to become accurate.
+#define GUN_AIMING_TIME (2 SECONDS)
+
//Object/Item sharpness
#define IS_BLUNT 0
#define IS_SHARP 1
@@ -249,6 +260,21 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
#define STAM_COST_W_CLASS_MULT 1.25
#define STAM_COST_THROW_MULT 2
+///Multiplier of the (STAMINA_NEAR_CRIT - user current stamina loss) : (STAMINA_NEAR_CRIT - STAMINA_SOFTCRIT) ratio used in damage penalties when stam soft-critted.
+#define STAM_CRIT_ITEM_ATTACK_PENALTY 0.66
+/// changeNext_move penalty multiplier of the above.
+#define STAM_CRIT_ITEM_ATTACK_DELAY 1.75
+/// Damage penalty when fighting prone.
+#define LYING_DAMAGE_PENALTY 0.5
+/// Added delay when firing guns stam-softcritted. Summed with a hardset CLICK_CD_RANGE delay, similar to STAM_CRIT_DAMAGE_DELAY otherwise.
+#define STAM_CRIT_GUN_DELAY 2.75
+
+/**
+ * should the current-attack-damage be lower than the item force multiplied by this value,
+ * a "inefficiently" prefix will be added to the message.
+ */
+#define INEFFICIENT_ATTACK_MSG_THRESHOLD 0.7
+
//bullet_act() return values
#define BULLET_ACT_HIT "HIT" //It's a successful hit, whatever that means in the context of the thing it's hitting.
diff --git a/code/__DEFINES/obj_flags.dm b/code/__DEFINES/obj_flags.dm
index 507126867f..a904d7a7e6 100644
--- a/code/__DEFINES/obj_flags.dm
+++ b/code/__DEFINES/obj_flags.dm
@@ -18,18 +18,29 @@
// Flags for the item_flags var on /obj/item
#define BEING_REMOVED (1<<0)
-#define IN_INVENTORY (1<<1) //is this item equipped into an inventory slot or hand of a mob? used for tooltips
-#define FORCE_STRING_OVERRIDE (1<<2) //used for tooltips
-#define NEEDS_PERMIT (1<<3) //Used by security bots to determine if this item is safe for public use.
+///is this item equipped into an inventory slot or hand of a mob? used for tooltips
+#define IN_INVENTORY (1<<1)
+///used for tooltips
+#define FORCE_STRING_OVERRIDE (1<<2)
+///Used by security bots to determine if this item is safe for public use.
+#define NEEDS_PERMIT (1<<3)
#define SLOWS_WHILE_IN_HAND (1<<4)
-#define NO_MAT_REDEMPTION (1<<5) //Stops you from putting things like an RCD or other items into an ORM or protolathe for materials.
-#define DROPDEL (1<<6) //When dropped, it calls qdel on itself
-#define NOBLUDGEON (1<<7) //when an item has this it produces no "X has been hit by Y with Z" message in the default attackby()
-#define ABSTRACT (1<<8) //for all things that are technically items but used for various different stuff
-#define IMMUTABLE_SLOW (1<<9) //When players should not be able to change the slowdown of the item (Speed potions, ect)
-#define SURGICAL_TOOL (1<<10) //Tool commonly used for surgery: won't attack targets in an active surgical operation on help intent (in case of mistakes)
-#define NO_UNIFORM_REQUIRED (1<<11) //Can be worn on certain slots (currently belt and id) that would otherwise require an uniform.
-#define NO_ATTACK_CHAIN_SOFT_STAMCRIT (1<<12) //Entirely blocks melee_attack_chain() if user is soft stamcritted. Uses getStaminaLoss() to check at this point in time. THIS DOES NOT BLOCK RANGED AFTERATTACK()S, ONLY MELEE RANGE AFTERATTACK()S.
+///Stops you from putting things like an RCD or other items into an ORM or protolathe for materials.
+#define NO_MAT_REDEMPTION (1<<5)
+///When dropped, it calls qdel on itself
+#define DROPDEL (1<<6)
+///when an item has this it produces no "X has been hit by Y with Z" message in the default attackby()
+#define NOBLUDGEON (1<<7)
+///for all things that are technically items but used for various different stuff
+#define ABSTRACT (1<<8)
+///When players should not be able to change the slowdown of the item (Speed potions, ect)
+#define IMMUTABLE_SLOW (1<<9)
+///Tool commonly used for surgery: won't attack targets in an active surgical operation on help intent (in case of mistakes)
+#define SURGICAL_TOOL (1<<10)
+///Can be worn on certain slots (currently belt and id) that would otherwise require an uniform.
+#define NO_UNIFORM_REQUIRED (1<<11)
+///Damage when attacking people is not affected by combat mode.
+#define NO_COMBAT_MODE_FORCE_MODIFIER (1<<12)
// Flags for the clothing_flags var on /obj/item/clothing
diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
index 5d2f916fba..357f317450 100644
--- a/code/_onclick/click.dm
+++ b/code/_onclick/click.dm
@@ -21,6 +21,7 @@
next_move = world.time + ((num+next_move_adjust)*next_move_modifier)
/mob/living/changeNext_move(num)
+ last_click_move = next_move
var/mod = next_move_modifier
var/adj = next_move_adjust
for(var/i in status_effects)
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index e2c160503c..b2d74844cf 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -10,10 +10,6 @@
/obj/item/proc/melee_attack_chain(mob/user, atom/target, params)
if(isliving(user))
var/mob/living/L = user
- if(item_flags & NO_ATTACK_CHAIN_SOFT_STAMCRIT)
- if(IS_STAMCRIT(L))
- to_chat(L, "You are too exhausted to swing [src]!")
- return
if(!CHECK_MOBILITY(L, MOBILITY_USE))
to_chat(L, "You are unable to swing [src] right now!")
return
@@ -59,8 +55,10 @@
/mob/living/attackby(obj/item/I, mob/living/user, params)
if(..())
return TRUE
- user.changeNext_move(CLICK_CD_MELEE)
- return I.attack(src, user)
+ I.attack_delay_done = FALSE //Should be set TRUE in pre_attacked_by()
+ . = I.attack(src, user)
+ if(!I.attack_delay_done) //Otherwise, pre_attacked_by() should handle it.
+ user.changeNext_move(I.click_delay)
/obj/item/proc/attack(mob/living/M, mob/living/user)
if(SEND_SIGNAL(src, COMSIG_ITEM_ATTACK, M, user) & COMPONENT_ITEM_NO_ATTACK)
@@ -68,11 +66,6 @@
SEND_SIGNAL(user, COMSIG_MOB_ITEM_ATTACK, M, user)
if(item_flags & NOBLUDGEON)
return
-
- if(IS_STAMCRIT(user)) // CIT CHANGE - makes it impossible to attack in stamina softcrit
- to_chat(user, "You're too exhausted.") // CIT CHANGE - ditto
- return // CIT CHANGE - ditto
-
if(force && damtype != STAMINA && HAS_TRAIT(user, TRAIT_PACIFISM))
to_chat(user, "You don't want to harm other living beings!")
return
@@ -91,7 +84,9 @@
log_combat(user, M, "attacked", src.name, "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])")
add_fingerprint(user)
- user.adjustStaminaLossBuffered(getweight(user, STAM_COST_ATTACK_MOB_MULT))//CIT CHANGE - makes attacking things cause stamina loss
+ var/weight = getweight(user, STAM_COST_ATTACK_MOB_MULT) //CIT CHANGE - makes attacking things cause stamina loss
+ if(weight)
+ user.adjustStaminaLossBuffered(weight)
//the equivalent of the standard version of attack() but for object targets.
/obj/item/proc/attack_obj(obj/O, mob/living/user)
@@ -99,13 +94,12 @@
return
if(item_flags & NOBLUDGEON)
return
- if(IS_STAMCRIT(user)) // CIT CHANGE - makes it impossible to attack in stamina softcrit
- to_chat(user, "You're too exhausted.") // CIT CHANGE - ditto
- return // CIT CHANGE - ditto
- user.adjustStaminaLossBuffered(getweight(user, STAM_COST_ATTACK_OBJ_MULT))//CIT CHANGE - makes attacking things cause stamina loss
- user.changeNext_move(CLICK_CD_MELEE)
user.do_attack_animation(O)
- O.attacked_by(src, user)
+ if(!O.attacked_by(src, user))
+ user.changeNext_move(click_delay)
+ var/weight = getweight(user, STAM_COST_ATTACK_OBJ_MULT)
+ if(weight)
+ user.adjustStaminaLossBuffered(weight)//CIT CHANGE - makes attacking things cause stamina loss
/atom/movable/proc/attacked_by()
return
@@ -113,9 +107,18 @@
/obj/attacked_by(obj/item/I, mob/living/user)
var/totitemdamage = I.force
var/bad_trait
- if(!SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
- totitemdamage *= 0.5
+
+ var/stamloss = user.getStaminaLoss()
+ var/next_move_mult = 1
+ if(stamloss > STAMINA_NEAR_SOFTCRIT) //The more tired you are, the less damage you do.
+ var/penalty = (stamloss - STAMINA_NEAR_SOFTCRIT)/(STAMINA_NEAR_CRIT - STAMINA_NEAR_SOFTCRIT)*STAM_CRIT_ITEM_ATTACK_PENALTY
+ totitemdamage *= 1 - penalty
+ next_move_mult += penalty*STAM_CRIT_ITEM_ATTACK_DELAY
+ user.changeNext_move(I.click_delay*next_move_mult)
+
+ if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
bad_trait = SKILL_COMBAT_MODE //blacklist combat skills.
+
if(I.used_skills && user.mind)
if(totitemdamage)
totitemdamage = user.mind.item_action_skills_mod(I, totitemdamage, I.skill_difficulty, SKILL_ATTACK_OBJ, bad_trait)
@@ -123,17 +126,19 @@
if(!(I.used_skills[skill] & SKILL_TRAIN_ATTACK_OBJ))
continue
user.mind.auto_gain_experience(skill, I.skill_gain)
+
if(totitemdamage)
visible_message("[user] has hit [src] with [I]!", null, null, COMBAT_MESSAGE_RANGE)
//only witnesses close by and the victim see a hit message.
log_combat(user, src, "attacked", I)
take_damage(totitemdamage, I.damtype, "melee", 1)
+ return TRUE
/mob/living/attacked_by(obj/item/I, mob/living/user)
var/totitemdamage = pre_attacked_by(I, user)
if((user != src) && mob_run_block(I, totitemdamage, "the [I.name]", ATTACK_TYPE_MELEE, I.armour_penetration, user, null, null) & BLOCK_SUCCESS)
return FALSE
- send_item_attack_message(I, user)
+ send_item_attack_message(I, user, null, totitemdamage)
I.do_stagger_action(src, user, totitemdamage)
if(I.force)
apply_damage(totitemdamage, I.damtype)
@@ -149,19 +154,37 @@
/mob/living/simple_animal/attacked_by(obj/item/I, mob/living/user)
if(I.force < force_threshold || I.damtype == STAMINA)
playsound(loc, 'sound/weapons/tap.ogg', I.get_clamped_volume(), 1, -1)
+ user.changeNext_move(I.click_delay) //pre_attacked_by not called
else
return ..()
/mob/living/proc/pre_attacked_by(obj/item/I, mob/living/user)
. = I.force
+ if(!.)
+ return
+
+ var/stamloss = user.getStaminaLoss()
+ var/stam_mobility_mult = 1
+ var/next_move_mult = 1
+ if(stamloss > STAMINA_NEAR_SOFTCRIT) //The more tired you are, the less damage you do.
+ var/penalty = (stamloss - STAMINA_NEAR_SOFTCRIT)/(STAMINA_NEAR_CRIT - STAMINA_NEAR_SOFTCRIT)*STAM_CRIT_ITEM_ATTACK_PENALTY
+ stam_mobility_mult -= penalty
+ next_move_mult += penalty*STAM_CRIT_ITEM_ATTACK_DELAY
+ if(stam_mobility_mult > LYING_DAMAGE_PENALTY && !CHECK_MOBILITY(user, MOBILITY_STAND)) //damage penalty for fighting prone, doesn't stack with the above.
+ stam_mobility_mult = LYING_DAMAGE_PENALTY
+ . *= stam_mobility_mult
+ user.changeNext_move(I.click_delay*next_move_mult)
+ I.attack_delay_done = TRUE
+
var/bad_trait
- if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
- . *= 0.5
- bad_trait = SKILL_COMBAT_MODE //blacklist combat skills.
- if(SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
- . *= 1.5
- if(!CHECK_MOBILITY(user, MOBILITY_STAND))
- . *= 0.5
+ if(!(I.item_flags & NO_COMBAT_MODE_FORCE_MODIFIER))
+ if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
+ bad_trait = SKILL_COMBAT_MODE //blacklist combat skills.
+ if(SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE))
+ . *= 0.5
+ else if(SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
+ . *= 1.5
+
if(!user.mind || !I.used_skills)
return
if(.)
@@ -171,7 +194,6 @@
continue
user.mind.auto_gain_experience(skill, I.skill_gain)
-
// Proximity_flag is 1 if this afterattack was called on something adjacent, in your square, or on your person.
// Click parameters is the params string from byond Click() code, see that documentation.
/obj/item/proc/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
@@ -185,10 +207,12 @@
else
return clamp(w_class * 6, 10, 100) // Multiply the item's weight class by 6, then clamp the value between 10 and 100
-/mob/living/proc/send_item_attack_message(obj/item/I, mob/living/user, hit_area)
+/mob/living/proc/send_item_attack_message(obj/item/I, mob/living/user, hit_area, current_force)
var/message_verb = "attacked"
if(I.attack_verb && I.attack_verb.len)
message_verb = "[pick(I.attack_verb)]"
+ if(current_force < I.force * INEFFICIENT_ATTACK_MSG_THRESHOLD)
+ message_verb = "inefficiently [message_verb]"
else if(!I.force)
return
var/message_hit_area = ""
@@ -215,6 +239,8 @@
bad_trait = SKILL_COMBAT_MODE
if(used_skills && user.mind)
. = user.mind.item_action_skills_mod(src, ., skill_difficulty, trait, bad_trait, FALSE)
+ var/total_health = user.getStaminaLoss()
+ . = clamp(., 0, STAMINA_NEAR_CRIT - total_health)
/// How long this staggers for. 0 and negatives supported.
/obj/item/proc/melee_stagger_duration(force_override)
diff --git a/code/game/gamemodes/gangs/dominator.dm b/code/game/gamemodes/gangs/dominator.dm
index af75315ded..a375c4f8b5 100644
--- a/code/game/gamemodes/gangs/dominator.dm
+++ b/code/game/gamemodes/gangs/dominator.dm
@@ -147,7 +147,7 @@
/obj/machinery/dominator/attacked_by(obj/item/I, mob/living/user)
add_fingerprint(user)
- ..()
+ return ..()
/obj/machinery/dominator/attack_hand(mob/user)
if(operating || (stat & BROKEN))
diff --git a/code/game/machinery/porta_turret/portable_turret_cover.dm b/code/game/machinery/porta_turret/portable_turret_cover.dm
index afb00d4ee2..2403f903a9 100644
--- a/code/game/machinery/porta_turret/portable_turret_cover.dm
+++ b/code/game/machinery/porta_turret/portable_turret_cover.dm
@@ -71,7 +71,7 @@
return ..()
/obj/machinery/porta_turret_cover/attacked_by(obj/item/I, mob/user)
- parent_turret.attacked_by(I, user)
+ return parent_turret.attacked_by(I, user)
/obj/machinery/porta_turret_cover/attack_alien(mob/living/carbon/alien/humanoid/user)
parent_turret.attack_alien(user)
diff --git a/code/game/mecha/mecha_defense.dm b/code/game/mecha/mecha_defense.dm
index 1fe7f74dec..56bb8cceda 100644
--- a/code/game/mecha/mecha_defense.dm
+++ b/code/game/mecha/mecha_defense.dm
@@ -284,7 +284,7 @@
/obj/mecha/attacked_by(obj/item/I, mob/living/user)
mecha_log_message("Attacked by [I]. Attacker - [user]")
- ..()
+ return ..()
/obj/mecha/proc/mech_toxin_damage(mob/living/target)
playsound(src, 'sound/effects/spray2.ogg', 50, 1)
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 55549f5fc4..776980badb 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -55,6 +55,15 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
/// How long, in deciseconds, this staggers for, if null it will autocalculate from w_class and force. Unlike total mass this supports 0 and negatives.
var/stagger_force
+ /**
+ * Set FALSE and then checked at the end of on mob/living/attackby(), set TRUE on living/pre_attacked_by().
+ * Should it be FALSE by the end of the item/attack(), that means the item overrode the standard attack behaviour
+ * and the user still needs the delay applied. We can't be using return values since that'll stop afterattack() from being triggered.
+ */
+ var/attack_delay_done = FALSE
+ ///next_move click/attack delay of this item.
+ var/click_delay = CLICK_CD_MELEE
+
var/slot_flags = 0 //This is used to determine on which slots an item can fit.
pass_flags = PASSTABLE
pressure_resistance = 4
diff --git a/code/game/objects/items/chrono_eraser.dm b/code/game/objects/items/chrono_eraser.dm
index c3b6c0312f..766c3d8636 100644
--- a/code/game/objects/items/chrono_eraser.dm
+++ b/code/game/objects/items/chrono_eraser.dm
@@ -65,7 +65,7 @@
. = ..()
AddElement(/datum/element/update_icon_blocker)
-/obj/item/gun/energy/chrono_gun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
+/obj/item/gun/energy/chrono_gun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
if(field)
field_disconnect(field)
..()
diff --git a/code/game/objects/items/powerfist.dm b/code/game/objects/items/powerfist.dm
index 648f465a22..b7e2d22d2f 100644
--- a/code/game/objects/items/powerfist.dm
+++ b/code/game/objects/items/powerfist.dm
@@ -6,6 +6,7 @@
lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi'
flags_1 = CONDUCT_1
+ item_flags = NEEDS_PERMIT | NO_COMBAT_MODE_FORCE_MODIFIER //To avoid ambushing and oneshotting healthy crewmembers on force setting 3.
attack_verb = list("whacked", "fisted", "power-punched")
force = 20
throwforce = 10
@@ -13,7 +14,7 @@
w_class = WEIGHT_CLASS_NORMAL
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 40)
resistance_flags = FIRE_PROOF
- var/click_delay = 1.5
+ click_delay = CLICK_CD_MELEE * 1.5
var/fisto_setting = 1
var/gasperfist = 3
var/obj/item/tank/internals/tank = null //Tank used for the gauntlet's piston-ram.
@@ -70,42 +71,46 @@
/obj/item/melee/powerfist/attack(mob/living/target, mob/living/user)
- if(!tank)
- to_chat(user, "\The [src] can't operate without a source of gas!")
- return
- var/datum/gas_mixture/gasused = tank.air_contents.remove(gasperfist * fisto_setting)
- var/turf/T = get_turf(src)
- if(!T)
- return
- T.assume_air(gasused)
- T.air_update_turf()
- if(!gasused)
- to_chat(user, "\The [src]'s tank is empty!")
- target.apply_damage((force / 5), BRUTE)
- playsound(loc, 'sound/weapons/punch1.ogg', 50, 1)
- target.visible_message("[user]'s powerfist lets out a dull thunk as [user.p_they()] punch[user.p_es()] [target.name]!", \
- "[user]'s punches you!")
- return
- if(gasused.total_moles() < gasperfist * fisto_setting)
- to_chat(user, "\The [src]'s piston-ram lets out a weak hiss, it needs more gas!")
- playsound(loc, 'sound/weapons/punch4.ogg', 50, 1)
- target.apply_damage((force / 2), BRUTE)
- target.visible_message("[user]'s powerfist lets out a weak hiss as [user.p_they()] punch[user.p_es()] [target.name]!", \
- "[user]'s punch strikes with force!")
- return
- target.apply_damage(force * fisto_setting, BRUTE)
- target.visible_message("[user]'s powerfist lets out a loud hiss as [user.p_they()] punch[user.p_es()] [target.name]!", \
- "You cry out in pain as [user]'s punch flings you backwards!")
- new /obj/effect/temp_visual/kinetic_blast(target.loc)
- playsound(loc, 'sound/weapons/resonator_blast.ogg', 50, 1)
- playsound(loc, 'sound/weapons/genhit2.ogg', 50, 1)
+ if(HAS_TRAIT(user, TRAIT_PACIFISM))
+ to_chat(user, "You don't want to harm other living beings!")
+ return FALSE
+ if(!tank)
+ to_chat(user, "\The [src] can't operate without a source of gas!")
+ return FALSE
+ var/datum/gas_mixture/gasused = tank.air_contents.remove(gasperfist * fisto_setting)
+ var/turf/T = get_turf(src)
+ if(!T)
+ return FALSE
+ var/totalitemdamage = target.pre_attacked_by(src, user)
+ T.assume_air(gasused)
+ T.air_update_turf()
+ if(!gasused)
+ to_chat(user, "\The [src]'s tank is empty!")
+ target.apply_damage((totalitemdamage / 5), BRUTE)
+ playsound(loc, 'sound/weapons/punch1.ogg', 50, 1)
+ target.visible_message("[user]'s powerfist lets out a dull thunk as [user.p_they()] punch[user.p_es()] [target.name]!", \
+ "[user]'s punches you!")
+ return
+ if(gasused.total_moles() < gasperfist * fisto_setting)
+ to_chat(user, "\The [src]'s piston-ram lets out a weak hiss, it needs more gas!")
+ playsound(loc, 'sound/weapons/punch4.ogg', 50, 1)
+ target.apply_damage((totalitemdamage / 2), BRUTE)
+ target.visible_message("[user]'s powerfist lets out a weak hiss as [user.p_they()] punch[user.p_es()] [target.name]!", \
+ "[user]'s punch strikes with force!")
+ return
+ target.apply_damage(totalitemdamage * fisto_setting, BRUTE)
+ target.visible_message("[user]'s powerfist lets out a loud hiss as [user.p_they()] punch[user.p_es()] [target.name]!", \
+ "You cry out in pain as [user]'s punch flings you backwards!")
+ new /obj/effect/temp_visual/kinetic_blast(target.loc)
+ playsound(loc, 'sound/weapons/resonator_blast.ogg', 50, 1)
+ playsound(loc, 'sound/weapons/genhit2.ogg', 50, 1)
- var/atom/throw_target = get_edge_target_turf(target, get_dir(src, get_step_away(target, src)))
+ var/atom/throw_target = get_edge_target_turf(target, get_dir(src, get_step_away(target, src)))
+ target.throw_at(throw_target, 5 * fisto_setting, 0.5 + (fisto_setting / 2))
- target.throw_at(throw_target, 5 * fisto_setting, 0.5 + (fisto_setting / 2))
+ log_combat(user, target, "power fisted", src)
- log_combat(user, target, "power fisted", src)
-
- user.changeNext_move(CLICK_CD_MELEE * click_delay)
-
- return
+ var/weight = getweight(user, STAM_COST_ATTACK_MOB_MULT)
+ if(weight)
+ user.adjustStaminaLossBuffered(weight)
+ return TRUE
diff --git a/code/game/objects/items/stunbaton.dm b/code/game/objects/items/stunbaton.dm
index e9364bcede..60fc761bfe 100644
--- a/code/game/objects/items/stunbaton.dm
+++ b/code/game/objects/items/stunbaton.dm
@@ -141,7 +141,7 @@
/obj/item/melee/baton/attack(mob/M, mob/living/carbon/human/user)
var/interrupt = common_baton_melee(M, user, FALSE)
if(!interrupt)
- ..()
+ return ..()
/obj/item/melee/baton/alt_pre_attack(atom/A, mob/living/user, params)
. = common_baton_melee(A, user, TRUE) //return true (attackchain interrupt) if this also returns true. no harm-disarming.
@@ -154,7 +154,7 @@
if(turned_on && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50))
clowning_around(user)
if(IS_STAMCRIT(user)) //CIT CHANGE - makes it impossible to baton in stamina softcrit
- to_chat(user, "You're too exhausted for that.")
+ to_chat(user, "You're too exhausted to use [src] properly.")
return TRUE
if(ishuman(M))
var/mob/living/carbon/human/L = M
diff --git a/code/game/objects/items/twohanded.dm b/code/game/objects/items/twohanded.dm
index 6f5e99e5aa..7c59f2fc63 100644
--- a/code/game/objects/items/twohanded.dm
+++ b/code/game/objects/items/twohanded.dm
@@ -1176,14 +1176,13 @@
/obj/item/twohanded/electrostaff/attack(mob/living/target, mob/living/user)
if(IS_STAMCRIT(user))//CIT CHANGE - makes it impossible to baton in stamina softcrit
- to_chat(user, "You're too exhausted for that.")//CIT CHANGE - ditto
+ to_chat(user, "You're too exhausted to use [src] properly.")//CIT CHANGE - ditto
return //CIT CHANGE - ditto
if(on && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50))
clowning_around(user) //ouch!
return
if(iscyborg(target))
- ..()
- return
+ return ..()
if(target.mob_run_block(src, 0, "[user]'s [name]", ATTACK_TYPE_MELEE, 0, user, null, null) & BLOCK_SUCCESS) //No message; run_block() handles that
playsound(target, 'sound/weapons/genhit.ogg', 50, 1)
return FALSE
diff --git a/code/modules/antagonists/cult/blood_magic.dm b/code/modules/antagonists/cult/blood_magic.dm
index 28d1a66e00..52ead9a1e7 100644
--- a/code/modules/antagonists/cult/blood_magic.dm
+++ b/code/modules/antagonists/cult/blood_magic.dm
@@ -343,7 +343,7 @@
icon = 'icons/obj/items_and_weapons.dmi'
icon_state = "disintegrate"
item_state = null
- item_flags = NEEDS_PERMIT | ABSTRACT | DROPDEL | NO_ATTACK_CHAIN_SOFT_STAMCRIT
+ item_flags = NEEDS_PERMIT | ABSTRACT | DROPDEL
w_class = WEIGHT_CLASS_HUGE
throwforce = 0
diff --git a/code/modules/antagonists/devil/true_devil/_true_devil.dm b/code/modules/antagonists/devil/true_devil/_true_devil.dm
index 1b245b5a01..f09592161d 100644
--- a/code/modules/antagonists/devil/true_devil/_true_devil.dm
+++ b/code/modules/antagonists/devil/true_devil/_true_devil.dm
@@ -118,22 +118,10 @@
/mob/living/carbon/true_devil/attacked_by(obj/item/I, mob/living/user, def_zone)
- var/weakness = check_weakness(I, user)
- apply_damage(I.force * weakness, I.damtype, def_zone)
- var/message_verb = ""
- if(I.attack_verb && I.attack_verb.len)
- message_verb = "[pick(I.attack_verb)]"
- else if(I.force)
- message_verb = "attacked"
-
- var/attack_message = "[src] has been [message_verb] with [I]."
- if(user)
- user.do_attack_animation(src)
- if(user in viewers(src, null))
- attack_message = "[user] has [message_verb] [src] with [I]!"
- if(message_verb)
- visible_message("[attack_message]",
- "[attack_message]", null, COMBAT_MESSAGE_RANGE)
+ var/totitemdamage = pre_attacked_by(I, user)
+ totitemdamage *= check_weakness(I, user)
+ apply_damage(totitemdamage, I.damtype, def_zone)
+ send_item_attack_message(I, user, null, totitemdamage)
return TRUE
/mob/living/carbon/true_devil/singularity_act()
diff --git a/code/modules/holodeck/items.dm b/code/modules/holodeck/items.dm
index 3fac417605..c68c5de804 100644
--- a/code/modules/holodeck/items.dm
+++ b/code/modules/holodeck/items.dm
@@ -40,9 +40,6 @@
return ..()
return ..()
-/obj/item/holo/esword/attack(target as mob, mob/user as mob)
- ..()
-
/obj/item/holo/esword/Initialize()
. = ..()
saber_color = pick("red","blue","green","purple")
diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm
index 282dab79a8..da24f190e8 100644
--- a/code/modules/mob/living/living_defines.dm
+++ b/code/modules/mob/living/living_defines.dm
@@ -8,6 +8,8 @@
typing_indicator_enabled = TRUE
+ var/last_click_move = 0 // Stores the previous next_move value.
+
var/resize = 1 //Badminnery resize
var/lastattacker = null
var/lastattackerckey = null
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm
index 116082d571..9d395ca5ff 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm
@@ -105,6 +105,7 @@ IGNORE_PROC_IF_NOT_TARGET(attack_slime)
/mob/living/simple_animal/hostile/asteroid/curseblob/attacked_by(obj/item/I, mob/living/L)
if(L != set_target)
+ L.changeNext_move(I.click_delay) //pre_attacked_by not called
return
return ..()
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index c4909c5583..b90f0aee0d 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -15,7 +15,7 @@
throw_speed = 3
throw_range = 5
force = 5
- item_flags = NEEDS_PERMIT | NO_ATTACK_CHAIN_SOFT_STAMCRIT
+ item_flags = NEEDS_PERMIT
attack_verb = list("struck", "hit", "bashed")
var/fire_sound = "gunshot"
@@ -140,12 +140,13 @@
to_chat(user, "*click*")
playsound(src, "gun_dry_fire", 30, 1)
-/obj/item/gun/proc/shoot_live_shot(mob/living/user as mob|obj, pointblank = 0, mob/pbtarget = null, message = 1)
+/obj/item/gun/proc/shoot_live_shot(mob/living/user, pointblank = FALSE, mob/pbtarget, message = 1, stam_cost = 0)
if(recoil)
shake_camera(user, recoil + 1, recoil)
- if(isliving(user)) //CIT CHANGE - makes gun recoil cause staminaloss
- user.adjustStaminaLossBuffered(getstamcost(user)*(firing && burst_size >= 2 ? 1/burst_size : 1)) //CIT CHANGE - ditto
+ if(stam_cost) //CIT CHANGE - makes gun recoil cause staminaloss
+ var/safe_cost = clamp(stam_cost, 0, STAMINA_NEAR_CRIT - user.getStaminaLoss())*(firing && burst_size >= 2 ? 1/burst_size : 1)
+ user.adjustStaminaLossBuffered(safe_cost) //CIT CHANGE - ditto
if(suppressed)
playsound(user, fire_sound, 10, 1)
@@ -172,9 +173,10 @@
return
if(firing)
return
- if(IS_STAMCRIT(user)) //respect stamina softcrit
- to_chat(user, "You are too exhausted to fire [src]!")
- return
+ var/stamloss = user.getStaminaLoss()
+ if(stamloss >= STAMINA_NEAR_SOFTCRIT) //The more tired you are, the less damage you do.
+ var/penalty = (stamloss - STAMINA_NEAR_SOFTCRIT)/(STAMINA_NEAR_CRIT - STAMINA_NEAR_SOFTCRIT)*STAM_CRIT_GUN_DELAY
+ user.changeNext_move(CLICK_CD_RANGE+(CLICK_CD_RANGE*penalty))
if(flag) //It's adjacent, is the user, or is on the user's person
if(target in user.contents) //can't shoot stuff inside us.
return
@@ -216,7 +218,7 @@
var/loop_counter = 0
if(user)
- bonus_spread += getinaccuracy(user) //CIT CHANGE - adds bonus spread while not aiming
+ bonus_spread = getinaccuracy(user, bonus_spread, stamloss) //CIT CHANGE - adds bonus spread while not aiming
if(ishuman(user) && user.a_intent == INTENT_HARM && weapon_weight <= WEAPON_LIGHT)
var/mob/living/carbon/human/H = user
for(var/obj/item/gun/G in H.held_items)
@@ -225,9 +227,11 @@
else if(G.can_trigger_gun(user))
bonus_spread += 24 * G.weapon_weight * G.dualwield_spread_mult
loop_counter++
- addtimer(CALLBACK(G, /obj/item/gun.proc/process_fire, target, user, TRUE, params, null, bonus_spread), loop_counter)
+ var/stam_cost = G.getstamcost(user)
+ addtimer(CALLBACK(G, /obj/item/gun.proc/process_fire, target, user, TRUE, params, null, bonus_spread, stam_cost), loop_counter)
- process_fire(target, user, TRUE, params, null, bonus_spread)
+ var/stam_cost = getstamcost(user)
+ process_fire(target, user, TRUE, params, null, bonus_spread, stam_cost)
/obj/item/gun/can_trigger_gun(mob/living/user)
. = ..()
@@ -258,21 +262,21 @@
/obj/item/gun/proc/on_cooldown()
return busy_action || firing || ((last_fire + fire_delay) > world.time)
-/obj/item/gun/proc/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
+/obj/item/gun/proc/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
add_fingerprint(user)
if(on_cooldown())
return
firing = TRUE
- . = do_fire(target, user, message, params, zone_override, bonus_spread)
+ . = do_fire(target, user, message, params, zone_override, bonus_spread, stam_cost)
firing = FALSE
last_fire = world.time
if(user)
user.update_inv_hands()
- SEND_SIGNAL(user, COMSIG_LIVING_GUN_PROCESS_FIRE, target, params, zone_override)
+ SEND_SIGNAL(user, COMSIG_LIVING_GUN_PROCESS_FIRE, target, params, zone_override, bonus_spread, stam_cost)
-/obj/item/gun/proc/do_fire(atom/target, mob/living/user, message = TRUE, params, zone_override = "", bonus_spread = 0)
+/obj/item/gun/proc/do_fire(atom/target, mob/living/user, message = TRUE, params, zone_override = "", bonus_spread = 0, stam_cost = 0)
var/sprd = 0
var/randomized_gun_spread = 0
var/rand_spr = rand()
@@ -290,7 +294,7 @@
sleep(burst_shot_delay)
if(QDELETED(src))
break
- do_burst_shot(user, target, message, params, zone_override, sprd, randomized_gun_spread, randomized_bonus_spread, rand_spr, i)
+ do_burst_shot(user, target, message, params, zone_override, sprd, randomized_gun_spread, randomized_bonus_spread, rand_spr, i, stam_cost)
else
if(chambered)
sprd = round((rand() - 0.5) * DUALWIELD_PENALTY_EXTRA_MULTIPLIER * (randomized_gun_spread + randomized_bonus_spread))
@@ -300,9 +304,9 @@
return
else
if(get_dist(user, target) <= 1) //Making sure whether the target is in vicinity for the pointblank shot
- shoot_live_shot(user, 1, target, message)
+ shoot_live_shot(user, 1, target, message, stam_cost)
else
- shoot_live_shot(user, 0, target, message)
+ shoot_live_shot(user, 0, target, message, stam_cost)
else
shoot_with_empty_chamber(user)
return
@@ -312,7 +316,7 @@
SSblackbox.record_feedback("tally", "gun_fired", 1, type)
return TRUE
-/obj/item/gun/proc/do_burst_shot(mob/living/user, atom/target, message = TRUE, params=null, zone_override = "", sprd = 0, randomized_gun_spread = 0, randomized_bonus_spread = 0, rand_spr = 0, iteration = 0)
+/obj/item/gun/proc/do_burst_shot(mob/living/user, atom/target, message = TRUE, params=null, zone_override = "", sprd = 0, randomized_gun_spread = 0, randomized_bonus_spread = 0, rand_spr = 0, iteration = 0, stam_cost = 0)
if(!user || !firing)
firing = FALSE
return FALSE
@@ -336,9 +340,9 @@
return FALSE
else
if(get_dist(user, target) <= 1) //Making sure whether the target is in vicinity for the pointblank shot
- shoot_live_shot(user, 1, target, message)
+ shoot_live_shot(user, 1, target, message, stam_cost)
else
- shoot_live_shot(user, 0, target, message)
+ shoot_live_shot(user, 0, target, message, stam_cost)
if (iteration >= burst_size)
firing = FALSE
else
@@ -349,20 +353,21 @@
update_icon()
return TRUE
-/obj/item/gun/attack(mob/M as mob, mob/user)
+/obj/item/gun/attack(mob/living/M, mob/user)
if(user.a_intent == INTENT_HARM) //Flogging
if(bayonet)
M.attackby(bayonet, user)
+ attack_delay_done = TRUE
return
else
return ..()
- return
+ attack_delay_done = TRUE //we are firing the gun, not bashing people with its butt.
/obj/item/gun/attack_obj(obj/O, mob/user)
if(user.a_intent == INTENT_HARM)
if(bayonet)
O.attackby(bayonet, user)
- return
+ return TRUE
return ..()
/obj/item/gun/attackby(obj/item/I, mob/user, params)
@@ -498,7 +503,7 @@
if(chambered && chambered.BB)
chambered.BB.damage *= 5
- process_fire(target, user, TRUE, params)
+ process_fire(target, user, TRUE, params, stam_cost = getstamcost(user))
/obj/item/gun/proc/unlock() //used in summon guns and as a convience for admins
if(pin)
@@ -566,7 +571,25 @@
chambered = null
update_icon()
-/obj/item/gun/proc/getinaccuracy(mob/user)
- if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
- return ((weapon_weight * 25) * inaccuracy_modifier)
- return 0
+/obj/item/gun/proc/getinaccuracy(mob/living/user, bonus_spread, stamloss)
+ if(inaccuracy_modifier == 0)
+ return bonus_spread
+ var/base_inaccuracy = weapon_weight * 25 * inaccuracy_modifier
+ var/aiming_delay = 0 //Otherwise aiming would be meaningless for slower guns such as sniper rifles and launchers.
+ if(fire_delay)
+ var/penalty = (last_fire + GUN_AIMING_TIME + fire_delay) - world.time
+ if(penalty > 0) //Yet we only penalize users firing it multiple times in a haste. fire_delay isn't necessarily cumbersomeness.
+ aiming_delay = penalty
+ if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE)) //To be removed in favor of something less tactless later.
+ base_inaccuracy /= 1.5
+ if(stamloss > STAMINA_NEAR_SOFTCRIT) //This can null out the above bonus.
+ base_inaccuracy *= 1 + (stamloss - STAMINA_NEAR_SOFTCRIT)/(STAMINA_NEAR_CRIT - STAMINA_NEAR_SOFTCRIT)*0.5
+ var/mult = max((GUN_AIMING_TIME + aiming_delay + user.last_click_move - world.time)/GUN_AIMING_TIME, -0.5) //Yes, there is a bonus for taking time aiming.
+ if(mult < 0) //accurate weapons should provide a proper bonus with negative inaccuracy. the opposite is true too.
+ mult *= 1/inaccuracy_modifier
+ return max(bonus_spread + (base_inaccuracy * mult), 0) //no negative spread.
+
+/obj/item/gun/proc/getstamcost(mob/living/carbon/user)
+ . = recoil
+ if(user && !user.has_gravity())
+ . = recoil*5
diff --git a/code/modules/projectiles/guns/ballistic/automatic.dm b/code/modules/projectiles/guns/ballistic/automatic.dm
index 31823dccf6..39956ef3e8 100644
--- a/code/modules/projectiles/guns/ballistic/automatic.dm
+++ b/code/modules/projectiles/guns/ballistic/automatic.dm
@@ -365,7 +365,7 @@
can_unsuppress = TRUE
can_suppress = TRUE
w_class = WEIGHT_CLASS_NORMAL
- inaccuracy_modifier = 0
+ inaccuracy_modifier = 0.5
zoomable = TRUE
zoom_amt = 10 //Long range, enough to see in front of you, but no tiles behind you.
zoom_out_amt = 13
diff --git a/code/modules/projectiles/guns/ballistic/laser_gatling.dm b/code/modules/projectiles/guns/ballistic/laser_gatling.dm
index 366aa367b4..7029cd4071 100644
--- a/code/modules/projectiles/guns/ballistic/laser_gatling.dm
+++ b/code/modules/projectiles/guns/ballistic/laser_gatling.dm
@@ -130,7 +130,7 @@
else
qdel(src)
-/obj/item/gun/ballistic/minigun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
+/obj/item/gun/ballistic/minigun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
if(ammo_pack)
if(ammo_pack.overheat < ammo_pack.overheat_max)
ammo_pack.overheat += burst_size
diff --git a/code/modules/projectiles/guns/ballistic/launchers.dm b/code/modules/projectiles/guns/ballistic/launchers.dm
index db614b97d3..34572d609d 100644
--- a/code/modules/projectiles/guns/ballistic/launchers.dm
+++ b/code/modules/projectiles/guns/ballistic/launchers.dm
@@ -6,7 +6,7 @@
name = "grenade launcher"
icon_state = "dshotgun-sawn"
item_state = "gun"
- inaccuracy_modifier = 0
+ inaccuracy_modifier = 0.5
mag_type = /obj/item/ammo_box/magazine/internal/grenadelauncher
fire_sound = 'sound/weapons/grenadelaunch.ogg'
w_class = WEIGHT_CLASS_NORMAL
@@ -87,7 +87,7 @@
pin = /obj/item/firing_pin/implant/pindicate
burst_size = 1
fire_delay = 0
- inaccuracy_modifier = 0
+ inaccuracy_modifier = 0.25
casing_ejector = FALSE
weapon_weight = WEAPON_HEAVY
magazine_wording = "rocket"
diff --git a/code/modules/projectiles/guns/ballistic/magweapon.dm b/code/modules/projectiles/guns/ballistic/magweapon.dm
index e71f414bd8..74b8b210a7 100644
--- a/code/modules/projectiles/guns/ballistic/magweapon.dm
+++ b/code/modules/projectiles/guns/ballistic/magweapon.dm
@@ -14,7 +14,7 @@
spread = 0
recoil = 0.1
casing_ejector = FALSE
- inaccuracy_modifier = 0
+ inaccuracy_modifier = 0.15
dualwield_spread_mult = 1.4
weapon_weight = WEAPON_MEDIUM
w_class = WEIGHT_CLASS_BULKY
@@ -46,7 +46,7 @@
return 0
. = ..()
-/obj/item/gun/ballistic/automatic/magrifle/shoot_live_shot()
+/obj/item/gun/ballistic/automatic/magrifle/shoot_live_shot(mob/living/user, pointblank = FALSE, mob/pbtarget, message = 1, stam_cost = 0)
var/obj/item/ammo_casing/caseless/magnetic/shot = chambered
cell.use(shot.energy_cost)
. = ..()
diff --git a/code/modules/projectiles/guns/ballistic/revolver.dm b/code/modules/projectiles/guns/ballistic/revolver.dm
index 9e43ec052f..b8b5ad6ec3 100644
--- a/code/modules/projectiles/guns/ballistic/revolver.dm
+++ b/code/modules/projectiles/guns/ballistic/revolver.dm
@@ -102,7 +102,7 @@
. = ..()
safe_calibers = magazine.caliber
-/obj/item/gun/ballistic/revolver/detective/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
+/obj/item/gun/ballistic/revolver/detective/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
if(chambered && !(chambered.caliber in safe_calibers))
if(prob(70 - (magazine.ammo_count() * 10))) //minimum probability of 10, maximum of 60
playsound(user, fire_sound, 50, 1)
@@ -242,7 +242,7 @@
user.visible_message("*click*")
playsound(src, "gun_dry_fire", 30, 1)
-/obj/item/gun/ballistic/revolver/russian/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
+/obj/item/gun/ballistic/revolver/russian/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
add_fingerprint(user)
playsound(src, "gun_dry_fire", 30, TRUE)
user.visible_message("[user.name] tries to fire \the [src] at the same time, but only succeeds at looking like an idiot.", "\The [src]'s anti-combat mechanism prevents you from firing it at the same time!")
diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm
index e438b351b3..17f5cc4262 100644
--- a/code/modules/projectiles/guns/ballistic/shotgun.dm
+++ b/code/modules/projectiles/guns/ballistic/shotgun.dm
@@ -116,7 +116,7 @@
icon_state = "moistnugget"
item_state = "moistnugget"
slot_flags = 0 //no ITEM_SLOT_BACK sprite, alas
- inaccuracy_modifier = 0
+ inaccuracy_modifier = 0.5
mag_type = /obj/item/ammo_box/magazine/internal/boltaction
var/bolt_open = FALSE
can_bayonet = TRUE
@@ -191,7 +191,7 @@
/obj/item/gun/ballistic/shotgun/boltaction/enchanted/attack_self()
return
-/obj/item/gun/ballistic/shotgun/boltaction/enchanted/shoot_live_shot(mob/living/user as mob|obj, pointblank = 0, mob/pbtarget = null, message = 1)
+/obj/item/gun/ballistic/shotgun/boltaction/enchanted/shoot_live_shot(mob/living/user, pointblank = FALSE, mob/pbtarget, message = 1, stam_cost = 0)
..()
if(guns_left)
var/obj/item/gun/ballistic/shotgun/boltaction/enchanted/GUN = new gun_type
@@ -205,7 +205,7 @@
// Automatic Shotguns//
-/obj/item/gun/ballistic/shotgun/automatic/shoot_live_shot(mob/living/user as mob|obj)
+/obj/item/gun/ballistic/shotgun/automatic/shoot_live_shot(mob/living/user, pointblank = FALSE, mob/pbtarget, message = 1, stam_cost = 0)
..()
src.pump(user)
diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm
index ff3f127817..8f9e364302 100644
--- a/code/modules/projectiles/guns/energy.dm
+++ b/code/modules/projectiles/guns/energy.dm
@@ -127,12 +127,12 @@
chambered = null //either way, released the prepared shot
recharge_newshot() //try to charge a new shot
-/obj/item/gun/energy/do_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
+/obj/item/gun/energy/do_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
if(!chambered && can_shoot())
process_chamber() // If the gun was drained and then recharged, load a new shot.
return ..()
-/obj/item/gun/energy/do_burst_shot(mob/living/user, atom/target, message = TRUE, params = null, zone_override="", sprd = 0, randomized_gun_spread = 0, randomized_bonus_spread = 0, rand_spr = 0, iteration = 0)
+/obj/item/gun/energy/do_burst_shot(mob/living/user, atom/target, message = TRUE, params = null, zone_override="", sprd = 0, randomized_gun_spread = 0, randomized_bonus_spread = 0, rand_spr = 0, iteration = 0, stam_cost = 0)
if(!chambered && can_shoot())
process_chamber() // Ditto.
return ..()
diff --git a/code/modules/projectiles/guns/energy/dueling.dm b/code/modules/projectiles/guns/energy/dueling.dm
index 7fa81f513f..80bb269b21 100644
--- a/code/modules/projectiles/guns/energy/dueling.dm
+++ b/code/modules/projectiles/guns/energy/dueling.dm
@@ -237,7 +237,7 @@
return FALSE
return TRUE
-/obj/item/gun/energy/dueling/process_fire(atom/target, mob/living/user, message, params, zone_override, bonus_spread)
+/obj/item/gun/energy/dueling/process_fire(atom/target, mob/living/user, message, params, zone_override, bonus_spread = 0, stam_cost = 0)
if(duel.state == DUEL_READY)
duel.confirmations[src] = TRUE
to_chat(user,"You confirm your readiness.")
diff --git a/code/modules/projectiles/guns/energy/energy_gun.dm b/code/modules/projectiles/guns/energy/energy_gun.dm
index 71ee8bc5ef..1b835d35a4 100644
--- a/code/modules/projectiles/guns/energy/energy_gun.dm
+++ b/code/modules/projectiles/guns/energy/energy_gun.dm
@@ -110,7 +110,7 @@
fail_tick--
..()
-/obj/item/gun/energy/e_gun/nuclear/shoot_live_shot()
+/obj/item/gun/energy/e_gun/nuclear/shoot_live_shot(mob/living/user, pointblank = FALSE, mob/pbtarget, message = 1, stam_cost = 0)
failcheck()
update_icon()
..()
diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
index c5660624a2..49c069ca62 100644
--- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
+++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
@@ -60,6 +60,12 @@
else
cut_overlays()
+/obj/item/gun/energy/kinetic_accelerator/getinaccuracy(mob/living/user, bonus_spread, stamloss)
+ var/old_fire_delay = fire_delay //It's pretty irrelevant tbh but whatever.
+ fire_delay = overheat_time
+ . = ..()
+ fire_delay = old_fire_delay
+
/obj/item/gun/energy/kinetic_accelerator/examine(mob/user)
. = ..()
if(max_mod_capacity)
@@ -128,7 +134,7 @@
if(!holds_charge)
empty()
-/obj/item/gun/energy/kinetic_accelerator/shoot_live_shot()
+/obj/item/gun/energy/kinetic_accelerator/shoot_live_shot(mob/living/user, pointblank = FALSE, mob/pbtarget, message = 1, stam_cost = 0)
. = ..()
attempt_reload()
@@ -207,6 +213,12 @@
var/obj/item/gun/energy/kinetic_accelerator/KA = loc
KA.modify_projectile(BB)
+/obj/item/gun/energy/kinetic_accelerator/getstamcost(mob/living/carbon/user)
+ if(user && !lavaland_equipment_pressure_check(get_turf(user)))
+ return 0
+ else
+ return ..()
+
//Projectiles
/obj/item/projectile/kinetic
name = "kinetic force"
diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm
index bcd3a97ccd..72ac9620b5 100644
--- a/code/modules/projectiles/guns/energy/laser.dm
+++ b/code/modules/projectiles/guns/energy/laser.dm
@@ -62,7 +62,7 @@
slot_flags = ITEM_SLOT_BACK
w_class = WEIGHT_CLASS_BULKY
weapon_weight = WEAPON_MEDIUM
- inaccuracy_modifier = 0.5
+ inaccuracy_modifier = 0.7
force = 10
throwforce = 10
cell_type = /obj/item/stock_parts/cell/lascarbine
diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm
index 807b414ce4..b55e26b6a3 100644
--- a/code/modules/projectiles/guns/energy/special.dm
+++ b/code/modules/projectiles/guns/energy/special.dm
@@ -89,7 +89,7 @@
suppressed = TRUE
ammo_type = list(/obj/item/ammo_casing/energy/bolt)
weapon_weight = WEAPON_LIGHT
- inaccuracy_modifier = 0
+ inaccuracy_modifier = 0.25
obj_flags = 0
overheat_time = 20
holds_charge = TRUE
@@ -126,7 +126,7 @@
attack_verb = list("attacked", "slashed", "cut", "sliced")
force = 12
sharpness = IS_SHARP
- inaccuracy_modifier = 0
+ inaccuracy_modifier = 0.25
can_charge = 0
heat = 3800
@@ -182,7 +182,7 @@
item_state = null
icon_state = "wormhole_projector"
pin = null
- inaccuracy_modifier = 0
+ inaccuracy_modifier = 0.25
var/obj/effect/portal/p_blue
var/obj/effect/portal/p_orange
var/atmos_link = FALSE
@@ -318,7 +318,7 @@
icon_state = "emitter_carbine"
force = 12
w_class = WEIGHT_CLASS_SMALL
- inaccuracy_modifier = 0
+ inaccuracy_modifier = 0.25
cell_type = /obj/item/stock_parts/cell/super
ammo_type = list(/obj/item/ammo_casing/energy/emitter)
diff --git a/code/modules/projectiles/guns/magic/staff.dm b/code/modules/projectiles/guns/magic/staff.dm
index c993c0013a..b23b059d89 100644
--- a/code/modules/projectiles/guns/magic/staff.dm
+++ b/code/modules/projectiles/guns/magic/staff.dm
@@ -45,7 +45,7 @@
/obj/item/projectile/magic/death, /obj/item/projectile/magic/teleport, /obj/item/projectile/magic/door, /obj/item/projectile/magic/aoe/fireball,
/obj/item/projectile/magic/spellblade, /obj/item/projectile/magic/arcane_barrage, /obj/item/projectile/magic/locker)
-/obj/item/gun/magic/staff/chaos/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
+/obj/item/gun/magic/staff/chaos/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
chambered.projectile_type = pick(allowed_projectile_types)
. = ..()
diff --git a/code/modules/projectiles/guns/misc/chem_gun.dm b/code/modules/projectiles/guns/misc/chem_gun.dm
index c05ec1c4be..9db5161247 100644
--- a/code/modules/projectiles/guns/misc/chem_gun.dm
+++ b/code/modules/projectiles/guns/misc/chem_gun.dm
@@ -9,7 +9,7 @@
throw_speed = 3
throw_range = 7
force = 4
- inaccuracy_modifier = 0
+ inaccuracy_modifier = 0.25
custom_materials = list(/datum/material/iron=2000)
clumsy_check = FALSE
fire_sound = 'sound/items/syringeproj.ogg'
diff --git a/code/modules/projectiles/guns/misc/grenade_launcher.dm b/code/modules/projectiles/guns/misc/grenade_launcher.dm
index 6113bc4857..86dd0c6ce4 100644
--- a/code/modules/projectiles/guns/misc/grenade_launcher.dm
+++ b/code/modules/projectiles/guns/misc/grenade_launcher.dm
@@ -31,7 +31,7 @@
/obj/item/gun/grenadelauncher/can_shoot()
return grenades.len
-/obj/item/gun/grenadelauncher/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
+/obj/item/gun/grenadelauncher/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
user.visible_message("[user] fired a grenade!", \
"You fire the grenade launcher!")
var/obj/item/grenade/F = grenades[1] //Now with less copypasta!
diff --git a/code/modules/projectiles/guns/misc/medbeam.dm b/code/modules/projectiles/guns/misc/medbeam.dm
index 8d800357df..e841422893 100644
--- a/code/modules/projectiles/guns/misc/medbeam.dm
+++ b/code/modules/projectiles/guns/misc/medbeam.dm
@@ -41,7 +41,7 @@
on_beam_release(current_target)
current_target = null
-/obj/item/gun/medbeam/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
+/obj/item/gun/medbeam/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
if(isliving(user))
add_fingerprint(user)
diff --git a/code/modules/projectiles/guns/misc/syringe_gun.dm b/code/modules/projectiles/guns/misc/syringe_gun.dm
index a5f871bdf0..dc2a1df03a 100644
--- a/code/modules/projectiles/guns/misc/syringe_gun.dm
+++ b/code/modules/projectiles/guns/misc/syringe_gun.dm
@@ -7,7 +7,7 @@
throw_speed = 3
throw_range = 7
force = 4
- inaccuracy_modifier = 0
+ inaccuracy_modifier = 0.25
custom_materials = list(/datum/material/iron=2000)
clumsy_check = 0
fire_sound = 'sound/items/syringeproj.ogg'
@@ -160,7 +160,7 @@
item_state = "blowgun"
fire_sound = 'sound/items/syringeproj.ogg'
-/obj/item/gun/syringe/blowgun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
+/obj/item/gun/syringe/blowgun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
visible_message("[user] starts aiming with a blowgun!")
if(do_after(user, 25, target = src))
user.adjustStaminaLoss(20)
diff --git a/code/modules/vehicles/cars/car.dm b/code/modules/vehicles/cars/car.dm
index dc6cccb9a9..958a4e65c4 100644
--- a/code/modules/vehicles/cars/car.dm
+++ b/code/modules/vehicles/cars/car.dm
@@ -51,10 +51,10 @@
/obj/vehicle/sealed/car/attacked_by(obj/item/I, mob/living/user)
if(!I.force)
- return
+ return FALSE
if(occupants[user])
to_chat(user, "Your attack bounces off of the car's padded interior.")
- return
+ return FALSE
return ..()
/obj/vehicle/sealed/car/attack_hand(mob/living/user)
diff --git a/modular_citadel/code/modules/projectiles/gun.dm b/modular_citadel/code/modules/projectiles/gun.dm
deleted file mode 100644
index 317f68b4c4..0000000000
--- a/modular_citadel/code/modules/projectiles/gun.dm
+++ /dev/null
@@ -1,11 +0,0 @@
-/obj/item/gun/proc/getstamcost(mob/living/carbon/user)
- if(user && user.has_gravity())
- return recoil
- else
- return recoil*5
-
-/obj/item/gun/energy/kinetic_accelerator/getstamcost(mob/living/carbon/user)
- if(user && !lavaland_equipment_pressure_check(get_turf(user)))
- return 0
- else
- return ..()
diff --git a/tgstation.dme b/tgstation.dme
index b7f998e7e4..d9769d4426 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -3407,7 +3407,6 @@
#include "modular_citadel\code\modules\mob\living\carbon\reindex_screams.dm"
#include "modular_citadel\code\modules\mob\living\carbon\human\human.dm"
#include "modular_citadel\code\modules\mob\living\carbon\human\human_defense.dm"
-#include "modular_citadel\code\modules\projectiles\gun.dm"
#include "modular_citadel\code\modules\projectiles\ammunition\caseless.dm"
#include "modular_citadel\code\modules\projectiles\ammunition\ballistic\smg\smg.dm"
#include "modular_citadel\code\modules\projectiles\boxes_magazines\ammo_boxes.dm"