- scriptified the remaining functions in a_artifacts.cpp.

- added some helpers to set scripted member variables through the native property parser.

Unfortunately some classes, e.g. PowerMorph, MorphProjectile and the powerup contain some that cannot be handled through the 'property' definition on the script side so they need to be done from the native side.
This commit is contained in:
Christoph Oelckers 2017-01-17 20:30:17 +01:00
parent 14f2c39e58
commit 98f9219334
12 changed files with 128 additions and 140 deletions

View file

@ -60,46 +60,6 @@ DEFINE_FIELD(APowerupGiver, BlendColor)
DEFINE_FIELD(APowerupGiver, Mode)
DEFINE_FIELD(APowerupGiver, Strength)
//===========================================================================
//
// APowerupGiver :: Use
//
//===========================================================================
bool APowerupGiver::Use (bool pickup)
{
if (PowerupType == NULL) return true; // item is useless
if (Owner == nullptr) return true;
APowerup *power = static_cast<APowerup *> (Spawn (PowerupType));
if (EffectTics != 0)
{
power->EffectTics = EffectTics;
}
if (BlendColor != 0)
{
if (BlendColor != MakeSpecialColormap(65535)) power->BlendColor = BlendColor;
else power->BlendColor = 0;
}
if (Mode != NAME_None)
{
power->Mode = Mode;
}
if (Strength != 0)
{
power->Strength = Strength;
}
power->ItemFlags |= ItemFlags & (IF_ALWAYSPICKUP|IF_ADDITIVETIME|IF_NOTELEPORTFREEZE);
if (power->CallTryPickup (Owner))
{
return true;
}
power->GoAwayAndDie ();
return false;
}
//===========================================================================
//
// APowerupGiver :: Serialize
@ -142,49 +102,3 @@ void APowerup::Serialize(FSerializer &arc)
("colormap", Colormap, def->Colormap);
}
//===========================================================================
//
// APowerup :: OwnerDied
//
// Powerups don't last beyond death.
//
//===========================================================================
void APowerup::OwnerDied ()
{
Destroy ();
}
// Morph powerup ------------------------------------------------------
IMPLEMENT_CLASS(APowerMorph, false, true)
IMPLEMENT_POINTERS_START(APowerMorph)
IMPLEMENT_POINTER(PlayerClass)
IMPLEMENT_POINTER(MorphFlash)
IMPLEMENT_POINTER(UnMorphFlash)
IMPLEMENT_POINTERS_END
DEFINE_FIELD(APowerMorph, PlayerClass)
DEFINE_FIELD(APowerMorph, MorphFlash)
DEFINE_FIELD(APowerMorph, UnMorphFlash)
DEFINE_FIELD(APowerMorph, MorphStyle)
DEFINE_FIELD(APowerMorph, MorphedPlayer)
//===========================================================================
//
// APowerMorph :: Serialize
//
//===========================================================================
void APowerMorph::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
arc("playerclass", PlayerClass)
("morphstyle", MorphStyle)
("morphflash", MorphFlash)
("unmorphflash", UnMorphFlash)
("morphedplayer", MorphedPlayer);
}

View file

@ -12,7 +12,6 @@ class APowerup : public AInventory
DECLARE_CLASS (APowerup, AInventory)
public:
virtual void Serialize(FSerializer &arc) override;
virtual void OwnerDied () override;
int EffectTics;
PalEntry BlendColor;
@ -31,7 +30,6 @@ class APowerupGiver : public AInventory
DECLARE_CLASS (APowerupGiver, AInventory)
HAS_OBJECT_POINTERS
public:
virtual bool Use (bool pickup) override;
virtual void Serialize(FSerializer &arc) override;
@ -42,19 +40,5 @@ public:
double Strength; // Meaning depends on powerup - currently used only by Invisibility
};
class APowerMorph : public APowerup
{
DECLARE_CLASS( APowerMorph, APowerup )
HAS_OBJECT_POINTERS
public:
virtual void Serialize(FSerializer &arc) override;
// Variables
PClassPlayerPawn *PlayerClass;
PClassActor *MorphFlash, *UnMorphFlash;
int MorphStyle;
player_t *MorphedPlayer;
};
#endif //__A_ARTIFACTS_H__

View file

@ -368,18 +368,6 @@ void AInventory::CallDoEffect()
}
//===========================================================================
//
// AInventory :: OwnerDied
//
// Items receive this message when their owners die.
//
//===========================================================================
void AInventory::OwnerDied ()
{
}
//===========================================================================
//
// AInventory :: HandlePickup
@ -1348,7 +1336,7 @@ bool AInventory::TryPickup (AActor *&toucher)
}
// The item is placed in the inventory just long enough to be used.
toucher->AddInventory (this);
bool usegood = Use (true);
bool usegood = CallUse (true);
toucher->RemoveInventory (this);
if (usegood)

View file

@ -138,8 +138,6 @@ public:
// virtual on the script side only.
double GetSpeedFactor();
bool GetNoTeleportFreeze();
// Stuff for later when more features are exported.
virtual void OwnerDied();
bool GoAway();

View file

@ -706,6 +706,10 @@ xx(WBobSpeed)
xx(PlayerClass)
xx(Wi_NoAutostartMap)
xx(MorphStyle)
xx(MorphFlash)
xx(UnMorphFlash)
// Decorate compatibility functions
xx(BuiltinTypeCheck)
xx(BuiltinRandom)

View file

@ -357,15 +357,19 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags)
static int dieticks[MAXPLAYERS]; // [ZzZombo] not used? Except if for peeking in debugger...
int pnum = int(this->player-players);
dieticks[pnum] = gametic;
fprintf (debugfile, "died (%d) on tic %d (%s)\n", pnum, gametic,
this->player->cheats&CF_PREDICTING?"predicting":"real");
fprintf(debugfile, "died (%d) on tic %d (%s)\n", pnum, gametic,
this->player->cheats&CF_PREDICTING ? "predicting" : "real");
}
// [RH] Notify this actor's items.
for (AInventory *item = Inventory; item != NULL; )
{
AInventory *next = item->Inventory;
item->OwnerDied();
IFVIRTUALPTR(item, AInventory, OwnerDied)
{
VMValue params[1] = { item };
GlobalVMStack.Call(func, params, 1, nullptr, 0);
}
item = next;
}

View file

@ -913,13 +913,14 @@ static void ParseActorProperty(FScanner &sc, Baggage &bag)
if (prop != NULL)
{
if (bag.Info->IsDescendantOf(*prop->cls))
auto pcls = PClass::FindActor(prop->clsname);
if (bag.Info->IsDescendantOf(pcls))
{
ParsePropertyParams(sc, prop, (AActor *)bag.Info->Defaults, bag);
}
else
{
sc.ScriptMessage("'%s' requires an actor of type '%s'\n", propname.GetChars(), (*prop->cls)->TypeName.GetChars());
sc.ScriptMessage("'%s' requires an actor of type '%s'\n", propname.GetChars(), pcls->TypeName.GetChars());
FScriptPosition::ErrorCounter++;
}
}

View file

@ -230,7 +230,7 @@ struct FPropertyInfo
{
const char *name;
const char *params;
const PClass * const *cls;
const char *clsname;
PropHandler Handler;
int category;
};
@ -242,17 +242,24 @@ int MatchString (const char *in, const char **strings);
#define DEFINE_PROPERTY_BASE(name, paramlist, clas, cat) \
static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, PClassActor *info, Baggage &bag, FPropParam *params); \
static FPropertyInfo Prop_##name##_##paramlist##_##clas = \
{ #name, #paramlist, &RUNTIME_CLASS_CASTLESS(A##clas), (PropHandler)Handler_##name##_##paramlist##_##clas, cat }; \
{ #name, #paramlist, #clas, (PropHandler)Handler_##name##_##paramlist##_##clas, cat }; \
MSVC_PSEG FPropertyInfo *infoptr_##name##_##paramlist##_##clas GCC_PSEG = &Prop_##name##_##paramlist##_##clas; \
static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, PClassActor *info, Baggage &bag, FPropParam *params)
#define DEFINE_PREFIXED_PROPERTY_BASE(prefix, name, paramlist, clas, cat) \
static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, PClassActor *info, Baggage &bag, FPropParam *params); \
static FPropertyInfo Prop_##name##_##paramlist##_##clas = \
{ #prefix"."#name, #paramlist, &RUNTIME_CLASS_CASTLESS(A##clas), (PropHandler)Handler_##name##_##paramlist##_##clas, cat }; \
{ #prefix"."#name, #paramlist, #clas, (PropHandler)Handler_##name##_##paramlist##_##clas, cat }; \
MSVC_PSEG FPropertyInfo *infoptr_##name##_##paramlist##_##clas GCC_PSEG = &Prop_##name##_##paramlist##_##clas; \
static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, PClassActor *info, Baggage &bag, FPropParam *params)
#define DEFINE_PREFIXED_SCRIPTED_PROPERTY_BASE(prefix, name, paramlist, clas, cat) \
static void Handler_##name##_##paramlist##_##clas(AActor *defaults, PClassActor *info, Baggage &bag, FPropParam *params); \
static FPropertyInfo Prop_##name##_##paramlist##_##clas = \
{ #prefix"."#name, #paramlist, #clas, (PropHandler)Handler_##name##_##paramlist##_##clas, cat }; \
MSVC_PSEG FPropertyInfo *infoptr_##name##_##paramlist##_##clas GCC_PSEG = &Prop_##name##_##paramlist##_##clas; \
static void Handler_##name##_##paramlist##_##clas(AActor *defaults, PClassActor *info, Baggage &bag, FPropParam *params)
#define DEFINE_PROPERTY(name, paramlist, clas) DEFINE_PROPERTY_BASE(name, paramlist, clas, CAT_PROPERTY)
#define DEFINE_INFO_PROPERTY(name, paramlist, clas) DEFINE_PROPERTY_BASE(name, paramlist, clas, CAT_INFO)
@ -260,6 +267,9 @@ int MatchString (const char *in, const char **strings);
#define DEFINE_CLASS_PROPERTY(name, paramlist, clas) DEFINE_PREFIXED_PROPERTY_BASE(clas, name, paramlist, clas, CAT_PROPERTY)
#define DEFINE_CLASS_PROPERTY_PREFIX(prefix, name, paramlist, clas) DEFINE_PREFIXED_PROPERTY_BASE(prefix, name, paramlist, clas, CAT_PROPERTY)
#define DEFINE_SCRIPTED_PROPERTY(name, paramlist, clas) DEFINE_PREFIXED_SCRIPTED_PROPERTY_BASE(clas, name, paramlist, clas, CAT_PROPERTY)
#define DEFINE_SCRIPTED_PROPERTY_PREFIX(prefix, name, paramlist, clas) DEFINE_PREFIXED_SCRIPTED_PROPERTY_BASE(prefix, name, paramlist, clas, CAT_PROPERTY)
#define PROP_PARM_COUNT (params[0].i)
#define PROP_STRING_PARM(var, no) \

View file

@ -456,12 +456,38 @@ int MatchString (const char *in, const char **strings)
return -1;
}
//==========================================================================
//
// Get access to scripted fields.
// Fortunately there's only a handful that cannot be done with a
// scripted property definition, most notably the powerup and morph stuff.
//
//==========================================================================
static void *ScriptVar(DObject *obj, PClass *cls, FName field, PType *type)
{
auto sym = dyn_cast<PField>(cls->Symbols.FindSymbol(field, true));
if (sym && sym->Type == type)
{
return (((char*)obj) + sym->Offset);
}
I_Error("Variable %s of type %s not found in %s\n", field.GetChars(), type->DescriptiveName(), cls->TypeName.GetChars());
return nullptr;
}
template<class T>
T &TypedScriptVar(DObject *obj, PClass *cls, FName field, PType *type)
{
return *(T*)ScriptVar(obj, cls, field, type);
}
//==========================================================================
//
// Info Property handlers
//
//==========================================================================
//==========================================================================
//
//==========================================================================
@ -3026,37 +3052,37 @@ DEFINE_CLASS_PROPERTY(unmorphflash, S, MorphProjectile)
//==========================================================================
// (non-fatal with non-existent types only in DECORATE)
//==========================================================================
DEFINE_CLASS_PROPERTY(playerclass, S, PowerMorph)
DEFINE_SCRIPTED_PROPERTY(playerclass, S, PowerMorph)
{
PROP_STRING_PARM(str, 0);
defaults->PlayerClass = FindClassTentativePlayerPawn(str, bag.fromDecorate);
TypedScriptVar<PClassActor*>(defaults, bag.Info, NAME_PlayerClass, NewClassPointer(RUNTIME_CLASS(APlayerPawn))) = FindClassTentativePlayerPawn(str, bag.fromDecorate);
}
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY(morphstyle, M, PowerMorph)
DEFINE_SCRIPTED_PROPERTY(morphstyle, M, PowerMorph)
{
PROP_INT_PARM(i, 0);
defaults->MorphStyle = i;
TypedScriptVar<int>(defaults, bag.Info, NAME_MorphStyle, TypeSInt32) = i;
}
//==========================================================================
// (non-fatal with non-existent types only in DECORATE)
//==========================================================================
DEFINE_CLASS_PROPERTY(morphflash, S, PowerMorph)
DEFINE_SCRIPTED_PROPERTY(morphflash, S, PowerMorph)
{
PROP_STRING_PARM(str, 0);
defaults->MorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
TypedScriptVar<PClassActor*>(defaults, bag.Info, NAME_MorphFlash, NewClassPointer(RUNTIME_CLASS(AActor))) = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
}
//==========================================================================
// (non-fatal with non-existent types only in DECORATE)
//==========================================================================
DEFINE_CLASS_PROPERTY(unmorphflash, S, PowerMorph)
DEFINE_SCRIPTED_PROPERTY(unmorphflash, S, PowerMorph)
{
PROP_STRING_PARM(str, 0);
defaults->UnMorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
TypedScriptVar<PClassActor*>(defaults, bag.Info, NAME_UnMorphFlash, NewClassPointer(RUNTIME_CLASS(AActor))) = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
}

View file

@ -2022,13 +2022,14 @@ void ZCCCompiler::ProcessDefaultProperty(PClassActor *cls, ZCC_PropertyStmt *pro
if (property != nullptr && property->category != CAT_INFO)
{
if (cls->IsDescendantOf(*property->cls))
auto pcls = PClass::FindActor(property->clsname);
if (cls->IsDescendantOf(pcls))
{
DispatchProperty(property, prop, (AActor *)bag.Info->Defaults, bag);
}
else
{
Error(prop, "'%s' requires an actor of type '%s'\n", propname.GetChars(), (*property->cls)->TypeName.GetChars());
Error(prop, "'%s' requires an actor of type '%s'\n", propname.GetChars(), pcls->TypeName.GetChars());
}
}
else

View file

@ -64,6 +64,7 @@ class Inventory : Actor native
virtual bool GetNoTeleportFreeze() { return false; }
virtual void ModifyDamage(int damage, Name damageType, out int newdamage, bool passive) {}
virtual void AlterWeaponSprite(VisStyle vis, in out int changed) {}
virtual void OwnerDied() {}
native bool GoAway();
native void GoAwayAndDie();

View file

@ -14,6 +14,50 @@ class PowerupGiver : Inventory native
+INVENTORY.FANCYPICKUPSOUND
Inventory.PickupSound "misc/p_pkup";
}
//===========================================================================
//
// APowerupGiver :: Use
//
//===========================================================================
override bool Use (bool pickup)
{
if (PowerupType == NULL) return true; // item is useless
if (Owner == null) return true;
let power = Powerup(Spawn (PowerupType));
if (EffectTics != 0)
{
power.EffectTics = EffectTics;
}
if (BlendColor != 0)
{
if (BlendColor != Powerup.SPECIALCOLORMAP_MASK | 65535) power.BlendColor = BlendColor;
else power.BlendColor = 0;
}
if (Mode != 'None')
{
power.Mode = Mode;
}
if (Strength != 0)
{
power.Strength = Strength;
}
power.bAlwaysPickup |= bAlwaysPickup;
power.bAdditiveTime |= bAdditiveTime;
power.bNoTeleportFreeze |= bNoTeleportFreeze;
if (power.CallTryPickup (Owner))
{
return true;
}
power.GoAwayAndDie ();
return false;
}
}
class Powerup : Inventory native
@ -248,6 +292,19 @@ class Powerup : Inventory native
return (EffectTics <= BLINKTHRESHOLD && (EffectTics & 8) && !bNoScreenBlink);
}
//===========================================================================
//
// APowerup :: OwnerDied
//
// Powerups don't last beyond death.
//
//===========================================================================
override void OwnerDied ()
{
Destroy ();
}
}
@ -1890,12 +1947,12 @@ class PowerInfiniteAmmo : Powerup
//
//===========================================================================
class PowerMorph : Powerup native
class PowerMorph : Powerup
{
native Class<PlayerPawn> PlayerClass;
native Class<Actor> MorphFlash, UnMorphFlash;
native int MorphStyle;
native PlayerInfo MorphedPlayer;
Class<PlayerPawn> PlayerClass;
Class<Actor> MorphFlash, UnMorphFlash;
int MorphStyle;
PlayerInfo MorphedPlayer;
Default
{