mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2024-11-10 14:51:46 +00:00
- split Damage into two variables: DamageVal for the old constant and DamageFunc for the DECORATE function.
The way this was done was a major headache inducer, requiring reconstruction of the function each time the value was changed and in general made actor damage a major hassle. There was a DECORATE wrapper to mimic the original behavior but this looked quite broken because it completely ignored the different semantics of both damage calculation types. It also made it impossible to determine if damage was a function or a value. This accessor has been reverted to what it should be, only returning the constant, which now is -1 for a damage function. I am sorry if this may break the odd mod out but a quick look over some DECORATE-heavy stuff showed that this was never combined in any of them so that accessing 'damage' in DECORATE code depended on an actual damage function. To get proper damage, a future commit will add a DECORATE function which calls AActor::GetMissileDamage.
This commit is contained in:
parent
3db7d9ad84
commit
f1ba19073f
16 changed files with 81 additions and 207 deletions
23
src/actor.h
23
src/actor.h
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
115
src/p_mobj.cpp
115
src/p_mobj.cpp
|
@ -139,7 +139,7 @@ IMPLEMENT_POINTY_CLASS (AActor)
|
|||
DECLARE_POINTER (LastHeard)
|
||||
DECLARE_POINTER (master)
|
||||
DECLARE_POINTER (Poisoner)
|
||||
DECLARE_POINTER (Damage)
|
||||
DECLARE_POINTER (DamageFunc)
|
||||
DECLARE_POINTER (alternative)
|
||||
END_POINTERS
|
||||
|
||||
|
@ -149,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
|
||||
|
@ -263,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
|
||||
|
@ -2975,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;
|
||||
|
@ -2988,22 +2932,11 @@ int AActor::GetMissileDamage (int mask, int add)
|
|||
results[0].IntAt(&amount);
|
||||
results[1].IntAt(&calculated);
|
||||
|
||||
if (stack.Call(Damage, ¶m, 1, results, 2) < 1)
|
||||
if (stack.Call(DamageFunc, ¶m, 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 ()
|
||||
|
@ -3695,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;
|
||||
}
|
||||
|
|
|
@ -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"))
|
||||
{
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
|
|
@ -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&);
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue