#include <u.h>#include <libc.h>#include <stdio.h>#include "../dat.h"#include "../fns.h" #define Function(f) {#f, f} mmove_t mmove_reloc; field_t fields[] = { {"classname", FOFS(classname), F_LSTRING}, {"model", FOFS(model), F_LSTRING}, {"spawnflags", FOFS(spawnflags), F_INT}, {"speed", FOFS(speed), F_FLOAT}, {"accel", FOFS(accel), F_FLOAT}, {"decel", FOFS(decel), F_FLOAT}, {"target", FOFS(target), F_LSTRING}, {"targetname", FOFS(targetname), F_LSTRING}, {"pathtarget", FOFS(pathtarget), F_LSTRING}, {"deathtarget", FOFS(deathtarget), F_LSTRING}, {"killtarget", FOFS(killtarget), F_LSTRING}, {"combattarget", FOFS(combattarget), F_LSTRING}, {"message", FOFS(message), F_LSTRING}, {"team", FOFS(team), F_LSTRING}, {"wait", FOFS(wait), F_FLOAT}, {"delay", FOFS(delay), F_FLOAT}, {"random", FOFS(random), F_FLOAT}, {"move_origin", FOFS(move_origin), F_VECTOR}, {"move_angles", FOFS(move_angles), F_VECTOR}, {"style", FOFS(style), F_INT}, {"count", FOFS(count), F_INT}, {"health", FOFS(health), F_INT}, {"sounds", FOFS(sounds), F_INT}, {"light", 0, F_IGNORE}, {"dmg", FOFS(dmg), F_INT}, {"mass", FOFS(mass), F_INT}, {"volume", FOFS(volume), F_FLOAT}, {"attenuation", FOFS(attenuation), F_FLOAT}, {"map", FOFS(map), F_LSTRING}, {"origin", FOFS(s.origin), F_VECTOR}, {"angles", FOFS(s.angles), F_VECTOR}, {"angle", FOFS(s.angles), F_ANGLEHACK}, {"goalentity", FOFS(goalentity), F_EDICT, FFL_NOSPAWN}, {"movetarget", FOFS(movetarget), F_EDICT, FFL_NOSPAWN}, {"enemy", FOFS(enemy), F_EDICT, FFL_NOSPAWN}, {"oldenemy", FOFS(oldenemy), F_EDICT, FFL_NOSPAWN}, {"activator", FOFS(activator), F_EDICT, FFL_NOSPAWN}, {"groundentity", FOFS(groundentity), F_EDICT, FFL_NOSPAWN}, {"teamchain", FOFS(teamchain), F_EDICT, FFL_NOSPAWN}, {"teammaster", FOFS(teammaster), F_EDICT, FFL_NOSPAWN}, {"owner", FOFS(owner), F_EDICT, FFL_NOSPAWN}, {"mynoise", FOFS(mynoise), F_EDICT, FFL_NOSPAWN}, {"mynoise2", FOFS(mynoise2), F_EDICT, FFL_NOSPAWN}, {"target_ent", FOFS(target_ent), F_EDICT, FFL_NOSPAWN}, {"chain", FOFS(chain), F_EDICT, FFL_NOSPAWN}, {"prethink", FOFS(prethink), F_FUNCTION, FFL_NOSPAWN}, {"think", FOFS(think), F_FUNCTION, FFL_NOSPAWN}, {"blocked", FOFS(blocked), F_FUNCTION, FFL_NOSPAWN}, {"touch", FOFS(touch), F_FUNCTION, FFL_NOSPAWN}, {"use", FOFS(use), F_FUNCTION, FFL_NOSPAWN}, {"pain", FOFS(pain), F_FUNCTION, FFL_NOSPAWN}, {"die", FOFS(die), F_FUNCTION, FFL_NOSPAWN}, {"stand", FOFS(monsterinfo.stand), F_FUNCTION, FFL_NOSPAWN}, {"idle", FOFS(monsterinfo.idle), F_FUNCTION, FFL_NOSPAWN}, {"search", FOFS(monsterinfo.search), F_FUNCTION, FFL_NOSPAWN}, {"walk", FOFS(monsterinfo.walk), F_FUNCTION, FFL_NOSPAWN}, {"run", FOFS(monsterinfo.run), F_FUNCTION, FFL_NOSPAWN}, {"dodge", FOFS(monsterinfo.dodge), F_FUNCTION, FFL_NOSPAWN}, {"attack", FOFS(monsterinfo.attack), F_FUNCTION, FFL_NOSPAWN}, {"melee", FOFS(monsterinfo.melee), F_FUNCTION, FFL_NOSPAWN}, {"sight", FOFS(monsterinfo.sight), F_FUNCTION, FFL_NOSPAWN}, {"checkattack", FOFS(monsterinfo.checkattack), F_FUNCTION, FFL_NOSPAWN}, {"currentmove", FOFS(monsterinfo.currentmove), F_MMOVE, FFL_NOSPAWN}, {"endfunc", FOFS(moveinfo.endfunc), F_FUNCTION, FFL_NOSPAWN}, // temp spawn vars -- only valid when the spawn function is called {"lip", STOFS(lip), F_INT, FFL_SPAWNTEMP}, {"distance", STOFS(distance), F_INT, FFL_SPAWNTEMP}, {"height", STOFS(height), F_INT, FFL_SPAWNTEMP}, {"noise", STOFS(noise), F_LSTRING, FFL_SPAWNTEMP}, {"pausetime", STOFS(pausetime), F_FLOAT, FFL_SPAWNTEMP}, {"item", STOFS(item), F_LSTRING, FFL_SPAWNTEMP}, //need for item field in edict struct, FFL_SPAWNTEMP item will be skipped on saves {"item", FOFS(item), F_ITEM}, {"gravity", STOFS(gravity), F_LSTRING, FFL_SPAWNTEMP}, {"sky", STOFS(sky), F_LSTRING, FFL_SPAWNTEMP}, {"skyrotate", STOFS(skyrotate), F_FLOAT, FFL_SPAWNTEMP}, {"skyaxis", STOFS(skyaxis), F_VECTOR, FFL_SPAWNTEMP}, {"minyaw", STOFS(minyaw), F_FLOAT, FFL_SPAWNTEMP}, {"maxyaw", STOFS(maxyaw), F_FLOAT, FFL_SPAWNTEMP}, {"minpitch", STOFS(minpitch), F_FLOAT, FFL_SPAWNTEMP}, {"maxpitch", STOFS(maxpitch), F_FLOAT, FFL_SPAWNTEMP}, {"nextmap", STOFS(nextmap), F_LSTRING, FFL_SPAWNTEMP}, {0, 0, 0, 0} }; field_t levelfields[] ={ {"changemap", LLOFS(changemap), F_LSTRING}, {"sight_client", LLOFS(sight_client), F_EDICT}, {"sight_entity", LLOFS(sight_entity), F_EDICT}, {"sound_entity", LLOFS(sound_entity), F_EDICT}, {"sound2_entity", LLOFS(sound2_entity), F_EDICT}, {NULL, 0, F_INT}}; field_t clientfields[] ={ {"pers.weapon", CLOFS(pers.weapon), F_ITEM}, {"pers.lastweapon", CLOFS(pers.lastweapon), F_ITEM}, {"newweapon", CLOFS(newweapon), F_ITEM}, {NULL, 0, F_INT}}; /*============InitGame This will be called when the dll is first loaded, whichonly happens when a new game is started or a save gameis loaded.============*/void InitGame (void){ gi.dprintf ("==== InitGame ====\n"); gun_x = gi.cvar ("gun_x", "0", 0); gun_y = gi.cvar ("gun_y", "0", 0); gun_z = gi.cvar ("gun_z", "0", 0); //FIXME: sv_ prefix is wrong for these sv_rollspeed = gi.cvar ("sv_rollspeed", "200", 0); sv_rollangle = gi.cvar ("sv_rollangle", "2", 0); sv_maxvelocity = gi.cvar ("sv_maxvelocity", "2000", 0); sv_gravity = gi.cvar ("sv_gravity", "800", 0); // noset vars dedicated = gi.cvar ("dedicated", "0", CVAR_NOSET); // latched vars sv_cheats = gi.cvar ("cheats", "0", CVAR_SERVERINFO|CVAR_LATCH); gi.cvar ("gamename", GAMEVERSION , CVAR_SERVERINFO | CVAR_LATCH); gi.cvar ("gamedate", "Nov 30 1997" , CVAR_SERVERINFO | CVAR_LATCH); maxclients = gi.cvar ("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH); maxspectators = gi.cvar ("maxspectators", "4", CVAR_SERVERINFO); deathmatch = gi.cvar ("deathmatch", "0", CVAR_LATCH); coop = gi.cvar ("coop", "0", CVAR_LATCH); skill = gi.cvar ("skill", "1", CVAR_LATCH); maxentities = gi.cvar ("maxentities", "1024", CVAR_LATCH); // change anytime vars dmflags = gi.cvar ("dmflags", "0", CVAR_SERVERINFO); fraglimit = gi.cvar ("fraglimit", "0", CVAR_SERVERINFO); timelimit = gi.cvar ("timelimit", "0", CVAR_SERVERINFO); password = gi.cvar ("password", "", CVAR_USERINFO); spectator_password = gi.cvar ("spectator_password", "", CVAR_USERINFO); filterban = gi.cvar ("filterban", "1", 0); g_select_empty = gi.cvar ("g_select_empty", "0", CVAR_ARCHIVE); run_pitch = gi.cvar ("run_pitch", "0.002", 0); run_roll = gi.cvar ("run_roll", "0.005", 0); bob_up = gi.cvar ("bob_up", "0.005", 0); bob_pitch = gi.cvar ("bob_pitch", "0.002", 0); bob_roll = gi.cvar ("bob_roll", "0.002", 0); // flood control flood_msgs = gi.cvar ("flood_msgs", "4", 0); flood_persecond = gi.cvar ("flood_persecond", "4", 0); flood_waitdelay = gi.cvar ("flood_waitdelay", "10", 0); // dm map list sv_maplist = gi.cvar ("sv_maplist", "", 0); // items InitItems (); Com_sprintf (game.helpmessage1, sizeof(game.helpmessage1), ""); Com_sprintf (game.helpmessage2, sizeof(game.helpmessage2), ""); // initialize all entities for this game game.maxentities = maxentities->value; g_edicts = gi.TagMalloc (game.maxentities * sizeof(g_edicts[0]), TAG_GAME); globals.edicts = g_edicts; globals.max_edicts = game.maxentities; // initialize all clients for this game game.maxclients = maxclients->value; game.clients = gi.TagMalloc (game.maxclients * sizeof(game.clients[0]), TAG_GAME); globals.num_edicts = game.maxclients+1;} //========================================================= void WriteField1 (FILE *, field_t *field, byte *base){ void *p; int len; int index; if (field->flags & FFL_SPAWNTEMP) return; p = (void *)(base + field->ofs); switch (field->type) { case F_INT: case F_FLOAT: case F_ANGLEHACK: case F_VECTOR: case F_IGNORE: break; case F_LSTRING: case F_GSTRING: if ( *(char **)p ) len = strlen(*(char **)p) + 1; else len = 0; *(int *)p = len; break; case F_EDICT: if ( *(edict_t **)p == NULL) index = -1; else index = *(edict_t **)p - g_edicts; *(int *)p = index; break; case F_CLIENT: if ( *(gclient_t **)p == NULL) index = -1; else index = *(gclient_t **)p - game.clients; *(int *)p = index; break; case F_ITEM: if ( *(edict_t **)p == NULL) index = -1; else index = *(gitem_t **)p - itemlist; *(int *)p = index; break; //relative to code segment case F_FUNCTION: if (*(byte **)p == NULL) index = 0; else index = *(byte **)p - ((byte *)InitGame); *(int *)p = index; break; //relative to data segment case F_MMOVE: if (*(byte **)p == NULL) index = 0; else index = *(byte **)p - (byte *)&mmove_reloc; *(int *)p = index; break; default: gi.error ("WriteEdict: unknown field type"); }} void WriteField2 (FILE *f, field_t *field, byte *base){ int len; void *p; if (field->flags & FFL_SPAWNTEMP) return; p = (void *)(base + field->ofs); switch (field->type) { case F_LSTRING: if ( *(char **)p ) { len = strlen(*(char **)p) + 1; fwrite (*(char **)p, len, 1, f); } break; }} void ReadField (FILE *f, field_t *field, byte *base){ void *p; int len; int index; if (field->flags & FFL_SPAWNTEMP) return; p = (void *)(base + field->ofs); switch (field->type) { case F_INT: case F_FLOAT: case F_ANGLEHACK: case F_VECTOR: case F_IGNORE: break; case F_LSTRING: len = *(int *)p; if (!len) *(char **)p = NULL; else { *(char **)p = gi.TagMalloc (len, TAG_LEVEL); fread (*(char **)p, len, 1, f); } break; case F_EDICT: index = *(int *)p; if ( index == -1 ) *(edict_t **)p = NULL; else *(edict_t **)p = &g_edicts[index]; break; case F_CLIENT: index = *(int *)p; if ( index == -1 ) *(gclient_t **)p = NULL; else *(gclient_t **)p = &game.clients[index]; break; case F_ITEM: index = *(int *)p; if ( index == -1 ) *(gitem_t **)p = NULL; else *(gitem_t **)p = &itemlist[index]; break; //relative to code segment case F_FUNCTION: index = *(int *)p; if ( index == 0 ) *(byte **)p = NULL; else *(byte **)p = ((byte *)InitGame) + index; break; //relative to data segment case F_MMOVE: index = *(int *)p; if (index == 0) *(byte **)p = NULL; else *(byte **)p = (byte *)&mmove_reloc + index; break; default: gi.error ("ReadEdict: unknown field type"); }} //========================================================= /*==============WriteClient All pointer variables (except function pointers) must be handled specially.==============*/void WriteClient (FILE *f, gclient_t *client){ field_t *field; gclient_t temp; // all of the ints, floats, and vectors stay as they are temp = *client; // change the pointers to lengths or indexes for (field=clientfields ; field->name ; field++) { WriteField1 (f, field, (byte *)&temp); } // write the block fwrite (&temp, sizeof(temp), 1, f); // now write any allocated data following the edict for (field=clientfields ; field->name ; field++) { WriteField2 (f, field, (byte *)client); }} /*==============ReadClient All pointer variables (except function pointers) must be handled specially.==============*/void ReadClient (FILE *f, gclient_t *client){ field_t *field; fread (client, sizeof(*client), 1, f); for (field=clientfields ; field->name ; field++) { ReadField (f, field, (byte *)client); }} /*============WriteGame This will be called whenever the game goes to a new level,and when the user explicitly saves the game. Game information include cross level data, like multi leveltriggers, help computer info, and all client states. A single player death will automatically restore from thelast save position.============*/void WriteGame (char *filename, qboolean autosave){ FILE *f; int i; char str[16]; if (!autosave) SaveClientData (); f = fopen (filename, "wb"); if (!f) gi.error ("Couldn't open %s", filename); memset (str, 0, sizeof(str)); strcpy (str, "Nov 30 1997"); fwrite (str, sizeof(str), 1, f); game.autosaved = autosave; fwrite (&game, sizeof(game), 1, f); game.autosaved = false; for (i=0 ; i<game.maxclients ; i++) WriteClient (f, &game.clients[i]); fclose (f);} void ReadGame (char *filename){ FILE *f; int i; char str[16]; gi.FreeTags (TAG_GAME); f = fopen (filename, "rb"); if (!f) gi.error ("Couldn't open %s", filename); fread (str, sizeof(str), 1, f); if (strcmp (str, "Nov 30 1997")) { fclose (f); gi.error ("Savegame from an older version.\n"); } g_edicts = gi.TagMalloc (game.maxentities * sizeof(g_edicts[0]), TAG_GAME); globals.edicts = g_edicts; fread (&game, sizeof(game), 1, f); game.clients = gi.TagMalloc (game.maxclients * sizeof(game.clients[0]), TAG_GAME); for (i=0 ; i<game.maxclients ; i++) ReadClient (f, &game.clients[i]); fclose (f);} Lines 1–500 of 753. Load more
#include <u.h> #include <libc.h> #include <stdio.h> #include "../dat.h" #include "../fns.h" #define Function(f) {#f, f} mmove_t mmove_reloc; field_t fields[] = { {"classname", FOFS(classname), F_LSTRING}, {"model", FOFS(model), F_LSTRING}, {"spawnflags", FOFS(spawnflags), F_INT}, {"speed", FOFS(speed), F_FLOAT}, {"accel", FOFS(accel), F_FLOAT}, {"decel", FOFS(decel), F_FLOAT}, {"target", FOFS(target), F_LSTRING}, {"targetname", FOFS(targetname), F_LSTRING}, {"pathtarget", FOFS(pathtarget), F_LSTRING}, {"deathtarget", FOFS(deathtarget), F_LSTRING}, {"killtarget", FOFS(killtarget), F_LSTRING}, {"combattarget", FOFS(combattarget), F_LSTRING}, {"message", FOFS(message), F_LSTRING}, {"team", FOFS(team), F_LSTRING}, {"wait", FOFS(wait), F_FLOAT}, {"delay", FOFS(delay), F_FLOAT}, {"random", FOFS(random), F_FLOAT}, {"move_origin", FOFS(move_origin), F_VECTOR}, {"move_angles", FOFS(move_angles), F_VECTOR}, {"style", FOFS(style), F_INT}, {"count", FOFS(count), F_INT}, {"health", FOFS(health), F_INT}, {"sounds", FOFS(sounds), F_INT}, {"light", 0, F_IGNORE}, {"dmg", FOFS(dmg), F_INT}, {"mass", FOFS(mass), F_INT}, {"volume", FOFS(volume), F_FLOAT}, {"attenuation", FOFS(attenuation), F_FLOAT}, {"map", FOFS(map), F_LSTRING}, {"origin", FOFS(s.origin), F_VECTOR}, {"angles", FOFS(s.angles), F_VECTOR}, {"angle", FOFS(s.angles), F_ANGLEHACK}, {"goalentity", FOFS(goalentity), F_EDICT, FFL_NOSPAWN}, {"movetarget", FOFS(movetarget), F_EDICT, FFL_NOSPAWN}, {"enemy", FOFS(enemy), F_EDICT, FFL_NOSPAWN}, {"oldenemy", FOFS(oldenemy), F_EDICT, FFL_NOSPAWN}, {"activator", FOFS(activator), F_EDICT, FFL_NOSPAWN}, {"groundentity", FOFS(groundentity), F_EDICT, FFL_NOSPAWN}, {"teamchain", FOFS(teamchain), F_EDICT, FFL_NOSPAWN}, {"teammaster", FOFS(teammaster), F_EDICT, FFL_NOSPAWN}, {"owner", FOFS(owner), F_EDICT, FFL_NOSPAWN}, {"mynoise", FOFS(mynoise), F_EDICT, FFL_NOSPAWN}, {"mynoise2", FOFS(mynoise2), F_EDICT, FFL_NOSPAWN}, {"target_ent", FOFS(target_ent), F_EDICT, FFL_NOSPAWN}, {"chain", FOFS(chain), F_EDICT, FFL_NOSPAWN}, {"prethink", FOFS(prethink), F_FUNCTION, FFL_NOSPAWN}, {"think", FOFS(think), F_FUNCTION, FFL_NOSPAWN}, {"blocked", FOFS(blocked), F_FUNCTION, FFL_NOSPAWN}, {"touch", FOFS(touch), F_FUNCTION, FFL_NOSPAWN}, {"use", FOFS(use), F_FUNCTION, FFL_NOSPAWN}, {"pain", FOFS(pain), F_FUNCTION, FFL_NOSPAWN}, {"die", FOFS(die), F_FUNCTION, FFL_NOSPAWN}, {"stand", FOFS(monsterinfo.stand), F_FUNCTION, FFL_NOSPAWN}, {"idle", FOFS(monsterinfo.idle), F_FUNCTION, FFL_NOSPAWN}, {"search", FOFS(monsterinfo.search), F_FUNCTION, FFL_NOSPAWN}, {"walk", FOFS(monsterinfo.walk), F_FUNCTION, FFL_NOSPAWN}, {"run", FOFS(monsterinfo.run), F_FUNCTION, FFL_NOSPAWN}, {"dodge", FOFS(monsterinfo.dodge), F_FUNCTION, FFL_NOSPAWN}, {"attack", FOFS(monsterinfo.attack), F_FUNCTION, FFL_NOSPAWN}, {"melee", FOFS(monsterinfo.melee), F_FUNCTION, FFL_NOSPAWN}, {"sight", FOFS(monsterinfo.sight), F_FUNCTION, FFL_NOSPAWN}, {"checkattack", FOFS(monsterinfo.checkattack), F_FUNCTION, FFL_NOSPAWN}, {"currentmove", FOFS(monsterinfo.currentmove), F_MMOVE, FFL_NOSPAWN}, {"endfunc", FOFS(moveinfo.endfunc), F_FUNCTION, FFL_NOSPAWN}, // temp spawn vars -- only valid when the spawn function is called {"lip", STOFS(lip), F_INT, FFL_SPAWNTEMP}, {"distance", STOFS(distance), F_INT, FFL_SPAWNTEMP}, {"height", STOFS(height), F_INT, FFL_SPAWNTEMP}, {"noise", STOFS(noise), F_LSTRING, FFL_SPAWNTEMP}, {"pausetime", STOFS(pausetime), F_FLOAT, FFL_SPAWNTEMP}, {"item", STOFS(item), F_LSTRING, FFL_SPAWNTEMP}, //need for item field in edict struct, FFL_SPAWNTEMP item will be skipped on saves {"item", FOFS(item), F_ITEM}, {"gravity", STOFS(gravity), F_LSTRING, FFL_SPAWNTEMP}, {"sky", STOFS(sky), F_LSTRING, FFL_SPAWNTEMP}, {"skyrotate", STOFS(skyrotate), F_FLOAT, FFL_SPAWNTEMP}, {"skyaxis", STOFS(skyaxis), F_VECTOR, FFL_SPAWNTEMP}, {"minyaw", STOFS(minyaw), F_FLOAT, FFL_SPAWNTEMP}, {"maxyaw", STOFS(maxyaw), F_FLOAT, FFL_SPAWNTEMP}, {"minpitch", STOFS(minpitch), F_FLOAT, FFL_SPAWNTEMP}, {"maxpitch", STOFS(maxpitch), F_FLOAT, FFL_SPAWNTEMP}, {"nextmap", STOFS(nextmap), F_LSTRING, FFL_SPAWNTEMP}, {0, 0, 0, 0} }; field_t levelfields[] = { {"changemap", LLOFS(changemap), F_LSTRING}, {"sight_client", LLOFS(sight_client), F_EDICT}, {"sight_entity", LLOFS(sight_entity), F_EDICT}, {"sound_entity", LLOFS(sound_entity), F_EDICT}, {"sound2_entity", LLOFS(sound2_entity), F_EDICT}, {NULL, 0, F_INT} }; field_t clientfields[] = { {"pers.weapon", CLOFS(pers.weapon), F_ITEM}, {"pers.lastweapon", CLOFS(pers.lastweapon), F_ITEM}, {"newweapon", CLOFS(newweapon), F_ITEM}, {NULL, 0, F_INT} }; /* ============ InitGame This will be called when the dll is first loaded, which only happens when a new game is started or a save game is loaded. ============ */ void InitGame (void) { gi.dprintf ("==== InitGame ====\n"); gun_x = gi.cvar ("gun_x", "0", 0); gun_y = gi.cvar ("gun_y", "0", 0); gun_z = gi.cvar ("gun_z", "0", 0); //FIXME: sv_ prefix is wrong for these sv_rollspeed = gi.cvar ("sv_rollspeed", "200", 0); sv_rollangle = gi.cvar ("sv_rollangle", "2", 0); sv_maxvelocity = gi.cvar ("sv_maxvelocity", "2000", 0); sv_gravity = gi.cvar ("sv_gravity", "800", 0); // noset vars dedicated = gi.cvar ("dedicated", "0", CVAR_NOSET); // latched vars sv_cheats = gi.cvar ("cheats", "0", CVAR_SERVERINFO|CVAR_LATCH); gi.cvar ("gamename", GAMEVERSION , CVAR_SERVERINFO | CVAR_LATCH); gi.cvar ("gamedate", "Nov 30 1997" , CVAR_SERVERINFO | CVAR_LATCH); maxclients = gi.cvar ("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH); maxspectators = gi.cvar ("maxspectators", "4", CVAR_SERVERINFO); deathmatch = gi.cvar ("deathmatch", "0", CVAR_LATCH); coop = gi.cvar ("coop", "0", CVAR_LATCH); skill = gi.cvar ("skill", "1", CVAR_LATCH); maxentities = gi.cvar ("maxentities", "1024", CVAR_LATCH); // change anytime vars dmflags = gi.cvar ("dmflags", "0", CVAR_SERVERINFO); fraglimit = gi.cvar ("fraglimit", "0", CVAR_SERVERINFO); timelimit = gi.cvar ("timelimit", "0", CVAR_SERVERINFO); password = gi.cvar ("password", "", CVAR_USERINFO); spectator_password = gi.cvar ("spectator_password", "", CVAR_USERINFO); filterban = gi.cvar ("filterban", "1", 0); g_select_empty = gi.cvar ("g_select_empty", "0", CVAR_ARCHIVE); run_pitch = gi.cvar ("run_pitch", "0.002", 0); run_roll = gi.cvar ("run_roll", "0.005", 0); bob_up = gi.cvar ("bob_up", "0.005", 0); bob_pitch = gi.cvar ("bob_pitch", "0.002", 0); bob_roll = gi.cvar ("bob_roll", "0.002", 0); // flood control flood_msgs = gi.cvar ("flood_msgs", "4", 0); flood_persecond = gi.cvar ("flood_persecond", "4", 0); flood_waitdelay = gi.cvar ("flood_waitdelay", "10", 0); // dm map list sv_maplist = gi.cvar ("sv_maplist", "", 0); // items InitItems (); Com_sprintf (game.helpmessage1, sizeof(game.helpmessage1), ""); Com_sprintf (game.helpmessage2, sizeof(game.helpmessage2), ""); // initialize all entities for this game game.maxentities = maxentities->value; g_edicts = gi.TagMalloc (game.maxentities * sizeof(g_edicts[0]), TAG_GAME); globals.edicts = g_edicts; globals.max_edicts = game.maxentities; // initialize all clients for this game game.maxclients = maxclients->value; game.clients = gi.TagMalloc (game.maxclients * sizeof(game.clients[0]), TAG_GAME); globals.num_edicts = game.maxclients+1; } //========================================================= void WriteField1 (FILE *, field_t *field, byte *base) { void *p; int len; int index; if (field->flags & FFL_SPAWNTEMP) return; p = (void *)(base + field->ofs); switch (field->type) { case F_INT: case F_FLOAT: case F_ANGLEHACK: case F_VECTOR: case F_IGNORE: break; case F_LSTRING: case F_GSTRING: if ( *(char **)p ) len = strlen(*(char **)p) + 1; else len = 0; *(int *)p = len; break; case F_EDICT: if ( *(edict_t **)p == NULL) index = -1; else index = *(edict_t **)p - g_edicts; *(int *)p = index; break; case F_CLIENT: if ( *(gclient_t **)p == NULL) index = -1; else index = *(gclient_t **)p - game.clients; *(int *)p = index; break; case F_ITEM: if ( *(edict_t **)p == NULL) index = -1; else index = *(gitem_t **)p - itemlist; *(int *)p = index; break; //relative to code segment case F_FUNCTION: if (*(byte **)p == NULL) index = 0; else index = *(byte **)p - ((byte *)InitGame); *(int *)p = index; break; //relative to data segment case F_MMOVE: if (*(byte **)p == NULL) index = 0; else index = *(byte **)p - (byte *)&mmove_reloc; *(int *)p = index; break; default: gi.error ("WriteEdict: unknown field type"); } } void WriteField2 (FILE *f, field_t *field, byte *base) { int len; void *p; if (field->flags & FFL_SPAWNTEMP) return; p = (void *)(base + field->ofs); switch (field->type) { case F_LSTRING: if ( *(char **)p ) { len = strlen(*(char **)p) + 1; fwrite (*(char **)p, len, 1, f); } break; } } void ReadField (FILE *f, field_t *field, byte *base) { void *p; int len; int index; if (field->flags & FFL_SPAWNTEMP) return; p = (void *)(base + field->ofs); switch (field->type) { case F_INT: case F_FLOAT: case F_ANGLEHACK: case F_VECTOR: case F_IGNORE: break; case F_LSTRING: len = *(int *)p; if (!len) *(char **)p = NULL; else { *(char **)p = gi.TagMalloc (len, TAG_LEVEL); fread (*(char **)p, len, 1, f); } break; case F_EDICT: index = *(int *)p; if ( index == -1 ) *(edict_t **)p = NULL; else *(edict_t **)p = &g_edicts[index]; break; case F_CLIENT: index = *(int *)p; if ( index == -1 ) *(gclient_t **)p = NULL; else *(gclient_t **)p = &game.clients[index]; break; case F_ITEM: index = *(int *)p; if ( index == -1 ) *(gitem_t **)p = NULL; else *(gitem_t **)p = &itemlist[index]; break; //relative to code segment case F_FUNCTION: index = *(int *)p; if ( index == 0 ) *(byte **)p = NULL; else *(byte **)p = ((byte *)InitGame) + index; break; //relative to data segment case F_MMOVE: index = *(int *)p; if (index == 0) *(byte **)p = NULL; else *(byte **)p = (byte *)&mmove_reloc + index; break; default: gi.error ("ReadEdict: unknown field type"); } } //========================================================= /* ============== WriteClient All pointer variables (except function pointers) must be handled specially. ============== */ void WriteClient (FILE *f, gclient_t *client) { field_t *field; gclient_t temp; // all of the ints, floats, and vectors stay as they are temp = *client; // change the pointers to lengths or indexes for (field=clientfields ; field->name ; field++) { WriteField1 (f, field, (byte *)&temp); } // write the block fwrite (&temp, sizeof(temp), 1, f); // now write any allocated data following the edict for (field=clientfields ; field->name ; field++) { WriteField2 (f, field, (byte *)client); } } /* ============== ReadClient All pointer variables (except function pointers) must be handled specially. ============== */ void ReadClient (FILE *f, gclient_t *client) { field_t *field; fread (client, sizeof(*client), 1, f); for (field=clientfields ; field->name ; field++) { ReadField (f, field, (byte *)client); } } /* ============ WriteGame This will be called whenever the game goes to a new level, and when the user explicitly saves the game. Game information include cross level data, like multi level triggers, help computer info, and all client states. A single player death will automatically restore from the last save position. ============ */ void WriteGame (char *filename, qboolean autosave) { FILE *f; int i; char str[16]; if (!autosave) SaveClientData (); f = fopen (filename, "wb"); if (!f) gi.error ("Couldn't open %s", filename); memset (str, 0, sizeof(str)); strcpy (str, "Nov 30 1997"); fwrite (str, sizeof(str), 1, f); game.autosaved = autosave; fwrite (&game, sizeof(game), 1, f); game.autosaved = false; for (i=0 ; i<game.maxclients ; i++) WriteClient (f, &game.clients[i]); fclose (f); } void ReadGame (char *filename) { FILE *f; int i; char str[16]; gi.FreeTags (TAG_GAME); f = fopen (filename, "rb"); if (!f) gi.error ("Couldn't open %s", filename); fread (str, sizeof(str), 1, f); if (strcmp (str, "Nov 30 1997")) { fclose (f); gi.error ("Savegame from an older version.\n"); } g_edicts = gi.TagMalloc (game.maxentities * sizeof(g_edicts[0]), TAG_GAME); globals.edicts = g_edicts; fread (&game, sizeof(game), 1, f); game.clients = gi.TagMalloc (game.maxclients * sizeof(game.clients[0]), TAG_GAME); for (i=0 ; i<game.maxclients ; i++) ReadClient (f, &game.clients[i]); fclose (f); }