00001
00025 #define QueuePlaceTank __func_QueuePlaceTank
00026 #define QueuePlaceShell __func_QueuePlaceShell
00027 #define QueuePlaceName __func_QueuePlaceName
00028
00029 #include "game.h"
00030 #include "gameconfig.h"
00031 #include "color.h"
00032 #include "net.h"
00033 #include "obstacle.h"
00034 #include "tanksprite.h"
00035 #include "playernet.h"
00036 #include "random.h"
00037 #include "notice.h"
00038 #include <assert.h>
00039 #include <stddef.h>
00040 #include <stdlib.h>
00041 #include <string.h>
00042 #ifdef USE_AUDIO
00043 #include "audio.h"
00044 #endif
00045
00046 #undef QueuePlaceTank
00047 #undef QueuePlaceShell
00048 #undef QueuePlaceName
00049
00050 #ifdef _MSC_VER
00051
00052
00053
00054
00055
00056 #ifndef fabsf
00057 #define fabsf(x) (float)fabs(x)
00058 #endif
00059 #ifndef sqrtf
00060 #define sqrtf(x) (float)sqrt(x)
00061 #endif
00062 #endif
00063
00070 static const Sint32 motionTable[16][2] = {
00071
00072 { 0, -rounddiv(MOTION_0_1, MOTION_DIV) },
00073
00074 { rounddiv(MOTION_22_0, MOTION_DIV), -rounddiv(MOTION_22_1, MOTION_DIV) },
00075
00076 { rounddiv(MOTION_45_0, MOTION_DIV), -rounddiv(MOTION_45_1, MOTION_DIV) },
00077
00078 { rounddiv(MOTION_22_1, MOTION_DIV), -rounddiv(MOTION_22_0, MOTION_DIV) },
00079
00080 { rounddiv(MOTION_0_1, MOTION_DIV), 0 },
00081
00082 { rounddiv(MOTION_22_1, MOTION_DIV), rounddiv(MOTION_22_0, MOTION_DIV) },
00083
00084 { rounddiv(MOTION_45_0, MOTION_DIV), rounddiv(MOTION_45_1, MOTION_DIV) },
00085
00086 { rounddiv(MOTION_22_0, MOTION_DIV), rounddiv(MOTION_22_1, MOTION_DIV) },
00087
00088 { 0, rounddiv(MOTION_0_1, MOTION_DIV) },
00089
00090 { -rounddiv(MOTION_22_0, MOTION_DIV), rounddiv(MOTION_22_1, MOTION_DIV) },
00091
00092 { -rounddiv(MOTION_45_0, MOTION_DIV), rounddiv(MOTION_45_1, MOTION_DIV) },
00093
00094 { -rounddiv(MOTION_22_1, MOTION_DIV), rounddiv(MOTION_22_0, MOTION_DIV) },
00095
00096 { -rounddiv(MOTION_0_1, MOTION_DIV), 0 },
00097
00098 { -rounddiv(MOTION_22_1, MOTION_DIV), -rounddiv(MOTION_22_0, MOTION_DIV) },
00099
00100 { -rounddiv(MOTION_45_0, MOTION_DIV), -rounddiv(MOTION_45_1, MOTION_DIV) },
00101
00102 { -rounddiv(MOTION_22_0, MOTION_DIV), -rounddiv(MOTION_22_1, MOTION_DIV) }
00103 };
00104
00105 #ifdef DOXYGEN
00106
00112 static const float normalTable[16][2] = {
00113
00114 { 0, -FMOTION_0_1 },
00115
00116 { FMOTION_22_0, -FMOTION_22_1 },
00117
00118 { FMOTION_45_0, -FMOTION_45_1 },
00119
00120 { FMOTION_22_1, -FMOTION_22_0 },
00121
00122 { FMOTION_0_1, 0 },
00123
00124 { FMOTION_22_1, FMOTION_22_0 },
00125
00126 { FMOTION_45_0, FMOTION_45_1 },
00127
00128 { FMOTION_22_0, FMOTION_22_1 },
00129
00130 { 0, FMOTION_0_1 },
00131
00132 { -FMOTION_22_0, FMOTION_22_1 },
00133
00134 { -FMOTION_45_0, FMOTION_45_1 },
00135
00136 { -FMOTION_22_1, FMOTION_22_0 },
00137
00138 { -FMOTION_0_1, 0 },
00139
00140 { -FMOTION_22_1, -FMOTION_22_0 },
00141
00142 { -FMOTION_45_0, -FMOTION_45_1 },
00143
00144 { -FMOTION_22_0, -FMOTION_22_1 }
00145 };
00146 #endif
00147
00148 #if defined(USE_AUDIO) || defined(DOXYGEN)
00149
00154 static unsigned int oldClosest = 0xFFFFFFFF;
00155 #endif
00156
00157 void PlacePlayerLabel(Player *p) {
00158 if (p->labelName.renderer == NULL) return;
00159
00160 if (RenderWillRenderAll()) {
00161
00162
00163 p->tank.physDest.x = p->tank.loc.x + p->tank.parent->offX;
00164 p->tank.physDest.y = p->tank.loc.y + p->tank.parent->offY;
00165 p->tank.physDest.w = p->tank.loc.w;
00166 p->tank.physDest.h = p->tank.loc.h;
00167
00168 ClipRectToWH(&(p->tank.physDest), dInfo.pw, dInfo.ph);
00169 }
00170
00171 if ((p->tank.physDest.h >= (dInfo.luh << 2)) &&
00172 (p->tank.physDest.w >= (dInfo.luw << 2))) {
00173
00174 p->labelName.loc.x = p->tank.loc.x + (dInfo.luw << 2) -
00175 (p->labelName.loc.w >> 1);
00176
00177 if (((dInfo.luw << 3) + p->tank.physLocY +
00178 p->labelName.loc.h) < dInfo.ph) {
00179
00180 p->labelName.loc.y = (dInfo.luw << 3) + p->tank.loc.y;
00181 }
00182 else {
00183
00184 p->labelName.loc.y = p->tank.loc.y - p->labelName.loc.h;
00185 }
00186
00187 if (dInfo.showLabels)
00188 PlaceRenderItem(&(p->labelName));
00189 }
00190
00191 else if (p->labelName.enableDraw && dInfo.showLabels) {
00192
00193 ClearRenderItem(&(p->labelName));
00194 }
00195 }
00196
00197 void EnablePlayerLabels() {
00198 Player *p;
00199 int loop;
00200
00201
00202 for (p = players, loop = MAX_PLAYERS; loop > 0; loop--, p++) {
00203 if (((p->flags & (PLAYER_ACTIVE | PLAYER_DEAD)) == PLAYER_ACTIVE) &&
00204 !p->labelName.enableDraw && p->labelName.renderer) {
00205 PlaceRenderItem(&(p->labelName));
00206 }
00207 }
00208
00209 dInfo.showLabels = TRUE;
00210 }
00211
00212 void DisablePlayerLabels() {
00213 Player *p;
00214 int loop;
00215
00216
00217 for (p = players, loop = MAX_PLAYERS; loop > 0; loop--, p++) {
00218 if ((p->flags & PLAYER_ACTIVE) && p->labelName.enableDraw) {
00219 ClearRenderItem(&(p->labelName));
00220 }
00221 }
00222
00223 dInfo.showLabels = FALSE;
00224 }
00225
00233 static Uint32 batchTankDraw[rounddivup(MAX_PLAYERS, 32)] = { 0 };
00234
00242 static Uint32 batchShellDraw[rounddivup(MAX_PLAYERS, 32)] = { 0 };
00243
00251 static Uint32 batchNameDraw[rounddivup(MAX_PLAYERS, 32)] = { 0 };
00252
00264 #define BatchIndex(pid) ((pid) >> 5)
00265
00279 #define BatchBit(pid) (1 << ((pid) & 0x1F))
00280
00288 #define QueuePlaceTank(pid) \
00289 batchTankDraw[BatchIndex(pid)] |= BatchBit(pid)
00290
00298 #define QueuePlaceShell(pid) \
00299 batchShellDraw[BatchIndex(pid)] |= BatchBit(pid)
00300
00309 #define QueuePlaceName(pid) \
00310 batchNameDraw[BatchIndex(pid)] |= BatchBit(pid)
00311
00320 typedef void (*PlacementFunc)(void *data);
00321
00335 static void BatchRender(Uint32 *batch, PlacementFunc placement, long offset) {
00336 Player *p;
00337 int index, bit;
00338 Uint32 byte;
00339
00340 for (index = rounddivup(MAX_PLAYERS, 32), p = players; index > 0;
00341 batch++, index--) {
00342
00343 if (*batch) {
00344
00345 for (bit = 1, byte = 0xFF; byte; byte <<= 8) {
00346
00347 if (*batch & byte) {
00348
00349 for (; bit & byte; p++, bit <<= 1) {
00350
00351 if (*batch & bit) {
00352 (*placement)(((char*)p) + offset);
00353 }
00354 }
00355 }
00356 else {
00357
00358 p += 8;
00359 bit <<= 8;
00360 }
00361 }
00362 }
00363 else {
00364
00365 p += 32;
00366 }
00367
00368 *batch = 0;
00369 }
00370 }
00371
00372 void RenderGame() {
00373
00374 BatchRender(batchTankDraw, (PlacementFunc)PlaceRenderItem,
00375 offsetof(Player, tank));
00376
00377 BatchRender(batchShellDraw, (PlacementFunc)PlaceRenderItem,
00378 offsetof(Player, shell));
00379
00380 if (dInfo.showLabels) {
00381
00382 BatchRender(batchNameDraw, (PlacementFunc)PlacePlayerLabel, 0);
00383 }
00384 }
00385
00386 void MoveTank(Player *p, int factor) {
00387 int tempLoc;
00388
00389 if (factor > 0) {
00390
00391 p->x += motionTable[(p->rot >> 8) & 0xF][0] * factor;
00392 p->y += motionTable[(p->rot >> 8) & 0xF][1] * factor;
00393 }
00394
00395 else if (factor < 0) {
00396 p->x += (motionTable[(p->rot >> 8) & 0xF][0] * factor) >> 1;
00397 p->y += (motionTable[(p->rot >> 8) & 0xF][1] * factor) >> 1;
00398 }
00399
00400 if (gameOpts.width > 0) {
00401 if (p->x < 0)
00402 p->x = 0;
00403 else if (p->x > ((gameOpts.width - 8) << 8))
00404 p->x = (gameOpts.width - 8) << 8;
00405 if (p->y < 0)
00406 p->y = 0;
00407 else if (p->y > ((gameOpts.height - 8) << 8))
00408 p->y = (gameOpts.height - 8) << 8;
00409 }
00410
00411 if ((tempLoc = (p->y >> 8) * dInfo.luh) != p->tank.loc.y) {
00412
00413 p->tank.loc.y = tempLoc;
00414 p->tank.loc.x = (p->x >> 8) * dInfo.luw;
00415
00416 QueuePlaceTank(p->pid);
00417
00418 QueuePlaceName(p->pid);
00419 }
00420 else if ((tempLoc = (p->x >> 8) * dInfo.luw) != p->tank.loc.x) {
00421
00422 p->tank.loc.x = tempLoc;
00423 QueuePlaceTank(p->pid);
00424
00425 QueuePlaceName(p->pid);
00426 }
00427 }
00428
00429 void MoveShell(Player *p) {
00430
00431 if (p->shellDist++ == 0) {
00432
00433 p->shellX = p->x + (shellInitLoc[(p->rot >> 8) & 0xF][0] << 8);
00434 p->shellY = p->y + (shellInitLoc[(p->rot >> 8) & 0xF][1] << 8);
00435
00436 p->shellRot = p->rot;
00437 goto MoveShell_placeShell;
00438 }
00439
00440 else if (p->flags & PLAYER_PONG) {
00441 if (p->shellDist > SHELL_PONG_DIST) {
00442 MoveShell_killShell:
00443
00444 batchShellDraw[BatchIndex(p->pid)] &= ~BatchBit(p->pid);
00445 ClearRenderItem(&(p->shell));
00446
00447 p->flags &= ~PLAYER_SHOT;
00448
00449 return;
00450 }
00451
00452 }
00453 else if (p->shellDist > SHELL_GUIDED_DIST) {
00454 goto MoveShell_killShell;
00455 }
00456
00457 p->shellX += motionTable[(p->shellRot >> 8) & 0xF][0] * MOTION_SHELL_FACTOR;
00458 p->shellY += motionTable[(p->shellRot >> 8) & 0xF][1] * MOTION_SHELL_FACTOR;
00459
00460 if ((p->shellX < 0) || (p->shellY < 0) ||
00461 ((p->shellX >> 8) > gameOpts.width) || ((p->shellY >> 8) > gameOpts.height))
00462 goto MoveShell_killShell;
00463
00464 if ((p->shell.loc.x != (p->shellX >> 8)) ||
00465 (p->shell.loc.y != (p->shellY >> 8))) {
00466 MoveShell_placeShell:
00467
00468 p->shell.loc.x = (p->shellX >> 8) * dInfo.luh;
00469 p->shell.loc.y = (p->shellY >> 8) * dInfo.luh;
00470
00471 QueuePlaceShell(p->pid);
00472 }
00473 }
00474
00484 static void RotateTank(Player *p, Sint16 rot) {
00485 Sint16 oldRot;
00486
00487 oldRot = p->rot;
00488
00489 p->rot += rot;
00490
00491 if (!p->tank.placed && ((oldRot & 0xF00) != (p->rot & 0xF00))) {
00492
00493 QueuePlaceTank(p->pid);
00494
00495 }
00496
00497 if ((p->flags & PLAYER_SHOT) && !(p->flags & PLAYER_PONG)) {
00498
00499 p->shellRot = p->rot;
00500 }
00501 }
00502
00503 void SpawnTank(Player *p) {
00504 Player *c;
00505 SDL_Rect *rect;
00506 int attempts = 8, maxArea = gameOpts.spawnAreas[p->team], loop;
00507 Uint32 rndnum;
00508 Bool bad;
00509
00510 assert(networkState == NETSTATE_SERVER);
00511
00512 do {
00513
00514 rndnum = RandNum();
00515 p->rot = rndnum >> 16;
00516 rect = &(spawnAreas[p->team][rndnum % maxArea]);
00517
00518 rndnum = RandNum();
00519 p->x = (p->tank.loc.x = (rect->x + (rndnum & 0xFFFF) % rect->w)) << 8;
00520 p->y = (p->tank.loc.y = (rect->y + (rndnum >> 16) % rect->h)) << 8;
00521 p->tank.loc.x *= dInfo.luw;
00522 p->tank.loc.y *= dInfo.luh;
00523
00524 bad = FALSE;
00525
00526 if (--attempts == 0) {
00527
00528 break;
00529 }
00530
00531 for (c = players, loop = MAX_PLAYERS; loop > 0; loop--, c++) {
00532
00533 if ((c == p) || !(c->flags & PLAYER_ACTIVE) ||
00534 (c->flags & PLAYER_DEAD)) {
00535
00536 continue;
00537 }
00538
00539 if (IsCollidingTank(p, c)) {
00540
00541 bad = TRUE;
00542 break;
00543 }
00544 }
00545 } while (bad);
00546
00547 QueuePlaceTank(p->pid);
00548 QueuePlaceName(p->pid);
00549
00550 p->flags = (p->flags & ~PLAYER_DEAD) | PLAYER_UPDATE_TANK |
00551 PLAYER_UPDATE_DFS;
00552 p->deadTime = 0;
00553 }
00554
00555 void HandleInput(Uint8 *eventState) {
00556
00557 Player *p = &(players[localPlayer]);
00558
00559 if (!(p->flags & PLAYER_DEAD)) {
00560
00561 if (eventState[EC_FORWARD] == 1) {
00562
00563 eventState[EC_FORWARD]++;
00564
00565
00566 p->flags |= PLAYER_FORWARD | PLAYER_UPDATE_TANK;
00567 #ifdef USE_AUDIO
00568
00569 oldClosest = 0;
00570
00571 #endif
00572 }
00573
00574 else if ((eventState[EC_FORWARD] == 0) && (p->flags & PLAYER_FORWARD)) {
00575
00576
00577 p->flags = (p->flags & ~PLAYER_FORWARD) | PLAYER_UPDATE_TANK;
00578 #ifdef USE_AUDIO
00579 if (!(p->flags & PLAYER_BACKWARD)) {
00580
00581 oldClosest = 0;
00582
00583 }
00584 #endif
00585 }
00586
00587 if (eventState[EC_BACKWARD] == 1) {
00588
00589 eventState[EC_BACKWARD]++;
00590
00591
00592 p->flags |= PLAYER_BACKWARD | PLAYER_UPDATE_TANK;
00593 #ifdef USE_AUDIO
00594
00595 oldClosest = 0;
00596
00597 #endif
00598 }
00599 else if ((eventState[EC_BACKWARD] == 0) && (p->flags & PLAYER_BACKWARD)) {
00600
00601
00602 p->flags = (p->flags & ~PLAYER_BACKWARD) | PLAYER_UPDATE_TANK;
00603 #ifdef USE_AUDIO
00604 if (!(p->flags & PLAYER_FORWARD)) {
00605
00606 oldClosest = 0;
00607
00608 }
00609 #endif
00610 }
00611 if (eventState[EC_ROTRIGHT] == 1) {
00612 eventState[EC_ROTRIGHT]++;
00613 p->flags |= PLAYER_STARTROTRIGHT | PLAYER_UPDATE_TANK;
00614 }
00615 else if ((eventState[EC_ROTRIGHT] == 0) && p->flags & PLAYER_ROTRIGHT) {
00616 p->flags = (p->flags & ~PLAYER_ROTRIGHT) | PLAYER_UPDATE_TANK;
00617 }
00618 if (eventState[EC_ROTLEFT] == 1) {
00619 eventState[EC_ROTLEFT]++;
00620 p->flags |= PLAYER_STARTROTLEFT | PLAYER_UPDATE_TANK;
00621 }
00622 else if ((eventState[EC_ROTLEFT] == 0) && p->flags & PLAYER_ROTLEFT) {
00623 p->flags = (p->flags & ~PLAYER_ROTLEFT) | PLAYER_UPDATE_TANK;
00624 }
00625 }
00626
00627
00628
00629
00630 if (eventState[EC_FIRE] == 1) {
00631
00632 if ((p->flags & PLAYER_DEAD) && (p->deadTime > DEAD_TIME)) {
00633
00634 eventState[EC_FIRE]++;
00635
00636 if (networkState == NETSTATE_SERVER) {
00637
00638 SpawnTank(p);
00639 }
00640
00641 else {
00642
00643 SendSpawnRequest();
00644 }
00645 #ifdef USE_AUDIO
00646
00647 PlaySound(SND_IDLE, SND_CH_TANK, -1);
00648 #endif
00649 }
00650
00651 else if ((p->flags & (PLAYER_SHOT | PLAYER_DEAD)) == 0) {
00652
00653
00654 p->flags |= PLAYER_SHOT | PLAYER_UPDATE_SHELL;
00655
00656 p->shellDist = 0;
00657
00658
00659 #ifdef USE_AUDIO
00660
00661 PlaySound(SND_SHOOT, SND_CH_LOCALSHOOT, 0);
00662 #endif
00663 }
00664 }
00665 }
00666
00673 static void FixTankCollision(Player *p) {
00674
00675 if (p->flags & (PLAYER_FORWARD | PLAYER_BACKWARD | PLAYER_ROTRIGHT |
00676 PLAYER_ROTLEFT)) {
00677
00678 if (p->flags & PLAYER_FORWARD) {
00679 MoveTank(p, -10);
00680 }
00681 else if (p->flags & PLAYER_BACKWARD) {
00682 MoveTank(p, 8);
00683 }
00684
00685 else if (p->flags & PLAYER_ROTRIGHT) {
00686 RotateTank(p, -64);
00687 }
00688 else if (p->flags & PLAYER_ROTLEFT) {
00689 RotateTank(p, 64);
00690 }
00691
00692 if (networkState == NETSTATE_SERVER) {
00693
00694 p->flags |= PLAYER_UPDATE_TANK;
00695 }
00696 }
00697 }
00698
00699 void UpdatePlayers(Uint32 time) {
00700
00701
00702 ScoreUpdate scores[MAX_PLAYERS / 2];
00703 int numScores = 0, loop, inner;
00704
00705 int outdated;
00706 #ifdef USE_AUDIO
00707 unsigned int dist, closest = 0xFFFFFFFF;
00708 Player *local = &(players[localPlayer]);
00709 #endif
00710 Player *p, *c;
00711 Obstacle *obst;
00712
00713
00714 do {
00715
00720
00721 outdated = 0;
00722
00723 for (p = players, loop = MAX_PLAYERS; loop > 0; loop--, p++) {
00724
00725 if (!(p->flags & PLAYER_ACTIVE) || (p->localUpdate >= time))
00726
00727 continue;
00728
00729 p->localUpdate += FRAME_DURATION;
00730
00731 if (p->flags & PLAYER_DEAD) {
00732
00733
00734 if (p->deadTime == DEAD_TIME) {
00735
00736 batchTankDraw[BatchIndex(p->pid)] &= ~BatchBit(p->pid);
00737 ClearRenderItem(&(p->tank));
00738 ClearRenderItem(&(p->labelName));
00739 p->deadTime++;
00740 }
00741 else if (p->deadTime < DEAD_TIME) {
00742
00743 RotateTank(p, 256);
00744 p->deadTime++;
00745 }
00746 }
00747
00748 else {
00749
00750 if (p->flags & PLAYER_FORWARD) {
00751 MoveTank(p, 1);
00752 }
00753
00754 if (p->flags & PLAYER_BACKWARD) {
00755 MoveTank(p, -1);
00756 }
00757
00758 if (p->flags & PLAYER_STARTROTRIGHT) {
00759
00760 p->flags = (p->flags & ~PLAYER_STARTROTRIGHT) |
00761 PLAYER_ROTRIGHT;
00762 RotateTank(p, 64);
00763 }
00764
00765 else if (p->flags & PLAYER_ROTRIGHT) {
00766 RotateTank(p, 16);
00767 }
00768
00769 if (p->flags & PLAYER_STARTROTLEFT) {
00770
00771 p->flags = (p->flags & ~PLAYER_STARTROTLEFT) |
00772 PLAYER_ROTLEFT;
00773 RotateTank(p, -64);
00774 }
00775
00776 else if (p->flags & PLAYER_ROTLEFT) {
00777 RotateTank(p, -16);
00778 }
00779 }
00780
00781 if (p->flags & PLAYER_SHOT) {
00782
00783 MoveShell(p);
00784 }
00785 }
00786
00787 for (p = players, loop = MAX_PLAYERS; loop > 0; loop--, p++) {
00788
00789 if (!(p->flags & PLAYER_ACTIVE) || ((p->flags & PLAYER_DEAD) &&
00790 (p->deadTime > DEAD_TIME))) {
00791 continue;
00792 }
00793
00794 if (networkState == NETSTATE_SERVER) {
00795 c = players;
00796 inner = MAX_PLAYERS;
00797 }
00798 else {
00799 c = p + 1;
00800 inner = loop - 1;
00801 }
00802 for ( ; inner > 0; inner--, c++) {
00803
00804 if ((c == p) || !(c->flags & PLAYER_ACTIVE) ||
00805 ((c->flags & PLAYER_DEAD) && (c->deadTime > DEAD_TIME))) {
00806
00807 continue;
00808 }
00809
00810 if (networkState == NETSTATE_SERVER) {
00811
00812
00813 if ((c->flags & PLAYER_SHOT) && IsCollidingShell(p, c)) {
00814
00815
00816 c->flags &= ~PLAYER_SHOT;
00817 ClearRenderItem(&(c->shell));
00818 batchShellDraw[BatchIndex(c->pid)] &= ~BatchBit(c->pid);
00819
00820 c->flags |= PLAYER_UPDATE_DFS;
00821
00822 if (!(p->flags & PLAYER_DEAD)) {
00823
00824 p->deadTime = 0;
00825
00826 p->flags |= PLAYER_DEAD | PLAYER_UPDATE_DFS;
00827
00828 p->flags &= ~(PLAYER_FORWARD | PLAYER_BACKWARD |
00829 PLAYER_ROTRIGHT | PLAYER_ROTLEFT | PLAYER_SHOT);
00830
00831 ClearRenderItem(&(p->shell));
00832 batchShellDraw[BatchIndex(p->pid)] &=
00833 ~BatchBit(p->pid);
00834
00835 if (c->team == p->team) {
00836
00837 if (p->kills >= 0) {
00838
00839 c->kills -= 4;
00840 }
00841
00842 }
00843 else {
00844
00845 if ((++c->kills > 0) &&
00846 !(gameOpts.flags & OPT_ISCTF)) {
00847
00848 gameOpts.teamScore[c->team]++;
00849
00850 gameOpts.flags |= OPT_UPDATESCORE;
00851 }
00852 }
00853
00854 AddScoreNotice(scores[numScores].killerId = c->pid,
00855 scores[numScores].killedId = p->pid, c->kills);
00856 numScores++;
00857 #ifdef USE_AUDIO
00858
00859 if (p == local) {
00860
00861 PlayLocalDeath();
00862 }
00863 else {
00864
00865 int distsq = DistSq(p, local);
00866
00867 if (distsq < (MAX_SQ_DIST >> 1)) {
00868
00869 PlayTankKilled(distsq);
00870 }
00871 }
00872 #endif
00873 }
00874 }
00875
00876 if (inner > loop) continue;
00877 }
00878
00879 if (IsCollidingTank(p, c)) {
00880
00881 FixTankCollision(p);
00882 FixTankCollision(c);
00883 }
00884 }
00885
00886 for (inner = gameOpts.obstacles, obst = obstacles; inner > 0;
00887 obst++, inner--) {
00888
00889 if ((p->flags & (PLAYER_FORWARD | PLAYER_BACKWARD |
00890 PLAYER_ROTRIGHT | PLAYER_ROTLEFT)) &&
00891 IsCollidingObstacle(p, obst)) {
00892
00893 if (networkState == NETSTATE_SERVER) {
00894
00895 p->flags |= PLAYER_UPDATE_TANK;
00896 }
00897
00898 if (p->flags & PLAYER_FORWARD) {
00899 MoveTank(p, -10);
00900 goto UpdatePlayers_contObst;
00901 }
00902 else if (p->flags & PLAYER_BACKWARD) {
00903 MoveTank(p, 8);
00904 goto UpdatePlayers_contObst;
00905 }
00906
00907 if (p->flags & PLAYER_ROTRIGHT) {
00908 RotateTank(p, -64);
00909 }
00910 else if (p->flags & PLAYER_ROTLEFT) {
00911 RotateTank(p, 64);
00912 }
00913 }
00914 UpdatePlayers_contObst:
00915
00916 if ((p->flags & PLAYER_SHOT) &&
00917 ((p->shellX >> 8) >= obst->loc.x) &&
00918 ((p->shellX >> 8) < (obst->loc.x + obst->loc.w)) &&
00919 ((p->shellY >> 8) >= obst->loc.y) &&
00920 ((p->shellY >> 8) < (obst->loc.y + obst->loc.h))) {
00921
00922 p->flags &= ~PLAYER_SHOT;
00923 ClearRenderItem(&(p->shell));
00924 batchShellDraw[BatchIndex(p->pid)] &= ~BatchBit(p->pid);
00925 }
00926 }
00927 #ifdef USE_AUDIO
00928
00929
00930 if ((p != local) &&
00931 !(local->flags & (PLAYER_DEAD | PLAYER_MOVEMENT_SOUND)) &&
00932 (p->flags & PLAYER_MOVEMENT_SOUND)) {
00933
00934 dist = DistSq(p, local);
00935
00936
00937 if (dist < closest) {
00938
00939 closest = dist;
00940 }
00941 }
00942 #endif
00943 }
00944 } while (outdated);
00945
00946 if ((networkState == NETSTATE_SERVER) && (numScores > 0)) {
00947
00948 SendScoreUpdate(scores, numScores);
00949 }
00950
00951 if (dInfo.showGame) {
00952 RenderGame();
00953 }
00954 #ifdef USE_AUDIO
00955
00956 if (closest != oldClosest) {
00957
00958
00959 if (closest < (MAX_SQ_DIST >> 2)) {
00960
00961 PlayTankMove(closest);
00962 }
00963 else {
00964
00965 if (local->flags & PLAYER_MOVEMENT_SOUND) {
00966 PlayLocalTankMove();
00967 }
00968 else {
00969 PlayTankIdle();
00970 }
00971 }
00972
00973 oldClosest = closest;
00974 }
00975 #endif
00976 }
00977
00978 #undef QueuePlaceTank
00979 #undef QueuePlaceShell
00980 #undef QueuePlaceName
00981
00982 void QueuePlaceTank(Uint8 pid) {
00983 batchTankDraw[BatchIndex(pid)] |= BatchBit(pid);
00984 }
00985
00986 void QueuePlaceShell(Uint8 pid) {
00987 batchShellDraw[BatchIndex(pid)] |= BatchBit(pid);
00988 }
00989
00990 void RemoveShell(Uint8 pid) {
00991 batchShellDraw[BatchIndex(pid)] &= ~BatchBit(pid);
00992 }
00993
00994 void QueuePlaceName(Uint8 pid) {
00995 batchNameDraw[BatchIndex(pid)] |= BatchBit(pid);
00996 }