void UnitWalkBState::init() { _unit = _action.actor; setNormalWalkSpeed(); _pf = _parent->getPathfinding(); _terrain = _parent->getTileEngine(); _target = _action.target; }
/** * Initializes the state. */ void UnitWalkBState::init() { _unit = _action.actor; _numUnitsSpotted = _unit->getUnitsSpottedThisTurn().size(); setNormalWalkSpeed(); _pf = _parent->getPathfinding(); _terrain = _parent->getTileEngine(); _target = _action.target; if (Options::traceAI) { Log(LOG_INFO) << "Walking from: " << _unit->getPosition() << "," << " to " << _target;} int dir = _pf->getStartDirection(); if (!_action.strafe && dir != -1 && dir != _unit->getDirection()) { _beforeFirstStep = true; } }
void UnitWalkBState::think() { bool unitspotted = false; if (_unit->isOut()) { _pf->abortPath(); _parent->popState(); return; } // during a walking cycle we make step sounds if (_unit->getStatus() == STATUS_WALKING || _unit->getStatus() == STATUS_FLYING) { if (_unit->getVisible() && _unit->getStatus() == STATUS_WALKING) { if (_unit->getUnit()->getArmor()->getSize() > 1) { // play hwp engine sound if (_unit->getWalkingPhase() == 0) { // tank with threads "walks" if (_unit->getUnit()->getArmor()->getMovementType() == MT_WALK) _parent->getResourcePack()->getSoundSet("BATTLE.CAT")->getSound(14)->play(); else // hovering tank hovers _parent->getResourcePack()->getSoundSet("BATTLE.CAT")->getSound(40)->play(); } } else { // play footstep sound 1 if (_unit->getWalkingPhase() == 3) { Tile *tile = _unit->getTile(); if (tile->getFootstepSound()) { _parent->getResourcePack()->getSoundSet("BATTLE.CAT")->getSound(22 + (tile->getFootstepSound()*2))->play(); } } // play footstep sound 2 if (_unit->getWalkingPhase() == 7) { Tile *tile = _unit->getTile(); if (tile->getFootstepSound()) { _parent->getResourcePack()->getSoundSet("BATTLE.CAT")->getSound(23 + (tile->getFootstepSound()*2))->play(); } } } } _unit->keepWalking(); // advances the phase // unit moved from one tile to the other, update the tiles if (_unit->getPosition() != _unit->getLastPosition()) { int size = _unit->getUnit()->getArmor()->getSize() - 1; for (int x = size; x >= 0; x--) { for (int y = size; y >= 0; y--) { _parent->getSave()->getTile(_unit->getLastPosition() + Position(x,y,0))->setUnit(0); } } for (int x = size; x >= 0; x--) { for (int y = size; y >= 0; y--) { _parent->getSave()->getTile(_unit->getPosition() + Position(x,y,0))->setUnit(_unit); } } // if the unit changed level, camera changes level with _parent->getMap()->getCamera()->setViewHeight(_unit->getPosition().z); } // is the step finished? if (_unit->getStatus() == STATUS_STANDING) { // move our personal lighting with us _terrain->calculateUnitLighting(); BattleAction action; // check for proximity grenades (1 tile around the unit in every direction) (for large units, we need to check every tile it occupies) int size = _unit->getUnit()->getArmor()->getSize() - 1; for (int x = size; x >= 0; x--) { for (int y = size; y >= 0; y--) { for (int tx = -1; tx < 2; tx++) { for (int ty = -1; ty < 2; ty++) { Tile *t = _parent->getSave()->getTile(_unit->getPosition() + Position(x,y,0) + Position(tx,ty,0)); if (t) for (std::vector<BattleItem*>::iterator i = t->getInventory()->begin(); i != t->getInventory()->end(); ++i) { if ((*i)->getRules()->getBattleType() == BT_PROXIMITYGRENADE && (*i)->getExplodeTurn() > 0) { Position p; p.x = t->getPosition().x*16 + 8; p.y = t->getPosition().y*16 + 8; p.z = t->getPosition().z*24 + t->getTerrainLevel(); _parent->statePushNext(new ExplosionBState(_parent, p, (*i), (*i)->getPreviousOwner())); t->getInventory()->erase(i); return; } } } } } } // check for reaction fire if (_terrain->checkReactionFire(_unit, &action)) { _parent->statePushBack(new ProjectileFlyBState(_parent, action)); // unit got fired upon - stop walking _pf->abortPath(); return; } } else { // make sure the unit sprites are up to date _parent->getMap()->cacheUnit(_unit); } } // we are just standing around, shouldn't we be walking? if (_unit->getStatus() == STATUS_STANDING) { // check if we can spot new units unitspotted = _terrain->calculateFOV(_unit); if (unitspotted) { _pf->abortPath(); // a hostile unit will aggro on the new unit if it sees one - it will not start walking if (_unit->getFaction() == FACTION_HOSTILE) { AggroBAIState *aggro = dynamic_cast<AggroBAIState*>(_unit->getCurrentAIState()); if (aggro == 0) { _unit->setAIState(new AggroBAIState(_parent->getSave(), _unit)); } } return; } if (_unit->getVisible()) { setNormalWalkSpeed(); } else { _parent->setStateInterval(1); } int dir = _pf->getStartDirection(); if (dir != -1) { Position destination; int tu = _pf->getTUCost(_unit->getPosition(), dir, &destination, _unit); // gets tu cost, but also gets the destination position. if (tu > _unit->getTimeUnits() && !_parent->dontSpendTUs()) { _action.result = "STR_NOT_ENOUGH_TIME_UNITS"; _pf->abortPath(); return; } if (_parent->checkReservedTU(_unit, tu) == false) { _pf->abortPath(); return; } // we are looking in the wrong way, turn first // we are not using the turn state, because turning during walking costs no tu if (dir != _unit->getDirection() && dir < Pathfinding::DIR_UP) { _unit->lookAt(dir); return; } // now open doors (if any) int door = _terrain->unitOpensDoor(_unit); if (door == 3) { return; // don't start walking yet, wait for the ufo door to open } if (door == 0) { _parent->getResourcePack()->getSoundSet("BATTLE.CAT")->getSound(3)->play(); // normal door } if (door == 1) { _parent->getResourcePack()->getSoundSet("BATTLE.CAT")->getSound(20)->play(); // ufo door return; // don't start walking yet, wait for the ufo door to open } // now start moving dir = _pf->dequeuePath(); if (_unit->spendTimeUnits(tu, _parent->dontSpendTUs())) { if (_unit->spendEnergy(tu, _parent->dontSpendTUs())) { _unit->startWalking(dir, destination); } else { _action.result = "STR_NOT_ENOUGH_ENERGY"; _parent->popState(); } } else { _action.result = "STR_NOT_ENOUGH_TIME_UNITS"; _parent->popState(); } // make sure the unit sprites are up to date _parent->getMap()->cacheUnit(_unit); } else { postPathProcedures(); return; } } // turning during walking costs no tu if (_unit->getStatus() == STATUS_TURNING) { _unit->turn(); unitspotted = _terrain->calculateFOV(_unit); // make sure the unit sprites are up to date _parent->getMap()->cacheUnit(_unit); if (unitspotted) { _pf->abortPath(); return; } } }
void UnitWalkBState::think() { bool unitspotted = false; // during a walking cycle we make step sounds if (_unit->getStatus() == STATUS_WALKING || _unit->getStatus() == STATUS_FLYING) { if (_unit->getVisible() && _unit->getStatus() == STATUS_WALKING) { // play footstep sound 1 if (_unit->getWalkingPhase() == 3) { Tile *tile = _unit->getTile(); if (tile->getFootstepSound()) { _parent->getGame()->getResourcePack()->getSoundSet("BATTLE.CAT")->getSound(22 + (tile->getFootstepSound()*2))->play(); } } // play footstep sound 2 if (_unit->getWalkingPhase() == 7) { Tile *tile = _unit->getTile(); if (tile->getFootstepSound()) { _parent->getGame()->getResourcePack()->getSoundSet("BATTLE.CAT")->getSound(23 + (tile->getFootstepSound()*2))->play(); } } } _unit->keepWalking(); // advances the phase // unit moved from one tile to the other, update the tiles if (_unit->getPosition() != _unit->getLastPosition()) { _parent->getGame()->getSavedGame()->getBattleGame()->getTile(_unit->getLastPosition())->setUnit(0); //don't change these _parent->getGame()->getSavedGame()->getBattleGame()->getTile(_unit->getPosition())->setUnit(_unit); //don't change these // if the unit changed level, camera changes level with _parent->getMap()->getCamera()->setViewHeight(_unit->getPosition().z); } // is the step finished? if (_unit->getStatus() == STATUS_STANDING) { _terrain->calculateUnitLighting(); unitspotted = _terrain->calculateFOV(_unit); if (unitspotted) { _pf->abortPath(); if (_unit->getFaction() == FACTION_HOSTILE) { AggroBAIState *aggro = dynamic_cast<AggroBAIState*>(_unit->getCurrentAIState()); if (aggro == 0) { _unit->setAIState(new AggroBAIState(_parent->getGame()->getSavedGame()->getBattleGame(), _unit)); } _parent->handleAI(_unit); } return; } BattleAction action; if (_terrain->checkReactionFire(_unit, &action)) { _parent->statePushBack(new ProjectileFlyBState(_parent, action)); // unit got fired upon - stop walking _pf->abortPath(); return; } } else { // make sure the unit sprites are up to date _parent->getMap()->cacheUnit(_unit); } } // we are just standing around, shouldn't we be walking? if (_unit->getStatus() == STATUS_STANDING) { if (_unit->getVisible()) { setNormalWalkSpeed(); } else { _parent->setStateInterval(1); } int dir = _pf->getStartDirection(); if (dir != -1) { Position destination; int tu = _pf->getTUCost(_unit->getPosition(), dir, &destination, _unit); // gets tu cost, but also gets the destination position. if (tu > _unit->getTimeUnits() && !_parent->dontSpendTUs()) { _result = "STR_NOT_ENOUGH_TIME_UNITS"; _pf->abortPath(); return; } if (_parent->checkReservedTU(_unit, tu) == false) { _pf->abortPath(); return; } // we are looking in the wrong way, turn first // we are not using the turn state, because turning during walking costs no tu if (dir != _unit->getDirection() && dir < Pathfinding::DIR_UP) { _unit->lookAt(dir); return; } // now open doors (if any) int door = _terrain->unitOpensDoor(_unit); if (door == 3) { return; // don't start walking yet, wait for the ufo door to open } if (door == 0) { _parent->getGame()->getResourcePack()->getSoundSet("BATTLE.CAT")->getSound(3)->play(); // normal door } if (door == 1) { _parent->getGame()->getResourcePack()->getSoundSet("BATTLE.CAT")->getSound(20)->play(); // ufo door return; // don't start walking yet, wait for the ufo door to open } // now start moving dir = _pf->dequeuePath(); if (_unit->spendTimeUnits(tu, _parent->dontSpendTUs())) { if (_unit->spendEnergy(tu, _parent->dontSpendTUs())) { _unit->startWalking(dir, destination); } else { _result = "STR_NOT_ENOUGH_ENERGY"; _parent->popState(); } } else { _result = "STR_NOT_ENOUGH_TIME_UNITS"; _parent->popState(); } // make sure the unit sprites are up to date _parent->getMap()->cacheUnit(_unit); } else { postPathProcedures(); return; } } // turning during walking costs no tu if (_unit->getStatus() == STATUS_TURNING) { _unit->turn(); unitspotted = _terrain->calculateFOV(_unit); // make sure the unit sprites are up to date _parent->getMap()->cacheUnit(_unit); if (unitspotted) { _pf->abortPath(); return; } } }
/** * Runs state functionality every cycle. */ void UnitWalkBState::think() { bool unitSpotted = false; int size = _unit->getArmor()->getSize() - 1; bool onScreen = (_unit->getVisible() && _parent->getMap()->getCamera()->isOnScreen(_unit->getPosition(), true, size, false)); if (_unit->isKneeled()) { if (_parent->kneel(_unit)) { _unit->setCache(0); _terrain->calculateFOV(_unit); _parent->getMap()->cacheUnit(_unit); return; } else { _action.result = "STR_NOT_ENOUGH_TIME_UNITS"; _pf->abortPath(); _parent->popState(); return; } } Tile *tileBelow = _parent->getSave()->getTile(_unit->getPosition() + Position(0,0,-1)); if (_unit->isOut()) { _pf->abortPath(); _parent->popState(); return; } if (_unit->getStatus() == STATUS_WALKING || _unit->getStatus() == STATUS_FLYING) { if ((_parent->getSave()->getTile(_unit->getDestination())->getUnit() == 0) || // next tile must be not occupied (_parent->getSave()->getTile(_unit->getDestination())->getUnit() == _unit)) { bool onScreenBoundary = (_unit->getVisible() && _parent->getMap()->getCamera()->isOnScreen(_unit->getPosition(), true, size, true)); _unit->keepWalking(tileBelow, onScreenBoundary); // advances the phase playMovementSound(); } else if (!_falling) { _unit->lookAt(_unit->getDestination(), (_unit->getTurretType() != -1)); // turn to undiscovered unit _pf->abortPath(); } // unit moved from one tile to the other, update the tiles if (_unit->getPosition() != _unit->getLastPosition()) { bool largeCheck = true; for (int x = size; x >= 0; x--) { for (int y = size; y >= 0; y--) { Tile *otherTileBelow = _parent->getSave()->getTile(_unit->getPosition() + Position(x,y,-1)); if (!_parent->getSave()->getTile(_unit->getPosition() + Position(x,y,0))->hasNoFloor(otherTileBelow) || _unit->getMovementType() == MT_FLY) largeCheck = false; _parent->getSave()->getTile(_unit->getLastPosition() + Position(x,y,0))->setUnit(0); } } for (int x = size; x >= 0; x--) { for (int y = size; y >= 0; y--) { _parent->getSave()->getTile(_unit->getPosition() + Position(x,y,0))->setUnit(_unit, _parent->getSave()->getTile(_unit->getPosition() + Position(x,y,-1))); } } _falling = largeCheck && _unit->getPosition().z != 0 && _unit->getTile()->hasNoFloor(tileBelow) && _unit->getMovementType() != MT_FLY && _unit->getWalkingPhase() == 0; if (_falling) { for (int x = size; x >= 0; --x) { for (int y = size; y >= 0; --y) { Tile *otherTileBelow = _parent->getSave()->getTile(_unit->getPosition() + Position(x,y,-1)); if (otherTileBelow && otherTileBelow->getUnit()) { _falling = false; _pf->dequeuePath(); _parent->getSave()->addFallingUnit(_unit); _parent->statePushFront(new UnitFallBState(_parent)); return; } } } } if (!_parent->getMap()->getCamera()->isOnScreen(_unit->getPosition(), true, size, false) && _unit->getFaction() != FACTION_PLAYER && _unit->getVisible()) _parent->getMap()->getCamera()->centerOnPosition(_unit->getPosition()); // if the unit changed level, camera changes level with _parent->getMap()->getCamera()->setViewLevel(_unit->getPosition().z); } // is the step finished? if (_unit->getStatus() == STATUS_STANDING) { // update the TU display _parent->getSave()->getBattleState()->updateSoldierInfo(); // if the unit burns floortiles, burn floortiles as long as we're not falling if (!_falling && (_unit->getSpecialAbility() == SPECAB_BURNFLOOR || _unit->getSpecialAbility() == SPECAB_BURN_AND_EXPLODE)) { _unit->getTile()->ignite(1); Position posHere = _unit->getPosition(); Position voxelHere = (posHere * Position(16,16,24)) + Position(8,8,-(_unit->getTile()->getTerrainLevel())); _parent->getTileEngine()->hit(voxelHere, _unit->getBaseStats()->strength, DT_IN, _unit); if (_unit->getStatus() != STATUS_STANDING) // ie: we burned a hole in the floor and fell through it { _pf->abortPath(); return; } } // move our personal lighting with us _terrain->calculateUnitLighting(); if (_unit->getFaction() != FACTION_PLAYER) { _unit->setVisible(false); } _terrain->calculateFOV(_unit->getPosition()); unitSpotted = (!_falling && !_action.desperate && _parent->getPanicHandled() && _numUnitsSpotted != _unit->getUnitsSpottedThisTurn().size()); if (_parent->checkForProximityGrenades(_unit)) { _parent->popState(); return; } if (unitSpotted) { _unit->setCache(0); _parent->getMap()->cacheUnit(_unit); _pf->abortPath(); _parent->popState(); return; } // check for reaction fire if (!_falling) { if (_terrain->checkReactionFire(_unit)) { // unit got fired upon - stop walking _unit->setCache(0); _parent->getMap()->cacheUnit(_unit); _pf->abortPath(); _parent->popState(); return; } } } else if (onScreen) { // make sure the unit sprites are up to date if (_pf->getStrafeMove()) { // This is where we fake out the strafe movement direction so the unit "moonwalks" int dirTemp = _unit->getDirection(); _unit->setDirection(_unit->getFaceDirection()); _parent->getMap()->cacheUnit(_unit); _unit->setDirection(dirTemp); } else { _parent->getMap()->cacheUnit(_unit); } } } // we are just standing around, shouldn't we be walking? if (_unit->getStatus() == STATUS_STANDING || _unit->getStatus() == STATUS_PANICKING) { // check if we did spot new units if (unitSpotted && !_action.desperate && _unit->getCharging() == 0 && !_falling) { if (Options::traceAI) { Log(LOG_INFO) << "Uh-oh! Company!"; } _unit->setHiding(false); // clearly we're not hidden now _parent->getMap()->cacheUnit(_unit); postPathProcedures(); return; } if (onScreen || _parent->getSave()->getDebugMode()) { setNormalWalkSpeed(); } else { _parent->setStateInterval(0); } int dir = _pf->getStartDirection(); if (_falling) { dir = Pathfinding::DIR_DOWN; } if (dir != -1) { if (_pf->getStrafeMove()) { _unit->setFaceDirection(_unit->getDirection()); } Position destination; int tu = _pf->getTUCost(_unit->getPosition(), dir, &destination, _unit, 0, false); // gets tu cost, but also gets the destination position. if (_unit->getFaction() != FACTION_PLAYER && _unit->getSpecialAbility() < SPECAB_BURNFLOOR && _parent->getSave()->getTile(destination) && _parent->getSave()->getTile(destination)->getFire() > 0) { tu -= 32; // we artificially inflate the TU cost by 32 points in getTUCost under these conditions, so we have to deflate it here. } if (_falling) { tu = 0; } int energy = tu; if (dir >= Pathfinding::DIR_UP) { energy = 0; } else if (_action.run) { tu *= 0.75; energy *= 1.5; } if (tu > _unit->getTimeUnits()) { if (_parent->getPanicHandled() && tu < 255) { _action.result = "STR_NOT_ENOUGH_TIME_UNITS"; } _pf->abortPath(); _unit->setCache(0); _parent->getMap()->cacheUnit(_unit); _parent->popState(); return; } if (energy / 2 > _unit->getEnergy()) { if (_parent->getPanicHandled()) { _action.result = "STR_NOT_ENOUGH_ENERGY"; } _pf->abortPath(); _unit->setCache(0); _parent->getMap()->cacheUnit(_unit); _parent->popState(); return; } if (_parent->getPanicHandled() && _parent->checkReservedTU(_unit, tu) == false) { _pf->abortPath(); _unit->setCache(0); _parent->getMap()->cacheUnit(_unit); return; } // we are looking in the wrong way, turn first (unless strafing) // we are not using the turn state, because turning during walking costs no tu if (dir != _unit->getDirection() && dir < Pathfinding::DIR_UP && !_pf->getStrafeMove()) { _unit->lookAt(dir); _unit->setCache(0); _parent->getMap()->cacheUnit(_unit); return; } // now open doors (if any) if (dir < Pathfinding::DIR_UP) { int door = _terrain->unitOpensDoor(_unit, false, dir); if (door == 3) { return; // don't start walking yet, wait for the ufo door to open } if (door == 0) { _parent->getMod()->getSoundByDepth(_parent->getDepth(), Mod::DOOR_OPEN)->play(-1, _parent->getMap()->getSoundAngle(_unit->getPosition())); // normal door } if (door == 1) { _parent->getMod()->getSoundByDepth(_parent->getDepth(), Mod::SLIDING_DOOR_OPEN)->play(-1, _parent->getMap()->getSoundAngle(_unit->getPosition())); // ufo door return; // don't start walking yet, wait for the ufo door to open } } for (int x = size; x >= 0; --x) { for (int y = size; y >= 0; --y) { BattleUnit* unitInMyWay = _parent->getSave()->getTile(destination + Position(x,y,0))->getUnit(); BattleUnit* unitBelowMyWay = 0; Tile* belowDest = _parent->getSave()->getTile(destination + Position(x,y,-1)); if (belowDest) { unitBelowMyWay = belowDest->getUnit(); } // can't walk into units in this tile, or on top of other units sticking their head into this tile if (!_falling && ((unitInMyWay && unitInMyWay != _unit) || (belowDest && unitBelowMyWay && unitBelowMyWay != _unit && (-belowDest->getTerrainLevel() + unitBelowMyWay->getFloatHeight() + unitBelowMyWay->getHeight()) >= 28))) // 4+ voxels poking into the tile above, we don't kick people in the head here at XCom. { _action.TU = 0; _pf->abortPath(); _unit->setCache(0); _parent->getMap()->cacheUnit(_unit); _parent->popState(); return; } } } // now start moving dir = _pf->dequeuePath(); if (_falling) { dir = Pathfinding::DIR_DOWN; } if (_unit->spendTimeUnits(tu)) { if (_unit->spendEnergy(energy)) { Tile *tileBelow = _parent->getSave()->getTile(_unit->getPosition() + Position(0,0,-1)); _unit->startWalking(dir, destination, tileBelow, onScreen); _beforeFirstStep = false; } } // make sure the unit sprites are up to date if (onScreen) { if (_pf->getStrafeMove()) { // This is where we fake out the strafe movement direction so the unit "moonwalks" int dirTemp = _unit->getDirection(); _unit->setDirection(_unit->getFaceDirection()); _parent->getMap()->cacheUnit(_unit); _unit->setDirection(dirTemp); } else { _parent->getMap()->cacheUnit(_unit); } } } else { postPathProcedures(); return; } } // turning during walking costs no tu if (_unit->getStatus() == STATUS_TURNING) { // except before the first step. if (_beforeFirstStep) { _preMovementCost++; } _unit->turn(); // calculateFOV is unreliable for setting the unitSpotted bool, as it can be called from various other places // in the code, ie: doors opening, and this messes up the result. _terrain->calculateFOV(_unit); unitSpotted = (!_falling && !_action.desperate && _parent->getPanicHandled() && _numUnitsSpotted != _unit->getUnitsSpottedThisTurn().size()); // make sure the unit sprites are up to date _unit->setCache(0); _parent->getMap()->cacheUnit(_unit); if (unitSpotted && !_action.desperate && !_unit->getCharging() && !_falling) { if (_beforeFirstStep) { _unit->spendTimeUnits(_preMovementCost); } if (Options::traceAI) { Log(LOG_INFO) << "Egads! A turn reveals new units! I must pause!"; } _unit->setHiding(false); // not hidden, are we... _pf->abortPath(); _unit->abortTurn(); //revert to a standing state. _unit->setCache(0); _parent->getMap()->cacheUnit(_unit); _parent->popState(); } } }
void UnitWalkBState::think() { bool unitspotted = false; bool onScreen = (_unit->getVisible() && _parent->getMap()->getCamera()->isOnScreen(_unit->getPosition())); Tile *tileBelow = _parent->getSave()->getTile(_unit->getPosition() + Position(0,0,-1)); if (_unit->isOut()) { _pf->abortPath(); _parent->popState(); return; } if (_unit->getStatus() == STATUS_WALKING || _unit->getStatus() == STATUS_FLYING) { if ((_parent->getSave()->getTile(_unit->getDestination())->getUnit() == 0) || // next tile must be not occupied (_parent->getSave()->getTile(_unit->getDestination())->getUnit() == _unit)) { playMovementSound(); _unit->keepWalking(tileBelow, onScreen); // advances the phase } else if (!_falling) { _unit->lookAt(_unit->getDestination(), true); // turn to undiscovered unit _pf->abortPath(); } // unit moved from one tile to the other, update the tiles if (_unit->getPosition() != _unit->getLastPosition()) { int size = _unit->getArmor()->getSize() - 1; bool largeCheck = true; for (int x = size; x >= 0; x--) { for (int y = size; y >= 0; y--) { Tile *otherTileBelow = _parent->getSave()->getTile(_unit->getPosition() + Position(x,y,-1)); if (!_parent->getSave()->getTile(_unit->getPosition() + Position(x,y,0))->hasNoFloor(otherTileBelow) || _unit->getArmor()->getMovementType() == MT_FLY) largeCheck = false; _parent->getSave()->getTile(_unit->getLastPosition() + Position(x,y,0))->setUnit(0); } } for (int x = size; x >= 0; x--) { for (int y = size; y >= 0; y--) { _parent->getSave()->getTile(_unit->getPosition() + Position(x,y,0))->setUnit(_unit, _parent->getSave()->getTile(_unit->getPosition() + Position(x,y,-1))); } } _falling = largeCheck && _unit->getPosition().z != 0 && _unit->getTile()->hasNoFloor(tileBelow) && _unit->getArmor()->getMovementType() != MT_FLY && _unit->getWalkingPhase() == 0; if (_falling) { for (int x = _unit->getArmor()->getSize() - 1; x >= 0; --x) { for (int y = _unit->getArmor()->getSize() - 1; y >= 0; --y) { Tile *otherTileBelow = _parent->getSave()->getTile(_unit->getPosition() + Position(x,y,-1)); if (otherTileBelow && otherTileBelow->getUnit()) { Position originalPosition(otherTileBelow->getUnit()->getPosition()); for (int dir = 0; dir < Pathfinding::DIR_UP; dir++) { Position offset; Pathfinding::directionToVector(dir, &offset); Tile *t = _parent->getSave()->getTile(originalPosition + offset); Tile *bt = _parent->getSave()->getTile(originalPosition + offset + Position(0,0,-1)); Tile *bu = _parent->getSave()->getTile(originalPosition + Position(0,0,-1)); if (t && !_parent->getPathfinding()->isBlocked(otherTileBelow, t, dir, 0) && t->getUnit() == 0 && (!t->hasNoFloor(bt) || otherTileBelow->getUnit()->getArmor()->getMovementType() == MT_FLY)) { _falling = false; _pf->dequeuePath(); otherTileBelow->getUnit()->startWalking(dir, t->getPosition(), t, bu, bt, onScreen); _parent->getSave()->addFallingUnit(otherTileBelow->getUnit()); _parent->getSave()->addFallingUnit(_unit); _parent->statePushFront(new UnitFallBState(_parent)); return; } } } } } } if (!_parent->getMap()->getCamera()->isOnScreen(_unit->getPosition()) && _unit->getFaction() != FACTION_PLAYER && _unit->getVisible()) _parent->getMap()->getCamera()->centerOnPosition(_unit->getPosition()); // if the unit changed level, camera changes level with _parent->getMap()->getCamera()->setViewLevel(_unit->getPosition().z); } // is the step finished? if (_unit->getStatus() == STATUS_STANDING) { // if the unit burns floortiles, burn floortiles if (_unit->getSpecialAbility() == SPECAB_BURNFLOOR) { _unit->getTile()->destroy(MapData::O_FLOOR); } // move our personal lighting with us _terrain->calculateUnitLighting(); unitspotted = _terrain->calculateFOV(_unit); BattleAction action; // check for proximity grenades (1 tile around the unit in every direction) (for large units, we need to check every tile it occupies) int size = _unit->getArmor()->getSize() - 1; for (int x = size; x >= 0; x--) { for (int y = size; y >= 0; y--) { for (int tx = -1; tx < 2; tx++) { for (int ty = -1; ty < 2; ty++) { Tile *t = _parent->getSave()->getTile(_unit->getPosition() + Position(x,y,0) + Position(tx,ty,0)); if (t) for (std::vector<BattleItem*>::iterator i = t->getInventory()->begin(); i != t->getInventory()->end(); ++i) { if ((*i)->getRules()->getBattleType() == BT_PROXIMITYGRENADE && (*i)->getExplodeTurn() > 0) { Position p; p.x = t->getPosition().x*16 + 8; p.y = t->getPosition().y*16 + 8; p.z = t->getPosition().z*24 + t->getTerrainLevel(); _parent->statePushNext(new ExplosionBState(_parent, p, (*i), (*i)->getPreviousOwner())); t->getInventory()->erase(i); return; } } } } } } // check for reaction fire if (!_falling && !_action.reckless && _terrain->checkReactionFire(_unit, &action)) { postPathProcedures(); action.cameraPosition = _parent->getMap()->getCamera()->getMapOffset(); _parent->statePushBack(new ProjectileFlyBState(_parent, action)); // unit got fired upon - stop walking _pf->abortPath(); return; } } else if (onScreen) { // make sure the unit sprites are up to date if (_pf->getStrafeMove()) { // This is where we fake out the strafe movement direction so the unit "moonwalks" int dirTemp = _unit->getDirection(); _unit->setDirection(_unit->getFaceDirection()); _parent->getMap()->cacheUnit(_unit); _unit->setDirection(dirTemp); } else { _parent->getMap()->cacheUnit(_unit); } } } // we are just standing around, shouldn't we be walking? if (_unit->getStatus() == STATUS_STANDING || _unit->getStatus() == STATUS_PANICKING) { // check if we did spot new units if (unitspotted && !_action.desperate && _unit->getCharging() == 0 && !_falling) { _parent->getMap()->cacheUnit(_unit); _pf->abortPath(); return; } if (onScreen || _parent->getSave()->getDebugMode()) { setNormalWalkSpeed(); } else { _parent->setStateInterval(0); } int dir = _pf->getStartDirection(); if (_falling) { dir = Pathfinding::DIR_DOWN; } if (dir != -1) { if (_pf->getStrafeMove()) { _unit->setFaceDirection(_unit->getDirection()); } Position destination; int tu = _pf->getTUCost(_unit->getPosition(), dir, &destination, _unit, 0); // gets tu cost, but also gets the destination position. if (_falling) { tu = 0; } int energy = tu; if (_action.run) { tu *= 0.75; energy *= 1.5; } if (tu > _unit->getTimeUnits()) { _action.result = "STR_NOT_ENOUGH_TIME_UNITS"; _pf->abortPath(); _parent->getMap()->cacheUnit(_unit); return; } if (_parent->checkReservedTU(_unit, tu) == false) { _pf->abortPath(); _parent->getMap()->cacheUnit(_unit); return; } // we are looking in the wrong way, turn first (unless strafing) // we are not using the turn state, because turning during walking costs no tu if (dir != _unit->getDirection() && dir < Pathfinding::DIR_UP && !_pf->getStrafeMove()) { _unit->lookAt(dir, true); return; } // now open doors (if any) int door = _terrain->unitOpensDoor(_unit); if (door == 3) { return; // don't start walking yet, wait for the ufo door to open } if (door == 0) { _parent->getResourcePack()->getSound("BATTLE.CAT", 3)->play(); // normal door } if (door == 1) { _parent->getResourcePack()->getSound("BATTLE.CAT", 20)->play(); // ufo door return; // don't start walking yet, wait for the ufo door to open } // now start moving dir = _pf->dequeuePath(); if (_falling) { dir = Pathfinding::DIR_DOWN; } if (_unit->spendTimeUnits(tu)) { if (_unit->spendEnergy(energy)) { Tile *tileBelow = _parent->getSave()->getTile(_unit->getPosition() + Position(0,0,-1)); Tile *tileBelowDestination = _parent->getSave()->getTile(destination + Position(0,0,-1)); _unit->startWalking(dir, destination, _parent->getSave()->getTile(destination), tileBelow, tileBelowDestination, onScreen); } else { _action.result = "STR_NOT_ENOUGH_ENERGY"; _parent->getMap()->cacheUnit(_unit); _parent->popState(); } } else { _action.result = "STR_NOT_ENOUGH_TIME_UNITS"; _parent->getMap()->cacheUnit(_unit); _parent->popState(); } // make sure the unit sprites are up to date if (onScreen) { if (_pf->getStrafeMove()) { // This is where we fake out the strafe movement direction so the unit "moonwalks" int dirTemp = _unit->getDirection(); _unit->setDirection(_unit->getFaceDirection()); _unit->setDirection(dirTemp); } _parent->getMap()->cacheUnit(_unit); } } else { postPathProcedures(); return; } } // turning during walking costs no tu if (_unit->getStatus() == STATUS_TURNING) { if (_action.strafe && _unit->getTurretType() > -1) { _unit->turn(true); } else { _unit->turn(); } unitspotted = _terrain->calculateFOV(_unit); // make sure the unit sprites are up to date if (onScreen) _parent->getMap()->cacheUnit(_unit); if (unitspotted && !_action.desperate && _unit->getStatus() != STATUS_PANICKING && _unit->getCharging() == 0 && !_falling) { _pf->abortPath(); _parent->getMap()->cacheUnit(_unit); return; } } }