Annotation of quake2/game/g_save.c, revision 1.1.1.4

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.