diff --git a/_maps/map_files/PubbyStation/job_changes.dm b/_maps/map_files/PubbyStation/job_changes.dm deleted file mode 100644 index 726601725b..0000000000 --- a/_maps/map_files/PubbyStation/job_changes.dm +++ /dev/null @@ -1,20 +0,0 @@ -#define JOB_MODIFICATION_MAP_NAME "PubbyStation" - -/datum/job/hos/New() - ..() - MAP_JOB_CHECK - access += ACCESS_CREMATORIUM - minimal_access += ACCESS_CREMATORIUM - -/datum/job/warden/New() - ..() - MAP_JOB_CHECK - access += ACCESS_CREMATORIUM - minimal_access += ACCESS_CREMATORIUM - -/datum/job/officer/New() - ..() - MAP_JOB_CHECK - access += ACCESS_CREMATORIUM - minimal_access += ACCESS_CREMATORIUM - diff --git a/_maps/pubbystation.json b/_maps/pubbystation.json index f99cca57c5..acf49b773b 100644 --- a/_maps/pubbystation.json +++ b/_maps/pubbystation.json @@ -7,5 +7,10 @@ "whiteship": "whiteship_pubby", "ferry": "ferry_fancy", "cargo": "cargo_box" - } + }, + "job_access_add": { + "/datum/job/hos": [27], + "/datum/job/officer": [27], + "/datum/job/detective": [27] + } } diff --git a/code/__DEFINES/_flags/item_flags.dm b/code/__DEFINES/_flags/item_flags.dm index 26e764c45b..7da71e22cb 100644 --- a/code/__DEFINES/_flags/item_flags.dm +++ b/code/__DEFINES/_flags/item_flags.dm @@ -22,12 +22,10 @@ #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) /// This item can be used to parry. Only a basic check used to determine if we should proceed with parry chain at all. -#define ITEM_CAN_PARRY (1<<13) +#define ITEM_CAN_PARRY (1<<12) /// This item can be used in the directional blocking system. Only a basic check used to determine if we should proceed with directional block handling at all. -#define ITEM_CAN_BLOCK (1<<14) +#define ITEM_CAN_BLOCK (1<<13) // Flags for the clothing_flags var on /obj/item/clothing diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index eff5d9eca9..5f5a76b58d 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -34,6 +34,8 @@ #define COMBAT_FLAGS_DEFAULT (COMBAT_FLAG_PARRY_CAPABLE | COMBAT_FLAG_BLOCK_CAPABLE) /// Default combat flags for everyone else (so literally everyone but humans). #define COMBAT_FLAGS_SPRINT_EXEMPT (COMBAT_FLAG_SPRINT_ACTIVE | COMBAT_FLAG_SPRINT_TOGGLED | COMBAT_FLAG_SPRINT_FORCED | COMBAT_FLAG_PARRY_CAPABLE | COMBAT_FLAG_BLOCK_CAPABLE) +/// Default combat flags for those in stamina combat system +#define COMBAT_FLAGS_STAMINA_COMBAT (COMBAT_FLAG_PARRY_CAPABLE | COMBAT_FLAG_BLOCK_CAPABLE | COMBAT_FLAG_STAMINA_BUFFER) /// The user wants sprint mode on #define COMBAT_FLAG_SPRINT_TOGGLED (1<<0) @@ -47,8 +49,8 @@ #define COMBAT_FLAG_RESISTING_REST (1<<4) /// Intentionally resting #define COMBAT_FLAG_INTENTIONALLY_RESTING (1<<5) -/// Currently stamcritted but not as violently -#define COMBAT_FLAG_SOFT_STAMCRIT (1<<6) +/// This mob requires stamina buffer to do things that require stamina buffer. Not having this exempts the mob from stamina combat. +#define COMBAT_FLAG_STAMINA_BUFFER (1<<6) /// Force sprint mode on at all times, overrides everything including sprint disable traits. #define COMBAT_FLAG_SPRINT_FORCED (1<<7) /// This mob is capable of using the active parrying system. @@ -64,26 +66,17 @@ // Helpers for getting someone's stamcrit state. Cast to living. #define NOT_STAMCRIT 0 -#define SOFT_STAMCRIT 1 -#define HARD_STAMCRIT 2 +#define HARD_STAMCRIT 1 // Stamcrit check helpers #define IS_STAMCRIT(mob) (CHECK_STAMCRIT(mob) != NOT_STAMCRIT) -#define CHECK_STAMCRIT(mob) ((mob.combat_flags & COMBAT_FLAG_HARD_STAMCRIT)? HARD_STAMCRIT : ((mob.combat_flags & COMBAT_FLAG_SOFT_STAMCRIT)? SOFT_STAMCRIT : NOT_STAMCRIT)) +#define CHECK_STAMCRIT(mob) (mob.combat_flags & COMBAT_FLAG_HARD_STAMCRIT) //stamina stuff -///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 +/// 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 +/// Threshold under for which you are unable to draw from stamina health to replace stamina buffer +#define STAMINA_NO_OVERDRAW_THRESHOLD 100 #define CRAWLUNDER_DELAY 30 //Delay for crawling under a standing mob @@ -252,36 +245,6 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list( //We will round to this value in damage calculations. #define DAMAGE_PRECISION 0.01 -//items total mass, used to calculate their attacks' stamina costs. If not defined, the cost will be (w_class * 1.25) -#define TOTAL_MASS_TINY_ITEM 1.25 -#define TOTAL_MASS_SMALL_ITEM 2.5 -#define TOTAL_MASS_NORMAL_ITEM 3.75 -#define TOTAL_MASS_BULKY_ITEM 5 -#define TOTAL_MASS_HUGE_ITEM 6.25 -#define TOTAL_MASS_GIGANTIC_ITEM 7.5 - -#define TOTAL_MASS_HAND_REPLACEMENT 5 //standard punching stamina cost. most hand replacements are huge items anyway. -#define TOTAL_MASS_MEDIEVAL_WEAPON 3.6 //very, very generic average sword/warpick/etc. weight in pounds. -#define TOTAL_MASS_TOY_SWORD 1.5 - -//stamina cost defines. -#define STAM_COST_ATTACK_OBJ_MULT 1.2 -#define STAM_COST_ATTACK_MOB_MULT 1 -#define STAM_COST_BATON_MOB_MULT 1 -#define STAM_COST_NO_COMBAT_MULT 1.25 -#define STAM_COST_W_CLASS_MULT 1.25 -#define STAM_COST_THROW_MULT 2 -#define STAM_COST_THROW_MOB 2.5 //multiplied by (mob size + 1)^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.7 -/// 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 - //stamina recovery defines. Blocked if combat mode is on. #define STAM_RECOVERY_STAM_CRIT -7.5 #define STAM_RECOVERY_RESTING -6 diff --git a/code/__DEFINES/combat/stamina_combat.dm b/code/__DEFINES/combat/stamina_combat.dm new file mode 100644 index 0000000000..1f781ca3e0 --- /dev/null +++ b/code/__DEFINES/combat/stamina_combat.dm @@ -0,0 +1,35 @@ +// Stamina Buffer + +// Standard amounts for stamina usage + +// Multipliers +/// Base stamina cost for an item of a certain w_class without total_mass set. +#define STAM_COST_W_CLASS_MULT 1.25 + +// Flat amounts +/// Usage for eyestabbing with a screwdriver +#define STAMINA_COST_ITEM_EYESTAB 7.5 +/// Usage for shoving yourself off the ground instantly +#define STAMINA_COST_SHOVE_UP 10 + +//items total mass, used to calculate their attacks' stamina costs. If not defined, the cost will be (w_class * 1.25) +#define TOTAL_MASS_TINY_ITEM 1.25 +#define TOTAL_MASS_SMALL_ITEM 2.5 +#define TOTAL_MASS_NORMAL_ITEM 3.75 +#define TOTAL_MASS_BULKY_ITEM 5 +#define TOTAL_MASS_HUGE_ITEM 6.25 +#define TOTAL_MASS_GIGANTIC_ITEM 7.5 + +#define TOTAL_MASS_HAND_REPLACEMENT 5 //standard punching stamina cost. most hand replacements are huge items anyway. +#define TOTAL_MASS_MEDIEVAL_WEAPON 3.6 //very, very generic average sword/warpick/etc. weight in pounds. +#define TOTAL_MASS_TOY_SWORD 1.5 + +//stamina cost defines. +#define STAM_COST_ATTACK_OBJ_MULT 0.75 +#define STAM_COST_ATTACK_MOB_MULT 1 +#define STAM_COST_BATON_MOB_MULT 0.85 +#define STAM_COST_THROW_MULT 0.75 +#define STAM_COST_THROW_MOB 1.25 //multiplied by (mob size + 1)^2. + +/// Damage penalty when fighting prone. +#define LYING_DAMAGE_PENALTY 0.7 diff --git a/code/__DEFINES/configuration.dm b/code/__DEFINES/configuration.dm index 20c1df2ec7..0428a16828 100644 --- a/code/__DEFINES/configuration.dm +++ b/code/__DEFINES/configuration.dm @@ -3,6 +3,8 @@ #define CONFIG_SET(X, Y) global.config.Set(/datum/config_entry/##X, ##Y) /// Gets the datum of the object, for when editing a const define. #define CONFIG_GET_ENTRY(X) global.config.GetEntryDatum(/datum/config_entry/##X) +/// Caches an entry in the proc +#define CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(X, varname) var/static/datum/config_entry/##X/entrycache_##varname;if(!entrycache_##varname){entrycache_##varname=CONFIG_GET_ENTRY(##X);};var/##varname=entrycache_##varname.config_entry_value #define CONFIG_MAPS_FILE "maps.txt" diff --git a/code/__DEFINES/maps.dm b/code/__DEFINES/maps.dm index c5c2dd58c2..854b6c9dcf 100644 --- a/code/__DEFINES/maps.dm +++ b/code/__DEFINES/maps.dm @@ -20,11 +20,6 @@ Multi-Z stations are supported and multi-Z mining and away missions would require only minor tweaks. */ -// helpers for modifying jobs, used in various job_changes.dm files -#define MAP_JOB_CHECK if(SSmapping.config.map_name != JOB_MODIFICATION_MAP_NAME) { return; } -#define MAP_JOB_CHECK_BASE if(SSmapping.config.map_name != JOB_MODIFICATION_MAP_NAME) { return ..(); } -#define MAP_REMOVE_JOB(jobpath) /datum/job/##jobpath/map_check() { return (SSmapping.config.map_name != JOB_MODIFICATION_MAP_NAME) && ..() } - #define SPACERUIN_MAP_EDGE_PAD 15 // traits diff --git a/code/__DEFINES/skills/defines.dm b/code/__DEFINES/skills/defines.dm index 47aaeeb1dc..a0b34895df 100644 --- a/code/__DEFINES/skills/defines.dm +++ b/code/__DEFINES/skills/defines.dm @@ -40,7 +40,6 @@ #define SKILL_TRAIN_ATTACK_OBJ "train_attack_obj" #define SKILL_STAMINA_COST "stamina_cost" //Influences the stamina cost from weapon usage. #define SKILL_THROW_STAM_COST "throw_stam_cost" -#define SKILL_COMBAT_MODE "combat_mode" //The user must have combat mode on. #define SKILL_SANITY "sanity" //Is the skill affected by (in)sanity. #define SKILL_INTELLIGENCE "intelligence" //Is the skill affected by brain damage? diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index a5190af23a..520f205381 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -208,6 +208,10 @@ #define TRAIT_FAST_PUMP "fast_pump" #define TRAIT_NO_PROCESS_FOOD "no-process-food" // You don't get benefits from nutriment, nor nutrition from reagent consumables #define TRAIT_NICE_SHOT "nice_shot" //hnnnnnnnggggg..... you're pretty good... +/// Prevents stamina buffer regeneration +#define TRAIT_NO_STAMINA_BUFFER_REGENERATION "block_stamina_buffer_regen" +/// Prevents stamina regeneration +#define TRAIT_NO_STAMINA_REGENERATION "block_stamina_regen" // mobility flag traits // IN THE FUTURE, IT WOULD BE NICE TO DO SOMETHING SIMILAR TO https://github.com/tgstation/tgstation/pull/48923/files (ofcourse not nearly the same because I have my.. thoughts on it) diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 85f5e4fd9b..b558b28cf2 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -252,7 +252,6 @@ GLOBAL_LIST_INIT(bitfields, list( "COMBAT_FLAG_SPRINT_ACTIVE" = COMBAT_FLAG_SPRINT_ACTIVE, "COMBAT_FLAG_ATTEMPTING_CRAWL" = COMBAT_FLAG_ATTEMPTING_CRAWL, "COMBAT_FLAG_HARD_STAMCRIT" = COMBAT_FLAG_HARD_STAMCRIT, - "COMBAT_FLAG_SOFT_STAMCRIT" = COMBAT_FLAG_SOFT_STAMCRIT, "COMBAT_FLAG_INTENTIONALLY_RESTING" = COMBAT_FLAG_INTENTIONALLY_RESTING, "COMBAT_FLAG_RESISTING_REST" = COMBAT_FLAG_RESISTING_REST, "COMBAT_FLAG_SPRINT_FORCED" = COMBAT_FLAG_SPRINT_FORCED diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm index 134f9d9cbe..64bac1f9af 100644 --- a/code/_globalvars/lists/mobs.dm +++ b/code/_globalvars/lists/mobs.dm @@ -40,6 +40,7 @@ GLOBAL_LIST_EMPTY(sentient_disease_instances) GLOBAL_LIST_EMPTY(latejoin_ai_cores) GLOBAL_LIST_EMPTY(mob_config_movespeed_type_lookup) +GLOBAL_LIST_EMPTY(mob_config_movespeed_type_lookup_floating) GLOBAL_LIST_EMPTY(latejoiners) //CIT CHANGE - All latejoining people, for traitor-target purposes. @@ -47,14 +48,22 @@ GLOBAL_LIST_EMPTY(latejoiners) //CIT CHANGE - All latejoining people, for traito // NOTE: This is entirely based on the fact that byond typesof/subtypesof gets longer/deeper paths before shallower ones. // If that ever breaks this entire proc breaks. var/list/mob_types = typesof(/mob) - var/list/entry_value = CONFIG_GET(keyed_list/multiplicative_movespeed) + var/list/mob_types_floating = typesof(/mob) + var/list/entry_value = CONFIG_GET(keyed_list/multiplicative_movespeed/normal) + var/list/entry_value_floating = CONFIG_GET(keyed_list/multiplicative_movespeed/floating) var/list/configured_types = list() + var/list/configured_types_floating = list() for(var/path in entry_value) var/value = entry_value[path] if(isnull(value)) continue // associative list sets for elements that already exist preserve order mob_types[path] = value + for(var/path in entry_value_floating) + var/value = entry_value_floating[path] + if(isnull(value)) + continue + mob_types_floating[path] = value // now go back up through it to set everything, making absolute sure that base paths are overridden by child paths all the way down the path tree. for(var/i in length(mob_types) to 1 step -1) var/path = mob_types[i] @@ -63,7 +72,14 @@ GLOBAL_LIST_EMPTY(latejoiners) //CIT CHANGE - All latejoining people, for traito // we're going from bottom to top so it should be safe to do this without further checks.. for(var/subpath in typesof(path)) configured_types[subpath] = mob_types[path] + for(var/i in length(mob_types_floating) to 1 step -1) + var/path = mob_types_floating[i] + if(isnull(mob_types_floating[path])) + continue + for(var/subpath in typesof(path)) + configured_types_floating[subpath] = mob_types_floating[path] GLOB.mob_config_movespeed_type_lookup = configured_types + GLOB.mob_config_movespeed_type_lookup_floating = configured_types_floating if(update_mobs) update_mob_config_movespeeds() diff --git a/code/_onclick/hud/screen_objects/stamina.dm b/code/_onclick/hud/screen_objects/stamina.dm index 5484014f8f..98a387d32d 100644 --- a/code/_onclick/hud/screen_objects/stamina.dm +++ b/code/_onclick/hud/screen_objects/stamina.dm @@ -11,7 +11,9 @@ /obj/screen/staminas/Click(location,control,params) if(isliving(usr)) var/mob/living/L = usr - to_chat(L, "You have [L.getStaminaLoss()] stamina loss.
Your stamina buffer can take [L.stambuffer] stamina loss, and recharges at no cost.
Your stamina buffer is [(L.stambuffer*(100/L.stambuffer))-(L.bufferedstam*(100/L.stambuffer))]% full.
") + CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(number/stamina_combat/buffer_max, buffer_max) + to_chat(L, "You have [L.getStaminaLoss()] stamina loss.
\ +
Your stamina buffer is [round((L.stamina_buffer / buffer_max) * 100, 0.1)]% full.
") /obj/screen/staminas/update_icon_state() var/mob/living/carbon/user = hud?.mymob @@ -24,6 +26,19 @@ else icon_state = "stamina[clamp(FLOOR(user.getStaminaLoss() /20, 1), 0, 6)]" +/obj/screen/staminas/update_overlays() + . = ..() + var/mob/living/carbon/user = hud?.mymob + if(!user) + return + var/percent = user.getStaminaLoss() / STAMINA_CRIT + if((user.stat == DEAD) || (user.combat_flags & COMBAT_FLAG_HARD_STAMCRIT) || (user.hal_screwyhud in 1 to 2)) + . += list("stamina_alert3") + else if(percent >= 0.85) + . += list("stamina_alert2") + else if(percent >= 0.7) + . += list("stamina_alert1") + //stam buffer /obj/screen/staminabuffer icon = 'modular_citadel/icons/ui/screen_gen.dmi' @@ -33,29 +48,33 @@ layer = ABOVE_HUD_LAYER + 0.1 mouse_opacity = 0 -/obj/screen/staminabuffer/update_icon_state() +/obj/screen/staminabuffer/proc/mark_dirty() + if(update_to_mob()) + START_PROCESSING(SShuds, src) + +/obj/screen/staminabuffer/process() + if(!update_to_mob()) + return PROCESS_KILL + +/obj/screen/staminabuffer/Destroy() + STOP_PROCESSING(SShuds, src) + return ..() + +/obj/screen/staminabuffer/proc/update_to_mob() var/mob/living/carbon/user = hud?.mymob - if(!user) - return + user.UpdateStaminaBuffer(FALSE) + CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(number/stamina_combat/buffer_max, buffer_max) + if(!user?.client) + return FALSE if(user.stat == DEAD || (user.combat_flags & COMBAT_FLAG_HARD_STAMCRIT) || (user.hal_screwyhud in 1 to 2)) - icon_state = "stambuffer7" - else if(user.hal_screwyhud == 5) icon_state = "stambuffer0" + return FALSE + else if(user.hal_screwyhud == 5) + icon_state = "stambuffer29" + return FALSE + else if(user.stamina_buffer >= buffer_max) + icon_state = "stambuffer29" + return FALSE else - switch(user.bufferedstam / user.stambuffer) - if(0.95 to INFINITY) - icon_state = "stambuffer7" - if(0.9 to 0.95) - icon_state = "stambuffer6" - if(0.8 to 0.9) - icon_state = "stambuffer5" - if(0.6 to 0.8) - icon_state = "stambuffer4" - if(0.4 to 0.6) - icon_state = "stambuffer3" - if(0.2 to 0.4) - icon_state = "stambuffer2" - if(0.05 to 0.2) - icon_state = "stambuffer1" - else - icon_state = "stambuffer0" + icon_state = "stambuffer[FLOOR((user.stamina_buffer / buffer_max) * 29, 1)]" + return TRUE diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 9e88476513..cd1ee56848 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -85,6 +85,9 @@ if(force && damtype != STAMINA && HAS_TRAIT(user, TRAIT_PACIFISM)) to_chat(user, "You don't want to harm other living beings!") return + + if(!UseStaminaBufferStandard(user, STAM_COST_ATTACK_MOB_MULT, null, TRUE)) + return DISCARD_LAST_ACTION if(!force) playsound(loc, 'sound/weapons/tap.ogg', get_clamped_volume(), 1, -1) @@ -100,10 +103,6 @@ log_combat(user, M, "attacked", src.name, "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])") add_fingerprint(user) - var/weight = getweight(user, STAM_COST_ATTACK_MOB_MULT) //CIT CHANGE - makes attacking things cause stamina loss - if(weight) - user.adjustStaminaLossBuffered(weight) - // CIT SCREENSHAKE if(force >= 15) shake_camera(user, ((force - 10) * 0.01 + 1), ((force - 10) * 0.01)) @@ -120,31 +119,21 @@ if(SEND_SIGNAL(src, COMSIG_ITEM_ATTACK_OBJ, O, user) & COMPONENT_NO_ATTACK_OBJ) return if(item_flags & NOBLUDGEON) - return + return DISCARD_LAST_ACTION + if(!UseStaminaBufferStandard(user, STAM_COST_ATTACK_OBJ_MULT, warn = TRUE)) + return DISCARD_LAST_ACTION user.do_attack_animation(O) O.attacked_by(src, user) - 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 /obj/attacked_by(obj/item/I, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1) var/totitemdamage = I.force * damage_multiplier - var/bad_trait - - 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_ITEM_ATTACK_PENALTY - totitemdamage *= 1 - penalty - - 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) + totitemdamage = user.mind.item_action_skills_mod(I, totitemdamage, I.skill_difficulty, SKILL_ATTACK_OBJ) for(var/skill in I.used_skills) if(!(SKILL_TRAIN_ATTACK_OBJ in I.used_skills[skill])) continue @@ -187,28 +176,15 @@ if(!.) return - var/stamloss = user.getStaminaLoss() var/stam_mobility_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 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 - var/bad_trait - 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.8 - else if(SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE)) - . *= 1.2 - if(!user.mind || !I.used_skills) return if(.) - . = user.mind.item_action_skills_mod(I, ., I.skill_difficulty, SKILL_ATTACK_MOB, bad_trait) + . = user.mind.item_action_skills_mod(I, ., I.skill_difficulty, SKILL_ATTACK_MOB) for(var/skill in I.used_skills) if(!(SKILL_TRAIN_ATTACK_MOB in I.used_skills[skill])) continue @@ -263,21 +239,23 @@ . = (total_mass || w_class * STAM_COST_W_CLASS_MULT) * multiplier if(!user) return - var/bad_trait - if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE)) - . *= STAM_COST_NO_COMBAT_MULT - 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) + . = user.mind.item_action_skills_mod(src, ., skill_difficulty, trait, null, FALSE) + +/** + * Uses the amount of stamina required for a standard hit + */ +/obj/item/proc/UseStaminaBufferStandard(mob/living/user, multiplier = 1, trait = SKILL_STAMINA_COST, warn = TRUE) + ASSERT(user) + var/cost = getweight(user, multiplier, trait) + return user.UseStaminaBuffer(cost, warn) /// How long this staggers for. 0 and negatives supported. /obj/item/proc/melee_stagger_duration(force_override) if(!isnull(stagger_force)) return stagger_force /// totally not an untested, arbitrary equation. - return clamp((1.5 + (w_class/7.5)) * ((force_override || force) / 2), 0, 10 SECONDS) + return clamp((1.5 + (w_class/5)) * ((force_override || force) / 1.5), 0, 10 SECONDS) /obj/item/proc/do_stagger_action(mob/living/target, mob/living/user, force_override) if(!CHECK_BITFIELD(target.status_flags, CANSTAGGER)) diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm index 8f55293820..c91ac2e0d4 100644 --- a/code/controllers/configuration/entries/game_options.dm +++ b/code/controllers/configuration/entries/game_options.dm @@ -230,14 +230,6 @@ /datum/config_entry/keyed_list/multiplicative_movespeed key_mode = KEY_MODE_TYPE value_mode = VALUE_MODE_NUM - config_entry_value = list( //DEFAULTS - /mob/living/simple_animal = 1, - /mob/living/silicon/pai = 1, - /mob/living/carbon/alien/humanoid/sentinel = 0.25, - /mob/living/carbon/alien/humanoid/drone = 0.5, - /mob/living/carbon/alien/humanoid/royal/praetorian = 1, - /mob/living/carbon/alien/humanoid/royal/queen = 3 - ) /datum/config_entry/keyed_list/multiplicative_movespeed/ValidateAndSet() . = ..() @@ -249,6 +241,24 @@ if(. && (var_name == NAMEOF(src, config_entry_value))) update_config_movespeed_type_lookup(TRUE) +/datum/config_entry/keyed_list/multiplicative_movespeed/normal + config_entry_value = list( //DEFAULTS + /mob/living/simple_animal = 1, + /mob/living/silicon/pai = 1, + /mob/living/carbon/alien/humanoid/sentinel = 0.25, + /mob/living/carbon/alien/humanoid/drone = 0.5, + /mob/living/carbon/alien/humanoid/royal/praetorian = 1, + /mob/living/carbon/alien/humanoid/royal/queen = 3 + ) + +/datum/config_entry/keyed_list/multiplicative_movespeed/floating + config_entry_value = list( + /mob/living = 0, + /mob/living/carbon/alien/humanoid = 0, + /mob/living/carbon/alien/humanoid/royal/praetorian = 0, + /mob/living/carbon/alien/humanoid/royal/queen = 2 + ) + /datum/config_entry/number/movedelay //Used for modifying movement speed for mobs. abstract_type = /datum/config_entry/number/movedelay integer = FALSE @@ -280,6 +290,12 @@ /datum/config_entry/number/movedelay/sprint_speed_increase config_entry_value = 1 +/datum/config_entry/number/movedelay/sprint_max_tiles_increase + config_entry_value = 5 + +/datum/config_entry/number/movedelay/sprint_absolute_max_tiles + config_entry_value = 13 + /datum/config_entry/number/movedelay/sprint_buffer_max config_entry_value = 24 @@ -291,7 +307,7 @@ /////////////////////////////////////////////////Outdated move delay /datum/config_entry/number/outdated_movedelay - deprecated_by = /datum/config_entry/keyed_list/multiplicative_movespeed + deprecated_by = /datum/config_entry/keyed_list/multiplicative_movespeed/normal abstract_type = /datum/config_entry/number/outdated_movedelay var/movedelay_type diff --git a/code/controllers/configuration/entries/stamina_combat.dm b/code/controllers/configuration/entries/stamina_combat.dm new file mode 100644 index 0000000000..65580899f1 --- /dev/null +++ b/code/controllers/configuration/entries/stamina_combat.dm @@ -0,0 +1,35 @@ +/datum/config_entry/number/stamina_combat + integer = FALSE + abstract_type = /datum/config_entry/number/stamina_combat + +/// Maximum stamina buffer +/datum/config_entry/number/stamina_combat/buffer_max + config_entry_value = 25 + +/// Seconds until percent_regeneration_out_of_combat kicks in +/datum/config_entry/number/stamina_combat/out_of_combat_timer + config_entry_value = 15 + +/// Base regeneration per second +/datum/config_entry/number/stamina_combat/base_regeneration + config_entry_value = 0.5 + +/// Combat mode regeneration per second +/datum/config_entry/number/stamina_combat/combat_regeneration + config_entry_value = 5 + +/// After out_of_combat_timer elapses, additionally regenerate this percent of total stamina per second. Unaffected by combat mode. +/datum/config_entry/number/stamina_combat/percent_regeneration_out_of_combat + config_entry_value = 30 + +/// Seconds after an action for which your regeneration is penalized +/datum/config_entry/number/stamina_combat/post_action_penalty_delay + config_entry_value = 5 + +/// Factor to multiply by for penalizing post-action-stamina-regen +/datum/config_entry/number/stamina_combat/post_action_penalty_factor + config_entry_value = 0.25 + +/// Factor to multiply by for stamina usage past buffer into health +/datum/config_entry/number/stamina_combat/overdraw_penalty_factor + config_entry_value = 1.5 diff --git a/code/controllers/subsystem/input.dm b/code/controllers/subsystem/input.dm index 32936af9e9..bc3f6cf51b 100644 --- a/code/controllers/subsystem/input.dm +++ b/code/controllers/subsystem/input.dm @@ -64,10 +64,10 @@ SUBSYSTEM_DEF(input) // Misc macroset_classic_input["Tab"] = "\".winset \\\"mainwindow.macro=[SKIN_MACROSET_CLASSIC_HOTKEYS] map.focus=true input.background-color=[COLOR_INPUT_DISABLED]\\\"\"" macroset_classic_input["Escape"] = "\".winset \\\"input.text=\\\"\\\"\\\"\"" - + // FINALLY, WE CAN DO SOMETHING MORE NORMAL FOR THE SNOWFLAKE-BUT-LESS KEYSET. - - // HAHA - SIKE. Because of BYOND weirdness (tl;dr not specifically binding this way results in potentially duplicate chatboxes when + + // HAHA - SIKE. Because of BYOND weirdness (tl;dr not specifically binding this way results in potentially duplicate chatboxes when // conflicts occur with something like say indicator vs say), we're going to snowflake this anyways var/list/hard_binds = list( "O" = "ooc", @@ -80,7 +80,7 @@ SUBSYSTEM_DEF(input) for(var/key in hard_binds) for(var/modifier in anti_collision_modifiers) hard_bind_anti_collision["[modifier]+[key]"] = ".NONSENSICAL_VERB_THAT_DOES_NOTHING" - + macroset_classic_hotkey = list( "Any" = "\"KeyDown \[\[*\]\]\"", "Any+UP" = "\"KeyUp \[\[*\]\]\"", @@ -88,7 +88,7 @@ SUBSYSTEM_DEF(input) "Escape" = "\".winset \\\"input.text=\\\"\\\"\\\"\"", "Back" = "\".winset \\\"input.text=\\\"\\\"\\\"\"", ) - + macroset_classic_hotkey |= hard_binds macroset_classic_hotkey |= hard_bind_anti_collision @@ -100,7 +100,7 @@ SUBSYSTEM_DEF(input) "Escape" = "\".winset \\\"input.text=\\\"\\\"\\\"\"", "Back" = "\".winset \\\"input.text=\\\"\\\"\\\"\"", ) - + macroset_hotkey |= hard_binds macroset_hotkey |= hard_bind_anti_collision diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm index e61a3b3854..0f936bdeff 100644 --- a/code/controllers/subsystem/job.dm +++ b/code/controllers/subsystem/job.dm @@ -55,9 +55,10 @@ SUBSYSTEM_DEF(job) continue if(!job.config_check()) continue - if(!job.map_check()) //Even though we initialize before mapping, this is fine because the config is loaded at new + if(!job.map_check(SSmapping.config)) //Even though we initialize before mapping, this is fine because the config is loaded at new testing("Removed [job.type] due to map config"); continue + job.process_map_overrides(SSmapping.config) occupations += job name_occupations[job.title] = job type_occupations[J] = job diff --git a/code/controllers/subsystem/npcpool.dm b/code/controllers/subsystem/npcpool.dm index c67deaede1..c20820c092 100644 --- a/code/controllers/subsystem/npcpool.dm +++ b/code/controllers/subsystem/npcpool.dm @@ -5,6 +5,10 @@ SUBSYSTEM_DEF(npcpool) runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME var/list/currentrun = list() + /// catches sleeping + var/invoking = FALSE + /// Invoke start time + var/invoke_start = 0 /datum/controller/subsystem/npcpool/stat_entry(msg) var/list/activelist = GLOB.simple_animals[AI_ON] @@ -12,7 +16,6 @@ SUBSYSTEM_DEF(npcpool) return ..() /datum/controller/subsystem/npcpool/fire(resumed = FALSE) - if (!resumed) var/list/activelist = GLOB.simple_animals[AI_ON] src.currentrun = activelist.Copy() @@ -24,12 +27,22 @@ SUBSYSTEM_DEF(npcpool) var/mob/living/simple_animal/SA = currentrun[currentrun.len] --currentrun.len - if(!SA.ckey && !SA.mob_transforming) - if(SA.stat != DEAD) - SA.handle_automated_movement() - if(SA.stat != DEAD) - SA.handle_automated_action() - if(SA.stat != DEAD) - SA.handle_automated_speech() + invoking = TRUE + invoke_start = world.time + INVOKE_ASYNC(src, .proc/invoke_process, SA) + if(invoking) + stack_trace("WARNING: [SA] ([SA.type]) slept during NPCPool processing.") + invoking = FALSE + if (MC_TICK_CHECK) return + +/datum/controller/subsystem/npcpool/proc/invoke_process(mob/living/simple_animal/SA) + if(!SA.ckey && !SA.mob_transforming) + if(SA.stat != DEAD) + SA.handle_automated_movement() + if(SA.stat != DEAD) + SA.handle_automated_action() + if(SA.stat != DEAD) + SA.handle_automated_speech() + invoking = FALSE diff --git a/code/datums/martial/sleeping_carp.dm b/code/datums/martial/sleeping_carp.dm index 7d884344f1..81b7ea0628 100644 --- a/code/datums/martial/sleeping_carp.dm +++ b/code/datums/martial/sleeping_carp.dm @@ -130,7 +130,7 @@ playsound(get_turf(A), pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, TRUE) P.firer = A P.setAngle(rand(0, 360))//SHING - A.adjustStaminaLossBuffered (3) //Citadel change to stop infinite bullet sponging as you run away, but it is buffered! + A.adjustStaminaLoss(3) return BULLET_ACT_FORCE_PIERCE return BULLET_ACT_HIT diff --git a/code/datums/weather/weather_types/ash_storm.dm b/code/datums/weather/weather_types/ash_storm.dm index 43190ef50c..6248be0de5 100644 --- a/code/datums/weather/weather_types/ash_storm.dm +++ b/code/datums/weather/weather_types/ash_storm.dm @@ -95,8 +95,8 @@ if(is_ash_immune(L)) return if(is_species(L, /datum/species/lizard/ashwalker)) - if(!IS_STAMCRIT(L)) - L.adjustStaminaLossBuffered(4) + if(L.getStaminaLoss() < (STAMINA_CRIT - 40)) + L.adjustStaminaLoss(4) return L.adjustFireLoss(4) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 65fdbb6f1c..1c75f1e533 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -565,7 +565,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb to_chat(user, "You cannot locate any organic eyes on this brain!") return - if(IS_STAMCRIT(user))//CIT CHANGE - makes eyestabbing impossible if you're in stamina softcrit + if(IS_STAMCRIT(user) || !user.UseStaminaBuffer(STAMINA_COST_ITEM_EYESTAB, warn = TRUE))//CIT CHANGE - makes eyestabbing impossible if you're in stamina softcrit to_chat(user, "You're too exhausted for that.")//CIT CHANGE - ditto return //CIT CHANGE - ditto @@ -575,8 +575,6 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb user.do_attack_animation(M) - user.adjustStaminaLossBuffered(10)//CIT CHANGE - makes eyestabbing cost stamina - if(M != user) M.visible_message("[user] has stabbed [M] in the eye with [src]!", \ "[user] stabs you in the eye with [src]!") diff --git a/code/game/objects/items/electrostaff.dm b/code/game/objects/items/electrostaff.dm index 65d2fdd699..31aaff12b5 100644 --- a/code/game/objects/items/electrostaff.dm +++ b/code/game/objects/items/electrostaff.dm @@ -21,12 +21,11 @@ var/can_block_projectiles = FALSE //can't block guns var/lethal_cost = 400 //10000/400*20 = 500. decent enough? var/lethal_damage = 20 - var/lethal_stam_cost = 4 var/stun_cost = 333 //10000/333*25 = 750. stunbatons are at time of writing 10000/1000*49 = 490. var/stun_status_effect = STATUS_EFFECT_ELECTROSTAFF //a small slowdown effect var/stun_stamdmg = 40 var/stun_status_duration = 25 - var/stun_stam_cost = 3.5 + var/stam_cost = 3.5 var/wielded = FALSE // track wielded status on item // haha security desword time /s @@ -171,7 +170,7 @@ turn_off() /obj/item/electrostaff/attack(mob/living/target, mob/living/user) - if(IS_STAMCRIT(user))//CIT CHANGE - makes it impossible to baton in stamina softcrit + if(IS_STAMCRIT(user) || !user.UseStaminaBuffer(stam_cost))//CIT CHANGE - makes it impossible to baton in stamina softcrit 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)) @@ -186,13 +185,11 @@ if(user.a_intent != INTENT_HARM) if(stun_act(target, user, null, return_list)) user.do_attack_animation(target) - user.adjustStaminaLossBuffered(stun_stam_cost) return else if(!harm_act(target, user, null, return_list)) return ..() //if you can't fry them just beat them with it else //we did harm act them user.do_attack_animation(target) - user.adjustStaminaLossBuffered(lethal_stam_cost) /obj/item/electrostaff/proc/stun_act(mob/living/target, mob/living/user, no_charge_and_force = FALSE, list/block_return = list()) var/stunforce = block_calculate_resultant_damage(stun_stamdmg, block_return) diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm index 52ff0f740e..15d10c4d11 100644 --- a/code/game/objects/items/melee/misc.dm +++ b/code/game/objects/items/melee/misc.dm @@ -352,6 +352,8 @@ return else if(cooldown_check < world.time) + if(!UseStaminaBufferStandard(user, STAM_COST_BATON_MOB_MULT, warn = TRUE)) + return DISCARD_LAST_ACTION if(target.mob_run_block(src, 0, "[user]'s [name]", ATTACK_TYPE_MELEE, 0, user, null, null) & BLOCK_SUCCESS) playsound(target, 'sound/weapons/genhit.ogg', 50, 1) return @@ -373,7 +375,6 @@ else target.LAssailant = WEAKREF(user) cooldown_check = world.time + cooldown - user.adjustStaminaLossBuffered(getweight(user, STAM_COST_BATON_MOB_MULT)) else var/wait_desc = get_wait_description() if(wait_desc) diff --git a/code/game/objects/items/mop.dm b/code/game/objects/items/mop.dm index b420bfc002..01ef96b7e8 100644 --- a/code/game/objects/items/mop.dm +++ b/code/game/objects/items/mop.dm @@ -56,22 +56,20 @@ return if(T) + if(!L.UseStaminaBuffer(stamusage, warn = TRUE)) + return user.visible_message("[user] cleans \the [T] with [src].", "You clean \the [T] with [src].") clean(T) user.DelayNextAction(CLICK_CD_MELEE) user.do_attack_animation(T, used_item = src) - if(istype(L)) - L.adjustStaminaLossBuffered(stamusage) playsound(T, "slosh", 50, 1) - /obj/effect/attackby(obj/item/I, mob/user, params) if(istype(I, /obj/item/mop) || istype(I, /obj/item/soap)) return else return ..() - /obj/item/mop/proc/janicart_insert(mob/user, obj/structure/janitorialcart/J) if(insertable) J.put_in_cart(src, user) diff --git a/code/game/objects/items/powerfist.dm b/code/game/objects/items/powerfist.dm index 2834b3b758..bd83404356 100644 --- a/code/game/objects/items/powerfist.dm +++ b/code/game/objects/items/powerfist.dm @@ -6,7 +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. + item_flags = NEEDS_PERMIT attack_verb = list("whacked", "fisted", "power-punched") force = 20 throwforce = 10 @@ -76,6 +76,9 @@ if(!tank) to_chat(user, "\The [src] can't operate without a source of gas!") return FALSE + var/weight = getweight(user, STAM_COST_ATTACK_MOB_MULT) + if(!user.UseStaminaBuffer(weight, warn = TRUE)) + return FALSE var/datum/gas_mixture/gasused = tank.air_contents.remove(gasperfist * fisto_setting) var/turf/T = get_turf(src) if(!T) @@ -108,8 +111,4 @@ target.throw_at(throw_target, 5 * fisto_setting, 0.5 + (fisto_setting / 2)) log_combat(user, target, "power fisted", src) - - var/weight = getweight(user, STAM_COST_ATTACK_MOB_MULT) - if(weight) - user.adjustStaminaLossBuffered(weight) return TRUE diff --git a/code/game/objects/items/shields.dm b/code/game/objects/items/shields.dm index 4952c93928..d1d57fe375 100644 --- a/code/game/objects/items/shields.dm +++ b/code/game/objects/items/shields.dm @@ -136,15 +136,17 @@ if(!(shield_flags & SHIELD_BASH_GROUND_SLAM)) to_chat(user, "You can't ground slam with [src]!") return FALSE + if(!user.UseStaminaBuffer(shieldbash_stamcost, warn = TRUE)) + return FALSE bash_target(user, target, NONE, harmful) user.do_attack_animation(target, used_item = src) playsound(src, harmful? "swing_hit" : 'sound/weapons/thudswoosh.ogg', 75, 1) last_shieldbash = world.time - user.adjustStaminaLossBuffered(shieldbash_stamcost) return TRUE // Directional sweep! last_shieldbash = world.time - user.adjustStaminaLossBuffered(shieldbash_stamcost) + if(!user.UseStaminaBuffer(shieldbash_stamcost, warn = TRUE)) + return FALSE // Since we are in combat mode, we can probably safely use the user's dir instead of getting their mouse pointing cardinal dir. var/bashdir = user.dir do_shieldbash_effect(user, bashdir, harmful) diff --git a/code/game/objects/items/stunbaton.dm b/code/game/objects/items/stunbaton.dm index caad287e6c..16efecec7c 100644 --- a/code/game/objects/items/stunbaton.dm +++ b/code/game/objects/items/stunbaton.dm @@ -166,13 +166,12 @@ if(turned_on) if(baton_stun(M, user, disarming)) user.do_attack_animation(M) - user.adjustStaminaLossBuffered(getweight(user, STAM_COST_BATON_MOB_MULT)) else if(user.a_intent != INTENT_HARM) //they'll try to bash in the last proc. M.visible_message("[user] has prodded [M] with [src]. Luckily it was off.", \ "[user] has prodded you with [src]. Luckily it was off") return disarming || (user.a_intent != INTENT_HARM) -/obj/item/melee/baton/proc/baton_stun(mob/living/L, mob/user, disarming = FALSE) +/obj/item/melee/baton/proc/baton_stun(mob/living/L, mob/living/user, disarming = FALSE) var/list/return_list = list() if(L.mob_run_block(src, 0, "[user]'s [name]", ATTACK_TYPE_MELEE, 0, user, null, return_list) & BLOCK_SUCCESS) //No message; check_shields() handles that playsound(L, 'sound/weapons/genhit.ogg', 50, 1) @@ -194,6 +193,9 @@ return FALSE stunpwr *= round(stuncharge/hitcost, 0.1) + if(!user.UseStaminaBuffer(getweight(user, STAM_COST_BATON_MOB_MULT), warn = TRUE)) + return FALSE + if(!disarming) if(knockdown) L.DefaultCombatKnockdown(50, override_stamdmg = 0) //knockdown diff --git a/code/game/objects/items/tanks/jetpack.dm b/code/game/objects/items/tanks/jetpack.dm index 7cf25098e1..29961d12b4 100644 --- a/code/game/objects/items/tanks/jetpack.dm +++ b/code/game/objects/items/tanks/jetpack.dm @@ -55,6 +55,8 @@ RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/move_react) if(full_speed) user.add_movespeed_modifier(/datum/movespeed_modifier/jetpack/fullspeed) + else + user.add_movespeed_modifier(/datum/movespeed_modifier/jetpack) /obj/item/tank/jetpack/proc/turn_off(mob/user) on = FALSE @@ -63,6 +65,7 @@ ion_trail.stop() UnregisterSignal(user, COMSIG_MOVABLE_MOVED) user.remove_movespeed_modifier(/datum/movespeed_modifier/jetpack/fullspeed) + user.remove_movespeed_modifier(/datum/movespeed_modifier/jetpack) /obj/item/tank/jetpack/proc/move_react(mob/user) allow_thrust(0.01, user) diff --git a/code/game/objects/items/tools/screwdriver.dm b/code/game/objects/items/tools/screwdriver.dm index bb507e5725..bf767af2ed 100644 --- a/code/game/objects/items/tools/screwdriver.dm +++ b/code/game/objects/items/tools/screwdriver.dm @@ -161,4 +161,4 @@ item_state = "screwdriver_nuke" usesound = 'sound/items/pshoom.ogg' toolspeed = 0.2 - random_color = FALSE \ No newline at end of file + random_color = FALSE diff --git a/code/modules/holiday/holidays.dm b/code/modules/holiday/holidays.dm index 83bb67b879..f6e4684e21 100644 --- a/code/modules/holiday/holidays.dm +++ b/code/modules/holiday/holidays.dm @@ -351,7 +351,7 @@ /datum/holiday/halloween name = HALLOWEEN - begin_day = 28 + begin_day = 1 begin_month = OCTOBER end_day = 2 end_month = NOVEMBER diff --git a/code/modules/integrated_electronics/subtypes/output.dm b/code/modules/integrated_electronics/subtypes/output.dm index efd98c4d50..833b2963ad 100644 --- a/code/modules/integrated_electronics/subtypes/output.dm +++ b/code/modules/integrated_electronics/subtypes/output.dm @@ -44,18 +44,18 @@ /obj/item/integrated_circuit/output/screen/large/do_work() ..() - if(isliving(assembly.loc))//this whole block just returns if the assembly is neither in a mobs hands or on the ground - var/mob/living/H = assembly.loc - if(H.get_active_held_item() != assembly && H.get_inactive_held_item() != assembly) - return - else - if(!isturf(assembly.loc)) - return - - var/atom/host = assembly || src var/list/mobs = list() - for(var/mob/M in range(0, get_turf(src))) - mobs += M + if(isliving(assembly.loc)) + mobs += assembly.loc + var/mob/living/L = assembly.loc + if(L.is_holding(src)) + for(var/mob/M in range(1, get_turf(src))) + mobs += M + else + for(var/mob/M in range(2, get_turf(src))) + mobs += M + + var/atom/host = assembly || src to_chat(mobs, "[icon2html(host.icon, world, host.icon_state)] flashes a message: [stuff_to_display]") host.investigate_log("displayed \"[html_encode(stuff_to_display)]\" as [type].", INVESTIGATE_CIRCUIT) diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm index 0feceaf1a8..b0ac5248c1 100644 --- a/code/modules/jobs/job_types/_job.dm +++ b/code/modules/jobs/job_types/_job.dm @@ -73,6 +73,31 @@ /// Starting skill modifiers. var/list/starting_modifiers +/** + * Checks if we should be created on a certain map + */ +/datum/job/proc/map_check(datum/map_config/C) + return (length(C.job_whitelist)? (type in C.job_whitelist) : !(type in C.job_blacklist)) + +/** + * Processes map specific overrides + */ +/datum/job/proc/process_map_overrides(datum/map_config/C) + if(type in C.job_override_spawn_positions) + spawn_positions = C.job_override_spawn_positions[type] + if(type in C.job_override_total_positions) + total_positions = C.job_override_total_positions[type] + if(type in C.job_access_override) + access = C.job_access_override[type] + minimal_access = access + else + if(type in C.job_access_add) + access += C.job_access_add[type] + minimal_access += C.job_access_add[type] + if(type in C.job_access_remove) + access -= C.job_access_add[type] + minimal_access -= C.job_access_remove[type] + //Only override this proc //H is usually a human unless an /equip override transformed it /datum/job/proc/after_spawn(mob/living/H, mob/M, latejoin = FALSE) @@ -175,9 +200,6 @@ /datum/job/proc/config_check() return TRUE -/datum/job/proc/map_check() - return TRUE - /datum/job/proc/radio_help_message(mob/M) to_chat(M, "Prefix your message with :h to speak on your department's radio. To see other prefixes, look closely at your headset.") diff --git a/code/modules/jobs/map_changes/map_changes.dm b/code/modules/jobs/map_changes/map_changes.dm deleted file mode 100644 index 575075037b..0000000000 --- a/code/modules/jobs/map_changes/map_changes.dm +++ /dev/null @@ -1,4 +0,0 @@ -//this needs to come after the job_types subfolder to keep the correct ordering - -#include "..\..\..\..\_maps\map_files\PubbyStation\job_changes.dm" -#undef JOB_MODIFICATION_MAP_NAME \ No newline at end of file diff --git a/code/modules/keybindings/bindings_client.dm b/code/modules/keybindings/bindings_client.dm index 3a47cd2315..3d12f89cfe 100644 --- a/code/modules/keybindings/bindings_client.dm +++ b/code/modules/keybindings/bindings_client.dm @@ -1,6 +1,7 @@ // Clients aren't datums so we have to define these procs indpendently. // These verbs are called for all key press and release events /client/verb/keyDown(_key as text) + SHOULD_NOT_SLEEP(TRUE) set instant = TRUE set hidden = TRUE @@ -83,6 +84,7 @@ keyUp("[key]") /client/verb/keyUp(_key as text) + SHOULD_NOT_SLEEP(TRUE) set instant = TRUE set hidden = TRUE diff --git a/code/modules/keybindings/setup.dm b/code/modules/keybindings/setup.dm index a53820b5d2..47dbfd855f 100644 --- a/code/modules/keybindings/setup.dm +++ b/code/modules/keybindings/setup.dm @@ -1,12 +1,11 @@ /datum/proc/key_down(key, client/user) // Called when a key is pressed down initially - return + SHOULD_NOT_SLEEP(TRUE) /datum/proc/key_up(key, client/user) // Called when a key is released - return + SHOULD_NOT_SLEEP(TRUE) /datum/proc/keyLoop(client/user) // Called once every frame - set waitfor = FALSE - return + SHOULD_NOT_SLEEP(TRUE) // removes all the existing macros /client/proc/erase_all_macros() diff --git a/code/modules/mapping/map_config.dm b/code/modules/mapping/map_config.dm index c03ef65f43..d18ca1e1e3 100644 --- a/code/modules/mapping/map_config.dm +++ b/code/modules/mapping/map_config.dm @@ -43,6 +43,21 @@ /// Orientation to load in by default. var/orientation = SOUTH //byond defaults to placing everyting SOUTH. + /// Jobs whitelist - if this is not empty, ONLY these jobs are allowed. Overrides blacklist. + var/list/job_whitelist + /// Jobs blacklist - if this is not empty, jobs in this aren't allowed. + var/list/job_blacklist + /// Job spawn position mod - type = number + var/list/job_override_spawn_positions + /// Job total position mod - type = number + var/list/job_override_total_positions + /// Add these accesses to jobs - type = list() + var/list/job_access_add + /// Remove these accesses from jobs - type = list() + var/list/job_access_remove + /// Override job accesses - type = list() - overrides everything else + var/list/job_access_override + /proc/load_map_config(filename = "data/next_map.json", default_to_box, delete_after, error_if_missing = TRUE) var/datum/map_config/config = new if (default_to_box) @@ -161,6 +176,69 @@ allow_custom_shuttles = json["allow_custom_shuttles"] != FALSE + if("job_whitelist" in json) + job_whitelist = list() + for(var/path in json["job_whitelist"]) + var/type = text2path(path) + if(!path) + log_config("map datum [config_filename] failed to validate path [path] in job overrides.") + continue + job_whitelist += type + + if("job_blacklist" in json) + job_blacklist = list() + for(var/path in json["job_blacklist"]) + var/type = text2path(path) + if(!path) + log_config("map datum [config_filename] failed to validate path [path] in job overrides.") + continue + job_blacklist += type + + if("job_override_spawn_positions" in json) + job_override_spawn_positions = list() + for(var/path in json["job_override_spawn_positions"]) + var/type = text2path(path) + if(!path) + log_config("map datum [config_filename] failed to validate path [path] in job overrides.") + continue + job_override_spawn_positions += type + + if("job_override_total_positions" in json) + job_override_total_positions = list() + for(var/path in json["job_override_total_positions"]) + var/type = text2path(path) + if(!path) + log_config("map datum [config_filename] failed to validate path [path] in job overrides.") + continue + job_override_total_positions += type + + if("job_access_add" in json) + job_access_add = list() + for(var/path in json["job_acces_add"]) + var/type = text2path(path) + if(!path) + log_config("map datum [config_filename] failed to validate path [path] in job overrides.") + continue + job_access_add[type] = json["job_access_add"] + + if("job_access_remove" in json) + job_access_remove = list() + for(var/path in json["job_acces_add"]) + var/type = text2path(path) + if(!path) + log_config("map datum [config_filename] failed to validate path [path] in job overrides.") + continue + job_access_remove[type] = json["job_access_remove"] + + if("job_access_override" in json) + job_access_override = list() + for(var/path in json["job_acces_add"]) + var/type = text2path(path) + if(!path) + log_config("map datum [config_filename] failed to validate path [path] in job overrides.") + continue + job_access_override[type] = json["job_access_override"] + defaulted = FALSE return TRUE #undef CHECK_EXISTS @@ -190,6 +268,13 @@ jsonlist["announcertype"] = announcertype jsonlist["orientation"] = orientation jsonlist["allow_custom_shuttles"] = allow_custom_shuttles + jsonlist["job_whitelist"] = job_whitelist + jsonlist["job_blacklist"] = job_blacklist + jsonlist["job_override_spawn_positions"] = job_override_spawn_positions + jsonlist["job_override_total_positions"] = job_override_total_positions + jsonlist["job_access_add"] = job_access_add + jsonlist["job_access_remove"] = job_access_remove + jsonlist["job_access_override"] = job_access_override if(fexists("data/next_map.json")) fdel("data/next_map.json") var/F = file("data/next_map.json") diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 11b133f5e7..26486f255a 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -191,8 +191,8 @@ if(HAS_TRAIT(src, TRAIT_PACIFISM)) to_chat(src, "You gently let go of [throwable_mob].") return - - adjustStaminaLossBuffered(STAM_COST_THROW_MOB * ((throwable_mob.mob_size+1)**2))// throwing an entire person shall be very tiring + if(!UseStaminaBuffer(STAM_COST_THROW_MOB * ((throwable_mob.mob_size+1)**2), TRUE)) + return var/turf/start_T = get_turf(loc) //Get the start and target tile for the descriptors var/turf/end_T = get_turf(target) if(start_T && end_T) @@ -206,7 +206,8 @@ to_chat(src, "You set [I] down gently on the ground.") return - adjustStaminaLossBuffered(I.getweight(src, STAM_COST_THROW_MULT, SKILL_THROW_STAM_COST)) + if(!UseStaminaBuffer(I.getweight(src, STAM_COST_THROW_MULT, SKILL_THROW_STAM_COST), warn = TRUE)) + return if(thrown_thing) var/power_throw = 0 @@ -594,15 +595,23 @@ remove_movespeed_modifier(/datum/movespeed_modifier/carbon_softcrit) /mob/living/carbon/update_stamina() - var/stam = getStaminaLoss() - if(stam > DAMAGE_PRECISION) - var/total_health = (maxHealth - stam) - if(total_health <= crit_threshold && !stat) - if(CHECK_MOBILITY(src, MOBILITY_STAND)) - to_chat(src, "You're too exhausted to keep going...") - KnockToFloor(TRUE) - update_health_hud() - + var/total_health = getStaminaLoss() + if(total_health) + if(!(combat_flags & COMBAT_FLAG_HARD_STAMCRIT) && total_health >= STAMINA_CRIT && !stat) + to_chat(src, "You're too exhausted to keep going...") + set_resting(TRUE, FALSE, FALSE) + SEND_SIGNAL(src, COMSIG_DISABLE_COMBAT_MODE) + ENABLE_BITFIELD(combat_flags, COMBAT_FLAG_HARD_STAMCRIT) + filters += CIT_FILTER_STAMINACRIT + update_mobility() + if((combat_flags & COMBAT_FLAG_HARD_STAMCRIT) && total_health <= STAMINA_CRIT) + to_chat(src, "You don't feel nearly as exhausted anymore.") + DISABLE_BITFIELD(combat_flags, COMBAT_FLAG_HARD_STAMCRIT) + filters -= CIT_FILTER_STAMINACRIT + update_mobility() + UpdateStaminaBuffer() + update_health_hud() + /mob/living/carbon/update_sight() if(!client) return diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index a4543389b4..1b7ab81d59 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -805,7 +805,7 @@ hud_used.healthdoll.icon_state = "healthdoll_DEAD" hud_used.staminas?.update_icon_state() - hud_used.staminabuffer?.update_icon_state() + hud_used.staminabuffer?.mark_dirty() /mob/living/carbon/human/fully_heal(admin_revive = FALSE) if(admin_revive) @@ -1044,10 +1044,9 @@ remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown) remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying) return - var/stambufferinfluence = (bufferedstam*(100/stambuffer))*0.2 //CIT CHANGE - makes stamina buffer influence movedelay if(!HAS_TRAIT(src, TRAIT_IGNOREDAMAGESLOWDOWN)) //if we want to ignore slowdown from damage, but not from equipment var/scaling = maxHealth / 100 - var/health_deficiency = (((maxHealth / scaling) + stambufferinfluence) - (health / scaling) + (getStaminaLoss()*0.75))//CIT CHANGE - reduces the impact of staminaloss and makes stamina buffer influence it + var/health_deficiency = ((maxHealth / scaling) - (health / scaling) + (getStaminaLoss()*0.75))//CIT CHANGE - reduces the impact of staminaloss and makes stamina buffer influence it if(health_deficiency >= 40) add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown, TRUE, (health_deficiency-39) / 75) add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying, TRUE, (health_deficiency-39) / 25) diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index a6a3f408dc..89a4570e8d 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -7,7 +7,7 @@ buckle_lying = FALSE mob_biotypes = MOB_ORGANIC|MOB_HUMANOID /// Enable stamina combat - combat_flags = COMBAT_FLAGS_DEFAULT | COMBAT_FLAG_UNARMED_PARRY + combat_flags = COMBAT_FLAGS_STAMINA_COMBAT | COMBAT_FLAG_UNARMED_PARRY status_flags = CANSTUN|CANKNOCKDOWN|CANUNCONSCIOUS|CANPUSH|CANSTAGGER has_field_of_vision = FALSE //Handled by species. diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index 5ced11e35a..97c40c96d7 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -11,11 +11,6 @@ /mob/living/carbon/human/movement_delay() . = ..() - if(CHECK_MOBILITY(src, MOBILITY_STAND) && m_intent == MOVE_INTENT_RUN && (combat_flags & COMBAT_FLAG_SPRINT_ACTIVE)) - var/static/datum/config_entry/number/movedelay/sprint_speed_increase/SSI - if(!SSI) - SSI = CONFIG_GET_ENTRY(number/movedelay/sprint_speed_increase) - . -= SSI.config_entry_value if (m_intent == MOVE_INTENT_WALK && HAS_TRAIT(src, TRAIT_SPEEDY_STEP)) . -= 1.5 @@ -61,7 +56,11 @@ HM.on_move(NewLoc) if(. && (combat_flags & COMBAT_FLAG_SPRINT_ACTIVE) && !(movement_type & FLYING) && CHECK_ALL_MOBILITY(src, MOBILITY_MOVE|MOBILITY_STAND) && m_intent == MOVE_INTENT_RUN && has_gravity(loc) && (!pulledby || (pulledby.pulledby == src))) if(!HAS_TRAIT(src, TRAIT_FREESPRINT)) - doSprintLossTiles(1) + var/datum/movespeed_modifier/equipment_speedmod/MM = get_movespeed_modifier_datum(/datum/movespeed_modifier/equipment_speedmod) + var/amount = 1 + if(MM?.multiplicative_slowdown >= 1) + amount *= (1 + (6 - (3 / MM.multiplicative_slowdown))) + doSprintLossTiles(amount) if((oldpseudoheight - pseudo_z_axis) >= 8) to_chat(src, "You trip off of the elevated surface!") for(var/obj/item/I in held_items) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index bfeba22a04..50a725f8cf 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1364,9 +1364,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(!(attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK)) if(HAS_TRAIT(user, TRAIT_PUGILIST))//CITADEL CHANGE - makes punching cause staminaloss but funny martial artist types get a discount - user.adjustStaminaLossBuffered(1.5) - else - user.adjustStaminaLossBuffered(3.5) + if(!user.UseStaminaBuffer(1.5, warn = TRUE)) + return + else if(!user.UseStaminaBuffer(3.5, warn = TRUE)) + return if(attacker_style && attacker_style.harm_act(user,target)) return TRUE @@ -1505,6 +1506,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) return FALSE else if(aim_for_mouth && ( target_on_help || target_restrained || target_aiming_for_mouth)) + if(!user.UseStaminaBuffer(3, warn = TRUE)) + return playsound(target.loc, 'sound/weapons/slap.ogg', 50, 1, -1) target.visible_message(\ @@ -1512,7 +1515,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) "[user] slaps you in the face! ",\ "You hear a slap.", target = user, target_message = "You slap [user == target ? "yourself" : "\the [target]"] in the face! ") user.do_attack_animation(target, ATTACK_EFFECT_FACE_SLAP) - user.adjustStaminaLossBuffered(3) if (!HAS_TRAIT(target, TRAIT_PERMABONER)) stop_wagging_tail(target) return FALSE @@ -1520,8 +1522,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(target.client?.prefs.cit_toggles & NO_ASS_SLAP) to_chat(user,"A force stays your hand, preventing you from slapping \the [target]'s ass!") return FALSE + if(!user.UseStaminaBuffer(3, warn = TRUE)) + return FALSE user.do_attack_animation(target, ATTACK_EFFECT_ASS_SLAP) - user.adjustStaminaLossBuffered(3) target.adjust_arousal(20,maso = TRUE) if (ishuman(target) && HAS_TRAIT(target, TRAIT_MASO) && target.has_dna() && prob(10)) target.mob_climax(forced_climax=TRUE) @@ -1539,9 +1542,11 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) user.do_attack_animation(target, ATTACK_EFFECT_DISARM) if(HAS_TRAIT(user, TRAIT_PUGILIST))//CITADEL CHANGE - makes disarmspam cause staminaloss, pugilists can do it almost effortlessly - user.adjustStaminaLossBuffered(1) + if(!user.UseStaminaBuffer(1, warn = TRUE)) + return else - user.adjustStaminaLossBuffered(3) + if(!user.UseStaminaBuffer(1, warn = TRUE)) + return if(attacker_style && attacker_style.disarm_act(user,target)) return TRUE @@ -1777,9 +1782,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(CHECK_MOBILITY(user, MOBILITY_STAND)) to_chat(user, "You can only force yourself up if you're on the ground.") return + if(!user.UseStaminaBuffer(STAMINA_COST_SHOVE_UP, TRUE)) + return user.visible_message("[user] forces [p_them()]self up to [p_their()] feet!", "You force yourself up to your feet!") user.set_resting(FALSE, TRUE) - user.adjustStaminaLossBuffered(user.stambuffer) //Rewards good stamina management by making it easier to instantly get up from resting playsound(user, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) /datum/species/proc/altdisarm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style) @@ -1798,8 +1804,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) else if(user == target) return + if(!user.UseStaminaBuffer(4, warn = TRUE)) + return user.do_attack_animation(target, ATTACK_EFFECT_DISARM) - user.adjustStaminaLossBuffered(4) playsound(target, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1) if(target.w_uniform) diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 8f181d47fd..30785a0103 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -502,19 +502,14 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put //this updates all special effects: stun, sleeping, knockdown, druggy, stuttering, etc.. /mob/living/carbon/handle_status_effects() ..() - if(getStaminaLoss() && !SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE)) //CIT CHANGE - prevents stamina regen while combat mode is active - adjustStaminaLoss(!CHECK_MOBILITY(src, MOBILITY_STAND) ? ((combat_flags & COMBAT_FLAG_HARD_STAMCRIT) ? STAM_RECOVERY_STAM_CRIT : STAM_RECOVERY_RESTING) : STAM_RECOVERY_NORMAL) + var/combat_mode = SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE) + if(getStaminaLoss() && !HAS_TRAIT(src, TRAIT_NO_STAMINA_REGENERATION)) + adjustStaminaLoss((!CHECK_MOBILITY(src, MOBILITY_STAND) ? ((combat_flags & COMBAT_FLAG_HARD_STAMCRIT) ? STAM_RECOVERY_STAM_CRIT : STAM_RECOVERY_RESTING) : STAM_RECOVERY_NORMAL) * (combat_mode? 0.25 : 1)) if(!(combat_flags & COMBAT_FLAG_HARD_STAMCRIT) && incomingstammult != 1) incomingstammult = max(0.01, incomingstammult) incomingstammult = min(1, incomingstammult*2) - //CIT CHANGES START HERE. STAMINA BUFFER STUFF - if(bufferedstam && world.time > stambufferregentime) - var/drainrate = max((bufferedstam*(bufferedstam/(5)))*0.1,1) - bufferedstam = max(bufferedstam - drainrate, 0) - //END OF CIT CHANGES - var/restingpwr = 1 + 4 * !CHECK_MOBILITY(src, MOBILITY_STAND) //Dizziness diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm index 1d78979cbd..4ee52a08a6 100644 --- a/code/modules/mob/living/emote.dm +++ b/code/modules/mob/living/emote.dm @@ -562,7 +562,7 @@ if(. && iscarbon(user)) var/mob/living/carbon/C = user if(isjellyperson(C)) - pick(playsound(C, 'sound/effects/attackblob.ogg', 50, 1),playsound(C, 'sound/effects/blobattack.ogg', 50, 1)) + playsound(C, 'sound/effects/attackblob.ogg', 50, 1) /datum/emote/living/audio_emote/blurp key = "blurp" diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 7e872992dc..57d688bde3 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -8,6 +8,8 @@ for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds) diag_hud.add_to_hud(src) faction += "[REF(src)]" + stamina_buffer = INFINITY + UpdateStaminaBuffer() GLOB.mob_living_list += src /mob/living/prepare_huds() @@ -1257,7 +1259,7 @@ SetUnconscious(clamp_unconscious_to) HealAllImmobilityUpTo(clamp_immobility_to) adjustStaminaLoss(min(0, -stamina_boost)) - adjustStaminaLossBuffered(min(0, -stamina_buffer_boost)) + RechargeStaminaBuffer(stamina_buffer_boost) // this MUST GO AFTER ADJUSTSTAMINALOSS. if(scale_stamina_loss_recovery) adjustStaminaLoss(min(-((getStaminaLoss() - stamina_loss_recovery_bypass) * scale_stamina_loss_recovery), 0)) if(put_on_feet) diff --git a/code/modules/mob/living/living_active_block.dm b/code/modules/mob/living/living_active_block.dm index 8e8b94463b..db472df388 100644 --- a/code/modules/mob/living/living_active_block.dm +++ b/code/modules/mob/living/living_active_block.dm @@ -8,6 +8,8 @@ active_block_item = null REMOVE_TRAIT(src, TRAIT_MOBILITY_NOUSE, ACTIVE_BLOCK_TRAIT) REMOVE_TRAIT(src, TRAIT_SPRINT_LOCKED, ACTIVE_BLOCK_TRAIT) + REMOVE_TRAIT(src, TRAIT_NO_STAMINA_BUFFER_REGENERATION, ACTIVE_BLOCK_TRAIT) + REMOVE_TRAIT(src, TRAIT_NO_STAMINA_REGENERATION, ACTIVE_BLOCK_TRAIT) remove_movespeed_modifier(/datum/movespeed_modifier/active_block) var/datum/block_parry_data/data = I.get_block_parry_data() DelayNextAction(data.block_end_click_cd_add) @@ -27,6 +29,10 @@ ADD_TRAIT(src, TRAIT_MOBILITY_NOUSE, ACTIVE_BLOCK_TRAIT) //probably should be something else at some point if(data.block_lock_sprinting) ADD_TRAIT(src, TRAIT_SPRINT_LOCKED, ACTIVE_BLOCK_TRAIT) + if(data.block_no_stamina_regeneration) + ADD_TRAIT(src, TRAIT_NO_STAMINA_REGENERATION, ACTIVE_BLOCK_TRAIT) + if(data.block_no_stambuffer_regeneration) + ADD_TRAIT(src, TRAIT_NO_STAMINA_BUFFER_REGENERATION, ACTIVE_BLOCK_TRAIT) add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/active_block, multiplicative_slowdown = data.block_slowdown) active_block_effect_start() return TRUE @@ -192,7 +198,7 @@ var/held_index = C.get_held_index_of_item(src) var/obj/item/bodypart/BP = C.hand_bodyparts[held_index] if(!BP?.body_zone) - return C.adjustStaminaLossBuffered(stamina_amount) //nah + return C.adjustStaminaLoss(stamina_amount) //nah var/zone = BP.body_zone var/stamina_to_zone = data.block_stamina_limb_ratio * stamina_amount var/stamina_to_chest = stamina_amount - stamina_to_zone @@ -200,9 +206,9 @@ stamina_to_chest -= stamina_buffered C.apply_damage(stamina_to_zone, STAMINA, zone) C.apply_damage(stamina_to_chest, STAMINA, BODY_ZONE_CHEST) - C.adjustStaminaLossBuffered(stamina_buffered) + C.adjustStaminaLoss(stamina_buffered) else - owner.adjustStaminaLossBuffered(stamina_amount) + owner.adjustStaminaLoss(stamina_amount) /obj/item/proc/on_active_block(mob/living/owner, atom/object, damage, damage_blocked, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, override_direction) return diff --git a/code/modules/mob/living/living_active_parry.dm b/code/modules/mob/living/living_active_parry.dm index 10dece1ffc..7353add745 100644 --- a/code/modules/mob/living/living_active_parry.dm +++ b/code/modules/mob/living/living_active_parry.dm @@ -68,12 +68,13 @@ // can always implement it later, whatever. if((data.parry_respect_clickdelay && !CheckActionCooldown()) || ((parry_end_time_last + data.parry_cooldown) > world.time)) to_chat(src, "You are not ready to parry (again)!") - return + return FALSE // Point of no return, make sure everything is set. parrying = method if(method == ITEM_PARRY) active_parry_item = using_item - adjustStaminaLossBuffered(data.parry_stamina_cost) + if(!UseStaminaBuffer(data.parry_stamina_cost, TRUE)) + return FALSE parry_start_time = world.time successful_parries = list() addtimer(CALLBACK(src, .proc/end_parry_sequence), full_parry_duration) diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm index 47dae8849d..08ef674b33 100644 --- a/code/modules/mob/living/living_blocking_parrying.dm +++ b/code/modules/mob/living/living_blocking_parrying.dm @@ -74,8 +74,12 @@ GLOBAL_LIST_EMPTY(block_parry_data) /// Ratio of stamina incurred by chest (so after [block_stamina_limb_ratio] runs) that is buffered. var/block_stamina_buffer_ratio = 1 - /// Stamina dealt directly via adjustStaminaLossBuffered() per SECOND of block. + /// Stamina dealt directly via UseStaminaBuffer() per SECOND of block. var/block_stamina_cost_per_second = 1.5 + /// Prevent stamina buffer regeneration while block? + var/block_no_stambuffer_regeneration = TRUE + /// Prevent stamina regeneration while block? + var/block_no_stamina_regeneration = FALSE /// Bitfield for attack types that we can block while down. This will work in any direction. var/block_resting_attack_types_anydir = ATTACK_TYPE_MELEE | ATTACK_TYPE_UNARMED | ATTACK_TYPE_TACKLE @@ -307,7 +311,7 @@ GLOBAL_LIST_EMPTY(block_parry_data) /mob/living/proc/handle_block_parry(seconds = 1) if(combat_flags & COMBAT_FLAG_ACTIVE_BLOCKING) var/datum/block_parry_data/data = return_block_parry_datum(active_block_item.block_parry_data) - adjustStaminaLossBuffered(data.block_stamina_cost_per_second * seconds) + UseStaminaBuffer(data.block_stamina_cost_per_second * seconds) /mob/living/on_item_dropped(obj/item/I) if(I == active_block_item) diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index 5495d37297..5621fab9c1 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -53,6 +53,7 @@ var/hallucination = 0 //Directly affects how long a mob will hallucinate for + var/last_special = 0 //Used by the resist verb, likely used to prevent players from bypassing next_move by logging in/out. var/timeofdeath = 0 //Allows mobs to move through dense areas without restriction. For instance, in space or out of holder objects. @@ -148,9 +149,6 @@ var/combatmessagecooldown = 0 var/incomingstammult = 1 - var/bufferedstam = 0 - var/stambuffer = 20 - var/stambufferregentime //Sprint buffer--- var/sprint_buffer = 42 //Tiles @@ -159,3 +157,13 @@ var/sprint_buffer_regen_last = 0 //last world.time this was regen'd for math. var/sprint_stamina_cost = 0.70 //stamina loss per tile while insufficient sprint buffer. //---End + + // Stamina Buffer--- + /// Our stamina buffer + var/stamina_buffer + /// Stamina buffer regen modifier + var/stamina_buffer_regen_mod = 1 + /// Last time stamina buffer regen was done + var/stamina_buffer_regen_last = 0 + /// Last time we used stamina buffer + var/stamina_buffer_last_use = 0 diff --git a/code/modules/mob/living/living_mobility.dm b/code/modules/mob/living/living_mobility.dm index 92de711c27..8c6cf9d207 100644 --- a/code/modules/mob/living/living_mobility.dm +++ b/code/modules/mob/living/living_mobility.dm @@ -176,4 +176,6 @@ else remove_movespeed_modifier(/datum/movespeed_modifier/limbless) + update_movespeed() + return mobility_flags diff --git a/code/modules/mob/living/living_sprint.dm b/code/modules/mob/living/living_sprint.dm index dc0f6d2767..3ef67c9edd 100644 --- a/code/modules/mob/living/living_sprint.dm +++ b/code/modules/mob/living/living_sprint.dm @@ -29,6 +29,7 @@ if(combat_flags & COMBAT_FLAG_SPRINT_ACTIVE) return ENABLE_BITFIELD(combat_flags, COMBAT_FLAG_SPRINT_ACTIVE) + add_movespeed_modifier(/datum/movespeed_modifier/sprinting) if(update_icon) update_sprint_icon() @@ -36,6 +37,7 @@ if(!(combat_flags & COMBAT_FLAG_SPRINT_ACTIVE) || (combat_flags & COMBAT_FLAG_SPRINT_FORCED)) return DISABLE_BITFIELD(combat_flags, COMBAT_FLAG_SPRINT_ACTIVE) + remove_movespeed_modifier(/datum/movespeed_modifier/sprinting) if(update_icon) update_sprint_icon() diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index 66c2cd96c7..4c03e74d70 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -82,6 +82,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list( return new_msg /mob/living/say(message, bubble_type,var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null) + set waitfor = FALSE var/static/list/crit_allowed_modes = list(MODE_WHISPER = TRUE, MODE_CHANGELING = TRUE, MODE_ALIEN = TRUE) var/static/list/unconscious_allowed_modes = list(MODE_CHANGELING = TRUE, MODE_ALIEN = TRUE) var/talk_key = get_key(message) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 1eb308af00..83df3ffba5 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -1132,10 +1132,6 @@ bellyup = 1 update_icons() -/mob/living/silicon/robot/adjustStaminaLossBuffered(amount, updating_health = 1) - if(istype(cell)) - cell.charge -= amount * 5 - /mob/living/silicon/robot/verb/viewmanifest() set category = "Robot Commands" set name = "View Crew Manifest" diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm index 3f28fd6e01..8375d621d4 100644 --- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm +++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm @@ -236,7 +236,7 @@ Auto Patrol[]"}, if(targets.len>0) var/mob/living/carbon/t = pick(targets) if((t.stat!=2) && (t.lying != 1) && (!t.handcuffed)) //we don't shoot people who are dead, cuffed or lying down. - shootAt(t) + INVOKE_ASYNC(src, .proc/shootAt, t) switch(mode) if(BOT_IDLE) // idle @@ -254,7 +254,7 @@ Auto Patrol[]"}, if(target) // make sure target exists if(Adjacent(target) && isturf(target.loc)) // if right next to perp - stun_attack(target) + INVOKE_ASYNC(src, .proc/stun_attack, target) mode = BOT_PREP_ARREST anchored = TRUE diff --git a/code/modules/mob/living/simple_animal/hostile/wizard.dm b/code/modules/mob/living/simple_animal/hostile/wizard.dm index b3523fc42c..59bd67e42a 100644 --- a/code/modules/mob/living/simple_animal/hostile/wizard.dm +++ b/code/modules/mob/living/simple_animal/hostile/wizard.dm @@ -62,6 +62,9 @@ /mob/living/simple_animal/hostile/wizard/handle_automated_action() . = ..() + INVOKE_ASYNC(src, .proc/AutomatedCast) + +/mob/living/simple_animal/hostile/wizard/proc/AutomatedCast() if(target && next_cast < world.time) if((get_dir(src,target) in list(SOUTH,EAST,WEST,NORTH)) && fireball.cast_check(0,src)) //Lined up for fireball src.setDir(get_dir(src,target)) diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm index 3ca29b6746..1ff7e2f799 100644 --- a/code/modules/mob/living/simple_animal/parrot.dm +++ b/code/modules/mob/living/simple_animal/parrot.dm @@ -436,12 +436,7 @@ newspeak.Add(possible_phrase) speak = newspeak - //Search for item to steal - parrot_interest = search_for_item() - if(parrot_interest) - emote("me", EMOTE_VISIBLE, "looks in [parrot_interest]'s direction and takes flight.") - parrot_state = PARROT_SWOOP | PARROT_STEAL - icon_state = icon_living + INVOKE_ASYNC(src, .proc/attempt_item_theft) return //-----WANDERING - This is basically a 'I dont know what to do yet' state @@ -620,6 +615,14 @@ parrot_lastmove = src.loc return 0 +/mob/living/simple_animal/parrot/proc/attempt_item_theft() + //Search for item to steal + search_for_item() + if(parrot_interest) + emote("me", EMOTE_VISIBLE, "looks in [parrot_interest]'s direction and takes flight.") + parrot_state = PARROT_SWOOP | PARROT_STEAL + icon_state = icon_living + /mob/living/simple_animal/parrot/proc/search_for_item() var/item for(var/atom/movable/AM in view(src)) diff --git a/code/modules/mob/living/stamina_buffer.dm b/code/modules/mob/living/stamina_buffer.dm new file mode 100644 index 0000000000..a410df582b --- /dev/null +++ b/code/modules/mob/living/stamina_buffer.dm @@ -0,0 +1,56 @@ +/** + * Attempts to use an amount of stamina from our stamina buffer. + * Does not use anything if we don't have enough. + * + * Returns TRUE or FALSE based on if we have it. + */ +/mob/living/proc/UseStaminaBuffer(amount, warn = FALSE, considered_action = TRUE) + if(!(combat_flags & COMBAT_FLAG_STAMINA_BUFFER)) + return TRUE + if(stamina_buffer < amount) + var/stamina_health = getStaminaLoss() + if(stamina_health > STAMINA_NO_OVERDRAW_THRESHOLD) + if(warn) + to_chat(src, "You do not have enough action stamina to do that!") + return FALSE + adjustStaminaLoss(amount * CONFIG_GET(number/stamina_combat/overdraw_penalty_factor)) + else + stamina_buffer -= amount + if(considered_action) + stamina_buffer_last_use = world.time + UpdateStaminaBuffer() + return TRUE + +/** + * Updates our stamina buffer amount. + */ +/mob/living/proc/UpdateStaminaBuffer(updating_hud = TRUE) + var/time = world.time - stamina_buffer_regen_last + CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(number/stamina_combat/buffer_max, buffer_max) + stamina_buffer_regen_last = world.time + if((stamina_buffer >= buffer_max) || !(combat_flags & COMBAT_FLAG_STAMINA_BUFFER)) + stamina_buffer = buffer_max + return + else if(!time || HAS_TRAIT(src, TRAIT_NO_STAMINA_BUFFER_REGENERATION)) + return + CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(number/stamina_combat/out_of_combat_timer, out_of_combat_timer) + CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(number/stamina_combat/base_regeneration, base_regeneration) + CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(number/stamina_combat/combat_regeneration, combat_regeneration) + CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(number/stamina_combat/percent_regeneration_out_of_combat, percent_regeneration_out_of_combat) + CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(number/stamina_combat/post_action_penalty_delay, post_action_penalty_delay) + CONFIG_CACHE_ENTRY_AND_FETCH_VALUE(number/stamina_combat/post_action_penalty_factor, post_action_penalty_factor) + var/base_regen = (SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))? base_regeneration : combat_regeneration + var/time_since_last_action = world.time - stamina_buffer_last_use + var/action_penalty = ((time_since_last_action) < (post_action_penalty_delay * 10))? post_action_penalty_factor : 1 + var/out_of_combat_bonus = (time_since_last_action < (out_of_combat_timer * 10))? 0 : ((buffer_max * percent_regeneration_out_of_combat * 0.01)) + var/regen = ((base_regen * action_penalty) + out_of_combat_bonus) * time * 0.1 * stamina_buffer_regen_mod + stamina_buffer += min((buffer_max - stamina_buffer), regen) + if(updating_hud) + hud_used?.staminabuffer?.mark_dirty() + +/** + * Boosts our stamina buffer by this much. + */ +/mob/living/proc/RechargeStaminaBuffer(amount) + stamina_buffer += abs(amount) + UpdateStaminaBuffer() diff --git a/code/modules/movespeed/_movespeed_modifier.dm b/code/modules/movespeed/_movespeed_modifier.dm index 3bc4463531..9c8036bd55 100644 --- a/code/modules/movespeed/_movespeed_modifier.dm +++ b/code/modules/movespeed/_movespeed_modifier.dm @@ -38,6 +38,12 @@ Key procs /// Multiplicative slowdown var/multiplicative_slowdown = 0 + /// Next two variables depend on this: Should we do advanced calculations? + var/complex_calculation = FALSE + /// Absolute max tiles we can boost to + var/absolute_max_tiles_per_second + /// Max tiles per second we can boost + var/max_tiles_per_second_boost /// Movetypes this applies to var/movetypes = ALL @@ -53,6 +59,16 @@ Key procs if(!id) id = "[type]" //We turn the path into a string. +/** + * Returns new multiplicative movespeed after modification. + */ +/datum/movespeed_modifier/proc/apply_multiplicative(existing, mob/target) + if(!complex_calculation || (multiplicative_slowdown > 0)) // we aren't limiting how much things can slowdown.. yet. + return existing + multiplicative_slowdown + var/current_tiles = 10 / max(existing, world.tick_lag) + var/minimum_speed = 10 / min(current_tiles + max_tiles_per_second_boost, max(current_tiles, absolute_max_tiles_per_second)) + return max(minimum_speed, existing + multiplicative_slowdown) + GLOBAL_LIST_EMPTY(movespeed_modification_cache) /// Grabs a STATIC MODIFIER datum from cache. YOU MUST NEVER EDIT THESE DATUMS, OR IT WILL AFFECT ANYTHING ELSE USING IT TOO! @@ -171,13 +187,15 @@ GLOBAL_LIST_EMPTY(movespeed_modification_cache) /// Set or update the global movespeed config on a mob /mob/proc/update_config_movespeed() add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/mob_config_speedmod, multiplicative_slowdown = get_config_multiplicative_speed()) + add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/mob_config_speedmod_floating, multiplicative_slowdown = get_config_multiplicative_speed(TRUE)) /// Get the global config movespeed of a mob by type -/mob/proc/get_config_multiplicative_speed() - if(!islist(GLOB.mob_config_movespeed_type_lookup) || !GLOB.mob_config_movespeed_type_lookup[type]) +/mob/proc/get_config_multiplicative_speed(floating = FALSE) + var/list/read = floating? GLOB.mob_config_movespeed_type_lookup_floating : GLOB.mob_config_movespeed_type_lookup + if(!islist(read) || !read[type]) return 0 else - return GLOB.mob_config_movespeed_type_lookup[type] + return read[type] /// Go through the list of movespeed modifiers and calculate a final movespeed. ANY ADD/REMOVE DONE IN UPDATE_MOVESPEED MUST HAVE THE UPDATE ARGUMENT SET AS FALSE! /mob/proc/update_movespeed() @@ -198,7 +216,7 @@ GLOBAL_LIST_EMPTY(movespeed_modification_cache) conflict_tracker[conflict] = amt else continue - . += amt + . = M.apply_multiplicative(., src) var/old = cached_multiplicative_slowdown // CITAEDL EDIT - To make things a bit less jarring, when in situations where // your delay decreases, "give" the delay back to the client cached_multiplicative_slowdown = . @@ -220,6 +238,13 @@ GLOBAL_LIST_EMPTY(movespeed_modification_cache) var/datum/movespeed_modifier/M = movespeed_modification[id] . += M.multiplicative_slowdown +/** + * Gets the movespeed modifier datum of a modifier on a mob. Returns null if not found. + * DANGER: IT IS UP TO THE PERSON USING THIS TO MAKE SURE THE MODIFIER IS NOT MODIFIED IF IT HAPPENS TO BE GLOBAL/CACHED. + */ +/mob/proc/get_movespeed_modifier_datum(id) + return movespeed_modification[id] + /// Checks if a move speed modifier is valid and not missing any data /proc/movespeed_data_null_check(datum/movespeed_modifier/M) //Determines if a data list is not meaningful and should be discarded. . = TRUE diff --git a/code/modules/movespeed/modifiers/items.dm b/code/modules/movespeed/modifiers/items.dm index 94dc2a1553..a8510ecd86 100644 --- a/code/modules/movespeed/modifiers/items.dm +++ b/code/modules/movespeed/modifiers/items.dm @@ -1,12 +1,13 @@ /datum/movespeed_modifier/jetpack conflicts_with = MOVE_CONFLICT_JETPACK movetypes = FLOATING + multiplicative_slowdown = -1 /datum/movespeed_modifier/jetpack/cybernetic - multiplicative_slowdown = -0.5 + multiplicative_slowdown = -1.25 /datum/movespeed_modifier/jetpack/fullspeed - multiplicative_slowdown = -2 + multiplicative_slowdown = -1.5 /datum/movespeed_modifier/die_of_fate multiplicative_slowdown = 1 diff --git a/code/modules/movespeed/modifiers/mobs.dm b/code/modules/movespeed/modifiers/mobs.dm index d17767bb1f..f6cf84eb83 100644 --- a/code/modules/movespeed/modifiers/mobs.dm +++ b/code/modules/movespeed/modifiers/mobs.dm @@ -111,6 +111,12 @@ /datum/movespeed_modifier/mob_config_speedmod variable = TRUE + blacklisted_movetypes = FLOATING + flags = IGNORE_NOSLOW + +/datum/movespeed_modifier/mob_config_speedmod_floating + variable = TRUE + movetypes = FLOATING flags = IGNORE_NOSLOW /datum/movespeed_modifier/liver_cirrhosis @@ -120,3 +126,30 @@ /datum/movespeed_modifier/active_block variable = TRUE flags = IGNORE_NOSLOW + +/datum/movespeed_modifier/sprinting + flags = IGNORE_NOSLOW + blacklisted_movetypes = FLOATING + priority = 100 + +/// for speed reasons this is sorta copypasty. +/datum/movespeed_modifier/sprinting/apply_multiplicative(existing, mob/target) + . = existing + if(target.m_intent != MOVE_INTENT_RUN) + return + if(isliving(target)) + var/mob/living/L = target + if(!(L.mobility_flags & MOBILITY_STAND)) + return + var/static/datum/config_entry/number/movedelay/sprint_max_tiles_increase/SMTI + if(!SMTI) + SMTI = CONFIG_GET_ENTRY(number/movedelay/sprint_max_tiles_increase) + var/static/datum/config_entry/number/movedelay/sprint_speed_increase/SSI + if(!SSI) + SSI = CONFIG_GET_ENTRY(number/movedelay/sprint_speed_increase) + var/static/datum/config_entry/number/movedelay/sprint_absolute_max_tiles/SAMT + if(!SAMT) + SAMT = CONFIG_GET_ENTRY(number/movedelay/sprint_absolute_max_tiles) + var/current_tiles = 10 / max(existing, world.tick_lag) + var/minimum_speed = 10 / min(max(SAMT.config_entry_value, current_tiles), current_tiles + SMTI.config_entry_value) + . = min(., max(minimum_speed, existing - SSI.config_entry_value)) diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index e3fdbd3654..d61220a1a2 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -928,8 +928,15 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) var/mob/living/user = AM if(user.status_flags & GODMODE) return - message_admins("[src] has consumed [key_name_admin(user)] [ADMIN_JMP(src)].") - investigate_log("has consumed [key_name(user)].", INVESTIGATE_SUPERMATTER) + var/add + if(user.mind?.assigned_role == "Clown") + var/denergy = rand(-1000, 1000) + var/ddamage = rand(-150, clamp(150, 0, (explosion_point - damage) + 150)) + energy += denergy + damage += ddamage + add = ", adding [denergy] energy and [ddamage] damage to the crystal" + message_admins("[src] has consumed [key_name_admin(user)] [ADMIN_JMP(src)][add].") + investigate_log("has consumed [key_name(user)][add].", INVESTIGATE_SUPERMATTER) user.dust(force = TRUE) if(power_changes) matter_power += 200 diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 1369115b0d..1c3a0d230f 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -154,8 +154,8 @@ shake_camera(user, recoil + 1, recoil) 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 + var/safe_cost = clamp(stam_cost, 0, user.stamina_buffer)*(firing && burst_size >= 2 ? 1/burst_size : 1) + user.UseStaminaBuffer(safe_cost) if(suppressed) playsound(user, fire_sound, 10, 1) @@ -590,6 +590,9 @@ update_icon() /obj/item/gun/proc/getinaccuracy(mob/living/user, bonus_spread, stamloss) + return 0 // Replacement TBD: Exponential curved aim instability system. + +/* if(inaccuracy_modifier == 0) return bonus_spread var/base_inaccuracy = weapon_weight * 25 * inaccuracy_modifier @@ -612,6 +615,7 @@ 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 diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm index ecf6e538b8..7b3ac36ef6 100644 --- a/code/modules/projectiles/guns/ballistic/shotgun.dm +++ b/code/modules/projectiles/guns/ballistic/shotgun.dm @@ -44,10 +44,9 @@ if(HAS_TRAIT(user, TRAIT_FAST_PUMP)) recentpump = world.time + 2 else + if(!user.UseStaminaBuffer(2, warn = TRUE)) + return recentpump = world.time + 10 - if(istype(user))//CIT CHANGE - makes pumping shotguns cost a lil bit of stamina. - user.adjustStaminaLossBuffered(2) //CIT CHANGE - DITTO. make this scale inversely to the strength stat when stats/skills are added - return /obj/item/gun/ballistic/shotgun/blow_up(mob/user) . = 0 diff --git a/html/changelogs/AutoChangeLog-pr-13193.yml b/html/changelogs/AutoChangeLog-pr-13193.yml new file mode 100644 index 0000000000..980a9366d8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13193.yml @@ -0,0 +1,4 @@ +author: "silicons" +delete-after: True +changes: + - tweak: "medium screens are better now" diff --git a/html/changelogs/AutoChangeLog-pr-13530.yml b/html/changelogs/AutoChangeLog-pr-13530.yml new file mode 100644 index 0000000000..b99ed1c545 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13530.yml @@ -0,0 +1,4 @@ +author: "silicons" +delete-after: True +changes: + - rscadd: "Clowns now have unpredictable effects on supermatter crystals when dusting from contact." diff --git a/modular_citadel/code/modules/mob/living/carbon/damage_procs.dm b/modular_citadel/code/modules/mob/living/carbon/damage_procs.dm index 17c3f17ad8..0457b853b7 100644 --- a/modular_citadel/code/modules/mob/living/carbon/damage_procs.dm +++ b/modular_citadel/code/modules/mob/living/carbon/damage_procs.dm @@ -1,16 +1,3 @@ -/mob/living/carbon/adjustStaminaLossBuffered(amount, updating_health = 1) - if(status_flags & GODMODE) - return 0 - if(CONFIG_GET(flag/disable_stambuffer)) - return - var/directstamloss = (bufferedstam + amount) - stambuffer - if(directstamloss > 0) - adjustStaminaLoss(directstamloss) - bufferedstam = clamp(bufferedstam + amount, 0, stambuffer) - stambufferregentime = world.time + 10 - if(updating_health) - update_health_hud() - /mob/living/carbon/adjustStaminaLoss(amount, updating_health = TRUE, forced = FALSE, affected_zone = BODY_ZONE_CHEST) if(!forced && (status_flags & GODMODE)) return FALSE diff --git a/modular_citadel/code/modules/mob/living/damage_procs.dm b/modular_citadel/code/modules/mob/living/damage_procs.dm deleted file mode 100644 index a399c17c71..0000000000 --- a/modular_citadel/code/modules/mob/living/damage_procs.dm +++ /dev/null @@ -1,2 +0,0 @@ -/mob/living/proc/adjustStaminaLossBuffered(amount, updating_health = TRUE, forced = FALSE) - return diff --git a/modular_citadel/code/modules/mob/living/living.dm b/modular_citadel/code/modules/mob/living/living.dm index 01867e9dcc..b5be028607 100644 --- a/modular_citadel/code/modules/mob/living/living.dm +++ b/modular_citadel/code/modules/mob/living/living.dm @@ -1,5 +1,3 @@ -/mob/living - /atom var/pseudo_z_axis @@ -24,26 +22,3 @@ if(.) pseudo_z_axis = newloc.get_fake_z() pixel_z = pseudo_z_axis - -/mob/living/carbon/update_stamina() - var/total_health = getStaminaLoss() - if(total_health >= STAMINA_SOFTCRIT) - if(!(combat_flags & COMBAT_FLAG_SOFT_STAMCRIT)) - ENABLE_BITFIELD(combat_flags, COMBAT_FLAG_SOFT_STAMCRIT) - else - if(combat_flags & COMBAT_FLAG_SOFT_STAMCRIT) - DISABLE_BITFIELD(combat_flags, COMBAT_FLAG_SOFT_STAMCRIT) - if(total_health) - if(!(combat_flags & COMBAT_FLAG_HARD_STAMCRIT) && total_health >= STAMINA_CRIT && !stat) - to_chat(src, "You're too exhausted to keep going...") - set_resting(TRUE, FALSE, FALSE) - SEND_SIGNAL(src, COMSIG_DISABLE_COMBAT_MODE) - ENABLE_BITFIELD(combat_flags, COMBAT_FLAG_HARD_STAMCRIT) - filters += CIT_FILTER_STAMINACRIT - update_mobility() - if((combat_flags & COMBAT_FLAG_HARD_STAMCRIT) && total_health <= STAMINA_SOFTCRIT) - to_chat(src, "You don't feel nearly as exhausted anymore.") - DISABLE_BITFIELD(combat_flags, COMBAT_FLAG_HARD_STAMCRIT | COMBAT_FLAG_SOFT_STAMCRIT) - filters -= CIT_FILTER_STAMINACRIT - update_mobility() - update_health_hud() diff --git a/modular_citadel/icons/ui/screen_gen.dmi b/modular_citadel/icons/ui/screen_gen.dmi index d006185a3c..510d312f1c 100644 Binary files a/modular_citadel/icons/ui/screen_gen.dmi and b/modular_citadel/icons/ui/screen_gen.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 9587a792de..750486e032 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -139,6 +139,7 @@ #include "code\__DEFINES\combat\attack_types.dm" #include "code\__DEFINES\combat\block.dm" #include "code\__DEFINES\combat\block_parry.dm" +#include "code\__DEFINES\combat\stamina_combat.dm" #include "code\__DEFINES\dcs\flags.dm" #include "code\__DEFINES\dcs\helpers.dm" #include "code\__DEFINES\dcs\signals.dm" @@ -293,6 +294,7 @@ #include "code\controllers\configuration\entries\plushies.dm" #include "code\controllers\configuration\entries\policy.dm" #include "code\controllers\configuration\entries\resources.dm" +#include "code\controllers\configuration\entries\stamina_combat.dm" #include "code\controllers\subsystem\acid.dm" #include "code\controllers\subsystem\adjacent_air.dm" #include "code\controllers\subsystem\air.dm" @@ -2283,7 +2285,6 @@ #include "code\modules\jobs\job_types\station_engineer.dm" #include "code\modules\jobs\job_types\virologist.dm" #include "code\modules\jobs\job_types\warden.dm" -#include "code\modules\jobs\map_changes\map_changes.dm" #include "code\modules\keybindings\bindings_atom.dm" #include "code\modules\keybindings\bindings_client.dm" #include "code\modules\keybindings\focus.dm" @@ -2465,6 +2466,7 @@ #include "code\modules\mob\living\login.dm" #include "code\modules\mob\living\logout.dm" #include "code\modules\mob\living\say.dm" +#include "code\modules\mob\living\stamina_buffer.dm" #include "code\modules\mob\living\status_procs.dm" #include "code\modules\mob\living\taste.dm" #include "code\modules\mob\living\update_icons.dm" @@ -3604,7 +3606,6 @@ #include "modular_citadel\code\modules\mentor\mentorpm.dm" #include "modular_citadel\code\modules\mentor\mentorsay.dm" #include "modular_citadel\code\modules\mob\cit_emotes.dm" -#include "modular_citadel\code\modules\mob\living\damage_procs.dm" #include "modular_citadel\code\modules\mob\living\living.dm" #include "modular_citadel\code\modules\mob\living\carbon\carbon.dm" #include "modular_citadel\code\modules\mob\living\carbon\damage_procs.dm"