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