This commit is contained in:
Christoph Oelckers 2014-05-08 09:49:00 +02:00
commit 6988156d0f
9 changed files with 250 additions and 202 deletions

View file

@ -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
{
@ -1011,6 +1011,8 @@ public:
bool isSlow();
void SetIdle();
void ClearCounters();
FState *GetRaiseState();
void Revive();
FState *FindState (FName label) const
{

View file

@ -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;

View file

@ -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);
}
}
else
{
FActorIterator iterator (STACK(2));
AActor *actor;
while ( (actor = iterator.Next ()) )
{
actor->SetAngle(STACK(1) << 16);
}
}
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);
}
}
else
{
FActorIterator iterator (STACK(2));
AActor *actor;
while ( (actor = iterator.Next ()) )
{
actor->SetPitch(STACK(1) << 16);
}
}
SetActorPitch(activator, STACK(2), STACK(1), false);
sp -= 2;
break;

View file

@ -2520,151 +2520,126 @@ 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()))
{
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;

View file

@ -1,4 +1,5 @@
// Emacs style mode select -*- C++ -*-
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
@ -2973,24 +2974,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;
}
@ -6074,6 +6075,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;

View file

@ -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;
}

View file

@ -3931,12 +3931,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));
}
//===========================================================================
@ -3947,11 +3954,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);
@ -3974,7 +3976,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetPitch)
}
pitch = clamp<int>(pitch, min, max);
}
self->SetPitch(pitch);
self->SetPitch(pitch, !!(flags & SPF_INTERPOLATE));
}
//===========================================================================

View file

@ -289,7 +289,7 @@ ACTOR Actor native //: Thinker
action native A_DropWeaponPieces(class<Actor> p1, class<Actor> p2, class<Actor> 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);

View file

@ -307,8 +307,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