From 8cb37c09e58204d29d7d01c9f6dda6414d453584 Mon Sep 17 00:00:00 2001 From: Wrycu Date: Tue, 6 Feb 2024 21:54:36 -0800 Subject: [PATCH] feat(animations): animations will now miss if the attack misses * there is also slight variation on where hits hit --- ffg-star-wars-enhancements.js | 1 + release-notes.md | 2 ++ scripts/animation.js | 61 +++++++++++++++++++++++++++++------ 3 files changed, 55 insertions(+), 9 deletions(-) diff --git a/ffg-star-wars-enhancements.js b/ffg-star-wars-enhancements.js index f9c7b9f..68cb897 100644 --- a/ffg-star-wars-enhancements.js +++ b/ffg-star-wars-enhancements.js @@ -153,6 +153,7 @@ function register_hooks() { we may want to monkeypatch a different function in the future. this location doesn't seem to have access to the actual weapon in use. I'm not sure if we actually care yet, but worth considering. */ + if (!this._evaluated) this.evaluate(); var data = attack_animation(this, ...args); return wrapped(...data); } diff --git a/release-notes.md b/release-notes.md index 78ec248..eb61ab9 100644 --- a/release-notes.md +++ b/release-notes.md @@ -1,6 +1,8 @@ - NEW FEATURE: Configurable Book of Boba Fett-style title cards can be played like the opening crawl - IMPROVEMENT: Opening crawl timing can be configured in the settings - FIX: Module settings popup windows titles corrected +- NEW FEATURE: Attack animations now take into account if the attack hit or not. Have fun watching blaster bolts go + everywhere but your target! `2.0.5` - 2023-12-29 diff --git a/scripts/animation.js b/scripts/animation.js index 80c0af0..b8ac4be 100644 --- a/scripts/animation.js +++ b/scripts/animation.js @@ -200,7 +200,10 @@ export function attack_animation_check() { export function attack_animation(...args) { // take our custom arg out of the array so we don't return it - let that = args[0]; + const roll_data = args[0]; + console.log(roll_data); + const hit = roll_data.ffg.success > 0; + console.log(hit); args = args.splice(1); if (!game.settings.get("ffg-star-wars-enhancements", "attack-animation-enable")) { @@ -311,14 +314,14 @@ export function attack_animation(...args) { actor_id = args[0]["speaker"]["actor"]["_id"]; } - if (that["data"] === null || jQuery.isEmptyObject(that["data"])) { + if (roll_data["data"] === null || jQuery.isEmptyObject(roll_data["data"])) { // this was a roll from a skill var flag_data = null; var item_name = null; } else { // this was a roll from an item - let item_id = that["data"]["_id"]; - var item_name = that["data"]["name"]; + let item_id = roll_data["data"]["_id"]; + var item_name = roll_data["data"]["name"]; let the_item = game.actors.get(actor_id).items.get(item_id); if (the_item !== null && the_item !== undefined) { var flag_data = the_item.getFlag("ffg-star-wars-enhancements", "attack-animation"); @@ -361,7 +364,7 @@ export function attack_animation(...args) { // todo: based on dice results, we could have the animation miss log("attack_animation", "Playing the attack animation: " + animation_file + " / " + sound_file); // noinspection JSIgnoredPromiseFromCall - play_animation(animation_file, sound_file, skill, source, count); + play_animation(animation_file, sound_file, skill, source, count, hit); return args; } else { // not a combat skill; ignore it @@ -371,9 +374,12 @@ export function attack_animation(...args) { const sleepNow = (delay) => new Promise((resolve) => setTimeout(resolve, delay)); -async function play_animation(animation_file, sound_file, skill, source, count) { +async function play_animation(animation_file, sound_file, skill, source, count, hit) { const tokens = source; + let min_miss_offset = 30; + let max_miss_offset = 50; var arrayLength = game.user.targets.size; + let position; for (var i = 0; i < arrayLength; i++) { if (count !== null) { var range = count.split("-"); @@ -394,9 +400,46 @@ async function play_animation(animation_file, sound_file, skill, source, count) var num_shots = Math.floor(Math.random() * 6 + 1); } for (var x = lower_bound - 1; x < num_shots; x++) { + const center = Array.from(game.user.targets)[i].center; + // pick a random spot to draw the ray to (based on if the attack hit or not) + if (hit) { + min_miss_offset = 2; + max_miss_offset = 15; + } else { + min_miss_offset = 40; + max_miss_offset = 55; + } + let dir = Math.floor(Math.random() * 4); + switch (dir) { + case 0: + position = { + x: center["x"] - Math.floor(Math.random() * max_miss_offset) - min_miss_offset, + y: center["y"] - Math.floor(Math.random() * max_miss_offset) - min_miss_offset, + }; + break; + case 1: + position = { + x: center["x"] - Math.floor(Math.random() * max_miss_offset) - min_miss_offset, + y: center["y"] + Math.floor(Math.random() * max_miss_offset) + min_miss_offset, + }; + break; + case 2: + position = { + x: center["x"] + Math.floor(Math.random() * max_miss_offset) + min_miss_offset, + y: center["y"] - Math.floor(Math.random() * max_miss_offset) - min_miss_offset, + }; + break; + case 3: + position = { + x: center["x"] + Math.floor(Math.random() * max_miss_offset) + min_miss_offset, + y: center["y"] + Math.floor(Math.random() * max_miss_offset) + min_miss_offset, + }; + break; + } + // configure the animation if (skill === "grenade") { var animation_config = { - position: Array.from(game.user.targets)[i].center, + position: position, file: animation_file, anchor: { x: 0.5, @@ -405,7 +448,7 @@ async function play_animation(animation_file, sound_file, skill, source, count) angle: -90, }; } else if (skill.toLowerCase().includes("ranged") || skill.toLowerCase().includes("gunnery")) { - var ray = new Ray(tokens[0].center, Array.from(game.user.targets)[i].center); + var ray = new Ray(tokens[0].center, position); var animation_config = { position: tokens[0].center, file: animation_file, @@ -420,7 +463,7 @@ async function play_animation(animation_file, sound_file, skill, source, count) }, }; } else { - var ray = new Ray(tokens[0].center, Array.from(game.user.targets)[i].center); + var ray = new Ray(tokens[0].center, position); var animation_config = { position: tokens[0].center, file: animation_file,