/*******************************************************************************
* Copyright (c) 2015 - 2017
*
* 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* 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.logic.movable.strategies;
import jsettlers.common.material.EMaterialType;
import jsettlers.common.movable.EMovableType;
import jsettlers.common.position.ShortPoint2D;
import jsettlers.logic.map.grid.partition.manager.manageables.IManageable;
import jsettlers.logic.map.grid.partition.manager.manageables.IManageableBearer;
import jsettlers.logic.map.grid.partition.manager.manageables.interfaces.IBarrack;
import jsettlers.logic.map.grid.partition.manager.materials.interfaces.IMaterialOffer;
import jsettlers.logic.map.grid.partition.manager.materials.interfaces.IMaterialRequest;
import jsettlers.logic.map.grid.partition.manager.materials.offers.EOfferPriority;
import jsettlers.logic.map.grid.partition.manager.objects.WorkerCreationRequest;
import jsettlers.logic.movable.Movable;
import jsettlers.logic.movable.MovableStrategy;
/**
* Strategy for bearers.
*
* @author Andreas Eberle
*
*/
public final class BearerMovableStrategy extends MovableStrategy implements IManageableBearer {
private static final long serialVersionUID = -734268451796522451L;
private EBearerState state = EBearerState.JOBLESS;
private IMaterialOffer offer;
private IMaterialRequest request;
private EMaterialType materialType;
private IBarrack barrack;
private IWorkerRequester workerRequester;
private WorkerCreationRequest workerCreationRequest;
public BearerMovableStrategy(Movable movable) {
super(movable);
reportJobless();
}
public final void reportJobless() {
super.getGrid().addJobless(this);
}
@Override
protected void action() {
switch (state) {
case JOBLESS:
break;
case INIT_CONVERT_WITH_TOOL_JOB:
case INIT_CARRY_JOB:
state = EBearerState.GOING_TO_OFFER;
if (!movable.getPos().equals(offer.getPos())) { // if we are not at the offers position, go to it.
if (!super.goToPos(offer.getPos())) {
handleJobFailed(true);
}
break;
}
case GOING_TO_OFFER:
if (movable.getPos().equals(offer.getPos())) {
state = EBearerState.TAKING;
if (!super.take(materialType, true)) {
handleJobFailed(true);
}
} else {
handleJobFailed(true);
}
break;
case TAKING:
if (workerCreationRequest != null) { // we handle a convert with tool job
state = EBearerState.DEAD_OBJECT;
super.setMaterial(EMaterialType.NO_MATERIAL);
movable.convertTo(workerCreationRequest.requestedMovableType());
} else {
offer = null;
state = EBearerState.GOING_TO_REQUEST;
if (!movable.getPos().equals(request.getPos()) && !super.goToPos(request.getPos())) {
handleJobFailed(true);
}
}
break;
case GOING_TO_REQUEST:
if (movable.getPos().equals(request.getPos())) {
state = EBearerState.DROPPING;
super.drop(materialType);
} else {
handleJobFailed(true);
}
break;
case DROPPING:
request = null;
materialType = null;
state = EBearerState.JOBLESS;
reportJobless();
break;
case INIT_CONVERT_JOB:
state = EBearerState.DEAD_OBJECT;
movable.convertTo(workerCreationRequest.requestedMovableType());
break;
case INIT_BECOME_SOLDIER_JOB:
super.goToPos(barrack.getDoor());
state = EBearerState.GOING_TO_BARRACK;
break;
case GOING_TO_BARRACK:
EMovableType movableType = barrack.popWeaponForBearer();
if (movableType == null) { // weapon got missing, make this bearer jobless again
this.barrack = null;
this.state = EBearerState.JOBLESS;
reportJobless();
} else {
this.state = EBearerState.DEAD_OBJECT;
movable.convertTo(movableType);
super.goToPos(barrack.getSoldierTargetPosition());
movable.getPlayer().getEndgameStatistic().incrementAmountOfProducedSoldiers();
}
break;
case DEAD_OBJECT:
assert false : "we should never get here!";
}
}
protected void tookMaterial() {
if (offer != null) {
offer.offerTaken();
}
}
@Override
public boolean droppingMaterial() {
if (request != null) {
if (request.isActive() && request.getPos().equals(movable.getPos())) {
request.deliveryFulfilled();
request = null;
return false;
} else {
request.deliveryAborted();
request = null;
}
}
return true; // offer the material
}
private void handleJobFailed(boolean reportAsJobless) {
switch (state) {
case INIT_CARRY_JOB:
case GOING_TO_OFFER:
case TAKING:
if (super.movable.getMaterial() == EMaterialType.NO_MATERIAL) {
reoffer();
}
if (workerCreationRequest != null) {
workerRequester.workerCreationRequestFailed(workerCreationRequest);
}
case GOING_TO_REQUEST:
if (request != null) {
request.deliveryAborted();
}
break;
case DROPPING:
if (request != null) {
boolean offerMaterial = droppingMaterial();
super.setMaterial(EMaterialType.NO_MATERIAL);
super.getGrid().dropMaterial(super.getPos(), materialType, offerMaterial, false);
}
break;
case INIT_BECOME_SOLDIER_JOB:
case GOING_TO_BARRACK:
barrack.bearerRequestFailed();
break;
case INIT_CONVERT_WITH_TOOL_JOB:
reoffer();
case INIT_CONVERT_JOB:
workerRequester.workerCreationRequestFailed(workerCreationRequest);
break;
case DEAD_OBJECT:
break;
case JOBLESS:
break;
default:
break;
}
EMaterialType carriedMaterial = super.setMaterial(EMaterialType.NO_MATERIAL);
if (carriedMaterial != EMaterialType.NO_MATERIAL) {
super.getGrid().dropMaterial(movable.getPos(), materialType, true, false);
}
offer = null;
request = null;
materialType = null;
workerCreationRequest = null;
workerRequester = null;
state = EBearerState.JOBLESS;
if (reportAsJobless) {
reportJobless();
}
}
private void reoffer() {
offer.distributionAborted();
}
@Override
protected boolean checkPathStepPreconditions(ShortPoint2D pathTarget, int step) {
if (request != null && !request.isActive()) {
return false;
}
if (offer != null) {
EOfferPriority minimumAcceptedPriority = request != null ? request.getMinimumAcceptedOfferPriority() : EOfferPriority.LOWEST;
if (!offer.isStillValid(minimumAcceptedPriority)) {
return false;
}
}
return true;
}
@Override
public void deliver(EMaterialType materialType, IMaterialOffer offer, IMaterialRequest request) {
if (state == EBearerState.JOBLESS) {
this.offer = offer;
this.request = request;
this.materialType = materialType;
this.state = EBearerState.INIT_CARRY_JOB;
offer.distributionAccepted();
request.deliveryAccepted();
}
}
@Override
public boolean becomeWorker(IWorkerRequester requester, WorkerCreationRequest workerCreationRequest) {
if (state == EBearerState.JOBLESS) {
this.workerRequester = requester;
this.workerCreationRequest = workerCreationRequest;
this.state = EBearerState.INIT_CONVERT_JOB;
this.offer = null;
this.materialType = null;
return true;
} else {
return false;
}
}
@Override
public boolean becomeWorker(IWorkerRequester requester, WorkerCreationRequest workerCreationRequest, IMaterialOffer offer) {
if (state == EBearerState.JOBLESS) {
this.workerRequester = requester;
this.workerCreationRequest = workerCreationRequest;
this.offer = offer;
this.state = EBearerState.INIT_CONVERT_WITH_TOOL_JOB;
this.materialType = workerCreationRequest.requestedMovableType().getTool();
offer.distributionAccepted();
return true;
} else {
return false;
}
}
@Override
public boolean becomeSoldier(IBarrack barrack) {
if (state == EBearerState.JOBLESS) {
this.barrack = barrack;
this.state = EBearerState.INIT_BECOME_SOLDIER_JOB;
return true;
} else {
return false;
}
}
@Override
protected void strategyKilledEvent(ShortPoint2D pathTarget) {
if (state == EBearerState.JOBLESS) {
super.getGrid().removeJobless(this);
} else {
handleJobFailed(false);
}
state = EBearerState.DEAD_OBJECT;
}
@Override
protected void pathAborted(ShortPoint2D pathTarget) {
if (state != EBearerState.JOBLESS) {
handleJobFailed(true);
}
}
/**
* This enum defines the internal states of a bearer.
*
* @author Andreas Eberle
*
*/
private enum EBearerState {
JOBLESS,
INIT_CARRY_JOB,
GOING_TO_REQUEST,
GOING_TO_OFFER,
TAKING,
DROPPING,
INIT_CONVERT_JOB,
INIT_CONVERT_WITH_TOOL_JOB,
DEAD_OBJECT,
INIT_BECOME_SOLDIER_JOB,
GOING_TO_BARRACK,
}
}