/*******************************************************************************
* Copyright (c) 2015, 2016
*
* 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.landscape.ELandscapeType;
import jsettlers.common.movable.EMovableAction;
import jsettlers.common.position.RelativePoint;
import jsettlers.common.position.ShortPoint2D;
import jsettlers.logic.constants.MatchConstants;
import jsettlers.logic.map.grid.partition.manager.manageables.IManageableDigger;
import jsettlers.logic.map.grid.partition.manager.manageables.interfaces.IDiggerRequester;
import jsettlers.logic.movable.Movable;
import jsettlers.logic.movable.MovableStrategy;
public final class DiggerStrategy extends MovableStrategy implements IManageableDigger {
private static final long serialVersionUID = 1581926355853324624L;
private IDiggerRequester requester;
private EDiggerState state = EDiggerState.JOBLESS;
public DiggerStrategy(Movable movable) {
super(movable);
reportJobless();
}
@Override
public boolean setDiggerJob(IDiggerRequester requester) {
if (state == EDiggerState.JOBLESS) {
this.requester = requester;
this.state = EDiggerState.INIT_JOB;
return true;
} else {
return false;
}
}
@Override
protected void action() {
switch (state) {
case JOBLESS:
break;
case INIT_JOB:
goToDiggablePosition();
break;
case PLAYING_ACTION:
executeDigg();
if (!requester.isDiggerRequestActive()) {
super.getGrid().setMarked(movable.getPos(), false);
reportJobless();
break;
}
case GOING_TO_POS:
if (needsToBeWorkedOn(movable.getPos())) {
super.playAction(EMovableAction.ACTION1, 1f);
this.state = EDiggerState.PLAYING_ACTION;
} else {
goToDiggablePosition();
}
break;
case DEAD_OBJECT:
break;
}
}
private void executeDigg() {
ShortPoint2D pos = movable.getPos();
super.getGrid().changeHeightTowards(pos.x, pos.y, requester.getAverageHeight());
}
private void goToDiggablePosition() {
super.getGrid().setMarked(movable.getPos(), false);
ShortPoint2D diggablePos = getDiggablePosition();
if (diggablePos != null) {
if (super.goToPos(diggablePos)) {
state = EDiggerState.GOING_TO_POS;
super.getGrid().setMarked(diggablePos, true);
} else {
reportJobless();
}
} else if (allPositionsFlattened()) { // all positions are flattened => building is finished
reportJobless();
} // else { not all positions are finished, so wait if one becomes unmarked or all are finished => do nothing
}
private boolean allPositionsFlattened() {
for (RelativePoint relativePosition : requester.getBuildingType().getProtectedTiles()) {
if (needsToBeWorkedOn(relativePosition.calculatePoint(requester.getPos()))) {
return false;
}
}
return true;
}
private ShortPoint2D getDiggablePosition() {
RelativePoint[] blockedTiles = requester.getBuildingType().getProtectedTiles();
ShortPoint2D buildingPos = requester.getPos();
int offset = MatchConstants.random().nextInt(blockedTiles.length);
for (int i = 0; i < blockedTiles.length; i++) {
ShortPoint2D pos = blockedTiles[(i + offset) % blockedTiles.length].calculatePoint(buildingPos);
if (!super.getGrid().isMarked(pos) && needsToBeWorkedOn(pos)) {
return pos;
}
}
return null;
}
private boolean needsToBeWorkedOn(ShortPoint2D pos) {
return needsToChangeHeight(pos) || isNotFlattened(pos);
}
private boolean isNotFlattened(ShortPoint2D pos) {
return super.getGrid().getLandscapeTypeAt(pos.x, pos.y) != ELandscapeType.FLATTENED;
}
private boolean needsToChangeHeight(ShortPoint2D pos) {
return super.getGrid().getHeightAt(pos) != requester.getAverageHeight();
}
private void reportJobless() {
this.state = EDiggerState.JOBLESS;
this.requester = null;
super.getGrid().addJobless(this);
}
@Override
protected boolean checkPathStepPreconditions(ShortPoint2D pathTarget, int step) {
if (requester == null || requester.isDiggerRequestActive()) {
return true;
} else {
if (state != EDiggerState.JOBLESS) {
reportJobless();
}
if (pathTarget != null) {
super.getGrid().setMarked(pathTarget, false);
}
return false;
}
}
@Override
protected void strategyKilledEvent(ShortPoint2D pathTarget) {
if (pathTarget != null) {
super.getGrid().setMarked(pathTarget, false);
}
switch (state) {
case JOBLESS:
super.getGrid().removeJobless(this);
break;
case PLAYING_ACTION:
super.getGrid().setMarked(movable.getPos(), false);
break;
default:
break;
}
if (requester != null) {
abortJob();
}
state = EDiggerState.DEAD_OBJECT;
}
@Override
protected void pathAborted(ShortPoint2D pathTarget) {
if (requester != null) {
super.getGrid().setMarked(pathTarget, false);
abortJob();
reportJobless();
}
}
private void abortJob() {
requester.diggerRequestFailed();
}
private static enum EDiggerState {
JOBLESS,
INIT_JOB,
GOING_TO_POS,
PLAYING_ACTION,
DEAD_OBJECT
}
}