1 | /* |
2 | Copyright 2003 Russell Steffen <rsteffen@bayarea.net> |
3 | Copyright 2003 Stephan Zehetner <s.zehetner@nevox.org> |
4 | Copyright 2006 Dmitry Suzdalev <dimsuz@gmail.com> |
5 | Copyright 2006 Inge Wallin <inge@lysator.liu.se> |
6 | Copyright 2006 Pierre Ducroquet <pinaraf@gmail.com> |
7 | |
8 | This program is free software; you can redistribute it and/or modify |
9 | it under the terms of the GNU General Public License as published by |
10 | the Free Software Foundation; either version 2 of the License, or |
11 | (at your option) any later version. |
12 | |
13 | This program is distributed in the hope that it will be useful, |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | GNU General Public License for more details. |
17 | |
18 | You should have received a copy of the GNU General Public License |
19 | along with this program; if not, write to the Free Software |
20 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
21 | */ |
22 | |
23 | #include "game.h" |
24 | #include "players/player.h" |
25 | #include "planet.h" |
26 | #include <KLocalizedString> |
27 | #include <KDebug> |
28 | #include <cmath> |
29 | |
30 | KRandomSequence Game::random = KRandomSequence(); |
31 | |
32 | Game::Game(QObject *parent) : |
33 | QObject(parent) |
34 | { |
35 | m_finalState = new QFinalState(); |
36 | m_turnCounter = 0; |
37 | m_map = new Map(10, 10); |
38 | m_gameMachine.addState(m_finalState); |
39 | m_neutral = new NeutralPlayer(this); |
40 | connect(&m_gameMachine, SIGNAL(finished()), this, SIGNAL(finished())); |
41 | } |
42 | |
43 | QList<Planet*> Game::planets() |
44 | { |
45 | return m_map->planets(); |
46 | } |
47 | |
48 | bool Game::isRunning() |
49 | { |
50 | return m_gameMachine.isRunning(); |
51 | } |
52 | |
53 | Coordinate Game::generatePlanetCoordinates(int x, int y) |
54 | { |
55 | return Coordinate(random.getLong(x), random.getLong(y)); |
56 | } |
57 | |
58 | double Game::generateKillPercentage() |
59 | { |
60 | // 0.30 - 0.90 |
61 | return 0.30 + random.getDouble()*0.60; |
62 | } |
63 | |
64 | int Game::generatePlanetProduction() |
65 | { |
66 | // 5 - 15 |
67 | return 5 + random.getLong(10); |
68 | } |
69 | |
70 | bool Game::attack(Planet *sourcePlanet, Planet *destPlanet, int shipCount, bool standingOrder) |
71 | { |
72 | int arrival = int(std::ceil(m_map->distance(sourcePlanet, destPlanet))) + m_turnCounter; |
73 | if(standingOrder) |
74 | { |
75 | m_currentPlayer->addStandingOrder(new AttackFleet(sourcePlanet, destPlanet, shipCount, arrival)); |
76 | return true; |
77 | } |
78 | else |
79 | { |
80 | AttackFleet *fleet = sourcePlanet->fleet().spawnAttackFleet(destPlanet, shipCount, arrival); |
81 | if (fleet) { |
82 | m_currentPlayer->addAttackFleet(fleet); |
83 | return true; |
84 | } |
85 | return false; |
86 | } |
87 | } |
88 | |
89 | void Game::setPlayers(const QList<Player *> &players) |
90 | { |
91 | m_players = players; |
92 | } |
93 | |
94 | void Game::setCurrentPlayer(Player *player) |
95 | { |
96 | m_currentPlayer = player; |
97 | } |
98 | |
99 | bool Game::doFleetArrival(AttackFleet *fleet) |
100 | { |
101 | // First, sanity check |
102 | if (fleet->arrivalTurn != m_turnCounter) |
103 | return false; |
104 | |
105 | // Check to see of (fleet owner) == (planet owner) |
106 | // if the planet and fleet owner are the same, then merge the fleets |
107 | // otherwise attack. |
108 | if( fleet->owner == fleet->destination->player()) { |
109 | fleet->destination->fleet().absorb(fleet); |
110 | if ( !fleet->owner->isAiPlayer() ) |
111 | emit gameMsg(ki18np("Reinforcements (1 ship) have arrived for planet %2." , |
112 | "Reinforcements (%1 ships) have arrived for planet %2." ) |
113 | .subs(fleet->shipCount()), 0, fleet->destination); |
114 | } else { |
115 | // let's get ready to rumble... |
116 | AttackFleet *attacker = fleet; |
117 | Planet *attackerPlanet = attacker->source; |
118 | Planet *defenderPlanet = attacker->destination; |
119 | DefenseFleet &defender = defenderPlanet->fleet(); |
120 | |
121 | bool haveVictor = false; |
122 | bool planetHolds = true; |
123 | |
124 | while( !haveVictor ) { |
125 | double attackerRoll = random.getDouble(); |
126 | double defenderRoll = random.getDouble(); |
127 | |
128 | /* special case if both have 0 kill percentages */ |
129 | if( defenderPlanet->killPercentage() == 0 && |
130 | attackerPlanet->killPercentage() == 0) { |
131 | if(attackerRoll < defenderRoll ) |
132 | makeKill(&defender, attackerPlanet->player()); |
133 | else |
134 | makeKill(attacker, defenderPlanet->player()); |
135 | } |
136 | |
137 | if( defenderRoll < defenderPlanet->killPercentage() ) |
138 | makeKill(attacker, defenderPlanet->player()); |
139 | |
140 | if( attacker->shipCount() <= 0 ) { |
141 | haveVictor = true; |
142 | planetHolds = true; |
143 | continue; |
144 | } |
145 | if( attackerRoll < attackerPlanet->killPercentage() ) |
146 | makeKill(&defender, attackerPlanet->player()); |
147 | |
148 | if( defender.shipCount() <= 0 ) { |
149 | haveVictor = true; |
150 | planetHolds = false; |
151 | } |
152 | } |
153 | |
154 | if( planetHolds ) { |
155 | defenderPlanet->player()->statEnemyFleetsDestroyed(1); |
156 | emit gameMsg(ki18n("Planet %2 has held against an attack from %1." ), |
157 | attacker->owner, defenderPlanet); |
158 | } else { |
159 | Player *defender = defenderPlanet->player(); |
160 | attacker->owner->statEnemyFleetsDestroyed( 1 ); |
161 | |
162 | defenderPlanet->conquer( attacker ); |
163 | |
164 | emit gameMsg(ki18n("Planet %2 has fallen to %1." ), |
165 | attacker->owner, defenderPlanet, defender); |
166 | } |
167 | } |
168 | return true; |
169 | } |
170 | |
171 | void Game::makeKill(Fleet *fleet, Player *player) |
172 | { |
173 | fleet->removeShips( 1 ); |
174 | player->statEnemyShipsDestroyed( 1 ); |
175 | } |
176 | |
177 | void Game::findWinner() |
178 | { |
179 | kDebug() << "Searching for survivors" ; |
180 | // Check for survivors |
181 | Player *winner = 0; |
182 | foreach (Player *player, m_players) { |
183 | if (player->isNeutral() || player->isSpectator()) { |
184 | continue; |
185 | } |
186 | if (!player->isDead()) { |
187 | if (winner) { |
188 | kDebug() << "Ok, returning 0" ; |
189 | return; |
190 | } else { |
191 | winner = player; |
192 | } |
193 | } |
194 | } |
195 | kDebug() << "Ok, returning " << winner; |
196 | if (winner) |
197 | { |
198 | // We got a winner |
199 | kDebug() << "Trying to stop" ; |
200 | this->stop(); |
201 | emit(finished()); |
202 | } |
203 | } |
204 | |