|
|
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: // ROGUE ! 100: {"bad_area", FOFS(bad_area), F_EDICT}, ! 101: // while the hint_path stuff could be reassembled on the fly, no reason to be different ! 102: {"hint_chain", FOFS(hint_chain), F_EDICT}, ! 103: {"monster_hint_chain", FOFS(monster_hint_chain), F_EDICT}, ! 104: {"target_hint_chain", FOFS(target_hint_chain), F_EDICT}, ! 105: // ! 106: {"goal_hint", FOFS(monsterinfo.goal_hint), F_EDICT}, ! 107: {"badMedic1", FOFS(monsterinfo.badMedic1), F_EDICT}, ! 108: {"badMedic2", FOFS(monsterinfo.badMedic2), F_EDICT}, ! 109: {"last_player_enemy", FOFS(monsterinfo.last_player_enemy), F_EDICT}, ! 110: {"commander", FOFS(monsterinfo.commander), F_EDICT}, ! 111: {"blocked", FOFS(monsterinfo.blocked), F_MMOVE, FFL_NOSPAWN}, ! 112: {"duck", FOFS(monsterinfo.duck), F_MMOVE, FFL_NOSPAWN}, ! 113: {"unduck", FOFS(monsterinfo.unduck), F_MMOVE, FFL_NOSPAWN}, ! 114: {"sidestep", FOFS(monsterinfo.sidestep), F_MMOVE, FFL_NOSPAWN}, ! 115: // ROGUE ! 116: ! 117: {0, 0, 0, 0} ! 118: ! 119: }; ! 120: ! 121: field_t levelfields[] = ! 122: { ! 123: {"changemap", LLOFS(changemap), F_LSTRING}, ! 124: ! 125: {"sight_client", LLOFS(sight_client), F_EDICT}, ! 126: {"sight_entity", LLOFS(sight_entity), F_EDICT}, ! 127: {"sound_entity", LLOFS(sound_entity), F_EDICT}, ! 128: {"sound2_entity", LLOFS(sound2_entity), F_EDICT}, ! 129: ! 130: // ROGUE ! 131: {"disguise_violator", LLOFS(disguise_violator), F_EDICT}, ! 132: // ROGUE ! 133: ! 134: {NULL, 0, F_INT} ! 135: }; ! 136: ! 137: field_t clientfields[] = ! 138: { ! 139: {"pers.weapon", CLOFS(pers.weapon), F_ITEM}, ! 140: {"pers.lastweapon", CLOFS(pers.lastweapon), F_ITEM}, ! 141: {"newweapon", CLOFS(newweapon), F_ITEM}, ! 142: // ROGUE ! 143: {"owned_sphere", CLOFS(owned_sphere), F_EDICT}, ! 144: // ROGUE ! 145: ! 146: {NULL, 0, F_INT} ! 147: }; ! 148: ! 149: /* ! 150: ============ ! 151: InitGame ! 152: ! 153: This will be called when the dll is first loaded, which ! 154: only happens when a new game is started or a save game ! 155: is loaded. ! 156: ============ ! 157: */ ! 158: void InitGame (void) ! 159: { ! 160: gi.dprintf ("==== InitGame ====\n"); ! 161: ! 162: gun_x = gi.cvar ("gun_x", "0", 0); ! 163: gun_y = gi.cvar ("gun_y", "0", 0); ! 164: gun_z = gi.cvar ("gun_z", "0", 0); ! 165: ! 166: //FIXME: sv_ prefix is wrong for these ! 167: sv_rollspeed = gi.cvar ("sv_rollspeed", "200", 0); ! 168: sv_rollangle = gi.cvar ("sv_rollangle", "2", 0); ! 169: sv_maxvelocity = gi.cvar ("sv_maxvelocity", "2000", 0); ! 170: sv_gravity = gi.cvar ("sv_gravity", "800", 0); ! 171: ! 172: sv_stopspeed = gi.cvar ("sv_stopspeed", "100", 0); // PGM - was #define in g_phys.c ! 173: ! 174: //ROGUE ! 175: g_showlogic = gi.cvar ("g_showlogic", "0", 0); ! 176: huntercam = gi.cvar ("huntercam", "1", CVAR_SERVERINFO|CVAR_LATCH); ! 177: randomrespawn = gi.cvar ("randomrespawn", "0", 0); ! 178: //ROGUE ! 179: ! 180: // noset vars ! 181: dedicated = gi.cvar ("dedicated", "0", CVAR_NOSET); ! 182: ! 183: // latched vars ! 184: sv_cheats = gi.cvar ("cheats", "0", CVAR_SERVERINFO|CVAR_LATCH); ! 185: gi.cvar ("gamename", GAMEVERSION , CVAR_SERVERINFO | CVAR_LATCH); ! 186: gi.cvar ("gamedate", __DATE__ , CVAR_SERVERINFO | CVAR_LATCH); ! 187: ! 188: maxclients = gi.cvar ("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH); ! 189: maxspectators = gi.cvar ("maxspectators", "4", CVAR_SERVERINFO); ! 190: deathmatch = gi.cvar ("deathmatch", "0", CVAR_LATCH); ! 191: coop = gi.cvar ("coop", "0", CVAR_LATCH); ! 192: skill = gi.cvar ("skill", "1", CVAR_LATCH); ! 193: maxentities = gi.cvar ("maxentities", "1024", CVAR_LATCH); ! 194: gamerules = gi.cvar ("gamerules", "0", CVAR_LATCH); //PGM ! 195: ! 196: // change anytime vars ! 197: dmflags = gi.cvar ("dmflags", "0", CVAR_SERVERINFO); ! 198: fraglimit = gi.cvar ("fraglimit", "0", CVAR_SERVERINFO); ! 199: timelimit = gi.cvar ("timelimit", "0", CVAR_SERVERINFO); ! 200: password = gi.cvar ("password", "", CVAR_USERINFO); ! 201: spectator_password = gi.cvar ("spectator_password", "", CVAR_USERINFO); ! 202: filterban = gi.cvar ("filterban", "1", 0); ! 203: ! 204: g_select_empty = gi.cvar ("g_select_empty", "0", CVAR_ARCHIVE); ! 205: ! 206: run_pitch = gi.cvar ("run_pitch", "0.002", 0); ! 207: run_roll = gi.cvar ("run_roll", "0.005", 0); ! 208: bob_up = gi.cvar ("bob_up", "0.005", 0); ! 209: bob_pitch = gi.cvar ("bob_pitch", "0.002", 0); ! 210: bob_roll = gi.cvar ("bob_roll", "0.002", 0); ! 211: ! 212: // flood control ! 213: flood_msgs = gi.cvar ("flood_msgs", "4", 0); ! 214: flood_persecond = gi.cvar ("flood_persecond", "4", 0); ! 215: flood_waitdelay = gi.cvar ("flood_waitdelay", "10", 0); ! 216: ! 217: // dm map list ! 218: sv_maplist = gi.cvar ("sv_maplist", "", 0); ! 219: ! 220: // items ! 221: InitItems (); ! 222: ! 223: Com_sprintf (game.helpmessage1, sizeof(game.helpmessage1), ""); ! 224: ! 225: Com_sprintf (game.helpmessage2, sizeof(game.helpmessage2), ""); ! 226: ! 227: // initialize all entities for this game ! 228: game.maxentities = maxentities->value; ! 229: g_edicts = gi.TagMalloc (game.maxentities * sizeof(g_edicts[0]), TAG_GAME); ! 230: globals.edicts = g_edicts; ! 231: globals.max_edicts = game.maxentities; ! 232: ! 233: // initialize all clients for this game ! 234: game.maxclients = maxclients->value; ! 235: game.clients = gi.TagMalloc (game.maxclients * sizeof(game.clients[0]), TAG_GAME); ! 236: globals.num_edicts = game.maxclients+1; ! 237: ! 238: //====== ! 239: //ROGUE ! 240: if(gamerules) ! 241: { ! 242: InitGameRules(); // if there are game rules to set up, do so now. ! 243: } ! 244: //ROGUE ! 245: //====== ! 246: } ! 247: ! 248: //========================================================= ! 249: ! 250: void WriteField1 (FILE *f, field_t *field, byte *base) ! 251: { ! 252: void *p; ! 253: int len; ! 254: int index; ! 255: ! 256: if (field->flags & FFL_SPAWNTEMP) ! 257: return; ! 258: ! 259: p = (void *)(base + field->ofs); ! 260: switch (field->type) ! 261: { ! 262: case F_INT: ! 263: case F_FLOAT: ! 264: case F_ANGLEHACK: ! 265: case F_VECTOR: ! 266: case F_IGNORE: ! 267: break; ! 268: ! 269: case F_LSTRING: ! 270: case F_GSTRING: ! 271: if ( *(char **)p ) ! 272: len = strlen(*(char **)p) + 1; ! 273: else ! 274: len = 0; ! 275: *(int *)p = len; ! 276: break; ! 277: case F_EDICT: ! 278: if ( *(edict_t **)p == NULL) ! 279: index = -1; ! 280: else ! 281: index = *(edict_t **)p - g_edicts; ! 282: *(int *)p = index; ! 283: break; ! 284: case F_CLIENT: ! 285: if ( *(gclient_t **)p == NULL) ! 286: index = -1; ! 287: else ! 288: index = *(gclient_t **)p - game.clients; ! 289: *(int *)p = index; ! 290: break; ! 291: case F_ITEM: ! 292: if ( *(edict_t **)p == NULL) ! 293: index = -1; ! 294: else ! 295: index = *(gitem_t **)p - itemlist; ! 296: *(int *)p = index; ! 297: break; ! 298: ! 299: //relative to code segment ! 300: case F_FUNCTION: ! 301: if (*(byte **)p == NULL) ! 302: index = 0; ! 303: else ! 304: index = *(byte **)p - ((byte *)InitGame); ! 305: *(int *)p = index; ! 306: break; ! 307: ! 308: //relative to data segment ! 309: case F_MMOVE: ! 310: if (*(byte **)p == NULL) ! 311: index = 0; ! 312: else ! 313: index = *(byte **)p - (byte *)&mmove_reloc; ! 314: *(int *)p = index; ! 315: break; ! 316: ! 317: default: ! 318: gi.error ("WriteEdict: unknown field type"); ! 319: } ! 320: } ! 321: ! 322: ! 323: void WriteField2 (FILE *f, field_t *field, byte *base) ! 324: { ! 325: int len; ! 326: void *p; ! 327: ! 328: if (field->flags & FFL_SPAWNTEMP) ! 329: return; ! 330: ! 331: p = (void *)(base + field->ofs); ! 332: switch (field->type) ! 333: { ! 334: case F_LSTRING: ! 335: if ( *(char **)p ) ! 336: { ! 337: len = strlen(*(char **)p) + 1; ! 338: fwrite (*(char **)p, len, 1, f); ! 339: } ! 340: break; ! 341: } ! 342: } ! 343: ! 344: void ReadField (FILE *f, field_t *field, byte *base) ! 345: { ! 346: void *p; ! 347: int len; ! 348: int index; ! 349: ! 350: if (field->flags & FFL_SPAWNTEMP) ! 351: return; ! 352: ! 353: p = (void *)(base + field->ofs); ! 354: switch (field->type) ! 355: { ! 356: case F_INT: ! 357: case F_FLOAT: ! 358: case F_ANGLEHACK: ! 359: case F_VECTOR: ! 360: case F_IGNORE: ! 361: break; ! 362: ! 363: case F_LSTRING: ! 364: len = *(int *)p; ! 365: if (!len) ! 366: *(char **)p = NULL; ! 367: else ! 368: { ! 369: *(char **)p = gi.TagMalloc (len, TAG_LEVEL); ! 370: fread (*(char **)p, len, 1, f); ! 371: } ! 372: break; ! 373: case F_EDICT: ! 374: index = *(int *)p; ! 375: if ( index == -1 ) ! 376: *(edict_t **)p = NULL; ! 377: else ! 378: *(edict_t **)p = &g_edicts[index]; ! 379: break; ! 380: case F_CLIENT: ! 381: index = *(int *)p; ! 382: if ( index == -1 ) ! 383: *(gclient_t **)p = NULL; ! 384: else ! 385: *(gclient_t **)p = &game.clients[index]; ! 386: break; ! 387: case F_ITEM: ! 388: index = *(int *)p; ! 389: if ( index == -1 ) ! 390: *(gitem_t **)p = NULL; ! 391: else ! 392: *(gitem_t **)p = &itemlist[index]; ! 393: break; ! 394: ! 395: //relative to code segment ! 396: case F_FUNCTION: ! 397: index = *(int *)p; ! 398: if ( index == 0 ) ! 399: *(byte **)p = NULL; ! 400: else ! 401: *(byte **)p = ((byte *)InitGame) + index; ! 402: break; ! 403: ! 404: //relative to data segment ! 405: case F_MMOVE: ! 406: index = *(int *)p; ! 407: if (index == 0) ! 408: *(byte **)p = NULL; ! 409: else ! 410: *(byte **)p = (byte *)&mmove_reloc + index; ! 411: break; ! 412: ! 413: default: ! 414: gi.error ("ReadEdict: unknown field type"); ! 415: } ! 416: } ! 417: ! 418: //========================================================= ! 419: ! 420: /* ! 421: ============== ! 422: WriteClient ! 423: ! 424: All pointer variables (except function pointers) must be handled specially. ! 425: ============== ! 426: */ ! 427: void WriteClient (FILE *f, gclient_t *client) ! 428: { ! 429: field_t *field; ! 430: gclient_t temp; ! 431: ! 432: // all of the ints, floats, and vectors stay as they are ! 433: temp = *client; ! 434: ! 435: // change the pointers to lengths or indexes ! 436: for (field=clientfields ; field->name ; field++) ! 437: { ! 438: WriteField1 (f, field, (byte *)&temp); ! 439: } ! 440: ! 441: // write the block ! 442: fwrite (&temp, sizeof(temp), 1, f); ! 443: ! 444: // now write any allocated data following the edict ! 445: for (field=clientfields ; field->name ; field++) ! 446: { ! 447: WriteField2 (f, field, (byte *)client); ! 448: } ! 449: } ! 450: ! 451: /* ! 452: ============== ! 453: ReadClient ! 454: ! 455: All pointer variables (except function pointers) must be handled specially. ! 456: ============== ! 457: */ ! 458: void ReadClient (FILE *f, gclient_t *client) ! 459: { ! 460: field_t *field; ! 461: ! 462: fread (client, sizeof(*client), 1, f); ! 463: ! 464: for (field=clientfields ; field->name ; field++) ! 465: { ! 466: ReadField (f, field, (byte *)client); ! 467: } ! 468: } ! 469: ! 470: /* ! 471: ============ ! 472: WriteGame ! 473: ! 474: This will be called whenever the game goes to a new level, ! 475: and when the user explicitly saves the game. ! 476: ! 477: Game information include cross level data, like multi level ! 478: triggers, help computer info, and all client states. ! 479: ! 480: A single player death will automatically restore from the ! 481: last save position. ! 482: ============ ! 483: */ ! 484: void WriteGame (char *filename, qboolean autosave) ! 485: { ! 486: FILE *f; ! 487: int i; ! 488: char str[16]; ! 489: ! 490: if (!autosave) ! 491: SaveClientData (); ! 492: ! 493: f = fopen (filename, "wb"); ! 494: if (!f) ! 495: gi.error ("Couldn't open %s", filename); ! 496: ! 497: memset (str, 0, sizeof(str)); ! 498: strcpy (str, __DATE__); ! 499: fwrite (str, sizeof(str), 1, f); ! 500: ! 501: game.autosaved = autosave; ! 502: fwrite (&game, sizeof(game), 1, f); ! 503: game.autosaved = false; ! 504: ! 505: for (i=0 ; i<game.maxclients ; i++) ! 506: WriteClient (f, &game.clients[i]); ! 507: ! 508: fclose (f); ! 509: } ! 510: ! 511: void ReadGame (char *filename) ! 512: { ! 513: FILE *f; ! 514: int i; ! 515: char str[16]; ! 516: ! 517: gi.FreeTags (TAG_GAME); ! 518: ! 519: f = fopen (filename, "rb"); ! 520: if (!f) ! 521: gi.error ("Couldn't open %s", filename); ! 522: ! 523: fread (str, sizeof(str), 1, f); ! 524: if (strcmp (str, __DATE__)) ! 525: { ! 526: fclose (f); ! 527: gi.error ("Savegame from an older version.\n"); ! 528: } ! 529: ! 530: g_edicts = gi.TagMalloc (game.maxentities * sizeof(g_edicts[0]), TAG_GAME); ! 531: globals.edicts = g_edicts; ! 532: ! 533: fread (&game, sizeof(game), 1, f); ! 534: game.clients = gi.TagMalloc (game.maxclients * sizeof(game.clients[0]), TAG_GAME); ! 535: for (i=0 ; i<game.maxclients ; i++) ! 536: ReadClient (f, &game.clients[i]); ! 537: ! 538: fclose (f); ! 539: } ! 540: ! 541: //========================================================== ! 542: ! 543: ! 544: /* ! 545: ============== ! 546: WriteEdict ! 547: ! 548: All pointer variables (except function pointers) must be handled specially. ! 549: ============== ! 550: */ ! 551: void WriteEdict (FILE *f, edict_t *ent) ! 552: { ! 553: field_t *field; ! 554: edict_t temp; ! 555: ! 556: // all of the ints, floats, and vectors stay as they are ! 557: temp = *ent; ! 558: ! 559: // change the pointers to lengths or indexes ! 560: for (field=fields ; field->name ; field++) ! 561: { ! 562: WriteField1 (f, field, (byte *)&temp); ! 563: } ! 564: ! 565: // write the block ! 566: fwrite (&temp, sizeof(temp), 1, f); ! 567: ! 568: // now write any allocated data following the edict ! 569: for (field=fields ; field->name ; field++) ! 570: { ! 571: WriteField2 (f, field, (byte *)ent); ! 572: } ! 573: ! 574: } ! 575: ! 576: /* ! 577: ============== ! 578: WriteLevelLocals ! 579: ! 580: All pointer variables (except function pointers) must be handled specially. ! 581: ============== ! 582: */ ! 583: void WriteLevelLocals (FILE *f) ! 584: { ! 585: field_t *field; ! 586: level_locals_t temp; ! 587: ! 588: // all of the ints, floats, and vectors stay as they are ! 589: temp = level; ! 590: ! 591: // change the pointers to lengths or indexes ! 592: for (field=levelfields ; field->name ; field++) ! 593: { ! 594: WriteField1 (f, field, (byte *)&temp); ! 595: } ! 596: ! 597: // write the block ! 598: fwrite (&temp, sizeof(temp), 1, f); ! 599: ! 600: // now write any allocated data following the edict ! 601: for (field=levelfields ; field->name ; field++) ! 602: { ! 603: WriteField2 (f, field, (byte *)&level); ! 604: } ! 605: } ! 606: ! 607: ! 608: /* ! 609: ============== ! 610: ReadEdict ! 611: ! 612: All pointer variables (except function pointers) must be handled specially. ! 613: ============== ! 614: */ ! 615: void ReadEdict (FILE *f, edict_t *ent) ! 616: { ! 617: field_t *field; ! 618: ! 619: fread (ent, sizeof(*ent), 1, f); ! 620: ! 621: for (field=fields ; field->name ; field++) ! 622: { ! 623: ReadField (f, field, (byte *)ent); ! 624: } ! 625: } ! 626: ! 627: /* ! 628: ============== ! 629: ReadLevelLocals ! 630: ! 631: All pointer variables (except function pointers) must be handled specially. ! 632: ============== ! 633: */ ! 634: void ReadLevelLocals (FILE *f) ! 635: { ! 636: field_t *field; ! 637: ! 638: fread (&level, sizeof(level), 1, f); ! 639: ! 640: for (field=levelfields ; field->name ; field++) ! 641: { ! 642: ReadField (f, field, (byte *)&level); ! 643: } ! 644: } ! 645: ! 646: /* ! 647: ================= ! 648: WriteLevel ! 649: ! 650: ================= ! 651: */ ! 652: void WriteLevel (char *filename) ! 653: { ! 654: int i; ! 655: edict_t *ent; ! 656: FILE *f; ! 657: void *base; ! 658: ! 659: f = fopen (filename, "wb"); ! 660: if (!f) ! 661: gi.error ("Couldn't open %s", filename); ! 662: ! 663: // write out edict size for checking ! 664: i = sizeof(edict_t); ! 665: fwrite (&i, sizeof(i), 1, f); ! 666: ! 667: // write out a function pointer for checking ! 668: base = (void *)InitGame; ! 669: fwrite (&base, sizeof(base), 1, f); ! 670: ! 671: // write out level_locals_t ! 672: WriteLevelLocals (f); ! 673: ! 674: // write out all the entities ! 675: for (i=0 ; i<globals.num_edicts ; i++) ! 676: { ! 677: ent = &g_edicts[i]; ! 678: if (!ent->inuse) ! 679: continue; ! 680: fwrite (&i, sizeof(i), 1, f); ! 681: WriteEdict (f, ent); ! 682: } ! 683: i = -1; ! 684: fwrite (&i, sizeof(i), 1, f); ! 685: ! 686: fclose (f); ! 687: } ! 688: ! 689: ! 690: /* ! 691: ================= ! 692: ReadLevel ! 693: ! 694: SpawnEntities will already have been called on the ! 695: level the same way it was when the level was saved. ! 696: ! 697: That is necessary to get the baselines ! 698: set up identically. ! 699: ! 700: The server will have cleared all of the world links before ! 701: calling ReadLevel. ! 702: ! 703: No clients are connected yet. ! 704: ================= ! 705: */ ! 706: void ReadLevel (char *filename) ! 707: { ! 708: int entnum; ! 709: FILE *f; ! 710: int i; ! 711: void *base; ! 712: edict_t *ent; ! 713: ! 714: f = fopen (filename, "rb"); ! 715: if (!f) ! 716: gi.error ("Couldn't open %s", filename); ! 717: ! 718: // free any dynamic memory allocated by loading the level ! 719: // base state ! 720: gi.FreeTags (TAG_LEVEL); ! 721: ! 722: // wipe all the entities ! 723: memset (g_edicts, 0, game.maxentities*sizeof(g_edicts[0])); ! 724: globals.num_edicts = maxclients->value+1; ! 725: ! 726: // check edict size ! 727: fread (&i, sizeof(i), 1, f); ! 728: if (i != sizeof(edict_t)) ! 729: { ! 730: fclose (f); ! 731: gi.error ("ReadLevel: mismatched edict size"); ! 732: } ! 733: ! 734: // check function pointer base address ! 735: fread (&base, sizeof(base), 1, f); ! 736: #ifdef _WIN32 ! 737: if (base != (void *)InitGame) ! 738: { ! 739: fclose (f); ! 740: gi.error ("ReadLevel: function pointers have moved"); ! 741: } ! 742: #else ! 743: gi.dprintf("Function offsets %d\n", ((byte *)base) - ((byte *)InitGame)); ! 744: #endif ! 745: ! 746: // load the level locals ! 747: ReadLevelLocals (f); ! 748: ! 749: // load all the entities ! 750: while (1) ! 751: { ! 752: if (fread (&entnum, sizeof(entnum), 1, f) != 1) ! 753: { ! 754: fclose (f); ! 755: gi.error ("ReadLevel: failed to read entnum"); ! 756: } ! 757: if (entnum == -1) ! 758: break; ! 759: if (entnum >= globals.num_edicts) ! 760: globals.num_edicts = entnum+1; ! 761: ! 762: ent = &g_edicts[entnum]; ! 763: ReadEdict (f, ent); ! 764: ! 765: // let the server rebuild world links for this ent ! 766: memset (&ent->area, 0, sizeof(ent->area)); ! 767: gi.linkentity (ent); ! 768: } ! 769: ! 770: fclose (f); ! 771: ! 772: // PMM - rebuild the hint path chains ! 773: // InitHintPaths(); ! 774: // pmm ! 775: ! 776: // mark all clients as unconnected ! 777: for (i=0 ; i<maxclients->value ; i++) ! 778: { ! 779: ent = &g_edicts[i+1]; ! 780: ent->client = game.clients + i; ! 781: ent->client->pers.connected = false; ! 782: } ! 783: ! 784: // do any load time things at this point ! 785: for (i=0 ; i<globals.num_edicts ; i++) ! 786: { ! 787: ent = &g_edicts[i]; ! 788: ! 789: if (!ent->inuse) ! 790: continue; ! 791: ! 792: // fire any cross-level triggers ! 793: if (ent->classname) ! 794: if (strcmp(ent->classname, "target_crosslevel_target") == 0) ! 795: ent->nextthink = level.time + ent->delay; ! 796: } ! 797: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.