package onlinefrontlines.game.actions;
import java.util.ArrayList;
import java.awt.Point;
import onlinefrontlines.auth.User;
import onlinefrontlines.game.*;
import onlinefrontlines.utils.IllegalRequestException;
/**
* Action to move a unit, possibly in or out a container.
*
* @author jorrit
*
* Copyright (C) 2009-2013 Jorrit Rouwe
*
* This file is part of Online Frontlines.
*
* Online Frontlines 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.
*
* Online Frontlines 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.
*
* You should have received a copy of the GNU General Public License
* along with Online Frontlines. If not, see <http://www.gnu.org/licenses/>.
*/
public class ActionMoveUnit extends Action
{
private UnitState selectedUnit;
private ArrayList<Point> path;
private boolean captureTiles;
/**
* Default constructor
*/
public ActionMoveUnit()
{
}
/**
* Constructor to set properties
*/
public ActionMoveUnit(UnitState selectedUnit, ArrayList<Point> path)
{
this.selectedUnit = selectedUnit;
this.path = path;
}
/**
* Query if remote client should receive this action
*/
public receiveTime pendingActionGetReceiveTime(Faction remoteFaction)
{
return remoteFaction != Faction.opposite(selectedUnit.faction)
|| selectedUnit.isDetected()? receiveTime.now : receiveTime.never;
}
/**
* Apply the action
*/
public void doAction(boolean addToDb) throws IllegalRequestException
{
// Calculate cost of move
int cost = 0;
for (int i = 1; i < path.size(); ++i)
{
Point p = path.get(i);
cost += gameState.getMovementCost(selectedUnit, p.x, p.y);
}
// Determine if this unit will capture tiles (remote client can be unaware of this when unit is in fog of war)
captureTiles = selectedUnit.unitConfig.unitClass == UnitClass.land;
// Change ownership of area
if (captureTiles)
for (Point p : path)
if (gameState.getTerrainAt(p.x, p.y).victoryPoints > 0)
gameState.setTerrainOwnerAt(p.x, p.y, selectedUnit.faction);
// Remember container we came from
UnitState fromContainer = selectedUnit.container;
// Get target
Point last = path.get(path.size() - 1);
// Get unit at target location
UnitState targetUnit = gameState.getUnit(last.x, last.y);
// Move unit
if (selectedUnit.container != null)
{
// If the units requires transforming before he can move here do it now
UnitConfig otherConfig = UnitConfig.allUnitsMap.get(selectedUnit.unitConfig.transformableToUnitId);
TerrainConfig terrain = gameState.getTerrainAt(last.x, last.y);
if (!selectedUnit.unitConfig.canMoveOn(terrain)
&& otherConfig != null
&& otherConfig.canMoveOn(terrain))
selectedUnit.transform();
// Move out of container
gameState.moveUnitOutOfContainer(selectedUnit, selectedUnit.container, last.x, last.y);
}
else if (targetUnit == null)
{
// Move the unit
gameState.moveUnit(selectedUnit, last.x, last.y);
}
else
{
// Move the unit in the container
gameState.moveUnitInContainer(selectedUnit, targetUnit);
}
// Update action points
if (fromContainer != null)
{
// Deduct cost when leaving container
selectedUnit.actionsLeft--;
selectedUnit.lastActionWasMove = false;
}
else if (selectedUnit.container != null)
{
// Lose all points when going into container
selectedUnit.movementPointsLeft = 0;
selectedUnit.actionsLeft = 0;
selectedUnit.lastActionWasMove = true;
}
else
{
// Deduct cost
if (!selectedUnit.lastActionWasMove)
selectedUnit.actionsLeft--;
selectedUnit.movementPointsLeft -= cost;
selectedUnit.lastActionWasMove = true;
}
// Current player did something
gameState.currentPlayerIdle = false;
}
/**
* Convert action from a string
*/
public void fromString(String[] param, User initiatingUser) throws IllegalRequestException, IgnoreActionException
{
// Check phase
if (gameState.turnNumber == 0)
throw new IllegalRequestException("Not valid during setup phase");
// Check winning state
if (gameState.winningFaction != Faction.invalid)
throw new IllegalRequestException("Game has ended");
// Get selected unit
selectedUnit = gameState.getUnitById(Integer.parseInt(param[1]));
if (selectedUnit == null)
throw new IllegalRequestException("Invalid unit");
// Get path
path = new ArrayList<Point>();
Point prev = null;
for (int c = 3; c < param.length; c += 2)
{
if (c + 2 > param.length)
throw new IllegalRequestException("Expected 2 parameters for point");
Point p = new Point(Integer.parseInt(param[c]), Integer.parseInt(param[c + 1]));
if (!gameState.mapConfig.isTileInPlayableArea(p))
throw new IllegalRequestException("Position '" + p.toString() + "' is not in playable area");
if (prev != null && MapConfig.getDistance(prev.x, prev.y, p.x, p.y) != 1)
throw new IllegalRequestException("Position '" + p.toString() + "' is not one tile away from '" + prev.toString() + "'");
path.add(p);
prev = p;
}
// Check path is valid
if (path.size() < 2)
throw new IllegalRequestException("Path length < 2");
// Get first and last point
Point first = path.get(0);
Point last = path.get(path.size() - 1);
// Validate initial position
if ((selectedUnit.container == null && (selectedUnit.locationX != first.x || selectedUnit.locationY != first.y))
|| (selectedUnit.container != null && (selectedUnit.container.locationX != first.x || selectedUnit.container.locationY != first.y)))
throw new IllegalRequestException("Invalid starting point");
// Get unit at target location
UnitState targetUnit = gameState.getUnit(last.x, last.y);
// Check target is valid
if (targetUnit != null && !targetUnit.canHold(selectedUnit))
throw new IllegalRequestException("Trying to move into container when it is not possible");
// Check if not moving from and to container
if (targetUnit != null && selectedUnit.container != null)
throw new IllegalRequestException("Cannot move from container to container");
if (selectedUnit.container == null)
{
// Normal move
// Check if actions left
if (!selectedUnit.lastActionWasMove && selectedUnit.actionsLeft <= 0)
throw new IllegalRequestException("No actions left");
// Check if we have enough movement points
int cost = 0;
for (int i = 1; i < path.size(); ++i)
{
Point p = path.get(i);
cost += gameState.getMovementCost(selectedUnit, p.x, p.y);
}
if (selectedUnit.movementPointsLeft < cost)
throw new IllegalRequestException("Not enough movement points");
}
else
{
// Deploying
// Check if actions left
if (selectedUnit.actionsLeft <= 0)
throw new IllegalRequestException("No actions left");
// Check deploying from a contained container
if (selectedUnit.container.container != null)
throw new IllegalRequestException("Cannot deploy from a container in a container");
// Check if path length is 2
if (path.size() != 2)
throw new IllegalRequestException("Deploy must have path length 2");
// Check if unit can be deployed at target
UnitConfig otherConfig = UnitConfig.allUnitsMap.get(selectedUnit.unitConfig.transformableToUnitId);
TerrainConfig terrain = gameState.getTerrainAt(last.x, last.y);
if (!selectedUnit.unitConfig.canMoveOn(terrain)
&& (selectedUnit.unitConfig.transformableType == TransformableType.inBase || otherConfig == null || !otherConfig.canMoveOn(terrain)))
throw new IllegalRequestException("Unit cannot be deployed here");
}
}
/**
* Convert action to a string
*/
public String toString(Faction remoteFaction)
{
String rv = "m," + selectedUnit.id + "," + (captureTiles? 1 : 0);
for (Point p : path)
rv += "," + p.x + "," + p.y;
return rv;
}
}