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"