# Conflicts:
#	src/version.h
This commit is contained in:
raa-eruanna 2016-09-19 03:05:38 -04:00
commit 20e620bbe7
20 changed files with 141 additions and 210 deletions

View File

@ -111,6 +111,8 @@ struct FPortalGroupArray;
// Any questions?
//
// --- mobj.flags ---
enum ActorFlag
{
@ -1014,7 +1016,9 @@ public:
SDWORD tics; // state tic counter
FState *state;
VMFunction *Damage; // For missiles and monster railgun
//VMFunction *Damage; // For missiles and monster railgun
int DamageVal;
VMFunction *DamageFunc;
int projectileKickback;
ActorFlags flags;
ActorFlags2 flags2; // Heretic flags
@ -1201,6 +1205,23 @@ public:
FState *GetRaiseState();
void Revive();
void SetDamage(int dmg)
{
DamageVal = dmg;
DamageFunc = nullptr;
}
bool IsZeroDamage() const
{
return DamageVal == 0 && DamageFunc == nullptr;
}
void RestoreDamage()
{
DamageVal = GetDefault()->DamageVal;
DamageFunc = GetDefault()->DamageFunc;
}
FState *FindState (FName label) const
{
return GetClass()->FindState(1, &label);

View File

@ -915,7 +915,7 @@ static int PatchThing (int thingy)
}
else if (linelen == 14 && stricmp (Line1, "Missile damage") == 0)
{
info->Damage = CreateDamageFunction(val);
info->SetDamage(val);
}
else if (linelen == 5)
{

View File

@ -47,7 +47,7 @@ static void BrainishExplosion (const DVector3 &pos)
boom->SetState (state);
}
boom->effects = 0;
boom->Damage = NULL; // disables collision detection which is not wanted here
boom->SetDamage(0); // disables collision detection which is not wanted here
boom->tics -= pr_brainscream() & 7;
if (boom->tics < 1)
boom->tics = 1;

View File

@ -115,7 +115,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichAttack)
fire->target = baseFire->target;
fire->Angles.Yaw = baseFire->Angles.Yaw;
fire->Vel = baseFire->Vel;
fire->Damage = NULL;
fire->SetDamage(0);
fire->health = (i+1) * 2;
P_CheckMissileSpawn (fire, self->radius);
}
@ -205,7 +205,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichFireGrow)
self->AddZ(9.);
if (self->health == 0)
{
self->Damage = self->GetDefault()->Damage;
self->RestoreDamage();
self->SetState (self->FindState("NoGrow"));
}
return 0;

View File

@ -340,7 +340,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LastZap)
{
mo->SetState (mo->FindState (NAME_Death));
mo->Vel.Z = 40;
mo->Damage = NULL;
mo->SetDamage(0);
}
return 0;
}

View File

@ -497,6 +497,10 @@ void GLDrawList::SortWallIntoWall(SortNode * head,SortNode * sort)
//
//
//==========================================================================
EXTERN_CVAR(Int, gl_billboard_mode)
EXTERN_CVAR(Bool, gl_billboard_faces_camera)
EXTERN_CVAR(Bool, gl_billboard_particles)
void GLDrawList::SortSpriteIntoWall(SortNode * head,SortNode * sort)
{
GLWall * wh=&walls[drawitems[head->itemindex].index];
@ -527,6 +531,27 @@ void GLDrawList::SortSpriteIntoWall(SortNode * head,SortNode * sort)
}
else
{
const bool drawWithXYBillboard = ((ss->particle && gl_billboard_particles) || (!(ss->actor && ss->actor->renderflags & RF_FORCEYBILLBOARD)
&& (gl_billboard_mode == 1 || (ss->actor && ss->actor->renderflags & RF_FORCEXYBILLBOARD))));
const bool drawBillboardFacingCamera = gl_billboard_faces_camera;
// [Nash] has +ROLLSPRITE
const bool rotated = (ss->actor != nullptr && ss->actor->renderflags & RF_ROLLSPRITE | RF_WALLSPRITE | RF_FLATSPRITE);
// cannot sort them at the moment. This requires more complex splitting.
if (drawWithXYBillboard || drawBillboardFacingCamera || rotated)
{
float v1 = wh->PointOnSide(ss->x, ss->y);
if (v1 < 0)
{
head->AddToLeft(sort);
}
else
{
head->AddToRight(sort);
}
return;
}
double r=ss->CalcIntersectionVertex(wh);
float ix=(float)(ss->x1 + r * (ss->x2-ss->x1));

View File

@ -923,7 +923,7 @@ void GLSprite::Process(AActor* thing, sector_t * sector, int thruportal)
// This is a non-translucent sprite (i.e. STYLE_Normal or equivalent)
trans=1.f;
if (!gl_sprite_blend || modelframe || (thing->renderflags & RF_SPRITETYPEMASK) == RF_WALLSPRITE)
if (!gl_sprite_blend || modelframe || (thing->renderflags & (RF_FLATSPRITE|RF_WALLSPRITE)) || gl_billboard_faces_camera)
{
RenderStyle.SrcAlpha = STYLEALPHA_One;
RenderStyle.DestAlpha = STYLEALPHA_Zero;
@ -934,8 +934,6 @@ void GLSprite::Process(AActor* thing, sector_t * sector, int thruportal)
RenderStyle.SrcAlpha = STYLEALPHA_Src;
RenderStyle.DestAlpha = STYLEALPHA_InvSrc;
}
}
if ((gltexture && gltexture->GetTransparent()) || (RenderStyle.Flags & STYLEF_RedIsAlpha))
{

View File

@ -344,7 +344,7 @@ size_t PClassActor::PropagateMark()
// Mark damage function
if (Defaults != NULL)
{
GC::Mark(((AActor *)Defaults)->Damage);
GC::Mark(((AActor *)Defaults)->DamageFunc);
}
// marked += ActorInfo->NumOwnedStates * sizeof(FState);

View File

@ -3791,7 +3791,7 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value)
break;
case APROP_Damage:
actor->Damage = CreateDamageFunction(value);
actor->SetDamage(value);
break;
case APROP_Alpha:

View File

@ -1320,7 +1320,7 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch
// [RH] What is the point of this check, again? In Hexen, it is unconditional,
// but here we only do it if the missile's damage is 0.
// MBF bouncer might have a non-0 damage value, but they must not deal damage on impact either.
if ((tm.thing->BounceFlags & BOUNCE_Actors) && (tm.thing->Damage == 0 || !(tm.thing->flags & MF_MISSILE)))
if ((tm.thing->BounceFlags & BOUNCE_Actors) && (tm.thing->IsZeroDamage() || !(tm.thing->flags & MF_MISSILE)))
{
return (tm.thing->target == thing || !(thing->flags & MF_SOLID));
}

View File

@ -139,7 +139,8 @@ IMPLEMENT_POINTY_CLASS (AActor)
DECLARE_POINTER (LastHeard)
DECLARE_POINTER (master)
DECLARE_POINTER (Poisoner)
DECLARE_POINTER (Damage)
DECLARE_POINTER (DamageFunc)
DECLARE_POINTER (alternative)
END_POINTERS
AActor::~AActor ()
@ -148,73 +149,6 @@ AActor::~AActor ()
// Use Destroy() instead.
}
//==========================================================================
//
// CalcDamageValue
//
// Given a script function, returns an integer to represent it in a
// savegame. This encoding is compatible with previous incarnations
// where damage was an integer.
//
// 0 : use null function
// 0x40000000 : use default function
// anything else : use function that returns this number
//
//==========================================================================
static int CalcDamageValue(VMFunction *func)
{
if (func == NULL)
{
return 0;
}
VMScriptFunction *sfunc = dyn_cast<VMScriptFunction>(func);
if (sfunc == NULL)
{
return 0x40000000;
}
VMOP *op = sfunc->Code;
// If the function was created by CreateDamageFunction(), extract
// the value used to create it and return that. Otherwise, return
// indicating to use the default function.
if (op->op == OP_RETI && op->a == 0)
{
return op->i16;
}
if (op->op == OP_RET && op->a == 0 && op->b == (REGT_INT | REGT_KONST))
{
return sfunc->KonstD[op->c];
}
return 0x40000000;
}
//==========================================================================
//
// UncalcDamageValue
//
// Given a damage integer, returns a script function for it.
//
//==========================================================================
static VMFunction *UncalcDamageValue(int dmg, VMFunction *def)
{
if (dmg == 0)
{
return NULL;
}
if ((dmg & 0xC0000000) == 0x40000000)
{
return def;
}
// Does the default version return this? If so, use it. Otherwise,
// create a new function.
if (CalcDamageValue(def) == dmg)
{
return def;
}
return CreateDamageFunction(dmg);
}
//==========================================================================
//
// AActor :: Serialize
@ -262,18 +196,16 @@ void AActor::Serialize(FArchive &arc)
<< projectilepassheight
<< Vel
<< tics
<< state;
if (arc.IsStoring())
<< state
<< DamageVal;
if (DamageVal == 0x40000000 || DamageVal == -1)
{
int dmg;
dmg = CalcDamageValue(Damage);
arc << dmg;
DamageVal = -1;
DamageFunc = GetDefault()->DamageFunc;
}
else
{
int dmg;
arc << dmg;
Damage = UncalcDamageValue(dmg, GetDefault()->Damage);
DamageFunc = nullptr;
}
P_SerializeTerrain(arc, floorterrain);
arc << projectileKickback
@ -2974,8 +2906,21 @@ CCMD(utid)
int AActor::GetMissileDamage (int mask, int add)
{
if (Damage == NULL)
if (DamageVal >= 0)
{
if (mask == 0)
{
return add * DamageVal;
}
else
{
return ((pr_missiledamage() & mask) + add) * DamageVal;
}
}
if (DamageFunc == nullptr)
{
// This should never happen
assert(false && "No damage function found");
return 0;
}
VMFrameStack stack;
@ -2987,22 +2932,11 @@ int AActor::GetMissileDamage (int mask, int add)
results[0].IntAt(&amount);
results[1].IntAt(&calculated);
if (stack.Call(Damage, &param, 1, results, 2) < 1)
if (stack.Call(DamageFunc, &param, 1, results, 2) < 1)
{ // No results
return 0;
}
if (calculated)
{
return amount;
}
else if (mask == 0)
{
return add * amount;
}
else
{
return ((pr_missiledamage() & mask) + add) * amount;
}
return amount;
}
void AActor::Howl ()
@ -3694,7 +3628,7 @@ void AActor::Tick ()
// still have missiles that go straight up and down through actors without
// damaging anything.
// (for backwards compatibility this must check for lack of damage function, not for zero damage!)
if ((flags & MF_MISSILE) && Vel.X == 0 && Vel.Y == 0 && Damage != NULL)
if ((flags & MF_MISSILE) && Vel.X == 0 && Vel.Y == 0 && !IsZeroDamage())
{
Vel.X = MinVel;
}

View File

@ -496,8 +496,7 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults,
else if (def == DEF_Projectile && sc.Compare ("Damage"))
{
sc.MustGetNumber ();
FxDamageValue *x = new FxDamageValue(new FxConstant(sc.Number, sc), false);
defaults->Damage = (VMFunction *)(uintptr_t)(ActorDamageFuncs.Push(x) + 1);
defaults->SetDamage(sc.Number);
}
else if (def == DEF_Projectile && sc.Compare ("DamageType"))
{

View File

@ -348,12 +348,12 @@ static void FinishThingdef()
continue;
}
if (def->Damage != NULL)
if (def->DamageFunc != nullptr)
{
FxDamageValue *dmg = (FxDamageValue *)ActorDamageFuncs[(uintptr_t)def->Damage - 1];
FxDamageValue *dmg = (FxDamageValue *)ActorDamageFuncs[(uintptr_t)def->DamageFunc - 1];
VMScriptFunction *sfunc;
sfunc = dmg->GetFunction();
if (sfunc == NULL)
if (sfunc == nullptr)
{
FCompileContext ctx(ti);
dmg = static_cast<FxDamageValue *>(dmg->Resolve(ctx));
@ -365,15 +365,15 @@ static void FinishThingdef()
dmg->Emit(&buildit);
sfunc = buildit.MakeFunction();
sfunc->NumArgs = 1;
sfunc->Proto = NULL; ///FIXME: Need a proper prototype here
sfunc->Proto = nullptr; ///FIXME: Need a proper prototype here
// Save this function in case this damage value was reused
// (which happens quite easily with inheritance).
dmg->SetFunction(sfunc);
}
}
def->Damage = sfunc;
def->DamageFunc = sfunc;
if (dump != NULL && sfunc != NULL)
if (dump != nullptr && sfunc != nullptr)
{
char label[64];
int labellen = mysnprintf(label, countof(label), "Function %s.Damage",

View File

@ -231,6 +231,38 @@ DEFINE_ACTION_FUNCTION(AActor, CheckClass)
return 0;
}
//==========================================================================
//
// CheckClass
//
// NON-ACTION function to calculate missile damage for the given actor
//
//==========================================================================
DEFINE_ACTION_FUNCTION(AActor, GetMissileDamage)
{
if (numret > 0)
{
assert(ret != NULL);
PARAM_SELF_PROLOGUE(AActor);
PARAM_INT(mask);
PARAM_INT(add)
PARAM_INT_OPT(pick_pointer) { pick_pointer = AAPTR_DEFAULT; }
self = COPY_AAPTR(self, pick_pointer);
if (self == NULL)
{
ret->SetInt(0);
}
else
{
ret->SetInt(self->GetMissileDamage(mask, add));
}
return 1;
}
return 0;
}
//==========================================================================
//
// IsPointerEqual

View File

@ -666,4 +666,5 @@ void InitThingdef()
symt.AddSymbol(new PField(NAME_Speed, TypeFloat64, VARF_Native, myoffsetof(AActor, Speed)));
symt.AddSymbol(new PField(NAME_Threshold, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, threshold)));
symt.AddSymbol(new PField(NAME_DefThreshold, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, DefThreshold)));
symt.AddSymbol(new PField(NAME_Damage, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, DamageVal)));
}

View File

@ -854,20 +854,6 @@ public:
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
//
// FxDamage
//
//==========================================================================
class FxDamage : public FxExpression
{
public:
FxDamage(const FScriptPosition&);
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
//
// FxArrayElement
@ -1188,12 +1174,11 @@ public:
class FxDamageValue : public FxExpression
{
FxExpression *val;
bool Calculated;
VMScriptFunction *MyFunction;
public:
FxDamageValue(FxExpression *v, bool calc);
FxDamageValue(FxExpression *v);
~FxDamageValue();
FxExpression *Resolve(FCompileContext&);

View File

@ -3218,11 +3218,6 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx)
ScriptPosition.Message(MSG_ERROR, "Invalid member identifier '%s'\n", Identifier.GetChars());
}
}
// the damage property needs special handling
else if (Identifier == NAME_Damage)
{
newex = new FxDamage(ScriptPosition);
}
// now check the global identifiers.
else if ((sym = ctx.FindGlobal(Identifier)) != NULL)
{
@ -3316,65 +3311,6 @@ ExpEmit FxSelf::Emit(VMFunctionBuilder *build)
}
//==========================================================================
//
//
//
//==========================================================================
FxDamage::FxDamage(const FScriptPosition &pos)
: FxExpression(pos)
{
}
//==========================================================================
//
// FxDamage :: Resolve
//
//==========================================================================
FxExpression *FxDamage::Resolve(FCompileContext& ctx)
{
CHECKRESOLVED();
ValueType = TypeSInt32;
return this;
}
//==========================================================================
//
// FxDamage :: Emit
//
// Call this actor's damage function, if it has one
//
//==========================================================================
ExpEmit FxDamage::Emit(VMFunctionBuilder *build)
{
ExpEmit dmgval(build, REGT_INT);
// Get damage function
ExpEmit dmgfunc(build, REGT_POINTER);
build->Emit(OP_LO, dmgfunc.RegNum, 0/*self*/, build->GetConstantInt(myoffsetof(AActor, Damage)));
// If it's non-null...
build->Emit(OP_EQA_K, 1, dmgfunc.RegNum, build->GetConstantAddress(nullptr, ATAG_GENERIC));
size_t nulljump = build->Emit(OP_JMP, 0);
// ...call it
build->Emit(OP_PARAM, 0, REGT_POINTER, 0/*self*/);
build->Emit(OP_CALL, dmgfunc.RegNum, 1, 1);
build->Emit(OP_RESULT, 0, REGT_INT, dmgval.RegNum);
size_t notnulljump = build->Emit(OP_JMP, 0);
// Otherwise, use 0
build->BackpatchToHere(nulljump);
build->EmitLoadInt(dmgval.RegNum, 0);
build->BackpatchToHere(notnulljump);
return dmgval;
}
//==========================================================================
//
//
@ -5225,18 +5161,12 @@ ExpEmit FxMultiNameState::Emit(VMFunctionBuilder *build)
//
//==========================================================================
FxDamageValue::FxDamageValue(FxExpression *v, bool calc)
FxDamageValue::FxDamageValue(FxExpression *v)
: FxExpression(v->ScriptPosition)
{
val = v;
ValueType = TypeVoid;
Calculated = calc;
MyFunction = NULL;
if (!calc)
{
assert(v->isConstant() && "Non-calculated damage must be constant");
}
}
FxDamageValue::~FxDamageValue()
@ -5272,7 +5202,7 @@ ExpEmit FxDamageValue::Emit(VMFunctionBuilder *build)
assert(emitval.RegType == REGT_INT);
build->Emit(OP_RET, 0, REGT_INT | (emitval.Konst ? REGT_KONST : 0), emitval.RegNum);
}
build->Emit(OP_RETI, 1 | RET_FINAL, Calculated);
build->Emit(OP_RETI, 1 | RET_FINAL, true);
return ExpEmit();
}

View File

@ -865,19 +865,21 @@ static bool ParsePropertyParams(FScanner &sc, FPropertyInfo *prop, AActor *defau
if (sc.CheckString ("("))
{
x = new FxDamageValue(new FxIntCast(ParseExpression(sc, bag.Info)), true);
conv.i = -1;
params.Push(conv);
x = new FxDamageValue(new FxIntCast(ParseExpression(sc, bag.Info)));
sc.MustGetStringName(")");
conv.exp = x;
params.Push(conv);
}
else
{
sc.MustGetNumber();
if (sc.Number != 0)
{
x = new FxDamageValue(new FxConstant(sc.Number, bag.ScriptPosition), false);
}
conv.i = sc.Number;
params.Push(conv);
conv.exp = nullptr;
}
conv.exp = x;
params.Push(conv);
}
break;

View File

@ -636,7 +636,8 @@ DEFINE_PROPERTY(threshold, I, Actor)
//==========================================================================
DEFINE_PROPERTY(damage, X, Actor)
{
PROP_EXP_PARM(id, 0);
PROP_INT_PARM(dmgval, 0);
PROP_EXP_PARM(id, 1);
// Damage can either be a single number, in which case it is subject
// to the original damage calculation rules. Or, it can be an expression
@ -646,13 +647,15 @@ DEFINE_PROPERTY(damage, X, Actor)
// Store this expression here for now. It will be converted to a function
// later once all actors have been processed.
if (id == NULL)
defaults->DamageVal = dmgval;
if (id == nullptr)
{
defaults->Damage = NULL;
defaults->DamageFunc = nullptr;
}
else
{
defaults->Damage = (VMFunction *)(uintptr_t)(ActorDamageFuncs.Push(id) + 1);
defaults->DamageFunc = (VMFunction *)(uintptr_t)(ActorDamageFuncs.Push(id) + 1);
}
}

View File

@ -53,6 +53,7 @@ ACTOR Actor native //: Thinker
native int CountProximity(class<Actor> classname, float distance, int flags = 0, int ptr = AAPTR_DEFAULT);
native float GetSpriteAngle(int ptr = AAPTR_DEFAULT);
native float GetSpriteRotation(int ptr = AAPTR_DEFAULT);
native int GetMissileDamage(int mask, int add, int ptr = AAPTR_DEFAULT);
// Action functions
// Meh, MBF redundant functions. Only for DeHackEd support.