From 3f88829af8dcfb4a6284662454fea4a957bd9a10 Mon Sep 17 00:00:00 2001 From: Drathek <76988376+Drulikar@users.noreply.github.com> Date: Wed, 29 May 2024 10:19:40 -0700 Subject: [PATCH 1/9] Reduce chem smoke logging spam (#6345) # About the pull request Smoke reactions are now a niche admin log, and somewhat spam reduced by storing the last event in a static var. The reason why I say somewhat is because say two different people spray at the same time the last event will swap between both people each cloud. Now the hour/minute, area, chem, and user are used to create a siganture. # Explain why it's good for the game Chem smoke is now commonly used in rounds so its better to keep information sent to admins more relevant rather than spammed. # Testing Photographs and Procedure
Screenshots & Videos Second log was after a minute elapsed (which makes the signature unique again) ![image](https://github.com/cmss13-devs/cmss13/assets/76988376/eaac12d5-01ee-4679-9c67-ddc8597409b6)
# Changelog :cl: Drathek admin: Logging for chem smoke is now niche logged and less spammy /:cl: --- code/game/objects/effects/effect_system/chemsmoke.dm | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/code/game/objects/effects/effect_system/chemsmoke.dm b/code/game/objects/effects/effect_system/chemsmoke.dm index 702760333ccc..10c0bc7acd22 100644 --- a/code/game/objects/effects/effect_system/chemsmoke.dm +++ b/code/game/objects/effects/effect_system/chemsmoke.dm @@ -27,7 +27,7 @@ var/list/targetTurfs var/list/wallList var/density - + var/static/last_reaction_signature /datum/effect_system/smoke_spread/chem/New() ..() @@ -80,14 +80,19 @@ contained = "\[[contained]\]" var/area/A = get_area(location) + var/reaction_signature = "[time2text(world.timeofday, "hh:mm")]: ([A.name])[contained] by [carry.my_atom.fingerprintslast]" + if(last_reaction_signature == reaction_signature) + return + last_reaction_signature = reaction_signature + var/where = "[A.name]|[location.x], [location.y]" var/whereLink = "[where]" if(carry.my_atom.fingerprintslast) - message_admins("A chemical smoke reaction has taken place in ([whereLink])[contained]. Last associated key is [carry.my_atom.fingerprintslast].") + msg_admin_niche("A chemical smoke reaction has taken place in ([whereLink])[contained]. Last associated key is [carry.my_atom.fingerprintslast].") log_game("A chemical smoke reaction has taken place in ([where])[contained]. Last associated key is [carry.my_atom.fingerprintslast].") else - message_admins("A chemical smoke reaction has taken place in ([whereLink]). No associated key.") + msg_admin_niche("A chemical smoke reaction has taken place in ([whereLink])[contained]. No associated key.") log_game("A chemical smoke reaction has taken place in ([where])[contained]. No associated key.") From f4726bb374de82810fd2310d453f2fef58518fb3 Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Wed, 29 May 2024 18:24:01 +0100 Subject: [PATCH 2/9] Automatic changelog for PR #6345 [ci skip] --- html/changelogs/AutoChangeLog-pr-6345.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-6345.yml diff --git a/html/changelogs/AutoChangeLog-pr-6345.yml b/html/changelogs/AutoChangeLog-pr-6345.yml new file mode 100644 index 000000000000..8321411f87b6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-6345.yml @@ -0,0 +1,4 @@ +author: "Drathek" +delete-after: True +changes: + - admin: "Logging for chem smoke is now niche logged and less spammy" \ No newline at end of file From 63f828621dd86ff4f8dac8613cb5dccaa8ef8191 Mon Sep 17 00:00:00 2001 From: Paul Mullen <101871009+mullenpaul@users.noreply.github.com> Date: Wed, 29 May 2024 18:21:23 +0100 Subject: [PATCH 3/9] Ghost orbit refactor (#6346) # About the pull request Some usability changes to the orbit menu and general refactoring. - Marines now appear per squad - Marine job icons now appear in line with the name - Marine job is sorted by job, similar to squad UI - Xenos now appear per hive # Explain why it's good for the game Improving usability is a good thing # Testing Photographs and Procedure
Screenshots & Videos Put screenshots and videos here with an empty line between the screenshots and the `
` tags. https://media.discordapp.net/attachments/964684928161808384/1244701305751212084/image.png?ex=6656baac&is=6655692c&hm=6d0bb3234ac1d511e55978a046414f080c95f8c5dd2bedc51bfb3787ee1ff754&=&format=webp&quality=lossless&width=958&height=1342 https://media.discordapp.net/attachments/964684928161808384/1244783033517871154/image.png?ex=665706ca&is=6655b54a&hm=591f86a278ab6217d28a6890efef7a344f4467b25432a8c1bcab3723004e223b&=&format=webp&quality=lossless&width=958&height=1342
# Changelog :cl: ui: orbit menu now splits marine squads ui: orbit menu now splits xeno hives ui: orbit menu sorts marines by job /:cl: --- tgui/packages/tgui/interfaces/Orbit/index.tsx | 307 +++++++++++------- tgui/packages/tgui/interfaces/Orbit/types.ts | 21 ++ 2 files changed, 213 insertions(+), 115 deletions(-) diff --git a/tgui/packages/tgui/interfaces/Orbit/index.tsx b/tgui/packages/tgui/interfaces/Orbit/index.tsx index 76a2ce874497..bc440e733939 100644 --- a/tgui/packages/tgui/interfaces/Orbit/index.tsx +++ b/tgui/packages/tgui/interfaces/Orbit/index.tsx @@ -1,8 +1,8 @@ -import { filter, sortBy } from 'common/collections'; import { capitalizeFirst } from 'common/string'; -import { useState } from 'react'; +import { createContext, useContext, useState } from 'react'; import { useBackend } from 'tgui/backend'; import { + Box, Button, Collapsible, ColorBox, @@ -21,39 +21,49 @@ import { getMostRelevant, isJobOrNameMatch, } from './helpers'; -import type { Observable, OrbitData } from './types'; +import { + buildSquadObservable, + groupSorter, + type Observable, + type OrbitData, + splitter, +} from './types'; + +type search = { + value: string; + setValue: (value: string) => void; +}; -export const Orbit = (props) => { +const SearchContext = createContext({ value: '', setValue: () => {} }); + +export const Orbit = () => { const [searchQuery, setSearchQuery] = useState(''); return ( - - - - - -
- -
-
-
+ + + + + + +
+ +
+
+
+
); }; /** Controls filtering out the list of observables via search */ -const ObservableSearch = (props: { - readonly searchQuery: string; - readonly setSearchQuery: React.Dispatch>; -}) => { +const ObservableSearch = () => { const { act, data } = useBackend(); - const { searchQuery, setSearchQuery } = props; const { humans = [], marines = [], survivors = [], xenos = [] } = data; let auto_observe = data.auto_observe; @@ -74,6 +84,8 @@ const ObservableSearch = (props: { } }; + const { value, setValue } = useContext(SearchContext); + return (
@@ -85,9 +97,9 @@ const ObservableSearch = (props: { autoFocus fluid onEnter={(event, value) => orbitMostRelevant(value)} - onInput={(event, value) => setSearchQuery(value)} + onInput={(event, value) => setValue(value)} placeholder="Search..." - value={searchQuery} + value={value} /> @@ -96,7 +108,7 @@ const ObservableSearch = (props: { color={auto_observe ? 'good' : 'transparent'} icon={auto_observe ? 'toggle-on' : 'toggle-off'} onClick={() => act('toggle_auto_observe')} - tooltip={`Toggle Full Observe. When active, you'll see the UI / full inventory of whoever you're orbiting. Neat!`} + tooltip={`Toggle Full Observe. When active, you'll see the UI / full inventory of whoever you're orbiting.`} tooltipPosition="bottom-start" /> @@ -114,14 +126,137 @@ const ObservableSearch = (props: { ); }; +const xenoSplitter = (members: Array) => { + const primeHive: Array = []; + const corruptedHive: Array = []; + + members.forEach((x) => { + if (x.full_name?.includes('Corrupted')) { + corruptedHive.push(x); + } else { + primeHive.push(x); + } + }); + const squads = [ + buildSquadObservable('Prime', 'xeno', primeHive), + buildSquadObservable('Corrupted', 'green', corruptedHive), + ]; + return squads; +}; + +const marineSplitter = (members: Array) => { + const alphaSquad: Array = []; + const bravoSquad: Array = []; + const charlieSquad: Array = []; + const deltaSquad: Array = []; + const foxtrotSquad: Array = []; + const other: Array = []; + + members.forEach((x) => { + if (x.job?.includes('Alpha')) { + alphaSquad.push(x); + } else if (x.job?.includes('Bravo')) { + bravoSquad.push(x); + } else if (x.job?.includes('Charlie')) { + charlieSquad.push(x); + } else if (x.job?.includes('Delta')) { + deltaSquad.push(x); + } else if (x.job?.includes('Foxtrot')) { + foxtrotSquad.push(x); + } else { + other.push(x); + } + }); + + const squads = [ + buildSquadObservable('Alpha', 'red', alphaSquad), + buildSquadObservable('Bravo', 'yellow', bravoSquad), + buildSquadObservable('Charlie', 'purple', charlieSquad), + buildSquadObservable('Delta', 'blue', deltaSquad), + buildSquadObservable('Foxtrot', 'teal', foxtrotSquad), + buildSquadObservable('Other', 'grey', other), + ]; + return squads; +}; + +const rankList = [ + 'Rifleman', + 'Spotter', + 'Hospital Corpsman', + 'Combat Technician', + 'Smartgunner', + 'Weapons Specialist', + 'Fireteam Leader', + 'Squad Leader', +]; +const marineSort = (a: Observable, b: Observable) => { + const a_index = rankList.findIndex((str) => a.job?.includes(str)) ?? 0; + const b_index = rankList.findIndex((str) => b.job?.includes(str)) ?? 0; + if (a_index === b_index) { + return a.full_name.localeCompare(b.full_name); + } + return a_index > b_index ? -1 : 1; +}; + +const GroupedObservable = (props: { + readonly color?: string; + readonly section: Array; + readonly title: string; + readonly splitter: splitter; + readonly sorter?: groupSorter; +}) => { + const { color, section = [], title } = props; + + const { value: searchQuery } = useContext(SearchContext); + + if (!section.length) { + return null; + } + + const filteredSection = section + .filter((observable) => isJobOrNameMatch(observable, searchQuery)) + .sort((a, b) => + a.full_name + .toLocaleLowerCase() + .localeCompare(b.full_name.toLocaleLowerCase()), + ); + + if (!filteredSection.length) { + return null; + } + + const squads = props.splitter(filteredSection); + + return ( + + + + {squads.map((x) => ( + + ))} + + + + ); +}; + /** * The primary content display for points of interest. * Renders a scrollable section replete with subsections for each * observable group. */ -const ObservableContent = (props: { readonly searchQuery: string }) => { +const ObservableContent = () => { const { data } = useBackend(); - const { searchQuery } = props; const { humans = [], marines = [], @@ -150,138 +285,76 @@ const ObservableContent = (props: { readonly searchQuery: string }) => { return ( - - - + + - + - + - - - - - - - - - + + + + + + + + ); }; @@ -294,21 +367,22 @@ const ObservableSection = (props: { readonly color?: string; readonly section: Array; readonly title: string; - readonly searchQuery: string; }) => { - const { color, section = [], title, searchQuery } = props; + const { color, section = [], title } = props; + + const { value: searchQuery } = useContext(SearchContext); if (!section.length) { return null; } - const filteredSection = sortBy( - filter(section, (observable) => isJobOrNameMatch(observable, searchQuery)), - (observable) => - getDisplayName(observable.full_name, observable.nickname) - .replace(/^"/, '') - .toLowerCase(), - ); + const filteredSection = section + .filter((observable) => isJobOrNameMatch(observable, searchQuery)) + .sort((a, b) => + a.full_name + .toLocaleLowerCase() + .localeCompare(b.full_name.toLocaleLowerCase()), + ); if (!filteredSection.length) { return null; @@ -356,6 +430,9 @@ const ObservableItem = (props: { tooltipPosition="bottom-start" > {displayHealth && } + {!!icon && ( + + )} {capitalizeFirst(getDisplayName(full_name, nickname))} {!!orbiters && ( <> diff --git a/tgui/packages/tgui/interfaces/Orbit/types.ts b/tgui/packages/tgui/interfaces/Orbit/types.ts index afbed5b16468..8318a91f1c89 100644 --- a/tgui/packages/tgui/interfaces/Orbit/types.ts +++ b/tgui/packages/tgui/interfaces/Orbit/types.ts @@ -39,3 +39,24 @@ export type Observable = { orbiters?: number; ref: string; }; + +export type SquadObservable = { + members: Array; + color: string; + title: string; +}; + +export const buildSquadObservable: ( + title: string, + color: string, + members: Array, +) => SquadObservable = (title, color, members = []) => { + return { + members: members, + color: color, + title: title, + }; +}; + +export type splitter = (members: Array) => Array; +export type groupSorter = (a: Observable, b: Observable) => number; From 780607955c1d14efeed24b3fb351190e5e925b76 Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Wed, 29 May 2024 18:31:01 +0100 Subject: [PATCH 4/9] Automatic changelog for PR #6346 [ci skip] --- html/changelogs/AutoChangeLog-pr-6346.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-6346.yml diff --git a/html/changelogs/AutoChangeLog-pr-6346.yml b/html/changelogs/AutoChangeLog-pr-6346.yml new file mode 100644 index 000000000000..b574a72da22b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-6346.yml @@ -0,0 +1,6 @@ +author: "mullenpaul" +delete-after: True +changes: + - ui: "orbit menu now splits marine squads" + - ui: "orbit menu now splits xeno hives" + - ui: "orbit menu sorts marines by job" \ No newline at end of file From a4a658604e10a67151665ee4ad43ec64a2f4aac4 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Thu, 30 May 2024 01:14:23 +0000 Subject: [PATCH 5/9] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-6345.yml | 4 ---- html/changelogs/AutoChangeLog-pr-6346.yml | 6 ------ html/changelogs/archive/2024-05.yml | 7 +++++++ 3 files changed, 7 insertions(+), 10 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-6345.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-6346.yml diff --git a/html/changelogs/AutoChangeLog-pr-6345.yml b/html/changelogs/AutoChangeLog-pr-6345.yml deleted file mode 100644 index 8321411f87b6..000000000000 --- a/html/changelogs/AutoChangeLog-pr-6345.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Drathek" -delete-after: True -changes: - - admin: "Logging for chem smoke is now niche logged and less spammy" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-6346.yml b/html/changelogs/AutoChangeLog-pr-6346.yml deleted file mode 100644 index b574a72da22b..000000000000 --- a/html/changelogs/AutoChangeLog-pr-6346.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "mullenpaul" -delete-after: True -changes: - - ui: "orbit menu now splits marine squads" - - ui: "orbit menu now splits xeno hives" - - ui: "orbit menu sorts marines by job" \ No newline at end of file diff --git a/html/changelogs/archive/2024-05.yml b/html/changelogs/archive/2024-05.yml index 593ae69be94f..74a91185afc3 100644 --- a/html/changelogs/archive/2024-05.yml +++ b/html/changelogs/archive/2024-05.yml @@ -330,3 +330,10 @@ - balance: Daze no longer stops xenos from talking and is slightly less punishing when applied to humans from the neurotoxic property - code_imp: New snowflake daze component for neurotoxic property +2024-05-30: + Drathek: + - admin: Logging for chem smoke is now niche logged and less spammy + mullenpaul: + - ui: orbit menu now splits marine squads + - ui: orbit menu now splits xeno hives + - ui: orbit menu sorts marines by job From 6bfac7c476338e58241f23d08c3ca12b502e5f88 Mon Sep 17 00:00:00 2001 From: Kaga-404 <103199482+Kaga-404@users.noreply.github.com> Date: Thu, 30 May 2024 01:33:16 -0700 Subject: [PATCH 6/9] Heavy Sniper Part 2 - The Heavying (#6163) # About the pull request New Updates: - AMR Aimed Shot base cast time increased by 60% from the M42A (1.25s to 2s), to emphasize working with spotter and normal shots, and solidly setting the Aimed Shot DPS under the M42A even under optimal conditions (decreased by ~40%). If this is too crippling, may increase Spotter Bino bonus to the AMR or slightly roll back cast time in the future. - Interrupt no longer applies to Queen and Crushers unless they are the primary target of an Aimed Shot. Damage threshold requirements still apply, and any piercing will still prevent it from interrupting big xenos at all. - Charger Strain no longer gets interrupted or slowed while charging. - Aimed Shot slow no longer applies to Runners, as they didn't have the protection of Focused Fire to reduce the duration by half initially. - Screenshake maximum against big xenos decreased by 1 step. Now applies at 90 and above to them, instead of 60. - Changed non-xeno (human) stun to stamina damage instead of directly stunning, to match slugs and high impact. XM43E1 AMR shots now have stopping power, a scaling system that functions similarly to shotgun slugs and heavy impact ammo, both in role and visible effect. **SCREENSHAKE:** Hitting a target will shake their screen so they know they got hit by something heavy. This shaking scales with damage dealt, with the maximum shake being equal to slugs and impact ammo. At 60 or less damage, this does not shake the screen. **INTERRUPTION:** Hitting a target will apply a mini-stun, scaling with damage dealt. At 60 or less damage, this does not interrupt targets at all. - Big Xenos need a base damage of 90 or more damage, will only ever by stunned for 0.1s max, and **cannot be knocked back.** - Other xenos can be stunned for up to 0.3s if the base damage is more than 120, losing 0.1s per 30 base damage, and will be knocked back at 90 damage or more. - Non-xenos can be stunned for up to 3s, losing 1s per 30 base damage. For comparison, impact rounds stun for 1s, and slugs stun for 1.4s as well as buckshot within range. **The stun on this is much lower as it is only meant to interrupt, and can affect big xenos if they are the only target hit, which other heavy rounds cannot.** **AIMED SHOT:** Can now potentially apply a slow scaling with stopping power, similar but much weaker than M42A Flak. At 60 or less base damage, no slows are applied. - Lasts for at most 5s of slow, 2.5s of superslow against runners and non-xenos, at 120 or more base damage. - Slows are reduced by 1s and 0.5s respectively per size tier, and for every 30 base damage lost. - If this slows any amount, it will always give 0.2s of reduced vision as a visible warning. Other Changes: - Defenders are no longer counted as an exception for Aimed Shot, only Runners. Defenders should take 200+20% current health damage on an aimed shot now, but are affected by Focus modifiers, so only 10% current health on first, then 15%, then 20% current health. Being Fortified reduces the flat damage to 125 but increases current health damage to 15/22.5/30%. - Increased base armor penetration for XM43E1 and M42C, as in rare cases target armor could go above 50. # Explain why it's good for the game The heavy sniper currently has almost no incentive to use its standard fire due to how little ammo it has, and being less damage efficient overall, as well as no utility on its normal shots. Consequently, it's unable to actually support allies in most cases. These mechanics should hopefully encourage standard fire more, especially against non T3s, allowing heavy sniper users to juggle their objectives of focusing aimed shots against a priority target while also using their standard shots at critical points to save allies from getting dragged off. This leans further into the weapon's identity as a support, as playtesting so far has shown that it's generally much worse at securing kills due to massively reduced DPS and aimed shot damage against T3s in the majority of situations, with its current health scaling. Because the stopping power mechanic has very low stun numbers, max 0.3s against xenos, and the firerate is incredibly low at 3s between shots, there's effectively no kill potential with this support feature. Instead, it's a way to save allies from a far distance like slug shotguns, but with IFF and much higher range, allowing it to be done from safety with no risk of slugging your teammates in the back because they resisted out of a grab. Additionally, high-caliber rounds should feel heavy, which is why ammo like Scout Impact and shotgun slugs give both mechanical and visual cues when they hit a target. Briefly reduced vision, stun, knockback. Both from the user's and target's perspectives, getting hit by a heavy sniper round doesn't have any visual cue different from a pistol bullet, and the only noticeable impact is health loss unless you're staring at chat to see the 'hit by' message. There's a distinctive firing sound, but in an active front it doesn't really let the target know they got hit by the AMR, in the midst of all the other guns firing in their direction. With this update, the screenshake and small knockdown should make it much more likely for targets to realize they've been hit by something dangerous. # Testing Photographs and Procedure
Screenshots & Videos Put screenshots and videos here with an empty line between the screenshots and the `
` tags.
# Changelog :cl: Kaga balance: The Heavy Sniper's XM43E1 rounds are now actually heavy. Targets hit will get screenshake, like slugs and impact rounds, scaling with damage dealt. balance: XM43E1 shots can now potentially interrupt targets if it deals enough damage. The heavier the target, the more force is needed to interrupt them. Big xenos require a full-damage shot with no piercing, while smaller targets can also be knocked back with enough damage. balance: XM43E1 Aimed Shots can now potentially apply a slow to the main target only, scaling with base damage and target size. If a slow is applied, vision range is reduced for a moment as a warning. balance: XM43E1 and M42C ammo AP increased to 75 (from 50) balance: Removed the Defender exception from the AMR Aimed Shot calculations. /:cl: --------- Co-authored-by: forest2001 <41653574+realforest2001@users.noreply.github.com> Co-authored-by: Drathek <76988376+Drulikar@users.noreply.github.com> --- code/datums/ammo/bullet/sniper.dm | 71 +++++++++++++++++-- .../modules/cm_marines/equipment/kit_boxes.dm | 2 +- .../projectiles/guns/specialist/sniper.dm | 5 +- 3 files changed, 71 insertions(+), 7 deletions(-) diff --git a/code/datums/ammo/bullet/sniper.dm b/code/datums/ammo/bullet/sniper.dm index fa45b269d810..eceea9f36fd3 100644 --- a/code/datums/ammo/bullet/sniper.dm +++ b/code/datums/ammo/bullet/sniper.dm @@ -106,11 +106,59 @@ accuracy = HIT_ACCURACY_TIER_8 damage = 125 shell_speed = AMMO_SPEED_TIER_6 + penetration = ARMOR_PENETRATION_TIER_10 + ARMOR_PENETRATION_TIER_5 + +/datum/ammo/bullet/sniper/anti_materiel/proc/stopping_power_knockback(mob/living/living_mob, obj/projectile/fired_projectile) + var/stopping_power = min(CEILING((fired_projectile.damage/30), 1), 5) // This is from bullet damage, and does not take Aimed Shot into account. + + if(!living_mob || living_mob == fired_projectile.firer) + return stopping_power + + if(stopping_power > 2) + + // Depending on target size and damage, may apply a mini-stun to interrupt channels. Support your allies! + // For reference: Scout Impact stuns for up to 1s and slows for up to 10s, Shotgun stuns for 1.4s and slows for 4s + if(living_mob.mob_size >= MOB_SIZE_BIG) + // If above 90 damage, screenshake. This maxes out at (2,3), weaker than other impact rounds. + if(stopping_power > 3) + shake_camera(living_mob, (stopping_power - 3), (stopping_power - 2)) + if(HAS_TRAIT(living_mob, TRAIT_CHARGING) && isxeno(living_mob)) + to_chat(living_mob, SPAN_WARNING("A sudden massive impact strikes you, but your charge will not be stopped!")) + return stopping_power + if(stopping_power >= 4) + to_chat(living_mob, SPAN_XENOHIGHDANGER("You are knocked off-balance by the sudden massive impact!")) + if(living_mob.mob_size >= MOB_SIZE_IMMOBILE && !((fired_projectile.projectile_flags & PROJECTILE_BULLSEYE) && living_mob == fired_projectile.original)) // Queens and Crushers + return stopping_power // For Crushers and Queens, must be aimed at them. + living_mob.KnockDown(0.05) // Must deal more than 90 damage to mini-stun big mobs for 0.1s + // Can't interrupt a big mob unless it's completely alone with nothing blocking the shot. + else + to_chat(living_mob, SPAN_XENODANGER("You are shaken by the sudden heavy impact!")) + else + // If above 60 damage, screenshake. This maxes out at (3,4) like buckshot and heavy rounds. (1,2) (2,3) or (3,4) + shake_camera(living_mob, (stopping_power - 2), (stopping_power - 1)) + if(living_mob.body_position != LYING_DOWN) + to_chat(living_mob, SPAN_XENOHIGHDANGER("You are thrown back by the sudden massive force!")) + slam_back(living_mob, fired_projectile) + else + to_chat(living_mob, SPAN_XENODANGER("You are shaken by the sudden heavy impact!")) + + if(isxeno(living_mob)) + living_mob.KnockDown((stopping_power - 2)*0.05) // Up to 0.3s on a solo target. + else + if(living_mob.stamina) + living_mob.apply_stamina_damage(fired_projectile.ammo.damage, fired_projectile.def_zone, ARMOR_BULLET) + // Not sure what this comes out to exactly, but follows the example of other heavy ammo like slugs of applying full base damage as stamina damage. + else + living_mob.KnockDown((stopping_power - 2)*0.3) // Rare exception of up to 1.8s on non-xenos without stamina. + + return stopping_power /datum/ammo/bullet/sniper/anti_materiel/on_hit_mob(mob/target_mob,obj/projectile/aimed_projectile) var/mob/living/living_target = target_mob + var/stopping_power = stopping_power_knockback(living_target, aimed_projectile) + if((aimed_projectile.projectile_flags & PROJECTILE_BULLSEYE) && target_mob == aimed_projectile.original) var/amr_counter = 0 @@ -150,22 +198,28 @@ var/size_damage_mod = 0.8 // 1.8x vs Non-Xenos (225) var/size_current_health_damage = 0 // % Current Health calculation, only used for Xeno calculations at the moment. var/focused_fire_active = 0 // Whether to try and use focused fire calculations or not, for that kind of target. + var/slow_duration = stopping_power // Based on damage dealt. + + if(slow_duration <= 2) // Must be over 60 base damage. + slow_duration = 0 if(isxeno(target_mob)) var/mob/living/carbon/xenomorph/target = target_mob size_damage_mod -= 0.2 // Down to 1.6x damage, 200. size_current_health_damage = 0.1 // 1.6x Damage + 10% current health (200 + 10%, 223 vs Runners) - if(target.mob_size >= MOB_SIZE_XENO && (target.caste_type != XENO_CASTE_DEFENDER)) + if(target.mob_size >= MOB_SIZE_XENO) size_current_health_damage += 0.1 // 1.6x Damage + 20% current health focused_fire_active = 1 // Focus Fire Required. Only deals 50% bonus damage on a first Aimed Shot, then 75%, then 100%. Resets with a successful aimed shot on another target. + slow_duration = max(slow_duration-1, 0) - if(target.mob_size >= MOB_SIZE_BIG && (target.caste_type != XENO_CASTE_DEFENDER)) + if(target.mob_size >= MOB_SIZE_BIG) size_damage_mod -= 0.6 // Down to 1x Damage. size_current_health_damage += 0.1 // 1x Damage + 30% current health. focused_fire_active = 1 + slow_duration = max(slow_duration-1, 0) // Most T3s have around 650 to 700 HP, meaning the health modifier grants a MAXIMUM of around 195-210 damage for a total max of 320-335. This is fully focused (3 shots) and at max HP. - // Queen takes around 275 at max health and unfocused, 425 fully focused. Defender only takes 200 damage, even while fortified, but still causes falloff like a Big Xeno. + // Queen takes around 275 at max health and unfocused, 425 fully focused. // At low health, does little more than a normal shot. Does WORSE than a normal shot if unfocused and hitting through blockers, all of which stack to reduce it. var/final_xeno_damage = ((damage * size_damage_mod) + ((target.health + damage) * size_current_health_damage)) @@ -173,13 +227,21 @@ if(focused_fire_active && amr_counter) // If this is a target that needs to be focus-fired and the gun supports it, reduce bonus damage to 50%, then 75%, then 100% // If amr_counter is 0, then the gun likely doesn't have the tracker functions, so skip this and deal normal damage. final_xeno_damage *= (0.25 + (0.25 * amr_counter)) + slow_duration *= (0.25 + (0.25 * amr_counter)) // 0-3s slow on Big mobs, based on Focus and falloff. living_target.apply_armoured_damage((final_xeno_damage), ARMOR_BULLET, BRUTE, null, penetration) else living_target.apply_armoured_damage((damage*size_damage_mod), ARMOR_BULLET, BRUTE, null, penetration) - // Base 1.8x damage to non-xeno targets (225), 1.6x + 10% current against Runners and Defenders (223), 1.6x + 20% current health against most non-Runner xenos, and +30% current health against Big xenos. -Kaga + if(slow_duration && (living_target.mob_size != MOB_SIZE_XENO_SMALL) && !(HAS_TRAIT(living_target, TRAIT_CHARGING))) // Runners and Charging Crushers are not slowed. + living_target.Slow((slow_duration / 2)) + if(slow_duration >= 2) + living_target.Superslow((slow_duration / 4)) + if(stopping_power > 3) + living_target.Daze(0.1) // Visual cue that you got hit by something HARD. + + // Base 1.8x damage to non-xeno targets (225), 1.6x + 10% current against Runners (223), 1.6x + 20% current health against most non-Runner xenos, and 1x + 30% current health against Big xenos. -Kaga // This applies after pen reductions. After hitting 1 other thing, it deals 80% damage, or 40% after hitting a dense wall or big xeno. if((focused_fire_active || isxeno(target_mob)) && !(target_mob.is_dead())) @@ -253,6 +315,7 @@ accuracy = HIT_ACCURACY_TIER_8 damage = 150 shell_speed = AMMO_SPEED_TIER_6 + AMMO_SPEED_TIER_2 + penetration = ARMOR_PENETRATION_TIER_10 + ARMOR_PENETRATION_TIER_5 /datum/ammo/bullet/sniper/elite/set_bullet_traits() . = ..() diff --git a/code/modules/cm_marines/equipment/kit_boxes.dm b/code/modules/cm_marines/equipment/kit_boxes.dm index 43e6bc90e220..e0220d017d42 100644 --- a/code/modules/cm_marines/equipment/kit_boxes.dm +++ b/code/modules/cm_marines/equipment/kit_boxes.dm @@ -71,7 +71,7 @@ /obj/item/storage/box/spec/sniper/anti_materiel/fill_preset_inventory() name = "\improper AMR equipment case" - desc = "A large case containing an experimental XM43E1, a set of M45 ghillie armor and helmet, a M42 scout sight, ammunition, spotter equipment, and additional pieces of equipment.\nDrag this sprite onto yourself to open it up! NOTE: You cannot put items back inside this case." + desc = "A large case containing an experimental XM43E1, a set of M45 ghillie armor and helmet, an M42 scout sight, ammunition, a set of spotter gear, and additional pieces of equipment.\nDrag this sprite onto yourself to open it up! NOTE: You cannot put items back inside this case." new /obj/item/clothing/suit/storage/marine/ghillie(src) new /obj/item/clothing/head/helmet/marine/ghillie(src) new /obj/item/clothing/glasses/night/m42_night_goggles(src) diff --git a/code/modules/projectiles/guns/specialist/sniper.dm b/code/modules/projectiles/guns/specialist/sniper.dm index fe79d995d1a6..a6bb400ba5c9 100644 --- a/code/modules/projectiles/guns/specialist/sniper.dm +++ b/code/modules/projectiles/guns/specialist/sniper.dm @@ -29,7 +29,7 @@ . = ..() if(!has_aimed_shot) return - . += SPAN_NOTICE("This weapon has an unique ability, Aimed Shot, allowing it to deal great damage after a windup.
Additionally, the aimed shot can be sped up with a tracking laser, which is enabled by default but may be disabled.") + . += SPAN_NOTICE("This weapon has a special ability, Aimed Shot, allowing it to deal increased damage and inflict additional crippling effects after a windup, depending on the ammunition used.
Additionally, the aimed shot can be sped up with a spotter or by using the tracking laser, which is enabled by default but may be disabled.") /obj/item/weapon/gun/rifle/sniper/Initialize(mapload, spawn_empty) if(has_aimed_shot) @@ -362,12 +362,13 @@ /obj/item/weapon/gun/rifle/sniper/XM43E1 name = "\improper XM43E1 experimental anti-materiel rifle" - desc = "An experimental anti-materiel rifle produced by Armat Systems, recently reacquired from the deep storage of an abandoned prototyping facility. This one in particular is currently undergoing field testing. Chambered in 10x99mm Caseless.\nThis weapon can punch through thin metal plating and walls, though it'll lose most of its lethality in the process. It can even work for demolitions, with experienced users known to disassemble segments of solid, reinforced walls in the field with just a single standard magazine of 10x99mm. In lieu of explosives or an engineer, they instead use each of the 8 shots to break down vital structural supports, taking the wall apart in the process." + desc = "An experimental anti-materiel rifle produced by Armat Systems, recently reacquired from the deep storage of an abandoned prototyping facility. This one in particular is currently undergoing field testing. Chambered in 10x99mm Caseless.\n\nThis weapon can punch through thin metal plating and walls, though it'll lose most of its lethality in the process. It can even work for demolitions, with experienced users known to disassemble segments of solid, reinforced walls in the field with just a single standard magazine of 10x99mm. In lieu of explosives or an engineer, they instead use each of the 8 shots to break down vital structural supports, taking the wall apart in the process." icon = 'icons/obj/items/weapons/guns/guns_by_faction/uscm.dmi' icon_state = "xm43e1" item_state = "xm43e1" unacidable = TRUE indestructible = 1 + aiming_time = 2 SECONDS aimed_shot_cooldown_delay = 4.5 SECONDS var/focused_fire_counter = 0 var/datum/weakref/focused_fire_target = null From 642e21277a96e8aee9cb7ea178128386c405b024 Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Thu, 30 May 2024 09:37:43 +0100 Subject: [PATCH 7/9] Automatic changelog for PR #6163 [ci skip] --- html/changelogs/AutoChangeLog-pr-6163.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-6163.yml diff --git a/html/changelogs/AutoChangeLog-pr-6163.yml b/html/changelogs/AutoChangeLog-pr-6163.yml new file mode 100644 index 000000000000..d8f5715ed988 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-6163.yml @@ -0,0 +1,8 @@ +author: "Kaga" +delete-after: True +changes: + - balance: "The Heavy Sniper's XM43E1 rounds are now actually heavy. Targets hit will get screenshake, like slugs and impact rounds, scaling with damage dealt." + - balance: "XM43E1 shots can now potentially interrupt targets if it deals enough damage. The heavier the target, the more force is needed to interrupt them. Big xenos require a full-damage shot with no piercing, while smaller targets can also be knocked back with enough damage." + - balance: "XM43E1 Aimed Shots can now potentially apply a slow to the main target only, scaling with base damage and target size. If a slow is applied, vision range is reduced for a moment as a warning." + - balance: "XM43E1 and M42C ammo AP increased to 75 (from 50)" + - balance: "Removed the Defender exception from the AMR Aimed Shot calculations." \ No newline at end of file From 681e5220588fa75888de0f6c11ab25427884aff3 Mon Sep 17 00:00:00 2001 From: Tyranicranger4 <80382633+Tyranicranger4@users.noreply.github.com> Date: Thu, 30 May 2024 08:43:49 -0700 Subject: [PATCH 8/9] Fixes Burrowers being able to use corrosive acid while underground (#6348) # About the pull request Adds an extra check for being burrowed *after* the do_after in corrosive acid. Without this (how things are before this PR) it's possible to start channeling the burrow ability and then start aciding an object, in which case the acid will finish applying while you're underground since you've already cleared the check for being burrowed. # Explain why it's good for the game Obviously unintended behavior and I *have* seen people in-game abusing this. It's quite awful to play against since there is absolutely zero counterplay. # Testing Photographs and Procedure
Screenshots & Videos Put screenshots and videos here with an empty line between the screenshots and the `
` tags. https://streamable.com/22ualc
# Changelog :cl: fix: Fixed an exploit that allowed Burrowers to apply acid to objects while underground /:cl: --- .../living/carbon/xenomorph/abilities/ability_helper_procs.dm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/ability_helper_procs.dm b/code/modules/mob/living/carbon/xenomorph/abilities/ability_helper_procs.dm index 0990df678f61..0472dd9901b2 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/ability_helper_procs.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/ability_helper_procs.dm @@ -106,6 +106,10 @@ to_chat(src, SPAN_WARNING("[A] is already drenched in acid.")) return + if(HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) //Checked again to account for people trying to place acid while channeling the burrow ability + to_chat(src, SPAN_WARNING("We can't melt [O] from here!")) + return + if(!check_state()) return From a8e1d419f3ecd1134b0428f2a34b7a5e632cbea5 Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Thu, 30 May 2024 16:48:03 +0100 Subject: [PATCH 9/9] Automatic changelog for PR #6348 [ci skip] --- html/changelogs/AutoChangeLog-pr-6348.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-6348.yml diff --git a/html/changelogs/AutoChangeLog-pr-6348.yml b/html/changelogs/AutoChangeLog-pr-6348.yml new file mode 100644 index 000000000000..90a466eef737 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-6348.yml @@ -0,0 +1,4 @@ +author: "Tyranicranger4" +delete-after: True +changes: + - bugfix: "Fixed an exploit that allowed Burrowers to apply acid to objects while underground" \ No newline at end of file