File indexing completed on 2024-12-08 06:47:08
0001 /* 0002 SPDX-FileCopyrightText: 2003 Russell Steffen <rsteffen@bayarea.net> 0003 SPDX-FileCopyrightText: 2003 Stephan Zehetner <s.zehetner@nevox.org> 0004 SPDX-FileCopyrightText: 2006 Dmitry Suzdalev <dimsuz@gmail.com> 0005 SPDX-FileCopyrightText: 2006 Inge Wallin <inge@lysator.liu.se> 0006 SPDX-FileCopyrightText: 2006 Pierre Ducroquet <pinaraf@gmail.com> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 #include "game.h" 0012 #include "planet.h" 0013 #include <KLocalizedString> 0014 #include <QDebug> 0015 #include <cmath> 0016 0017 QRandomGenerator Game::random = QRandomGenerator(QRandomGenerator::global()->generate()); 0018 0019 Game::Game(QObject *parent) : 0020 QObject(parent) 0021 { 0022 m_finalState = new QFinalState(); 0023 m_turnCounter = 0; 0024 m_map = new Map(10, 10); 0025 m_gameMachine.addState(m_finalState); 0026 m_neutral = new NeutralPlayer(this); 0027 connect(&m_gameMachine, &QStateMachine::finished, this, &Game::finished); 0028 } 0029 0030 Game::~Game() 0031 { 0032 delete m_map; 0033 } 0034 0035 const QList<Planet*> Game::planets() 0036 { 0037 return m_map->planets(); 0038 } 0039 0040 bool Game::isRunning() 0041 { 0042 return m_gameMachine.isRunning(); 0043 } 0044 0045 Coordinate Game::generatePlanetCoordinates(int x, int y) 0046 { 0047 return Coordinate(random.bounded(x), random.bounded(y)); 0048 } 0049 0050 double Game::generateKillPercentage() 0051 { 0052 // 0.30 - 0.90 0053 return 0.30 + random.bounded(0.60); 0054 } 0055 0056 int Game::generatePlanetProduction() 0057 { 0058 // 5 - 15 0059 return 5 + random.bounded(10); 0060 } 0061 0062 bool Game::attack(Planet *sourcePlanet, Planet *destPlanet, long long shipCount, bool standingOrder) 0063 { 0064 int arrival = int(std::ceil(m_map->distance(sourcePlanet, destPlanet))) + m_turnCounter; 0065 if(standingOrder) 0066 { 0067 m_currentPlayer->addStandingOrder(new AttackFleet(sourcePlanet, destPlanet, shipCount, arrival)); 0068 return true; 0069 } 0070 else 0071 { 0072 AttackFleet *fleet = sourcePlanet->fleet().spawnAttackFleet(destPlanet, shipCount, arrival); 0073 if (fleet) { 0074 m_currentPlayer->addAttackFleet(fleet); 0075 return true; 0076 } 0077 return false; 0078 } 0079 } 0080 0081 void Game::setPlayers(const QList<Player *> &players) 0082 { 0083 m_players = players; 0084 } 0085 0086 void Game::setCurrentPlayer(Player *player) 0087 { 0088 m_currentPlayer = player; 0089 } 0090 0091 bool Game::doFleetArrival(AttackFleet *fleet) 0092 { 0093 // First, sanity check 0094 if (fleet->arrivalTurn != m_turnCounter) 0095 return false; 0096 0097 // Check to see of (fleet owner) == (planet owner) 0098 // if the planet and fleet owner are the same, then merge the fleets 0099 // otherwise attack. 0100 if( fleet->owner == fleet->destination->player()) { 0101 fleet->destination->fleet().absorb(fleet); 0102 if ( !fleet->owner->isAiPlayer() ) 0103 Q_EMIT gameMsg(ki18np("Reinforcements (1 ship) have arrived for planet %2.", 0104 "Reinforcements (%1 ships) have arrived for planet %2.") 0105 .subs(fleet->shipCount()), nullptr, fleet->destination); 0106 } else { 0107 // let's get ready to rumble... 0108 AttackFleet *attacker = fleet; 0109 Planet *attackerPlanet = attacker->source; 0110 Planet *defenderPlanet = attacker->destination; 0111 DefenseFleet &defender = defenderPlanet->fleet(); 0112 0113 bool haveVictor = false; 0114 bool planetHolds = true; 0115 0116 while( !haveVictor ) { 0117 double attackerRoll = random.bounded(1.0); 0118 double defenderRoll = random.bounded(1.0); 0119 0120 /* special case if both have 0 kill percentages */ 0121 if( defenderPlanet->killPercentage() == 0 && 0122 attackerPlanet->killPercentage() == 0) { 0123 if(attackerRoll < defenderRoll ) 0124 makeKill(&defender, attackerPlanet->player()); 0125 else 0126 makeKill(attacker, defenderPlanet->player()); 0127 } 0128 0129 if( defenderRoll < defenderPlanet->killPercentage() ) 0130 makeKill(attacker, defenderPlanet->player()); 0131 0132 if( attacker->shipCount() <= 0 ) { 0133 haveVictor = true; 0134 planetHolds = true; 0135 continue; 0136 } 0137 if( attackerRoll < attackerPlanet->killPercentage() ) 0138 makeKill(&defender, attackerPlanet->player()); 0139 0140 if( defender.shipCount() <= 0 ) { 0141 haveVictor = true; 0142 planetHolds = false; 0143 } 0144 } 0145 0146 if( planetHolds ) { 0147 defenderPlanet->player()->statEnemyFleetsDestroyed(1); 0148 Q_EMIT gameMsg(ki18n("Planet %2 has held against an attack from %1."), 0149 attacker->owner, defenderPlanet); 0150 } else { 0151 Player *defender = defenderPlanet->player(); 0152 attacker->owner->statEnemyFleetsDestroyed( 1 ); 0153 0154 defenderPlanet->conquer( attacker ); 0155 0156 Q_EMIT gameMsg(ki18n("Planet %2 has fallen to %1."), 0157 attacker->owner, defenderPlanet, defender); 0158 } 0159 } 0160 return true; 0161 } 0162 0163 void Game::makeKill(Fleet *fleet, Player *player) 0164 { 0165 fleet->removeShips( 1 ); 0166 player->statEnemyShipsDestroyed( 1 ); 0167 } 0168 0169 void Game::findWinner() 0170 { 0171 //qDebug() << "Searching for survivors"; 0172 // Check for survivors 0173 Player *winner = nullptr; 0174 for (Player *player : players()) { 0175 if (player->isNeutral() || player->isSpectator()) { 0176 continue; 0177 } 0178 if (!player->isDead()) { 0179 if (winner) { 0180 //qDebug() << "Ok, returning 0"; 0181 return; 0182 } else { 0183 winner = player; 0184 } 0185 } 0186 } 0187 //qDebug() << "Ok, returning " << winner; 0188 if (winner) 0189 { 0190 // We got a winner 0191 //qDebug() << "Trying to stop"; 0192 this->stop(); 0193 Q_EMIT finished(); 0194 } 0195 } 0196 0197 #include "moc_game.cpp"