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 <stdio.h>
22 #include <tank/Tank.h>
23 #include <tank/TankState.h>
24 #include <target/TargetLife.h>
25 #include <target/TargetShield.h>
26 #include <target/TargetState.h>
27 #include <engine/ScorchedContext.h>
28 #include <lang/LangResource.h>
29 #include <common/OptionsScorched.h>
30 #include <common/Defines.h>
31 #include <common/Logger.h>
32
33 static struct AllowedStateTransitions
34 {
35 TankState::State from, to;
36 }
37 allowedStateTransitions[] =
38 {
39 { TankState::sLoading, TankState::sSpectator },
40 { TankState::sLoading, TankState::sDead },
41 { TankState::sSpectator, TankState::sNormal },
42 { TankState::sSpectator, TankState::sDead },
43 { TankState::sDead, TankState::sNormal },
44 { TankState::sDead, TankState::sBuying },
45 { TankState::sDead, TankState::sLoading },
46 { TankState::sDead, TankState::sSpectator },
47 { TankState::sNormal, TankState::sDead },
48 { TankState::sNormal, TankState::sLoading },
49 { TankState::sNormal, TankState::sSpectator },
50 { TankState::sSpectator, TankState::sLoading },
51 { TankState::sBuying, TankState::sSpectator },
52 { TankState::sBuying, TankState::sLoading },
53 { TankState::sBuying, TankState::sNormal }
54 };
55
TankState(ScorchedContext & context,unsigned int playerId)56 TankState::TankState(ScorchedContext &context, unsigned int playerId) :
57 state_(sLoading), tank_(0),
58 context_(context),
59 muted_(false),
60 skipshots_(false),
61 lives_(0), maxLives_(1),
62 notSpectator_(false),
63 newlyJoined_(true),
64 stateChangeCount_(0)
65 {
66 }
67
~TankState()68 TankState::~TankState()
69 {
70 }
71
newMatch()72 void TankState::newMatch()
73 {
74 stateChangeCount_ = 0;
75 setState(sDead);
76 }
77
newGame()78 void TankState::newGame()
79 {
80 setState(sNormal);
81
82 maxLives_ = context_.getOptionsGame().getPlayerLives();
83
84 lives_ = maxLives_;
85 tank_->getTargetState().setFalling(0);
86 tank_->getTargetState().setMoving(0);
87 }
88
clientNewGame()89 void TankState::clientNewGame()
90 {
91 skipshots_ = false;
92 }
93
setState(State s)94 void TankState::setState(State s)
95 {
96 for (int i=0; i<sizeof(allowedStateTransitions) /
97 sizeof(AllowedStateTransitions); i++)
98 {
99 if (state_ == allowedStateTransitions[i].from &&
100 s == allowedStateTransitions[i].to)
101 {
102 state_ = s;
103 stateChangeCount_++;
104 break;
105 }
106 }
107
108 if (state_ != sNormal && state_ != sBuying)
109 {
110 // Make sure the target and shield physics
111 // are disabled
112 tank_->getLife().setLife(0);
113 tank_->getShield().setCurrentShield(0);
114 }
115 else
116 {
117 // Make sure target space contains tank
118 tank_->getLife().setLife(tank_->getLife().getLife());
119 }
120 }
121
getStateString()122 const char *TankState::getStateString()
123 {
124 static char string[1024];
125 snprintf(string, 1024, "%s %s (%i hp)",
126 getSmallStateString(),
127 (muted_?"muted ":""),
128 (int) tank_->getLife().getLife().asInt());
129 return string;
130 }
131
getSmallStateString()132 const char *TankState::getSmallStateString()
133 {
134 const char *type = "";
135 switch (state_)
136 {
137 case sNormal:
138 type = "Alive";
139 break;
140 case sDead:
141 type = "Dead";
142 break;
143 case sSpectator:
144 type = "Spectator";
145 break;
146 case sLoading:
147 type = "Loading";
148 break;
149 case sBuying:
150 type = "Buying";
151 break;
152 }
153
154 return type;
155 }
156
getSmallStateLangString()157 LangString &TankState::getSmallStateLangString()
158 {
159 LANG_RESOURCE_CONST_VAR(DEAD, "DEAD", "Dead");
160 LANG_RESOURCE_CONST_VAR(ALIVE, "ALIVE", "Alive");
161 LANG_RESOURCE_CONST_VAR(SPECTATOR, "SPECTATOR", "Spectator");
162 LANG_RESOURCE_CONST_VAR(LOADING, "LOADING", "Loading");
163 LANG_RESOURCE_CONST_VAR(BUYING, "BUYING", "Buying");
164
165 switch (state_)
166 {
167 case sNormal:
168 return ALIVE;
169 case sDead:
170 return DEAD;
171 case sSpectator:
172 return SPECTATOR;
173 case sLoading:
174 return LOADING;
175 case sBuying:
176 return BUYING;
177 }
178
179 static LangString nullResult;
180 return nullResult;
181 }
182
getTankPlaying()183 bool TankState::getTankPlaying()
184 {
185 return state_ == sNormal || state_ == sDead || state_ == sBuying;
186 }
187
getTankAliveOrBuying()188 bool TankState::getTankAliveOrBuying()
189 {
190 return state_ == sNormal || state_ == sBuying;
191 }
192
writeMessage(NamedNetBuffer & buffer)193 bool TankState::writeMessage(NamedNetBuffer &buffer)
194 {
195 NamedNetBufferSection section(buffer, "TankState");
196
197 buffer.addToBufferNamed("state", (int) state_);
198 buffer.addToBufferNamed("lives", lives_);
199 buffer.addToBufferNamed("maxLives", maxLives_);
200 buffer.addToBufferNamed("newlyjoined", newlyJoined_);
201 buffer.addToBufferNamed("notspectator", notSpectator_);
202 return true;
203 }
204
readMessage(NetBufferReader & reader)205 bool TankState::readMessage(NetBufferReader &reader)
206 {
207 int s;
208 if (!reader.getFromBuffer(s))
209 {
210 Logger::log("TankState::state_ read failed");
211 return false;
212 }
213 state_ = (TankState::State) s;
214 setState((TankState::State) s);
215 if (!reader.getFromBuffer(lives_))
216 {
217 Logger::log("TankState::lives_ read failed");
218 return false;
219 }
220 if (!reader.getFromBuffer(maxLives_))
221 {
222 Logger::log("TankState::maxLives_ read failed");
223 return false;
224 }
225 if (!reader.getFromBuffer(newlyJoined_))
226 {
227 Logger::log("TankState::newlyJoined_ read failed");
228 return false;
229 }
230 if (!reader.getFromBuffer(notSpectator_))
231 {
232 Logger::log("TankState::notSpectator_ read failed");
233 return false;
234 }
235 return true;
236 }
237