|
|
1.1 ! root 1: ! 2: #include "g_local.h" ! 3: ! 4: #define Function(f) {#f, f} ! 5: ! 6: mmove_t mmove_reloc; ! 7: ! 8: field_t fields[] = { ! 9: {"classname", FOFS(classname), F_LSTRING}, ! 10: {"model", FOFS(model), F_LSTRING}, ! 11: {"spawnflags", FOFS(spawnflags), F_INT}, ! 12: {"speed", FOFS(speed), F_FLOAT}, ! 13: {"accel", FOFS(accel), F_FLOAT}, ! 14: {"decel", FOFS(decel), F_FLOAT}, ! 15: {"target", FOFS(target), F_LSTRING}, ! 16: {"targetname", FOFS(targetname), F_LSTRING}, ! 17: {"pathtarget", FOFS(pathtarget), F_LSTRING}, ! 18: {"deathtarget", FOFS(deathtarget), F_LSTRING}, ! 19: {"killtarget", FOFS(killtarget), F_LSTRING}, ! 20: {"combattarget", FOFS(combattarget), F_LSTRING}, ! 21: {"message", FOFS(message), F_LSTRING}, ! 22: {"team", FOFS(team), F_LSTRING}, ! 23: {"wait", FOFS(wait), F_FLOAT}, ! 24: {"delay", FOFS(delay), F_FLOAT}, ! 25: {"random", FOFS(random), F_FLOAT}, ! 26: {"move_origin", FOFS(move_origin), F_VECTOR}, ! 27: {"move_angles", FOFS(move_angles), F_VECTOR}, ! 28: {"style", FOFS(style), F_INT}, ! 29: {"count", FOFS(count), F_INT}, ! 30: {"health", FOFS(health), F_INT}, ! 31: {"sounds", FOFS(sounds), F_INT}, ! 32: {"light", 0, F_IGNORE}, ! 33: {"dmg", FOFS(dmg), F_INT}, ! 34: {"mass", FOFS(mass), F_INT}, ! 35: {"volume", FOFS(volume), F_FLOAT}, ! 36: {"attenuation", FOFS(attenuation), F_FLOAT}, ! 37: {"map", FOFS(map), F_LSTRING}, ! 38: {"origin", FOFS(s.origin), F_VECTOR}, ! 39: {"angles", FOFS(s.angles), F_VECTOR}, ! 40: {"angle", FOFS(s.angles), F_ANGLEHACK}, ! 41: ! 42: {"goalentity", FOFS(goalentity), F_EDICT, FFL_NOSPAWN}, ! 43: {"movetarget", FOFS(movetarget), F_EDICT, FFL_NOSPAWN}, ! 44: {"enemy", FOFS(enemy), F_EDICT, FFL_NOSPAWN}, ! 45: {"oldenemy", FOFS(oldenemy), F_EDICT, FFL_NOSPAWN}, ! 46: {"activator", FOFS(activator), F_EDICT, FFL_NOSPAWN}, ! 47: {"groundentity", FOFS(groundentity), F_EDICT, FFL_NOSPAWN}, ! 48: {"teamchain", FOFS(teamchain), F_EDICT, FFL_NOSPAWN}, ! 49: {"teammaster", FOFS(teammaster), F_EDICT, FFL_NOSPAWN}, ! 50: {"owner", FOFS(owner), F_EDICT, FFL_NOSPAWN}, ! 51: {"mynoise", FOFS(mynoise), F_EDICT, FFL_NOSPAWN}, ! 52: {"mynoise2", FOFS(mynoise2), F_EDICT, FFL_NOSPAWN}, ! 53: {"target_ent", FOFS(target_ent), F_EDICT, FFL_NOSPAWN}, ! 54: {"chain", FOFS(chain), F_EDICT, FFL_NOSPAWN}, ! 55: ! 56: {"prethink", FOFS(prethink), F_FUNCTION, FFL_NOSPAWN}, ! 57: {"think", FOFS(think), F_FUNCTION, FFL_NOSPAWN}, ! 58: {"blocked", FOFS(blocked), F_FUNCTION, FFL_NOSPAWN}, ! 59: {"touch", FOFS(touch), F_FUNCTION, FFL_NOSPAWN}, ! 60: {"use", FOFS(use), F_FUNCTION, FFL_NOSPAWN}, ! 61: {"pain", FOFS(pain), F_FUNCTION, FFL_NOSPAWN}, ! 62: {"die", FOFS(die), F_FUNCTION, FFL_NOSPAWN}, ! 63: ! 64: {"stand", FOFS(monsterinfo.stand), F_FUNCTION, FFL_NOSPAWN}, ! 65: {"idle", FOFS(monsterinfo.idle), F_FUNCTION, FFL_NOSPAWN}, ! 66: {"search", FOFS(monsterinfo.search), F_FUNCTION, FFL_NOSPAWN}, ! 67: {"walk", FOFS(monsterinfo.walk), F_FUNCTION, FFL_NOSPAWN}, ! 68: {"run", FOFS(monsterinfo.run), F_FUNCTION, FFL_NOSPAWN}, ! 69: {"dodge", FOFS(monsterinfo.dodge), F_FUNCTION, FFL_NOSPAWN}, ! 70: {"attack", FOFS(monsterinfo.attack), F_FUNCTION, FFL_NOSPAWN}, ! 71: {"melee", FOFS(monsterinfo.melee), F_FUNCTION, FFL_NOSPAWN}, ! 72: {"sight", FOFS(monsterinfo.sight), F_FUNCTION, FFL_NOSPAWN}, ! 73: {"checkattack", FOFS(monsterinfo.checkattack), F_FUNCTION, FFL_NOSPAWN}, ! 74: {"currentmove", FOFS(monsterinfo.currentmove), F_MMOVE, FFL_NOSPAWN}, ! 75: ! 76: {"endfunc", FOFS(moveinfo.endfunc), F_FUNCTION, FFL_NOSPAWN}, ! 77: ! 78: // temp spawn vars -- only valid when the spawn function is called ! 79: {"lip", STOFS(lip), F_INT, FFL_SPAWNTEMP}, ! 80: {"distance", STOFS(distance), F_INT, FFL_SPAWNTEMP}, ! 81: {"height", STOFS(height), F_INT, FFL_SPAWNTEMP}, ! 82: {"noise", STOFS(noise), F_LSTRING, FFL_SPAWNTEMP}, ! 83: {"pausetime", STOFS(pausetime), F_FLOAT, FFL_SPAWNTEMP}, ! 84: {"item", STOFS(item), F_LSTRING, FFL_SPAWNTEMP}, ! 85: ! 86: //need for item field in edict struct, FFL_SPAWNTEMP item will be skipped on saves ! 87: {"item", FOFS(item), F_ITEM}, ! 88: ! 89: {"gravity", STOFS(gravity), F_LSTRING, FFL_SPAWNTEMP}, ! 90: {"sky", STOFS(sky), F_LSTRING, FFL_SPAWNTEMP}, ! 91: {"skyrotate", STOFS(skyrotate), F_FLOAT, FFL_SPAWNTEMP}, ! 92: {"skyaxis", STOFS(skyaxis), F_VECTOR, FFL_SPAWNTEMP}, ! 93: {"minyaw", STOFS(minyaw), F_FLOAT, FFL_SPAWNTEMP}, ! 94: {"maxyaw", STOFS(maxyaw), F_FLOAT, FFL_SPAWNTEMP}, ! 95: {"minpitch", STOFS(minpitch), F_FLOAT, FFL_SPAWNTEMP}, ! 96: {"maxpitch", STOFS(maxpitch), F_FLOAT, FFL_SPAWNTEMP}, ! 97: {"nextmap", STOFS(nextmap), F_LSTRING, FFL_SPAWNTEMP}, ! 98: ! 99: {0, 0, 0, 0} ! 100: ! 101: }; ! 102: ! 103: field_t levelfields[] = ! 104: { ! 105: {"changemap", LLOFS(changemap), F_LSTRING}, ! 106: ! 107: {"sight_client", LLOFS(sight_client), F_EDICT}, ! 108: {"sight_entity", LLOFS(sight_entity), F_EDICT}, ! 109: {"sound_entity", LLOFS(sound_entity), F_EDICT}, ! 110: {"sound2_entity", LLOFS(sound2_entity), F_EDICT}, ! 111: ! 112: {NULL, 0, F_INT} ! 113: }; ! 114: ! 115: field_t clientfields[] = ! 116: { ! 117: {"pers.weapon", CLOFS(pers.weapon), F_ITEM}, ! 118: {"pers.lastweapon", CLOFS(pers.lastweapon), F_ITEM}, ! 119: {"newweapon", CLOFS(newweapon), F_ITEM}, ! 120: ! 121: {NULL, 0, F_INT} ! 122: }; ! 123: ! 124: /* ! 125: ============ ! 126: InitGame ! 127: ! 128: This will be called when the dll is first loaded, which ! 129: only happens when a new game is started or a save game ! 130: is loaded. ! 131: ============ ! 132: */ ! 133: void InitGame (void) ! 134: { ! 135: gi.dprintf ("==== InitGame ====\n"); ! 136: ! 137: gun_x = gi.cvar ("gun_x", "0", 0); ! 138: gun_y = gi.cvar ("gun_y", "0", 0); ! 139: gun_z = gi.cvar ("gun_z", "0", 0); ! 140: ! 141: //FIXME: sv_ prefix is wrong for these ! 142: sv_rollspeed = gi.cvar ("sv_rollspeed", "200", 0); ! 143: sv_rollangle = gi.cvar ("sv_rollangle", "2", 0); ! 144: sv_maxvelocity = gi.cvar ("sv_maxvelocity", "2000", 0); ! 145: sv_gravity = gi.cvar ("sv_gravity", "800", 0); ! 146: ! 147: // noset vars ! 148: dedicated = gi.cvar ("dedicated", "0", CVAR_NOSET); ! 149: ! 150: // latched vars ! 151: sv_cheats = gi.cvar ("cheats", "0", CVAR_SERVERINFO|CVAR_LATCH); ! 152: gi.cvar ("gamename", GAMEVERSION , CVAR_SERVERINFO | CVAR_LATCH); ! 153: gi.cvar ("gamedate", __DATE__ , CVAR_SERVERINFO | CVAR_LATCH); ! 154: ! 155: maxclients = gi.cvar ("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH); ! 156: maxspectators = gi.cvar ("maxspectators", "4", CVAR_SERVERINFO); ! 157: deathmatch = gi.cvar ("deathmatch", "0", CVAR_LATCH); ! 158: coop = gi.cvar ("coop", "0", CVAR_LATCH); ! 159: skill = gi.cvar ("skill", "1", CVAR_LATCH); ! 160: maxentities = gi.cvar ("maxentities", "1024", CVAR_LATCH); ! 161: ! 162: // change anytime vars ! 163: dmflags = gi.cvar ("dmflags", "0", CVAR_SERVERINFO); ! 164: fraglimit = gi.cvar ("fraglimit", "0", CVAR_SERVERINFO); ! 165: timelimit = gi.cvar ("timelimit", "0", CVAR_SERVERINFO); ! 166: password = gi.cvar ("password", "", CVAR_USERINFO); ! 167: spectator_password = gi.cvar ("spectator_password", "", 0); ! 168: filterban = gi.cvar ("filterban", "1", 0); ! 169: ! 170: g_select_empty = gi.cvar ("g_select_empty", "0", CVAR_ARCHIVE); ! 171: ! 172: run_pitch = gi.cvar ("run_pitch", "0.002", 0); ! 173: run_roll = gi.cvar ("run_roll", "0.005", 0); ! 174: bob_up = gi.cvar ("bob_up", "0.005", 0); ! 175: bob_pitch = gi.cvar ("bob_pitch", "0.002", 0); ! 176: bob_roll = gi.cvar ("bob_roll", "0.002", 0); ! 177: ! 178: // flood control ! 179: flood_msgs = gi.cvar ("flood_msgs", "4", 0); ! 180: flood_persecond = gi.cvar ("flood_persecond", "4", 0); ! 181: flood_waitdelay = gi.cvar ("flood_waitdelay", "10", 0); ! 182: ! 183: // dm map list ! 184: sv_maplist = gi.cvar ("sv_maplist", "", 0); ! 185: ! 186: // items ! 187: InitItems (); ! 188: ! 189: Com_sprintf (game.helpmessage1, sizeof(game.helpmessage1), ""); ! 190: ! 191: Com_sprintf (game.helpmessage2, sizeof(game.helpmessage2), ""); ! 192: ! 193: // initialize all entities for this game ! 194: game.maxentities = maxentities->value; ! 195: g_edicts = gi.TagMalloc (game.maxentities * sizeof(g_edicts[0]), TAG_GAME); ! 196: globals.edicts = g_edicts; ! 197: globals.max_edicts = game.maxentities; ! 198: ! 199: // initialize all clients for this game ! 200: game.maxclients = maxclients->value; ! 201: game.clients = gi.TagMalloc (game.maxclients * sizeof(game.clients[0]), TAG_GAME); ! 202: globals.num_edicts = game.maxclients+1; ! 203: } ! 204: ! 205: //========================================================= ! 206: ! 207: void WriteField1 (FILE *f, field_t *field, byte *base) ! 208: { ! 209: void *p; ! 210: int len; ! 211: int index; ! 212: ! 213: if (field->flags & FFL_SPAWNTEMP) ! 214: return; ! 215: ! 216: p = (void *)(base + field->ofs); ! 217: switch (field->type) ! 218: { ! 219: case F_INT: ! 220: case F_FLOAT: ! 221: case F_ANGLEHACK: ! 222: case F_VECTOR: ! 223: case F_IGNORE: ! 224: break; ! 225: ! 226: case F_LSTRING: ! 227: case F_GSTRING: ! 228: if ( *(char **)p ) ! 229: len = strlen(*(char **)p) + 1; ! 230: else ! 231: len = 0; ! 232: *(int *)p = len; ! 233: break; ! 234: case F_EDICT: ! 235: if ( *(edict_t **)p == NULL) ! 236: index = -1; ! 237: else ! 238: index = *(edict_t **)p - g_edicts; ! 239: *(int *)p = index; ! 240: break; ! 241: case F_CLIENT: ! 242: if ( *(gclient_t **)p == NULL) ! 243: index = -1; ! 244: else ! 245: index = *(gclient_t **)p - game.clients; ! 246: *(int *)p = index; ! 247: break; ! 248: case F_ITEM: ! 249: if ( *(edict_t **)p == NULL) ! 250: index = -1; ! 251: else ! 252: index = *(gitem_t **)p - itemlist; ! 253: *(int *)p = index; ! 254: break; ! 255: ! 256: //relative to code segment ! 257: case F_FUNCTION: ! 258: if (*(byte **)p == NULL) ! 259: index = 0; ! 260: else ! 261: index = *(byte **)p - ((byte *)InitGame); ! 262: *(int *)p = index; ! 263: break; ! 264: ! 265: //relative to data segment ! 266: case F_MMOVE: ! 267: if (*(byte **)p == NULL) ! 268: index = 0; ! 269: else ! 270: index = *(byte **)p - (byte *)&mmove_reloc; ! 271: *(int *)p = index; ! 272: break; ! 273: ! 274: default: ! 275: gi.error ("WriteEdict: unknown field type"); ! 276: } ! 277: } ! 278: ! 279: ! 280: void WriteField2 (FILE *f, field_t *field, byte *base) ! 281: { ! 282: int len; ! 283: void *p; ! 284: ! 285: if (field->flags & FFL_SPAWNTEMP) ! 286: return; ! 287: ! 288: p = (void *)(base + field->ofs); ! 289: switch (field->type) ! 290: { ! 291: case F_LSTRING: ! 292: if ( *(char **)p ) ! 293: { ! 294: len = strlen(*(char **)p) + 1; ! 295: fwrite (*(char **)p, len, 1, f); ! 296: } ! 297: break; ! 298: } ! 299: } ! 300: ! 301: void ReadField (FILE *f, field_t *field, byte *base) ! 302: { ! 303: void *p; ! 304: int len; ! 305: int index; ! 306: ! 307: if (field->flags & FFL_SPAWNTEMP) ! 308: return; ! 309: ! 310: p = (void *)(base + field->ofs); ! 311: switch (field->type) ! 312: { ! 313: case F_INT: ! 314: case F_FLOAT: ! 315: case F_ANGLEHACK: ! 316: case F_VECTOR: ! 317: case F_IGNORE: ! 318: break; ! 319: ! 320: case F_LSTRING: ! 321: len = *(int *)p; ! 322: if (!len) ! 323: *(char **)p = NULL; ! 324: else ! 325: { ! 326: *(char **)p = gi.TagMalloc (len, TAG_LEVEL); ! 327: fread (*(char **)p, len, 1, f); ! 328: } ! 329: break; ! 330: case F_EDICT: ! 331: index = *(int *)p; ! 332: if ( index == -1 ) ! 333: *(edict_t **)p = NULL; ! 334: else ! 335: *(edict_t **)p = &g_edicts[index]; ! 336: break; ! 337: case F_CLIENT: ! 338: index = *(int *)p; ! 339: if ( index == -1 ) ! 340: *(gclient_t **)p = NULL; ! 341: else ! 342: *(gclient_t **)p = &game.clients[index]; ! 343: break; ! 344: case F_ITEM: ! 345: index = *(int *)p; ! 346: if ( index == -1 ) ! 347: *(gitem_t **)p = NULL; ! 348: else ! 349: *(gitem_t **)p = &itemlist[index]; ! 350: break; ! 351: ! 352: //relative to code segment ! 353: case F_FUNCTION: ! 354: index = *(int *)p; ! 355: if ( index == 0 ) ! 356: *(byte **)p = NULL; ! 357: else ! 358: *(byte **)p = ((byte *)InitGame) + index; ! 359: break; ! 360: ! 361: //relative to data segment ! 362: case F_MMOVE: ! 363: index = *(int *)p; ! 364: if (index == 0) ! 365: *(byte **)p = NULL; ! 366: else ! 367: *(byte **)p = (byte *)&mmove_reloc + index; ! 368: break; ! 369: ! 370: default: ! 371: gi.error ("ReadEdict: unknown field type"); ! 372: } ! 373: } ! 374: ! 375: //========================================================= ! 376: ! 377: /* ! 378: ============== ! 379: WriteClient ! 380: ! 381: All pointer variables (except function pointers) must be handled specially. ! 382: ============== ! 383: */ ! 384: void WriteClient (FILE *f, gclient_t *client) ! 385: { ! 386: field_t *field; ! 387: gclient_t temp; ! 388: ! 389: // all of the ints, floats, and vectors stay as they are ! 390: temp = *client; ! 391: ! 392: // change the pointers to lengths or indexes ! 393: for (field=clientfields ; field->name ; field++) ! 394: { ! 395: WriteField1 (f, field, (byte *)&temp); ! 396: } ! 397: ! 398: // write the block ! 399: fwrite (&temp, sizeof(temp), 1, f); ! 400: ! 401: // now write any allocated data following the edict ! 402: for (field=clientfields ; field->name ; field++) ! 403: { ! 404: WriteField2 (f, field, (byte *)client); ! 405: } ! 406: } ! 407: ! 408: /* ! 409: ============== ! 410: ReadClient ! 411: ! 412: All pointer variables (except function pointers) must be handled specially. ! 413: ============== ! 414: */ ! 415: void ReadClient (FILE *f, gclient_t *client) ! 416: { ! 417: field_t *field; ! 418: ! 419: fread (client, sizeof(*client), 1, f); ! 420: ! 421: for (field=clientfields ; field->name ; field++) ! 422: { ! 423: ReadField (f, field, (byte *)client); ! 424: } ! 425: } ! 426: ! 427: /* ! 428: ============ ! 429: WriteGame ! 430: ! 431: This will be called whenever the game goes to a new level, ! 432: and when the user explicitly saves the game. ! 433: ! 434: Game information include cross level data, like multi level ! 435: triggers, help computer info, and all client states. ! 436: ! 437: A single player death will automatically restore from the ! 438: last save position. ! 439: ============ ! 440: */ ! 441: void WriteGame (char *filename, qboolean autosave) ! 442: { ! 443: FILE *f; ! 444: int i; ! 445: char str[16]; ! 446: ! 447: if (!autosave) ! 448: SaveClientData (); ! 449: ! 450: f = fopen (filename, "wb"); ! 451: if (!f) ! 452: gi.error ("Couldn't open %s", filename); ! 453: ! 454: memset (str, 0, sizeof(str)); ! 455: strcpy (str, __DATE__); ! 456: fwrite (str, sizeof(str), 1, f); ! 457: ! 458: game.autosaved = autosave; ! 459: fwrite (&game, sizeof(game), 1, f); ! 460: game.autosaved = false; ! 461: ! 462: for (i=0 ; i<game.maxclients ; i++) ! 463: WriteClient (f, &game.clients[i]); ! 464: ! 465: fclose (f); ! 466: } ! 467: ! 468: void ReadGame (char *filename) ! 469: { ! 470: FILE *f; ! 471: int i; ! 472: char str[16]; ! 473: ! 474: gi.FreeTags (TAG_GAME); ! 475: ! 476: f = fopen (filename, "rb"); ! 477: if (!f) ! 478: gi.error ("Couldn't open %s", filename); ! 479: ! 480: fread (str, sizeof(str), 1, f); ! 481: if (strcmp (str, __DATE__)) ! 482: { ! 483: fclose (f); ! 484: gi.error ("Savegame from an older version.\n"); ! 485: } ! 486: ! 487: g_edicts = gi.TagMalloc (game.maxentities * sizeof(g_edicts[0]), TAG_GAME); ! 488: globals.edicts = g_edicts; ! 489: ! 490: fread (&game, sizeof(game), 1, f); ! 491: game.clients = gi.TagMalloc (game.maxclients * sizeof(game.clients[0]), TAG_GAME); ! 492: for (i=0 ; i<game.maxclients ; i++) ! 493: ReadClient (f, &game.clients[i]); ! 494: ! 495: fclose (f); ! 496: } ! 497: ! 498: //========================================================== ! 499: ! 500: ! 501: /* ! 502: ============== ! 503: WriteEdict ! 504: ! 505: All pointer variables (except function pointers) must be handled specially. ! 506: ============== ! 507: */ ! 508: void WriteEdict (FILE *f, edict_t *ent) ! 509: { ! 510: field_t *field; ! 511: edict_t temp; ! 512: ! 513: // all of the ints, floats, and vectors stay as they are ! 514: temp = *ent; ! 515: ! 516: // change the pointers to lengths or indexes ! 517: for (field=fields ; field->name ; field++) ! 518: { ! 519: WriteField1 (f, field, (byte *)&temp); ! 520: } ! 521: ! 522: // write the block ! 523: fwrite (&temp, sizeof(temp), 1, f); ! 524: ! 525: // now write any allocated data following the edict ! 526: for (field=fields ; field->name ; field++) ! 527: { ! 528: WriteField2 (f, field, (byte *)ent); ! 529: } ! 530: ! 531: } ! 532: ! 533: /* ! 534: ============== ! 535: WriteLevelLocals ! 536: ! 537: All pointer variables (except function pointers) must be handled specially. ! 538: ============== ! 539: */ ! 540: void WriteLevelLocals (FILE *f) ! 541: { ! 542: field_t *field; ! 543: level_locals_t temp; ! 544: ! 545: // all of the ints, floats, and vectors stay as they are ! 546: temp = level; ! 547: ! 548: // change the pointers to lengths or indexes ! 549: for (field=levelfields ; field->name ; field++) ! 550: { ! 551: WriteField1 (f, field, (byte *)&temp); ! 552: } ! 553: ! 554: // write the block ! 555: fwrite (&temp, sizeof(temp), 1, f); ! 556: ! 557: // now write any allocated data following the edict ! 558: for (field=levelfields ; field->name ; field++) ! 559: { ! 560: WriteField2 (f, field, (byte *)&level); ! 561: } ! 562: } ! 563: ! 564: ! 565: /* ! 566: ============== ! 567: ReadEdict ! 568: ! 569: All pointer variables (except function pointers) must be handled specially. ! 570: ============== ! 571: */ ! 572: void ReadEdict (FILE *f, edict_t *ent) ! 573: { ! 574: field_t *field; ! 575: ! 576: fread (ent, sizeof(*ent), 1, f); ! 577: ! 578: for (field=fields ; field->name ; field++) ! 579: { ! 580: ReadField (f, field, (byte *)ent); ! 581: } ! 582: } ! 583: ! 584: /* ! 585: ============== ! 586: ReadLevelLocals ! 587: ! 588: All pointer variables (except function pointers) must be handled specially. ! 589: ============== ! 590: */ ! 591: void ReadLevelLocals (FILE *f) ! 592: { ! 593: field_t *field; ! 594: ! 595: fread (&level, sizeof(level), 1, f); ! 596: ! 597: for (field=levelfields ; field->name ; field++) ! 598: { ! 599: ReadField (f, field, (byte *)&level); ! 600: } ! 601: } ! 602: ! 603: /* ! 604: ================= ! 605: WriteLevel ! 606: ! 607: ================= ! 608: */ ! 609: void WriteLevel (char *filename) ! 610: { ! 611: int i; ! 612: edict_t *ent; ! 613: FILE *f; ! 614: void *base; ! 615: ! 616: f = fopen (filename, "wb"); ! 617: if (!f) ! 618: gi.error ("Couldn't open %s", filename); ! 619: ! 620: // write out edict size for checking ! 621: i = sizeof(edict_t); ! 622: fwrite (&i, sizeof(i), 1, f); ! 623: ! 624: // write out a function pointer for checking ! 625: base = (void *)InitGame; ! 626: fwrite (&base, sizeof(base), 1, f); ! 627: ! 628: // write out level_locals_t ! 629: WriteLevelLocals (f); ! 630: ! 631: // write out all the entities ! 632: for (i=0 ; i<globals.num_edicts ; i++) ! 633: { ! 634: ent = &g_edicts[i]; ! 635: if (!ent->inuse) ! 636: continue; ! 637: fwrite (&i, sizeof(i), 1, f); ! 638: WriteEdict (f, ent); ! 639: } ! 640: i = -1; ! 641: fwrite (&i, sizeof(i), 1, f); ! 642: ! 643: fclose (f); ! 644: } ! 645: ! 646: ! 647: /* ! 648: ================= ! 649: ReadLevel ! 650: ! 651: SpawnEntities will allready have been called on the ! 652: level the same way it was when the level was saved. ! 653: ! 654: That is necessary to get the baselines ! 655: set up identically. ! 656: ! 657: The server will have cleared all of the world links before ! 658: calling ReadLevel. ! 659: ! 660: No clients are connected yet. ! 661: ================= ! 662: */ ! 663: void ReadLevel (char *filename) ! 664: { ! 665: int entnum; ! 666: FILE *f; ! 667: int i; ! 668: void *base; ! 669: edict_t *ent; ! 670: ! 671: f = fopen (filename, "rb"); ! 672: if (!f) ! 673: gi.error ("Couldn't open %s", filename); ! 674: ! 675: // free any dynamic memory allocated by loading the level ! 676: // base state ! 677: gi.FreeTags (TAG_LEVEL); ! 678: ! 679: // wipe all the entities ! 680: memset (g_edicts, 0, game.maxentities*sizeof(g_edicts[0])); ! 681: globals.num_edicts = maxclients->value+1; ! 682: ! 683: // check edict size ! 684: fread (&i, sizeof(i), 1, f); ! 685: if (i != sizeof(edict_t)) ! 686: { ! 687: fclose (f); ! 688: gi.error ("ReadLevel: mismatched edict size"); ! 689: } ! 690: ! 691: // check function pointer base address ! 692: fread (&base, sizeof(base), 1, f); ! 693: #ifdef _WIN32 ! 694: if (base != (void *)InitGame) ! 695: { ! 696: fclose (f); ! 697: gi.error ("ReadLevel: function pointers have moved"); ! 698: } ! 699: #else ! 700: gi.dprintf("Function offsets %d\n", ((byte *)base) - ((byte *)InitGame)); ! 701: #endif ! 702: ! 703: // load the level locals ! 704: ReadLevelLocals (f); ! 705: ! 706: // load all the entities ! 707: while (1) ! 708: { ! 709: if (fread (&entnum, sizeof(entnum), 1, f) != 1) ! 710: { ! 711: fclose (f); ! 712: gi.error ("ReadLevel: failed to read entnum"); ! 713: } ! 714: if (entnum == -1) ! 715: break; ! 716: if (entnum >= globals.num_edicts) ! 717: globals.num_edicts = entnum+1; ! 718: ! 719: ent = &g_edicts[entnum]; ! 720: ReadEdict (f, ent); ! 721: ! 722: // let the server rebuild world links for this ent ! 723: memset (&ent->area, 0, sizeof(ent->area)); ! 724: gi.linkentity (ent); ! 725: } ! 726: ! 727: fclose (f); ! 728: ! 729: // mark all clients as unconnected ! 730: for (i=0 ; i<maxclients->value ; i++) ! 731: { ! 732: ent = &g_edicts[i+1]; ! 733: ent->client = game.clients + i; ! 734: ent->client->pers.connected = false; ! 735: } ! 736: ! 737: // do any load time things at this point ! 738: for (i=0 ; i<globals.num_edicts ; i++) ! 739: { ! 740: ent = &g_edicts[i]; ! 741: ! 742: if (!ent->inuse) ! 743: continue; ! 744: ! 745: // fire any cross-level triggers ! 746: if (ent->classname) ! 747: if (strcmp(ent->classname, "target_crosslevel_target") == 0) ! 748: ent->nextthink = level.time + ent->delay; ! 749: } ! 750: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.