/** * Handles some calculations when the path is finished. */ void UnitWalkBState::postPathProcedures() { _action.clearTU(); if (_unit->getFaction() != FACTION_PLAYER) { int dir = _action.finalFacing; if (_action.finalAction) { _unit->dontReselect(); } if (_unit->getCharging() != 0) { dir = _parent->getTileEngine()->getDirectionTo(_unit->getPosition(), _unit->getCharging()->getPosition()); if (_parent->getTileEngine()->validMeleeRange(_unit, _action.actor->getCharging(), dir)) { BattleAction action; action.actor = _unit; action.target = _unit->getCharging()->getPosition(); action.weapon = _unit->getUtilityWeapon(BT_MELEE); action.type = BA_HIT; action.targeting = true; action.updateTU(); _unit->setCharging(0); _parent->statePushBack(new MeleeAttackBState(_parent, action)); } } else if (_unit->isHiding()) { dir = _unit->getDirection() + 4; _unit->setHiding(false); _unit->dontReselect(); } if (dir != -1) { if (dir >= 8) { dir -= 8; } _unit->lookAt(dir); while (_unit->getStatus() == STATUS_TURNING) { _unit->turn(); _parent->getTileEngine()->calculateFOV(_unit); } } } else if (!_parent->getPanicHandled()) { //todo: set the unit to aggrostate and try to find cover? _unit->setTimeUnits(0); } _terrain->calculateLighting(LL_UNITS, _unit->getPosition()); _terrain->calculateFOV(_unit); if (!_falling) _parent->popState(); }
/** * Runs state functionality every cycle. * Ends the panicking when done. */ void UnitPanicBState::think() { if (_unit) { // berserking requires handling here, as the target selection isn't completely random // and needs updating between shots. if (!_unit->isOut() && _shotsFired < 10 && _berserking) { _shotsFired++; BattleAction ba; ba.actor = _unit; ba.weapon = _unit->getMainHandWeapon(); if (_parent->getSave()->canUseWeapon(ba.weapon, ba.actor, _berserking)) { // make autoshots if possible. ba.type = BA_AUTOSHOT; ba.updateTU(); bool canShoot = ba.haveTU(); if (!canShoot) { ba.type = BA_SNAPSHOT; ba.updateTU(); canShoot = ba.haveTU(); } if (!canShoot) { ba.type = BA_AIMEDSHOT; ba.updateTU(); canShoot = ba.haveTU(); } if (canShoot) { // if we see enemies, shoot at the closest living one. if (!_unit->getVisibleUnits()->empty()) { int dist = 255; for (std::vector<BattleUnit*>::const_iterator i = _unit->getVisibleUnits()->begin(); i != _unit->getVisibleUnits()->end(); ++i) { int newDist = _parent->getTileEngine()->distance(_unit->getPosition(), (*i)->getPosition()); if (newDist < dist) { ba.target = (*i)->getPosition(); dist = newDist; } } } else // otherwise shoot randomly { ba.target = Position(_unit->getPosition().x + RNG::generate(-6,6), _unit->getPosition().y + RNG::generate(-6,6), _unit->getPosition().z); } // include the cost for facing our target int turnCost = std::abs(_unit->getDirection() - _unit->directionTo(ba.target)); if (turnCost > 4) { turnCost = 8-turnCost; } _unit->spendTimeUnits(turnCost); _parent->statePushFront(new UnitTurnBState(_parent, ba, false)); // even if we don't have enough TUs to turn AND shoot, we still want to turn. if (ba.haveTU()) { _parent->statePushNext(new ProjectileFlyBState(_parent, ba)); } } } return; } if (!_unit->isOut()) { _unit->abortTurn(); // set the unit status to standing in case it wasn't otherwise changed from berserk/panicked } // reset the unit's time units when all panicking is done _unit->setTimeUnits(0); _unit->moraleChange(+15); } _parent->popState(); _parent->setupCursor(); }