From 70b8d833c0bfa2daa1f43b888ce732b6cb761a4a Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Sun, 28 Feb 2021 00:00:14 -0700 Subject: [PATCH 01/43] changes --- code/__HELPERS/do_after.dm | 47 +++++++++-------- code/_onclick/item_attack.dm | 2 +- .../configuration/entries/game_options.dm | 9 ++++ code/datums/status_effects/debuffs.dm | 12 ++++- code/game/objects/effects/decals/misc.dm | 51 +++++++++++++++++++ code/modules/mob/living/carbon/carbon.dm | 20 +++++++- code/modules/mob/living/carbon/human/human.dm | 6 +-- .../mob/living/carbon/human/species.dm | 3 +- code/modules/mob/living/say.dm | 21 +++++--- .../movespeed/modifiers/status_effects.dm | 6 +++ code/modules/ninja/suit/suit.dm | 4 +- .../projectiles/ammunition/energy/stun.dm | 4 ++ .../projectiles/guns/energy/energy_gun.dm | 14 ++++- .../projectiles/projectile/energy/stun.dm | 14 ++--- .../reagents/reagent_containers/spray.dm | 51 +++---------------- 15 files changed, 173 insertions(+), 91 deletions(-) diff --git a/code/__HELPERS/do_after.dm b/code/__HELPERS/do_after.dm index c65cd80394..550eea65c0 100644 --- a/code/__HELPERS/do_after.dm +++ b/code/__HELPERS/do_after.dm @@ -1,23 +1,24 @@ /** - * Higher overhead "advanced" version of do_after. - * @params - * - atom/user is the atom doing the action or the "physical" user - * - delay is time in deciseconds - * - atom/target is the atom the action is being done to, defaults to user - * - do_after_flags see __DEFINES/flags/do_after.dm for details. - * - datum/callback/extra_checks - Every time this ticks, extra_checks() is invoked with (user, delay, target, time_left, do_after_flags, required_mobility_flags, required_combat_flags, mob_redirect, stage, initially_held_item, tool). - * Stage can be DO_AFTER_STARTING, DO_AFTER_PROGRESSING, DO_AFTER_FINISHING - * If it returns DO_AFTER_STOP, this breaks. - * If it returns nothing, all other checks are done. - * If it returns DO_AFTER_PROCEED, all other checks are ignored. - * - required_mobility_flags is checked with CHECK_ALL_MOBILITY. Will immediately fail if the user isn't a mob. - * - requried_combat_flags is checked with CHECK_MULTIPLE_BITFIELDS. Will immediately fail if the user isn't a mob. - * - mob/living/mob_redirect - advanced option: If this is specified, movement and mobility/combat flag checks will use this instead of user. Progressbars will also go to this. - * - obj/item/tool - The tool we're using. See do_after flags for details. - */ -#define INVOKE_CALLBACK cb_return = extra_checks?.Invoke(user, delay, target, world.time - starttime, do_after_flags, required_mobility_flags, required_combat_flags, mob_redirect, stage, initially_held_item, tool) + * Higher overhead "advanced" version of do_after. + * @params + * - atom/user is the atom doing the action or the "physical" user + * - delay is time in deciseconds + * - atom/target is the atom the action is being done to, defaults to user + * - do_after_flags see __DEFINES/flags/do_after.dm for details. + * - datum/callback/extra_checks - Every time this ticks, extra_checks() is invoked with (user, delay, target, time_left, do_after_flags, required_mobility_flags, required_combat_flags, mob_redirect, stage, initially_held_item, tool, passed_in). + * Stage can be DO_AFTER_STARTING, DO_AFTER_PROGRESSING, DO_AFTER_FINISHING + * If it returns DO_AFTER_STOP, this breaks. + * If it returns nothing, all other checks are done. + * If it returns DO_AFTER_PROCEED, all other checks are ignored. + * passed_in is a list[PROGRESS_MULTIPLIER], for modification. + * - required_mobility_flags is checked with CHECK_ALL_MOBILITY. Will immediately fail if the user isn't a mob. + * - requried_combat_flags is checked with CHECK_MULTIPLE_BITFIELDS. Will immediately fail if the user isn't a mob. + * - mob/living/mob_redirect - advanced option: If this is specified, movement and mobility/combat flag checks will use this instead of user. Progressbars will also go to this. + * - obj/item/tool - The tool we're using. See do_after flags for details. + */ +#define INVOKE_CALLBACK cb_return = extra_checks?.Invoke(user, delay, target, timeleft, do_after_flags, required_mobility_flags, required_combat_flags, mob_redirect, stage, initially_held_item, tool, passed_in) #define CHECK_FLAG_FAILURE ((required_mobility_flags || required_combat_flags) && (!living_user || (required_mobility_flags && !CHECK_ALL_MOBILITY(living_user, required_mobility_flags)) || (required_combat_flags && !CHECK_MULTIPLE_BITFIELDS(living_user.combat_flags, required_combat_flags)))) -#define TIMELEFT (world.time - starttime) +#define TIMELEFT (timeleft) /proc/do_after_advanced(atom/user, delay, atom/target, do_after_flags, datum/callback/extra_checks, required_mobility_flags, required_combat_flags, mob/living/mob_redirect, obj/item/tool) // CHECK AND SET VARIABLES if(!user) @@ -40,8 +41,7 @@ return FALSE if(!(do_after_flags & DO_AFTER_NO_COEFFICIENT) && living_user) delay *= living_user.cached_multiplicative_actions_slowdown - var/starttime = world.time - var/endtime = world.time + delay + var/timeleft = delay var/obj/item/initially_held_item = mob_redirect?.get_active_held_item() var/atom/movable/AM_user = ismovable(user) && user var/drifting = AM_user?.Process_Spacemove(NONE) && AM_user.inertia_dir @@ -70,13 +70,18 @@ var/locchanged var/ctu var/ctt - while(world.time < endtime) + var/tick_time = world.time + var/list/passed_in = list(1) + while(timeleft > 0) stoplag(1) + var/timepassed = world.time - tick_time + timepassed = world.time progbar?.update(TIMELEFT) if(QDELETED(user) || QDELETED(target) || (user.loc == null) || (target.loc == null)) . = FALSE break INVOKE_CALLBACK + timeleft -= timepassed * passed_in[1] if(cb_return == DO_AFTER_STOP) . = FALSE break diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 7a614da07b..bedb0f6dec 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -255,7 +255,7 @@ if(!isnull(stagger_force)) return stagger_force /// totally not an untested, arbitrary equation. - return clamp((1.5 + (w_class/5)) * ((force_override || force) / 1.5), 0, 10 SECONDS) + return clamp((1.5 + (w_class/5)) * ((force_override || force) / 1.5), 0, 10 SECONDS) * CONFIG_GET(number/melee_stagger_factor) /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 4034722417..f6a3388c01 100644 --- a/code/controllers/configuration/entries/game_options.dm +++ b/code/controllers/configuration/entries/game_options.dm @@ -262,6 +262,15 @@ /mob/living/carbon/alien/humanoid/royal/queen = 2 ) +/datum/config_entry/number/sprintless_stagger_slowdown + config_entry_value = 0 + +/datum/config_entry/number/melee_stagger_factor + config_entry_value = 1 + +/datum/config_entry/number/sprintless_off_balance_slowdown + config_entry_value = 0.85 + /datum/config_entry/number/movedelay //Used for modifying movement speed for mobs. abstract_type = /datum/config_entry/number/movedelay integer = FALSE diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm index fe59bbe14a..1909327cc9 100644 --- a/code/datums/status_effects/debuffs.dm +++ b/code/datums/status_effects/debuffs.dm @@ -95,21 +95,31 @@ /datum/status_effect/staggered/on_creation(mob/living/new_owner, set_duration) if(isnum(set_duration)) duration = set_duration + if(!CONFIG_GET(flag/sprint_enabled)) + new_owner.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/status_effect/stagger, TRUE, CONFIG_GET(number/sprintless_stagger_slowdown)) + return ..() + +/datum/status_effect/staggered/on_remove() + owner.remove_movespeed_modifier(/datum/movespeed_modifier/status_effect/stagger) return ..() /datum/status_effect/off_balance id = "offbalance" + blocks_sprint = TRUE alert_type = null /datum/status_effect/off_balance/on_creation(mob/living/new_owner, set_duration) if(isnum(set_duration)) duration = set_duration + if(!CONFIG_GET(flag/sprint_enabled)) + new_owner.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/status_effect/off_balance, TRUE, CONFIG_GET(number/sprintless_off_balance_slowdown)) return ..() /datum/status_effect/off_balance/on_remove() var/active_item = owner.get_active_held_item() if(is_type_in_typecache(active_item, GLOB.shove_disarming_types)) owner.visible_message("[owner.name] regains their grip on \the [active_item]!", "You regain your grip on \the [active_item]", null, COMBAT_MESSAGE_RANGE) + owner.remove_movespeed_modifier(/datum/movespeed_modifier/status_effect/off_balance) return ..() /obj/screen/alert/status_effect/asleep @@ -162,7 +172,7 @@ id = "tased" alert_type = null var/movespeed_mod = /datum/movespeed_modifier/status_effect/tased - var/stamdmg_per_ds = 0 //a 20 duration would do 20 stamdmg, disablers do 24 or something + var/stamdmg_per_ds = 1 //a 20 duration would do 20 stamdmg, disablers do 24 or something var/last_tick = 0 //fastprocess processing speed is a goddamn sham, don't trust it. /datum/status_effect/electrode/on_creation(mob/living/new_owner, set_duration) diff --git a/code/game/objects/effects/decals/misc.dm b/code/game/objects/effects/decals/misc.dm index 8f46d5cc46..514fcdd68a 100644 --- a/code/game/objects/effects/decals/misc.dm +++ b/code/game/objects/effects/decals/misc.dm @@ -19,10 +19,61 @@ icon = 'icons/obj/chempuff.dmi' pass_flags = PASSTABLE | PASSGRILLE layer = FLY_LAYER + var/stream = FALSE + var/speed = 1 + var/range = 3 + var/hits_left = 3 + var/range_left = 3 /obj/effect/decal/chempuff/blob_act(obj/structure/blob/B) return +/obj/effect/decal/chempuff/Initialize(mapload, stream_mode, speed, range, hits_left) + . = ..() + stream = stream_mode + src.speed = speed + src.range = scc.range_left = range + src.hits_left = hits_left + +/obj/effect/decal/chempuff/proc/hit_thing(atom/A) + if(A == src || A.invisibility) + return + if(!hits_left) + return + if(stream) + if(ismob(A)) + var/mob/M = A + if(!M.lying || !range_left) + reagents.reaction(M, VAPOR) + hits_left-- + else + if(!range_left) + reagents.reaction(A, VAPOR) + else + reagents.reaction(A) + if(ismob(A)) + hits_left-- + +/obj/effect/decal/chempuff/Crossed(atom/movable/AM, oldloc) + . = ..() + hit_thing(AM) + +/obj/effect/decal/chempuff/proc/run(atom/target) + for(var/i in 1 to range) + range_left-- + if(!isturf(loc)) + break + for(var/atom/T in loc) + hit_thing(T) + if(!hits_left || !isturf(loc)) + break + if(hits_left && isturf(loc) && (!stream || !range_left)) + reagents.reaction(loc, VAPOR) + hits_left-- + if(!hits_left) + break + qdel(src) + /obj/effect/decal/fakelattice name = "lattice" desc = "A lightweight support lattice." diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index f143f6302d..c7a2d611d6 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -358,10 +358,11 @@ return I.item_flags |= BEING_REMOVED breakouttime = I.breakouttime + var/datum/cuffbreak_checker/cuffbreak_checker = new(get_turf(src)) if(!cuff_break) visible_message("[src] attempts to remove [I]!") to_chat(src, "You attempt to remove [I]... (This will take around [DisplayTimeText(breakouttime)] and you need to stand still.)") - if(do_after(src, breakouttime, 0, target = src, required_mobility_flags = MOBILITY_RESIST)) + if(do_after_advanced(src, breakouttime, src, NONE, CALLBACK(cuffbreak_checker, /datum/cuffbreak_checker.proc/check_movement), required_mobility_flags = MOBILITY_RESIST)) clear_cuffs(I, cuff_break) else to_chat(src, "You fail to remove [I]!") @@ -370,15 +371,30 @@ breakouttime = 50 visible_message("[src] is trying to break [I]!") to_chat(src, "You attempt to break [I]... (This will take around 5 seconds and you need to stand still.)") - if(do_after(src, breakouttime, 0, target = src)) + if(do_after_advanced(src, breakouttime, src, NONE, CALLBACK(cuffbreak_checker, /datum/cuffbreak_checker.proc/check_movement), required_mobility_flags = MOBILITY_RESIST)) clear_cuffs(I, cuff_break) else to_chat(src, "You fail to break [I]!") else if(cuff_break == INSTANT_CUFFBREAK) clear_cuffs(I, cuff_break) + + QDEL_NULL(cuffbreak_checker) I.item_flags &= ~BEING_REMOVED +/datum/cuffbreak_checker + var/turf/last + +/datum/cuffbreak_checker/New(turf/initial_turf) + last = initial_turf + +/datum/cuffbreak_checker/proc/check_movement(atom/user, delay, atom/target, time_left, do_after_flags, required_mobility_flags, required_combat_flags, mob_redirect, stage, initially_held_item, tool, list/passed_in) + if(get_turf(user) != last) + last = get_turf(user) + passed_in[1] = 0.5 + else + passed_in[1] = 1 + /mob/living/carbon/proc/uncuff() if (handcuffed) var/obj/item/W = handcuffed diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 8660e115a6..6190518963 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1053,10 +1053,10 @@ return 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) - (health / scaling) + (getStaminaLoss()*0.75))//CIT CHANGE - reduces the impact of staminaloss and makes stamina buffer influence it + var/health_deficiency = max(((maxHealth / scaling) - (health / scaling)), (getStaminaLoss()*0.75)) 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) + add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown, TRUE, (health_deficiency - 15) / 75) + add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying, TRUE, (health_deficiency - 15) / 25) else remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown) remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index a7e305201d..8bae43848d 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1834,6 +1834,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(CHECK_MOBILITY(target, MOBILITY_STAND)) target.adjustStaminaLoss(5) + else + target.adjustStaminaLoss(target.getStaminaLoss() > 75? 5 : 75) if(target.is_shove_knockdown_blocked()) return @@ -1876,7 +1878,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) target.visible_message("[user.name] shoves [target.name]!", "[user.name] shoves you!", null, COMBAT_MESSAGE_RANGE, null, user, "You shove [target.name]!") - target.Stagger(SHOVE_STAGGER_DURATION) var/obj/item/target_held_item = target.get_active_held_item() if(!is_type_in_typecache(target_held_item, GLOB.shove_disarming_types)) target_held_item = null diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index 9646796802..d72b8c904a 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -266,16 +266,10 @@ GLOBAL_LIST_INIT(department_radio_keys, list( eavesdrop_range = EAVESDROP_EXTRA_RANGE var/list/listening = get_hearers_in_view(message_range+eavesdrop_range, source) var/list/the_dead = list() - var/list/yellareas //CIT CHANGE - adds the ability for yelling to penetrate walls and echo throughout areas - if(!eavesdrop_range && say_test(message) == "2") //CIT CHANGE - ditto - yellareas = get_areas_in_range(message_range*0.5, source) //CIT CHANGE - ditto + for(var/_M in GLOB.player_list) var/mob/M = _M if(M.stat != DEAD) //not dead, not important - if(yellareas) //CIT CHANGE - see above. makes yelling penetrate walls - var/area/A = get_area(M) //CIT CHANGE - ditto - if(istype(A) && A.ambientsounds != SPACE && (A in yellareas)) //CIT CHANGE - ditto - listening |= M //CIT CHANGE - ditto continue if(!M.client || !client) //client is so that ghosts don't have to listen to mice continue @@ -302,6 +296,9 @@ GLOBAL_LIST_INIT(department_radio_keys, list( AM.Hear(rendered, src, message_language, message, null, spans, message_mode, source) SEND_GLOBAL_SIGNAL(COMSIG_GLOB_LIVING_SAY_SPECIAL, src, message) + if(!eavesdrop_range && say_test(message) == "2") // Yell hook + process_yelling(listening, rendered, src, message_language, message, spans, message_mode, source) + //speech bubble var/list/speech_bubble_recipients = list() for(var/mob/M in listening) @@ -311,6 +308,14 @@ GLOBAL_LIST_INIT(department_radio_keys, list( I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA INVOKE_ASYNC(GLOBAL_PROC, /.proc/flick_overlay, I, speech_bubble_recipients, 30) +/atom/movable/proc/process_yelling(list/already_heard, rendered, atom/movable/speaker, datum/language/message_language, list/spans, message_mode, obj/source) + var/list/overhearing = list() +#warn todo: yelling + overhearing -= already_heard + for(var/_AM in overhearing) + var/atom/movable/AM = _AM + AM.Hear(rendered, speaker, message_language, message, null, spans, message_mode, source) + /mob/proc/binarycheck() return FALSE @@ -333,7 +338,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list( var/obj/item/bodypart/rightarm = get_bodypart(BODY_ZONE_R_ARM) if(HAS_TRAIT(src, TRAIT_MUTE) && get_selected_language() != /datum/language/signlanguage) return 0 - + if (get_selected_language() == /datum/language/signlanguage) var/left_disabled = FALSE var/right_disabled = FALSE diff --git a/code/modules/movespeed/modifiers/status_effects.dm b/code/modules/movespeed/modifiers/status_effects.dm index 4c710cb483..d174524898 100644 --- a/code/modules/movespeed/modifiers/status_effects.dm +++ b/code/modules/movespeed/modifiers/status_effects.dm @@ -42,3 +42,9 @@ /datum/movespeed_modifier/status_effect/mkultra multiplicative_slowdown = -2 blacklisted_movetypes= FLYING|FLOATING + +/datum/movespeed_modifier/status_effect/staggered + variable = TRUE + +/datum/movespeed_modifier/status_effect/off_balance + variable = TRUE diff --git a/code/modules/ninja/suit/suit.dm b/code/modules/ninja/suit/suit.dm index b46f30b4fb..ed711771bf 100644 --- a/code/modules/ninja/suit/suit.dm +++ b/code/modules/ninja/suit/suit.dm @@ -118,7 +118,7 @@ Contents: ADD_TRAIT(n_hood, TRAIT_NODROP, NINJA_SUIT_TRAIT) n_shoes = H.shoes ADD_TRAIT(n_shoes, TRAIT_NODROP, NINJA_SUIT_TRAIT) - n_shoes.slowdown-- + n_shoes.slowdown -= 0.5 n_gloves = H.gloves ADD_TRAIT(n_gloves, TRAIT_NODROP, NINJA_SUIT_TRAIT) return TRUE @@ -139,7 +139,7 @@ Contents: REMOVE_TRAIT(n_hood, TRAIT_NODROP, NINJA_SUIT_TRAIT) if(n_shoes) REMOVE_TRAIT(n_shoes, TRAIT_NODROP, NINJA_SUIT_TRAIT) - n_shoes.slowdown++ + n_shoes.slowdown += 0.5 if(n_gloves) n_gloves.icon_state = "s-ninja" n_gloves.item_state = "s-ninja" diff --git a/code/modules/projectiles/ammunition/energy/stun.dm b/code/modules/projectiles/ammunition/energy/stun.dm index f063672654..aa889c10bf 100644 --- a/code/modules/projectiles/ammunition/energy/stun.dm +++ b/code/modules/projectiles/ammunition/energy/stun.dm @@ -9,6 +9,10 @@ projectile_type = /obj/item/projectile/energy/electrode/security e_cost = 100 +/obj/item/ammo_casing/energy/electrode/hos + projectile_type = /obj/item/projectile/energy/electrode/hos + e_cost = 100 + /obj/item/ammo_casing/energy/electrode/spec e_cost = 100 diff --git a/code/modules/projectiles/guns/energy/energy_gun.dm b/code/modules/projectiles/guns/energy/energy_gun.dm index 45bc3a79dc..ae78423813 100644 --- a/code/modules/projectiles/guns/energy/energy_gun.dm +++ b/code/modules/projectiles/guns/energy/energy_gun.dm @@ -48,13 +48,23 @@ /obj/item/gun/energy/e_gun/hos name = "\improper X-01 MultiPhase Energy Gun" - desc = "This is an expensive, modern recreation of an antique laser gun. This gun has several unique firemodes, but lacks the ability to recharge over time in exchange for inbuilt advanced firearm EMP shielding." + desc = "This is an expensive, modern recreation of an antique laser gun. This gun has several unique firemodes, but lacks the ability to recharge over time in exchange for inbuilt advanced firearm EMP shielding. Right click in combat mode to fire a taser shot with a cooldown." icon_state = "hoslaser" force = 10 - ammo_type = list(/obj/item/ammo_casing/energy/disabler, /obj/item/ammo_casing/energy/laser/hos, /obj/item/ammo_casing/energy/ion/hos) + ammo_type = list(/obj/item/ammo_casing/energy/disabler, /obj/item/ammo_casing/energy/laser/hos, /obj/item/ammo_casing/energy/ion/hos, /obj/item/ammo_casing/energy/electrode/hos) ammo_x_offset = 4 resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF +/obj/item/gun/energy/e_gun/hos/altafterattack(atom/target, mob/user, proximity_flag, params) + . = TRUE + if(last_altfire + altfire_delay > world.time) + return + var/current_index = current_firemode_index + set_firemode_to_type(/obj/item/ammo_casing/energy/electrode) + process_afterattack(target, user, proximity_flag, params) + set_firemode_index(current_index) + last_altfire = world.time + /obj/item/gun/energy/e_gun/hos/emp_act(severity) return diff --git a/code/modules/projectiles/projectile/energy/stun.dm b/code/modules/projectiles/projectile/energy/stun.dm index 83b753e0a3..6f272dab40 100644 --- a/code/modules/projectiles/projectile/energy/stun.dm +++ b/code/modules/projectiles/projectile/energy/stun.dm @@ -37,15 +37,17 @@ ..() /obj/item/projectile/energy/electrode/security - tase_duration = 30 + tase_duration = 40 knockdown = 0 - stamina = 10 + stamina = 0 knockdown_stamoverride = 0 knockdown_stam_max = 0 strong_tase = FALSE /obj/item/projectile/energy/electrode/security/hos - knockdown = 100 - knockdown_stamoverride = 30 - knockdown_stam_max = null - tase_duration = 10 + tase_duration = 40 + knockdown = 0 + stamina = 0 + knockdown_stamoverride = 0 + knockdown_stam_max = 0 + strong_tase = FALSE diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index eb3b80b693..20fe6b7bc8 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -18,7 +18,8 @@ var/spray_range = 3 //the range of tiles the sprayer will reach when in spray mode. var/stream_range = 1 //the range of tiles the sprayer will reach when in stream mode. var/stream_amount = 10 //the amount of reagents transfered when in stream mode. - var/spray_delay = 3 //The amount of sleep() delay between each chempuff step. + /// Amount of time it takes for a spray to completely travel. + var/spray_delay = 8 /// Last world.time of spray var/last_spray = 0 /// Spray cooldown @@ -72,58 +73,20 @@ if((last_spray + spray_cooldown) > world.time) return var/range = clamp(get_dist(src, A), 1, current_range) - var/obj/effect/decal/chempuff/D = new /obj/effect/decal/chempuff(get_turf(src)) + var/wait_step = CEILING(spray_delay * INVERSE(range), world.tick_lag) + var/obj/effect/decal/chempuff/D = new /obj/effect/decal/chempuff(get_turf(src), stream_mode, wait_step, range, stream_mode? 1 : range) + log_reagent("SPRAY: [key_name(usr)] fired [src] ([REF(src)]) [COORD(T)] at [A] ([REF(A)]) [COORD(A)] (chempuff: [D.reagents.log_list()])") D.create_reagents(amount_per_transfer_from_this, NONE, NO_REAGENTS_VALUE) - var/puff_reagent_left = range //how many turf, mob or dense objet we can react with before we consider the chem puff consumed if(stream_mode) reagents.trans_to(D, amount_per_transfer_from_this) - puff_reagent_left = 1 else reagents.trans_to(D, amount_per_transfer_from_this, 1/range) D.color = mix_color_from_reagents(D.reagents.reagent_list) var/turf/T = get_turf(src) if(!T) return - log_reagent("SPRAY: [key_name(usr)] fired [src] ([REF(src)]) [COORD(T)] at [A] ([REF(A)]) [COORD(A)] (chempuff: [D.reagents.log_list()])") - var/wait_step = max(round(2+ spray_delay * INVERSE(range)), 2) last_spray = world.time - INVOKE_ASYNC(src, .proc/do_spray, A, wait_step, D, range, puff_reagent_left) - return TRUE - -/obj/item/reagent_containers/spray/proc/do_spray(atom/A, wait_step, obj/effect/decal/chempuff/D, range, puff_reagent_left) - var/range_left = range - for(var/i=0, i 0 && (!stream_mode || !range_left)) - D.reagents.reaction(get_turf(D), VAPOR) - puff_reagent_left -= 1 - - if(puff_reagent_left <= 0) // we used all the puff so we delete it. - qdel(D) - return - qdel(D) + D.run((A) /obj/item/reagent_containers/spray/attack_self(mob/user) stream_mode = !stream_mode @@ -207,7 +170,7 @@ righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi' volume = 40 stream_range = 4 - spray_delay = 1 + spray_delay = 2 amount_per_transfer_from_this = 5 list_reagents = list(/datum/reagent/consumable/condensedcapsaicin = 40) From e483ce8dfc060bfe37e9543c8102a49c1071aa67 Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Sun, 28 Feb 2021 00:05:32 -0700 Subject: [PATCH 02/43] changes --- code/modules/reagents/reagent_containers/spray.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index 20fe6b7bc8..6f4b0b37e8 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -86,7 +86,7 @@ if(!T) return last_spray = world.time - D.run((A) + D.run(A) /obj/item/reagent_containers/spray/attack_self(mob/user) stream_mode = !stream_mode From 70c828f74d26789c02b1456e0a87eb0e76c8741d Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Sun, 28 Feb 2021 00:27:14 -0700 Subject: [PATCH 03/43] changes --- code/__DEFINES/combat/block.dm | 2 ++ code/datums/martial/sleeping_carp.dm | 4 ++-- code/game/objects/items/dualsaber.dm | 2 -- code/game/objects/items/electrostaff.dm | 10 +++++----- code/game/objects/items/melee/energy.dm | 6 +++--- code/game/objects/items/melee/misc.dm | 4 ++-- code/game/objects/items/weaponry.dm | 18 ++++++++++++------ .../objects/structures/beds_chairs/chair.dm | 2 +- .../clock_weapons/ratvarian_spear.dm | 2 +- .../mob/living/carbon/human/human_defines.dm | 2 +- .../modules/mob/living/carbon/human/species.dm | 8 ++------ code/modules/mob/living/living_active_parry.dm | 2 +- .../mob/living/living_blocking_parrying.dm | 2 +- code/modules/smithing/finished_items.dm | 4 ++-- 14 files changed, 35 insertions(+), 33 deletions(-) diff --git a/code/__DEFINES/combat/block.dm b/code/__DEFINES/combat/block.dm index bc85947d71..9be4aaa2bf 100644 --- a/code/__DEFINES/combat/block.dm +++ b/code/__DEFINES/combat/block.dm @@ -63,6 +63,8 @@ #define BLOCK_RETURN_MITIGATION_PERCENT "partial_mitigation" /// Used internally by run_parry proc, use on an on_active_parry() proc to override parrying efficiency. #define BLOCK_RETURN_OVERRIDE_PARRY_EFFICIENCY "override_parry_efficiency" +/// Used internally by run_parry proc, use on an on_active_parry() proc to prevent counterattacks +#define BLOCK_RETURN_FORCE_NO_PARRY_COUNTERATTACK "no_parry_counterattack" /// Always set to 100 by run_block() if BLOCK_SUCCESS is in return value. Otherwise, defaults to mitigation percent if not set. Used by projectile/proc/on_hit(). #define BLOCK_RETURN_PROJECTILE_BLOCK_PERCENTAGE "projectile_block_percentage" diff --git a/code/datums/martial/sleeping_carp.dm b/code/datums/martial/sleeping_carp.dm index 5881c76827..e926da78d0 100644 --- a/code/datums/martial/sleeping_carp.dm +++ b/code/datums/martial/sleeping_carp.dm @@ -144,8 +144,8 @@ parry_time_active_visual_override = 3 parry_time_spindown_visual_override = 12 parry_flags = PARRY_DEFAULT_HANDLE_FEEDBACK //can attack while - parry_time_perfect = 2.5 // first ds isn't perfect - parry_time_perfect_leeway = 1.5 + parry_time_perfect = 2.5 + parry_time_perfect_leeway = 2.5 parry_imperfect_falloff_percent = 5 parry_efficiency_to_counterattack = 100 parry_efficiency_considered_successful = 65 // VERY generous diff --git a/code/game/objects/items/dualsaber.dm b/code/game/objects/items/dualsaber.dm index 3d62a98ddf..86522b9587 100644 --- a/code/game/objects/items/dualsaber.dm +++ b/code/game/objects/items/dualsaber.dm @@ -69,7 +69,6 @@ parry_time_perfect = 2 // first ds isn't perfect parry_time_perfect_leeway = 1 parry_imperfect_falloff_percent = 10 - parry_efficiency_to_counterattack = 100 parry_efficiency_considered_successful = 25 // VERY generous parry_failed_stagger_duration = 3 SECONDS parry_failed_clickcd_duration = CLICK_CD_MELEE @@ -369,7 +368,6 @@ parry_time_perfect = 1 parry_time_perfect_leeway = 1 parry_imperfect_falloff_percent = 7.5 - parry_efficiency_to_counterattack = 100 parry_efficiency_considered_successful = 80 parry_efficiency_perfect = 120 parry_efficiency_perfect_override = list( diff --git a/code/game/objects/items/electrostaff.dm b/code/game/objects/items/electrostaff.dm index 31aaff12b5..71cebc38c6 100644 --- a/code/game/objects/items/electrostaff.dm +++ b/code/game/objects/items/electrostaff.dm @@ -45,15 +45,15 @@ // no attacking while blocking block_lock_attacking = TRUE - parry_time_windup = 1 - parry_time_active = 5 + parry_time_windup = 0 + parry_time_active = 7 parry_time_spindown = 0 parry_time_spindown_visual_override = 1 parry_flags = PARRY_DEFAULT_HANDLE_FEEDBACK | PARRY_LOCK_ATTACKING // no attacking while parrying parry_time_perfect = 0 parry_time_perfect_leeway = 0.5 - parry_efficiency_perfect = 100 - parry_imperfect_falloff_percent = 1 + parry_efficiency_perfect = 85 + parry_imperfect_falloff_percent = 10 parry_imperfect_falloff_percent_override = list( TEXT_ATTACK_TYPE_PROJECTILE = 45 // really crappy vs projectiles ) @@ -61,7 +61,7 @@ TEXT_ATTACK_TYPE_PROJECTILE = 1 // extremely harsh window for projectiles ) // not extremely punishing to fail, but no spamming the parry. - parry_cooldown = 2.5 SECONDS + parry_cooldown = 1.5 SECONDS parry_failed_stagger_duration = 1.5 SECONDS parry_failed_clickcd_duration = 1 SECONDS diff --git a/code/game/objects/items/melee/energy.dm b/code/game/objects/items/melee/energy.dm index 55546a7f9c..f1201dca4f 100644 --- a/code/game/objects/items/melee/energy.dm +++ b/code/game/objects/items/melee/energy.dm @@ -121,7 +121,7 @@ parry_time_perfect = 2.5 // first ds isn't perfect parry_time_perfect_leeway = 1.5 parry_imperfect_falloff_percent = 5 - parry_efficiency_to_counterattack = 100 + parry_efficiency_to_counterattack = INFINITY parry_efficiency_considered_successful = 65 // VERY generous parry_efficiency_perfect = 100 parry_failed_stagger_duration = 4 SECONDS @@ -149,8 +149,8 @@ /obj/item/melee/transforming/energy/sword/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time) . = ..() - if(parry_efficiency >= 80) // perfect parry - block_return[BLOCK_RETURN_REDIRECT_METHOD] = REDIRECT_METHOD_RETURN_TO_SENDER + if(parry_efficiency >= 100) // perfect parry + block_return[BLOCK_RETURN_REDIRECT_METHOD] = REDIRECT_METHOD_DEFLECT . |= BLOCK_SHOULD_REDIRECT /obj/item/melee/transforming/energy/sword/cyborg diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm index 15d10c4d11..d2dea3c502 100644 --- a/code/game/objects/items/melee/misc.dm +++ b/code/game/objects/items/melee/misc.dm @@ -81,7 +81,7 @@ parry_imperfect_falloff_percent = 30 parry_efficiency_perfect = 100 parry_failed_stagger_duration = 3 SECONDS - parry_failed_clickcd_duration = 2 SECONDS + parry_failed_clickcd_duration = 1 SECONDS /obj/item/melee/sabre/Initialize() . = ..() @@ -192,7 +192,7 @@ TEXT_ATTACK_TYPE_PROJECTILE = 50 // useless after 3rd decisecond ) parry_imperfect_falloff_percent = 30 - parry_efficiency_to_counterattack = 100 + parry_efficiency_to_counterattack = INFINITY parry_efficiency_considered_successful = 1 parry_efficiency_perfect = 100 parry_data = list( diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index 554ea81974..a826900871 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -315,6 +315,12 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 bare_wound_bonus = 0 wound_bonus = 0 +/obj/item/melee/bokken/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time) + . = ..() + if(!istype(object, /obj/item/melee/bokken)) + // no counterattack. + block_return[BLOCK_RETURN_FORCE_NO_PARRY_COUNTERATTACK] = TRUE + /datum/block_parry_data/bokken // fucked up parry data, emphasizing quicker, shorter parries parry_stamina_cost = 10 // be wise about when you parry, though, else you won't be able to fight enough to make it count parry_time_windup = 0 @@ -417,7 +423,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 desc = "A misnomer of sorts, this is effectively a blunt katana made from steelwood, a dense organic wood derived from steelcaps. Why steelwood? Druids can use it. Duh." icon_state = "bokken_steel" item_state = "bokken_steel" - force = 12 + force = 12 stamina_damage_increment = 3 /obj/item/melee/bokken/waki @@ -427,7 +433,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 item_state = "wakibokken" slot_flags = ITEM_SLOT_BELT w_class = WEIGHT_CLASS_NORMAL - force = 6 + force = 6 stamina_damage_increment = 4 block_parry_data = /datum/block_parry_data/bokken/waki default_parry_data = /datum/block_parry_data/bokken/waki @@ -442,7 +448,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 parry_time_perfect_leeway = 1 parry_imperfect_falloff_percent = 7.5 parry_efficiency_to_counterattack = 120 - parry_efficiency_considered_successful = 65 + parry_efficiency_considered_successful = 65 parry_efficiency_perfect = 120 parry_efficiency_perfect_override = list( TEXT_ATTACK_TYPE_PROJECTILE = 30, @@ -455,10 +461,10 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 /datum/block_parry_data/bokken/waki/quick_parry //For the parry spammer in you parry_stamina_cost = 2 // Slam that parry button parry_time_active = 2.5 - parry_time_perfect = 1 + parry_time_perfect = 1 parry_time_perfect_leeway = 1 parry_failed_stagger_duration = 1 SECONDS - parry_failed_clickcd_duration = 1 SECONDS + parry_failed_clickcd_duration = 1 SECONDS /datum/block_parry_data/bokken/waki/quick_parry/proj parry_efficiency_perfect_override = list() @@ -468,7 +474,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 desc = "A misnomer of sorts, this is effectively a blunt wakizashi made from steelwood, a dense organic wood derived from steelcaps. Why steelwood? Druids can use it. Duh." icon_state = "wakibokken_steel" item_state = "wakibokken_steel" - force = 8 + force = 8 stamina_damage_increment = 2 /obj/item/melee/bokken/debug diff --git a/code/game/objects/structures/beds_chairs/chair.dm b/code/game/objects/structures/beds_chairs/chair.dm index 76ab086eb2..89f018f291 100644 --- a/code/game/objects/structures/beds_chairs/chair.dm +++ b/code/game/objects/structures/beds_chairs/chair.dm @@ -348,7 +348,7 @@ parry_time_perfect = 1.5 parry_time_perfect_leeway = 1 parry_imperfect_falloff_percent = 7.5 - parry_efficiency_to_counterattack = 100 + parry_efficiency_to_counterattack = INFINITY parry_efficiency_considered_successful = 50 parry_efficiency_perfect = 120 parry_efficiency_perfect_override = list( diff --git a/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_spear.dm b/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_spear.dm index aa69478217..d0f63ac887 100644 --- a/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_spear.dm +++ b/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_spear.dm @@ -90,7 +90,7 @@ parry_time_perfect = 2 parry_efficiency_perfect = 110 //Very low leeway for counterattacks... parry_efficiency_considered_successful = 0.8 - parry_efficiency_to_counterattack = 1 + parry_efficiency_to_counterattack = 110 parry_cooldown = 15 //But also very low cooldown.. parry_failed_stagger_duration = 2 SECONDS //And relatively small penalties for failing. parry_failed_clickcd_duration = 1 SECONDS diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 66d3154ee3..10abc87237 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -140,7 +140,7 @@ ) parry_efficiency_considered_successful = 0.01 - parry_efficiency_to_counterattack = 0.01 + parry_efficiency_to_counterattack = INFINITY // no counterattacks parry_max_attacks = INFINITY parry_failed_cooldown_duration = 1.5 SECONDS parry_failed_stagger_duration = 1 SECONDS diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 8bae43848d..7851631b33 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1559,12 +1559,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) else 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 - if(!user.UseStaminaBuffer(1, warn = TRUE)) - return - else - if(!user.UseStaminaBuffer(1, warn = TRUE)) - return + if(!user.UseStaminaBuffer(1, warn = TRUE)) + return if(attacker_style && attacker_style.disarm_act(user,target)) return TRUE diff --git a/code/modules/mob/living/living_active_parry.dm b/code/modules/mob/living/living_active_parry.dm index 10f8aaf2f4..513fe43747 100644 --- a/code/modules/mob/living/living_active_parry.dm +++ b/code/modules/mob/living/living_active_parry.dm @@ -281,7 +281,7 @@ pacifist_counter_check = (!active_parry_item.force || active_parry_item.damtype == STAMINA) else pacifist_counter_check = FALSE //Both martial and unarmed counter attacks generally are harmful, so no need to have the same line twice. - if(efficiency >= data.parry_efficiency_to_counterattack && pacifist_counter_check) + if(efficiency >= data.parry_efficiency_to_counterattack && pacifist_counter_check && !return_list[BLOCK_RETURN_FORCE_NO_PARRY_COUNTERATTACK]) effect_text = run_parry_countereffects(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency) if(data.parry_flags & PARRY_DEFAULT_HANDLE_FEEDBACK) handle_parry_feedback(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency, effect_text) diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm index 9e974177e5..d1ccf7f0c4 100644 --- a/code/modules/mob/living/living_blocking_parrying.dm +++ b/code/modules/mob/living/living_blocking_parrying.dm @@ -139,7 +139,7 @@ GLOBAL_LIST_EMPTY(block_parry_data) /// Efficiency must be at least this to be considered successful var/parry_efficiency_considered_successful = 0.1 /// Efficiency must be at least this to run automatic counterattack - var/parry_efficiency_to_counterattack = 0.1 + var/parry_efficiency_to_counterattack = INFINITY /// Maximum attacks to parry successfully or unsuccessfully (but not efficiency < 0) during active period, hitting this immediately ends the sequence. var/parry_max_attacks = INFINITY /// Visual icon state override for parrying diff --git a/code/modules/smithing/finished_items.dm b/code/modules/smithing/finished_items.dm index 20eaee8a08..06953f462c 100644 --- a/code/modules/smithing/finished_items.dm +++ b/code/modules/smithing/finished_items.dm @@ -209,7 +209,7 @@ parry_time_perfect = 2 parry_time_perfect_leeway = 0.75 parry_imperfect_falloff_percent = 7.5 - parry_efficiency_to_counterattack = 100 + parry_efficiency_to_counterattack = INFINITY parry_efficiency_considered_successful = 80 parry_efficiency_perfect = 120 parry_failed_stagger_duration = 3 SECONDS @@ -270,7 +270,7 @@ parry_time_windup = 0 parry_time_spindown = 0 parry_imperfect_falloff_percent = 0 - parry_efficiency_to_counterattack = 100 + parry_efficiency_to_counterattack = INFINITY parry_efficiency_considered_successful = 120 parry_efficiency_perfect = 120 parry_data = list(PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN = 4) From 8e249eed4f73f96ade820a6c2094b0a9fddbebf3 Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Sun, 28 Feb 2021 00:33:10 -0700 Subject: [PATCH 04/43] changes --- code/game/objects/items/stunbaton.dm | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/code/game/objects/items/stunbaton.dm b/code/game/objects/items/stunbaton.dm index cc01e6aaee..11c8716bc2 100644 --- a/code/game/objects/items/stunbaton.dm +++ b/code/game/objects/items/stunbaton.dm @@ -19,6 +19,8 @@ var/stamforce = 35 var/turned_on = FALSE var/knockdown = TRUE + /// block percent needed to prevent knockdown/disarm + var/block_percent_to_counter = 60 var/obj/item/stock_parts/cell/cell var/hitcost = 750 var/throw_hit_chance = 35 @@ -180,6 +182,7 @@ playsound(L, 'sound/weapons/genhit.ogg', 50, 1) return FALSE var/stunpwr = stamforce + var/countered = return_list[BLOCK_RETURN_MITIGATION_PERCENT] > block_percent_to_counter stunpwr = block_calculate_resultant_damage(stunpwr, return_list) var/obj/item/stock_parts/cell/our_cell = get_cell() if(!our_cell) @@ -200,10 +203,10 @@ return FALSE if(!disarming) - if(knockdown) + if(knockdown && !countered) L.DefaultCombatKnockdown(50, override_stamdmg = 0) //knockdown L.adjustStaminaLoss(stunpwr) - else + else if(!countered) L.drop_all_held_items() //no knockdown/stamina damage, instead disarm. L.apply_effect(EFFECT_STUTTER, stamforce) @@ -211,9 +214,13 @@ if(user) L.lastattacker = user.real_name L.lastattackerckey = user.ckey - L.visible_message("[user] has [disarming? "disarmed" : "stunned"] [L] with [src]!", \ + if(!countered) + L.visible_message("[user] has [disarming? "disarmed" : "stunned"] [L] with [src]!", \ "[user] has [disarming? "disarmed" : "stunned"] you with [src]!") - log_combat(user, L, disarming? "disarmed" : "stunned") + else + L.visible_message("[user] tries to [disarming? "disarm" : "stun"] [L] with [src], but is deflected!", \ + "[user] tries to [disarming? "disarm" : "stun"] you with [src], but is deflected!") + log_combat(user, L, disarming? "disarmed" : "stunned" + countered? " (countered)" : "") playsound(loc, 'sound/weapons/egloves.ogg', 50, 1, -1) @@ -306,7 +313,8 @@ w_class = WEIGHT_CLASS_BULKY force = 3 throwforce = 5 - stamforce = 25 + stamforce = 35 + block_percent_to_counter = 45 hitcost = 1000 throw_hit_chance = 10 slot_flags = ITEM_SLOT_BACK From e43838739de292f12c48d2d6e095955e2f218b9b Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Sun, 28 Feb 2021 00:37:39 -0700 Subject: [PATCH 05/43] changes --- code/game/objects/items/melee/misc.dm | 8 ++++++-- code/game/objects/items/stunbaton.dm | 6 +++--- code/modules/mob/living/status_procs.dm | 6 ++++-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm index d2dea3c502..a6e85fadb8 100644 --- a/code/game/objects/items/melee/misc.dm +++ b/code/game/objects/items/melee/misc.dm @@ -260,6 +260,8 @@ var/stam_dmg = 30 var/cooldown_check = 0 // Used internally, you don't want to modify var/cooldown = 13 // Default wait time until can stun again. + /// block mitigation needed to prevent knockdown/disarms + var/block_percent_to_counter = 50 var/stun_time_silicon = 60 // How long it stuns silicons for - 6 seconds. var/affect_silicon = FALSE // Does it stun silicons. var/on_sound // "On" sound, played when switching between able to stun or not. @@ -354,7 +356,8 @@ 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) + var/list/block_return = list() + if(target.mob_run_block(src, 0, "[user]'s [name]", ATTACK_TYPE_MELEE, 0, user, null, block_return) & BLOCK_SUCCESS) playsound(target, 'sound/weapons/genhit.ogg', 50, 1) return if(ishuman(target)) @@ -365,7 +368,8 @@ if(stun_animation) user.do_attack_animation(target) playsound(get_turf(src), on_stun_sound, 75, 1, -1) - target.DefaultCombatKnockdown(softstun_ds, TRUE, FALSE, hardstun_ds, stam_dmg) + var/countered = block_return[BLOCK_RETURN_MITIGATION_PERCENT] > block_percent_to_counter + target.DefaultCombatKnockdown(softstun_ds, TRUE, FALSE, countered? 0 : hardstun_ds, stam_dmg, !countered) additional_effects_carbon(target, user) log_combat(user, target, "stunned", src) add_fingerprint(user) diff --git a/code/game/objects/items/stunbaton.dm b/code/game/objects/items/stunbaton.dm index 11c8716bc2..862b2c8c3e 100644 --- a/code/game/objects/items/stunbaton.dm +++ b/code/game/objects/items/stunbaton.dm @@ -20,7 +20,7 @@ var/turned_on = FALSE var/knockdown = TRUE /// block percent needed to prevent knockdown/disarm - var/block_percent_to_counter = 60 + var/block_percent_to_counter = 50 var/obj/item/stock_parts/cell/cell var/hitcost = 750 var/throw_hit_chance = 35 @@ -204,7 +204,7 @@ if(!disarming) if(knockdown && !countered) - L.DefaultCombatKnockdown(50, override_stamdmg = 0) //knockdown + L.DefaultCombatKnockdown(50, override_stamdmg = 0, knocktofloor = !countered) //knockdown L.adjustStaminaLoss(stunpwr) else if(!countered) L.drop_all_held_items() //no knockdown/stamina damage, instead disarm. @@ -314,7 +314,7 @@ force = 3 throwforce = 5 stamforce = 35 - block_percent_to_counter = 45 + block_percent_to_counter = 30 hitcost = 1000 throw_hit_chance = 10 slot_flags = ITEM_SLOT_BACK diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm index 87fd0cf609..389f5ee5b5 100644 --- a/code/modules/mob/living/status_procs.dm +++ b/code/modules/mob/living/status_procs.dm @@ -4,7 +4,8 @@ // ignore_castun = same logic as Paralyze() in general // override_duration = If this is set, does Paralyze() for this duration. // override_stam = If this is set, does this amount of stamina damage. -/mob/living/proc/DefaultCombatKnockdown(amount, updating = TRUE, ignore_canknockdown = FALSE, override_hardstun, override_stamdmg) +// knocktofloor - whether to knock them to the ground +/mob/living/proc/DefaultCombatKnockdown(amount, updating = TRUE, ignore_canknockdown = FALSE, override_hardstun, override_stamdmg, knocktofloor = TRUE) if(!iscarbon(src)) return Paralyze(amount, updating, ignore_canknockdown) if(!ignore_canknockdown && !(status_flags & CANKNOCKDOWN)) @@ -13,7 +14,8 @@ buckled.unbuckle_mob(src) var/drop_items = amount > 80 //80 is cutoff for old item dropping behavior var/stamdmg = isnull(override_stamdmg)? (amount * 0.25) : override_stamdmg - KnockToFloor(drop_items, TRUE, updating) + if(knocktofloor) + KnockToFloor(drop_items, TRUE, updating) adjustStaminaLoss(stamdmg) if(!isnull(override_hardstun)) Paralyze(override_hardstun) From 8fc1dc9c2994b48ec77aa8ac21c4449f8b0e8fc9 Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Sun, 28 Feb 2021 00:40:04 -0700 Subject: [PATCH 06/43] changes --- code/game/objects/effects/decals/misc.dm | 1 + code/modules/mob/living/say.dm | 2 +- code/modules/movespeed/modifiers/status_effects.dm | 2 +- code/modules/projectiles/guns/energy/energy_gun.dm | 2 ++ code/modules/reagents/reagent_containers/spray.dm | 1 + 5 files changed, 6 insertions(+), 2 deletions(-) diff --git a/code/game/objects/effects/decals/misc.dm b/code/game/objects/effects/decals/misc.dm index 514fcdd68a..53ad432121 100644 --- a/code/game/objects/effects/decals/misc.dm +++ b/code/game/objects/effects/decals/misc.dm @@ -59,6 +59,7 @@ hit_thing(AM) /obj/effect/decal/chempuff/proc/run(atom/target) + set waitfor = FALSE for(var/i in 1 to range) range_left-- if(!isturf(loc)) diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index d72b8c904a..148c66043f 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -308,7 +308,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list( I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA INVOKE_ASYNC(GLOBAL_PROC, /.proc/flick_overlay, I, speech_bubble_recipients, 30) -/atom/movable/proc/process_yelling(list/already_heard, rendered, atom/movable/speaker, datum/language/message_language, list/spans, message_mode, obj/source) +/atom/movable/proc/process_yelling(list/already_heard, rendered, atom/movable/speaker, datum/language/message_language, message, list/spans, message_mode, obj/source) var/list/overhearing = list() #warn todo: yelling overhearing -= already_heard diff --git a/code/modules/movespeed/modifiers/status_effects.dm b/code/modules/movespeed/modifiers/status_effects.dm index d174524898..ed8eaf1303 100644 --- a/code/modules/movespeed/modifiers/status_effects.dm +++ b/code/modules/movespeed/modifiers/status_effects.dm @@ -43,7 +43,7 @@ multiplicative_slowdown = -2 blacklisted_movetypes= FLYING|FLOATING -/datum/movespeed_modifier/status_effect/staggered +/datum/movespeed_modifier/status_effect/stagger variable = TRUE /datum/movespeed_modifier/status_effect/off_balance diff --git a/code/modules/projectiles/guns/energy/energy_gun.dm b/code/modules/projectiles/guns/energy/energy_gun.dm index ae78423813..294040b040 100644 --- a/code/modules/projectiles/guns/energy/energy_gun.dm +++ b/code/modules/projectiles/guns/energy/energy_gun.dm @@ -54,6 +54,8 @@ ammo_type = list(/obj/item/ammo_casing/energy/disabler, /obj/item/ammo_casing/energy/laser/hos, /obj/item/ammo_casing/energy/ion/hos, /obj/item/ammo_casing/energy/electrode/hos) ammo_x_offset = 4 resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF + var/last_altfire = 0 + var/altfire_delay = 0 /obj/item/gun/energy/e_gun/hos/altafterattack(atom/target, mob/user, proximity_flag, params) . = TRUE diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index 6f4b0b37e8..3f62829b32 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -75,6 +75,7 @@ var/range = clamp(get_dist(src, A), 1, current_range) var/wait_step = CEILING(spray_delay * INVERSE(range), world.tick_lag) var/obj/effect/decal/chempuff/D = new /obj/effect/decal/chempuff(get_turf(src), stream_mode, wait_step, range, stream_mode? 1 : range) + var/turf/T = get_turf(src) log_reagent("SPRAY: [key_name(usr)] fired [src] ([REF(src)]) [COORD(T)] at [A] ([REF(A)]) [COORD(A)] (chempuff: [D.reagents.log_list()])") D.create_reagents(amount_per_transfer_from_this, NONE, NO_REAGENTS_VALUE) if(stream_mode) From 519c6942528dad73d1f5ec1d5fc59e6b7260c5dd Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Sun, 28 Feb 2021 00:44:56 -0700 Subject: [PATCH 07/43] removes combat mode effects --- .../configuration/entries/stamina_combat.dm | 6 +----- code/datums/components/combat_mode.dm | 5 ----- code/datums/martial/_martial.dm | 4 ---- code/game/objects/items/shields.dm | 2 -- code/modules/mob/living/carbon/carbon.dm | 4 ---- code/modules/mob/living/carbon/human/species.dm | 11 ----------- code/modules/mob/living/carbon/life.dm | 3 +-- code/modules/mob/living/living_active_block.dm | 7 ------- code/modules/mob/living/living_active_parry.dm | 5 ----- code/modules/mob/living/stamina_buffer.dm | 3 +-- 10 files changed, 3 insertions(+), 47 deletions(-) diff --git a/code/controllers/configuration/entries/stamina_combat.dm b/code/controllers/configuration/entries/stamina_combat.dm index 65580899f1..5c2c9d7ec5 100644 --- a/code/controllers/configuration/entries/stamina_combat.dm +++ b/code/controllers/configuration/entries/stamina_combat.dm @@ -12,11 +12,7 @@ /// 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 + config_entry_value = 3.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 diff --git a/code/datums/components/combat_mode.dm b/code/datums/components/combat_mode.dm index 29d90fd509..576d012093 100644 --- a/code/datums/components/combat_mode.dm +++ b/code/datums/components/combat_mode.dm @@ -128,11 +128,6 @@ if((mode_flags & COMBAT_MODE_ACTIVE) && L.client) L.setDir(lastmousedir, ismousemovement = TRUE) -/// Added movement delay if moving backward. -/datum/component/combat_mode/proc/on_client_move(mob/source, client/client, direction, n, oldloc, added_delay) - if(oldloc != n && direction == REVERSE_DIR(source.dir)) - client.move_delay += added_delay*0.5 - ///Changes the user direction to (try) match the pointer. /datum/component/combat_mode/proc/onMouseMove(mob/source, object, location, control, params) if(source.client.show_popup_menus) diff --git a/code/datums/martial/_martial.dm b/code/datums/martial/_martial.dm index bc48e82395..19cfc7691d 100644 --- a/code/datums/martial/_martial.dm +++ b/code/datums/martial/_martial.dm @@ -43,12 +43,8 @@ /datum/martial_art/proc/damage_roll(mob/living/carbon/human/A, mob/living/carbon/human/D) //Here we roll for our damage to be added into the damage var in the various attack procs. This is changed depending on whether we are in combat mode, lying down, or if our target is in combat mode. var/damage = rand(A.dna.species.punchdamagelow, A.dna.species.punchdamagehigh) - if(SEND_SIGNAL(D, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE)) - damage *= 1.2 if(!CHECK_MOBILITY(A, MOBILITY_STAND)) damage *= 0.7 - if(SEND_SIGNAL(A, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE)) - damage *= 0.8 return damage /datum/martial_art/proc/teach(mob/living/carbon/human/H, make_temporary = FALSE) diff --git a/code/game/objects/items/shields.dm b/code/game/objects/items/shields.dm index 5c3e4fd612..9841a29ae0 100644 --- a/code/game/objects/items/shields.dm +++ b/code/game/objects/items/shields.dm @@ -120,8 +120,6 @@ return TRUE /obj/item/shield/proc/user_shieldbash(mob/living/user, atom/target, harmful) - if(!SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE)) //Combat mode has to be enabled for shield bashing - return FALSE if(!(shield_flags & SHIELD_CAN_BASH)) to_chat(user, "[src] can't be used to shield bash!") return FALSE diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index c7a2d611d6..4462780996 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -475,10 +475,6 @@ if(HAS_TRAIT(src, TRAIT_CLUMSY)) modifier -= 40 //Clumsy people are more likely to hit themselves -Honk! - //CIT CHANGES START HERE - else if(SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE)) - modifier -= 50 - if(modifier < 100) dropItemToGround(I) //END OF CIT CHANGES diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 7851631b33..07f35f9ce0 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1429,12 +1429,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) var/punchedbrute = target.getBruteLoss() //CITADEL CHANGES - makes resting and disabled combat mode reduce punch damage, makes being out of combat mode result in you taking more damage - if(!SEND_SIGNAL(target, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE)) - damage *= 1.2 if(!CHECK_MOBILITY(user, MOBILITY_STAND)) damage *= 0.65 - if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE)) - damage *= 0.8 //END OF CITADEL CHANGES var/obj/item/bodypart/affecting = target.get_bodypart(ran_zone(user.zone_selected)) @@ -1578,12 +1574,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) log_combat(user, target, "disarmed out of grab from") return var/randn = rand(1, 100) - if(SEND_SIGNAL(target, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE)) // CITADEL CHANGE - randn += -10 //CITADEL CHANGE - being out of combat mode makes it easier for you to get disarmed if(!CHECK_MOBILITY(user, MOBILITY_STAND)) //CITADEL CHANGE randn += 100 //CITADEL CHANGE - No kosher disarming if you're resting - if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE)) //CITADEL CHANGE - randn += 25 //CITADEL CHANGE - Makes it harder to disarm outside of combat mode if(user.pulling == target) randn -= 20 //If you have the time to get someone in a grab, you should have a greater chance at snatching the thing in their hand. Will be made completely obsolete by the grab rework but i've got a poor track record for releasing big projects on time so w/e i guess if(HAS_TRAIT(user, TRAIT_PUGILIST)) @@ -1788,9 +1780,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(IS_STAMCRIT(user)) to_chat(user, "You're too exhausted for that.") return - if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE)) - to_chat(user, "You need combat mode to be active to that!") - return if(user.IsKnockdown() || user.IsParalyzed() || user.IsStun()) to_chat(user, "You can't seem to force yourself up right now!") return diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 9885efd7c7..07204bdebe 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -510,9 +510,8 @@ 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() ..() - 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)) + adjustStaminaLoss((!CHECK_MOBILITY(src, MOBILITY_STAND) ? ((combat_flags & COMBAT_FLAG_HARD_STAMCRIT) ? STAM_RECOVERY_STAM_CRIT : STAM_RECOVERY_RESTING) : STAM_RECOVERY_NORMAL)) if(!(combat_flags & COMBAT_FLAG_HARD_STAMCRIT) && incomingstammult != 1) incomingstammult = max(0.01, incomingstammult) diff --git a/code/modules/mob/living/living_active_block.dm b/code/modules/mob/living/living_active_block.dm index db472df388..ad42a3e477 100644 --- a/code/modules/mob/living/living_active_block.dm +++ b/code/modules/mob/living/living_active_block.dm @@ -48,8 +48,6 @@ animate(src, pixel_x = get_standard_pixel_x_offset(), pixel_y = get_standard_pixel_y_offset(), time = 2.5, FALSE, SINE_EASING | EASE_IN) /mob/living/proc/continue_starting_active_block() - if(SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE)) - return DO_AFTER_STOP return (combat_flags & COMBAT_FLAG_ACTIVE_BLOCK_STARTING)? DO_AFTER_CONTINUE : DO_AFTER_STOP /mob/living/get_standard_pixel_x_offset() @@ -100,11 +98,6 @@ if(!I.can_active_block()) to_chat(src, "[I] is either not capable of being used to actively block, or is not currently in a state that can! (Try wielding it if it's twohanded, for example.)") return - // QOL: Attempt to toggle on combat mode if it isn't already - SEND_SIGNAL(src, COMSIG_ENABLE_COMBAT_MODE) - if(SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE)) - to_chat(src, "You must be in combat mode to actively block!") - return FALSE var/datum/block_parry_data/data = I.get_block_parry_data() var/delay = data.block_start_delay combat_flags |= COMBAT_FLAG_ACTIVE_BLOCK_STARTING diff --git a/code/modules/mob/living/living_active_parry.dm b/code/modules/mob/living/living_active_parry.dm index 513fe43747..571813f30e 100644 --- a/code/modules/mob/living/living_active_parry.dm +++ b/code/modules/mob/living/living_active_parry.dm @@ -74,11 +74,6 @@ if(!method) to_chat(src, "You have nothing to parry with!") return FALSE - //QOL: Try to enable combat mode if it isn't already - SEND_SIGNAL(src, COMSIG_ENABLE_COMBAT_MODE) - if(SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE)) - to_chat(src, "You must be in combat mode to parry!") - return FALSE data = return_block_parry_datum(data) var/full_parry_duration = data.parry_time_windup + data.parry_time_active + data.parry_time_spindown // no system in place to "fallback" if out of the 3 the top priority one can't parry due to constraints but something else can. diff --git a/code/modules/mob/living/stamina_buffer.dm b/code/modules/mob/living/stamina_buffer.dm index a410df582b..91811e048a 100644 --- a/code/modules/mob/living/stamina_buffer.dm +++ b/code/modules/mob/living/stamina_buffer.dm @@ -35,11 +35,10 @@ 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/base_regen = base_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)) From 5d37871cd211e8ce4a5dbbc29229d72ca4ff1380 Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Sun, 28 Feb 2021 00:47:24 -0700 Subject: [PATCH 08/43] changes --- code/modules/mob/living/living_active_block.dm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/modules/mob/living/living_active_block.dm b/code/modules/mob/living/living_active_block.dm index ad42a3e477..5c184313ee 100644 --- a/code/modules/mob/living/living_active_block.dm +++ b/code/modules/mob/living/living_active_block.dm @@ -54,17 +54,17 @@ . = ..() if(combat_flags & (COMBAT_FLAG_ACTIVE_BLOCK_STARTING | COMBAT_FLAG_ACTIVE_BLOCKING)) if(dir & EAST) - . += 8 + . += 4 if(dir & WEST) - . -= 8 + . -= 4 /mob/living/get_standard_pixel_y_offset() . = ..() if(combat_flags & (COMBAT_FLAG_ACTIVE_BLOCK_STARTING | COMBAT_FLAG_ACTIVE_BLOCKING)) if(dir & NORTH) - . += 8 + . += 4 if(dir & SOUTH) - . -= 8 + . -= 4 /** * Proc called by keybindings to toggle active blocking. From 0f35f01a9bdbfae8cf34bc28a4de837d586773c4 Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Sun, 28 Feb 2021 00:58:13 -0700 Subject: [PATCH 09/43] changes --- code/modules/surgery/bodyparts/_bodyparts.dm | 15 ++++++++++++--- code/modules/surgery/bodyparts/parts.dm | 20 ++++++++++++-------- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 962bc8c1ce..d6379e1166 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -32,6 +32,8 @@ var/max_stamina_damage = 0 var/incoming_stam_mult = 1 //Multiplier for incoming staminaloss, decreases when taking staminaloss when the limb is disabled, resets back to 1 when limb is no longer disabled. var/max_damage = 0 + /// Threshold at which we are disabled. Defaults to max_damage if unset. + var/disable_threshold var/stam_heal_tick = 0 //per Life(). Defaults to 0 due to citadel changes var/brute_reduction = 0 //Subtracted to brute damage taken @@ -494,6 +496,12 @@ return set_disabled(is_disabled(silent), silent) +/** + * Gets the damage at which point we're disabled. + */ +/obj/item/bodypart/proc/get_disable_threshold() + return isnull(disable_threshold)? max_damage : disable_threshold + /obj/item/bodypart/proc/is_disabled(silent = FALSE) if(!owner) return @@ -503,15 +511,16 @@ var/datum/wound/W = i if(W.disabling) return BODYPART_DISABLED_WOUND + var/disable_threshold = get_disable_threshold() if(can_dismember() && !HAS_TRAIT(owner, TRAIT_NODISMEMBER)) . = disabled //inertia, to avoid limbs healing 0.1 damage and being re-enabled - if(get_damage(TRUE) >= max_damage * (HAS_TRAIT(owner, TRAIT_EASYLIMBDISABLE) ? 0.6 : 1)) //Easy limb disable disables the limb at 40% health instead of 0% + if(get_damage(TRUE) >= disable_threshold * (HAS_TRAIT(owner, TRAIT_EASYLIMBDISABLE) ? 0.6 : 1)) //Easy limb disable disables the limb at 40% health instead of 0% if(!last_maxed && !silent) owner.emote("scream") last_maxed = TRUE - if(!is_organic_limb(FALSE) || stamina_dam >= max_damage) + if(!is_organic_limb(FALSE) || stamina_dam >= disable_threshold) return BODYPART_DISABLED_DAMAGE - else if(disabled && (get_damage(TRUE) <= (max_damage * 0.8))) // reenabled at 80% now instead of 50% as of wounds update + else if(disabled && (get_damage(TRUE) <= (disable_threshold * 0.8))) // reenabled at 80% now instead of 50% as of wounds update last_maxed = FALSE return BODYPART_NOT_DISABLED else diff --git a/code/modules/surgery/bodyparts/parts.dm b/code/modules/surgery/bodyparts/parts.dm index 86288564ae..8c7553d8e3 100644 --- a/code/modules/surgery/bodyparts/parts.dm +++ b/code/modules/surgery/bodyparts/parts.dm @@ -59,12 +59,13 @@ one though." icon_state = "default_human_l_arm" attack_verb = list("slapped", "punched") - max_damage = 50 + max_damage = 150 + disable_threshold = 75 max_stamina_damage = 50 body_zone = BODY_ZONE_L_ARM body_part = ARM_LEFT aux_icons = list(BODY_ZONE_PRECISE_L_HAND = HANDS_PART_LAYER, "l_hand_behind" = BODY_BEHIND_LAYER) - body_damage_coeff = 0.75 + body_damage_coeff = 0.25 held_index = 1 px_x = -6 px_y = 0 @@ -120,11 +121,12 @@ among humans missing their right arm." icon_state = "default_human_r_arm" attack_verb = list("slapped", "punched") - max_damage = 50 + max_damage = 150 + disable_threshold = 75 body_zone = BODY_ZONE_R_ARM body_part = ARM_RIGHT aux_icons = list(BODY_ZONE_PRECISE_R_HAND = HANDS_PART_LAYER, "r_hand_behind" = BODY_BEHIND_LAYER) - body_damage_coeff = 0.75 + body_damage_coeff = 0.25 held_index = 2 px_x = 6 px_y = 0 @@ -182,10 +184,11 @@ luck. In this instance, it probably would not have helped." icon_state = "default_human_l_leg" attack_verb = list("kicked", "stomped") - max_damage = 50 + max_damage = 150 + disable_threshold = 75 body_zone = BODY_ZONE_L_LEG body_part = LEG_LEFT - body_damage_coeff = 0.75 + body_damage_coeff = 0.25 px_x = -2 px_y = 12 stam_heal_tick = STAM_RECOVERY_LIMB @@ -240,10 +243,11 @@ // alternative spellings of 'pokey' are availible icon_state = "default_human_r_leg" attack_verb = list("kicked", "stomped") - max_damage = 50 + max_damage = 150 + disable_threshold = 75 body_zone = BODY_ZONE_R_LEG body_part = LEG_RIGHT - body_damage_coeff = 0.75 + body_damage_coeff = 0.25 px_x = 2 px_y = 12 max_stamina_damage = 50 From e7981c0a44b51a4b2fb271b1a5e4cf7bcfc50530 Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Sun, 28 Feb 2021 01:02:18 -0700 Subject: [PATCH 10/43] changes --- code/datums/wounds/pierce.dm | 10 +++++----- code/datums/wounds/slash.dm | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/code/datums/wounds/pierce.dm b/code/datums/wounds/pierce.dm index 56c60b31d7..b26728c377 100644 --- a/code/datums/wounds/pierce.dm +++ b/code/datums/wounds/pierce.dm @@ -128,7 +128,7 @@ initial_flow = 1.5 gauzed_clot_rate = 0.8 internal_bleeding_chance = 30 - internal_bleeding_coefficient = 1.25 + internal_bleeding_coefficient = 1 threshold_minimum = 40 threshold_penalty = 15 status_effect_type = /datum/status_effect/wound/pierce/moderate @@ -142,10 +142,10 @@ occur_text = "looses a violent spray of blood, revealing a pierced wound" sound_effect = 'sound/effects/wounds/pierce2.ogg' severity = WOUND_SEVERITY_SEVERE - initial_flow = 2.25 + initial_flow = 2 gauzed_clot_rate = 0.6 internal_bleeding_chance = 60 - internal_bleeding_coefficient = 1.5 + internal_bleeding_coefficient = 1.25 threshold_minimum = 60 threshold_penalty = 25 status_effect_type = /datum/status_effect/wound/pierce/severe @@ -159,10 +159,10 @@ occur_text = "blasts apart, sending chunks of viscera flying in all directions" sound_effect = 'sound/effects/wounds/pierce3.ogg' severity = WOUND_SEVERITY_CRITICAL - initial_flow = 3 + initial_flow = 2.7 gauzed_clot_rate = 0.4 internal_bleeding_chance = 80 - internal_bleeding_coefficient = 1.75 + internal_bleeding_coefficient = 1.5 threshold_minimum = 110 threshold_penalty = 40 status_effect_type = /datum/status_effect/wound/pierce/critical diff --git a/code/datums/wounds/slash.dm b/code/datums/wounds/slash.dm index 9044835272..6a631ab8f4 100644 --- a/code/datums/wounds/slash.dm +++ b/code/datums/wounds/slash.dm @@ -253,7 +253,7 @@ occur_text = "is cut open, slowly leaking blood" sound_effect = 'sound/effects/wounds/blood1.ogg' severity = WOUND_SEVERITY_MODERATE - initial_flow = 1.5 + initial_flow = 1.25 minimum_flow = 0.375 max_per_type = 3 clot_rate = 0.12 @@ -270,8 +270,8 @@ occur_text = "is ripped open, veins spurting blood" sound_effect = 'sound/effects/wounds/blood2.ogg' severity = WOUND_SEVERITY_SEVERE - initial_flow = 2.4375 - minimum_flow = 2.0625 + initial_flow = 2 + minimum_flow = 1.75 clot_rate = 0.07 max_per_type = 4 threshold_minimum = 60 @@ -288,8 +288,8 @@ occur_text = "is torn open, spraying blood wildly" sound_effect = 'sound/effects/wounds/blood3.ogg' severity = WOUND_SEVERITY_CRITICAL - initial_flow = 3.1875 - minimum_flow = 3 + initial_flow = 2.75 + minimum_flow = 2.5 clot_rate = -0.05 // critical cuts actively get worse instead of better max_per_type = 5 threshold_minimum = 90 From 0f161784252cd6ee53ffc280002138f81427dbf7 Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Sun, 28 Feb 2021 02:43:32 -0700 Subject: [PATCH 11/43] changes --- code/__HELPERS/do_after.dm | 2 +- code/game/objects/effects/decals/misc.dm | 2 +- code/modules/mob/living/carbon/alien/status_procs.dm | 2 +- code/modules/mob/living/carbon/human/status_procs.dm | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/code/__HELPERS/do_after.dm b/code/__HELPERS/do_after.dm index 550eea65c0..c0c07e3620 100644 --- a/code/__HELPERS/do_after.dm +++ b/code/__HELPERS/do_after.dm @@ -51,6 +51,7 @@ var/dy = initial_dy // DO OUR STARTING CHECKS var/cb_return + var/list/passed_in = list(1) INVOKE_CALLBACK if(cb_return == DO_AFTER_STOP) return FALSE @@ -71,7 +72,6 @@ var/ctu var/ctt var/tick_time = world.time - var/list/passed_in = list(1) while(timeleft > 0) stoplag(1) var/timepassed = world.time - tick_time diff --git a/code/game/objects/effects/decals/misc.dm b/code/game/objects/effects/decals/misc.dm index 53ad432121..7ed90253c8 100644 --- a/code/game/objects/effects/decals/misc.dm +++ b/code/game/objects/effects/decals/misc.dm @@ -32,7 +32,7 @@ . = ..() stream = stream_mode src.speed = speed - src.range = scc.range_left = range + src.range = src.range_left = range src.hits_left = hits_left /obj/effect/decal/chempuff/proc/hit_thing(atom/A) diff --git a/code/modules/mob/living/carbon/alien/status_procs.dm b/code/modules/mob/living/carbon/alien/status_procs.dm index 71d61cab25..e20b20ef3d 100644 --- a/code/modules/mob/living/carbon/alien/status_procs.dm +++ b/code/modules/mob/living/carbon/alien/status_procs.dm @@ -2,7 +2,7 @@ //The effects include: stun, knockdown, unconscious, sleeping, resting, jitteriness, dizziness, ear damage, // eye damage, eye_blind, eye_blurry, druggy, TRAIT_BLIND trait, and TRAIT_NEARSIGHT trait. -/mob/living/carbon/alien/DefaultCombatKnockdown(amount, updating = TRUE, ignore_canknockdown = FALSE, override_hardstun, override_stamdmg) +/mob/living/carbon/alien/DefaultCombatKnockdown(amount, updating = TRUE, ignore_canknockdown = FALSE, override_hardstun, override_stamdmg, knocktofloor) return //no /////////////////////////////////// STUN //////////////////////////////////// diff --git a/code/modules/mob/living/carbon/human/status_procs.dm b/code/modules/mob/living/carbon/human/status_procs.dm index 7892380d8b..ec961da4dd 100644 --- a/code/modules/mob/living/carbon/human/status_procs.dm +++ b/code/modules/mob/living/carbon/human/status_procs.dm @@ -3,7 +3,7 @@ amount = dna.species.spec_stun(src,amount) return ..() -/mob/living/carbon/human/DefaultCombatKnockdown(amount, updating = TRUE, ignore_canknockdown = FALSE, override_hardstun, override_stamdmg) +/mob/living/carbon/human/DefaultCombatKnockdown(amount, updating = TRUE, ignore_canknockdown = FALSE, override_hardstun, override_stamdmg, knocktofloor) amount = dna.species.spec_stun(src,amount) return ..() From c6ba7bfe1f2f15ce77d88931f8d7c44b5e8ab5c4 Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Sat, 6 Mar 2021 18:06:53 -0700 Subject: [PATCH 12/43] changes --- code/__DEFINES/sound.dm | 6 +++- code/__DEFINES/status_effects.dm | 2 +- code/datums/status_effects/debuffs.dm | 8 ++--- code/datums/status_effects/status_effect.dm | 8 ----- code/game/sound.dm | 10 +++--- .../mob/living/carbon/human/human_defense.dm | 2 +- .../carbon/human/innate_abilities/blobform.dm | 2 -- .../modules/mob/living/living_active_parry.dm | 5 ++- code/modules/mob/living/living_block.dm | 2 ++ .../mob/living/living_blocking_parrying.dm | 35 +++++++++++++++++-- 10 files changed, 55 insertions(+), 25 deletions(-) diff --git a/code/__DEFINES/sound.dm b/code/__DEFINES/sound.dm index 1098a07b39..72543970ba 100644 --- a/code/__DEFINES/sound.dm +++ b/code/__DEFINES/sound.dm @@ -25,7 +25,11 @@ ///Percentage of sound's range where no falloff is applied #define SOUND_DEFAULT_FALLOFF_DISTANCE 1 //For a normal sound this would be 1 tile of no falloff ///The default exponent of sound falloff -#define SOUND_FALLOFF_EXPONENT 6 +#define SOUND_FALLOFF_EXPONENT 7.5 +/// Default distance multiplier for sounds +#define SOUND_DEFAULT_DISTANCE_MULTIPLIER 2.5 +/// Default range at which sound distance multiplier applies +#define SOUND_DEFAULT_MULTIPLIER_EFFECT_RANGE 7 //THIS SHOULD ALWAYS BE THE LOWEST ONE! //KEEP IT UPDATED diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index e2ace84156..db645f2a11 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -105,7 +105,7 @@ #define STATUS_EFFECT_FAKE_VIRUS /datum/status_effect/fake_virus //gives you fluff messages for cough, sneeze, headache, etc but without an actual virus -#define STATUS_EFFECT_NO_COMBAT_MODE /datum/status_effect/no_combat_mode //Wont allow combat mode and will disable it +#define STATUS_EFFECT_NO_COMBAT_MODE /datum/status_effect //Wont allow combat mode and will disable it #define STATUS_EFFECT_MESMERIZE /datum/status_effect/mesmerize //Just reskinned no_combat_mode #define STATUS_EFFECT_ELECTROSTAFF /datum/status_effect/electrostaff //slows down victim diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm index 1909327cc9..9585502264 100644 --- a/code/datums/status_effects/debuffs.dm +++ b/code/datums/status_effects/debuffs.dm @@ -127,18 +127,18 @@ desc = "You've fallen asleep. Wait a bit and you should wake up. Unless you don't, considering how helpless you are." icon_state = "asleep" -/datum/status_effect/no_combat_mode +/datum/status_effect id = "no_combat_mode" alert_type = null status_type = STATUS_EFFECT_REPLACE blocks_combatmode = TRUE -/datum/status_effect/no_combat_mode/on_creation(mob/living/new_owner, set_duration) +/datum/status_effect/on_creation(mob/living/new_owner, set_duration) if(isnum(set_duration)) duration = set_duration . = ..() -/datum/status_effect/no_combat_mode/robotic_emp +/datum/status_effect/robotic_emp id = "emp_no_combat_mode" /datum/status_effect/mesmerize @@ -148,13 +148,11 @@ /datum/status_effect/mesmerize/on_creation(mob/living/new_owner, set_duration) . = ..() ADD_TRAIT(owner, TRAIT_MUTE, "mesmerize") - ADD_TRAIT(owner, TRAIT_COMBAT_MODE_LOCKED, "mesmerize") owner.add_movespeed_modifier(/datum/movespeed_modifier/status_effect/mesmerize) /datum/status_effect/mesmerize/on_remove() . = ..() REMOVE_TRAIT(owner, TRAIT_MUTE, "mesmerize") - REMOVE_TRAIT(owner, TRAIT_COMBAT_MODE_LOCKED, "mesmerize") owner.remove_movespeed_modifier(/datum/movespeed_modifier/status_effect/mesmerize) /datum/status_effect/mesmerize/on_creation(mob/living/new_owner, set_duration) diff --git a/code/datums/status_effects/status_effect.dm b/code/datums/status_effects/status_effect.dm index 9dbbc1c469..b38b755f28 100644 --- a/code/datums/status_effects/status_effect.dm +++ b/code/datums/status_effects/status_effect.dm @@ -11,8 +11,6 @@ var/on_remove_on_mob_delete = FALSE //if we call on_remove() when the mob is deleted var/examine_text //If defined, this text will appear when the mob is examined - to use he, she etc. use "SUBJECTPRONOUN" and replace it in the examines themselves var/alert_type = /obj/screen/alert/status_effect //the alert thrown by the status effect, contains name and description - /// If this is TRUE, the user will have combt mode forcefully disabled while this is active. - var/blocks_combatmode = FALSE /// If this is TRUE, the user will have sprint forcefully disabled while this is active. var/blocks_sprint = FALSE var/obj/screen/alert/status_effect/linked_alert = null //the alert itself, if it exists @@ -61,8 +59,6 @@ /datum/status_effect/proc/on_apply() //Called whenever the buff is applied; returning FALSE will cause it to autoremove itself. SHOULD_CALL_PARENT(TRUE) - if(blocks_combatmode) - ADD_TRAIT(owner, TRAIT_COMBAT_MODE_LOCKED, src) if(blocks_sprint) ADD_TRAIT(owner, TRAIT_SPRINT_LOCKED, src) return TRUE @@ -74,8 +70,6 @@ /datum/status_effect/proc/on_remove() //Called whenever the buff expires or is removed; do note that at the point this is called, it is out of the owner's status_effects but owner is not yet null SHOULD_CALL_PARENT(TRUE) - if(blocks_combatmode) - REMOVE_TRAIT(owner, TRAIT_COMBAT_MODE_LOCKED, src) if(blocks_sprint) REMOVE_TRAIT(owner, TRAIT_SPRINT_LOCKED, src) return TRUE @@ -83,8 +77,6 @@ /datum/status_effect/proc/be_replaced() //Called instead of on_remove when a status effect is replaced by itself or when a status effect with on_remove_on_mob_delete = FALSE has its mob deleted owner.clear_alert(id) LAZYREMOVE(owner.status_effects, src) - if(blocks_combatmode) - REMOVE_TRAIT(owner, TRAIT_COMBAT_MODE_LOCKED, src) if(blocks_sprint) REMOVE_TRAIT(owner, TRAIT_SPRINT_LOCKED, src) owner = null diff --git a/code/game/sound.dm b/code/game/sound.dm index 1816336bd1..b233ebd6d2 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -43,7 +43,8 @@ falloff_distance - Distance at which falloff begins. Sound is at peak volume (in */ -/proc/playsound(atom/source, soundin, vol as num, vary, extrarange as num, falloff_exponent = SOUND_FALLOFF_EXPONENT, frequency = null, channel = 0, pressure_affected = TRUE, ignore_walls = TRUE, falloff_distance = SOUND_DEFAULT_FALLOFF_DISTANCE, envwet = -10000, envdry = 0) +/proc/playsound(atom/source, soundin, vol as num, vary, extrarange as num, falloff_exponent = SOUND_FALLOFF_EXPONENT, frequency = null, channel = 0, pressure_affected = TRUE, ignore_walls = TRUE, + falloff_distance = SOUND_DEFAULT_FALLOFF_DISTANCE, envwet = -10000, envdry = 0, distance_multiplier = SOUND_DEFAULT_DISTANCE_MULTIPLIER, distance_multiplier_min_range = SOUND_DEFAULT_MULTIPLIER_EFFECT_RANGE) if(isarea(source)) CRASH("playsound(): source is an area") @@ -83,11 +84,11 @@ falloff_distance - Distance at which falloff begins. Sound is at peak volume (in for(var/P in listeners) var/mob/M = P if(get_dist(M, turf_source) <= maxdistance) - M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff_exponent, channel, pressure_affected, S, maxdistance, falloff_distance, null, envwet, envdry) + M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff_exponent, channel, pressure_affected, S, maxdistance, falloff_distance, get_dist(M, turf_sounrce) <= distance_multiplier_min_range? 1 : distance_multiplier, envwet, envdry) for(var/P in SSmobs.dead_players_by_zlevel[source_z]) var/mob/M = P if(get_dist(M, turf_source) <= maxdistance) - M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff_exponent, channel, pressure_affected, S, maxdistance, falloff_distance, null, envwet, envdry) + M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff_exponent, channel, pressure_affected, S, maxdistance, falloff_distance, get_dist(M, turf_sounrce) <= distance_multiplier_min_range? 1 : distance_multiplier, envwet, envdry) /*! playsound @@ -108,7 +109,8 @@ distance_multiplier - Can be used to multiply the distance at which the sound is */ -/mob/proc/playsound_local(turf/turf_source, soundin, vol as num, vary, frequency, falloff_exponent = SOUND_FALLOFF_EXPONENT, channel = 0, pressure_affected = TRUE, sound/S, max_distance, falloff_distance = SOUND_DEFAULT_FALLOFF_DISTANCE, distance_multiplier = 1, envwet = -10000, envdry = 0) +/mob/proc/playsound_local(turf/turf_source, soundin, vol as num, vary, frequency, falloff_exponent = SOUND_FALLOFF_EXPONENT, channel = 0, pressure_affected = TRUE, sound/S, max_distance, + falloff_distance = SOUND_DEFAULT_FALLOFF_DISTANCE, distance_multiplier = SOUND_DEFAULT_DISTANCE_MULTIPLIER, envwet = -10000, envdry = 0) if(!client || !can_hear()) return diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index a74afc10f5..1174fcba70 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -409,7 +409,7 @@ return var/informed = FALSE if(isrobotic(src)) - apply_status_effect(/datum/status_effect/no_combat_mode/robotic_emp, severity / 20) + apply_status_effect(/datum/status_effect/robotic_emp, severity / 20) severity *= 0.5 var/do_not_stun = FALSE if(HAS_TRAIT(src, TRAIT_ROBOTIC_ORGANISM)) diff --git a/code/modules/mob/living/carbon/human/innate_abilities/blobform.dm b/code/modules/mob/living/carbon/human/innate_abilities/blobform.dm index ed3c7e21d4..76abdf85fe 100644 --- a/code/modules/mob/living/carbon/human/innate_abilities/blobform.dm +++ b/code/modules/mob/living/carbon/human/innate_abilities/blobform.dm @@ -55,7 +55,6 @@ ADD_TRAIT(H, TRAIT_MOBILITY_NOPICKUP, SLIMEPUDDLE_TRAIT) ADD_TRAIT(H, TRAIT_MOBILITY_NOUSE, SLIMEPUDDLE_TRAIT) ADD_TRAIT(H, TRAIT_SPRINT_LOCKED, SLIMEPUDDLE_TRAIT) - ADD_TRAIT(H, TRAIT_COMBAT_MODE_LOCKED, SLIMEPUDDLE_TRAIT) ADD_TRAIT(H, TRAIT_MOBILITY_NOREST, SLIMEPUDDLE_TRAIT) ADD_TRAIT(H, TRAIT_ARMOR_BROKEN, SLIMEPUDDLE_TRAIT) H.update_disabled_bodyparts(silent = TRUE) //silently update arms to be paralysed @@ -96,7 +95,6 @@ REMOVE_TRAIT(H, TRAIT_MOBILITY_NOPICKUP, SLIMEPUDDLE_TRAIT) REMOVE_TRAIT(H, TRAIT_MOBILITY_NOUSE, SLIMEPUDDLE_TRAIT) REMOVE_TRAIT(H, TRAIT_SPRINT_LOCKED, SLIMEPUDDLE_TRAIT) - REMOVE_TRAIT(H, TRAIT_COMBAT_MODE_LOCKED, SLIMEPUDDLE_TRAIT) REMOVE_TRAIT(H, TRAIT_MOBILITY_NOREST, SLIMEPUDDLE_TRAIT) REMOVE_TRAIT(H, TRAIT_ARMOR_BROKEN, SLIMEPUDDLE_TRAIT) REMOVE_TRAIT(H, TRAIT_HUMAN_NO_RENDER, SLIMEPUDDLE_TRAIT) diff --git a/code/modules/mob/living/living_active_parry.dm b/code/modules/mob/living/living_active_parry.dm index 571813f30e..a000bbab23 100644 --- a/code/modules/mob/living/living_active_parry.dm +++ b/code/modules/mob/living/living_active_parry.dm @@ -230,9 +230,12 @@ return world.time - parry_start_time /// same return values as normal blocking, called with absolute highest priority in the block "chain". -/mob/living/proc/run_parry(atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list = list()) +/mob/living/proc/run_parry(atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list = list(), allow_auto = TRUE) var/stage = get_parry_stage() if(stage != PARRY_ACTIVE) + // If they're not currently parrying, attempt auto parry + if((stage == NOT_PARRYING) && allow_auto) + return attempt_auto_parry() return BLOCK_NONE var/datum/block_parry_data/data = get_parry_data() if(attack_type && (!(attack_type & data.parry_attack_types) || (attack_type & ATTACK_TYPE_PARRY_COUNTERATTACK))) // if this attack is from a parry do not parry it lest we infinite loop. diff --git a/code/modules/mob/living/living_block.dm b/code/modules/mob/living/living_block.dm index d32265e478..10427c20ec 100644 --- a/code/modules/mob/living/living_block.dm +++ b/code/modules/mob/living/living_block.dm @@ -37,6 +37,8 @@ var/results if(I == active_block_item) results = I.active_block(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, return_list, attack_direction) + else if(I.can_passive_block()) + results = I.passive_block(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, return_list, attack_direction) else results = I.run_block(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, return_list) . |= results diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm index d1ccf7f0c4..0a0ef30f33 100644 --- a/code/modules/mob/living/living_blocking_parrying.dm +++ b/code/modules/mob/living/living_blocking_parrying.dm @@ -75,7 +75,7 @@ GLOBAL_LIST_EMPTY(block_parry_data) var/block_stamina_buffer_ratio = 1 /// Stamina dealt directly via UseStaminaBuffer() per SECOND of block. - var/block_stamina_cost_per_second = 1.5 + var/block_stamina_cost_per_second = 1 /// Prevent stamina buffer regeneration while block? var/block_no_stambuffer_regeneration = TRUE /// Prevent stamina regeneration while block? @@ -93,6 +93,13 @@ GLOBAL_LIST_EMPTY(block_parry_data) /// Sounds for blocking var/list/block_sounds = list('sound/block_parry/block_metal1.ogg' = 1, 'sound/block_parry/block_metal1.ogg' = 1) + // Autoblock + // Other than for overrides, this mostly just reads from the above vars + /// Can this item automatically block? + var/block_automatic_enabled = TRUE + /// Directions that you can autoblock in + var/block_automatic_directions = BLOCK_DIR_NORTH | BLOCK_DIR_NORTHEAST | BLOCK_DIR_NORTHWEST + /////////// PARRYING //////////// /// Prioriry for [mob/do_run_block()] while we're being used to parry. // None - Parry is always highest priority! @@ -106,7 +113,7 @@ GLOBAL_LIST_EMPTY(block_parry_data) var/parry_flags = PARRY_DEFAULT_HANDLE_FEEDBACK | PARRY_LOCK_ATTACKING /// Parry windup duration in deciseconds. 0 to this is windup, afterwards is main stage. - var/parry_time_windup = 2 + var/parry_time_windup = 0 /// Parry spindown duration in deciseconds. main stage end to this is the spindown stage, afterwards the parry fully ends. var/parry_time_spindown = 3 /// Main parry window in deciseconds. This is between [parry_time_windup] and [parry_time_spindown] @@ -167,6 +174,30 @@ GLOBAL_LIST_EMPTY(block_parry_data) var/imperfect_parry_block_return_list var/failed_parry_block_return_list + // Auto parry + // Anything not specified like cooldowns/clickdelay respecting is pulled from above. + /// Can this data automatically parry + var/parry_automatic_enabled = TRUE + /// Hard autoparry cooldown + var/autoparry_cooldown_absolute = 3 SECONDS + /// Autoparry : Simulate a parry sequence starting at a certain tick, or simply simulate a single attack parry? + var/autoparry_sequence_simulation = FALSE + // Single attack simulation: + /// Parry cooldown to inflict on single-attack autoparry + var/autoparry_single_parry_cooldown = 3 SECONDS + /// Clickdelay to inflict on single-attack autoparry + var/autoparry_single_click_cooldown = 0 + /// Single attack autoparry - efficiency + var/autoparry_single_efficiency = 60 + /// Single attack autoparry - efficiency overrides by attack type, see above + var/list/autoparry_single_efficiency_override + // Parry sequence simulation: + /// Decisecond of sequence to start on. -1 to start to 0th tick of active parry window. + var/autoparry_sequence_start_time = -1 + /// Efficiency multiplier + var/autoparry_sequence_efficiency_multiplier = 0.8 + // Clickdelay/cooldown settings not included, as well as whether or not to lock attack/sprinting/etc. They will be pulled from the above. + /** * Quirky proc to get average of flags in list that are in attack_type because why is attack_type a flag. */ From cf7d428ac6b8f1324dd0ad3962987cbd38d2488e Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Sat, 6 Mar 2021 18:11:40 -0700 Subject: [PATCH 13/43] changes --- code/modules/mob/living/living_active_parry.dm | 2 +- code/modules/mob/living/living_block.dm | 2 +- code/modules/mob/living/living_blocking_parrying.dm | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/code/modules/mob/living/living_active_parry.dm b/code/modules/mob/living/living_active_parry.dm index a000bbab23..c15b56afe8 100644 --- a/code/modules/mob/living/living_active_parry.dm +++ b/code/modules/mob/living/living_active_parry.dm @@ -234,7 +234,7 @@ var/stage = get_parry_stage() if(stage != PARRY_ACTIVE) // If they're not currently parrying, attempt auto parry - if((stage == NOT_PARRYING) && allow_auto) + if((stage == NOT_PARRYING) && allow_auto && !SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE)) return attempt_auto_parry() return BLOCK_NONE var/datum/block_parry_data/data = get_parry_data() diff --git a/code/modules/mob/living/living_block.dm b/code/modules/mob/living/living_block.dm index 10427c20ec..99e74916da 100644 --- a/code/modules/mob/living/living_block.dm +++ b/code/modules/mob/living/living_block.dm @@ -37,7 +37,7 @@ var/results if(I == active_block_item) results = I.active_block(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, return_list, attack_direction) - else if(I.can_passive_block()) + else if(I.can_passive_block() && !SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE)) results = I.passive_block(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, return_list, attack_direction) else results = I.run_block(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, return_list) diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm index 0a0ef30f33..1fd2ad2615 100644 --- a/code/modules/mob/living/living_blocking_parrying.dm +++ b/code/modules/mob/living/living_blocking_parrying.dm @@ -99,6 +99,10 @@ GLOBAL_LIST_EMPTY(block_parry_data) var/block_automatic_enabled = TRUE /// Directions that you can autoblock in var/block_automatic_directions = BLOCK_DIR_NORTH | BLOCK_DIR_NORTHEAST | BLOCK_DIR_NORTHWEST + /// Effectiveness multiplier for automated block + var/block_automatic_mitigation_multiplier = 0.33 + /// Stamina cost multiplier for automated block + var/block_automatic_stamina_multiplier = 1 /////////// PARRYING //////////// /// Prioriry for [mob/do_run_block()] while we're being used to parry. From 5d1cda26dc60cc1621dd7509e3841f55cb1a7e41 Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Sat, 6 Mar 2021 18:15:37 -0700 Subject: [PATCH 14/43] changes --- code/modules/mob/living/living_blocking_parrying.dm | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm index 1fd2ad2615..1ed490b0d8 100644 --- a/code/modules/mob/living/living_blocking_parrying.dm +++ b/code/modules/mob/living/living_blocking_parrying.dm @@ -97,6 +97,7 @@ GLOBAL_LIST_EMPTY(block_parry_data) // Other than for overrides, this mostly just reads from the above vars /// Can this item automatically block? var/block_automatic_enabled = TRUE +#warn have autoblock items warn user on pickup /// Directions that you can autoblock in var/block_automatic_directions = BLOCK_DIR_NORTH | BLOCK_DIR_NORTHEAST | BLOCK_DIR_NORTHWEST /// Effectiveness multiplier for automated block @@ -180,8 +181,10 @@ GLOBAL_LIST_EMPTY(block_parry_data) // Auto parry // Anything not specified like cooldowns/clickdelay respecting is pulled from above. - /// Can this data automatically parry - var/parry_automatic_enabled = TRUE + /// Can this data automatically parry? This is off by default because this is something that requires thought to balance. + var/parry_automatic_enabled = FALSE +#warn implement autoparry in items +#warn have autoparry items warn user on pickup /// Hard autoparry cooldown var/autoparry_cooldown_absolute = 3 SECONDS /// Autoparry : Simulate a parry sequence starting at a certain tick, or simply simulate a single attack parry? From 15dd80a0851f07ebc50240b9bfcd55cc01727cfc Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Sat, 20 Mar 2021 13:39:59 -0700 Subject: [PATCH 15/43] less awful --- .../objects/items/robot/robot_upgrades.dm | 2 +- .../projectiles/ammunition/energy/laser.dm | 3 ++ .../boxes_magazines/internal/misc.dm | 6 --- .../guns/ballistic/laser_gatling.dm | 38 ++++++++++--------- code/modules/surgery/bodyparts/_bodyparts.dm | 2 +- 5 files changed, 25 insertions(+), 26 deletions(-) diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index 291fc30aa2..ed92623a37 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -681,7 +681,7 @@ as performing this in action() will cause the upgrade to end up in the borg inst action_icon_state = "Chevron_State_0" var/currentState = 0 - var/maxReduction = 1 + var/maxReduction = 0.5 /obj/effect/proc_holder/silicon/cyborg/vtecControl/Trigger(mob/living/silicon/robot/user) diff --git a/code/modules/projectiles/ammunition/energy/laser.dm b/code/modules/projectiles/ammunition/energy/laser.dm index f6eca57e29..5b727d76de 100644 --- a/code/modules/projectiles/ammunition/energy/laser.dm +++ b/code/modules/projectiles/ammunition/energy/laser.dm @@ -2,6 +2,9 @@ projectile_type = /obj/item/projectile/beam/laser select_name = "kill" +/obj/item/ammo_casing/energy/laser/minigun + click_cooldown_override = 2 + /obj/item/ammo_casing/energy/lasergun projectile_type = /obj/item/projectile/beam/laser e_cost = 83 diff --git a/code/modules/projectiles/boxes_magazines/internal/misc.dm b/code/modules/projectiles/boxes_magazines/internal/misc.dm index 2b87557b39..76f3c88381 100644 --- a/code/modules/projectiles/boxes_magazines/internal/misc.dm +++ b/code/modules/projectiles/boxes_magazines/internal/misc.dm @@ -3,9 +3,3 @@ ammo_type = /obj/item/ammo_casing/caseless/magspear caliber = "speargun" max_ammo = 1 - -/obj/item/ammo_box/magazine/internal/minigun - name = "gatling gun fusion core" - ammo_type = /obj/item/ammo_casing/caseless/laser/gatling - caliber = "gatling" - max_ammo = 5000 diff --git a/code/modules/projectiles/guns/ballistic/laser_gatling.dm b/code/modules/projectiles/guns/ballistic/laser_gatling.dm index 244bc5b124..2abb7b720f 100644 --- a/code/modules/projectiles/guns/ballistic/laser_gatling.dm +++ b/code/modules/projectiles/guns/ballistic/laser_gatling.dm @@ -11,19 +11,19 @@ righthand_file = 'icons/mob/inhands/equipment/backpack_righthand.dmi' slot_flags = ITEM_SLOT_BACK w_class = WEIGHT_CLASS_HUGE - var/obj/item/gun/ballistic/minigun/gun + var/obj/item/gun/energy/minigun/gun var/armed = 0 //whether the gun is attached, 0 is attached, 1 is the gun is wielded. var/overheat = 0 - var/overheat_max = 40 + var/overheat_max = 50 var/heat_diffusion = 1 /obj/item/minigunpack/Initialize() . = ..() gun = new(src) - START_PROCESSING(SSobj, src) + START_PROCESSING(SSfastprocess, src) /obj/item/minigunpack/Destroy() - STOP_PROCESSING(SSobj, src) + STOP_PROCESSING(SSfastprocess, src) return ..() /obj/item/minigunpack/process() @@ -72,7 +72,6 @@ var/obj/screen/inventory/hand/H = over_object M.putItemFromInventoryInHandIfPossible(src, H.held_index) - /obj/item/minigunpack/update_icon_state() if(armed) icon_state = "notholstered" @@ -92,7 +91,7 @@ user.update_inv_back() -/obj/item/gun/ballistic/minigun +/obj/item/gun/energy/minigun name = "laser gatling gun" desc = "An advanced laser cannon with an incredible rate of fire. Requires a bulky backpack power source to use." icon = 'icons/obj/guns/minigun.dmi' @@ -103,17 +102,20 @@ slot_flags = null w_class = WEIGHT_CLASS_HUGE custom_materials = null - burst_size = 3 - automatic = 0 - fire_delay = 1 + automatic = 0.5 + fire_delay = 2 + ammo_type = list( + /obj/item/ammo_casing/energy/laser + ) + weapon_weight = WEAPON_HEAVY fire_sound = 'sound/weapons/laser.ogg' - mag_type = /obj/item/ammo_box/magazine/internal/minigun - casing_ejector = FALSE + charge_sections = 0 + shaded_charge = 0 item_flags = NEEDS_PERMIT | SLOWS_WHILE_IN_HAND var/obj/item/minigunpack/ammo_pack -/obj/item/gun/ballistic/minigun/Initialize() +/obj/item/gun/energy/minigun/Initialize() if(istype(loc, /obj/item/minigunpack)) //We should spawn inside an ammo pack so let's use that one. ammo_pack = loc else @@ -121,29 +123,29 @@ return ..() -/obj/item/gun/ballistic/minigun/attack_self(mob/living/user) +/obj/item/gun/energy/minigun/attack_self(mob/living/user) return -/obj/item/gun/ballistic/minigun/dropped(mob/user) +/obj/item/gun/energy/minigun/dropped(mob/user) . = ..() if(ammo_pack) ammo_pack.attach_gun(user) else qdel(src) -/obj/item/gun/ballistic/minigun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0) +/obj/item/gun/energy/minigun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0) if(ammo_pack) if(ammo_pack.overheat < ammo_pack.overheat_max) - ammo_pack.overheat += burst_size + ammo_pack.overheat++ ..() else to_chat(user, "The gun's heat sensor locked the trigger to prevent lens damage.") -/obj/item/gun/ballistic/minigun/afterattack(atom/target, mob/living/user, flag, params) +/obj/item/gun/energy/minigun/afterattack(atom/target, mob/living/user, flag, params) if(!ammo_pack || ammo_pack.loc != user) to_chat(user, "You need the backpack power source to fire the gun!") . = ..() -/obj/item/gun/ballistic/minigun/dropped(mob/living/user) +/obj/item/gun/energy/minigun/dropped(mob/living/user) . = ..() ammo_pack.attach_gun(user) diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index d6379e1166..9144eefdbc 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -211,7 +211,7 @@ switch(animal_origin) if(ALIEN_BODYPART,LARVA_BODYPART) //aliens take some additional burn //nothing can burn with so much snowflake code around - burn *= 1.2 + burn *= 1.5 /* // START WOUND HANDLING From 604a6efeca05b2148625bbe50648bb945947b4f9 Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Sat, 20 Mar 2021 13:45:39 -0700 Subject: [PATCH 16/43] baton change --- code/datums/martial/sleeping_carp.dm | 16 ++++++++-------- code/game/objects/items/stunbaton.dm | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/code/datums/martial/sleeping_carp.dm b/code/datums/martial/sleeping_carp.dm index e926da78d0..f41529564d 100644 --- a/code/datums/martial/sleeping_carp.dm +++ b/code/datums/martial/sleeping_carp.dm @@ -181,14 +181,14 @@ REMOVE_TRAIT(H, TRAIT_PIERCEIMMUNE, SLEEPING_CARP_TRAIT) REMOVE_TRAIT(H, TRAIT_NODISMEMBER, SLEEPING_CARP_TRAIT) REMOVE_TRAIT(H, TRAIT_TASED_RESISTANCE, SLEEPING_CARP_TRAIT) - H.physiology.brute_mod = initial(H.physiology.brute_mod) - H.physiology.burn_mod = initial(H.physiology.burn_mod) - H.physiology.stamina_mod = initial(H.physiology.stamina_mod) - H.physiology.stun_mod = initial(H.physiology.stun_mod) - H.physiology.pressure_mod = initial(H.physiology.pressure_mod) //no more carpies - H.physiology.cold_mod = initial(H.physiology.cold_mod) - H.physiology.heat_mod = initial(H.physiology.heat_mod) - H.physiology.stamina_buffer_mod = initial(H.physiology.stamina_buffer_mod) + H.physiology.brute_mod *= (1/0.4) //brute is really not gonna cut it + H.physiology.burn_mod *= (1/0.7) //burn is distinctly more useful against them than brute but they're still resistant + H.physiology.stamina_mod *= (1/0.4) //You take less stamina damage overall, but you do not reduce the damage from stun batons as much + H.physiology.stun_mod *= (1/0.3) //for those rare stuns + H.physiology.pressure_mod *= (1/0.3) //go hang out with carp + H.physiology.cold_mod *= (1/0.3) //cold mods are different to burn mods, they do stack however + H.physiology.heat_mod *= (1/2) //this is mostly so sleeping carp has a viable weakness. Cooking them alive. Setting them on fire and heating them will be their biggest weakness. The reason for this is....filet jokes. + H.physiology.stamina_buffer_mod *= (1/0.75) //to help with some stamina H.faction -= "carp" //:( /mob/living/carbon/human/proc/sleeping_carp_help() diff --git a/code/game/objects/items/stunbaton.dm b/code/game/objects/items/stunbaton.dm index 862b2c8c3e..bbc962ebb7 100644 --- a/code/game/objects/items/stunbaton.dm +++ b/code/game/objects/items/stunbaton.dm @@ -205,7 +205,7 @@ if(!disarming) if(knockdown && !countered) L.DefaultCombatKnockdown(50, override_stamdmg = 0, knocktofloor = !countered) //knockdown - L.adjustStaminaLoss(stunpwr) + L.apply_damage(stunpwr, STAMINA, BODY_ZONE_CHEST) else if(!countered) L.drop_all_held_items() //no knockdown/stamina damage, instead disarm. From 427919d1479c824699985e1c31c09fea70f2ad19 Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Sat, 20 Mar 2021 13:57:48 -0700 Subject: [PATCH 17/43] whew --- code/game/objects/items/dualsaber.dm | 2 +- code/game/objects/items/shields.dm | 2 +- .../changeling/powers/mutations.dm | 2 +- .../modules/mob/living/living_active_block.dm | 34 +++++++++++++------ .../mob/living/living_blocking_parrying.dm | 2 +- 5 files changed, 27 insertions(+), 15 deletions(-) diff --git a/code/game/objects/items/dualsaber.dm b/code/game/objects/items/dualsaber.dm index 86522b9587..01e68a6516 100644 --- a/code/game/objects/items/dualsaber.dm +++ b/code/game/objects/items/dualsaber.dm @@ -73,7 +73,7 @@ parry_failed_stagger_duration = 3 SECONDS parry_failed_clickcd_duration = CLICK_CD_MELEE -/obj/item/dualsaber/active_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, override_direction) +/obj/item/dualsaber/directional_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, override_direction) if((attack_type & ATTACK_TYPE_PROJECTILE) && is_energy_reflectable_projectile(object)) block_return[BLOCK_RETURN_REDIRECT_METHOD] = REDIRECT_METHOD_RETURN_TO_SENDER return BLOCK_SUCCESS | BLOCK_REDIRECTED | BLOCK_SHOULD_REDIRECT diff --git a/code/game/objects/items/shields.dm b/code/game/objects/items/shields.dm index 9841a29ae0..deb8a8ac7d 100644 --- a/code/game/objects/items/shields.dm +++ b/code/game/objects/items/shields.dm @@ -446,7 +446,7 @@ return BLOCK_SUCCESS | BLOCK_REDIRECTED | BLOCK_SHOULD_REDIRECT return ..() -/obj/item/shield/energy/active_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, override_direction) +/obj/item/shield/energy/directional_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, override_direction) if((attack_type & ATTACK_TYPE_PROJECTILE) && is_energy_reflectable_projectile(object)) block_return[BLOCK_RETURN_REDIRECT_METHOD] = REDIRECT_METHOD_DEFLECT return BLOCK_SUCCESS | BLOCK_REDIRECTED | BLOCK_SHOULD_REDIRECT diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm index 5b6a7648c8..0d1496039a 100644 --- a/code/modules/antagonists/changeling/powers/mutations.dm +++ b/code/modules/antagonists/changeling/powers/mutations.dm @@ -466,7 +466,7 @@ block_return[BLOCK_RETURN_BLOCK_CAPACITY] = (block_return[BLOCK_RETURN_BLOCK_CAPACITY] || 0) + remaining_uses return ..() -/obj/item/shield/changeling/active_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return) +/obj/item/shield/changeling/directional_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return) . = ..() if(--remaining_uses < 1) if(ishuman(loc)) diff --git a/code/modules/mob/living/living_active_block.dm b/code/modules/mob/living/living_active_block.dm index 5c184313ee..719fa4bc53 100644 --- a/code/modules/mob/living/living_active_block.dm +++ b/code/modules/mob/living/living_active_block.dm @@ -140,7 +140,7 @@ /** * Calculates FINAL ATTACK DAMAGE after mitigation */ -/obj/item/proc/active_block_calculate_final_damage(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return) +/obj/item/proc/active_block_calculate_final_damage(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, passive = FALSE) var/datum/block_parry_data/data = get_block_parry_data() var/absorption = data.attack_type_list_scan(data.block_damage_absorption_override, attack_type) var/efficiency = data.attack_type_list_scan(data.block_damage_multiplier_override, attack_type) @@ -149,7 +149,7 @@ if(isnull(absorption)) absorption = data.block_damage_absorption if(isnull(efficiency)) - efficiency = data.block_damage_multiplier + efficiency = data.block_damage_multiplier * (passive? data.block_automatic_mitigation_multiplier : 1) if(isnull(limit)) limit = data.block_damage_limit // now we calculate damage to reduce. @@ -165,7 +165,7 @@ return final_damage /// Amount of stamina from damage blocked. Note that the damage argument is damage_blocked. -/obj/item/proc/active_block_stamina_cost(mob/living/owner, atom/object, damage_blocked, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return) +/obj/item/proc/active_block_stamina_cost(mob/living/owner, atom/object, damage_blocked, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, passive = FALSE) var/datum/block_parry_data/data = get_block_parry_data() var/efficiency = data.attack_type_list_scan(data.block_stamina_efficiency_override, attack_type) if(isnull(efficiency)) @@ -175,7 +175,7 @@ multiplier = data.attack_type_list_scan(data.block_resting_stamina_penalty_multiplier_override, attack_type) if(isnull(multiplier)) multiplier = data.block_resting_stamina_penalty_multiplier - return (damage_blocked / efficiency) * multiplier + return (damage_blocked / efficiency) * multiplier * (passive? data.block_automatic_stamina_multiplier : 1) /// Apply the stamina damage to our user, notice how damage argument is stamina_amount. /obj/item/proc/active_block_do_stamina_damage(mob/living/owner, atom/object, stamina_amount, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return) @@ -207,6 +207,18 @@ return /obj/item/proc/active_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, override_direction) + return directional_block(owner, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, block_return, override_direction) + +/obj/item/proc/can_passive_block() + if(!block_parry_data || !(item_flags & ITEM_CAN_BLOCK)) + return FALSE + var/datum/block_parry_data/data = return_block_parry_datum(block_parry_data) + return data.block_automatic_enabled + +/obj/item/proc/passive_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, override_direction) + return directional_block(owner, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, block_return, override_direction, TRUE) + +/obj/item/proc/directional_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, override_direction, passive = FALSE) if(!can_active_block()) return BLOCK_NONE var/datum/block_parry_data/data = get_block_parry_data() @@ -221,12 +233,12 @@ incoming_direction = get_dir(get_turf(attacker) || get_turf(object), src) if(!CHECK_MOBILITY(owner, MOBILITY_STAND) && !(data.block_resting_attack_types_anydir & attack_type) && (!(data.block_resting_attack_types_directional & attack_type) || !can_block_direction(owner.dir, incoming_direction))) return BLOCK_NONE - else if(!can_block_direction(owner.dir, incoming_direction)) + else if(!can_block_direction(owner.dir, incoming_direction, passive)) return BLOCK_NONE block_return[BLOCK_RETURN_ACTIVE_BLOCK] = TRUE - var/final_damage = active_block_calculate_final_damage(owner, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, block_return) + var/final_damage = active_block_calculate_final_damage(owner, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, block_return, passive) var/damage_blocked = damage - final_damage - var/stamina_cost = active_block_stamina_cost(owner, object, damage_blocked, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, block_return) + var/stamina_cost = active_block_stamina_cost(owner, object, damage_blocked, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, block_return, passive) active_block_do_stamina_damage(owner, object, stamina_cost, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, block_return) block_return[BLOCK_RETURN_ACTIVE_BLOCK_DAMAGE_MITIGATED] = damage - final_damage block_return[BLOCK_RETURN_SET_DAMAGE_TO] = final_damage @@ -254,9 +266,9 @@ /** * Gets the block direction bitflags of what we can block. */ -/obj/item/proc/blockable_directions() +/obj/item/proc/blockable_directions(passive = FALSE) var/datum/block_parry_data/data = get_block_parry_data() - return data.can_block_directions + return passive? data.block_automatic_directions : data.can_block_directions /** * Checks if we can block from a specific direction from our direction. @@ -265,14 +277,14 @@ * * our_dir - our direction. * * their_dir - their direction. Must be a single direction, or NONE for an attack from the same tile. This is incoming direction. */ -/obj/item/proc/can_block_direction(our_dir, their_dir) +/obj/item/proc/can_block_direction(our_dir, their_dir, passive = FALSE) their_dir = turn(their_dir, 180) if(our_dir != NORTH) var/turn_angle = dir2angle(our_dir) // dir2angle(), ss13 proc is clockwise so dir2angle(EAST) == 90 // turn(), byond proc is counterclockwise so turn(NORTH, 90) == WEST their_dir = turn(their_dir, turn_angle) - return (DIR2BLOCKDIR(their_dir) & blockable_directions()) + return (DIR2BLOCKDIR(their_dir) & blockable_directions(passive)) /** * can_block_direction but for "compound" directions to check all of them and return the number of directions that were blocked. diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm index 1ed490b0d8..b273324028 100644 --- a/code/modules/mob/living/living_blocking_parrying.dm +++ b/code/modules/mob/living/living_blocking_parrying.dm @@ -100,7 +100,7 @@ GLOBAL_LIST_EMPTY(block_parry_data) #warn have autoblock items warn user on pickup /// Directions that you can autoblock in var/block_automatic_directions = BLOCK_DIR_NORTH | BLOCK_DIR_NORTHEAST | BLOCK_DIR_NORTHWEST - /// Effectiveness multiplier for automated block + /// Effectiveness multiplier for automated block. Only applies to efficiency, absorption and limits stay the same! var/block_automatic_mitigation_multiplier = 0.33 /// Stamina cost multiplier for automated block var/block_automatic_stamina_multiplier = 1 From 957c1fcc5dfe2e0c19664200eb6cb171c887efaf Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Sat, 20 Mar 2021 14:09:23 -0700 Subject: [PATCH 18/43] okay --- code/datums/components/combat_mode.dm | 3 +-- code/game/sound.dm | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/code/datums/components/combat_mode.dm b/code/datums/components/combat_mode.dm index 576d012093..ac18becb67 100644 --- a/code/datums/components/combat_mode.dm +++ b/code/datums/components/combat_mode.dm @@ -90,7 +90,6 @@ source.playsound_local(source, 'sound/misc/ui_toggle.ogg', 50, FALSE, pressure_affected = FALSE) //Sound from interbay! RegisterSignal(source, COMSIG_MOB_CLIENT_MOUSEMOVE, .proc/onMouseMove) RegisterSignal(source, COMSIG_MOVABLE_MOVED, .proc/on_move) - RegisterSignal(source, COMSIG_MOB_CLIENT_MOVE, .proc/on_client_move) if(hud_icon) hud_icon.combat_on = TRUE hud_icon.update_icon() @@ -115,7 +114,7 @@ to_chat(source, self_message) if(playsound) source.playsound_local(source, 'sound/misc/ui_toggleoff.ogg', 50, FALSE, pressure_affected = FALSE) //Slightly modified version of the toggleon sound! - UnregisterSignal(source, list(COMSIG_MOB_CLIENT_MOUSEMOVE, COMSIG_MOVABLE_MOVED, COMSIG_MOB_CLIENT_MOVE)) + UnregisterSignal(source, list(COMSIG_MOB_CLIENT_MOUSEMOVE, COMSIG_MOVABLE_MOVED)) if(hud_icon) hud_icon.combat_on = FALSE hud_icon.update_icon() diff --git a/code/game/sound.dm b/code/game/sound.dm index b233ebd6d2..3a65d47f3f 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -84,11 +84,11 @@ falloff_distance - Distance at which falloff begins. Sound is at peak volume (in for(var/P in listeners) var/mob/M = P if(get_dist(M, turf_source) <= maxdistance) - M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff_exponent, channel, pressure_affected, S, maxdistance, falloff_distance, get_dist(M, turf_sounrce) <= distance_multiplier_min_range? 1 : distance_multiplier, envwet, envdry) + M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff_exponent, channel, pressure_affected, S, maxdistance, falloff_distance, get_dist(M, turf_source) <= distance_multiplier_min_range? 1 : distance_multiplier, envwet, envdry) for(var/P in SSmobs.dead_players_by_zlevel[source_z]) var/mob/M = P if(get_dist(M, turf_source) <= maxdistance) - M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff_exponent, channel, pressure_affected, S, maxdistance, falloff_distance, get_dist(M, turf_sounrce) <= distance_multiplier_min_range? 1 : distance_multiplier, envwet, envdry) + M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff_exponent, channel, pressure_affected, S, maxdistance, falloff_distance, get_dist(M, turf_source) <= distance_multiplier_min_range? 1 : distance_multiplier, envwet, envdry) /*! playsound From efa4139aff51c0b0f27936a3bc0ff5e43ed823bc Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Sat, 20 Mar 2021 14:17:13 -0700 Subject: [PATCH 19/43] math fix --- code/game/objects/items/dualsaber.dm | 6 +++--- code/modules/mob/living/living_active_block.dm | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/code/game/objects/items/dualsaber.dm b/code/game/objects/items/dualsaber.dm index 01e68a6516..5ae79b3c3a 100644 --- a/code/game/objects/items/dualsaber.dm +++ b/code/game/objects/items/dualsaber.dm @@ -41,7 +41,7 @@ /datum/block_parry_data/dual_esword // please run at the man going apeshit with his funny doublesword can_block_directions = BLOCK_DIR_NORTH | BLOCK_DIR_NORTHEAST | BLOCK_DIR_NORTHWEST | BLOCK_DIR_WEST | BLOCK_DIR_EAST - block_damage_absorption = 2 + block_damage_absorption = 5 block_damage_multiplier = 0.15 block_damage_multiplier_override = list( ATTACK_TYPE_MELEE = 0.25 @@ -59,7 +59,7 @@ ) parry_time_windup = 0 - parry_time_active = 8 + parry_time_active = 12 parry_time_spindown = 0 // we want to signal to players the most dangerous phase, the time when automatic counterattack is a thing. parry_time_windup_visual_override = 1 @@ -82,7 +82,7 @@ /obj/item/dualsaber/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time) . = ..() if(parry_efficiency >= 90) // perfect parry - block_return[BLOCK_RETURN_REDIRECT_METHOD] = REDIRECT_METHOD_RETURN_TO_SENDER + block_return[BLOCK_RETURN_REDIRECT_METHOD] = REDIRECT_METHOD_DEFLECT . |= BLOCK_SHOULD_REDIRECT /obj/item/dualsaber/Initialize() diff --git a/code/modules/mob/living/living_active_block.dm b/code/modules/mob/living/living_active_block.dm index 719fa4bc53..e6f9a569a3 100644 --- a/code/modules/mob/living/living_active_block.dm +++ b/code/modules/mob/living/living_active_block.dm @@ -149,7 +149,7 @@ if(isnull(absorption)) absorption = data.block_damage_absorption if(isnull(efficiency)) - efficiency = data.block_damage_multiplier * (passive? data.block_automatic_mitigation_multiplier : 1) + efficiency = data.block_damage_multiplier * (passive? (1 / data.block_automatic_mitigation_multiplier) : 1) if(isnull(limit)) limit = data.block_damage_limit // now we calculate damage to reduce. From 02b52e61429250e01c2f1b699c0ddc3ba74d8b3a Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Sat, 20 Mar 2021 16:02:26 -0700 Subject: [PATCH 20/43] framework --- code/_onclick/drag_drop.dm | 5 +- code/datums/martial/sleeping_carp.dm | 2 + code/game/objects/items.dm | 15 +++ code/game/objects/items/electrostaff.dm | 1 - code/game/objects/items/melee/misc.dm | 23 ++-- code/modules/client/client_defines.dm | 4 + .../modules/mob/living/living_active_block.dm | 2 +- .../modules/mob/living/living_active_parry.dm | 117 +++++++++++++----- .../mob/living/living_blocking_parrying.dm | 17 +-- code/modules/mob/living/living_defines.dm | 2 + code/modules/surgery/bodyparts/_bodyparts.dm | 2 +- 11 files changed, 132 insertions(+), 58 deletions(-) diff --git a/code/_onclick/drag_drop.dm b/code/_onclick/drag_drop.dm index 8e2e0c3fb5..43f2581de8 100644 --- a/code/_onclick/drag_drop.dm +++ b/code/_onclick/drag_drop.dm @@ -94,6 +94,10 @@ mouseControlObject = control if(mob) SEND_SIGNAL(mob, COMSIG_MOB_CLIENT_MOUSEMOVE, object, location, control, params) + // god forgive me for i have sinned - used for autoparry. currently at 5 objects. + mousedOverObjects[object] = world.time + if(mousedOverObjects.len > 7) + mousedOverObjects.Cut(1, 2) ..() /client/MouseDrag(src_object,atom/over_object,src_location,over_location,src_control,over_control,params) @@ -115,7 +119,6 @@ if(active_mousedown_item) active_mousedown_item.onMouseDrag(src_object, over_object, src_location, over_location, params, mob) - /obj/item/proc/onMouseDrag(src_object, over_object, src_location, over_location, params, mob) return diff --git a/code/datums/martial/sleeping_carp.dm b/code/datums/martial/sleeping_carp.dm index f41529564d..d6e2b1a2c0 100644 --- a/code/datums/martial/sleeping_carp.dm +++ b/code/datums/martial/sleeping_carp.dm @@ -151,7 +151,9 @@ parry_efficiency_considered_successful = 65 // VERY generous parry_efficiency_perfect = 100 parry_failed_stagger_duration = 4 SECONDS + parry_failed_cooldown_duration = 2 SECONDS parry_cooldown = 0.5 SECONDS + parry_flags = NONE /mob/living/carbon/human/UseStaminaBuffer(amount, warn = FALSE, considered_action = TRUE) amount *= physiology? physiology.stamina_buffer_mod : 1 diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 8a09bca0bf..c3b0ab0d26 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -453,6 +453,21 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb SHOULD_CALL_PARENT(TRUE) SEND_SIGNAL(src, COMSIG_ITEM_PICKUP, user) item_flags |= IN_INVENTORY + if(combat_flags & (ITEM_CAN_BLOCK | ITEM_CAN_PARRY) && user.client && !(type in user.client.block_parry_hinted)) + var/list/dat = list("You have picked up an item that can be used to block and/or parry:") + // cit change - parry/block feedback + var/datum/block_parry_data/data = return_block_parry_datum(block_parry_data) + if(combat_flags & ITEM_CAN_BLOCK) + dat += "[src] can be used to block damage using directional block. Press your active block keybind to use it." + if(data.block_automatic_enabled) + dat += "[src] is also capable of automatically blocking damage, if you are facing the right direction (usually towards your attacker)!" + if(combat_flags & ITEM_CAN_PARRY) + dat += "[src] can be used to parry damage using active parry. Pressed your active parry keybind to initiate a timed parry sequence." + if(data.parry_automatic_enabled) + dat += "[src] is also capable of automatically parrying an incoming attack, if your mouse is over your attacker at the time if you being hit in a direct, melee attack." + dat += "Examine [src] to get a full readout of its block/parry stats." + to_chat(user, dat.Join("
")) + user.client.block_parry_hinted |= type // called when "found" in pockets and storage items. Returns 1 if the search should end. /obj/item/proc/on_found(mob/finder) diff --git a/code/game/objects/items/electrostaff.dm b/code/game/objects/items/electrostaff.dm index 71cebc38c6..52b5c556c9 100644 --- a/code/game/objects/items/electrostaff.dm +++ b/code/game/objects/items/electrostaff.dm @@ -61,7 +61,6 @@ TEXT_ATTACK_TYPE_PROJECTILE = 1 // extremely harsh window for projectiles ) // not extremely punishing to fail, but no spamming the parry. - parry_cooldown = 1.5 SECONDS parry_failed_stagger_duration = 1.5 SECONDS parry_failed_clickcd_duration = 1 SECONDS diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm index 1043876061..c361c1e20d 100644 --- a/code/game/objects/items/melee/misc.dm +++ b/code/game/objects/items/melee/misc.dm @@ -72,15 +72,16 @@ block_parry_data = /datum/block_parry_data/captain_saber /datum/block_parry_data/captain_saber - parry_time_windup = 0.5 - parry_time_active = 4 - parry_time_spindown = 1 + parry_time_windup = 0 + parry_time_active = 6 + parry_time_spindown = 0 parry_time_perfect = 0.75 parry_time_perfect_leeway = 0.75 parry_imperfect_falloff_percent = 30 parry_efficiency_perfect = 100 parry_failed_stagger_duration = 3 SECONDS parry_failed_clickcd_duration = 1 SECONDS + parry_flags = NONE /obj/item/melee/sabre/Initialize() . = ..() @@ -176,28 +177,22 @@ // Fast, efficient parry. /datum/block_parry_data/traitor_rapier - parry_time_windup = 0.5 - parry_time_active = 5 + parry_time_windup = 0 + parry_time_active = 6 parry_time_spindown = 0 parry_time_active_visual_override = 3 parry_time_spindown_visual_override = 2 parry_flags = PARRY_DEFAULT_HANDLE_FEEDBACK | PARRY_LOCK_ATTACKING - parry_time_perfect = 0 - parry_time_perfect_leeway = 3 + parry_time_perfect = 1 + parry_time_perfect_leeway = 1 parry_time_perfect_leeway_override = list( TEXT_ATTACK_TYPE_PROJECTILE = 1 ) - parry_imperfect_falloff_percent_override = list( - TEXT_ATTACK_TYPE_PROJECTILE = 50 // useless after 3rd decisecond - ) parry_imperfect_falloff_percent = 30 parry_efficiency_to_counterattack = INFINITY parry_efficiency_considered_successful = 1 parry_efficiency_perfect = 100 - parry_data = list( - PARRY_DISARM_ATTACKER = TRUE, - PARRY_KNOCKDOWN_ATTACKER = 10 - ) + parry_stamina_cost = 5 parry_failed_stagger_duration = 2 SECONDS parry_failed_clickcd_duration = CLICK_CD_RANGE parry_cooldown = 0 diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm index 241cd6be93..a4d94e994c 100644 --- a/code/modules/client/client_defines.dm +++ b/code/modules/client/client_defines.dm @@ -183,3 +183,7 @@ //world.time of when the crew manifest can be accessed var/crew_manifest_delay + /// Should go in persistent round player data sometime. This tracks what items have already warned the user on pickup that they can block/parry. + var/list/block_parry_hinted = list() + /// moused over objects, currently capped at 7. this is awful, and should be replaced with a component to track it using signals for parrying at some point. + var/list/moused_over_objects = list() diff --git a/code/modules/mob/living/living_active_block.dm b/code/modules/mob/living/living_active_block.dm index e6f9a569a3..9ccaeb6c59 100644 --- a/code/modules/mob/living/living_active_block.dm +++ b/code/modules/mob/living/living_active_block.dm @@ -268,7 +268,7 @@ */ /obj/item/proc/blockable_directions(passive = FALSE) var/datum/block_parry_data/data = get_block_parry_data() - return passive? data.block_automatic_directions : data.can_block_directions + return (!isnull(data.block_automatic_directions) && passive)? data.block_automatic_directions : data.can_block_directions /** * Checks if we can block from a specific direction from our direction. diff --git a/code/modules/mob/living/living_active_parry.dm b/code/modules/mob/living/living_active_parry.dm index c15b56afe8..bdd6174314 100644 --- a/code/modules/mob/living/living_active_parry.dm +++ b/code/modules/mob/living/living_active_parry.dm @@ -14,18 +14,57 @@ /** * Initiates a parrying sequence. */ -/mob/living/proc/initiate_parry_sequence() +/mob/living/proc/initiate_parry_sequence(silent = FALSE, list/override_method_data) if(parrying) - return // already parrying + return FALSE // already parrying if(!(mobility_flags & MOBILITY_USE)) - to_chat(src, "You can't move your arms!") - return + if(!silent) + to_chat(src, "You can't move your arms!") + return FALSE if(!(combat_flags & COMBAT_FLAG_PARRY_CAPABLE)) - to_chat(src, "You are not something that can parry attacks.") - return + if(!silent) + to_chat(src, "You are not something that can parry attacks.") + return FALSE if(!(mobility_flags & MOBILITY_STAND)) - to_chat(src, "You aren't able to parry without solid footing!") - return + if(!silent) + to_chat(src, "You aren't able to parry without solid footing!") + return FALSE + var/datum/block_parry_data/data + var/list/determined = override_method_data || determine_parry_method(FALSE, FALSE) + if(!islist(determined)) + return FALSE + var/method = determined[1] + data = return_block_parry_datum(determined[2]) + var/full_parry_duration = data.parry_time_windup + data.parry_time_active + data.parry_time_spindown + // no system in place to "fallback" if out of the 3 the top priority one can't parry due to constraints but something else can. + // can always implement it later, whatever. + if((data.parry_respect_clickdelay && !CheckActionCooldown()) || ((parry_end_time_last + data.parry_cooldown) > world.time)) + if(!silent) + to_chat(src, "You are not ready to parry (again)!") + return FALSE + // Point of no return, make sure everything is set. + parrying = method + if(method == ITEM_PARRY) + active_parry_item = using_item + if(!UseStaminaBuffer(data.parry_stamina_cost, TRUE)) + return FALSE + parry_start_time = world.time + successful_parries = list() + successful_parry_counterattacks = list() + addtimer(CALLBACK(src, .proc/end_parry_sequence), full_parry_duration) + if(data.parry_flags & PARRY_LOCK_ATTACKING) + ADD_TRAIT(src, TRAIT_MOBILITY_NOUSE, ACTIVE_PARRY_TRAIT) + if(data.parry_flags & PARRY_LOCK_SPRINTING) + ADD_TRAIT(src, TRAIT_SPRINT_LOCKED, ACTIVE_PARRY_TRAIT) + handle_parry_starting_effects(data) + return TRUE + +/** + * Massive snowflake proc for getting something to parry with. + * + * @return list of [method, data, tool], where method is the parry method define, data is the block_parry_data var that must be run through return_block_parry_data, and tool is the concept/object/martial art/etc used. + */ +/mob/living/proc/determine_parry_method(silent = TRUE, autoparry = FALSE) // Prioritize item, then martial art, then unarmed. // yanderedev else if time var/obj/item/using_item = get_active_held_item() @@ -55,7 +94,8 @@ var/list/other_items = list() var/list/override = list() if(SEND_SIGNAL(src, COMSIG_LIVING_ACTIVE_PARRY_START, method, tool, other_items, override) & COMPONENT_PREVENT_PARRY_START) - to_chat(src, "Something is preventing you from parrying!") + if(!silent) + to_chat(src, "Something is preventing you from parrying!") return if(length(override)) var/datum/thing = override[1] @@ -72,30 +112,10 @@ method = ITEM_PARRY data = using_item.block_parry_data if(!method) - to_chat(src, "You have nothing to parry with!") + if(!silent) + to_chat(src, "You have nothing to parry with!") return FALSE - data = return_block_parry_datum(data) - var/full_parry_duration = data.parry_time_windup + data.parry_time_active + data.parry_time_spindown - // no system in place to "fallback" if out of the 3 the top priority one can't parry due to constraints but something else can. - // 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 FALSE - // Point of no return, make sure everything is set. - parrying = method - if(method == ITEM_PARRY) - active_parry_item = using_item - 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) - if(data.parry_flags & PARRY_LOCK_ATTACKING) - ADD_TRAIT(src, TRAIT_MOBILITY_NOUSE, ACTIVE_PARRY_TRAIT) - if(data.parry_flags & PARRY_LOCK_SPRINTING) - ADD_TRAIT(src, TRAIT_SPRINT_LOCKED, ACTIVE_PARRY_TRAIT) - handle_parry_starting_effects(data) - return TRUE + return list(method, data, tool) /** * Tries to find a backup parry item. @@ -141,6 +161,7 @@ parry_start_time = 0 parry_end_time_last = world.time + (successful? 0 : data.parry_failed_cooldown_duration) successful_parries = null + successful_parry_counterattacks = null /** * Handles starting effects for parrying. @@ -200,6 +221,35 @@ */ /datum/martial_art/proc/active_parry_reflex_counter(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list, parry_efficiency, list/effect_text) +/** + * Attempts to automatically parry an attacker. + */ +/mob/living/proc/attempt_auto_parry() + // determine how we'll parry + var/list/determined = determine_parry_method(TRUE, TRUE) + if(!islist(determined)) + return FALSE + var/method = determined[1] + var/datum/block_parry_data/data = return_block_parry_datum(determined[2]) + if(!data.parry_automatic_enabled) + return FALSE + // before doing anything, check if the user moused over them properly + + // if that works, try to start parry + // first, check cooldowns + + // now, depending on if we're doing a single simulation or a full sequence + if(data.autoparry_sequence_simulation) + // for full sequence simulation + initiate_parry_sequence(TRUE, determined) + if(data.autoparry_sequence_start_time == -1) + parry_start_time = world.time - data.parry_time_windup + else + parry_start_time = world.time - data.autoparry_sequence_start_time + else + // for single attack block + + /** * Gets the stage of our parry sequence we're currently in. */ @@ -279,7 +329,7 @@ pacifist_counter_check = (!active_parry_item.force || active_parry_item.damtype == STAMINA) else pacifist_counter_check = FALSE //Both martial and unarmed counter attacks generally are harmful, so no need to have the same line twice. - if(efficiency >= data.parry_efficiency_to_counterattack && pacifist_counter_check && !return_list[BLOCK_RETURN_FORCE_NO_PARRY_COUNTERATTACK]) + if(efficiency >= data.parry_efficiency_to_counterattack && pacifist_counter_check && !return_list[BLOCK_RETURN_FORCE_NO_PARRY_COUNTERATTACK] && (!(attacker in successful_parry_counterattacks) && !data.parry_allow_repeated_counterattacks)) effect_text = run_parry_countereffects(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency) if(data.parry_flags & PARRY_DEFAULT_HANDLE_FEEDBACK) handle_parry_feedback(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency, effect_text) @@ -303,6 +353,7 @@ var/mob/living/L = attacker var/datum/block_parry_data/data = get_parry_data() var/list/effect_text = list() + successful_parry_counterattacks |= attacker // Always proc so items can override behavior easily switch(parrying) if(ITEM_PARRY) diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm index b273324028..36fb160e0f 100644 --- a/code/modules/mob/living/living_blocking_parrying.dm +++ b/code/modules/mob/living/living_blocking_parrying.dm @@ -98,15 +98,15 @@ GLOBAL_LIST_EMPTY(block_parry_data) /// Can this item automatically block? var/block_automatic_enabled = TRUE #warn have autoblock items warn user on pickup - /// Directions that you can autoblock in - var/block_automatic_directions = BLOCK_DIR_NORTH | BLOCK_DIR_NORTHEAST | BLOCK_DIR_NORTHWEST + /// Directions that you can autoblock in. Null to default to normal directions. + var/block_automatic_directions = null /// Effectiveness multiplier for automated block. Only applies to efficiency, absorption and limits stay the same! var/block_automatic_mitigation_multiplier = 0.33 /// Stamina cost multiplier for automated block var/block_automatic_stamina_multiplier = 1 /////////// PARRYING //////////// - /// Prioriry for [mob/do_run_block()] while we're being used to parry. + /// Priority for [mob/do_run_block()] while we're being used to parry. // None - Parry is always highest priority! /// Parry doesn't work if you aren't able to otherwise attack due to clickdelay var/parry_respect_clickdelay = TRUE @@ -178,12 +178,13 @@ GLOBAL_LIST_EMPTY(block_parry_data) var/perfect_parry_block_return_list var/imperfect_parry_block_return_list var/failed_parry_block_return_list + /// Allow multiple counterattacks per parry sequence. Bad idea. + var/parry_allow_repeated_counterattacks = FALSE // Auto parry // Anything not specified like cooldowns/clickdelay respecting is pulled from above. /// Can this data automatically parry? This is off by default because this is something that requires thought to balance. var/parry_automatic_enabled = FALSE -#warn implement autoparry in items #warn have autoparry items warn user on pickup /// Hard autoparry cooldown var/autoparry_cooldown_absolute = 3 SECONDS @@ -195,16 +196,17 @@ GLOBAL_LIST_EMPTY(block_parry_data) /// Clickdelay to inflict on single-attack autoparry var/autoparry_single_click_cooldown = 0 /// Single attack autoparry - efficiency - var/autoparry_single_efficiency = 60 + var/autoparry_single_efficiency = 75 /// Single attack autoparry - efficiency overrides by attack type, see above var/list/autoparry_single_efficiency_override // Parry sequence simulation: /// Decisecond of sequence to start on. -1 to start to 0th tick of active parry window. var/autoparry_sequence_start_time = -1 - /// Efficiency multiplier - var/autoparry_sequence_efficiency_multiplier = 0.8 // Clickdelay/cooldown settings not included, as well as whether or not to lock attack/sprinting/etc. They will be pulled from the above. + /// ADVANCED - Autoparry requirement for time since last moused over for a specific object + var/autoparry_mouse_delay_maximum = 0.5 + /** * Quirky proc to get average of flags in list that are in attack_type because why is attack_type a flag. */ @@ -346,6 +348,7 @@ GLOBAL_LIST_EMPTY(block_parry_data) RENDER_VARIABLE_SIMPLE(parry_cooldown, "Deciseconds it has to be since the last time a parry sequence ended for you before you can parry again.") RENDER_VARIABLE_SIMPLE(parry_failed_stagger_duration, "Deciseconds you are staggered for at the of the parry sequence if you do not successfully parry anything.") RENDER_VARIABLE_SIMPLE(parry_failed_clickcd_duration, "Deciseconds you are put on attack cooldown at the end of the parry sequence if you do not successfully parry anything.") + dat += "" dat += "" return dat.Join("") #undef RENDER_VARIABLE_SIMPLE diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index 386f1174e1..14acf72f57 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -52,6 +52,8 @@ var/parry_end_time_last = 0 /// Successful parries within the current parry cycle. It's a list of efficiency percentages. var/list/successful_parries + /// Current parry counterattacks. Makes sure we can only counterattack someone once per parry. + var/list/successful_parry_counterattacks var/confused = 0 //Makes the mob move in random directions. diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 9144eefdbc..83c587b81d 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -211,7 +211,7 @@ switch(animal_origin) if(ALIEN_BODYPART,LARVA_BODYPART) //aliens take some additional burn //nothing can burn with so much snowflake code around - burn *= 1.5 + burn *= 1.75 /* // START WOUND HANDLING From 1fd06a89b749a0e73aeff4c51ddc304b13641a1d Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Sat, 20 Mar 2021 16:27:52 -0700 Subject: [PATCH 21/43] Oh Boy --- code/__DEFINES/dcs/signals.dm | 3 +++ code/datums/components/identification.dm | 1 + code/game/objects/items.dm | 11 ++++++----- .../objects/items/devices/traitordevices.dm | 18 +++++++++++++----- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index 13e6c5772a..c36e21ae06 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -550,3 +550,6 @@ // twitch plays /// Returns direction: (wipe_votes) #define COMSIG_TWITCH_PLAYS_MOVEMENT_DATA "twitch_plays_movement_data" + +// /datum/component/identification signals +#define COMSIG_IDENTIFICATION_KNOWLEDGE_CHECK "id_knowledge_check" // (mob/user) - returns a value from ID_COMPONENT_KNOWLEDGE_NONE to ID_COMPONENT_KNOWLEDGE_FULL diff --git a/code/datums/components/identification.dm b/code/datums/components/identification.dm index f7dc211504..474363b85b 100644 --- a/code/datums/components/identification.dm +++ b/code/datums/components/identification.dm @@ -24,6 +24,7 @@ identification_method_flags = id_method_flags /datum/component/identification/RegisterWithParent() + RegisterSignal(parent, COMSIG_IDENFICATION_KNOWLEDGE_CHECK, .proc/check_knowledge) RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_examine) if(identification_effect_flags & ID_COMPONENT_EFFECT_NO_ACTIONS) RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, .proc/on_equip) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index c3b0ab0d26..330865c5b7 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -511,12 +511,13 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb */ /obj/item/proc/equipped(mob/user, slot, initial = FALSE) SHOULD_CALL_PARENT(TRUE) - SEND_SIGNAL(src, COMSIG_ITEM_EQUIPPED, user, slot) + var/signal_flags = SEND_SIGNAL(src, COMSIG_ITEM_EQUIPPED, user, slot) current_equipped_slot = slot - for(var/X in actions) - var/datum/action/A = X - if(item_action_slot_check(slot, user, A)) //some items only give their actions buttons when in a specific slot. - A.Grant(user) + if(!(signal_flags & COMPONENT_NO_GRANT_ACTIONS)) + for(var/X in actions) + var/datum/action/A = X + if(item_action_slot_check(slot, user, A)) //some items only give their actions buttons when in a specific slot. + A.Grant(user) item_flags |= IN_INVENTORY // if(!initial) // if(equip_sound && (slot_flags & slot)) diff --git a/code/game/objects/items/devices/traitordevices.dm b/code/game/objects/items/devices/traitordevices.dm index 70edd3f43d..6fb3aef083 100644 --- a/code/game/objects/items/devices/traitordevices.dm +++ b/code/game/objects/items/devices/traitordevices.dm @@ -79,21 +79,27 @@ effective or pretty fucking useless. var/ui_x = 320 var/ui_y = 335 +/obj/item/healthanalyzer/rad_laser/Initialize() + . = ..() + AddComponent(/datum/component/identification/syndicate, ID_COMPONENT_DEL_ON_IDENTIFY, ID_COMPONENT_EFFECT_NO_ACTIONS, ID_COMPONENT_IDENTIFY_WITH_DECONSTRUCTOR) + /obj/item/healthanalyzer/rad_laser/attack(mob/living/M, mob/living/user) if(!stealth || !irradiate) - ..() + return ..() + var/knowledge = SEND_SIGNAL(COMSIG_IDENTIFICATION_KNOWLEDGE_CHECK, user) == ID_COMPONENT_KNOWLEDGE_FULL if(!irradiate) return if(!used) - log_combat(user, M, "irradiated", src) + log_combat(user, M, "[knowledge? "" : "unknowingly "]irradiated", src) var/cooldown = get_cooldown() used = TRUE icon_state = "health1" addtimer(VARSET_CALLBACK(src, used, FALSE), cooldown) addtimer(VARSET_CALLBACK(src, icon_state, "health"), cooldown) - to_chat(user, "Successfully irradiated [M].") + if(knowledge) + to_chat(user, "Successfully irradiated [M].") addtimer(CALLBACK(src, .proc/radiation_aftereffect, M), (wavelength+(intensity*4))*5) - else + else if(knowledge) to_chat(user, "The radioactive microlaser is still recharging.") /obj/item/healthanalyzer/rad_laser/proc/radiation_aftereffect(mob/living/M) @@ -110,7 +116,9 @@ effective or pretty fucking useless. interact(user) /obj/item/healthanalyzer/rad_laser/interact(mob/user) - ui_interact(user) + var/knowledge = SEND_SIGNAL(COMSIG_IDENTIFICATION_KNOWLEDGE_CHECK, user) == ID_COMPONENT_KNOWLEDGE_FULL + if(knowledge) + ui_interact(user) /obj/item/healthanalyzer/rad_laser/ui_state(mob/user) return GLOB.hands_state From 7ccb5bc711fb1339c6a05ed5b2f1e2778fb244db Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Mon, 26 Apr 2021 14:21:59 -0700 Subject: [PATCH 22/43] fixes --- code/datums/components/identification.dm | 2 +- code/datums/status_effects/debuffs.dm | 2 +- code/game/objects/items.dm | 6 +++--- code/game/objects/items/devices/traitordevices.dm | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/code/datums/components/identification.dm b/code/datums/components/identification.dm index 474363b85b..59b98b57ac 100644 --- a/code/datums/components/identification.dm +++ b/code/datums/components/identification.dm @@ -24,7 +24,7 @@ identification_method_flags = id_method_flags /datum/component/identification/RegisterWithParent() - RegisterSignal(parent, COMSIG_IDENFICATION_KNOWLEDGE_CHECK, .proc/check_knowledge) + RegisterSignal(parent, COMSIG_IDENTIFICATION_KNOWLEDGE_CHECK, .proc/check_knowledge) RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_examine) if(identification_effect_flags & ID_COMPONENT_EFFECT_NO_ACTIONS) RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, .proc/on_equip) diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm index 27de3bd702..d01d3a1454 100644 --- a/code/datums/status_effects/debuffs.dm +++ b/code/datums/status_effects/debuffs.dm @@ -190,9 +190,9 @@ /datum/status_effect/electrode/no_combat_mode id = "tased_strong" movespeed_mod = /datum/movespeed_modifier/status_effect/tased/no_combat_mode - blocks_combatmode = TRUE stamdmg_per_ds = 1 + //OTHER DEBUFFS /datum/status_effect/his_wrath //does minor damage over time unless holding His Grace id = "his_wrath" diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 330865c5b7..5dd9b9928c 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -453,15 +453,15 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb SHOULD_CALL_PARENT(TRUE) SEND_SIGNAL(src, COMSIG_ITEM_PICKUP, user) item_flags |= IN_INVENTORY - if(combat_flags & (ITEM_CAN_BLOCK | ITEM_CAN_PARRY) && user.client && !(type in user.client.block_parry_hinted)) + if(item_flags & (ITEM_CAN_BLOCK | ITEM_CAN_PARRY) && user.client && !(type in user.client.block_parry_hinted)) var/list/dat = list("You have picked up an item that can be used to block and/or parry:") // cit change - parry/block feedback var/datum/block_parry_data/data = return_block_parry_datum(block_parry_data) - if(combat_flags & ITEM_CAN_BLOCK) + if(item_flags & ITEM_CAN_BLOCK) dat += "[src] can be used to block damage using directional block. Press your active block keybind to use it." if(data.block_automatic_enabled) dat += "[src] is also capable of automatically blocking damage, if you are facing the right direction (usually towards your attacker)!" - if(combat_flags & ITEM_CAN_PARRY) + if(item_flags & ITEM_CAN_PARRY) dat += "[src] can be used to parry damage using active parry. Pressed your active parry keybind to initiate a timed parry sequence." if(data.parry_automatic_enabled) dat += "[src] is also capable of automatically parrying an incoming attack, if your mouse is over your attacker at the time if you being hit in a direct, melee attack." diff --git a/code/game/objects/items/devices/traitordevices.dm b/code/game/objects/items/devices/traitordevices.dm index 6e3a73f25c..6e06a87ac3 100644 --- a/code/game/objects/items/devices/traitordevices.dm +++ b/code/game/objects/items/devices/traitordevices.dm @@ -116,7 +116,7 @@ effective or pretty fucking useless. interact(user) /obj/item/healthanalyzer/rad_laser/interact(mob/user) - var/knowledge = SEND_SIGNAL(COMSIG_IDENTIFICATION_KNOWLEDGE_CHECK, user) == ID_COMPONENT_KNOWLEDGE_FULL + var/knowledge = SEND_SIGNAL(src, COMSIG_IDENTIFICATION_KNOWLEDGE_CHECK, user) == ID_COMPONENT_KNOWLEDGE_FULL if(knowledge) ui_interact(user) From 02b40589fe6125b09e6ca6c3ba4d559346fcf204 Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Mon, 26 Apr 2021 22:46:16 -0700 Subject: [PATCH 23/43] conflict gone --- code/game/objects/items/stunbaton.dm | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/code/game/objects/items/stunbaton.dm b/code/game/objects/items/stunbaton.dm index 13b091bd94..a733c282c6 100644 --- a/code/game/objects/items/stunbaton.dm +++ b/code/game/objects/items/stunbaton.dm @@ -19,7 +19,7 @@ var/stamina_loss_amount = 35 var/turned_on = FALSE var/knockdown = TRUE - /// block percent needed to prevent knockdown/disarm - UNUSED RIGHT NOW + /// block percent needed to prevent knockdown/disarm var/block_percent_to_counter = 50 var/obj/item/stock_parts/cell/cell var/hitcost = 750 @@ -221,12 +221,12 @@ if(user && !user.UseStaminaBuffer(getweight(user, STAM_COST_BATON_MOB_MULT), warn = TRUE)) return FALSE -<<<<<<< HEAD - if(!disarming) - if(knockdown && !countered) - L.DefaultCombatKnockdown(50, override_stamdmg = 0, knocktofloor = !countered) //knockdown - L.apply_damage(stunpwr, STAMINA, BODY_ZONE_CHEST) - else if(!countered) + if(shoving && COOLDOWN_FINISHED(src, shove_cooldown) && !HAS_TRAIT(L, TRAIT_IWASBATONED)) //Rightclicking applies a knockdown, but only once every couple of seconds, based on the cooldown_duration var. If they were recently knocked down, they can't be knocked down again by a baton. + L.DefaultCombatKnockdown(50, override_stamdmg = 0) + L.apply_status_effect(STATUS_EFFECT_TASED_WEAK, status_duration) //Even if they shove themselves up, they're still slowed. + L.apply_status_effect(STATUS_EFFECT_OFF_BALANCE, status_duration) //They're very likely to drop items if shoved briefly after a knockdown. + shoved = TRUE + COOLDOWN_START(src, shove_cooldown, cooldown_duration) ADD_TRAIT(L, TRAIT_IWASBATONED, STATUS_EFFECT_TRAIT) //Prevents swapping to a new baton to avoid the cooldown by just acquiring more batons addtimer(TRAIT_CALLBACK_REMOVE(L, TRAIT_IWASBATONED, STATUS_EFFECT_TRAIT), cooldown_duration) playsound(loc, 'sound/weapons/zapbang.ogg', 50, 1, -1) @@ -241,12 +241,12 @@ L.visible_message("[user] has [shoved ? "brutally stunned" : "stunned"] [L] with [src]!", \ "[user] has [shoved ? "brutally stunnned" : "stunned"] you with [src]!") log_combat(user, L, shoved ? "stunned and attempted knockdown" : "stunned") ->>>>>>> citadel/master playsound(loc, 'sound/weapons/egloves.ogg', 50, 1, -1) if(ishuman(L)) var/mob/living/carbon/human/H = L + H.forcesay(GLOB.hit_appends) return TRUE From 8fe45263c589a2c1394fed00662fbc9be867df7e Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Mon, 26 Apr 2021 22:58:30 -0700 Subject: [PATCH 24/43] whew --- code/_onclick/drag_drop.dm | 6 ++-- code/datums/status_effects/debuffs.dm | 7 +++++ .../objects/items/devices/traitordevices.dm | 2 +- .../modules/mob/living/living_active_parry.dm | 29 +++++++++++++++---- .../mob/living/living_blocking_parrying.dm | 2 -- 5 files changed, 34 insertions(+), 12 deletions(-) diff --git a/code/_onclick/drag_drop.dm b/code/_onclick/drag_drop.dm index 43f2581de8..43451bd056 100644 --- a/code/_onclick/drag_drop.dm +++ b/code/_onclick/drag_drop.dm @@ -95,9 +95,9 @@ if(mob) SEND_SIGNAL(mob, COMSIG_MOB_CLIENT_MOUSEMOVE, object, location, control, params) // god forgive me for i have sinned - used for autoparry. currently at 5 objects. - mousedOverObjects[object] = world.time - if(mousedOverObjects.len > 7) - mousedOverObjects.Cut(1, 2) + moused_over_objects[object] = world.time + if(moused_over_objects.len > 7) + moused_over_objects.Cut(1, 2) ..() /client/MouseDrag(src_object,atom/over_object,src_location,over_location,src_control,over_control,params) diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm index d01d3a1454..7fc7da2ef7 100644 --- a/code/datums/status_effects/debuffs.dm +++ b/code/datums/status_effects/debuffs.dm @@ -127,6 +127,13 @@ desc = "You've fallen asleep. Wait a bit and you should wake up. Unless you don't, considering how helpless you are." icon_state = "asleep" + +/datum/status_effect/grouped/stasis + id = "stasis" + duration = -1 + tick_interval = 10 + var/last_dead_time + /datum/status_effect/robotic_emp id = "emp_no_combat_mode" diff --git a/code/game/objects/items/devices/traitordevices.dm b/code/game/objects/items/devices/traitordevices.dm index 6e06a87ac3..ac79b3b887 100644 --- a/code/game/objects/items/devices/traitordevices.dm +++ b/code/game/objects/items/devices/traitordevices.dm @@ -85,7 +85,7 @@ effective or pretty fucking useless. /obj/item/healthanalyzer/rad_laser/attack(mob/living/M, mob/living/user) if(!stealth || !irradiate) return ..() - var/knowledge = SEND_SIGNAL(COMSIG_IDENTIFICATION_KNOWLEDGE_CHECK, user) == ID_COMPONENT_KNOWLEDGE_FULL + var/knowledge = SEND_SIGNAL(src, COMSIG_IDENTIFICATION_KNOWLEDGE_CHECK, user) == ID_COMPONENT_KNOWLEDGE_FULL if(!irradiate) return if(!used) diff --git a/code/modules/mob/living/living_active_parry.dm b/code/modules/mob/living/living_active_parry.dm index bdd6174314..e062a60aa8 100644 --- a/code/modules/mob/living/living_active_parry.dm +++ b/code/modules/mob/living/living_active_parry.dm @@ -35,6 +35,7 @@ return FALSE var/method = determined[1] data = return_block_parry_datum(determined[2]) + var/datum/tool = determined[3] var/full_parry_duration = data.parry_time_windup + data.parry_time_active + data.parry_time_spindown // no system in place to "fallback" if out of the 3 the top priority one can't parry due to constraints but something else can. // can always implement it later, whatever. @@ -224,7 +225,7 @@ /** * Attempts to automatically parry an attacker. */ -/mob/living/proc/attempt_auto_parry() +/mob/living/proc/attempt_auto_parry(atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list = list()) // determine how we'll parry var/list/determined = determine_parry_method(TRUE, TRUE) if(!islist(determined)) @@ -234,6 +235,16 @@ if(!data.parry_automatic_enabled) return FALSE // before doing anything, check if the user moused over them properly + if(!client) + return FALSE + var/found = FALSE + for(var/i in client.moused_over_objects) + if(i == object) + if((client.moused_over_objects[i] + (data.autoparry_mouse_delay_maximum SECONDS)) >= world.time) + found = TRUE + break + if(!found) + return FALSE // if that works, try to start parry // first, check cooldowns @@ -246,9 +257,11 @@ parry_start_time = world.time - data.parry_time_windup else parry_start_time = world.time - data.autoparry_sequence_start_time + return TRUE else // for single attack block - + #warn single attack block + return FALSE /** * Gets the stage of our parry sequence we're currently in. @@ -282,13 +295,17 @@ /// same return values as normal blocking, called with absolute highest priority in the block "chain". /mob/living/proc/run_parry(atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list = list(), allow_auto = TRUE) var/stage = get_parry_stage() + if(attack_type & ATTACK_TYPE_PARRY_COUNTERATTACK) + return BLOCK_NONE // don't infinite loop if(stage != PARRY_ACTIVE) // If they're not currently parrying, attempt auto parry - if((stage == NOT_PARRYING) && allow_auto && !SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE)) - return attempt_auto_parry() - return BLOCK_NONE + if(stage == NOT_PARRYING) + if(!allow_auto || SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE) || !attempt_auto_parry(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list)) + return BLOCK_NONE + else + return BLOCK_NONE var/datum/block_parry_data/data = get_parry_data() - if(attack_type && (!(attack_type & data.parry_attack_types) || (attack_type & ATTACK_TYPE_PARRY_COUNTERATTACK))) // if this attack is from a parry do not parry it lest we infinite loop. + if(attack_type && !(attack_type & data.parry_attack_types)) return BLOCK_NONE var/efficiency = data.get_parry_efficiency(attack_type, get_parry_time()) switch(parrying) diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm index 36fb160e0f..453f521575 100644 --- a/code/modules/mob/living/living_blocking_parrying.dm +++ b/code/modules/mob/living/living_blocking_parrying.dm @@ -97,7 +97,6 @@ GLOBAL_LIST_EMPTY(block_parry_data) // Other than for overrides, this mostly just reads from the above vars /// Can this item automatically block? var/block_automatic_enabled = TRUE -#warn have autoblock items warn user on pickup /// Directions that you can autoblock in. Null to default to normal directions. var/block_automatic_directions = null /// Effectiveness multiplier for automated block. Only applies to efficiency, absorption and limits stay the same! @@ -185,7 +184,6 @@ GLOBAL_LIST_EMPTY(block_parry_data) // Anything not specified like cooldowns/clickdelay respecting is pulled from above. /// Can this data automatically parry? This is off by default because this is something that requires thought to balance. var/parry_automatic_enabled = FALSE -#warn have autoparry items warn user on pickup /// Hard autoparry cooldown var/autoparry_cooldown_absolute = 3 SECONDS /// Autoparry : Simulate a parry sequence starting at a certain tick, or simply simulate a single attack parry? From eb2c12ceee9c518bb3f6255d4c39af8c495d9147 Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Mon, 26 Apr 2021 23:10:10 -0700 Subject: [PATCH 25/43] yell wip --- code/__HELPERS/game.dm | 14 ++++++++++++++ code/modules/mob/living/say.dm | 3 ++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index b9f180ac4a..745b12e84f 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -270,6 +270,20 @@ SEND_SIGNAL(A, COMSIG_ATOM_HEARER_IN_VIEW, processing, .) processing += A.contents +/proc/get_hearers_in_range(R, atom/source) + var/turf/T = get_turf(source) + . = list() + if(!T) + return + var/list/processing = range(R, source) + var/i = 0 + while(i < length(processing)) + var/atom/A = processing[++i] + if(A.flags_1 & HEAR_1) + . += A + SEND_SIGNAL(A, COMSIG_ATOM_HEARER_IN_VIEW, processing, .) + processing += A.contents + //viewers() but with a signal, for blacklisting. /proc/fov_viewers(depth = world.view, atom/center) if(!center) diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index cad1bdf1d6..2f90f04cef 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -311,7 +311,8 @@ GLOBAL_LIST_INIT(department_radio_keys, list( /atom/movable/proc/process_yelling(list/already_heard, rendered, atom/movable/speaker, datum/language/message_language, message, list/spans, message_mode, obj/source) var/list/overhearing = list() -#warn todo: yelling + overhearing = yelling_wavefill(src, 35) + overhearing = get_hearers_in_view(35, src) | get_hearers_in_range(5, src) overhearing -= already_heard for(var/_AM in overhearing) var/atom/movable/AM = _AM From a415453540887b5757b72bb7c3a2db874b6c6dcb Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Mon, 26 Apr 2021 23:29:37 -0700 Subject: [PATCH 26/43] ripping off my own code --- code/__HELPERS/yelling.dm | 134 ++++++++++++++++++ code/game/turfs/closed.dm | 9 +- code/game/turfs/turf.dm | 11 ++ .../modules/mob/living/living_active_parry.dm | 2 +- code/modules/mob/living/say.dm | 2 +- tgstation.dme | 1 + 6 files changed, 155 insertions(+), 4 deletions(-) create mode 100644 code/__HELPERS/yelling.dm diff --git a/code/__HELPERS/yelling.dm b/code/__HELPERS/yelling.dm new file mode 100644 index 0000000000..e9a2697c87 --- /dev/null +++ b/code/__HELPERS/yelling.dm @@ -0,0 +1,134 @@ +/datum/yelling_wavefill + var/stop = FALSE + var/list/atom/collected + +/datum/yelling_wavefill/Destroy(force, ...) + stop = TRUE + return ..() + +/datum/yelling_wavefill/proc/run(atom/source, dist = 50) + collected = list() + do_run(source, dist) + // gc + if(QDELETED(src)) + collected = null + +// blatantly copied from wave explosion code +/datum/yelling_wavefill/proc/do_run(atom/source, dist) + var/list/edges = list(source = (NORTH|SOUTH|EAST|WEST)) + var/list/powers = list(source = dist) + var/list/processed_last = list() + var/turf/T + var/turf/expanding + var/power + var/dir + var/returned +#define RUN_YELL(_T, _P, _D) \ + returned = max(powers[_T] - _T.get_yelling_resistance() - 1, 0); \ + _T.maptext = "[returned]"; + + var/list/turf/edges_next = list() + var/list/turf/powers_next = list() + var/list/turf/powers_returned = list() + var/list/turf/diagonals = list() + var/list/turf/diagonal_powers = list() + var/list/turf/diagonal_powers_max = list() + + while(edges.len) + // process cardinals + for(var/i in edges) + T = i + power = powers[T] + dir = edges[T] + RUN_YELL(T, power, dir) + powers_returned[T] = returned + if(returned) + // get hearing atoms + else + continue + + // diagonal power calc when multiple things hit one diagonal +#define CALCULATE_DIAGONAL_POWER(existing, adding, maximum) min(maximum, existing + adding) + // diagonal hitting cardinal expansion +#define CALCULATE_DIAGONAL_CROSS_POWER(existing, adding) max(existing, adding) + // insanity define to mark the next set of cardinals. +#define CARDINAL_MARK(ndir, cdir, edir) \ + if(edir & cdir) { \ + expanding = get_step(T,ndir); \ + if(expanding && !processed_last[expanding] && !edges[expanding]) { \ + powers_next[expanding] = max(powers_next[expanding], returned); \ + edges_next[expanding] = (cdir | edges_next[expanding]); \ + }; \ + }; + +#define DIAGONAL_SUBSTEP(ndir, cdir, edir) \ + expanding = get_step(T,ndir); \ + if(expanding && !processed_last[expanding] && !edges[expanding]) { \ + if(!edges_next[expanding]) { \ + diagonal_powers_max[expanding] = max(diagonal_powers_max[expanding], returned, powers[T]); \ + diagonal_powers[expanding] = CALCULATE_DIAGONAL_POWER(diagonal_powers[expanding], returned, diagonal_powers_max[expanding]); \ + diagonals[expanding] = (cdir | diagonals[expanding]); \ + }; \ + else { \ + powers_next[expanding] = CALCULATE_DIAGONAL_CROSS_POWER(powers_next[expanding], returned); \ + }; \ + }; + +#define DIAGONAL_MARK(ndir, cdir, edir) \ + if(edir & cdir) { \ + DIAGONAL_SUBSTEP(turn(ndir, 90), turn(cdir, 90), edir); \ + DIAGONAL_SUBSTEP(turn(ndir, -90), turn(cdir, -90), edir); \ + }; + CARDINAL_MARK(NORTH, NORTH, dir) + CARDINAL_MARK(SOUTH, SOUTH, dir) + CARDINAL_MARK(EAST, EAST, dir) + CARDINAL_MARK(WEST, WEST, dir) + CHECK_TICK + + // to_chat(world, "DEBUG: cycle mid edges_next [english_list_assoc(edges_next)]") + + // Sweep after cardinals for diagonals + for(var/i in edges) + T = i + power = powers[T] + dir = edges[T] + returned = powers_returned[T] + DIAGONAL_MARK(NORTH, NORTH, dir) + DIAGONAL_MARK(SOUTH, SOUTH, dir) + DIAGONAL_MARK(EAST, EAST, dir) + DIAGONAL_MARK(WEST, WEST, dir) + CHECK_TICK + + // to_chat(world, "DEBUG: cycle mid diagonals [english_list_assoc(diagonals)]") + + // Process diagonals: + for(var/i in diagonals) + T = i + power = diagonal_powers[T] + dir = diagonals[T] + RUN_YELL(T, power, dir) + if(!returned) + continue + CARDINAL_MARK(NORTH, NORTH, dir) + CARDINAL_MARK(SOUTH, SOUTH, dir) + CARDINAL_MARK(EAST, EAST, dir) + CARDINAL_MARK(WEST, WEST, dir) + CHECK_TICK + + // to_chat(world, "DEBUG: cycle end edges_next [english_list_assoc(edges_next)]") + + // flush lists + processed_last = edges + diagonals + edges = edges_next + powers = powers_next + +#undef RUN_YELL +#undef DIAGONAL_SUBSTEP +#undef DIAGONAL_MARK +#undef CARDINAL_MARK + +/proc/yelling_wavefill(atom/source, dist = 50) + var/datum/yelling_wavefill/Y = new + Y.run(source, dist) + return Y.collected || list() + diff --git a/code/game/turfs/closed.dm b/code/game/turfs/closed.dm index be0c444541..9c6dbf1912 100644 --- a/code/game/turfs/closed.dm +++ b/code/game/turfs/closed.dm @@ -6,6 +6,8 @@ blocks_air = 1 rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE rad_insulation = RAD_MEDIUM_INSULATION + /// How much we block yelling + var/yelling_resistance = 40 /turf/closed/Initialize() . = ..() @@ -198,16 +200,19 @@ desc = "A wall made out of a strange metal. The squares on it pulse in a predictable pattern." icon = 'icons/turf/walls/hierophant_wall.dmi' icon_state = "wall" - + /turf/closed/indestructible/rock/glacierrock name = "unaturally hard ice wall" desc = "Ice, hardened over thousands of years, you're not breaking through this." icon = 'icons/turf/walls.dmi' icon_state = "snow_rock" - + /turf/closed/indestructible/rock/glacierrock/blue name = "blue ice wall" desc = "The incredible compressive forces that formed this sturdy ice wall gave it a blue color." icon = 'icons/turf/walls.dmi' icon_state = "ice" canSmoothWith = list(/turf/closed/indestructible/rock/glacierrock/blue) + +/turf/closed/get_yelling_resistance() + return yelling_resistance diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 0808408192..7e61364e2a 100755 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -594,3 +594,14 @@ GLOBAL_LIST_EMPTY(station_turfs) . = ..() if(. != BULLET_ACT_FORCE_PIERCE) . = BULLET_ACT_TURF + +/turf/proc/get_yelling_resistance() + . = 0 + // don't bother checking fulltile, we don't need accuracy + var/obj/structure/window/W = locate() in src + if(W) + . += 7 + for(var/obj/machinery/door/D in src) + if(!D.density) + continue + . += D.opacity? 7 : 15 diff --git a/code/modules/mob/living/living_active_parry.dm b/code/modules/mob/living/living_active_parry.dm index e062a60aa8..32bc5fd59d 100644 --- a/code/modules/mob/living/living_active_parry.dm +++ b/code/modules/mob/living/living_active_parry.dm @@ -46,7 +46,7 @@ // Point of no return, make sure everything is set. parrying = method if(method == ITEM_PARRY) - active_parry_item = using_item + active_parry_item = tool if(!UseStaminaBuffer(data.parry_stamina_cost, TRUE)) return FALSE parry_start_time = world.time diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index 2f90f04cef..949a47e50c 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -312,7 +312,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list( /atom/movable/proc/process_yelling(list/already_heard, rendered, atom/movable/speaker, datum/language/message_language, message, list/spans, message_mode, obj/source) var/list/overhearing = list() overhearing = yelling_wavefill(src, 35) - overhearing = get_hearers_in_view(35, src) | get_hearers_in_range(5, src) + // overhearing = get_hearers_in_view(35, src) | get_hearers_in_range(5, src) overhearing -= already_heard for(var/_AM in overhearing) var/atom/movable/AM = _AM diff --git a/tgstation.dme b/tgstation.dme index 017bd393e7..30229b1cda 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -199,6 +199,7 @@ #include "code\__HELPERS\vector.dm" #include "code\__HELPERS\verbs.dm" #include "code\__HELPERS\view.dm" +#include "code\__HELPERS\yelling.dm" #include "code\__HELPERS\sorts\__main.dm" #include "code\__HELPERS\sorts\InsertSort.dm" #include "code\__HELPERS\sorts\MergeSort.dm" From 1585d1c2be0bb483ca979d579b816fb1c6adb1c5 Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Mon, 26 Apr 2021 23:32:33 -0700 Subject: [PATCH 27/43] fixes --- code/__HELPERS/yelling.dm | 37 ++++++++++--------- code/modules/mining/equipment/survival_pod.dm | 2 +- .../modules/mob/living/living_active_parry.dm | 1 - .../projectiles/ammunition/energy/stun.dm | 3 +- .../{ballistic => energy}/laser_gatling.dm | 1 - .../reagents/reagent_containers/spray.dm | 5 +-- 6 files changed, 23 insertions(+), 26 deletions(-) rename code/modules/projectiles/guns/{ballistic => energy}/laser_gatling.dm (99%) diff --git a/code/__HELPERS/yelling.dm b/code/__HELPERS/yelling.dm index e9a2697c87..cf8ca52417 100644 --- a/code/__HELPERS/yelling.dm +++ b/code/__HELPERS/yelling.dm @@ -6,7 +6,7 @@ stop = TRUE return ..() -/datum/yelling_wavefill/proc/run(atom/source, dist = 50) +/datum/yelling_wavefill/proc/run_wavefill(atom/source, dist = 50) collected = list() do_run(source, dist) // gc @@ -14,6 +14,7 @@ collected = null // blatantly copied from wave explosion code +// check explosion2.dm for what this does and how it works. /datum/yelling_wavefill/proc/do_run(atom/source, dist) var/list/edges = list(source = (NORTH|SOUTH|EAST|WEST)) var/list/powers = list(source = dist) @@ -34,24 +35,8 @@ var/list/turf/diagonal_powers = list() var/list/turf/diagonal_powers_max = list() - while(edges.len) - // process cardinals - for(var/i in edges) - T = i - power = powers[T] - dir = edges[T] - RUN_YELL(T, power, dir) - powers_returned[T] = returned - if(returned) - // get hearing atoms - else - continue - - // diagonal power calc when multiple things hit one diagonal #define CALCULATE_DIAGONAL_POWER(existing, adding, maximum) min(maximum, existing + adding) - // diagonal hitting cardinal expansion #define CALCULATE_DIAGONAL_CROSS_POWER(existing, adding) max(existing, adding) - // insanity define to mark the next set of cardinals. #define CARDINAL_MARK(ndir, cdir, edir) \ if(edir & cdir) { \ expanding = get_step(T,ndir); \ @@ -79,6 +64,22 @@ DIAGONAL_SUBSTEP(turn(ndir, 90), turn(cdir, 90), edir); \ DIAGONAL_SUBSTEP(turn(ndir, -90), turn(cdir, -90), edir); \ }; + + while(edges.len) + // to_chat(world, "DEBUG: cycle start edges [english_list_assoc(edges)]") + + // process cardinals + for(var/i in edges) + T = i + power = powers[T] + dir = edges[T] + RUN_YELL(T, power, dir) + powers_returned[T] = returned + if(returned) + // get hearing atoms + else + continue + CARDINAL_MARK(NORTH, NORTH, dir) CARDINAL_MARK(SOUTH, SOUTH, dir) CARDINAL_MARK(EAST, EAST, dir) @@ -129,6 +130,6 @@ /proc/yelling_wavefill(atom/source, dist = 50) var/datum/yelling_wavefill/Y = new - Y.run(source, dist) + Y.run_wavefill(source, dist) return Y.collected || list() diff --git a/code/modules/mining/equipment/survival_pod.dm b/code/modules/mining/equipment/survival_pod.dm index fff971c953..777f1bfc3b 100644 --- a/code/modules/mining/equipment/survival_pod.dm +++ b/code/modules/mining/equipment/survival_pod.dm @@ -299,7 +299,7 @@ /obj/item/energy_katana, /obj/item/hierophant_club, /obj/item/his_grace, - /obj/item/gun/ballistic/minigun, + /obj/item/gun/energy/minigun, /obj/item/gun/ballistic/automatic/l6_saw, /obj/item/gun/magic/staff/chaos, /obj/item/gun/magic/staff/spellblade, diff --git a/code/modules/mob/living/living_active_parry.dm b/code/modules/mob/living/living_active_parry.dm index 32bc5fd59d..57866bacbe 100644 --- a/code/modules/mob/living/living_active_parry.dm +++ b/code/modules/mob/living/living_active_parry.dm @@ -230,7 +230,6 @@ var/list/determined = determine_parry_method(TRUE, TRUE) if(!islist(determined)) return FALSE - var/method = determined[1] var/datum/block_parry_data/data = return_block_parry_datum(determined[2]) if(!data.parry_automatic_enabled) return FALSE diff --git a/code/modules/projectiles/ammunition/energy/stun.dm b/code/modules/projectiles/ammunition/energy/stun.dm index aa889c10bf..cb7f80d949 100644 --- a/code/modules/projectiles/ammunition/energy/stun.dm +++ b/code/modules/projectiles/ammunition/energy/stun.dm @@ -10,7 +10,7 @@ e_cost = 100 /obj/item/ammo_casing/energy/electrode/hos - projectile_type = /obj/item/projectile/energy/electrode/hos + projectile_type = /obj/item/projectile/energy/electrode/security/hos e_cost = 100 /obj/item/ammo_casing/energy/electrode/spec @@ -20,7 +20,6 @@ fire_sound = 'sound/weapons/gunshot.ogg' e_cost = 100 - /obj/item/ammo_casing/energy/electrode/old e_cost = 1000 diff --git a/code/modules/projectiles/guns/ballistic/laser_gatling.dm b/code/modules/projectiles/guns/energy/laser_gatling.dm similarity index 99% rename from code/modules/projectiles/guns/ballistic/laser_gatling.dm rename to code/modules/projectiles/guns/energy/laser_gatling.dm index 2abb7b720f..716cc6f31d 100644 --- a/code/modules/projectiles/guns/ballistic/laser_gatling.dm +++ b/code/modules/projectiles/guns/energy/laser_gatling.dm @@ -90,7 +90,6 @@ update_icon() user.update_inv_back() - /obj/item/gun/energy/minigun name = "laser gatling gun" desc = "An advanced laser cannon with an incredible rate of fire. Requires a bulky backpack power source to use." diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index 3f62829b32..de4151a82d 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -76,6 +76,8 @@ var/wait_step = CEILING(spray_delay * INVERSE(range), world.tick_lag) var/obj/effect/decal/chempuff/D = new /obj/effect/decal/chempuff(get_turf(src), stream_mode, wait_step, range, stream_mode? 1 : range) var/turf/T = get_turf(src) + if(!T) + return log_reagent("SPRAY: [key_name(usr)] fired [src] ([REF(src)]) [COORD(T)] at [A] ([REF(A)]) [COORD(A)] (chempuff: [D.reagents.log_list()])") D.create_reagents(amount_per_transfer_from_this, NONE, NO_REAGENTS_VALUE) if(stream_mode) @@ -83,9 +85,6 @@ else reagents.trans_to(D, amount_per_transfer_from_this, 1/range) D.color = mix_color_from_reagents(D.reagents.reagent_list) - var/turf/T = get_turf(src) - if(!T) - return last_spray = world.time D.run(A) From d547aa7ff1db5cb955dea4d36f82e9eb49c07ea9 Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Mon, 26 Apr 2021 23:37:26 -0700 Subject: [PATCH 28/43] almost compiling --- code/__HELPERS/yelling.dm | 2 +- code/game/objects/effects/decals/misc.dm | 2 +- code/modules/reagents/reagent_containers/spray.dm | 2 +- tgstation.dme | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/code/__HELPERS/yelling.dm b/code/__HELPERS/yelling.dm index cf8ca52417..d4d6e5ac95 100644 --- a/code/__HELPERS/yelling.dm +++ b/code/__HELPERS/yelling.dm @@ -25,7 +25,7 @@ var/dir var/returned #define RUN_YELL(_T, _P, _D) \ - returned = max(powers[_T] - _T.get_yelling_resistance() - 1, 0); \ + returned = max(_P - _T.get_yelling_resistance() - 1, 0); \ _T.maptext = "[returned]"; var/list/turf/edges_next = list() diff --git a/code/game/objects/effects/decals/misc.dm b/code/game/objects/effects/decals/misc.dm index 7ed90253c8..6b90cfd62c 100644 --- a/code/game/objects/effects/decals/misc.dm +++ b/code/game/objects/effects/decals/misc.dm @@ -58,7 +58,7 @@ . = ..() hit_thing(AM) -/obj/effect/decal/chempuff/proc/run(atom/target) +/obj/effect/decal/chempuff/proc/run_puff(atom/target) set waitfor = FALSE for(var/i in 1 to range) range_left-- diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index de4151a82d..b90815d543 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -86,7 +86,7 @@ reagents.trans_to(D, amount_per_transfer_from_this, 1/range) D.color = mix_color_from_reagents(D.reagents.reagent_list) last_spray = world.time - D.run(A) + D.run_puff(A) /obj/item/reagent_containers/spray/attack_self(mob/user) stream_mode = !stream_mode diff --git a/tgstation.dme b/tgstation.dme index 30229b1cda..f7069d4783 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -3111,7 +3111,6 @@ #include "code\modules\projectiles\guns\ballistic\automatic.dm" #include "code\modules\projectiles\guns\ballistic\bow.dm" #include "code\modules\projectiles\guns\ballistic\derringer.dm" -#include "code\modules\projectiles\guns\ballistic\laser_gatling.dm" #include "code\modules\projectiles\guns\ballistic\launchers.dm" #include "code\modules\projectiles\guns\ballistic\magweapon.dm" #include "code\modules\projectiles\guns\ballistic\pistol.dm" @@ -3122,6 +3121,7 @@ #include "code\modules\projectiles\guns\energy\energy_gun.dm" #include "code\modules\projectiles\guns\energy\kinetic_accelerator.dm" #include "code\modules\projectiles\guns\energy\laser.dm" +#include "code\modules\projectiles\guns\energy\laser_gatling.dm" #include "code\modules\projectiles\guns\energy\megabuster.dm" #include "code\modules\projectiles\guns\energy\mounted.dm" #include "code\modules\projectiles\guns\energy\plasma_cit.dm" From a60f801f69c1031bbf4cc38a326c06fa7579e803 Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Wed, 12 May 2021 04:23:53 -0700 Subject: [PATCH 29/43] e --- code/modules/mob/living/living_active_parry.dm | 3 ++- code/modules/mob/living/living_blocking_parrying.dm | 4 ---- code/modules/mob/living/living_defines.dm | 2 ++ 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/code/modules/mob/living/living_active_parry.dm b/code/modules/mob/living/living_active_parry.dm index 57866bacbe..d8f5edefb8 100644 --- a/code/modules/mob/living/living_active_parry.dm +++ b/code/modules/mob/living/living_active_parry.dm @@ -231,7 +231,7 @@ if(!islist(determined)) return FALSE var/datum/block_parry_data/data = return_block_parry_datum(determined[2]) - if(!data.parry_automatic_enabled) + if(!data.parry_automatic_enabled || (last_autoparry > (world.time + data.autoparry_cooldown_absolute))) return FALSE // before doing anything, check if the user moused over them properly if(!client) @@ -249,6 +249,7 @@ // first, check cooldowns // now, depending on if we're doing a single simulation or a full sequence + last_autoparry = world.time if(data.autoparry_sequence_simulation) // for full sequence simulation initiate_parry_sequence(TRUE, determined) diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm index 453f521575..d32ef5a2ac 100644 --- a/code/modules/mob/living/living_blocking_parrying.dm +++ b/code/modules/mob/living/living_blocking_parrying.dm @@ -189,10 +189,6 @@ GLOBAL_LIST_EMPTY(block_parry_data) /// Autoparry : Simulate a parry sequence starting at a certain tick, or simply simulate a single attack parry? var/autoparry_sequence_simulation = FALSE // Single attack simulation: - /// Parry cooldown to inflict on single-attack autoparry - var/autoparry_single_parry_cooldown = 3 SECONDS - /// Clickdelay to inflict on single-attack autoparry - var/autoparry_single_click_cooldown = 0 /// Single attack autoparry - efficiency var/autoparry_single_efficiency = 75 /// Single attack autoparry - efficiency overrides by attack type, see above diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index 14acf72f57..94f4ff60a3 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -50,6 +50,8 @@ var/obj/effect/abstract/parry/parry_visual_effect /// world.time of last parry end var/parry_end_time_last = 0 + /// Last autoparry + var/last_autoparry = 0 /// Successful parries within the current parry cycle. It's a list of efficiency percentages. var/list/successful_parries /// Current parry counterattacks. Makes sure we can only counterattack someone once per parry. From 2d763a9ab307c9f2ed382a485da7819f881bdf8b Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Mon, 7 Jun 2021 16:37:19 -0700 Subject: [PATCH 30/43] auto --- code/modules/mob/living/living_active_parry.dm | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/code/modules/mob/living/living_active_parry.dm b/code/modules/mob/living/living_active_parry.dm index d8f5edefb8..2b4b0ecbac 100644 --- a/code/modules/mob/living/living_active_parry.dm +++ b/code/modules/mob/living/living_active_parry.dm @@ -229,13 +229,13 @@ // determine how we'll parry var/list/determined = determine_parry_method(TRUE, TRUE) if(!islist(determined)) - return FALSE + return BLOCK_NONE var/datum/block_parry_data/data = return_block_parry_datum(determined[2]) if(!data.parry_automatic_enabled || (last_autoparry > (world.time + data.autoparry_cooldown_absolute))) - return FALSE + return BLOCK_NONE // before doing anything, check if the user moused over them properly if(!client) - return FALSE + return BLOCK_NONE var/found = FALSE for(var/i in client.moused_over_objects) if(i == object) @@ -243,7 +243,7 @@ found = TRUE break if(!found) - return FALSE + return BLOCK_NONE // if that works, try to start parry // first, check cooldowns @@ -257,7 +257,8 @@ parry_start_time = world.time - data.parry_time_windup else parry_start_time = world.time - data.autoparry_sequence_start_time - return TRUE + // recurse back to original + return run_parry(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, FALSE) else // for single attack block #warn single attack block @@ -300,8 +301,8 @@ if(stage != PARRY_ACTIVE) // If they're not currently parrying, attempt auto parry if(stage == NOT_PARRYING) - if(!allow_auto || SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE) || !attempt_auto_parry(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list)) - return BLOCK_NONE + if(!allow_auto || SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE)) + return attempt_auto_parry(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list) else return BLOCK_NONE var/datum/block_parry_data/data = get_parry_data() From d67c4d9fa889da263c8baca1c8037fbdc21e94fc Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Mon, 7 Jun 2021 16:45:51 -0700 Subject: [PATCH 31/43] hacky --- .../modules/mob/living/living_active_parry.dm | 67 ++++++++++++++++--- 1 file changed, 57 insertions(+), 10 deletions(-) diff --git a/code/modules/mob/living/living_active_parry.dm b/code/modules/mob/living/living_active_parry.dm index 2b4b0ecbac..b0e1f7d9ef 100644 --- a/code/modules/mob/living/living_active_parry.dm +++ b/code/modules/mob/living/living_active_parry.dm @@ -195,17 +195,17 @@ /** * Called when an attack is parried using this, whether or not the parry was successful. */ -/obj/item/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time) +/obj/item/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time, autoparry = FALSE) /** * Called when an attack is parried innately, whether or not the parry was successful. */ -/mob/living/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time) +/mob/living/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time, autoparry = FALSE) /** * Called when an attack is parried using this, whether or not the parry was successful. */ -/datum/martial_art/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time) +/datum/martial_art/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time, autoparry = FALSE) /** * Called when an attack is parried and block_parra_data indicates to use a proc to handle counterattack. @@ -233,6 +233,8 @@ var/datum/block_parry_data/data = return_block_parry_datum(determined[2]) if(!data.parry_automatic_enabled || (last_autoparry > (world.time + data.autoparry_cooldown_absolute))) return BLOCK_NONE + if(attack_type && !(attack_type & data.parry_attack_types)) + return BLOCK_NONE // before doing anything, check if the user moused over them properly if(!client) return BLOCK_NONE @@ -260,9 +262,52 @@ // recurse back to original return run_parry(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, FALSE) else - // for single attack block - #warn single attack block - return FALSE + // yes, this is mostly a copypaste of run_parry. + var/efficiency = data.attack_type_list_scan(data.autoparry_single_efficiency_override, attack_type) + if(isnull(efficiency)) + efficiency = data.autoparry_single_efficiency + var/method = determined[1] + switch(parrying) + if(ITEM_PARRY) + var/obj/item/I = determined[3] + . = I.on_active_parry(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency, null, TRUE) + if(UNARMED_PARRY) + . = on_active_parry(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency, null, TRUE) + if(MARTIAL_PARRY) + . = mind.martial_art.on_active_parry(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency, null, TRUE) + if(!isnull(return_list[BLOCK_RETURN_OVERRIDE_PARRY_EFFICIENCY])) // one of our procs overrode + efficiency = return_list[BLOCK_RETURN_OVERRIDE_PARRY_EFFICIENCY] + if(efficiency <= 0) // Do not allow automatically handled/standardized parries that increase damage for now. + return + . |= BLOCK_SHOULD_PARTIAL_MITIGATE + if(efficiency >= data.parry_efficiency_perfect) + . |= data.perfect_parry_block_return_flags + if(data.perfect_parry_block_return_list) + return_list |= data.perfect_parry_block_return_list + else if(efficiency >= data.parry_efficiency_considered_successful) + . |= data.imperfect_parry_block_return_flags + if(data.imperfect_parry_block_return_list) + return_list |= data.imperfect_parry_block_return_list + else + . |= data.failed_parry_block_return_flags + if(data.failed_parry_block_return_list) + return_list |= data.failed_parry_block_return_list + if(isnull(return_list[BLOCK_RETURN_MITIGATION_PERCENT])) // if one of the on_active_parry procs overrode. We don't have to worry about interference since parries are the first thing checked in the [do_run_block()] sequence. + return_list[BLOCK_RETURN_MITIGATION_PERCENT] = clamp(efficiency, 0, 100) // do not allow > 100% or < 0% for now. + if((return_list[BLOCK_RETURN_MITIGATION_PERCENT] >= 100) || (damage <= 0)) + . |= BLOCK_SUCCESS + var/list/effect_text + var/pacifist_counter_check = TRUE + if(HAS_TRAIT(src, TRAIT_PACIFISM)) + switch(parrying) + if(ITEM_PARRY) + pacifist_counter_check = (!active_parry_item.force || active_parry_item.damtype == STAMINA) + else + pacifist_counter_check = FALSE //Both martial and unarmed counter attacks generally are harmful, so no need to have the same line twice. + if(efficiency >= data.parry_efficiency_to_counterattack && pacifist_counter_check && !return_list[BLOCK_RETURN_FORCE_NO_PARRY_COUNTERATTACK] && (!(attacker in successful_parry_counterattacks) && !data.parry_allow_repeated_counterattacks)) + effect_text = run_parry_countereffects(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency, data) + if(data.parry_flags & PARRY_DEFAULT_HANDLE_FEEDBACK) + handle_parry_feedback(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency, effect_text) /** * Gets the stage of our parry sequence we're currently in. @@ -355,8 +400,9 @@ if(length(successful_parries) >= data.parry_max_attacks) end_parry_sequence() -/mob/living/proc/handle_parry_feedback(atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list = list(), parry_efficiency, list/effect_text) - var/datum/block_parry_data/data = get_parry_data() +/mob/living/proc/handle_parry_feedback(atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list = list(), parry_efficiency, list/effect_text, datum/block_parry_data/data) + if(!data) + data = get_parry_data() var/knockdown_check = FALSE if(data.parry_data[PARRY_KNOCKDOWN_ATTACKER] && parry_efficiency >= data.parry_efficiency_to_counterattack) knockdown_check = TRUE @@ -365,11 +411,12 @@ visible_message("[src] parries [attack_text][length(effect_text)? ", [english_list(effect_text)] [attacker]" : ""][length(effect_text) && knockdown_check? " and" : ""][knockdown_check? " knocking them to the ground" : ""]!") /// Run counterattack if any -/mob/living/proc/run_parry_countereffects(atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list = list(), parry_efficiency) +/mob/living/proc/run_parry_countereffects(atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list = list(), parry_efficiency, datum/block_parry_data/data) if(!isliving(attacker)) return var/mob/living/L = attacker - var/datum/block_parry_data/data = get_parry_data() + if(!data) + data = get_parry_data() var/list/effect_text = list() successful_parry_counterattacks |= attacker // Always proc so items can override behavior easily From b3382a8fe22351d10b0bddb77af3fea784d09f2c Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Mon, 7 Jun 2021 16:49:27 -0700 Subject: [PATCH 32/43] local testing time --- code/__HELPERS/yelling.dm | 2 ++ code/datums/explosion2.dm | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/code/__HELPERS/yelling.dm b/code/__HELPERS/yelling.dm index d4d6e5ac95..6fc9cd7846 100644 --- a/code/__HELPERS/yelling.dm +++ b/code/__HELPERS/yelling.dm @@ -125,6 +125,8 @@ #undef RUN_YELL #undef DIAGONAL_SUBSTEP +#undef CALCULATE_DIAGONAL_POWER +#undef CALCULATE_DIAGONAL_CROSS_POWER #undef DIAGONAL_MARK #undef CARDINAL_MARK diff --git a/code/datums/explosion2.dm b/code/datums/explosion2.dm index 75f65e4b23..9a9f2b40cf 100644 --- a/code/datums/explosion2.dm +++ b/code/datums/explosion2.dm @@ -372,6 +372,10 @@ #undef WEX_ACT +#undef CALCULATE_DIAGONAL_POWER +#undef CALCULATE_DIAGONAL_CROSS_POWER +#undef CARDINAL_MARK_NOCHECK + #undef DIAGONAL_SUBSTEP #undef DIAGONAL_MARK #undef CARDINAL_MARK From 1a800cc470e3e8e469549e1abdfba708e6d96be8 Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Mon, 7 Jun 2021 19:40:16 -0700 Subject: [PATCH 33/43] modifications --- code/__HELPERS/yelling.dm | 6 ++++-- code/game/objects/items/dualsaber.dm | 2 -- code/game/objects/items/electrostaff.dm | 1 - code/game/objects/items/melee/energy.dm | 3 +++ code/game/objects/items/melee/misc.dm | 1 - code/game/objects/items/shields.dm | 7 +++++-- code/game/objects/items/weaponry.dm | 2 -- .../clock_weapons/ratvarian_spear.dm | 1 - code/modules/clothing/gloves/miscellaneous.dm | 5 ++--- .../mining/equipment/kinetic_crusher.dm | 1 - code/modules/mob/living/living_active_parry.dm | 18 ++++++++++-------- .../mob/living/living_blocking_parrying.dm | 6 +++--- code/modules/smithing/finished_items.dm | 3 ++- 13 files changed, 29 insertions(+), 27 deletions(-) diff --git a/code/__HELPERS/yelling.dm b/code/__HELPERS/yelling.dm index 6fc9cd7846..6987aef262 100644 --- a/code/__HELPERS/yelling.dm +++ b/code/__HELPERS/yelling.dm @@ -16,8 +16,10 @@ // blatantly copied from wave explosion code // check explosion2.dm for what this does and how it works. /datum/yelling_wavefill/proc/do_run(atom/source, dist) - var/list/edges = list(source = (NORTH|SOUTH|EAST|WEST)) - var/list/powers = list(source = dist) + var/list/edges = list() + edges[source] = (NORTH|SOUTH|EAST|WEST) + var/list/powers = list() + powers[source] = dist var/list/processed_last = list() var/turf/T var/turf/expanding diff --git a/code/game/objects/items/dualsaber.dm b/code/game/objects/items/dualsaber.dm index 5ae79b3c3a..eea189c3be 100644 --- a/code/game/objects/items/dualsaber.dm +++ b/code/game/objects/items/dualsaber.dm @@ -71,7 +71,6 @@ parry_imperfect_falloff_percent = 10 parry_efficiency_considered_successful = 25 // VERY generous parry_failed_stagger_duration = 3 SECONDS - parry_failed_clickcd_duration = CLICK_CD_MELEE /obj/item/dualsaber/directional_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, override_direction) if((attack_type & ATTACK_TYPE_PROJECTILE) && is_energy_reflectable_projectile(object)) @@ -374,7 +373,6 @@ TEXT_ATTACK_TYPE_PROJECTILE = 30, ) parry_failed_stagger_duration = 3 SECONDS - parry_failed_clickcd_duration = 2 SECONDS /obj/item/dualsaber/hypereutactic/chaplain/ComponentInitialize() . = ..() diff --git a/code/game/objects/items/electrostaff.dm b/code/game/objects/items/electrostaff.dm index 2828841b22..9bb12d18b8 100644 --- a/code/game/objects/items/electrostaff.dm +++ b/code/game/objects/items/electrostaff.dm @@ -62,7 +62,6 @@ ) // not extremely punishing to fail, but no spamming the parry. parry_failed_stagger_duration = 1.5 SECONDS - parry_failed_clickcd_duration = 1 SECONDS /obj/item/electrostaff/Initialize(mapload) . = ..() diff --git a/code/game/objects/items/melee/energy.dm b/code/game/objects/items/melee/energy.dm index f1201dca4f..1be570b62b 100644 --- a/code/game/objects/items/melee/energy.dm +++ b/code/game/objects/items/melee/energy.dm @@ -126,6 +126,9 @@ parry_efficiency_perfect = 100 parry_failed_stagger_duration = 4 SECONDS parry_cooldown = 0.5 SECONDS + parry_automatic_enabled = TRUE + autoparry_single_efficiency = 65 + autoparry_cooldown_absolute = 3 SECONDS /obj/item/melee/transforming/energy/sword/Initialize(mapload) . = ..() diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm index a981ad98a0..6278eb5f36 100644 --- a/code/game/objects/items/melee/misc.dm +++ b/code/game/objects/items/melee/misc.dm @@ -194,7 +194,6 @@ parry_efficiency_perfect = 100 parry_stamina_cost = 5 parry_failed_stagger_duration = 2 SECONDS - parry_failed_clickcd_duration = CLICK_CD_RANGE parry_cooldown = 0 /obj/item/melee/rapier/active_parry_reflex_counter(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list, parry_efficiency, list/effect_text) diff --git a/code/game/objects/items/shields.dm b/code/game/objects/items/shields.dm index d5b3674564..9aed545509 100644 --- a/code/game/objects/items/shields.dm +++ b/code/game/objects/items/shields.dm @@ -34,6 +34,10 @@ block_damage_absorption = 5 block_resting_stamina_penalty_multiplier = 2 block_projectile_mitigation = 75 + block_damage_absorption_override = list( + TEXT_ATTACK_TYPE_TACKLE = INFINITY, + TEXT_ATTACK_TYPE_THROWN = 10 + ) /obj/item/shield/examine(mob/user) . = ..() @@ -374,11 +378,10 @@ /obj/item/shield/riot/flash/on_shield_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return) . = ..() - if (. && !embedded_flash.crit_fail) + if (. && damage && !embedded_flash.crit_fail) embedded_flash.activate() update_icon() - /obj/item/shield/riot/flash/attackby(obj/item/W, mob/user) if(istype(W, /obj/item/assembly/flash/handheld)) var/obj/item/assembly/flash/handheld/flash = W diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index 4ee9427ec8..37bdc33659 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -364,7 +364,6 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 parry_time_perfect = 2.5 // however... parry_time_perfect_leeway = 2 // the entire time, the parry is perfect parry_failed_stagger_duration = 1 SECONDS - parry_failed_clickcd_duration = 1 SECONDS // more forgiving punishments for missed parries // still, don't fucking miss your parries or you're down stamina and staggered to shit /datum/block_parry_data/bokken/quick_parry/proj @@ -481,7 +480,6 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 parry_time_perfect = 1 parry_time_perfect_leeway = 1 parry_failed_stagger_duration = 1 SECONDS - parry_failed_clickcd_duration = 1 SECONDS /datum/block_parry_data/bokken/waki/quick_parry/proj parry_efficiency_perfect_override = list() diff --git a/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_spear.dm b/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_spear.dm index d0f63ac887..b702b19566 100644 --- a/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_spear.dm +++ b/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_spear.dm @@ -93,4 +93,3 @@ parry_efficiency_to_counterattack = 110 parry_cooldown = 15 //But also very low cooldown.. parry_failed_stagger_duration = 2 SECONDS //And relatively small penalties for failing. - parry_failed_clickcd_duration = 1 SECONDS diff --git a/code/modules/clothing/gloves/miscellaneous.dm b/code/modules/clothing/gloves/miscellaneous.dm index a337439931..d96ded67d2 100644 --- a/code/modules/clothing/gloves/miscellaneous.dm +++ b/code/modules/clothing/gloves/miscellaneous.dm @@ -224,10 +224,9 @@ parry_efficiency_considered_successful = 0.01 parry_efficiency_to_counterattack = INFINITY // no auto counter parry_max_attacks = INFINITY - parry_failed_cooldown_duration = 2.25 SECONDS - parry_failed_stagger_duration = 2.25 SECONDS + parry_failed_cooldown_duration = 1.5 SECONDS + parry_failed_stagger_duration = 1.5 SECONDS parry_cooldown = 0 - parry_failed_clickcd_duration = 0 /obj/item/clothing/gloves/fingerless/pugilist/mauler name = "mauler gauntlets" diff --git a/code/modules/mining/equipment/kinetic_crusher.dm b/code/modules/mining/equipment/kinetic_crusher.dm index 859ea58d26..ddec9232ce 100644 --- a/code/modules/mining/equipment/kinetic_crusher.dm +++ b/code/modules/mining/equipment/kinetic_crusher.dm @@ -196,7 +196,6 @@ parry_imperfect_falloff_percent = 20 parry_efficiency_to_counterattack = 100 // perfect parry or you're cringe parry_failed_stagger_duration = 1.5 SECONDS // a good time to reconsider your actions... - parry_failed_clickcd_duration = 1.5 SECONDS // or your failures /obj/item/kinetic_crusher/glaive/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time) // if you're dumb enough to go for a parry... var/turf/proj_turf = owner.loc // destabilizer bolt, ignoring cooldown diff --git a/code/modules/mob/living/living_active_parry.dm b/code/modules/mob/living/living_active_parry.dm index b0e1f7d9ef..a673b81203 100644 --- a/code/modules/mob/living/living_active_parry.dm +++ b/code/modules/mob/living/living_active_parry.dm @@ -238,12 +238,13 @@ // before doing anything, check if the user moused over them properly if(!client) return BLOCK_NONE - var/found = FALSE - for(var/i in client.moused_over_objects) - if(i == object) - if((client.moused_over_objects[i] + (data.autoparry_mouse_delay_maximum SECONDS)) >= world.time) - found = TRUE - break + var/found = attacker == client.mouseObject + if(!found) + for(var/i in client.moused_over_objects) + if(i == object) + if((client.moused_over_objects[i] + (data.autoparry_mouse_delay_maximum)) >= world.time) + found = TRUE + break if(!found) return BLOCK_NONE @@ -267,7 +268,7 @@ if(isnull(efficiency)) efficiency = data.autoparry_single_efficiency var/method = determined[1] - switch(parrying) + switch(method) if(ITEM_PARRY) var/obj/item/I = determined[3] . = I.on_active_parry(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency, null, TRUE) @@ -347,7 +348,8 @@ // If they're not currently parrying, attempt auto parry if(stage == NOT_PARRYING) if(!allow_auto || SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE)) - return attempt_auto_parry(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list) + return BLOCK_NONE + return attempt_auto_parry(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list) else return BLOCK_NONE var/datum/block_parry_data/data = get_parry_data() diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm index d32ef5a2ac..3a828e0c81 100644 --- a/code/modules/mob/living/living_blocking_parrying.dm +++ b/code/modules/mob/living/living_blocking_parrying.dm @@ -108,7 +108,7 @@ GLOBAL_LIST_EMPTY(block_parry_data) /// Priority for [mob/do_run_block()] while we're being used to parry. // None - Parry is always highest priority! /// Parry doesn't work if you aren't able to otherwise attack due to clickdelay - var/parry_respect_clickdelay = TRUE + var/parry_respect_clickdelay = FALSE /// Parry stamina cost var/parry_stamina_cost = 5 /// Attack types we can block @@ -164,7 +164,7 @@ GLOBAL_LIST_EMPTY(block_parry_data) /// Stagger duration post-parry if you fail to parry an attack var/parry_failed_stagger_duration = 3.5 SECONDS /// Clickdelay duration post-parry if you fail to parry an attack - var/parry_failed_clickcd_duration = 2 SECONDS + var/parry_failed_clickcd_duration = 0 SECONDS /// Parry cooldown post-parry if failed. This is ADDED to parry_cooldown!!! var/parry_failed_cooldown_duration = 0 SECONDS @@ -199,7 +199,7 @@ GLOBAL_LIST_EMPTY(block_parry_data) // Clickdelay/cooldown settings not included, as well as whether or not to lock attack/sprinting/etc. They will be pulled from the above. /// ADVANCED - Autoparry requirement for time since last moused over for a specific object - var/autoparry_mouse_delay_maximum = 0.5 + var/autoparry_mouse_delay_maximum = 0.5 SECONDS /** * Quirky proc to get average of flags in list that are in attack_type because why is attack_type a flag. diff --git a/code/modules/smithing/finished_items.dm b/code/modules/smithing/finished_items.dm index 06953f462c..27be8c034d 100644 --- a/code/modules/smithing/finished_items.dm +++ b/code/modules/smithing/finished_items.dm @@ -266,7 +266,6 @@ parry_time_perfect = 2 parry_time_perfect_leeway = 2 parry_failed_stagger_duration = 3 SECONDS - parry_failed_clickcd_duration = 3 SECONDS parry_time_windup = 0 parry_time_spindown = 0 parry_imperfect_falloff_percent = 0 @@ -274,6 +273,8 @@ parry_efficiency_considered_successful = 120 parry_efficiency_perfect = 120 parry_data = list(PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN = 4) + parry_automatic_enabled = TRUE + autoparry_single_efficiency = 75 //unique hammers /obj/item/melee/smith/hammer/toolbox From 2f9492945d9c5e5d0ad23ad9dd586616479f68db Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Mon, 7 Jun 2021 19:45:58 -0700 Subject: [PATCH 34/43] sigh --- code/__HELPERS/yelling.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/__HELPERS/yelling.dm b/code/__HELPERS/yelling.dm index 6987aef262..2dc2d0aec6 100644 --- a/code/__HELPERS/yelling.dm +++ b/code/__HELPERS/yelling.dm @@ -16,6 +16,7 @@ // blatantly copied from wave explosion code // check explosion2.dm for what this does and how it works. /datum/yelling_wavefill/proc/do_run(atom/source, dist) + source = get_turf(source) var/list/edges = list() edges[source] = (NORTH|SOUTH|EAST|WEST) var/list/powers = list() From b6bb20842fe2ad29249647171cb58260b92a8156 Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Sun, 13 Jun 2021 00:50:00 -0700 Subject: [PATCH 35/43] Yelling works --- code/__HELPERS/yelling.dm | 42 +++++++++++-------- code/datums/explosion2.dm | 31 ++++---------- code/game/atoms_movable.dm | 2 + code/game/turfs/closed.dm | 8 ++-- code/game/turfs/turf.dm | 2 +- .../mob/living/living_blocking_parrying.dm | 2 +- code/modules/mob/living/say.dm | 2 +- 7 files changed, 44 insertions(+), 45 deletions(-) diff --git a/code/__HELPERS/yelling.dm b/code/__HELPERS/yelling.dm index 2dc2d0aec6..7fec64c276 100644 --- a/code/__HELPERS/yelling.dm +++ b/code/__HELPERS/yelling.dm @@ -19,6 +19,7 @@ source = get_turf(source) var/list/edges = list() edges[source] = (NORTH|SOUTH|EAST|WEST) + collected += typecache_filter_list(source.contents, GLOB.typecache_living) var/list/powers = list() powers[source] = dist var/list/processed_last = list() @@ -28,22 +29,23 @@ var/dir var/returned #define RUN_YELL(_T, _P, _D) \ - returned = max(_P - _T.get_yelling_resistance() - 1, 0); \ - _T.maptext = "[returned]"; + returned = max(_P - max(_T.get_yelling_resistance(_P), 0) - 1, 0); + // _T.maptext = "[returned]"; - var/list/turf/edges_next = list() - var/list/turf/powers_next = list() - var/list/turf/powers_returned = list() - var/list/turf/diagonals = list() - var/list/turf/diagonal_powers = list() - var/list/turf/diagonal_powers_max = list() + var/list/turf/edges_next + var/list/turf/powers_next + var/list/turf/powers_returned + var/list/turf/diagonals + var/list/turf/diagonal_powers + var/list/turf/diagonal_powers_max + var/safety = 1000 #define CALCULATE_DIAGONAL_POWER(existing, adding, maximum) min(maximum, existing + adding) #define CALCULATE_DIAGONAL_CROSS_POWER(existing, adding) max(existing, adding) #define CARDINAL_MARK(ndir, cdir, edir) \ if(edir & cdir) { \ expanding = get_step(T,ndir); \ - if(expanding && !processed_last[expanding] && !edges[expanding]) { \ + if(expanding && isnull(processed_last[expanding]) && isnull(edges[expanding])) { \ powers_next[expanding] = max(powers_next[expanding], returned); \ edges_next[expanding] = (cdir | edges_next[expanding]); \ }; \ @@ -51,7 +53,7 @@ #define DIAGONAL_SUBSTEP(ndir, cdir, edir) \ expanding = get_step(T,ndir); \ - if(expanding && !processed_last[expanding] && !edges[expanding]) { \ + if(expanding && isnull(processed_last[expanding]) && isnull(edges[expanding])) { \ if(!edges_next[expanding]) { \ diagonal_powers_max[expanding] = max(diagonal_powers_max[expanding], returned, powers[T]); \ diagonal_powers[expanding] = CALCULATE_DIAGONAL_POWER(diagonal_powers[expanding], returned, diagonal_powers_max[expanding]); \ @@ -69,6 +71,12 @@ }; while(edges.len) + edges_next = list() + powers_next = list() + powers_returned = list() + diagonals = list() + diagonal_powers = list() + diagonal_powers_max = list() // to_chat(world, "DEBUG: cycle start edges [english_list_assoc(edges)]") // process cardinals @@ -78,8 +86,8 @@ dir = edges[T] RUN_YELL(T, power, dir) powers_returned[T] = returned - if(returned) - // get hearing atoms + if(returned >= 1) + collected |= typecache_filter_list(T.contents, GLOB.typecache_living) else continue @@ -87,7 +95,6 @@ CARDINAL_MARK(SOUTH, SOUTH, dir) CARDINAL_MARK(EAST, EAST, dir) CARDINAL_MARK(WEST, WEST, dir) - CHECK_TICK // to_chat(world, "DEBUG: cycle mid edges_next [english_list_assoc(edges_next)]") @@ -101,7 +108,6 @@ DIAGONAL_MARK(SOUTH, SOUTH, dir) DIAGONAL_MARK(EAST, EAST, dir) DIAGONAL_MARK(WEST, WEST, dir) - CHECK_TICK // to_chat(world, "DEBUG: cycle mid diagonals [english_list_assoc(diagonals)]") @@ -111,13 +117,12 @@ power = diagonal_powers[T] dir = diagonals[T] RUN_YELL(T, power, dir) - if(!returned) + if(returned < 1) continue CARDINAL_MARK(NORTH, NORTH, dir) CARDINAL_MARK(SOUTH, SOUTH, dir) CARDINAL_MARK(EAST, EAST, dir) CARDINAL_MARK(WEST, WEST, dir) - CHECK_TICK // to_chat(world, "DEBUG: cycle end edges_next [english_list_assoc(edges_next)]") @@ -126,6 +131,10 @@ edges = edges_next powers = powers_next + // sleep(2.5) + if(!--safety) + CRASH("Yelling ran out of safety.") + #undef RUN_YELL #undef DIAGONAL_SUBSTEP #undef CALCULATE_DIAGONAL_POWER @@ -137,4 +146,3 @@ var/datum/yelling_wavefill/Y = new Y.run_wavefill(source, dist) return Y.collected || list() - diff --git a/code/datums/explosion2.dm b/code/datums/explosion2.dm index 9a9f2b40cf..d3429bdebe 100644 --- a/code/datums/explosion2.dm +++ b/code/datums/explosion2.dm @@ -283,14 +283,11 @@ // insanity define to mark the next set of cardinals. #define CARDINAL_MARK(ndir, cdir, edir) \ if(edir & cdir) { \ - CARDINAL_MARK_NOCHECK(ndir, cdir, edir); \ - }; - -#define CARDINAL_MARK_NOCHECK(ndir, cdir, edir) \ - expanding = get_step(T,ndir); \ - if(expanding && !exploded_last[expanding] && !edges[expanding]) { \ - powers_next[expanding] = max(powers_next[expanding], returned); \ - edges_next[expanding] = (cdir | edges_next[expanding]); \ + expanding = get_step(T,ndir); \ + if(expanding && !exploded_last[expanding] && !edges[expanding]) { \ + powers_next[expanding] = max(powers_next[expanding], returned); \ + edges_next[expanding] = (cdir | edges_next[expanding]); \ + }; \ }; // insanity define to do diagonal marking as 2 substeps @@ -308,24 +305,15 @@ }; // insanity define to mark the diagonals that would otherwise be missed -#define DIAGONAL_MARK(ndir, cdir, edir) \ - if(edir & cdir) { \ - DIAGONAL_MARK_NOCHECK(ndir, cdir, edir); \ - }; - // this only works because right now, WEX_DIR_X is the same as a byond dir // and we know we're only passing in one dir at a time. // if this ever stops being the case, and explosions break when you touch this, now you know why. -#define DIAGONAL_MARK_NOCHECK(ndir, cdir, edir) \ - DIAGONAL_SUBSTEP(turn(ndir, 90), turn(cdir, 90), edir); \ - DIAGONAL_SUBSTEP(turn(ndir, -90), turn(cdir, -90), edir); - - // mark -#define MARK(ndir, cdir, edir) \ +#define DIAGONAL_MARK(ndir, cdir, edir) \ if(edir & cdir) { \ - CARDINAL_MARK_NOCHECK(ndir, cdir, edir); \ - DIAGONAL_MARK_NOCHECK(ndir, cdir, edir); \ + DIAGONAL_SUBSTEP(turn(ndir, 90), turn(cdir, 90), edir); \ + DIAGONAL_SUBSTEP(turn(ndir, -90), turn(cdir, -90), edir); \ }; + CARDINAL_MARK(NORTH, WEX_DIR_NORTH, dir) CARDINAL_MARK(SOUTH, WEX_DIR_SOUTH, dir) CARDINAL_MARK(EAST, WEX_DIR_EAST, dir) @@ -379,4 +367,3 @@ #undef DIAGONAL_SUBSTEP #undef DIAGONAL_MARK #undef CARDINAL_MARK -#undef MARK diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 098f1a2ea0..bcae3059e0 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -57,6 +57,8 @@ /// Should we use tooltips, if the thing does not have the code implemented `get_tooltip_data()`, it will default to examine(src) var/tooltips = FALSE + /// How loudly we yell + var/yell_power = 35 /atom/movable/Initialize(mapload) diff --git a/code/game/turfs/closed.dm b/code/game/turfs/closed.dm index 46d0bd9486..7af6c6780e 100644 --- a/code/game/turfs/closed.dm +++ b/code/game/turfs/closed.dm @@ -9,7 +9,9 @@ wave_explosion_block = 10 wave_explosion_multiply = 0.75 /// How much we block yelling - var/yelling_resistance = 40 + var/yelling_resistance = 15 + /// how much of inbound yelling to dampen + var/yelling_dampen = 0.5 /turf/closed/Initialize() . = ..() @@ -217,5 +219,5 @@ icon_state = "ice" canSmoothWith = list(/turf/closed/indestructible/rock/glacierrock/blue) -/turf/closed/get_yelling_resistance() - return yelling_resistance +/turf/closed/get_yelling_resistance(power) + return yelling_resistance + (power * yelling_dampen) diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 29b2db20ba..f8e2a2e18f 100755 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -613,7 +613,7 @@ GLOBAL_LIST_EMPTY(station_turfs) if(. != BULLET_ACT_FORCE_PIERCE) . = BULLET_ACT_TURF -/turf/proc/get_yelling_resistance() +/turf/proc/get_yelling_resistance(power) . = 0 // don't bother checking fulltile, we don't need accuracy var/obj/structure/window/W = locate() in src diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm index 3a828e0c81..d69b40be16 100644 --- a/code/modules/mob/living/living_blocking_parrying.dm +++ b/code/modules/mob/living/living_blocking_parrying.dm @@ -114,7 +114,7 @@ GLOBAL_LIST_EMPTY(block_parry_data) /// Attack types we can block var/parry_attack_types = ALL /// Parry flags - var/parry_flags = PARRY_DEFAULT_HANDLE_FEEDBACK | PARRY_LOCK_ATTACKING + var/parry_flags = PARRY_DEFAULT_HANDLE_FEEDBACK /// Parry windup duration in deciseconds. 0 to this is windup, afterwards is main stage. var/parry_time_windup = 0 diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index 949a47e50c..9f39fe492b 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -311,7 +311,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list( /atom/movable/proc/process_yelling(list/already_heard, rendered, atom/movable/speaker, datum/language/message_language, message, list/spans, message_mode, obj/source) var/list/overhearing = list() - overhearing = yelling_wavefill(src, 35) + overhearing = yelling_wavefill(src, yell_power) // overhearing = get_hearers_in_view(35, src) | get_hearers_in_range(5, src) overhearing -= already_heard for(var/_AM in overhearing) From 5c44cc22f481fece783803a0255dd67ba9ec4801 Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Sun, 13 Jun 2021 00:54:15 -0700 Subject: [PATCH 36/43] attempt examinate --- code/_onclick/click.dm | 3 +++ code/modules/keybindings/keybind/mob.dm | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 935fbce301..d24aa06806 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -288,6 +288,9 @@ return /atom/proc/ShiftClick(mob/user) + attempt_examinate(user) + +/atom/proc/attempt_examinate(mob/user) var/flags = SEND_SIGNAL(src, COMSIG_CLICK_SHIFT, user) | SEND_SIGNAL(user, COMSIG_MOB_CLICKED_SHIFT_ON, src) if(!(flags & COMPONENT_DENY_EXAMINATE) && user.client && (user.client.eye == user || user.client.eye == user.loc || flags & COMPONENT_ALLOW_EXAMINATE)) user.examinate(src) diff --git a/code/modules/keybindings/keybind/mob.dm b/code/modules/keybindings/keybind/mob.dm index 257ccc37e6..85862ee14f 100644 --- a/code/modules/keybindings/keybind/mob.dm +++ b/code/modules/keybindings/keybind/mob.dm @@ -76,3 +76,15 @@ else user.mob.dropItemToGround(I) return TRUE + +/datum/keybinding/mob/examine_immediate + hotkey_keys = list() + classic_keys = list() + name = "examine_immediate" + full_name = "Examine (Immediate)" + description = "Immediately examine anything you're hovering your mouse over." + +/datum/keybinding/mob/examine_immediate/down(client/user) + var/atom/A = user.mosueObject + if(A) + A.attempt_examinate(user.mob)) From e84f7ae4ac3510b943feb02f61023ef8f3abc6db Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Sun, 13 Jun 2021 01:16:44 -0700 Subject: [PATCH 37/43] fix --- code/__HELPERS/yelling.dm | 14 ++++++++------ code/modules/keybindings/keybind/mob.dm | 4 ++-- code/modules/mob/living/say.dm | 1 + 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/code/__HELPERS/yelling.dm b/code/__HELPERS/yelling.dm index 7fec64c276..3134e866be 100644 --- a/code/__HELPERS/yelling.dm +++ b/code/__HELPERS/yelling.dm @@ -4,14 +4,13 @@ /datum/yelling_wavefill/Destroy(force, ...) stop = TRUE + collected = null // don't cut it, something else is probably using it now! return ..() /datum/yelling_wavefill/proc/run_wavefill(atom/source, dist = 50) collected = list() do_run(source, dist) - // gc - if(QDELETED(src)) - collected = null + // to_chat(world, "DEBUG: collected [english_list(collected)]") // blatantly copied from wave explosion code // check explosion2.dm for what this does and how it works. @@ -29,7 +28,7 @@ var/dir var/returned #define RUN_YELL(_T, _P, _D) \ - returned = max(_P - max(_T.get_yelling_resistance(_P), 0) - 1, 0); + returned = max(_P - max(_T.get_yelling_resistance(_P), 0) - 1, 0); // \ // _T.maptext = "[returned]"; var/list/turf/edges_next @@ -117,7 +116,9 @@ power = diagonal_powers[T] dir = diagonals[T] RUN_YELL(T, power, dir) - if(returned < 1) + if(returned >= 1) + collected |= typecache_filter_list(T.contents, GLOB.typecache_living) + else continue CARDINAL_MARK(NORTH, NORTH, dir) CARDINAL_MARK(SOUTH, SOUTH, dir) @@ -145,4 +146,5 @@ /proc/yelling_wavefill(atom/source, dist = 50) var/datum/yelling_wavefill/Y = new Y.run_wavefill(source, dist) - return Y.collected || list() + . = Y.collected + qdel(Y) diff --git a/code/modules/keybindings/keybind/mob.dm b/code/modules/keybindings/keybind/mob.dm index 85862ee14f..15911d831e 100644 --- a/code/modules/keybindings/keybind/mob.dm +++ b/code/modules/keybindings/keybind/mob.dm @@ -85,6 +85,6 @@ description = "Immediately examine anything you're hovering your mouse over." /datum/keybinding/mob/examine_immediate/down(client/user) - var/atom/A = user.mosueObject + var/atom/A = user.mouseObject if(A) - A.attempt_examinate(user.mob)) + A.attempt_examinate(user.mob) diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index 9f39fe492b..6e24f9f1e4 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -314,6 +314,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list( overhearing = yelling_wavefill(src, yell_power) // overhearing = get_hearers_in_view(35, src) | get_hearers_in_range(5, src) overhearing -= already_heard + // to_chat(world, "DEBUG: overhearing [english_list(overhearing)]") for(var/_AM in overhearing) var/atom/movable/AM = _AM AM.Hear(rendered, speaker, message_language, message, null, spans, message_mode, source) From e7f5f80fb19c130c1abfab129e5b3f44a20a1308 Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Sun, 13 Jun 2021 15:34:47 -0700 Subject: [PATCH 38/43] yelling --- code/__HELPERS/yelling.dm | 6 +++--- code/game/atoms_movable.dm | 5 +++-- code/game/turfs/closed.dm | 4 ++-- code/game/turfs/space/space.dm | 2 ++ code/game/turfs/turf.dm | 15 +++++++++++---- code/modules/mob/living/say.dm | 5 +++++ 6 files changed, 26 insertions(+), 11 deletions(-) diff --git a/code/__HELPERS/yelling.dm b/code/__HELPERS/yelling.dm index 3134e866be..94ebfb7726 100644 --- a/code/__HELPERS/yelling.dm +++ b/code/__HELPERS/yelling.dm @@ -44,15 +44,15 @@ #define CARDINAL_MARK(ndir, cdir, edir) \ if(edir & cdir) { \ expanding = get_step(T,ndir); \ - if(expanding && isnull(processed_last[expanding]) && isnull(edges[expanding])) { \ + if(expanding && (isnull(processed_last[expanding]) || (processed_last[expanding] < (power - 5))) && (isnull(edges[expanding]) || (edges[expanding] < (power - 5)))) { \ powers_next[expanding] = max(powers_next[expanding], returned); \ - edges_next[expanding] = (cdir | edges_next[expanding]); \ + edges_next[expanding] = cdir; \ }; \ }; #define DIAGONAL_SUBSTEP(ndir, cdir, edir) \ expanding = get_step(T,ndir); \ - if(expanding && isnull(processed_last[expanding]) && isnull(edges[expanding])) { \ + if(expanding && (isnull(processed_last[expanding])) && (isnull(edges[expanding]))) { \ if(!edges_next[expanding]) { \ diagonal_powers_max[expanding] = max(diagonal_powers_max[expanding], returned, powers[T]); \ diagonal_powers[expanding] = CALCULATE_DIAGONAL_POWER(diagonal_powers[expanding], returned, diagonal_powers_max[expanding]); \ diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index bcae3059e0..155a462295 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -58,8 +58,9 @@ /// Should we use tooltips, if the thing does not have the code implemented `get_tooltip_data()`, it will default to examine(src) var/tooltips = FALSE /// How loudly we yell - var/yell_power = 35 - + var/yell_power = 50 + /// last time we yelled + var/last_yell = 0 /atom/movable/Initialize(mapload) . = ..() diff --git a/code/game/turfs/closed.dm b/code/game/turfs/closed.dm index 7af6c6780e..3b2762c0c4 100644 --- a/code/game/turfs/closed.dm +++ b/code/game/turfs/closed.dm @@ -9,9 +9,9 @@ wave_explosion_block = 10 wave_explosion_multiply = 0.75 /// How much we block yelling - var/yelling_resistance = 15 + var/yelling_resistance = 5 /// how much of inbound yelling to dampen - var/yelling_dampen = 0.5 + var/yelling_dampen = 0.75 /turf/closed/Initialize() . = ..() diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm index b1a4efc97e..b566b7efbf 100644 --- a/code/game/turfs/space/space.dm +++ b/code/game/turfs/space/space.dm @@ -274,6 +274,8 @@ destination_y = dest_y destination_z = dest_z +/turf/open/space/get_yelling_resistance(power) + return INFINITY // no sound through space for crying out loud /turf/open/space/transparent baseturfs = /turf/open/space/transparent/openspace diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index f8e2a2e18f..1bc2050685 100755 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -616,10 +616,17 @@ GLOBAL_LIST_EMPTY(station_turfs) /turf/proc/get_yelling_resistance(power) . = 0 // don't bother checking fulltile, we don't need accuracy - var/obj/structure/window/W = locate() in src - if(W) - . += 7 + var/obj/window = locate(/obj/structure/window) in src + if(!window) + window = locate(/obj/machinery/door/window) in src + if(window) + . += 5 // windows are minimally resistant + // if there's more than one someone fucked up as that shouldn't happen + var/obj/machinery/door/D = locate() in src + if(D?.density) + . += D.opacity? 30 : 20 // glass doors are slightly more resistant to screaming for(var/obj/machinery/door/D in src) if(!D.density) continue - . += D.opacity? 7 : 15 + break + . += D.opacity? 30 : diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index 6e24f9f1e4..84c2bf9e66 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -310,8 +310,13 @@ GLOBAL_LIST_INIT(department_radio_keys, list( INVOKE_ASYNC(GLOBAL_PROC, /.proc/flick_overlay, I, speech_bubble_recipients, 30) /atom/movable/proc/process_yelling(list/already_heard, rendered, atom/movable/speaker, datum/language/message_language, message, list/spans, message_mode, obj/source) + if(last_yell > (world.time - 10)) + to_chat(src, "Your voice doesn't project as far as you try to yell in such quick succession.") // yeah no, no spamming an expensive floodfill. + return + last_yell = world.time var/list/overhearing = list() overhearing = yelling_wavefill(src, yell_power) + log_say("YELL: [ismob(src)? key_name(src) : src] yelled [message] with overhearing mobs [overhearing]") // overhearing = get_hearers_in_view(35, src) | get_hearers_in_range(5, src) overhearing -= already_heard // to_chat(world, "DEBUG: overhearing [english_list(overhearing)]") From 8224546cfca20013dbcaef1ce827c6927ebb6953 Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Sun, 13 Jun 2021 15:36:20 -0700 Subject: [PATCH 39/43] ok --- code/modules/mob/living/say.dm | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index 84c2bf9e66..1a925e8eaf 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -315,10 +315,19 @@ GLOBAL_LIST_INIT(department_radio_keys, list( return last_yell = world.time var/list/overhearing = list() + var/list/overhearing_text = list() overhearing = yelling_wavefill(src, yell_power) - log_say("YELL: [ismob(src)? key_name(src) : src] yelled [message] with overhearing mobs [overhearing]") + if(!overhearing.len) + overhearing_text = "none" + else + for(var/mob/M as anything in overhearing) + overhearing_text += key_name(M) + overhearing_text = english_list(overhearing_text) + log_say("YELL: [ismob(src)? key_name(src) : src] yelled [message] with overhearing mobs [overhearing_text]") // overhearing = get_hearers_in_view(35, src) | get_hearers_in_range(5, src) overhearing -= already_heard + if(!overhearing.len) + return // to_chat(world, "DEBUG: overhearing [english_list(overhearing)]") for(var/_AM in overhearing) var/atom/movable/AM = _AM From b04a580e1de3e775576193fe9a96a8dd1861939c Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Sun, 13 Jun 2021 22:19:06 -0700 Subject: [PATCH 40/43] it works --- code/__HELPERS/yelling.dm | 12 ++++++------ code/game/turfs/closed.dm | 4 ++-- code/game/turfs/turf.dm | 9 ++------- tgui/public/tgui-common.bundle.js | 2 +- 4 files changed, 11 insertions(+), 16 deletions(-) diff --git a/code/__HELPERS/yelling.dm b/code/__HELPERS/yelling.dm index 94ebfb7726..8bb7690694 100644 --- a/code/__HELPERS/yelling.dm +++ b/code/__HELPERS/yelling.dm @@ -21,14 +21,15 @@ collected += typecache_filter_list(source.contents, GLOB.typecache_living) var/list/powers = list() powers[source] = dist - var/list/processed_last = list() + var/list/processed = list() var/turf/T var/turf/expanding var/power var/dir var/returned #define RUN_YELL(_T, _P, _D) \ - returned = max(_P - max(_T.get_yelling_resistance(_P), 0) - 1, 0); // \ + returned = max(_P - max(_T.get_yelling_resistance(_P), 0) - 1, 0); \ + processed[_T] = returned; // \ // _T.maptext = "[returned]"; var/list/turf/edges_next @@ -44,15 +45,15 @@ #define CARDINAL_MARK(ndir, cdir, edir) \ if(edir & cdir) { \ expanding = get_step(T,ndir); \ - if(expanding && (isnull(processed_last[expanding]) || (processed_last[expanding] < (power - 5))) && (isnull(edges[expanding]) || (edges[expanding] < (power - 5)))) { \ + if(expanding && (isnull(processed[expanding]) || (processed[expanding] < (power - 3)))) { \ powers_next[expanding] = max(powers_next[expanding], returned); \ - edges_next[expanding] = cdir; \ + edges_next[expanding] = (cdir | edges_next[expanding]); \ }; \ }; #define DIAGONAL_SUBSTEP(ndir, cdir, edir) \ expanding = get_step(T,ndir); \ - if(expanding && (isnull(processed_last[expanding])) && (isnull(edges[expanding]))) { \ + if(expanding && (isnull(processed[expanding]) || (processed[expanding] < (power - 3)))) { \ if(!edges_next[expanding]) { \ diagonal_powers_max[expanding] = max(diagonal_powers_max[expanding], returned, powers[T]); \ diagonal_powers[expanding] = CALCULATE_DIAGONAL_POWER(diagonal_powers[expanding], returned, diagonal_powers_max[expanding]); \ @@ -128,7 +129,6 @@ // to_chat(world, "DEBUG: cycle end edges_next [english_list_assoc(edges_next)]") // flush lists - processed_last = edges + diagonals edges = edges_next powers = powers_next diff --git a/code/game/turfs/closed.dm b/code/game/turfs/closed.dm index 3b2762c0c4..dc06062276 100644 --- a/code/game/turfs/closed.dm +++ b/code/game/turfs/closed.dm @@ -9,9 +9,9 @@ wave_explosion_block = 10 wave_explosion_multiply = 0.75 /// How much we block yelling - var/yelling_resistance = 5 + var/yelling_resistance = 10 /// how much of inbound yelling to dampen - var/yelling_dampen = 0.75 + var/yelling_dampen = 0.5 /turf/closed/Initialize() . = ..() diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 1bc2050685..d64d421065 100755 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -620,13 +620,8 @@ GLOBAL_LIST_EMPTY(station_turfs) if(!window) window = locate(/obj/machinery/door/window) in src if(window) - . += 5 // windows are minimally resistant + . += 4 // windows are minimally resistant // if there's more than one someone fucked up as that shouldn't happen var/obj/machinery/door/D = locate() in src if(D?.density) - . += D.opacity? 30 : 20 // glass doors are slightly more resistant to screaming - for(var/obj/machinery/door/D in src) - if(!D.density) - continue - break - . += D.opacity? 30 : + . += D.opacity? 29 : 19 // glass doors are slightly more resistant to screaming diff --git a/tgui/public/tgui-common.bundle.js b/tgui/public/tgui-common.bundle.js index 6fea6086cb..fe8b6fe0dd 100644 --- a/tgui/public/tgui-common.bundle.js +++ b/tgui/public/tgui-common.bundle.js @@ -1 +1 @@ -(self.webpackChunktgui_workspace=self.webpackChunktgui_workspace||[]).push([[962],{15453:function(e){"use strict";e.exports=function(e){if("function"!=typeof e)throw TypeError(String(e)+" is not a function");return e}},25401:function(e,t,n){"use strict";var r=n(99766);e.exports=function(e){if(!r(e)&&null!==e)throw TypeError("Can't set "+String(e)+" as a prototype");return e}},63142:function(e,t,n){"use strict";var r=n(55090),o=n(73072),i=n(19965),u=r("unscopables"),a=Array.prototype;a[u]==undefined&&i.f(a,u,{configurable:!0,value:o(null)}),e.exports=function(e){a[u][e]=!0}},78838:function(e,t,n){"use strict";var r=n(93294).charAt;e.exports=function(e,t,n){return t+(n?r(e,t).length:1)}},48246:function(e){"use strict";e.exports=function(e,t,n){if(!(e instanceof t))throw TypeError("Incorrect "+(n?n+" ":"")+"invocation");return e}},34699:function(e,t,n){"use strict";var r=n(99766);e.exports=function(e){if(!r(e))throw TypeError(String(e)+" is not an object");return e}},56097:function(e){"use strict";e.exports="undefined"!=typeof ArrayBuffer&&"undefined"!=typeof DataView},77066:function(e,t,n){"use strict";var r,o=n(56097),i=n(15289),u=n(93156),a=n(99766),c=n(13375),s=n(45423),l=n(57068),f=n(55103),d=n(19965).f,p=n(11993),h=n(62743),g=n(55090),v=n(94633),m=u.Int8Array,y=m&&m.prototype,b=u.Uint8ClampedArray,E=b&&b.prototype,D=m&&p(m),x=y&&p(y),w=Object.prototype,C=w.isPrototypeOf,_=g("toStringTag"),k=v("TYPED_ARRAY_TAG"),S=o&&!!h&&"Opera"!==s(u.opera),A=!1,N={Int8Array:1,Uint8Array:1,Uint8ClampedArray:1,Int16Array:2,Uint16Array:2,Int32Array:4,Uint32Array:4,Float32Array:4,Float64Array:8},F={BigInt64Array:8,BigUint64Array:8},B=function(e){if(!a(e))return!1;var t=s(e);return"DataView"===t||c(N,t)||c(F,t)},O=function(e){if(!a(e))return!1;var t=s(e);return c(N,t)||c(F,t)};for(r in N)u[r]||(S=!1);if((!S||"function"!=typeof D||D===Function.prototype)&&(D=function(){throw TypeError("Incorrect invocation")},S))for(r in N)u[r]&&h(u[r],D);if((!S||!x||x===w)&&(x=D.prototype,S))for(r in N)u[r]&&h(u[r].prototype,x);if(S&&p(E)!==x&&h(E,x),i&&!c(x,_))for(r in A=!0,d(x,_,{get:function(){return a(this)?this[k]:undefined}}),N)u[r]&&l(u[r],k,r);e.exports={NATIVE_ARRAY_BUFFER_VIEWS:S,TYPED_ARRAY_TAG:A&&k,aTypedArray:function(e){if(O(e))return e;throw TypeError("Target is not a typed array")},aTypedArrayConstructor:function(e){if(h){if(C.call(D,e))return e}else for(var t in N)if(c(N,r)){var n=u[t];if(n&&(e===n||C.call(n,e)))return e}throw TypeError("Target is not a typed array constructor")},exportTypedArrayMethod:function(e,t,n){if(i){if(n)for(var r in N){var o=u[r];o&&c(o.prototype,e)&&delete o.prototype[e]}x[e]&&!n||f(x,e,n?t:S&&y[e]||t)}},exportTypedArrayStaticMethod:function(e,t,n){var r,o;if(i){if(h){if(n)for(r in N)(o=u[r])&&c(o,e)&&delete o[e];if(D[e]&&!n)return;try{return f(D,e,n?t:S&&m[e]||t)}catch(a){}}for(r in N)!(o=u[r])||o[e]&&!n||f(o,e,t)}},isView:B,isTypedArray:O,TypedArray:D,TypedArrayPrototype:x}},3011:function(e,t,n){"use strict";var r=n(93156),o=n(15289),i=n(56097),u=n(57068),a=n(1165),c=n(62213),s=n(48246),l=n(30150),f=n(19047),d=n(20306),p=n(58383),h=n(11993),g=n(62743),v=n(68715).f,m=n(19965).f,y=n(83759),b=n(33698),E=n(90206),D=E.get,x=E.set,w="ArrayBuffer",C="DataView",_="Wrong index",k=r.ArrayBuffer,S=k,A=r.DataView,N=A&&A.prototype,F=Object.prototype,B=r.RangeError,O=p.pack,T=p.unpack,I=function(e){return[255&e]},M=function(e){return[255&e,e>>8&255]},V=function(e){return[255&e,e>>8&255,e>>16&255,e>>24&255]},R=function(e){return e[3]<<24|e[2]<<16|e[1]<<8|e[0]},L=function(e){return O(e,23,4)},P=function(e){return O(e,52,8)},j=function(e,t){m(e.prototype,t,{get:function(){return D(this)[t]}})},z=function(e,t,n,r){var o=d(n),i=D(e);if(o+t>i.byteLength)throw B(_);var u=D(i.buffer).bytes,a=o+i.byteOffset,c=u.slice(a,a+t);return r?c:c.reverse()},K=function(e,t,n,r,o,i){var u=d(n),a=D(e);if(u+t>a.byteLength)throw B(_);for(var c=D(a.buffer).bytes,s=u+a.byteOffset,l=r(+o),f=0;fH;)(U=$[H++])in S||u(S,U,k[U]);Y.constructor=S}g&&h(N)!==F&&g(N,F);var W=new A(new S(2)),G=N.setInt8;W.setInt8(0,2147483648),W.setInt8(1,2147483649),!W.getInt8(0)&&W.getInt8(1)||a(N,{setInt8:function(e,t){G.call(this,e,t<<24>>24)},setUint8:function(e,t){G.call(this,e,t<<24>>24)}},{unsafe:!0})}else S=function(e){s(this,S,w);var t=d(e);x(this,{bytes:y.call(new Array(t),0),byteLength:t}),o||(this.byteLength=t)},A=function(e,t,n){s(this,A,C),s(e,S,C);var r=D(e).byteLength,i=l(t);if(i<0||i>r)throw B("Wrong offset");if(i+(n=n===undefined?r-i:f(n))>r)throw B("Wrong length");x(this,{buffer:e,byteLength:n,byteOffset:i}),o||(this.buffer=e,this.byteLength=n,this.byteOffset=i)},o&&(j(S,"byteLength"),j(A,"buffer"),j(A,"byteLength"),j(A,"byteOffset")),a(A.prototype,{getInt8:function(e){return z(this,1,e)[0]<<24>>24},getUint8:function(e){return z(this,1,e)[0]},getInt16:function(e){var t=z(this,2,e,arguments.length>1?arguments[1]:undefined);return(t[1]<<8|t[0])<<16>>16},getUint16:function(e){var t=z(this,2,e,arguments.length>1?arguments[1]:undefined);return t[1]<<8|t[0]},getInt32:function(e){return R(z(this,4,e,arguments.length>1?arguments[1]:undefined))},getUint32:function(e){return R(z(this,4,e,arguments.length>1?arguments[1]:undefined))>>>0},getFloat32:function(e){return T(z(this,4,e,arguments.length>1?arguments[1]:undefined),23)},getFloat64:function(e){return T(z(this,8,e,arguments.length>1?arguments[1]:undefined),52)},setInt8:function(e,t){K(this,1,e,I,t)},setUint8:function(e,t){K(this,1,e,I,t)},setInt16:function(e,t){K(this,2,e,M,t,arguments.length>2?arguments[2]:undefined)},setUint16:function(e,t){K(this,2,e,M,t,arguments.length>2?arguments[2]:undefined)},setInt32:function(e,t){K(this,4,e,V,t,arguments.length>2?arguments[2]:undefined)},setUint32:function(e,t){K(this,4,e,V,t,arguments.length>2?arguments[2]:undefined)},setFloat32:function(e,t){K(this,4,e,L,t,arguments.length>2?arguments[2]:undefined)},setFloat64:function(e,t){K(this,8,e,P,t,arguments.length>2?arguments[2]:undefined)}});b(S,w),b(A,C),e.exports={ArrayBuffer:S,DataView:A}},90838:function(e,t,n){"use strict";var r=n(62314),o=n(60248),i=n(19047),u=Math.min;e.exports=[].copyWithin||function(e,t){var n=r(this),a=i(n.length),c=o(e,a),s=o(t,a),l=arguments.length>2?arguments[2]:undefined,f=u((l===undefined?a:o(l,a))-s,a-c),d=1;for(s0;)s in n?n[c]=n[s]:delete n[c],c+=d,s+=d;return n}},83759:function(e,t,n){"use strict";var r=n(62314),o=n(60248),i=n(19047);e.exports=function(e){for(var t=r(this),n=i(t.length),u=arguments.length,a=o(u>1?arguments[1]:undefined,n),c=u>2?arguments[2]:undefined,s=c===undefined?n:o(c,n);s>a;)t[a++]=e;return t}},83679:function(e,t,n){"use strict";var r=n(73846).forEach,o=n(67481)("forEach");e.exports=o?[].forEach:function(e){return r(this,e,arguments.length>1?arguments[1]:undefined)}},18703:function(e,t,n){"use strict";var r=n(6738),o=n(62314),i=n(83180),u=n(71713),a=n(19047),c=n(92996),s=n(3933);e.exports=function(e){var t,n,l,f,d,p,h=o(e),g="function"==typeof this?this:Array,v=arguments.length,m=v>1?arguments[1]:undefined,y=m!==undefined,b=s(h),E=0;if(y&&(m=r(m,v>2?arguments[2]:undefined,2)),b==undefined||g==Array&&u(b))for(n=new g(t=a(h.length));t>E;E++)p=y?m(h[E],E):h[E],c(n,E,p);else for(d=(f=b.call(h)).next,n=new g;!(l=d.call(f)).done;E++)p=y?i(f,m,[l.value,E],!0):l.value,c(n,E,p);return n.length=E,n}},38682:function(e,t,n){"use strict";var r=n(75018),o=n(19047),i=n(60248),u=function(e){return function(t,n,u){var a,c=r(t),s=o(c.length),l=i(u,s);if(e&&n!=n){for(;s>l;)if((a=c[l++])!=a)return!0}else for(;s>l;l++)if((e||l in c)&&c[l]===n)return e||l||0;return!e&&-1}};e.exports={includes:u(!0),indexOf:u(!1)}},73846:function(e,t,n){"use strict";var r=n(6738),o=n(98475),i=n(62314),u=n(19047),a=n(89130),c=[].push,s=function(e){var t=1==e,n=2==e,s=3==e,l=4==e,f=6==e,d=7==e,p=5==e||f;return function(h,g,v,m){for(var y,b,E=i(h),D=o(E),x=r(g,v,3),w=u(D.length),C=0,_=m||a,k=t?_(h,w):n||d?_(h,0):undefined;w>C;C++)if((p||C in D)&&(b=x(y=D[C],C,E),e))if(t)k[C]=b;else if(b)switch(e){case 3:return!0;case 5:return y;case 6:return C;case 2:c.call(k,y)}else switch(e){case 4:return!1;case 7:c.call(k,y)}return f?-1:s||l?l:k}};e.exports={forEach:s(0),map:s(1),filter:s(2),some:s(3),every:s(4),find:s(5),findIndex:s(6),filterOut:s(7)}},95180:function(e,t,n){"use strict";var r=n(75018),o=n(30150),i=n(19047),u=n(67481),a=Math.min,c=[].lastIndexOf,s=!!c&&1/[1].lastIndexOf(1,-0)<0,l=u("lastIndexOf"),f=s||!l;e.exports=f?function(e){if(s)return c.apply(this,arguments)||0;var t=r(this),n=i(t.length),u=n-1;for(arguments.length>1&&(u=a(u,o(arguments[1]))),u<0&&(u=n+u);u>=0;u--)if(u in t&&t[u]===e)return u||0;return-1}:c},35876:function(e,t,n){"use strict";var r=n(62213),o=n(55090),i=n(51976),u=o("species");e.exports=function(e){return i>=51||!r((function(){var t=[];return(t.constructor={})[u]=function(){return{foo:1}},1!==t[e](Boolean).foo}))}},67481:function(e,t,n){"use strict";var r=n(62213);e.exports=function(e,t){var n=[][e];return!!n&&r((function(){n.call(null,t||function(){throw 1},1)}))}},90047:function(e,t,n){"use strict";var r=n(15453),o=n(62314),i=n(98475),u=n(19047),a=function(e){return function(t,n,a,c){r(n);var s=o(t),l=i(s),f=u(s.length),d=e?f-1:0,p=e?-1:1;if(a<2)for(;;){if(d in l){c=l[d],d+=p;break}if(d+=p,e?d<0:f<=d)throw TypeError("Reduce of empty array with no initial value")}for(;e?d>=0:f>d;d+=p)d in l&&(c=n(c,l[d],d,s));return c}};e.exports={left:a(!1),right:a(!0)}},89130:function(e,t,n){"use strict";var r=n(99766),o=n(73707),i=n(55090)("species");e.exports=function(e,t){var n;return o(e)&&("function"!=typeof(n=e.constructor)||n!==Array&&!o(n.prototype)?r(n)&&null===(n=n[i])&&(n=undefined):n=undefined),new(n===undefined?Array:n)(0===t?0:t)}},83180:function(e,t,n){"use strict";var r=n(34699),o=n(6816);e.exports=function(e,t,n,i){try{return i?t(r(n)[0],n[1]):t(n)}catch(u){throw o(e),u}}},84673:function(e,t,n){"use strict";var r=n(55090)("iterator"),o=!1;try{var i=0,u={next:function(){return{done:!!i++}},"return":function(){o=!0}};u[r]=function(){return this},Array.from(u,(function(){throw 2}))}catch(a){}e.exports=function(e,t){if(!t&&!o)return!1;var n=!1;try{var i={};i[r]=function(){return{next:function(){return{done:n=!0}}}},e(i)}catch(a){}return n}},74803:function(e){"use strict";var t={}.toString;e.exports=function(e){return t.call(e).slice(8,-1)}},45423:function(e,t,n){"use strict";var r=n(94274),o=n(74803),i=n(55090)("toStringTag"),u="Arguments"==o(function(){return arguments}());e.exports=r?o:function(e){var t,n,r;return e===undefined?"Undefined":null===e?"Null":"string"==typeof(n=function(e,t){try{return e[t]}catch(n){}}(t=Object(e),i))?n:u?o(t):"Object"==(r=o(t))&&"function"==typeof t.callee?"Arguments":r}},36579:function(e,t,n){"use strict";var r=n(19965).f,o=n(73072),i=n(1165),u=n(6738),a=n(48246),c=n(32732),s=n(490),l=n(83360),f=n(15289),d=n(33214).fastKey,p=n(90206),h=p.set,g=p.getterFor;e.exports={getConstructor:function(e,t,n,s){var l=e((function(e,r){a(e,l,t),h(e,{type:t,index:o(null),first:undefined,last:undefined,size:0}),f||(e.size=0),r!=undefined&&c(r,e[s],{that:e,AS_ENTRIES:n})})),p=g(t),v=function(e,t,n){var r,o,i=p(e),u=m(e,t);return u?u.value=n:(i.last=u={index:o=d(t,!0),key:t,value:n,previous:r=i.last,next:undefined,removed:!1},i.first||(i.first=u),r&&(r.next=u),f?i.size++:e.size++,"F"!==o&&(i.index[o]=u)),e},m=function(e,t){var n,r=p(e),o=d(t);if("F"!==o)return r.index[o];for(n=r.first;n;n=n.next)if(n.key==t)return n};return i(l.prototype,{clear:function(){for(var e=p(this),t=e.index,n=e.first;n;)n.removed=!0,n.previous&&(n.previous=n.previous.next=undefined),delete t[n.index],n=n.next;e.first=e.last=undefined,f?e.size=0:this.size=0},"delete":function(e){var t=this,n=p(t),r=m(t,e);if(r){var o=r.next,i=r.previous;delete n.index[r.index],r.removed=!0,i&&(i.next=o),o&&(o.previous=i),n.first==r&&(n.first=o),n.last==r&&(n.last=i),f?n.size--:t.size--}return!!r},forEach:function(e){for(var t,n=p(this),r=u(e,arguments.length>1?arguments[1]:undefined,3);t=t?t.next:n.first;)for(r(t.value,t.key,this);t&&t.removed;)t=t.previous},has:function(e){return!!m(this,e)}}),i(l.prototype,n?{get:function(e){var t=m(this,e);return t&&t.value},set:function(e,t){return v(this,0===e?0:e,t)}}:{add:function(e){return v(this,e=0===e?0:e,e)}}),f&&r(l.prototype,"size",{get:function(){return p(this).size}}),l},setStrong:function(e,t,n){var r=t+" Iterator",o=g(t),i=g(r);s(e,t,(function(e,t){h(this,{type:r,target:e,state:o(e),kind:t,last:undefined})}),(function(){for(var e=i(this),t=e.kind,n=e.last;n&&n.removed;)n=n.previous;return e.target&&(e.last=n=n?n.next:e.state.first)?"keys"==t?{value:n.key,done:!1}:"values"==t?{value:n.value,done:!1}:{value:[n.key,n.value],done:!1}:(e.target=undefined,{value:undefined,done:!0})}),n?"entries":"values",!n,!0),l(t)}}},60079:function(e,t,n){"use strict";var r=n(1165),o=n(33214).getWeakData,i=n(34699),u=n(99766),a=n(48246),c=n(32732),s=n(73846),l=n(13375),f=n(90206),d=f.set,p=f.getterFor,h=s.find,g=s.findIndex,v=0,m=function(e){return e.frozen||(e.frozen=new y)},y=function(){this.entries=[]},b=function(e,t){return h(e.entries,(function(e){return e[0]===t}))};y.prototype={get:function(e){var t=b(this,e);if(t)return t[1]},has:function(e){return!!b(this,e)},set:function(e,t){var n=b(this,e);n?n[1]=t:this.entries.push([e,t])},"delete":function(e){var t=g(this.entries,(function(t){return t[0]===e}));return~t&&this.entries.splice(t,1),!!~t}},e.exports={getConstructor:function(e,t,n,s){var f=e((function(e,r){a(e,f,t),d(e,{type:t,id:v++,frozen:undefined}),r!=undefined&&c(r,e[s],{that:e,AS_ENTRIES:n})})),h=p(t),g=function(e,t,n){var r=h(e),u=o(i(t),!0);return!0===u?m(r).set(t,n):u[r.id]=n,e};return r(f.prototype,{"delete":function(e){var t=h(this);if(!u(e))return!1;var n=o(e);return!0===n?m(t)["delete"](e):n&&l(n,t.id)&&delete n[t.id]},has:function(e){var t=h(this);if(!u(e))return!1;var n=o(e);return!0===n?m(t).has(e):n&&l(n,t.id)}}),r(f.prototype,n?{get:function(e){var t=h(this);if(u(e)){var n=o(e);return!0===n?m(t).get(e):n?n[t.id]:undefined}},set:function(e,t){return g(this,e,t)}}:{add:function(e){return g(this,e,!0)}}),f}}},31912:function(e,t,n){"use strict";var r=n(10629),o=n(93156),i=n(76799),u=n(55103),a=n(33214),c=n(32732),s=n(48246),l=n(99766),f=n(62213),d=n(84673),p=n(33698),h=n(65136);e.exports=function(e,t,n){var g=-1!==e.indexOf("Map"),v=-1!==e.indexOf("Weak"),m=g?"set":"add",y=o[e],b=y&&y.prototype,E=y,D={},x=function(e){var t=b[e];u(b,e,"add"==e?function(e){return t.call(this,0===e?0:e),this}:"delete"==e?function(e){return!(v&&!l(e))&&t.call(this,0===e?0:e)}:"get"==e?function(e){return v&&!l(e)?undefined:t.call(this,0===e?0:e)}:"has"==e?function(e){return!(v&&!l(e))&&t.call(this,0===e?0:e)}:function(e,n){return t.call(this,0===e?0:e,n),this})};if(i(e,"function"!=typeof y||!(v||b.forEach&&!f((function(){(new y).entries().next()})))))E=n.getConstructor(t,e,g,m),a.REQUIRED=!0;else if(i(e,!0)){var w=new E,C=w[m](v?{}:-0,1)!=w,_=f((function(){w.has(1)})),k=d((function(e){new y(e)})),S=!v&&f((function(){for(var e=new y,t=5;t--;)e[m](t,t);return!e.has(-0)}));k||((E=t((function(t,n){s(t,E,e);var r=h(new y,t,E);return n!=undefined&&c(n,r[m],{that:r,AS_ENTRIES:g}),r}))).prototype=b,b.constructor=E),(_||S)&&(x("delete"),x("has"),g&&x("get")),(S||C)&&x(m),v&&b.clear&&delete b.clear}return D[e]=E,r({global:!0,forced:E!=y},D),p(E,e),v||n.setStrong(E,e,g),E}},7924:function(e,t,n){"use strict";var r=n(13375),o=n(92506),i=n(48378),u=n(19965);e.exports=function(e,t){for(var n=o(t),a=u.f,c=i.f,s=0;s"+u+""}},47155:function(e,t,n){"use strict";var r=n(37916).IteratorPrototype,o=n(73072),i=n(42831),u=n(33698),a=n(17080),c=function(){return this};e.exports=function(e,t,n){var s=t+" Iterator";return e.prototype=o(r,{next:i(1,n)}),u(e,s,!1,!0),a[s]=c,e}},57068:function(e,t,n){"use strict";var r=n(15289),o=n(19965),i=n(42831);e.exports=r?function(e,t,n){return o.f(e,t,i(1,n))}:function(e,t,n){return e[t]=n,e}},42831:function(e){"use strict";e.exports=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}},92996:function(e,t,n){"use strict";var r=n(57391),o=n(19965),i=n(42831);e.exports=function(e,t,n){var u=r(t);u in e?o.f(e,u,i(0,n)):e[u]=n}},33743:function(e,t,n){"use strict";var r=n(62213),o=n(52274).start,i=Math.abs,u=Date.prototype,a=u.getTime,c=u.toISOString;e.exports=r((function(){return"0385-07-25T07:06:39.999Z"!=c.call(new Date(-50000000000001))}))||!r((function(){c.call(new Date(NaN))}))?function(){if(!isFinite(a.call(this)))throw RangeError("Invalid time value");var e=this,t=e.getUTCFullYear(),n=e.getUTCMilliseconds(),r=t<0?"-":t>9999?"+":"";return r+o(i(t),r?6:4,0)+"-"+o(e.getUTCMonth()+1,2,0)+"-"+o(e.getUTCDate(),2,0)+"T"+o(e.getUTCHours(),2,0)+":"+o(e.getUTCMinutes(),2,0)+":"+o(e.getUTCSeconds(),2,0)+"."+o(n,3,0)+"Z"}:c},57029:function(e,t,n){"use strict";var r=n(34699),o=n(57391);e.exports=function(e){if("string"!==e&&"number"!==e&&"default"!==e)throw TypeError("Incorrect hint");return o(r(this),"number"!==e)}},490:function(e,t,n){"use strict";var r=n(10629),o=n(47155),i=n(11993),u=n(62743),a=n(33698),c=n(57068),s=n(55103),l=n(55090),f=n(27689),d=n(17080),p=n(37916),h=p.IteratorPrototype,g=p.BUGGY_SAFARI_ITERATORS,v=l("iterator"),m="keys",y="values",b="entries",E=function(){return this};e.exports=function(e,t,n,l,p,D,x){o(n,t,l);var w,C,_,k=function(e){if(e===p&&B)return B;if(!g&&e in N)return N[e];switch(e){case m:case y:case b:return function(){return new n(this,e)}}return function(){return new n(this)}},S=t+" Iterator",A=!1,N=e.prototype,F=N[v]||N["@@iterator"]||p&&N[p],B=!g&&F||k(p),O="Array"==t&&N.entries||F;if(O&&(w=i(O.call(new e)),h!==Object.prototype&&w.next&&(f||i(w)===h||(u?u(w,h):"function"!=typeof w[v]&&c(w,v,E)),a(w,S,!0,!0),f&&(d[S]=E))),p==y&&F&&F.name!==y&&(A=!0,B=function(){return F.call(this)}),f&&!x||N[v]===B||c(N,v,B),d[t]=B,p)if(C={values:k(y),keys:D?B:k(m),entries:k(b)},x)for(_ in C)(g||A||!(_ in N))&&s(N,_,C[_]);else r({target:t,proto:!0,forced:g||A},C);return C}},49712:function(e,t,n){"use strict";var r=n(10483),o=n(13375),i=n(43384),u=n(19965).f;e.exports=function(e){var t=r.Symbol||(r.Symbol={});o(t,e)||u(t,e,{value:i.f(e)})}},15289:function(e,t,n){"use strict";var r=n(62213);e.exports=!r((function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]}))},17765:function(e,t,n){"use strict";var r=n(93156),o=n(99766),i=r.document,u=o(i)&&o(i.createElement);e.exports=function(e){return u?i.createElement(e):{}}},88621:function(e,t,n){"use strict";var r=n(22909);e.exports=/(iphone|ipod|ipad).*applewebkit/i.test(r)},80597:function(e,t,n){"use strict";var r=n(74803),o=n(93156);e.exports="process"==r(o.process)},68486:function(e,t,n){"use strict";var r=n(22909);e.exports=/web0s(?!.*chrome)/i.test(r)},22909:function(e,t,n){"use strict";var r=n(1555);e.exports=r("navigator","userAgent")||""},51976:function(e,t,n){"use strict";var r,o,i=n(93156),u=n(22909),a=i.process,c=a&&a.versions,s=c&&c.v8;s?o=(r=s.split("."))[0]+r[1]:u&&(!(r=u.match(/Edge\/(\d+)/))||r[1]>=74)&&(r=u.match(/Chrome\/(\d+)/))&&(o=r[1]),e.exports=o&&+o},92002:function(e){"use strict";e.exports=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"]},10629:function(e,t,n){"use strict";var r=n(93156),o=n(48378).f,i=n(57068),u=n(55103),a=n(16731),c=n(7924),s=n(76799);e.exports=function(e,t){var n,l,f,d,p,h=e.target,g=e.global,v=e.stat;if(n=g?r:v?r[h]||a(h,{}):(r[h]||{}).prototype)for(l in t){if(d=t[l],f=e.noTargetGet?(p=o(n,l))&&p.value:n[l],!s(g?l:h+(v?".":"#")+l,e.forced)&&f!==undefined){if(typeof d==typeof f)continue;c(d,f)}(e.sham||f&&f.sham)&&i(d,"sham",!0),u(n,l,d,e)}}},62213:function(e){"use strict";e.exports=function(e){try{return!!e()}catch(t){return!0}}},63905:function(e,t,n){"use strict";n(16431);var r=n(55103),o=n(62213),i=n(55090),u=n(69107),a=n(57068),c=i("species"),s=!o((function(){var e=/./;return e.exec=function(){var e=[];return e.groups={a:"7"},e},"7"!=="".replace(e,"$")})),l="$0"==="a".replace(/./,"$0"),f=i("replace"),d=!!/./[f]&&""===/./[f]("a","$0"),p=!o((function(){var e=/(?:)/,t=e.exec;e.exec=function(){return t.apply(this,arguments)};var n="ab".split(e);return 2!==n.length||"a"!==n[0]||"b"!==n[1]}));e.exports=function(e,t,n,f){var h=i(e),g=!o((function(){var t={};return t[h]=function(){return 7},7!=""[e](t)})),v=g&&!o((function(){var t=!1,n=/a/;return"split"===e&&((n={}).constructor={},n.constructor[c]=function(){return n},n.flags="",n[h]=/./[h]),n.exec=function(){return t=!0,null},n[h](""),!t}));if(!g||!v||"replace"===e&&(!s||!l||d)||"split"===e&&!p){var m=/./[h],y=n(h,""[e],(function(e,t,n,r,o){return t.exec===u?g&&!o?{done:!0,value:m.call(t,n,r)}:{done:!0,value:e.call(n,t,r)}:{done:!1}}),{REPLACE_KEEPS_$0:l,REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE:d}),b=y[0],E=y[1];r(String.prototype,e,b),r(RegExp.prototype,h,2==t?function(e,t){return E.call(e,this,t)}:function(e){return E.call(e,this)})}f&&a(RegExp.prototype[h],"sham",!0)}},67767:function(e,t,n){"use strict";var r=n(73707),o=n(19047),i=n(6738);e.exports=function u(e,t,n,a,c,s,l,f){for(var d,p=c,h=0,g=!!l&&i(l,f,3);h0&&r(d))p=u(e,t,d,o(d.length),p,s-1)-1;else{if(p>=9007199254740991)throw TypeError("Exceed the acceptable array length");e[p]=d}p++}h++}return p}},41830:function(e,t,n){"use strict";var r=n(62213);e.exports=!r((function(){return Object.isExtensible(Object.preventExtensions({}))}))},6738:function(e,t,n){"use strict";var r=n(15453);e.exports=function(e,t,n){if(r(e),t===undefined)return e;switch(n){case 0:return function(){return e.call(t)};case 1:return function(n){return e.call(t,n)};case 2:return function(n,r){return e.call(t,n,r)};case 3:return function(n,r,o){return e.call(t,n,r,o)}}return function(){return e.apply(t,arguments)}}},67043:function(e,t,n){"use strict";var r=n(15453),o=n(99766),i=[].slice,u={},a=function(e,t,n){if(!(t in u)){for(var r=[],o=0;o]*>)/g,a=/\$([$&'`]|\d\d?)/g;e.exports=function(e,t,n,c,s,l){var f=n+e.length,d=c.length,p=a;return s!==undefined&&(s=r(s),p=u),i.call(l,p,(function(r,i){var u;switch(i.charAt(0)){case"$":return"$";case"&":return e;case"`":return t.slice(0,n);case"'":return t.slice(f);case"<":u=s[i.slice(1,-1)];break;default:var a=+i;if(0===a)return r;if(a>d){var l=o(a/10);return 0===l?r:l<=d?c[l-1]===undefined?i.charAt(1):c[l-1]+i.charAt(1):r}u=c[a-1]}return u===undefined?"":u}))}},93156:function(e,t,n){"use strict";var r=function(e){return e&&e.Math==Math&&e};e.exports=r("object"==typeof globalThis&&globalThis)||r("object"==typeof window&&window)||r("object"==typeof self&&self)||r("object"==typeof n.g&&n.g)||function(){return this}()||Function("return this")()},13375:function(e){"use strict";var t={}.hasOwnProperty;e.exports=function(e,n){return t.call(e,n)}},97204:function(e){"use strict";e.exports={}},31538:function(e,t,n){"use strict";var r=n(93156);e.exports=function(e,t){var n=r.console;n&&n.error&&(1===arguments.length?n.error(e):n.error(e,t))}},73214:function(e,t,n){"use strict";var r=n(1555);e.exports=r("document","documentElement")},76689:function(e,t,n){"use strict";var r=n(15289),o=n(62213),i=n(17765);e.exports=!r&&!o((function(){return 7!=Object.defineProperty(i("div"),"a",{get:function(){return 7}}).a}))},58383:function(e){"use strict";var t=Math.abs,n=Math.pow,r=Math.floor,o=Math.log,i=Math.LN2;e.exports={pack:function(e,u,a){var c,s,l,f=new Array(a),d=8*a-u-1,p=(1<>1,g=23===u?n(2,-24)-n(2,-77):0,v=e<0||0===e&&1/e<0?1:0,m=0;for((e=t(e))!=e||e===Infinity?(s=e!=e?1:0,c=p):(c=r(o(e)/i),e*(l=n(2,-c))<1&&(c--,l*=2),(e+=c+h>=1?g/l:g*n(2,1-h))*l>=2&&(c++,l/=2),c+h>=p?(s=0,c=p):c+h>=1?(s=(e*l-1)*n(2,u),c+=h):(s=e*n(2,h-1)*n(2,u),c=0));u>=8;f[m++]=255&s,s/=256,u-=8);for(c=c<0;f[m++]=255&c,c/=256,d-=8);return f[--m]|=128*v,f},unpack:function(e,t){var r,o=e.length,i=8*o-t-1,u=(1<>1,c=i-7,s=o-1,l=e[s--],f=127&l;for(l>>=7;c>0;f=256*f+e[s],s--,c-=8);for(r=f&(1<<-c)-1,f>>=-c,c+=t;c>0;r=256*r+e[s],s--,c-=8);if(0===f)f=1-a;else{if(f===u)return r?NaN:l?-Infinity:Infinity;r+=n(2,t),f-=a}return(l?-1:1)*r*n(2,f-t)}}},98475:function(e,t,n){"use strict";var r=n(62213),o=n(74803),i="".split;e.exports=r((function(){return!Object("z").propertyIsEnumerable(0)}))?function(e){return"String"==o(e)?i.call(e,""):Object(e)}:Object},65136:function(e,t,n){"use strict";var r=n(99766),o=n(62743);e.exports=function(e,t,n){var i,u;return o&&"function"==typeof(i=t.constructor)&&i!==n&&r(u=i.prototype)&&u!==n.prototype&&o(e,u),e}},59601:function(e,t,n){"use strict";var r=n(41030),o=Function.toString;"function"!=typeof r.inspectSource&&(r.inspectSource=function(e){return o.call(e)}),e.exports=r.inspectSource},33214:function(e,t,n){"use strict";var r=n(97204),o=n(99766),i=n(13375),u=n(19965).f,a=n(94633),c=n(41830),s=a("meta"),l=0,f=Object.isExtensible||function(){return!0},d=function(e){u(e,s,{value:{objectID:"O"+ ++l,weakData:{}}})},p=e.exports={REQUIRED:!1,fastKey:function(e,t){if(!o(e))return"symbol"==typeof e?e:("string"==typeof e?"S":"P")+e;if(!i(e,s)){if(!f(e))return"F";if(!t)return"E";d(e)}return e[s].objectID},getWeakData:function(e,t){if(!i(e,s)){if(!f(e))return!0;if(!t)return!1;d(e)}return e[s].weakData},onFreeze:function(e){return c&&p.REQUIRED&&f(e)&&!i(e,s)&&d(e),e}};r[s]=!0},90206:function(e,t,n){"use strict";var r,o,i,u=n(60768),a=n(93156),c=n(99766),s=n(57068),l=n(13375),f=n(41030),d=n(67543),p=n(97204),h=a.WeakMap;if(u){var g=f.state||(f.state=new h),v=g.get,m=g.has,y=g.set;r=function(e,t){return t.facade=e,y.call(g,e,t),t},o=function(e){return v.call(g,e)||{}},i=function(e){return m.call(g,e)}}else{var b=d("state");p[b]=!0,r=function(e,t){return t.facade=e,s(e,b,t),t},o=function(e){return l(e,b)?e[b]:{}},i=function(e){return l(e,b)}}e.exports={set:r,get:o,has:i,enforce:function(e){return i(e)?o(e):r(e,{})},getterFor:function(e){return function(t){var n;if(!c(t)||(n=o(t)).type!==e)throw TypeError("Incompatible receiver, "+e+" required");return n}}}},71713:function(e,t,n){"use strict";var r=n(55090),o=n(17080),i=r("iterator"),u=Array.prototype;e.exports=function(e){return e!==undefined&&(o.Array===e||u[i]===e)}},73707:function(e,t,n){"use strict";var r=n(74803);e.exports=Array.isArray||function(e){return"Array"==r(e)}},76799:function(e,t,n){"use strict";var r=n(62213),o=/#|\.prototype\./,i=function(e,t){var n=a[u(e)];return n==s||n!=c&&("function"==typeof t?r(t):!!t)},u=i.normalize=function(e){return String(e).replace(o,".").toLowerCase()},a=i.data={},c=i.NATIVE="N",s=i.POLYFILL="P";e.exports=i},92285:function(e,t,n){"use strict";var r=n(99766),o=Math.floor;e.exports=function(e){return!r(e)&&isFinite(e)&&o(e)===e}},99766:function(e){"use strict";e.exports=function(e){return"object"==typeof e?null!==e:"function"==typeof e}},27689:function(e){"use strict";e.exports=!1},10874:function(e,t,n){"use strict";var r=n(99766),o=n(74803),i=n(55090)("match");e.exports=function(e){var t;return r(e)&&((t=e[i])!==undefined?!!t:"RegExp"==o(e))}},32732:function(e,t,n){"use strict";var r=n(34699),o=n(71713),i=n(19047),u=n(6738),a=n(3933),c=n(6816),s=function(e,t){this.stopped=e,this.result=t};e.exports=function(e,t,n){var l,f,d,p,h,g,v,m=n&&n.that,y=!(!n||!n.AS_ENTRIES),b=!(!n||!n.IS_ITERATOR),E=!(!n||!n.INTERRUPTED),D=u(t,m,1+y+E),x=function(e){return l&&c(l),new s(!0,e)},w=function(e){return y?(r(e),E?D(e[0],e[1],x):D(e[0],e[1])):E?D(e,x):D(e)};if(b)l=e;else{if("function"!=typeof(f=a(e)))throw TypeError("Target is not iterable");if(o(f)){for(d=0,p=i(e.length);p>d;d++)if((h=w(e[d]))&&h instanceof s)return h;return new s(!1)}l=f.call(e)}for(g=l.next;!(v=g.call(l)).done;){try{h=w(v.value)}catch(C){throw c(l),C}if("object"==typeof h&&h&&h instanceof s)return h}return new s(!1)}},6816:function(e,t,n){"use strict";var r=n(34699);e.exports=function(e){var t=e["return"];if(t!==undefined)return r(t.call(e)).value}},37916:function(e,t,n){"use strict";var r,o,i,u=n(62213),a=n(11993),c=n(57068),s=n(13375),l=n(55090),f=n(27689),d=l("iterator"),p=!1;[].keys&&("next"in(i=[].keys())?(o=a(a(i)))!==Object.prototype&&(r=o):p=!0);var h=r==undefined||u((function(){var e={};return r[d].call(e)!==e}));h&&(r={}),f&&!h||s(r,d)||c(r,d,(function(){return this})),e.exports={IteratorPrototype:r,BUGGY_SAFARI_ITERATORS:p}},17080:function(e){"use strict";e.exports={}},78216:function(e){"use strict";var t=Math.expm1,n=Math.exp;e.exports=!t||t(10)>22025.465794806718||t(10)<22025.465794806718||-2e-17!=t(-2e-17)?function(e){return 0==(e=+e)?e:e>-1e-6&&e<1e-6?e+e*e/2:n(e)-1}:t},69945:function(e,t,n){"use strict";var r=n(57845),o=Math.abs,i=Math.pow,u=i(2,-52),a=i(2,-23),c=i(2,127)*(2-a),s=i(2,-126);e.exports=Math.fround||function(e){var t,n,i=o(e),l=r(e);return ic||n!=n?l*Infinity:l*n}},90738:function(e){"use strict";var t=Math.log;e.exports=Math.log1p||function(e){return(e=+e)>-1e-8&&e<1e-8?e-e*e/2:t(1+e)}},57845:function(e){"use strict";e.exports=Math.sign||function(e){return 0==(e=+e)||e!=e?e:e<0?-1:1}},74317:function(e,t,n){"use strict";var r,o,i,u,a,c,s,l,f=n(93156),d=n(48378).f,p=n(24446).set,h=n(88621),g=n(68486),v=n(80597),m=f.MutationObserver||f.WebKitMutationObserver,y=f.document,b=f.process,E=f.Promise,D=d(f,"queueMicrotask"),x=D&&D.value;x||(r=function(){var e,t;for(v&&(e=b.domain)&&e.exit();o;){t=o.fn,o=o.next;try{t()}catch(n){throw o?u():i=undefined,n}}i=undefined,e&&e.enter()},h||v||g||!m||!y?E&&E.resolve?(s=E.resolve(undefined),l=s.then,u=function(){l.call(s,r)}):u=v?function(){b.nextTick(r)}:function(){p.call(f,r)}:(a=!0,c=y.createTextNode(""),new m(r).observe(c,{characterData:!0}),u=function(){c.data=a=!a})),e.exports=x||function(e){var t={fn:e,next:undefined};i&&(i.next=t),o||(o=t,u()),i=t}},77085:function(e,t,n){"use strict";var r=n(93156);e.exports=r.Promise},19530:function(e,t,n){"use strict";var r=n(62213);e.exports=!!Object.getOwnPropertySymbols&&!r((function(){return!String(Symbol())}))},60768:function(e,t,n){"use strict";var r=n(93156),o=n(59601),i=r.WeakMap;e.exports="function"==typeof i&&/native code/.test(o(i))},604:function(e,t,n){"use strict";var r=n(15453),o=function(e){var t,n;this.promise=new e((function(e,r){if(t!==undefined||n!==undefined)throw TypeError("Bad Promise constructor");t=e,n=r})),this.resolve=r(t),this.reject=r(n)};e.exports.f=function(e){return new o(e)}},90225:function(e,t,n){"use strict";var r=n(10874);e.exports=function(e){if(r(e))throw TypeError("The method doesn't accept regular expressions");return e}},5366:function(e,t,n){"use strict";var r=n(93156).isFinite;e.exports=Number.isFinite||function(e){return"number"==typeof e&&r(e)}},5868:function(e,t,n){"use strict";var r=n(93156),o=n(52420).trim,i=n(98398),u=r.parseFloat,a=1/u(i+"-0")!=-Infinity;e.exports=a?function(e){var t=o(String(e)),n=u(t);return 0===n&&"-"==t.charAt(0)?-0:n}:u},94219:function(e,t,n){"use strict";var r=n(93156),o=n(52420).trim,i=n(98398),u=r.parseInt,a=/^[+-]?0[Xx]/,c=8!==u(i+"08")||22!==u(i+"0x16");e.exports=c?function(e,t){var n=o(String(e));return u(n,t>>>0||(a.test(n)?16:10))}:u},3669:function(e,t,n){"use strict";var r=n(15289),o=n(62213),i=n(91165),u=n(84491),a=n(21058),c=n(62314),s=n(98475),l=Object.assign,f=Object.defineProperty;e.exports=!l||o((function(){if(r&&1!==l({b:1},l(f({},"a",{enumerable:!0,get:function(){f(this,"b",{value:3,enumerable:!1})}}),{b:2})).b)return!0;var e={},t={},n=Symbol(),o="abcdefghijklmnopqrst";return e[n]=7,o.split("").forEach((function(e){t[e]=e})),7!=l({},e)[n]||i(l({},t)).join("")!=o}))?function(e,t){for(var n=c(e),o=arguments.length,l=1,f=u.f,d=a.f;o>l;)for(var p,h=s(arguments[l++]),g=f?i(h).concat(f(h)):i(h),v=g.length,m=0;v>m;)p=g[m++],r&&!d.call(h,p)||(n[p]=h[p]);return n}:l},73072:function(e,t,n){"use strict";var r,o=n(34699),i=n(54550),u=n(92002),a=n(97204),c=n(73214),s=n(17765),l=n(67543),f=l("IE_PROTO"),d=function(){},p=function(e){return"