Get most of the custom Initiative sorting stuff through the door

This commit is contained in:
Oliver-Akins 2025-02-14 00:04:48 -07:00
parent ed93e9f927
commit e302b56a4e
10 changed files with 142 additions and 14 deletions

View file

@ -16,6 +16,7 @@ export default [
languageOptions: { languageOptions: {
globals: { globals: {
CONFIG: `writable`, CONFIG: `writable`,
CONST: `readonly`,
game: `readonly`, game: `readonly`,
Handlebars: `readonly`, Handlebars: `readonly`,
Hooks: `readonly`, Hooks: `readonly`,
@ -32,6 +33,7 @@ export default [
TextEditor: `readonly`, TextEditor: `readonly`,
fromUuid: `readonly`, fromUuid: `readonly`,
Combat: `readonly`, Combat: `readonly`,
Combatant: `readonly`,
}, },
}, },
}, },

View file

@ -116,7 +116,7 @@ export class HeroSummaryCardV1 extends GenericAppMixin(HandlebarsApplicationMixi
ctx.fate.selected = ctx.actor.system.fate; ctx.fate.selected = ctx.actor.system.fate;
ctx.fate.options = [ ctx.fate.options = [
{ label: `RipCrypt.common.empty`, v: `` }, { label: `RipCrypt.common.empty`, v: `` },
...gameTerms.FatePath ...Object.values(gameTerms.FatePath)
.map(v => ({ label: `RipCrypt.common.path.${v}`, value: v })), .map(v => ({ label: `RipCrypt.common.path.${v}`, value: v })),
]; ];
return ctx; return ctx;

View file

@ -0,0 +1,27 @@
import { Logger } from "../../utils/Logger.mjs";
const { CombatTracker } = foundry.applications.sidebar.tabs;
export class RipCryptCombatTracker extends CombatTracker {
/**
* @override
*/
async _prepareTurnContext(combat, combatant, index) {
Logger.debug(`_prepareTurnContext`);
const turn = await super._prepareTurnContext(combat, combatant, index);
// if ( !this.viewed ) return;
// ! TODO: This is causing an error while the combat is not active, but is fine when it's active, this needs to be fixed
Logger.debug(turn, combatant);
const groupKey = combatant.groupKey;
if (groupKey) {
turn.active ||= combat.combatant.groupKey === groupKey;
if (turn.active && !turn.css.includes(`active`)) {
turn.css += `active`;
};
};
return turn;
}
};

View file

@ -90,7 +90,7 @@ export class HeroData extends foundry.abstract.TypeDataModel {
trim: true, trim: true,
nullable: false, nullable: false,
choices: () => { choices: () => {
return gameTerms.FatePath.concat(``); return Object.values(gameTerms.FatePath).concat(``);
}, },
}), }),
level: new fields.SchemaField({ level: new fields.SchemaField({

View file

@ -6,6 +6,24 @@ Resources:
*/ */
export class RipCryptCombat extends Combat { export class RipCryptCombat extends Combat {
get groups() {
let groups = new Map();
for (const combatant of this.combatants) {
const groupKey = combatant.groupKey;
if (!groupKey) { continue };
if (groups.has(groupKey)) {
groups.get(groupKey).push(combatant);
} else {
groups.set(groupKey, [combatant]);
};
};
return groups;
};
/** /**
* @override * @override
* Sorts combatants for the combat tracker in the following way: * Sorts combatants for the combat tracker in the following way:
@ -14,13 +32,14 @@ export class RipCryptCombat extends Combat {
*/ */
_sortCombatants(a, b) { _sortCombatants(a, b) {
// The distance from fate // The distance from fate
return super._sortCombatants(a, b) * -1;
}; };
nextTurn() { // nextTurn() {
// Make it skip all combatants with the same initiative value // // Make it skip all combatants with the same initiative value
}; // };
previousTurn() { // previousTurn() {
// Go back a step // // Go back a step
}; // };
}; };

View file

@ -0,0 +1,37 @@
import { distanceBetweenFates } from "../utils/distanceBetweenFates.mjs";
export class RipCryptCombatant extends Combatant {
async _preCreate(data, options, user) {
const allowed = await super._preCreate(data, options, user);
if (allowed === false) { return false };
const start = game.settings.get(`ripcrypt`, `currentFate`);
const end = this.actor?.system?.fate || this.baseActor?.system?.fate;
const fateDistance = distanceBetweenFates(start, end);
this.updateSource({
initiative: fateDistance,
});
};
get groupKey() {
const path = this.token?.actor?.system?.fate;
// Disallow grouping things that don't have a fate path
if (!path) { return null };
// Token Disposition (group into: friendlies, unknown, hostiles)
let disposition = `unknown`;
switch (this.token.disposition) {
case CONST.TOKEN_DISPOSITIONS.HOSTILE:
disposition = `hostile`;
break;
case CONST.TOKEN_DISPOSITIONS.FRIENDLY:
disposition = `friendly`;
break;
};
return `${path}:${disposition}`;
};
};

View file

@ -11,12 +11,12 @@ export const gameTerms = Object.preventExtensions({
FLECT: `flect`, FLECT: `flect`,
FRACT: `fract`, FRACT: `fract`,
}), }),
FatePath: [ FatePath: Object.freeze({
`North`, NORTH: `North`,
`East`, EAST: `East`,
`South`, SOUTH: `South`,
`West`, WEST: `West`,
], }),
Access: [ Access: [
`Common`, `Common`,
`Uncommon`, `Uncommon`,

View file

@ -28,6 +28,9 @@ import { registerDevSettings } from "../settings/devSettings.mjs";
import { registerMetaSettings } from "../settings/metaSettings.mjs"; import { registerMetaSettings } from "../settings/metaSettings.mjs";
import { registerUserSettings } from "../settings/userSettings.mjs"; import { registerUserSettings } from "../settings/userSettings.mjs";
import { registerWorldSettings } from "../settings/worldSettings.mjs"; import { registerWorldSettings } from "../settings/worldSettings.mjs";
import { RipCryptCombat } from "../documents/combat.mjs";
import { RipCryptCombatant } from "../documents/combatant.mjs";
import { RipCryptCombatTracker } from "../Apps/sidebar/CombatTracker.mjs";
Hooks.once(`init`, () => { Hooks.once(`init`, () => {
Logger.log(`Initializing`); Logger.log(`Initializing`);
@ -53,6 +56,9 @@ Hooks.once(`init`, () => {
// #endregion // #endregion
// #region Class Changes // #region Class Changes
CONFIG.ui.combat = RipCryptCombatTracker;
CONFIG.Combat.documentClass = RipCryptCombat;
CONFIG.Combatant.documentClass = RipCryptCombatant;
CONFIG.Item.documentClass = RipCryptItem; CONFIG.Item.documentClass = RipCryptItem;
CONFIG.Dice.terms.d = CryptDie; CONFIG.Dice.terms.d = CryptDie;
// #endregion // #endregion

View file

@ -8,4 +8,14 @@ export function registerMetaSettings() {
ui.crypt.render({ parts: [ `delveConditions` ]}); ui.crypt.render({ parts: [ `delveConditions` ]});
}, },
}); });
game.settings.register(`ripcrypt`, `currentFate`, {
scope: `world`,
type: String,
config: false,
requiresReload: false,
onChange: () => {
ui.crypt.render({ parts: [ `fate` ] });
},
});
}; };

View file

@ -0,0 +1,27 @@
import { gameTerms } from "../gameTerms.mjs";
import { Logger } from "./Logger.mjs";
const { FatePath } = gameTerms;
export function isOppositeFates(a, b) {
return a === FatePath.NORTH && b === FatePath.SOUTH
|| a === FatePath.EAST && FatePath.WEST;
};
export function distanceBetweenFates(start, end) {
if (!start || !end) {
Logger.error(`Start and End must both have a defined value, given`, {start, end});
return undefined;
};
if (isOppositeFates(start, end)) {
return 2;
};
let isForward = start === FatePath.SOUTH && end === FatePath.WEST;
isForward ||= start === FatePath.NORTH && end === FatePath.EAST;
if (isForward) {
return 1;
};
return 3;
};