1 /*
2  *  FlagInfo.cpp
3  *  OpenLieroX
4  *
5  *  Created by Albert Zeyer on 20.03.09.
6  *  code under LGPL
7  *
8  */
9 
10 // TODO: remove unnecessary includes
11 #include <SDL.h>
12 #include <map>
13 #include "Debug.h"
14 #include "FlagInfo.h"
15 #include "CWorm.h"
16 #include "CServer.h"
17 #include "CClient.h"
18 #include "LieroX.h"
19 #include "CGameMode.h"
20 #include "CBytestream.h"
21 #include "CServerConnection.h"
22 #include "CServerNetEngine.h"
23 #include "CViewport.h"
24 #include "CGameSkin.h"
25 #include "DeprecatedGUI/Graphics.h"
26 #include "GfxPrimitives.h"
27 #include "CMap.h"
28 
29 #define FLAG_FRAME_WIDTH 32
30 #define FLAG_FRAME_HEIGHT 18
31 #define FLAG_SPACING 4
32 #define FLAG_WIDTH 18
33 #define FLAG_HEIGHT 18
34 
Flag(int i)35 Flag::Flag(int i) : id(i), holderWorm(-1), atSpawnPoint(true), skin(NULL) {
36 	skin = new CGameSkin("../data/gfx/flags.png", FLAG_FRAME_WIDTH, FLAG_FRAME_HEIGHT, FLAG_SPACING, FLAG_WIDTH, FLAG_HEIGHT);
37 
38 	if(i >= 0 && i < 4) {
39 		skin->Colorize(tLX->clTeamColors[i]);
40 	}
41 }
42 
operator =(const Flag & f)43 Flag& Flag::operator=(const Flag& f) {
44 	if(skin) {
45 		delete skin;
46 		skin = NULL;
47 	}
48 
49 	id = f.id;
50 	pos = f.pos;
51 	holderWorm = f.holderWorm;
52 	spawnPoint = f.spawnPoint;
53 	atSpawnPoint = f.atSpawnPoint;
54 	if(f.skin)
55 		skin = new CGameSkin(*f.skin);
56 	else
57 		skin = NULL;
58 	return *this;
59 }
60 
~Flag()61 Flag::~Flag() {
62 	if(skin) {
63 		delete skin;
64 		skin = NULL;
65 	}
66 }
67 
getPos()68 CVec Flag::getPos() {
69 	if(atSpawnPoint)
70 		return spawnPoint.pos;
71 	if(holderWorm >= 0) {
72 		if(tLX->iGameType == GME_JOIN)
73 			return cClient->getRemoteWorms()[holderWorm].getPos();
74 		else
75 			return cServer->getWorms()[holderWorm].getPos();
76 	}
77 	return pos;
78 }
79 
80 typedef std::map<int,Flag> Flags;
81 
82 struct FlagInfoData {
83 	Flags flags;
84 };
85 
FlagInfo()86 FlagInfo::FlagInfo() {
87 	data = new FlagInfoData();
88 	reset();
89 }
90 
~FlagInfo()91 FlagInfo::~FlagInfo() {
92 	delete data; data = NULL;
93 }
94 
reset()95 void FlagInfo::reset() {
96 	data->flags.clear();
97 }
98 
initFlag(int id)99 Flag* FlagInfo::initFlag(int id) {
100 	return &( data->flags[id] = Flag(id) );
101 }
102 
getFlag(int id)103 Flag* FlagInfo::getFlag(int id) {
104 	Flags::iterator i = data->flags.find(id);
105 	if(i != data->flags.end())
106 		return &i->second;
107 	else
108 		return NULL;
109 }
110 
getFlagOfWorm(int worm)111 Flag* FlagInfo::getFlagOfWorm(int worm) {
112 	for(Flags::iterator i = data->flags.begin(); i != data->flags.end(); ++i) {
113 		if(!i->second.atSpawnPoint && i->second.holderWorm == worm)
114 			return &i->second;
115 	}
116 	return NULL;
117 }
118 
removeFlag(int id)119 bool FlagInfo::removeFlag(int id) {
120 	Flags::iterator i = data->flags.find(id);
121 	if(i != data->flags.end()) {
122 		data->flags.erase(i);
123 		return true;
124 	}
125 	return false;
126 }
127 
128 
drawFlagSpawnPoint(Flag * flag,SDL_Surface * bmpDest,CViewport * v)129 static void drawFlagSpawnPoint(Flag* flag, SDL_Surface* bmpDest, CViewport* v) {
130 	SDL_Surface* bmp = NULL;
131 	if(flag->id >= 0 && flag->id < 4)
132 		bmp = DeprecatedGUI::gfxGame.bmpFlagSpawnpoint[flag->id].get();
133 	else
134 		bmp = DeprecatedGUI::gfxGame.bmpFlagSpawnpointDefault.get();
135 
136 	CMap* map = cClient->getMap();
137 	VectorD2<int> p = v->physicToReal(flag->spawnPoint.pos, cClient->getGameLobby()->features[FT_InfiniteMap], map->GetWidth(), map->GetHeight());
138 
139 	DrawImage(bmpDest, bmp, p.x - bmp->w/2, p.y - bmp->h/2);
140 }
141 
drawUnattachedFlag(Flag * flag,SDL_Surface * bmpDest,CViewport * v)142 static void drawUnattachedFlag(Flag* flag, SDL_Surface* bmpDest, CViewport* v) {
143 	if(flag->skin == NULL) return;
144 
145 	CMap* map = cClient->getMap();
146 	VectorD2<int> p = v->physicToReal(flag->getPos(), cClient->getGameLobby()->features[FT_InfiniteMap], map->GetWidth(), map->GetHeight());
147 
148 	int f = ((int) cClient->serverTime().seconds() *7);
149 	if (flag->skin->getFrameCount() != 0)
150 		f %= flag->skin->getFrameCount(); // every skin has exactly 21 frames
151 
152 	flag->skin->Draw(bmpDest, p.x - FLAG_WIDTH/2, p.y - FLAG_HEIGHT/2, f, false, true);
153 }
154 
draw(SDL_Surface * bmpDest,CViewport * v)155 void FlagInfo::draw(SDL_Surface* bmpDest, CViewport* v) {
156 	for(Flags::iterator i = data->flags.begin(); i != data->flags.end(); ++i) {
157 		Flag& flag = i->second;
158 
159 		drawFlagSpawnPoint(&flag, bmpDest, v);
160 
161 		if(flag.holderWorm >= 0) continue;
162 
163 		// drawing unattached or flags at spawnpoint
164 		drawUnattachedFlag(&flag, bmpDest, v);
165 	}
166 }
167 
drawWormAttachedFlag(CWorm * worm,SDL_Surface * bmpDest,CViewport * v)168 void FlagInfo::drawWormAttachedFlag(CWorm* worm, SDL_Surface* bmpDest, CViewport* v) {
169 	Flag* flag = getFlagOfWorm(worm->getID());
170 	if(flag == NULL) return;
171 	if(flag->skin == NULL) return;
172 
173 	// see CWorm::Draw() for all these calculations
174 
175 	CMap* map = cClient->getMap();
176 	VectorD2<int> p = v->physicToReal(worm->getPos(), cClient->getGameLobby()->features[FT_InfiniteMap], map->GetWidth(), map->GetHeight());
177 
178 	int f = ((int) worm->frame()*7);
179 	int ang = (int)( (worm->getAngle()+90)/151 * 7 );
180 	f += ang;
181 
182 	if(worm->getFaceDirectionSide() == DIR_LEFT) {
183 		flag->skin->Draw(bmpDest, p.x - flag->skin->getSkinWidth(), p.y - flag->skin->getSkinHeight(), f, false, true);
184 	}
185 	else {
186 		flag->skin->Draw(bmpDest, p.x, p.y - flag->skin->getSkinHeight(), f, false, false);
187 	}
188 }
189 
drawOnMiniMap(CMap * cMap,SDL_Surface * bmpDest,uint miniX,uint miniY)190 void FlagInfo::drawOnMiniMap(CMap* cMap, SDL_Surface* bmpDest, uint miniX, uint miniY) {
191 	for(Flags::iterator i = data->flags.begin(); i != data->flags.end(); ++i) {
192 		Flag& flag = i->second;
193 
194 		Uint8 r = 255,g=255,b=255;
195 		if(flag.id >= 0 && flag.id < 4) {
196 			r = tLX->clTeamColors[flag.id].r;
197 			g = tLX->clTeamColors[flag.id].g;
198 			b = tLX->clTeamColors[flag.id].b;
199 		}
200 
201 		cMap->drawOnMiniMap(bmpDest, miniX, miniY, flag.spawnPoint.pos, r, g, b, true, true);
202 
203 		if(flag.holderWorm >= 0) continue;
204 
205 		// drawing unattached or flags at spawnpoint
206 		cMap->drawOnMiniMap(bmpDest, miniX, miniY, flag.getPos(), r, g, b, false, true);
207 	}
208 }
209 
210 
211 
212 
213 
checkWorm(CWorm * worm)214 void FlagInfo::checkWorm(CWorm* worm) {
215 	if(tLX->iGameType == GME_JOIN) {
216 		errors << "FlagInfo::checkWorm: this function is only supposed to be called by the server" << endl;
217 		return;
218 	}
219 
220 	if(!worm->getAlive()) return;
221 
222 	if(!cServer || !cServer->isServerRunning() || !cServer->getGameMode()) {
223 		errors << "FlagInfo::checkWorm: server is corrupt" << endl;
224 		return;
225 	}
226 
227 	float flagPointRadius = cServer->getGameMode()->FlagPointRadius(); flagPointRadius *= flagPointRadius;
228 	float flagRadius = cServer->getGameMode()->FlagRadius(); flagRadius *= flagRadius;
229 
230 	for(Flags::iterator i = data->flags.begin(); i != data->flags.end(); ++i) {
231 		if( (worm->getPos() - i->second.spawnPoint.pos).GetLength2() < flagPointRadius ) {
232 			cServer->getGameMode()->hitFlagSpawnPoint(worm, &i->second);
233 
234 			if(i->second.atSpawnPoint)
235 				cServer->getGameMode()->hitFlag(worm, &i->second);
236 		}
237 
238 		if(!i->second.atSpawnPoint && i->second.holderWorm < 0) {
239 			if( (worm->getPos() - i->second.pos).GetLength2() < flagRadius ) {
240 				cServer->getGameMode()->hitFlag(worm, &i->second);
241 			}
242 		}
243 	}
244 }
245 
getWidth() const246 int FlagInfo::getWidth() const
247 {
248 	return FLAG_WIDTH;
249 }
250 
getHeight() const251 int FlagInfo::getHeight() const
252 {
253 	return FLAG_HEIGHT;
254 }
255 
256 
257 enum FlagUpdateType {
258 	FUT_NEWFLAG = 0,
259 	FUT_REMOVEFLAG = 1,
260 	FUT_POS = 2,
261 	FUT_SPAWNPOS = 3,
262 	FUT_HOLDERWORM = 4,
263 	FUT_RESET = 5
264 };
265 
readUpdate(CBytestream * bs)266 void FlagInfo::readUpdate(CBytestream* bs) {
267 	int id = bs->readByte();
268 	int type = bs->readByte();
269 	if(type == FUT_NEWFLAG) {
270 		// spawnpos
271 		short x, y;
272 		bs->read2Int12( x, y );
273 		Flag* flag = initFlag(id);
274 		flag->spawnPoint.pos = CVec(x,y);
275 		return;
276 	}
277 	if(type == FUT_REMOVEFLAG) {
278 		if(!removeFlag(id))
279 			warnings << "FlagInfo::readUpdate: removing flag " << id << " not found" << endl;
280 		return;
281 	}
282 
283 	Flag* flag = getFlag(id);
284 	if(flag == NULL) {
285 		warnings << "FlagInfo::readUpdate: flag " << id << " not found" << endl;
286 		bs->revertByte(); bs->revertByte();
287 		FlagInfo::skipUpdate(bs);
288 		return;
289 	}
290 
291 	switch(type) {
292 		case FUT_POS: {
293 			short x, y;
294 			bs->read2Int12( x, y );
295 			flag->setCustomPos( CVec(x, y) );
296 			break;
297 		}
298 
299 		case FUT_SPAWNPOS: {
300 			short x, y;
301 			bs->read2Int12( x, y );
302 			flag->spawnPoint.pos = CVec(x, y);
303 			break;
304 		}
305 
306 		case FUT_HOLDERWORM: {
307 			int worm = bs->readByte();
308 			if(worm < 0 || worm >= MAX_WORMS) {
309 				warnings << "FlagInfo::readUpdate: holder worm id " << worm << " is invalid" << endl;
310 				return;
311 			}
312 			flag->setHolderWorm(worm);
313 			break;
314 		}
315 
316 		case FUT_RESET: {
317 			flag->setBack();
318 			break;
319 		}
320 
321 		default: {
322 			warnings << "FlagInfo::readUpdate: update type " << type << " is invalid" << endl;
323 			bs->SkipAll(); // probably screwed up anyway
324 		}
325 	}
326 }
327 
skipUpdate(CBytestream * bs)328 void FlagInfo::skipUpdate(CBytestream* bs) {
329 	/* int id = */ bs->readByte();
330 	int type = bs->readByte();
331 	switch(type) {
332 		case FUT_NEWFLAG: bs->Skip(3); break;
333 		case FUT_REMOVEFLAG: break;
334 		case FUT_POS: bs->Skip(3); break;
335 		case FUT_SPAWNPOS: bs->Skip(3); break;
336 		case FUT_HOLDERWORM: bs->Skip(1); break;
337 		case FUT_RESET: break;
338 		default: {
339 			warnings << "FlagInfo::skipUpdate: update type " << type << " is invalid" << endl;
340 			bs->SkipAll(); // probably screwed up anyway
341 		}
342 	}
343 }
344 
345 
346 
applyInitFlag(int id,const CVec & spawnPos)347 Flag* FlagInfo::applyInitFlag(int id, const CVec& spawnPos) {
348 	if(tLX->iGameType == GME_JOIN) {
349 		errors << "FlagInfo::applyInitFlag: this function is only supposed to be called by the server" << endl;
350 		return NULL;
351 	}
352 
353 	Flag* flag = initFlag(id);
354 	flag->spawnPoint.pos = spawnPos;
355 
356 	CBytestream bs;
357 	bs.writeByte(S2C_FLAGINFO);
358 	bs.writeByte(id);
359 	bs.writeByte(FUT_NEWFLAG);
360 	bs.write2Int12((int)spawnPos.x, (int)spawnPos.y);
361 	cServer->SendGlobalPacket(&bs, OLXBetaVersion(0,58,1));
362 	return flag;
363 }
364 
applyRemoveFlag(int id)365 void FlagInfo::applyRemoveFlag(int id) {
366 	if(tLX->iGameType == GME_JOIN) {
367 		errors << "FlagInfo::applyRemoveFlag: this function is only supposed to be called by the server" << endl;
368 		return;
369 	}
370 
371 	removeFlag(id);
372 
373 	CBytestream bs;
374 	bs.writeByte(S2C_FLAGINFO);
375 	bs.writeByte(id);
376 	bs.writeByte(FUT_REMOVEFLAG);
377 	cServer->SendGlobalPacket(&bs, OLXBetaVersion(0,58,1));
378 }
379 
applyCustomPos(Flag * flag,const CVec & pos)380 void FlagInfo::applyCustomPos(Flag* flag, const CVec& pos) {
381 	if(tLX->iGameType == GME_JOIN) {
382 		errors << "FlagInfo::applyCustomPos: this function is only supposed to be called by the server" << endl;
383 		return;
384 	}
385 
386 	flag->setCustomPos(pos);
387 
388 	CBytestream bs;
389 	bs.writeByte(S2C_FLAGINFO);
390 	bs.writeByte(flag->id);
391 	bs.writeByte(FUT_POS);
392 	bs.write2Int12((int)pos.x, (int)pos.y);
393 	cServer->SendGlobalPacket(&bs, OLXBetaVersion(0,58,1));
394 }
395 
applySpawnPos(Flag * flag,const CVec & spawnPos)396 void FlagInfo::applySpawnPos(Flag* flag, const CVec& spawnPos) {
397 	if(tLX->iGameType == GME_JOIN) {
398 		errors << "FlagInfo::applySpawnPos: this function is only supposed to be called by the server" << endl;
399 		return;
400 	}
401 
402 	flag->spawnPoint.pos = spawnPos;
403 
404 	CBytestream bs;
405 	bs.writeByte(S2C_FLAGINFO);
406 	bs.writeByte(flag->id);
407 	bs.writeByte(FUT_SPAWNPOS);
408 	bs.write2Int12((int)spawnPos.x, (int)spawnPos.y);
409 	cServer->SendGlobalPacket(&bs, OLXBetaVersion(0,58,1));
410 }
411 
applyHolderWorm(Flag * flag,int w)412 void FlagInfo::applyHolderWorm(Flag* flag, int w) {
413 	if(tLX->iGameType == GME_JOIN) {
414 		errors << "FlagInfo::applyHolderWorm: this function is only supposed to be called by the server" << endl;
415 		return;
416 	}
417 
418 	flag->setHolderWorm(w);
419 
420 	CBytestream bs;
421 	bs.writeByte(S2C_FLAGINFO);
422 	bs.writeByte(flag->id);
423 	bs.writeByte(FUT_HOLDERWORM);
424 	bs.writeByte(w);
425 	cServer->SendGlobalPacket(&bs, OLXBetaVersion(0,58,1));
426 }
427 
applySetBack(Flag * flag)428 void FlagInfo::applySetBack(Flag* flag) {
429 	if(tLX->iGameType == GME_JOIN) {
430 		errors << "FlagInfo::applySetBack: this function is only supposed to be called by the server" << endl;
431 		return;
432 	}
433 
434 	flag->setBack();
435 
436 	CBytestream bs;
437 	bs.writeByte(S2C_FLAGINFO);
438 	bs.writeByte(flag->id);
439 	bs.writeByte(FUT_RESET);
440 	cServer->SendGlobalPacket(&bs, OLXBetaVersion(0,58,1));
441 }
442 
sendCurrentState(CServerConnection * cl)443 void FlagInfo::sendCurrentState(CServerConnection* cl) {
444 	if(cl->getClientVersion() < OLXBetaVersion(0,58,1)) return;
445 
446 	for(Flags::iterator i = data->flags.begin(); i != data->flags.end(); ++i) {
447 		Flag& flag = i->second;
448 
449 		CBytestream bs;
450 		bs.writeByte(S2C_FLAGINFO);
451 		bs.writeByte(flag.id);
452 		bs.writeByte(FUT_NEWFLAG);
453 		bs.write2Int12((int)flag.spawnPoint.pos.x, (int)flag.spawnPoint.pos.y);
454 
455 		if(!flag.atSpawnPoint && flag.holderWorm < 0) {
456 			bs.writeByte(S2C_FLAGINFO);
457 			bs.writeByte(flag.id);
458 			bs.writeByte(FUT_POS);
459 			bs.write2Int12((int)flag.pos.x, (int)flag.pos.y);
460 		}
461 		else if(!flag.atSpawnPoint && flag.holderWorm >= 0) {
462 			bs.writeByte(S2C_FLAGINFO);
463 			bs.writeByte(flag.id);
464 			bs.writeByte(FUT_HOLDERWORM);
465 			bs.writeByte(flag.holderWorm);
466 		}
467 
468 		cl->getNetEngine()->SendPacket(&bs);
469 	}
470 }
471 
472