/* G_game.c */ #include #include #include "doomdef.h" #include "p_local.h" #include "soundst.h" #ifdef GL_HERETIC #include "gl_struct.h" #endif #ifdef GL_HERETIC boolean g_bMlook=FALSE; /* to be looked into later */ long g_bMD2=0; #endif /* Macros */ #define SVG_RAM 0 #define SVG_FILE 1 #define SAVE_GAME_TERMINATOR 0x1d #define AM_STARTKEY 9 /* Functions */ boolean G_CheckDemoStatus (void); void G_ReadDemoTiccmd (ticcmd_t *cmd); void G_WriteDemoTiccmd (ticcmd_t *cmd); void G_PlayerReborn (int player); void G_InitNew (skill_t skill, int episode, int map); void G_DoReborn (int playernum); void G_DoLoadLevel (void); void G_DoNewGame (void); void G_DoLoadGame (void); void G_DoPlayDemo (void); void G_DoCompleted (void); void G_DoVictory (void); void G_DoWorldDone (void); void G_DoSaveGame (void); void D_PageTicker(void); void D_AdvanceDemo(void); struct { mobjtype_t type; int speed[2]; } MonsterMissileInfo[] = { { MT_IMPBALL, {10, 20} }, { MT_MUMMYFX1, {9, 18} }, { MT_KNIGHTAXE, {9, 18} }, { MT_REDAXE, {9, 18} }, { MT_BEASTBALL, {12, 20} }, { MT_WIZFX1, {18, 24} }, { MT_SNAKEPRO_A, {14, 20} }, { MT_SNAKEPRO_B, {14, 20} }, { MT_HEADFX1, {13, 20} }, { MT_HEADFX3, {10, 18} }, { MT_MNTRFX1, {20, 26} }, { MT_MNTRFX2, {14, 20} }, { MT_SRCRFX1, {20, 28} }, { MT_SOR2FX1, {20, 28} }, { -1, {-1, -1} } /* Terminator */ }; FILE *SaveGameFP; int SaveGameType; gameaction_t gameaction; gamestate_t gamestate; skill_t gameskill; boolean respawnmonsters; int gameepisode; int gamemap; int prevmap; boolean paused; boolean sendpause; /* send a pause event next tic */ boolean sendsave; /* send a save event next tic */ boolean usergame; /* ok to save / end game */ boolean timingdemo; /* if true, exit with report on completion */ int starttime; /* for comparative timing purposes */ boolean viewactive; boolean deathmatch; /* only if started as net death */ boolean netgame; /* only true if packets are broadcast */ boolean playeringame[MAXPLAYERS]; player_t players[MAXPLAYERS]; int consoleplayer; /* player taking events and displaying */ int displayplayer; /* view being displayed */ int gametic; int levelstarttic; /* gametic at level start */ int totalkills, totalitems, totalsecret; /* for intermission */ char demoname[32]; boolean demorecording; boolean demoplayback; byte *demobuffer, *demo_p; boolean singledemo; /* quit after playing a demo from cmdline */ boolean precache = true; /* if true, load all graphics at start */ short consistancy[MAXPLAYERS][BACKUPTICS]; byte *savebuffer, *save_p; extern char* homedir; /* * controls (have defaults) */ long key_right, key_left, key_up, key_down; long key_strafeleft, key_straferight; long key_fire, key_use, key_strafe, key_speed; long key_flyup, key_flydown, key_flycenter; long key_lookup, key_lookdown, key_lookcenter; long key_invleft, key_invright, key_useartifact; long mousebfire; long mousebstrafe; long mousebforward; long invertmouse; long joybfire; long joybstrafe; long joybuse; long joybspeed; #define MAXPLMOVE 0x32 fixed_t forwardmove[2] = {0x19, 0x32}; fixed_t sidemove[2] = {0x18, 0x28}; fixed_t angleturn[3] = {640, 1280, 320}; /* + slow turn */ #define SLOWTURNTICS 6 #define NUMKEYS 256 boolean gamekeydown[NUMKEYS]; int turnheld; /* for accelerative turning */ int lookheld; boolean mousearray[4]; boolean *mousebuttons = &mousearray[1]; /* allow [-1] */ int mousex, mousey; /* mouse values are used once */ int dclicktime, dclickstate, dclicks; int dclicktime2, dclickstate2, dclicks2; int joyxmove, joyymove; /* joystick values are repeated */ boolean joyarray[5]; boolean *joybuttons = &joyarray[1]; /* allow [-1] */ int savegameslot; char savedescription[32]; int inventoryTics; /* ============================================================================= * Not used - ripped out for Heretic */ /* int G_CmdChecksum(ticcmd_t *cmd) { int i; int sum; sum = 0; for(i = 0; i < sizeof(*cmd)/4-1; i++) { sum += ((int *)cmd)[i]; } return(sum); } */ /* ==================== = = G_BuildTiccmd = = Builds a ticcmd from all of the available inputs or reads it from the = demo buffer. = If recording a demo, write it out ==================== */ extern boolean inventory; extern int curpos; extern int inv_ptr; boolean usearti = true; void G_BuildTiccmd (ticcmd_t *cmd) { int i; boolean strafe, bstrafe; int speed, tspeed, lspeed; int forward, side; int look, arti; int flyheight; extern boolean noartiskip; memset (cmd,0,sizeof(*cmd)); /* * cmd->consistancy = * consistancy[consoleplayer][(maketic*ticdup)%BACKUPTICS]; */ cmd->consistancy = consistancy[consoleplayer][maketic%BACKUPTICS]; /* printf ("cons: %i\n",cmd->consistancy); */ strafe = gamekeydown[key_strafe] || mousebuttons[mousebstrafe] || joybuttons[joybstrafe]; speed = gamekeydown[key_speed] || joybuttons[joybspeed] || joybuttons[joybspeed]; forward = side = look = arti = flyheight = 0; /* * use two stage accelerative turning on the keyboard and joystick */ if (joyxmove < 0 || joyxmove > 0 || gamekeydown[key_right] || gamekeydown[key_left]) turnheld += ticdup; else turnheld = 0; if (turnheld < SLOWTURNTICS) tspeed = 2; /* slow turn */ else tspeed = speed; if(gamekeydown[key_lookdown] || gamekeydown[key_lookup]) { lookheld += ticdup; } else { lookheld = 0; } if(lookheld < SLOWTURNTICS) { lspeed = 1; } else { lspeed = 2; } /* * let movement keys cancel each other out */ if(strafe) { if (gamekeydown[key_right]) side += sidemove[speed]; if (gamekeydown[key_left]) side -= sidemove[speed]; if (joyxmove > 0) side += sidemove[speed]; if (joyxmove < 0) side -= sidemove[speed]; } else { if (gamekeydown[key_right]) cmd->angleturn -= angleturn[tspeed]; if (gamekeydown[key_left]) cmd->angleturn += angleturn[tspeed]; if (joyxmove > 0) cmd->angleturn -= angleturn[tspeed]; if (joyxmove < 0) cmd->angleturn += angleturn[tspeed]; } if (gamekeydown[key_up]) forward += forwardmove[speed]; if (gamekeydown[key_down]) forward -= forwardmove[speed]; if (joyymove < 0) forward += forwardmove[speed]; if (joyymove > 0) forward -= forwardmove[speed]; if (gamekeydown[key_straferight]) side += sidemove[speed]; if (gamekeydown[key_strafeleft]) side -= sidemove[speed]; /* Look up/down/center keys */ if(gamekeydown[key_lookup]) { look = lspeed; } if(gamekeydown[key_lookdown]) { look = -lspeed; } if(gamekeydown[key_lookcenter]) { look = TOCENTER; } /* Fly up/down/drop keys */ if(gamekeydown[key_flyup]) { flyheight = 5; /* note that the actual flyheight will be twice this */ } if(gamekeydown[key_flydown]) { flyheight = -5; } if(gamekeydown[key_flycenter]) { flyheight = TOCENTER; look = TOCENTER; } /* Use artifact key */ if(gamekeydown[key_useartifact]) { if(gamekeydown[key_speed] && !noartiskip) { if(players[consoleplayer].inventory[inv_ptr].type != arti_none) { gamekeydown[key_useartifact] = false; cmd->arti = 0xff; /* skip artifact code */ } } else { if(inventory) { players[consoleplayer].readyArtifact = players[consoleplayer].inventory[inv_ptr].type; inventory = false; cmd->arti = 0; usearti = false; } else if(usearti) { cmd->arti = players[consoleplayer].inventory[inv_ptr].type; usearti = false; } } } if(gamekeydown[127] && !cmd->arti && !players[consoleplayer].powers[pw_weaponlevel2]) { gamekeydown[127] = false; cmd->arti = arti_tomeofpower; } /* * buttons */ cmd->chatchar = CT_dequeueChatChar(); if (gamekeydown[key_fire] || mousebuttons[mousebfire] || joybuttons[joybfire]) cmd->buttons |= BT_ATTACK; if (gamekeydown[key_use] || joybuttons[joybuse] ) { cmd->buttons |= BT_USE; dclicks = 0; /* clear double clicks if hit use button */ } for(i = 0; i < NUMWEAPONS-2; i++) { if(gamekeydown['1'+i]) { cmd->buttons |= BT_CHANGE; cmd->buttons |= i< 1 ) { dclickstate = mousebuttons[mousebforward]; if (dclickstate) dclicks++; if (dclicks == 2) { cmd->buttons |= BT_USE; dclicks = 0; } else dclicktime = 0; } else { dclicktime += ticdup; if (dclicktime > 20) { dclicks = 0; dclickstate = 0; } } /* * strafe double click */ bstrafe = mousebuttons[mousebstrafe] || joybuttons[joybstrafe]; if (bstrafe != dclickstate2 && dclicktime2 > 1 ) { dclickstate2 = bstrafe; if (dclickstate2) dclicks2++; if (dclicks2 == 2) { cmd->buttons |= BT_USE; dclicks2 = 0; } else dclicktime2 = 0; } else { dclicktime2 += ticdup; if (dclicktime2 > 20) { dclicks2 = 0; dclickstate2 = 0; } } if (strafe) { side += mousex*2; } else { cmd->angleturn -= mousex*0x8; } /* rhandeev: added mouse invert option */ if (mouseInvert == true) mousey = -mousey; #ifndef GL_HERETIC /* rhandeev: added mouse look option */ if (mouseLook == true) { static int mouse_sum = 0; mouse_sum += mousey; if (abs(mouse_sum) > 10) { look += mouse_sum / 10; mouse_sum %= 10; } } else #endif #ifdef GL_HERETIC /* Mlook */ if (g_bMlook) { player_t *player; /* lmousey+=mousey; */ player = &players[consoleplayer]; if (!invertmouse) player->lookdir +=(int)((float)mousey/10.0f); else player->lookdir -=(int)((float)mousey/10.0f); if(player->lookdir > 90) player->lookdir=90; if(player->lookdir < -110) player->lookdir=-110; /* look+=(int)((float)mousey/1.0f); */ } else #endif { forward += mousey; } mousex = mousey = 0; if (forward > MAXPLMOVE) forward = MAXPLMOVE; else if (forward < -MAXPLMOVE) forward = -MAXPLMOVE; if (side > MAXPLMOVE) side = MAXPLMOVE; else if (side < -MAXPLMOVE) side = -MAXPLMOVE; cmd->forwardmove += forward; cmd->sidemove += side; if(players[consoleplayer].playerstate == PST_LIVE) { if(look < 0) { look += 16; } cmd->lookfly = look; } if(flyheight < 0) { flyheight += 16; } cmd->lookfly |= flyheight<<4; /* * special buttons */ if (sendpause) { sendpause = false; cmd->buttons = BT_SPECIAL | BTS_PAUSE; } if (sendsave) { sendsave = false; cmd->buttons = BT_SPECIAL | BTS_SAVEGAME | (savegameslot<type == ev_keyup && ev->data1 == key_useartifact) { /* flag to denote that it's okay to use an artifact */ if(!inventory) { plr->readyArtifact = plr->inventory[inv_ptr].type; } usearti = true; } /* Check for spy mode player cycle */ if(gamestate == GS_LEVEL && ev->type == ev_keydown && ev->data1 == KEY_F12 && !deathmatch) { /* Cycle the display player */ do { displayplayer++; if(displayplayer == MAXPLAYERS) { displayplayer = 0; } } while(!playeringame[displayplayer] && displayplayer != consoleplayer); return(true); } if(gamestate == GS_LEVEL) { if(CT_Responder(ev)) { /* Chat ate the event */ return(true); } if(SB_Responder(ev)) { /* Status bar ate the event */ return(true); } if(AM_Responder(ev)) { /* Automap ate the event */ return(true); } } switch(ev->type) { case ev_keydown: if(ev->data1 == key_invleft) { inventoryTics = 5*35; if(!inventory) { inventory = true; break; } inv_ptr--; if(inv_ptr < 0) { inv_ptr = 0; } else { curpos--; if(curpos < 0) { curpos = 0; } } return(true); } if(ev->data1 == key_invright) { inventoryTics = 5*35; if(!inventory) { inventory = true; break; } inv_ptr++; if(inv_ptr >= plr->inventorySlotNum) { inv_ptr--; if(inv_ptr < 0) inv_ptr = 0; } else { curpos++; if(curpos > 6) { curpos = 6; } } return(true); } if(ev->data1 == KEY_PAUSE && !MenuActive) { sendpause = true; return(true); } if(ev->data1 < NUMKEYS) { gamekeydown[ev->data1] = true; } return(true); /* eat key down events */ case ev_keyup: if(ev->data1 < NUMKEYS) { gamekeydown[ev->data1] = false; } return(false); /* always let key up events filter down */ case ev_mouse: mousebuttons[0] = ev->data1&1; mousebuttons[1] = ev->data1&2; mousebuttons[2] = ev->data1&4; mousex = ev->data2*mouseXSensitivity/10; mousey = ev->data3*mouseYSensitivity/10; return(true); /* eat events */ case ev_joystick: joybuttons[0] = ev->data1&1; joybuttons[1] = ev->data1&2; joybuttons[2] = ev->data1&4; joybuttons[3] = ev->data1&8; joyxmove = ev->data2; joyymove = ev->data3; return(true); /* eat events */ default: break; } return(false); } /* =============================================================================== = = G_Ticker = =============================================================================== */ void G_Ticker (void) { int i, buf; /* changed from ticcmd_t *cmd */ ticcmd_t *cmd=NULL; /* * do player reborns if needed */ for (i=0 ; i BACKUPTICS && consistancy[i][buf] != cmd->consistancy) { I_Error ("consistency failure (%i should be %i)",cmd->consistancy, consistancy[i][buf]); } if (players[i].mo) consistancy[i][buf] = players[i].mo->x; else consistancy[i][buf] = rndindex; } } /* * check for special buttons */ for (i=0 ; i>BTS_SAVESHIFT; gameaction = ga_savegame; break; } } } /* turn inventory off after a certain amount of time */ if(inventory && !(--inventoryTics)) { players[consoleplayer].readyArtifact = players[consoleplayer].inventory[inv_ptr].type; inventory = false; cmd->arti = 0; } /* * do main actions * * * do main actions */ switch (gamestate) { case GS_LEVEL: P_Ticker (); SB_Ticker (); AM_Ticker (); CT_Ticker(); break; case GS_INTERMISSION: IN_Ticker (); break; case GS_FINALE: F_Ticker(); break; case GS_DEMOSCREEN: D_PageTicker (); break; } } /* ============================================================================== PLAYER STRUCTURE FUNCTIONS also see P_SpawnPlayer in P_Things ============================================================================== */ /* ==================== = = G_InitPlayer = = Called at the start = Called by the game initialization functions ==================== */ void G_InitPlayer (int player) { player_t *p; /* set up the saved info */ p = &players[player]; /* clear everything else to defaults */ G_PlayerReborn (player); } /* ==================== = = G_PlayerFinishLevel = = Can when a player completes a level ==================== */ extern int curpos; extern int inv_ptr; extern int playerkeys; void G_PlayerFinishLevel(int player) { player_t *p; int i; /* // BIG HACK inv_ptr = 0; curpos = 0; */ /* END HACK */ p = &players[player]; for(i=0; iinventorySlotNum; i++) { p->inventory[i].count = 1; } p->artifactCount = p->inventorySlotNum; if(!deathmatch) { for(i = 0; i < 16; i++) { P_PlayerUseArtifact(p, arti_fly); } } memset(p->powers, 0, sizeof(p->powers)); memset(p->keys, 0, sizeof(p->keys)); playerkeys = 0; /* memset(p->inventory, 0, sizeof(p->inventory)); */ if(p->chickenTics) { p->readyweapon = p->mo->special1; /* Restore weapon */ p->chickenTics = 0; } p->messageTics = 0; p->lookdir = 0; p->mo->flags &= ~MF_SHADOW; /* Remove invisibility */ p->extralight = 0; /* Remove weapon flashes */ p->fixedcolormap = 0; /* Remove torch */ p->damagecount = 0; /* No palette changes */ p->bonuscount = 0; p->rain1 = NULL; p->rain2 = NULL; if(p == &players[consoleplayer]) { SB_state = -1; /* refresh the status bar */ } } /* ==================== = = G_PlayerReborn = = Called after a player dies = almost everything is cleared and initialized ==================== */ void G_PlayerReborn(int player) { player_t *p; int i,j; int frags[MAXPLAYERS]; int killcount, itemcount, secretcount; boolean secret; secret = false; for(j=0;jdidsecret) { secret = true; } memset(p, 0, sizeof(*p)); for(j=0;jusedown = p->attackdown = true; /* don't do anything immediately */ p->playerstate = PST_LIVE; p->health = MAXHEALTH; p->readyweapon = p->pendingweapon = wp_goldwand; p->weaponowned[wp_staff] = true; p->weaponowned[wp_goldwand] = true; p->messageTics = 0; p->lookdir = 0; p->ammo[am_goldwand] = 50; for(i = 0; i < NUMAMMO; i++) { p->maxammo[i] = maxammo[i]; } if(gamemap == 9 || secret) { p->didsecret = true; } if(p == &players[consoleplayer]) { SB_state = -1; /* refresh the status bar */ inv_ptr = 0; /* reset the inventory pointer */ curpos = 0; } } /* ==================== = = G_CheckSpot = = Returns false if the player cannot be respawned at the given mapthing_t spot = because something is occupying it ==================== */ void P_SpawnPlayer (mapthing_t *mthing); boolean G_CheckSpot (int playernum, mapthing_t *mthing) { fixed_t x,y; subsector_t *ss; unsigned an; mobj_t *mo; x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; players[playernum].mo->flags2 &= ~MF2_PASSMOBJ; if (!P_CheckPosition (players[playernum].mo, x, y) ) { players[playernum].mo->flags2 |= MF2_PASSMOBJ; return false; } players[playernum].mo->flags2 |= MF2_PASSMOBJ; /* spawn a teleport fog */ ss = R_PointInSubsector (x,y); an = ( ANG45 * (mthing->angle/45) ) >> ANGLETOFINESHIFT; mo = P_SpawnMobj (x+20*finecosine[an], y+20*finesine[an] , ss->sector->floorheight+TELEFOGHEIGHT , MT_TFOG); if (players[consoleplayer].viewz != 1) S_StartSound (mo, sfx_telept); /* don't start sound on first frame */ return true; } /* ==================== = = G_DeathMatchSpawnPlayer = = Spawns a player at one of the random death match spots = called at level load and each death ==================== */ void G_DeathMatchSpawnPlayer (int playernum) { int i,j; int selections; selections = deathmatch_p - deathmatchstarts; if (selections < 4) I_Error ("Only %i deathmatch spots, 4 required", selections); for (j=0 ; j<20 ; j++) { i = P_Random() % selections; if (G_CheckSpot (playernum, &deathmatchstarts[i]) ) { deathmatchstarts[i].type = playernum+1; P_SpawnPlayer (&deathmatchstarts[i]); return; } } /* no good spot, so the player will probably get stuck */ P_SpawnPlayer (&playerstarts[playernum]); } /* ==================== = = G_DoReborn = ==================== */ void G_DoReborn (int playernum) { int i; if (G_CheckDemoStatus ()) return; if (!netgame) gameaction = ga_loadlevel; /* reload the level from scratch */ else { /* respawn at the start */ players[playernum].mo->player = NULL; /* dissasociate the corpse */ /* spawn at random spot if in death match */ if (deathmatch) { G_DeathMatchSpawnPlayer (playernum); return; } if (G_CheckSpot (playernum, &playerstarts[playernum]) ) { P_SpawnPlayer (&playerstarts[playernum]); return; } /* try to spawn at one of the other players spots */ for (i=0 ; i sk_nightmare) skill = sk_nightmare; if(episode < 1) episode = 1; /* Up to 9 episodes for testing */ if(episode > 9) episode = 9; if(map < 1) map = 1; if(map > 9) map = 9; M_ClearRandom(); if(respawnparm) { respawnmonsters = true; } else { respawnmonsters = false; } /* Set monster missile speeds */ speed = skill == sk_nightmare; for(i = 0; MonsterMissileInfo[i].type != -1; i++) { mobjinfo[MonsterMissileInfo[i].type].speed = MonsterMissileInfo[i].speed[speed]< 5) { skytexture = R_TextureNumForName("SKY1"); } else { skytexture = R_TextureNumForName(skyLumpNames[episode-1]); } /* * give one null ticcmd_t */ #if 0 gametic = 0; maketic = 1; for (i=0 ; iforwardmove = ((signed char)*demo_p++); cmd->sidemove = ((signed char)*demo_p++); cmd->angleturn = ((unsigned char)*demo_p++)<<8; cmd->buttons = (unsigned char)*demo_p++; cmd->lookfly = (unsigned char)*demo_p++; cmd->arti = (unsigned char)*demo_p++; } void G_WriteDemoTiccmd (ticcmd_t *cmd) { if (gamekeydown['q']) /* press q to end demo recording */ G_CheckDemoStatus (); *demo_p++ = cmd->forwardmove; *demo_p++ = cmd->sidemove; *demo_p++ = cmd->angleturn>>8; *demo_p++ = cmd->buttons; *demo_p++ = cmd->lookfly; *demo_p++ = cmd->arti; demo_p -= 6; G_ReadDemoTiccmd (cmd); /* make SURE it is exactly the same */ } /* =================== = = G_RecordDemo = =================== */ void G_RecordDemo (skill_t skill, int numplayers, int episode, int map, char *name) { int i; G_InitNew (skill, episode, map); usergame = false; strcpy (demoname, name); strcat (demoname, ".lmp"); demobuffer = demo_p = Z_Malloc (0x20000,PU_STATIC,NULL); *demo_p++ = skill; *demo_p++ = episode; *demo_p++ = map; for (i=0 ; i is a 24 byte text string. // //========================================================================== */ void G_SaveGame(int slot, char *description) { savegameslot = slot; strcpy(savedescription, description); sendsave = true; } /* //========================================================================== // // G_DoSaveGame // // Called by G_Ticker based on gameaction. // //========================================================================== */ void G_DoSaveGame(void) { int i; char name[100]; char verString[VERSIONSIZE]; char *description; if(cdrom) { sprintf(name, SAVEGAMENAMECD"%d.hsg", savegameslot); } else { sprintf(name, "%s"SAVEGAMENAME"%d.hsg", homedir, savegameslot); } description = savedescription; SV_Open(name); SV_Write(description, SAVESTRINGSIZE); memset(verString, 0, sizeof(verString)); sprintf(verString, "version %i", VERSION); SV_Write(verString, VERSIONSIZE); SV_WriteByte(gameskill); SV_WriteByte(gameepisode); SV_WriteByte(gamemap); for(i = 0; i < MAXPLAYERS; i++) { SV_WriteByte(playeringame[i]); } SV_WriteByte(leveltime>>16); SV_WriteByte(leveltime>>8); SV_WriteByte(leveltime); P_ArchivePlayers(); P_ArchiveWorld(); P_ArchiveThinkers(); P_ArchiveSpecials(); #ifdef GL_HERETIC GL_ArchiveWallImpacts(); #endif SV_Close(name); gameaction = ga_nothing; savedescription[0] = 0; P_SetMessage(&players[consoleplayer], TXT_GAMESAVED, true); } /* //========================================================================== // // SV_Open // //========================================================================== */ void SV_Open(char *fileName) { MallocFailureOk = true; save_p = savebuffer = Z_Malloc(SAVEGAMESIZE, PU_STATIC, NULL); MallocFailureOk = false; if(savebuffer == NULL) { /* Not enough memory - use file save method */ SaveGameType = SVG_FILE; SaveGameFP = fopen(fileName, "wb"); } else { SaveGameType = SVG_RAM; } } /* //========================================================================== // // SV_Close // //========================================================================== */ void SV_Close(char *fileName) { int length; SV_WriteByte(SAVE_GAME_TERMINATOR); if(SaveGameType == SVG_RAM) { length = save_p-savebuffer; if(length > SAVEGAMESIZE) { I_Error("Savegame buffer overrun"); } M_WriteFile(fileName, savebuffer, length); Z_Free(savebuffer); } else { /* SVG_FILE */ fclose(SaveGameFP); } } /* //========================================================================== // // SV_Write // //========================================================================== */ void SV_Write(void *buffer, size_t size) { if(SaveGameType == SVG_RAM) { memcpy(save_p, buffer, size); save_p += size; } else { /* SVG_FILE */ fwrite(buffer, size, 1, SaveGameFP); } } void SV_WriteByte(byte val) { SV_Write(&val, sizeof(byte)); } void SV_WriteWord(unsigned short val) { SV_Write(&val, sizeof(unsigned short)); } void SV_WriteLong(unsigned int val) { SV_Write(&val, sizeof(int)); }