|
/* theripper93
|
|
* Copyright (C) 2021 dnd-randomizer
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* Original License:
|
|
* https://github.com/theripper93/dnd-randomizer/blob/master/LICENSE
|
|
*/
|
|
|
|
/* WARPGATE CHANGES
|
|
* exporting propagator class
|
|
* removed test function from original code
|
|
*/
|
|
|
|
export class Propagator{
|
|
// Find a non-occupied cell in the grid that matches the size of the token given an origin
|
|
static getFreePosition(tokenData,origin, collision = true){
|
|
const center = canvas.grid.getCenter(origin.x,origin.y)
|
|
origin = {x:center[0],y:center[1]};
|
|
const positions = Propagator.generatePositions(origin);
|
|
for(let position of positions){
|
|
if(Propagator.canFit(tokenData, position, positions[0], collision)){
|
|
return position;
|
|
}
|
|
}
|
|
|
|
}
|
|
//generate positions radiantially from the origin
|
|
static generatePositions(origin){
|
|
let positions = [canvas.grid.getSnappedPosition(origin.x-1,origin.y-1)];
|
|
for(let r = canvas.scene.dimensions.size; r < canvas.scene.dimensions.size*10; r+=canvas.scene.dimensions.size){
|
|
|
|
for(let theta = 0; theta < 2*Math.PI; theta+=Math.PI/(4*r/canvas.scene.dimensions.size)){
|
|
const newPos = canvas.grid.getTopLeft(origin.x + r*Math.cos(theta),origin.y + r*Math.sin(theta))
|
|
positions.push({x:newPos[0],y:newPos[1]});
|
|
}
|
|
}
|
|
return positions;
|
|
}
|
|
//check if a position is free
|
|
static isFree(position){
|
|
for(let token of canvas.tokens.placeables){
|
|
const hitBox = new PIXI.Rectangle(token.x,token.y,token.w,token.h);
|
|
if(hitBox.contains(position.x,position.y)){
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
//check if a token can fit in a position
|
|
static canFit(tokenData, position, origin, collision){
|
|
for(let i = 0; i < tokenData.width; i++){
|
|
for(let j = 0; j < tokenData.height; j++){
|
|
const x = position.x + j*canvas.scene.dimensions.size;
|
|
const y = position.y + i*canvas.scene.dimensions.size;
|
|
if(!Propagator.isFree({x,y})){
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
const wallCollisions = canvas.walls.checkCollision(
|
|
new Ray(origin, {
|
|
x:position.x+tokenData.width*canvas.scene.dimensions.size/2,
|
|
y:position.y+tokenData.height*canvas.scene.dimensions.size/2
|
|
}),{ type: "move" }
|
|
)?.length ?? 0;
|
|
|
|
|
|
return !collision || !wallCollisions
|
|
}
|
|
}
|