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