diff --git a/lang/en.json b/lang/en.json index 8603325..f268d6e 100644 --- a/lang/en.json +++ b/lang/en.json @@ -1,5 +1,9 @@ { - "lancer-weapon-fx.Sound Volume": "Sound Volume", - "lancer-weapon-fx.Sound Volume Hint": "Set a base volume level for all sound effects. Note that for each user, this value is combined with the user's \"Global: Interface\" volume setting (see the \"Playlists\" sidebar tab) to produce their final volume level.", - "lancer-weapon-fx.Debug: Play Miss Animations by Default": "Debug: Play Miss Animations by Default" + "lancer-weapon-fx": { + "Sound Volume": "Sound Volume", + "Sound Volume Hint": "Set a base volume level for all sound effects. Note that for each user, this value is combined with the user's \"Global: Interface\" volume setting (see the \"Playlists\" sidebar tab) to produce their final volume level.", + "Use Weapon Heuristic": "Use Weapon Heuristic", + "Use Weapon Heuristic Hint": "Use a heuristic to determine a suitable effect to play when using an unknown (homebrew/custom) weapon.", + "Debug: Play Miss Animations by Default": "Debug: Play Miss Animations by Default" + } } diff --git a/scripts/effectResolver/weaponEffects.js b/scripts/effectResolver/weaponEffects.js index 8040223..4f49cdb 100644 --- a/scripts/effectResolver/weaponEffects.js +++ b/scripts/effectResolver/weaponEffects.js @@ -199,6 +199,20 @@ const weaponEffects = { "npc_Tempest_NaniteMonsoonDispensers": "Nexus", "npc_Tempest_TyphoonNaniteCannon": "Nexus", "npc_PDCTurret": "Leviathan", + //HEURISTICS + "lwfx_heuristic_melee": "DefaultMelee", + "lwfx_heuristic_cqb_energy": "PPC", + "lwfx_heuristic_cqb_shotgun": "Shotgun", + "lwfx_heuristic_cqb_other": "Pistol", + "lwfx_heuristic_cannon_energy": "Tachyon Lance", + "lwfx_heuristic_cannon_mg": "HMG", + "lwfx_heuristic_cannon_other": "Mortar", + "lwfx_heuristic_launcher": "Missile", + "lwfx_heuristic_nexus": "Nexus", + "lwfx_heuristic_rifle_energy": "Thermal Rifle", + "lwfx_heuristic_rifle_mg": "HMG", + "lwfx_heuristic_rifle_ar": "Assault Rifle", + "lwfx_heuristic_rifle_other": "AMR", }; export { weaponEffects }; diff --git a/scripts/flow/WeaponAttackFlow/heuristic.js b/scripts/flow/WeaponAttackFlow/heuristic.js new file mode 100644 index 0000000..e1d7ea8 --- /dev/null +++ b/scripts/flow/WeaponAttackFlow/heuristic.js @@ -0,0 +1,68 @@ +import { MODULE_ID } from "../../consts.js"; +import { SETTING_IS_WEAPON_HEURISTIC_ACTIVE } from "../../settings.js"; + +const getPrimaryDamageType = ({ activeProfile }) => { + return activeProfile.all_damage?.[0]?.type; +}; + +const getPrimaryRange = ({ activeProfile }) => { + return activeProfile.all_range?.[0]?.type; +}; + +const isShotgun = ({ name, activeProfile }) => { + if (getPrimaryRange({ activeProfile }) === "Cone") return true; + return /\bshotgun\b/i.test(name); +}; + +const isMachineGun = ({ name }) => { + return /\b(?:assault|lmg|hmg|machine gun|minigun)\b/i.test(name); +}; + +export const fallbackActionIdentifier = flow => { + if (!game.settings.get(MODULE_ID, SETTING_IS_WEAPON_HEURISTIC_ACTIVE)) return null; + + const activeProfile = flow.state.item?.system?.active_profile; + if (!activeProfile) return null; + + const { + name, + system: { size }, + } = flow.state.item; + + switch (flow.state.item.system.active_profile.type) { + case "Melee": { + return "lwfx_heuristic_melee"; + } + + case "CQB": { + if (getPrimaryDamageType({ activeProfile }) === "Energy") return "lwfx_heuristic_cqb_energy"; + if (isShotgun({ name, activeProfile })) return "lwfx_heuristic_cqb_shotgun"; + return "lwfx_heuristic_cqb_other"; + } + + case "Rifle": { + if (getPrimaryDamageType({ activeProfile }) === "Energy") return "lwfx_heuristic_rifle_energy"; + if (isMachineGun({ name })) { + if (["Heavy", "Superheavy"].includes(size)) return "lwfx_heuristic_rifle_mg"; + return "lwfx_heuristic_rifle_ar"; + } + return "lwfx_heuristic_rifle_other"; + } + + case "Launcher": { + return "lwfx_heuristic_launcher"; + } + + case "Cannon": { + if (getPrimaryDamageType({ activeProfile }) === "Energy") return "lwfx_heuristic_cannon_energy"; + if (isMachineGun({ name })) return "lwfx_heuristic_cannon_mg"; + return "lwfx_heuristic_cannon_other"; + } + + case "Nexus": { + return "lwfx_heuristic_nexus"; + } + } + + return null; +}; diff --git a/scripts/flow/flowListener.js b/scripts/flow/flowListener.js index e3a9682..56c59ad 100644 --- a/scripts/flow/flowListener.js +++ b/scripts/flow/flowListener.js @@ -1,5 +1,6 @@ import { FlowInfo, getTokenByIdOrActorId, processFlowInfo } from "./common.js"; import { pGetMacroUuid } from "../effectResolver/effectResolver.js"; +import { fallbackActionIdentifier as fallbackActionIdentifier_WeaponAttackFlow } from "./WeaponAttackFlow/heuristic.js"; /** * @param state @@ -108,7 +109,10 @@ const _onReady = () => { if (!foundry.utils.isNewerVersion(game.version, "11")) return; // Weapon attacks - _bindFlowHook({ flowName: "WeaponAttackFlow" }); + _bindFlowHook({ + flowName: "WeaponAttackFlow", + fallbackActionIdentifier: fallbackActionIdentifier_WeaponAttackFlow, + }); // Basic attacks _bindFlowHook({ flowName: "BasicAttackFlow", fallbackActionIdentifier: fallbackActionIdentifier_BasicAttackFlow }); diff --git a/scripts/settings.js b/scripts/settings.js index 35065d7..475d31a 100644 --- a/scripts/settings.js +++ b/scripts/settings.js @@ -1,6 +1,7 @@ import { MODULE_ID } from "./consts.js"; export const SETTING_VOLUME = "volume"; +export const SETTING_IS_WEAPON_HEURISTIC_ACTIVE = "isWeaponHeuristicActive"; export const SETTING_DEBUG_IS_DEFAULT_MISS = "debug-is-default-miss"; @@ -17,6 +18,15 @@ export const bindHooks = () => { default: 1.0, }); + game.settings.register(MODULE_ID, SETTING_IS_WEAPON_HEURISTIC_ACTIVE, { + name: "lancer-weapon-fx.Use Weapon Heuristic", + hint: "lancer-weapon-fx.Use Weapon Heuristic Hint", + scope: "world", + config: true, + type: Boolean, + default: true, + }); + game.settings.register(MODULE_ID, SETTING_DEBUG_IS_DEFAULT_MISS, { name: "lancer-weapon-fx.Debug: Play Miss Animations by Default", scope: "client",