1 // Emacs style mode select   -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: g_level.cpp 4664 2014-03-21 19:57:19Z dr_sean $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Copyright (C) 1998-2006 by Randy Heit (ZDoom).
8 // Copyright (C) 2006-2014 by The Odamex Team.
9 //
10 // This program is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU General Public License
12 // as published by the Free Software Foundation; either version 2
13 // of the License, or (at your option) any later version.
14 //
15 // This program is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 // GNU General Public License for more details.
19 //
20 // DESCRIPTION:
21 //	G_LEVEL
22 //
23 //-----------------------------------------------------------------------------
24 
25 #include <set>
26 
27 #include "am_map.h"
28 #include "c_console.h"
29 #include "c_dispatch.h"
30 #include "c_level.h"
31 #include "cl_main.h"
32 #include "d_event.h"
33 #include "d_main.h"
34 #include "doomstat.h"
35 #include "f_finale.h"
36 #include "g_level.h"
37 #include "g_game.h"
38 #include "gstrings.h"
39 #include "gi.h"
40 #include "hu_stuff.h"
41 #include "i_system.h"
42 #include "m_alloc.h"
43 #include "m_fileio.h"
44 #include "m_misc.h"
45 #include "minilzo.h"
46 #include "m_random.h"
47 #include "p_acs.h"
48 #include "p_ctf.h"
49 #include "p_local.h"
50 #include "p_mobj.h"
51 #include "p_saveg.h"
52 #include "p_setup.h"
53 #include "p_unlag.h"
54 #include "r_data.h"
55 #include "r_sky.h"
56 #include "s_sound.h"
57 #include "s_sndseq.h"
58 #include "sc_man.h"
59 #include "st_stuff.h"
60 #include "v_video.h"
61 #include "v_text.h"
62 #include "w_wad.h"
63 #include "wi_stuff.h"
64 #include "z_zone.h"
65 
66 
67 #define lioffset(x)		myoffsetof(level_pwad_info_t,x)
68 #define cioffset(x)		myoffsetof(cluster_info_t,x)
69 
70 bool G_CheckSpot (player_t &player, mapthing2_t *mthing);
71 void P_SpawnPlayer (player_t &player, mapthing2_t *mthing);
72 void R_ResetInterpolation();
73 
74 extern int shotclock;
75 
76 EXTERN_CVAR(sv_fastmonsters)
77 EXTERN_CVAR(sv_monstersrespawn)
78 EXTERN_CVAR(sv_gravity)
79 EXTERN_CVAR(sv_aircontrol)
80 
81 // Start time for timing demos
82 dtime_t starttime;
83 
84 // ACS variables with world scope
85 int ACS_WorldVars[NUM_WORLDVARS];
86 
87 // ACS variables with global scope
88 int ACS_GlobalVars[NUM_GLOBALVARS];
89 
90 // [AM] Stores the reset snapshot
91 FLZOMemFile	*reset_snapshot = NULL;
92 
93 extern bool r_underwater;
94 BOOL savegamerestore;
95 
96 extern int mousex, mousey, joyforward, joystrafe, joyturn, joylook, Impulse;
97 extern BOOL sendpause, sendsave, sendcenterview;
98 
99 
100 bool isFast = false;
101 
102 //
103 // G_InitNew
104 // Can be called by the startup code or the menu task,
105 // consoleplayer, displayplayer, should be set.
106 //
107 static char d_mapname[9];
108 
G_DeferedInitNew(char * mapname)109 void G_DeferedInitNew (char *mapname)
110 {
111 	G_CleanupDemo();
112 	strncpy (d_mapname, mapname, 8);
113 	gameaction = ga_newgame;
114 }
115 
116 
BEGIN_COMMAND(wad)117 BEGIN_COMMAND (wad) // denis - changes wads
118 {
119 	// [Russell] print out some useful info
120 	if (argc == 1)
121 	{
122 	    Printf(PRINT_HIGH, "Usage: wad pwad [...] [deh/bex [...]]\n");
123 	    Printf(PRINT_HIGH, "       wad iwad [pwad [...]] [deh/bex [...]]\n");
124 	    Printf(PRINT_HIGH, "\n");
125 	    Printf(PRINT_HIGH, "Load a wad file on the fly, pwads/dehs/bexs require extension\n");
126 	    Printf(PRINT_HIGH, "eg: wad doom\n");
127 
128 	    return;
129 	}
130 
131 	if (paused)
132 	{
133 		paused = false;
134 		S_ResumeSound ();
135 	}
136 
137 	C_HideConsole();
138 
139 	std::string str = JoinStrings(VectorArgs(argc, argv), " ");
140 	G_LoadWad(str);
141 
142 	D_StartTitle ();
143 	CL_QuitNetGame();
144 	S_StopMusic();
145 	S_StartMusic(gameinfo.titleMusic);
146 }
147 END_COMMAND (wad)
148 
EXTERN_CVAR(sv_allowexit)149 EXTERN_CVAR(sv_allowexit)
150 EXTERN_CVAR(sv_nomonsters)
151 EXTERN_CVAR(sv_freelook)
152 EXTERN_CVAR(sv_allowjump)
153 
154 void G_DoNewGame (void)
155 {
156 	if (demoplayback)
157 	{
158 		cvar_t::C_RestoreCVars ();
159 		demoplayback = false;
160 		D_SetupUserInfo ();
161 	}
162 
163 	CL_QuitNetGame();
164 
165 	netgame = false;
166 	multiplayer = false;
167 
168 	// denis - single player warp (like in d_main)
169 	serverside = true;
170 
171 	players.clear();
172 	players.push_back(player_t());
173 	players.back().playerstate = PST_REBORN;
174 	consoleplayer_id = displayplayer_id = players.back().id = 1;
175 
176 	G_InitNew (d_mapname);
177 	gameaction = ga_nothing;
178 }
179 
G_InitNew(const char * mapname)180 void G_InitNew (const char *mapname)
181 {
182 	size_t i;
183 
184 	// [RH] Remove all particles
185 	R_ClearParticles ();
186 
187 	for (Players::iterator it = players.begin();it != players.end();++it)
188 	{
189 		it->mo = AActor::AActorPtr();
190 		it->camera = AActor::AActorPtr();
191 		it->attacker = AActor::AActorPtr();
192 	}
193 
194 	if (!savegamerestore)
195 		G_ClearSnapshots ();
196 
197 	// [RH] Mark all levels as not visited
198 	if (!savegamerestore)
199 	{
200 		for (i = 0; i < wadlevelinfos.size(); i++)
201 			wadlevelinfos[i].flags &= ~LEVEL_VISITED;
202 
203 		for (i = 0; LevelInfos[i].mapname[0]; i++)
204 			LevelInfos[i].flags &= ~LEVEL_VISITED;
205 	}
206 
207 	cvar_t::UnlatchCVars ();
208 
209 	if (sv_skill > sk_nightmare)
210 		sv_skill.Set (sk_nightmare);
211 	else if (sv_skill < sk_baby)
212 		sv_skill.Set (sk_baby);
213 
214 	cvar_t::UnlatchCVars ();
215 
216 	if (paused)
217 	{
218 		paused = false;
219 		S_ResumeSound ();
220 	}
221 
222 	// If were in chasecam mode, clear out // [Toke - fix]
223 	if ((consoleplayer().cheats & CF_CHASECAM))
224 	{
225 		consoleplayer().cheats &= ~CF_CHASECAM;
226 	}
227 
228 	// [RH] If this map doesn't exist, bomb out
229 	if (W_CheckNumForName (mapname) == -1)
230 	{
231 		I_Error ("Could not find map %s\n", mapname);
232 	}
233 
234 	if (sv_skill == sk_nightmare || sv_monstersrespawn)
235 		respawnmonsters = true;
236 	else
237 		respawnmonsters = false;
238 
239 	bool wantFast = sv_fastmonsters || (sv_skill == sk_nightmare);
240 	if (wantFast != isFast)
241 	{
242 		if (wantFast)
243 		{
244 			for (i=S_SARG_RUN1 ; i<=S_SARG_PAIN2 ; i++)
245 				states[i].tics >>= 1;
246 			mobjinfo[MT_BRUISERSHOT].speed = 20*FRACUNIT;
247 			mobjinfo[MT_HEADSHOT].speed = 20*FRACUNIT;
248 			mobjinfo[MT_TROOPSHOT].speed = 20*FRACUNIT;
249 		}
250 		else
251 		{
252 			for (i=S_SARG_RUN1 ; i<=S_SARG_PAIN2 ; i++)
253 				states[i].tics <<= 1;
254 			mobjinfo[MT_BRUISERSHOT].speed = 15*FRACUNIT;
255 			mobjinfo[MT_HEADSHOT].speed = 10*FRACUNIT;
256 			mobjinfo[MT_TROOPSHOT].speed = 10*FRACUNIT;
257 		}
258 		isFast = wantFast;
259 	}
260 
261 	if (!savegamerestore)
262 	{
263 		M_ClearRandom ();
264 		memset (ACS_WorldVars, 0, sizeof(ACS_WorldVars));
265 		memset (ACS_GlobalVars, 0, sizeof(ACS_GlobalVars));
266 		level.time = 0;
267 		level.timeleft = 0;
268 		level.inttimeleft = 0;
269 
270 		// force players to be initialized upon first level load
271 		for (Players::iterator it = players.begin();it != players.end();++it)
272 			it->playerstate = PST_ENTER; // [BC]
273 	}
274 
275 	usergame = true;				// will be set false if a demo
276 	paused = false;
277 	demoplayback = false;
278 	automapactive = false;
279 	viewactive = true;
280 	shotclock = 0;
281 
282 	D_SetupUserInfo();
283 
284 	strncpy (level.mapname, mapname, 8);
285 	G_DoLoadLevel (0);
286 }
287 
288 //
289 // G_DoCompleted
290 //
291 BOOL 			secretexit;
292 static int		startpos;	// [RH] Support for multiple starts per level
293 extern BOOL		NoWipe;		// [RH] Don't wipe when travelling in hubs
294 
295 // [RH] The position parameter to these next three functions should
296 //		match the first parameter of the single player start spots
297 //		that should appear in the next map.
goOn(int position)298 static void goOn (int position)
299 {
300 	cluster_info_t *thiscluster = FindClusterInfo (level.cluster);
301 	cluster_info_t *nextcluster = FindClusterInfo (FindLevelInfo (level.nextmap)->cluster);
302 
303 	startpos = position;
304 	gameaction = ga_completed;
305 
306 	if (thiscluster && (thiscluster->flags & CLUSTER_HUB))
307 	{
308 		if ((level.flags & LEVEL_NOINTERMISSION) || (nextcluster == thiscluster))
309 			NoWipe = 4;
310 		D_DrawIcon = "TELEICON";
311 	}
312 }
313 
G_ExitLevel(int position,int drawscores)314 void G_ExitLevel (int position, int drawscores)
315 {
316 	secretexit = false;
317 	shotclock = 0;
318 
319 	goOn (position);
320 
321 	//gameaction = ga_completed;
322 }
323 
324 // Here's for the german edition.
G_SecretExitLevel(int position,int drawscores)325 void G_SecretExitLevel (int position, int drawscores)
326 {
327 	// IF NO WOLF3D LEVELS, NO SECRET EXIT!
328 	if ( (gameinfo.flags & GI_MAPxx)
329 		 && (W_CheckNumForName("map31")<0))
330 		secretexit = false;
331 	else
332 		secretexit = true;
333 
334 	shotclock = 0;
335 
336     goOn (position);
337 	//gameaction = ga_completed;
338 }
339 
G_DoCompleted(void)340 void G_DoCompleted (void)
341 {
342 	size_t i;
343 
344 	gameaction = ga_nothing;
345 
346 	for (Players::iterator it = players.begin();it != players.end();++it)
347 		if (it->ingame())
348 			G_PlayerFinishLevel(*it);
349 
350 	V_RestoreScreenPalette();
351 
352 	// [RH] Mark this level as having been visited
353 	if (!(level.flags & LEVEL_CHANGEMAPCHEAT))
354 		FindLevelInfo (level.mapname)->flags |= LEVEL_VISITED;
355 
356 	if (automapactive)
357 		AM_Stop ();
358 
359 	// [ML] Chex mode: they didn't even show the intermission screen
360 	// after the fifth level - I checked.
361 	if (gamemode == retail_chex && !strncmp(level.mapname,"E1M5",4)) {
362 		G_WorldDone();
363 		return;
364 	}
365 
366 	wminfo.epsd = level.cluster - 1;		// Only used for DOOM I.
367 	strncpy (wminfo.lname0, level.info->pname, 8);
368 	strncpy (wminfo.current, level.mapname, 8);
369 
370 	if (sv_gametype != GM_COOP &&
371 		!(level.flags & LEVEL_CHANGEMAPCHEAT)) {
372 		strncpy (wminfo.next, level.mapname, 8);
373 		strncpy (wminfo.lname1, level.info->pname, 8);
374 	} else {
375 		wminfo.next[0] = 0;
376 		if (secretexit) {
377 			if (W_CheckNumForName (level.secretmap) != -1) {
378 				strncpy (wminfo.next, level.secretmap, 8);
379 				strncpy (wminfo.lname1, FindLevelInfo (level.secretmap)->pname, 8);
380 			} else {
381 				secretexit = false;
382 			}
383 		}
384 		if (!wminfo.next[0]) {
385 			strncpy (wminfo.next, level.nextmap, 8);
386 			strncpy (wminfo.lname1, FindLevelInfo (level.nextmap)->pname, 8);
387 		}
388 	}
389 
390 	wminfo.maxkills = level.total_monsters;
391 	wminfo.maxitems = level.total_items;
392 	wminfo.maxsecret = level.total_secrets;
393 	wminfo.maxfrags = 0;
394 	wminfo.partime = TICRATE * level.partime;
395 
396 	wminfo.plyr.resize(players.size());
397 
398 	i = 0;
399 	for (Players::iterator it = players.begin();it != players.end();++it,++i)
400 	{
401 		wminfo.plyr[i].in = it->ingame();
402 		wminfo.plyr[i].skills = it->killcount;
403 		wminfo.plyr[i].sitems = it->itemcount;
404 		wminfo.plyr[i].ssecret = it->secretcount;
405 		wminfo.plyr[i].stime = level.time;
406 		//memcpy (wminfo.plyr[i].frags, players[i].frags
407 		//		, sizeof(wminfo.plyr[i].frags));
408 		wminfo.plyr[i].fragcount = it->fragcount;
409 
410 		if(&*it == &consoleplayer())
411 			wminfo.pnum = i;
412 	}
413 
414 	// [RH] If we're in a hub and staying within that hub, take a snapshot
415 	//		of the level. If we're traveling to a new hub, take stuff from
416 	//		the player and clear the world vars. If this is just an
417 	//		ordinary cluster (not a hub), take stuff from the player, but
418 	//		leave the world vars alone.
419 	{
420 		cluster_info_t *thiscluster = FindClusterInfo (level.cluster);
421 		cluster_info_t *nextcluster = FindClusterInfo (FindLevelInfo (level.nextmap)->cluster);
422 
423 		if (thiscluster != nextcluster ||
424 			sv_gametype == GM_DM ||
425 			!(thiscluster->flags & CLUSTER_HUB)) {
426 			for (Players::iterator it = players.begin();it != players.end();++it)
427 				if (it->ingame())
428 					G_PlayerFinishLevel(*it); // take away cards and stuff
429 
430 				if (nextcluster->flags & CLUSTER_HUB) {
431 					memset (ACS_WorldVars, 0, sizeof(ACS_WorldVars));
432 					P_RemoveDefereds ();
433 					G_ClearSnapshots ();
434 				}
435 		} else {
436 			G_SnapshotLevel ();
437 		}
438 		if (!(nextcluster->flags & CLUSTER_HUB) || !(thiscluster->flags & CLUSTER_HUB))
439 		{
440 			level.time = 0;	// Reset time to zero if not entering/staying in a hub
441 			level.timeleft = 0;
442 			//level.inttimeleft = 0;
443 		}
444 
445 		if (!(sv_gametype == GM_DM) &&
446 			((level.flags & LEVEL_NOINTERMISSION) ||
447 			((nextcluster == thiscluster) && (thiscluster->flags & CLUSTER_HUB)))) {
448 			G_WorldDone ();
449 			return;
450 		}
451 	}
452 
453 	gamestate = GS_INTERMISSION;
454 	viewactive = false;
455 	automapactive = false;
456 
457 	WI_Start (&wminfo);
458 }
459 
460 //
461 // G_DoLoadLevel
462 //
463 extern gamestate_t 	wipegamestate;
464 
465 
G_DoLoadLevel(int position)466 void G_DoLoadLevel (int position)
467 {
468 	static int lastposition = 0;
469 	size_t i;
470 
471 	if (position == -1)
472 		position = lastposition;
473 	else
474 		lastposition = position;
475 
476 	cvar_t::UnlatchCVars();
477 
478 	G_InitLevelLocals ();
479 
480     Printf_Bold ("\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36"
481                  "\36\36\36\36\36\36\36\36\36\36\36\36\37\n"
482                  "%s: \"%s\"\n\n", level.mapname, level.level_name);
483 
484 	if (wipegamestate == GS_LEVEL)
485 		wipegamestate = GS_FORCEWIPE;
486 
487 	if(gamestate != GS_DEMOSCREEN && ConsoleState == c_down)
488 		C_HideConsole();
489 
490 	gamestate = GS_LEVEL;
491 
492 	// [SL] clear the saved sector data from the last level
493 	R_ResetInterpolation();
494 
495 	// Set the sky map.
496 	// First thing, we have a dummy sky texture name,
497 	//	a flat. The data is in the WAD only because
498 	//	we look for an actual index, instead of simply
499 	//	setting one.
500 	skyflatnum = R_FlatNumForName ( SKYFLATNAME );
501 
502 	// DOOM determines the sky texture to be used
503 	// depending on the current episode, and the game version.
504 	// [RH] Fetch sky parameters from level_locals_t.
505 	// [ML] 5/11/06 - remove sky2 remenants
506 	// [SL] 2012-03-19 - Add sky2 back
507 	sky1texture = R_TextureNumForName (level.skypic);
508 	if (strlen(level.skypic2))
509 		sky2texture = R_TextureNumForName (level.skypic2);
510 	else
511 		sky2texture = 0;
512 
513 	// [RH] Set up details about sky rendering
514 	R_InitSkyMap ();
515 
516 	for (Players::iterator it = players.begin();it != players.end();++it)
517 	{
518 		if (it->ingame() && it->playerstate == PST_DEAD)
519 			it->playerstate = PST_REBORN;
520 
521 		// [AM] If sv_keepkeys is on, players might still be carrying keys, so
522 		//      make sure they're gone.
523 		for (size_t j = 0; j < NUMCARDS; j++)
524 			it->cards[j] = false;
525 
526 		it->fragcount = 0;
527 		it->itemcount = 0;
528 		it->secretcount = 0;
529 		it->deathcount = 0; // [Toke - Scores - deaths]
530 		it->killcount = 0; // [deathz0r] Coop kills
531 		it->points = 0;
532 	}
533 
534 	// initialize the msecnode_t freelist.					phares 3/25/98
535 	// any nodes in the freelist are gone by now, cleared
536 	// by Z_FreeTags() when the previous level ended or player
537 	// died.
538 
539 	{
540 		extern msecnode_t *headsecnode; // phares 3/25/98
541 		headsecnode = NULL;
542 
543 		// denis - todo - wtf is this crap?
544 		// [RH] Need to prevent the AActor destructor from trying to
545 		//		free the nodes
546 		AActor *actor;
547 		TThinkerIterator<AActor> iterator;
548 
549 		while ( (actor = iterator.Next ()) )
550 			actor->touching_sectorlist = NULL;
551 	}
552 
553  	SN_StopAllSequences (); // denis - todo - equivalent?
554 	P_SetupLevel (level.mapname, position);
555 
556 	// [SL] 2011-09-18 - Find an alternative start if the single player start
557 	// point is not availible.
558 	if (!multiplayer && !consoleplayer().mo && consoleplayer().ingame())
559 	{
560 		// Check for a co-op start point
561 		for (size_t n = 0; n < playerstarts.size() && !consoleplayer().mo; n++)
562 		{
563 			if (G_CheckSpot(consoleplayer(), &playerstarts[n]))
564 				P_SpawnPlayer(consoleplayer(), &playerstarts[n]);
565 		}
566 
567 		// Check for a free deathmatch start point
568 		for (int n = 0; n < deathmatch_p - deathmatchstarts && !consoleplayer().mo; n++)
569 		{
570 			if (G_CheckSpot(consoleplayer(), &deathmatchstarts[n]))
571 				P_SpawnPlayer(consoleplayer(), &deathmatchstarts[n]);
572 		}
573 
574 		// Check for a free team start point
575 		for (int n = 0; n < blueteam_p - blueteamstarts && !consoleplayer().mo; n++)
576 		{
577 			if (G_CheckSpot(consoleplayer(), &blueteamstarts[n]))
578 				P_SpawnPlayer(consoleplayer(), &blueteamstarts[n]);
579 		}
580 
581 		// Check for a free team start point
582 		for (int n = 0; n <redteam_p - redteamstarts && !consoleplayer().mo; n++)
583 		{
584 			if (G_CheckSpot(consoleplayer(), &redteamstarts[n]))
585 				P_SpawnPlayer(consoleplayer(), &redteamstarts[n]);
586 		}
587 	}
588 
589 	displayplayer_id = consoleplayer_id;				// view the guy you are playing
590 	ST_Start();		// [RH] Make sure status bar knows who we are
591 	gameaction = ga_nothing;
592 	Z_CheckHeap ();
593 
594 	// clear cmd building stuff // denis - todo - could we get rid of this?
595 	Impulse = 0;
596 	for (i = 0; i < NUM_ACTIONS; i++)
597 		if (i != ACTION_MLOOK && i != ACTION_KLOOK)
598 			Actions[i] = 0;
599 	joyforward = joystrafe = joyturn = joylook = 0;
600 	mousex = mousey = 0;
601 	sendpause = sendsave = paused = sendcenterview = false;
602 
603 	if (timingdemo)
604 	{
605 		static BOOL firstTime = true;
606 
607 		if (firstTime)
608 		{
609 			starttime = I_MSTime();
610 			firstTime = false;
611 		}
612 	}
613 
614 	level.starttime = I_MSTime() * TICRATE / 1000;
615 	G_UnSnapshotLevel (!savegamerestore);	// [RH] Restore the state of the level.
616     P_DoDeferedScripts ();	// [RH] Do script actions that were triggered on another map.
617 
618 	C_FlushDisplay ();
619 }
620 
621 //
622 // G_WorldDone
623 //
G_WorldDone(void)624 void G_WorldDone (void)
625 {
626 	cluster_info_t *nextcluster;
627 	cluster_info_t *thiscluster;
628 
629 	gameaction = ga_worlddone;
630 
631 	if (level.flags & LEVEL_CHANGEMAPCHEAT)
632 		return;
633 
634 	thiscluster = FindClusterInfo (level.cluster);
635 	if (!strncmp (level.nextmap, "EndGame", 7) || (gamemode == retail_chex && !strncmp (level.nextmap, "E1M6", 4))) {
636 		automapactive = false;
637 		F_StartFinale (thiscluster->messagemusic, thiscluster->finaleflat, thiscluster->exittext);
638 	} else {
639 		if (!secretexit)
640 			nextcluster = FindClusterInfo (FindLevelInfo (level.nextmap)->cluster);
641 		else
642 			nextcluster = FindClusterInfo (FindLevelInfo (level.secretmap)->cluster);
643 
644 		if (nextcluster->cluster != level.cluster && sv_gametype == GM_COOP) {
645 			// Only start the finale if the next level's cluster is different
646 			// than the current one and we're not in deathmatch.
647 			if (nextcluster->entertext) {
648 				automapactive = false;
649 				F_StartFinale (nextcluster->messagemusic, nextcluster->finaleflat, nextcluster->entertext);
650 			} else if (thiscluster->exittext) {
651 				automapactive = false;
652 				F_StartFinale (thiscluster->messagemusic, thiscluster->finaleflat, thiscluster->exittext);
653 			}
654 		}
655 	}
656 }
657 
658 
659 
660 
661 VERSION_CONTROL (g_level_cpp, "$Id: g_level.cpp 4664 2014-03-21 19:57:19Z dr_sean $")
662