Skip to content

Commit

Permalink
amend reaction fire behaviour
Browse files Browse the repository at this point in the history
allow xcom soldiers to spin and shoot at aggressors
  • Loading branch information
Warboy1982 committed Nov 8, 2017
1 parent 132671d commit aaf8cf6
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/Battlescape/BattlescapeGame.cpp
Expand Up @@ -105,6 +105,7 @@ void BattlescapeGame::think()
// it's a non player side (ALIENS or CIVILIANS)
if (_save->getSide() != FACTION_PLAYER)
{
_save->resetUnitHitStates();
if (!_debugPlay)
{
if (_save->getSelectedUnit())
Expand Down
19 changes: 18 additions & 1 deletion src/Battlescape/TileEngine.cpp
Expand Up @@ -857,7 +857,24 @@ std::vector<std::pair<BattleUnit *, int> > TileEngine::getSpottingUnits(BattleUn
Position originVoxel = getOriginVoxel(falseAction, 0);
Position targetVoxel;
AIModule *ai = (*i)->getAIModule();
bool gotHit = (ai != 0 && ai->getWasHitBy(unit->getId()));

// Inquisitor's note regarding 'gotHit' variable
// in vanilla, the 'hitState' flag is the only part of this equation that comes into play.
// any time a unit takes damage, this flag is set, then it would be reset by a call to
// a function analogous to SavedBattleGame::resetUnitHitStates(), any time:
// 1: a unit was selected by being clicked on.
// 2: either "next unit" button was pressed.
// 3: the inventory screen was accessed. (i didn't look too far into this one, it's possible it's only called in the pre-mission equip screen)
// 4: the same place where we call it, immediately before every move the AI makes.
// this flag is responsible for units turning around to respond to hits, and is in keeping with the details listed on http://www.ufopaedia.org/index.php/Reaction_fire_triggers
// we've gone for a slightly different implementation: AI units keep a list of which units have hit them and don't forget until the end of the player's turn.
// this method is in keeping with the spirit of the original feature, but much less exploitable by players.
// the hitState flag in our implementation allows player units to turn and react as they did in the original, (which is far less cumbersome than giving them all an AI module)
// we don't extend the same "enhanced aggressor memory" courtesy to players, because in the original, they could only turn and react to damage immediately after it happened.
// this is because as much as we want the player's soldiers dead, we don't want them to feel like we're being unfair about it.

bool gotHit = (ai != 0 && ai->getWasHitBy(unit->getId())) || (ai == 0 && (*i)->getHitState());

// can actually see the target Tile, or we got hit
if (((*i)->checkViewSector(unit->getPosition()) || gotHit) &&
// can actually target the unit
Expand Down
34 changes: 31 additions & 3 deletions src/Savegame/BattleUnit.cpp
Expand Up @@ -52,7 +52,7 @@ BattleUnit::BattleUnit(Soldier *soldier, int depth) :
_verticalDirection(0), _status(STATUS_STANDING), _walkPhase(0), _fallPhase(0), _kneeled(false), _floating(false),
_dontReselect(false), _fire(0), _currentAIState(0), _visible(false), _cacheInvalid(true),
_expBravery(0), _expReactions(0), _expFiring(0), _expThrowing(0), _expPsiSkill(0), _expPsiStrength(0), _expMelee(0),
_motionPoints(0), _kills(0), _hitByFire(false), _moraleRestored(0), _coverReserve(0), _charging(0), _turnsSinceSpotted(255),
_motionPoints(0), _kills(0), _hitByFire(false), _hitByAnything(false), _moraleRestored(0), _coverReserve(0), _charging(0), _turnsSinceSpotted(255),
_statistics(), _murdererId(0), _mindControllerID(0), _fatalShotSide(SIDE_FRONT), _fatalShotBodyPart(BODYPART_HEAD),
_geoscapeSoldier(soldier), _unitRules(0), _rankInt(0), _turretType(-1), _hidingForTurn(false), _respawn(false)
{
Expand Down Expand Up @@ -164,7 +164,7 @@ BattleUnit::BattleUnit(Unit *unit, UnitFaction faction, int id, Armor *armor, St
_toDirectionTurret(0), _verticalDirection(0), _status(STATUS_STANDING), _walkPhase(0),
_fallPhase(0), _kneeled(false), _floating(false), _dontReselect(false), _fire(0), _currentAIState(0),
_visible(false), _cacheInvalid(true), _expBravery(0), _expReactions(0), _expFiring(0),
_expThrowing(0), _expPsiSkill(0), _expPsiStrength(0), _expMelee(0), _motionPoints(0), _kills(0), _hitByFire(false),
_expThrowing(0), _expPsiSkill(0), _expPsiStrength(0), _expMelee(0), _motionPoints(0), _kills(0), _hitByFire(false), _hitByAnything(false),
_moraleRestored(0), _coverReserve(0), _charging(0), _turnsSinceSpotted(255),
_statistics(), _murdererId(0), _mindControllerID(0), _fatalShotSide(SIDE_FRONT),
_fatalShotBodyPart(BODYPART_HEAD), _armor(armor), _geoscapeSoldier(0), _unitRules(unit),
Expand Down Expand Up @@ -1079,7 +1079,7 @@ int BattleUnit::damage(Position relative, int power, ItemDamageType type, bool i
{
UnitSide side = SIDE_FRONT;
UnitBodyPart bodypart = BODYPART_TORSO;

_hitByAnything = true;
if (power <= 0)
{
return 0;
Expand Down Expand Up @@ -1639,6 +1639,11 @@ void BattleUnit::prepareNewTurn(bool fullProcess)
if (_faction != _originalFaction)
{
_faction = _originalFaction;
if (_faction == FACTION_PLAYER && _currentAIState)
{
delete _currentAIState;
_currentAIState = 0;
}
}
else
{
Expand Down Expand Up @@ -3242,13 +3247,36 @@ int BattleUnit::getMindControllerId() const
return _mindControllerID;
}

/**
* Get the unit's total firing xp for this mission.
*/
int BattleUnit::getFiringXP() const
{
return _expFiring;
}

/**
* Artificially alter a unit's firing xp. (used for shotguns)
*/
void BattleUnit::nerfFiringXP(int newXP)
{
_expFiring = newXP;
}

/**
* Was this unit just hit?
*/
bool BattleUnit::getHitState()
{
return _hitByAnything;
}

/**
* reset the unit hit state.
*/
void BattleUnit::resetHitState()
{
_hitByAnything = false;
}

}
10 changes: 8 additions & 2 deletions src/Savegame/BattleUnit.h
Expand Up @@ -91,7 +91,7 @@ class BattleUnit
int _motionPoints;
int _kills;
int _faceDirection; // used only during strafeing moves
bool _hitByFire;
bool _hitByFire, _hitByAnything;
int _moraleRestored;
int _coverReserve;
BattleUnit *_charging;
Expand Down Expand Up @@ -494,9 +494,15 @@ class BattleUnit
void setMindControllerId(int id);
/// Get the unit mind controller's id.
int getMindControllerId() const;
/// Get the unit's total firing xp for this mission.
int getFiringXP() const;
/// Artificially alter a unit's firing xp. (used for shotguns)
void nerfFiringXP(int newXP);

/// Was this unit just hit?
bool getHitState();
/// reset the unit hit state.
void resetHitState();

};

}
11 changes: 11 additions & 0 deletions src/Savegame/SavedBattleGame.cpp
Expand Up @@ -2059,4 +2059,15 @@ bool SavedBattleGame::isItemUsable(RuleItem *item) const
return true;
}

/**
* Resets all unit hit state flags.
*/
void SavedBattleGame::resetUnitHitStates()
{
for (std::vector<BattleUnit*>::iterator i = _units.begin(); i != _units.end(); ++i)
{
(*i)->resetHitState();
}
}

}
3 changes: 3 additions & 0 deletions src/Savegame/SavedBattleGame.h
Expand Up @@ -289,9 +289,12 @@ class SavedBattleGame
void setChronoTrigger(ChronoTrigger trigger);
/// Sets the turn to start the aliens cheating.
void setCheatTurn(int turn);
/// Check whether the battle has actually commenced or not.
bool isBeforeGame() const;
/// Checks if an item is usable on this map.
bool isItemUsable(RuleItem *item) const;
/// Reset all the unit hit state flags.
void resetUnitHitStates();
};

}

0 comments on commit aaf8cf6

Please sign in to comment.