doom

a minimalistic implementation of doom
git clone git://ssnf.xyz/doom
Log | Files | Refs

g_game.c (22772B)


      1 #include <string.h>
      2 #include <stdlib.h>
      3 
      4 #include "doomdef.h"
      5 #include "doomstat.h"
      6 #include "z_zone.h"
      7 #include "f_finale.h"
      8 #include "m_argv.h"
      9 #include "m_misc.h"
     10 #include "m_menu.h"
     11 #include "m_random.h"
     12 #include "i_system.h"
     13 #include "p_setup.h"
     14 #include "p_saveg.h"
     15 #include "p_tick.h"
     16 #include "d_main.h"
     17 #include "wi_stuff.h"
     18 #include "hu_stuff.h"
     19 #include "st_stuff.h"
     20 #include "am_map.h"
     21 #include "v_video.h"
     22 #include "w_wad.h"
     23 #include "p_local.h"
     24 #include "s_sound.h"
     25 #include "sounds.h"
     26 #include "r_data.h"
     27 #include "g_game.h"
     28 
     29 #define SAVEGAMESIZE	0x2c000
     30 #define SAVESTRINGSIZE	24
     31 #define MAXPLMOVE		(forwardmove[1])
     32 #define TURBOTHRESHOLD	0x32
     33 #define SLOWTURNTICS	6
     34 #define NUMKEYS		256
     35 #define	BODYQUESIZE	32
     36 #define VERSIONSIZE		16
     37 #define DEMOMARKER		0x80
     38 
     39 boolean	G_CheckDemoStatus ();
     40 void	G_ReadDemoTiccmd (ticcmd_t* cmd);
     41 void	G_WriteDemoTiccmd (ticcmd_t* cmd);
     42 void	G_PlayerReborn (int player);
     43 void	G_InitNew (skill_t skill, int episode, int map);
     44 void	G_DoReborn (int playernum);
     45 void	G_DoLoadLevel ();
     46 void	G_DoNewGame ();
     47 void	G_DoLoadGame ();
     48 void	G_DoPlayDemo ();
     49 void	G_DoCompleted ();
     50 void	G_DoVictory ();
     51 void	G_DoWorldDone ();
     52 void	G_DoSaveGame ();
     53 void	R_ExecuteSetViewSize ();
     54 
     55 extern  gamestate_t	 wipegamestate;
     56 extern boolean setsizeneeded;
     57 extern char*	pagename;
     58 extern  int	skytexture;
     59 skill_t	d_skill;
     60 int	 d_episode;
     61 int	 d_map;
     62 boolean		secretexit;
     63 gameaction_t	gameaction;
     64 gamestate_t	 gamestate;
     65 skill_t		 gameskill;
     66 boolean		respawnmonsters;
     67 int			 gameepisode;
     68 int			 gamemap;
     69 boolean		 paused;
     70 boolean		 sendpause;
     71 boolean		 sendsave;
     72 boolean		 usergame;
     73 boolean		 timingdemo;
     74 boolean		 nodrawers;
     75 boolean		 noblit;
     76 int			 starttime;
     77 boolean		 viewactive;
     78 boolean		 deathmatch;
     79 boolean		 netgame;
     80 boolean		 playeringame[MAXPLAYERS];
     81 player_t		players[MAXPLAYERS];
     82 int			 consoleplayer;
     83 int			 displayplayer;
     84 int			 gametic;
     85 int			 levelstarttic;
     86 int			 totalkills, totalitems, totalsecret;
     87 char			demoname[32];
     88 boolean		 demorecording;
     89 boolean		 demoplayback;
     90 boolean		netdemo;
     91 byte*		demobuffer;
     92 byte*		demo_p;
     93 byte*		demoend;
     94 boolean		 singledemo;
     95 boolean		 precache = true;
     96 wbstartstruct_t wminfo;
     97 short		consistancy[MAXPLAYERS][BACKUPTICS];
     98 byte*		savebuffer;
     99 int			 key_right;
    100 int		key_left;
    101 int		key_up;
    102 int		key_down;
    103 int			 key_strafeleft;
    104 int		key_straferight;
    105 int			 key_fire;
    106 int		key_use;
    107 int		key_strafe;
    108 int		key_speed;
    109 int			 mousebfire;
    110 int			 mousebstrafe;
    111 int			 mousebforward;
    112 int			 joybfire;
    113 int			 joybstrafe;
    114 int			 joybuse;
    115 int			 joybspeed;
    116 fixed_t		forwardmove[2] = {0x19, 0x32};
    117 fixed_t		sidemove[2] = {0x18, 0x28};
    118 fixed_t		angleturn[3] = {640, 1280, 320};
    119 boolean		 gamekeydown[NUMKEYS];
    120 int			 turnheld;
    121 boolean		mousearray[4];
    122 boolean*	mousebuttons = &mousearray[1];
    123 int			 mousex;
    124 int		mousey;
    125 int			 dclicktime;
    126 int		dclickstate;
    127 int		dclicks;
    128 int			 dclicktime2;
    129 int		dclickstate2;
    130 int		dclicks2;
    131 int			 joyxmove;
    132 int		joyymove;
    133 boolean		 joyarray[5];
    134 boolean*	joybuttons = &joyarray[1];
    135 int		savegameslot;
    136 char		savedescription[32];
    137 mobj_t*		bodyque[BODYQUESIZE];
    138 int		bodyqueslot;
    139 void*		statcopy;
    140 char*	defdemoname;
    141 
    142 int pars[4][10] = {
    143 	{0},
    144 	{0,30,75,120,90,165,180,180,30,165},
    145 	{0,90,90,90,120,90,360,240,30,170},
    146 	{0,90,45,90,150,90,90,165,30,135}
    147 };
    148 
    149 int cpars[32] = {
    150 	30,90,120,120,90,150,120,120,270,90,
    151 	210,150,150,150,210,150,420,150,210,150,
    152 	240,150,180,150,150,300,330,420,300,180,
    153 	120,30
    154 };
    155 
    156 int
    157 G_CmdChecksum(ticcmd_t* cmd)
    158 {
    159 	int i, sum;
    160 
    161 	for (sum = i = 0; i < sizeof(*cmd)/4 - 1; ++i) sum += ((int*)cmd)[i];
    162 	return sum;
    163 }
    164 
    165 void
    166 G_BuildTiccmd(ticcmd_t* cmd)
    167 {
    168 	static ticcmd_t base;
    169 	int             i, speed, tspeed, forward, side;
    170 	boolean	strafe,  bstrafe;
    171 
    172 	memcpy(cmd, &base, sizeof(*cmd));
    173 	cmd->consistancy = consistancy[consoleplayer][maketic%BACKUPTICS];
    174 	strafe = gamekeydown[key_strafe] || mousebuttons[mousebstrafe]  || joybuttons[joybstrafe];
    175 	speed = gamekeydown[key_speed] || joybuttons[joybspeed];
    176 	forward = side = 0;
    177 	if (joyxmove < 0 || joyxmove > 0 || gamekeydown[key_right] || gamekeydown[key_left]) turnheld += ticdup;
    178 	else turnheld = 0;
    179 	if (turnheld < SLOWTURNTICS) tspeed = 2;
    180 	else tspeed = speed;
    181 	if (strafe) {
    182 		if (gamekeydown[key_right]) side += sidemove[speed];
    183 		if (gamekeydown[key_left]) side -= sidemove[speed];
    184 		if (joyxmove > 0) side += sidemove[speed];
    185 		if (joyxmove < 0) side -= sidemove[speed];
    186 	}
    187 	else {
    188 		if (gamekeydown[key_right]) cmd->angleturn -= angleturn[tspeed];
    189 		if (gamekeydown[key_left]) cmd->angleturn += angleturn[tspeed];
    190 		if (joyxmove > 0) cmd->angleturn -= angleturn[tspeed];
    191 		if (joyxmove < 0) cmd->angleturn += angleturn[tspeed];
    192 	}
    193 	if (gamekeydown[key_up]) forward += forwardmove[speed];
    194 	if (gamekeydown[key_down]) forward -= forwardmove[speed];
    195 	if (joyymove < 0) forward += forwardmove[speed];
    196 	if (joyymove > 0) forward -= forwardmove[speed];
    197 	if (gamekeydown[key_straferight]) side += sidemove[speed];
    198 	if (gamekeydown[key_strafeleft]) side -= sidemove[speed];
    199 	cmd->chatchar = HU_dequeueChatChar();
    200 	if (gamekeydown[key_fire] || mousebuttons[mousebfire] || joybuttons[joybfire])
    201 		cmd->buttons |= BT_ATTACK;
    202 	if (gamekeydown[key_use] || joybuttons[joybuse]) {
    203 		cmd->buttons |= BT_USE;
    204 		dclicks = 0;
    205 	}
    206 	for (i = 0; i < NUMWEAPONS - 1; ++i)
    207 		if (gamekeydown['1'+i]) {
    208 			cmd->buttons |= BT_CHANGE;
    209 			cmd->buttons |= i<<BT_WEAPONSHIFT;
    210 			break;
    211 		}
    212 	if (mousebuttons[mousebforward]) forward += forwardmove[speed];
    213 	if (mousebuttons[mousebforward] != dclickstate && dclicktime > 1 ) {
    214 		dclickstate = mousebuttons[mousebforward];
    215 		if (dclickstate) dclicks++;
    216 		if (dclicks == 2) {
    217 			cmd->buttons |= BT_USE;
    218 			dclicks = 0;
    219 		} else dclicktime = 0;
    220 	} else {
    221 		dclicktime += ticdup;
    222 		if (dclicktime > 20) {
    223 			dclicks = 0;
    224 			dclickstate = 0;
    225 		}
    226 	}
    227 	bstrafe = mousebuttons[mousebstrafe] || joybuttons[joybstrafe];
    228 	if (bstrafe != dclickstate2 && dclicktime2 > 1 ) {
    229 		dclickstate2 = bstrafe;
    230 		if (dclickstate2) dclicks2++;
    231 		if (dclicks2 == 2) {
    232 			cmd->buttons |= BT_USE;
    233 			dclicks2 = 0;
    234 		} else dclicktime2 = 0;
    235 	} else {
    236 		dclicktime2 += ticdup;
    237 		if (dclicktime2 > 20) {
    238 			dclicks2 = 0;
    239 			dclickstate2 = 0;
    240 		}
    241 	}
    242 	forward += mousey;
    243 	if (strafe) side += mousex * 2;
    244 	else cmd->angleturn -= mousex*0x8;
    245 	mousex = mousey = 0;
    246 	if (forward > MAXPLMOVE) forward = MAXPLMOVE;
    247 	if (forward < -MAXPLMOVE) forward = -MAXPLMOVE;
    248 	if (side > MAXPLMOVE) side = MAXPLMOVE;
    249 	if (side < -MAXPLMOVE) side = -MAXPLMOVE;
    250 	cmd->forwardmove += forward;
    251 	cmd->sidemove += side;
    252 	if (sendpause) {
    253 		sendpause = false;
    254 		cmd->buttons = BT_SPECIAL | BTS_PAUSE;
    255 	}
    256 	if (sendsave) {
    257 		sendsave = false;
    258 		cmd->buttons = BT_SPECIAL | BTS_SAVEGAME | (savegameslot<<BTS_SAVESHIFT);
    259 	}
    260 }
    261 
    262 void
    263 G_DoLoadLevel()
    264 {
    265 	int i;
    266 
    267 	skyflatnum = R_FlatNumForName(SKYFLATNAME);
    268 	levelstarttic = gametic;
    269 	if (wipegamestate == GS_LEVEL) wipegamestate = -1;
    270 	gamestate = GS_LEVEL;
    271 	for (i = 0; i < MAXPLAYERS; ++i) {
    272 		if (playeringame[i] && players[i].playerstate == PST_DEAD) players[i].playerstate = PST_REBORN;
    273 		memset(players[i].frags,0,sizeof(players[i].frags));
    274 	}
    275 	P_SetupLevel(gameepisode, gamemap, 0, gameskill);
    276 	displayplayer = consoleplayer;
    277 	starttime = I_GetTime();
    278 	gameaction = ga_nothing;
    279 	Z_CheckHeap();
    280 	memset(gamekeydown, 0, sizeof(gamekeydown));
    281 	joyxmove = joyymove = 0;
    282 	mousex = mousey = 0;
    283 	sendpause = sendsave = paused = false;
    284 	memset(mousebuttons, 0, sizeof(*mousebuttons));
    285 	memset(joybuttons, 0, sizeof(*joybuttons));
    286 }
    287 
    288 boolean
    289 G_Responder(event_t* ev)
    290 {
    291 	if (gamestate == GS_LEVEL && ev->type == ev_keydown && ev->data1 == KEY_F12 && (singledemo || !deathmatch)) {
    292 		do {
    293 			displayplayer++;
    294 			if (displayplayer == MAXPLAYERS) displayplayer = 0;
    295 		} while (!playeringame[displayplayer] && displayplayer != consoleplayer);
    296 		return true;
    297 	}
    298 	if (gameaction == ga_nothing && !singledemo && (demoplayback || gamestate == GS_DEMOSCREEN)) {
    299 		if (ev->type == ev_keydown || (ev->type == ev_mouse && ev->data1) || (ev->type == ev_joystick && ev->data1)) {
    300 			M_StartControlPanel();
    301 			return true;
    302 		}
    303 		return false;
    304 	}
    305 	if (gamestate == GS_LEVEL) {
    306 		if (HU_Responder(ev))
    307 			return true;
    308 		if (ST_Responder(ev))
    309 			return true;
    310 		if (AM_Responder(ev))
    311 			return true;
    312 	}
    313 	if (gamestate == GS_FINALE)
    314 		if (F_Responder(ev)) return true;
    315 
    316 	switch (ev->type) {
    317 		case ev_keydown:
    318 			if (ev->data1 == KEY_PAUSE) {
    319 				sendpause = true;
    320 				return true;
    321 			}
    322 			if (ev->data1 <NUMKEYS) gamekeydown[ev->data1] = true;
    323 			return true;
    324 		case ev_keyup:
    325 			if (ev->data1 <NUMKEYS) gamekeydown[ev->data1] = false;
    326 			return false;
    327 		case ev_mouse:
    328 			mousebuttons[0] = ev->data1 & 1;
    329 			mousebuttons[1] = ev->data1 & 2;
    330 			mousebuttons[2] = ev->data1 & 4;
    331 			mousex = ev->data2*(mouseSensitivity+5)/10;
    332 			mousey = ev->data3*(mouseSensitivity+5)/10;
    333 			return true;
    334 		case ev_joystick:
    335 			joybuttons[0] = ev->data1 & 1;
    336 			joybuttons[1] = ev->data1 & 2;
    337 			joybuttons[2] = ev->data1 & 4;
    338 			joybuttons[3] = ev->data1 & 8;
    339 			joyxmove = ev->data2;
    340 			joyymove = ev->data3;
    341 			return true;
    342 		default:
    343 			return false;
    344 	}
    345 }
    346 
    347 void
    348 G_Ticker()
    349 {
    350 	int	   i, buf;
    351 	ticcmd_t* cmd;
    352 
    353 
    354 	for (i = 0; i < MAXPLAYERS; ++i) if(playeringame[i] && players[i].playerstate == PST_REBORN) G_DoReborn (i);
    355 	while (gameaction != ga_nothing) {
    356 		switch (gameaction) {
    357 			case ga_loadlevel:
    358 				G_DoLoadLevel();
    359 				break;
    360 			case ga_newgame:
    361 				G_DoNewGame();
    362 				break;
    363 			case ga_loadgame:
    364 				G_DoLoadGame();
    365 				break;
    366 			case ga_savegame:
    367 				G_DoSaveGame();
    368 				break;
    369 			case ga_playdemo:
    370 				G_DoPlayDemo();
    371 				break;
    372 			case ga_completed:
    373 				G_DoCompleted();
    374 				break;
    375 			case ga_victory:
    376 				F_StartFinale();
    377 				break;
    378 			case ga_worlddone:
    379 				G_DoWorldDone();
    380 				break;
    381 			case ga_nothing:
    382 				break;
    383 		}
    384 	}
    385 	buf = (gametic/ticdup)%BACKUPTICS;
    386 	for (i = 0; i < MAXPLAYERS; ++i) {
    387 		if (playeringame[i]) {
    388 			cmd = &players[i].cmd;
    389 			memcpy (cmd, &netcmds[i][buf], sizeof(ticcmd_t));
    390 			if (demoplayback) G_ReadDemoTiccmd (cmd);
    391 			if (demorecording) G_WriteDemoTiccmd (cmd);
    392 			if (cmd->forwardmove > TURBOTHRESHOLD && !(gametic&31) && ((gametic>>5)&3) == i) {
    393 				static char turbomessage[80];
    394 				extern char *player_names[4];
    395 				sprintf (turbomessage, "%s is turbo!",player_names[i]);
    396 				players[consoleplayer].message = turbomessage;
    397 			}
    398 			if (netgame && !netdemo && !(gametic%ticdup) ) {
    399 				if (gametic > BACKUPTICS && consistancy[i][buf] != cmd->consistancy) I_Error("consistency failure (%i should be %i)", cmd->consistancy, consistancy[i][buf]);
    400 				if (players[i].mo) consistancy[i][buf] = players[i].mo->x;
    401 				else consistancy[i][buf] = rndindex;
    402 			}
    403 		}
    404 	}
    405 	for (i = 0; i < MAXPLAYERS; ++i) {
    406 		if (playeringame[i]) {
    407 			if (players[i].cmd.buttons & BT_SPECIAL){
    408 				switch (players[i].cmd.buttons & BT_SPECIALMASK) {
    409 					case BTS_PAUSE:
    410 						paused ^= 1;
    411 						if (paused) S_PauseSound ();
    412 						else S_ResumeSound ();
    413 						break;
    414 					case BTS_SAVEGAME:
    415 						if (!savedescription[0]) strcpy(savedescription, "NET GAME");
    416 						savegameslot = (players[i].cmd.buttons & BTS_SAVEMASK)>>BTS_SAVESHIFT;
    417 						gameaction = ga_savegame;
    418 						break;
    419 				}
    420 			}
    421 		}
    422 	}
    423 	switch (gamestate) {
    424 		case GS_LEVEL:
    425 			P_Ticker();
    426 			ST_Ticker();
    427 			AM_Ticker();
    428 			HU_Ticker();
    429 			break;
    430 		case GS_INTERMISSION:
    431 			WI_Ticker();
    432 			break;
    433 		case GS_FINALE:
    434 			F_Ticker();
    435 			break;
    436 		case GS_DEMOSCREEN:
    437 			D_PageTicker();
    438 			break;
    439 	}
    440 }
    441 
    442 void
    443 G_InitPlayer(int player)
    444 {
    445 	G_PlayerReborn(player);
    446 }
    447 
    448 void
    449 G_PlayerFinishLevel(int player)
    450 {
    451 	player_t*	p;
    452 
    453 	p = &players[player];
    454 	memset (p->powers, 0, sizeof (p->powers));
    455 	memset (p->cards, 0, sizeof (p->cards));
    456 	p->mo->flags &= ~MF_SHADOW;
    457 	p->extralight = 0;
    458 	p->fixedcolormap = 0;
    459 	p->damagecount = 0;
    460 	p->bonuscount = 0;
    461 }
    462 
    463 void
    464 G_PlayerReborn(int player)
    465 {
    466 	player_t*	p;
    467 	int		i, killcount, itemcount, secretcount, frags[MAXPLAYERS];
    468 
    469 	memcpy(frags,players[player].frags,sizeof(frags));
    470 	killcount = players[player].killcount;
    471 	itemcount = players[player].itemcount;
    472 	secretcount = players[player].secretcount;
    473 	p = &players[player];
    474 	memset(p, 0, sizeof(*p));
    475 	memcpy(players[player].frags, frags, sizeof(players[player].frags));
    476 	players[player].killcount = killcount;
    477 	players[player].itemcount = itemcount;
    478 	players[player].secretcount = secretcount;
    479 	p->usedown = p->attackdown = true;
    480 	p->playerstate = PST_LIVE;
    481 	p->health = MAXHEALTH;
    482 	p->readyweapon = p->pendingweapon = wp_pistol;
    483 	p->weaponowned[wp_fist] = true;
    484 	p->weaponowned[wp_pistol] = true;
    485 	p->ammo[am_clip] = 50;
    486 	for (i = 0; i < NUMAMMO; ++i) p->maxammo[i] = maxammo[i];
    487 }
    488 
    489 void P_SpawnPlayer(mapthing_t* mthing);
    490 
    491 boolean
    492 G_CheckSpot(int playernum, mapthing_t* mthing)
    493 {
    494 	subsector_t*	ss;
    495 	mobj_t*		mo;
    496 	fixed_t		x, y;
    497 	unsigned	an;
    498 	int			i;
    499 
    500 	if (!players[playernum].mo) {
    501 		for (i = 0; i < playernum; ++i)
    502 			if (players[i].mo->x == mthing->x << FRACBITS && players[i].mo->y == mthing->y << FRACBITS)
    503 				return false;
    504 		return true;
    505 	}
    506 	x = mthing->x << FRACBITS;
    507 	y = mthing->y << FRACBITS;
    508 	if (!P_CheckPosition (players[playernum].mo, x, y)) return false;
    509 	if (bodyqueslot >= BODYQUESIZE) P_RemoveMobj (bodyque[bodyqueslot%BODYQUESIZE]);
    510 	bodyque[bodyqueslot%BODYQUESIZE] = players[playernum].mo;
    511 	bodyqueslot++;
    512 	ss = R_PointInSubsector(x,y);
    513 	an = (ANG45 * (mthing->angle/45)) >> ANGLETOFINESHIFT;
    514 	mo = P_SpawnMobj (x+20*finecosine[an], y+20*finesine[an], ss->sector->floorheight, MT_TFOG);
    515 	if (players[consoleplayer].viewz != 1) S_StartSound (mo, sfx_telept);
    516 	return true;
    517 }
    518 
    519 void
    520 G_DeathMatchSpawnPlayer(int playernum)
    521 {
    522 	int i, j, selections;
    523 
    524 	selections = deathmatch_p - deathmatchstarts;
    525 	if (selections < 4) I_Error ("Only %i deathmatch spots, 4 required", selections);
    526 	for (j = 0; j < 20; ++j) {
    527 		i = P_Random() % selections;
    528 		if (G_CheckSpot (playernum, &deathmatchstarts[i])) {
    529 			deathmatchstarts[i].type = playernum+1;
    530 			P_SpawnPlayer (&deathmatchstarts[i]);
    531 			return;
    532 		}
    533 	}
    534 	P_SpawnPlayer(&playerstarts[playernum]);
    535 }
    536 
    537 void
    538 G_DoReborn(int playernum)
    539 {
    540 	int i;
    541 
    542 	if (!netgame) gameaction = ga_loadlevel;
    543 	else {
    544 		players[playernum].mo->player = NULL;
    545 		if (deathmatch) {
    546 			G_DeathMatchSpawnPlayer (playernum);
    547 			return;
    548 		}
    549 		if (G_CheckSpot(playernum, &playerstarts[playernum])) {
    550 			P_SpawnPlayer (&playerstarts[playernum]);
    551 			return;
    552 		}
    553 		for (i = 0; i < MAXPLAYERS; ++i) {
    554 			if (G_CheckSpot (playernum, &playerstarts[i])) {
    555 				playerstarts[i].type = playernum+1;
    556 				P_SpawnPlayer (&playerstarts[i]);
    557 				playerstarts[i].type = i+1;
    558 				return;
    559 			}
    560 		}
    561 		P_SpawnPlayer(&playerstarts[playernum]);
    562 	}
    563 }
    564 
    565 void
    566 G_ExitLevel()
    567 {
    568 	secretexit = false;
    569 	gameaction = ga_completed;
    570 }
    571 
    572 void
    573 G_SecretExitLevel()
    574 {
    575 	secretexit = true;
    576 	gameaction = ga_completed;
    577 }
    578 
    579 void
    580 G_DoCompleted()
    581 {
    582 	int i;
    583 
    584 	gameaction = ga_nothing;
    585 	for (i = 0; i < MAXPLAYERS; ++i)
    586 		if (playeringame[i])
    587 			G_PlayerFinishLevel (i);
    588 	if (automapactive) AM_Stop();
    589 	if (gamemap == 9)
    590 		for (i = 0; i < MAXPLAYERS; ++i) players[i].didsecret = true;
    591 	wminfo.didsecret = players[consoleplayer].didsecret;
    592 	wminfo.epsd = gameepisode -1;
    593 	wminfo.last = gamemap -1;
    594 	if (secretexit) wminfo.next = 8;
    595 	else if (gamemap == 9) {
    596 		switch (gameepisode) {
    597 		case 1:
    598 			wminfo.next = 3;
    599 			break;
    600 		case 2:
    601 			wminfo.next = 5;
    602 			break;
    603 		case 3:
    604 			wminfo.next = 6;
    605 			break;
    606 		case 4:
    607 			wminfo.next = 2;
    608 			break;
    609 		}
    610 	} else wminfo.next = gamemap;
    611 	wminfo.maxkills = totalkills;
    612 	wminfo.maxitems = totalitems;
    613 	wminfo.maxsecret = totalsecret;
    614 	wminfo.maxfrags = 0;
    615 	wminfo.partime = 35*pars[gameepisode][gamemap];
    616 	wminfo.pnum = consoleplayer;
    617 	for (i = 0; i < MAXPLAYERS; ++i) {
    618 		wminfo.plyr[i].in = playeringame[i];
    619 		wminfo.plyr[i].skills = players[i].killcount;
    620 		wminfo.plyr[i].sitems = players[i].itemcount;
    621 		wminfo.plyr[i].ssecret = players[i].secretcount;
    622 		wminfo.plyr[i].stime = leveltime; memcpy(wminfo.plyr[i].frags, players[i].frags, sizeof(wminfo.plyr[i].frags));
    623 	}
    624 	gamestate = GS_INTERMISSION;
    625 	viewactive = false;
    626 	automapactive = false;
    627 	if (statcopy) memcpy(statcopy, &wminfo, sizeof(wminfo));
    628 	WI_Start (&wminfo);
    629 }
    630 
    631 void
    632 G_WorldDone()
    633 {
    634 	gameaction = ga_worlddone;
    635 	if (secretexit) players[consoleplayer].didsecret = true;
    636 }
    637 
    638 void
    639 G_DoWorldDone()
    640 {
    641 	gamestate = GS_LEVEL;
    642 	gamemap = wminfo.next+1;
    643 	G_DoLoadLevel();
    644 	gameaction = ga_nothing;
    645 	viewactive = true;
    646 }
    647 
    648 char	savename[256];
    649 
    650 void G_LoadGame (char* name)
    651 {
    652 	strcpy (savename, name);
    653 	gameaction = ga_loadgame;
    654 }
    655 
    656 void
    657 G_DoLoadGame()
    658 {
    659 	int		i, a, b, c;
    660 	char	vcheck[VERSIONSIZE];
    661 
    662 	gameaction = ga_nothing;
    663 	M_ReadFile(savename, &savebuffer);
    664 	save_p = savebuffer + SAVESTRINGSIZE;
    665 	memset(vcheck, 0, sizeof(vcheck));
    666 	sprintf (vcheck, "version %i", VERSION);
    667 	if (strcmp ((char*)save_p, vcheck)) return;
    668 	save_p += VERSIONSIZE;
    669 	gameskill = *save_p++;
    670 	gameepisode = *save_p++;
    671 	gamemap = *save_p++;
    672 	for (i = 0; i < MAXPLAYERS; ++i) playeringame[i] = *save_p++;
    673 	G_InitNew(gameskill, gameepisode, gamemap);
    674 	a = *save_p++;
    675 	b = *save_p++;
    676 	c = *save_p++;
    677 	leveltime = (a<<16) + (b<<8) + c;
    678 	P_UnArchivePlayers();
    679 	P_UnArchiveWorld();
    680 	P_UnArchiveThinkers();
    681 	P_UnArchiveSpecials();
    682 	if (*save_p != 0x1d) I_Error("Bad savegame");
    683 	Z_Free(savebuffer);
    684 	if (setsizeneeded) R_ExecuteSetViewSize();
    685 	R_FillBackScreen();
    686 }
    687 
    688 void
    689 G_SaveGame(int slot, char* description)
    690 {
    691 	savegameslot = slot;
    692 	strcpy(savedescription, description);
    693 	sendsave = true;
    694 }
    695 
    696 void
    697 G_DoSaveGame()
    698 {
    699 	char*	description;
    700 	char	name[100];
    701 	char	name2[VERSIONSIZE];
    702 	int		i, length;
    703 
    704 	if (M_CheckParm("-cdrom"))
    705 		sprintf(name, "c:\\doomdata\\%s%d.dsg", lang[SAVEGAMENAME], savegameslot);
    706 	else
    707 		sprintf(name, "%s%d.dsg", lang[SAVEGAMENAME], savegameslot);
    708 	description = savedescription;
    709 	save_p = savebuffer = screens[1]+0x4000;
    710 	memcpy (save_p, description, SAVESTRINGSIZE);
    711 	save_p += SAVESTRINGSIZE;
    712 	memset (name2,0,sizeof(name2));
    713 	sprintf (name2,"version %i",VERSION);
    714 	memcpy (save_p, name2, VERSIONSIZE);
    715 	save_p += VERSIONSIZE;
    716 	*save_p++ = gameskill;
    717 	*save_p++ = gameepisode;
    718 	*save_p++ = gamemap;
    719 	for (i=0 ; i<MAXPLAYERS ; i++)
    720 	*save_p++ = playeringame[i];
    721 	*save_p++ = leveltime>>16;
    722 	*save_p++ = leveltime>>8;
    723 	*save_p++ = leveltime;
    724 	P_ArchivePlayers();
    725 	P_ArchiveWorld();
    726 	P_ArchiveThinkers();
    727 	P_ArchiveSpecials();
    728 	*save_p++ = 0x1d;
    729 	length = save_p - savebuffer;
    730 	if (length > SAVEGAMESIZE) I_Error("Savegame buffer overrun");
    731 	M_WriteFile(name, savebuffer, length);
    732 	gameaction = ga_nothing;
    733 	savedescription[0] = 0;
    734 	players[consoleplayer].message = lang[GGSAVED];
    735 	R_FillBackScreen();
    736 }
    737 
    738 void
    739 G_DeferedInitNew(skill_t skill, int episode, int map)
    740 {
    741 	d_skill = skill;
    742 	d_episode = episode;
    743 	d_map = map;
    744 	gameaction = ga_newgame;
    745 }
    746 
    747 void
    748 G_DoNewGame()
    749 {
    750 	demoplayback = false;
    751 	netdemo = false;
    752 	netgame = false;
    753 	deathmatch = false;
    754 	playeringame[1] = playeringame[2] = playeringame[3] = 0;
    755 	respawnparm = false;
    756 	fastparm = false;
    757 	nomonsters = false;
    758 	consoleplayer = 0;
    759 	G_InitNew (d_skill, d_episode, d_map);
    760 	gameaction = ga_nothing;
    761 }
    762 
    763 void
    764 G_InitNew(skill_t skill, int episode, int map)
    765 {
    766 	int i;
    767 
    768 	if (paused) {
    769 		paused = false;
    770 		S_ResumeSound();
    771 	}
    772 	if (skill > sk_nightmare)
    773 		skill = sk_nightmare;
    774 	episode = 1;
    775 	if (map < 1) map = 1;
    776 	if (map > 9) map = 9;
    777 	M_ClearRandom();
    778 	if (skill == sk_nightmare || respawnparm)
    779 		respawnmonsters = true;
    780 	else respawnmonsters = false;
    781 	if (fastparm || (skill == sk_nightmare && gameskill != sk_nightmare)) {
    782 		for (i = S_SARG_RUN1; i <= S_SARG_PAIN2; ++i) states[i].tics >>= 1;
    783 		mobjinfo[MT_BRUISERSHOT].speed = 20*FRACUNIT;
    784 		mobjinfo[MT_HEADSHOT].speed = 20*FRACUNIT;
    785 		mobjinfo[MT_TROOPSHOT].speed = 20*FRACUNIT;
    786 	}
    787 	if (skill != sk_nightmare && gameskill == sk_nightmare) {
    788 		for (i = S_SARG_RUN1; i <= S_SARG_PAIN2; ++i) states[i].tics <<= 1;
    789 		mobjinfo[MT_BRUISERSHOT].speed = 15*FRACUNIT;
    790 		mobjinfo[MT_HEADSHOT].speed = 10*FRACUNIT;
    791 		mobjinfo[MT_TROOPSHOT].speed = 10*FRACUNIT;
    792 	}
    793 	for (i = 0; i < MAXPLAYERS;  ++i) players[i].playerstate = PST_REBORN;
    794 	usergame = true;
    795 	paused = false;
    796 	demoplayback = false;
    797 	automapactive = false;
    798 	viewactive = true;
    799 	gameepisode = episode;
    800 	gamemap = map;
    801 	gameskill = skill;
    802 	viewactive = true;
    803 	switch(episode) {
    804 		case 1:
    805 			skytexture = R_TextureNumForName("SKY1");
    806 			break;
    807 		case 2:
    808 			skytexture = R_TextureNumForName("SKY2");
    809 			break;
    810 		case 3:
    811 			skytexture = R_TextureNumForName("SKY3");
    812 			break;
    813 		case 4:
    814 			skytexture = R_TextureNumForName("SKY4");
    815 			break;
    816 	}
    817 	G_DoLoadLevel();
    818 }
    819 
    820 void
    821 G_ReadDemoTiccmd(ticcmd_t* cmd)
    822 {
    823 	if (*demo_p == DEMOMARKER) {
    824 		G_CheckDemoStatus();
    825 		return;
    826 	}
    827 	cmd->forwardmove = ((signed char)*demo_p++);
    828 	cmd->sidemove = ((signed char)*demo_p++);
    829 	cmd->angleturn = ((unsigned char)*demo_p++)<<8;
    830 	cmd->buttons = (unsigned char)*demo_p++;
    831 }
    832 
    833 void
    834 G_WriteDemoTiccmd(ticcmd_t* cmd)
    835 {
    836 	if (gamekeydown['q']) G_CheckDemoStatus();
    837 	*demo_p++ = cmd->forwardmove;
    838 	*demo_p++ = cmd->sidemove;
    839 	*demo_p++ = (cmd->angleturn+128)>>8;
    840 	*demo_p++ = cmd->buttons;
    841 	demo_p -= 4;
    842 	if (demo_p > demoend - 16) {
    843 		G_CheckDemoStatus();
    844 		return;
    845 	}
    846 	G_ReadDemoTiccmd(cmd);
    847 }
    848 
    849 void
    850 G_BeginRecording()
    851 {
    852 	int i;
    853 
    854 	demo_p = demobuffer;
    855 	*demo_p++ = VERSION;
    856 	*demo_p++ = gameskill;
    857 	*demo_p++ = gameepisode;
    858 	*demo_p++ = gamemap;
    859 	*demo_p++ = deathmatch;
    860 	*demo_p++ = respawnparm;
    861 	*demo_p++ = fastparm;
    862 	*demo_p++ = nomonsters;
    863 	*demo_p++ = consoleplayer;
    864 	for (i = 0; i < MAXPLAYERS; ++i)
    865 	*demo_p++ = playeringame[i];
    866 }
    867 
    868 void
    869 G_DeferedPlayDemo(char* name)
    870 {
    871 	defdemoname = name;
    872 	gameaction = ga_playdemo;
    873 }
    874 
    875 void
    876 G_DoPlayDemo()
    877 {
    878 	skill_t skill;
    879 	int     i, episode, map;
    880 
    881 	gameaction = ga_nothing;
    882 	demobuffer = demo_p = W_CacheLumpName (defdemoname, PU_STATIC);
    883 	if (*demo_p++ != VERSION) {
    884 		fprintf( stderr, "Demo is from a different game version!\n");
    885 		gameaction = ga_nothing;
    886 		return;
    887 	}
    888 
    889 	skill = *demo_p++;
    890 	episode = *demo_p++;
    891 	map = *demo_p++;
    892 	deathmatch = *demo_p++;
    893 	respawnparm = *demo_p++;
    894 	fastparm = *demo_p++;
    895 	nomonsters = *demo_p++;
    896 	consoleplayer = *demo_p++;
    897 	for (i = 0; i < MAXPLAYERS; ++i) playeringame[i] = *demo_p++;
    898 	if (playeringame[1]) {
    899 		netgame = true;
    900 		netdemo = true;
    901 	}
    902 	precache = false;
    903 	G_InitNew(skill, episode, map);
    904 	precache = true;
    905 	usergame = false;
    906 	demoplayback = true;
    907 }
    908 
    909 boolean
    910 G_CheckDemoStatus()
    911 {
    912 	int endtime;
    913 
    914 	if (timingdemo) {
    915 		endtime = I_GetTime();
    916 		I_Error("timed %i gametics in %i realtics", gametic , endtime-starttime);
    917 	}
    918 	if (demoplayback) {
    919 		if (singledemo) I_Quit ();
    920 		Z_ChangeTag(demobuffer, PU_CACHE);
    921 		demoplayback = false;
    922 		netdemo = false;
    923 		netgame = false;
    924 		deathmatch = false;
    925 		playeringame[1] = playeringame[2] = playeringame[3] = 0;
    926 		respawnparm = false;
    927 		fastparm = false;
    928 		nomonsters = false;
    929 		consoleplayer = 0;
    930 		D_AdvanceDemo();
    931 		return true;
    932 	}
    933 	if (demorecording) {
    934 		*demo_p++ = DEMOMARKER;
    935 		M_WriteFile(demoname, demobuffer, demo_p - demobuffer);
    936 		Z_Free(demobuffer);
    937 		demorecording = false;
    938 		I_Error("Demo %s recorded",demoname);
    939 	}
    940 	return false;
    941 }