예제 #1
0
/**
 * 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();
}
예제 #2
0
/**
 * 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();
}