1 //**************************************************************************
2 //**
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
9 //**
10 //** $Id: p_entity.cpp 4001 2009-03-03 20:22:11Z dj_jl $
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 IMPLEMENT_CLASS(V, Entity);
46
47 // PRIVATE DATA DEFINITIONS ------------------------------------------------
48
49 int VEntity::FIndex_OnMapSpawn;
50 int VEntity::FIndex_BeginPlay;
51 int VEntity::FIndex_Destroyed;
52 int VEntity::FIndex_Touch;
53 int VEntity::FIndex_BlastedHitLine;
54 int VEntity::FIndex_CheckForPushSpecial;
55 int VEntity::FIndex_ApplyFriction;
56 int VEntity::FIndex_HandleFloorclip;
57 int VEntity::FIndex_CrossSpecialLine;
58 int VEntity::FIndex_SectorChanged;
59 int VEntity::FIndex_RoughCheckThing;
60 int VEntity::FIndex_GiveInventory;
61 int VEntity::FIndex_TakeInventory;
62 int VEntity::FIndex_CheckInventory;
63 int VEntity::FIndex_GetSigilPieces;
64 int VEntity::FIndex_MoveThing;
65 int VEntity::FIndex_GetStateTime;
66
67 // CODE --------------------------------------------------------------------
68
69 //==========================================================================
70 //
71 // VEntity::InitFuncIndexes
72 //
73 //==========================================================================
74
InitFuncIndexes()75 void VEntity::InitFuncIndexes()
76 {
77 guard(VEntity::InitFuncIndexes);
78 FIndex_OnMapSpawn = StaticClass()->GetMethodIndex(NAME_OnMapSpawn);
79 FIndex_BeginPlay = StaticClass()->GetMethodIndex(NAME_BeginPlay);
80 FIndex_Destroyed = StaticClass()->GetMethodIndex(NAME_Destroyed);
81 FIndex_Touch = StaticClass()->GetMethodIndex(NAME_Touch);
82 FIndex_BlastedHitLine = StaticClass()->GetMethodIndex(NAME_BlastedHitLine);
83 FIndex_CheckForPushSpecial = StaticClass()->GetMethodIndex(NAME_CheckForPushSpecial);
84 FIndex_ApplyFriction = StaticClass()->GetMethodIndex(NAME_ApplyFriction);
85 FIndex_HandleFloorclip = StaticClass()->GetMethodIndex(NAME_HandleFloorclip);
86 FIndex_CrossSpecialLine = StaticClass()->GetMethodIndex(NAME_CrossSpecialLine);
87 FIndex_SectorChanged = StaticClass()->GetMethodIndex(NAME_SectorChanged);
88 FIndex_RoughCheckThing = StaticClass()->GetMethodIndex(NAME_RoughCheckThing);
89 FIndex_GiveInventory = StaticClass()->GetMethodIndex(NAME_GiveInventory);
90 FIndex_TakeInventory = StaticClass()->GetMethodIndex(NAME_TakeInventory);
91 FIndex_CheckInventory = StaticClass()->GetMethodIndex(NAME_CheckInventory);
92 FIndex_GetSigilPieces = StaticClass()->GetMethodIndex(NAME_GetSigilPieces);
93 FIndex_MoveThing = StaticClass()->GetMethodIndex(NAME_MoveThing);
94 FIndex_GetStateTime = StaticClass()->GetMethodIndex(NAME_GetStateTime);
95 unguard;
96 }
97
98 //==========================================================================
99 //
100 // VEntity::Serialise
101 //
102 //==========================================================================
103
Serialise(VStream & Strm)104 void VEntity::Serialise(VStream& Strm)
105 {
106 guard(VEntity::Serialise);
107 Super::Serialise(Strm);
108
109 if (Strm.IsLoading())
110 {
111 if (EntityFlags & EF_IsPlayer)
112 {
113 Player->MO = this;
114 }
115 SubSector = NULL; // Must mark as not linked
116 LinkToWorld();
117 }
118 unguard;
119 }
120
121 //==========================================================================
122 //
123 // VEntity::DestroyThinker
124 //
125 //==========================================================================
126
DestroyThinker()127 void VEntity::DestroyThinker()
128 {
129 guard(VEntity::DestroyThinker)
130 if (Role == ROLE_Authority)
131 {
132 eventDestroyed();
133
134 if (TID)
135 {
136 // Remove from TID list
137 RemoveFromTIDList();
138 }
139
140 // stop any playing sound
141 StopSound(0);
142 }
143
144 // unlink from sector and block lists
145 UnlinkFromWorld();
146 XLevel->DelSectorList();
147
148 Super::DestroyThinker();
149 unguard;
150 }
151
152 //==========================================================================
153 //
154 // VEntity::AddedToLevel
155 //
156 //==========================================================================
157
AddedToLevel()158 void VEntity::AddedToLevel()
159 {
160 guard(VEntity::AddedToLevel);
161 if (!XLevel->NextSoundOriginID)
162 {
163 XLevel->NextSoundOriginID = 1;
164 }
165 SoundOriginID = XLevel->NextSoundOriginID + (SNDORG_Entity << 24);
166 XLevel->NextSoundOriginID = (XLevel->NextSoundOriginID + 1) & 0x00ffffff;
167 unguard;
168 }
169
170 //==========================================================================
171 //
172 // VEntity::SetTID
173 //
174 //==========================================================================
175
SetTID(int tid)176 void VEntity::SetTID(int tid)
177 {
178 guard(VEntity::SetTID);
179 RemoveFromTIDList();
180 if (tid)
181 {
182 InsertIntoTIDList(tid);
183 }
184 unguard;
185 }
186
187 //==========================================================================
188 //
189 // VEntity::InsertIntoTIDList
190 //
191 //==========================================================================
192
InsertIntoTIDList(int tid)193 void VEntity::InsertIntoTIDList(int tid)
194 {
195 guard(VEntity::InsertIntoTIDList);
196 TID = tid;
197 int HashIndex = tid & (VLevelInfo::TID_HASH_SIZE - 1);
198 TIDHashPrev = NULL;
199 TIDHashNext = Level->TIDHash[HashIndex];
200 if (TIDHashNext)
201 {
202 TIDHashNext->TIDHashPrev = this;
203 }
204 Level->TIDHash[HashIndex] = this;
205 unguard;
206 }
207
208 //==========================================================================
209 //
210 // VEntity::RemoveFromTIDList
211 //
212 //==========================================================================
213
RemoveFromTIDList()214 void VEntity::RemoveFromTIDList()
215 {
216 guard(VEntity::RemoveFromTIDList);
217 if (!TID)
218 {
219 // No TID, which means it's not in the cache.
220 return;
221 }
222
223 if (TIDHashNext)
224 {
225 TIDHashNext->TIDHashPrev = TIDHashPrev;
226 }
227 if (TIDHashPrev)
228 {
229 TIDHashPrev->TIDHashNext = TIDHashNext;
230 }
231 else
232 {
233 int HashIndex = TID & (VLevelInfo::TID_HASH_SIZE - 1);
234 check(Level->TIDHash[HashIndex] == this);
235 Level->TIDHash[HashIndex] = TIDHashNext;
236 }
237 TID = 0;
238 unguard;
239 }
240
241 //==========================================================================
242 //
243 // VEntity::SetState
244 //
245 // Returns true if the actor is still present.
246 //
247 //==========================================================================
248
SetState(VState * InState)249 bool VEntity::SetState(VState* InState)
250 {
251 guard(VEntity::SetState);
252 VState *st = InState;
253 do
254 {
255 if (!st)
256 {
257 // Remove mobj
258 State = NULL;
259 StateTime = -1;
260 DestroyThinker();
261 return false;
262 }
263
264 if (st->SpriteIndex == 1)
265 {
266 // 1 is ----, which is "do not change sprite"
267 if (!(EntityFlags & EF_UseDispState))
268 {
269 DispState = State;
270 EntityFlags |= EF_UseDispState;
271 }
272 }
273 else
274 {
275 EntityFlags &= ~EF_UseDispState;
276 }
277 State = st;
278 StateTime = eventGetStateTime(st, st->Time);
279 EntityFlags &= ~EF_FullBright;
280
281 // Modified handling.
282 // Call action functions when the state is set
283 if (st->Function)
284 {
285 XLevel->CallingState = State;
286 P_PASS_SELF;
287 ExecuteFunction(st->Function);
288 }
289
290 if (!State)
291 {
292 return false;
293 }
294 st = State->NextState;
295 }
296 while (!StateTime);
297 return true;
298 unguard;
299 }
300
301 //==========================================================================
302 //
303 // VEntity::SetInitialState
304 //
305 // Returns true if the actor is still present.
306 //
307 //==========================================================================
308
SetInitialState(VState * InState)309 void VEntity::SetInitialState(VState* InState)
310 {
311 guard(VEntity::SetInitialState);
312 State = InState;
313 if (InState)
314 {
315 StateTime = eventGetStateTime(InState, InState->Time);
316 }
317 else
318 {
319 StateTime = -1.0;
320 }
321 unguard;
322 }
323
324 //==========================================================================
325 //
326 // VEntity::AdvanceState
327 //
328 //==========================================================================
329
AdvanceState(float deltaTime)330 bool VEntity::AdvanceState(float deltaTime)
331 {
332 guard(VEntity::AdvanceState);
333 if (State && StateTime != -1.0)
334 {
335 StateTime -= deltaTime;
336 // you can cycle through multiple states in a tic
337 if (StateTime <= 0.0)
338 {
339 if (!SetState(State->NextState))
340 {
341 return false; // freed itself
342 }
343 }
344 }
345 return true;
346 unguard;
347 }
348
349 //==========================================================================
350 //
351 // VEntity::FindState
352 //
353 //==========================================================================
354
FindState(VName StateName,VName SubLabel,bool Exact)355 VState* VEntity::FindState(VName StateName, VName SubLabel, bool Exact)
356 {
357 guard(VEntity::FindState);
358 VStateLabel* Lbl = GetClass()->FindStateLabel(StateName, SubLabel, Exact);
359 return Lbl ? Lbl->State : NULL;
360 unguard;
361 }
362
363 //==========================================================================
364 //
365 // VEntity::FindStateEx
366 //
367 //==========================================================================
368
FindStateEx(const VStr & StateName,bool Exact)369 VState* VEntity::FindStateEx(const VStr& StateName, bool Exact)
370 {
371 guard(VEntity::FindStateEx);
372 TArray<VName> Names;
373 VMemberBase::StaticSplitStateLabel(StateName, Names);
374 VStateLabel* Lbl = GetClass()->FindStateLabel(Names, Exact);
375 return Lbl ? Lbl->State : NULL;
376 unguard;
377 }
378
379 //==========================================================================
380 //
381 // VEntity::HasSpecialStates
382 //
383 //==========================================================================
384
HasSpecialStates(VName StateName)385 bool VEntity::HasSpecialStates(VName StateName)
386 {
387 guard(VEntity::HasSpecialStates);
388 VStateLabel* Lbl = GetClass()->FindStateLabel(StateName);
389 return Lbl && Lbl->SubLabels.Num() > 0;
390 unguard;
391 }
392
393 //==========================================================================
394 //
395 // VEntity::GetStateEffects
396 //
397 //==========================================================================
398
GetStateEffects(TArray<VLightEffectDef * > & Lights,TArray<VParticleEffectDef * > & Part) const399 void VEntity::GetStateEffects(TArray<VLightEffectDef*>& Lights,
400 TArray<VParticleEffectDef*>& Part) const
401 {
402 guard(VEntity::GetStateEffects);
403 // Clear arrays.
404 Lights.Clear();
405
406 // Check for valid state
407 if (!State)
408 {
409 return;
410 }
411
412 // Find all matching effects.
413 for (int i = 0; i < GetClass()->SpriteEffects.Num(); i++)
414 {
415 VSpriteEffect& SprFx = GetClass()->SpriteEffects[i];
416 if (SprFx.SpriteIndex != State->SpriteIndex)
417 {
418 continue;
419 }
420 if (SprFx.Frame != -1 &&
421 SprFx.Frame != (State->Frame & VState::FF_FRAMEMASK))
422 {
423 continue;
424 }
425
426 if (SprFx.LightDef)
427 {
428 Lights.Append(SprFx.LightDef);
429 }
430 if (SprFx.PartDef)
431 {
432 Part.Append(SprFx.PartDef);
433 }
434 }
435 unguard;
436 }
437
438 //==========================================================================
439 //
440 // VEntity::CallStateChain
441 //
442 //==========================================================================
443
CallStateChain(VEntity * Actor,VState * AState)444 bool VEntity::CallStateChain(VEntity* Actor, VState* AState)
445 {
446 guard(VEntity::CallStateChain);
447 // Set up state call structure.
448 VStateCall* PrevCall = XLevel->StateCall;
449 VStateCall Call;
450 Call.Item = this;
451 bool Ret = false;
452 XLevel->StateCall = &Call;
453
454 int RunAway = 0;
455 VState* S = AState;
456 while (S)
457 {
458 Call.State = S;
459 // Call action function.
460 if (S->Function)
461 {
462 // Assume success by default.
463 XLevel->CallingState = S;
464 Call.Result = true;
465 P_PASS_REF(Actor);
466 ExecuteFunction(S->Function);
467 // At least one success means overal success.
468 if (Call.Result)
469 {
470 Ret = true;
471 }
472 }
473
474 // Check for infinite loops
475 RunAway++;
476 if (RunAway > 1000)
477 {
478 break;
479 }
480
481 if (Call.State == S)
482 {
483 // Abort immediately if next state loops to itself. In this case
484 // the overal result is always false.
485 if (S->NextState == S)
486 {
487 Ret = false;
488 break;
489 }
490 // Advance to the next state.
491 S = S->NextState;
492 }
493 else
494 {
495 // There was a state jump.
496 S = Call.State;
497 }
498 }
499
500 XLevel->StateCall = PrevCall;
501 return Ret;
502 unguard;
503 }
504
505 //==========================================================================
506 //
507 // VEntity::StartSound
508 //
509 //==========================================================================
510
StartSound(VName Sound,vint32 Channel,float Volume,float Attenuation,bool Loop)511 void VEntity::StartSound(VName Sound, vint32 Channel, float Volume,
512 float Attenuation, bool Loop)
513 {
514 guard(VEntity::StartSound);
515 if (Sector->SectorFlags & sector_t::SF_Silent)
516 {
517 return;
518 }
519 Super::StartSound(Origin, SoundOriginID,
520 GSoundManager->ResolveEntitySound(SoundClass, SoundGender, Sound),
521 Channel, Volume, Attenuation, Loop);
522 unguard;
523 }
524
525 //==========================================================================
526 //
527 // VEntity::StartLocalSound
528 //
529 //==========================================================================
530
StartLocalSound(VName Sound,vint32 Channel,float Volume,float Attenuation)531 void VEntity::StartLocalSound(VName Sound, vint32 Channel, float Volume,
532 float Attenuation)
533 {
534 guard(VEntity::StartLocalSound);
535 if (Sector->SectorFlags & sector_t::SF_Silent)
536 {
537 return;
538 }
539 if (Player)
540 {
541 Player->eventClientStartSound(
542 GSoundManager->ResolveEntitySound(SoundClass, SoundGender, Sound),
543 TVec(0, 0, 0), 0, Channel, Volume, Attenuation, false);
544 }
545 unguard;
546 }
547
548 //==========================================================================
549 //
550 // VEntity::StopSound
551 //
552 //==========================================================================
553
StopSound(vint32 channel)554 void VEntity::StopSound(vint32 channel)
555 {
556 guard(VEntity::StopSound);
557 Super::StopSound(SoundOriginID, channel);
558 unguard;
559 }
560
561 //==========================================================================
562 //
563 // VEntity::StartSoundSequence
564 //
565 //==========================================================================
566
StartSoundSequence(VName Name,vint32 ModeNum)567 void VEntity::StartSoundSequence(VName Name, vint32 ModeNum)
568 {
569 guard(VEntity::StartSoundSequence);
570 if (Sector->SectorFlags & sector_t::SF_Silent)
571 {
572 return;
573 }
574 Super::StartSoundSequence(Origin, SoundOriginID, Name, ModeNum);
575 unguard;
576 }
577
578 //==========================================================================
579 //
580 // VEntity::AddSoundSequenceChoice
581 //
582 //==========================================================================
583
AddSoundSequenceChoice(VName Choice)584 void VEntity::AddSoundSequenceChoice(VName Choice)
585 {
586 guard(VEntity::AddSoundSequenceChoice);
587 if (Sector->SectorFlags & sector_t::SF_Silent)
588 {
589 return;
590 }
591 Super::AddSoundSequenceChoice(SoundOriginID, Choice);
592 unguard;
593 }
594
595 //==========================================================================
596 //
597 // VEntity::StopSoundSequence
598 //
599 //==========================================================================
600
StopSoundSequence()601 void VEntity::StopSoundSequence()
602 {
603 guard(VEntity::StopSoundSequence);
604 Super::StopSoundSequence(SoundOriginID);
605 unguard;
606 }
607
608 //==========================================================================
609 //
610 // Script natives
611 //
612 //==========================================================================
613
IMPLEMENT_FUNCTION(VEntity,SetTID)614 IMPLEMENT_FUNCTION(VEntity, SetTID)
615 {
616 P_GET_INT(tid);
617 P_GET_SELF;
618 Self->SetTID(tid);
619 }
620
IMPLEMENT_FUNCTION(VEntity,SetState)621 IMPLEMENT_FUNCTION(VEntity, SetState)
622 {
623 P_GET_PTR(VState, state);
624 P_GET_SELF;
625 RET_BOOL(Self->SetState(state));
626 }
627
IMPLEMENT_FUNCTION(VEntity,SetInitialState)628 IMPLEMENT_FUNCTION(VEntity, SetInitialState)
629 {
630 P_GET_PTR(VState, state);
631 P_GET_SELF;
632 Self->SetInitialState(state);
633 }
634
IMPLEMENT_FUNCTION(VEntity,AdvanceState)635 IMPLEMENT_FUNCTION(VEntity, AdvanceState)
636 {
637 P_GET_FLOAT(deltaTime);
638 P_GET_SELF;
639 RET_BOOL(Self->AdvanceState(deltaTime));
640 }
641
IMPLEMENT_FUNCTION(VEntity,FindState)642 IMPLEMENT_FUNCTION(VEntity, FindState)
643 {
644 P_GET_BOOL_OPT(Exact, false);
645 P_GET_NAME_OPT(SubLabel, NAME_None);
646 P_GET_NAME(StateName);
647 P_GET_SELF;
648 RET_PTR(Self->FindState(StateName, SubLabel, Exact));
649 }
650
IMPLEMENT_FUNCTION(VEntity,FindStateEx)651 IMPLEMENT_FUNCTION(VEntity, FindStateEx)
652 {
653 P_GET_BOOL_OPT(Exact, false);
654 P_GET_STR(StateName);
655 P_GET_SELF;
656 RET_PTR(Self->FindStateEx(StateName, Exact));
657 }
658
IMPLEMENT_FUNCTION(VEntity,HasSpecialStates)659 IMPLEMENT_FUNCTION(VEntity, HasSpecialStates)
660 {
661 P_GET_NAME(StateName);
662 P_GET_SELF;
663 RET_BOOL(Self->HasSpecialStates(StateName));
664 }
665
IMPLEMENT_FUNCTION(VEntity,GetStateEffects)666 IMPLEMENT_FUNCTION(VEntity, GetStateEffects)
667 {
668 P_GET_PTR(TArray<VParticleEffectDef*>, Part);
669 P_GET_PTR(TArray<VLightEffectDef*>, Lights);
670 P_GET_SELF;
671 Self->GetStateEffects(*Lights, *Part);
672 }
673
IMPLEMENT_FUNCTION(VEntity,CallStateChain)674 IMPLEMENT_FUNCTION(VEntity, CallStateChain)
675 {
676 P_GET_PTR(VState, State);
677 P_GET_REF(VEntity, Actor);
678 P_GET_SELF;
679 RET_BOOL(Self->CallStateChain(Actor, State));
680 }
681
IMPLEMENT_FUNCTION(VEntity,PlaySound)682 IMPLEMENT_FUNCTION(VEntity, PlaySound)
683 {
684 P_GET_BOOL_OPT(Loop, false);
685 P_GET_FLOAT_OPT(Attenuation, 1.0);
686 P_GET_FLOAT_OPT(Volume, 1.0);
687 P_GET_INT(Channel);
688 P_GET_NAME(SoundName);
689 P_GET_SELF;
690 Self->StartSound(SoundName, Channel, Volume, Attenuation, Loop);
691 }
692
IMPLEMENT_FUNCTION(VEntity,StopSound)693 IMPLEMENT_FUNCTION(VEntity, StopSound)
694 {
695 P_GET_INT(Channel);
696 P_GET_SELF;
697 Self->StopSound(Channel);
698 }
699
IMPLEMENT_FUNCTION(VEntity,AreSoundsEquivalent)700 IMPLEMENT_FUNCTION(VEntity, AreSoundsEquivalent)
701 {
702 P_GET_NAME(Sound2);
703 P_GET_NAME(Sound1);
704 P_GET_SELF;
705 RET_BOOL(GSoundManager->ResolveEntitySound(Self->SoundClass,
706 Self->SoundGender, Sound1) == GSoundManager->ResolveEntitySound(
707 Self->SoundClass, Self->SoundGender, Sound2));
708 }
709
IMPLEMENT_FUNCTION(VEntity,IsSoundPresent)710 IMPLEMENT_FUNCTION(VEntity, IsSoundPresent)
711 {
712 P_GET_NAME(Sound);
713 P_GET_SELF;
714 RET_BOOL(GSoundManager->IsSoundPresent(Self->SoundClass,
715 Self->SoundGender, Sound));
716 }
717
IMPLEMENT_FUNCTION(VEntity,StartSoundSequence)718 IMPLEMENT_FUNCTION(VEntity, StartSoundSequence)
719 {
720 P_GET_INT(ModeNum);
721 P_GET_NAME(Name);
722 P_GET_SELF;
723 Self->StartSoundSequence(Name, ModeNum);
724 }
725
IMPLEMENT_FUNCTION(VEntity,AddSoundSequenceChoice)726 IMPLEMENT_FUNCTION(VEntity, AddSoundSequenceChoice)
727 {
728 P_GET_NAME(Choice);
729 P_GET_SELF;
730 Self->AddSoundSequenceChoice(Choice);
731 }
732
IMPLEMENT_FUNCTION(VEntity,StopSoundSequence)733 IMPLEMENT_FUNCTION(VEntity, StopSoundSequence)
734 {
735 P_GET_SELF;
736 Self->StopSoundSequence();
737 }
738
IMPLEMENT_FUNCTION(VEntity,SetDecorateFlag)739 IMPLEMENT_FUNCTION(VEntity, SetDecorateFlag)
740 {
741 P_GET_BOOL(Value);
742 P_GET_STR(Name);
743 P_GET_SELF;
744 Self->SetDecorateFlag(Name, Value);
745 }
746