From 93aa1ea2c4da75918f19b97d9dfead98952b1bd5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 5 May 2014 11:24:20 +0200 Subject: [PATCH 1/6] fixed some issues with reviving monsters - fixed: Thing_Raise didn't properly set the spawn health. - fixed: Thing_Raise did not the CanRaise state flag. - fixed: Reviving a monster must also reset the damage type. - fixed: Thing_Raise reset the actor after calling the raise state, but it should be before, just as the Archvile code is doing. - consolidated some common code of Thing_Raise and Archvile resurrection into AActor methods. --- src/actor.h | 2 + src/p_enemy.cpp | 222 +++++++++++++++++++++-------------------------- src/p_mobj.cpp | 43 +++++++++ src/p_things.cpp | 36 ++------ 4 files changed, 152 insertions(+), 151 deletions(-) diff --git a/src/actor.h b/src/actor.h index 21057d86c3..4b7696752e 100644 --- a/src/actor.h +++ b/src/actor.h @@ -1011,6 +1011,8 @@ public: bool isSlow(); void SetIdle(); void ClearCounters(); + FState *GetRaiseState(); + void Revive(); FState *FindState (FName label) const { diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 14c6b68aab..f84dd13aa5 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -2525,146 +2525,122 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates) FBlockThingsIterator it(FBoundingBox(viletryx, viletryy, 32*FRACUNIT)); while ((corpsehit = it.Next())) { - if (!(corpsehit->flags & MF_CORPSE) ) - continue; // not a monster - - if (corpsehit->tics != -1 && // not lying still yet - !corpsehit->state->GetCanRaise()) // or not ready to be raised yet - continue; - - raisestate = corpsehit->FindState(NAME_Raise); - if (raisestate == NULL) - continue; // monster doesn't have a raise state - - if (corpsehit->IsKindOf(RUNTIME_CLASS(APlayerPawn))) - continue; // do not resurrect players - - // use the current actor's radius instead of the Arch Vile's default. - fixed_t maxdist = corpsehit->GetDefault()->radius + self->radius; - - maxdist = corpsehit-> GetDefault()->radius + self->radius; - - if ( abs(corpsehit-> x - viletryx) > maxdist || - abs(corpsehit-> y - viletryy) > maxdist ) - continue; // not actually touching -#ifdef _3DFLOORS - // Let's check if there are floors in between the archvile and its target - sector_t *vilesec = self->Sector; - sector_t *corpsec = corpsehit->Sector; - // We only need to test if at least one of the sectors has a 3D floor. - sector_t *testsec = vilesec->e->XFloor.ffloors.Size() ? vilesec : - (vilesec != corpsec && corpsec->e->XFloor.ffloors.Size()) ? corpsec : NULL; - if (testsec) + FState *raisestate = corpsehit->GetRaiseState(); + if (raisestate != NULL) { - fixed_t zdist1, zdist2; - if (P_Find3DFloor(testsec, corpsehit->x, corpsehit->y, corpsehit->z, false, true, zdist1) - != P_Find3DFloor(testsec, self->x, self->y, self->z, false, true, zdist2)) + // use the current actor's radius instead of the Arch Vile's default. + fixed_t maxdist = corpsehit->GetDefault()->radius + self->radius; + + maxdist = corpsehit->GetDefault()->radius + self->radius; + + if (abs(corpsehit->x - viletryx) > maxdist || + abs(corpsehit->y - viletryy) > maxdist) + continue; // not actually touching +#ifdef _3DFLOORS + // Let's check if there are floors in between the archvile and its target + sector_t *vilesec = self->Sector; + sector_t *corpsec = corpsehit->Sector; + // We only need to test if at least one of the sectors has a 3D floor. + sector_t *testsec = vilesec->e->XFloor.ffloors.Size() ? vilesec : + (vilesec != corpsec && corpsec->e->XFloor.ffloors.Size()) ? corpsec : NULL; + if (testsec) { - // Not on same floor - if (vilesec == corpsec || abs(zdist1 - self->z) > self->height) + fixed_t zdist1, zdist2; + if (P_Find3DFloor(testsec, corpsehit->x, corpsehit->y, corpsehit->z, false, true, zdist1) + != P_Find3DFloor(testsec, self->x, self->y, self->z, false, true, zdist2)) + { + // Not on same floor + if (vilesec == corpsec || abs(zdist1 - self->z) > self->height) continue; + } } - } #endif - corpsehit->velx = corpsehit->vely = 0; - // [RH] Check against real height and radius + corpsehit->velx = corpsehit->vely = 0; + // [RH] Check against real height and radius - fixed_t oldheight = corpsehit->height; - fixed_t oldradius = corpsehit->radius; - int oldflags = corpsehit->flags; + fixed_t oldheight = corpsehit->height; + fixed_t oldradius = corpsehit->radius; + int oldflags = corpsehit->flags; - corpsehit->flags |= MF_SOLID; - corpsehit->height = corpsehit->GetDefault()->height; - bool check = P_CheckPosition (corpsehit, corpsehit->x, corpsehit->y); - corpsehit->flags = oldflags; - corpsehit->radius = oldradius; - corpsehit->height = oldheight; - if (!check) continue; + corpsehit->flags |= MF_SOLID; + corpsehit->height = corpsehit->GetDefault()->height; + bool check = P_CheckPosition(corpsehit, corpsehit->x, corpsehit->y); + corpsehit->flags = oldflags; + corpsehit->radius = oldradius; + corpsehit->height = oldheight; + if (!check) continue; - // got one! - temp = self->target; - self->target = corpsehit; - A_FaceTarget (self); - if (self->flags & MF_FRIENDLY) - { - // If this is a friendly Arch-Vile (which is turning the resurrected monster into its friend) - // and the Arch-Vile is currently targetting the resurrected monster the target must be cleared. - if (self->lastenemy == temp) self->lastenemy = NULL; - if (self->lastenemy == corpsehit) self->lastenemy = NULL; - if (temp == self->target) temp = NULL; - } - self->target = temp; - - // Make the state the monster enters customizable. - FState * state = self->FindState(NAME_Heal); - if (state != NULL) - { - self->SetState (state); - } - else if (usevilestates) - { - // For Dehacked compatibility this has to use the Arch Vile's - // heal state as a default if the actor doesn't define one itself. - const PClass *archvile = PClass::FindClass("Archvile"); - if (archvile != NULL) + // got one! + temp = self->target; + self->target = corpsehit; + A_FaceTarget(self); + if (self->flags & MF_FRIENDLY) { - self->SetState (archvile->ActorInfo->FindState(NAME_Heal)); + // If this is a friendly Arch-Vile (which is turning the resurrected monster into its friend) + // and the Arch-Vile is currently targetting the resurrected monster the target must be cleared. + if (self->lastenemy == temp) self->lastenemy = NULL; + if (self->lastenemy == corpsehit) self->lastenemy = NULL; + if (temp == self->target) temp = NULL; } - } - S_Sound (corpsehit, CHAN_BODY, "vile/raise", 1, ATTN_IDLE); - info = corpsehit->GetDefault (); - - if (corpsehit->state == corpsehit->FindState(NAME_GenericCrush)) - { - corpsehit->Translation = info->Translation; // Clean up bloodcolor translation from crushed corpses - } - if (ib_compatflags & BCOMPATF_VILEGHOSTS) - { - corpsehit->height <<= 2; - // [GZ] This was a commented-out feature, so let's make use of it, - // but only for ghost monsters so that they are visibly different. - if (corpsehit->height == 0) + self->target = temp; + + // Make the state the monster enters customizable. + FState * state = self->FindState(NAME_Heal); + if (state != NULL) { - // Make raised corpses look ghostly - if (corpsehit->alpha > TRANSLUC50) + self->SetState(state); + } + else if (usevilestates) + { + // For Dehacked compatibility this has to use the Arch Vile's + // heal state as a default if the actor doesn't define one itself. + const PClass *archvile = PClass::FindClass("Archvile"); + if (archvile != NULL) { - corpsehit->alpha /= 2; - } - // This will only work if the render style is changed as well. - if (corpsehit->RenderStyle == LegacyRenderStyles[STYLE_Normal]) - { - corpsehit->RenderStyle = STYLE_Translucent; + self->SetState(archvile->ActorInfo->FindState(NAME_Heal)); } } - } - else - { - corpsehit->height = info->height; // [RH] Use real mobj height - corpsehit->radius = info->radius; // [RH] Use real radius - } - corpsehit->flags = info->flags; - corpsehit->flags2 = info->flags2; - corpsehit->flags3 = info->flags3; - corpsehit->flags4 = info->flags4; - corpsehit->flags5 = info->flags5; - corpsehit->flags6 = info->flags6; - corpsehit->flags7 = info->flags7; - corpsehit->health = corpsehit->SpawnHealth(); - corpsehit->target = NULL; - corpsehit->lastenemy = NULL; + S_Sound(corpsehit, CHAN_BODY, "vile/raise", 1, ATTN_IDLE); + info = corpsehit->GetDefault(); - // [RH] If it's a monster, it gets to count as another kill - if (corpsehit->CountsAsKill()) - { - level.total_monsters++; + if (corpsehit->state == corpsehit->FindState(NAME_GenericCrush)) + { + corpsehit->Translation = info->Translation; // Clean up bloodcolor translation from crushed corpses + } + if (ib_compatflags & BCOMPATF_VILEGHOSTS) + { + corpsehit->height <<= 2; + // [GZ] This was a commented-out feature, so let's make use of it, + // but only for ghost monsters so that they are visibly different. + if (corpsehit->height == 0) + { + // Make raised corpses look ghostly + if (corpsehit->alpha > TRANSLUC50) + { + corpsehit->alpha /= 2; + } + // This will only work if the render style is changed as well. + if (corpsehit->RenderStyle == LegacyRenderStyles[STYLE_Normal]) + { + corpsehit->RenderStyle = STYLE_Translucent; + } + } + } + else + { + corpsehit->height = info->height; // [RH] Use real mobj height + corpsehit->radius = info->radius; // [RH] Use real radius + } + + corpsehit->Revive(); + + // You are the Archvile's minion now, so hate what it hates + corpsehit->CopyFriendliness(self, false); + corpsehit->SetState(raisestate); + + return true; } - - // You are the Archvile's minion now, so hate what it hates - corpsehit->CopyFriendliness (self, false); - corpsehit->SetState (raisestate); - - return true; } } return false; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index f519ba763c..05eddf3abf 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -6074,6 +6074,49 @@ int AActor::SpawnHealth() } } +FState *AActor::GetRaiseState() +{ + if (!(flags & MF_CORPSE)) + { + return NULL; // not a monster + } + + if (tics != -1 && // not lying still yet + state->GetCanRaise()) // or not ready to be raised yet + { + return NULL; + } + + if (IsKindOf(RUNTIME_CLASS(APlayerPawn))) + { + return NULL; // do not resurrect players + } + + return FindState(NAME_Raise); +} + +void AActor::Revive() +{ + AActor *info = GetDefault(); + flags = info->flags; + flags2 = info->flags2; + flags3 = info->flags3; + flags4 = info->flags4; + flags5 = info->flags5; + flags6 = info->flags6; + flags7 = info->flags7; + DamageType = info->DamageType; + health = SpawnHealth(); + target = NULL; + lastenemy = NULL; + + // [RH] If it's a monster, it gets to count as another kill + if (CountsAsKill()) + { + level.total_monsters++; + } +} + FDropItem *AActor::GetDropItems() { unsigned int index = GetClass()->Meta.GetMetaInt (ACMETA_DropItems) - 1; diff --git a/src/p_things.cpp b/src/p_things.cpp index 4828e8cbc6..e62c65ae78 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -410,18 +410,11 @@ void P_RemoveThing(AActor * actor) bool P_Thing_Raise(AActor *thing) { - if (thing == NULL) - return false; // not valid - - if (!(thing->flags & MF_CORPSE) ) - return true; // not a corpse - - if (thing->tics != -1) - return true; // not lying still yet - - FState * RaiseState = thing->FindState(NAME_Raise); + FState * RaiseState = thing->GetRaiseState(); if (RaiseState == NULL) + { return true; // monster doesn't have a raise state + } AActor *info = thing->GetDefault (); @@ -443,25 +436,12 @@ bool P_Thing_Raise(AActor *thing) return false; } - S_Sound (thing, CHAN_BODY, "vile/raise", 1, ATTN_IDLE); - - thing->SetState (RaiseState); - thing->flags = info->flags; - thing->flags2 = info->flags2; - thing->flags3 = info->flags3; - thing->flags4 = info->flags4; - thing->flags5 = info->flags5; - thing->flags6 = info->flags6; - thing->flags7 = info->flags7; - thing->health = info->health; - thing->target = NULL; - thing->lastenemy = NULL; - // [RH] If it's a monster, it gets to count as another kill - if (thing->CountsAsKill()) - { - level.total_monsters++; - } + S_Sound (thing, CHAN_BODY, "vile/raise", 1, ATTN_IDLE); + + thing->Revive(); + + thing->SetState (RaiseState); return true; } From 90e9937b71b6d846edbd7ae245189e9aa3353039 Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Mon, 5 May 2014 22:47:48 +1200 Subject: [PATCH 2/6] Stop NetUpdate from corrupting demo playback --- src/d_net.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/d_net.cpp b/src/d_net.cpp index c912d29a2b..170e9ed120 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -1052,6 +1052,12 @@ void NetUpdate (void) if (singletics) return; // singletic update is synchronous + if (demoplayback) + { + nettics[0] = (maketic / ticdup); + return; // Don't touch netcmd data while playing a demo, as it'll already exist. + } + // If maketic didn't cross a ticdup boundary, only send packets // to players waiting for resends. resendOnly = (maketic / ticdup) == (maketic - i) / ticdup; From fcbb72a4d45760c3f4512cea6d535b7ef12ecb15 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 6 May 2014 09:59:56 +0200 Subject: [PATCH 3/6] - removed redundant variable. --- src/p_enemy.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index f84dd13aa5..bdc72b0c82 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -2520,7 +2520,6 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates) fixed_t viletryx = self->x + FixedMul (absSpeed, xspeed[self->movedir]); fixed_t viletryy = self->y + FixedMul (absSpeed, yspeed[self->movedir]); AActor *corpsehit; - FState *raisestate; FBlockThingsIterator it(FBoundingBox(viletryx, viletryy, 32*FRACUNIT)); while ((corpsehit = it.Next())) From 890e9ecdddd36e1075098a3dcbaf0a93f73ddb51 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 7 May 2014 17:18:44 +0200 Subject: [PATCH 4/6] - typo in resurrection code. --- src/p_mobj.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 05eddf3abf..78b1124d42 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1,4 +1,5 @@ // Emacs style mode select -*- C++ -*- +// Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // // $Id:$ @@ -6082,7 +6083,7 @@ FState *AActor::GetRaiseState() } if (tics != -1 && // not lying still yet - state->GetCanRaise()) // or not ready to be raised yet + !state->GetCanRaise()) // or not ready to be raised yet { return NULL; } From 67ebbe3ed4bb2028c8850157d9e551569cc0aaba Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 8 May 2014 09:15:56 +0200 Subject: [PATCH 5/6] made some changes to turn the CF_INTERPVIEW flag when changing angles into an op-in feature instead of making it automatic. --- src/p_acs.cpp | 8 ++++---- src/p_mobj.cpp | 8 ++++---- src/thingdef/thingdef_codeptr.cpp | 18 ++++++++++-------- wadsrc/static/actors/actor.txt | 2 +- wadsrc/static/actors/constants.txt | 3 ++- 5 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index d70cc2c0be..8326d7b821 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -8251,7 +8251,7 @@ scriptwait: { if (activator != NULL) { - activator->SetAngle(STACK(1) << 16); + activator->SetAngle(STACK(1) << 16, false); } } else @@ -8261,7 +8261,7 @@ scriptwait: while ( (actor = iterator.Next ()) ) { - actor->SetAngle(STACK(1) << 16); + actor->SetAngle(STACK(1) << 16, false); } } sp -= 2; @@ -8272,7 +8272,7 @@ scriptwait: { if (activator != NULL) { - activator->SetPitch(STACK(1) << 16); + activator->SetPitch(STACK(1) << 16, false); } } else @@ -8282,7 +8282,7 @@ scriptwait: while ( (actor = iterator.Next ()) ) { - actor->SetPitch(STACK(1) << 16); + actor->SetPitch(STACK(1) << 16, false); } } sp -= 2; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 69d4203fe9..2bcae99b02 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -2962,24 +2962,24 @@ void AActor::SetShade (int r, int g, int b) fillcolor = MAKEARGB(ColorMatcher.Pick (r, g, b), r, g, b); } -void AActor::SetPitch(int p) +void AActor::SetPitch(int p, bool interpolate) { if (p != pitch) { pitch = p; - if (player != NULL) + if (player != NULL && interpolate) { player->cheats |= CF_INTERPVIEW; } } } -void AActor::SetAngle(angle_t ang) +void AActor::SetAngle(angle_t ang, bool interpolate) { if (ang != angle) { angle = ang; - if (player != NULL) + if (player != NULL && interpolate) { player->cheats |= CF_INTERPVIEW; } diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index d48b18a2aa..251a5de918 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -3930,12 +3930,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MonsterRefire) // Set actor's angle (in degrees). // //=========================================================================== +enum +{ + SPF_FORCECLAMP = 1, // players always clamp + SPF_INTERPOLATE = 2, +}; + DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetAngle) { - ACTION_PARAM_START(1); + ACTION_PARAM_START(2); ACTION_PARAM_ANGLE(angle, 0); - self->SetAngle(angle); + ACTION_PARAM_INT(flags, 1) + self->SetAngle(angle, !!(flags & SPF_INTERPOLATE)); } //=========================================================================== @@ -3946,11 +3953,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetAngle) // //=========================================================================== -enum -{ - SPF_FORCECLAMP = 1, // players always clamp -}; - DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetPitch) { ACTION_PARAM_START(2); @@ -3973,7 +3975,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetPitch) } pitch = clamp(pitch, min, max); } - self->SetPitch(pitch); + self->SetPitch(pitch, !!(flags & SPF_INTERPOLATE)); } //=========================================================================== diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 73119c9413..1eb00440c8 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -289,7 +289,7 @@ ACTOR Actor native //: Thinker action native A_DropWeaponPieces(class p1, class p2, class p3); action native A_PigPain (); action native A_MonsterRefire(int chance, state label); - action native A_SetAngle(float angle = 0); + action native A_SetAngle(float angle = 0, int flags = 0); action native A_SetPitch(float pitch, int flags = 0); action native A_ScaleVelocity(float scale); action native A_ChangeVelocity(float x = 0, float y = 0, float z = 0, int flags = 0); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index dee498b6a0..b252e31940 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -304,8 +304,9 @@ Const Int WARPF_STOP = 0x80; Const Int WARPF_TOFLOOR = 0x100; Const Int WARPF_TESTONLY = 0x200; -// flags for A_SetPitch +// flags for A_SetPitch/SetAngle const int SPF_FORCECLAMP = 1; +const int SPF_INTERPOLATE = 2; // flags for A_CheckLOF From 2223c12938ab24995a798443bee841b1fa249563 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 8 May 2014 09:43:58 +0200 Subject: [PATCH 6/6] - added new ChangeActorAngle/ChangeActorPitch ACS functions because the new required 'interpolate' parameter cannot be added to the existing SetActorAngle/SetActorPitch functions without breaking old scripts. --- src/actor.h | 4 +- src/p_acs.cpp | 106 ++++++++++++++++++++++++++++++++++---------------- 2 files changed, 74 insertions(+), 36 deletions(-) diff --git a/src/actor.h b/src/actor.h index 4b7696752e..0dd20c14f9 100644 --- a/src/actor.h +++ b/src/actor.h @@ -765,8 +765,8 @@ public: } // These also set CF_INTERPVIEW for players. - void SetPitch(int p); - void SetAngle(angle_t ang); + void SetPitch(int p, bool interpolate); + void SetAngle(angle_t ang, bool interpolate); const PClass *GetBloodType(int type = 0) const { diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 198ba0cd04..50dd2733b1 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4263,6 +4263,18 @@ enum EACSFunctions ACSF_SetLineActivation, ACSF_GetLineActivation, ACSF_GetActorPowerupTics, + ACSF_ChangeActorAngle, + ACSF_ChangeActorPitch, // 80 + + /* Zandronum's - these must be skipped when we reach 99! + -100:ResetMap(0), + -101 : PlayerIsSpectator(1), + -102 : ConsolePlayerNumber(0), + -103 : GetTeamProperty(2), + -104 : GetPlayerLivesLeft(1), + -105 : SetPlayerLivesLeft(2), + -106 : KickFromGame(2), + */ // ZDaemon ACSF_GetTeamScore = 19620, // (int team) @@ -4522,6 +4534,50 @@ static bool DoSpawnDecal(AActor *actor, const FDecalTemplate *tpl, int flags, an angle, distance, !!(flags & SDF_PERMANENT)); } +static void SetActorAngle(AActor *activator, int tid, int angle, bool interpolate) +{ + if (tid == 0) + { + if (activator != NULL) + { + activator->SetAngle(angle << 16, interpolate); + } + } + else + { + FActorIterator iterator(tid); + AActor *actor; + + while ((actor = iterator.Next())) + { + actor->SetAngle(angle << 16, interpolate); + } + } +} + +static void SetActorPitch(AActor *activator, int tid, int angle, bool interpolate) +{ + if (tid == 0) + { + if (activator != NULL) + { + activator->SetPitch(angle << 16, interpolate); + } + } + else + { + FActorIterator iterator(tid); + AActor *actor; + + while ((actor = iterator.Next())) + { + actor->SetPitch(angle << 16, interpolate); + } + } +} + + + int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args, const SDWORD *stack, int stackdepth) { AActor *actor; @@ -5349,6 +5405,20 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) } break; + case ACSF_ChangeActorAngle: + if (argCount >= 2) + { + SetActorAngle(activator, args[0], args[1], argCount > 2 ? !!args[2] : false); + } + break; + + case ACSF_ChangeActorPitch: + if (argCount >= 2) + { + SetActorPitch(activator, args[0], args[1], argCount > 2 ? !!args[2] : false); + } + break; + default: break; } @@ -8323,44 +8393,12 @@ scriptwait: break; case PCD_SETACTORANGLE: // [GRB] - if (STACK(2) == 0) - { - if (activator != NULL) - { - activator->SetAngle(STACK(1) << 16, false); - } - } - else - { - FActorIterator iterator (STACK(2)); - AActor *actor; - - while ( (actor = iterator.Next ()) ) - { - actor->SetAngle(STACK(1) << 16, false); - } - } + SetActorAngle(activator, STACK(2), STACK(1), false); sp -= 2; break; case PCD_SETACTORPITCH: - if (STACK(2) == 0) - { - if (activator != NULL) - { - activator->SetPitch(STACK(1) << 16, false); - } - } - else - { - FActorIterator iterator (STACK(2)); - AActor *actor; - - while ( (actor = iterator.Next ()) ) - { - actor->SetPitch(STACK(1) << 16, false); - } - } + SetActorPitch(activator, STACK(2), STACK(1), false); sp -= 2; break;