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