Skip to content

Commit c88fd74

Browse files
committed
- Implemented Panicking units.
- Various little tweaks and fixes.
1 parent 0f78c9d commit c88fd74

20 files changed

Lines changed: 432 additions & 59 deletions

CHANGELOG.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ New features:
88
-- Abort screen.
99
-- Debriefing screen.
1010
-- Battlescape save game.
11+
-- Panicking units.
1112

1213

1314
Bugfixes:
@@ -30,6 +31,7 @@ Bugfixes:
3031
- Missing text in Monthly Report.
3132
- Ground items showing up in soldier's hands.
3233
- Improved interface performance.
34+
- Bug with seeing through undiscovered floors.
3335

3436
Version 0.3 (01-09-2011)
3537
-------------------------

src/Battlescape/BattlescapeState.cpp

Lines changed: 156 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@
6666
#include "WarningMessage.h"
6767
#include "BattlescapeOptionsState.h"
6868
#include "DebriefingState.h"
69+
#include "../Engine/RNG.h"
70+
#include "InfoboxState.h"
6971

7072
namespace OpenXcom
7173
{
@@ -344,6 +346,8 @@ void BattlescapeState::init()
344346
_map->cacheUnits();
345347
_map->draw();
346348
updateSoldierInfo();
349+
if (_battleGame->getSide() == FACTION_PLAYER)
350+
_playerPanicHandled = false;
347351
}
348352

349353
/**
@@ -371,13 +375,33 @@ void BattlescapeState::think()
371375
_game->pushState(*_popups.begin());
372376
_popups.erase(_popups.begin());
373377
popped = true;
378+
return;
374379
}
375380

376-
// it's the alien side, and nothing is happening
377-
if (_battleGame->getSide() != FACTION_PLAYER && _states.empty() && !_debugPlay)
381+
// nothing is happening - see if we need some alien AI or units panicking or what have you
382+
if (_states.empty())
378383
{
379-
if (_battleGame->getSelectedUnit())
380-
handleAI(_battleGame->getSelectedUnit());
384+
// it's a non player side (ALIENS or CIVILIANS)
385+
if (_battleGame->getSide() != FACTION_PLAYER)
386+
{
387+
if (!_debugPlay)
388+
{
389+
if (_battleGame->getSelectedUnit())
390+
{
391+
if (!handlePanickingUnit(_battleGame->getSelectedUnit()))
392+
handleAI(_battleGame->getSelectedUnit());
393+
}
394+
}
395+
}
396+
else
397+
{
398+
// it's a player side && we have not handled all panicking units
399+
if (!_playerPanicHandled)
400+
{
401+
_playerPanicHandled = handlePanickingPlayer();
402+
}
403+
}
404+
381405
}
382406

383407
}
@@ -395,7 +419,6 @@ void BattlescapeState::handleAI(BattleUnit *unit)
395419
unit->think(&_action);
396420
if (_action.type == BA_WALK)
397421
{
398-
_tuReserved = BA_SNAPSHOT; // aliens are not dumb :)
399422
statePushBack(new UnitWalkBState(this, _action));
400423
}
401424

@@ -424,7 +447,7 @@ void BattlescapeState::handleAI(BattleUnit *unit)
424447
_debugPlay = true;
425448
}
426449
}
427-
if (playableUnitSelected())
450+
if (_battleGame->getSelectedUnit())
428451
{
429452
_map->centerOnPosition(_battleGame->getSelectedUnit()->getPosition());
430453
}
@@ -687,8 +710,6 @@ void BattlescapeState::endTurn()
687710
Position p;
688711

689712
_debugPlay = false;
690-
_tuReserved = BA_NONE;
691-
_reserve = _btnReserveNone;
692713
_action.type = BA_NONE;
693714

694715
// check for hot grenades on the ground
@@ -760,13 +781,19 @@ void BattlescapeState::endTurn()
760781
statePushNext(new ExplosionBState(this, p, 0, 0, t));
761782
}
762783

763-
checkForCasualties(0, 0);
784+
bool bBattleIsOver = checkForCasualties(0, 0);
785+
if (bBattleIsOver)
786+
{
787+
return;
788+
}
764789

765790
updateSoldierInfo();
791+
766792
if (playableUnitSelected())
767793
{
768794
_map->centerOnPosition(_battleGame->getSelectedUnit()->getPosition());
769795
}
796+
770797
_game->pushState(new NextTurnState(_game, _battleGame));
771798
}
772799

@@ -775,8 +802,9 @@ void BattlescapeState::endTurn()
775802
* Checks for casualties and adjusts morale accordingly.
776803
* @param murderweapon
777804
* @param murderer
805+
* @return Whether the battle is finished.
778806
*/
779-
void BattlescapeState::checkForCasualties(BattleItem *murderweapon, BattleUnit *murderer)
807+
bool BattlescapeState::checkForCasualties(BattleItem *murderweapon, BattleUnit *murderer)
780808
{
781809
// TODO : include rank bonuses and penalties !!
782810
for (std::vector<BattleUnit*>::iterator j = _battleGame->getUnits()->begin(); j != _battleGame->getUnits()->end(); ++j)
@@ -842,7 +870,10 @@ void BattlescapeState::checkForCasualties(BattleItem *murderweapon, BattleUnit *
842870
if (liveAliens == 0 || liveSoldiers == 0)
843871
{
844872
finishBattle(false);
873+
return true;
845874
}
875+
876+
return false;
846877
}
847878

848879
/**
@@ -966,7 +997,7 @@ void BattlescapeState::handleNonTargetAction()
966997
{
967998
if (_action.type == BA_PRIME && _action.value > -1)
968999
{
969-
if (_action.actor->spendTimeUnits(_action.TU, _game->getSavedGame()->getBattleGame()->getDebugMode()))
1000+
if (_action.actor->spendTimeUnits(_action.TU, dontSpendTUs()))
9701001
{
9711002
_action.weapon->setExplodeTurn(_game->getSavedGame()->getBattleGame()->getTurn() + _action.value);
9721003
}
@@ -1268,7 +1299,7 @@ void BattlescapeState::popState()
12681299

12691300
if (_states.empty()) return;
12701301

1271-
if (_states.front()->getResult().length() > 0 && _battleGame->getSide() == FACTION_PLAYER)
1302+
if (_states.front()->getResult().length() > 0 && _battleGame->getSide() == FACTION_PLAYER && !dontSpendTUs())
12721303
{
12731304
_warning->showMessage(_game->getLanguage()->getString(_states.front()->getResult()));
12741305
actionFailed = true;
@@ -1279,7 +1310,7 @@ void BattlescapeState::popState()
12791310
{
12801311
if (_action.targeting && _battleGame->getSelectedUnit() && !actionFailed)
12811312
{
1282-
_action.actor->spendTimeUnits(_action.TU, _battleGame->getDebugMode());
1313+
_action.actor->spendTimeUnits(_action.TU, dontSpendTUs());
12831314
}
12841315
if (_action.type == BA_THROW && !actionFailed)
12851316
{
@@ -1396,6 +1427,8 @@ void BattlescapeState::popup(State *state)
13961427
*/
13971428
bool BattlescapeState::checkReservedTU(BattleUnit *bu, int tu)
13981429
{
1430+
if (dontSpendTUs() || _battleGame->getSide() != FACTION_PLAYER) return true; // aliens don't reserve TUs
1431+
13991432
if (_tuReserved != BA_NONE &&
14001433
tu + bu->getActionTUs(_tuReserved, bu->getMainHandWeapon()) > bu->getTimeUnits())
14011434
{
@@ -1457,6 +1490,116 @@ void BattlescapeState::dropItem(const Position &position, BattleItem *item, bool
14571490
}
14581491

14591492
item->setSlot(_game->getRuleset()->getInventory("STR_GROUND"));
1493+
item->setOwner(0);
1494+
}
1495+
1496+
/**
1497+
* Pick the first soldier from the list in status panic.
1498+
* @return True when all panicking is over.
1499+
*/
1500+
bool BattlescapeState::handlePanickingPlayer()
1501+
{
1502+
for (std::vector<BattleUnit*>::iterator j = _battleGame->getUnits()->begin(); j != _battleGame->getUnits()->end(); ++j)
1503+
{
1504+
if (handlePanickingUnit(*j))
1505+
return false;
1506+
}
1507+
return true;
1508+
}
1509+
1510+
/**
1511+
* Cmmon function for panicking units.
1512+
* @return False when unit not in panicking mode.
1513+
*/
1514+
bool BattlescapeState::handlePanickingUnit(BattleUnit *unit)
1515+
{
1516+
UnitStatus status = unit->getStatus();
1517+
if (status != STATUS_PANICKING && status != STATUS_BERSERK) return false;
1518+
unit->setVisible(true);
1519+
1520+
std::wstringstream ss;
1521+
ss << unit->getUnit()->getName(_game->getLanguage()) << L'\n' << _game->getLanguage()->getString(status==STATUS_PANICKING?"STR_HAS_PANICKED":"STR_HAS_GONE_BERSERK");
1522+
_game->pushState(new InfoboxState(_game, ss.str()));
1523+
1524+
unit->abortTurn(); //makes the unit go to status STANDING :p
1525+
1526+
int dropweapons = RNG::generate(0,100);
1527+
int flee = RNG::generate(0,100);
1528+
switch (status)
1529+
{
1530+
case STATUS_PANICKING: // 1/2 chance to drop weapons and 1/2 chance try to flee
1531+
1532+
if (dropweapons <= 50)
1533+
{
1534+
BattleItem *item = unit->getItem("STR_RIGHT_HAND");
1535+
if (item)
1536+
{
1537+
dropItem(unit->getPosition(), item);
1538+
item->moveToOwner(0);
1539+
}
1540+
item = unit->getItem("STR_LEFT_HAND");
1541+
if (item)
1542+
{
1543+
dropItem(unit->getPosition(), item);
1544+
item->moveToOwner(0);
1545+
}
1546+
unit->setCache(0);
1547+
}
1548+
1549+
if (flee <= 50)
1550+
{
1551+
_action.actor = unit;
1552+
_action.target = Position(unit->getPosition().x + RNG::generate(-5,5), unit->getPosition().y + RNG::generate(-5,5), unit->getPosition().z);
1553+
statePushBack(new UnitWalkBState(this, _action));
1554+
}
1555+
break;
1556+
case STATUS_BERSERK: // berserk - do some weird turning around and then pick the closest unit to shoot towards
1557+
_action.actor = unit;
1558+
for (int i= 0; i < 4; i++)
1559+
{
1560+
_action.target = Position(unit->getPosition().x + RNG::generate(-5,5), unit->getPosition().y + RNG::generate(-5,5), unit->getPosition().z);
1561+
statePushBack(new UnitTurnBState(this, _action));
1562+
}
1563+
int mindistance = 10000;
1564+
for (std::vector<BattleUnit*>::iterator i = _battleGame->getUnits()->begin(); i != _battleGame->getUnits()->end(); ++i)
1565+
{
1566+
int x = abs(unit->getPosition().x - (*i)->getPosition().x);
1567+
int y = abs(unit->getPosition().y - (*i)->getPosition().y);
1568+
int distance = int(floor(sqrt(float(x*x + y*y)) + 0.5));
1569+
1570+
if (distance < mindistance && (*i) != unit && !(*i)->isOut())
1571+
{
1572+
_action.target = (*i)->getPosition();
1573+
mindistance = distance;
1574+
}
1575+
}
1576+
statePushBack(new UnitTurnBState(this, _action));
1577+
_action.type = BA_SNAPSHOT;
1578+
_action.weapon = unit->getMainHandWeapon();
1579+
for (int i= 0; i < 6; i++)
1580+
{
1581+
statePushBack(new ProjectileFlyBState(this, _action));
1582+
}
1583+
break;
1584+
}
1585+
unit->setTimeUnits(0);
1586+
unit->moraleChange(+15);
1587+
1588+
return true;
1589+
}
1590+
1591+
/**
1592+
* TUs are not spent when handling panicking mode or in debug mode.
1593+
* @return Whether TUs are spent or not.
1594+
*/
1595+
bool BattlescapeState::dontSpendTUs()
1596+
{
1597+
if (_battleGame->getDebugMode())
1598+
return true;
1599+
if (!_playerPanicHandled)
1600+
return true;
1601+
1602+
return false;
14601603
}
14611604

14621605
}

src/Battlescape/BattlescapeState.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,14 +86,16 @@ class BattlescapeState : public State
8686
BattleAction _action;
8787
BattleActionType _tuReserved;
8888
std::vector<State*> _popups;
89-
bool _debugPlay;
89+
bool _debugPlay, _playerPanicHandled;
9090

9191
void selectNextPlayerUnit(bool checkReselect);
9292
void endTurn();
9393
void handleItemClick(BattleItem *item);
9494
void blinkVisibleUnitButtons();
9595
void handleNonTargetAction();
9696
void setupCursor();
97+
bool handlePanickingPlayer();
98+
bool handlePanickingUnit(BattleUnit *unit);
9799
public:
98100
static const int DEFAULT_ANIM_SPEED = 100;
99101
/// Creates the Battlescape state.
@@ -179,7 +181,9 @@ class BattlescapeState : public State
179181
/// Displays a popup window.
180182
void popup(State *state);
181183
/// Checks for casualties in battle.
182-
void checkForCasualties(BattleItem *murderweapon, BattleUnit *murderer);
184+
bool checkForCasualties(BattleItem *murderweapon, BattleUnit *murderer);
185+
/// Checks if a unit panics.
186+
void checkForPanic(BattleUnit *unit);
183187
/// Check reserved tu.
184188
bool checkReservedTU(BattleUnit *bu, int tu);
185189
/// Handles unit AI.
@@ -188,6 +192,8 @@ class BattlescapeState : public State
188192
void finishBattle(bool abort);
189193
/// Add item & affect with gravity.
190194
void dropItem(const Position &position, BattleItem *item, bool newItem = false);
195+
/// Check whether TUs should be spent.
196+
bool dontSpendTUs();
191197
};
192198

193199
}

0 commit comments

Comments
 (0)