/*******************************************************************************
* Copyright (c) 2015 - 2017
* <p>
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
* <p>
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
* <p>
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*******************************************************************************/
package jsettlers.input;
import static java8.util.stream.StreamSupport.stream;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import jsettlers.common.buildings.IBuilding;
import jsettlers.common.map.shapes.HexGridArea;
import jsettlers.common.menu.UIState;
import jsettlers.common.position.ShortPoint2D;
import jsettlers.common.utils.mutables.MutableInt;
import jsettlers.input.tasks.ChangeTowerSoldiersGuiTask;
import jsettlers.input.tasks.ChangeTradingRequestGuiTask;
import jsettlers.input.tasks.ConstructBuildingTask;
import jsettlers.input.tasks.ConvertGuiTask;
import jsettlers.input.tasks.DestroyBuildingGuiTask;
import jsettlers.input.tasks.EGuiAction;
import jsettlers.input.tasks.MovableGuiTask;
import jsettlers.input.tasks.MoveToGuiTask;
import jsettlers.input.tasks.SetAcceptedStockMaterialGuiTask;
import jsettlers.input.tasks.SetBuildingPriorityGuiTask;
import jsettlers.input.tasks.SetMaterialDistributionSettingsGuiTask;
import jsettlers.input.tasks.SetMaterialPrioritiesGuiTask;
import jsettlers.input.tasks.SetMaterialProductionGuiTask;
import jsettlers.input.tasks.SetTradingWaypointGuiTask;
import jsettlers.input.tasks.SimpleGuiTask;
import jsettlers.input.tasks.UpgradeSoldiersGuiTask;
import jsettlers.input.tasks.WorkAreaGuiTask;
import jsettlers.logic.buildings.Building;
import jsettlers.logic.buildings.MaterialProductionSettings;
import jsettlers.logic.buildings.military.OccupyingBuilding;
import jsettlers.logic.buildings.others.StockBuilding;
import jsettlers.logic.buildings.trading.TradingBuilding;
import jsettlers.logic.movable.Movable;
import jsettlers.logic.movable.interfaces.ILogicMovable;
import jsettlers.network.client.task.packets.TaskPacket;
import jsettlers.network.synchronic.timer.ITaskExecutor;
import java8.util.Objects;
import java8.util.Optional;
import java8.util.stream.Collectors;
/**
*
* @author Andreas Eberle
*
*/
public class GuiTaskExecutor implements ITaskExecutor {
private static GuiTaskExecutor instance = null;
private final IGuiInputGrid grid;
private final ITaskExecutorGuiInterface guiInterface;
private final byte playerId;
public GuiTaskExecutor(IGuiInputGrid grid, ITaskExecutorGuiInterface guiInterface, byte playerId) {
this.grid = grid;
this.guiInterface = guiInterface;
this.playerId = playerId;
}
public static GuiTaskExecutor get() {
return instance;
}
@Override
public void executeTask(TaskPacket iTask) {
if (!(iTask instanceof SimpleGuiTask)) {
return;
}
SimpleGuiTask guiTask = (SimpleGuiTask) iTask;
System.out.println("executeTask(GuiTask): " + guiTask.getGuiAction());
switch (guiTask.getGuiAction()) {
case SET_WORK_AREA: {
WorkAreaGuiTask task = (WorkAreaGuiTask) guiTask;
setWorkArea(task.getPosition(), task.getBuildingPos().x, task.getBuildingPos().y);
break;
}
case BUILD: {
ConstructBuildingTask task = (ConstructBuildingTask) guiTask;
grid.constructBuildingAt(task.getPosition(), task.getType(), task.getPlayerId());
break;
}
case MOVE_TO: {
MoveToGuiTask task = (MoveToGuiTask) guiTask;
moveSelectedTo(task.getPosition(), task.getSelection());
break;
}
case QUICK_SAVE:
save();
break;
case DESTROY_BUILDING: {
ShortPoint2D buildingPos = ((DestroyBuildingGuiTask) guiTask).getPosition();
Building building = ((Building) grid.getBuildingAt(buildingPos.x, buildingPos.y));
if (building != null) {
building.kill();
}
break;
}
case DESTROY_MOVABLES:
killSelectedMovables(((MovableGuiTask) guiTask).getSelection());
break;
case START_WORKING:
case STOP_WORKING:
stopOrStartWorking(((MovableGuiTask) guiTask).getSelection(), guiTask.getGuiAction() == EGuiAction.STOP_WORKING);
break;
case CONVERT:
convertMovables((ConvertGuiTask) guiTask);
break;
case SET_BUILDING_PRIORITY:
setBuildingPriority((SetBuildingPriorityGuiTask) guiTask);
break;
case SET_MATERIAL_DISTRIBUTION_SETTINGS: {
SetMaterialDistributionSettingsGuiTask task = (SetMaterialDistributionSettingsGuiTask) guiTask;
grid.setMaterialDistributionSettings(task.getManagerPosition(), task.getMaterialType(), task.getProbabilities());
break;
}
case SET_MATERIAL_PRIORITIES: {
SetMaterialPrioritiesGuiTask task = (SetMaterialPrioritiesGuiTask) guiTask;
grid.setMaterialPrioritiesSettings(task.getManagerPosition(), task.getMaterialTypeForPriority());
}
break;
case UPGRADE_SOLDIERS: {
UpgradeSoldiersGuiTask task = (UpgradeSoldiersGuiTask) guiTask;
grid.getPlayer(task.getPlayerId()).getMannaInformation().upgrade(task.getSoldierType());
break;
}
case CHANGE_TRADING: {
ChangeTradingRequestGuiTask task = (ChangeTradingRequestGuiTask) guiTask;
ShortPoint2D buildingPos = task.getBuildingPos();
IBuilding building = grid.getBuildingAt(buildingPos.x, buildingPos.y);
if (building instanceof TradingBuilding) {
((TradingBuilding) building).changeRequestedMaterial(task.getMaterial(), task.getAmount(), task.isRelative());
}
break;
}
case SET_TRADING_WAYPOINT: {
SetTradingWaypointGuiTask task = (SetTradingWaypointGuiTask) guiTask;
ShortPoint2D buildingPos = task.getBuildingPos();
IBuilding building = grid.getBuildingAt(buildingPos.x, buildingPos.y);
if (building instanceof TradingBuilding) {
((TradingBuilding) building).setWaypoint(task.getWaypointType(), task.getPosition());
}
break;
}
case SET_MATERIAL_PRODUCTION: {
SetMaterialProductionGuiTask task = (SetMaterialProductionGuiTask) guiTask;
MaterialProductionSettings materialProduction = grid.getMaterialProductionAt(task.getPosition());
switch (task.getProductionType()) {
case INCREASE:
materialProduction.increaseAbsoluteProductionRequest(task.getMaterialType());
break;
case DECREASE:
materialProduction.decreaseAbsoluteProductionRequest(task.getMaterialType());
break;
case SET_PRODUCTION:
materialProduction.setAbsoluteProductionRequest(task.getMaterialType(), (int) task.getRatio());
break;
case SET_RATIO:
materialProduction.setRelativeProductionRequest(task.getMaterialType(), task.getRatio());
break;
}
break;
}
case CHANGE_TOWER_SOLDIERS:
changeTowerSoldiers((ChangeTowerSoldiersGuiTask) guiTask);
break;
case SET_ACCEPTED_STOCK_MATERIAL:
setAcceptedStockMaterial((SetAcceptedStockMaterialGuiTask) guiTask);
break;
default:
break;
}
}
private void setAcceptedStockMaterial(SetAcceptedStockMaterialGuiTask guiTask) {
ShortPoint2D taskPosition = guiTask.getPosition();
if (guiTask.isLocal()) {
IBuilding building = grid.getBuildingAt(taskPosition.x, taskPosition.y);
if (building != null && building instanceof StockBuilding) {
StockBuilding stock = (StockBuilding) building;
stock.setAcceptedMaterial(guiTask.getMaterialType(), guiTask.isAccepted());
}
} else {
grid.setAcceptedStockMaterial(taskPosition, guiTask.getMaterialType(), guiTask.isAccepted());
}
}
private void changeTowerSoldiers(ChangeTowerSoldiersGuiTask soldierTask) {
ShortPoint2D buildingPosition = soldierTask.getBuildingPos();
OccupyingBuilding occupyingBuilding = (OccupyingBuilding) grid.getBuildingAt(buildingPosition.x, buildingPosition.y);
switch (soldierTask.getTaskType()) {
case FULL:
occupyingBuilding.requestSoldiers();
break;
case MORE:
occupyingBuilding.requestSoldier(soldierTask.getSoldierType());
break;
case ONE:
occupyingBuilding.releaseSoldiers();
break;
case LESS:
occupyingBuilding.releaseSoldier(soldierTask.getSoldierType());
break;
}
}
private void save() {
try {
byte numberOfPlayers = grid.getNumberOfPlayers();
PlayerState[] playerStates = new PlayerState[numberOfPlayers];
for (byte playerId = 0; playerId < numberOfPlayers; playerId++) {
// find a tower of the player
UIState uiState = null;
for (Building building : Building.getAllBuildings()) {
if (building.getPlayer().playerId == playerId && building instanceof OccupyingBuilding) {
uiState = new UIState(building.getPos());
break;
}
}
playerStates[playerId] = new PlayerState(playerId, uiState);
}
playerStates[playerId] = new PlayerState(this.playerId, guiInterface.getUIState(), grid.getFogOfWar());
grid.save(playerStates);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
private void setBuildingPriority(SetBuildingPriorityGuiTask guiTask) {
ShortPoint2D pos = guiTask.getBuildingPosition();
Building building = ((Building) grid.getBuildingAt(pos.x, pos.y));
if (building != null) {
building.setPriority(guiTask.getNewPriority());
}
}
private void convertMovables(ConvertGuiTask guiTask) {
for (Integer currID : guiTask.getSelection()) {
ILogicMovable movable = Movable.getMovableByID(currID);
if (movable != null) {
movable.convertTo(guiTask.getTargetType());
}
}
guiInterface.refreshSelection();
}
private void stopOrStartWorking(List<Integer> selectedMovables, boolean stop) {
for (Integer currID : selectedMovables) {
ILogicMovable movable = Movable.getMovableByID(currID);
if (movable != null) {
movable.stopOrStartWorking(stop);
}
}
}
private void killSelectedMovables(List<Integer> selectedMovables) {
for (Integer currID : selectedMovables) {
ILogicMovable curr = Movable.getMovableByID(currID);
if (curr != null) {
curr.kill();
}
}
}
/**
* Move the selected {@link Movable} to the given position.
*
* @param targetPosition
* position to move to
* @param movableIds
* A list of the id's of the movables.
*/
private void moveSelectedTo(ShortPoint2D targetPosition, List<Integer> movableIds) {
if (movableIds.size() == 1) {
ILogicMovable currMovable = Movable.getMovableByID(movableIds.get(0));
if (currMovable != null) {
currMovable.moveTo(targetPosition);
}
} else if (!movableIds.isEmpty()) {
sendMovablesNew(targetPosition, movableIds);
}
}
private void sendMovablesNew(ShortPoint2D targetPosition, List<Integer> movableIds) {
List<ILogicMovable> movables = stream(movableIds).map(Movable::getMovableByID).filter(Objects::nonNull).collect(Collectors.toList());
if (movables.isEmpty()) {
return;
}
for (int radius = 1, ringsWithoutSuccessCtr = 0; ringsWithoutSuccessCtr <= 5 && !movables.isEmpty(); radius++) {
MutableInt numberOfSendMovables = new MutableInt(0);
HexGridArea
.streamBorder(targetPosition.x, targetPosition.y, radius)
.filterBounds(grid.getWidth(), grid.getHeight())
.getEvery(2)
.forEach((x, y) -> {
Optional<ILogicMovable> movableOptional = removeMovableThatCanMoveTo(movables, x, y);
movableOptional.ifPresent(movable -> {
movable.moveTo(new ShortPoint2D(x, y));
numberOfSendMovables.value++;
});
});
if (numberOfSendMovables.value > 0) {
ringsWithoutSuccessCtr = 0;
} else {
ringsWithoutSuccessCtr++;
}
}
}
private Optional<ILogicMovable> removeMovableThatCanMoveTo(List<ILogicMovable> movables, int x, int y) {
for (Iterator<ILogicMovable> iterator = movables.iterator(); iterator.hasNext();) {
ILogicMovable movable = iterator.next();
if (canMoveTo(movable, x, y)) {
iterator.remove();
return Optional.of(movable);
}
}
return Optional.empty();
}
private boolean canMoveTo(ILogicMovable movable, int x, int y) {
return !grid.isBlocked(x, y) && grid.getBlockedPartition(movable.getPos().x, movable.getPos().y) == grid.getBlockedPartition(x, y);
}
private void setWorkArea(ShortPoint2D pos, short buildingX, short buildingY) {
Building building = (Building) grid.getBuildingAt(buildingX, buildingY);
if (building != null) {
building.setWorkAreaCenter(pos);
}
}
}