00001
00025 #ifdef WIN32
00026 #define OpenFile W32OpenFile
00027 #endif
00028 #include "gameconfig.h"
00029 #include "net.h"
00030 #include "playernet.h"
00031 #include "obstacle.h"
00032 #include "vector.h"
00033 #include "notice.h"
00034 #include <assert.h>
00035 #include <ctype.h>
00036 #include <stdarg.h>
00037 #include <stdio.h>
00038 #include <stdlib.h>
00039 #include <string.h>
00040
00041 #ifdef WIN32
00042 #undef OpenFile
00043 #endif
00044
00045 ClientData *configListStart = NULL, *configListEnd = NULL;
00046
00047 GameOptions gameOpts = { 0 };
00048
00049 SDL_Rect *spawnAreas[TEAM_MAX];
00050 SDL_Rect *goalAreas[TEAM_MAX];
00051
00052 BattleFieldError bfErr;
00053
00057 #define MAX_TOKEN_LEN 8
00058
00063 static Vector cfgMsgBuffVec = {
00064 NULL,
00065 BufferVecDestr,
00066 NULL,
00067 sizeof(NetBuffer*),
00068 0,
00069 0,
00070 32
00071 };
00072
00077 static Uint32 *optionMsgFlags = NULL;
00078
00082 static Uint32 lastTransmit = 0;
00083
00087 static Uint16 nextItem = 0;
00088
00093 static Uint16 remainOptionMsgs = 0;
00094
00101 static DESTMAPTYPE destMap[DESTMAPLEN] = { 0 };
00102
00108 static const Vector configInitVec = {
00109 NULL,
00110 NULL,
00111 NULL,
00112 sizeof(SDL_Rect),
00113 0,
00114 0,
00115 64
00116 };
00117
00123 #define FILENAMELEN (64 - sizeof(FILE*) - sizeof(int) - 4)
00124
00132 struct ConfigFileStackFrame_t {
00136 FILE *file;
00140 int line;
00145 Sint16 xoffset;
00150 Sint16 yoffset;
00154 Uint16 width;
00158 Uint16 height;
00162 char filename[FILENAMELEN];
00163 union {
00167 Uint8 flags;
00168 struct {
00172 Bool flipHoriz : 1;
00176 Bool flipVert : 1;
00180 Bool transpose : 1;
00181 };
00182 };
00183 };
00184
00185 typedef struct ConfigFileStackFrame_t ConfigFileStackFrame;
00186
00195 static void ErrorOut(ConfigFileStackFrame *frame, const rtsa_char *format, ...) {
00196 va_list args;
00197 rtsa_char errmsg[BFLDERRLEN];
00198
00199 va_start(args, format);
00200
00201 vprnstr(errmsg, BFLDERRLEN, format, args);
00202
00203 va_end(args);
00204
00205 if (frame) {
00206
00207 bfErr.line = frame->line;
00208 strncpy(bfErr.file, frame->filename, 80);
00209
00210 prnstr(bfErr.msg, BFLDERRLEN, strings[STRING_ERR_READ], frame->filename,
00211 frame->line, errmsg);
00212 }
00213 else {
00214
00215 bfErr.line = -1;
00216 bfErr.file[0] = 0;
00217 bfErr.msg[0] = 0;
00218
00219 prnstr(bfErr.msg, BFLDERRLEN, strings[STRING_ERR_READ], errmsg);
00220 }
00221
00222 prnfile(stderr, bfErr.msg);
00223
00224 witechar('\n', stderr);
00225
00226 gameOpts.flags |= OPT_ERROR;
00227 }
00228
00247 static Bool OpenFile(ConfigFileStackFrame *frame) {
00248
00249 if (strchr(frame->filename, '\\')) {
00250 ErrorOut(frame, strings[STRING_ERR_BACKSLASH], frame->filename);
00251 frame->file = NULL;
00252 return FALSE;
00253 }
00254
00255
00256 if ((frame->file = fopen(frame->filename, "rb")) == NULL) {
00257
00258
00259 return FALSE;
00260 }
00261
00262 return TRUE;
00263 }
00264
00274 static Bool ReadToken(ConfigFileStackFrame *frame, char *buff, int loop) {
00275
00276 for (; loop < MAX_TOKEN_LEN; loop++) {
00277
00278 if ((buff[loop] = tolower(fgetc(frame->file))) == EOF) {
00279
00280 ErrorOut(frame, strings[STRING_ERR_IO]);
00281
00282 return FALSE;
00283 }
00284
00285 if (buff[loop] == '\n') frame->line++;
00286 if ((buff[loop] == '\n') || (buff[loop] == '\r')) {
00287
00288 buff[loop] = 0;
00289 ErrorOut(frame, strings[STRING_ERR_EOL]);
00290
00291 return FALSE;
00292 }
00293
00294 if (isspace(buff[loop])) {
00295
00296 break;
00297 }
00298 }
00299
00300 buff[loop] = 0;
00301
00302 return TRUE;
00303 }
00304
00323 static Bool ReadInts(ConfigFileStackFrame *frame, int *array, int flags,
00324 int xoff, int yoff) {
00325
00326 if (((flags & 1) &&
00327 (fscanf(frame->file, "%d %d", &array[0], &array[1]) != 2)) || ((flags & 2)
00328 && (fscanf(frame->file, "%d %d", &array[2], &array[3]) != 2))) {
00329
00330 ErrorOut(frame, strings[STRING_ERR_PARAM]);
00331
00332 return FALSE;
00333 }
00334
00335
00336 if (flags == 3) {
00337
00338 if (frame->transpose) {
00339 int x, y;
00340 x = array[0];
00341 y = array[1];
00342 array[0] = y;
00343 array[1] = x;
00344 x = array[2];
00345 y = array[3];
00346 array[2] = y;
00347 array[3] = x;
00348 }
00349
00350 if (frame->width) {
00351
00352 if (frame->flipHoriz) {
00353 array[0] = frame->width - array[0] - array[2];
00354 }
00355
00356 if (frame->flipVert) {
00357 array[1] = frame->height - array[1] - array[3];
00358 }
00359 }
00360 }
00361
00362 if (flags & 1) {
00363 int xsize, ysize;
00364
00365 if (gameOpts.width) {
00366
00367 xsize = gameOpts.width;
00368 ysize = gameOpts.height;
00369 }
00370 else {
00371
00372 xsize = ysize = 2048;
00373
00374
00375
00376
00377
00378
00379 }
00380
00381 array[0] += xoff;
00382 array[1] += yoff;
00383 if ((array[0] < 0) || (array[1] < 0) || (array[0] >= xsize) ||
00384 (array[1] >= ysize)) {
00385
00386 ErrorOut(frame, strings[STRING_ERR_XYRANGE]);
00387
00388 return FALSE;
00389 }
00390 }
00391
00392 if (flags & 2) {
00393
00394 if ((array[2] < 1) || (array[3] < 1) || (array[2] >= 2048) ||
00395 (array[3] >= 2048)) {
00396
00397 ErrorOut(frame, strings[STRING_ERR_WHRANGE]);
00398
00399 return FALSE;
00400 }
00401 }
00402
00403 return TRUE;
00404 }
00405
00414 static Bool ReadAreaParams(ConfigFileStackFrame *frame, Vector *areas) {
00415 SDL_Rect *area;
00416 int vals[4];
00417 char token[MAX_TOKEN_LEN] = { 0 };
00418
00419 if (!ReadToken(frame, token, 0)) {
00420 return FALSE;
00421 }
00422
00423 if (strcmp(token, "red") == 0) {
00424
00425 area = VectorAdd(&areas[TEAM_RED]);
00426 }
00427
00428 else if (strcmp(token, "blue") == 0) {
00429
00430 area = VectorAdd(&areas[TEAM_BLUE]);
00431 }
00432
00433 else {
00434
00435 ErrorOut(frame, strings[STRING_ERR_BADOWN], token);
00436
00437 return FALSE;
00438 }
00439
00440 if (area == NULL) {
00441
00442 ErrorOut(frame, strings[STRING_ERR_MEM]);
00443
00444 return FALSE;
00445 }
00446
00447 if (!ReadInts(frame, vals, 3, frame->xoffset, frame->yoffset)) {
00448 return FALSE;
00449 }
00450
00451 area->x = vals[0];
00452 area->y = vals[1];
00453 area->w = vals[2];
00454 area->h = vals[3];
00455
00456 return TRUE;
00457 }
00458
00469 static Bool CopyAreaData(Vector *input, SDL_Rect **output) {
00470
00471 if ((*output = malloc(sizeof(SDL_Rect) * input->items)) == NULL) {
00472
00473 free(obstacles);
00474 obstacles = NULL;
00475 ErrorOut(NULL, strings[STRING_ERR_MEM]);
00476 return FALSE;
00477 }
00478
00479 memcpy(*output, input->array, sizeof(SDL_Rect) * input->items);
00480 return TRUE;
00481 }
00482
00488 static void StartLoadConfig(const char *fname) {
00489
00490 #define SigErr goto StartLoadConfig_cleanup
00491
00492 ConfigFileStackFrame *frame;
00493 Vector stack = configInitVec, blocks = configInitVec;
00494 Vector goals[TEAM_MAX], spawns[TEAM_MAX];
00495 int xoff = 0, yoff = 0;
00496 int loop;
00497
00498 stack.itemSize = sizeof(ConfigFileStackFrame);
00499 spawns[TEAM_RED] = spawns[TEAM_BLUE] = goals[TEAM_RED] = goals[TEAM_BLUE]
00500 = configInitVec;
00501
00502 if (!VectorInit(&stack, 64) || !VectorInit(&blocks, 64) ||
00503 !VectorInit(&spawns[TEAM_RED], 64) || !VectorInit(&spawns[TEAM_BLUE], 64) ||
00504 !VectorInit(&goals[TEAM_RED], 64) || !VectorInit(&goals[TEAM_BLUE], 64)) {
00505
00506 SigErr;
00507 }
00508
00509 gameOpts.width = gameOpts.height = 0;
00510
00511
00512 if ((frame = VectorAdd(&stack)) == NULL) {
00513
00514 ErrorOut(NULL, strings[STRING_ERR_MEM]);
00515
00516 SigErr;
00517 }
00518 frame->flags = 0;
00519 frame->width = frame->height = 0;
00520 frame->xoffset = frame->yoffset = 0;
00521 frame->line = 1;
00522
00523
00524
00525
00526 strncpy(frame->filename, fname, FILENAMELEN);
00527
00528 frame->filename[FILENAMELEN - 1] = 0;
00529
00530 if (!OpenFile(frame)) {
00531
00532 ErrorOut(frame, strings[STRING_ERR_FOPEN], frame->filename);
00533 SigErr;
00534 }
00535
00536
00537 do {
00538 char token[MAX_TOKEN_LEN] = { 0 };
00539
00540 while ((token[0] = tolower(fgetc(frame->file))) != EOF) {
00541 int vals[4];
00542
00543 if (token[0] == '\n') {
00544
00545 frame->line++;
00546 }
00547
00548 else if (token[0] == '#') {
00549
00550 do {
00551
00552 if ((token[0] = fgetc(frame->file)) == EOF) {
00553
00554 break;
00555 }
00556 } while ((token[0] != '\n') && (token[0] != '\r'));
00557
00558 frame->line++;
00559 }
00560
00561 else if (isalnum(token[0])) {
00562 SDL_Rect *rect;
00563 if (!ReadToken(frame, token, 1)) {
00564
00565 goto StartLoadConfig_cleanup;
00566 }
00567
00568
00569 if (strcmp(token, "block") == 0) {
00570
00571 if (!ReadInts(frame, vals, 3, frame->xoffset,
00572 frame->yoffset)) {
00573 goto StartLoadConfig_cleanup;
00574 }
00575
00576 if ((rect = (SDL_Rect*)VectorAdd(&blocks)) == NULL) {
00577
00578 ErrorOut(frame, strings[STRING_ERR_MEM]);
00579
00580 SigErr;
00581 }
00582
00583 rect->x = vals[0];
00584 rect->y = vals[1];
00585 rect->w = vals[2];
00586 rect->h = vals[3];
00587 }
00588
00589
00590 else if (strcmp(token, "flip") == 0) {
00591
00592 if (!ReadToken(frame, token, 0)) {
00593
00594 goto StartLoadConfig_cleanup;
00595 }
00596
00597 if (strcmp(token, "none") == 0) {
00598
00599 frame->flags = 0;
00600 }
00601 else if (strcmp(token, "trans") == 0) {
00602
00603 frame->transpose = TRUE;
00604 }
00605 else if (strcmp(token, "horiz") == 0) {
00606
00607 frame->flipHoriz = TRUE;
00608 }
00609 else if (strcmp(token, "vert") == 0) {
00610
00611 frame->flipVert = TRUE;
00612 }
00613 else {
00614
00615 ErrorOut(frame, strings[STRING_ERR_INVLDKEY], token);
00616
00617 SigErr;
00618 }
00619 }
00620
00621
00622 else if (strcmp(token, "goal") == 0) {
00623 if (!ReadAreaParams(frame, goals)) {
00624 SigErr;
00625 }
00626 }
00627
00628
00629 else if (strcmp(token, "include") == 0) {
00630 char fname[128];
00631 ConfigFileStackFrame *incFrame;
00632
00633 xoff = frame->xoffset;
00634 yoff = frame->yoffset;
00635
00636 do {
00637
00638 if ((fname[0] = fgetc(frame->file)) == EOF) {
00639
00640 ErrorOut(frame, strings[STRING_ERR_EOFINC]);
00641
00642 SigErr;
00643 }
00644 } while (isspace(fname[0]));
00645
00646 for (loop = 1; loop < 128; loop++) {
00647
00648 if ((fname[loop] = fgetc(frame->file)) == EOF) {
00649
00650 fname[loop] = 0;
00651 ErrorOut(frame, strings[STRING_ERR_EOFNAME], fname);
00652
00653 SigErr;
00654 }
00655
00656 if ((fname[loop] == ';') || (fname[loop] == '\n') ||
00657 (fname[loop] == '\r')) {
00658
00659 fname[loop] = 0;
00660
00661 break;
00662 }
00663 }
00664
00665 if (loop == 127) {
00666
00667 fname[10] = 0;
00668
00669 ErrorOut(frame, strings[STRING_ERR_NAMELONG], fname);
00670
00671 SigErr;
00672 }
00673
00674 if ((incFrame = VectorAdd(&stack)) == NULL) {
00675
00676 ErrorOut(frame, strings[STRING_ERR_MEM]);
00677
00678 SigErr;
00679 }
00680
00681 strcpy(incFrame->filename, fname);
00682
00683 if (!OpenFile(incFrame)) {
00684
00685 ErrorOut(frame, strings[STRING_ERR_FOPEN], fname);
00686
00687 SigErr;
00688 }
00689
00690 incFrame->flags = frame->flags;
00691 incFrame->width = frame->width;
00692 incFrame->height = frame->height;
00693 frame = incFrame;
00694 frame->line = 1;
00695 frame->xoffset = xoff;
00696 frame->yoffset = yoff;
00697 }
00698
00699
00700 else if (strcmp(token, "offset") == 0) {
00701
00702 if (!ReadInts(frame, vals, 1, xoff, yoff)) {
00703 goto StartLoadConfig_cleanup;
00704 }
00705
00706 frame->xoffset = vals[0];
00707 frame->yoffset = vals[1];
00708 }
00709
00710
00711 else if (strcmp(token, "size") == 0) {
00712
00713 if (!ReadInts(frame, vals, 2, 0, 0)) {
00714 goto StartLoadConfig_cleanup;
00715 }
00716
00717 if (gameOpts.width == 0) {
00718
00719 if ((vals[2] < 32) || (vals[3] < 32)) {
00720
00721 ErrorOut(frame, strings[STRING_ERR_FLDSMALL],
00722 vals[2], vals[3]);
00723
00724 SigErr;
00725 }
00726
00727 gameOpts.width = vals[2];
00728 gameOpts.height = vals[3];
00729 }
00730
00731 frame->width = vals[2];
00732 frame->height = vals[3];
00733 }
00734
00735
00736 else if (strcmp(token, "spawn") == 0) {
00737 if (!ReadAreaParams(frame, spawns)) {
00738 SigErr;
00739 }
00740 }
00741 else {
00742
00743 token[MAX_TOKEN_LEN - 1] = 0;
00744
00745 ErrorOut(frame, strings[STRING_ERR_INVLDKEY], token);
00746
00747 SigErr;
00748 }
00749 }
00750 }
00751
00752 fclose(frame->file);
00753 VectorPop(&stack);
00754
00755 frame = &(((ConfigFileStackFrame*)(stack.array))[stack.items - 1]);
00756
00757 if (stack.items > 1) {
00758
00759 xoff = (frame - 1)->xoffset;
00760 yoff = (frame - 1)->yoffset;
00761 }
00762
00763 else if (stack.items == 1) {
00764
00765 xoff = yoff = 0;
00766 }
00767 } while (stack.items > 0);
00768
00769 if (gameOpts.height == 0) {
00770
00771 ErrorOut(NULL, strings[STRING_ERR_NOSIZE]);
00772
00773 SigErr;
00774 }
00775
00776 if (spawns[TEAM_RED].items == 0) {
00777
00778 ErrorOut(NULL, strings[STRING_ERR_NOREDSPN]);
00779
00780 SigErr;
00781 }
00782 if (spawns[TEAM_BLUE].items == 0) {
00783
00784 ErrorOut(NULL, strings[STRING_ERR_NOBLSPN]);
00785
00786 SigErr;
00787 }
00788
00789 if (gameOpts.flags & OPT_ISCTF) {
00790
00791 if (goals[TEAM_RED].items == 0) {
00792
00793 ErrorOut(NULL, strings[STRING_ERR_NOREDGOAL]);
00794
00795 SigErr;
00796 }
00797 if (goals[TEAM_BLUE].items == 0) {
00798
00799 ErrorOut(NULL, strings[STRING_ERR_NOBLGOAL]);
00800
00801 SigErr;
00802 }
00803 }
00804
00805
00806 prnout(strings[STRING_BF_STAT], spawns[TEAM_RED].items,
00807 spawns[TEAM_BLUE].items, goals[TEAM_RED].items, goals[TEAM_BLUE].items,
00808 blocks.items);
00809
00810
00811
00812
00813
00814
00815 if (blocks.items > 0) {
00816 Obstacle *obst;
00817 SDL_Rect *rect;
00818 if ((obst = obstacles = malloc((loop = blocks.items) *
00819 sizeof(Obstacle))) == NULL) {
00820
00821 ErrorOut(NULL, strings[STRING_ERR_MEM]);
00822 SigErr;
00823 }
00824
00825 for (rect = blocks.array; loop > 0; loop--, rect++, obst++) {
00826 obst->loc = *rect;
00827 }
00828 }
00829
00830
00831 if (!CopyAreaData(&(spawns[TEAM_RED]), &(spawnAreas[TEAM_RED]))) {
00832 SigErr;
00833 }
00834
00835 if (!CopyAreaData(&(spawns[TEAM_BLUE]), (&spawnAreas[TEAM_BLUE]))) {
00836 SigErr;
00837 }
00838
00839 if (gameOpts.flags & OPT_ISCTF) {
00840
00841 if (!CopyAreaData(&(goals[TEAM_RED]), &(goalAreas[TEAM_RED]))) {
00842 SigErr;
00843 }
00844
00845 if (!CopyAreaData(&(goals[TEAM_BLUE]), &(goalAreas[TEAM_BLUE]))) {
00846 SigErr;
00847 }
00848 }
00849
00850 gameOpts.obstacles = blocks.items;
00851 gameOpts.spawnAreas[TEAM_RED] = spawns[TEAM_RED].items;
00852 gameOpts.spawnAreas[TEAM_BLUE] = spawns[TEAM_BLUE].items;
00853
00854
00855 StartLoadConfig_cleanup:
00856
00857 frame = &(((ConfigFileStackFrame*)(stack.array))[stack.items - 1]);
00858 for (loop = stack.items - 1; loop >=0; loop--, frame--) {
00859 if (frame->file) {
00860 fclose(frame->file);
00861 }
00862 }
00863
00864 VectorDestroy(&stack);
00865 VectorDestroy(&blocks);
00866 VectorDestroy(&spawns[TEAM_RED]);
00867 VectorDestroy(&spawns[TEAM_BLUE]);
00868 VectorDestroy(&goals[TEAM_RED]);
00869 VectorDestroy(&goals[TEAM_BLUE]);
00870 #undef SigErr
00871 }
00872
00883 static Bool MakeAreaBuffers(Uint8 *totalAreas, SDL_Rect **areas, Uint8 type) {
00884
00885
00886 unsigned int loop, team, set = 0;
00887 SDL_Rect *area;
00888 Uint8 *ptr = NULL;
00889 NetBuffer *buff = NULL;
00890
00891
00892 for (team = 0; team < 2; team++) {
00893 for (area = areas[team], loop = 0;
00894 loop < totalAreas[team]; area++, loop++) {
00895
00896 if ((ptr == NULL) ||
00897 ((MSG_MAX_SIZE - (int)(buff->data - ptr)) < 10)) {
00898 NetBuffer **spot;
00899
00900
00901 if (buff) {
00902 buff->length = (Sint16)(ptr - buff->data);
00903 }
00904
00905 if ((buff = BufferNew()) == NULL) {
00906
00907 return FALSE;
00908 }
00909
00910 if ((spot = VectorAdd(&cfgMsgBuffVec)) == NULL) {
00911
00912 BufferFree(buff);
00913 return FALSE;
00914 }
00915
00916 *spot = buff;
00917
00918 buff->data[0] = type;
00919 ptr = buff->data + 5;
00920 MSG_WRITE_16(ptr, cfgMsgBuffVec.items - 1);
00921 MSG_WRITE_8(ptr, totalAreas[TEAM_RED]);
00922 MSG_WRITE_8(ptr, totalAreas[TEAM_BLUE]);
00923
00924 set = 0;
00925 }
00926
00927 if (set == 0) {
00928
00929 if ((set = (MSG_MAX_SIZE - (int)(ptr - buff->data) - 2) >> 3) >
00930 (totalAreas[team] - loop)) {
00931
00932
00933 set = totalAreas[team] - loop;
00934 }
00935
00936 if (set > 64) {
00937
00938 set = 64;
00939 }
00940
00941 MSG_WRITE_8(ptr, loop);
00942 MSG_WRITE_8(ptr, (set - 1) | (team << 6));
00943 }
00944
00945 set--;
00946
00947 MSG_WRITE_16(ptr, area->x);
00948 MSG_WRITE_16(ptr, area->y);
00949 MSG_WRITE_16(ptr, area->w);
00950 MSG_WRITE_16(ptr, area->h);
00951 }
00952 assert(set == 0);
00953 }
00954
00955 if (buff) {
00956
00957 buff->length = (Sint16)(ptr - buff->data);
00958 }
00959 return TRUE;
00960 }
00961
00980 static Bool MakeBuffers() {
00981 unsigned int loop;
00982 Uint8 *ptr;
00983 Obstacle *obst;
00984 NetBuffer *buff, **spot;
00985
00986
00987 if ((buff = BufferNew()) == NULL) {
00988 return FALSE;
00989 }
00990
00991 if ((spot = VectorAdd(&cfgMsgBuffVec)) == NULL) {
00992
00993 BufferFree(buff);
00994 return FALSE;
00995 }
00996 *spot = buff;
00997 ptr = buff->data;
00998 buff->length = 20;
00999
01000 buff = NULL;
01001
01002 ptr[0] = MSG_TYPE_OPTION;
01003 ptr[3] = gameOpts.flags;
01004 ptr += 4;
01005 MSG_WRITE_32(ptr, gameOpts.duration);
01006 MSG_WRITE_16(ptr, gameOpts.teamScore[TEAM_RED]);
01007 MSG_WRITE_16(ptr, gameOpts.teamScore[TEAM_BLUE]);
01008 MSG_WRITE_16(ptr, gameOpts.winScore);
01009 MSG_WRITE_16(ptr, gameOpts.width);
01010 MSG_WRITE_16(ptr, gameOpts.height);
01011
01012
01013
01014
01015 for (obst = obstacles, loop = 0; loop < gameOpts.obstacles; obst++, loop++) {
01016
01017 if ((loop % MAX_OBSTACLES_PER_MSG) == 0) {
01018
01019
01020 if (buff) {
01021 buff->length = (Sint16)(ptr - buff->data);
01022 }
01023
01024 if ((buff = BufferNew()) == NULL) {
01025
01026 goto MakeBuffers_failure;
01027 }
01028
01029 if ((spot = VectorAdd(&cfgMsgBuffVec)) == NULL) {
01030
01031 BufferFree(buff);
01032 goto MakeBuffers_failure;
01033 }
01034
01035 *spot = buff;
01036
01037 buff->data[0] = MSG_TYPE_OBSTACLE;
01038 ptr = buff->data + 5;
01039 MSG_WRITE_16(ptr, cfgMsgBuffVec.items - 1);
01040 MSG_WRITE_16(ptr, gameOpts.obstacles);
01041 MSG_WRITE_16(ptr, loop);
01042 }
01043
01044 MSG_WRITE_16(ptr, obst->loc.x);
01045 MSG_WRITE_16(ptr, obst->loc.y);
01046 MSG_WRITE_16(ptr, obst->loc.w);
01047 MSG_WRITE_16(ptr, obst->loc.h);
01048 }
01049
01050 if (buff) {
01051
01052 buff->length = (Sint16)(ptr - buff->data);
01053
01054 buff = NULL;
01055 }
01056
01057 if (!MakeAreaBuffers(gameOpts.spawnAreas, spawnAreas, MSG_TYPE_SPAWN)) {
01058 goto MakeBuffers_failure;
01059 }
01060
01061 if (!MakeAreaBuffers(gameOpts.goalAreas, goalAreas, MSG_TYPE_GOAL)) {
01062 goto MakeBuffers_failure;
01063 }
01064
01065
01066 prnout(strings[STRING_CMPLOPT],
01067 gameOpts.totalMsgs = gameOpts.rcvdMsgs = cfgMsgBuffVec.items);
01068
01069
01070 spot = (NetBuffer**)(cfgMsgBuffVec.array);
01071
01072 MSG_WRITE_16C((*spot)->data, 18, gameOpts.totalMsgs);
01073
01074 for (spot++, loop = gameOpts.totalMsgs - 1; loop > 0; loop--, spot++) {
01075 MSG_WRITE_16C((*spot)->data, 3, gameOpts.totalMsgs);
01076 }
01077 return TRUE;
01078
01079
01080 MakeBuffers_failure:
01081
01082 VectorDestroy(&cfgMsgBuffVec);
01083
01084 return FALSE;
01085 }
01086
01087
01088 Bool InitGameConfig(const char *fname) {
01089
01090 gameOpts.flags &= ~OPT_ERROR;
01091
01092 if (!VectorInit(&cfgMsgBuffVec, cfgMsgBuffVec.minSize)) {
01093
01094 return FALSE;
01095 }
01096
01097 StartLoadConfig(fname);
01098
01099 if (gameOpts.flags & OPT_ERROR) {
01100
01101 free(cfgMsgBuffVec.array);
01102 cfgMsgBuffVec.array = NULL;
01103 return FALSE;
01104 }
01105
01106 if (!MakeBuffers()) {
01107
01108 free(cfgMsgBuffVec.array);
01109 cfgMsgBuffVec.array = NULL;
01110 return FALSE;
01111 }
01112
01113 gameOpts.flags |= OPT_ISSET;
01114 return TRUE;
01115 }
01116
01117 void UninitGameConfig() {
01118 int loop;
01119
01120 configListStart = configListEnd = NULL;
01121
01122 nextItem = 0;
01123
01124 ObstacleUninit();
01125
01126 for (loop = 0; loop < 2; loop++) {
01127 if ((gameOpts.goalAreas[loop] > 0) && goalAreas[loop]) {
01128 free(goalAreas[loop]);
01129 }
01130 goalAreas[loop] = NULL;
01131 gameOpts.goalAreas[loop] = 0;
01132 if ((gameOpts.spawnAreas[loop] > 0) && spawnAreas[loop]) {
01133 free(spawnAreas[loop]);
01134 }
01135 spawnAreas[loop] = NULL;
01136 gameOpts.spawnAreas[loop] = 0;
01137 }
01138
01139 if (optionMsgFlags) {
01140
01141 free(optionMsgFlags);
01142 optionMsgFlags = NULL;
01143 }
01144
01145 memset(&gameOpts, 0, sizeof(gameOpts));
01146
01147 memset(destMap, 0, sizeof(destMap));
01148
01149 VectorDestroy(&cfgMsgBuffVec);
01150 }
01151
01152 void AddToConfigList(ClientData *client) {
01153 MsgDescr *msg = NULL;
01154 Player *p;
01155 int loop, now, ind, destflag, flags;
01156
01157 if ((client->configPrev = configListEnd) == NULL) {
01158 configListStart = configListEnd = client;
01159 }
01160 else {
01161 configListEnd->configNext = client;
01162 configListEnd = client;
01163 }
01164 client->configNext = NULL;
01165
01166 client->configFirst = nextItem;
01167
01168 destMap[ind = GetDestMapIndex(client->cid)] |=
01169 destflag = GetDestMapFlag(client->cid);
01170
01171 now = SDL_GetTicks();
01172
01173 for (p = players, loop = MAX_PLAYERS; loop > 0; loop--, p++) {
01174
01175 if (!(p->flags & PLAYER_ACTIVE))
01176 continue;
01177
01178 flags = p->flags;
01179
01180 p->flags |= PLAYER_UPDATE_IDENT | PLAYER_UPDATE_DFS;
01181 if (!(p->flags & PLAYER_DEAD)) {
01182 p->flags |= PLAYER_UPDATE_TANK | PLAYER_UPDATE_SHELL;
01183 }
01184
01185 if ((msg = AppendPlayerData(msg, p, now)) == NULL) {
01186
01187 return;
01188 }
01189
01190
01191 msg->bcast = msg->mcast = FALSE;
01192 msg->destMap[ind] = destflag;
01193
01194 p->flags = flags;
01195 }
01196
01197 if (msg) {
01198 AddMessage(msg);
01199 }
01200
01202 SendScoreUpdate(NULL, 0);
01203 }
01204
01205 void RemoveFromConfigList(ClientData *client) {
01206
01207 if (client->configPrev != NULL) {
01208 client->configPrev->configNext = client->configNext;
01209
01210 if (client->configNext == NULL) {
01211 configListEnd = client->configPrev;
01212 }
01213 }
01214
01215 else if (client == configListStart) {
01216
01217 if ((configListStart = client->configNext) == NULL) {
01218 configListEnd = NULL;
01219 }
01220 }
01221
01222 client->configNext = client->configPrev = NULL;
01223
01224 destMap[GetDestMapIndex(client->cid)] &=
01225 ~GetDestMapFlag(client->cid);
01226 }
01227
01228 Bool ServiceGameConfig() {
01229 ClientData *client;
01230 MsgDescr *msg;
01231 Uint32 now, loop;
01232
01233
01234
01240 if ((configListStart == NULL) || !(gameOpts.flags & OPT_ISSET) ||
01241 (((now = SDL_GetTicks()) - lastTransmit) < 64)) {
01242
01243 return TRUE;
01244 }
01245
01246 if ((msg = MessageNew()) == NULL) {
01247
01248 return FALSE;
01249 }
01250
01251 msg->buffer = *(NetBuffer**)VectorItem(&cfgMsgBuffVec, nextItem);
01252 assert(msg->buffer != NULL);
01253 assert(msg->buffer->length > 0);
01254
01255 msg->approveFunc = NULL;
01256 msg->ackFunc = NULL;
01257 msg->failFunc = NULL;
01258 msg->bcast = msg->buffLifeUnmanaged = TRUE;
01259 for (loop = 0; loop < DESTMAPLEN; loop++) {
01260 msg->destMap[loop] = destMap[loop];
01261 }
01262
01263 if (!AddMessage(msg)) {
01264
01265
01266 return FALSE;
01267 }
01268
01269 if (++nextItem == cfgMsgBuffVec.items) {
01270
01271
01272 nextItem = 0;
01273 }
01274
01275
01276 while (configListStart->configFirst == nextItem) {
01277
01278
01279
01280
01281
01282
01283 client = configListStart;
01284
01285 destMap[GetDestMapIndex(client->cid)] &=
01286 ~GetDestMapFlag(client->cid);
01287
01288 if ((configListStart = configListStart->configNext) == NULL) {
01289 assert(client == configListEnd);
01290
01291 configListEnd = NULL;
01292
01293 break;
01294 }
01295
01296 client->configNext = client->configPrev = NULL;
01297 }
01298
01299 return TRUE;
01300 }
01301
01316 static Bool FlagCfgMsg(int max, int index) {
01317 int arrayInd, arrayBit;
01318
01319 if (optionMsgFlags == NULL) {
01320
01321 if ((optionMsgFlags = calloc(rounddivup(max, 32), 4)) == NULL) {
01322
01323 return FALSE;
01324 }
01325
01326 gameOpts.totalMsgs = remainOptionMsgs = max;
01327 }
01328
01329 else if (max != gameOpts.totalMsgs) {
01330
01331 return FALSE;
01332 }
01333
01334 assert(remainOptionMsgs > 0);
01335
01336 arrayInd = bitindex(index, Uint32);
01337 arrayBit = bitflag(index, Uint32);
01338
01339 if (!(optionMsgFlags[arrayInd] & arrayBit)) {
01340
01341 optionMsgFlags[arrayInd] |= arrayBit;
01342
01343 if (--remainOptionMsgs == 0) {
01344
01345 networkState = NETSTATE_CLIENT;
01346
01347 free(optionMsgFlags);
01348 optionMsgFlags = NULL;
01349 }
01350
01351 return TRUE;
01352 }
01353
01354 return FALSE;
01355 }
01356
01357 Bool HandleGameOption(SocketAddr *origin, NetBuffer *buffer, Uint8 *unused,
01358 Uint16 noid) {
01359 int total;
01360
01361 if ((networkState < NETSTATE_RCVCFG) || (networkState > NETSTATE_CLIENT) ||
01362 (buffer->length != 20) || !ValidateServer(origin)) {
01363
01364 return FALSE;
01365 }
01366
01367 if (networkState != NETSTATE_RCVCFG) {
01368 return TRUE;
01369 }
01370
01371 MSG_READ_16C(buffer->data, 18, total);
01372
01373 if (FlagCfgMsg(total, 0)) {
01374
01375 gameOpts.flags = buffer->data[3];
01376 MSG_READ_32C(buffer->data, 4, gameOpts.duration);
01377 MSG_READ_16C(buffer->data, 8, gameOpts.teamScore[TEAM_RED]);
01378 MSG_READ_16C(buffer->data, 10, gameOpts.teamScore[TEAM_BLUE]);
01379 MSG_READ_16C(buffer->data, 12, gameOpts.winScore);
01380 MSG_READ_16C(buffer->data, 14, gameOpts.width);
01381 MSG_READ_16C(buffer->data, 16, gameOpts.height);
01382 }
01383 return TRUE;
01384 }
01385
01386 Bool HandleObstacle(SocketAddr *origin, NetBuffer *buffer, Uint8 *unused,
01387 Uint16 noid) {
01388 int total, msgIndex;
01389 Uint16 numObst, index, loop;
01390 Obstacle *obst;
01391 Uint8 *ptr;
01392
01393 if ((networkState < NETSTATE_RCVCFG) || (networkState > NETSTATE_CLIENT) ||
01394 !ValidateServer(origin)) {
01395
01396 return FALSE;
01397 }
01398
01399 if (networkState != NETSTATE_RCVCFG) {
01400 return TRUE;
01401 }
01402
01403 ptr = buffer->data + 3;
01404
01405 MSG_READ_16(ptr, total);
01406
01407 MSG_READ_16(ptr, msgIndex);
01408
01409 if (!FlagCfgMsg(total, msgIndex)) {
01410
01411 return TRUE;
01412 }
01413
01414 MSG_READ_16(ptr, numObst);
01415
01416 if ((gameOpts.obstacles == 0) && (numObst > 0)) {
01417
01418 if ((obstacles =
01419 malloc(sizeof(Obstacle) * (gameOpts.obstacles = numObst))) == NULL) {
01420
01421 gameOpts.obstacles = 0;
01422
01423 gameOpts.flags |= OPT_ERROR;
01424
01425 return FALSE;
01426 }
01427 }
01428
01429 else if (gameOpts.obstacles != numObst) {
01430
01431 return FALSE;
01432 }
01433
01434 MSG_READ_16(ptr, index);
01435
01436 if ((index >= numObst) || (index % MAX_OBSTACLES_PER_MSG)) {
01437
01438 gameOpts.flags |= OPT_ERROR;
01439
01440 return FALSE;
01441 }
01442
01443 loop = ((numObst - index) >= MAX_OBSTACLES_PER_MSG) ? MAX_OBSTACLES_PER_MSG
01444 : numObst - index;
01445
01446 for (obst = &(obstacles[index]); loop > 0; loop--, obst++) {
01447
01448 MSG_READ_16(ptr, obst->loc.x);
01449
01450 MSG_READ_16(ptr, obst->loc.y);
01451
01452 MSG_READ_16(ptr, obst->loc.w);
01453
01454 MSG_READ_16(ptr, obst->loc.h);
01455 }
01456 return TRUE;
01457 }
01458
01459 Bool HandleArea(SocketAddr *origin, NetBuffer *buffer, Uint8 *unused,
01460 Uint16 noid) {
01461 int loop, total, msgIndex;
01462 SDL_Rect *rect, **areas;
01463 Uint8 *ptr, *numAreas, team, togo;
01464
01465 if ((networkState < NETSTATE_RCVCFG) || (networkState > NETSTATE_CLIENT) ||
01466 !ValidateServer(origin)) {
01467
01468 return FALSE;
01469 }
01470
01471 if (networkState != NETSTATE_RCVCFG) {
01472 return TRUE;
01473 }
01474
01475 ptr = buffer->data + 3;
01476
01477 MSG_READ_16(ptr, total);
01478
01479 MSG_READ_16(ptr, msgIndex);
01480
01481 if (!FlagCfgMsg(total, msgIndex)) {
01482
01483 return TRUE;
01484 }
01485
01486 switch (buffer->data[0]) {
01487
01488 case MSG_TYPE_SPAWN:
01489 numAreas = gameOpts.spawnAreas;
01490 areas = spawnAreas;
01491 break;
01492
01493 case MSG_TYPE_GOAL:
01494 numAreas = gameOpts.goalAreas;
01495 areas = goalAreas;
01496 break;
01497 default:
01498
01499
01500 assert(0);
01501 exit(__LINE__);
01502 }
01503
01504 for (loop = 0; loop < 2; loop++, ptr++) {
01505
01506 if ((numAreas[loop] == 0) && (*ptr > 0)) {
01507
01508 if ((areas[loop] =
01509 malloc(sizeof(SDL_Rect) * (numAreas[loop] = *ptr))) == NULL) {
01510
01511 numAreas[loop] = 0;
01512
01513 gameOpts.flags |= OPT_ERROR;
01514
01515 return FALSE;
01516 }
01517 }
01518
01519 else if (numAreas[loop] != *ptr) {
01520
01521 return FALSE;
01522 }
01523 }
01524
01525
01526 while ((buffer->length - (ptr - buffer->data)) >= 10) {
01527
01528 MSG_READ_8(ptr, loop);
01529
01530 togo = (*ptr & 0x3F) + 1;
01531
01532 team = *(ptr++) >> 6;
01533
01534 if (((loop + togo) > numAreas[team]) ||
01535 ((ptr - buffer->data + togo * 8) > buffer->length)) {
01536
01537 return FALSE;
01538 }
01539
01540 for (rect = &(areas[team][loop]); togo > 0; togo--, rect++) {
01541
01542 MSG_READ_16(ptr, rect->x);
01543
01544 MSG_READ_16(ptr, rect->y);
01545
01546 MSG_READ_16(ptr, rect->w);
01547
01548 MSG_READ_16(ptr, rect->h);
01549 }
01550 }
01551 return TRUE;
01552 }
01553
01554 Bool HandleScoreUpdate(SocketAddr *origin, NetBuffer *buffer, Uint8 *unused,
01555 Uint16 noid) {
01556 int playerUpdates, killerID, killedID;
01557 Uint8 *data;
01558 Sint16 score;
01559
01560 if (((networkState != NETSTATE_RCVCFG) && (networkState != NETSTATE_CLIENT))
01561 || (buffer->length < 8) || !ValidateServer(origin)) {
01562
01563 return FALSE;
01564 }
01565
01566 data = buffer->data + 3;
01567
01568 MSG_READ_8(data, playerUpdates);
01569
01570 if (playerUpdates > MAX_PLAYERS) {
01571
01572 return FALSE;
01573 }
01574 MSG_READ_16(data, gameOpts.teamScore[TEAM_RED]);
01575 MSG_READ_16(data, gameOpts.teamScore[TEAM_BLUE]);
01576
01577 for (; playerUpdates > 0; playerUpdates--) {
01578 MSG_READ_8(data, killerID);
01579 MSG_READ_8(data, killedID);
01580 MSG_READ_16(data, score);
01581
01582 if ((killerID >= MAX_PLAYERS) || (killedID >= MAX_PLAYERS)) {
01583
01584 return FALSE;
01585 }
01586
01587 AddScoreNotice(killerID, killedID, score);
01588 }
01589
01590 gameOpts.flags |= OPT_UPDATESCORE;
01591 return TRUE;
01592 }
01593
01594 Bool SendScoreUpdate(ScoreUpdate *scores, int len) {
01595 MsgDescr *msg;
01596 Uint8 *data;
01597
01598 assert(networkState == NETSTATE_SERVER);
01599
01600 assert((len == 0) || (scores != NULL));
01601
01602 if ((msg = MessageNew()) == NULL) {
01603
01604 return FALSE;
01605 }
01606
01607 if ((msg->buffer = BufferNew()) == NULL) {
01608
01609 MessageFree(msg);
01610 return FALSE;
01611 }
01612 data = msg->buffer->data;
01613
01614 msg->approveFunc = NULL;
01615 msg->ackFunc = NULL;
01616 msg->failFunc = MsgFailDisconnect;
01617 msg->interval <<= 2;
01618 SetDestToAll(msg);
01619
01620 MSG_WRITE_8(data, MSG_TYPE_SCORE);
01621 data += 2;
01622 MSG_WRITE_8(data, len);
01623 MSG_WRITE_16(data, gameOpts.teamScore[TEAM_RED]);
01624 MSG_WRITE_16(data, gameOpts.teamScore[TEAM_BLUE]);
01625 for (; len > 0; len--, scores++) {
01626
01627 MSG_WRITE_8(data, scores->killerId);
01628
01629 MSG_WRITE_8(data, scores->killedId);
01630
01631 MSG_WRITE_16(data, players[scores->killerId].kills);
01632 }
01633
01634 msg->buffer->length = data - msg->buffer->data;
01635 msg->bcast = TRUE;
01636
01637 SetDestToAll(msg);
01638 AddMessage(msg);
01639 return TRUE;
01640 }
01641