1 //**************************************************************************
2 //**
3 //**	##   ##    ##    ##   ##   ####     ####   ###     ###
4 //**	##   ##  ##  ##  ##   ##  ##  ##   ##  ##  ####   ####
5 //**	 ## ##  ##    ##  ## ##  ##    ## ##    ## ## ## ## ##
6 //**	 ## ##  ########  ## ##  ##    ## ##    ## ##  ###  ##
7 //**	  ###   ##    ##   ###    ##  ##   ##  ##  ##       ##
8 //**	   #    ##    ##    #      ####     ####   ##       ##
9 //**
10 //**	$Id: p_levelinfo.cpp 4297 2010-06-03 22:49:00Z firebrand_kh $
11 //**
12 //**	Copyright (C) 1999-2006 Jānis Legzdiņš
13 //**
14 //**	This program is free software; you can redistribute it and/or
15 //**  modify it under the terms of the GNU General Public License
16 //**  as published by the Free Software Foundation; either version 2
17 //**  of the License, or (at your option) any later version.
18 //**
19 //**	This program is distributed in the hope that it will be useful,
20 //**  but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 //**  GNU General Public License for more details.
23 //**
24 //**************************************************************************
25 
26 // HEADER FILES ------------------------------------------------------------
27 
28 #include "gamedefs.h"
29 #include "sv_local.h"
30 
31 // MACROS ------------------------------------------------------------------
32 
33 // TYPES -------------------------------------------------------------------
34 
35 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
36 
37 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
38 
39 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
40 
41 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
42 
43 // PUBLIC DATA DEFINITIONS -------------------------------------------------
44 
45 VCvarI	compat_shorttex("compat_shorttex", "0", 0);
46 VCvarI	compat_stairs("compat_stairs", "0", 0);
47 VCvarI	compat_limitpain("compat_limitpain", "0", 0);
48 VCvarI	compat_nopassover("compat_nopassover", "0", 0);
49 VCvarI	compat_notossdrops("compat_notossdrops", "0", 0);
50 VCvarI	compat_useblocking("compat_useblocking", "0", 0);
51 VCvarI	compat_nodoorlight("compat_nodoorlight", "0", 0);
52 VCvarI	compat_ravenscroll("compat_ravenscroll", "0", 0);
53 VCvarI	compat_soundtarget("compat_soundtarget", "0", 0);
54 VCvarI	compat_dehhealth("compat_dehhealth", "0", 0);
55 VCvarI	compat_trace("compat_trace", "0", 0);
56 VCvarI	compat_dropoff("compat_dropoff", "0", 0);
57 VCvarI	compat_boomscroll("compat_boomscroll", "0", 0);
58 VCvarI	compat_invisibility("compat_invisibility", "0", 0);
59 
60 // PRIVATE DATA DEFINITIONS ------------------------------------------------
61 
62 IMPLEMENT_CLASS(V, LevelInfo)
63 
64 static VCvarF	sv_gravity("sv_gravity", "800.0", CVAR_ServerInfo);
65 static VCvarF	sv_aircontrol("sv_aircontrol", "0.00390625", CVAR_ServerInfo);
66 
67 // CODE --------------------------------------------------------------------
68 
69 //==========================================================================
70 //
71 //	VLevelInfo::VLevelInfo
72 //
73 //==========================================================================
74 
VLevelInfo()75 VLevelInfo::VLevelInfo()
76 {
77 	Level = this;
78 }
79 
80 //==========================================================================
81 //
82 //	VLevelInfo::SetMapInfo
83 //
84 //==========================================================================
85 
SetMapInfo(const mapInfo_t & Info)86 void VLevelInfo::SetMapInfo(const mapInfo_t& Info)
87 {
88 	guard(VLevelInfo::SetMapInfo);
89 	const VClusterDef* CInfo = P_GetClusterDef(Info.Cluster);
90 
91 	LevelName = Info.Name;
92 	LevelNum = Info.LevelNum;
93 	Cluster = Info.Cluster;
94 
95 	NextMap = Info.NextMap;
96 	SecretMap = Info.SecretMap;
97 
98 	ParTime = Info.ParTime;
99 	SuckTime = Info.SuckTime;
100 
101 	Sky1Texture = Info.Sky1Texture;
102 	Sky2Texture = Info.Sky2Texture;
103 	Sky1ScrollDelta = Info.Sky1ScrollDelta;
104 	Sky2ScrollDelta = Info.Sky2ScrollDelta;
105 	SkyBox = Info.SkyBox;
106 
107 	FadeTable = Info.FadeTable;
108 	Fade = Info.Fade;
109 	OutsideFog = Info.OutsideFog;
110 
111 	SongLump = Info.SongLump;
112 	CDTrack = Info.CDTrack;
113 
114 	if (Info.Gravity)
115 	{
116 		Gravity = Info.Gravity * DEFAULT_GRAVITY / 800.0;
117 	}
118 	else
119 	{
120 		Gravity = sv_gravity * DEFAULT_GRAVITY / 800.0;
121 	}
122 
123 	if (Info.AirControl)
124 	{
125 		AirControl = Info.AirControl;
126 	}
127 	else
128 	{
129 		AirControl = sv_aircontrol;
130 	}
131 
132 	Infighting = Info.Infighting;
133 	SpecialActions = Info.SpecialActions;
134 
135 	//	Copy flags from mapinfo.
136 	LevelInfoFlags = Info.Flags;
137 	LevelInfoFlags2 = Info.Flags2;
138 
139 	//	Doom format maps use strict monster activation by default.
140 	if (!(XLevel->LevelFlags & VLevel::LF_Extended) &&
141 		!(LevelInfoFlags2 & LIF2_HaveMonsterActivation))
142 	{
143 		LevelInfoFlags2 &= ~LIF2_LaxMonsterActivation;
144 	}
145 
146 	if (CInfo->Flags & CLUSTERF_Hub)
147 	{
148 		LevelInfoFlags2 |= LIF2_ClusterHub;
149 	}
150 
151 	//	No auto sequences flag sets all sectors to use sequence 0 by
152 	// default.
153 	if (Info.Flags & MAPINFOF_NoAutoSndSeq)
154 	{
155 		for (int i = 0; i < XLevel->NumSectors; i++)
156 		{
157 			XLevel->Sectors[i].seqType = 0;
158 		}
159 	}
160 	unguard;
161 }
162 
163 //==========================================================================
164 //
165 //	VLevelInfo::SectorStartSound
166 //
167 //==========================================================================
168 
SectorStartSound(const sector_t * Sector,int SoundId,int Channel,float Volume,float Attenuation)169 void VLevelInfo::SectorStartSound(const sector_t* Sector, int SoundId,
170 	int Channel, float Volume, float Attenuation)
171 {
172 	guard(VLevelInfo::SectorStartSound);
173 	if (Sector)
174 	{
175 		if (Sector->SectorFlags & sector_t::SF_Silent)
176 		{
177 			return;
178 		}
179 		StartSound(Sector->soundorg, (Sector - XLevel->Sectors) +
180 			(SNDORG_Sector << 24), SoundId, Channel, Volume, Attenuation,
181 			false);
182 	}
183 	else
184 	{
185 		StartSound(TVec(0, 0, 0), 0, SoundId, Channel, Volume,
186 			Attenuation, false);
187 	}
188 	unguard;
189 }
190 
191 //==========================================================================
192 //
193 //	VLevelInfo::SectorStopSound
194 //
195 //==========================================================================
196 
SectorStopSound(const sector_t * sector,int channel)197 void VLevelInfo::SectorStopSound(const sector_t *sector, int channel)
198 {
199 	guard(VLevelInfo::SectorStopSound);
200 	StopSound((sector - XLevel->Sectors) + (SNDORG_Sector << 24), channel);
201 	unguard;
202 }
203 
204 //==========================================================================
205 //
206 //	VLevelInfo::SectorStartSequence
207 //
208 //==========================================================================
209 
SectorStartSequence(const sector_t * Sector,VName Name,int ModeNum)210 void VLevelInfo::SectorStartSequence(const sector_t* Sector, VName Name,
211 	int ModeNum)
212 {
213 	guard(VLevelInfo::SectorStartSequence);
214 	if (Sector)
215 	{
216 		if (Sector->SectorFlags & sector_t::SF_Silent)
217 		{
218 			return;
219 		}
220 		StartSoundSequence(Sector->soundorg, (Sector - XLevel->Sectors) +
221 			(SNDORG_Sector << 24), Name, ModeNum);
222 	}
223 	else
224 	{
225 		StartSoundSequence(TVec(0, 0, 0), 0, Name, ModeNum);
226 	}
227 	unguard;
228 }
229 
230 //==========================================================================
231 //
232 //	VLevelInfo::SectorStopSequence
233 //
234 //==========================================================================
235 
SectorStopSequence(const sector_t * sector)236 void VLevelInfo::SectorStopSequence(const sector_t *sector)
237 {
238 	guard(VLevelInfo::SectorStopSequence);
239 	StopSoundSequence((sector - XLevel->Sectors) + (SNDORG_Sector << 24));
240 	unguard;
241 }
242 
243 //==========================================================================
244 //
245 //	VLevelInfo::PolyobjStartSequence
246 //
247 //==========================================================================
248 
PolyobjStartSequence(const polyobj_t * Poly,VName Name,int ModeNum)249 void VLevelInfo::PolyobjStartSequence(const polyobj_t* Poly, VName Name,
250 	int ModeNum)
251 {
252 	guard(VLevelInfo::PolyobjStartSequence);
253 	if (Poly->subsector->sector->SectorFlags & sector_t::SF_Silent)
254 	{
255 		return;
256 	}
257 	StartSoundSequence(Poly->startSpot, (Poly - XLevel->PolyObjs) +
258 		(SNDORG_PolyObj << 24), Name, ModeNum);
259 	unguard;
260 }
261 
262 //==========================================================================
263 //
264 //	VLevelInfo::PolyobjStopSequence
265 //
266 //==========================================================================
267 
PolyobjStopSequence(const polyobj_t * poly)268 void VLevelInfo::PolyobjStopSequence(const polyobj_t *poly)
269 {
270 	guard(VLevelInfo::PolyobjStopSequence);
271 	StopSoundSequence((poly - XLevel->PolyObjs) + (SNDORG_PolyObj << 24));
272 	unguard;
273 }
274 
275 //==========================================================================
276 //
277 //	VLevelInfo::ExitLevel
278 //
279 //==========================================================================
280 
ExitLevel(int Position)281 void VLevelInfo::ExitLevel(int Position)
282 {
283 	guard(VLevelInfo::ExitLevel);
284 	LeavePosition = Position;
285 	completed = true;
286 	unguard;
287 }
288 
289 //==========================================================================
290 //
291 //	VLevelInfo::SecretExitLevel
292 //
293 //==========================================================================
294 
SecretExitLevel(int Position)295 void VLevelInfo::SecretExitLevel(int Position)
296 {
297 	guard(VLevelInfo::SecretExitLevel);
298 	if (SecretMap == NAME_None)
299 	{
300 		// No secret map, use normal exit
301 		ExitLevel(Position);
302 		return;
303 	}
304 
305 	LeavePosition = Position;
306 	completed = true;
307 
308 	NextMap = SecretMap; 	// go to secret level
309 
310 	for (int i = 0; i < MAXPLAYERS; i++)
311 	{
312 		if (Game->Players[i])
313 		{
314 			Game->Players[i]->PlayerFlags |= VBasePlayer::PF_DidSecret;
315 		}
316 	}
317 	unguard;
318 }
319 
320 //==========================================================================
321 //
322 //	VLevelInfo::Completed
323 //
324 //	Starts intermission routine, which is used only during hub exits,
325 // and DeathMatch games.
326 //
327 //==========================================================================
328 
Completed(int InMap,int InPosition,int SaveAngle)329 void VLevelInfo::Completed(int InMap, int InPosition, int SaveAngle)
330 {
331 	guard(VLevelInfo::Completed);
332 	int Map = InMap;
333 	int Position = InPosition;
334 	if (Map == -1 && Position == -1)
335 	{
336 		if (!deathmatch)
337 		{
338 			for (int i = 0; i < svs.max_clients; i++)
339 			{
340 				if (Game->Players[i])
341 				{
342 					Game->Players[i]->eventClientFinale(
343 						VStr(NextMap).StartsWith("EndGame") ? *NextMap : "");
344 				}
345 			}
346 			sv.intermission = 2;
347 			return;
348 		}
349 		Map = 1;
350 		Position = 0;
351 	}
352 	NextMap = P_GetMapNameByLevelNum(Map);
353 
354 	LeavePosition = Position;
355 	completed = true;
356 	unguard;
357 }
358 
359 //==========================================================================
360 //
361 //	VLevelInfo::FindMobjFromTID
362 //
363 //==========================================================================
364 
FindMobjFromTID(int tid,VEntity * Prev)365 VEntity* VLevelInfo::FindMobjFromTID(int tid, VEntity* Prev)
366 {
367 	guard(VLevelInfo::FindMobjFromTID);
368 	for (VEntity* E = Prev ? Prev->TIDHashNext : TIDHash[tid &
369 		(TID_HASH_SIZE - 1)]; E; E = E->TIDHashNext)
370 	{
371 		if (E->TID == tid)
372 		{
373 			return E;
374 		}
375 	}
376 	return NULL;
377 	unguard;
378 }
379 
380 //==========================================================================
381 //
382 //	VLevelInfo::ChangeMusic
383 //
384 //==========================================================================
385 
ChangeMusic(VName SongName)386 void VLevelInfo::ChangeMusic(VName SongName)
387 {
388 	guard(SV_ChangeMusic);
389 	SongLump = SongName;
390 	unguard;
391 }
392 
393 //==========================================================================
394 //
395 //	VLevelInfo natives
396 //
397 //==========================================================================
398 
IMPLEMENT_FUNCTION(VLevelInfo,AddStaticLight)399 IMPLEMENT_FUNCTION(VLevelInfo, AddStaticLight)
400 {
401 	P_GET_FLOAT(Radius);
402 	P_GET_VEC(Origin);
403 	P_GET_SELF;
404 	rep_light_t* OldLights = Self->XLevel->StaticLights;
405 	Self->XLevel->NumStaticLights++;
406 	Self->XLevel->StaticLights = new rep_light_t[Self->XLevel->NumStaticLights];
407 	if (OldLights)
408 	{
409 		memcpy(Self->XLevel->StaticLights, OldLights,
410 			(Self->XLevel->NumStaticLights - 1) * sizeof(rep_light_t));
411 		delete[] OldLights;
412 		OldLights = NULL;
413 	}
414 	rep_light_t& L = Self->XLevel->StaticLights[Self->XLevel->NumStaticLights - 1];
415 	L.Origin = Origin;
416 	L.Radius = Radius;
417 	L.Colour = 0xffffffff;
418 }
419 
IMPLEMENT_FUNCTION(VLevelInfo,AddStaticLightRGB)420 IMPLEMENT_FUNCTION(VLevelInfo, AddStaticLightRGB)
421 {
422 	P_GET_INT(Colour);
423 	P_GET_FLOAT(Radius);
424 	P_GET_VEC(Origin);
425 	P_GET_SELF;
426 	rep_light_t* OldLights = Self->XLevel->StaticLights;
427 	Self->XLevel->NumStaticLights++;
428 	Self->XLevel->StaticLights = new rep_light_t[Self->XLevel->NumStaticLights];
429 	if (OldLights)
430 	{
431 		memcpy(Self->XLevel->StaticLights, OldLights,
432 			(Self->XLevel->NumStaticLights - 1) * sizeof(rep_light_t));
433 		delete[] OldLights;
434 		OldLights = NULL;
435 	}
436 	rep_light_t& L = Self->XLevel->StaticLights[Self->XLevel->NumStaticLights - 1];
437 	L.Origin = Origin;
438 	L.Radius = Radius;
439 	L.Colour = Colour;
440 }
441 
IMPLEMENT_FUNCTION(VLevelInfo,SectorStartSequence)442 IMPLEMENT_FUNCTION(VLevelInfo, SectorStartSequence)
443 {
444 	P_GET_INT(ModeNum);
445 	P_GET_NAME(name);
446 	P_GET_PTR(sector_t, sec);
447 	P_GET_SELF;
448 	Self->SectorStartSequence(sec, name, ModeNum);
449 }
450 
IMPLEMENT_FUNCTION(VLevelInfo,SectorStopSequence)451 IMPLEMENT_FUNCTION(VLevelInfo, SectorStopSequence)
452 {
453 	P_GET_PTR(sector_t, sec);
454 	P_GET_SELF;
455 	Self->SectorStopSequence(sec);
456 }
457 
IMPLEMENT_FUNCTION(VLevelInfo,PolyobjStartSequence)458 IMPLEMENT_FUNCTION(VLevelInfo, PolyobjStartSequence)
459 {
460 	P_GET_INT(ModeNum);
461 	P_GET_NAME(name);
462 	P_GET_PTR(polyobj_t, poly);
463 	P_GET_SELF;
464 	Self->PolyobjStartSequence(poly, name, ModeNum);
465 }
466 
IMPLEMENT_FUNCTION(VLevelInfo,PolyobjStopSequence)467 IMPLEMENT_FUNCTION(VLevelInfo, PolyobjStopSequence)
468 {
469 	P_GET_PTR(polyobj_t, poly);
470 	P_GET_SELF;
471 	Self->PolyobjStopSequence(poly);
472 }
473 
IMPLEMENT_FUNCTION(VLevelInfo,ExitLevel)474 IMPLEMENT_FUNCTION(VLevelInfo, ExitLevel)
475 {
476 	P_GET_INT(Position);
477 	P_GET_SELF;
478 	Self->ExitLevel(Position);
479 }
480 
IMPLEMENT_FUNCTION(VLevelInfo,SecretExitLevel)481 IMPLEMENT_FUNCTION(VLevelInfo, SecretExitLevel)
482 {
483 	P_GET_INT(Position);
484 	P_GET_SELF;
485 	Self->SecretExitLevel(Position);
486 }
487 
IMPLEMENT_FUNCTION(VLevelInfo,Completed)488 IMPLEMENT_FUNCTION(VLevelInfo, Completed)
489 {
490 	P_GET_INT(SaveAngle);
491 	P_GET_INT(pos);
492 	P_GET_INT(map);
493 	P_GET_SELF;
494 	Self->Completed(map, pos, SaveAngle);
495 }
496 
IMPLEMENT_FUNCTION(VLevelInfo,ChangeSwitchTexture)497 IMPLEMENT_FUNCTION(VLevelInfo, ChangeSwitchTexture)
498 {
499 	P_GET_PTR(vuint8, pQuest);
500 	P_GET_NAME(DefaultSound);
501 	P_GET_BOOL(useAgain);
502 	P_GET_INT(SideNum);
503 	P_GET_SELF;
504 	bool Quest;
505 	bool Ret = Self->ChangeSwitchTexture(SideNum, useAgain, DefaultSound,
506 		Quest);
507 	*pQuest = Quest;
508 	RET_BOOL(Ret);
509 }
510 
IMPLEMENT_FUNCTION(VLevelInfo,FindMobjFromTID)511 IMPLEMENT_FUNCTION(VLevelInfo, FindMobjFromTID)
512 {
513 	P_GET_REF(VEntity, Prev);
514 	P_GET_INT(tid);
515 	P_GET_SELF;
516 	RET_REF(Self->FindMobjFromTID(tid, Prev));
517 }
518 
IMPLEMENT_FUNCTION(VLevelInfo,AutoSave)519 IMPLEMENT_FUNCTION(VLevelInfo, AutoSave)
520 {
521 	P_GET_SELF;
522 	if (Self->Game->NetMode == NM_Standalone)
523 	{
524 		SV_SaveGame(SV_GetRebornSlot(), REBORN_DESCRIPTION);
525 	}
526 }
527 
IMPLEMENT_FUNCTION(VLevelInfo,ChangeMusic)528 IMPLEMENT_FUNCTION(VLevelInfo, ChangeMusic)
529 {
530 	P_GET_NAME(SongName);
531 	P_GET_SELF;
532 	Self->ChangeMusic(SongName);
533 }
534