- Sync scripting branch with what was in trunk on Sunday. I believe that would be revision 2739.

SVN r2790 (scripting)
This commit is contained in:
Randy Heit 2010-09-16 03:14:32 +00:00
commit 99670b708c
317 changed files with 17299 additions and 7273 deletions

View file

@ -60,6 +60,7 @@
#include "colormatcher.h"
#include "v_palette.h"
#include "p_enemy.h"
#include "gstrings.h"
// MACROS ------------------------------------------------------------------
@ -171,6 +172,7 @@ IMPLEMENT_POINTY_CLASS (AActor)
DECLARE_POINTER (Inventory)
DECLARE_POINTER (LastHeard)
DECLARE_POINTER (master)
DECLARE_POINTER (Poisoner)
END_POINTERS
AActor::~AActor ()
@ -345,6 +347,11 @@ void AActor::Serialize (FArchive &arc)
WeaveIndexZ = 0;
}
}
if (SaveVersion >= 2450)
{
arc << PoisonDamageReceived << PoisonDurationReceived << PoisonPeriodReceived << Poisoner;
arc << PoisonDamage << PoisonDuration << PoisonPeriod;
}
// Skip past uservar array in old savegames
if (SaveVersion < 1933)
@ -354,65 +361,24 @@ void AActor::Serialize (FArchive &arc)
arc << foo;
}
if (arc.IsStoring ())
if (SaveVersion > 2560)
{
int convnum = 0;
unsigned int i;
if (Conversation != NULL)
{
for (i = 0; i < StrifeDialogues.Size(); ++i)
{
if (StrifeDialogues[i] == GetDefault()->Conversation)
{
break;
}
}
for (; i + convnum < StrifeDialogues.Size(); ++convnum)
{
if (StrifeDialogues[i + convnum] == Conversation)
{
break;
}
}
if (i + convnum < StrifeDialogues.Size())
{
convnum++;
}
else
{
convnum = 0;
}
}
arc.WriteCount (convnum);
arc << ConversationRoot << Conversation;
}
else
else // old code which uses relative indexing.
{
int convnum;
unsigned int i;
convnum = arc.ReadCount();
if (convnum == 0 || GetDefault()->Conversation == NULL)
if (GetConversation(GetClass()->TypeName) == -1)
{
Conversation = NULL;
ConversationRoot = -1;
}
else
{
for (i = 0; i < StrifeDialogues.Size(); ++i)
{
if (StrifeDialogues[i] == GetDefault()->Conversation)
{
break;
}
}
if (i + convnum <= StrifeDialogues.Size())
{
Conversation = StrifeDialogues[i + convnum - 1];
}
else
{
Conversation = GetDefault()->Conversation;
}
// This cannot be restored anymore.
I_Error("Cannot load old savegames with active dialogues");
}
}
@ -528,7 +494,7 @@ int AActor::GetTics(FState * newstate)
//
//==========================================================================
bool AActor::SetState (FState *newstate)
bool AActor::SetState (FState *newstate, bool nofunction)
{
if (debugfile && player && (player->cheats & CF_PREDICTING))
fprintf (debugfile, "for pl %td: SetState while predicting!\n", player-players);
@ -554,37 +520,41 @@ bool AActor::SetState (FState *newstate)
tics = GetTics(newstate);
renderflags = (renderflags & ~RF_FULLBRIGHT) | newstate->GetFullbright();
newsprite = newstate->sprite;
if (newsprite != 1)
{
// Sprite 1 is ----, which means "do not change the sprite"
frame = newstate->GetFrame();
if (!(flags4 & MF4_NOSKIN) && newsprite == SpawnState->sprite)
{ // [RH] If the new sprite is the same as the original sprite, and
// this actor is attached to a player, use the player's skin's
// sprite. If a player is not attached, do not change the sprite
// unless it is different from the previous state's sprite; a
// player may have been attached, died, and respawned elsewhere,
// and we do not want to lose the skin on the body. If it wasn't
// for Dehacked, I would move sprite changing out of the states
// altogether, since actors rarely change their sprites after
// spawning.
if (player != NULL)
{
sprite = skins[player->userinfo.skin].sprite;
if (newsprite != SPR_FIXED)
{ // okay to change sprite and/or frame
if (!newstate->GetSameFrame())
{ // okay to change frame
frame = newstate->GetFrame();
}
if (newsprite != SPR_NOCHANGE)
{ // okay to change sprite
if (!(flags4 & MF4_NOSKIN) && newsprite == SpawnState->sprite)
{ // [RH] If the new sprite is the same as the original sprite, and
// this actor is attached to a player, use the player's skin's
// sprite. If a player is not attached, do not change the sprite
// unless it is different from the previous state's sprite; a
// player may have been attached, died, and respawned elsewhere,
// and we do not want to lose the skin on the body. If it wasn't
// for Dehacked, I would move sprite changing out of the states
// altogether, since actors rarely change their sprites after
// spawning.
if (player != NULL)
{
sprite = skins[player->userinfo.skin].sprite;
}
else if (newsprite != prevsprite)
{
sprite = newsprite;
}
}
else if (newsprite != prevsprite)
else
{
sprite = newsprite;
}
}
else
{
sprite = newsprite;
}
}
if (newstate->CallAction(this, this))
if (!nofunction && newstate->CallAction(this, this))
{
// Check whether the called action function resulted in destroying the actor
if (ObjectFlags & OF_EuthanizeMe)
@ -593,67 +563,10 @@ bool AActor::SetState (FState *newstate)
newstate = newstate->GetNextState();
} while (tics == 0);
screen->StateChanged(this);
return true;
}
//----------------------------------------------------------------------------
//
// FUNC AActor::SetStateNF
//
// Same as SetState, but does not call the state function.
//
//----------------------------------------------------------------------------
bool AActor::SetStateNF (FState *newstate)
{
do
if (screen != NULL)
{
if (newstate == NULL)
{
state = NULL;
Destroy ();
return false;
}
int prevsprite, newsprite;
if (state != NULL)
{
prevsprite = state->sprite;
}
else
{
prevsprite = -1;
}
state = newstate;
tics = GetTics(newstate);
renderflags = (renderflags & ~RF_FULLBRIGHT) | newstate->GetFullbright();
newsprite = newstate->sprite;
if (newsprite != 1)
{
// Sprite 1 is ----, which means "do not change the sprite"
frame = newstate->GetFrame();
if (!(flags4 & MF4_NOSKIN) && newsprite == SpawnState->sprite)
{
if (player != NULL && gameinfo.gametype != GAME_Hexen)
{
sprite = skins[player->userinfo.skin].sprite;
}
else if (newsprite != prevsprite)
{
sprite = newsprite;
}
}
else
{
sprite = newsprite;
}
}
newstate = newstate->GetNextState();
} while (tics == 0);
screen->StateChanged(this);
screen->StateChanged(this);
}
return true;
}
@ -824,7 +737,7 @@ AInventory *AActor::DropInventory (AInventory *item)
//
//============================================================================
AInventory *AActor::FindInventory (PClassActor *type)
AInventory *AActor::FindInventory (PClassActor *type, bool subclass)
{
AInventory *item;
@ -834,9 +747,19 @@ AInventory *AActor::FindInventory (PClassActor *type)
}
for (item = Inventory; item != NULL; item = item->Inventory)
{
if (item->GetClass() == type)
if (!subclass)
{
break;
if (item->GetClass() == type)
{
break;
}
}
else
{
if (item->IsKindOf(type))
{
break;
}
}
}
return item;
@ -1528,8 +1451,8 @@ bool AActor::CanSeek(AActor *target) const
if (target->flags5 & MF5_CANTSEEK) return false;
if ((flags2 & MF2_DONTSEEKINVISIBLE) &&
((target->flags & MF_SHADOW) ||
target->renderflags & RF_INVISIBLE ||
target->RenderStyle.IsVisible(target->alpha)
(target->renderflags & RF_INVISIBLE) ||
!target->RenderStyle.IsVisible(target->alpha)
)
) return false;
return true;
@ -1544,7 +1467,7 @@ bool AActor::CanSeek(AActor *target) const
//
//----------------------------------------------------------------------------
bool P_SeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax)
bool P_SeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax, bool precise)
{
int dir;
int dist;
@ -1580,28 +1503,54 @@ bool P_SeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax)
actor->angle -= delta;
}
angle = actor->angle>>ANGLETOFINESHIFT;
actor->velx = FixedMul (actor->Speed, finecosine[angle]);
actor->vely = FixedMul (actor->Speed, finesine[angle]);
if (!(actor->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER)))
if (!precise)
{
if (actor->z + actor->height < target->z ||
target->z + target->height < actor->z)
{ // Need to seek vertically
dist = P_AproxDistance (target->x - actor->x, target->y - actor->y);
dist = dist / actor->Speed;
if (dist < 1)
{
dist = 1;
actor->velx = FixedMul (actor->Speed, finecosine[angle]);
actor->vely = FixedMul (actor->Speed, finesine[angle]);
if (!(actor->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER)))
{
if (actor->z + actor->height < target->z ||
target->z + target->height < actor->z)
{ // Need to seek vertically
dist = P_AproxDistance (target->x - actor->x, target->y - actor->y);
dist = dist / actor->Speed;
if (dist < 1)
{
dist = 1;
}
actor->velz = ((target->z+target->height/2) - (actor->z+actor->height/2)) / dist;
}
actor->velz = ((target->z+target->height/2) - (actor->z+actor->height/2)) / dist;
}
}
else
{
angle_t pitch = 0;
if (!(actor->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER)))
{ // Need to seek vertically
double dist = MAX(1.0, FVector2(target->x - actor->x, target->y - actor->y).Length());
// Aim at a player's eyes and at the middle of the actor for everything else.
fixed_t aimheight = target->height/2;
if (target->IsKindOf(RUNTIME_CLASS(APlayerPawn)))
{
aimheight = static_cast<APlayerPawn *>(target)->ViewHeight;
}
pitch = R_PointToAngle2(0, actor->z + actor->height/2, xs_CRoundToInt(dist), target->z + aimheight);
pitch >>= ANGLETOFINESHIFT;
}
fixed_t xyscale = FixedMul(actor->Speed, finecosine[pitch]);
actor->velz = FixedMul(actor->Speed, finesine[pitch]);
actor->velx = FixedMul(xyscale, finecosine[angle]);
actor->vely = FixedMul(xyscale, finesine[angle]);
}
return true;
}
//
// P_XYMovement
//
@ -3189,41 +3138,27 @@ void AActor::Tick ()
velz <= 0 &&
floorz == z)
{
const secplane_t * floorplane = &floorsector->floorplane;
static secplane_t copyplane;
secplane_t floorplane = floorsector->floorplane;
#ifdef _3DFLOORS
// Check 3D floors as well
if (floorsector->e) // apparently this can be called when the data is already gone-
for(unsigned int i=0;i<floorsector->e->XFloor.ffloors.Size();i++)
{
F3DFloor * rover= floorsector->e->XFloor.ffloors[i];
if(!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue;
if (rover->top.plane->ZatPoint(x, y) == floorz)
{
copyplane = *rover->top.plane;
if (copyplane.c<0) copyplane.FlipVert();
floorplane = &copyplane;
break;
}
}
floorplane = P_FindFloorPlane(floorsector, x, y, floorz);
#endif
if (floorplane->c < STEEPSLOPE &&
floorplane->ZatPoint (x, y) <= floorz)
if (floorplane.c < STEEPSLOPE &&
floorplane.ZatPoint (x, y) <= floorz)
{
const msecnode_t *node;
bool dopush = true;
if (floorplane->c > STEEPSLOPE*2/3)
if (floorplane.c > STEEPSLOPE*2/3)
{
for (node = touching_sectorlist; node; node = node->m_tnext)
{
const sector_t *sec = node->m_sector;
if (sec->floorplane.c >= STEEPSLOPE)
{
if (floorplane->ZatPoint (x, y) >= z - MaxStepHeight)
if (floorplane.ZatPoint (x, y) >= z - MaxStepHeight)
{
dopush = false;
break;
@ -3233,8 +3168,8 @@ void AActor::Tick ()
}
if (dopush)
{
velx += floorplane->a;
vely += floorplane->b;
velx += floorplane.a;
vely += floorplane.b;
}
}
}
@ -3331,6 +3266,18 @@ void AActor::Tick ()
{
return;
}
// Check for poison damage, but only once per PoisonPeriod tics (or once per second if none).
if (PoisonDurationReceived && (level.time % (PoisonPeriodReceived ? PoisonPeriodReceived : TICRATE) == 0))
{
P_DamageMobj(this, NULL, Poisoner, PoisonDamageReceived, NAME_Poison, 0);
--PoisonDurationReceived;
// Must clear damage when duration is done, otherwise it
// could be added to with ADDITIVEPOISONDAMAGE.
if (!PoisonDurationReceived) PoisonDamageReceived = 0;
}
}
// cycle through states, calling action functions at transitions
@ -3495,6 +3442,7 @@ bool AActor::UpdateWaterLevel (fixed_t oldz, bool dosplash)
return false; // we did the splash ourselves
}
//==========================================================================
//
// P_SpawnMobj
@ -3517,6 +3465,17 @@ AActor *AActor::StaticSpawn (PClassActor *type, fixed_t ix, fixed_t iy, fixed_t
actor = static_cast<AActor *>(const_cast<PClassActor *>(type)->CreateNew ());
// Set default dialogue
actor->ConversationRoot = GetConversation(actor->GetClass()->TypeName);
if (actor->ConversationRoot != -1)
{
actor->Conversation = StrifeDialogues[actor->ConversationRoot];
}
else
{
actor->Conversation = NULL;
}
actor->x = actor->PrevX = ix;
actor->y = actor->PrevY = iy;
actor->z = actor->PrevZ = iz;
@ -3663,7 +3622,10 @@ AActor *AActor::StaticSpawn (PClassActor *type, fixed_t ix, fixed_t iy, fixed_t
{
level.total_items++;
}
screen->StateChanged(actor);
if (screen != NULL)
{
screen->StateChanged(actor);
}
return actor;
}
@ -3985,7 +3947,6 @@ APlayerPawn *P_SpawnPlayer (FMapThing *mthing, bool tempplayer)
// [GRB] Reset skin
p->userinfo.skin = R_FindSkin (skins[p->userinfo.skin].name, p->CurrentPlayerClass);
StatusBar->SetFace (&skins[p->userinfo.skin]);
if (!(mobj->flags2 & MF2_DONTTRANSLATE))
@ -4314,6 +4275,11 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position)
mthing->args[0] = mthing->type - 14000;
mthing->type = 14065;
}
else if (mthing->type >= 14101 && mthing->type <= 14164)
{
mthing->args[0] = mthing->type - 14100;
mthing->type = 14165;
}
// find which type to spawn
i = DoomEdMap.FindType (mthing->type);
@ -4430,6 +4396,19 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position)
mobj->AddToHash ();
mobj->PrevAngle = mobj->angle = (DWORD)((mthing->angle * UCONST64(0x100000000)) / 360);
// Check if this actor's mapthing has a conversation defined
if (mthing->Conversation > 0)
{
// Make sure that this does not partially overwrite the default dialogue settings.
int root = GetConversation(mthing->Conversation);
if (root != -1)
{
mobj->ConversationRoot = root;
mobj->Conversation = StrifeDialogues[mobj->ConversationRoot];
}
}
mobj->BeginPlay ();
if (!(mobj->ObjectFlags & OF_EuthanizeMe))
{
@ -4522,7 +4501,7 @@ void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AAc
if (bloodcls!=NULL && bloodtype <= 1)
{
z += pr_spawnblood.Random2 () << 10;
th = Spawn (bloodcls, x, y, z, ALLOW_REPLACE);
th = Spawn (bloodcls, x, y, z, NO_REPLACE); // GetBloodType already performed the replacement
th->velz = FRACUNIT*2;
th->angle = dir;
if (gameinfo.gametype & GAME_DoomChex)
@ -4585,7 +4564,7 @@ void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator)
{
AActor *mo;
mo = Spawn(bloodcls, x, y, z, ALLOW_REPLACE);
mo = Spawn(bloodcls, x, y, z, NO_REPLACE); // GetBloodType already performed the replacement
mo->target = originator;
mo->velx = pr_splatter.Random2 () << 10;
mo->vely = pr_splatter.Random2 () << 10;
@ -4626,7 +4605,7 @@ void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator)
x += ((pr_splat()-128)<<11);
y += ((pr_splat()-128)<<11);
mo = Spawn (bloodcls, x, y, z, ALLOW_REPLACE);
mo = Spawn (bloodcls, x, y, z, NO_REPLACE); // GetBloodType already performed the replacement
mo->target = originator;
// colorize the blood!
@ -4665,7 +4644,7 @@ void P_RipperBlood (AActor *mo, AActor *bleeder)
if (bloodcls!=NULL && bloodtype <= 1)
{
AActor *th;
th = Spawn (bloodcls, x, y, z, ALLOW_REPLACE);
th = Spawn (bloodcls, x, y, z, NO_REPLACE); // GetBloodType already performed the replacement
if (gameinfo.gametype == GAME_Heretic)
th->flags |= MF_NOGRAVITY;
th->velx = mo->velx >> 1;
@ -4728,6 +4707,20 @@ bool P_HitWater (AActor * thing, sector_t * sec, fixed_t x, fixed_t y, fixed_t z
// don't splash above the object
if (checkabove && z > thing->z + (thing->height >> 1)) return false;
#if 0 // needs some rethinking before activation
// This avoids spawning splashes on invisible self referencing sectors.
// For network consistency do this only in single player though because
// it is not guaranteed that all players have GL nodes loaded.
if (!multiplayer && thing->subsector->sector != thing->subsector->render_sector)
{
fixed_t zs = thing->subsector->sector->floorplane.ZatPoint(x, y);
fixed_t zr = thing->subsector->render_sector->floorplane.ZatPoint(x, y);
if (zs > zr && thing->z >= zs) return false;
}
#endif
#ifdef _3DFLOORS
for(unsigned int i=0;i<sec->e->XFloor.ffloors.Size();i++)
{
@ -4846,7 +4839,7 @@ bool P_HitFloor (AActor *thing)
{
thing->flags6 &= ~MF6_ARMED; // Disarm
P_DamageMobj (thing, NULL, NULL, thing->health, NAME_Crush, DMG_FORCED); // kill object
return true;
return false;
}
if (thing->flags2 & MF2_FLOATBOB || thing->flags3 & MF3_DONTSPLASH)
@ -4972,7 +4965,7 @@ bool P_CheckMissileSpawn (AActor* th)
bool MBFGrenade = (!(th->flags & MF_MISSILE) || (th->BounceFlags & BOUNCE_MBF));
// killough 3/15/98: no dropoff (really = don't care for missiles)
if (!(P_TryMove (th, th->x, th->y, false, false, tm)))
if (!(P_TryMove (th, th->x, th->y, false, NULL, tm)))
{
// [RH] Don't explode ripping missiles that spawn inside something
if (th->BlockingMobj == NULL || !(th->flags2 & MF2_RIP) || (th->BlockingMobj->flags5 & MF5_DONTRIP))
@ -5456,10 +5449,10 @@ int AActor::DoSpecialDamage (AActor *target, int damage)
{
if (target->player)
{
int poisondamage = GetClass()->PoisonDamage;
if (poisondamage > 0)
// Only do this for old style poison damage.
if (PoisonDamage > 0 && PoisonDuration == INT_MIN)
{
P_PoisonPlayer (target->player, this, this->target, poisondamage);
P_PoisonPlayer (target->player, this, this->target, PoisonDamage);
damage >>= 1;
}
}
@ -5605,9 +5598,26 @@ bool AActor::IsSentient() const
const char *AActor::GetTag(const char *def) const
{
if (Tag != NAME_None) return Tag.GetChars();
else if (def) return def;
else return GetClass()->TypeName.GetChars();
if (Tag != NAME_None)
{
const char *tag = Tag.GetChars();
if (tag[0] == '$')
{
return GStrings(tag + 1);
}
else
{
return tag;
}
}
else if (def)
{
return def;
}
else
{
return GetClass()->TypeName.GetChars();
}
}