Skip to content

Commit 30935d9

Browse files
committed
1. Added hotseat support, allowing two players to play on the same computer. Player 1 plays as X-Com and Player 2 plays as the aliens. Hotseat can be enabled from the co-op menu.
2. Added a key binding for 'Give Unit to Teammate' in the multiplayer options. In Battlescape, when a player selects a unit and presses the assigned key, the other player will be able to control that soldier on the next turn. 3. Added the multiplayer option 'Unbalanced Craft Soldiers Limit'. For example, if the craft has a maximum capacity of 14, the host can assign 10 soldiers and the client can assign 4 soldiers. 4. Fixed a crash at the end of a Battlescape mission caused by missing Cyberdisc unit rules.
1 parent c2446bd commit 30935d9

18 files changed

Lines changed: 525 additions & 41 deletions

src/Basescape/SoldierInfoState.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -319,9 +319,12 @@ SoldierInfoState::SoldierInfoState(Base *base, size_t soldierId, bool forceLimit
319319
_btnSack->setText(tr("STR_SACK"));
320320

321321
// COOP
322-
if (_game->getCoopMod()->getCoopStatic() == true && _base->_coopBase == true)
322+
if (_base)
323323
{
324-
_btnSack->setText("MOVE");
324+
if (_game->getCoopMod()->getCoopStatic() == true && _base->_coopBase == true)
325+
{
326+
_btnSack->setText("MOVE");
327+
}
325328
}
326329

327330
_btnSack->onMouseClick((ActionHandler)&SoldierInfoState::btnSackClick);

src/Battlescape/BattlescapeGame.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -922,7 +922,7 @@ int BattlescapeGame::think()
922922
if (!_debugPlay)
923923
{
924924
// coop (PVP)
925-
if ((getCoopMod()->getCoopGamemode() == 2 || getCoopMod()->getCoopGamemode() == 3) && _save->getSelectedUnit())
925+
if ((getCoopMod()->getCoopGamemode() == 2 || getCoopMod()->getCoopGamemode() == 3 || getCoopMod()->_isHotseatActive == true) && _save->getSelectedUnit())
926926
{
927927

928928
if (_save->getSelectedUnit()->getFaction() == FACTION_HOSTILE)
@@ -4613,4 +4613,11 @@ void BattlescapeGame::hitCoop(BattleActionAttack attack, Position center, int po
46134613
getTileEngine()->hitCoop(attack, center, power, type, rangeAtack, terrainMeleeTilePart, seed);
46144614
}
46154615

4616+
void BattlescapeGame::centerOnPositionCoop(Position pos)
4617+
{
4618+
4619+
getMap()->getCamera()->centerOnPosition(pos);
4620+
4621+
}
4622+
46164623
}

src/Battlescape/BattlescapeGame.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ class BattlescapeGame
328328
void clearWaypointsCoop();
329329
void CoopShoot();
330330
void hitCoop(BattleActionAttack attack, Position center, int power, const RuleDamageType* type, bool rangeAtack = true, int terrainMeleeTilePart = 0, uint64_t seed = 0);
331+
void centerOnPositionCoop(Position pos);
331332
};
332333

333334
}

src/Battlescape/BattlescapeState.cpp

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,50 @@ BattlescapeState::BattlescapeState() :
750750

751751
_barHealthColor = _barHealth->getColor();
752752

753+
// coop
754+
// hotseat
755+
if (_game->getCoopMod()->_isHotseatActive == true)
756+
{
757+
758+
_game->getCoopMod()->_isHotseatAlienTurn = false;
759+
_game->getCoopMod()->_changeHotseatTurn = false;
760+
761+
}
762+
763+
// coop
764+
// reset tiles (PVP)
765+
if (_game->getCoopMod()->getCoopStatic() == true && _save)
766+
{
767+
768+
if ((_game->getCoopMod()->getCoopGamemode() == 3 && _game->getCoopMod()->getHost() == true || _game->getCoopMod()->getCoopGamemode() == 2 && _game->getCoopMod()->getHost() == false))
769+
{
770+
771+
_save->resetTiles();
772+
773+
for (auto& unit : *_save->getUnits())
774+
{
775+
776+
if (unit->getFaction() == FACTION_PLAYER)
777+
{
778+
779+
if (_save->getTileEngine())
780+
{
781+
782+
_save->getTileEngine()->calculateLighting(LL_UNITS, unit->getPosition());
783+
_save->getTileEngine()->calculateFOV(unit);
784+
785+
}
786+
}
787+
else if (unit->getFaction() == FACTION_HOSTILE)
788+
{
789+
790+
unit->setVisible(false);
791+
792+
}
793+
}
794+
}
795+
}
796+
753797
// COOP
754798
// BATTLESCAPE INIT
755799
if (_game->getCoopMod()->getCoopStatic() == true && !_save->isPreview() && _game->getCoopMod()->isCoopSession() == true && (_game->getCoopMod()->_waitBC == false || _game->getCoopMod()->_waitBH == false))
@@ -2508,6 +2552,14 @@ void BattlescapeState::btnHelpClick(Action *)
25082552
void BattlescapeState::btnEndTurnClick(Action *)
25092553
{
25102554

2555+
// hotseat
2556+
if (_game->getCoopMod()->_isHotseatActive == true)
2557+
{
2558+
2559+
_game->getCoopMod()->_changeHotseatTurn = true;
2560+
2561+
}
2562+
25112563
_game->getCoopMod()->_isActivePlayerSync = false;
25122564

25132565
bool is_return = false;
@@ -5277,6 +5329,53 @@ void BattlescapeState::popup(State *state)
52775329
void BattlescapeState::finishBattle(bool abort, int inExitArea)
52785330
{
52795331

5332+
// coop
5333+
// hotseat
5334+
if (_game->getCoopMod()->_isHotseatActive == true)
5335+
{
5336+
5337+
_game->getCoopMod()->_changeHotseatTurn = false;
5338+
5339+
if (_game->getCoopMod()->_isHotseatAlienTurn == true)
5340+
{
5341+
for (auto& unit : *_game->getSavedGame()->getSavedBattle()->getUnits())
5342+
{
5343+
5344+
if (unit->getFaction() == FACTION_HOSTILE)
5345+
{
5346+
5347+
unit->convertToFaction(FACTION_PLAYER);
5348+
unit->setOriginalFaction(FACTION_PLAYER);
5349+
}
5350+
else if (unit->getFaction() == FACTION_PLAYER)
5351+
{
5352+
5353+
unit->convertToFaction(FACTION_HOSTILE);
5354+
unit->setOriginalFaction(FACTION_HOSTILE);
5355+
5356+
if (!unit->getUnitRules())
5357+
{
5358+
5359+
std::string alienName = "MALE_CIVILIAN";
5360+
5361+
if (unit->getGeoscapeSoldier())
5362+
{
5363+
5364+
if (unit->getGeoscapeSoldier()->getGender() == GENDER_FEMALE)
5365+
{
5366+
alienName = "FEMALE_CIVILIAN";
5367+
}
5368+
}
5369+
5370+
Unit* rule = _game->getMod()->getUnit(alienName, true);
5371+
unit->setUnitRulesCoop(rule);
5372+
}
5373+
}
5374+
}
5375+
}
5376+
5377+
}
5378+
52805379
// coop
52815380
if (_game->getCoopMod()->getCoopStatic() == true && _game->getCoopMod()->getHost() == false && abort == false && _save->isPreview() == false)
52825381
{

src/Battlescape/DebriefingState.cpp

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,15 @@ DebriefingState::DebriefingState() : _eventToSpawn(nullptr), _region(0), _countr
299299

300300

301301
// COOP
302+
// hotseat
303+
if (_game->getCoopMod()->_isHotseatActive == true)
304+
{
305+
306+
_game->getCoopMod()->_changeHotseatTurn = false;
307+
_game->getCoopMod()->_isHotseatAlienTurn = false;
308+
309+
}
310+
302311
if (_game->getCoopMod()->isCoopSession() == true)
303312
{
304313
_game->getCoopMod()->coopMissionEnd = true;
@@ -1257,34 +1266,46 @@ void DebriefingState::init()
12571266

12581267
// rank
12591268
int soldier_index = 0;
1260-
for (auto &soldier : participants)
1261-
{
12621269

1263-
root["soldiers"][soldier_index]["coopname"] = soldier->getCoopName();
1264-
root["soldiers"][soldier_index]["name"] = soldier->getName();
1265-
root["soldiers"][soldier_index]["nationality"] = soldier->getNationality();
1266-
root["soldiers"][soldier_index]["rank"] = _game->getCoopMod()->SoldierRanktoInt(soldier->getRank());
1267-
root["soldiers"][soldier_index]["promoted"] = soldier->getRecentlyPromotedCoop();
1270+
if (_base)
1271+
{
12681272

1269-
if (soldier->getCurrentStats())
1273+
for (auto& soldier : *_base->getSoldiers())
12701274
{
12711275

1272-
root["soldiers"][soldier_index]["unit_stats"]["tu"] = static_cast<int>(soldier->getCurrentStats()->tu);
1273-
root["soldiers"][soldier_index]["unit_stats"]["stamina"] = static_cast<int>(soldier->getCurrentStats()->stamina);
1274-
root["soldiers"][soldier_index]["unit_stats"]["health"] = static_cast<int>(soldier->getCurrentStats()->health);
1275-
root["soldiers"][soldier_index]["unit_stats"]["bravery"] = static_cast<int>(soldier->getCurrentStats()->bravery);
1276-
root["soldiers"][soldier_index]["unit_stats"]["reactions"] = static_cast<int>(soldier->getCurrentStats()->reactions);
1277-
root["soldiers"][soldier_index]["unit_stats"]["firing"] = static_cast<int>(soldier->getCurrentStats()->firing);
1278-
root["soldiers"][soldier_index]["unit_stats"]["throwing"] = static_cast<int>(soldier->getCurrentStats()->throwing);
1279-
root["soldiers"][soldier_index]["unit_stats"]["strength"] = static_cast<int>(soldier->getCurrentStats()->strength);
1280-
root["soldiers"][soldier_index]["unit_stats"]["psiStrength"] = static_cast<int>(soldier->getCurrentStats()->psiStrength);
1281-
root["soldiers"][soldier_index]["unit_stats"]["psiSkill"] = static_cast<int>(soldier->getCurrentStats()->psiSkill);
1282-
root["soldiers"][soldier_index]["unit_stats"]["melee"] = static_cast<int>(soldier->getCurrentStats()->melee);
1283-
root["soldiers"][soldier_index]["unit_stats"]["mana"] = static_cast<int>(soldier->getCurrentStats()->mana);
1276+
root["soldiers"][soldier_index]["coopbase"] = soldier->getCoopBase();
1277+
root["soldiers"][soldier_index]["coopname"] = soldier->getCoopName();
1278+
root["soldiers"][soldier_index]["name"] = soldier->getName();
1279+
root["soldiers"][soldier_index]["nationality"] = soldier->getNationality();
1280+
root["soldiers"][soldier_index]["rank"] = _game->getCoopMod()->SoldierRanktoInt(soldier->getRank());
1281+
root["soldiers"][soldier_index]["promoted"] = soldier->getRecentlyPromotedCoop();
12841282

1285-
}
1283+
if (soldier->getInitStats())
1284+
{
12861285

1287-
soldier_index++;
1286+
root["soldiers"][soldier_index]["init_tu"] = static_cast<int>(soldier->getInitStats()->tu);
1287+
1288+
}
1289+
1290+
if (soldier->getCurrentStats())
1291+
{
1292+
1293+
root["soldiers"][soldier_index]["unit_stats"]["tu"] = static_cast<int>(soldier->getCurrentStats()->tu);
1294+
root["soldiers"][soldier_index]["unit_stats"]["stamina"] = static_cast<int>(soldier->getCurrentStats()->stamina);
1295+
root["soldiers"][soldier_index]["unit_stats"]["health"] = static_cast<int>(soldier->getCurrentStats()->health);
1296+
root["soldiers"][soldier_index]["unit_stats"]["bravery"] = static_cast<int>(soldier->getCurrentStats()->bravery);
1297+
root["soldiers"][soldier_index]["unit_stats"]["reactions"] = static_cast<int>(soldier->getCurrentStats()->reactions);
1298+
root["soldiers"][soldier_index]["unit_stats"]["firing"] = static_cast<int>(soldier->getCurrentStats()->firing);
1299+
root["soldiers"][soldier_index]["unit_stats"]["throwing"] = static_cast<int>(soldier->getCurrentStats()->throwing);
1300+
root["soldiers"][soldier_index]["unit_stats"]["strength"] = static_cast<int>(soldier->getCurrentStats()->strength);
1301+
root["soldiers"][soldier_index]["unit_stats"]["psiStrength"] = static_cast<int>(soldier->getCurrentStats()->psiStrength);
1302+
root["soldiers"][soldier_index]["unit_stats"]["psiSkill"] = static_cast<int>(soldier->getCurrentStats()->psiSkill);
1303+
root["soldiers"][soldier_index]["unit_stats"]["melee"] = static_cast<int>(soldier->getCurrentStats()->melee);
1304+
root["soldiers"][soldier_index]["unit_stats"]["mana"] = static_cast<int>(soldier->getCurrentStats()->mana);
1305+
}
1306+
1307+
soldier_index++;
1308+
}
12881309

12891310
}
12901311

@@ -3053,6 +3074,13 @@ void DebriefingState::recoverItems(std::vector<BattleItem*> *from, Base *base, C
30533074
}
30543075
else
30553076
{
3077+
3078+
// coop fix
3079+
if (!bi->getUnit())
3080+
{
3081+
continue;
3082+
}
3083+
30563084
if (rule->isRecoverable() && !bi->getXCOMProperty())
30573085
{
30583086
if (rule->getBattleType() == BT_CORPSE)

src/Battlescape/NextTurnState.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,76 @@ void NextTurnState::close()
605605
if (_battleGame->getSide() == FACTION_PLAYER)
606606
{
607607

608+
// hotseat
609+
if (_game->getCoopMod()->_isHotseatActive == true && _game->getCoopMod()->_changeHotseatTurn == true && _game->getSavedGame()->getSavedBattle())
610+
{
611+
612+
_game->getCoopMod()->_changeHotseatTurn = false;
613+
614+
_game->getCoopMod()->_isHotseatAlienTurn = !_game->getCoopMod()->_isHotseatAlienTurn;
615+
616+
_battleGame->resetTiles();
617+
618+
for (auto& unit : *_game->getSavedGame()->getSavedBattle()->getUnits())
619+
{
620+
621+
if (unit->getFaction() == FACTION_HOSTILE)
622+
{
623+
624+
unit->convertToFaction(FACTION_PLAYER);
625+
unit->setOriginalFaction(FACTION_PLAYER);
626+
_battleGame->setSelectedUnit(unit);
627+
628+
if (_battleGame->getTileEngine())
629+
{
630+
631+
_battleGame->getTileEngine()->calculateLighting(LL_UNITS, unit->getPosition());
632+
_battleGame->getTileEngine()->calculateFOV(unit);
633+
634+
}
635+
636+
}
637+
else if (unit->getFaction() == FACTION_PLAYER)
638+
{
639+
640+
unit->convertToFaction(FACTION_HOSTILE);
641+
unit->setOriginalFaction(FACTION_HOSTILE);
642+
643+
if (!unit->getUnitRules())
644+
{
645+
646+
std::string alienName = "MALE_CIVILIAN";
647+
648+
if (unit->getGeoscapeSoldier())
649+
{
650+
651+
if (unit->getGeoscapeSoldier()->getGender() == GENDER_FEMALE)
652+
{
653+
alienName = "FEMALE_CIVILIAN";
654+
}
655+
}
656+
657+
Unit* rule = _game->getMod()->getUnit(alienName, true);
658+
unit->setUnitRulesCoop(rule);
659+
660+
}
661+
662+
unit->setVisible(false);
663+
664+
665+
}
666+
667+
}
668+
669+
if (_battleGame->getSelectedUnit() && _battleGame->getBattleGame())
670+
{
671+
672+
_battleGame->getBattleGame()->centerOnPositionCoop(_battleGame->getSelectedUnit()->getPosition());
673+
674+
}
675+
676+
}
677+
608678
// coop resets
609679
if (_game->getCoopMod()->getCoopStatic() == true)
610680
{

0 commit comments

Comments
 (0)