All user data for FoundryVTT. Includes worlds, systems, modules, and any asset in the "foundryuserdata" directory. Does NOT include the FoundryVTT installation itself.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

142 lines
8.4 KiB

import {registerSettings} from "./settings.js"
import {movementTracking, actionCount} from "./movementFunctions.js"
Hooks.once("init", () => {
//Wait until the game is initialized, then register the settings created previously.
registerSettings();
});
Hooks.once("canvasInit", () => {
//When the canvas intializes the first time after a reload, if enhanced terrain layer is active, overwrite the original environment/obstacle lists with a PF2e specific list.
if (game.modules.get("enhanced-terrain-layer")?.active){
canvas.terrain.getEnvironments = function(){return [
{ id: 'aquatic', text: 'Aquatic', icon:'systems/pf2e/icons/spells/crashing-wave.webp'},
{ id: 'arctic', text: 'Arctic', icon:'systems/pf2e/icons/spells/warped-terrain.webp' },
{ id: 'coast', text: 'Coast', icon:'systems/pf2e/icons/features/ancestry/skilled-heritage.webp' },
{ id: 'desert', text: 'Desert', icon:'systems/pf2e/icons/spells/dust-storm.webp' },
{ id: 'forest', text: 'Forest', icon:'systems/pf2e/icons/spells/plant-growth.webp' },
{ id: 'hills', text: 'Hills', icon:'systems/pf2e/icons/spells/passwall.webp' },
{ id: 'mountain', text: 'Mountain', icon:'systems/pf2e/icons/spells/stone-tell.webp' },
{ id: 'plains', text: 'Plains', icon:'systems/pf2e/icons/spells/commune-with-nature.webp' },
{ id: 'sky', text: 'Sky', icon:'systems/pf2e/icons/spells/darkness.webp' },
{ id: 'swamp', text: 'Swamp', icon:'systems/pf2e/icons/spells/blight.webp' },
{ id: 'underground', text: 'Underground', icon:'systems/pf2e/icons/spells/dance-of-darkness.webp' },
{ id: 'urban', text: 'Urban', icon:'systems/pf2e/icons/spells/pulse-of-the-city.webp' },
{ id: 'current', text: 'Current', icon:'systems/pf2e/icons/spells/air-walk.webp', obstacle:true },
{ id: 'crowd', text: 'Crowd', icon:'systems/pf2e/icons/spells/tireless-worker.webp' , obstacle:true},
{ id: 'furniture', text: 'Furniture', icon:'systems/pf2e/icons/spells/secret-chest.webp', obstacle:true},
{ id: 'ice', text: 'Ice', icon:'systems/pf2e/icons/spells/clinging-ice.webp', obstacle:true},
{ id: 'incline', text: 'Incline', icon:'systems/pf2e/icons/spells/unimpeded-stride.webp', obstacle:true },
{ id: 'magical', text: 'Magical', icon:'systems/pf2e/icons/default-icons/spell.webp', obstacle:true},
{ id: 'plants', text: 'Plants', icon:'systems/pf2e/icons/spells/natures-enmity.webp', obstacle:true },
{ id: 'rubble', text: 'Rubble', icon:'systems/pf2e/icons/spells/wall-of-stone.webp', obstacle:true },
{ id: 'water', text: 'Water', icon:'systems/pf2e/icons/spells/mariners-curse.webp', obstacle:true },
{ id: 'wind', text: 'Wind', icon:'systems/pf2e/icons/spells/punishing-winds.webp', obstacle:true }
];
}
}
});
Hooks.once("dragRuler.ready", (SpeedProvider) => {
class PF2eSpeedProvider extends SpeedProvider {
//Registers colours for up to four movement actions so colours can be customized for them, and sets defaults
get colors(){
return [
{id: "FirstAction", default: 0x3222C7},
{id: "SecondAction", default: 0xFFEC07},
{id: "ThirdAction", default: 0xC033E0},
{id: "FourthAction", default: 0x1BCAD8}
]
};
// Get the distance for each movement interval to give to drag ruler
getRanges(token){
var numactions = actionCount(token); //Use the actionCount function to determine how many actions that token gets each round.
var movement = movementTracking(token); //Use the movementTracking function to get how far each movement range should be.
const ranges = []; //create blank array to store the ranges in.
if (numactions > 0 && movement.A1 > 0){
//Set the ranges for each of our four actions to be given to the drag ruler.
ranges.push({range: movement.A1, color: "FirstAction"},{range: movement.A2, color: "SecondAction"}, { range: movement.A3, color: "ThirdAction"},{range: movement.A4, color: "FourthAction"});
//Remove ranges from the function until only the ranges equal to the number of legal actions remain.
for (var i = numactions, len=ranges.length; i<len; i++){
ranges.pop();
};
} else {ranges.push({range: 0, color: "FirstAction"})}; //Since ranges is empty if you've got no actions add a range for the first action of 0.
return ranges;
};
};
// When dragruler is ready to go give it all the PF2 specific stuff
dragRuler.registerModule("pf2e-dragruler", PF2eSpeedProvider) //register the speed provider so its selectable from the drag ruler configuration.
});
Hooks.on('updateCombat', () => {
if(game.user.isGM && game.settings.get("drag-ruler", "enableMovementHistory") && game.settings.get("pf2e-dragruler", "offTurnMovement")){
const combat = game.combats.active; //set the current combat
if(combat?.turns.length > 0){
const previousCombatant = combat.turns[(combat.turn - 1) < 0 ? (combat.turns.length - 1) : (combat.turn - 1)];
const nextCombatant = combat.turns[combat.turn]; //find the next combatant
if(nextCombatant?.flags?.dragRuler){
dragRuler.resetMovementHistory(combat, nextCombatant._id); //if movement history exists, clears it for the next combatant prior to acting. Gives a clean slate for the new turn, important for clearing out off turn movement.
};
if(previousCombatant?.flags?.dragRuler){
dragRuler.resetMovementHistory(combat, previousCombatant._id); //if movement history exists, clears it for the next combatant prior to acting. Gives a clean slate for the new turn, important for clearing out off turn movement.
};
};
};
});
Hooks.once("enhancedTerrainLayer.ready", (RuleProvider) => {
class PF2eRuleProvider extends RuleProvider {
calculateCombinedCost(terrain, options) {
const token = options?.token;
const tokenElevation = token?.document?.elevation || 0
let cost;
if(token){
var movementType = movementTracking(token).type; //gets type of movement.
//gets token elevation.
var ignoredEnv= Object.keys(token.actor.flags.pf2e?.movement?.env?.ignore || {any: false} ).filter(a => token.actor.flags.pf2e?.movement?.env?.ignore?.[a]); //finds all the flags set by effects asking the actor to ignore a type of terrain.
var reducedEnv= Object.keys(token.actor.flags.pf2e?.movement?.env?.reduce || {any: false} ).filter(a => token.actor.flags.pf2e?.movement?.env?.reduce?.[a]); //finds all the flags set by effects asking the actor to reduce the cost of a type of terrain.
if(token.actor.flags.pf2e?.movement?.ignoreTerrain|| token.actor.flags.pf2e?.movement?.climbing){
cost = 1
return cost
};
}
//Function for Minus Equal, minimum 1.
function mem1(a, value){
if(a <= value){return 1}
else{return (a - value)}
}
let environments = [];
let obstacles = [];
let costs = [];
for(var ii = 0; ii<terrain.length; ii++) {
if(terrain[ii].object.document.elevation >= tokenElevation && (terrain[ii].object.document.elevation-(terrain[ii].object.document.depth ?? 0)) <= tokenElevation && (token?.actor?.alliance ?? "none" !== (terrain[ii].object?.actor?.alliance ?? 0))){
environments.push(terrain[ii].environment)
obstacles.push(terrain[ii].obstacle)
costs.push(terrain[ii].cost)
if(token && !token.actor.flags.pf2e?.movement?.respectTerrain){
if(reducedEnv?.find(e => e == 'non-magical') && (environments[ii] !== 'magical' || obstacles[ii] !== 'magical')){
costs[ii] = mem1(costs[ii],1)
}
if(ignoredEnv?.find(e => e == 'non-magical') && (environments[ii] !== 'magical' || obstacles[ii] !== 'magical')){
costs[ii] = 1
}
}
}
}
// Calculate the cost for this terrain
if(token && !token.actor.flags.pf2e?.movement?.respectTerrain){
for(var i = 0; i < environments.length; i++){
if(reducedEnv?.find(e => e == environments[i])||reducedEnv?.find(e => e == obstacles[i])||token.actor.flags.pf2e?.movement?.reduceTerrain){costs[i] = mem1(costs[i],1)}
if(ignoredEnv?.find(e => e == environments[i])||ignoredEnv?.find(e => e == obstacles[i])){costs[i]=1}
if (movementType == 'swim' && obstacles[i] == "water" || movementType == 'swim' && environments[i] == "water" ){costs[i]=1}
if (movementType == 'burrow' && obstacles[i] == "underground" || movementType == 'burrow' && environments[i] == "underground" ){costs[i]=1}
}
}
costs.push(1);
cost = Math.max(...costs)
if(token && token.actor.flags.pf2e?.movement?.increaseTerrain){cost += 1}
return cost;
}
}
enhancedTerrainLayer.registerModule("pf2e-dragruler", PF2eRuleProvider);
});