14 #define SAVE_GAME_TERMINATOR 0x1d
19 boolean G_CheckDemoStatus (void);
20 void G_ReadDemoTiccmd (ticcmd_t *cmd);
21 void G_WriteDemoTiccmd (ticcmd_t *cmd);
22 void G_PlayerReborn (int player);
23 void G_InitNew (skill_t skill, int episode, int map);
25 void G_DoReborn (int playernum);
27 void G_DoLoadLevel (void);
28 void G_DoNewGame (void);
29 void G_DoLoadGame (void);
30 void G_DoPlayDemo (void);
31 void G_DoCompleted (void);
32 void G_DoVictory (void);
33 void G_DoWorldDone (void);
34 void G_DoSaveGame (void);
36 void D_PageTicker(void);
37 void D_AdvanceDemo(void);
43 } MonsterMissileInfo[] =
45 { MT_IMPBALL, {10, 20} },
46 { MT_MUMMYFX1, {9, 18} },
47 { MT_KNIGHTAXE, {9, 18} },
48 { MT_REDAXE, {9, 18} },
49 { MT_BEASTBALL, {12, 20} },
50 { MT_WIZFX1, {18, 24} },
51 { MT_SNAKEPRO_A, {14, 20} },
52 { MT_SNAKEPRO_B, {14, 20} },
53 { MT_HEADFX1, {13, 20} },
54 { MT_HEADFX3, {10, 18} },
55 { MT_MNTRFX1, {20, 26} },
56 { MT_MNTRFX2, {14, 20} },
57 { MT_SRCRFX1, {20, 28} },
58 { MT_SOR2FX1, {20, 28} },
59 { -1, {-1, -1} } // Terminator
65 gameaction_t gameaction;
66 gamestate_t gamestate;
68 boolean respawnmonsters;
74 boolean sendpause; // send a pause event next tic
75 boolean sendsave; // send a save event next tic
76 boolean usergame; // ok to save / end game
78 boolean timingdemo; // if true, exit with report on completion
79 int starttime; // for comparative timing purposes
83 boolean deathmatch; // only if started as net death
84 boolean netgame; // only true if packets are broadcast
85 boolean playeringame[MAXPLAYERS];
86 player_t players[MAXPLAYERS];
88 int consoleplayer; // player taking events and displaying
89 int displayplayer; // view being displayed
91 int levelstarttic; // gametic at level start
92 int totalkills, totalitems, totalsecret; // for intermission
95 boolean demorecording;
97 byte *demobuffer, *demo_p;
98 boolean singledemo; // quit after playing a demo from cmdline
100 boolean precache = true; // if true, load all graphics at start
102 short consistancy[MAXPLAYERS][BACKUPTICS];
104 byte *savebuffer, *save_p;
108 // controls (have defaults)
110 int key_right, key_left, key_up, key_down;
111 int key_strafeleft, key_straferight;
112 int key_fire, key_use, key_strafe, key_speed;
113 int key_flyup, key_flydown, key_flycenter;
114 int key_lookup, key_lookdown, key_lookcenter;
115 int key_invleft, key_invright, key_useartifact;
128 #define MAXPLMOVE 0x32
130 fixed_t forwardmove[2] = {0x19, 0x32};
131 fixed_t sidemove[2] = {0x18, 0x28};
132 fixed_t angleturn[3] = {640, 1280, 320}; // + slow turn
133 #define SLOWTURNTICS 6
136 boolean gamekeydown[NUMKEYS];
137 int turnheld; // for accelerative turning
141 boolean mousearray[4];
142 boolean *mousebuttons = &mousearray[1];
144 int mousex, mousey; // mouse values are used once
145 int dclicktime, dclickstate, dclicks;
146 int dclicktime2, dclickstate2, dclicks2;
148 int joyxmove, joyymove; // joystick values are repeated
150 boolean *joybuttons = &joyarray[1]; // allow [-1]
153 char savedescription[32];
158 extern externdata_t *i_ExternData;
161 //=============================================================================
162 // Not used - ripped out for Heretic
164 int G_CmdChecksum(ticcmd_t *cmd)
170 for(i = 0; i < sizeof(*cmd)/4-1; i++)
172 sum += ((int *)cmd)[i];
183 = Builds a ticcmd from all of the available inputs or reads it from the
185 = If recording a demo, write it out
189 extern boolean inventory;
193 extern int isCyberPresent; // is CyberMan present?
194 boolean usearti = true;
195 void I_ReadCyberCmd (ticcmd_t *cmd);
197 void G_BuildTiccmd (ticcmd_t *cmd)
200 boolean strafe, bstrafe;
201 int speed, tspeed, lspeed;
206 extern boolean noartiskip;
211 extern int newViewAngleOff;
212 static int externInvKey;
213 extern boolean automapactive;
218 memset (cmd,0,sizeof(*cmd));
220 // consistancy[consoleplayer][(maketic*ticdup)%BACKUPTICS];
222 consistancy[consoleplayer][maketic%BACKUPTICS];
224 //printf ("cons: %i\n",cmd->consistancy);
226 strafe = gamekeydown[key_strafe] || mousebuttons[mousebstrafe]
227 || joybuttons[joybstrafe];
228 speed = gamekeydown[key_speed] || joybuttons[joybspeed]
229 || joybuttons[joybspeed];
233 speed |= (i_ExternData->buttons&EBT_SPEED);
234 strafe |= (i_ExternData->buttons&EBT_STRAFE);
238 forward = side = look = arti = flyheight = 0;
241 // use two stage accelerative turning on the keyboard and joystick
243 if (joyxmove < 0 || joyxmove > 0
244 || gamekeydown[key_right] || gamekeydown[key_left])
248 if (turnheld < SLOWTURNTICS)
249 tspeed = 2; // slow turn
253 if(gamekeydown[key_lookdown] || gamekeydown[key_lookup])
261 if(lookheld < SLOWTURNTICS)
271 // let movement keys cancel each other out
275 if (gamekeydown[key_right])
276 side += sidemove[speed];
277 if (gamekeydown[key_left])
278 side -= sidemove[speed];
280 side += sidemove[speed];
282 side -= sidemove[speed];
286 if (gamekeydown[key_right])
287 cmd->angleturn -= angleturn[tspeed];
288 if (gamekeydown[key_left])
289 cmd->angleturn += angleturn[tspeed];
291 cmd->angleturn -= angleturn[tspeed];
293 cmd->angleturn += angleturn[tspeed];
296 if (gamekeydown[key_up])
297 forward += forwardmove[speed];
298 if (gamekeydown[key_down])
299 forward -= forwardmove[speed];
301 forward += forwardmove[speed];
303 forward -= forwardmove[speed];
304 if (gamekeydown[key_straferight])
305 side += sidemove[speed];
306 if (gamekeydown[key_strafeleft])
307 side -= sidemove[speed];
309 // Look up/down/center keys
310 if(gamekeydown[key_lookup])
314 if(gamekeydown[key_lookdown])
319 if(gamekeydown[key_lookcenter] && !useexterndriver)
324 if(gamekeydown[key_lookcenter])
331 if(useexterndriver && look != TOCENTER && (gamestate == GS_LEVEL ||
332 gamestate == GS_INTERMISSION))
334 if(i_ExternData->moveForward)
336 forward += i_ExternData->moveForward;
342 if(i_ExternData->angleTurn)
346 side += i_ExternData->angleTurn;
350 cmd->angleturn += i_ExternData->angleTurn;
353 if(i_ExternData->moveSideways)
355 side += i_ExternData->moveSideways;
361 if(i_ExternData->buttons&EBT_CENTERVIEW)
366 else if(i_ExternData->pitch)
368 angleDelta = i_ExternData->pitch-oldAngle;
369 if(abs(angleDelta) < 35)
375 look = 7*(angleDelta > 0 ? 1 : -1);
383 if(i_ExternData->flyDirection)
385 if(i_ExternData->flyDirection > 0)
394 if(abs(newViewAngleOff-i_ExternData->angleHead) < 3000)
396 newViewAngleOff = i_ExternData->angleHead;
398 if(i_ExternData->buttons&EBT_FIRE)
400 cmd->buttons |= BT_ATTACK;
402 if(i_ExternData->buttons&EBT_OPENDOOR)
404 cmd->buttons |= BT_USE;
406 if(i_ExternData->buttons&EBT_PAUSE)
408 cmd->buttons = BT_SPECIAL | BTS_PAUSE;
409 i_ExternData->buttons &= ~EBT_PAUSE;
411 if(externInvKey&EBT_USEARTIFACT)
414 ev.data1 = key_useartifact;
416 externInvKey &= ~EBT_USEARTIFACT;
418 else if(i_ExternData->buttons&EBT_USEARTIFACT)
420 externInvKey |= EBT_USEARTIFACT;
421 ev.type = ev_keydown;
422 ev.data1 = key_useartifact;
425 if(externInvKey&EBT_INVENTORYRIGHT)
428 ev.data1 = key_invright;
430 externInvKey &= ~EBT_INVENTORYRIGHT;
432 else if(i_ExternData->buttons&EBT_INVENTORYRIGHT)
434 externInvKey |= EBT_INVENTORYRIGHT;
435 ev.type = ev_keydown;
436 ev.data1 = key_invright;
439 if(externInvKey&EBT_INVENTORYLEFT)
442 ev.data1 = key_invleft;
444 externInvKey &= ~EBT_INVENTORYLEFT;
446 else if(i_ExternData->buttons&EBT_INVENTORYLEFT)
448 externInvKey |= EBT_INVENTORYLEFT;
449 ev.type = ev_keydown;
450 ev.data1 = key_invleft;
453 if(i_ExternData->buttons&EBT_FLYDROP)
455 flyheight = TOCENTER;
457 if(gamestate == GS_LEVEL)
459 if(externInvKey&EBT_MAP)
462 ev.data1 = AM_STARTKEY;
464 externInvKey &= ~EBT_MAP;
466 else if(i_ExternData->buttons&EBT_MAP)
468 externInvKey |= EBT_MAP;
469 ev.type = ev_keydown;
470 ev.data1 = AM_STARTKEY;
475 if((i = (i_ExternData->buttons>>EBT_WEAPONSHIFT)&EBT_WEAPONMASK) != 0)
477 cmd->buttons |= BT_CHANGE;
478 cmd->buttons |= (i-1)<<BT_WEAPONSHIFT;
481 if(i_ExternData->buttons&EBT_WEAPONCYCLE)
486 pl = &players[consoleplayer];
487 curWeapon = pl->readyweapon;
488 for(curWeapon = (curWeapon+1)&7; curWeapon != pl->readyweapon;
489 curWeapon = (curWeapon+1)&7)
491 if(pl->weaponowned[curWeapon])
493 if(curWeapon >= wp_goldwand && curWeapon <= wp_mace &&
494 !pl->ammo[wpnlev1info[curWeapon].ammo])
495 { // weapon that requires ammo is empty
501 cmd->buttons |= BT_CHANGE;
502 cmd->buttons |= curWeapon<<BT_WEAPONSHIFT;
507 // Fly up/down/drop keys
508 if(gamekeydown[key_flyup])
510 flyheight = 5; // note that the actual flyheight will be twice this
512 if(gamekeydown[key_flydown])
516 if(gamekeydown[key_flycenter])
518 flyheight = TOCENTER;
530 if(gamekeydown[key_useartifact])
532 if(gamekeydown[key_speed] && !noartiskip)
534 if(players[consoleplayer].inventory[inv_ptr].type != arti_none)
536 gamekeydown[key_useartifact] = false;
537 cmd->arti = 0xff; // skip artifact code
544 players[consoleplayer].readyArtifact =
545 players[consoleplayer].inventory[inv_ptr].type;
552 cmd->arti = players[consoleplayer].inventory[inv_ptr].type;
557 if(gamekeydown[127] && !cmd->arti
558 && !players[consoleplayer].powers[pw_weaponlevel2])
560 gamekeydown[127] = false;
561 cmd->arti = arti_tomeofpower;
567 cmd->chatchar = CT_dequeueChatChar();
569 if (gamekeydown[key_fire] || mousebuttons[mousebfire]
570 || joybuttons[joybfire])
571 cmd->buttons |= BT_ATTACK;
573 if (gamekeydown[key_use] || joybuttons[joybuse] )
575 cmd->buttons |= BT_USE;
576 dclicks = 0; // clear double clicks if hit use button
579 for(i = 0; i < NUMWEAPONS-2; i++)
581 if(gamekeydown['1'+i])
583 cmd->buttons |= BT_CHANGE;
584 cmd->buttons |= i<<BT_WEAPONSHIFT;
592 if (mousebuttons[mousebforward])
594 forward += forwardmove[speed];
598 // forward double click
600 if (mousebuttons[mousebforward] != dclickstate && dclicktime > 1 )
602 dclickstate = mousebuttons[mousebforward];
607 cmd->buttons |= BT_USE;
615 dclicktime += ticdup;
624 // strafe double click
626 bstrafe = mousebuttons[mousebstrafe]
627 || joybuttons[joybstrafe];
628 if (bstrafe != dclickstate2 && dclicktime2 > 1 )
630 dclickstate2 = bstrafe;
635 cmd->buttons |= BT_USE;
643 dclicktime2 += ticdup;
644 if (dclicktime2 > 20)
657 cmd->angleturn -= mousex*0x8;
662 if (forward > MAXPLMOVE)
664 else if (forward < -MAXPLMOVE)
665 forward = -MAXPLMOVE;
666 if (side > MAXPLMOVE)
668 else if (side < -MAXPLMOVE)
671 cmd->forwardmove += forward;
672 cmd->sidemove += side;
673 if(players[consoleplayer].playerstate == PST_LIVE)
685 cmd->lookfly |= flyheight<<4;
693 cmd->buttons = BT_SPECIAL | BTS_PAUSE;
699 cmd->buttons = BT_SPECIAL | BTS_SAVEGAME | (savegameslot<<BTS_SAVESHIFT);
713 void G_DoLoadLevel (void)
717 levelstarttic = gametic; // for time calculation
718 gamestate = GS_LEVEL;
719 for (i=0 ; i<MAXPLAYERS ; i++)
721 if (playeringame[i] && players[i].playerstate == PST_DEAD)
722 players[i].playerstate = PST_REBORN;
723 memset (players[i].frags,0,sizeof(players[i].frags));
726 P_SetupLevel (gameepisode, gamemap, 0, gameskill);
727 displayplayer = consoleplayer; // view the guy you are playing
728 starttime = I_GetTime ();
729 gameaction = ga_nothing;
733 // clear cmd building stuff
736 memset (gamekeydown, 0, sizeof(gamekeydown));
737 joyxmove = joyymove = 0;
739 sendpause = sendsave = paused = false;
740 memset (mousebuttons, 0, sizeof(mousebuttons));
741 memset (joybuttons, 0, sizeof(joybuttons));
746 ===============================================================================
750 = get info needed to make ticcmd_ts for the players
752 ===============================================================================
755 boolean G_Responder(event_t *ev)
758 extern boolean MenuActive;
760 plr = &players[consoleplayer];
761 if(ev->type == ev_keyup && ev->data1 == key_useartifact)
762 { // flag to denote that it's okay to use an artifact
765 plr->readyArtifact = plr->inventory[inv_ptr].type;
770 // Check for spy mode player cycle
771 if(gamestate == GS_LEVEL && ev->type == ev_keydown
772 && ev->data1 == KEY_F12 && !deathmatch)
773 { // Cycle the display player
777 if(displayplayer == MAXPLAYERS)
781 } while(!playeringame[displayplayer]
782 && displayplayer != consoleplayer);
786 if(gamestate == GS_LEVEL)
789 { // Chat ate the event
793 { // Status bar ate the event
797 { // Automap ate the event
805 if(ev->data1 == key_invleft)
807 inventoryTics = 5*35;
828 if(ev->data1 == key_invright)
830 inventoryTics = 5*35;
837 if(inv_ptr >= plr->inventorySlotNum)
853 if(ev->data1 == KEY_PAUSE && !MenuActive)
858 if(ev->data1 < NUMKEYS)
860 gamekeydown[ev->data1] = true;
862 return(true); // eat key down events
865 if(ev->data1 < NUMKEYS)
867 gamekeydown[ev->data1] = false;
869 return(false); // always let key up events filter down
872 mousebuttons[0] = ev->data1&1;
873 mousebuttons[1] = ev->data1&2;
874 mousebuttons[2] = ev->data1&4;
875 mousex = ev->data2*(mouseSensitivity+5)/10;
876 mousey = ev->data3*(mouseSensitivity+5)/10;
877 return(true); // eat events
880 joybuttons[0] = ev->data1&1;
881 joybuttons[1] = ev->data1&2;
882 joybuttons[2] = ev->data1&4;
883 joybuttons[3] = ev->data1&8;
884 joyxmove = ev->data2;
885 joyymove = ev->data3;
886 return(true); // eat events
895 ===============================================================================
899 ===============================================================================
905 ticcmd_t *cmd = NULL;
908 // do player reborns if needed
910 for (i=0 ; i<MAXPLAYERS ; i++)
911 if (playeringame[i] && players[i].playerstate == PST_REBORN)
915 // do things to change the game state
917 while (gameaction != ga_nothing)
938 gameaction = ga_nothing;
956 // get commands, check consistancy, and build new consistancy check
958 //buf = gametic%BACKUPTICS;
959 buf = (gametic/ticdup)%BACKUPTICS;
961 for (i=0 ; i<MAXPLAYERS ; i++)
964 cmd = &players[i].cmd;
966 memcpy (cmd, &netcmds[i][buf], sizeof(ticcmd_t));
969 G_ReadDemoTiccmd (cmd);
971 G_WriteDemoTiccmd (cmd);
973 if (netgame && !(gametic%ticdup) )
975 if (gametic > BACKUPTICS
976 && consistancy[i][buf] != cmd->consistancy)
978 I_Error ("consistency failure (%i should be %i)",cmd->consistancy, consistancy[i][buf]);
981 consistancy[i][buf] = players[i].mo->x;
983 consistancy[i][buf] = rndindex;
988 // check for special buttons
990 for (i=0 ; i<MAXPLAYERS ; i++)
993 if (players[i].cmd.buttons & BT_SPECIAL)
995 switch (players[i].cmd.buttons & BT_SPECIALMASK)
1010 if (!savedescription[0])
1014 strcpy (savedescription, "NET GAME");
1018 strcpy(savedescription, "SAVE GAME");
1022 (players[i].cmd.buttons & BTS_SAVEMASK)>>BTS_SAVESHIFT;
1023 gameaction = ga_savegame;
1028 // turn inventory off after a certain amount of time
1029 if(inventory && !(--inventoryTics))
1031 players[consoleplayer].readyArtifact =
1032 players[consoleplayer].inventory[inv_ptr].type;
1050 case GS_INTERMISSION:
1064 ==============================================================================
1066 PLAYER STRUCTURE FUNCTIONS
1068 also see P_SpawnPlayer in P_Things
1069 ==============================================================================
1073 ====================
1077 = Called at the start
1078 = Called by the game initialization functions
1079 ====================
1082 void G_InitPlayer (int player)
1086 // set up the saved info
1087 p = &players[player];
1089 // clear everything else to defaults
1090 G_PlayerReborn (player);
1096 ====================
1098 = G_PlayerFinishLevel
1100 = Can when a player completes a level
1101 ====================
1105 extern int playerkeys;
1107 void G_PlayerFinishLevel(int player)
1117 p = &players[player];
1118 for(i=0; i<p->inventorySlotNum; i++)
1120 p->inventory[i].count = 1;
1122 p->artifactCount = p->inventorySlotNum;
1126 for(i = 0; i < 16; i++)
1128 P_PlayerUseArtifact(p, arti_fly);
1131 memset(p->powers, 0, sizeof(p->powers));
1132 memset(p->keys, 0, sizeof(p->keys));
1134 // memset(p->inventory, 0, sizeof(p->inventory));
1137 p->readyweapon = p->mo->special1; // Restore weapon
1142 p->mo->flags &= ~MF_SHADOW; // Remove invisibility
1143 p->extralight = 0; // Remove weapon flashes
1144 p->fixedcolormap = 0; // Remove torch
1145 p->damagecount = 0; // No palette changes
1149 if(p == &players[consoleplayer])
1151 SB_state = -1; // refresh the status bar
1156 ====================
1160 = Called after a player dies
1161 = almost everything is cleared and initialized
1162 ====================
1165 void G_PlayerReborn(int player)
1169 int frags[MAXPLAYERS];
1170 int killcount, itemcount, secretcount;
1174 memcpy(frags, players[player].frags, sizeof(frags));
1175 killcount = players[player].killcount;
1176 itemcount = players[player].itemcount;
1177 secretcount = players[player].secretcount;
1179 p = &players[player];
1184 memset(p, 0, sizeof(*p));
1186 memcpy(players[player].frags, frags, sizeof(players[player].frags));
1187 players[player].killcount = killcount;
1188 players[player].itemcount = itemcount;
1189 players[player].secretcount = secretcount;
1191 p->usedown = p->attackdown = true; // don't do anything immediately
1192 p->playerstate = PST_LIVE;
1193 p->health = MAXHEALTH;
1194 p->readyweapon = p->pendingweapon = wp_goldwand;
1195 p->weaponowned[wp_staff] = true;
1196 p->weaponowned[wp_goldwand] = true;
1199 p->ammo[am_goldwand] = 50;
1200 for(i = 0; i < NUMAMMO; i++)
1202 p->maxammo[i] = maxammo[i];
1204 if(gamemap == 9 || secret)
1206 p->didsecret = true;
1208 if(p == &players[consoleplayer])
1210 SB_state = -1; // refresh the status bar
1211 inv_ptr = 0; // reset the inventory pointer
1217 ====================
1221 = Returns false if the player cannot be respawned at the given mapthing_t spot
1222 = because something is occupying it
1223 ====================
1226 void P_SpawnPlayer (mapthing_t *mthing);
1228 boolean G_CheckSpot (int playernum, mapthing_t *mthing)
1235 x = mthing->x << FRACBITS;
1236 y = mthing->y << FRACBITS;
1238 players[playernum].mo->flags2 &= ~MF2_PASSMOBJ;
1239 if (!P_CheckPosition (players[playernum].mo, x, y) )
1241 players[playernum].mo->flags2 |= MF2_PASSMOBJ;
1244 players[playernum].mo->flags2 |= MF2_PASSMOBJ;
1246 // spawn a teleport fog
1247 ss = R_PointInSubsector (x,y);
1248 an = ( ANG45 * (mthing->angle/45) ) >> ANGLETOFINESHIFT;
1250 mo = P_SpawnMobj (x+20*finecosine[an], y+20*finesine[an]
1251 , ss->sector->floorheight+TELEFOGHEIGHT
1254 if (players[consoleplayer].viewz != 1)
1255 S_StartSound (mo, sfx_telept); // don't start sound on first frame
1261 ====================
1263 = G_DeathMatchSpawnPlayer
1265 = Spawns a player at one of the random death match spots
1266 = called at level load and each death
1267 ====================
1270 void G_DeathMatchSpawnPlayer (int playernum)
1275 selections = deathmatch_p - deathmatchstarts;
1277 I_Error ("Only %i deathmatch spots, 4 required", selections);
1279 for (j=0 ; j<20 ; j++)
1281 i = P_Random() % selections;
1282 if (G_CheckSpot (playernum, &deathmatchstarts[i]) )
1284 deathmatchstarts[i].type = playernum+1;
1285 P_SpawnPlayer (&deathmatchstarts[i]);
1290 // no good spot, so the player will probably get stuck
1291 P_SpawnPlayer (&playerstarts[playernum]);
1295 ====================
1299 ====================
1302 void G_DoReborn (int playernum)
1306 if (G_CheckDemoStatus ())
1309 gameaction = ga_loadlevel; // reload the level from scratch
1311 { // respawn at the start
1312 players[playernum].mo->player = NULL; // dissasociate the corpse
1314 // spawn at random spot if in death match
1317 G_DeathMatchSpawnPlayer (playernum);
1321 if (G_CheckSpot (playernum, &playerstarts[playernum]) )
1323 P_SpawnPlayer (&playerstarts[playernum]);
1326 // try to spawn at one of the other players spots
1327 for (i=0 ; i<MAXPLAYERS ; i++)
1328 if (G_CheckSpot (playernum, &playerstarts[i]) )
1330 playerstarts[i].type = playernum+1; // fake as other player
1331 P_SpawnPlayer (&playerstarts[i]);
1332 playerstarts[i].type = i+1; // restore
1335 // he's going to be inside something. Too bad.
1336 P_SpawnPlayer (&playerstarts[playernum]);
1341 void G_ScreenShot (void)
1343 gameaction = ga_screenshot;
1348 ====================
1352 ====================
1357 void G_ExitLevel (void)
1360 gameaction = ga_completed;
1363 void G_SecretExitLevel (void)
1366 gameaction = ga_completed;
1369 void G_DoCompleted(void)
1372 static int afterSecret[5] = { 7, 5, 5, 5, 4 };
1374 gameaction = ga_nothing;
1375 if(G_CheckDemoStatus())
1379 for(i = 0; i < MAXPLAYERS; i++)
1383 G_PlayerFinishLevel(i);
1387 if(secretexit == true)
1391 else if(gamemap == 9)
1392 { // Finished secret level
1393 gamemap = afterSecret[gameepisode-1];
1395 else if(gamemap == 8)
1397 gameaction = ga_victory;
1404 gamestate = GS_INTERMISSION;
1408 //============================================================================
1412 //============================================================================
1414 void G_WorldDone(void)
1416 gameaction = ga_worlddone;
1419 //============================================================================
1423 //============================================================================
1425 void G_DoWorldDone(void)
1427 gamestate = GS_LEVEL;
1429 gameaction = ga_nothing;
1433 //---------------------------------------------------------------------------
1437 // Can be called by the startup code or the menu task.
1439 //---------------------------------------------------------------------------
1443 void G_LoadGame(char *name)
1445 strcpy(savename, name);
1446 gameaction = ga_loadgame;
1449 //---------------------------------------------------------------------------
1451 // PROC G_DoLoadGame
1453 // Called by G_Ticker based on gameaction.
1455 //---------------------------------------------------------------------------
1457 #define VERSIONSIZE 16
1459 void G_DoLoadGame(void)
1464 char vcheck[VERSIONSIZE];
1466 gameaction = ga_nothing;
1468 length = M_ReadFile(savename, &savebuffer);
1469 save_p = savebuffer+SAVESTRINGSIZE;
1470 // Skip the description field
1471 memset(vcheck, 0, sizeof(vcheck));
1472 sprintf(vcheck, "version %i", VERSION);
1473 if (strcmp (save_p, vcheck))
1477 save_p += VERSIONSIZE;
1478 gameskill = *save_p++;
1479 gameepisode = *save_p++;
1480 gamemap = *save_p++;
1481 for(i = 0; i < MAXPLAYERS; i++)
1483 playeringame[i] = *save_p++;
1485 // Load a base level
1486 G_InitNew(gameskill, gameepisode, gamemap);
1492 leveltime = (a<<16)+(b<<8)+c;
1494 // De-archive all the modifications
1495 P_UnArchivePlayers();
1497 P_UnArchiveThinkers();
1498 P_UnArchiveSpecials();
1500 if(*save_p != SAVE_GAME_TERMINATOR)
1501 { // Missing savegame termination marker
1502 I_Error("Bad savegame");
1509 ====================
1513 = Can be called by the startup code or the menu task
1514 = consoleplayer, displayplayer, playeringame[] should be set
1515 ====================
1522 void G_DeferedInitNew (skill_t skill, int episode, int map)
1525 d_episode = episode;
1527 gameaction = ga_newgame;
1530 void G_DoNewGame (void)
1532 G_InitNew (d_skill, d_episode, d_map);
1533 gameaction = ga_nothing;
1536 extern int skytexture;
1538 void G_InitNew(skill_t skill, int episode, int map)
1542 static char *skyLumpNames[5] =
1544 "SKY1", "SKY2", "SKY3", "SKY1", "SKY3"
1554 if(skill > sk_nightmare)
1555 skill = sk_nightmare;
1558 // Up to 9 episodes for testing
1568 respawnmonsters = true;
1572 respawnmonsters = false;
1574 // Set monster missile speeds
1575 speed = skill == sk_nightmare;
1576 for(i = 0; MonsterMissileInfo[i].type != -1; i++)
1578 mobjinfo[MonsterMissileInfo[i].type].speed
1579 = MonsterMissileInfo[i].speed[speed]<<FRACBITS;
1581 // Force players to be initialized upon first level load
1582 for(i = 0; i < MAXPLAYERS; i++)
1584 players[i].playerstate = PST_REBORN;
1585 players[i].didsecret = false;
1587 // Set up a bunch of globals
1588 usergame = true; // will be set false if a demo
1590 demorecording = false;
1591 demoplayback = false;
1593 gameepisode = episode;
1597 BorderNeedRefresh = true;
1602 skytexture = R_TextureNumForName("SKY1");
1606 skytexture = R_TextureNumForName(skyLumpNames[episode-1]);
1610 // give one null ticcmd_t
1615 for (i=0 ; i<MAXPLAYERS ; i++)
1616 nettics[i] = 1; // one null event for this gametic
1617 memset (localcmds,0,sizeof(localcmds));
1618 memset (netcmds,0,sizeof(netcmds));
1625 ===============================================================================
1629 ===============================================================================
1632 #define DEMOMARKER 0x80
1634 void G_ReadDemoTiccmd (ticcmd_t *cmd)
1636 if (*demo_p == DEMOMARKER)
1637 { // end of demo data stream
1638 G_CheckDemoStatus ();
1641 cmd->forwardmove = ((signed char)*demo_p++);
1642 cmd->sidemove = ((signed char)*demo_p++);
1643 cmd->angleturn = ((unsigned char)*demo_p++)<<8;
1644 cmd->buttons = (unsigned char)*demo_p++;
1645 cmd->lookfly = (unsigned char)*demo_p++;
1646 cmd->arti = (unsigned char)*demo_p++;
1649 void G_WriteDemoTiccmd (ticcmd_t *cmd)
1651 if (gamekeydown['q']) // press q to end demo recording
1652 G_CheckDemoStatus ();
1653 *demo_p++ = cmd->forwardmove;
1654 *demo_p++ = cmd->sidemove;
1655 *demo_p++ = cmd->angleturn>>8;
1656 *demo_p++ = cmd->buttons;
1657 *demo_p++ = cmd->lookfly;
1658 *demo_p++ = cmd->arti;
1660 G_ReadDemoTiccmd (cmd); // make SURE it is exactly the same
1673 void G_RecordDemo (skill_t skill, int numplayers, int episode, int map, char *name)
1677 G_InitNew (skill, episode, map);
1679 strcpy (demoname, name);
1680 strcat (demoname, ".lmp");
1681 demobuffer = demo_p = Z_Malloc (0x20000,PU_STATIC,NULL);
1683 *demo_p++ = episode;
1686 for (i=0 ; i<MAXPLAYERS ; i++)
1687 *demo_p++ = playeringame[i];
1689 demorecording = true;
1703 void G_DeferedPlayDemo (char *name)
1706 gameaction = ga_playdemo;
1709 void G_DoPlayDemo (void)
1712 int i, episode, map;
1714 gameaction = ga_nothing;
1715 demobuffer = demo_p = W_CacheLumpName (defdemoname, PU_STATIC);
1717 episode = *demo_p++;
1720 for (i=0 ; i<MAXPLAYERS ; i++)
1721 playeringame[i] = *demo_p++;
1723 precache = false; // don't spend a lot of time in loadlevel
1724 G_InitNew (skill, episode, map);
1727 demoplayback = true;
1739 void G_TimeDemo (char *name)
1744 demobuffer = demo_p = W_CacheLumpName (name, PU_STATIC);
1746 episode = *demo_p++;
1748 G_InitNew (skill, episode, map);
1750 demoplayback = true;
1761 = Called after a death or level completion to allow demos to be cleaned up
1762 = Returns true if a new demo loop action will take place
1766 boolean G_CheckDemoStatus (void)
1772 endtime = I_GetTime ();
1773 I_Error ("timed %i gametics in %i realtics",gametic
1774 , endtime-starttime);
1782 Z_ChangeTag (demobuffer, PU_CACHE);
1783 demoplayback = false;
1790 *demo_p++ = DEMOMARKER;
1791 M_WriteFile (demoname, demobuffer, demo_p - demobuffer);
1792 Z_Free (demobuffer);
1793 demorecording = false;
1794 I_Error ("Demo %s recorded",demoname);
1800 /**************************************************************************/
1801 /**************************************************************************/
1803 //==========================================================================
1807 // Called by the menu task. <description> is a 24 byte text string.
1809 //==========================================================================
1811 void G_SaveGame(int slot, char *description)
1813 savegameslot = slot;
1814 strcpy(savedescription, description);
1818 //==========================================================================
1822 // Called by G_Ticker based on gameaction.
1824 //==========================================================================
1826 void G_DoSaveGame(void)
1830 char verString[VERSIONSIZE];
1835 sprintf(name, SAVEGAMENAMECD"%d.hsg", savegameslot);
1839 sprintf(name, SAVEGAMENAME"%d.hsg", savegameslot);
1841 description = savedescription;
1844 SV_Write(description, SAVESTRINGSIZE);
1845 memset(verString, 0, sizeof(verString));
1846 sprintf(verString, "version %i", VERSION);
1847 SV_Write(verString, VERSIONSIZE);
1848 SV_WriteByte(gameskill);
1849 SV_WriteByte(gameepisode);
1850 SV_WriteByte(gamemap);
1851 for(i = 0; i < MAXPLAYERS; i++)
1853 SV_WriteByte(playeringame[i]);
1855 SV_WriteByte(leveltime>>16);
1856 SV_WriteByte(leveltime>>8);
1857 SV_WriteByte(leveltime);
1860 P_ArchiveThinkers();
1861 P_ArchiveSpecials();
1864 gameaction = ga_nothing;
1865 savedescription[0] = 0;
1866 P_SetMessage(&players[consoleplayer], TXT_GAMESAVED, true);
1869 //==========================================================================
1873 //==========================================================================
1875 void SV_Open(char *fileName)
1877 MallocFailureOk = true;
1878 save_p = savebuffer = Z_Malloc(SAVEGAMESIZE, PU_STATIC, NULL);
1879 MallocFailureOk = false;
1880 if(savebuffer == NULL)
1881 { // Not enough memory - use file save method
1882 SaveGameType = SVG_FILE;
1883 SaveGameFP = fopen(fileName, "wb");
1887 SaveGameType = SVG_RAM;
1891 //==========================================================================
1895 //==========================================================================
1897 void SV_Close(char *fileName)
1901 SV_WriteByte(SAVE_GAME_TERMINATOR);
1902 if(SaveGameType == SVG_RAM)
1904 length = save_p-savebuffer;
1905 if(length > SAVEGAMESIZE)
1907 I_Error("Savegame buffer overrun");
1909 M_WriteFile(fileName, savebuffer, length);
1918 //==========================================================================
1922 //==========================================================================
1924 void SV_Write(void *buffer, int size)
1926 if(SaveGameType == SVG_RAM)
1928 memcpy(save_p, buffer, size);
1933 fwrite(buffer, size, 1, SaveGameFP);
1937 void SV_WriteByte(byte val)
1939 SV_Write(&val, sizeof(byte));
1942 void SV_WriteWord(unsigned short val)
1944 SV_Write(&val, sizeof(unsigned short));
1947 void SV_WriteLong(unsigned int val)
1949 SV_Write(&val, sizeof(int));