diff --git a/package.json b/package.json index bd08bb2f..d5e9b240 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,11 @@ "fmt": "next lint --fix", "analyse": "ANALYSE=true next build", "test": "jest", - "cdn-docker": "yarn build-docker-scraper && docker run --rm -it -v $(pwd)/cdn:/srv/cdn -v $(pwd)/src/lib/EquipmentAliases.ts:/srv/src/lib/EquipmentAliases.ts weirdgloop/osrs-dps-calc:scraper", + "cdn-docker-base": "docker run --rm -it -v $(pwd)/scripts:/srv/scripts -v $(pwd)/cdn:/srv/cdn -v $(pwd)/src/lib/EquipmentAliases.ts:/srv/src/lib/EquipmentAliases.ts weirdgloop/osrs-dps-calc:scraper", + "cdn-docker": "yarn build-docker-scraper && yarn cdn-docker-base", + "cdn-docker-aliases": "yarn cdn-docker-base python generateEquipmentAliases.py", + "cdn-docker-equipment": "yarn cdn-docker-base python generateEquipment.py", + "cdn-docker-monsters": "yarn cdn-docker-base python generateMonsters.py", "cdn-dispatch": "gh workflow run regenerate.yml" }, "dependencies": { diff --git a/src/app/home.tsx b/src/app/home.tsx index 6f153faf..b66ed6d0 100644 --- a/src/app/home.tsx +++ b/src/app/home.tsx @@ -3,7 +3,7 @@ import type { NextPage } from 'next'; import MonsterContainer from '@/app/components/monster/MonsterContainer'; import { Tooltip } from 'react-tooltip'; -import React, { Suspense, useEffect } from 'react'; +import React, { Suspense, useEffect, useMemo } from 'react'; import { observer } from 'mobx-react-lite'; import { useStore } from '@/state'; import { ToastContainer } from 'react-toastify'; @@ -18,6 +18,11 @@ import DebugPanels from '@/app/components/results/DebugPanels'; import { IconAlertTriangle } from '@tabler/icons-react'; import NPCVersusPlayerResultsContainer from '@/app/components/results/NPCVersusPlayerResultsContainer'; import { CalcProvider, useCalc } from '@/worker/CalcWorker'; +import UserIssueType from '@/enums/UserIssueType'; + +const GLOBAL_ISSUE_TYPES: UserIssueType[] = [ + UserIssueType.IMPORT_MISSING_DATA, +]; const Home: NextPage = observer(() => { const calc = useCalc(); @@ -91,6 +96,23 @@ const Home: NextPage = observer(() => { // eslint-disable-next-line react-hooks/exhaustive-deps }, []); + const globalIssues = useMemo(() => { + const issues = store.userIssues.filter((is) => GLOBAL_ISSUE_TYPES.includes(is.type)); + return ( + <> + {issues.map((is) => ( +
+ + {`${is.loadout ? `Loadout ${is.loadout}: ` : ''}${is.message}`} +
+ ))} + + ); + }, [store.userIssues]); + return (
{store.prefs.manualMode && ( @@ -103,6 +125,7 @@ const Home: NextPage = observer(() => { Manual mode is enabled! Some things may not function correctly. Click here to disable it. )} + {globalIssues} diff --git a/src/enums/UserIssueType.ts b/src/enums/UserIssueType.ts index c7e65cf5..34da3741 100644 --- a/src/enums/UserIssueType.ts +++ b/src/enums/UserIssueType.ts @@ -1,10 +1,12 @@ enum UserIssueType { EQUIPMENT_MISSING_AMMO = 'equipment_slot_ammo_missing', EQUIPMENT_WRONG_AMMO = 'equipment_slot_ammo_wrong', + EQUIPMENT_WEAPON_EMPTY = 'equipment_slot_weapon_empty', EQUIPMENT_SET_EFFECT_UNSUPPORTED = 'equipment_slot_body_unsupported_set_effect', SPELL_WRONG_WEAPON = 'spell_wrong_weapon', SPELL_WRONG_MONSTER = 'spell_wrong_monster', MONSTER_UNIQUE_EFFECTS = 'monster_overall_unique_effects', + IMPORT_MISSING_DATA = 'runelite_import_missing_data', } export default UserIssueType; diff --git a/src/lib/BaseCalc.ts b/src/lib/BaseCalc.ts index 3034ce1b..6aa52d8a 100644 --- a/src/lib/BaseCalc.ts +++ b/src/lib/BaseCalc.ts @@ -1,6 +1,11 @@ import { EquipmentPiece, Player } from '@/types/Player'; import { Monster } from '@/types/Monster'; -import { AmmoApplicability, ammoApplicability, getCanonicalEquipment } from '@/lib/Equipment'; +import { + AmmoApplicability, + ammoApplicability, + EMPTY_BLOWPIPE, + getCanonicalEquipment, +} from '@/lib/Equipment'; import UserIssueType from '@/enums/UserIssueType'; import { MonsterAttribute } from '@/enums/MonsterAttribute'; import { CAST_STANCES } from '@/lib/constants'; @@ -58,6 +63,8 @@ export default class BaseCalc { userIssues: UserIssue[] = []; + protected fatal: boolean = false; + constructor(player: Player, monster: Monster, opts: CalcOpts = {}) { this.opts = { ...DEFAULT_OPTS, @@ -532,8 +539,14 @@ export default class BaseCalc { ]); } - protected addIssue(type: UserIssueType, message: string) { - this.userIssues.push({ type, message, loadout: this.opts.loadoutName }); + protected addIssue(type: UserIssueType, message: string, severity: UserIssue['severity'] = 'warn') { + this.userIssues.push({ + type, + severity, + message, + loadout: this.opts.loadoutName, + }); + this.fatal ||= severity === 'fatal'; } private sanitizeInputs() { @@ -558,11 +571,12 @@ export default class BaseCalc { }; } - if (this.player.style.stance !== 'Manual Cast' && ammoApplicability(eq.weapon?.id, eq.ammo?.id) === AmmoApplicability.INVALID) { + if (ammoApplicability(eq.weapon?.id, eq.ammo?.id) === AmmoApplicability.INVALID) { + const severity = this.player.style.stance === 'Manual Cast' ? 'warn' : 'fatal'; if (eq.ammo?.name) { - this.addIssue(UserIssueType.EQUIPMENT_WRONG_AMMO, 'This ammo does not work with your current weapon.'); + this.addIssue(UserIssueType.EQUIPMENT_WRONG_AMMO, 'This ammo does not work with your current weapon.', severity); } else { - this.addIssue(UserIssueType.EQUIPMENT_MISSING_AMMO, 'Your weapon requires ammo to use.'); + this.addIssue(UserIssueType.EQUIPMENT_MISSING_AMMO, 'Your weapon requires ammo to use.', severity); } } @@ -579,7 +593,7 @@ export default class BaseCalc { ...this.player, spell: null, }; - this.addIssue(UserIssueType.SPELL_WRONG_WEAPON, 'This spell needs a specific weapon equipped to cast.'); + this.addIssue(UserIssueType.SPELL_WRONG_WEAPON, 'This spell needs a specific weapon equipped to cast.', 'fatal'); } // Certain spells can only be cast on specific monsters @@ -591,7 +605,7 @@ export default class BaseCalc { ...this.player, spell: null, }; - this.addIssue(UserIssueType.SPELL_WRONG_MONSTER, 'This spell cannot be cast on the selected monster.'); + this.addIssue(UserIssueType.SPELL_WRONG_MONSTER, 'This spell cannot be cast on the selected monster.', 'fatal'); } // Some set effects are currently not accounted for @@ -601,5 +615,14 @@ export default class BaseCalc { ) { this.addIssue(UserIssueType.EQUIPMENT_SET_EFFECT_UNSUPPORTED, 'The calculator currently does not account for your equipment set effect.'); } + + if (this.wearing(['Toxic blowpipe', 'Blazing blowpipe'])) { + const severity = this.player.style.stance === 'Manual Cast' ? 'warn' : 'fatal'; + if (eq.weapon?.version === 'Empty') { + this.addIssue(UserIssueType.EQUIPMENT_WEAPON_EMPTY, 'An empty weapon cannot be used.', severity); + } else if (eq.weapon?.bonuses?.ranged_str === EMPTY_BLOWPIPE?.bonuses?.ranged_str) { + this.addIssue(UserIssueType.IMPORT_MISSING_DATA, 'The import data did not specify darts for the blowpipe equipped', severity); + } + } } } diff --git a/src/lib/Equipment.ts b/src/lib/Equipment.ts index 6b2e22ee..ea500bea 100644 --- a/src/lib/Equipment.ts +++ b/src/lib/Equipment.ts @@ -12,6 +12,9 @@ export type EquipmentBonuses = Pick e.name === 'Toxic blowpipe' && e.version === 'Charged', +); export const noStatExceptions = [ 'Castle wars bracelet', diff --git a/src/lib/PlayerVsNPCCalc.ts b/src/lib/PlayerVsNPCCalc.ts index d8d7f554..d5272915 100644 --- a/src/lib/PlayerVsNPCCalc.ts +++ b/src/lib/PlayerVsNPCCalc.ts @@ -707,12 +707,8 @@ export default class PlayerVsNPCCalc extends BaseCalc { * Get the max hit for this loadout, which is based on the player's current combat style */ private getMaxHit(): MinMax { - if (this.player.style.stance !== 'Manual Cast') { - const weaponId = this.player.equipment.weapon?.id; - const ammoId = this.player.equipment.ammo?.id; - if (ammoApplicability(weaponId, ammoId) === AmmoApplicability.INVALID) { - return [0, 0]; - } + if (this.fatal) { + return [0, 0]; } const style = this.player.style.type; @@ -818,6 +814,10 @@ export default class PlayerVsNPCCalc extends BaseCalc { } private getDistributionImpl(): AttackDistribution { + if (this.fatal) { + return new AttackDistribution([new HitDistribution([new WeightedHit(1.0, [new Hitsplat(0, false)])])]); + } + const mattrs = this.monster.attributes; const acc = this.getHitChance(); const [min, max] = this.getMaxHit(); diff --git a/src/types/State.ts b/src/types/State.ts index b1aac6d8..278d7dec 100644 --- a/src/types/State.ts +++ b/src/types/State.ts @@ -6,6 +6,7 @@ import { DetailEntry } from '@/lib/CalcDetails'; export interface UserIssue { type: UserIssueType; + severity: 'warn' | 'fatal'; message: string; loadout?: string; }