00001
00025 #include "states.h"
00026 #include "game.h"
00027 #include "color.h"
00028 #include "gameconfig.h"
00029 #include "obstacle.h"
00030 #include "playernet.h"
00031 #include "tanksprite.h"
00032 #include "name.h"
00033 #include "net.h"
00034 #include "notice.h"
00035 #include "menustate.h"
00036 #include <assert.h>
00037 #include <stdlib.h>
00038 #include <string.h>
00039 #ifdef USE_SDLIMAGE
00040 #include <SDL_image.h>
00041 #endif
00042 #ifdef USE_AUDIO
00043 #include "audio.h"
00044 #endif
00045
00051 Uint8 eventState[EC_MAX];
00052
00053 extern Uint32 frameTime;
00054
00055 RenderItem background;
00056
00057 static Sint16 scores[2];
00058
00062 #define BORDER_WIDTH 4
00063
00067 static RenderItem border[4];
00068
00077 static void RenderScore(Bool forceRender) {
00078
00079 int loop;
00080 for (loop = 0; loop < 2; loop++) {
00081
00082 if (forceRender ||
00083 (scores[loop] != gameOpts.teamScore[TEAM_RED + loop])) {
00084
00085 scores[loop] = gameOpts.teamScore[TEAM_RED + loop];
00086
00087 TextRenderString(&textItems[TEXTITEM_REDSCORE + loop], FONT_SCORE,
00088 0, colorFmtInd[COLOR_RED + loop],
00089 #ifdef USE_GETTEXT
00090 L"%d",
00091 #else
00092 "%d",
00093 #endif
00094 scores[loop]);
00095
00096 textItems[TEXTITEM_REDSCORE + loop].loc.y = 5;
00097 if (loop) {
00098 textItems[TEXTITEM_BLUESCORE].loc.x =
00099 dInfo.pw - textItems[TEXTITEM_BLUESCORE].loc.w - 5;
00100 }
00101 else {
00102 textItems[TEXTITEM_REDSCORE].loc.x = 5;
00103 }
00104 PlaceRenderItem(&textItems[TEXTITEM_REDSCORE + loop]);
00105 }
00106 }
00107 }
00108
00116 static void SetupScrolling() {
00117
00118 if ((dInfo.lw >= gameOpts.width) && (dInfo.lh >= gameOpts.height)) {
00119
00120 dInfo.scrollField = FALSE;
00121
00122 SetLayerOffset(&(layers[LAYER_OBSTACLES]), 0, 0);
00123 SetLayerOffset(&(layers[LAYER_NAMES]), 0, 0);
00124 SetLayerOffset(&(layers[LAYER_TANKS]), 0, 0);
00125 }
00126 else {
00127
00128 dInfo.scrollField = TRUE;
00129
00130 }
00131 }
00132
00140 static Bool GraphicReset() {
00141
00142 ForceRenderAll();
00143 #ifdef USE_SDLIMAGE
00144
00145 if ((back = IMG_Load("back.jpg")) == NULL) {
00146 #endif
00147
00148 background.loc.w = dInfo.pw;
00149 background.loc.h = dInfo.ph;
00150 background.renderer = SolidFillRenderer;
00151 background.data = &(colorVals[COLOR_REGBACK]);
00152 #ifdef USE_SDLIMAGE
00153 }
00154 else {
00155 SDL_Surface *back;
00156
00157
00158
00159 if ((background.data = SDL_ConvertSurface(back, dInfo.display->format,
00160 FASTEST_SURFACE)) == NULL) {
00161
00162 background.data = back;
00163 }
00164 else {
00165
00166 SDL_FreeSurface(back);
00167 }
00168
00169 background.loc.w = ((SDL_Surface*)(background.data))->w;
00170 background.loc.h = ((SDL_Surface*)(background.data))->h;
00171 background.renderer = GenericSurfaceRenderer;
00172 }
00173 #endif
00174
00175 SetupColorVals();
00176
00177 colorFmtInd[COLOR_TEXT] = colorFmtInd[COLOR_WHITE];
00178
00179 TextSetupStatePlay();
00180
00181 RenderScore(TRUE);
00182 SetupScrolling();
00183 return TRUE;
00184 }
00185
00186 int GameInit() {
00187 Player *p;
00188 int loop;
00189
00190 memset(eventState, 0, EC_MAX);
00191 memset(&background, 0, sizeof(background));
00192
00193 dInfo.luw = dInfo.luh = 3;
00194 dInfo.lw = dInfo.pw / dInfo.luw;
00195 dInfo.lh = dInfo.ph / dInfo.luh;
00196
00197 dInfo.showGame = TRUE;
00198
00199 textItems[TEXTITEM_REDSCORE].renderer =
00200 textItems[TEXTITEM_BLUESCORE].renderer = GenericSurfaceRenderer;
00201 AddRenderItem(&textItems[TEXTITEM_REDSCORE], LAYER_TEXT);
00202 AddRenderItem(&textItems[TEXTITEM_BLUESCORE], LAYER_TEXT);
00203
00204 if (!GraphicReset()) return STATE_ERROR;
00205
00206 if (networkState == NETSTATE_SERVER) {
00207
00208
00209 if (!InitGameConfig("field.bfld")) {
00210 TextUnsetState();
00211
00212 return STATE_BFLDERR;
00213 }
00214
00215 frameTime += SRV_FRAME_OFFSET;
00216
00217
00218
00219 localPlayer = 0;
00220 }
00221
00222 SetupScrolling();
00223
00224 if (dInfo.scrollField) {
00225
00226
00227 int x = -(gameOpts.width >> 1) * dInfo.luw + (dInfo.pw >> 1);
00228 int y = -(gameOpts.height >> 1) * dInfo.luh + (dInfo.ph >> 1);
00229
00230 SetLayerOffset(&(layers[LAYER_OBSTACLES]), x, y);
00231 SetLayerOffset(&(layers[LAYER_NAMES]), x, y);
00232 SetLayerOffset(&(layers[LAYER_TANKS]), x, y);
00233 }
00234
00235 ObstacleInit();
00236
00237 AddRenderItem(&background, LAYER_BACKGROUND);
00238 PlaceRenderItem(&background);
00239
00240
00241 players[localPlayer].pid = localPlayer;
00242 players[localPlayer].flags |= PLAYER_ACTIVE | PLAYER_UPDATE_IDENT |
00243 PLAYER_DEAD;
00244 players[localPlayer].team = menuSettings->team;
00245
00246 players[localPlayer].x = 1 << 8;
00247 players[localPlayer].y = (12 * localPlayer) << 8;
00248
00249 GetLocalPlayerName(players[localPlayer].name);
00250
00251 AddPlayer(&players[localPlayer]);
00252
00253
00254
00255 if (networkState != NETSTATE_SERVER) {
00256 MsgDescr *msg;
00257
00258 if ((msg = AppendPlayerData(NULL, &players[localPlayer], 1)) == NULL) {
00259
00260 return STATE_ERROR;
00261 }
00262
00263 if (!AddMessage(msg)) {
00264
00265 return STATE_ERROR;
00266 }
00267 }
00268
00269 frameTime = SDL_GetTicks();
00270
00271
00272
00273 for (p = players, loop = 0; loop < MAX_PLAYERS; loop++, p++) {
00274
00275 if (p->flags & PLAYER_ACTIVE) {
00276 p->localUpdate = frameTime;
00277 p->tank.loc.x = (p->x >> 8) * dInfo.luw;
00278 p->tank.loc.y = (p->y >> 8) * dInfo.luh;
00279 p->tank.loc.w = dInfo.luw * 8;
00280 p->tank.loc.h = dInfo.luh * 8;
00281
00282 p->shell.loc.w = dInfo.luw;
00283 p->shell.loc.h = dInfo.luh;
00284 p->shell.data = &(colorVals[p->team]);
00285
00286 if (!(p->flags & PLAYER_DEAD)) {
00287 assert(p->pid == loop);
00288
00289
00290 PlaceRenderItem(&(p->tank));
00291 PlacePlayerLabel(p);
00292 if (p->flags & PLAYER_SHOT) {
00293 PlaceRenderItem(&(p->shell));
00294 }
00295 }
00296 }
00297 }
00298
00299 free(menuSettings);
00300 menuSettings = NULL;
00301
00302
00303 border[0].renderer = border[1].renderer = border[2].renderer =
00304 border[3].renderer = SolidFillRenderer;
00305 border[0].data = border[1].data = border[2].data = border[3].data =
00306 &(colorVals[COLOR_BLACK]);
00307
00308 border[0].loc.x = -BORDER_WIDTH * dInfo.luw;
00309 border[0].loc.y = -BORDER_WIDTH * dInfo.luh;
00310 border[0].loc.w = (gameOpts.width + (BORDER_WIDTH << 1)) * dInfo.luw;
00311 border[0].loc.h = BORDER_WIDTH * dInfo.luh;
00312
00313 border[1].loc.x = -BORDER_WIDTH * dInfo.luw;
00314 border[1].loc.y = gameOpts.height * dInfo.luh;
00315 border[1].loc.w = (gameOpts.width + (BORDER_WIDTH << 1)) * dInfo.luw;
00316 border[1].loc.h = BORDER_WIDTH * dInfo.luh;
00317
00318 border[2].loc.x = -BORDER_WIDTH * dInfo.luw;
00319 border[2].loc.y = 0;
00320 border[2].loc.w = BORDER_WIDTH * dInfo.luw;
00321 border[2].loc.h = gameOpts.height * dInfo.luh;
00322
00323 border[3].loc.x = gameOpts.width * dInfo.luw;
00324 border[3].loc.y = 0;
00325 border[3].loc.w = BORDER_WIDTH * dInfo.luw;
00326 border[3].loc.h = gameOpts.height * dInfo.luh;
00327
00328 AddRenderItem(&border[0], LAYER_OBSTACLES);
00329 AddRenderItem(&border[1], LAYER_OBSTACLES);
00330 AddRenderItem(&border[2], LAYER_OBSTACLES);
00331 AddRenderItem(&border[3], LAYER_OBSTACLES);
00332 PlaceRenderItem(&border[0]);
00333 PlaceRenderItem(&border[1]);
00334 PlaceRenderItem(&border[2]);
00335 PlaceRenderItem(&border[3]);
00336
00337
00338 return STATE_OK;
00339 }
00340
00341 int GameUninit() {
00342 int loop;
00343 Player *p;
00344 #ifdef USE_AUDIO
00345
00346 StopAllSounds();
00347 #endif
00348
00349 for (p = players, loop = MAX_PLAYERS; loop > 0; loop--, p++) {
00350 RemovePlayer(p);
00351 }
00352 UninitGameConfig();
00353
00354 SetupScrolling();
00355 TextUnsetState();
00356
00357 if (background.renderer == GenericSurfaceRenderer) {
00358
00359 SDL_FreeSurface(background.data);
00360 }
00361 RemoveRenderItem(&background);
00362
00363 RemoveRenderItem(&border[0]);
00364 RemoveRenderItem(&border[1]);
00365 RemoveRenderItem(&border[2]);
00366 RemoveRenderItem(&border[3]);
00367
00368 RemoveAllNotices();
00369
00370 ForceRenderAll();
00371
00373
00374 dInfo.showGame = FALSE;
00375
00376
00377 loop = SDL_GetTicks();
00378 frameTime = loop - (loop % FRAME_DURATION) + FRAME_DURATION;
00379 return STATE_OK;
00380 }
00381
00382 int GameRun() {
00383 static Bool enableLables = FALSE;
00384 static int animTest = 0;
00385 SDL_Event event;
00386
00387
00388 if ((networkState != NETSTATE_CLIENT)
00389 && (networkState != NETSTATE_SERVER)) {
00390
00391 return STATE_MENUROOT;
00392 }
00393
00394 while (SDL_PollEvent(&event)) {
00395
00396 switch (event.type) {
00397 case SDL_QUIT:
00398 return STATE_QUIT;
00399 break;
00400 case SDL_ACTIVEEVENT:
00401
00402
00403
00404
00405
00406
00407
00408 break;
00409 case SDL_KEYDOWN:
00410
00411 switch (event.key.keysym.sym) {
00412 case SDLK_ESCAPE:
00413 return STATE_QUIT;
00414 break;
00415 case SDLK_UP:
00416 case SDLK_w:
00417 eventState[EC_FORWARD] |= 1;
00418 break;
00419 case SDLK_DOWN:
00420 case SDLK_s:
00421 eventState[EC_BACKWARD] |= 1;
00422 break;
00423 case SDLK_LEFT:
00424 case SDLK_a:
00425 eventState[EC_ROTLEFT] |= 1;
00426 break;
00427 case SDLK_RIGHT:
00428 case SDLK_d:
00429 eventState[EC_ROTRIGHT] |= 1;
00430 break;
00431 case SDLK_RETURN:
00432 case SDLK_SPACE:
00433 eventState[EC_FIRE] |= 1;
00434 break;
00435
00436
00437 case SDLK_n:
00438 if (dInfo.showLabels) {
00439 DisablePlayerLabels();
00440 }
00441 else {
00442 enableLables = TRUE;
00443 dInfo.showLabels = TRUE;
00444 }
00445 break;
00446 case SDLK_KP_PLUS:
00447 animTest++;
00448 break;
00449 case SDLK_KP_MINUS:
00450 animTest--;
00451 break;
00452 case SDLK_f:
00453 #ifndef WIN32
00454 if (!eventState[EC_FS_TOGGLE]) {
00455 SDL_WM_ToggleFullScreen(dInfo.display);
00456 ForceRenderAll();
00457 RenderScore(TRUE);
00458 SetupScrolling();
00459 }
00460 #else
00461
00462
00463
00464 #endif
00465 default:
00466 break;
00467 }
00468 break;
00469 case SDL_KEYUP:
00470 switch (event.key.keysym.sym) {
00471 case SDLK_UP:
00472 case SDLK_w:
00473 eventState[EC_FORWARD] = 0;
00474 break;
00475 case SDLK_DOWN:
00476 case SDLK_s:
00477 eventState[EC_BACKWARD] = 0;
00478 break;
00479 case SDLK_LEFT:
00480 case SDLK_a:
00481 eventState[EC_ROTLEFT] = 0;
00482 break;
00483 case SDLK_RIGHT:
00484 case SDLK_d:
00485 eventState[EC_ROTRIGHT] = 0;
00486 break;
00487 case SDLK_RETURN:
00488 case SDLK_SPACE:
00489 eventState[EC_FIRE] = 0;
00490 break;
00491 case SDLK_c:
00492 ClearRenderItem(&(players[0].tank));
00493 break;
00494 case SDLK_v:
00495 PlaceRenderItem(&(players[0].tank));
00496 break;
00497 case SDLK_r:
00498 ForceRenderAll();
00499 default:
00500 break;
00501 }
00502 break;
00503 case SDL_JOYAXISMOTION:
00504 if (!(SDL_GetAppState() & SDL_APPINPUTFOCUS)) break;
00505
00506 if (event.jaxis.axis == 0) {
00507
00508 if (event.jaxis.value > 16384) {
00509 eventState[EC_ROTRIGHT] |= 1;
00510 eventState[EC_ROTLEFT] = 0;
00511 }
00512
00513 else if (event.jaxis.value < -16384) {
00514 eventState[EC_ROTLEFT] |= 1;
00515 eventState[EC_ROTRIGHT] = 0;
00516 }
00517
00518 else {
00519 eventState[EC_ROTLEFT] = 0;
00520 eventState[EC_ROTRIGHT] = 0;
00521 }
00522 }
00523
00524 else if (event.jaxis.axis == 1) {
00525
00526 if (event.jaxis.value > 16384) {
00527 eventState[EC_BACKWARD] |= 1;
00528 eventState[EC_FORWARD] = 0;
00529 }
00530
00531 else if (event.jaxis.value < -16384) {
00532 eventState[EC_FORWARD] |= 1;
00533 eventState[EC_BACKWARD] = 0;
00534 }
00535
00536 else {
00537 eventState[EC_FORWARD] = 0;
00538 eventState[EC_BACKWARD] = 0;
00539 }
00540 }
00541 break;
00542 case SDL_JOYBUTTONDOWN:
00543 if (!(SDL_GetAppState() & SDL_APPINPUTFOCUS)) break;
00544 eventState[EC_FIRE] |= 1;
00545 break;
00546 case SDL_JOYBUTTONUP:
00547 if (!(SDL_GetAppState() & SDL_APPINPUTFOCUS)) break;
00548 eventState[EC_FIRE] = 0;
00549 break;
00550 case SDL_VIDEORESIZE:
00551 ResizeWindow(event.resize.w, event.resize.h);
00552
00553 if (background.renderer == SolidFillRenderer) {
00554
00555 background.loc.w = dInfo.pw;
00556 background.loc.h = dInfo.ph;
00557 }
00558 RenderScore(TRUE);
00559 SetupScrolling();
00560
00561 default:
00562 break;
00563 }
00564 }
00565
00566 HandleInput(eventState);
00567
00568 ProcessNetworkMessages();
00569
00570 if ((networkState == NETSTATE_CLIENT) &&
00571 (players[localPlayer].flags & PLAYER_CLIENT_MASK)) {
00573 MsgDescr *msg;
00574
00575 if ((msg = AppendPlayerData(NULL, &players[localPlayer], frameTime))
00576 == NULL) {
00577
00578 return STATE_ERROR;
00579 }
00580
00581 if (!AddMessage(msg)) {
00582
00583 return STATE_ERROR;
00584 }
00585
00586 players[localPlayer].flags &= ~PLAYER_UPDATE_ITEMS;
00587 }
00588 else if (networkState == NETSTATE_SERVER) {
00589 MsgDescr *msg = NULL;
00590 Player *p;
00591 int loop;
00592
00593 for (p = players, loop = 0; loop < MAX_PLAYERS; loop++, p++) {
00594
00595 if (!(p->flags & PLAYER_ACTIVE) ||
00596 !(p->flags & PLAYER_UPDATE_ITEMS)) continue;
00597
00598 if ((msg = AppendPlayerData(msg, p, frameTime)) == NULL) {
00599
00600 return STATE_ERROR;
00601 }
00602
00603 p->flags &= ~PLAYER_UPDATE_ITEMS;
00604 }
00605
00606 if (msg) {
00607 AddMessage(msg);
00608 }
00609 }
00610
00611 if (gameOpts.flags & OPT_UPDATESCORE) {
00612
00613 gameOpts.flags &= ~OPT_UPDATESCORE;
00614
00615 RenderScore(FALSE);
00616 }
00617
00618 if (dInfo.scrollField && !(players[localPlayer].flags & PLAYER_DEAD)) {
00619
00620 int x = -(players[localPlayer].x >> 8) * dInfo.luw + (dInfo.pw >> 1);
00621 int y = -(players[localPlayer].y >> 8) * dInfo.luh + (dInfo.ph >> 1);
00622
00623 if ((x != layers[LAYER_OBSTACLES].offX) ||
00624 (y != layers[LAYER_OBSTACLES].offY)) {
00625
00626 SetLayerOffset(&(layers[LAYER_OBSTACLES]), x, y);
00627 SetLayerOffset(&(layers[LAYER_NAMES]), x, y);
00628 SetLayerOffset(&(layers[LAYER_TANKS]), x, y);
00629 }
00630 }
00631
00632 if ((players[localPlayer].flags & PLAYER_DEAD) &&
00633 (players[localPlayer].deadTime > DEAD_TIME)) {
00634 if (!textItems[TEXTITEM_RESPAWN].enableDraw) {
00635
00636 textItems[TEXTITEM_RESPAWN].loc.x =
00637 (dInfo.pw - textItems[TEXTITEM_RESPAWN].loc.w) >> 1;
00638 textItems[TEXTITEM_RESPAWN].loc.y =
00639 (dInfo.ph - textItems[TEXTITEM_RESPAWN].loc.h) >> 1;
00640
00641 PlaceRenderItem(&textItems[TEXTITEM_RESPAWN]);
00642 }
00643 }
00644 else if (textItems[TEXTITEM_RESPAWN].enableDraw) {
00645 ClearRenderItem(&textItems[TEXTITEM_RESPAWN]);
00646 }
00647
00648 if (enableLables) {
00649 enableLables = FALSE;
00650 EnablePlayerLabels();
00651 }
00652
00653
00654 UpdateNotices(frameTime);
00655
00656
00657 return STATE_PLAY;
00658 }
00659