1 ////////////////////////////////////////////////////////////////////////////////
2 // Scorched3D (c) 2000-2011
3 //
4 // This file is part of Scorched3D.
5 //
6 // Scorched3D is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // Scorched3D is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License along
17 // with this program; if not, write to the Free Software Foundation, Inc.,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 ////////////////////////////////////////////////////////////////////////////////
20
21 #include <server/ServerTurnsSequential.h>
22 #include <server/ScorchedServer.h>
23 #include <server/ServerSimulator.h>
24 #include <common/OptionsGame.h>
25 #include <common/OptionsScorched.h>
26 #include <common/OptionsTransient.h>
27 #include <simactions/PlayMovesSimAction.h>
28 #include <simactions/TankStopMoveSimAction.h>
29 #include <coms/ComsPlayedMoveMessage.h>
30 #include <tank/TankSort.h>
31 #include <tanket/Tanket.h>
32 #include <target/TargetContainer.h>
33 #include <tanket/TanketShotInfo.h>
34 #include <list>
35
ServerTurnsSequential()36 ServerTurnsSequential::ServerTurnsSequential() :
37 ServerTurns(true),
38 playingPlayer_(0), nextMoveId_(0)
39 {
40 }
41
~ServerTurnsSequential()42 ServerTurnsSequential::~ServerTurnsSequential()
43 {
44 }
45
internalEnterState()46 void ServerTurnsSequential::internalEnterState()
47 {
48 playingPlayer_ = 0;
49 waitingPlayers_.clear();
50
51 OptionsGame::TurnType turnType = (OptionsGame::TurnType)
52 ScorchedServer::instance()->getOptionsGame().getTurnType().getValue();
53
54 // On the very first round make the order random (if loser first chosen)
55 // as there is no loser yet!
56 if ((ScorchedServer::instance()->getOptionsTransient().getCurrentRoundNo() == 1) &&
57 turnType == OptionsGame::TurnSequentialLoserFirst)
58 {
59 turnType = OptionsGame::TurnSequentialRandom;
60 }
61
62 // Standard player ordering is the reverse of the tank score
63 TankSort::getSortedTanksIds(
64 ScorchedServer::instance()->getContext(),
65 waitingPlayers_); // All tanks
66 waitingPlayers_.reverse();
67 {
68 // Tankets wont be on the list, so add them
69 std::map<unsigned int, Tanket*> &tankets =
70 ScorchedServer::instance()->getTargetContainer().getTankets();
71 std::map<unsigned int, Tanket*>::iterator itor;
72 for (itor = tankets.begin();
73 itor != tankets.end();
74 ++itor)
75 {
76 Tanket *tanket = itor->second;
77 if (!tanket->getShotInfo().getUseNormalMoves()) continue;
78
79 tanket->getShotInfo().setMoveId(0);
80 if (tanket->getType() == Target::TypeTanket)
81 {
82 waitingPlayers_.push_back(tanket->getPlayerId());
83 }
84 }
85 }
86
87 // Check for a different ordering
88 if (turnType == OptionsGame::TurnSequentialRandom)
89 {
90 // Create zero player vector
91 std::vector<unsigned int> tmpPlayers;
92 for (int i=0; i<(int) waitingPlayers_.size(); i++)
93 {
94 tmpPlayers.push_back(0);
95 }
96
97 // Randomize list order into vector
98 while (!waitingPlayers_.empty())
99 {
100 unsigned int player = waitingPlayers_.front();
101 waitingPlayers_.pop_front();
102 bool done = false;
103 while (!done)
104 {
105 int pos = int(RAND * float(tmpPlayers.size()));
106 if (pos < int(tmpPlayers.size()) && tmpPlayers[pos] == 0)
107 {
108 tmpPlayers[pos] = player;
109 done = true;
110 }
111 }
112 }
113
114 // Copy vector back to list
115 for (int i=0; i<(int) tmpPlayers.size(); i++)
116 {
117 waitingPlayers_.push_back(tmpPlayers[i]);
118 }
119 }
120 }
121
internalSimulate(fixed frameTime)122 void ServerTurnsSequential::internalSimulate(fixed frameTime)
123 {
124 // Check if all the tanks have made their moves
125 if (waitingPlayers_.empty() && playingPlayer_ == 0)
126 {
127 internalEnterState();
128 incrementTurn();
129 }
130
131 // Check tanks are alive
132 Tanket *playingTanket =
133 ScorchedServer::instance()->getTargetContainer().getTanketById(playingPlayer_);
134 if (!playingTanket || !playingTanket->getAlive())
135 {
136 if (playingTanket && playingTanket->getShotInfo().getMoveId() != 0)
137 {
138 playMoveFinished(playingTanket);
139 }
140
141 playingPlayer_ = 0;
142 }
143
144 // Check if we are ready for the next player
145 if (playingPlayer_ == 0)
146 {
147 while (!waitingPlayers_.empty())
148 {
149 unsigned int waitingPlayer = waitingPlayers_.front();
150 waitingPlayers_.pop_front();
151
152 Tanket *waitingTanket =
153 ScorchedServer::instance()->getTargetContainer().getTanketById(waitingPlayer);
154 if (waitingTanket && waitingTanket->getAlive())
155 {
156 playingPlayer_ = waitingPlayer;
157 makeMove(waitingTanket);
158 break;
159 }
160 }
161 }
162 }
163
makeMove(Tanket * tanket)164 void ServerTurnsSequential::makeMove(Tanket *tanket)
165 {
166 nextMoveId_++;
167 fixed shotTime = fixed(
168 ScorchedServer::instance()->getOptionsGame().getShotTime());
169 playMove(tanket, nextMoveId_, shotTime);
170 }
171
internalMoveFinished(ComsPlayedMoveMessage & playedMessage)172 void ServerTurnsSequential::internalMoveFinished(ComsPlayedMoveMessage &playedMessage)
173 {
174 unsigned int playerId = playedMessage.getPlayerId();
175 unsigned int moveId = playedMessage.getMoveId();
176 if (playerId != playingPlayer_) return;
177 Tanket *tanket = ScorchedServer::instance()->getTargetContainer().getTanketById(playerId);
178 if (!tanket || tanket->getShotInfo().getMoveId() != moveId) return;
179
180 playMoveFinished(tanket);
181 playingPlayer_ = 0;
182
183 if (tanket->getAlive())
184 {
185 std::list<ComsPlayedMoveMessage*> messages;
186 messages.push_back(new ComsPlayedMoveMessage(playedMessage));
187 playShots(messages, moveId, true, true);
188 }
189 }
190