@@ -5,7 +5,7 @@ import d3 from 'd3';

class Unit {

static getUnitPaths = (regions, unitList, onUnitClick, onUnitStackClick, onUnitDragStart, onUnitDragEnd, viewState, onMoveCancelClick, onArmyClick, measurementPass) => {
static getUnitPaths = (regions, unitList, onUnitClick, onUnitStackClick, onUnitDragStart, onUnitDragEnd, viewState, onMoveCancelClick, onArmyClick, measurementPassDone) => {
let els = [];
regions.forEach((region) => {
let unitsInRegion = unitList.filter((unitInfo) => {
@@ -18,25 +18,24 @@ class Unit {
region.bbox.px = regionBbox.left;
region.bbox.py = regionBbox.top;

let regionTestPositions = Unit.getRondelPlacementPositions(unitsInRegion, region.bbox, measurementPass);
let regionTestPositions = Unit.getPlacementPositions(unitsInRegion, region.bbox, measurementPassDone);
regionTestPositions.forEach((playerPositions) => {
let playerUnitsInRegion = unitsInRegion.filter((unit) => { return unit.owner === playerPositions.player });
if(playerPositions.showRondel && measurementPass) els.push(Unit.getPlayerArmyRondelPath(playerPositions.roundelPosition, playerPositions.player, onArmyClick, region.attributes.id));
if(playerPositions.showRondel && measurementPassDone) els.push(Unit.getPlayerArmyRondelPath(playerPositions.roundelPosition, playerPositions.player, onArmyClick, region.attributes.id));
else els = els.concat(Unit.getPlayerUnitPathsForRegion(playerPositions, playerUnitsInRegion, onUnitClick, onUnitStackClick, onUnitDragStart, onUnitDragEnd, viewState, onMoveCancelClick));
});
}
});

return els;
};

static getRondelPlacementPositions = (unitsInRegion, regionCentroid, measurementPassDone) => {
static getPlacementPositions = (unitsInRegion, regionCentroid, measurementPassDone) => {

let players = [], numPlayers = 0;
let regionId;
unitsInRegion.forEach((unit) => { if(players.indexOf(unit.owner) === -1) { players.push(unit.owner); numPlayers++; regionId=unit.region; }});

let availablePlayerDimensions = { width: regionCentroid.pxWidth / numPlayers, height: regionCentroid.pxHeight / numPlayers };

let i=0;

players = players.map((player) => {
@@ -53,48 +52,29 @@ class Unit {
let numRows = 0;
let numCols = 0;

//Construct unitPositions array as you go
let unitPositions = [];
let playerRect = {x:regionCentroid.x, y: regionCentroid.y + ((regionCentroid.height/(numPlayers))*i), width: regionCentroid.width, height: regionCentroid.height/numPlayers, px: regionCentroid.px, py: regionCentroid.py + ((regionCentroid.pxHeight/(numPlayers))*i)};
let playerRect = {x: regionCentroid.x, y: regionCentroid.y + ((regionCentroid.height/(numPlayers))*i), width: regionCentroid.width, height: regionCentroid.height/numPlayers, px: regionCentroid.px, py: regionCentroid.py + ((regionCentroid.pxHeight/(numPlayers))*i)};

playerUnitTypes.forEach((unitType) => {
if(fit || !(measurementPassDone)){

let potentialPosition = { x: playerRect.x + (numCols*7), y: playerRect.y + 5*numRows };

let currentUnit =playerUnits.filter((unit) => {
return unit.type === unitType;
let defaultUnitPosition = Constants.Units.DefaultPositions.filter((unitPosition) => {
return unitPosition.region + unitPosition.type + unitPosition.owner === regionId + unitType + player;
})[0];

let unitWidth = currentUnit.bbox ? currentUnit.bbox.width : 0;
let unitHeight = currentUnit.bbox ? currentUnit.bbox.height : 0;

if(currentUnit.bbox){
//test this point to see if it actually overlaps the region polygon.
let unitBoundingRect = Utils.getPathBoundingRectById(Utils.getUnitUniqueId(currentUnit));
if(unitBoundingRect){
//Is it in the viewport?
let isInViewport = (
unitBoundingRect.top >= 0 &&
unitBoundingRect.left >= 0 &&
unitBoundingRect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
unitBoundingRect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
if(isInViewport){
let possibleNewRegion = document.elementsFromPoint(playerRect.px + (unitBoundingRect.width), playerRect.py + (unitBoundingRect.height)).filter((element) => {
return element.attributes.id && element.attributes.id.nodeValue === regionId;
});

fit = possibleNewRegion.length === 1;
}
}
else{
//Rondel is being rendered for this unit so it is not in the DOM
fit = false;
}
if(defaultUnitPosition.initialX){
unitPositions.push({ x: defaultUnitPosition.initialX, y:defaultUnitPosition.initialY});
}
else{
let potentialPosition = { x: playerRect.x + (numCols*7), y: playerRect.y + (5*numRows) };

let currentUnit =playerUnits.filter((unit) => {
return unit.type === unitType;
})[0];

let unitWidth = currentUnit.bbox ? currentUnit.bbox.width : 0;
let unitHeight = currentUnit.bbox ? currentUnit.bbox.height : 0;

if(fit){
//Will it fit into the player unit slots?
let fitBeforeWrap = (potentialPosition.x + ((playerRect.width/unitWidth)*15)) < playerRect.width + playerRect.x;

@@ -108,17 +88,18 @@ class Unit {

//If we don't fit the height, we don't continue
fit = (potentialPosition.y + ((playerRect.height/unitHeight)*15)) < playerRect.height + playerRect.y;
}

if(fit || !(measurementPassDone)) unitPositions.push(potentialPosition);

unitPositions.push(potentialPosition);
}
numCols++;
}
});

i++;

if(fit || !measurementPassDone){
return { player, availablePlayerDimensions, unitTypes: playerUnitTypes, rect: playerRect, unitPositions };
return { player, unitTypes: playerUnitTypes, rect: playerRect, unitPositions };
}
else{
return { player, showRondel: true, roundelPosition: { x: playerRect.x + (playerRect.width/2) - 2.5, y: playerRect.y + (playerRect.height/2) - 2.5 } };
@@ -137,37 +118,43 @@ class Unit {
let els = [];
let i = 0;
playerUnitsInRegion.forEach((unitInfo) => {
els.push(Unit.getUnitImageGroup(Unit.getPlacementPositionInRect(unitInfo, playerPositions, i, viewState), unitInfo, onUnitClick, onUnitStackClick, onUnitDragStart, onUnitDragEnd, viewState, onMoveCancelClick));
els.push(Unit.getUnitImageGroup(Unit.getPlacementPositionInRect(unitInfo, playerPositions, i), unitInfo, onUnitClick, onUnitStackClick, onUnitDragStart, onUnitDragEnd, viewState, onMoveCancelClick));
i++;
});
return els;
};

static getPlacementPositionInRect = (unitInfo, playerPositions, i, viewState) => {
//TODO, modify position by number of different players and unit types in region
//i is number of unit types placed in region for current player already
//gets you playerPositions.xOffset * i etc...
if(viewState.unitDragStart && viewState.unitDragStart.uniqueId === (Utils.getUnitUniqueId(unitInfo))){
static getPlacementPositionInRect = (unitInfo, playerPositions, i) => {
if(unitInfo.dragPosition && unitInfo.queuedForMove){
return unitInfo.dragPosition;
}
else if(unitInfo.dragPosition && !unitInfo.queuedForMove){
unitInfo.dragPosition = unitInfo.lastGoodPosition;
return unitInfo.dragPosition;
}
else{
let staticPosition = {x: playerPositions.unitPositions[i].x, y: playerPositions.unitPositions[i].y};
unitInfo.staticPosition = staticPosition;
return staticPosition;
if(playerPositions.unitPositions[i]) {
let initialPosition = {x: playerPositions.unitPositions[i].x, y: playerPositions.unitPositions[i].y};
unitInfo.lastGoodPosition = initialPosition;
return unitInfo.lastGoodPosition;
}
else{
return unitInfo.lastGoodPosition;
}
}
};

static getUnitImageGroup = (position, unitInfo, onUnitClick, onUnitStackClick, onUnitDragStart, onUnitDragEnd, viewState, onMoveCancelClick) => {

let pathEls = [];
unitInfo.paths.forEach((path) => {
pathEls.push((<path d={path.attributes.d} className='turnbase-unit' id={Utils.getUnitUniqueId(unitInfo)} fill={Constants.Players[unitInfo.owner].color}
pathEls.push((<path d={path.attributes.d} className='turnbase-unit' id={unitInfo.id} fill={Constants.Players[unitInfo.owner].color}
onClick={()=> onUnitClick(unitInfo)}></path>));
});
let pathEl, moveFill;

//Drawing move arrows
if(viewState.unitDragStart && viewState.unitDragStart.uniqueId === (Utils.getUnitUniqueId(unitInfo))){
if(viewState.unitDragStart && (viewState.unitDragStart.unitInfo.id) === unitInfo.id && unitInfo.queuedForMove){
//let angleToMouse = (Math.atan2(position.x - viewState.unitOriginalStart.x, position.y - viewState.unitOriginalStart.y )*(180/Math.PI));
let dist = Math.sqrt( ((viewState.unitOriginalStart.x-position.x)*(viewState.unitOriginalStart.x - position.x)) + ((viewState.unitOriginalStart.y-position.y)*(viewState.unitOriginalStart.y-position.y)) );

@@ -183,9 +170,8 @@ class Unit {
}
let savedMoveArrowInfo;
if((!viewState.unitDragStart) && viewState.savedMoveArrows){
let uniqueId = Utils.getUnitUniqueId(unitInfo) + '_queued';
savedMoveArrowInfo = viewState.savedMoveArrows.get(uniqueId);
if(savedMoveArrowInfo){
savedMoveArrowInfo = viewState.savedMoveArrows.get(unitInfo.id);
if(savedMoveArrowInfo && unitInfo.queuedForMove){
let dist = Math.sqrt( ((savedMoveArrowInfo.unitOriginalStart.x-savedMoveArrowInfo.newPosition.x)*(savedMoveArrowInfo.unitOriginalStart.x - savedMoveArrowInfo.newPosition.x))
+ ((savedMoveArrowInfo.unitOriginalStart.y-savedMoveArrowInfo.newPosition.y)*(savedMoveArrowInfo.unitOriginalStart.y-savedMoveArrowInfo.newPosition.y)) );

@@ -195,15 +181,15 @@ class Unit {
let y2 = -(savedMoveArrowInfo.unitOriginalStart.y-savedMoveArrowInfo.newPosition.y);

pathEl=(<g transform={'scale('+Math.min(Math.max(dist/20, 0.6), 0.9)+')translate(0,5)'}>
<line onClick={()=>onMoveCancelClick(uniqueId)} markerEnd="url(#arrowhead)" x1={0} y1={5} x2={x2} y2={y2} stroke={moveFill} strokeWidth={1.5}/>
<line onClick={()=>onMoveCancelClick(unitInfo.id)} markerEnd="url(#arrowhead)" x1={0} y1={5} x2={x2} y2={y2} stroke={moveFill} strokeWidth={1.5}/>
</g>);
}
}

return (<svg>
{pathEl ? <svg x={viewState.unitOriginalStart ? viewState.unitOriginalStart.x : savedMoveArrowInfo.unitOriginalStart.x} y={viewState.unitOriginalStart ? viewState.unitOriginalStart.y : savedMoveArrowInfo.unitOriginalStart.y}>
<defs dangerouslySetInnerHTML={{__html: '<marker id="arrowhead" markerWidth="5" markerHeight="5" orient="auto" refX="0" refY="2.5"><polygon fill="'+moveFill+'" points="0,0 5,2.5 0,5"/></marker>'}}></defs>{pathEl}</svg> : null}
<svg className={savedMoveArrowInfo ? 'no-events' : null} x={position.x} y={position.y}><g onMouseDown={(e) => onUnitDragStart(e, unitInfo)}
<svg className={unitInfo.queuedForMove ? 'no-events' : null} x={position.x} y={position.y}><g onMouseDown={(e) => onUnitDragStart(e, unitInfo)}
onMouseUp={onUnitDragEnd}
transform={'scale('+Constants.Units[unitInfo.type].scaleFactor+')'}>{pathEls}</g></svg>
</svg>);