public MovePart(MoveInfantry aParentMove, MobileEntity aMe, Pos aStart, Pos aDestCell) { this.parentMove = aParentMove; this.me = aMe; this.me.targetCellX = (int) aDestCell.getX(); this.me.targetCellY = (int) aDestCell.getY(); int subOffsetXnext = (int) EntityInfantry.subcellOffsets[this.me.desiredSubcell.ordinal()].getX(); int subOffsetYnext = (int) EntityInfantry.subcellOffsets[this.me.desiredSubcell.ordinal()].getY(); int subOffsetXcurr = (int) EntityInfantry.subcellOffsets[this.me.currentSubcell.ordinal()].getX(); int subOffsetYcurr = (int) EntityInfantry.subcellOffsets[this.me.currentSubcell.ordinal()].getY(); this.end = new Pos( (aDestCell.getX() * 24) + subOffsetXnext, (aDestCell.getY() * 24) + subOffsetYnext); this.start = aStart; this.lengthInTicks = (int) (40 - (10 * me.getMoveSpeed())); int facing = RotationUtil.getRotationFromXY(start.getX(), start.getY(), end.getX(), end.getY()); this.desiredFacing = RotationUtil.quantizeFacings(facing, this.me.getMaxFacings()); }
@Override public Activity tick(EntityActor a) { Pos nextCell = null; if (isCancelled || !(a instanceof MobileEntity)) { return nextActivity; } MobileEntity me = (MobileEntity) a; if (currentPath == null) { return nextActivity; } if (randomWaitTicks > 0) { randomWaitTicks--; return this; } nextCell = popPath(me); if (nextCell == null) { return this; } me.isMovingToCell = true; me.targetCellX = (int) nextCell.getX(); me.targetCellY = (int) nextCell.getY(); /* * 1. Turn to required facing * 2. Drag to required cell * 3. Continue moving * * Movement system: * * +-----<------+ * | | * v ^ * Activity queue: MovePart --+ | (change facing and drag to target cell) * | ^ * v | * Move ->+ (if we have next cell to move) */ MovePart movePartActivity = new MovePart(this, me, me.getPos(), nextCell); if (this.isNewPath) { movePartActivity.setIsNewPath(true); this.isNewPath = false; } movePartActivity.tick( me); // Tick once to avoid tick skipping without movement when current activiy is Move return movePartActivity; }
@Override public Activity tick(EntityActor a) { Pos nextPos; if (lengthInTicks > 1) { nextPos = PointsUtil.interpolatePos(start, end, ticks, lengthInTicks - 1); } else { nextPos = end; } if (me.currentFacing != this.desiredFacing) { me.currentFacing = this.desiredFacing % this.me.getMaxFacings(); // Don't move while our turn is not finished for new direction if (isNewPath) { return this; } } else { this.isNewPath = false; } me.setPos(nextPos); ticks++; // If move is finished, return control to parent activity if ((me.getPos().getX() == end.getX() && me.getPos().getY() == end.getY()) || ticks >= lengthInTicks) { me.currentFacing = this.desiredFacing % this.me.getMaxFacings(); me.currentSubcell = me.desiredSubcell; me.finishMoving(); // Parent Move activity is cancelled, lets switch to next activity (user send move order // when Move/PartMove activity is working) if (this.nextActivity instanceof MoveInfantry || parentMove.isCancelled()) { return this.nextActivity; } else { return parentMove; } } else { return this; } }
private Pos popPath(MobileEntity me) { int px = 0, py = 0; if (this.currentPath == null || currentPathIndex >= this.currentPath.getLength() || this.currentPath.getLength() < 1) { this.currentPath = null; return null; } Step s = currentPath.getStep(currentPathIndex); px = s.getX(); py = s.getY(); Pos nextCell = new Pos(px, py); me.desiredSubcell = me.currentSubcell; if (!me.world.blockingEntityMap.isSubcellFree(nextCell, me.desiredSubcell)) { me.desiredSubcell = me.world.blockingEntityMap.getFreeSubCell(nextCell, me.currentSubcell); if (me.desiredSubcell == null) { me.desiredSubcell = me.currentSubcell; } } if (!me.canEnterCell(nextCell)) { // This building we ignore if (this.ignoreBuilding != null && me.world.getBuildingInCell(nextCell) == this.ignoreBuilding) { this.hasNotifiedBlocker = false; this.hasWaited = false; return null; } // See if we close enough float dx = destCell.getX() - nextCell.getX(); float dy = destCell.getY() - nextCell.getY(); if (dx * dx + dy * dy <= this.destRange * this.destRange) { // System.out.println("We're close enough. Range: " + Math.sqrt(dx * dx + dy * dy) + " <= " // + this.destRange); this.currentPathIndex = this.currentPath.getLength(); // stop and skip all path this.currentPath = null; return null; } // Notify all friendly blockers inside cell if (!this.hasNotifiedBlocker) { for (Influence i : me.world.blockingEntityMap.getCellInfluences(nextCell)) { Entity blocker = i.entity; if (blocker instanceof MobileEntity) { // Notify blocker if (blocker != null && ((MobileEntity) blocker).isFrendlyTo(me)) { ((MobileEntity) blocker).notifyBlocking(me); } } } this.hasNotifiedBlocker = true; } // Wait a bit if (!this.hasWaited) { this.waitTicksRemaining = me.getWaitAverageTime() + me.world.getRandomInt(-me.getWaitSpreadTime(), me.getWaitSpreadTime()); // System.out.println("Waiting time: " + this.waitTicksRemaining); this.hasWaited = true; ((EntityInfantry) me).setCurrentAnimationState(AnimationState.WAITING); } if (--this.waitTicksRemaining >= 0) { // We're waiting now return null; } // We're totally blocked, try to calculate new path chooseNewPath(me); return null; } ((EntityInfantry) me).setCurrentAnimationState(AnimationState.MOVING); if (--this.ticksBeforeRepath <= 0) { this.ticksBeforeRepath = this.REPATHING_INTERVAL_TICKS; chooseNewPath(me); } this.currentPathIndex++; this.hasNotifiedBlocker = false; this.hasWaited = false; return nextCell; }