diff --git a/code/modules/mob/living/simple_mob/combat.dm b/code/modules/mob/living/simple_mob/combat.dm index 3ff7eb5b2d..461abcc954 100644 --- a/code/modules/mob/living/simple_mob/combat.dm +++ b/code/modules/mob/living/simple_mob/combat.dm @@ -14,9 +14,9 @@ handle_attack_delay(A, melee_attack_delay) // This will sleep this proc for a bit, which is why waitfor is false. // Cooldown testing is done at click code (for players) and interface code (for AI). - setClickCooldown(get_attack_speed()) + setClickCooldown(get_attack_speed() + ((injury_level / 2) SECONDS)) // CHOMPStation Edit: Delay how fast we can attack by our injury level / 2 - // Returns a value, but will be lost if + // Returns a value, but will be lost if . = do_attack(A, their_T) if(melee_attack_delay) @@ -90,7 +90,7 @@ if(!istype(A) || QDELETED(A)) return - setClickCooldown(get_attack_speed()) + setClickCooldown(get_attack_speed() + ((injury_level / 2) SECONDS)) // CHOMPStation Edit: Delay how fast we can attack by our injury level / 2 face_atom(A) @@ -102,7 +102,7 @@ if(reload_count >= reload_max) try_reload() return FALSE - + //CHOMP Addition: This section here is special snowflake code for metroids only, or for whatever else in the future that you want to have move and shoot at the same time. Basically, this is a non-stupid version of the above intended for ranged vore mobs i.e. metroids. ranged_attack_delay is stupid because it sleeps the entire mob. This new ranged_cooldown_time is smarter in the sense that it is an internalized timer. Try not to confuse the names. if(ranged_cooldown_time) //If you have a non-zero number in a mob's variables, this pattern begins. if(ranged_cooldown <= world.time) //Further down, a timer keeps adding to the ranged_cooldown variable automatically. @@ -110,7 +110,7 @@ shoot(A) //Perform the shoot action if(casingtype) //If the mob is designated to leave casings... new casingtype(loc) //... leave the casing. - ranged_cooldown = world.time + ranged_cooldown_time //Special addition here. This is a timer. Keeping updating the time after shooting. Add that ranged cooldown time specified in the mob to the world time. + ranged_cooldown = world.time + ranged_cooldown_time + ((injury_level / 2) SECONDS) //Special addition here. This is a timer. Keeping updating the time after shooting. Add that ranged cooldown time specified in the mob to the world time. return TRUE //End these commands here. visible_message("\The [src] fires at \the [A]!") @@ -120,7 +120,7 @@ if(ranged_attack_delay) ranged_post_animation(A) - + return TRUE // Shoot a bullet at something. @@ -268,4 +268,4 @@ /mob/living/simple_mob/proc/special_pre_animation(atom/A) do_windup_animation(A, special_attack_delay) // Semi-placeholder. -/mob/living/simple_mob/proc/special_post_animation(atom/A) \ No newline at end of file +/mob/living/simple_mob/proc/special_post_animation(atom/A) diff --git a/code/modules/mob/living/simple_mob/simple_mob.dm b/code/modules/mob/living/simple_mob/simple_mob.dm index 7aeee0011a..a5f66b3af4 100644 --- a/code/modules/mob/living/simple_mob/simple_mob.dm +++ b/code/modules/mob/living/simple_mob/simple_mob.dm @@ -170,6 +170,11 @@ var/obj/item/weapon/card/id/mobcard = null //VOREStation Edit var/list/mobcard_access = list() //VOREStation Edit var/mobcard_provided = FALSE //VOREStation Edit + // CHOMPStation Add: Move/Shoot/Attack delays based on damage + var/damage_fatigue_mult = 1 // Our multiplier for how heavily mobs are affected by injury. [UPDATE THIS IF THE FORMULA CHANGES]: Formula = injury_level = round(rand(2,6) * damage_fatigue_mult * clamp(((rand(2,5) * (health / getMaxHealth())) - rand(0,2)), 1, 20)) + var/injury_level = 0 // What our injury level is. Rather than being the flat damage, this is the amount added to various delays to simulate injuries in a manner as lightweight as possible. + var/threshold = 0.6 // When we start slowing down. Configure this setting per-mob. Default is 60% + // CHOMPStation Add End /mob/living/simple_mob/Initialize() verbs -= /mob/verb/observe @@ -269,9 +274,11 @@ if(m_intent == "walk") . *= 1.5 - . += config.animal_delay + . += injury_level // CHOMPStation Edit: Adding our injury level delay to our total - . += ..() + . += config.animal_delay + + . += ..() /mob/living/simple_mob/Stat() @@ -327,3 +334,21 @@ else ..() //Vorestation Add End + +/* + * CHOMPStation Add + * How injured are we? Returns a number that is then added to movement cooldown and firing/melee delay respectively. + * Called by movement_delay and our firing/melee delay checks +*/ +/mob/living/simple_mob/proc/get_injury_level(var/mob/living/simple_mob/M) + var/h = getMaxHealth() - getOxyLoss() - getToxLoss() - getFireLoss() - getBruteLoss() - getCloneLoss() - halloss // We're not updating our actual health here bc we want updatehealth() and other checks to handle that + if(h > 0) // Safety to prevent division by 0 errors + if((h / getMaxHealth()) <= threshold) // Essentially, did our health go down? We don't modify want to modify our total slowdown if we didn't actually take damage, and aren't below our threshold % + var/totaldelay = round(rand(2,6) * damage_fatigue_mult * clamp(((rand(2,5) * (h / getMaxHealth())) - rand(0,2)), 1, 20)) // totaldelay is how much delay we're going to feed into attacks and movement. Do NOT change this formula unless you know how to math. + injury_level = totaldelay // Adds our returned slowdown to the mob's injury level + +/mob/living/simple_mob/updatehealth() // We don't want to fully override the check, just hook our own code in + get_injury_level() // We check how injured we are, then actually update the mob on how hurt we are. + . = ..() // Calling parent here, actually updating our mob on how hurt we are. + +// CHOMPStation Add End diff --git a/code/modules/mob/living/simple_mob/subtypes/humanoid/mercs/mercs.dm b/code/modules/mob/living/simple_mob/subtypes/humanoid/mercs/mercs.dm index 14e28d049c..9ae28c6e6e 100644 --- a/code/modules/mob/living/simple_mob/subtypes/humanoid/mercs/mercs.dm +++ b/code/modules/mob/living/simple_mob/subtypes/humanoid/mercs/mercs.dm @@ -286,7 +286,8 @@ ai_holder_type = /datum/ai_holder/simple_mob/merc/ranged/sniper - ranged_attack_delay = 2.5 SECONDS + //ranged_attack_delay = 2.5 SECONDS // CHOMPStation Removal: Ranged attack delay is stupid. + ranged_cooldown_time = 2 SECONDS // CHOMPStation Add: Use this for sniper cooldown instead. loot_list = list(/obj/item/sniper_rifle_part/barrel = 50, /obj/item/sniper_rifle_part/stock = 50, @@ -326,6 +327,21 @@ try_reload() return FALSE + /* + * CHOMP Addition: This section here is (duplicated) special snowflake code because sniper does not call parent. Basically, this is a non-stupid version of the above intended for ranged mobs. + * ranged_attack_delay is stupid because it sleeps the entire mob. + * This new ranged_cooldown_time is smarter in the sense that it is an internalized timer. Try not to confuse the names. + */ + if(ranged_cooldown_time) //If you have a non-zero number in a mob's variables, this pattern begins. + if(ranged_cooldown <= world.time) //Further down, a timer keeps adding to the ranged_cooldown variable automatically. + visible_message("\The [src] fires at \the [A]!") //Leave notice of shooting. + shoot(A) //Perform the shoot action + if(casingtype) //If the mob is designated to leave casings... + new casingtype(loc) //... leave the casing. + ranged_cooldown = world.time + ranged_cooldown_time + ((injury_level / 2) SECONDS) //Special addition here. This is a timer. Keeping updating the time after shooting. Add that ranged cooldown time specified in the mob to the world time. + return TRUE //End these commands here. + // CHOMPAddition End + visible_message("\The [src] fires at \the [orig_targ]!") shoot(A) if(casingtype) diff --git a/code/modules/tension/tension.dm b/code/modules/tension/tension.dm index aa95662849..9cfd68de17 100644 --- a/code/modules/tension/tension.dm +++ b/code/modules/tension/tension.dm @@ -28,7 +28,7 @@ potential_damage = (melee_damage_lower + melee_damage_upper) / 2 // Treat potential_damage as estimated DPS. If the enemy attacks twice as fast as usual, it will double the number. - potential_damage *= 1 SECOND / (base_attack_cooldown + melee_attack_delay) + potential_damage *= 1 SECOND / (base_attack_cooldown + melee_attack_delay + injury_level) // CHOMPStation Add: Injury level should affect potential damage, thereby increasing the threat level else var/obj/item/projectile/P = new projectiletype(src) if(P.nodamage || P.taser_effect) // Tasers are somewhat less scary. @@ -41,7 +41,7 @@ potential_damage += P.agony / 2 qdel(P) - potential_damage *= 1 SECOND / (base_attack_cooldown + ranged_attack_delay) + potential_damage *= 1 SECOND / (base_attack_cooldown + ranged_attack_delay + injury_level) // CHOMPStation Add: Injury level should affect potential damage, thereby increasing the threat level // Special attacks are ultra-specific to the mob so a generic threat assessment isn't really possible.