diff --git a/.gitignore b/.gitignore index cfa4882e6b..596fe51824 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,9 @@ /src/xlat/xlat_parser.c /src/xlat/xlat_parser.h /src/xlat/xlat_parser.out +/src/zscript/zcc-parse.c +/src/zscript/zcc-parse.h +/src/zscript/zcc-parse.out /tools/*/debug /tools/*/release /tools/*/*.exe diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6de8feabc0..56b75a7ec6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -685,6 +685,12 @@ add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c ${CMAKE_CUR WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} DEPENDS lemon ${CMAKE_CURRENT_SOURCE_DIR}/xlat/xlat_parser.y ) +add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.c ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.h + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/zscript/zcc-parse.lemon . + COMMAND lemon zcc-parse.lemon + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS lemon ${CMAKE_CURRENT_SOURCE_DIR}/zscript/zcc-parse.lemon ) + add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h COMMAND re2c --no-generation-date -s -o ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h ${CMAKE_CURRENT_SOURCE_DIR}/sc_man_scanner.re DEPENDS re2c ${CMAKE_CURRENT_SOURCE_DIR}/sc_man_scanner.re ) @@ -751,6 +757,7 @@ file( GLOB HEADER_FILES textures/*.h thingdef/*.h xlat/*.h + zscript/*.h *.h ) @@ -837,6 +844,9 @@ set( NOT_COMPILED_SOURCE_FILES xlat/xlat_parser.y xlat_parser.c xlat_parser.h + zscript/zcc-parse.lemon + zcc-parse.c + zcc-parse.h # We could have the ASM macro add these files, but it wouldn't add all # platforms. @@ -1136,7 +1146,6 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE thingdef/thingdef_data.cpp thingdef/thingdef_exp.cpp thingdef/thingdef_expression.cpp - thingdef/thingdef_function.cpp thingdef/thingdef_parse.cpp thingdef/thingdef_properties.cpp thingdef/thingdef_states.cpp @@ -1171,6 +1180,14 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE r_data/renderstyle.cpp r_data/r_interpolate.cpp r_data/r_translate.cpp + zscript/ast.cpp + zscript/vmbuilder.cpp + zscript/vmdisasm.cpp + zscript/vmexec.cpp + zscript/vmframe.cpp + zscript/zcc_compile.cpp + zscript/zcc_expr.cpp + zscript/zcc_parser.cpp zzautozend.cpp ) @@ -1197,6 +1214,7 @@ include_directories( . thingdef timidity xlat + zscript ../gdtoa ../dumb/include ${CMAKE_BINARY_DIR}/gdtoa @@ -1318,4 +1336,5 @@ source_group("Shared Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_sh source_group("Versioning" FILES version.h win32/zdoom.rc) source_group("Win32 Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/win32/.+") source_group("Xlat" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/xlat/.+" FILES ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.h) +source_group("ZScript" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/zscript/.+") source_group("Source Files" FILES ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h sc_man_scanner.re) diff --git a/src/__autostart.cpp b/src/__autostart.cpp index 6ed85ae157..1b111e1210 100644 --- a/src/__autostart.cpp +++ b/src/__autostart.cpp @@ -46,24 +46,26 @@ #if defined(_MSC_VER) -#pragma comment(linker, "/merge:.areg=.data /merge:.creg=.data /merge:.greg=.data /merge:.mreg=.data /merge:.yreg=.data") +// The various reg sections are used to group pointers spread across multiple +// source files into cohesive arrays in the final executable. We don't +// actually care about these sections themselves and merge them all into +// a single section during the final link. (.rdata is the standard section +// for initialized read-only data.) -#pragma data_seg(".areg$a") -void *ARegHead = 0; +#pragma comment(linker, "/merge:.areg=.rdata /merge:.creg=.rdata /merge:.greg=.rdata") +#pragma comment(linker, "/merge:.yreg=.rdata") -#pragma data_seg(".creg$a") -void *CRegHead = 0; +#pragma section(".areg$a",read) +__declspec(allocate(".areg$a")) void *const ARegHead = 0; -#pragma data_seg(".greg$a") -void *GRegHead = 0; +#pragma section(".creg$a",read) +__declspec(allocate(".creg$a")) void *const CRegHead = 0; -#pragma data_seg(".mreg$a") -void *MRegHead = 0; +#pragma section(".greg$a",read) +__declspec(allocate(".greg$a")) void *const GRegHead = 0; -#pragma data_seg(".yreg$a") -void *YRegHead = 0; - -#pragma data_seg() +#pragma section(".yreg$a",read) +__declspec(allocate(".yreg$a")) void *const YRegHead = 0; // We want visual styles support under XP #if defined _M_IX86 @@ -88,11 +90,15 @@ void *YRegHead = 0; #include "doomtype.h" -void *ARegHead __attribute__((section(SECTION_AREG))) = 0; -void *CRegHead __attribute__((section(SECTION_CREG))) = 0; -void *GRegHead __attribute__((section(SECTION_GREG))) = 0; -void *MRegHead __attribute__((section(SECTION_MREG))) = 0; -void *YRegHead __attribute__((section(SECTION_YREG))) = 0; +// I don't know of an easy way to merge sections together with the GNU linker, +// so GCC users will see all of these sections appear in the final executable. +// (There are linker scripts, but that apparently involves extracting the +// default script from ld and then modifying it.) + +void *const ARegHead __attribute__((section(SECTION_AREG))) = 0; +void *const CRegHead __attribute__((section(SECTION_CREG))) = 0; +void *const GRegHead __attribute__((section(SECTION_GREG))) = 0; +void *const YRegHead __attribute__((section(SECTION_YREG))) = 0; #else diff --git a/src/actor.h b/src/actor.h index ed38d0020c..f97d093c0a 100644 --- a/src/actor.h +++ b/src/actor.h @@ -42,6 +42,8 @@ #include "tflags.h" struct subsector_t; +class PClassAmmo; + // // NOTES: AActor // @@ -278,7 +280,7 @@ enum ActorFlag4 enum ActorFlag5 { MF5_DONTDRAIN = 0x00000001, // cannot be drained health from. - /* = 0x00000002, reserved for use by scripting branch */ + MF5_INSTATECALL = 0x00000002, // This actor is being run through CallStateChain MF5_NODROPOFF = 0x00000004, // cannot drop off under any circumstances. MF5_NOFORWARDFALL = 0x00000008, // Does not make any actor fall forward by being damaged by this MF5_COUNTSECRET = 0x00000010, // From Doom 64: actor acts like a secret @@ -560,67 +562,54 @@ inline AActor *GetDefaultByType (const PClass *type) template inline T *GetDefault () { - return (T *)(RUNTIME_CLASS(T)->Defaults); + return (T *)(RUNTIME_CLASS_CASTLESS(T)->Defaults); } struct line_t; struct secplane_t; struct FStrifeDialogueNode; -enum -{ - AMETA_BASE = 0x12000, - - AMETA_Obituary, // string (player was killed by this actor) - AMETA_HitObituary, // string (player was killed by this actor in melee) - AMETA_DeathHeight, // fixed (height on normal death) - AMETA_BurnHeight, // fixed (height on burning death) - AMETA_StrifeName, // string (for named Strife objects) - AMETA_BloodColor, // colorized blood - AMETA_GibHealth, // negative health below which this monster dies an extreme death - AMETA_WoundHealth, // health needed to enter wound state - AMETA_FastSpeed, // Speed in fast mode - AMETA_RDFactor, // Radius damage factor - AMETA_CameraHeight, // Height of camera when used as such - AMETA_HowlSound, // Sound being played when electrocuted or poisoned - AMETA_BloodType, // Blood replacement type - AMETA_BloodType2, // Bloodsplatter replacement type - AMETA_BloodType3, // AxeBlood replacement type -}; - struct fixedvec3 { fixed_t x, y, z; + + operator FVector3() + { + return FVector3(FIXED2FLOAT(x), FIXED2FLOAT(y), FIXED2FLOAT(z)); + } + + operator TVector3() + { + return TVector3(FIXED2DBL(x), FIXED2DBL(y), FIXED2DBL(z)); + } }; struct fixedvec2 { fixed_t x, y; -}; -struct FDropItem -{ - FName Name; - int probability; - int amount; - FDropItem * Next; -}; - -class FDropItemPtrArray : public TArray -{ -public: - ~FDropItemPtrArray() + operator FVector2() { - Clear(); + return FVector2(FIXED2FLOAT(x), FIXED2FLOAT(y)); } - void Clear(); + operator TVector2() + { + return TVector2(FIXED2DBL(x), FIXED2DBL(y)); + } }; -extern FDropItemPtrArray DropItemList; +class DDropItem : public DObject +{ + DECLARE_CLASS(DDropItem, DObject) + HAS_OBJECT_POINTERS +public: + DDropItem *Next; + FName Name; + int Probability; + int Amount; +}; -void FreeDropItemChain(FDropItem *chain); -int StoreDropItemChain(FDropItem *chain); fixed_t P_AproxDistance (fixed_t dx, fixed_t dy); // since we cannot include p_local here... angle_t R_PointToAngle2 (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2); // same reason here with r_defs.h @@ -628,7 +617,7 @@ angle_t R_PointToAngle2 (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2); // sam // Map Object definition. class AActor : public DThinker { - DECLARE_CLASS (AActor, DThinker) + DECLARE_CLASS_WITH_META (AActor, DThinker, PClassActor) HAS_OBJECT_POINTERS public: AActor () throw(); @@ -639,14 +628,14 @@ public: void Serialize (FArchive &arc); - static AActor *StaticSpawn (const PClass *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement, bool SpawningMapThing = false); + static AActor *StaticSpawn (PClassActor *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement, bool SpawningMapThing = false); inline AActor *GetDefault () const { - return (AActor *)(RUNTIME_TYPE(this)->Defaults); + return (AActor *)(this->GetClass()->Defaults); } - FDropItem *GetDropItems(); + DDropItem *GetDropItems() const; // Return true if the monster should use a missile attack, false for melee bool SuggestMissileAttack (fixed_t dist); @@ -727,7 +716,7 @@ public: // Take the amount value of an item from the inventory list. // If nothing is left, the item may be destroyed. // Returns true if the initial item count is positive. - virtual bool TakeInventory (const PClass *itemclass, int amount, bool fromdecorate = false, bool notakeinfinite = false); + virtual bool TakeInventory (PClassActor *itemclass, int amount, bool fromdecorate = false, bool notakeinfinite = false); // Uses an item and removes it from the inventory. virtual bool UseInventory (AInventory *item); @@ -742,21 +731,21 @@ public: bool CheckLocalView (int playernum) const; // Finds the first item of a particular type. - AInventory *FindInventory (const PClass *type, bool subclass = false); + AInventory *FindInventory (PClassActor *type, bool subclass=false); AInventory *FindInventory (FName type); template T *FindInventory () { - return static_cast (FindInventory (RUNTIME_CLASS(T))); + return static_cast (FindInventory (RUNTIME_TEMPLATE_CLASS(T))); } // Adds one item of a particular type. Returns NULL if it could not be added. - AInventory *GiveInventoryType (const PClass *type); + AInventory *GiveInventoryType (PClassActor *type); // Returns the first item held with IF_INVBAR set. AInventory *FirstInv (); // Tries to give the actor some ammo. - bool GiveAmmo (const PClass *type, int amount); + bool GiveAmmo (PClassAmmo *type, int amount); // Destroys all the inventory the actor is holding. void DestroyAllInventory (); @@ -810,8 +799,9 @@ public: void Crash(); // Return starting health adjusted by skill level - int SpawnHealth(); - int GibHealth(); + int SpawnHealth() const; + int GetGibHealth() const; + fixed_t GetCameraHeight() const; inline bool isMissile(bool precise=true) { @@ -826,7 +816,7 @@ public: PalEntry GetBloodColor() const { - return (PalEntry)GetClass()->Meta.GetMetaInt(AMETA_BloodColor); + return GetClass()->BloodColor; } // These also set CF_INTERPVIEW for players. @@ -834,22 +824,25 @@ public: void SetAngle(angle_t ang, bool interpolate); void SetRoll(angle_t roll, bool interpolate); - const PClass *GetBloodType(int type = 0) const + PClassActor *GetBloodType(int type = 0) const { - const PClass *bloodcls; + PClassActor *bloodcls; if (type == 0) { - bloodcls = PClass::FindClass((ENamedName)GetClass()->Meta.GetMetaInt(AMETA_BloodType, NAME_Blood)); + bloodcls = PClass::FindActor(GetClass()->BloodType); } else if (type == 1) { - bloodcls = PClass::FindClass((ENamedName)GetClass()->Meta.GetMetaInt(AMETA_BloodType2, NAME_BloodSplatter)); + bloodcls = PClass::FindActor(GetClass()->BloodType2); } else if (type == 2) { - bloodcls = PClass::FindClass((ENamedName)GetClass()->Meta.GetMetaInt(AMETA_BloodType3, NAME_AxeBlood)); + bloodcls = PClass::FindActor(GetClass()->BloodType3); + } + else + { + return NULL; } - else return NULL; if (bloodcls != NULL) { @@ -1020,7 +1013,7 @@ public: fixed_t velx, vely, velz; // velocity SDWORD tics; // state tic counter FState *state; - SDWORD Damage; // For missiles and monster railgun + VMFunction *Damage; // For missiles and monster railgun int projectileKickback; ActorFlags flags; ActorFlags2 flags2; // Heretic flags @@ -1144,8 +1137,8 @@ public: FNameNoInit PainType; FNameNoInit DeathType; - const PClass *TeleFogSourceType; - const PClass *TeleFogDestType; + PClassActor *TeleFogSourceType; + PClassActor *TeleFogDestType; int RipperLevel; int RipLevelMin; int RipLevelMax; @@ -1200,18 +1193,18 @@ public: FState *FindState (FName label) const { - return GetClass()->ActorInfo->FindState(1, &label); + return GetClass()->FindState(1, &label); } FState *FindState (FName label, FName sublabel, bool exact = false) const { FName names[] = { label, sublabel }; - return GetClass()->ActorInfo->FindState(2, names, exact); + return GetClass()->FindState(2, names, exact); } FState *FindState(int numnames, FName *names, bool exact = false) const { - return GetClass()->ActorInfo->FindState(numnames, names, exact); + return GetClass()->FindState(numnames, names, exact); } bool HasSpecialDeathStates () const; @@ -1356,7 +1349,7 @@ public: do { actor = FActorIterator::Next (); - } while (actor && !actor->IsKindOf (RUNTIME_CLASS(T))); + } while (actor && !actor->IsKindOf (RUNTIME_TEMPLATE_CLASS(T))); return static_cast(actor); } }; @@ -1383,12 +1376,11 @@ public: bool P_IsTIDUsed(int tid); int P_FindUniqueTID(int start_tid, int limit); -inline AActor *Spawn (const PClass *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement) +inline AActor *Spawn (PClassActor *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement) { return AActor::StaticSpawn (type, x, y, z, allowreplacement); } - -inline AActor *Spawn (const PClass *type, const fixedvec3 &pos, replace_t allowreplacement) +inline AActor *Spawn (PClassActor *type, const fixedvec3 &pos, replace_t allowreplacement) { return AActor::StaticSpawn (type, pos.x, pos.y, pos.z, allowreplacement); } @@ -1410,7 +1402,7 @@ inline AActor *Spawn (FName classname, const fixedvec3 &pos, replace_t allowrepl template inline T *Spawn (fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement) { - return static_cast(AActor::StaticSpawn (RUNTIME_CLASS(T), x, y, z, allowreplacement)); + return static_cast(AActor::StaticSpawn (RUNTIME_TEMPLATE_CLASS(T), x, y, z, allowreplacement)); } template diff --git a/src/actorptrselect.h b/src/actorptrselect.h index bfc88fb3c0..d5dfd5ffc2 100644 --- a/src/actorptrselect.h +++ b/src/actorptrselect.h @@ -66,13 +66,8 @@ enum AAPTR AActor *COPY_AAPTR(AActor *origin, int selector); -// Use COPY_AAPTR_NOT_NULL to return from a function if the pointer is NULL -#define COPY_AAPTR_NOT_NULL(source, destination, selector) { destination = COPY_AAPTR(source, selector); if (!destination) return; } - - - enum PTROP - { +{ PTROP_UNSAFETARGET = 1, PTROP_UNSAFEMASTER = 2, PTROP_NOSAFEGUARDS = PTROP_UNSAFETARGET|PTROP_UNSAFEMASTER diff --git a/src/autosegs.h b/src/autosegs.h index fb3c0d3ee5..61872610c0 100644 --- a/src/autosegs.h +++ b/src/autosegs.h @@ -36,7 +36,8 @@ #define AUTOSEGS_H #define REGMARKER(x) (x) -typedef void *REGINFO; +typedef void * const REGINFO; +typedef void * NCREGINFO; // List of Action functons extern REGINFO ARegHead; @@ -50,10 +51,6 @@ extern REGINFO CRegTail; extern REGINFO GRegHead; extern REGINFO GRegTail; -// List of variables -extern REGINFO MRegHead; -extern REGINFO MRegTail; - // List of MAPINFO map options extern REGINFO YRegHead; extern REGINFO YRegTail; @@ -76,7 +73,7 @@ class FAutoSegIterator } Probe = Head; } - REGINFO operator*() const + NCREGINFO operator*() const { return *Probe; } diff --git a/src/b_bot.cpp b/src/b_bot.cpp index 05cac045bb..aa52629299 100644 --- a/src/b_bot.cpp +++ b/src/b_bot.cpp @@ -270,7 +270,7 @@ void InitBotStuff() { w->MoveCombatDist = botinits[i].movecombatdist; w->WeaponFlags |= botinits[i].weaponflags; - w->ProjectileType = PClass::FindClass(botinits[i].projectile); + w->ProjectileType = PClass::FindActor(botinits[i].projectile); } } } diff --git a/src/b_think.cpp b/src/b_think.cpp index de74c04dbe..a2b169f56d 100644 --- a/src/b_think.cpp +++ b/src/b_think.cpp @@ -328,7 +328,7 @@ void DBot::WhatToGet (AActor *item) // FIXME AWeapon *heldWeapon; - heldWeapon = static_cast (player->mo->FindInventory (item->GetClass())); + heldWeapon = dyn_cast(player->mo->FindInventory(item->GetClass())); if (heldWeapon != NULL) { if (!weapgiveammo) @@ -343,7 +343,7 @@ void DBot::WhatToGet (AActor *item) else if (item->IsKindOf (RUNTIME_CLASS(AAmmo))) { AAmmo *ammo = static_cast (item); - const PClass *parent = ammo->GetParentAmmo (); + PClassActor *parent = ammo->GetParentAmmo (); AInventory *holdingammo = player->mo->FindInventory (parent); if (holdingammo != NULL && holdingammo->Amount >= holdingammo->MaxAmount) diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index 233c31d298..4f951540ad 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -30,8 +30,6 @@ ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **--------------------------------------------------------------------------- ** -** It might be a good idea to move these into files that they are more -** closely related to, but right now, I am too lazy to do that. */ #include @@ -929,8 +927,8 @@ static void PrintFilteredActorList(const ActorTypeChecker IsActorType, const cha if (FilterName != NULL) { - FilterClass = PClass::FindClass(FilterName); - if (FilterClass == NULL || FilterClass->ActorInfo == NULL) + FilterClass = PClass::FindActor(FilterName); + if (FilterClass == NULL) { Printf("%s is not an actor class.\n", FilterName); return; @@ -1094,6 +1092,34 @@ CCMD(currentpos) } } +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- +CCMD(vmengine) +{ + if (argv.argc() == 2) + { + if (stricmp(argv[1], "default") == 0) + { + VMSelectEngine(VMEngine_Default); + return; + } + else if (stricmp(argv[1], "checked") == 0) + { + VMSelectEngine(VMEngine_Checked); + return; + } + else if (stricmp(argv[1], "unchecked") == 0) + { + VMSelectEngine(VMEngine_Unchecked); + return; + } + } + Printf("Usage: vmengine \n"); +} + //----------------------------------------------------------------------------- // // Print secret info (submitted by Karl Murks) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 35abd13a89..5f784e6de0 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -62,8 +62,6 @@ #include "decallib.h" #include "v_palette.h" #include "a_sharedglobal.h" -#include "thingdef/thingdef.h" -#include "thingdef/thingdef_exp.h" #include "vectors.h" #include "dobject.h" #include "r_data/r_translate.h" @@ -72,6 +70,7 @@ #include "doomerrors.h" #include "p_effect.h" #include "farchive.h" +#include "vmbuilder.h" // [SO] Just the way Randy said to do it :) // [RH] Made this CVAR_SERVERINFO @@ -82,7 +81,7 @@ static void UnloadDehSupp (); // This is a list of all the action functions used by each of Doom's states. -static TArray Actions; +static TArray Actions; // These are the original heights of every Doom 2 thing. They are used if a patch // specifies that a thing should be hanging from the ceiling but doesn't specify @@ -110,7 +109,7 @@ struct StateMapper { FState *State; int StateSpan; - const PClass *Owner; + PClassActor *Owner; bool OwnerIsPickup; }; @@ -121,7 +120,7 @@ static TArray StateMap; static TArray SoundMap; // Names of different actor types, in original Doom 2 order -static TArray InfoNames; +static TArray InfoNames; // bit flags for PatchThing (a .bex extension): struct BitName @@ -142,8 +141,8 @@ struct StyleName static TArray StyleNames; -static TArray AmmoNames; -static TArray WeaponNames; +static TArray AmmoNames; +static TArray WeaponNames; // DeHackEd trickery to support MBF-style parameters // List of states that are hacked to use a codepointer @@ -156,7 +155,7 @@ static TArray MBFParamStates; // Data on how to correctly modify the codepointers struct CodePointerAlias { - char name[20]; + FName name; char alias[20]; BYTE params; }; @@ -164,7 +163,7 @@ static TArray MBFCodePointers; struct AmmoPerAttack { - actionf_p func; + VMNativeFunction **func; int ammocount; }; @@ -174,7 +173,7 @@ DECLARE_ACTION(A_FireShotgun) DECLARE_ACTION(A_FireShotgun2) DECLARE_ACTION(A_FireCGun) DECLARE_ACTION(A_FireMissile) -DECLARE_ACTION_PARAMS(A_Saw) +DECLARE_ACTION(A_Saw) DECLARE_ACTION(A_FirePlasma) DECLARE_ACTION(A_FireBFG) DECLARE_ACTION(A_FireOldBFG) @@ -182,17 +181,17 @@ DECLARE_ACTION(A_FireRailgun) // Default ammo use of the various weapon attacks static AmmoPerAttack AmmoPerAttacks[] = { - { AF_A_Punch, 0}, - { AF_A_FirePistol, 1}, - { AF_A_FireShotgun, 1}, - { AF_A_FireShotgun2, 2}, - { AF_A_FireCGun, 1}, - { AF_A_FireMissile, 1}, - { AFP_A_Saw, 0}, - { AF_A_FirePlasma, 1}, - { AF_A_FireBFG, -1}, // uses deh.BFGCells - { AF_A_FireOldBFG, 1}, - { AF_A_FireRailgun, 1}, + { &A_Punch_VMPtr, 0}, + { &A_FirePistol_VMPtr, 1}, + { &A_FireShotgun_VMPtr, 1}, + { &A_FireShotgun2_VMPtr, 2}, + { &A_FireCGun_VMPtr, 1}, + { &A_FireMissile_VMPtr, 1}, + { &A_Saw_VMPtr, 0}, + { &A_FirePlasma_VMPtr, 1}, + { &A_FireBFG_VMPtr, -1}, // uses deh.BFGCells + { &A_FireOldBFG_VMPtr, 1}, + { &A_FireRailgun_VMPtr, 1}, { NULL, 0} }; @@ -232,7 +231,7 @@ IMPLEMENT_POINTY_CLASS (ADehackedPickup) DECLARE_POINTER (RealPickup) END_POINTERS -TArray TouchedActors; +TArray TouchedActors; char *UnchangedSpriteNames; int NumUnchangedSprites; @@ -354,11 +353,14 @@ static bool ReadChars (char **stuff, int size); static char *igets (void); static int GetLine (void); -static void PushTouchedActor(PClass *cls) +static void PushTouchedActor(PClassActor *cls) { for(unsigned i = 0; i < TouchedActors.Size(); i++) { - if (TouchedActors[i] == cls) return; + if (TouchedActors[i] == cls) + { + return; + } } TouchedActors.Push(cls); } @@ -426,7 +428,7 @@ static FState *FindState (int statenum) { if (StateMap[i].OwnerIsPickup) { - PushTouchedActor(const_cast(StateMap[i].Owner)); + PushTouchedActor(StateMap[i].Owner); } return StateMap[i].State + statenum - stateacc; } @@ -632,28 +634,149 @@ static int GetLine (void) } } -// This enum must be in sync with the Aliases array in DEHSUPP. -enum MBFCodePointers +// misc1 = vrange (arg +3), misc2 = hrange (arg+4) +static int CreateMushroomFunc(VMFunctionBuilder &buildit, int value1, int value2) +{ // A_Mushroom + buildit.Emit(OP_PARAM, 0, REGT_NIL, 0); // spawntype + buildit.Emit(OP_PARAM, 0, REGT_NIL, 0); // numspawns + buildit.Emit(OP_PARAMI, 1); // flag + // vrange + if (value1 == 0) + { + buildit.Emit(OP_PARAM, 0, REGT_NIL, 0); + } + else + { + buildit.Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, buildit.GetConstantFloat(FIXED2DBL(value1))); + } + // hrange + if (value2 == 0) + { + buildit.Emit(OP_PARAM, 0, REGT_NIL, 0); + } + else + { + buildit.Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, buildit.GetConstantFloat(FIXED2DBL(value2))); + } + return 5; +} + +// misc1 = type (arg +0), misc2 = Z-pos (arg +2) +static int CreateSpawnFunc(VMFunctionBuilder &buildit, int value1, int value2) +{ // A_SpawnItem + if (InfoNames[value1-1] == NULL) + { + I_Error("No class found for dehackednum %d!\n", value1+1); + return 0; + } + int typereg = buildit.GetConstantAddress(InfoNames[value1-1], ATAG_OBJECT); + int heightreg = buildit.GetConstantFloat(value2); + + buildit.Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, typereg); // itemtype + buildit.Emit(OP_PARAM, 0, REGT_NIL, 0); // distance + buildit.Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, heightreg); // height + // The rest of the parameters to A_SpawnItem can just keep their defaults + return 3; +} + +// misc1 = angle (in degrees) (arg +0 but factor in current actor angle too) +static int CreateTurnFunc(VMFunctionBuilder &buildit, int value1, int value2) +{ // A_Turn + buildit.Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, buildit.GetConstantFloat(value1)); // angle + return 1; +} + +// misc1 = angle (in degrees) (arg +0) +static int CreateFaceFunc(VMFunctionBuilder &buildit, int value1, int value2) +{ // A_FaceTarget + buildit.Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, buildit.GetConstantFloat(value1)); // angle + return 1; +} + +// misc1 = damage, misc 2 = sound +static int CreateScratchFunc(VMFunctionBuilder &buildit, int value1, int value2) +{ // A_CustomMeleeAttack + buildit.EmitParamInt(value1); // damage + if (value2) + { + buildit.EmitParamInt(SoundMap[value2-1]); // hit sound + return 2; + } + return 1; +} + +// misc1 = sound, misc2 = attenuation none (true) or normal (false) +static int CreatePlaySoundFunc(VMFunctionBuilder &buildit, int value1, int value2) +{ // A_PlaySound + int float1 = buildit.GetConstantFloat(1); + int attenreg = buildit.GetConstantFloat(value2 ? ATTN_NONE : ATTN_NORM); + + buildit.EmitParamInt(SoundMap[value1-1]); // soundid + buildit.Emit(OP_PARAMI, CHAN_BODY); // channel + buildit.Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, float1); // volume + buildit.Emit(OP_PARAMI, false); // looping + buildit.Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, attenreg); // attenuation + return 5; +} + +// misc1 = state, misc2 = probability +static int CreateRandomJumpFunc(VMFunctionBuilder &buildit, int value1, int value2) +{ // A_Jump + int statereg = buildit.GetConstantAddress(FindState(value1), ATAG_STATE); + + buildit.EmitParamInt(value2); // maxchance + buildit.Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, statereg); // jumpto + return 2; +} + +// misc1 = Boom linedef type, misc2 = sector tag +static int CreateLineEffectFunc(VMFunctionBuilder &buildit, int value1, int value2) +{ // A_LineEffect + // This is the second MBF codepointer that couldn't be translated easily. + // Calling P_TranslateLineDef() here was a simple matter, as was adding an + // extra parameter to A_CallSpecial so as to replicate the LINEDONE stuff, + // but unfortunately DEHACKED lumps are processed before the map translation + // arrays are initialized so this didn't work. + buildit.EmitParamInt(value1); // special + buildit.EmitParamInt(value2); // tag + return 2; +} + +// No misc, but it's basically A_Explode with an added effect +static int CreateNailBombFunc(VMFunctionBuilder &buildit, int value1, int value2) +{ // A_Explode + // This one does not actually have MBF-style parameters. But since + // we're aliasing it to an extension of A_Explode... + buildit.Emit(OP_PARAM, 0, REGT_NIL, 0); // damage + buildit.Emit(OP_PARAM, 0, REGT_NIL, 0); // distance + buildit.Emit(OP_PARAM, 0, REGT_NIL, 0); // flags + buildit.Emit(OP_PARAM, 0, REGT_NIL, 0); // alert + buildit.Emit(OP_PARAM, 0, REGT_NIL, 0); // fulldamagedistance + buildit.Emit(OP_PARAMI, 30); // nails + buildit.Emit(OP_PARAMI, 10); // naildamage + return 7; +} + +// This array must be in sync with the Aliases array in DEHSUPP. +static int (*MBFCodePointerFactories[])(VMFunctionBuilder&, int, int) = { // Die and Detonate are not in this list because these codepointers have // no dehacked arguments and therefore do not need special handling. // NailBomb has no argument but is implemented as new parameters for A_Explode. - MBF_Mushroom, // misc1 = vrange (arg +3), misc2 = hrange (arg+4) - MBF_Spawn, // misc1 = type (arg +0), misc2 = Z-pos (arg +2) - MBF_Turn, // misc1 = angle (in degrees) (arg +0 but factor in current actor angle too) - MBF_Face, // misc1 = angle (in degrees) (arg +0) - MBF_Scratch, // misc1 = damage, misc 2 = sound - MBF_PlaySound, // misc1 = sound, misc2 = attenuation none (true) or normal (false) - MBF_RandomJump, // misc1 = state, misc2 = probability - MBF_LineEffect, // misc1 = Boom linedef type, misc2 = sector tag - SMMU_NailBomb, // No misc, but it's basically A_Explode with an added effect + CreateMushroomFunc, + CreateSpawnFunc, + CreateTurnFunc, + CreateFaceFunc, + CreateScratchFunc, + CreatePlaySoundFunc, + CreateRandomJumpFunc, + CreateLineEffectFunc, + CreateNailBombFunc }; -int PrepareStateParameters(FState * state, int numparams, const PClass *cls);// Should probably be in a .h file. +// Creates new functions for the given state so as to convert MBF-args (misc1 and misc2) into real args. -// Hacks the parameter list for the given state so as to convert MBF-args (misc1 and misc2) into real args. - -void SetDehParams(FState * state, int codepointer) +void SetDehParams(FState *state, int codepointer) { int value1 = state->GetMisc1(); int value2 = state->GetMisc2(); @@ -662,101 +785,36 @@ void SetDehParams(FState * state, int codepointer) // Fakey fake script position thingamajig. Because NULL cannot be used instead. // Even if the lump was parsed by an FScanner, there would hardly be a way to // identify which line is troublesome. - FScriptPosition * pos = new FScriptPosition(FString("DEHACKED"), 0); + FScriptPosition *pos = new FScriptPosition(FString("DEHACKED"), 0); // Let's identify the codepointer we're dealing with. - PSymbolActionFunction * sym; PSymbol * s; - s = RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(FName(MBFCodePointers[codepointer].name), true); - if (!s || s->SymbolType != SYM_ActionFunction) return; - sym = static_cast(s); + PFunction *sym; + sym = dyn_cast(RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(FName(MBFCodePointers[codepointer].name), true)); + if (sym == NULL) return; - - // Bleargh! This will all have to be redone once scripting works - - // Not sure exactly why the index for a state is greater by one point than the index for a symbol. - DPrintf("SetDehParams: Paramindex is %d, default is %d.\n", - state->ParameterIndex-1, sym->defaultparameterindex); - if (state->ParameterIndex-1 == sym->defaultparameterindex) + if (codepointer < 0 || (unsigned)codepointer >= countof(MBFCodePointerFactories)) { - int a = PrepareStateParameters(state, MBFCodePointers[codepointer].params+1, - FState::StaticFindStateOwner(state)) -1; - int b = sym->defaultparameterindex; - // StateParams.Copy(a, b, MBFParams[codepointer]); - // Meh, function doesn't work. For some reason it resets the paramindex to the default value. - // For instance, a dehacked Commander Keen calling A_Explode would result in a crash as - // ACTION_PARAM_INT(damage, 0) would properly evaluate at paramindex 1377, but then - // ACTION_PARAM_INT(distance, 1) would improperly evaluate at paramindex 148! Now I'm not sure - // whether it's a genuine problem or working as intended and merely not appropriate for the - // task at hand here. So rather than modify it, I use a simple for loop of Set()s and Get()s, - // with a small modification to Set() that I know will have no repercussion anywhere else. - for (int i = 0; iParameterIndex-1); - } - int ParamIndex = state->ParameterIndex - 1; - - switch (codepointer) - { - case MBF_Mushroom: - StateParams.Set(ParamIndex+2, new FxConstant(1, *pos)); // Flag - // NOTE: Do not convert to float here because it will lose precision. It must be double. - if (value1) StateParams.Set(ParamIndex+3, new FxConstant(value1/65536., *pos)); // vrange - if (value2) StateParams.Set(ParamIndex+4, new FxConstant(value2/65536., *pos)); // hrange - break; - case MBF_Spawn: - if (InfoNames[value1-1] == NULL) - { - I_Error("No class found for dehackednum %d!\n", value1+1); - return; - } - StateParams.Set(ParamIndex+0, new FxConstant(InfoNames[value1-1], *pos)); // type - StateParams.Set(ParamIndex+2, new FxConstant(value2, *pos)); // height - break; - case MBF_Turn: - // Intentional fall through. I tried something more complicated by creating an - // FxExpression that corresponded to "variable angle + angle" so as to use A_SetAngle - // as well, but it became an overcomplicated mess that didn't even work as I had to - // create a compile context as well and couldn't get it right. - case MBF_Face: - StateParams.Set(ParamIndex+0, new FxConstant(value1, *pos)); // angle - break; - case MBF_Scratch: // misc1 = damage, misc 2 = sound - StateParams.Set(ParamIndex+0, new FxConstant(value1, *pos)); // damage - if (value2) StateParams.Set(ParamIndex+1, new FxConstant(SoundMap[value2-1], *pos)); // hit sound - break; - case MBF_PlaySound: - StateParams.Set(ParamIndex+0, new FxConstant(SoundMap[value1-1], *pos)); // soundid - StateParams.Set(ParamIndex+1, new FxConstant(CHAN_BODY, *pos)); // channel - StateParams.Set(ParamIndex+2, new FxConstant(1.0, *pos)); // volume - StateParams.Set(ParamIndex+3, new FxConstant(false, *pos)); // looping - StateParams.Set(ParamIndex+4, new FxConstant((value2 ? ATTN_NONE : ATTN_NORM), *pos)); // attenuation - break; - case MBF_RandomJump: - StateParams.Set(ParamIndex+0, new FxConstant(2, *pos)); // count - StateParams.Set(ParamIndex+1, new FxConstant(value2, *pos)); // maxchance - StateParams.Set(ParamIndex+2, new FxConstant(FindState(value1), *pos)); // jumpto - break; - case MBF_LineEffect: - // This is the second MBF codepointer that couldn't be translated easily. - // Calling P_TranslateLineDef() here was a simple matter, as was adding an - // extra parameter to A_CallSpecial so as to replicate the LINEDONE stuff, - // but unfortunately DEHACKED lumps are processed before the map translation - // arrays are initialized so this didn't work. - StateParams.Set(ParamIndex+0, new FxConstant(value1, *pos)); // special - StateParams.Set(ParamIndex+1, new FxConstant(value2, *pos)); // tag - break; - case SMMU_NailBomb: - // That one does not actually have MBF-style parameters. But since - // we're aliasing it to an extension of A_Explode... - StateParams.Set(ParamIndex+5, new FxConstant(30, *pos)); // nails - StateParams.Set(ParamIndex+6, new FxConstant(10, *pos)); // naildamage - break; - default: // This simply should not happen. Printf("Unmanaged dehacked codepointer alias num %i\n", codepointer); } + else + { + VMFunctionBuilder buildit; + // Allocate registers used to pass parameters in. + // self, stateowner, state (all are pointers) + buildit.Registers[REGT_POINTER].Get(3); + // Emit code to pass the standard action function parameters. + buildit.Emit(OP_PARAM, 0, REGT_POINTER, 0); + buildit.Emit(OP_PARAM, 0, REGT_POINTER, 1); + buildit.Emit(OP_PARAM, 0, REGT_POINTER, 2); + // Emit code for action parameters. + int argcount = MBFCodePointerFactories[codepointer](buildit, value1, value2); + buildit.Emit(OP_TAIL_K, buildit.GetConstantAddress(sym->Variants[0].Implementation, ATAG_OBJECT), NAP + argcount, 0); + // Attach it to the state. + VMScriptFunction *sfunc = buildit.MakeFunction(); + sfunc->NumArgs = NAP; + state->SetAction(sfunc); + } } static int PatchThing (int thingy) @@ -785,7 +843,7 @@ static int PatchThing (int thingy) FStateDefinitions statedef; bool patchedStates = false; ActorFlags oldflags; - const PClass *type; + PClassActor *type; SWORD *ednum, dummyed; type = NULL; @@ -811,7 +869,7 @@ static int PatchThing (int thingy) else { info = GetDefaultByType (type); - ednum = &type->ActorInfo->DoomEdNum; + ednum = &type->DoomEdNum; } } } @@ -851,7 +909,7 @@ static int PatchThing (int thingy) } else if (linelen == 14 && stricmp (Line1, "Missile damage") == 0) { - info->Damage = val; + info->Damage = CreateDamageFunction(val); } else if (linelen == 5) { @@ -1227,7 +1285,7 @@ static int PatchThing (int thingy) if (info->flags & MF_SPECIAL) { - PushTouchedActor(const_cast(type)); + PushTouchedActor(const_cast(type)); } // If MF_COUNTKILL is set, make sure the other standard monster flags are @@ -1250,7 +1308,7 @@ static int PatchThing (int thingy) info->flags4 |= MF4_CANUSEWALLS; if (patchedStates) { - statedef.InstallStates(type->ActorInfo, info); + statedef.InstallStates(type, info); } } @@ -1462,7 +1520,7 @@ static int PatchSprite (int sprNum) static int PatchAmmo (int ammoNum) { - const PClass *ammoType = NULL; + PClassAmmo *ammoType = NULL; AAmmo *defaultAmmo = NULL; int result; int oldclip; @@ -1509,9 +1567,9 @@ static int PatchAmmo (int ammoNum) // Fix per-ammo/max-ammo amounts for descendants of the base ammo class if (oldclip != *per) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - PClass *type = PClass::m_Types[i]; + PClassActor *type = PClassActor::AllActorClasses[i]; if (type == ammoType) continue; @@ -1543,7 +1601,7 @@ static int PatchAmmo (int ammoNum) static int PatchWeapon (int weapNum) { int result; - const PClass *type = NULL; + PClassActor *type = NULL; BYTE dummy[sizeof(AWeapon)]; AWeapon *info = (AWeapon *)&dummy; bool patchedStates = false; @@ -1647,28 +1705,26 @@ static int PatchWeapon (int weapNum) if (patchedStates) { - statedef.InstallStates(type->ActorInfo, info); + statedef.InstallStates(type, info); } return result; } -static void SetPointer(FState *state, PSymbol *sym, int frame = 0) +static void SetPointer(FState *state, PFunction *sym, int frame = 0) { - if (sym==NULL || sym->SymbolType != SYM_ActionFunction) + if (sym == NULL) { state->SetAction(NULL); return; } else { - FString symname = sym->SymbolName.GetChars(); - state->SetAction(static_cast(sym)); + state->SetAction(sym->Variants[0].Implementation); - // Note: CompareNoCase() calls stricmp() and therefore returns 0 when they're the same. for (unsigned int i = 0; i < MBFCodePointers.Size(); i++) { - if (!symname.CompareNoCase(MBFCodePointers[i].name)) + if (sym->SymbolName == MBFCodePointers[i].name) { MBFParamState newstate; newstate.state = state; @@ -1722,7 +1778,9 @@ static int PatchPointer (int ptrNum) { int index = atoi(Line2); if ((unsigned)(index) >= Actions.Size()) + { SetPointer(state, NULL); + } else { SetPointer(state, Actions[index], CodePConv[ptrNum]); @@ -1820,16 +1878,16 @@ static int PatchMisc (int dummy) "Minotaur", NULL }; - static const PClass * const types[] = + static const PClass * const *types[] = { - RUNTIME_CLASS(APowerInvulnerable), - RUNTIME_CLASS(APowerStrength), - RUNTIME_CLASS(APowerInvisibility), - RUNTIME_CLASS(APowerIronFeet), - RUNTIME_CLASS(APowerLightAmp), - RUNTIME_CLASS(APowerWeaponLevel2), - RUNTIME_CLASS(APowerSpeed), - RUNTIME_CLASS(APowerMinotaur) + &RUNTIME_CLASS_CASTLESS(APowerInvulnerable), + &RUNTIME_CLASS_CASTLESS(APowerStrength), + &RUNTIME_CLASS_CASTLESS(APowerInvisibility), + &RUNTIME_CLASS_CASTLESS(APowerIronFeet), + &RUNTIME_CLASS_CASTLESS(APowerLightAmp), + &RUNTIME_CLASS_CASTLESS(APowerWeaponLevel2), + &RUNTIME_CLASS_CASTLESS(APowerSpeed), + &RUNTIME_CLASS_CASTLESS(APowerMinotaur) }; int i; @@ -1855,7 +1913,7 @@ static int PatchMisc (int dummy) } else if (a > 0) { - static_cast(GetDefaultByType (types[i]))->BlendColor = PalEntry( + static_cast(GetDefaultByType (*types[i]))->BlendColor = PalEntry( BYTE(clamp(a,0.f,1.f)*255.f), clamp(r,0,255), clamp(g,0,255), @@ -1863,7 +1921,7 @@ static int PatchMisc (int dummy) } else { - static_cast(GetDefaultByType (types[i]))->BlendColor = 0; + static_cast(GetDefaultByType (*types[i]))->BlendColor = 0; } } } @@ -1924,18 +1982,14 @@ static int PatchMisc (int dummy) player->health = deh.StartHealth; // Hm... I'm not sure that this is the right way to change this info... - int index = PClass::FindClass(NAME_DoomPlayer)->Meta.GetMetaInt (ACMETA_DropItems) - 1; - if (index >= 0 && index < (signed)DropItemList.Size()) + DDropItem *di = PClass::FindActor(NAME_DoomPlayer)->DropItems; + while (di != NULL) { - FDropItem * di = DropItemList[index]; - while (di != NULL) + if (di->Name == NAME_Clip) { - if (di->Name == NAME_Clip) - { - di->amount = deh.StartBullets; - } - di = di->Next; + di->Amount = deh.StartBullets; } + di = di->Next; } } @@ -2043,21 +2097,21 @@ static int PatchCodePtrs (int dummy) if (!symname.CompareNoCase(MBFCodePointers[i].alias)) { symname = MBFCodePointers[i].name; - Printf("%s --> %s\n", MBFCodePointers[i].alias, MBFCodePointers[i].name); + Printf("%s --> %s\n", MBFCodePointers[i].alias, MBFCodePointers[i].name.GetChars()); } } // This skips the action table and goes directly to the internal symbol table // DEH compatible functions are easy to recognize. - PSymbol *sym = RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(symname, true); - if (sym == NULL || sym->SymbolType != SYM_ActionFunction) + PFunction *sym = dyn_cast(RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(symname, true)); + if (sym == NULL) { Printf("Frame %d: Unknown code pointer '%s'\n", frame, Line2); } else { - FString &args = static_cast(sym)->Arguments; - if (args.Len()!=0 && (args[0]<'a' || args[0]>'z')) + TArray &args = sym->Variants[0].ArgFlags; + if (args.Size() != 0 && !(args[0] & VARF_Optional)) { Printf("Frame %d: Incompatible code pointer '%s'\n", frame, Line2); sym = NULL; @@ -2541,25 +2595,6 @@ static inline bool CompareLabel (const char *want, const BYTE *have) return *(DWORD *)want == *(DWORD *)have; } -static inline short GetWord (const BYTE *in) -{ - return (in[0] << 8) | (in[1]); -} - -static short *GetWordSpace (void *in, size_t size) -{ - short *ptr; - size_t i; - - ptr = (short *)in; - - for (i = 0; i < size; i++) - { - ptr[i] = GetWord ((BYTE *)in + i*2); - } - return ptr; -} - static int DehUseCount; static void UnloadDehSupp () @@ -2680,15 +2715,15 @@ static bool LoadDehSupp () // or AActor so this will find all of them. FString name = "A_"; name << sc.String; - PSymbol *sym = RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(name, true); - if (sym == NULL || sym->SymbolType != SYM_ActionFunction) + PFunction *sym = dyn_cast(RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(name, true)); + if (sym == NULL) { sc.ScriptError("Unknown code pointer '%s'", sc.String); } else { - FString &args = static_cast(sym)->Arguments; - if (args.Len()!=0 && (args[0]<'a' || args[0]>'z')) + TArray &args = sym->Variants[0].ArgFlags; + if (args.Size() != 0 && !(args[0] & VARF_Optional)) { sc.ScriptError("Incompatible code pointer '%s'", sc.String); } @@ -2757,19 +2792,20 @@ static bool LoadDehSupp () StateMapper s; sc.MustGetString(); - const PClass *type = PClass::FindClass (sc.String); + PClass *type = PClass::FindClass (sc.String); if (type == NULL) { sc.ScriptError ("Can't find type %s", sc.String); } - else if (type->ActorInfo == NULL) + else if (!type->IsKindOf(RUNTIME_CLASS(PClassActor))) { - sc.ScriptError ("%s has no ActorInfo", sc.String); + sc.ScriptError ("%s is not an actor", sc.String); } sc.MustGetStringName(","); sc.MustGetString(); - s.State = type->ActorInfo->FindState(sc.String); + PClassActor *actortype = static_cast(type); + s.State = actortype->FindState(sc.String); if (s.State == NULL) { sc.ScriptError("Invalid state '%s' in '%s'", sc.String, type->TypeName.GetChars()); @@ -2777,14 +2813,14 @@ static bool LoadDehSupp () sc.MustGetStringName(","); sc.MustGetNumber(); - if (s.State == NULL || s.State + sc.Number > type->ActorInfo->OwnedStates + type->ActorInfo->NumOwnedStates) + if (s.State == NULL || s.State + sc.Number > actortype->OwnedStates + actortype->NumOwnedStates) { sc.ScriptError("Invalid state range in '%s'", type->TypeName.GetChars()); } AActor *def = GetDefaultByType(type); s.StateSpan = sc.Number; - s.Owner = type; + s.Owner = actortype; s.OwnerIsPickup = def != NULL && (def->flags & MF_SPECIAL) != 0; if (addit) StateMap.Push(s); @@ -2809,7 +2845,7 @@ static bool LoadDehSupp () while (!sc.CheckString("}")) { sc.MustGetString(); - const PClass *cls = PClass::FindClass(sc.String); + PClassActor *cls = PClass::FindActor(sc.String); if (cls == NULL) { sc.ScriptError("Unknown actor type '%s'", sc.String); @@ -2876,8 +2912,8 @@ static bool LoadDehSupp () } else { - const PClass *cls = PClass::FindClass(sc.String); - if (cls == NULL || cls->ParentClass != RUNTIME_CLASS(AAmmo)) + PClassAmmo *cls = dyn_cast(PClass::FindClass(sc.String)); + if (cls == NULL) { sc.ScriptError("Unknown ammo type '%s'", sc.String); } @@ -2894,12 +2930,12 @@ static bool LoadDehSupp () while (!sc.CheckString("}")) { sc.MustGetString(); - const PClass *cls = PClass::FindClass(sc.String); + PClass *cls = PClass::FindClass(sc.String); if (cls == NULL || !cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { sc.ScriptError("Unknown weapon type '%s'", sc.String); } - WeaponNames.Push(cls); + WeaponNames.Push(static_cast(cls)); if (sc.CheckString("}")) break; sc.MustGetStringName(","); } @@ -2915,8 +2951,7 @@ static bool LoadDehSupp () temp.alias[19]=0; sc.MustGetStringName(","); sc.MustGetString(); - strncpy(temp.name, sc.String, 19); - temp.name[19]=0; + temp.name = sc.String; sc.MustGetStringName(","); sc.MustGetNumber(); temp.params = sc.Number; @@ -2949,7 +2984,7 @@ void FinishDehPatch () for (touchedIndex = 0; touchedIndex < TouchedActors.Size(); ++touchedIndex) { - PClass *type = TouchedActors[touchedIndex]; + PClassActor *type = TouchedActors[touchedIndex]; AActor *defaults1 = GetDefaultByType (type); if (!(defaults1->flags & MF_SPECIAL)) { // We only need to do this for pickups @@ -2959,8 +2994,8 @@ void FinishDehPatch () // Create a new class that will serve as the actual pickup char typeNameBuilder[32]; mysnprintf (typeNameBuilder, countof(typeNameBuilder), "DehackedPickup%d", touchedIndex); - PClass *subclass = RUNTIME_CLASS(ADehackedPickup)->CreateDerivedClass - (typeNameBuilder, sizeof(ADehackedPickup)); + PClassActor *subclass = static_cast(RUNTIME_CLASS(ADehackedPickup)-> + CreateDerivedClass(typeNameBuilder, sizeof(ADehackedPickup))); AActor *defaults2 = GetDefaultByType (subclass); memcpy ((void *)defaults2, (void *)defaults1, sizeof(AActor)); @@ -2971,21 +3006,21 @@ void FinishDehPatch () if (!type->IsDescendantOf(RUNTIME_CLASS(AInventory))) { // If this is a hacked non-inventory item we must also copy AInventory's special states - statedef.AddStateDefines(RUNTIME_CLASS(AInventory)->ActorInfo->StateList); + statedef.AddStateDefines(RUNTIME_CLASS(AInventory)->StateList); } - statedef.InstallStates(subclass->ActorInfo, defaults2); + statedef.InstallStates(subclass, defaults2); // Use the DECORATE replacement feature to redirect all spawns // of the original class to the new one. - FActorInfo *old_replacement = type->ActorInfo->Replacement; + PClassActor *old_replacement = type->Replacement; - type->ActorInfo->Replacement = subclass->ActorInfo; - subclass->ActorInfo->Replacee = type->ActorInfo; + type->Replacement = subclass; + subclass->Replacee = type; // If this actor was already replaced by another actor, copy that // replacement over to this item. if (old_replacement != NULL) { - subclass->ActorInfo->Replacement = old_replacement; + subclass->Replacement = old_replacement; } DPrintf ("%s replaces %s\n", subclass->TypeName.GetChars(), type->TypeName.GetChars()); @@ -3018,7 +3053,7 @@ void FinishDehPatch () TMap StateVisited; - FState *state = WeaponNames[i]->ActorInfo->FindState(NAME_Fire); + FState *state = WeaponNames[i]->FindState(NAME_Fire); while (state != NULL) { bool *check = StateVisited.CheckKey(state); @@ -3029,7 +3064,7 @@ void FinishDehPatch () StateVisited[state] = true; for(unsigned j = 0; AmmoPerAttacks[j].func != NULL; j++) { - if (state->ActionFunc == AmmoPerAttacks[j].func) + if (state->ActionFunc == *AmmoPerAttacks[j].func) { found = true; int use = AmmoPerAttacks[j].ammocount; @@ -3051,7 +3086,7 @@ void ModifyDropAmount(AInventory *inv, int dropamount); bool ADehackedPickup::TryPickup (AActor *&toucher) { - const PClass *type = DetermineType (); + PClassActor *type = DetermineType (); if (type == NULL) { return false; @@ -3125,7 +3160,7 @@ void ADehackedPickup::Destroy () Super::Destroy (); } -const PClass *ADehackedPickup::DetermineType () +PClassActor *ADehackedPickup::DetermineType () { // Look at the actor's current sprite to determine what kind of // item to pretend to me. @@ -3138,7 +3173,7 @@ const PClass *ADehackedPickup::DetermineType () int lex = memcmp (DehSpriteMappings[mid].Sprite, sprites[sprite].name, 4); if (lex == 0) { - return PClass::FindClass (DehSpriteMappings[mid].ClassName); + return PClass::FindActor(DehSpriteMappings[mid].ClassName); } else if (lex < 0) { diff --git a/src/d_dehacked.h b/src/d_dehacked.h index 67473f0718..71716bdcfc 100644 --- a/src/d_dehacked.h +++ b/src/d_dehacked.h @@ -50,7 +50,7 @@ public: void DoPickupSpecial (AActor *toucher); void Serialize(FArchive &arc); private: - const PClass *DetermineType (); + PClassActor *DetermineType (); AInventory *RealPickup; public: bool droppedbymonster; diff --git a/src/d_main.cpp b/src/d_main.cpp index 3b3cce1f4f..fddb2c86a7 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -107,6 +107,8 @@ #include "resourcefiles/resourcefile.h" #include "r_renderer.h" #include "p_local.h" +#include "autosegs.h" +#include "fragglescript/t_fs.h" EXTERN_CVAR(Bool, hud_althud) void DrawHUD(); @@ -1930,6 +1932,22 @@ static void SetMapxxFlag() if (lump_name >= 0 || lump_wad >= 0 || lump_map >= 0) gameinfo.flags |= GI_MAPxx; } +//========================================================================== +// +// FinalGC +// +// If this doesn't free everything, the debug CRT will let us know. +// +//========================================================================== + +static void FinalGC() +{ + Args = NULL; + GC::FinalGC = true; + GC::FullGC(); + GC::DelSoftRootHead(); // the soft root head will not be collected by a GC so we have to do it explicitly +} + //========================================================================== // // Initialize @@ -1958,6 +1976,8 @@ static void D_DoomInit() // Check response files before coalescing file parameters. M_FindResponseFile (); + atterm(FinalGC); + // Combine different file parameters with their pre-switch bits. Args->CollectFiles("-deh", ".deh"); Args->CollectFiles("-bex", ".bex"); @@ -2178,21 +2198,6 @@ static void CheckCmdLine() } } -//========================================================================== -// -// FinalGC -// -// If this doesn't free everything, the debug CRT will let us know. -// -//========================================================================== - -static void FinalGC() -{ - Args = NULL; - GC::FullGC(); - GC::DelSoftRootHead(); // the soft root head will not be collected by a GC so we have to do it explicitly -} - //========================================================================== // // D_DoomMain @@ -2241,7 +2246,6 @@ void D_DoomMain (void) // [RH] Make sure zdoom.pk3 is always loaded, // as it contains magic stuff we need. - wad = BaseFileSearch (BASEWAD, NULL, true); if (wad == NULL) { @@ -2255,13 +2259,13 @@ void D_DoomMain (void) // Now that we have the IWADINFO, initialize the autoload ini sections. GameConfig->DoAutoloadSetup(iwad_man); - PClass::StaticInit (); - atterm(FinalGC); - // reinit from here do { + PClass::StaticInit(); + PType::StaticInit(); + if (restart) { C_InitConsole(SCREENWIDTH, SCREENHEIGHT, false); @@ -2409,12 +2413,11 @@ void D_DoomMain (void) Printf ("ParseTeamInfo: Load team definitions.\n"); TeamLibrary.ParseTeamInfo (); - FActorInfo::StaticInit (); + PClassActor::StaticInit (); // [GRB] Initialize player class list SetupPlayerClasses (); - // [RH] Load custom key and weapon settings from WADs D_LoadWadSettings (); @@ -2460,9 +2463,8 @@ void D_DoomMain (void) FinishDehPatch(); InitActorNumsFromMapinfo(); + PClassActor::StaticSetActorNums (); InitSpawnablesFromMapinfo(); - FActorInfo::StaticSetActorNums (); - //Added by MC: bglobal.getspawned.Clear(); argcount = Args->CheckParmList("-bots", &args); @@ -2639,9 +2641,28 @@ void D_DoomMain (void) C_ClearAliases(); // CCMDs won't be reinitialized so these need to be deleted here DestroyCVarsFlagged(CVAR_MOD); // Delete any cvar left by mods - GC::FullGC(); // perform one final garbage collection before deleting the class data - PClass::ClearRuntimeData(); // clear all runtime generated class data + GC::FullGC(); // clean up before taking down the object list. + + // Delete the VM functions here. The garbage collector will not do this automatically because they are referenced from the global action function definitions. + FAutoSegIterator probe(ARegHead, ARegTail); + while (*++probe != NULL) + { + AFuncDesc *afunc = (AFuncDesc *)*probe; + *(afunc->VMPointer) = NULL; + } + + ReleaseGlobalSymbols(); + PClass::StaticShutdown(); + + GC::FullGC(); // perform one final garbage collection after shutdown + + for (DObject *obj = GC::Root; obj; obj = obj->ObjNext) + { + obj->ClearClass(); // Delete the Class pointer because the data it points to has been deleted. This will automatically be reset if needed. + } + restart++; + PClass::bShutdown = false; } } while (1); diff --git a/src/d_net.cpp b/src/d_net.cpp index 640ba4580f..17b2eee21b 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -2071,7 +2071,7 @@ BYTE *FDynamicBuffer::GetData (int *len) } -static int KillAll(const PClass *cls) +static int KillAll(PClassActor *cls) { AActor *actor; int killcount = 0; @@ -2291,7 +2291,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) case DEM_SUMMONFRIEND2: case DEM_SUMMONFOE2: { - const PClass *typeinfo; + PClassActor *typeinfo; int angle = 0; SWORD tid = 0; BYTE special = 0; @@ -2306,8 +2306,8 @@ void Net_DoCommand (int type, BYTE **stream, int player) for(i = 0; i < 5; i++) args[i] = ReadLong(stream); } - typeinfo = PClass::FindClass (s); - if (typeinfo != NULL && typeinfo->ActorInfo != NULL) + typeinfo = PClass::FindActor(s); + if (typeinfo != NULL) { AActor *source = players[player].mo; if (source != NULL) @@ -2534,7 +2534,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) case DEM_MORPHEX: { s = ReadString (stream); - const char *msg = cht_Morph (players + player, PClass::FindClass (s), false); + const char *msg = cht_Morph (players + player, dyn_cast(PClass::FindClass (s)), false); if (player == consoleplayer) { Printf ("%s\n", *msg != '\0' ? msg : "Morph failed."); @@ -2566,12 +2566,12 @@ void Net_DoCommand (int type, BYTE **stream, int player) { char *classname = ReadString (stream); int killcount = 0; - const PClass *cls = PClass::FindClass(classname); + PClassActor *cls = PClass::FindActor(classname); - if (cls != NULL && cls->ActorInfo != NULL) + if (cls != NULL) { killcount = KillAll(cls); - const PClass *cls_rep = cls->GetReplacement(); + PClassActor *cls_rep = cls->GetReplacement(); if (cls != cls_rep) { killcount += KillAll(cls_rep); @@ -2589,8 +2589,8 @@ void Net_DoCommand (int type, BYTE **stream, int player) { char *classname = ReadString(stream); int removecount = 0; - const PClass *cls = PClass::FindClass(classname); - if (cls != NULL && cls->ActorInfo != NULL) + PClassActor *cls = PClass::FindActor(classname); + if (cls != NULL && cls->IsKindOf(RUNTIME_CLASS(PClassActor))) { removecount = RemoveClass(cls); const PClass *cls_rep = cls->GetReplacement(); @@ -2633,7 +2633,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) } for(i = 0; i < count; ++i) { - const PClass *wpn = Net_ReadWeapon(stream); + PClassWeapon *wpn = Net_ReadWeapon(stream); players[pnum].weapons.AddSlot(slot, wpn, pnum == consoleplayer); } } @@ -2642,7 +2642,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) case DEM_ADDSLOT: { int slot = ReadByte(stream); - const PClass *wpn = Net_ReadWeapon(stream); + PClassWeapon *wpn = Net_ReadWeapon(stream); players[player].weapons.AddSlot(slot, wpn, player == consoleplayer); } break; @@ -2650,7 +2650,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) case DEM_ADDSLOTDEFAULT: { int slot = ReadByte(stream); - const PClass *wpn = Net_ReadWeapon(stream); + PClassWeapon *wpn = Net_ReadWeapon(stream); players[player].weapons.AddSlotDefault(slot, wpn, player == consoleplayer); } break; diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index 3010de16de..8b4b06209b 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -154,9 +154,9 @@ int D_PlayerClassToInt (const char *classname) { for (unsigned int i = 0; i < PlayerClasses.Size (); ++i) { - const PClass *type = PlayerClasses[i].Type; + PClassPlayerPawn *type = PlayerClasses[i].Type; - if (stricmp (type->Meta.GetMetaString (APMETA_DisplayName), classname) == 0) + if (type->DisplayName.IsNotEmpty() && stricmp(type->DisplayName, classname) == 0) { return i; } @@ -178,7 +178,7 @@ void D_GetPlayerColor (int player, float *h, float *s, float *v, FPlayerColorSet if (players[player].mo != NULL) { - colorset = P_GetPlayerColorSet(players[player].mo->GetClass()->TypeName, info->GetColorSet()); + colorset = players[player].mo->GetClass()->GetColorSet(info->GetColorSet()); } if (colorset != NULL) { @@ -723,7 +723,7 @@ void D_WriteUserInfoStrings (int pnum, BYTE **stream, bool compact) case NAME_PlayerClass: *stream += sprintf(*((char **)stream), "\\%s", info->GetPlayerClassNum() == -1 ? "Random" : - D_EscapeUserInfo(info->GetPlayerClassType()->Meta.GetMetaString(APMETA_DisplayName)).GetChars()); + D_EscapeUserInfo(info->GetPlayerClassType()->DisplayName.GetChars()).GetChars()); break; case NAME_Skin: @@ -925,7 +925,7 @@ void WriteUserInfo(FArchive &arc, userinfo_t &info) case NAME_PlayerClass: i = info.GetPlayerClassNum(); - arc.WriteString(i == -1 ? "Random" : PlayerClasses[i].Type->Meta.GetMetaString(APMETA_DisplayName)); + arc.WriteString(i == -1 ? "Random" : PlayerClasses[i].Type->DisplayName); break; default: @@ -1014,7 +1014,7 @@ CCMD (playerinfo) Printf("%20s: %s (%d)\n", "Skin", skins[ui->GetSkin()].name, ui->GetSkin()); Printf("%20s: %s (%d)\n", "Gender", GenderNames[ui->GetGender()], ui->GetGender()); Printf("%20s: %s (%d)\n", "PlayerClass", - ui->GetPlayerClassNum() == -1 ? "Random" : ui->GetPlayerClassType()->Meta.GetMetaString (APMETA_DisplayName), + ui->GetPlayerClassNum() == -1 ? "Random" : ui->GetPlayerClassType()->DisplayName.GetChars(), ui->GetPlayerClassNum()); // Print generic info diff --git a/src/d_player.h b/src/d_player.h index 5ada741dc0..168327f8a1 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -44,41 +44,61 @@ //Added by MC: #include "b_bot.h" -enum -{ - APMETA_BASE = 0x95000, +class player_t; - APMETA_DisplayName, // display name (used in menus etc.) - APMETA_SoundClass, // sound class - APMETA_Face, // doom status bar face (when used) - APMETA_ColorRange, // skin color range - APMETA_InvulMode, - APMETA_HealingRadius, - APMETA_Portrait, - APMETA_Hexenarmor0, - APMETA_Hexenarmor1, - APMETA_Hexenarmor2, - APMETA_Hexenarmor3, - APMETA_Hexenarmor4, - APMETA_Slot0, - APMETA_Slot1, - APMETA_Slot2, - APMETA_Slot3, - APMETA_Slot4, - APMETA_Slot5, - APMETA_Slot6, - APMETA_Slot7, - APMETA_Slot8, - APMETA_Slot9, +// Standard pre-defined skin colors +struct FPlayerColorSet +{ + struct ExtraRange + { + BYTE RangeStart, RangeEnd; // colors to remap + BYTE FirstColor, LastColor; // colors to map to + }; + + FName Name; // Name of this color + + int Lump; // Lump to read the translation from, otherwise use next 2 fields + BYTE FirstColor, LastColor; // Describes the range of colors to use for the translation + + BYTE RepresentativeColor; // A palette entry representative of this translation, + // for map arrows and status bar backgrounds and such + BYTE NumExtraRanges; + ExtraRange Extra[6]; }; -FPlayerColorSet *P_GetPlayerColorSet(FName classname, int setnum); -void P_EnumPlayerColorSets(FName classname, TArray *out); -const char *GetPrintableDisplayName(const PClass *cls); +typedef TMap FPlayerColorSetMap; +typedef TMap PainFlashList; + +class PClassPlayerPawn : public PClassActor +{ + DECLARE_CLASS(PClassPlayerPawn, PClassActor); +protected: + virtual void Derive(PClass *newclass); +public: + PClassPlayerPawn(); + void EnumColorSets(TArray *out); + FPlayerColorSet *GetColorSet(int setnum) { return ColorSets.CheckKey(setnum); } + void SetPainFlash(FName type, PalEntry color); + bool GetPainFlash(FName type, PalEntry *color) const; + + FString DisplayName; // Display name (used in menus, etc.) + FString SoundClass; // Sound class + FString Face; // Doom status bar face (when used) + FString Portrait; + FString Slot[10]; + FName InvulMode; + FName HealingRadiusType; + fixed_t HexenArmor[5]; + BYTE ColorRangeStart; // Skin color range + BYTE ColorRangeEnd; + FPlayerColorSetMap ColorSets; + PainFlashList PainFlashes; +}; +FString GetPrintableDisplayName(PClassPlayerPawn *cls); class APlayerPawn : public AActor { - DECLARE_CLASS (APlayerPawn, AActor) + DECLARE_CLASS_WITH_META(APlayerPawn, AActor, PClassPlayerPawn) HAS_OBJECT_POINTERS public: virtual void Serialize (FArchive &arc); @@ -96,9 +116,9 @@ public: virtual void TweakSpeeds (int &forwardmove, int &sidemove); virtual void MorphPlayerThink (); virtual void ActivateMorphWeapon (); - AWeapon *PickNewWeapon (const PClass *ammotype); - AWeapon *BestWeapon (const PClass *ammotype); - void CheckWeaponSwitch(const PClass *ammotype); + AWeapon *PickNewWeapon (PClassAmmo *ammotype); + AWeapon *BestWeapon (PClassAmmo *ammotype); + void CheckWeaponSwitch(PClassAmmo *ammotype); virtual void GiveDeathmatchInventory (); virtual void FilterCoopRespawnInventory (APlayerPawn *oldplayer); @@ -140,7 +160,8 @@ public: fixed_t AttackZOffset; // attack height, relative to player center fixed_t UseRange; // [NS] Distance at which player can +use fixed_t AirCapacity; // Multiplier for air supply underwater. - const PClass *FlechetteType; + PClassActor *FlechetteType; + // [CW] Fades for when you are being damaged. PalEntry DamageFade; @@ -251,7 +272,7 @@ public: bool CheckSkin (int skin); - const PClass *Type; + PClassPlayerPawn *Type; DWORD Flags; TArray Skins; }; @@ -319,7 +340,7 @@ struct userinfo_t : TMap { return *static_cast(*CheckKey(NAME_PlayerClass)); } - const PClass *GetPlayerClassType() const + PClassPlayerPawn *GetPlayerClassType() const { return PlayerClasses[GetPlayerClassNum()].Type; } @@ -376,7 +397,7 @@ public: userinfo_t userinfo; // [RH] who is this? - const PClass *cls; // class of associated PlayerPawn + PClassPlayerPawn *cls; // class of associated PlayerPawn float DesiredFOV; // desired field of vision float FOV; // current field of vision @@ -434,9 +455,9 @@ public: short fixedlightlevel; pspdef_t psprites[NUMPSPRITES]; // view sprites (gun, etc) int morphTics; // player is a chicken/pig if > 0 - const PClass *MorphedPlayerClass; // [MH] (for SBARINFO) class # for this player instance when morphed + PClassPlayerPawn *MorphedPlayerClass; // [MH] (for SBARINFO) class # for this player instance when morphed int MorphStyle; // which effects to apply for this player instance when morphed - const PClass *MorphExitFlash; // flash to apply when demorphing (cache of value given to P_MorphPlayer) + PClassActor *MorphExitFlash; // flash to apply when demorphing (cache of value given to P_MorphPlayer) TObjPtr PremorphWeapon; // ready weapon before morphing int chickenPeck; // chicken peck countdown int jumpTics; // delay the next jump for a moment diff --git a/src/decallib.cpp b/src/decallib.cpp index 784998977c..37a9dc6490 100644 --- a/src/decallib.cpp +++ b/src/decallib.cpp @@ -364,9 +364,9 @@ void FDecalLib::ReadAllDecals () ReadDecals (sc); } // Supporting code to allow specifying decals directly in the DECORATE lump - for (i = 0; i < PClass::m_RuntimeActors.Size(); i++) + for (i = 0; i < PClassActor::AllActorClasses.Size(); i++) { - AActor *def = (AActor*)GetDefaultByType (PClass::m_RuntimeActors[i]); + AActor *def = (AActor*)GetDefaultByType (PClassActor::AllActorClasses[i]); FName v = ENamedName(intptr_t(def->DecalGenerator)); if (v.IsValidName()) @@ -601,7 +601,7 @@ void FDecalLib::ParseDecalGroup (FScanner &sc) void FDecalLib::ParseGenerator (FScanner &sc) { - const PClass *type; + PClassActor *type; FDecalBase *decal; bool optional = false; @@ -610,8 +610,8 @@ void FDecalLib::ParseGenerator (FScanner &sc) optional = sc.Compare("optional"); if (optional) sc.MustGetString(); - type = PClass::FindClass (sc.String); - if (type == NULL || type->ActorInfo == NULL) + type = PClass::FindActor (sc.String); + if (type == NULL) { if (!optional) sc.ScriptError ("%s is not an actor.", sc.String); } diff --git a/src/decallib.h b/src/decallib.h index 4b45719229..8cf870c1d2 100644 --- a/src/decallib.h +++ b/src/decallib.h @@ -43,7 +43,7 @@ class FScanner; class FDecalTemplate; struct FDecalAnimator; -struct PClass; +class PClass; class DBaseDecal; struct side_t; diff --git a/src/dobject.cpp b/src/dobject.cpp index 9d674d2268..cd7b784a40 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -49,146 +49,18 @@ #include "dsectoreffect.h" #include "farchive.h" -PClass DObject::_StaticType; ClassReg DObject::RegistrationInfo = { - &DObject::_StaticType, // MyClass + NULL, // MyClass "DObject", // Name NULL, // ParentType - sizeof(DObject), // SizeOf NULL, // Pointers - &DObject::InPlaceConstructor // ConstructNative + &DObject::InPlaceConstructor, // ConstructNative + sizeof(DObject), // SizeOf + CLASSREG_PClass, // MetaClassNum }; _DECLARE_TI(DObject) -FMetaTable::~FMetaTable () -{ - FreeMeta (); -} - -FMetaTable::FMetaTable (const FMetaTable &other) -{ - Meta = NULL; - CopyMeta (&other); -} - -FMetaTable &FMetaTable::operator = (const FMetaTable &other) -{ - CopyMeta (&other); - return *this; -} - -void FMetaTable::FreeMeta () -{ - while (Meta != NULL) - { - FMetaData *meta = Meta; - - switch (meta->Type) - { - case META_String: - delete[] meta->Value.String; - break; - default: - break; - } - Meta = meta->Next; - delete meta; - } -} - -void FMetaTable::CopyMeta (const FMetaTable *other) -{ - const FMetaData *meta_src; - FMetaData **meta_dest; - - FreeMeta (); - - meta_src = other->Meta; - meta_dest = &Meta; - while (meta_src != NULL) - { - FMetaData *newmeta = new FMetaData (meta_src->Type, meta_src->ID); - switch (meta_src->Type) - { - case META_String: - newmeta->Value.String = copystring (meta_src->Value.String); - break; - default: - newmeta->Value = meta_src->Value; - break; - } - *meta_dest = newmeta; - meta_dest = &newmeta->Next; - meta_src = meta_src->Next; - } - *meta_dest = NULL; -} - -FMetaData *FMetaTable::FindMeta (EMetaType type, DWORD id) const -{ - FMetaData *meta = Meta; - - while (meta != NULL) - { - if (meta->ID == id && meta->Type == type) - { - return meta; - } - meta = meta->Next; - } - return NULL; -} - -FMetaData *FMetaTable::FindMetaDef (EMetaType type, DWORD id) -{ - FMetaData *meta = FindMeta (type, id); - if (meta == NULL) - { - meta = new FMetaData (type, id); - meta->Next = Meta; - meta->Value.String = NULL; - Meta = meta; - } - return meta; -} - -void FMetaTable::SetMetaInt (DWORD id, int parm) -{ - FMetaData *meta = FindMetaDef (META_Int, id); - meta->Value.Int = parm; -} - -int FMetaTable::GetMetaInt (DWORD id, int def) const -{ - FMetaData *meta = FindMeta (META_Int, id); - return meta != NULL ? meta->Value.Int : def; -} - -void FMetaTable::SetMetaFixed (DWORD id, fixed_t parm) -{ - FMetaData *meta = FindMetaDef (META_Fixed, id); - meta->Value.Fixed = parm; -} - -fixed_t FMetaTable::GetMetaFixed (DWORD id, fixed_t def) const -{ - FMetaData *meta = FindMeta (META_Fixed, id); - return meta != NULL ? meta->Value.Fixed : def; -} - -void FMetaTable::SetMetaString (DWORD id, const char *parm) -{ - FMetaData *meta = FindMetaDef (META_String, id); - ReplaceString (&meta->Value.String, parm); -} - -const char *FMetaTable::GetMetaString (DWORD id) const -{ - FMetaData *meta = FindMeta (META_String, id); - return meta != NULL ? meta->Value.String : NULL; -} - CCMD (dumpactors) { const char *const filters[32] = @@ -200,19 +72,26 @@ CCMD (dumpactors) "25:DoomStrifeChex", "26:HereticStrifeChex", "27:NotHexen", "28:HexenStrifeChex", "29:NotHeretic", "30:NotDoom", "31:All", }; - Printf("%i object class types total\nActor\tEd Num\tSpawnID\tFilter\tSource\n", PClass::m_Types.Size()); - for (unsigned int i = 0; i < PClass::m_Types.Size(); i++) + Printf("%i object class types total\nActor\tEd Num\tSpawnID\tFilter\tSource\n", PClass::AllClasses.Size()); + for (unsigned int i = 0; i < PClass::AllClasses.Size(); i++) { - PClass *cls = PClass::m_Types[i]; - if (cls != NULL && cls->ActorInfo != NULL) + PClass *cls = PClass::AllClasses[i]; + PClassActor *acls = dyn_cast(cls); + if (acls != NULL) + { Printf("%s\t%i\t%i\t%s\t%s\n", - cls->TypeName.GetChars(), cls->ActorInfo->DoomEdNum, - cls->ActorInfo->SpawnID, filters[cls->ActorInfo->GameFilter & 31], - cls->Meta.GetMetaString (ACMETA_Lump)); + acls->TypeName.GetChars(), acls->DoomEdNum, + acls->SpawnID, filters[acls->GameFilter & 31], + acls->SourceLumpName.GetChars()); + } else if (cls != NULL) + { Printf("%s\tn/a\tn/a\tn/a\tEngine (not an actor type)\n", cls->TypeName.GetChars()); + } else + { Printf("Type %i is not an object class\n", i); + } } } @@ -323,7 +202,6 @@ CCMD (dumpclasses) int shown, omitted; DumpInfo *tree = NULL; const PClass *root = NULL; - bool showall = true; if (argv.argc() > 1) { @@ -333,24 +211,14 @@ CCMD (dumpclasses) Printf ("Class '%s' not found\n", argv[1]); return; } - if (stricmp (argv[1], "Actor") == 0) - { - if (argv.argc() < 3 || stricmp (argv[2], "all") != 0) - { - showall = false; - } - } } shown = omitted = 0; DumpInfo::AddType (&tree, root != NULL ? root : RUNTIME_CLASS(DObject)); - for (i = 0; i < PClass::m_Types.Size(); i++) + for (i = 0; i < PClass::AllClasses.Size(); i++) { - PClass *cls = PClass::m_Types[i]; - if (root == NULL || - (cls->IsDescendantOf (root) && - (showall || cls == root || - cls->ActorInfo != root->ActorInfo))) + PClass *cls = PClass::AllClasses[i]; + if (root == NULL || cls == root || cls->IsDescendantOf(root)) { DumpInfo::AddType (&tree, cls); // Printf (" %s\n", PClass::m_Types[i]->Name + 1); @@ -389,7 +257,7 @@ DObject::DObject (PClass *inClass) DObject::~DObject () { - if (!(ObjectFlags & OF_Cleanup)) + if (!(ObjectFlags & OF_Cleanup) && !PClass::bShutdown) { DObject **probe; PClass *type = GetClass(); @@ -487,9 +355,12 @@ size_t DObject::StaticPointerSubstitution (DObject *old, DObject *notOld) int i; // Go through all objects. + i = 0;DObject *last=0; for (probe = GC::Root; probe != NULL; probe = probe->ObjNext) { + i++; changed += probe->PointerSubstitution(old, notOld); + last = probe; } // Go through the bodyque. @@ -549,23 +420,33 @@ void DObject::SerializeUserVars(FArchive &arc) // Write all user variables. for (; symt != NULL; symt = symt->ParentSymbolTable) { - for (unsigned i = 0; i < symt->Symbols.Size(); ++i) - { - PSymbol *sym = symt->Symbols[i]; - if (sym->SymbolType == SYM_Variable) - { - PSymbolVariable *var = static_cast(sym); - if (var->bUserVar) - { - count = var->ValueType.Type == VAL_Array ? var->ValueType.size : 1; - varloc = (int *)(reinterpret_cast(this) + var->offset); + PSymbolTable::MapType::Iterator it(symt->Symbols); + PSymbolTable::MapType::Pair *pair; - arc << var->SymbolName; - arc.WriteCount(count); - for (j = 0; j < count; ++j) - { - arc << varloc[j]; - } + while (it.NextPair(pair)) + { + PField *var = dyn_cast(pair->Value); + if (var != NULL && !(var->Flags & VARF_Native)) + { + PType *type = var->Type; + PArray *arraytype = dyn_cast(type); + if (arraytype == NULL) + { + count = 1; + } + else + { + count = arraytype->ElementCount; + type = arraytype->ElementType; + } + assert(type == TypeSInt32); + varloc = (int *)(reinterpret_cast(this) + var->Offset); + + arc << var->SymbolName; + arc.WriteCount(count); + for (j = 0; j < count; ++j) + { + arc << varloc[j]; } } } @@ -580,18 +461,24 @@ void DObject::SerializeUserVars(FArchive &arc) arc << varname; while (varname != NAME_None) { - PSymbol *sym = symt->FindSymbol(varname, true); + PField *var = dyn_cast(symt->FindSymbol(varname, true)); DWORD wanted = 0; - if (sym != NULL && sym->SymbolType == SYM_Variable) + if (var != NULL && !(var->Flags & VARF_Native)) { - PSymbolVariable *var = static_cast(sym); - - if (var->bUserVar) + PType *type = var->Type; + PArray *arraytype = dyn_cast(type); + if (arraytype != NULL) { - wanted = var->ValueType.Type == VAL_Array ? var->ValueType.size : 1; - varloc = (int *)(reinterpret_cast(this) + var->offset); + wanted = arraytype->ElementCount; + type = arraytype->ElementType; } + else + { + wanted = 1; + } + assert(type == TypeSInt32); + varloc = (int *)(reinterpret_cast(this) + var->Offset); } count = arc.ReadCount(); for (j = 0; j < MIN(wanted, count); ++j) diff --git a/src/dobject.h b/src/dobject.h index 74371c0d63..4b6f1ec49f 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -37,7 +37,7 @@ #include #include "doomtype.h" -struct PClass; +class PClass; class FArchive; @@ -78,89 +78,68 @@ class DFloorWaggle; class DPlat; class DPillar; -struct FActorInfo; +class PClassActor; -enum EMetaType +#define RUNTIME_CLASS_CASTLESS(cls) (cls::RegistrationInfo.MyClass) // Passed a native class name, returns a PClass representing that class +#define RUNTIME_CLASS(cls) ((cls::MetaClass *)RUNTIME_CLASS_CASTLESS(cls)) // Like above, but returns the true type of the meta object +#define RUNTIME_TEMPLATE_CLASS(cls) ((typename cls::MetaClass *)RUNTIME_CLASS_CASTLESS(cls)) // RUNTIME_CLASS, but works with templated parameters on GCC +#define NATIVE_TYPE(object) (object->StaticType()) // Passed an object, returns the type of the C++ class representing the object + +// Enumerations for the meta classes created by ClassReg::RegisterClass() +enum { - META_Int, // An int - META_Fixed, // A fixed point number - META_String, // A string + CLASSREG_PClass, + CLASSREG_PClassActor, + CLASSREG_PClassInventory, + CLASSREG_PClassAmmo, + CLASSREG_PClassHealth, + CLASSREG_PClassPuzzleItem, + CLASSREG_PClassWeapon, + CLASSREG_PClassPlayerPawn, + CLASSREG_PClassType, + CLASSREG_PClassClass, }; -class FMetaData -{ -private: - FMetaData (EMetaType type, uint32 id) : Type(type), ID(id) {} - - FMetaData *Next; - EMetaType Type; - uint32 ID; - union - { - int Int; - char *String; - fixed_t Fixed; - } Value; - - friend class FMetaTable; -}; - -class FMetaTable -{ -public: - FMetaTable() : Meta(NULL) {} - FMetaTable(const FMetaTable &other); - ~FMetaTable(); - FMetaTable &operator = (const FMetaTable &other); - - void SetMetaInt (uint32 id, int parm); - void SetMetaFixed (uint32 id, fixed_t parm); - void SetMetaString (uint32 id, const char *parm); // The string is copied - - int GetMetaInt (uint32 id, int def=0) const; - fixed_t GetMetaFixed (uint32 id, fixed_t def=0) const; - const char *GetMetaString (uint32 id) const; - - FMetaData *FindMeta (EMetaType type, uint32 id) const; - -private: - FMetaData *Meta; - FMetaData *FindMetaDef (EMetaType type, uint32 id); - void FreeMeta (); - void CopyMeta (const FMetaTable *other); -}; - -#define RUNTIME_TYPE(object) (object->GetClass()) // Passed an object, returns the type of that object -#define RUNTIME_CLASS(cls) (&cls::_StaticType) // Passed a class name, returns a PClass representing that class -#define NATIVE_TYPE(object) (object->StaticType()) // Passed an object, returns the type of the C++ class representing the object - struct ClassReg { PClass *MyClass; const char *Name; - PClass *ParentType; - unsigned int SizeOf; + ClassReg *ParentType; const size_t *Pointers; void (*ConstructNative)(void *); + unsigned int SizeOf:28; + unsigned int MetaClassNum:4; - void RegisterClass() const; + PClass *RegisterClass(); + void SetupClass(PClass *cls); }; enum EInPlace { EC_InPlace }; #define DECLARE_ABSTRACT_CLASS(cls,parent) \ public: \ - static PClass _StaticType; \ - virtual PClass *StaticType() const { return &_StaticType; } \ - static ClassReg RegistrationInfo, *RegistrationInfoPtr; \ + virtual PClass *StaticType() const; \ + static ClassReg RegistrationInfo, * const RegistrationInfoPtr; \ private: \ typedef parent Super; \ typedef cls ThisClass; +#define DECLARE_ABSTRACT_CLASS_WITH_META(cls,parent,meta) \ + DECLARE_ABSTRACT_CLASS(cls,parent) \ +public: \ + typedef meta MetaClass; \ + MetaClass *GetClass() const { return static_cast(DObject::GetClass()); } \ +protected: \ + enum { MetaClassNum = CLASSREG_##meta }; private: \ + #define DECLARE_CLASS(cls,parent) \ DECLARE_ABSTRACT_CLASS(cls,parent) \ private: static void InPlaceConstructor (void *mem); +#define DECLARE_CLASS_WITH_META(cls,parent,meta) \ + DECLARE_ABSTRACT_CLASS_WITH_META(cls,parent,meta) \ + private: static void InPlaceConstructor (void *mem); + #define HAS_OBJECT_POINTERS \ static const size_t PointerOffsets[]; @@ -170,23 +149,23 @@ private: \ #define END_POINTERS ~(size_t)0 }; #if defined(_MSC_VER) -# pragma data_seg(".creg$u") -# pragma data_seg() -# define _DECLARE_TI(cls) __declspec(allocate(".creg$u")) ClassReg *cls::RegistrationInfoPtr = &cls::RegistrationInfo; +# pragma section(".creg$u",read) +# define _DECLARE_TI(cls) __declspec(allocate(".creg$u")) ClassReg * const cls::RegistrationInfoPtr = &cls::RegistrationInfo; #else -# define _DECLARE_TI(cls) ClassReg *cls::RegistrationInfoPtr __attribute__((section(SECTION_CREG))) = &cls::RegistrationInfo; +# define _DECLARE_TI(cls) ClassReg * const cls::RegistrationInfoPtr __attribute__((section(SECTION_CREG))) = &cls::RegistrationInfo; #endif #define _IMP_PCLASS(cls,ptrs,create) \ - PClass cls::_StaticType; \ ClassReg cls::RegistrationInfo = {\ - RUNTIME_CLASS(cls), \ + NULL, \ #cls, \ - RUNTIME_CLASS(cls::Super), \ - sizeof(cls), \ + &cls::Super::RegistrationInfo, \ ptrs, \ - create }; \ - _DECLARE_TI(cls) + create, \ + sizeof(cls), \ + cls::MetaClassNum }; \ + _DECLARE_TI(cls) \ + PClass *cls::StaticType() const { return RegistrationInfo.MyClass; } #define _IMP_CREATE_OBJ(cls) \ void cls::InPlaceConstructor(void *mem) { new((EInPlace *)mem) cls; } @@ -207,7 +186,6 @@ private: \ _IMP_PCLASS(cls,cls::PointerOffsets,NULL) \ const size_t cls::PointerOffsets[] = { - enum EObjectFlags { // GC flags @@ -227,6 +205,7 @@ enum EObjectFlags OF_JustSpawned = 1 << 8, // Thinker was spawned this tic OF_SerialSuccess = 1 << 9, // For debugging Serialize() calls OF_Sentinel = 1 << 10, // Object is serving as the sentinel in a ring list + OF_StateChanged = 1 << 11, // Used by A_Jump* functions to feed back to SetState() }; template class TObjPtr; @@ -268,6 +247,9 @@ namespace GC // Size of GC steps. extern int StepMul; + // Is this the final collection just before exit? + extern bool FinalGC; + // Current white value for known-dead objects. static inline uint32 OtherWhite() { @@ -319,6 +301,9 @@ namespace GC // is NULLed instead. void Mark(DObject **obj); + // Marks an array of objects. + void MarkArray(DObject **objs, size_t count); + // For cleanup void DelSoftRootHead(); @@ -340,6 +325,15 @@ namespace GC obj = t; } template void Mark(TObjPtr &obj); + + template void MarkArray(T **obj, size_t count) + { + MarkArray((DObject **)(obj), count); + } + template void MarkArray(TArray &arr) + { + MarkArray(&arr[0], arr.Size()); + } } // A template class to help with handling read barriers. It does not @@ -441,12 +435,14 @@ template inline void GC::Mark(TObjPtr &obj) class DObject { public: - static PClass _StaticType; - virtual PClass *StaticType() const { return &_StaticType; } - static ClassReg RegistrationInfo, *RegistrationInfoPtr; + virtual PClass *StaticType() const { return RegistrationInfo.MyClass; } + static ClassReg RegistrationInfo, * const RegistrationInfoPtr; static void InPlaceConstructor (void *mem); + typedef PClass MetaClass; private: typedef DObject ThisClass; +protected: + enum { MetaClassNum = CLASSREG_PClass }; // Per-instance variables. There are four. private: @@ -466,6 +462,10 @@ public: void SerializeUserVars(FArchive &arc); virtual void Serialize (FArchive &arc); + void ClearClass() + { + Class = NULL; + } // For catching Serialize functions in derived classes // that don't call their base class. @@ -601,4 +601,18 @@ inline bool DObject::IsA (const PClass *type) const return (type == GetClass()); } +template T *dyn_cast(DObject *p) +{ + if (p != NULL && p->IsKindOf(RUNTIME_CLASS_CASTLESS(T))) + { + return static_cast(p); + } + return NULL; +} + +template const T *dyn_cast(const DObject *p) +{ + return dyn_cast(const_cast(p)); +} + #endif //__DOBJECT_H__ diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index 2efb5a15e0..efc6d310e3 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -71,6 +71,7 @@ #include "doomstat.h" #include "m_argv.h" #include "po_man.h" +#include "autosegs.h" #include "v_video.h" #include "menu/menu.h" #include "intermission/intermission.h" @@ -150,6 +151,7 @@ int Pause = DEFAULT_GCPAUSE; int StepMul = DEFAULT_GCMUL; int StepCount; size_t Dept; +bool FinalGC; // PRIVATE DATA DEFINITIONS ------------------------------------------------ @@ -286,6 +288,22 @@ void Mark(DObject **obj) } } +//========================================================================== +// +// MarkArray +// +// Mark an array of objects gray. +// +//========================================================================== + +void MarkArray(DObject **obj, size_t count) +{ + for (size_t i = 0; i < count; ++i) + { + Mark(obj[i]); + } +} + //========================================================================== // // MarkRoot @@ -336,6 +354,25 @@ static void MarkRoot() } Mark(SectorMarker); Mark(interpolator.Head); + // Mark action functions + if (!FinalGC) + { + FAutoSegIterator probe(ARegHead, ARegTail); + + while (*++probe != NULL) + { + AFuncDesc *afunc = (AFuncDesc *)*probe; + Mark(*(afunc->VMPointer)); + } + } + // Mark types + TypeTable.Mark(); + for (unsigned int i = 0; i < PClass::AllClasses.Size(); ++i) + { + Mark(PClass::AllClasses[i]); + } + // Mark global symbols + GlobalSymbols.MarkSymbols(); // Mark bot stuff. Mark(bglobal.firstthing); Mark(bglobal.body1); @@ -365,7 +402,7 @@ static void MarkRoot() // // Atomic // -// If their were any propagations that needed to be done atomicly, they +// If there were any propagations that needed to be done atomicly, they // would go here. It also sets things up for the sweep state. // //========================================================================== diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 76233d4d59..cc0a077f25 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -3,7 +3,7 @@ ** Implements the type information class ** **--------------------------------------------------------------------------- -** Copyright 1998-2008 Randy Heit +** Copyright 1998-2010 Randy Heit ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -32,45 +32,1980 @@ ** */ +// HEADER FILES ------------------------------------------------------------ + +#include +#include + #include "dobject.h" #include "i_system.h" #include "actor.h" #include "templates.h" #include "autosegs.h" #include "v_text.h" +#include "a_pickups.h" +#include "d_player.h" +#include "fragglescript/t_fs.h" -TArray PClass::m_RuntimeActors; -TArray PClass::m_Types; -PClass *PClass::TypeHash[PClass::HASH_SIZE]; +// MACROS ------------------------------------------------------------------ + +// TYPES ------------------------------------------------------------------- + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +FTypeTable TypeTable; +PSymbolTable GlobalSymbols; +TArray PClass::AllClasses; bool PClass::bShutdown; +PErrorType *TypeError; +PVoidType *TypeVoid; +PInt *TypeSInt8, *TypeUInt8; +PInt *TypeSInt16, *TypeUInt16; +PInt *TypeSInt32, *TypeUInt32; +PBool *TypeBool; +PFloat *TypeFloat32, *TypeFloat64; +PString *TypeString; +PName *TypeName; +PSound *TypeSound; +PColor *TypeColor; +PStatePointer *TypeState; +PFixed *TypeFixed; +PAngle *TypeAngle; + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + // A harmless non-NULL FlatPointer for classes without pointers. static const size_t TheEnd = ~(size_t)0; +// CODE -------------------------------------------------------------------- + +IMPLEMENT_CLASS(PErrorType) +IMPLEMENT_CLASS(PVoidType) + +void DumpTypeTable() +{ + int used = 0; + int min = INT_MAX; + int max = 0; + int all = 0; + int lens[10] = {0}; + for (size_t i = 0; i < countof(TypeTable.TypeHash); ++i) + { + int len = 0; + Printf("%4zu:", i); + for (PType *ty = TypeTable.TypeHash[i]; ty != NULL; ty = ty->HashNext) + { + Printf(" -> %s", ty->IsKindOf(RUNTIME_CLASS(PNamedType)) ? static_cast(ty)->TypeName.GetChars(): ty->GetClass()->TypeName.GetChars()); + len++; + all++; + } + if (len != 0) + { + used++; + if (len < min) + min = len; + if (len > max) + max = len; + } + if (len < (int)countof(lens)) + { + lens[len]++; + } + Printf("\n"); + } + Printf("Used buckets: %d/%lu (%.2f%%) for %d entries\n", used, countof(TypeTable.TypeHash), double(used)/countof(TypeTable.TypeHash)*100, all); + Printf("Min bucket size: %d\n", min); + Printf("Max bucket size: %d\n", max); + Printf("Avg bucket size: %.2f\n", double(all) / used); + int j,k; + for (k = countof(lens)-1; k > 0; --k) + if (lens[k]) + break; + for (j = 0; j <= k; ++j) + Printf("Buckets of len %d: %d (%.2f%%)\n", j, lens[j], j!=0?double(lens[j])/used*100:-1.0); +} + +/* PClassType *************************************************************/ + +IMPLEMENT_CLASS(PClassType) + +//========================================================================== +// +// PClassType Constructor +// +//========================================================================== + +PClassType::PClassType() +: TypeTableType(NULL) +{ +} + +//========================================================================== +// +// PClassType :: Derive +// +//========================================================================== + +void PClassType::Derive(PClass *newclass) +{ + assert(newclass->IsKindOf(RUNTIME_CLASS(PClassType))); + Super::Derive(newclass); + static_cast(newclass)->TypeTableType = TypeTableType; +} + +/* PClassClass ************************************************************/ + +IMPLEMENT_CLASS(PClassClass) + +//========================================================================== +// +// PClassClass Constructor +// +// The only thing we want to do here is automatically set TypeTableType +// to PClass. +// +//========================================================================== + +PClassClass::PClassClass() +{ + TypeTableType = RUNTIME_CLASS(PClass); +} + +/* PType ******************************************************************/ + +IMPLEMENT_ABSTRACT_POINTY_CLASS(PType) + DECLARE_POINTER(HashNext) +END_POINTERS + +//========================================================================== +// +// PType Default Constructor +// +//========================================================================== + +PType::PType() +: Size(0), Align(1), HashNext(NULL) +{ +} + +//========================================================================== +// +// PType Parameterized Constructor +// +//========================================================================== + +PType::PType(unsigned int size, unsigned int align) +: Size(size), Align(align), HashNext(NULL) +{ +} + +//========================================================================== +// +// PType Destructor +// +//========================================================================== + +PType::~PType() +{ +} + +//========================================================================== +// +// PType :: PropagateMark +// +//========================================================================== + +size_t PType::PropagateMark() +{ + size_t marked = Symbols.MarkSymbols(); + return marked + Super::PropagateMark(); +} + +//========================================================================== +// +// PType :: AddConversion +// +//========================================================================== + +bool PType::AddConversion(PType *target, void (*convertconst)(ZCC_ExprConstant *, class FSharedStringArena &)) +{ + // Make sure a conversion hasn't already been registered + for (unsigned i = 0; i < Conversions.Size(); ++i) + { + if (Conversions[i].TargetType == target) + return false; + } + Conversions.Push(Conversion(target, convertconst)); + return true; +} + +//========================================================================== +// +// PType :: FindConversion +// +// Returns <0 if there is no path to target. Otherwise, returns the distance +// to target and fills slots (if non-NULL) with the necessary conversions +// to get there. A result of 0 means this is the target. +// +//========================================================================== + +int PType::FindConversion(PType *target, const PType::Conversion **slots, int numslots) +{ + if (this == target) + { + return 0; + } + // The queue is implemented as a ring buffer + VisitQueue queue; + VisitedNodeSet visited; + + // Use a breadth-first search to find the shortest path to the target. + MarkPred(NULL, -1, -1); + queue.Push(this); + visited.Insert(this); + while (!queue.IsEmpty()) + { + PType *t = queue.Pop(); + if (t == target) + { // found it + if (slots != NULL) + { + if (t->Distance >= numslots) + { // Distance is too far for the output + return -2; + } + t->FillConversionPath(slots); + } + return t->Distance + 1; + } + for (unsigned i = 0; i < t->Conversions.Size(); ++i) + { + PType *succ = t->Conversions[i].TargetType; + if (!visited.Check(succ)) + { + succ->MarkPred(t, i, t->Distance + 1); + visited.Insert(succ); + queue.Push(succ); + } + } + } + return -1; +} + +//========================================================================== +// +// PType :: FillConversionPath +// +// Traces backwards from the target type to the original type and fills in +// the conversions necessary to get between them. slots must point to an +// array large enough to contain the entire path. +// +//========================================================================== + +void PType::FillConversionPath(const PType::Conversion **slots) +{ + for (PType *node = this; node->Distance >= 0; node = node->PredType) + { + assert(node->PredType != NULL); + slots[node->Distance] = &node->PredType->Conversions[node->PredConv]; + } +} + +//========================================================================== +// +// PType :: VisitQueue :: Push +// +//========================================================================== + +void PType::VisitQueue::Push(PType *type) +{ + Queue[In] = type; + Advance(In); + assert(!IsEmpty() && "Queue overflowed"); +} + +//========================================================================== +// +// PType :: VisitQueue :: Pop +// +//========================================================================== + +PType *PType::VisitQueue::Pop() +{ + if (IsEmpty()) + { + return NULL; + } + PType *node = Queue[Out]; + Advance(Out); + return node; +} + +//========================================================================== +// +// PType :: VisitedNodeSet :: Insert +// +//========================================================================== + +void PType::VisitedNodeSet::Insert(PType *node) +{ + assert(!Check(node) && "Node was already inserted"); + size_t buck = Hash(node) & (countof(Buckets) - 1); + node->VisitNext = Buckets[buck]; + Buckets[buck] = node; +} + +//========================================================================== +// +// PType :: VisitedNodeSet :: Check +// +//========================================================================== + +bool PType::VisitedNodeSet::Check(const PType *node) +{ + size_t buck = Hash(node) & (countof(Buckets) - 1); + for (const PType *probe = Buckets[buck]; probe != NULL; probe = probe->VisitNext) + { + if (probe == node) + { + return true; + } + } + return false; +} + +//========================================================================== +// +// PType :: SetValue +// +//========================================================================== + +void PType::SetValue(void *addr, int val) +{ + assert(0 && "Cannot set value for this type"); +} + +//========================================================================== +// +// PType :: GetValue +// +//========================================================================== + +int PType::GetValueInt(void *addr) const +{ + assert(0 && "Cannot get value for this type"); + return 0; +} + +//========================================================================== +// +// PType :: GetStoreOp +// +//========================================================================== + +int PType::GetStoreOp() const +{ + assert(0 && "Cannot store this type"); + return OP_NOP; +} + +//========================================================================== +// +// PType :: GetLoadOp +// +//========================================================================== + +int PType::GetLoadOp() const +{ + assert(0 && "Cannot load this type"); + return OP_NOP; +} + +//========================================================================== +// +// PType :: GetRegType +// +//========================================================================== + +int PType::GetRegType() const +{ + assert(0 && "No register for this type"); + return REGT_NIL; +} + +//========================================================================== +// +// PType :: IsMatch +// +//========================================================================== + +bool PType::IsMatch(intptr_t id1, intptr_t id2) const +{ + return false; +} + +//========================================================================== +// +// PType :: GetTypeIDs +// +//========================================================================== + +void PType::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +{ + id1 = 0; + id2 = 0; +} + +//========================================================================== +// +// PType :: StaticInit STATIC +// +// Set up TypeTableType values for every PType child and create basic types. +// +//========================================================================== + +void ReleaseGlobalSymbols() +{ + TypeTable.Clear(); + GlobalSymbols.ReleaseSymbols(); +} + +void PType::StaticInit() +{ + // Add types to the global symbol table. + atterm(ReleaseGlobalSymbols); + + // Set up TypeTable hash keys. + RUNTIME_CLASS(PErrorType)->TypeTableType = RUNTIME_CLASS(PErrorType); + RUNTIME_CLASS(PVoidType)->TypeTableType = RUNTIME_CLASS(PVoidType); + RUNTIME_CLASS(PInt)->TypeTableType = RUNTIME_CLASS(PInt); + RUNTIME_CLASS(PBool)->TypeTableType = RUNTIME_CLASS(PBool); + RUNTIME_CLASS(PFloat)->TypeTableType = RUNTIME_CLASS(PFloat); + RUNTIME_CLASS(PString)->TypeTableType = RUNTIME_CLASS(PString); + RUNTIME_CLASS(PName)->TypeTableType = RUNTIME_CLASS(PName); + RUNTIME_CLASS(PSound)->TypeTableType = RUNTIME_CLASS(PSound); + RUNTIME_CLASS(PColor)->TypeTableType = RUNTIME_CLASS(PColor); + RUNTIME_CLASS(PPointer)->TypeTableType = RUNTIME_CLASS(PPointer); + RUNTIME_CLASS(PClassPointer)->TypeTableType = RUNTIME_CLASS(PPointer); // not sure about this yet + RUNTIME_CLASS(PEnum)->TypeTableType = RUNTIME_CLASS(PEnum); + RUNTIME_CLASS(PArray)->TypeTableType = RUNTIME_CLASS(PArray); + RUNTIME_CLASS(PDynArray)->TypeTableType = RUNTIME_CLASS(PDynArray); + RUNTIME_CLASS(PVector)->TypeTableType = RUNTIME_CLASS(PVector); + RUNTIME_CLASS(PMap)->TypeTableType = RUNTIME_CLASS(PMap); + RUNTIME_CLASS(PStruct)->TypeTableType = RUNTIME_CLASS(PStruct); + RUNTIME_CLASS(PPrototype)->TypeTableType = RUNTIME_CLASS(PPrototype); + RUNTIME_CLASS(PClass)->TypeTableType = RUNTIME_CLASS(PClass); + RUNTIME_CLASS(PStatePointer)->TypeTableType = RUNTIME_CLASS(PStatePointer); + RUNTIME_CLASS(PFixed)->TypeTableType = RUNTIME_CLASS(PFixed); + RUNTIME_CLASS(PAngle)->TypeTableType = RUNTIME_CLASS(PAngle); + + // Create types and add them type the type table. + TypeTable.AddType(TypeError = new PErrorType); + TypeTable.AddType(TypeVoid = new PVoidType); + TypeTable.AddType(TypeSInt8 = new PInt(1, false)); + TypeTable.AddType(TypeUInt8 = new PInt(1, true)); + TypeTable.AddType(TypeSInt16 = new PInt(2, false)); + TypeTable.AddType(TypeUInt16 = new PInt(2, true)); + TypeTable.AddType(TypeSInt32 = new PInt(4, false)); + TypeTable.AddType(TypeUInt32 = new PInt(4, true)); + TypeTable.AddType(TypeBool = new PBool); + TypeTable.AddType(TypeFloat32 = new PFloat(4)); + TypeTable.AddType(TypeFloat64 = new PFloat(8)); + TypeTable.AddType(TypeString = new PString); + TypeTable.AddType(TypeName = new PName); + TypeTable.AddType(TypeSound = new PSound); + TypeTable.AddType(TypeColor = new PColor); + TypeTable.AddType(TypeState = new PStatePointer); + TypeTable.AddType(TypeFixed = new PFixed); + TypeTable.AddType(TypeAngle = new PAngle); + + GlobalSymbols.AddSymbol(new PSymbolType(NAME_sByte, TypeSInt8)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_Byte, TypeUInt8)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_Short, TypeSInt16)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_uShort, TypeUInt16)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_Int, TypeSInt32)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_uInt, TypeUInt32)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_Bool, TypeBool)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_Float, TypeFloat64)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_Double, TypeFloat64)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_Float32, TypeFloat32)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_Float64, TypeFloat64)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_String, TypeString)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_Name, TypeName)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_Sound, TypeSound)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_Color, TypeColor)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_State, TypeState)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_Fixed, TypeFixed)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_Angle, TypeAngle)); +} + + +/* PBasicType *************************************************************/ + +IMPLEMENT_ABSTRACT_CLASS(PBasicType) + +//========================================================================== +// +// PBasicType Default Constructor +// +//========================================================================== + +PBasicType::PBasicType() +{ +} + +//========================================================================== +// +// PBasicType Parameterized Constructor +// +//========================================================================== + +PBasicType::PBasicType(unsigned int size, unsigned int align) +: PType(size, align) +{ +} + +/* PCompoundType **********************************************************/ + +IMPLEMENT_ABSTRACT_CLASS(PCompoundType) + +/* PNamedType *************************************************************/ + +IMPLEMENT_ABSTRACT_POINTY_CLASS(PNamedType) + DECLARE_POINTER(Outer) +END_POINTERS + +//========================================================================== +// +// PNamedType :: IsMatch +// +//========================================================================== + +bool PNamedType::IsMatch(intptr_t id1, intptr_t id2) const +{ + const DObject *outer = (const DObject *)id1; + FName name = (ENamedName)(intptr_t)id2; + + return Outer == outer && TypeName == name; +} + +//========================================================================== +// +// PNamedType :: GetTypeIDs +// +//========================================================================== + +void PNamedType::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +{ + id1 = (intptr_t)Outer; + id2 = TypeName; +} + +/* PInt *******************************************************************/ + +IMPLEMENT_CLASS(PInt) + +//========================================================================== +// +// PInt Default Constructor +// +//========================================================================== + +PInt::PInt() +: PBasicType(4, 4), Unsigned(false) +{ + Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Min, this, -0x7FFFFFFF - 1)); + Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Max, this, 0x7FFFFFFF)); +} + +//========================================================================== +// +// PInt Parameterized Constructor +// +//========================================================================== + +PInt::PInt(unsigned int size, bool unsign) +: PBasicType(size, size), Unsigned(unsign) +{ + if (!unsign) + { + int maxval = (1 << ((8 * size) - 1)) - 1; + int minval = -maxval - 1; + Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Min, this, minval)); + Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Max, this, maxval)); + } + else + { + Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Min, this, 0u)); + Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Max, this, (1u << (8 * size)) - 1)); + } +} + +//========================================================================== +// +// PInt :: SetValue +// +//========================================================================== + +void PInt::SetValue(void *addr, int val) +{ + assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); + if (Size == 4) + { + *(int *)addr = val; + } + else if (Size == 1) + { + *(BYTE *)addr = val; + } + else if (Size == 2) + { + *(WORD *)addr = val; + } + else if (Size == 8) + { + *(QWORD *)addr = val; + } + else + { + assert(0 && "Unhandled integer size"); + } +} + +//========================================================================== +// +// PInt :: GetValueInt +// +//========================================================================== + +int PInt::GetValueInt(void *addr) const +{ + assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); + if (Size == 4) + { + return *(int *)addr; + } + else if (Size == 1) + { + return Unsigned ? *(BYTE *)addr : *(SBYTE *)addr; + } + else if (Size == 2) + { + return Unsigned ? *(WORD *)addr : *(SWORD *)addr; + } + else if (Size == 8) + { // truncated output + return (int)*(QWORD *)addr; + } + else + { + assert(0 && "Unhandled integer size"); + return 0; + } +} + +//========================================================================== +// +// PInt :: GetStoreOp +// +//========================================================================== + +int PInt::GetStoreOp() const +{ + if (Size == 4) + { + return OP_SW; + } + else if (Size == 1) + { + return OP_SB; + } + else if (Size == 2) + { + return OP_SH; + } + else + { + assert(0 && "Unhandled integer size"); + return OP_NOP; + } +} + +//========================================================================== +// +// PInt :: GetLoadOp +// +//========================================================================== + +int PInt::GetLoadOp() const +{ + if (Size == 4) + { + return OP_LW; + } + else if (Size == 1) + { + return Unsigned ? OP_LBU : OP_LB; + } + else if (Size == 2) + { + return Unsigned ? OP_LHU : OP_LH; + } + else + { + assert(0 && "Unhandled integer size"); + return OP_NOP; + } +} + +//========================================================================== +// +// PInt :: GetRegType +// +//========================================================================== + +int PInt::GetRegType() const +{ + return REGT_INT; +} + +/* PBool ******************************************************************/ + +IMPLEMENT_CLASS(PBool) + +//========================================================================== +// +// PBool Default Constructor +// +//========================================================================== + +PBool::PBool() +: PInt(sizeof(bool), true) +{ + // Override the default max set by PInt's constructor + PSymbolConstNumeric *maxsym = static_cast(Symbols.FindSymbol(NAME_Max, false)); + assert(maxsym != NULL && maxsym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric))); + maxsym->Value = 1; +} + +/* PFloat *****************************************************************/ + +IMPLEMENT_CLASS(PFloat) + +//========================================================================== +// +// PFloat Default Constructor +// +//========================================================================== + +PFloat::PFloat() +: PBasicType(8, 8) +{ + SetDoubleSymbols(); +} + +//========================================================================== +// +// PFloat Parameterized Constructor +// +//========================================================================== + +PFloat::PFloat(unsigned int size) +: PBasicType(size, size) +{ + if (size == 8) + { + SetDoubleSymbols(); + } + else + { + assert(size == 4); + SetSingleSymbols(); + } +} + +//========================================================================== +// +// PFloat :: SetDoubleSymbols +// +// Setup constant values for 64-bit floats. +// +//========================================================================== + +void PFloat::SetDoubleSymbols() +{ + static const SymbolInitF symf[] = + { + { NAME_Min_Normal, DBL_MIN }, + { NAME_Max, DBL_MAX }, + { NAME_Epsilon, DBL_EPSILON }, + { NAME_NaN, std::numeric_limits::quiet_NaN() }, + { NAME_Infinity, std::numeric_limits::infinity() }, + { NAME_Min_Denormal, std::numeric_limits::denorm_min() } + }; + static const SymbolInitI symi[] = + { + { NAME_Dig, DBL_DIG }, + { NAME_Min_Exp, DBL_MIN_EXP }, + { NAME_Max_Exp, DBL_MAX_EXP }, + { NAME_Mant_Dig, DBL_MANT_DIG }, + { NAME_Min_10_Exp, DBL_MIN_10_EXP }, + { NAME_Max_10_Exp, DBL_MAX_10_EXP } + }; + SetSymbols(symf, countof(symf)); + SetSymbols(symi, countof(symi)); +} + +//========================================================================== +// +// PFloat :: SetSingleSymbols +// +// Setup constant values for 32-bit floats. +// +//========================================================================== + +void PFloat::SetSingleSymbols() +{ + static const SymbolInitF symf[] = + { + { NAME_Min_Normal, FLT_MIN }, + { NAME_Max, FLT_MAX }, + { NAME_Epsilon, FLT_EPSILON }, + { NAME_NaN, std::numeric_limits::quiet_NaN() }, + { NAME_Infinity, std::numeric_limits::infinity() }, + { NAME_Min_Denormal, std::numeric_limits::denorm_min() } + }; + static const SymbolInitI symi[] = + { + { NAME_Dig, FLT_DIG }, + { NAME_Min_Exp, FLT_MIN_EXP }, + { NAME_Max_Exp, FLT_MAX_EXP }, + { NAME_Mant_Dig, FLT_MANT_DIG }, + { NAME_Min_10_Exp, FLT_MIN_10_EXP }, + { NAME_Max_10_Exp, FLT_MAX_10_EXP } + }; + SetSymbols(symf, countof(symf)); + SetSymbols(symi, countof(symi)); +} + +//========================================================================== +// +// PFloat :: SetSymbols +// +//========================================================================== + +void PFloat::SetSymbols(const PFloat::SymbolInitF *sym, size_t count) +{ + for (size_t i = 0; i < count; ++i) + { + Symbols.AddSymbol(new PSymbolConstNumeric(sym[i].Name, this, sym[i].Value)); + } +} + +void PFloat::SetSymbols(const PFloat::SymbolInitI *sym, size_t count) +{ + for (size_t i = 0; i < count; ++i) + { + Symbols.AddSymbol(new PSymbolConstNumeric(sym[i].Name, this, sym[i].Value)); + } +} + +//========================================================================== +// +// PFloat :: SetValue +// +//========================================================================== + +void PFloat::SetValue(void *addr, int val) +{ + assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); + if (Size == 4) + { + *(float *)addr = (float)val; + } + else + { + assert(Size == 8); + *(double *)addr = val; + } +} + +//========================================================================== +// +// PFloat :: GetValueInt +// +//========================================================================== + +int PFloat::GetValueInt(void *addr) const +{ + assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); + if (Size == 4) + { + return xs_ToInt(*(float *)addr); + } + else + { + assert(Size == 8); + return xs_ToInt(*(double *)addr); + } +} + +//========================================================================== +// +// PFloat :: GetStoreOp +// +//========================================================================== + +int PFloat::GetStoreOp() const +{ + if (Size == 4) + { + return OP_SSP; + } + else + { + assert(Size == 8); + return OP_SDP; + } +} + +//========================================================================== +// +// PFloat :: GetLoadOp +// +//========================================================================== + +int PFloat::GetLoadOp() const +{ + if (Size == 4) + { + return OP_LSP; + } + else + { + assert(Size == 8); + return OP_LDP; + } + assert(0 && "Cannot load this type"); + return OP_NOP; +} + +//========================================================================== +// +// PFloat :: GetRegType +// +//========================================================================== + +int PFloat::GetRegType() const +{ + return REGT_FLOAT; +} + +/* PString ****************************************************************/ + +IMPLEMENT_CLASS(PString) + +//========================================================================== +// +// PString Default Constructor +// +//========================================================================== + +PString::PString() +: PBasicType(sizeof(FString), __alignof(FString)) +{ +} + +//========================================================================== +// +// PString :: GetRegType +// +//========================================================================== + +int PString::GetRegType() const +{ + return REGT_STRING; +} + +/* PName ******************************************************************/ + +IMPLEMENT_CLASS(PName) + +//========================================================================== +// +// PName Default Constructor +// +//========================================================================== + +PName::PName() +: PInt(sizeof(FName), true) +{ + assert(sizeof(FName) == __alignof(FName)); +} + +/* PSound *****************************************************************/ + +IMPLEMENT_CLASS(PSound) + +//========================================================================== +// +// PSound Default Constructor +// +//========================================================================== + +PSound::PSound() +: PInt(sizeof(FSoundID), true) +{ + assert(sizeof(FSoundID) == __alignof(FSoundID)); +} + +/* PColor *****************************************************************/ + +IMPLEMENT_CLASS(PColor) + +//========================================================================== +// +// PColor Default Constructor +// +//========================================================================== + +PColor::PColor() +: PInt(sizeof(PalEntry), true) +{ + assert(sizeof(PalEntry) == __alignof(PalEntry)); +} + +/* PFixed *****************************************************************/ + +IMPLEMENT_CLASS(PFixed) + +//========================================================================== +// +// PFixed Default Constructor +// +//========================================================================== + +PFixed::PFixed() +: PFloat(sizeof(fixed_t)) +{ +} + +//========================================================================== +// +// PFixed :: SetValue +// +//========================================================================== + +void PFixed::SetValue(void *addr, int val) +{ + assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); + *(fixed_t *)addr = val << FRACBITS; +} + +//========================================================================== +// +// PFixed :: GetValueInt +// +//========================================================================== + +int PFixed::GetValueInt(void *addr) const +{ + assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); + return *(fixed_t *)addr >> FRACBITS; +} + +//========================================================================== +// +// PFixed :: GetStoreOp +// +//========================================================================== + +int PFixed::GetStoreOp() const +{ + return OP_SX; +} + +//========================================================================== +// +// PFixed :: GetLoadOp +// +//========================================================================== + +int PFixed::GetLoadOp() const +{ + return OP_LX; +} + +/* PAngle *****************************************************************/ + +IMPLEMENT_CLASS(PAngle) + +//========================================================================== +// +// PAngle Default Constructor +// +//========================================================================== + +PAngle::PAngle() +: PFloat(sizeof(angle_t)) +{ +} + +//========================================================================== +// +// PAngle :: SetValue +// +//========================================================================== + +void PAngle::SetValue(void *addr, int val) +{ + assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); + *(angle_t *)addr = Scale(val, ANGLE_90, 90); +} + +//========================================================================== +// +// PAngle :: GetValueInt +// +//========================================================================== + +int PAngle::GetValueInt(void *addr) const +{ + assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); + return *(angle_t *)addr / ANGLE_1; +} + +//========================================================================== +// +// PAngle :: GetStoreOp +// +//========================================================================== + +int PAngle::GetStoreOp() const +{ + return OP_SANG; +} + +//========================================================================== +// +// PAngle :: GetLoadOp +// +//========================================================================== + +int PAngle::GetLoadOp() const +{ + return OP_LANG; +} + +/* PStatePointer **********************************************************/ + +IMPLEMENT_CLASS(PStatePointer) + +//========================================================================== +// +// PStatePointer Default Constructor +// +//========================================================================== + +PStatePointer::PStatePointer() +: PBasicType(sizeof(FState *), __alignof(FState *)) +{ +} + + +/* PPointer ***************************************************************/ + +IMPLEMENT_POINTY_CLASS(PPointer) + DECLARE_POINTER(PointedType) +END_POINTERS + +//========================================================================== +// +// PPointer - Default Constructor +// +//========================================================================== + +PPointer::PPointer() +: PBasicType(sizeof(void *), __alignof(void *)), PointedType(NULL) +{ +} + +//========================================================================== +// +// PPointer - Parameterized Constructor +// +//========================================================================== + +PPointer::PPointer(PType *pointsat) +: PBasicType(sizeof(void *), __alignof(void *)), PointedType(pointsat) +{ +} + +//========================================================================== +// +// PPointer :: GetStoreOp +// +//========================================================================== + +int PPointer::GetStoreOp() const +{ + return OP_SP; +} + +//========================================================================== +// +// PPointer :: GetLoadOp +// +//========================================================================== + +int PPointer::GetLoadOp() const +{ + return PointedType->IsKindOf(RUNTIME_CLASS(PClass)) ? OP_LO : OP_LP; +} + +//========================================================================== +// +// PPointer :: GetRegType +// +//========================================================================== + +int PPointer::GetRegType() const +{ + return REGT_POINTER; +} + +//========================================================================== +// +// PPointer :: IsMatch +// +//========================================================================== + +bool PPointer::IsMatch(intptr_t id1, intptr_t id2) const +{ + assert(id2 == 0); + PType *pointat = (PType *)id1; + + return pointat == PointedType; +} + +//========================================================================== +// +// PPointer :: GetTypeIDs +// +//========================================================================== + +void PPointer::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +{ + id1 = (intptr_t)PointedType; + id2 = 0; +} + +//========================================================================== +// +// NewPointer +// +// Returns a PPointer to an object of the specified type +// +//========================================================================== + +PPointer *NewPointer(PType *type) +{ + size_t bucket; + PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PPointer), (intptr_t)type, 0, &bucket); + if (ptype == NULL) + { + ptype = new PPointer(type); + TypeTable.AddType(ptype, RUNTIME_CLASS(PPointer), (intptr_t)type, 0, bucket); + } + return static_cast(ptype); +} + + +/* PClassPointer **********************************************************/ + +IMPLEMENT_POINTY_CLASS(PClassPointer) + DECLARE_POINTER(ClassRestriction) +END_POINTERS + +//========================================================================== +// +// PClassPointer - Default Constructor +// +//========================================================================== + +PClassPointer::PClassPointer() +: PPointer(RUNTIME_CLASS(PClass)), ClassRestriction(NULL) +{ +} + +//========================================================================== +// +// PClassPointer - Parameterized Constructor +// +//========================================================================== + +PClassPointer::PClassPointer(PClass *restrict) +: PPointer(RUNTIME_CLASS(PClass)), ClassRestriction(restrict) +{ +} + +//========================================================================== +// +// PClassPointer :: IsMatch +// +//========================================================================== + +bool PClassPointer::IsMatch(intptr_t id1, intptr_t id2) const +{ + const PType *pointat = (const PType *)id1; + const PClass *classat = (const PClass *)id2; + + assert(pointat->IsKindOf(RUNTIME_CLASS(PClass))); + return classat == ClassRestriction; +} + +//========================================================================== +// +// PClassPointer :: GetTypeIDs +// +//========================================================================== + +void PClassPointer::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +{ + assert(PointedType == RUNTIME_CLASS(PClass)); + id1 = (intptr_t)PointedType; + id2 = (intptr_t)ClassRestriction; +} + +//========================================================================== +// +// NewClassPointer +// +// Returns a PClassPointer for the restricted type. +// +//========================================================================== + +PClassPointer *NewClassPointer(PClass *restrict) +{ + size_t bucket; + PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PPointer), (intptr_t)RUNTIME_CLASS(PClass), (intptr_t)restrict, &bucket); + if (ptype == NULL) + { + ptype = new PClassPointer(restrict); + TypeTable.AddType(ptype, RUNTIME_CLASS(PPointer), (intptr_t)RUNTIME_CLASS(PClass), (intptr_t)restrict, bucket); + } + return static_cast(ptype); +} + +/* PEnum ******************************************************************/ + +IMPLEMENT_POINTY_CLASS(PEnum) + DECLARE_POINTER(ValueType) +END_POINTERS + +//========================================================================== +// +// PEnum - Default Constructor +// +//========================================================================== + +PEnum::PEnum() +: ValueType(NULL) +{ +} + +//========================================================================== +// +// PEnum - Parameterized Constructor +// +//========================================================================== + +PEnum::PEnum(FName name, DObject *outer) +: PNamedType(name, outer), ValueType(NULL) +{ +} + +//========================================================================== +// +// NewEnum +// +// Returns a PEnum for the given name and container, making sure not to +// create duplicates. +// +//========================================================================== + +PEnum *NewEnum(FName name, DObject *outer) +{ + size_t bucket; + PType *etype = TypeTable.FindType(RUNTIME_CLASS(PEnum), (intptr_t)outer, (intptr_t)name, &bucket); + if (etype == NULL) + { + etype = new PEnum(name, outer); + TypeTable.AddType(etype, RUNTIME_CLASS(PEnum), (intptr_t)outer, (intptr_t)name, bucket); + } + return static_cast(etype); +} + +/* PArray *****************************************************************/ + +IMPLEMENT_POINTY_CLASS(PArray) + DECLARE_POINTER(ElementType) +END_POINTERS + +//========================================================================== +// +// PArray - Default Constructor +// +//========================================================================== + +PArray::PArray() +: ElementType(NULL), ElementCount(0) +{ +} + +//========================================================================== +// +// PArray - Parameterized Constructor +// +//========================================================================== + +PArray::PArray(PType *etype, unsigned int ecount) +: ElementType(etype), ElementCount(ecount) +{ + Align = etype->Align; + // Since we are concatenating elements together, the element size should + // also be padded to the nearest alignment. + ElementSize = (etype->Size + (etype->Align - 1)) & ~(etype->Align - 1); + Size = ElementSize * ecount; +} + +//========================================================================== +// +// PArray :: IsMatch +// +//========================================================================== + +bool PArray::IsMatch(intptr_t id1, intptr_t id2) const +{ + const PType *elemtype = (const PType *)id1; + unsigned int count = (unsigned int)(intptr_t)id2; + + return elemtype == ElementType && count == ElementCount; +} + +//========================================================================== +// +// PArray :: GetTypeIDs +// +//========================================================================== + +void PArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +{ + id1 = (intptr_t)ElementType; + id2 = ElementCount; +} + +//========================================================================== +// +// NewArray +// +// Returns a PArray for the given type and size, making sure not to create +// duplicates. +// +//========================================================================== + +PArray *NewArray(PType *type, unsigned int count) +{ + size_t bucket; + PType *atype = TypeTable.FindType(RUNTIME_CLASS(PArray), (intptr_t)type, count, &bucket); + if (atype == NULL) + { + atype = new PArray(type, count); + TypeTable.AddType(atype, RUNTIME_CLASS(PArray), (intptr_t)type, count, bucket); + } + return (PArray *)atype; +} + +/* PVector ****************************************************************/ + +IMPLEMENT_CLASS(PVector) + +//========================================================================== +// +// PVector - Default Constructor +// +//========================================================================== + +PVector::PVector() +: PArray(TypeFloat32, 3) +{ +} + +//========================================================================== +// +// PVector - Parameterized Constructor +// +//========================================================================== + +PVector::PVector(unsigned int size) +: PArray(TypeFloat32, size) +{ + assert(size >= 2 && size <= 4); +} + +//========================================================================== +// +// NewVector +// +// Returns a PVector with the given dimension, making sure not to create +// duplicates. +// +//========================================================================== + +PVector *NewVector(unsigned int size) +{ + size_t bucket; + PType *type = TypeTable.FindType(RUNTIME_CLASS(PVector), (intptr_t)TypeFloat32, size, &bucket); + if (type == NULL) + { + type = new PVector(size); + TypeTable.AddType(type, RUNTIME_CLASS(PVector), (intptr_t)TypeFloat32, size, bucket); + } + return (PVector *)type; +} + +/* PDynArray **************************************************************/ + +IMPLEMENT_POINTY_CLASS(PDynArray) + DECLARE_POINTER(ElementType) +END_POINTERS + +//========================================================================== +// +// PDynArray - Default Constructor +// +//========================================================================== + +PDynArray::PDynArray() +: ElementType(NULL) +{ + Size = sizeof(FArray); + Align = __alignof(FArray); +} + +//========================================================================== +// +// PDynArray - Parameterized Constructor +// +//========================================================================== + +PDynArray::PDynArray(PType *etype) +: ElementType(etype) +{ + Size = sizeof(FArray); + Align = __alignof(FArray); +} + +//========================================================================== +// +// PDynArray :: IsMatch +// +//========================================================================== + +bool PDynArray::IsMatch(intptr_t id1, intptr_t id2) const +{ + assert(id2 == 0); + const PType *elemtype = (const PType *)id1; + + return elemtype == ElementType; +} + +//========================================================================== +// +// PDynArray :: GetTypeIDs +// +//========================================================================== + +void PDynArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +{ + id1 = (intptr_t)ElementType; + id2 = 0; +} + +//========================================================================== +// +// NewDynArray +// +// Creates a new DynArray of the given type, making sure not to create a +// duplicate. +// +//========================================================================== + +PDynArray *NewDynArray(PType *type) +{ + size_t bucket; + PType *atype = TypeTable.FindType(RUNTIME_CLASS(PDynArray), (intptr_t)type, 0, &bucket); + if (atype == NULL) + { + atype = new PDynArray(type); + TypeTable.AddType(atype, RUNTIME_CLASS(PDynArray), (intptr_t)type, 0, bucket); + } + return (PDynArray *)atype; +} + +/* PMap *******************************************************************/ + +IMPLEMENT_POINTY_CLASS(PMap) + DECLARE_POINTER(KeyType) + DECLARE_POINTER(ValueType) +END_POINTERS + +//========================================================================== +// +// PMap - Default Constructor +// +//========================================================================== + +PMap::PMap() +: KeyType(NULL), ValueType(NULL) +{ + Size = sizeof(FMap); + Align = __alignof(FMap); +} + +//========================================================================== +// +// PMap - Parameterized Constructor +// +//========================================================================== + +PMap::PMap(PType *keytype, PType *valtype) +: KeyType(keytype), ValueType(valtype) +{ + Size = sizeof(FMap); + Align = __alignof(FMap); +} + +//========================================================================== +// +// PMap :: IsMatch +// +//========================================================================== + +bool PMap::IsMatch(intptr_t id1, intptr_t id2) const +{ + const PType *keyty = (const PType *)id1; + const PType *valty = (const PType *)id2; + + return keyty == KeyType && valty == ValueType; +} + +//========================================================================== +// +// PMap :: GetTypeIDs +// +//========================================================================== + +void PMap::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +{ + id1 = (intptr_t)KeyType; + id2 = (intptr_t)ValueType; +} + +//========================================================================== +// +// NewMap +// +// Returns a PMap for the given key and value types, ensuring not to create +// duplicates. +// +//========================================================================== + +PMap *NewMap(PType *keytype, PType *valuetype) +{ + size_t bucket; + PType *maptype = TypeTable.FindType(RUNTIME_CLASS(PMap), (intptr_t)keytype, (intptr_t)valuetype, &bucket); + if (maptype == NULL) + { + maptype = new PMap(keytype, valuetype); + TypeTable.AddType(maptype, RUNTIME_CLASS(PMap), (intptr_t)keytype, (intptr_t)valuetype, bucket); + } + return (PMap *)maptype; +} + +/* PStruct ****************************************************************/ + +IMPLEMENT_CLASS(PStruct) + +//========================================================================== +// +// PStruct - Default Constructor +// +//========================================================================== + +PStruct::PStruct() +{ +} + +//========================================================================== +// +// PStruct - Parameterized Constructor +// +//========================================================================== + +PStruct::PStruct(FName name, DObject *outer) +: PNamedType(name, outer) +{ +} + +//========================================================================== +// +// PStruct :: AddField +// +// Appends a new field to the end of a struct. Returns either the new field +// or NULL if a symbol by that name already exists. +// +//========================================================================== + +PField *PStruct::AddField(FName name, PType *type, DWORD flags) +{ + PField *field = new PField(name, type); + + // The new field is added to the end of this struct, alignment permitting. + field->Offset = (Size + (type->Align - 1)) & ~(type->Align - 1); + + // Enlarge this struct to enclose the new field. + Size = field->Offset + type->Size; + + // This struct's alignment is the same as the largest alignment of any of + // its fields. + Align = MAX(Align, type->Align); + + if (Symbols.AddSymbol(field) == NULL) + { // name is already in use + delete field; + return NULL; + } + Fields.Push(field); + + return field; +} + +//========================================================================== +// +// PStruct :: PropagateMark +// +//========================================================================== + +size_t PStruct::PropagateMark() +{ + GC::MarkArray(Fields); + return Fields.Size() * sizeof(void*) + Super::PropagateMark(); +} + +//========================================================================== +// +// NewStruct +// Returns a PStruct for the given name and container, making sure not to +// create duplicates. +// +//========================================================================== + +PStruct *NewStruct(FName name, DObject *outer) +{ + size_t bucket; + PType *stype = TypeTable.FindType(RUNTIME_CLASS(PStruct), (intptr_t)outer, (intptr_t)name, &bucket); + if (stype == NULL) + { + stype = new PStruct(name, outer); + TypeTable.AddType(stype, RUNTIME_CLASS(PStruct), (intptr_t)outer, (intptr_t)name, bucket); + } + return static_cast(stype); +} + +/* PField *****************************************************************/ + +IMPLEMENT_CLASS(PField) + +//========================================================================== +// +// PField - Default Constructor +// +//========================================================================== + +PField::PField() +: PSymbol(NAME_None), Offset(0), Type(NULL), Flags(0) +{ +} + +/* PPrototype *************************************************************/ + +IMPLEMENT_CLASS(PPrototype) + +//========================================================================== +// +// PPrototype - Default Constructor +// +//========================================================================== + +PPrototype::PPrototype() +{ +} + +//========================================================================== +// +// PPrototype - Parameterized Constructor +// +//========================================================================== + +PPrototype::PPrototype(const TArray &rettypes, const TArray &argtypes) +: ArgumentTypes(argtypes), ReturnTypes(rettypes) +{ +} + +//========================================================================== +// +// PPrototype :: IsMatch +// +//========================================================================== + +bool PPrototype::IsMatch(intptr_t id1, intptr_t id2) const +{ + const TArray *args = (const TArray *)id1; + const TArray *rets = (const TArray *)id2; + + return *args == ArgumentTypes && *rets == ReturnTypes; +} + +//========================================================================== +// +// PPrototype :: GetTypeIDs +// +//========================================================================== + +void PPrototype::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +{ + id1 = (intptr_t)&ArgumentTypes; + id2 = (intptr_t)&ReturnTypes; +} + +//========================================================================== +// +// PPrototype :: PropagateMark +// +//========================================================================== + +size_t PPrototype::PropagateMark() +{ + GC::MarkArray(ArgumentTypes); + GC::MarkArray(ReturnTypes); + return (ArgumentTypes.Size() + ReturnTypes.Size()) * sizeof(void*) + + Super::PropagateMark(); +} + +//========================================================================== +// +// NewPrototype +// +// Returns a PPrototype for the given return and argument types, making sure +// not to create duplicates. +// +//========================================================================== + +PPrototype *NewPrototype(const TArray &rettypes, const TArray &argtypes) +{ + size_t bucket; + PType *proto = TypeTable.FindType(RUNTIME_CLASS(PPrototype), (intptr_t)&argtypes, (intptr_t)&rettypes, &bucket); + if (proto == NULL) + { + proto = new PPrototype(rettypes, argtypes); + TypeTable.AddType(proto, RUNTIME_CLASS(PPrototype), (intptr_t)&argtypes, (intptr_t)&rettypes, bucket); + } + return static_cast(proto); +} + +/* PFunction **************************************************************/ + +IMPLEMENT_CLASS(PFunction) + +//========================================================================== +// +// PFunction :: PropagataMark +// +//========================================================================== + +size_t PFunction::PropagateMark() +{ + for (unsigned i = 0; i < Variants.Size(); ++i) + { + GC::Mark(Variants[i].Proto); + GC::Mark(Variants[i].Implementation); + } + return Variants.Size() * sizeof(Variants[0]) + Super::PropagateMark(); +} + +//========================================================================== +// +// PFunction :: AddVariant +// +// Adds a new variant for this function. Does not check if a matching +// variant already exists. +// +//========================================================================== + +unsigned PFunction::AddVariant(PPrototype *proto, TArray &argflags, VMFunction *impl) +{ + Variant variant; + + variant.Proto = proto; + variant.ArgFlags = argflags; + variant.Implementation = impl; + return Variants.Push(variant); +} + +/* PClass *****************************************************************/ + +IMPLEMENT_POINTY_CLASS(PClass) + DECLARE_POINTER(ParentClass) +END_POINTERS + +//========================================================================== +// +// cregcmp +// +// Sorter to keep built-in types in a deterministic order. (Needed?) +// +//========================================================================== + static int STACK_ARGS cregcmp (const void *a, const void *b) { - // VC++ introduces NULLs in the sequence. GCC seems to work as expected and not do it. - const ClassReg *class1 = *(const ClassReg **)a; - const ClassReg *class2 = *(const ClassReg **)b; - if (class1 == NULL) return 1; - if (class2 == NULL) return -1; - return strcmp (class1->Name, class2->Name); + const PClass *class1 = *(const PClass **)a; + const PClass *class2 = *(const PClass **)b; + return strcmp(class1->TypeName, class2->TypeName); } +//========================================================================== +// +// PClass :: StaticInit STATIC +// +// Creates class metadata for all built-in types. +// +//========================================================================== + void PClass::StaticInit () { atterm (StaticShutdown); - // Sort classes by name to remove dependance on how the compiler ordered them. - REGINFO *head = &CRegHead; - REGINFO *tail = &CRegTail; - - // MinGW's linker is linking the object files backwards for me now... - if (head > tail) - { - swapvalues (head, tail); - } - qsort (head + 1, tail - head - 1, sizeof(REGINFO), cregcmp); + StaticBootstrap(); FAutoSegIterator probe(CRegHead, CRegTail); @@ -78,35 +2013,31 @@ void PClass::StaticInit () { ((ClassReg *)*probe)->RegisterClass (); } + + // Keep built-in classes in consistant order. I did this before, though + // I'm not sure if this is really necessary to maintain any sort of sync. + qsort(&AllClasses[0], AllClasses.Size(), sizeof(AllClasses[0]), cregcmp); } -void PClass::ClearRuntimeData () -{ - StaticShutdown(); - - m_RuntimeActors.Clear(); - m_Types.Clear(); - memset(TypeHash, 0, sizeof(TypeHash)); - bShutdown = false; - - // Immediately reinitialize the internal classes - FAutoSegIterator probe(CRegHead, CRegTail); - - while (*++probe != NULL) - { - ((ClassReg *)*probe)->RegisterClass (); - } -} +//========================================================================== +// +// PClass :: StaticShutdown STATIC +// +// Frees FlatPointers belonging to all classes. Only really needed to avoid +// memory leak warnings at exit. +// +//========================================================================== void PClass::StaticShutdown () { TArray uniqueFPs(64); unsigned int i, j; - for (i = 0; i < PClass::m_Types.Size(); ++i) + FS_Close(); // this must be done before the classes get deleted. + for (i = 0; i < PClass::AllClasses.Size(); ++i) { - PClass *type = PClass::m_Types[i]; - PClass::m_Types[i] = NULL; + PClass *type = PClass::AllClasses[i]; + PClass::AllClasses[i] = NULL; if (type->FlatPointers != &TheEnd && type->FlatPointers != type->Pointers) { // FlatPointers are shared by many classes, so we must check for @@ -123,137 +2054,218 @@ void PClass::StaticShutdown () uniqueFPs.Push(const_cast(type->FlatPointers)); } } - type->FlatPointers = NULL; - - // For runtime classes, this call will also delete the PClass. - PClass::StaticFreeData (type); } for (i = 0; i < uniqueFPs.Size(); ++i) { delete[] uniqueFPs[i]; } + TypeTable.Clear(); bShutdown = true; + + AllClasses.Clear(); + PClassActor::AllActorClasses.Clear(); + + FAutoSegIterator probe(CRegHead, CRegTail); + + while (*++probe != NULL) + { + ((ClassReg *)*probe)->MyClass = NULL; + } + } -void PClass::StaticFreeData (PClass *type) -{ - if (type->Defaults != NULL) - { - M_Free(type->Defaults); - type->Defaults = NULL; - } - type->FreeStateList (); +//========================================================================== +// +// PClass :: StaticBootstrap STATIC +// +// PClass and PClassClass have intermingling dependencies on their +// definitions. To sort this out, we explicitly define them before +// proceeding with the RegisterClass loop in StaticInit(). +// +//========================================================================== - if (type->ActorInfo != NULL) +void PClass::StaticBootstrap() +{ + PClassClass *clscls = new PClassClass; + PClassClass::RegistrationInfo.SetupClass(clscls); + + PClassClass *cls = new PClassClass; + PClass::RegistrationInfo.SetupClass(cls); + + // The PClassClass constructor initialized these to NULL, because the + // PClass metadata had not been created yet. Now it has, so we know what + // they should be and can insert them into the type table successfully. + clscls->TypeTableType = cls; + cls->TypeTableType = cls; + clscls->InsertIntoHash(); + cls->InsertIntoHash(); + + // Create parent objects before we go so that these definitions are complete. + clscls->ParentClass = PClassType::RegistrationInfo.ParentType->RegisterClass(); + cls->ParentClass = PClass::RegistrationInfo.ParentType->RegisterClass(); +} + +//========================================================================== +// +// PClass Constructor +// +//========================================================================== + +PClass::PClass() +{ + Size = sizeof(DObject); + ParentClass = NULL; + Pointers = NULL; + FlatPointers = NULL; + HashNext = NULL; + Defaults = NULL; + bRuntimeClass = false; + ConstructNative = NULL; + + PClass::AllClasses.Push(this); +} + +//========================================================================== +// +// PClass Destructor +// +//========================================================================== + +PClass::~PClass() +{ + if (Defaults != NULL) { - if (type->ActorInfo->OwnedStates != NULL) - { - delete[] type->ActorInfo->OwnedStates; - type->ActorInfo->OwnedStates = NULL; - } - if (type->ActorInfo->DamageFactors != NULL) - { - delete type->ActorInfo->DamageFactors; - type->ActorInfo->DamageFactors = NULL; - } - if (type->ActorInfo->PainChances != NULL) - { - delete type->ActorInfo->PainChances; - type->ActorInfo->PainChances = NULL; - } - if (type->ActorInfo->ColorSets != NULL) - { - delete type->ActorInfo->ColorSets; - type->ActorInfo->ColorSets = NULL; - } - delete type->ActorInfo; - type->ActorInfo = NULL; - } - if (type->bRuntimeClass) - { - delete type; - } - else - { - type->Symbols.ReleaseSymbols(); + M_Free(Defaults); + Defaults = NULL; } } -void ClassReg::RegisterClass () const +//========================================================================== +// +// ClassReg :: RegisterClass +// +// Create metadata describing the built-in class this struct is intended +// for. +// +//========================================================================== + +PClass *ClassReg::RegisterClass() { - assert (MyClass != NULL); + static ClassReg *const metaclasses[] = + { + &PClass::RegistrationInfo, + &PClassActor::RegistrationInfo, + &PClassInventory::RegistrationInfo, + &PClassAmmo::RegistrationInfo, + &PClassHealth::RegistrationInfo, + &PClassPuzzleItem::RegistrationInfo, + &PClassWeapon::RegistrationInfo, + &PClassPlayerPawn::RegistrationInfo, + &PClassType::RegistrationInfo, + &PClassClass::RegistrationInfo, + }; + + // Skip classes that have already been registered + if (MyClass != NULL) + { + return MyClass; + } // Add type to list - MyClass->ClassIndex = PClass::m_Types.Push (MyClass); + PClass *cls; - MyClass->TypeName = FName(Name+1); - MyClass->ParentClass = ParentType; - MyClass->Size = SizeOf; - MyClass->Pointers = Pointers; - MyClass->ConstructNative = ConstructNative; - MyClass->InsertIntoHash (); + if (MetaClassNum >= countof(metaclasses)) + { + assert(0 && "Class registry has an invalid meta class identifier"); + } + + if (metaclasses[MetaClassNum]->MyClass == NULL) + { // Make sure the meta class is already registered before registering this one + metaclasses[MetaClassNum]->RegisterClass(); + } + cls = static_cast(metaclasses[MetaClassNum]->MyClass->CreateNew()); + + SetupClass(cls); + cls->InsertIntoHash(); + if (ParentType != NULL) + { + cls->ParentClass = ParentType->RegisterClass(); + } + return cls; } +//========================================================================== +// +// ClassReg :: SetupClass +// +// Copies the class-defining parameters from a ClassReg to the Class object +// created for it. +// +//========================================================================== + +void ClassReg::SetupClass(PClass *cls) +{ + assert(MyClass == NULL); + MyClass = cls; + cls->TypeName = FName(Name+1); + cls->Size = SizeOf; + cls->Pointers = Pointers; + cls->ConstructNative = ConstructNative; +} + +//========================================================================== +// +// PClass :: InsertIntoHash +// +// Add class to the type table. +// +//========================================================================== + void PClass::InsertIntoHash () { - // Add class to hash table. Classes are inserted into each bucket - // in ascending order by name index. - unsigned int bucket = TypeName % HASH_SIZE; - PClass **hashpos = &TypeHash[bucket]; - while (*hashpos != NULL) - { - int lexx = int(TypeName) - int((*hashpos)->TypeName); + size_t bucket; + PType *found; - if (lexx > 0) - { // This type should come later in the chain - hashpos = &((*hashpos)->HashNext); - } - else if (lexx == 0) - { // This type has already been inserted - // ... but there is no need whatsoever to make it a fatal error! - Printf (TEXTCOLOR_RED"Tried to register class '%s' more than once.\n", TypeName.GetChars()); - break; - } - else - { // Type comes right here - break; - } + found = TypeTable.FindType(RUNTIME_CLASS(PClass), (intptr_t)Outer, TypeName, &bucket); + if (found != NULL) + { // This type has already been inserted + // ... but there is no need whatsoever to make it a fatal error! + Printf (TEXTCOLOR_RED"Tried to register class '%s' more than once.\n", TypeName.GetChars()); + TypeTable.ReplaceType(this, found, bucket); + } + else + { + TypeTable.AddType(this, RUNTIME_CLASS(PClass), (intptr_t)Outer, TypeName, bucket); } - HashNext = *hashpos; - *hashpos = this; } -// Find a type, passed the name as a name -const PClass *PClass::FindClass (FName zaname) +//========================================================================== +// +// PClass :: FindClass +// +// Find a type, passed the name as a name. +// +//========================================================================== + +PClass *PClass::FindClass (FName zaname) { if (zaname == NAME_None) { return NULL; } - - PClass *cls = TypeHash[zaname % HASH_SIZE]; - - while (cls != 0) - { - int lexx = int(zaname) - int(cls->TypeName); - if (lexx > 0) - { - cls = cls->HashNext; - } - else if (lexx == 0) - { - return cls; - } - else - { - break; - } - } - return NULL; + return static_cast(TypeTable.FindType(RUNTIME_CLASS(PClass), + /*FIXME:Outer*/0, zaname, NULL)); } +//========================================================================== +// +// PClass :: CreateNew +// // Create a new object that this class represents -DObject *PClass::CreateNew () const +// +//========================================================================== + +DObject *PClass::CreateNew() const { BYTE *mem = (BYTE *)M_Malloc (Size); assert (mem != NULL); @@ -269,8 +2281,39 @@ DObject *PClass::CreateNew () const return (DObject *)mem; } +//========================================================================== +// +// PClass :: Derive +// +// Copies inheritable values into the derived class and other miscellaneous setup. +// +//========================================================================== + +void PClass::Derive(PClass *newclass) +{ + newclass->ParentClass = this; + newclass->ConstructNative = ConstructNative; + + // Set up default instance of the new class. + newclass->Defaults = (BYTE *)M_Malloc(newclass->Size); + if (Defaults) memcpy(newclass->Defaults, Defaults, Size); + if (newclass->Size > Size) + { + memset(newclass->Defaults + Size, 0, newclass->Size - Size); + } + + newclass->Symbols.SetParentTable(&this->Symbols); +} + +//========================================================================== +// +// PClass :: CreateDerivedClass +// // Create a new class based on an existing class -PClass *PClass::CreateDerivedClass (FName name, unsigned int size) +// +//========================================================================== + +PClass *PClass::CreateDerivedClass(FName name, unsigned int size) { assert (size >= Size); PClass *type; @@ -291,61 +2334,31 @@ PClass *PClass::CreateDerivedClass (FName name, unsigned int size) } else { - type = new PClass; + // Create a new type object of the same type as us. (We may be a derived class of PClass.) + type = static_cast(GetClass()->CreateNew()); notnew = false; } type->TypeName = name; - type->ParentClass = this; type->Size = size; - type->Pointers = NULL; - type->ConstructNative = ConstructNative; + type->bRuntimeClass = true; + Derive(type); if (!notnew) { - type->ClassIndex = m_Types.Push (type); - } - type->Meta = Meta; - - // Set up default instance of the new class. - type->Defaults = (BYTE *)M_Malloc(size); - memcpy (type->Defaults, Defaults, Size); - if (size > Size) - { - memset (type->Defaults + Size, 0, size - Size); - } - - type->FlatPointers = NULL; - type->bRuntimeClass = true; - type->ActorInfo = NULL; - type->Symbols.SetParentTable (&this->Symbols); - if (!notnew) type->InsertIntoHash(); - - // If this class has an actor info, then any classes derived from it - // also need an actor info. - if (this->ActorInfo != NULL) - { - FActorInfo *info = type->ActorInfo = new FActorInfo; - info->Class = type; - info->GameFilter = GAME_Any; - info->SpawnID = 0; - info->ConversationID = 0; - info->DoomEdNum = -1; - info->OwnedStates = NULL; - info->NumOwnedStates = 0; - info->Replacement = NULL; - info->Replacee = NULL; - info->StateList = NULL; - info->DamageFactors = NULL; - info->PainChances = NULL; - info->PainFlashes = NULL; - info->ColorSets = NULL; - m_RuntimeActors.Push (type); + type->InsertIntoHash(); } return type; } -// Add bytes to the end of this class. Returns the -// previous size of the class. +//========================================================================== +// +// PClass:: Extend +// +// Add bytes to the end of this class. Returns the previous +// size of the class. +// +//========================================================================== + unsigned int PClass::Extend(unsigned int extension) { assert(this->bRuntimeClass); @@ -357,92 +2370,53 @@ unsigned int PClass::Extend(unsigned int extension) return oldsize; } -// Like FindClass but creates a placeholder if no class -// is found. CreateDerivedClass will automatically fill -// in the placeholder when the actual class is defined. -const PClass *PClass::FindClassTentative (FName name) +//========================================================================== +// +// PClass :: FindClassTentative +// +// Like FindClass but creates a placeholder if no class is found. +// CreateDerivedClass will automatically fill in the placeholder when the +// actual class is defined. +// +//========================================================================== + +PClass *PClass::FindClassTentative(FName name) { if (name == NAME_None) { return NULL; } + size_t bucket; - PClass *cls = TypeHash[name % HASH_SIZE]; + PType *found = TypeTable.FindType(RUNTIME_CLASS(PClass), + /*FIXME:Outer*/0, name, &bucket); - while (cls != 0) + if (found != NULL) { - int lexx = int(name) - int(cls->TypeName); - if (lexx > 0) - { - cls = cls->HashNext; - } - else if (lexx == 0) - { - return cls; - } - else - { - break; - } + return static_cast(found); } - PClass *type = new PClass; + PClass *type = static_cast(GetClass()->CreateNew()); DPrintf("Creating placeholder class %s : %s\n", name.GetChars(), TypeName.GetChars()); type->TypeName = name; type->ParentClass = this; type->Size = -1; - type->Pointers = NULL; - type->ConstructNative = NULL; - type->ClassIndex = m_Types.Push (type); - type->Defaults = NULL; - type->FlatPointers = NULL; type->bRuntimeClass = true; - type->ActorInfo = NULL; - type->InsertIntoHash(); + TypeTable.AddType(type, RUNTIME_CLASS(PClass), (intptr_t)type->Outer, name, bucket); return type; } -// This is used by DECORATE to assign ActorInfos to internal classes -void PClass::InitializeActorInfo () -{ - Symbols.SetParentTable (&ParentClass->Symbols); - Defaults = (BYTE *)M_Malloc(Size); - if (ParentClass->Defaults != NULL) - { - memcpy (Defaults, ParentClass->Defaults, ParentClass->Size); - if (Size > ParentClass->Size) - { - memset (Defaults + ParentClass->Size, 0, Size - ParentClass->Size); - } - } - else - { - memset (Defaults, 0, Size); - } - - FActorInfo *info = ActorInfo = new FActorInfo; - info->Class = this; - info->GameFilter = GAME_Any; - info->SpawnID = 0; - info->ConversationID = 0; - info->DoomEdNum = -1; - info->OwnedStates = NULL; - info->NumOwnedStates = 0; - info->Replacement = NULL; - info->Replacee = NULL; - info->StateList = NULL; - info->DamageFactors = NULL; - info->PainChances = NULL; - info->PainFlashes = NULL; - info->ColorSets = NULL; - m_RuntimeActors.Push (this); -} - - +//========================================================================== +// +// PClass :: BuildFlatPointers +// // Create the FlatPointers array, if it doesn't exist already. -// It comprises all the Pointers from superclasses plus this class's own Pointers. -// If this class does not define any new Pointers, then FlatPointers will be set -// to the same array as the super class's. +// It comprises all the Pointers from superclasses plus this class's own +// Pointers. If this class does not define any new Pointers, then +// FlatPointers will be set to the same array as the super class. +// +//========================================================================== + void PClass::BuildFlatPointers () { if (FlatPointers != NULL) @@ -490,15 +2464,13 @@ void PClass::BuildFlatPointers () } } -void PClass::FreeStateList () -{ - if (ActorInfo != NULL && ActorInfo->StateList != NULL) - { - ActorInfo->StateList->Destroy(); - M_Free (ActorInfo->StateList); - ActorInfo->StateList = NULL; - } -} +//========================================================================== +// +// PClass :: NativeClass +// +// Finds the underlying native type underlying this class. +// +//========================================================================== const PClass *PClass::NativeClass() const { @@ -510,28 +2482,228 @@ const PClass *PClass::NativeClass() const return cls; } -PClass *PClass::GetReplacement() const +/* FTypeTable **************************************************************/ + +//========================================================================== +// +// FTypeTable :: FindType +// +//========================================================================== + +PType *FTypeTable::FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, size_t *bucketnum) { - return ActorInfo->GetReplacement()->Class; + size_t bucket = Hash(metatype, parm1, parm2) % HASH_SIZE; + if (bucketnum != NULL) + { + *bucketnum = bucket; + } + for (PType *type = TypeHash[bucket]; type != NULL; type = type->HashNext) + { + if (type->GetClass()->TypeTableType == metatype && type->IsMatch(parm1, parm2)) + { + return type; + } + } + return NULL; +} + +//========================================================================== +// +// FTypeTable :: ReplaceType +// +// Replaces an existing type in the table with a new version of the same +// type. For use when redefining actors in DECORATE. Does nothing if the +// old version is not in the table. +// +//========================================================================== + +void FTypeTable::ReplaceType(PType *newtype, PType *oldtype, size_t bucket) +{ + for (PType **type_p = &TypeHash[bucket]; *type_p != NULL; type_p = &(*type_p)->HashNext) + { + PType *type = *type_p; + if (type == oldtype) + { + newtype->HashNext = type->HashNext; + type->HashNext = NULL; + *type_p = newtype; + break; + } + } +} + +//========================================================================== +// +// FTypeTable :: AddType - Fully Parameterized Version +// +//========================================================================== + +void FTypeTable::AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t parm2, size_t bucket) +{ +#ifdef _DEBUG + size_t bucketcheck; + assert(metatype == type->GetClass()->TypeTableType && "Metatype does not match passed object"); + assert(FindType(metatype, parm1, parm2, &bucketcheck) == NULL && "Type must not be inserted more than once"); + assert(bucketcheck == bucket && "Passed bucket was wrong"); +#endif + type->HashNext = TypeHash[bucket]; + TypeHash[bucket] = type; + GC::WriteBarrier(type); +} + +//========================================================================== +// +// FTypeTable :: AddType - Simple Version +// +//========================================================================== + +void FTypeTable::AddType(PType *type) +{ + PClass *metatype; + intptr_t parm1, parm2; + size_t bucket; + + metatype = type->GetClass()->TypeTableType; + type->GetTypeIDs(parm1, parm2); + bucket = Hash(metatype, parm1, parm2) % HASH_SIZE; + assert(FindType(metatype, parm1, parm2, NULL) == NULL && "Type must not be inserted more than once"); + + type->HashNext = TypeHash[bucket]; + TypeHash[bucket] = type; + GC::WriteBarrier(type); +} + +//========================================================================== +// +// FTypeTable :: Hash STATIC +// +//========================================================================== + +size_t FTypeTable::Hash(const PClass *p1, intptr_t p2, intptr_t p3) +{ + size_t i1 = (size_t)p1; + + // Swap the high and low halves of i1. The compiler should be smart enough + // to transform this into a ROR or ROL. + i1 = (i1 >> (sizeof(size_t)*4)) | (i1 << (sizeof(size_t)*4)); + + if (p1 != RUNTIME_CLASS(PPrototype)) + { + size_t i2 = (size_t)p2; + size_t i3 = (size_t)p3; + return (~i1 ^ i2) + i3 * 961748927; // i3 is multiplied by a prime + } + else + { // Prototypes need to hash the TArrays at p2 and p3 + const TArray *a2 = (const TArray *)p2; + const TArray *a3 = (const TArray *)p3; + for (unsigned i = 0; i < a2->Size(); ++i) + { + i1 = (i1 * 961748927) + (size_t)((*a2)[i]); + } + for (unsigned i = 0; i < a3->Size(); ++i) + { + i1 = (i1 * 961748927) + (size_t)((*a3)[i]); + } + return i1; + } +} + +//========================================================================== +// +// FTypeTable :: Mark +// +// Mark all types in this table for the garbage collector. +// +//========================================================================== + +void FTypeTable::Mark() +{ + for (int i = HASH_SIZE - 1; i >= 0; --i) + { + if (TypeHash[i] != NULL) + { + GC::Mark(TypeHash[i]); + } + } +} + +//========================================================================== +// +// FTypeTable :: Clear +// +// Removes everything from the table. We let the garbage collector worry +// about deleting them. +// +//========================================================================== + +void FTypeTable::Clear() +{ + memset(TypeHash, 0, sizeof(TypeHash)); +} + +#include "c_dispatch.h" +CCMD(typetable) +{ + DumpTypeTable(); } // Symbol tables ------------------------------------------------------------ +IMPLEMENT_ABSTRACT_CLASS(PSymbol); +IMPLEMENT_CLASS(PSymbolConst); +IMPLEMENT_CLASS(PSymbolConstNumeric); +IMPLEMENT_CLASS(PSymbolConstString); +IMPLEMENT_POINTY_CLASS(PSymbolType) + DECLARE_POINTER(Type) +END_POINTERS +IMPLEMENT_POINTY_CLASS(PSymbolVMFunction) + DECLARE_POINTER(Function) +END_POINTERS + +//========================================================================== +// +// +// +//========================================================================== + PSymbol::~PSymbol() { } +PSymbolTable::PSymbolTable() +: ParentSymbolTable(NULL) +{ +} + +PSymbolTable::PSymbolTable(PSymbolTable *parent) +: ParentSymbolTable(parent) +{ +} + PSymbolTable::~PSymbolTable () { ReleaseSymbols(); } +size_t PSymbolTable::MarkSymbols() +{ + size_t count = 0; + MapType::Iterator it(Symbols); + MapType::Pair *pair; + + while (it.NextPair(pair)) + { + GC::Mark(pair->Value); + count++; + } + return count * sizeof(*pair); +} + void PSymbolTable::ReleaseSymbols() { - for (unsigned int i = 0; i < Symbols.Size(); ++i) - { - delete Symbols[i]; - } + // The GC will take care of deleting the symbols. We just need to + // clear our references to them. Symbols.Clear(); } @@ -542,64 +2714,21 @@ void PSymbolTable::SetParentTable (PSymbolTable *parent) PSymbol *PSymbolTable::FindSymbol (FName symname, bool searchparents) const { - int min, max; - - min = 0; - max = (int)Symbols.Size() - 1; - - while (min <= max) + PSymbol * const *value = Symbols.CheckKey(symname); + if (value == NULL && searchparents && ParentSymbolTable != NULL) { - unsigned int mid = (min + max) / 2; - PSymbol *sym = Symbols[mid]; - - if (sym->SymbolName == symname) - { - return sym; - } - else if (sym->SymbolName < symname) - { - min = mid + 1; - } - else - { - max = mid - 1; - } + return ParentSymbolTable->FindSymbol(symname, searchparents); } - if (searchparents && ParentSymbolTable != NULL) - { - return ParentSymbolTable->FindSymbol (symname, true); - } - return NULL; + return value != NULL ? *value : NULL; } PSymbol *PSymbolTable::AddSymbol (PSymbol *sym) { - // Insert it in sorted order. - int min, max, mid; - - min = 0; - max = (int)Symbols.Size() - 1; - - while (min <= max) + // Symbols that already exist are not inserted. + if (Symbols.CheckKey(sym->SymbolName) != NULL) { - mid = (min + max) / 2; - PSymbol *tsym = Symbols[mid]; - - if (tsym->SymbolName == sym->SymbolName) - { // A symbol with this name already exists in the table - return NULL; - } - else if (tsym->SymbolName < sym->SymbolName) - { - min = mid + 1; - } - else - { - max = mid - 1; - } + return NULL; } - - // Good. The symbol is not in the table yet. - Symbols.Insert (MAX(min, max), sym); + Symbols.Insert(sym->SymbolName, sym); return sym; } diff --git a/src/dobjtype.h b/src/dobjtype.h index 256e52ad83..313130ddba 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -6,95 +6,78 @@ #endif #include "thingdef/thingdef_type.h" +#include "vm.h" + +// Variable/parameter/field flags ------------------------------------------- + +// Making all these different storage types use a common set of flags seems +// like the simplest thing to do. + +#define VARF_Optional (1<<0) // func param is optional +#define VARF_Method (1<<1) // func has an implied self parameter +#define VARF_Action (1<<2) // func has implied owner and state parameters +#define VARF_Native (1<<3) // func is native code/don't auto serialize field // Symbol information ------------------------------------------------------- -enum ESymbolType -{ - SYM_Const, - SYM_Variable, - SYM_ActionFunction -}; - -struct PSymbol +class PSymbol : public DObject { + DECLARE_ABSTRACT_CLASS(PSymbol, DObject); +public: virtual ~PSymbol(); - ESymbolType SymbolType; FName SymbolName; protected: - PSymbol(FName name, ESymbolType type) { SymbolType = type; SymbolName = name; } -}; - -// A constant value --------------------------------------------------------- - -struct PSymbolConst : public PSymbol -{ - int ValueType; - union - { - int Value; - double Float; - }; - - PSymbolConst(FName name) : PSymbol(name, SYM_Const) {} -}; - -// A variable --------------------------------------------------------- - -struct PSymbolVariable : public PSymbol -{ - FExpressionType ValueType; - //int size; - intptr_t offset; - bool bUserVar; - - PSymbolVariable(FName name) : PSymbol(name, SYM_Variable) {} + PSymbol(FName name) { SymbolName = name; } }; // An action function ------------------------------------------------------- -// -// The Arguments string is a string of characters as understood by -// the DECORATE parser: -// -// If the letter is uppercase, it is required. Lowercase letters are optional. -// i = integer -// f = fixed point -// s = sound name -// m = actor name -// t = string -// l = jump label -// c = color -// x = expression -// y = expression -// If the final character is a +, the previous parameter is repeated indefinitely, -// and an "imaginary" first parameter is inserted containing the total number of -// parameters passed. + struct FState; struct StateCallData; -typedef void (*actionf_p)(AActor *self, AActor *stateowner, FState *state, int parameters, StateCallData *statecall); +class VMFrameStack; +struct VMValue; +struct VMReturn; +typedef int (*actionf_p)(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret);/*(VM_ARGS)*/ +class VMFunction; -struct PSymbolActionFunction : public PSymbol +// A VM function ------------------------------------------------------------ + +class PSymbolVMFunction : public PSymbol { - FString Arguments; - actionf_p Function; - int defaultparameterindex; + DECLARE_CLASS(PSymbolVMFunction, PSymbol); + HAS_OBJECT_POINTERS; +public: + VMFunction *Function; - PSymbolActionFunction(FName name) : PSymbol(name, SYM_ActionFunction) {} + PSymbolVMFunction(FName name) : PSymbol(name) {} + PSymbolVMFunction() : PSymbol(NAME_None) {} +}; + +// A symbol for a type ------------------------------------------------------ + +class PSymbolType : public PSymbol +{ + DECLARE_CLASS(PSymbolType, PSymbol); + HAS_OBJECT_POINTERS; +public: + class PType *Type; + + PSymbolType(FName name, class PType *ty) : PSymbol(name), Type(ty) {} + PSymbolType() : PSymbol(NAME_None) {} }; // A symbol table ----------------------------------------------------------- -class PSymbolTable +struct PSymbolTable { -public: - PSymbolTable() : ParentSymbolTable(NULL) - { - } - + PSymbolTable(); + PSymbolTable(PSymbolTable *parent); ~PSymbolTable(); + size_t MarkSymbols(); + // Sets the table to use for searches if this one doesn't contain the // requested symbol. void SetParentTable (PSymbolTable *parent); @@ -112,49 +95,549 @@ public: void ReleaseSymbols(); private: + typedef TMap MapType; + PSymbolTable *ParentSymbolTable; - TArray Symbols; + MapType Symbols; friend class DObject; }; +extern PSymbolTable GlobalSymbols; + +// Basic information shared by all types ------------------------------------ + +// Only one copy of a type is ever instantiated at one time. +// - Enums, classes, and structs are defined by their names and outer classes. +// - Pointers are uniquely defined by the type they point at. +// - ClassPointers are also defined by their class restriction. +// - Arrays are defined by their element type and count. +// - DynArrays are defined by their element type. +// - Maps are defined by their key and value types. +// - Prototypes are defined by the argument and return types. +// - Functions are defined by their names and outer objects. +// In table form: +// Outer Name Type Type2 Count +// Enum * * +// Class * * +// Struct * * +// Function * * +// Pointer * +// ClassPointer + * +// Array * * +// DynArray * +// Map * * +// Prototype *+ *+ + +struct ZCC_ExprConstant; +class PClassType; +class PType : public DObject +{ + //DECLARE_ABSTRACT_CLASS_WITH_META(PType, DObject, PClassType); + // We need to unravel the _WITH_META macro, since PClassType isn't defined yet, + // and we can't define it until we've defined PClass. But we can't define that + // without defining PType. + DECLARE_ABSTRACT_CLASS(PType, DObject) + HAS_OBJECT_POINTERS; +protected: + enum { MetaClassNum = CLASSREG_PClassType }; +public: + typedef PClassType MetaClass; + MetaClass *GetClass() const; + + struct Conversion + { + Conversion(PType *target, void (*convert)(ZCC_ExprConstant *, class FSharedStringArena &)) + : TargetType(target), ConvertConstant(convert) {} + + PType *TargetType; + void (*ConvertConstant)(ZCC_ExprConstant *val, class FSharedStringArena &strdump); + }; + + unsigned int Size; // this type's size + unsigned int Align; // this type's preferred alignment + PType *HashNext; // next type in this type table + PSymbolTable Symbols; + + PType(); + PType(unsigned int size, unsigned int align); + virtual ~PType(); + + bool AddConversion(PType *target, void (*convertconst)(ZCC_ExprConstant *, class FSharedStringArena &)); + + int FindConversion(PType *target, const Conversion **slots, int numslots); + + // Sets the value of a variable of this type at (addr) + virtual void SetValue(void *addr, int val); + + // Gets the value of a variable of this type at (addr) + virtual int GetValueInt(void *addr) const; + + // Gets the opcode to store from a register to memory + virtual int GetStoreOp() const; + + // Gets the opcode to load from memory to a register + virtual int GetLoadOp() const; + + // Gets the register type for this type + virtual int GetRegType() const; + + // Returns true if this type matches the two identifiers. Referring to the + // above table, any type is identified by at most two characteristics. Each + // type that implements this function will cast these to the appropriate type. + // It is up to the caller to make sure they are the correct types. There is + // only one prototype for this function in order to simplify type table + // management. + virtual bool IsMatch(intptr_t id1, intptr_t id2) const; + + // Get the type IDs used by IsMatch + virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; + + size_t PropagateMark(); + + static void StaticInit(); + +private: + // Stuff for type conversion searches + class VisitQueue + { + public: + VisitQueue() : In(0), Out(0) {} + void Push(PType *type); + PType *Pop(); + bool IsEmpty() { return In == Out; } + + private: + // This is a fixed-sized ring buffer. + PType *Queue[64]; + int In, Out; + + void Advance(int &ptr) + { + ptr = (ptr + 1) & (countof(Queue) - 1); + } + }; + + class VisitedNodeSet + { + public: + VisitedNodeSet() { memset(Buckets, 0, sizeof(Buckets)); } + void Insert(PType *node); + bool Check(const PType *node); + + private: + PType *Buckets[32]; + + size_t Hash(const PType *type) { return size_t(type) >> 4; } + }; + + TArray Conversions; + PType *PredType; + PType *VisitNext; + short PredConv; + short Distance; + + void MarkPred(PType *pred, int conv, int dist) + { + PredType = pred; + PredConv = conv; + Distance = dist; + } + void FillConversionPath(const Conversion **slots); +}; + +// Not-really-a-type types -------------------------------------------------- + +class PErrorType : public PType +{ + DECLARE_CLASS(PErrorType, PType); +public: + PErrorType() : PType(0, 1) {} +}; + +class PVoidType : public PType +{ + DECLARE_CLASS(PVoidType, PType); +public: + PVoidType() : PType(0, 1) {} +}; + +// Some categorization typing ----------------------------------------------- + +class PBasicType : public PType +{ + DECLARE_ABSTRACT_CLASS(PBasicType, PType); +public: + PBasicType(); + PBasicType(unsigned int size, unsigned int align); +}; + +class PCompoundType : public PType +{ + DECLARE_ABSTRACT_CLASS(PCompoundType, PType); +}; + +class PNamedType : public PCompoundType +{ + DECLARE_ABSTRACT_CLASS(PNamedType, PCompoundType); + HAS_OBJECT_POINTERS; +public: + DObject *Outer; // object this type is contained within + FName TypeName; // this type's name + + PNamedType() : Outer(NULL) {} + PNamedType(FName name, DObject *outer) : Outer(outer), TypeName(name) {} + + virtual bool IsMatch(intptr_t id1, intptr_t id2) const; + virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; +}; + +// Basic types -------------------------------------------------------------- + +class PInt : public PBasicType +{ + DECLARE_CLASS(PInt, PBasicType); +public: + PInt(unsigned int size, bool unsign); + + virtual void SetValue(void *addr, int val); + virtual int GetValueInt(void *addr) const; + virtual int GetStoreOp() const; + virtual int GetLoadOp() const; + virtual int GetRegType() const; + + bool Unsigned; +protected: + PInt(); +}; + +class PBool : public PInt +{ + DECLARE_CLASS(PBool, PInt); +public: + PBool(); +}; + +class PFloat : public PBasicType +{ + DECLARE_CLASS(PFloat, PBasicType); +public: + PFloat(unsigned int size); + + virtual void SetValue(void *addr, int val); + virtual int GetValueInt(void *addr) const; + virtual int GetStoreOp() const; + virtual int GetLoadOp() const; + virtual int GetRegType() const; +protected: + PFloat(); +private: + struct SymbolInitF + { + ENamedName Name; + double Value; + }; + struct SymbolInitI + { + ENamedName Name; + int Value; + }; + + void SetSingleSymbols(); + void SetDoubleSymbols(); + void SetSymbols(const SymbolInitF *syminit, size_t count); + void SetSymbols(const SymbolInitI *syminit, size_t count); +}; + +class PString : public PBasicType +{ + DECLARE_CLASS(PString, PBasicType); +public: + PString(); + + virtual int GetRegType() const; +}; + +// Variations of integer types ---------------------------------------------- + +class PName : public PInt +{ + DECLARE_CLASS(PName, PInt); +public: + PName(); +}; + +class PSound : public PInt +{ + DECLARE_CLASS(PSound, PInt); +public: + PSound(); +}; + +class PColor : public PInt +{ + DECLARE_CLASS(PColor, PInt); +public: + PColor(); +}; + +// Variations of floating point types --------------------------------------- +// These get converted to floats when they're loaded from memory. + +class PFixed : public PFloat +{ + DECLARE_CLASS(PFixed, PFloat); +public: + PFixed(); + + virtual void SetValue(void *addr, int val); + virtual int GetValueInt(void *addr) const; + virtual int GetStoreOp() const; + virtual int GetLoadOp() const; +}; + +class PAngle : public PFloat +{ + DECLARE_CLASS(PAngle, PFloat); +public: + PAngle(); + + virtual void SetValue(void *addr, int val); + virtual int GetValueInt(void *addr) const; + virtual int GetStoreOp() const; + virtual int GetLoadOp() const; +}; + +// Pointers ----------------------------------------------------------------- + +class PStatePointer : public PBasicType +{ + DECLARE_CLASS(PStatePointer, PBasicType); +public: + PStatePointer(); +}; + +class PPointer : public PBasicType +{ + DECLARE_CLASS(PPointer, PBasicType); + HAS_OBJECT_POINTERS; +public: + PPointer(PType *pointsat); + + PType *PointedType; + + virtual int GetStoreOp() const; + virtual int GetLoadOp() const; + virtual int GetRegType() const; + + virtual bool IsMatch(intptr_t id1, intptr_t id2) const; + virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; +protected: + PPointer(); +}; + +class PClassPointer : public PPointer +{ + DECLARE_CLASS(PClassPointer, PPointer); + HAS_OBJECT_POINTERS; +public: + PClassPointer(class PClass *restrict); + + class PClass *ClassRestriction; + + virtual bool IsMatch(intptr_t id1, intptr_t id2) const; + virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; +protected: + PClassPointer(); +}; + +// Struct/class fields ------------------------------------------------------ + +// A PField describes a symbol that takes up physical space in the struct. +class PField : public PSymbol +{ + DECLARE_CLASS(PField, PSymbol); + HAS_OBJECT_POINTERS +public: + PField(FName name, PType *type) : PSymbol(name), Offset(0), Type(type), Flags(0) {} + PField(FName name, PType *type, DWORD flags) : PSymbol(name), Offset(0), Type(type), Flags(flags) {} + PField(FName name, PType *type, DWORD flags, unsigned offset) : PSymbol(name), Offset(offset), Type(type), Flags(flags) {} + + unsigned int Offset; + PType *Type; + DWORD Flags; +protected: + PField(); +}; + +// Compound types ----------------------------------------------------------- + +class PEnum : public PNamedType +{ + DECLARE_CLASS(PEnum, PNamedType); + HAS_OBJECT_POINTERS; +public: + PEnum(FName name, DObject *outer); + + PType *ValueType; + TMap Values; +protected: + PEnum(); +}; + +class PArray : public PCompoundType +{ + DECLARE_CLASS(PArray, PCompoundType); + HAS_OBJECT_POINTERS; +public: + PArray(PType *etype, unsigned int ecount); + + PType *ElementType; + unsigned int ElementCount; + unsigned int ElementSize; + + virtual bool IsMatch(intptr_t id1, intptr_t id2) const; + virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; +protected: + PArray(); +}; + +// A vector is an array with extra operations. +class PVector : public PArray +{ + DECLARE_CLASS(PVector, PArray); + HAS_OBJECT_POINTERS; +public: + PVector(unsigned int size); +protected: + PVector(); +}; + +class PDynArray : public PCompoundType +{ + DECLARE_CLASS(PDynArray, PCompoundType); + HAS_OBJECT_POINTERS; +public: + PDynArray(PType *etype); + + PType *ElementType; + + virtual bool IsMatch(intptr_t id1, intptr_t id2) const; + virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; +protected: + PDynArray(); +}; + +class PMap : public PCompoundType +{ + DECLARE_CLASS(PMap, PCompoundType); + HAS_OBJECT_POINTERS; +public: + PMap(PType *keytype, PType *valtype); + + PType *KeyType; + PType *ValueType; + + virtual bool IsMatch(intptr_t id1, intptr_t id2) const; + virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; +protected: + PMap(); +}; + +class PStruct : public PNamedType +{ + DECLARE_CLASS(PStruct, PNamedType); +public: + PStruct(FName name, DObject *outer); + + TArray Fields; + + PField *AddField(FName name, PType *type, DWORD flags=0); + + size_t PropagateMark(); +protected: + PStruct(); +}; + +class PPrototype : public PCompoundType +{ + DECLARE_CLASS(PPrototype, PCompoundType); +public: + PPrototype(const TArray &rettypes, const TArray &argtypes); + + TArray ArgumentTypes; + TArray ReturnTypes; + + size_t PropagateMark(); + virtual bool IsMatch(intptr_t id1, intptr_t id2) const; + virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; +protected: + PPrototype(); +}; + +// TBD: Should we really support overloading? +class PFunction : public PSymbol +{ + DECLARE_CLASS(PFunction, PSymbol); +public: + struct Variant + { + PPrototype *Proto; + VMFunction *Implementation; + TArray ArgFlags; // Should be the same length as Proto->ArgumentTypes + }; + TArray Variants; + DWORD Flags; + + unsigned AddVariant(PPrototype *proto, TArray &argflags, VMFunction *impl); + + size_t PropagateMark(); + + PFunction(FName name) : PSymbol(name), Flags(0) {} + PFunction() : PSymbol(NAME_None), Flags(0) {} +}; + // Meta-info for every class derived from DObject --------------------------- -struct PClass +class PClassClass; +class PClass : public PStruct { - static void StaticInit (); - static void StaticShutdown (); - static void StaticFreeData (PClass *type); - static void ClearRuntimeData(); + DECLARE_CLASS(PClass, PStruct); + HAS_OBJECT_POINTERS; +protected: + virtual void Derive(PClass *newclass); + // We unravel _WITH_META here just as we did for PType. + enum { MetaClassNum = CLASSREG_PClassClass }; +public: + typedef PClassClass MetaClass; + MetaClass *GetClass() const; + + static void StaticInit(); + static void StaticShutdown(); + static void StaticBootstrap(); // Per-class information ------------------------------------- - FName TypeName; // this class's name - unsigned int Size; // this class's size PClass *ParentClass; // the class this class derives from const size_t *Pointers; // object pointers defined by this class *only* const size_t *FlatPointers; // object pointers defined by this class and all its superclasses; not initialized by default - FActorInfo *ActorInfo; - PClass *HashNext; - FMetaTable Meta; BYTE *Defaults; bool bRuntimeClass; // class was defined at run-time, not compile-time - unsigned short ClassIndex; - PSymbolTable Symbols; void (*ConstructNative)(void *); // The rest are all functions and static data ---------------- - void InsertIntoHash (); - DObject *CreateNew () const; - PClass *CreateDerivedClass (FName name, unsigned int size); + PClass(); + ~PClass(); + void InsertIntoHash(); + DObject *CreateNew() const; + PClass *CreateDerivedClass(FName name, unsigned int size); unsigned int Extend(unsigned int extension); - void InitializeActorInfo (); - void BuildFlatPointers (); - void FreeStateList(); + void InitializeActorInfo(); + void BuildFlatPointers(); const PClass *NativeClass() const; // Returns true if this type is an ancestor of (or same as) the passed type. - bool IsAncestorOf (const PClass *ti) const + bool IsAncestorOf(const PClass *ti) const { while (ti) { @@ -164,26 +647,160 @@ struct PClass } return false; } - inline bool IsDescendantOf (const PClass *ti) const + inline bool IsDescendantOf(const PClass *ti) const { - return ti->IsAncestorOf (this); + return ti->IsAncestorOf(this); } // Find a type, given its name. - static const PClass *FindClass (const char *name) { return FindClass (FName (name, true)); } - static const PClass *FindClass (const FString &name) { return FindClass (FName (name, true)); } - static const PClass *FindClass (ENamedName name) { return FindClass (FName (name)); } - static const PClass *FindClass (FName name); - const PClass *FindClassTentative (FName name); // not static! - PClass *GetReplacement() const; + static PClass *FindClass(const char *name) { return FindClass(FName(name, true)); } + static PClass *FindClass(const FString &name) { return FindClass(FName(name, true)); } + static PClass *FindClass(ENamedName name) { return FindClass(FName(name)); } + static PClass *FindClass(FName name); + static PClassActor *FindActor(const char *name) { return FindActor(FName(name, true)); } + static PClassActor *FindActor(const FString &name) { return FindActor(FName(name, true)); } + static PClassActor *FindActor(ENamedName name) { return FindActor(FName(name)); } + static PClassActor *FindActor(FName name); + PClass *FindClassTentative(FName name); // not static! - static TArray m_Types; - static TArray m_RuntimeActors; - - enum { HASH_SIZE = 256 }; - static PClass *TypeHash[HASH_SIZE]; + static TArray AllClasses; static bool bShutdown; }; +class PClassType : public PClass +{ + DECLARE_CLASS(PClassType, PClass); +protected: + virtual void Derive(PClass *newclass); +public: + PClassType(); + + PClass *TypeTableType; // The type to use for hashing into the type table +}; + +inline PType::MetaClass *PType::GetClass() const +{ + return static_cast(DObject::GetClass()); +} + +class PClassClass : public PClassType +{ + DECLARE_CLASS(PClassClass, PClassType); +public: + PClassClass(); +}; + +inline PClass::MetaClass *PClass::GetClass() const +{ + return static_cast(DObject::GetClass()); +} + +// A class that hasn't had its parent class defined yet --------------------- + +class PClassWaitingForParent : public PClass +{ + DECLARE_CLASS(PClassWaitingForParent, PClass); +public: + PClassWaitingForParent(FName myname, FName parentname); + + FName ParentName; +}; + +// Type tables -------------------------------------------------------------- + +struct FTypeTable +{ + enum { HASH_SIZE = 1021 }; + + PType *TypeHash[HASH_SIZE]; + + PType *FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, size_t *bucketnum); + void ReplaceType(PType *newtype, PType *oldtype, size_t bucket); + void AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t parm2, size_t bucket); + void AddType(PType *type); + void Mark(); + void Clear(); + + static size_t Hash(const PClass *p1, intptr_t p2, intptr_t p3); +}; + + +extern FTypeTable TypeTable; + +// Returns a type from the TypeTable. Will create one if it isn't present. +PVector *NewVector(unsigned int size); +PMap *NewMap(PType *keytype, PType *valuetype); +PArray *NewArray(PType *type, unsigned int count); +PDynArray *NewDynArray(PType *type); +PPointer *NewPointer(PType *type); +PClassPointer *NewClassPointer(PClass *restrict); +PClassWaitingForParent *NewUnknownClass(FName myname, FName parentname); +PEnum *NewEnum(FName name, DObject *outer); +PStruct *NewStruct(FName name, DObject *outer); +PPrototype *NewPrototype(const TArray &rettypes, const TArray &argtypes); + +// Built-in types ----------------------------------------------------------- + +extern PErrorType *TypeError; +extern PVoidType *TypeVoid; +extern PInt *TypeSInt8, *TypeUInt8; +extern PInt *TypeSInt16, *TypeUInt16; +extern PInt *TypeSInt32, *TypeUInt32; +extern PBool *TypeBool; +extern PFloat *TypeFloat32, *TypeFloat64; +extern PString *TypeString; +extern PName *TypeName; +extern PSound *TypeSound; +extern PColor *TypeColor; +extern PStatePointer *TypeState; +extern PFixed *TypeFixed; +extern PAngle *TypeAngle; + +// A constant value --------------------------------------------------------- + +class PSymbolConst : public PSymbol +{ + DECLARE_CLASS(PSymbolConst, PSymbol); +public: + PType *ValueType; + + PSymbolConst(FName name, PType *type=NULL) : PSymbol(name), ValueType(type) {} + PSymbolConst() : PSymbol(NAME_None), ValueType(NULL) {} +}; + +// A constant numeric value ------------------------------------------------- + +class PSymbolConstNumeric : public PSymbolConst +{ + DECLARE_CLASS(PSymbolConstNumeric, PSymbolConst); +public: + union + { + int Value; + double Float; + void *Pad; + }; + + PSymbolConstNumeric(FName name, PType *type=NULL) : PSymbolConst(name, type) {} + PSymbolConstNumeric(FName name, PType *type, int val) : PSymbolConst(name, type), Value(val) {} + PSymbolConstNumeric(FName name, PType *type, unsigned int val) : PSymbolConst(name, type), Value((int)val) {} + PSymbolConstNumeric(FName name, PType *type, double val) : PSymbolConst(name, type), Float(val) {} + PSymbolConstNumeric() {} +}; + +// A constant string value -------------------------------------------------- + +class PSymbolConstString : public PSymbolConst +{ + DECLARE_CLASS(PSymbolConstString, PSymbolConst); +public: + FString Str; + + PSymbolConstString(FName name, FString &str) : PSymbolConst(name, TypeString), Str(str) {} + PSymbolConstString() {} +}; + +void ReleaseGlobalSymbols(); + #endif diff --git a/src/doomtype.h b/src/doomtype.h index 98e6e7b65b..06541f5266 100644 --- a/src/doomtype.h +++ b/src/doomtype.h @@ -46,8 +46,8 @@ #include "zstring.h" #include "vectors.h" -struct PClass; -typedef TMap FClassMap; +class PClassActor; +typedef TMap FClassMap; // Since this file is included by everything, it seems an appropriate place // to check the NOASM/USEASM macros. diff --git a/src/dthinker.cpp b/src/dthinker.cpp index 9ab8d5e310..c186bb7ccd 100644 --- a/src/dthinker.cpp +++ b/src/dthinker.cpp @@ -43,6 +43,7 @@ static cycle_t ThinkCycles; extern cycle_t BotSupportCycles; +extern cycle_t ActionCycles; extern int BotWTG; IMPLEMENT_CLASS (DThinker) @@ -406,6 +407,7 @@ void DThinker::RunThinkers () ThinkCycles.Reset(); BotSupportCycles.Reset(); + ActionCycles.Reset(); BotWTG = 0; ThinkCycles.Clock(); @@ -573,6 +575,6 @@ DThinker *FThinkerIterator::Next () ADD_STAT (think) { FString out; - out.Format ("Think time = %04.1f ms", ThinkCycles.TimeMS()); + out.Format ("Think time = %04.1f ms, Action = %04.1f ms", ThinkCycles.TimeMS(), ActionCycles.TimeMS()); return out; } diff --git a/src/dthinker.h b/src/dthinker.h index 32857d86be..e010e536d5 100644 --- a/src/dthinker.h +++ b/src/dthinker.h @@ -121,10 +121,10 @@ public: template class TThinkerIterator : public FThinkerIterator { public: - TThinkerIterator (int statnum=MAX_STATNUM+1) : FThinkerIterator (RUNTIME_CLASS(T), statnum) + TThinkerIterator (int statnum=MAX_STATNUM+1) : FThinkerIterator (RUNTIME_TEMPLATE_CLASS(T), statnum) { } - TThinkerIterator (int statnum, DThinker *prev) : FThinkerIterator (RUNTIME_CLASS(T), statnum, prev) + TThinkerIterator (int statnum, DThinker *prev) : FThinkerIterator (RUNTIME_TEMPLATE_CLASS(T), statnum, prev) { } TThinkerIterator (const PClass *subclass, int statnum=MAX_STATNUM+1) : FThinkerIterator(subclass, statnum) diff --git a/src/farchive.cpp b/src/farchive.cpp index ac6c886312..6759b40de1 100644 --- a/src/farchive.cpp +++ b/src/farchive.cpp @@ -662,12 +662,8 @@ FArchive::FArchive (FFile &file) void FArchive::AttachToFile (FFile &file) { - unsigned int i; - m_HubTravel = false; m_File = &file; - m_MaxObjectCount = m_ObjectCount = 0; - m_ObjectMap = NULL; if (file.Mode() == FFile::EReading) { m_Loading = true; @@ -679,19 +675,17 @@ void FArchive::AttachToFile (FFile &file) m_Storing = true; } m_Persistent = file.IsPersistent(); - m_TypeMap = NULL; - m_TypeMap = new TypeMap[PClass::m_Types.Size()]; - for (i = 0; i < PClass::m_Types.Size(); i++) - { - m_TypeMap[i].toArchive = TypeMap::NO_INDEX; - m_TypeMap[i].toCurrent = NULL; - } - m_ClassCount = 0; - for (i = 0; i < EObjectHashSize; i++) - { - m_ObjectHash[i] = ~0; - m_NameHash[i] = NameMap::NO_INDEX; - } + + ClassToArchive.Clear(); + ArchiveToClass.Clear(); + + ObjectToArchive.Clear(); + ArchiveToObject.Clear(); + + memset(m_NameHash, 0xFF, sizeof(m_NameHash)); + m_Names.Clear(); + m_NameStorage.Clear(); + m_NumSprites = 0; m_SpriteMap = new int[sprites.Size()]; for (size_t s = 0; s < sprites.Size(); ++s) @@ -703,10 +697,6 @@ void FArchive::AttachToFile (FFile &file) FArchive::~FArchive () { Close (); - if (m_TypeMap) - delete[] m_TypeMap; - if (m_ObjectMap) - M_Free (m_ObjectMap); if (m_SpriteMap) delete[] m_SpriteMap; } @@ -727,7 +717,7 @@ void FArchive::Close () { m_File->Close (); m_File = NULL; - DPrintf ("Processed %u objects\n", m_ObjectCount); + DPrintf ("Processed %u objects\n", ArchiveToObject.Size()); } } @@ -1034,13 +1024,28 @@ FArchive &FArchive::SerializePointer (void *ptrbase, BYTE **ptr, DWORD elemSize) FArchive &FArchive::SerializeObject (DObject *&object, PClass *type) { - if (IsStoring ()) - { - return WriteObject (object); + if (!type->IsDescendantOf(RUNTIME_CLASS(PClass))) + { // a regular object + if (IsStoring()) + { + return WriteObject(object); + } + else + { + return ReadObject(object, type); + } } else - { - return ReadObject (object, type); + { // a class object + if (IsStoring()) + { + UserWriteClass((PClass *)object); + } + else + { + UserReadClass(object); + } + return *this; } } @@ -1068,7 +1073,8 @@ FArchive &FArchive::WriteObject (DObject *obj) } else { - const PClass *type = RUNTIME_TYPE(obj); + PClass *type = obj->GetClass(); + DWORD *classarcid; if (type == RUNTIME_CLASS(DObject)) { @@ -1077,7 +1083,7 @@ FArchive &FArchive::WriteObject (DObject *obj) id[0] = NULL_OBJ; Write (id, 1); } - else if (m_TypeMap[type->ClassIndex].toArchive == TypeMap::NO_INDEX) + else if (NULL == (classarcid = ClassToArchive.CheckKey(type))) { // No instances of this class have been written out yet. // Write out the class, then write out the object. If this @@ -1110,9 +1116,9 @@ FArchive &FArchive::WriteObject (DObject *obj) // to the saved object. Otherwise, save a reference to the // class, then save the object. Again, if this is a player- // controlled actor, remember that. - DWORD index = FindObjectIndex (obj); + DWORD *objarcid = ObjectToArchive.CheckKey(obj); - if (index == TypeMap::NO_INDEX) + if (objarcid == NULL) { if (obj->IsKindOf (RUNTIME_CLASS (AActor)) && @@ -1128,7 +1134,7 @@ FArchive &FArchive::WriteObject (DObject *obj) id[0] = NEW_OBJ; Write (id, 1); } - WriteCount (m_TypeMap[type->ClassIndex].toArchive); + WriteCount (*classarcid); // Printf ("Reuse class %s (%u)\n", type->Name, m_File->Tell()); MapObject (obj); obj->SerializeUserVars (*this); @@ -1139,7 +1145,7 @@ FArchive &FArchive::WriteObject (DObject *obj) { id[0] = OLD_OBJ; Write (id, 1); - WriteCount (index); + WriteCount (*objarcid); } } } @@ -1166,12 +1172,12 @@ FArchive &FArchive::ReadObject (DObject* &obj, PClass *wanttype) break; case OLD_OBJ: - index = ReadCount (); - if (index >= m_ObjectCount) + index = ReadCount(); + if (index >= ArchiveToObject.Size()) { - I_Error ("Object reference too high (%u; max is %u)\n", index, m_ObjectCount); + I_Error ("Object reference too high (%u; max is %u)\n", index, ArchiveToObject.Size()); } - obj = (DObject *)m_ObjectMap[index].object; + obj = ArchiveToObject[index]; break; case NEW_PLYR_CLS_OBJ: @@ -1386,24 +1392,19 @@ DWORD FArchive::FindName (const char *name, unsigned int bucket) const return (DWORD)map; } -DWORD FArchive::WriteClass (const PClass *info) +DWORD FArchive::WriteClass (PClass *info) { - if (m_ClassCount >= PClass::m_Types.Size()) - { - I_Error ("Too many unique classes have been written.\nOnly %u were registered\n", - PClass::m_Types.Size()); - } - if (m_TypeMap[info->ClassIndex].toArchive != TypeMap::NO_INDEX) + if (ClassToArchive.CheckKey(info) != NULL) { I_Error ("Attempt to write '%s' twice.\n", info->TypeName.GetChars()); } - m_TypeMap[info->ClassIndex].toArchive = m_ClassCount; - m_TypeMap[m_ClassCount].toCurrent = info; + DWORD index = ArchiveToClass.Push(info); + ClassToArchive[info] = index; WriteString (info->TypeName.GetChars()); - return m_ClassCount++; + return index; } -const PClass *FArchive::ReadClass () +PClass *FArchive::ReadClass () { struct String { String() { val = NULL; } @@ -1411,33 +1412,24 @@ const PClass *FArchive::ReadClass () char *val; } typeName; - if (m_ClassCount >= PClass::m_Types.Size()) - { - I_Error ("Too many unique classes have been read.\nOnly %u were registered\n", - PClass::m_Types.Size()); - } operator<< (typeName.val); FName zaname(typeName.val, true); if (zaname != NAME_None) { - for (unsigned int i = PClass::m_Types.Size(); i-- > 0; ) + PClass *type = PClass::FindClass(zaname); + if (type != NULL) { - if (PClass::m_Types[i]->TypeName == zaname) - { - m_TypeMap[i].toArchive = m_ClassCount; - m_TypeMap[m_ClassCount].toCurrent = PClass::m_Types[i]; - m_ClassCount++; - return PClass::m_Types[i]; - } + ClassToArchive[type] = ArchiveToClass.Push(type); + return type; } } I_Error ("Unknown class '%s'\n", typeName.val); return NULL; } -const PClass *FArchive::ReadClass (const PClass *wanttype) +PClass *FArchive::ReadClass (const PClass *wanttype) { - const PClass *type = ReadClass (); + PClass *type = ReadClass (); if (!type->IsDescendantOf (wanttype)) { I_Error ("Expected to extract an object of type '%s'.\n" @@ -1447,14 +1439,10 @@ const PClass *FArchive::ReadClass (const PClass *wanttype) return type; } -const PClass *FArchive::ReadStoredClass (const PClass *wanttype) +PClass *FArchive::ReadStoredClass (const PClass *wanttype) { DWORD index = ReadCount (); - if (index >= m_ClassCount) - { - I_Error ("Class reference too high (%u; max is %u)\n", index, m_ClassCount); - } - const PClass *type = m_TypeMap[index].toCurrent; + PClass *type = ArchiveToClass[index]; if (!type->IsDescendantOf (wanttype)) { I_Error ("Expected to extract an object of type '%s'.\n" @@ -1464,47 +1452,14 @@ const PClass *FArchive::ReadStoredClass (const PClass *wanttype) return type; } -DWORD FArchive::MapObject (const DObject *obj) +DWORD FArchive::MapObject (DObject *obj) { - DWORD i; - - if (m_ObjectCount >= m_MaxObjectCount) - { - m_MaxObjectCount = m_MaxObjectCount ? m_MaxObjectCount * 2 : 1024; - m_ObjectMap = (ObjectMap *)M_Realloc (m_ObjectMap, sizeof(ObjectMap)*m_MaxObjectCount); - for (i = m_ObjectCount; i < m_MaxObjectCount; i++) - { - m_ObjectMap[i].hashNext = ~0; - m_ObjectMap[i].object = NULL; - } - } - - DWORD index = m_ObjectCount++; - DWORD hash = HashObject (obj); - - m_ObjectMap[index].object = obj; - m_ObjectMap[index].hashNext = m_ObjectHash[hash]; - m_ObjectHash[hash] = index; - - return index; + DWORD i = ArchiveToObject.Push(obj); + ObjectToArchive[obj] = i; + return i; } -DWORD FArchive::HashObject (const DObject *obj) const -{ - return (DWORD)((size_t)obj % EObjectHashSize); -} - -DWORD FArchive::FindObjectIndex (const DObject *obj) const -{ - DWORD index = m_ObjectHash[HashObject (obj)]; - while (index != TypeMap::NO_INDEX && m_ObjectMap[index].object != obj) - { - index = m_ObjectMap[index].hashNext; - } - return index; -} - -void FArchive::UserWriteClass (const PClass *type) +void FArchive::UserWriteClass (PClass *type) { BYTE id; @@ -1515,7 +1470,8 @@ void FArchive::UserWriteClass (const PClass *type) } else { - if (m_TypeMap[type->ClassIndex].toArchive == TypeMap::NO_INDEX) + DWORD *arcid; + if (NULL == (arcid = ClassToArchive.CheckKey(type))) { id = 1; Write (&id, 1); @@ -1525,12 +1481,12 @@ void FArchive::UserWriteClass (const PClass *type) { id = 0; Write (&id, 1); - WriteCount (m_TypeMap[type->ClassIndex].toArchive); + WriteCount (*arcid); } } } -void FArchive::UserReadClass (const PClass *&type) +void FArchive::UserReadClass (PClass *&type) { BYTE newclass; @@ -1552,19 +1508,6 @@ void FArchive::UserReadClass (const PClass *&type) } } -FArchive &operator<< (FArchive &arc, const PClass * &info) -{ - if (arc.IsStoring ()) - { - arc.UserWriteClass (info); - } - else - { - arc.UserReadClass (info); - } - return arc; -} - FArchive &operator<< (FArchive &arc, sector_t *&sec) { return arc.SerializePointer (sectors, (BYTE **)&sec, sizeof(*sectors)); diff --git a/src/farchive.h b/src/farchive.h index 87ebf999b0..64c7cc9feb 100644 --- a/src/farchive.h +++ b/src/farchive.h @@ -170,8 +170,14 @@ virtual void Read (void *mem, unsigned int len); void WriteCount (DWORD count); DWORD ReadCount (); - void UserWriteClass (const PClass *info); - void UserReadClass (const PClass *&info); + void UserWriteClass (PClass *info); + void UserReadClass (PClass *&info); + template void UserReadClass(T *&info) + { + PClass *myclass; + UserReadClass(myclass); + info = dyn_cast(myclass); + } FArchive& operator<< (BYTE &c); FArchive& operator<< (WORD &s); @@ -206,13 +212,11 @@ inline FArchive& operator<< (DObject* &object) { return ReadObject (object, RUN protected: enum { EObjectHashSize = 137 }; - DWORD FindObjectIndex (const DObject *obj) const; - DWORD MapObject (const DObject *obj); - DWORD WriteClass (const PClass *info); - const PClass *ReadClass (); - const PClass *ReadClass (const PClass *wanttype); - const PClass *ReadStoredClass (const PClass *wanttype); - DWORD HashObject (const DObject *obj) const; + DWORD MapObject (DObject *obj); + DWORD WriteClass (PClass *info); + PClass *ReadClass (); + PClass *ReadClass (const PClass *wanttype); + PClass *ReadStoredClass (const PClass *wanttype); DWORD AddName (const char *name); DWORD AddName (unsigned int start); // Name has already been added to storage DWORD FindName (const char *name) const; @@ -223,24 +227,12 @@ protected: bool m_Storing; // inserting objects? bool m_HubTravel; // travelling inside a hub? FFile *m_File; // unerlying file object - DWORD m_ObjectCount; // # of objects currently serialized - DWORD m_MaxObjectCount; - DWORD m_ClassCount; // # of unique classes currently serialized - struct TypeMap - { - const PClass *toCurrent; // maps archive type index to execution type index - DWORD toArchive; // maps execution type index to archive type index + TMap ClassToArchive; // Maps PClass to archive type index + TArray ArchiveToClass; // Maps archive type index to PClass - enum { NO_INDEX = 0xffffffff }; - } *m_TypeMap; - - struct ObjectMap - { - const DObject *object; - DWORD hashNext; - } *m_ObjectMap; - DWORD m_ObjectHash[EObjectHashSize]; + TMap ObjectToArchive; // Maps objects to archive index + TArray ArchiveToObject; // Maps archive index to objects struct NameMap { @@ -281,11 +273,9 @@ inline FArchive &operator<< (FArchive &arc, PalEntry &p) template inline FArchive &operator<< (FArchive &arc, T* &object) { - return arc.SerializeObject ((DObject*&)object, RUNTIME_CLASS(T)); + return arc.SerializeObject ((DObject*&)object, RUNTIME_TEMPLATE_CLASS(T)); } -FArchive &operator<< (FArchive &arc, const PClass * &info); - class FFont; FArchive &SerializeFFontPtr (FArchive &arc, FFont* &font); template<> inline FArchive &operator<< (FArchive &arc, FFont* &font) diff --git a/src/fragglescript/t_fs.h b/src/fragglescript/t_fs.h index 91f90edb33..78a6f9337b 100644 --- a/src/fragglescript/t_fs.h +++ b/src/fragglescript/t_fs.h @@ -10,5 +10,6 @@ class AActor; void T_PreprocessScripts(); void T_LoadScripts(MapData * map); void T_AddSpawnedThing(AActor * ); +void FS_Close(); #endif diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index 3060c65aa1..a1e4a9f757 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -228,7 +228,7 @@ static const char * const ActorNames_init[]= "PointPuller", }; -static const PClass * ActorTypes[countof(ActorNames_init)]; +static PClassActor * ActorTypes[countof(ActorNames_init)]; //========================================================================== // @@ -244,32 +244,32 @@ static const PClass * ActorTypes[countof(ActorNames_init)]; // Doom index is only supported for the original things up to MBF // //========================================================================== -const PClass * T_GetMobjType(svalue_t arg) +PClassActor * T_GetMobjType(svalue_t arg) { - const PClass * PClass=NULL; + PClassActor * pclass=NULL; if (arg.type==svt_string) { - PClass=PClass::FindClass(arg.string); + pclass=PClass::FindActor(arg.string); // invalid object to spawn - if(!PClass) script_error("unknown object type: %s\n", arg.string.GetChars()); + if(!pclass) script_error("unknown object type: %s\n", arg.string.GetChars()); } else if (arg.type==svt_mobj) { AActor * mo = actorvalue(arg); - if (mo) PClass = mo->GetClass(); + if (mo) pclass = mo->GetClass(); } else { int objtype = intvalue(arg); - if (objtype>=0 && objtype=0 && objtypeIsDescendantOf(RUNTIME_CLASS(AAmmo))) + PClassAmmo * am=dyn_cast(PClass::FindActor(p)); + if (am == NULL) { script_error("unknown ammo type : %s", p); return NULL; @@ -861,12 +861,12 @@ void FParser::SF_Player(void) void FParser::SF_Spawn(void) { int x, y, z; - const PClass *PClass; + PClassActor *pclass; angle_t angle = 0; if (CheckArgs(3)) { - if (!(PClass=T_GetMobjType(t_argv[0]))) return; + if (!(pclass=T_GetMobjType(t_argv[0]))) return; x = fixedvalue(t_argv[1]); y = fixedvalue(t_argv[2]); @@ -892,7 +892,7 @@ void FParser::SF_Spawn(void) } t_return.type = svt_mobj; - t_return.value.mobj = Spawn(PClass, x, y, z, ALLOW_REPLACE); + t_return.value.mobj = Spawn(pclass, x, y, z, ALLOW_REPLACE); if (t_return.value.mobj) { @@ -2570,8 +2570,8 @@ static void FS_GiveInventory (AActor *actor, const char * type, int amount) { type = "BasicArmorPickup"; } - const PClass * info = PClass::FindClass (type); - if (info == NULL || !info->IsDescendantOf (RUNTIME_CLASS(AInventory))) + PClassInventory * info = dyn_cast(PClass::FindActor (type)); + if (info == NULL) { Printf ("Unknown inventory item: %s\n", type); return; @@ -2623,7 +2623,7 @@ static void FS_TakeInventory (AActor *actor, const char * type, int amount) { return; } - const PClass * info = PClass::FindClass (type); + PClassActor * info = PClass::FindActor (type); if (info == NULL) { return; @@ -2672,7 +2672,7 @@ static int FS_CheckInventory (AActor *activator, const char *type) return activator->health; } - const PClass *info = PClass::FindClass (type); + PClassActor *info = PClass::FindActor (type); AInventory *item = activator->FindInventory (info); return item ? item->Amount : 0; } @@ -2732,7 +2732,7 @@ void FParser::SF_PlayerKeys(void) void FParser::SF_PlayerAmmo(void) { int playernum, amount; - const PClass * ammotype; + PClassAmmo * ammotype; if (CheckArgs(2)) { @@ -2768,7 +2768,7 @@ void FParser::SF_PlayerAmmo(void) void FParser::SF_MaxPlayerAmmo() { int playernum, amount; - const PClass * ammotype; + PClassAmmo * ammotype; if (CheckArgs(2)) { @@ -2843,7 +2843,7 @@ void FParser::SF_PlayerWeapon() script_error("weaponnum out of range! %s\n", weaponnum); return; } - const PClass * ti = PClass::FindClass(WeaponNames[weaponnum]); + PClassWeapon * ti = static_cast(PClass::FindActor(WeaponNames[weaponnum])); if (!ti) { script_error("incompatibility in playerweapon\n", weaponnum); @@ -2924,7 +2924,7 @@ void FParser::SF_PlayerSelectedWeapon() script_error("weaponnum out of range! %s\n", weaponnum); return; } - const PClass * ti = PClass::FindClass(WeaponNames[weaponnum]); + PClassWeapon * ti = static_cast(PClass::FindActor(WeaponNames[weaponnum])); if (!ti) { script_error("incompatibility in playerweapon\n", weaponnum); @@ -3028,7 +3028,7 @@ void FParser::SF_SetWeapon() int playernum=T_GetPlayerNum(t_argv[0]); if (playernum!=-1) { - AInventory *item = players[playernum].mo->FindInventory (PClass::FindClass (stringvalue(t_argv[1]))); + AInventory *item = players[playernum].mo->FindInventory (PClass::FindActor (stringvalue(t_argv[1]))); if (item == NULL || !item->IsKindOf (RUNTIME_CLASS(AWeapon))) { @@ -3343,11 +3343,11 @@ void FParser::SF_SpawnExplosion() { fixed_t x, y, z; AActor* spawn; - const PClass * PClass; + PClassActor * pclass; if (CheckArgs(3)) { - if (!(PClass=T_GetMobjType(t_argv[0]))) return; + if (!(pclass=T_GetMobjType(t_argv[0]))) return; x = fixedvalue(t_argv[1]); y = fixedvalue(t_argv[2]); @@ -3356,7 +3356,7 @@ void FParser::SF_SpawnExplosion() else z = P_PointInSector(x, y)->floorplane.ZatPoint(x,y); - spawn = Spawn (PClass, x, y, z, ALLOW_REPLACE); + spawn = Spawn (pclass, x, y, z, ALLOW_REPLACE); t_return.type = svt_int; t_return.value.i=0; if (spawn) @@ -3514,15 +3514,15 @@ void FParser::SF_SpawnMissile() { AActor *mobj; AActor *target; - const PClass * PClass; + PClassActor * pclass; if (CheckArgs(3)) { - if (!(PClass=T_GetMobjType(t_argv[2]))) return; + if (!(pclass=T_GetMobjType(t_argv[2]))) return; mobj = actorvalue(t_argv[0]); target = actorvalue(t_argv[1]); - if (mobj && target) P_SpawnMissile(mobj, target, PClass); + if (mobj && target) P_SpawnMissile(mobj, target, pclass); } } @@ -4150,7 +4150,7 @@ void FParser::SF_MobjHeight(void) void FParser::SF_ThingCount(void) { - const PClass *pClass; + PClassActor *pClass; AActor * mo; int count=0; bool replacemented = false; @@ -4161,7 +4161,7 @@ void FParser::SF_ThingCount(void) pClass=T_GetMobjType(t_argv[0]); if (!pClass) return; // If we want to count map items we must consider actor replacement - pClass = pClass->ActorInfo->GetReplacement()->Class; + pClass = pClass->GetReplacement(); again: TThinkerIterator it; @@ -4191,7 +4191,7 @@ again: { // Again, with decorate replacements replacemented = true; - PClass *newkind = pClass->ActorInfo->GetReplacement()->Class; + PClassActor *newkind = pClass->GetReplacement(); if (newkind != pClass) { pClass = newkind; @@ -4259,7 +4259,7 @@ void FParser::SF_SetColor(void) void FParser::SF_SpawnShot2(void) { AActor *source = NULL; - const PClass * PClass; + PClassActor * pclass; int z=0; // t_argv[0] = type to spawn @@ -4277,11 +4277,11 @@ void FParser::SF_SpawnShot2(void) if(!source) return; - if (!(PClass=T_GetMobjType(t_argv[0]))) return; + if (!(pclass=T_GetMobjType(t_argv[0]))) return; t_return.type = svt_mobj; - AActor *mo = Spawn (PClass, source->PosPlusZ(z), ALLOW_REPLACE); + AActor *mo = Spawn (pclass, source->PosPlusZ(z), ALLOW_REPLACE); if (mo) { S_Sound (mo, CHAN_VOICE, mo->SeeSound, 1, ATTN_NORM); @@ -4606,7 +4606,7 @@ void init_functions(void) { for(unsigned i=0;ivariables[i]; - - while(current) - { - next = current->next; // save for after freeing - - current->ObjectFlags |= OF_YesReallyDelete; - delete current; - current = next; // go to next in chain - } - } - GC::DelSoftRoot(global_script); - global_script->ObjectFlags |= OF_YesReallyDelete; - delete global_script; + if (global_script != NULL) + { + GC::DelSoftRoot(global_script); + global_script->Destroy(); + global_script = NULL; + } } void T_Init() @@ -700,7 +685,6 @@ void T_Init() global_script = new DFsScript; GC::AddSoftRoot(global_script); init_functions(); - atterm(FS_Close); } } diff --git a/src/g_doom/a_arachnotron.cpp b/src/g_doom/a_arachnotron.cpp index 19c3bb63ad..0f42431c35 100644 --- a/src/g_doom/a_arachnotron.cpp +++ b/src/g_doom/a_arachnotron.cpp @@ -8,18 +8,23 @@ */ DEFINE_ACTION_FUNCTION(AActor, A_BspiAttack) -{ +{ + PARAM_ACTION_PROLOGUE; + if (!self->target) - return; + return 0; A_FaceTarget (self); // launch a missile - P_SpawnMissile (self, self->target, PClass::FindClass("ArachnotronPlasma")); + P_SpawnMissile (self, self->target, PClass::FindActor("ArachnotronPlasma")); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_BabyMetal) { + PARAM_ACTION_PROLOGUE; S_Sound (self, CHAN_BODY, "baby/walk", 1, ATTN_IDLE); - A_Chase (self); + A_Chase (stack, self); + return 0; } diff --git a/src/g_doom/a_archvile.cpp b/src/g_doom/a_archvile.cpp index 304bb271a9..623e41d3d7 100644 --- a/src/g_doom/a_archvile.cpp +++ b/src/g_doom/a_archvile.cpp @@ -21,7 +21,9 @@ void A_Fire(AActor *self, int height); // DEFINE_ACTION_FUNCTION(AActor, A_VileStart) { + PARAM_ACTION_PROLOGUE; S_Sound (self, CHAN_VOICE, "vile/start", 1, ATTN_NORM); + return 0; } @@ -31,22 +33,27 @@ DEFINE_ACTION_FUNCTION(AActor, A_VileStart) // DEFINE_ACTION_FUNCTION(AActor, A_StartFire) { + PARAM_ACTION_PROLOGUE; S_Sound (self, CHAN_BODY, "vile/firestrt", 1, ATTN_NORM); A_Fire (self, 0); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_FireCrackle) { + PARAM_ACTION_PROLOGUE; S_Sound (self, CHAN_BODY, "vile/firecrkl", 1, ATTN_NORM); A_Fire (self, 0); + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Fire) { - ACTION_PARAM_START(1); - ACTION_PARAM_FIXED(height,0); + PARAM_ACTION_PROLOGUE; + PARAM_FIXED_OPT(height) { height = 0; } A_Fire(self, height); + return 0; } void A_Fire(AActor *self, int height) @@ -73,12 +80,13 @@ void A_Fire(AActor *self, int height) // DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_VileTarget) { - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(fire,0); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS_OPT(fire, AActor) { fire = PClass::FindActor("ArchvileFire"); } + AActor *fog; if (!self->target) - return; + return 0; A_FaceTarget (self); @@ -88,6 +96,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_VileTarget) fog->target = self; fog->tracer = self->target; A_Fire(fog, 0); + return 0; } @@ -101,25 +110,25 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_VileTarget) #define VAF_DMGTYPEAPPLYTODIRECT 1 DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_VileAttack) -{ - ACTION_PARAM_START(7); - ACTION_PARAM_SOUND(snd,0); - ACTION_PARAM_INT(dmg,1); - ACTION_PARAM_INT(blastdmg,2); - ACTION_PARAM_INT(blastrad,3); - ACTION_PARAM_FIXED(thrust,4); - ACTION_PARAM_NAME(dmgtype,5); - ACTION_PARAM_INT(flags,6); +{ + PARAM_ACTION_PROLOGUE; + PARAM_SOUND_OPT (snd) { snd = "vile/stop"; } + PARAM_INT_OPT (dmg) { dmg = 20; } + PARAM_INT_OPT (blastdmg) { blastdmg = 70; } + PARAM_INT_OPT (blastrad) { blastrad = 70; } + PARAM_FIXED_OPT (thrust) { thrust = FRACUNIT; } + PARAM_NAME_OPT (dmgtype) { dmgtype = NAME_Fire; } + PARAM_INT_OPT (flags) { flags = 0; } AActor *fire, *target; if (NULL == (target = self->target)) - return; + return 0; A_FaceTarget (self); if (!P_CheckSight (self, target, 0) ) - return; + return 0; S_Sound (self, CHAN_WEAPON, snd, 1, ATTN_NORM); @@ -144,5 +153,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_VileAttack) P_RadiusAttack (fire, self, blastdmg, blastrad, dmgtype, 0); } if (!(target->flags7 & MF7_DONTTHRUST)) + { target->velz = Scale(thrust, 1000, target->Mass); + } + return 0; } diff --git a/src/g_doom/a_bossbrain.cpp b/src/g_doom/a_bossbrain.cpp index 29bdd2be13..aa8d78a1ad 100644 --- a/src/g_doom/a_bossbrain.cpp +++ b/src/g_doom/a_bossbrain.cpp @@ -18,13 +18,17 @@ static FRandom pr_spawnfly ("SpawnFly"); DEFINE_ACTION_FUNCTION(AActor, A_BrainAwake) { + PARAM_ACTION_PROLOGUE; // killough 3/26/98: only generates sound now S_Sound (self, CHAN_VOICE, "brain/sight", 1, ATTN_NONE); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_BrainPain) { + PARAM_ACTION_PROLOGUE; S_Sound (self, CHAN_VOICE, "brain/pain", 1, ATTN_NONE); + return 0; } static void BrainishExplosion (fixed_t x, fixed_t y, fixed_t z) @@ -35,16 +39,15 @@ static void BrainishExplosion (fixed_t x, fixed_t y, fixed_t z) boom->DeathSound = "misc/brainexplode"; boom->velz = pr_brainscream() << 9; - const PClass *cls = PClass::FindClass("BossBrain"); + PClassActor *cls = PClass::FindActor("BossBrain"); if (cls != NULL) { - FState *state = cls->ActorInfo->FindState(NAME_Brainexplode); + FState *state = cls->FindState(NAME_Brainexplode); if (state != NULL) boom->SetState (state); - } boom->effects = 0; - boom->Damage = 0; // disables collision detection which is not wanted here + boom->Damage = NULL; // disables collision detection which is not wanted here boom->tics -= pr_brainscream() & 7; if (boom->tics < 1) boom->tics = 1; @@ -53,6 +56,7 @@ static void BrainishExplosion (fixed_t x, fixed_t y, fixed_t z) DEFINE_ACTION_FUNCTION(AActor, A_BrainScream) { + PARAM_ACTION_PROLOGUE; fixed_t x; for (x = self->X() - 196*FRACUNIT; x < self->X() + 320*FRACUNIT; x += 8*FRACUNIT) @@ -61,20 +65,25 @@ DEFINE_ACTION_FUNCTION(AActor, A_BrainScream) 128 + (pr_brainscream() << (FRACBITS + 1))); } S_Sound (self, CHAN_VOICE, "brain/death", 1, ATTN_NONE); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_BrainExplode) { + PARAM_ACTION_PROLOGUE; fixed_t x = self->X() + pr_brainexplode.Random2()*2048; fixed_t z = 128 + pr_brainexplode()*2*FRACUNIT; BrainishExplosion (x, self->Y(), z); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_BrainDie) { + PARAM_ACTION_PROLOGUE; + // [RH] If noexit, then don't end the level. if ((deathmatch || alwaysapplydmflags) && (dmflags & DF_NO_EXIT)) - return; + return 0; // New dmflag: Kill all boss spawned monsters before ending the level. if (dmflags2 & DF2_KILLBOSSMONST) @@ -98,18 +107,19 @@ DEFINE_ACTION_FUNCTION(AActor, A_BrainDie) } G_ExitLevel (0, false); + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BrainSpit) { + PARAM_ACTION_PROLOGUE; + PARAM_CLASS_OPT(spawntype, AActor) { spawntype = NULL; } + DSpotState *state = DSpotState::GetSpotState(); AActor *targ; AActor *spit; bool isdefault = false; - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(spawntype, 0); - // shoot a cube at current target targ = state->GetNextInList(PClass::FindClass("BossTarget"), G_SkillProperty(SKILLP_EasyBossBrain)); @@ -117,7 +127,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BrainSpit) { if (spawntype == NULL) { - spawntype = PClass::FindClass("SpawnShot"); + spawntype = PClass::FindActor("SpawnShot"); isdefault = true; } @@ -161,9 +171,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BrainSpit) S_Sound (self, CHAN_WEAPON, "brain/spit", 1, ATTN_NONE); } } + return 0; } -static void SpawnFly(AActor *self, const PClass *spawntype, FSoundID sound) +static void SpawnFly(AActor *self, PClassActor *spawntype, FSoundID sound) { AActor *newmobj; AActor *fog; @@ -191,8 +202,8 @@ static void SpawnFly(AActor *self, const PClass *spawntype, FSoundID sound) FName SpawnName; - FDropItem *di; // di will be our drop item list iterator - FDropItem *drop; // while drop stays as the reference point. + DDropItem *di; // di will be our drop item list iterator + DDropItem *drop; // while drop stays as the reference point. int n = 0; // First see if this cube has its own actor list @@ -208,11 +219,11 @@ static void SpawnFly(AActor *self, const PClass *spawntype, FSoundID sound) { if (di->Name != NAME_None) { - if (di->amount < 0) + if (di->Amount < 0) { - di->amount = 1; // default value is -1, we need a positive value. + di->Amount = 1; // default value is -1, we need a positive value. } - n += di->amount; // this is how we can weight the list. + n += di->Amount; // this is how we can weight the list. } } di = drop; @@ -221,7 +232,7 @@ static void SpawnFly(AActor *self, const PClass *spawntype, FSoundID sound) { if (di->Name != NAME_None) { - n -= di->amount; // logically, none of the -1 values have survived by now. + n -= di->Amount; // logically, none of the -1 values have survived by now. } if ((di->Next != NULL) && (n >= 0)) { @@ -253,7 +264,7 @@ static void SpawnFly(AActor *self, const PClass *spawntype, FSoundID sound) else if (r < 246) SpawnName = "HellKnight"; else SpawnName = "BaronOfHell"; } - spawntype = PClass::FindClass(SpawnName); + spawntype = PClass::FindActor(SpawnName); if (spawntype != NULL) { newmobj = Spawn (spawntype, targ->Pos(), ALLOW_REPLACE); @@ -287,10 +298,10 @@ static void SpawnFly(AActor *self, const PClass *spawntype, FSoundID sound) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnFly) { - FSoundID sound; + PARAM_ACTION_PROLOGUE; + PARAM_CLASS_OPT (spawntype, AActor) { spawntype = NULL; } - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(spawntype, 0); + FSoundID sound; if (spawntype != NULL) { @@ -298,15 +309,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnFly) } else { - spawntype = PClass::FindClass ("SpawnFire"); + spawntype = PClass::FindActor("SpawnFire"); sound = "brain/spawn"; } SpawnFly(self, spawntype, sound); + return 0; } // travelling cube sound DEFINE_ACTION_FUNCTION(AActor, A_SpawnSound) { + PARAM_ACTION_PROLOGUE; S_Sound (self, CHAN_BODY, "brain/cube", 1, ATTN_IDLE); - SpawnFly(self, PClass::FindClass("SpawnFire"), "brain/spawn"); + SpawnFly(self, PClass::FindActor("SpawnFire"), "brain/spawn"); + return 0; } diff --git a/src/g_doom/a_bruiser.cpp b/src/g_doom/a_bruiser.cpp index ba1d92bc15..abcec8e6f2 100644 --- a/src/g_doom/a_bruiser.cpp +++ b/src/g_doom/a_bruiser.cpp @@ -3,8 +3,10 @@ static FRandom pr_bruisattack ("BruisAttack"); DEFINE_ACTION_FUNCTION(AActor, A_BruisAttack) { + PARAM_ACTION_PROLOGUE; + if (!self->target) - return; + return 0; if (self->CheckMeleeRange ()) { @@ -12,9 +14,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_BruisAttack) S_Sound (self, CHAN_WEAPON, "baron/melee", 1, ATTN_NORM); int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); - return; + return 0; } // launch a missile - P_SpawnMissile (self, self->target, PClass::FindClass("BaronBall")); + P_SpawnMissile (self, self->target, PClass::FindActor("BaronBall")); + return 0; } diff --git a/src/g_doom/a_cacodemon.cpp b/src/g_doom/a_cacodemon.cpp index 856360a13c..d8f03509e6 100644 --- a/src/g_doom/a_cacodemon.cpp +++ b/src/g_doom/a_cacodemon.cpp @@ -14,8 +14,10 @@ static FRandom pr_headattack ("HeadAttack"); DEFINE_ACTION_FUNCTION(AActor, A_HeadAttack) { + PARAM_ACTION_PROLOGUE; + if (!self->target) - return; + return 0; A_FaceTarget (self); if (self->CheckMeleeRange ()) @@ -24,9 +26,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_HeadAttack) S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM); int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); - return; + return 0; } // launch a missile - P_SpawnMissile (self, self->target, PClass::FindClass("CacodemonBall")); + P_SpawnMissile (self, self->target, PClass::FindActor("CacodemonBall")); + return 0; } diff --git a/src/g_doom/a_cyberdemon.cpp b/src/g_doom/a_cyberdemon.cpp index f13728e48b..5b436f2f3d 100644 --- a/src/g_doom/a_cyberdemon.cpp +++ b/src/g_doom/a_cyberdemon.cpp @@ -9,15 +9,21 @@ DEFINE_ACTION_FUNCTION(AActor, A_CyberAttack) { + PARAM_ACTION_PROLOGUE; + if (!self->target) - return; + return 0; A_FaceTarget (self); - P_SpawnMissile (self, self->target, PClass::FindClass("Rocket")); + P_SpawnMissile (self, self->target, PClass::FindActor("Rocket")); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_Hoof) { + PARAM_ACTION_PROLOGUE; + S_Sound (self, CHAN_BODY, "cyber/hoof", 1, ATTN_IDLE); - A_Chase (self); + A_Chase (stack, self); + return 0; } diff --git a/src/g_doom/a_demon.cpp b/src/g_doom/a_demon.cpp index f4a9f461f2..07b297005f 100644 --- a/src/g_doom/a_demon.cpp +++ b/src/g_doom/a_demon.cpp @@ -13,8 +13,10 @@ static FRandom pr_sargattack ("SargAttack"); DEFINE_ACTION_FUNCTION(AActor, A_SargAttack) { + PARAM_ACTION_PROLOGUE; + if (!self->target) - return; + return 0; A_FaceTarget (self); if (self->CheckMeleeRange ()) @@ -23,4 +25,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_SargAttack) int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); } + return 0; } diff --git a/src/g_doom/a_doomglobal.h b/src/g_doom/a_doomglobal.h index cab9a9bcd5..2cd2a9d6a0 100644 --- a/src/g_doom/a_doomglobal.h +++ b/src/g_doom/a_doomglobal.h @@ -28,7 +28,7 @@ public: void BeginPlay (); void Tick (); void SetWeapon (EMarineWeapon); - void SetSprite (const PClass *source); + void SetSprite (PClassActor *source); void Serialize (FArchive &arc); int CurrentWeapon; diff --git a/src/g_doom/a_doomimp.cpp b/src/g_doom/a_doomimp.cpp index 4c607f6e1d..35179c5b2b 100644 --- a/src/g_doom/a_doomimp.cpp +++ b/src/g_doom/a_doomimp.cpp @@ -17,8 +17,10 @@ static FRandom pr_troopattack ("TroopAttack"); // DEFINE_ACTION_FUNCTION(AActor, A_TroopAttack) { + PARAM_ACTION_PROLOGUE; + if (!self->target) - return; + return 0; A_FaceTarget (self); if (self->CheckMeleeRange ()) @@ -27,9 +29,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_TroopAttack) S_Sound (self, CHAN_WEAPON, "imp/melee", 1, ATTN_NORM); int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); - return; + return 0; } // launch a missile - P_SpawnMissile (self, self->target, PClass::FindClass("DoomImpBall")); + P_SpawnMissile (self, self->target, PClass::FindActor("DoomImpBall")); + return 0; } diff --git a/src/g_doom/a_doommisc.cpp b/src/g_doom/a_doommisc.cpp index 2c17b7d8d2..4aa1c17912 100644 --- a/src/g_doom/a_doommisc.cpp +++ b/src/g_doom/a_doommisc.cpp @@ -38,6 +38,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_BarrelDestroy) { + PARAM_ACTION_PROLOGUE; + if (dmflags2 & DF2_BARRELS_RESPAWN) { self->height = self->GetDefault()->height; @@ -48,4 +50,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_BarrelDestroy) { self->Destroy (); } + return 0; } diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp index 1ff05a0f4f..e3a05d0db2 100644 --- a/src/g_doom/a_doomweaps.cpp +++ b/src/g_doom/a_doomweaps.cpp @@ -28,6 +28,8 @@ static FRandom pr_oldbfg ("OldBFG"); // DEFINE_ACTION_FUNCTION(AActor, A_Punch) { + PARAM_ACTION_PROLOGUE; + angle_t angle; int damage; int pitch; @@ -39,7 +41,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Punch) if (weapon != NULL && !(weapon->WeaponFlags & WIF_DEHAMMO) && ACTION_CALL_FROM_WEAPON()) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } } @@ -61,6 +63,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Punch) S_Sound (self, CHAN_WEAPON, "*fist", 1, ATTN_NORM); self->angle = self->AngleTo(linetarget); } + return 0; } // @@ -68,6 +71,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_Punch) // DEFINE_ACTION_FUNCTION(AActor, A_FirePistol) { + PARAM_ACTION_PROLOGUE; + bool accurate; if (self->player != NULL) @@ -76,7 +81,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePistol) if (weapon != NULL && ACTION_CALL_FROM_WEAPON()) { if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1)) - return; + return 0; P_SetPsprite (self->player, ps_flash, weapon->FindState(NAME_Flash)); } @@ -91,7 +96,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePistol) S_Sound (self, CHAN_WEAPON, "weapons/pistol", 1, ATTN_NORM); - P_GunShot (self, accurate, PClass::FindClass(NAME_BulletPuff), P_BulletSlope (self)); + P_GunShot (self, accurate, PClass::FindActor(NAME_BulletPuff), P_BulletSlope (self)); + return 0; } // @@ -111,62 +117,70 @@ enum SAW_Flags DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw) { + PARAM_ACTION_PROLOGUE; + PARAM_SOUND_OPT (fullsound) { fullsound = "weapons/sawfull"; } + PARAM_SOUND_OPT (hitsound) { hitsound = "weapons/sawhit"; } + PARAM_INT_OPT (damage) { damage = 2; } + PARAM_CLASS_OPT (pufftype, AActor) { pufftype = NULL; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_FIXED_OPT (range) { range = 0; } + PARAM_ANGLE_OPT (spread_xy) { spread_xy = angle_t(2.8125 * (ANGLE_90 / 90.0)); } + PARAM_ANGLE_OPT (spread_z) { spread_z = 0; } + PARAM_FIXED_OPT (lifesteal) { lifesteal = 0; } + PARAM_INT_OPT (lifestealmax) { lifestealmax = 0; } + PARAM_CLASS_OPT (armorbonustype, ABasicArmorBonus) { armorbonustype = NULL; } + angle_t angle; angle_t slope; player_t *player; AActor *linetarget; int actualdamage; - ACTION_PARAM_START(11); - ACTION_PARAM_SOUND(fullsound, 0); - ACTION_PARAM_SOUND(hitsound, 1); - ACTION_PARAM_INT(damage, 2); - ACTION_PARAM_CLASS(pufftype, 3); - ACTION_PARAM_INT(Flags, 4); - ACTION_PARAM_FIXED(Range, 5); - ACTION_PARAM_ANGLE(Spread_XY, 6); - ACTION_PARAM_ANGLE(Spread_Z, 7); - ACTION_PARAM_FIXED(LifeSteal, 8); - ACTION_PARAM_INT(lifestealmax, 9); - ACTION_PARAM_CLASS(armorbonustype, 10); - if (NULL == (player = self->player)) { - return; + return 0; } - if (pufftype == NULL) pufftype = PClass::FindClass(NAME_BulletPuff); - if (damage == 0) damage = 2; - - if (!(Flags & SF_NORANDOM)) + if (pufftype == NULL) + { + pufftype = PClass::FindActor(NAME_BulletPuff); + } + if (damage == 0) + { + damage = 2; + } + if (!(flags & SF_NORANDOM)) + { damage *= (pr_saw()%10+1); - - // use meleerange + 1 so the puff doesn't skip the flash (i.e. plays all states) - if (Range == 0) Range = MELEERANGE+1; + } + if (range == 0) + { // use meleerange + 1 so the puff doesn't skip the flash (i.e. plays all states) + range = MELEERANGE+1; + } - angle = self->angle + (pr_saw.Random2() * (Spread_XY / 255)); - slope = P_AimLineAttack (self, angle, Range, &linetarget) + (pr_saw.Random2() * (Spread_Z / 255)); + angle = self->angle + (pr_saw.Random2() * (spread_xy / 255)); + slope = P_AimLineAttack (self, angle, range, &linetarget) + (pr_saw.Random2() * (spread_z / 255)); AWeapon *weapon = self->player->ReadyWeapon; - if ((weapon != NULL) && !(Flags & SF_NOUSEAMMO) && !(!linetarget && (Flags & SF_NOUSEAMMOMISS)) && !(weapon->WeaponFlags & WIF_DEHAMMO) && ACTION_CALL_FROM_WEAPON()) + if ((weapon != NULL) && !(flags & SF_NOUSEAMMO) && !(!linetarget && (flags & SF_NOUSEAMMOMISS)) && !(weapon->WeaponFlags & WIF_DEHAMMO) && ACTION_CALL_FROM_WEAPON()) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } - P_LineAttack (self, angle, Range, slope, damage, NAME_Melee, pufftype, false, &linetarget, &actualdamage); + P_LineAttack (self, angle, range, slope, damage, NAME_Melee, pufftype, false, &linetarget, &actualdamage); if (!linetarget) { - if ((Flags & SF_RANDOMLIGHTMISS) && (pr_saw() > 64)) + if ((flags & SF_RANDOMLIGHTMISS) && (pr_saw() > 64)) { player->extralight = !player->extralight; } S_Sound (self, CHAN_WEAPON, fullsound, 1, ATTN_NORM); - return; + return 0; } - if (Flags & SF_RANDOMLIGHTHIT) + if (flags & SF_RANDOMLIGHTHIT) { int randVal = pr_saw(); if (randVal < 64) @@ -183,16 +197,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw) } } - if (LifeSteal && !(linetarget->flags5 & MF5_DONTDRAIN)) + if (lifesteal && !(linetarget->flags5 & MF5_DONTDRAIN)) { - if (Flags & SF_STEALARMOR) + if (flags & SF_STEALARMOR) { - if (!armorbonustype) armorbonustype = PClass::FindClass("ArmorBonus"); - - if (armorbonustype->IsDescendantOf (RUNTIME_CLASS(ABasicArmorBonus))) + if (armorbonustype == NULL) { - ABasicArmorBonus *armorbonus = static_cast(Spawn (armorbonustype, 0,0,0, NO_REPLACE)); - armorbonus->SaveAmount *= (actualdamage * LifeSteal) >> FRACBITS; + armorbonustype = dyn_cast(PClass::FindClass("ArmorBonus")); + } + if (armorbonustype != NULL) + { + assert(armorbonustype->IsDescendantOf (RUNTIME_CLASS(ABasicArmorBonus))); + ABasicArmorBonus *armorbonus = static_cast(Spawn(armorbonustype, 0,0,0, NO_REPLACE)); + armorbonus->SaveAmount *= (actualdamage * lifesteal) >> FRACBITS; armorbonus->MaxSaveAmount = lifestealmax <= 0 ? armorbonus->MaxSaveAmount : lifestealmax; armorbonus->flags |= MF_DROPPED; armorbonus->ClearCounters(); @@ -206,14 +223,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw) else { - P_GiveBody (self, (actualdamage * LifeSteal) >> FRACBITS, lifestealmax); + P_GiveBody (self, (actualdamage * lifesteal) >> FRACBITS, lifestealmax); } } S_Sound (self, CHAN_WEAPON, hitsound, 1, ATTN_NORM); // turn to face target - if (!(Flags & SF_NOTURN)) + if (!(flags & SF_NOTURN)) { angle = self->AngleTo(linetarget); if (angle - self->angle > ANG180) @@ -231,8 +248,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw) self->angle += ANG90 / 20; } } - if (!(Flags & SF_NOPULLIN)) + if (!(flags & SF_NOPULLIN)) self->flags |= MF_JUSTATTACKED; + return 0; } // @@ -240,12 +258,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw) // DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun) { + PARAM_ACTION_PROLOGUE; + int i; player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } S_Sound (self, CHAN_WEAPON, "weapons/shotgf", 1, ATTN_NORM); @@ -253,15 +273,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun) if (weapon != NULL && ACTION_CALL_FROM_WEAPON()) { if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1)) - return; + return 0; P_SetPsprite (player, ps_flash, weapon->FindState(NAME_Flash)); } player->mo->PlayAttacking2 (); angle_t pitch = P_BulletSlope (self); - for (i=0 ; i<7 ; i++) - P_GunShot (self, false, PClass::FindClass(NAME_BulletPuff), pitch); + for (i = 0; i < 7; i++) + { + P_GunShot (self, false, PClass::FindActor(NAME_BulletPuff), pitch); + } + return 0; } // @@ -269,6 +292,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun) // DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun2) { + PARAM_ACTION_PROLOGUE; + int i; angle_t angle; int damage; @@ -276,7 +301,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun2) if (NULL == (player = self->player)) { - return; + return 0; } S_Sound (self, CHAN_WEAPON, "weapons/sshotf", 1, ATTN_NORM); @@ -284,7 +309,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun2) if (weapon != NULL && ACTION_CALL_FROM_WEAPON()) { if (!weapon->DepleteAmmo (weapon->bAltFire, true, 2)) - return; + return 0; P_SetPsprite (player, ps_flash, weapon->FindState(NAME_Flash)); } player->mo->PlayAttacking2 (); @@ -310,22 +335,29 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun2) pitch + (pr_fireshotgun2.Random2() * 332063), damage, NAME_Hitscan, NAME_BulletPuff); } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_OpenShotgun2) { + PARAM_ACTION_PROLOGUE; S_Sound (self, CHAN_WEAPON, "weapons/sshoto", 1, ATTN_NORM); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_LoadShotgun2) { + PARAM_ACTION_PROLOGUE; S_Sound (self, CHAN_WEAPON, "weapons/sshotl", 1, ATTN_NORM); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_CloseShotgun2) { + PARAM_ACTION_PROLOGUE; S_Sound (self, CHAN_WEAPON, "weapons/sshotc", 1, ATTN_NORM); A_ReFire (self); + return 0; } @@ -341,15 +373,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_CloseShotgun2) void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int index) { - const PClass * cls = weapon->GetClass(); + PClassActor *cls = weapon->GetClass(); while (cls != RUNTIME_CLASS(AWeapon)) { - FActorInfo * info = cls->ActorInfo; - if (flashstate >= info->OwnedStates && flashstate < info->OwnedStates + info->NumOwnedStates) + if (flashstate >= cls->OwnedStates && flashstate < cls->OwnedStates + cls->NumOwnedStates) { // The flash state belongs to this class. // Now let's check if the actually wanted state does also - if (flashstate+index < info->OwnedStates + info->NumOwnedStates) + if (flashstate + index < cls->OwnedStates + cls->NumOwnedStates) { // we're ok so set the state P_SetPsprite (player, ps_flash, flashstate + index); @@ -363,7 +394,7 @@ void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int i } } // try again with parent class - cls = cls->ParentClass; + cls = static_cast(cls->ParentClass); } // if we get here the state doesn't seem to belong to any class in the inheritance chain // This can happen with Dehacked if the flash states are remapped. @@ -382,18 +413,20 @@ void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int i // DEFINE_ACTION_FUNCTION(AActor, A_FireCGun) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (self == NULL || NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = player->ReadyWeapon; if (weapon != NULL && ACTION_CALL_FROM_WEAPON()) { if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1)) - return; + return 0; S_Sound (self, CHAN_WEAPON, "weapons/chngun", 1, ATTN_NORM); @@ -416,7 +449,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireCGun) } player->mo->PlayAttacking2 (); - P_GunShot (self, !player->refire, PClass::FindClass(NAME_BulletPuff), P_BulletSlope (self)); + P_GunShot (self, !player->refire, PClass::FindActor(NAME_BulletPuff), P_BulletSlope (self)); + return 0; } // @@ -424,19 +458,22 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireCGun) // DEFINE_ACTION_FUNCTION(AActor, A_FireMissile) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL && ACTION_CALL_FROM_WEAPON()) { if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1)) - return; + return 0; } - P_SpawnPlayerMissile (self, PClass::FindClass("Rocket")); + P_SpawnPlayerMissile (self, PClass::FindActor("Rocket")); + return 0; } // @@ -444,20 +481,23 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMissile) // DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireSTGrenade) { + PARAM_ACTION_PROLOGUE; + PARAM_CLASS_OPT(grenade, AActor) { grenade = PClass::FindActor("Grenade"); } + player_t *player; - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(grenade, 0); - if (grenade == NULL) return; + + if (grenade == NULL) + return 0; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL && ACTION_CALL_FROM_WEAPON()) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } // Temporarily raise the pitch to send the grenade slightly upwards @@ -465,6 +505,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireSTGrenade) self->pitch -= (1152 << FRACBITS); P_SpawnPlayerMissile(self, grenade); self->pitch = SavedPlayerPitch; + return 0; } // @@ -472,17 +513,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireSTGrenade) // DEFINE_ACTION_FUNCTION(AActor, A_FirePlasma) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL && ACTION_CALL_FROM_WEAPON()) { if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1)) - return; + return 0; FState *flash = weapon->FindState(NAME_Flash); if (flash != NULL) @@ -491,7 +534,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePlasma) } } - P_SpawnPlayerMissile (self, PClass::FindClass("PlasmaBall")); + P_SpawnPlayerMissile (self, PClass::FindActor("PlasmaBall")); + return 0; } // @@ -528,22 +572,29 @@ static void FireRailgun(AActor *self, int offset_xy, bool fromweapon) DEFINE_ACTION_FUNCTION(AActor, A_FireRailgun) { + PARAM_ACTION_PROLOGUE; FireRailgun(self, 0, ACTION_CALL_FROM_WEAPON()); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_FireRailgunRight) { + PARAM_ACTION_PROLOGUE; FireRailgun(self, 10, ACTION_CALL_FROM_WEAPON()); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_FireRailgunLeft) { + PARAM_ACTION_PROLOGUE; FireRailgun(self, -10, ACTION_CALL_FROM_WEAPON()); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_RailWait) { // Okay, this was stupid. Just use a NULL function instead of this. + return 0; } // @@ -552,21 +603,24 @@ DEFINE_ACTION_FUNCTION(AActor, A_RailWait) DEFINE_ACTION_FUNCTION(AActor, A_FireBFG) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL && ACTION_CALL_FROM_WEAPON()) { if (!weapon->DepleteAmmo (weapon->bAltFire, true, deh.BFGCells)) - return; + return 0; } - P_SpawnPlayerMissile (self, 0, 0, 0, PClass::FindClass("BFGBall"), self->angle, NULL, NULL, !!(dmflags2 & DF2_NO_FREEAIMBFG)); + P_SpawnPlayerMissile (self, 0, 0, 0, PClass::FindActor("BFGBall"), self->angle, NULL, NULL, !!(dmflags2 & DF2_NO_FREEAIMBFG)); + return 0; } @@ -576,22 +630,22 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireBFG) // DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray) { + PARAM_ACTION_PROLOGUE; + PARAM_CLASS_OPT (spraytype, AActor) { spraytype = NULL; } + PARAM_INT_OPT (numrays) { numrays = 40; } + PARAM_INT_OPT (damagecnt) { damagecnt = 15; } + PARAM_ANGLE_OPT (angle) { angle = ANGLE_90; } + PARAM_FIXED_OPT (distance) { distance = 16*64*FRACUNIT; } + PARAM_ANGLE_OPT (vrange) { vrange = 32*FRACUNIT; } + PARAM_INT_OPT (defdamage) { defdamage = 0; } + int i; int j; int damage; angle_t an; AActor *linetarget; - ACTION_PARAM_START(7); - ACTION_PARAM_CLASS(spraytype, 0); - ACTION_PARAM_INT(numrays, 1); - ACTION_PARAM_INT(damagecnt, 2); - ACTION_PARAM_ANGLE(angle, 3); - ACTION_PARAM_FIXED(distance, 4); - ACTION_PARAM_ANGLE(vrange, 5); - ACTION_PARAM_INT(defdamage, 6); - - if (spraytype == NULL) spraytype = PClass::FindClass("BFGExtra"); + if (spraytype == NULL) spraytype = PClass::FindActor("BFGExtra"); if (numrays <= 0) numrays = 40; if (damagecnt <= 0) damagecnt = 15; if (angle == 0) angle = ANG90; @@ -600,7 +654,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray) // [RH] Don't crash if no target if (!self->target) - return; + return 0; // offset angles from its attack angle for (i = 0; i < numrays; i++) @@ -646,6 +700,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray) P_TraceBleed(newdam > 0 ? newdam : damage, linetarget, self->target); } } + return 0; } // @@ -653,7 +708,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray) // DEFINE_ACTION_FUNCTION(AActor, A_BFGsound) { + PARAM_ACTION_PROLOGUE; S_Sound (self, CHAN_WEAPON, "weapons/bfgf", 1, ATTN_NORM); + return 0; } // @@ -667,7 +724,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_BFGsound) DEFINE_ACTION_FUNCTION(AActor, A_FireOldBFG) { - const PClass * plasma[] = {PClass::FindClass("PlasmaBall1"), PClass::FindClass("PlasmaBall2")}; + PARAM_ACTION_PROLOGUE; + PClassActor *plasma[] = { PClass::FindActor("PlasmaBall1"), PClass::FindActor("PlasmaBall2") }; AActor * mo = NULL; player_t *player; @@ -675,7 +733,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireOldBFG) if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = self->player->ReadyWeapon; @@ -683,7 +741,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireOldBFG) if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1)) - return; + return 0; doesautoaim = !(weapon->WeaponFlags & WIF_NOAUTOAIM); weapon->WeaponFlags |= WIF_NOAUTOAIM; // No autoaiming that gun @@ -702,5 +760,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireOldBFG) self->angle = SavedPlayerAngle; self->pitch = SavedPlayerPitch; } - if (doesautoaim && weapon != NULL) weapon->WeaponFlags &= ~WIF_NOAUTOAIM; // Restore autoaim setting + if (doesautoaim && weapon != NULL) + { // Restore autoaim setting + weapon->WeaponFlags &= ~WIF_NOAUTOAIM; + } + return 0; } diff --git a/src/g_doom/a_fatso.cpp b/src/g_doom/a_fatso.cpp index 9273febda4..f4d38b2280 100644 --- a/src/g_doom/a_fatso.cpp +++ b/src/g_doom/a_fatso.cpp @@ -19,22 +19,25 @@ DEFINE_ACTION_FUNCTION(AActor, A_FatRaise) { + PARAM_ACTION_PROLOGUE; + A_FaceTarget (self); S_Sound (self, CHAN_WEAPON, "fatso/raiseguns", 1, ATTN_NORM); + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FatAttack1) { + PARAM_ACTION_PROLOGUE; + PARAM_CLASS_OPT(spawntype, AActor) { spawntype = NULL; } + AActor *missile; angle_t an; if (!self->target) - return; + return 0; - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(spawntype, 0); - - if (spawntype == NULL) spawntype = PClass::FindClass("FatShot"); + if (spawntype == NULL) spawntype = PClass::FindActor("FatShot"); A_FaceTarget (self); // Change direction to ... @@ -49,20 +52,21 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FatAttack1) missile->velx = FixedMul (missile->Speed, finecosine[an]); missile->vely = FixedMul (missile->Speed, finesine[an]); } + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FatAttack2) { + PARAM_ACTION_PROLOGUE; + PARAM_CLASS_OPT(spawntype, AActor) { spawntype = NULL; } + AActor *missile; angle_t an; if (!self->target) - return; + return 0; - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(spawntype, 0); - - if (spawntype == NULL) spawntype = PClass::FindClass("FatShot"); + if (spawntype == NULL) spawntype = PClass::FindActor("FatShot"); A_FaceTarget (self); // Now here choose opposite deviation. @@ -77,20 +81,21 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FatAttack2) missile->velx = FixedMul (missile->Speed, finecosine[an]); missile->vely = FixedMul (missile->Speed, finesine[an]); } + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FatAttack3) { + PARAM_ACTION_PROLOGUE; + PARAM_CLASS_OPT(spawntype, AActor) { spawntype = NULL; } + AActor *missile; angle_t an; if (!self->target) - return; + return 0; - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(spawntype, 0); - - if (spawntype == NULL) spawntype = PClass::FindClass("FatShot"); + if (spawntype == NULL) spawntype = PClass::FindActor("FatShot"); A_FaceTarget (self); @@ -111,6 +116,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FatAttack3) missile->velx = FixedMul (missile->Speed, finecosine[an]); missile->vely = FixedMul (missile->Speed, finesine[an]); } + return 0; } // @@ -118,8 +124,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FatAttack3) // Original idea: Linguica // -AActor * P_OldSpawnMissile(AActor * source, AActor * owner, AActor * dest, const PClass *type); - enum { MSF_Standard = 0, @@ -129,17 +133,23 @@ enum DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Mushroom) { + PARAM_ACTION_PROLOGUE; + PARAM_CLASS_OPT (spawntype, AActor) { spawntype = NULL; } + PARAM_INT_OPT (n) { n = 0; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_FIXED_OPT (vrange) { vrange = 4*FRACUNIT; } + PARAM_FIXED_OPT (hrange) { hrange = FRACUNIT/2; } + int i, j; - ACTION_PARAM_START(5); - ACTION_PARAM_CLASS(spawntype, 0); - ACTION_PARAM_INT(n, 1); - ACTION_PARAM_INT(flags, 2); - ACTION_PARAM_FIXED(vrange, 3); - ACTION_PARAM_FIXED(hrange, 4); - - if (n == 0) n = self->Damage; // GetMissileDamage (0, 1); - if (spawntype == NULL) spawntype = PClass::FindClass("FatShot"); + if (n == 0) + { + n = self->GetMissileDamage(0, 1); + } + if (spawntype == NULL) + { + spawntype = PClass::FindActor("FatShot"); + } P_RadiusAttack (self, self->target, 128, 128, self->DamageType, (flags & MSF_DontHurt) ? 0 : RADF_HURTSOURCE); P_CheckSplash(self, 128<Destroy(); + return 0; } diff --git a/src/g_doom/a_keen.cpp b/src/g_doom/a_keen.cpp index 1504bdf389..22a344c449 100644 --- a/src/g_doom/a_keen.cpp +++ b/src/g_doom/a_keen.cpp @@ -13,8 +13,12 @@ // DOOM II special, map 32. // Uses special tag 666 by default. // + DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KeenDie) { + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT(doortag) { doortag = 666; } + A_Unblock(self, false); // scan the remaining thinkers to see if all Keens are dead @@ -27,14 +31,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KeenDie) if (other != self && other->health > 0 && other->IsA (matchClass)) { // other Keen not dead - return; + return 0; } } - ACTION_PARAM_START(1); - ACTION_PARAM_INT(doortag, 0); - EV_DoDoor (DDoor::doorOpen, NULL, NULL, doortag, 2*FRACUNIT, 0, 0, 0); + return 0; } diff --git a/src/g_doom/a_lostsoul.cpp b/src/g_doom/a_lostsoul.cpp index 7dc9a1b8f9..8015af9cd0 100644 --- a/src/g_doom/a_lostsoul.cpp +++ b/src/g_doom/a_lostsoul.cpp @@ -46,22 +46,27 @@ void A_SkullAttack(AActor *self, fixed_t speed) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SkullAttack) { - ACTION_PARAM_START(1); - ACTION_PARAM_FIXED(n, 0); + PARAM_ACTION_PROLOGUE; + PARAM_FIXED_OPT(speed) { speed = SKULLSPEED; } - if (n <= 0) n = SKULLSPEED; - A_SkullAttack(self, n); + if (speed <= 0) + speed = SKULLSPEED; + A_SkullAttack(self, speed); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_BetaSkullAttack) { + PARAM_ACTION_PROLOGUE; + int damage; if (!self || !self->target || self->target->GetSpecies() == self->GetSpecies()) - return; + return 0; S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM); A_FaceTarget(self); - damage = (pr_oldsoul()%8+1)*self->Damage; + damage = (pr_oldsoul()%8+1)*self->GetMissileDamage(0,1); P_DamageMobj(self->target, self, self, damage, NAME_None); + return 0; } diff --git a/src/g_doom/a_painelemental.cpp b/src/g_doom/a_painelemental.cpp index 69d6ef448e..f96e1cda0d 100644 --- a/src/g_doom/a_painelemental.cpp +++ b/src/g_doom/a_painelemental.cpp @@ -12,13 +12,22 @@ DECLARE_ACTION(A_SkullAttack) -static const PClass *GetSpawnType(DECLARE_PARAMINFO) +static PClassActor *GetSpawnType(VMValue *param) { - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(spawntype, 0); + PClassActor *spawntype; - if (spawntype == NULL) spawntype = PClass::FindClass("LostSoul"); - return spawntype; + if (param == NULL || param->Type == REGT_NIL) + { + spawntype = NULL; + } + else + { + assert(param->Type == REGT_POINTER); + assert(param->atag == ATAG_OBJECT || param->a == NULL); + spawntype = (PClassActor *)param->a; + } + + return (spawntype != NULL) ? spawntype : PClass::FindActor("LostSoul"); } @@ -33,13 +42,13 @@ enum PA_Flags // A_PainShootSkull // Spawn a lost soul and launch it at the target // -void A_PainShootSkull (AActor *self, angle_t angle, const PClass *spawntype, int flags = 0, int limit = -1) +void A_PainShootSkull (AActor *self, angle_t angle, PClassActor *spawntype, int flags = 0, int limit = -1) { AActor *other; int prestep; if (spawntype == NULL) return; - if (self->DamageType==NAME_Massacre) return; + if (self->DamageType == NAME_Massacre) return; // [RH] check to make sure it's not too close to the ceiling if (self->Top() + 8*FRACUNIT > self->ceilingz) @@ -163,42 +172,50 @@ void A_PainShootSkull (AActor *self, angle_t angle, const PClass *spawntype, int // DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PainAttack) { + PARAM_ACTION_PROLOGUE; + if (!self->target) - return; + return 0; - ACTION_PARAM_START(4); - ACTION_PARAM_CLASS(spawntype, 0); - ACTION_PARAM_ANGLE(angle, 1); - ACTION_PARAM_INT(flags, 2); - ACTION_PARAM_INT(limit, 3); + PARAM_CLASS_OPT (spawntype, AActor) { spawntype = NULL; } + PARAM_ANGLE_OPT (angle) { angle = 0; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_INT_OPT (limit) { limit = -1; } - if (spawntype == NULL) spawntype = PClass::FindClass("LostSoul"); + if (spawntype == NULL) spawntype = PClass::FindActor("LostSoul"); if (!(flags & PAF_AIMFACING)) A_FaceTarget (self); A_PainShootSkull (self, self->angle+angle, spawntype, flags, limit); + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DualPainAttack) { - if (!self->target) - return; + PARAM_ACTION_PROLOGUE; - const PClass *spawntype = GetSpawnType(PUSH_PARAMINFO); + if (!self->target) + return 0; + + PClassActor *spawntype = GetSpawnType(numparam > NAP ? ¶m[NAP] : NULL); A_FaceTarget (self); A_PainShootSkull (self, self->angle + ANG45, spawntype); A_PainShootSkull (self, self->angle - ANG45, spawntype); + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PainDie) { - if (self->target != NULL && self->IsFriend (self->target)) + PARAM_ACTION_PROLOGUE; + + if (self->target != NULL && self->IsFriend(self->target)) { // And I thought you were my friend! self->flags &= ~MF_FRIENDLY; } - const PClass *spawntype = GetSpawnType(PUSH_PARAMINFO); + PClassActor *spawntype = GetSpawnType(numparam > NAP ? ¶m[NAP] : NULL); A_Unblock(self, true); A_PainShootSkull (self, self->angle + ANG90, spawntype); A_PainShootSkull (self, self->angle + ANG180, spawntype); A_PainShootSkull (self, self->angle + ANG270, spawntype); + return 0; } diff --git a/src/g_doom/a_possessed.cpp b/src/g_doom/a_possessed.cpp index a5fef25326..5f9ab90184 100644 --- a/src/g_doom/a_possessed.cpp +++ b/src/g_doom/a_possessed.cpp @@ -20,12 +20,14 @@ static FRandom pr_cposrefire ("CPosRefire"); // DEFINE_ACTION_FUNCTION(AActor, A_PosAttack) { + PARAM_ACTION_PROLOGUE; + int angle; int damage; int slope; if (!self->target) - return; + return 0; A_FaceTarget (self); angle = self->angle; @@ -35,6 +37,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_PosAttack) angle += pr_posattack.Random2() << 20; damage = ((pr_posattack()%5)+1)*3; P_LineAttack (self, angle, MISSILERANGE, slope, damage, NAME_Hitscan, NAME_BulletPuff); + return 0; } static void A_SPosAttack2 (AActor *self) @@ -57,33 +60,41 @@ static void A_SPosAttack2 (AActor *self) DEFINE_ACTION_FUNCTION(AActor, A_SPosAttackUseAtkSound) { + PARAM_ACTION_PROLOGUE; + if (!self->target) - return; + return 0; S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM); A_SPosAttack2 (self); + return 0; } // This version of the function, which uses a hard-coded sound, is // meant for Dehacked only. DEFINE_ACTION_FUNCTION(AActor, A_SPosAttack) { + PARAM_ACTION_PROLOGUE; + if (!self->target) - return; + return 0; S_Sound (self, CHAN_WEAPON, "shotguy/attack", 1, ATTN_NORM); A_SPosAttack2 (self); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_CPosAttack) { + PARAM_ACTION_PROLOGUE; + int angle; int bangle; int damage; int slope; if (!self->target) - return; + return 0; // [RH] Andy Baker's stealth monsters if (self->flags & MF_STEALTH) @@ -99,15 +110,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_CPosAttack) angle = bangle + (pr_cposattack.Random2() << 20); damage = ((pr_cposattack()%5)+1)*3; P_LineAttack (self, angle, MISSILERANGE, slope, damage, NAME_Hitscan, NAME_BulletPuff); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_CPosRefire) { + PARAM_ACTION_PROLOGUE; + // keep firing unless target got out of sight A_FaceTarget (self); if (pr_cposrefire() < 40) - return; + return 0; if (!self->target || P_HitFriend (self) @@ -116,4 +130,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_CPosRefire) { self->SetState (self->SeeState); } + return 0; } diff --git a/src/g_doom/a_revenant.cpp b/src/g_doom/a_revenant.cpp index 9b8821fb47..7a54d9de44 100644 --- a/src/g_doom/a_revenant.cpp +++ b/src/g_doom/a_revenant.cpp @@ -19,27 +19,32 @@ static FRandom pr_skelfist ("SkelFist"); // A_SkelMissile // DEFINE_ACTION_FUNCTION(AActor, A_SkelMissile) -{ +{ + PARAM_ACTION_PROLOGUE; + AActor *missile; if (!self->target) - return; + return 0; A_FaceTarget (self); missile = P_SpawnMissileZ (self, self->Z() + 48*FRACUNIT, - self->target, PClass::FindClass("RevenantTracer")); + self->target, PClass::FindActor("RevenantTracer")); if (missile != NULL) { missile->SetOrigin(missile->Vec3Offset(missile->velx, missile->vely, 0), false); missile->tracer = self->target; } + return 0; } #define TRACEANGLE (0xc000000) DEFINE_ACTION_FUNCTION(AActor, A_Tracer) { + PARAM_ACTION_PROLOGUE; + angle_t exact; fixed_t dist; fixed_t slope; @@ -56,10 +61,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer) // [RH] level.time is always 0-based, so nothing special to do here. if (level.time & 3) - return; + return 0; // spawn a puff of smoke behind the rocket - P_SpawnPuff (self, PClass::FindClass(NAME_BulletPuff), self->X(), self->Y(), self->Z(), 0, 3); + P_SpawnPuff (self, PClass::FindActor(NAME_BulletPuff), self->X(), self->Y(), self->Z(), 0, 3); smoke = Spawn ("RevenantTracerSmoke", self->Vec3Offset(-self->velx, -self->vely, 0), ALLOW_REPLACE); @@ -72,7 +77,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer) dest = self->tracer; if (!dest || dest->health <= 0 || self->Speed == 0 || !self->CanSeek(dest)) - return; + return 0; // change angle exact = self->AngleTo(dest); @@ -119,21 +124,27 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer) else self->velz += FRACUNIT/8; } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_SkelWhoosh) { + PARAM_ACTION_PROLOGUE; + if (!self->target) - return; + return 0; A_FaceTarget (self); S_Sound (self, CHAN_WEAPON, "skeleton/swing", 1, ATTN_NORM); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_SkelFist) { + PARAM_ACTION_PROLOGUE; + if (!self->target) - return; + return 0; A_FaceTarget (self); @@ -144,4 +155,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkelFist) int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); } + return 0; } diff --git a/src/g_doom/a_scriptedmarine.cpp b/src/g_doom/a_scriptedmarine.cpp index 6e75d80e68..43eec76e1f 100644 --- a/src/g_doom/a_scriptedmarine.cpp +++ b/src/g_doom/a_scriptedmarine.cpp @@ -155,8 +155,8 @@ void AScriptedMarine::Tick () DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Refire) { - ACTION_PARAM_START(1); - ACTION_PARAM_BOOL(ignoremissile, 0); + PARAM_ACTION_PROLOGUE; + PARAM_BOOL_OPT(ignoremissile) { ignoremissile = false; } if (self->target == NULL || self->target->health <= 0) { @@ -164,11 +164,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Refire) { // Look for a new target most of the time if (P_LookForPlayers (self, true, NULL) && P_CheckMissileRange (self)) { // Found somebody new and in range, so don't stop shooting - return; + return 0; } } self->SetState (self->state + 1); - return; + return 0; } if (((ignoremissile || self->MissileState == NULL) && !self->CheckMeleeRange ()) || !P_CheckSight (self, self->target) || @@ -176,6 +176,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Refire) { self->SetState (self->state + 1); } + return 0; } //============================================================================ @@ -186,15 +187,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Refire) DEFINE_ACTION_FUNCTION(AActor, A_M_SawRefire) { + PARAM_ACTION_PROLOGUE; + if (self->target == NULL || self->target->health <= 0) { self->SetState (self->state + 1); - return; + return 0; } if (!self->CheckMeleeRange ()) { self->SetState (self->state + 1); } + return 0; } //============================================================================ @@ -205,10 +209,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_SawRefire) DEFINE_ACTION_FUNCTION(AActor, A_MarineNoise) { + PARAM_ACTION_PROLOGUE; + if (static_cast(self)->CurrentWeapon == AScriptedMarine::WEAPON_Chainsaw) { S_Sound (self, CHAN_WEAPON, "weapons/sawidle", 1, ATTN_NORM); } + return 0; } //============================================================================ @@ -219,8 +226,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_MarineNoise) DEFINE_ACTION_FUNCTION(AActor, A_MarineChase) { + PARAM_ACTION_PROLOGUE; CALL_ACTION(A_MarineNoise, self); - A_Chase (self); + A_Chase (stack, self); + return 0; } //============================================================================ @@ -231,8 +240,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_MarineChase) DEFINE_ACTION_FUNCTION(AActor, A_MarineLook) { + PARAM_ACTION_PROLOGUE; CALL_ACTION(A_MarineNoise, self); CALL_ACTION(A_Look, self); + return 0; } //============================================================================ @@ -243,17 +254,23 @@ DEFINE_ACTION_FUNCTION(AActor, A_MarineLook) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Saw) { - ACTION_PARAM_START(4); - ACTION_PARAM_SOUND(fullsound, 0); - ACTION_PARAM_SOUND(hitsound, 1); - ACTION_PARAM_INT(damage, 2); - ACTION_PARAM_CLASS(pufftype, 3); + PARAM_ACTION_PROLOGUE; + PARAM_SOUND_OPT (fullsound) { fullsound = "weapons/sawfull"; } + PARAM_SOUND_OPT (hitsound) { hitsound = "weapons/sawhit"; } + PARAM_INT_OPT (damage) { damage = 2; } + PARAM_CLASS_OPT (pufftype, AActor) { pufftype = NULL; } if (self->target == NULL) - return; + return 0; - if (pufftype == NULL) pufftype = PClass::FindClass(NAME_BulletPuff); - if (damage == 0) damage = 2; + if (pufftype == NULL) + { + pufftype = PClass::FindActor(NAME_BulletPuff); + } + if (damage == 0) + { + damage = 2; + } A_FaceTarget (self); if (self->CheckMeleeRange ()) @@ -271,7 +288,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Saw) if (!linetarget) { S_Sound (self, CHAN_WEAPON, fullsound, 1, ATTN_NORM); - return; + return 0; } S_Sound (self, CHAN_WEAPON, hitsound, 1, ATTN_NORM); @@ -297,6 +314,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Saw) S_Sound (self, CHAN_WEAPON, fullsound, 1, ATTN_NORM); } //A_Chase (self); + return 0; } //============================================================================ @@ -333,10 +351,11 @@ static void MarinePunch(AActor *self, int damagemul) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Punch) { - ACTION_PARAM_START(1); - ACTION_PARAM_INT(mult, 0); + PARAM_ACTION_PROLOGUE; + PARAM_INT(mult); MarinePunch(self, mult); + return 0; } //============================================================================ @@ -345,7 +364,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Punch) // //============================================================================ -void P_GunShot2 (AActor *mo, bool accurate, int pitch, const PClass *pufftype) +void P_GunShot2 (AActor *mo, bool accurate, int pitch, PClassActor *pufftype) { angle_t angle; int damage; @@ -369,16 +388,17 @@ void P_GunShot2 (AActor *mo, bool accurate, int pitch, const PClass *pufftype) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_FirePistol) { - if (self->target == NULL) - return; + PARAM_ACTION_PROLOGUE; + PARAM_BOOL(accurate); - ACTION_PARAM_START(1); - ACTION_PARAM_BOOL(accurate, 0); + if (self->target == NULL) + return 0; S_Sound (self, CHAN_WEAPON, "weapons/pistol", 1, ATTN_NORM); A_FaceTarget (self); P_GunShot2 (self, accurate, P_AimLineAttack (self, self->angle, MISSILERANGE), - PClass::FindClass(NAME_BulletPuff)); + PClass::FindActor(NAME_BulletPuff)); + return 0; } //============================================================================ @@ -389,19 +409,22 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_FirePistol) DEFINE_ACTION_FUNCTION(AActor, A_M_FireShotgun) { + PARAM_ACTION_PROLOGUE; + int pitch; if (self->target == NULL) - return; + return 0; S_Sound (self, CHAN_WEAPON, "weapons/shotgf", 1, ATTN_NORM); A_FaceTarget (self); pitch = P_AimLineAttack (self, self->angle, MISSILERANGE); for (int i = 0; i < 7; ++i) { - P_GunShot2 (self, false, pitch, PClass::FindClass(NAME_BulletPuff)); + P_GunShot2 (self, false, pitch, PClass::FindActor(NAME_BulletPuff)); } self->special1 = level.maptime + 27; + return 0; } //============================================================================ @@ -412,6 +435,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_FireShotgun) DEFINE_ACTION_FUNCTION(AActor, A_M_CheckAttack) { + PARAM_ACTION_PROLOGUE; + if (self->special1 != 0 || self->target == NULL) { self->SetState (self->FindState("SkipAttack")); @@ -420,6 +445,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_CheckAttack) { A_FaceTarget (self); } + return 0; } //============================================================================ @@ -430,10 +456,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_CheckAttack) DEFINE_ACTION_FUNCTION(AActor, A_M_FireShotgun2) { + PARAM_ACTION_PROLOGUE; + int pitch; if (self->target == NULL) - return; + return 0; S_Sound (self, CHAN_WEAPON, "weapons/sshotf", 1, ATTN_NORM); A_FaceTarget (self); @@ -448,6 +476,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_FireShotgun2) NAME_Hitscan, NAME_BulletPuff); } self->special1 = level.maptime; + return 0; } //============================================================================ @@ -458,16 +487,17 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_FireShotgun2) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_FireCGun) { - if (self->target == NULL) - return; + PARAM_ACTION_PROLOGUE; + PARAM_BOOL(accurate); - ACTION_PARAM_START(1); - ACTION_PARAM_BOOL(accurate, 0); + if (self->target == NULL) + return 0; S_Sound (self, CHAN_WEAPON, "weapons/chngun", 1, ATTN_NORM); A_FaceTarget (self); P_GunShot2 (self, accurate, P_AimLineAttack (self, self->angle, MISSILERANGE), - PClass::FindClass(NAME_BulletPuff)); + PClass::FindActor(NAME_BulletPuff)); + return 0; } //============================================================================ @@ -482,8 +512,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_FireCGun) DEFINE_ACTION_FUNCTION(AActor, A_M_FireMissile) { + PARAM_ACTION_PROLOGUE; + if (self->target == NULL) - return; + return 0; if (self->CheckMeleeRange ()) { // If too close, punch it @@ -492,8 +524,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_FireMissile) else { A_FaceTarget (self); - P_SpawnMissile (self, self->target, PClass::FindClass("Rocket")); + P_SpawnMissile (self, self->target, PClass::FindActor("Rocket")); } + return 0; } //============================================================================ @@ -504,11 +537,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_FireMissile) DEFINE_ACTION_FUNCTION(AActor, A_M_FireRailgun) { + PARAM_ACTION_PROLOGUE; + if (self->target == NULL) - return; + return 0; CALL_ACTION(A_MonsterRail, self); self->special1 = level.maptime + 50; + return 0; } //============================================================================ @@ -519,12 +555,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_FireRailgun) DEFINE_ACTION_FUNCTION(AActor, A_M_FirePlasma) { + PARAM_ACTION_PROLOGUE; + if (self->target == NULL) - return; + return 0; A_FaceTarget (self); - P_SpawnMissile (self, self->target, PClass::FindClass("PlasmaBall")); + P_SpawnMissile (self, self->target, PClass::FindActor("PlasmaBall")); self->special1 = level.maptime + 20; + return 0; } //============================================================================ @@ -535,8 +574,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_FirePlasma) DEFINE_ACTION_FUNCTION(AActor, A_M_BFGsound) { + PARAM_ACTION_PROLOGUE; + if (self->target == NULL) - return; + return 0; if (self->special1 != 0) { @@ -549,6 +590,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_BFGsound) // Don't interrupt the firing sequence self->PainChance = 0; } + return 0; } //============================================================================ @@ -559,13 +601,16 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_BFGsound) DEFINE_ACTION_FUNCTION(AActor, A_M_FireBFG) { + PARAM_ACTION_PROLOGUE; + if (self->target == NULL) - return; + return 0; A_FaceTarget (self); - P_SpawnMissile (self, self->target, PClass::FindClass("BFGBall")); + P_SpawnMissile (self, self->target, PClass::FindActor("BFGBall")); self->special1 = level.maptime + 30; self->PainChance = MARINE_PAIN_CHANCE; + return 0; } //--------------------------------------------------------------------------- @@ -597,11 +642,11 @@ void AScriptedMarine::SetWeapon (EMarineWeapon type) } } -void AScriptedMarine::SetSprite (const PClass *source) +void AScriptedMarine::SetSprite (PClassActor *source) { - if (source == NULL || source->ActorInfo == NULL) + if (source == NULL) { // A valid actor class wasn't passed, so use the standard sprite - SpriteOverride = sprite = GetClass()->ActorInfo->OwnedStates[0].sprite; + SpriteOverride = sprite = GetClass()->OwnedStates[0].sprite; // Copy the standard scaling scaleX = GetDefault()->scaleX; scaleY = GetDefault()->scaleY; diff --git a/src/g_doom/a_spidermaster.cpp b/src/g_doom/a_spidermaster.cpp index 1e3628c694..2f312f7a60 100644 --- a/src/g_doom/a_spidermaster.cpp +++ b/src/g_doom/a_spidermaster.cpp @@ -13,11 +13,13 @@ static FRandom pr_spidrefire ("SpidRefire"); DEFINE_ACTION_FUNCTION(AActor, A_SpidRefire) { + PARAM_ACTION_PROLOGUE; + // keep firing unless target got out of sight A_FaceTarget (self); if (pr_spidrefire() < 10) - return; + return 0; if (!self->target || P_HitFriend (self) @@ -26,10 +28,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpidRefire) { self->SetState (self->SeeState); } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_Metal) { + PARAM_ACTION_PROLOGUE; + S_Sound (self, CHAN_BODY, "spider/walk", 1, ATTN_IDLE); - A_Chase (self); + A_Chase (stack, self); + return 0; } diff --git a/src/g_doomedmap.cpp b/src/g_doomedmap.cpp index 42157101d0..cce2889c79 100644 --- a/src/g_doomedmap.cpp +++ b/src/g_doomedmap.cpp @@ -258,10 +258,10 @@ void InitActorNumsFromMapinfo() while (it.NextPair(pair)) { - const PClass *cls = NULL; + PClassActor *cls = NULL; if (pair->Value.classname != NAME_None) { - cls = PClass::FindClass(pair->Value.classname); + cls = PClass::FindActor(pair->Value.classname); if (cls == NULL) { Printf(TEXTCOLOR_RED "Script error, \"%s\" line %d:\nUnknown actor class %s\n", diff --git a/src/g_game.cpp b/src/g_game.cpp index 7f6305ca48..865e50c23f 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -439,13 +439,16 @@ CCMD (use) { if (argv.argc() > 1 && who != NULL) { - SendItemUse = who->FindInventory (PClass::FindClass (argv[1])); + SendItemUse = who->FindInventory(PClass::FindActor(argv[1])); } } CCMD (invdrop) { - if (players[consoleplayer].mo) SendItemDrop = players[consoleplayer].mo->InvSel; + if (players[consoleplayer].mo) + { + SendItemDrop = players[consoleplayer].mo->InvSel; + } } CCMD (weapdrop) @@ -457,11 +460,11 @@ CCMD (drop) { if (argv.argc() > 1 && who != NULL) { - SendItemDrop = who->FindInventory (PClass::FindClass (argv[1])); + SendItemDrop = who->FindInventory(PClass::FindActor(argv[1])); } } -const PClass *GetFlechetteType(AActor *other); +PClassActor *GetFlechetteType(AActor *other); CCMD (useflechette) { // Select from one of arti_poisonbag1-3, whichever the player has @@ -475,7 +478,7 @@ CCMD (useflechette) if (who == NULL) return; - const PClass *type = GetFlechetteType(who); + PClassActor *type = GetFlechetteType(who); if (type != NULL) { AInventory *item; @@ -502,7 +505,7 @@ CCMD (select) { if (argv.argc() > 1) { - AInventory *item = who->FindInventory (PClass::FindClass (argv[1])); + AInventory *item = who->FindInventory(PClass::FindActor(argv[1])); if (item != NULL) { who->InvSel = item; @@ -1350,7 +1353,7 @@ void G_PlayerReborn (int player) BYTE currclass; userinfo_t userinfo; // [RH] Save userinfo APlayerPawn *actor; - const PClass *cls; + PClassPlayerPawn *cls; FString log; DBot *Bot; //Added by MC: diff --git a/src/g_heretic/a_chicken.cpp b/src/g_heretic/a_chicken.cpp index 329b4d264d..dcc3e17745 100644 --- a/src/g_heretic/a_chicken.cpp +++ b/src/g_heretic/a_chicken.cpp @@ -66,9 +66,11 @@ void AChickenPlayer::MorphPlayerThink () DEFINE_ACTION_FUNCTION(AActor, A_ChicAttack) { + PARAM_ACTION_PROLOGUE; + if (!self->target) { - return; + return 0; } if (self->CheckMeleeRange()) { @@ -76,6 +78,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ChicAttack) int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); } + return 0; } //---------------------------------------------------------------------------- @@ -86,6 +89,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_ChicAttack) DEFINE_ACTION_FUNCTION(AActor, A_Feathers) { + PARAM_ACTION_PROLOGUE; + int i; int count; AActor *mo; @@ -107,6 +112,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Feathers) mo->velz = FRACUNIT + (pr_feathers() << 9); mo->SetState (mo->SpawnState + (pr_feathers()&7)); } + return 0; } //--------------------------------------------------------------------------- @@ -132,14 +138,17 @@ void P_UpdateBeak (AActor *self) DEFINE_ACTION_FUNCTION(AActor, A_BeakRaise) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } player->psprites[ps_weapon].sy = WEAPONTOP; P_SetPsprite (player, ps_weapon, player->ReadyWeapon->GetReadyState()); + return 0; } //---------------------------------------------------------------------------- @@ -161,6 +170,8 @@ void P_PlayPeck (AActor *chicken) DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL1) { + PARAM_ACTION_PROLOGUE; + angle_t angle; int damage; int slope; @@ -169,7 +180,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL1) if (NULL == (player = self->player)) { - return; + return 0; } damage = 1 + (pr_beakatkpl1()&3); @@ -183,6 +194,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL1) P_PlayPeck (player->mo); player->chickenPeck = 12; player->psprites[ps_weapon].tics -= pr_beakatkpl1() & 7; + return 0; } //---------------------------------------------------------------------------- @@ -193,6 +205,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL1) DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL2) { + PARAM_ACTION_PROLOGUE; + angle_t angle; int damage; int slope; @@ -201,7 +215,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL2) if (NULL == (player = self->player)) { - return; + return 0; } damage = pr_beakatkpl2.HitDice (4); @@ -215,4 +229,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL2) P_PlayPeck (player->mo); player->chickenPeck = 12; player->psprites[ps_weapon].tics -= pr_beakatkpl2()&3; + return 0; } diff --git a/src/g_heretic/a_dsparil.cpp b/src/g_heretic/a_dsparil.cpp index bb3cfb0c5d..938f4427b4 100644 --- a/src/g_heretic/a_dsparil.cpp +++ b/src/g_heretic/a_dsparil.cpp @@ -28,8 +28,11 @@ static FRandom pr_bluespark ("BlueSpark"); DEFINE_ACTION_FUNCTION(AActor, A_Sor1Pain) { + PARAM_ACTION_PROLOGUE; + self->special1 = 20; // Number of steps to walk fast CALL_ACTION(A_Pain, self); + return 0; } //---------------------------------------------------------------------------- @@ -40,12 +43,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_Sor1Pain) DEFINE_ACTION_FUNCTION(AActor, A_Sor1Chase) { + PARAM_ACTION_PROLOGUE; + if (self->special1) { self->special1--; self->tics -= 3; } - A_Chase(self); + A_Chase(stack, self); + return 0; } //---------------------------------------------------------------------------- @@ -58,13 +64,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_Sor1Chase) DEFINE_ACTION_FUNCTION(AActor, A_Srcr1Attack) { + PARAM_ACTION_PROLOGUE; + AActor *mo; fixed_t velz; angle_t angle; if (!self->target) { - return; + return 0; } S_Sound (self, CHAN_BODY, self->AttackSound, 1, ATTN_NORM); if (self->CheckMeleeRange ()) @@ -72,10 +80,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_Srcr1Attack) int damage = pr_scrc1atk.HitDice (8); int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); - return; + return 0; } - const PClass *fx = PClass::FindClass("SorcererFX1"); + PClassActor *fx = PClass::FindActor("SorcererFX1"); if (self->health > (self->SpawnHealth()/3)*2) { // Spit one fireball P_SpawnMissileZ (self, self->Z() + 48*FRACUNIT, self->target, fx ); @@ -103,6 +111,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Srcr1Attack) } } } + return 0; } //---------------------------------------------------------------------------- @@ -113,6 +122,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_Srcr1Attack) DEFINE_ACTION_FUNCTION(AActor, A_SorcererRise) { + PARAM_ACTION_PROLOGUE; + AActor *mo; self->flags &= ~MF_SOLID; @@ -121,6 +132,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcererRise) mo->SetState (mo->FindState("Rise")); mo->angle = self->angle; mo->CopyFriendliness (self, true); + return 0; } //---------------------------------------------------------------------------- @@ -167,6 +179,7 @@ void P_DSparilTeleport (AActor *actor) DEFINE_ACTION_FUNCTION(AActor, A_Srcr2Decide) { + PARAM_ACTION_PROLOGUE; static const int chance[] = { @@ -183,6 +196,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Srcr2Decide) { P_DSparilTeleport (self); } + return 0; } //---------------------------------------------------------------------------- @@ -193,11 +207,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_Srcr2Decide) DEFINE_ACTION_FUNCTION(AActor, A_Srcr2Attack) { + PARAM_ACTION_PROLOGUE; + int chance; if (!self->target) { - return; + return 0; } S_Sound (self, CHAN_BODY, self->AttackSound, 1, ATTN_NONE); if (self->CheckMeleeRange()) @@ -205,13 +221,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_Srcr2Attack) int damage = pr_s2a.HitDice (20); int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); - return; + return 0; } chance = self->health < self->SpawnHealth()/2 ? 96 : 48; if (pr_s2a() < chance) { // Wizard spawners - const PClass *fx = PClass::FindClass("Sorcerer2FX2"); + PClassActor *fx = PClass::FindActor("Sorcerer2FX2"); if (fx) { P_SpawnMissileAngle (self, fx, self->angle-ANG45, FRACUNIT/2); @@ -220,8 +236,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_Srcr2Attack) } else { // Blue bolt - P_SpawnMissile (self, self->target, PClass::FindClass("Sorcerer2FX1")); + P_SpawnMissile (self, self->target, PClass::FindActor("Sorcerer2FX1")); } + return 0; } //---------------------------------------------------------------------------- @@ -232,6 +249,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_Srcr2Attack) DEFINE_ACTION_FUNCTION(AActor, A_BlueSpark) { + PARAM_ACTION_PROLOGUE; + int i; AActor *mo; @@ -242,6 +261,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BlueSpark) mo->vely = pr_bluespark.Random2() << 9; mo->velz = FRACUNIT + (pr_bluespark()<<8); } + return 0; } //---------------------------------------------------------------------------- @@ -252,6 +272,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_BlueSpark) DEFINE_ACTION_FUNCTION(AActor, A_GenWizard) { + PARAM_ACTION_PROLOGUE; + AActor *mo; mo = Spawn("Wizard", self->Pos(), ALLOW_REPLACE); @@ -275,6 +297,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_GenWizard) Spawn (self->Pos(), ALLOW_REPLACE); } } + return 0; } //---------------------------------------------------------------------------- @@ -285,8 +308,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_GenWizard) DEFINE_ACTION_FUNCTION(AActor, A_Sor2DthInit) { + PARAM_ACTION_PROLOGUE; + self->special1 = 7; // Animation loop counter P_Massacre (); // Kill monsters early + return 0; } //---------------------------------------------------------------------------- @@ -297,9 +323,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_Sor2DthInit) DEFINE_ACTION_FUNCTION(AActor, A_Sor2DthLoop) { + PARAM_ACTION_PROLOGUE; + if (--self->special1) { // Need to loop self->SetState (self->FindState("DeathLoop")); } + return 0; } diff --git a/src/g_heretic/a_hereticartifacts.cpp b/src/g_heretic/a_hereticartifacts.cpp index 322869f19e..65a5a58598 100644 --- a/src/g_heretic/a_hereticartifacts.cpp +++ b/src/g_heretic/a_hereticartifacts.cpp @@ -47,12 +47,15 @@ bool AArtiTomeOfPower::Use (bool pickup) DEFINE_ACTION_FUNCTION(AActor, A_TimeBomb) { + PARAM_ACTION_PROLOGUE; + self->AddZ(32*FRACUNIT, false); self->PrevZ = self->Z(); // no interpolation! self->RenderStyle = STYLE_Add; self->alpha = FRACUNIT; P_RadiusAttack (self, self->target, 128, 128, self->DamageType, RADF_HURTSOURCE); P_CheckSplash(self, 128<target || pr_impmsatk() > 64) { self->SetState (self->SeeState); - return; + return 0; } A_SkullAttack(self, 12 * FRACUNIT); + return 0; } //---------------------------------------------------------------------------- @@ -37,6 +40,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_ImpMsAttack) DEFINE_ACTION_FUNCTION(AActor, A_ImpExplode) { + PARAM_ACTION_PROLOGUE; + AActor *chunk; self->flags &= ~MF_NOGRAVITY; @@ -54,6 +59,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ImpExplode) { // Extreme death crash self->SetState (self->FindState("XCrash")); } + return 0; } //---------------------------------------------------------------------------- @@ -64,8 +70,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_ImpExplode) DEFINE_ACTION_FUNCTION(AActor, A_ImpDeath) { + PARAM_ACTION_PROLOGUE; + self->flags &= ~MF_SOLID; self->flags2 |= MF2_FLOORCLIP; + return 0; } //---------------------------------------------------------------------------- @@ -76,9 +85,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_ImpDeath) DEFINE_ACTION_FUNCTION(AActor, A_ImpXDeath1) { + PARAM_ACTION_PROLOGUE; + self->flags &= ~MF_SOLID; self->flags |= MF_NOGRAVITY; self->flags2 |= MF2_FLOORCLIP; self->special1 = 666; // Flag the crash routine + return 0; } diff --git a/src/g_heretic/a_hereticmisc.cpp b/src/g_heretic/a_hereticmisc.cpp index 09c3d42538..91499bd68b 100644 --- a/src/g_heretic/a_hereticmisc.cpp +++ b/src/g_heretic/a_hereticmisc.cpp @@ -43,8 +43,8 @@ static FRandom pr_volcimpact ("VolcBallImpact"); DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PodPain) { - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(gootype, 0); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS_OPT (gootype, AActor) { gootype = PClass::FindActor("PodGoo"); } int count; int chance; @@ -53,7 +53,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PodPain) chance = pr_podpain (); if (chance < 128) { - return; + return 0; } for (count = chance > 240 ? 2 : 1; count; count--) { @@ -63,6 +63,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PodPain) goo->vely = pr_podpain.Random2() << 9; goo->velz = FRACUNIT/2 + (pr_podpain() << 9); } + return 0; } //---------------------------------------------------------------------------- @@ -73,15 +74,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PodPain) DEFINE_ACTION_FUNCTION(AActor, A_RemovePod) { + PARAM_ACTION_PROLOGUE; + AActor *mo; - if ( (mo = self->master)) + if ( (mo = self->master) ) { if (mo->special1 > 0) { mo->special1--; } } + return 0; } //---------------------------------------------------------------------------- @@ -94,8 +98,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_RemovePod) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MakePod) { - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(podtype, 0); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS_OPT(podtype, AActor) { podtype = PClass::FindActor("Pod"); } AActor *mo; fixed_t x; @@ -103,7 +107,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MakePod) if (self->special1 == MAX_GEN_PODS) { // Too many generated pods - return; + return 0; } x = self->X(); y = self->Y(); @@ -111,14 +115,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MakePod) if (!P_CheckPosition (mo, x, y)) { // Didn't fit mo->Destroy (); - return; + return 0; } mo->SetState (mo->FindState("Grow")); P_ThrustMobj (mo, pr_makepod()<<24, (fixed_t)(4.5*FRACUNIT)); S_Sound (mo, CHAN_BODY, self->AttackSound, 1, ATTN_IDLE); self->special1++; // Increment generated pod count mo->master = self; // Link the generator to the pod - return; + return 0; } //---------------------------------------------------------------------------- @@ -129,10 +133,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MakePod) DEFINE_ACTION_FUNCTION(AActor, A_AccTeleGlitter) { + PARAM_ACTION_PROLOGUE; + if (++self->health > 35) { self->velz += self->velz/2; } + return 0; } @@ -144,7 +151,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_AccTeleGlitter) DEFINE_ACTION_FUNCTION(AActor, A_VolcanoSet) { + PARAM_ACTION_PROLOGUE; + self->tics = 105 + (pr_volcano() & 127); + return 0; } //---------------------------------------------------------------------------- @@ -155,6 +165,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_VolcanoSet) DEFINE_ACTION_FUNCTION(AActor, A_VolcanoBlast) { + PARAM_ACTION_PROLOGUE; + int i; int count; AActor *blast; @@ -174,6 +186,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_VolcanoBlast) S_Sound (blast, CHAN_BODY, "world/volcano/shoot", 1, ATTN_NORM); P_CheckMissileSpawn (blast, self->radius); } + return 0; } //---------------------------------------------------------------------------- @@ -184,6 +197,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_VolcanoBlast) DEFINE_ACTION_FUNCTION(AActor, A_VolcBallImpact) { + PARAM_ACTION_PROLOGUE; + unsigned int i; AActor *tiny; angle_t angle; @@ -208,5 +223,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_VolcBallImpact) tiny->velz = FRACUNIT + (pr_volcimpact() << 9); P_CheckMissileSpawn (tiny, self->radius); } + return 0; } diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp index c6ccc6ae6a..636b25a257 100644 --- a/src/g_heretic/a_hereticweaps.cpp +++ b/src/g_heretic/a_hereticweaps.cpp @@ -61,6 +61,8 @@ extern bool P_AutoUseChaosDevice (player_t *player); DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StaffAttack) { + PARAM_ACTION_PROLOGUE; + angle_t angle; int slope; player_t *player; @@ -68,20 +70,22 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StaffAttack) if (NULL == (player = self->player)) { - return; + return 0; } - ACTION_PARAM_START(2); - ACTION_PARAM_INT(damage, 0); - ACTION_PARAM_CLASS(puff, 1); + PARAM_INT (damage); + PARAM_CLASS (puff, AActor); AWeapon *weapon = player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; + } + if (puff == NULL) + { + puff = PClass::FindActor(NAME_BulletPuff); // just to be sure } - if (puff == NULL) puff = PClass::FindClass(NAME_BulletPuff); // just to be sure angle = self->angle; angle += pr_sap.Random2() << 18; slope = P_AimLineAttack (self, angle, MELEERANGE, &linetarget); @@ -92,6 +96,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StaffAttack) // turn to face target self->angle = self->AngleTo(linetarget); } + return 0; } @@ -103,20 +108,22 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StaffAttack) DEFINE_ACTION_FUNCTION(AActor, A_FireGoldWandPL1) { + PARAM_ACTION_PROLOGUE; + angle_t angle; int damage; player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } angle_t pitch = P_BulletSlope(self); damage = 7+(pr_fgw()&7); @@ -127,6 +134,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireGoldWandPL1) } P_LineAttack (self, angle, PLAYERMISSILERANGE, pitch, damage, NAME_Hitscan, "GoldWandPuff1"); S_Sound (self, CHAN_WEAPON, "weapons/wandhit", 1, ATTN_NORM); + return 0; } //---------------------------------------------------------------------------- @@ -137,6 +145,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireGoldWandPL1) DEFINE_ACTION_FUNCTION(AActor, A_FireGoldWandPL2) { + PARAM_ACTION_PROLOGUE; + int i; angle_t angle; int damage; @@ -145,20 +155,20 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireGoldWandPL2) if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } angle_t pitch = P_BulletSlope(self); velz = FixedMul (GetDefaultByName("GoldWandFX2")->Speed, finetangent[FINEANGLES/4-((signed)pitch>>ANGLETOFINESHIFT)]); - P_SpawnMissileAngle (self, PClass::FindClass("GoldWandFX2"), self->angle-(ANG45/8), velz); - P_SpawnMissileAngle (self, PClass::FindClass("GoldWandFX2"), self->angle+(ANG45/8), velz); + P_SpawnMissileAngle (self, PClass::FindActor("GoldWandFX2"), self->angle-(ANG45/8), velz); + P_SpawnMissileAngle (self, PClass::FindActor("GoldWandFX2"), self->angle+(ANG45/8), velz); angle = self->angle-(ANG45/8); for(i = 0; i < 5; i++) { @@ -167,6 +177,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireGoldWandPL2) angle += ((ANG45/8)*2)/4; } S_Sound (self, CHAN_WEAPON, "weapons/wandhit", 1, ATTN_NORM); + return 0; } //---------------------------------------------------------------------------- @@ -177,22 +188,25 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireGoldWandPL2) DEFINE_ACTION_FUNCTION(AActor, A_FireCrossbowPL1) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } - P_SpawnPlayerMissile (self, PClass::FindClass("CrossbowFX1")); - P_SpawnPlayerMissile (self, PClass::FindClass("CrossbowFX3"), self->angle-(ANG45/10)); - P_SpawnPlayerMissile (self, PClass::FindClass("CrossbowFX3"), self->angle+(ANG45/10)); + P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX1")); + P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX3"), self->angle-(ANG45/10)); + P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX3"), self->angle+(ANG45/10)); + return 0; } //---------------------------------------------------------------------------- @@ -203,24 +217,27 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireCrossbowPL1) DEFINE_ACTION_FUNCTION(AActor, A_FireCrossbowPL2) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } - P_SpawnPlayerMissile (self, PClass::FindClass("CrossbowFX2")); - P_SpawnPlayerMissile (self, PClass::FindClass("CrossbowFX2"), self->angle-(ANG45/10)); - P_SpawnPlayerMissile (self, PClass::FindClass("CrossbowFX2"), self->angle+(ANG45/10)); - P_SpawnPlayerMissile (self, PClass::FindClass("CrossbowFX3"), self->angle-(ANG45/5)); - P_SpawnPlayerMissile (self, PClass::FindClass("CrossbowFX3"), self->angle+(ANG45/5)); + P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX2")); + P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX2"), self->angle-(ANG45/10)); + P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX2"), self->angle+(ANG45/10)); + P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX3"), self->angle-(ANG45/5)); + P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX3"), self->angle+(ANG45/5)); + return 0; } //--------------------------------------------------------------------------- @@ -231,29 +248,30 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireCrossbowPL2) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GauntletAttack) { + PARAM_ACTION_PROLOGUE; + angle_t angle; int damage; int slope; int randVal; fixed_t dist; player_t *player; - const PClass *pufftype; + PClassActor *pufftype; AActor *linetarget; int actualdamage = 0; if (NULL == (player = self->player)) { - return; + return 0; } - ACTION_PARAM_START(1); - ACTION_PARAM_INT(power, 0); + PARAM_INT(power); AWeapon *weapon = player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } player->psprites[ps_weapon].sx = ((pr_gatk()&3)-2) * FRACUNIT; player->psprites[ps_weapon].sy = WEAPONTOP + (pr_gatk()&3) * FRACUNIT; @@ -263,14 +281,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GauntletAttack) damage = pr_gatk.HitDice (2); dist = 4*MELEERANGE; angle += pr_gatk.Random2() << 17; - pufftype = PClass::FindClass("GauntletPuff2"); + pufftype = PClass::FindActor("GauntletPuff2"); } else { damage = pr_gatk.HitDice (2); dist = MELEERANGE+1; angle += pr_gatk.Random2() << 18; - pufftype = PClass::FindClass("GauntletPuff1"); + pufftype = PClass::FindActor("GauntletPuff1"); } slope = P_AimLineAttack (self, angle, dist, &linetarget); P_LineAttack (self, angle, dist, slope, damage, NAME_Melee, pufftype, false, &linetarget, &actualdamage); @@ -281,7 +299,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GauntletAttack) player->extralight = !player->extralight; } S_Sound (self, CHAN_AUTO, "weapons/gauntletson", 1, ATTN_NORM); - return; + return 0; } randVal = pr_gatk(); if (randVal < 64) @@ -322,6 +340,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GauntletAttack) self->angle += ANG90/20; } self->flags |= MF_JUSTATTACKED; + return 0; } // --- Mace ----------------------------------------------------------------- @@ -404,33 +423,36 @@ void FireMacePL1B (AActor *actor) DEFINE_ACTION_FUNCTION(AActor, A_FireMacePL1) { + PARAM_ACTION_PROLOGUE; + AActor *ball; player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } if (pr_maceatk() < 28) { FireMacePL1B (self); - return; + return 0; } AWeapon *weapon = player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } player->psprites[ps_weapon].sx = ((pr_maceatk()&3)-2)*FRACUNIT; player->psprites[ps_weapon].sy = WEAPONTOP+(pr_maceatk()&3)*FRACUNIT; - ball = P_SpawnPlayerMissile (self, PClass::FindClass("MaceFX1"), + ball = P_SpawnPlayerMissile (self, PClass::FindActor("MaceFX1"), self->angle+(((pr_maceatk()&7)-4)<<24)); if (ball) { ball->special1 = 16; // tics till dropoff } + return 0; } //---------------------------------------------------------------------------- @@ -441,14 +463,16 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMacePL1) DEFINE_ACTION_FUNCTION(AActor, A_MacePL1Check) { + PARAM_ACTION_PROLOGUE; + if (self->special1 == 0) { - return; + return 0; } self->special1 -= 4; if (self->special1 > 0) { - return; + return 0; } self->special1 = 0; self->flags &= ~MF_NOGRAVITY; @@ -467,6 +491,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MacePL1Check) self->vely = (int)(self->vely * velscale); #endif self->velz -= self->velz >> 1; + return 0; } //---------------------------------------------------------------------------- @@ -477,6 +502,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_MacePL1Check) DEFINE_ACTION_FUNCTION(AActor, A_MaceBallImpact) { + PARAM_ACTION_PROLOGUE; + if ((self->health != MAGIC_JUNK) && (self->flags & MF_INBOUNCE)) { // Bounce self->health = MAGIC_JUNK; @@ -492,6 +519,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MaceBallImpact) self->gravity = FRACUNIT; S_Sound (self, CHAN_BODY, "weapons/macehit", 1, ATTN_NORM); } + return 0; } //---------------------------------------------------------------------------- @@ -502,13 +530,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_MaceBallImpact) DEFINE_ACTION_FUNCTION(AActor, A_MaceBallImpact2) { + PARAM_ACTION_PROLOGUE; + AActor *tiny; angle_t angle; if ((self->Z() <= self->floorz) && P_HitFloor (self)) { // Landed in some sort of liquid self->Destroy (); - return; + return 0; } if (self->flags & MF_INBOUNCE) { @@ -549,6 +579,7 @@ boom: self->BounceFlags = BOUNCE_None; self->gravity = FRACUNIT; } + return 0; } //---------------------------------------------------------------------------- @@ -559,20 +590,22 @@ boom: DEFINE_ACTION_FUNCTION(AActor, A_FireMacePL2) { + PARAM_ACTION_PROLOGUE; + AActor *mo; player_t *player; AActor *linetarget; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } mo = P_SpawnPlayerMissile (self, 0,0,0, RUNTIME_CLASS(AMaceFX4), self->angle, &linetarget); if (mo) @@ -587,6 +620,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMacePL2) } } S_Sound (self, CHAN_WEAPON, "weapons/maceshoot", 1, ATTN_NORM); + return 0; } //---------------------------------------------------------------------------- @@ -597,6 +631,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMacePL2) DEFINE_ACTION_FUNCTION(AActor, A_DeathBallImpact) { + PARAM_ACTION_PROLOGUE; + int i; AActor *target; angle_t angle = 0; @@ -606,7 +642,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DeathBallImpact) if ((self->Z() <= self->floorz) && P_HitFloor (self)) { // Landed in some sort of liquid self->Destroy (); - return; + return 0; } if (self->flags & MF_INBOUNCE) { @@ -664,6 +700,7 @@ boom: self->gravity = FRACUNIT; S_Sound (self, CHAN_BODY, "weapons/maceexplode", 1, ATTN_NORM); } + return 0; } @@ -739,20 +776,22 @@ int ARipper::DoSpecialDamage (AActor *target, int damage, FName damagetype) DEFINE_ACTION_FUNCTION(AActor, A_FireBlasterPL1) { + PARAM_ACTION_PROLOGUE; + angle_t angle; int damage; player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } angle_t pitch = P_BulletSlope(self); damage = pr_fb1.HitDice (4); @@ -763,6 +802,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireBlasterPL1) } P_LineAttack (self, angle, PLAYERMISSILERANGE, pitch, damage, NAME_Hitscan, "BlasterPuff"); S_Sound (self, CHAN_WEAPON, "weapons/blastershoot", 1, ATTN_NORM); + return 0; } //---------------------------------------------------------------------------- @@ -773,6 +813,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireBlasterPL1) DEFINE_ACTION_FUNCTION(AActor, A_SpawnRippers) { + PARAM_ACTION_PROLOGUE; + unsigned int i; angle_t angle; AActor *ripper; @@ -788,6 +830,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnRippers) ripper->vely = FixedMul (ripper->Speed, finesine[angle]); P_CheckMissileSpawn (ripper, self->radius); } + return 0; } // --- Skull rod ------------------------------------------------------------ @@ -860,26 +903,29 @@ void ARainTracker::Serialize (FArchive &arc) DEFINE_ACTION_FUNCTION(AActor, A_FireSkullRodPL1) { + PARAM_ACTION_PROLOGUE; + AActor *mo; player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } - mo = P_SpawnPlayerMissile (self, PClass::FindClass("HornRodFX1")); + mo = P_SpawnPlayerMissile (self, PClass::FindActor("HornRodFX1")); // Randomize the first frame if (mo && pr_fsr1() > 128) { mo->SetState (mo->state->GetNextState()); } + return 0; } //---------------------------------------------------------------------------- @@ -893,19 +939,21 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSkullRodPL1) DEFINE_ACTION_FUNCTION(AActor, A_FireSkullRodPL2) { + PARAM_ACTION_PROLOGUE; + player_t *player; AActor *MissileActor; AActor *linetarget; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } P_SpawnPlayerMissile (self, 0,0,0, RUNTIME_CLASS(AHornRodFX2), self->angle, &linetarget, &MissileActor); // Use MissileActor instead of the return value from @@ -920,6 +968,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSkullRodPL2) } S_Sound (MissileActor, CHAN_WEAPON, "weapons/hornrodpowshoot", 1, ATTN_NORM); } + return 0; } //---------------------------------------------------------------------------- @@ -930,11 +979,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSkullRodPL2) DEFINE_ACTION_FUNCTION(AActor, A_AddPlayerRain) { + PARAM_ACTION_PROLOGUE; + ARainTracker *tracker; if (self->target == NULL || self->target->health <= 0) { // Shooter is dead or nonexistant - return; + return 0; } tracker = self->target->FindInventory (); @@ -977,6 +1028,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_AddPlayerRain) tracker->Rain1 = self; } self->special1 = S_FindSound ("misc/rain"); + return 0; } //---------------------------------------------------------------------------- @@ -987,6 +1039,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_AddPlayerRain) DEFINE_ACTION_FUNCTION(AActor, A_SkullRodStorm) { + PARAM_ACTION_PROLOGUE; + AActor *mo; ARainTracker *tracker; @@ -996,7 +1050,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkullRodStorm) if (self->target == NULL) { // Player left the game self->Destroy (); - return; + return 0; } tracker = self->target->FindInventory (); if (tracker != NULL) @@ -1011,18 +1065,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkullRodStorm) } } self->Destroy (); - return; + return 0; } if (pr_storm() < 25) { // Fudge rain frequency - return; + return 0; } fixedvec2 pos = self->Vec2Offset( ((pr_storm()&127) - 64) * FRACUNIT, ((pr_storm()&127) - 64) * FRACUNIT); mo = Spawn (pos.x, pos.y, ONCEILINGZ, ALLOW_REPLACE); // We used bouncecount to store the 3D floor index in A_HideInCeiling - if (!mo) return; + if (!mo) return 0; fixed_t newz; if (self->bouncecount >= 0 && (unsigned)self->bouncecount < self->Sector->e->XFloor.ffloors.Size()) @@ -1043,6 +1097,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkullRodStorm) { S_Sound (self, CHAN_BODY|CHAN_LOOP, self->special1, 1, ATTN_NORM); } + return 0; } //---------------------------------------------------------------------------- @@ -1053,6 +1108,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkullRodStorm) DEFINE_ACTION_FUNCTION(AActor, A_RainImpact) { + PARAM_ACTION_PROLOGUE; if (self->Z() > self->floorz) { self->SetState (self->FindState("NotFloor")); @@ -1061,6 +1117,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_RainImpact) { P_HitFloor (self); } + return 0; } //---------------------------------------------------------------------------- @@ -1071,6 +1128,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_RainImpact) DEFINE_ACTION_FUNCTION(AActor, A_HideInCeiling) { + PARAM_ACTION_PROLOGUE; + // We use bouncecount to store the 3D floor index fixed_t foo; for (unsigned int i=0; i< self->Sector->e->XFloor.ffloors.Size(); i++) @@ -1082,11 +1141,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_HideInCeiling) { self->SetZ(foo + 4*FRACUNIT, false); self->bouncecount = i; - return; + return 0; } } self->bouncecount = -1; self->SetZ(self->ceilingz + 4*FRACUNIT, false); + return 0; } // --- Phoenix Rod ---------------------------------------------------------- @@ -1170,25 +1230,28 @@ int APhoenixFX2::DoSpecialDamage (AActor *target, int damage, FName damagetype) DEFINE_ACTION_FUNCTION(AActor, A_FirePhoenixPL1) { + PARAM_ACTION_PROLOGUE; + angle_t angle; player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } P_SpawnPlayerMissile (self, RUNTIME_CLASS(APhoenixFX1)); angle = self->angle + ANG180; angle >>= ANGLETOFINESHIFT; self->velx += FixedMul (4*FRACUNIT, finecosine[angle]); self->vely += FixedMul (4*FRACUNIT, finesine[angle]); + return 0; } //---------------------------------------------------------------------------- @@ -1199,6 +1262,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePhoenixPL1) DEFINE_ACTION_FUNCTION(AActor, A_PhoenixPuff) { + PARAM_ACTION_PROLOGUE; + AActor *puff; angle_t angle; @@ -1216,6 +1281,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_PhoenixPuff) puff->velx = FixedMul (FRACUNIT*13/10, finecosine[angle]); puff->vely = FixedMul (FRACUNIT*13/10, finesine[angle]); puff->velz = 0; + return 0; } //---------------------------------------------------------------------------- @@ -1226,6 +1292,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_PhoenixPuff) DEFINE_ACTION_FUNCTION(AActor, A_InitPhoenixPL2) { + PARAM_ACTION_PROLOGUE; + if (self->player != NULL) { APhoenixRod *flamethrower = static_cast (self->player->ReadyWeapon); @@ -1234,6 +1302,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_InitPhoenixPL2) flamethrower->FlameCount = FLAME_THROWER_TICS; } } + return 0; } //---------------------------------------------------------------------------- @@ -1246,6 +1315,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_InitPhoenixPL2) DEFINE_ACTION_FUNCTION(AActor, A_FirePhoenixPL2) { + PARAM_ACTION_PROLOGUE; + AActor *mo; angle_t angle; @@ -1256,7 +1327,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePhoenixPL2) if (NULL == (player = self->player)) { - return; + return 0; } soundid = "weapons/phoenixpowshoot"; @@ -1267,7 +1338,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePhoenixPL2) P_SetPsprite (player, ps_weapon, flamethrower->FindState("Powerdown")); player->refire = 0; S_StopSound (self, CHAN_WEAPON); - return; + return 0; } angle = self->angle; @@ -1288,6 +1359,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePhoenixPL2) S_Sound (self, CHAN_WEAPON|CHAN_LOOP, soundid, 1, ATTN_NORM); } P_CheckMissileSpawn (mo, self->radius); + return 0; } //---------------------------------------------------------------------------- @@ -1298,19 +1370,22 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePhoenixPL2) DEFINE_ACTION_FUNCTION(AActor, A_ShutdownPhoenixPL2) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } S_StopSound (self, CHAN_WEAPON); AWeapon *weapon = player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } + return 0; } //---------------------------------------------------------------------------- @@ -1321,7 +1396,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_ShutdownPhoenixPL2) DEFINE_ACTION_FUNCTION(AActor, A_FlameEnd) { + PARAM_ACTION_PROLOGUE; + self->velz += FRACUNIT*3/2; + return 0; } //---------------------------------------------------------------------------- @@ -1332,6 +1410,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_FlameEnd) DEFINE_ACTION_FUNCTION(AActor, A_FloatPuff) { + PARAM_ACTION_PROLOGUE; + self->velz += FRACUNIT*18/10; + return 0; } diff --git a/src/g_heretic/a_ironlich.cpp b/src/g_heretic/a_ironlich.cpp index 206ba5e8b5..7262db2e5f 100644 --- a/src/g_heretic/a_ironlich.cpp +++ b/src/g_heretic/a_ironlich.cpp @@ -63,6 +63,8 @@ int AWhirlwind::DoSpecialDamage (AActor *target, int damage, FName damagetype) DEFINE_ACTION_FUNCTION(AActor, A_LichAttack) { + PARAM_ACTION_PROLOGUE; + int i; AActor *fire; AActor *baseFire; @@ -81,7 +83,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichAttack) target = self->target; if (target == NULL) { - return; + return 0; } A_FaceTarget (self); if (self->CheckMeleeRange ()) @@ -89,18 +91,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichAttack) int damage = pr_atk.HitDice (6); int newdam = P_DamageMobj (target, self, self, damage, NAME_Melee); P_TraceBleed (newdam > 0 ? newdam : damage, target, self); - return; + return 0; } dist = self->AproxDistance (target) > 8*64*FRACUNIT; randAttack = pr_atk (); if (randAttack < atkResolve1[dist]) { // Ice ball - P_SpawnMissile (self, target, PClass::FindClass("HeadFX1")); + P_SpawnMissile (self, target, PClass::FindActor("HeadFX1")); S_Sound (self, CHAN_BODY, "ironlich/attack2", 1, ATTN_NORM); } else if (randAttack < atkResolve2[dist]) { // Fire column - baseFire = P_SpawnMissile (self, target, PClass::FindClass("HeadFX3")); + baseFire = P_SpawnMissile (self, target, PClass::FindActor("HeadFX3")); if (baseFire != NULL) { baseFire->SetState (baseFire->FindState("NoGrow")); @@ -116,7 +118,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichAttack) fire->velx = baseFire->velx; fire->vely = baseFire->vely; fire->velz = baseFire->velz; - fire->Damage = 0; + fire->Damage = NULL; fire->health = (i+1) * 2; P_CheckMissileSpawn (fire, self->radius); } @@ -135,6 +137,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichAttack) S_Sound (self, CHAN_BODY, "ironlich/attack3", 1, ATTN_NORM); } } + return 0; } //---------------------------------------------------------------------------- @@ -145,13 +148,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichAttack) DEFINE_ACTION_FUNCTION(AActor, A_WhirlwindSeek) { + PARAM_ACTION_PROLOGUE; + self->health -= 3; if (self->health < 0) { self->velx = self->vely = self->velz = 0; self->SetState (self->FindState(NAME_Death)); self->flags &= ~MF_MISSILE; - return; + return 0; } if ((self->special2 -= 3) < 0) { @@ -160,9 +165,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_WhirlwindSeek) } if (self->tracer && self->tracer->flags&MF_SHADOW) { - return; + return 0; } P_SeekerMissile (self, ANGLE_1*10, ANGLE_1*30); + return 0; } //---------------------------------------------------------------------------- @@ -173,6 +179,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_WhirlwindSeek) DEFINE_ACTION_FUNCTION(AActor, A_LichIceImpact) { + PARAM_ACTION_PROLOGUE; + unsigned int i; angle_t angle; AActor *shard; @@ -189,6 +197,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichIceImpact) shard->velz = -FRACUNIT*6/10; P_CheckMissileSpawn (shard, self->radius); } + return 0; } //---------------------------------------------------------------------------- @@ -199,6 +208,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichIceImpact) DEFINE_ACTION_FUNCTION(AActor, A_LichFireGrow) { + PARAM_ACTION_PROLOGUE; + self->health--; self->AddZ(9*FRACUNIT); if (self->health == 0) @@ -206,5 +217,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichFireGrow) self->Damage = self->GetDefault()->Damage; self->SetState (self->FindState("NoGrow")); } + return 0; } diff --git a/src/g_heretic/a_knight.cpp b/src/g_heretic/a_knight.cpp index 0ae5a240a8..f335ddcffc 100644 --- a/src/g_heretic/a_knight.cpp +++ b/src/g_heretic/a_knight.cpp @@ -21,6 +21,8 @@ static FRandom pr_knightatk ("KnightAttack"); DEFINE_ACTION_FUNCTION(AActor, A_DripBlood) { + PARAM_ACTION_PROLOGUE; + AActor *mo; fixed_t xo = (pr_dripblood.Random2() << 11); @@ -29,6 +31,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DripBlood) mo->velx = pr_dripblood.Random2 () << 10; mo->vely = pr_dripblood.Random2 () << 10; mo->gravity = FRACUNIT/8; + return 0; } //---------------------------------------------------------------------------- @@ -39,9 +42,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_DripBlood) DEFINE_ACTION_FUNCTION(AActor, A_KnightAttack) { + PARAM_ACTION_PROLOGUE; + if (!self->target) { - return; + return 0; } if (self->CheckMeleeRange ()) { @@ -49,16 +54,17 @@ DEFINE_ACTION_FUNCTION(AActor, A_KnightAttack) int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); S_Sound (self, CHAN_BODY, "hknight/melee", 1, ATTN_NORM); - return; + return 0; } // Throw axe S_Sound (self, CHAN_BODY, self->AttackSound, 1, ATTN_NORM); if (self->flags & MF_SHADOW || pr_knightatk () < 40) { // Red axe - P_SpawnMissileZ (self, self->Z() + 36*FRACUNIT, self->target, PClass::FindClass("RedAxe")); - return; + P_SpawnMissileZ (self, self->Z() + 36*FRACUNIT, self->target, PClass::FindActor("RedAxe")); + return 0; } // Green axe - P_SpawnMissileZ (self, self->Z() + 36*FRACUNIT, self->target, PClass::FindClass("KnightAxe")); + P_SpawnMissileZ (self, self->Z() + 36*FRACUNIT, self->target, PClass::FindActor("KnightAxe")); + return 0; } diff --git a/src/g_heretic/a_wizard.cpp b/src/g_heretic/a_wizard.cpp index ea5e6559b7..b6b3861122 100644 --- a/src/g_heretic/a_wizard.cpp +++ b/src/g_heretic/a_wizard.cpp @@ -20,8 +20,11 @@ static FRandom pr_wizatk3 ("WizAtk3"); DEFINE_ACTION_FUNCTION(AActor, A_GhostOff) { + PARAM_ACTION_PROLOGUE; + self->RenderStyle = STYLE_Normal; self->flags3 &= ~MF3_GHOST; + return 0; } //---------------------------------------------------------------------------- @@ -32,8 +35,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_GhostOff) DEFINE_ACTION_FUNCTION(AActor, A_WizAtk1) { + PARAM_ACTION_PROLOGUE; + A_FaceTarget (self); CALL_ACTION(A_GhostOff, self); + return 0; } //---------------------------------------------------------------------------- @@ -44,10 +50,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_WizAtk1) DEFINE_ACTION_FUNCTION(AActor, A_WizAtk2) { + PARAM_ACTION_PROLOGUE; + A_FaceTarget (self); self->alpha = HR_SHADOW; self->RenderStyle = STYLE_Translucent; self->flags3 |= MF3_GHOST; + return 0; } //---------------------------------------------------------------------------- @@ -58,12 +67,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_WizAtk2) DEFINE_ACTION_FUNCTION(AActor, A_WizAtk3) { + PARAM_ACTION_PROLOGUE; + AActor *mo; CALL_ACTION(A_GhostOff, self); if (!self->target) { - return; + return 0; } S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM); if (self->CheckMeleeRange()) @@ -71,13 +82,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_WizAtk3) int damage = pr_wizatk3.HitDice (4); int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); - return; + return 0; } - const PClass *fx = PClass::FindClass("WizardFX1"); + PClassActor *fx = PClass::FindActor("WizardFX1"); mo = P_SpawnMissile (self, self->target, fx); if (mo != NULL) { P_SpawnMissileAngle(self, fx, mo->angle-(ANG45/8), mo->velz); P_SpawnMissileAngle(self, fx, mo->angle+(ANG45/8), mo->velz); } + return 0; } diff --git a/src/g_hexen/a_bats.cpp b/src/g_hexen/a_bats.cpp index 8edb68cee9..035137675d 100644 --- a/src/g_hexen/a_bats.cpp +++ b/src/g_hexen/a_bats.cpp @@ -27,23 +27,28 @@ static FRandom pr_batmove ("BatMove"); DEFINE_ACTION_FUNCTION(AActor, A_BatSpawnInit) { + PARAM_ACTION_PROLOGUE; + self->special1 = 0; // Frequency count + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_BatSpawn) { + PARAM_ACTION_PROLOGUE; + AActor *mo; int delta; angle_t angle; // Countdown until next spawn - if (self->special1-- > 0) return; + if (self->special1-- > 0) return 0; self->special1 = self->args[0]; // Reset frequency count delta = self->args[1]; if (delta==0) delta=1; angle = self->angle + (((pr_batspawn()%delta)-(delta>>1))<<24); - mo = P_SpawnMissileAngle (self, PClass::FindClass ("Bat"), angle, 0); + mo = P_SpawnMissileAngle (self, PClass::FindActor("Bat"), angle, 0); if (mo) { mo->args[0] = pr_batspawn()&63; // floatbob index @@ -51,11 +56,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_BatSpawn) mo->special2 = self->args[3]<<3; // Set lifetime mo->target = self; } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_BatMove) { + PARAM_ACTION_PROLOGUE; + angle_t newangle; if (self->special2 < 0) @@ -86,4 +94,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_BatMove) // Handle Z movement self->SetZ(self->target->Z() + 16*finesine[self->args[0] << BOBTOFINESHIFT]); self->args[0] = (self->args[0]+3)&63; + return 0; } diff --git a/src/g_hexen/a_bishop.cpp b/src/g_hexen/a_bishop.cpp index 167fae5685..9bef4f1dc8 100644 --- a/src/g_hexen/a_bishop.cpp +++ b/src/g_hexen/a_bishop.cpp @@ -24,9 +24,11 @@ static FRandom pr_pain ("BishopPainBlur"); DEFINE_ACTION_FUNCTION(AActor, A_BishopAttack) { + PARAM_ACTION_PROLOGUE; + if (!self->target) { - return; + return 0; } S_Sound (self, CHAN_BODY, self->AttackSound, 1, ATTN_NORM); if (self->CheckMeleeRange()) @@ -34,9 +36,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopAttack) int damage = pr_atk.HitDice (4); int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); - return; + return 0; } self->special1 = (pr_atk() & 3) + 5; + return 0; } //============================================================================ @@ -48,20 +51,23 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopAttack) DEFINE_ACTION_FUNCTION(AActor, A_BishopAttack2) { + PARAM_ACTION_PROLOGUE; + AActor *mo; if (!self->target || !self->special1) { self->special1 = 0; self->SetState (self->SeeState); - return; + return 0; } - mo = P_SpawnMissile (self, self->target, PClass::FindClass("BishopFX")); + mo = P_SpawnMissile (self, self->target, PClass::FindActor("BishopFX")); if (mo != NULL) { mo->tracer = self->target; } self->special1--; + return 0; } //============================================================================ @@ -72,7 +78,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopAttack2) DEFINE_ACTION_FUNCTION(AActor, A_BishopMissileWeave) { + PARAM_ACTION_PROLOGUE; + A_Weave(self, 2, 2, 2*FRACUNIT, FRACUNIT); + return 0; } //============================================================================ @@ -83,14 +92,17 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopMissileWeave) DEFINE_ACTION_FUNCTION(AActor, A_BishopDecide) { + PARAM_ACTION_PROLOGUE; + if (pr_decide() < 220) { - return; + return 0; } else { self->SetState (self->FindState ("Blur")); - } + } + return 0; } //============================================================================ @@ -101,6 +113,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopDecide) DEFINE_ACTION_FUNCTION(AActor, A_BishopDoBlur) { + PARAM_ACTION_PROLOGUE; + self->special1 = (pr_doblur() & 3) + 3; // Random number of blurs if (pr_doblur() < 120) { @@ -115,6 +129,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopDoBlur) P_ThrustMobj (self, self->angle, 11*FRACUNIT); } S_Sound (self, CHAN_BODY, "BishopBlur", 1, ATTN_NORM); + return 0; } //============================================================================ @@ -125,6 +140,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopDoBlur) DEFINE_ACTION_FUNCTION(AActor, A_BishopSpawnBlur) { + PARAM_ACTION_PROLOGUE; + AActor *mo; if (!--self->special1) @@ -145,6 +162,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopSpawnBlur) { mo->angle = self->angle; } + return 0; } //============================================================================ @@ -155,10 +173,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopSpawnBlur) DEFINE_ACTION_FUNCTION(AActor, A_BishopChase) { + PARAM_ACTION_PROLOGUE; + fixed_t newz = self->Z() - finesine[self->special2 << BOBTOFINESHIFT] * 4; self->special2 = (self->special2 + 4) & 63; newz += finesine[self->special2 << BOBTOFINESHIFT] * 4; self->SetZ(newz); + return 0; } //============================================================================ @@ -169,6 +190,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopChase) DEFINE_ACTION_FUNCTION(AActor, A_BishopPuff) { + PARAM_ACTION_PROLOGUE; + AActor *mo; mo = Spawn ("BishopPuff", self->PosPlusZ(40*FRACUNIT), ALLOW_REPLACE); @@ -176,6 +199,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopPuff) { mo->velz = FRACUNIT/2; } + return 0; } //============================================================================ @@ -186,12 +210,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopPuff) DEFINE_ACTION_FUNCTION(AActor, A_BishopPainBlur) { + PARAM_ACTION_PROLOGUE; + AActor *mo; if (pr_pain() < 64) { self->SetState (self->FindState ("Blur")); - return; + return 0; } fixed_t xo = (pr_pain.Random2() << 12); fixed_t yo = (pr_pain.Random2() << 12); @@ -201,4 +227,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopPainBlur) { mo->angle = self->angle; } + return 0; } diff --git a/src/g_hexen/a_blastradius.cpp b/src/g_hexen/a_blastradius.cpp index bbd87c87d1..c832115859 100644 --- a/src/g_hexen/a_blastradius.cpp +++ b/src/g_hexen/a_blastradius.cpp @@ -22,7 +22,7 @@ // //========================================================================== -void BlastActor (AActor *victim, fixed_t strength, fixed_t speed, AActor * Owner, const PClass * blasteffect, bool dontdamage) +void BlastActor (AActor *victim, fixed_t strength, fixed_t speed, AActor *Owner, PClassActor *blasteffect, bool dontdamage) { angle_t angle,ang; AActor *mo; @@ -97,13 +97,13 @@ enum DEFINE_ACTION_FUNCTION_PARAMS (AActor, A_Blast) { - ACTION_PARAM_START(6); - ACTION_PARAM_INT (blastflags, 0); - ACTION_PARAM_FIXED(strength, 1); - ACTION_PARAM_FIXED(radius, 2); - ACTION_PARAM_FIXED(speed, 3); - ACTION_PARAM_CLASS(blasteffect, 4); - ACTION_PARAM_SOUND(blastsound, 5); + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT (blastflags) { blastflags = 0; } + PARAM_INT_OPT (strength) { strength = 255; } + PARAM_INT_OPT (radius) { radius = 255; } + PARAM_FIXED_OPT (speed) { speed = 20; } + PARAM_CLASS_OPT (blasteffect, AActor) { blasteffect = PClass::FindActor("BlastEffect"); } + PARAM_SOUND_OPT (blastsound) { blastsound = "BlastRadius"; } AActor *mo; TThinkerIterator iterator; @@ -111,15 +111,19 @@ DEFINE_ACTION_FUNCTION_PARAMS (AActor, A_Blast) if (self->player && (blastflags & BF_USEAMMO) && ACTION_CALL_FROM_WEAPON()) { - AWeapon * weapon = self->player->ReadyWeapon; + AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL && !weapon->DepleteAmmo(weapon->bAltFire)) - return; + { + return 0; + } } S_Sound (self, CHAN_AUTO, blastsound, 1, ATTN_NORM); - if (!(blastflags & BF_DONTWARN)) P_NoiseAlert (self, self); - + if (!(blastflags & BF_DONTWARN)) + { + P_NoiseAlert (self, self); + } while ( (mo = iterator.Next ()) ) { if ((mo == self) || ((mo->flags2 & MF2_BOSS) && !(blastflags & BF_AFFECTBOSSES)) @@ -149,4 +153,5 @@ DEFINE_ACTION_FUNCTION_PARAMS (AActor, A_Blast) } BlastActor (mo, strength, speed, self, blasteffect, !!(blastflags & BF_NOIMPACTDAMAGE)); } + return 0; } diff --git a/src/g_hexen/a_centaur.cpp b/src/g_hexen/a_centaur.cpp index f7ba3b99f9..ff79ae9fd5 100644 --- a/src/g_hexen/a_centaur.cpp +++ b/src/g_hexen/a_centaur.cpp @@ -16,6 +16,8 @@ static FRandom pr_centaurdefend ("CentaurDefend"); DEFINE_ACTION_FUNCTION(AActor, A_CentaurDefend) { + PARAM_ACTION_PROLOGUE; + A_FaceTarget (self); if (self->CheckMeleeRange() && pr_centaurdefend() < 32) { @@ -24,4 +26,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_CentaurDefend) self->flags2&=~(MF2_REFLECTIVE|MF2_INVULNERABLE); self->SetState (self->MeleeState); } + return 0; } diff --git a/src/g_hexen/a_clericflame.cpp b/src/g_hexen/a_clericflame.cpp index d2bc983296..bde92992fa 100644 --- a/src/g_hexen/a_clericflame.cpp +++ b/src/g_hexen/a_clericflame.cpp @@ -69,20 +69,23 @@ void ACFlameMissile::Effect () DEFINE_ACTION_FUNCTION(AActor, A_CFlameAttack) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } P_SpawnPlayerMissile (self, RUNTIME_CLASS(ACFlameMissile)); S_Sound (self, CHAN_WEAPON, "ClericFlameFire", 1, ATTN_NORM); + return 0; } //============================================================================ @@ -93,11 +96,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_CFlameAttack) DEFINE_ACTION_FUNCTION(AActor, A_CFlamePuff) { + PARAM_ACTION_PROLOGUE; + self->renderflags &= ~RF_INVISIBLE; self->velx = 0; self->vely = 0; self->velz = 0; S_Sound (self, CHAN_BODY, "ClericFlameExplode", 1, ATTN_NORM); + return 0; } //============================================================================ @@ -108,6 +114,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_CFlamePuff) DEFINE_ACTION_FUNCTION(AActor, A_CFlameMissile) { + PARAM_ACTION_PROLOGUE; + int i; int an, an90; fixed_t dist; @@ -150,6 +158,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CFlameMissile) } self->SetState (self->SpawnState); } + return 0; } //============================================================================ @@ -160,10 +169,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_CFlameMissile) DEFINE_ACTION_FUNCTION(AActor, A_CFlameRotate) { + PARAM_ACTION_PROLOGUE; + int an; an = (self->angle+ANG90)>>ANGLETOFINESHIFT; self->velx = self->special1+FixedMul(FLAMEROTSPEED, finecosine[an]); self->vely = self->special2+FixedMul(FLAMEROTSPEED, finesine[an]); self->angle += ANG90/15; + return 0; } diff --git a/src/g_hexen/a_clericholy.cpp b/src/g_hexen/a_clericholy.cpp index 5604ee7e34..466c0f7c8a 100644 --- a/src/g_hexen/a_clericholy.cpp +++ b/src/g_hexen/a_clericholy.cpp @@ -130,6 +130,8 @@ bool AHolySpirit::SpecialBlastHandling (AActor *source, fixed_t strength) DEFINE_ACTION_FUNCTION(AActor, A_CHolyAttack2) { + PARAM_ACTION_PROLOGUE; + int j; int i; AActor *mo; @@ -175,6 +177,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolyAttack2) } SpawnSpiritTail (mo); } + return 0; } //============================================================================ @@ -207,24 +210,30 @@ void SpawnSpiritTail (AActor *spirit) DEFINE_ACTION_FUNCTION(AActor, A_CHolyAttack) { + PARAM_ACTION_PROLOGUE; + player_t *player; AActor *linetarget; if (NULL == (player = self->player)) { - return; + return 0; } ACWeapWraithverge *weapon = static_cast (self->player->ReadyWeapon); if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; + } + AActor *missile = P_SpawnPlayerMissile (self, 0,0,0, PClass::FindActor("HolyMissile"), self->angle, &linetarget); + if (missile != NULL) + { + missile->tracer = linetarget; } - AActor * missile = P_SpawnPlayerMissile (self, 0,0,0, PClass::FindClass ("HolyMissile"), self->angle, &linetarget); - if (missile != NULL) missile->tracer = linetarget; weapon->CHolyCount = 3; S_Sound (self, CHAN_WEAPON, "HolySymbolFire", 1, ATTN_NORM); + return 0; } //============================================================================ @@ -235,6 +244,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolyAttack) DEFINE_ACTION_FUNCTION(AActor, A_CHolyPalette) { + PARAM_ACTION_PROLOGUE; + if (self->player != NULL) { ACWeapWraithverge *weapon = static_cast (self->player->ReadyWeapon); @@ -243,6 +254,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolyPalette) weapon->CHolyCount--; } } + return 0; } //============================================================================ @@ -316,6 +328,8 @@ static void CHolyTailRemove (AActor *actor) DEFINE_ACTION_FUNCTION(AActor, A_CHolyTail) { + PARAM_ACTION_PROLOGUE; + AActor *parent; parent = self->target; @@ -323,7 +337,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolyTail) if (parent == NULL || parent->health <= 0) // better check for health than current state - it's safer! { // Ghost removed, so remove all tail parts CHolyTailRemove (self); - return; + return 0; } else { @@ -335,6 +349,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolyTail) } CHolyTailFollow (self, 10*FRACUNIT); } + return 0; } //============================================================================ @@ -471,6 +486,8 @@ void CHolyWeave (AActor *actor, FRandom &pr_random) DEFINE_ACTION_FUNCTION(AActor, A_CHolySeek) { + PARAM_ACTION_PROLOGUE; + self->health--; if (self->health <= 0) { @@ -479,7 +496,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolySeek) self->velz = 0; self->SetState (self->FindState(NAME_Death)); self->tics -= pr_holyseek()&3; - return; + return 0; } if (self->tracer) { @@ -491,6 +508,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolySeek) } } CHolyWeave (self, pr_holyweave); + return 0; } //============================================================================ @@ -501,6 +519,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolySeek) DEFINE_ACTION_FUNCTION(AActor, A_CHolyCheckScream) { + PARAM_ACTION_PROLOGUE; + CALL_ACTION(A_CHolySeek, self); if (pr_checkscream() < 20) { @@ -510,6 +530,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolyCheckScream) { CHolyFindTarget(self); } + return 0; } //============================================================================ @@ -521,10 +542,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolyCheckScream) DEFINE_ACTION_FUNCTION(AActor, A_ClericAttack) { - if (!self->target) return; + PARAM_ACTION_PROLOGUE; - AActor * missile = P_SpawnMissileZ (self, self->Z() + 40*FRACUNIT, self->target, PClass::FindClass ("HolyMissile")); + if (!self->target) return 0; + + AActor * missile = P_SpawnMissileZ (self, self->Z() + 40*FRACUNIT, self->target, PClass::FindActor ("HolyMissile")); if (missile != NULL) missile->tracer = NULL; // No initial target S_Sound (self, CHAN_WEAPON, "HolySymbolFire", 1, ATTN_NORM); + return 0; } diff --git a/src/g_hexen/a_clericmace.cpp b/src/g_hexen/a_clericmace.cpp index 79b5df3402..ecd28da4f3 100644 --- a/src/g_hexen/a_clericmace.cpp +++ b/src/g_hexen/a_clericmace.cpp @@ -17,6 +17,8 @@ static FRandom pr_maceatk ("CMaceAttack"); DEFINE_ACTION_FUNCTION(AActor, A_CMaceAttack) { + PARAM_ACTION_PROLOGUE; + angle_t angle; int damage; int slope; @@ -26,9 +28,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_CMaceAttack) if (NULL == (player = self->player)) { - return; + return 0; } + PClassActor *hammertime = PClass::FindActor("HammerPuff"); + damage = 25+(pr_maceatk()&15); for (i = 0; i < 16; i++) { @@ -36,7 +40,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CMaceAttack) slope = P_AimLineAttack (player->mo, angle, 2*MELEERANGE, &linetarget); if (linetarget) { - P_LineAttack (player->mo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, PClass::FindClass ("HammerPuff"), true, &linetarget); + P_LineAttack (player->mo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, hammertime, true, &linetarget); if (linetarget != NULL) { AdjustPlayerAngle (player->mo, linetarget); @@ -47,7 +51,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CMaceAttack) slope = P_AimLineAttack (player->mo, angle, 2*MELEERANGE, &linetarget); if (linetarget) { - P_LineAttack (player->mo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, PClass::FindClass ("HammerPuff"), true, &linetarget); + P_LineAttack (player->mo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, hammertime, true, &linetarget); if (linetarget != NULL) { AdjustPlayerAngle (player->mo, linetarget); @@ -60,7 +64,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CMaceAttack) angle = player->mo->angle; slope = P_AimLineAttack (player->mo, angle, MELEERANGE, &linetarget); - P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, PClass::FindClass ("HammerPuff")); + P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, hammertime); macedone: - return; + return 0; } diff --git a/src/g_hexen/a_clericstaff.cpp b/src/g_hexen/a_clericstaff.cpp index eeda968fa1..a5a5fdfece 100644 --- a/src/g_hexen/a_clericstaff.cpp +++ b/src/g_hexen/a_clericstaff.cpp @@ -46,6 +46,8 @@ int ACStaffMissile::DoSpecialDamage (AActor *target, int damage, FName damagetyp DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck) { + PARAM_ACTION_PROLOGUE; + APlayerPawn *pmo; int damage; int newLife, max; @@ -54,45 +56,47 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck) int i; player_t *player; AActor *linetarget; + PClassActor *puff; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = self->player->ReadyWeapon; pmo = player->mo; damage = 20+(pr_staffcheck()&15); max = pmo->GetMaxHealth(); + puff = PClass::FindActor("CStaffPuff"); for (i = 0; i < 3; i++) { angle = pmo->angle+i*(ANG45/16); slope = P_AimLineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), &linetarget, 0, ALF_CHECK3D); if (linetarget) { - P_LineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, PClass::FindClass ("CStaffPuff"), false, &linetarget); + P_LineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, puff, false, &linetarget); if (linetarget != NULL) { pmo->angle = pmo->AngleTo(linetarget); - if (((linetarget->player && (!linetarget->IsTeammate (pmo) || level.teamdamage != 0))|| linetarget->flags3&MF3_ISMONSTER) + if (((linetarget->player && (!linetarget->IsTeammate (pmo) || level.teamdamage != 0))|| linetarget->flags3&MF3_ISMONSTER) && (!(linetarget->flags2&(MF2_DORMANT|MF2_INVULNERABLE)))) + { + newLife = player->health+(damage>>3); + newLife = newLife > max ? max : newLife; + if (newLife > player->health) { - newLife = player->health+(damage>>3); - newLife = newLife > max ? max : newLife; - if (newLife > player->health) - { - pmo->health = player->health = newLife; - } + pmo->health = player->health = newLife; + } if (weapon != NULL) { FState * newstate = weapon->FindState("Drain"); if (newstate != NULL) P_SetPsprite(player, ps_weapon, newstate); - } - } - if (weapon != NULL) - { - weapon->DepleteAmmo (weapon->bAltFire, false); + } } + if (weapon != NULL) + { + weapon->DepleteAmmo (weapon->bAltFire, false); + } } break; } @@ -100,17 +104,17 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck) slope = P_AimLineAttack (player->mo, angle, fixed_t(1.5*MELEERANGE), &linetarget, 0, ALF_CHECK3D); if (linetarget) { - P_LineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, PClass::FindClass ("CStaffPuff"), false, &linetarget); + P_LineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, puff, false, &linetarget); if (linetarget != NULL) { pmo->angle = pmo->AngleTo(linetarget); - if ((linetarget->player && (!linetarget->IsTeammate (pmo) || level.teamdamage != 0)) || linetarget->flags3&MF3_ISMONSTER) - { - newLife = player->health+(damage>>4); - newLife = newLife > max ? max : newLife; - pmo->health = player->health = newLife; - P_SetPsprite (player, ps_weapon, weapon->FindState ("Drain")); - } + if ((linetarget->player && (!linetarget->IsTeammate (pmo) || level.teamdamage != 0)) || linetarget->flags3&MF3_ISMONSTER) + { + newLife = player->health+(damage>>4); + newLife = newLife > max ? max : newLife; + pmo->health = player->health = newLife; + P_SetPsprite (player, ps_weapon, weapon->FindState ("Drain")); + } if (weapon != NULL) { weapon->DepleteAmmo (weapon->bAltFire, false); @@ -119,6 +123,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck) break; } } + return 0; } //============================================================================ @@ -129,19 +134,21 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck) DEFINE_ACTION_FUNCTION(AActor, A_CStaffAttack) { + PARAM_ACTION_PROLOGUE; + AActor *mo; player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } mo = P_SpawnPlayerMissile (self, RUNTIME_CLASS(ACStaffMissile), self->angle-(ANG45/15)); if (mo) @@ -154,6 +161,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffAttack) mo->WeaveIndexXY = 0; } S_Sound (self, CHAN_WEAPON, "ClericCStaffFire", 1, ATTN_NORM); + return 0; } //============================================================================ @@ -164,7 +172,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffAttack) DEFINE_ACTION_FUNCTION(AActor, A_CStaffMissileSlither) { + PARAM_ACTION_PROLOGUE; + A_Weave(self, 3, 0, FRACUNIT, 0); + return 0; } //============================================================================ @@ -175,7 +186,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffMissileSlither) DEFINE_ACTION_FUNCTION(AActor, A_CStaffInitBlink) { + PARAM_ACTION_PROLOGUE; + self->weaponspecial = (pr_blink()>>1)+20; + return 0; } //============================================================================ @@ -186,6 +200,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffInitBlink) DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheckBlink) { + PARAM_ACTION_PROLOGUE; + if (self->player && self->player->ReadyWeapon) { if (!--self->weaponspecial) @@ -198,4 +214,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheckBlink) DoReadyWeapon(self); } } + return 0; } diff --git a/src/g_hexen/a_dragon.cpp b/src/g_hexen/a_dragon.cpp index 9dc577aa94..ca934dbe67 100644 --- a/src/g_hexen/a_dragon.cpp +++ b/src/g_hexen/a_dragon.cpp @@ -86,7 +86,7 @@ static void DragonSeek (AActor *actor, angle_t thresh, angle_t turnMax) } else if (pr_dragonseek() < 128 && P_CheckMissileRange(actor)) { - P_SpawnMissile(actor, target, PClass::FindClass ("DragonFireball")); + P_SpawnMissile(actor, target, PClass::FindActor("DragonFireball")); S_Sound (actor, CHAN_WEAPON, actor->AttackSound, 1, ATTN_NORM); } actor->target = oldTarget; @@ -155,6 +155,8 @@ static void DragonSeek (AActor *actor, angle_t thresh, angle_t turnMax) DEFINE_ACTION_FUNCTION(AActor, A_DragonInitFlight) { + PARAM_ACTION_PROLOGUE; + FActorIterator iterator (self->tid); do @@ -163,10 +165,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonInitFlight) if (self->tracer == NULL) { self->SetState (self->SpawnState); - return; + return 0; } } while (self->tracer == self); self->RemoveFromHash (); + return 0; } //============================================================================ @@ -177,6 +180,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonInitFlight) DEFINE_ACTION_FUNCTION(AActor, A_DragonFlight) { + PARAM_ACTION_PROLOGUE; + angle_t angle; DragonSeek (self, 4*ANGLE_1, 8*ANGLE_1); @@ -185,7 +190,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonFlight) if(!(self->target->flags&MF_SHOOTABLE)) { // target died self->target = NULL; - return; + return 0; } angle = self->AngleTo(self->target); if (absangle(self->angle-angle) < ANGLE_45/2 && self->CheckMeleeRange()) @@ -205,6 +210,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonFlight) { P_LookForPlayers (self, true, NULL); } + return 0; } //============================================================================ @@ -215,6 +221,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonFlight) DEFINE_ACTION_FUNCTION(AActor, A_DragonFlap) { + PARAM_ACTION_PROLOGUE; + CALL_ACTION(A_DragonFlight, self); if (pr_dragonflap() < 240) { @@ -224,6 +232,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonFlap) { self->PlayActiveSound (); } + return 0; } //============================================================================ @@ -234,7 +243,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonFlap) DEFINE_ACTION_FUNCTION(AActor, A_DragonAttack) { - P_SpawnMissile (self, self->target, PClass::FindClass ("DragonFireball")); + PARAM_ACTION_PROLOGUE; + + P_SpawnMissile (self, self->target, PClass::FindActor("DragonFireball")); + return 0; } //============================================================================ @@ -245,6 +257,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonAttack) DEFINE_ACTION_FUNCTION(AActor, A_DragonFX2) { + PARAM_ACTION_PROLOGUE; + AActor *mo; int i; int delay; @@ -262,7 +276,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonFX2) mo->tics = delay+(pr_dragonfx2()&3)*i*2; mo->target = self->target; } - } + } + return 0; } //============================================================================ @@ -273,11 +288,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonFX2) DEFINE_ACTION_FUNCTION(AActor, A_DragonPain) { + PARAM_ACTION_PROLOGUE; + CALL_ACTION(A_Pain, self); if (!self->tracer) { // no destination spot yet self->SetState (self->SeeState); } + return 0; } //============================================================================ @@ -288,8 +306,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonPain) DEFINE_ACTION_FUNCTION(AActor, A_DragonCheckCrash) { + PARAM_ACTION_PROLOGUE; + if (self->Z() <= self->floorz) { self->SetState (self->FindState ("Crash")); } + return 0; } diff --git a/src/g_hexen/a_fighteraxe.cpp b/src/g_hexen/a_fighteraxe.cpp index c1e3968107..575b8d8c13 100644 --- a/src/g_hexen/a_fighteraxe.cpp +++ b/src/g_hexen/a_fighteraxe.cpp @@ -68,11 +68,13 @@ FState *AFWeapAxe::GetAtkState (bool hold) DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckReady) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } if (player->ReadyWeapon->Ammo1->Amount) { @@ -82,6 +84,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckReady) { DoReadyWeapon(self); } + return 0; } //============================================================================ @@ -92,11 +95,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckReady) DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckReadyG) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } if (player->ReadyWeapon->Ammo1->Amount <= 0) { @@ -106,6 +111,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckReadyG) { DoReadyWeapon(self); } + return 0; } //============================================================================ @@ -116,11 +122,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckReadyG) DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckUp) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } if (player->ReadyWeapon->Ammo1->Amount) { @@ -130,6 +138,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckUp) { CALL_ACTION(A_Raise, self); } + return 0; } //============================================================================ @@ -140,11 +149,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckUp) DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckUpG) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } if (player->ReadyWeapon->Ammo1->Amount <= 0) { @@ -154,6 +165,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckUpG) { CALL_ACTION(A_Raise, self); } + return 0; } //============================================================================ @@ -164,16 +176,19 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckUpG) DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckAtk) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } if (player->ReadyWeapon->Ammo1->Amount) { P_SetPsprite (player, ps_weapon, player->ReadyWeapon->FindState ("FireGlow")); } + return 0; } //============================================================================ @@ -184,6 +199,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckAtk) DEFINE_ACTION_FUNCTION(AActor, A_FAxeAttack) { + PARAM_ACTION_PROLOGUE; + angle_t angle; fixed_t power; int damage; @@ -192,12 +209,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeAttack) int useMana; player_t *player; AWeapon *weapon; - const PClass *pufftype; + PClassActor *pufftype; AActor *linetarget; if (NULL == (player = self->player)) { - return; + return 0; } AActor *pmo=player->mo; @@ -209,12 +226,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeAttack) { damage <<= 1; power = 6*FRACUNIT; - pufftype = PClass::FindClass ("AxePuffGlow"); + pufftype = PClass::FindActor ("AxePuffGlow"); useMana = 1; } else { - pufftype = PClass::FindClass ("AxePuff"); + pufftype = PClass::FindActor ("AxePuff"); useMana = 0; } for (i = 0; i < 16; i++) @@ -275,6 +292,6 @@ axedone: } } } - return; + return 0; } diff --git a/src/g_hexen/a_fighterhammer.cpp b/src/g_hexen/a_fighterhammer.cpp index 42aae31fbd..2980dec7a2 100644 --- a/src/g_hexen/a_fighterhammer.cpp +++ b/src/g_hexen/a_fighterhammer.cpp @@ -27,6 +27,8 @@ extern void AdjustPlayerAngle (AActor *pmo, AActor *linetarget); DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack) { + PARAM_ACTION_PROLOGUE; + angle_t angle; int damage; fixed_t power; @@ -34,28 +36,30 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack) int i; player_t *player; AActor *linetarget; + PClassActor *hammertime; if (NULL == (player = self->player)) { - return; + return 0; } AActor *pmo=player->mo; damage = 60+(pr_hammeratk()&63); power = 10*FRACUNIT; + hammertime = PClass::FindActor("HammerPuff"); for (i = 0; i < 16; i++) { angle = pmo->angle + i*(ANG45/32); slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE, &linetarget, 0, ALF_CHECK3D); - if (linetarget) + if (linetarget != NULL) { - P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, PClass::FindClass ("HammerPuff"), true, &linetarget); + P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true, &linetarget); if (linetarget != NULL) { AdjustPlayerAngle(pmo, linetarget); - if (linetarget->flags3&MF3_ISMONSTER || linetarget->player) + if (linetarget->flags3 & MF3_ISMONSTER || linetarget->player) { - P_ThrustMobj (linetarget, angle, power); + P_ThrustMobj(linetarget, angle, power); } pmo->weaponspecial = false; // Don't throw a hammer goto hammerdone; @@ -63,13 +67,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack) } angle = pmo->angle-i*(ANG45/32); slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE, &linetarget, 0, ALF_CHECK3D); - if(linetarget) + if (linetarget != NULL) { - P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, PClass::FindClass ("HammerPuff"), true, &linetarget); + P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true, &linetarget); if (linetarget != NULL) { AdjustPlayerAngle(pmo, linetarget); - if (linetarget->flags3&MF3_ISMONSTER || linetarget->player) + if (linetarget->flags3 & MF3_ISMONSTER || linetarget->player) { P_ThrustMobj(linetarget, angle, power); } @@ -81,7 +85,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack) // didn't find any targets in meleerange, so set to throw out a hammer angle = pmo->angle; slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE, &linetarget, 0, ALF_CHECK3D); - if (P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, PClass::FindClass ("HammerPuff"), true) != NULL) + if (P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true) != NULL) { pmo->weaponspecial = false; } @@ -97,7 +101,7 @@ hammerdone: { pmo->weaponspecial = false; } - return; + return 0; } //============================================================================ @@ -108,27 +112,30 @@ hammerdone: DEFINE_ACTION_FUNCTION(AActor, A_FHammerThrow) { + PARAM_ACTION_PROLOGUE; + AActor *mo; player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } if (!player->mo->weaponspecial) { - return; + return 0; } AWeapon *weapon = player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire, false)) - return; + return 0; } - mo = P_SpawnPlayerMissile (player->mo, PClass::FindClass ("HammerMissile")); + mo = P_SpawnPlayerMissile (player->mo, PClass::FindActor("HammerMissile")); if (mo) { mo->special1 = 0; - } + } + return 0; } diff --git a/src/g_hexen/a_fighterplayer.cpp b/src/g_hexen/a_fighterplayer.cpp index 82cb8bd054..944a4aa459 100644 --- a/src/g_hexen/a_fighterplayer.cpp +++ b/src/g_hexen/a_fighterplayer.cpp @@ -59,7 +59,7 @@ void AdjustPlayerAngle (AActor *pmo, AActor *linetarget) static bool TryPunch(APlayerPawn *pmo, angle_t angle, int damage, fixed_t power) { - const PClass *pufftype; + PClassActor *pufftype; AActor *linetarget; int slope; @@ -70,11 +70,11 @@ static bool TryPunch(APlayerPawn *pmo, angle_t angle, int damage, fixed_t power) { damage <<= 1; power *= 3; - pufftype = PClass::FindClass ("HammerPuff"); + pufftype = PClass::FindActor("HammerPuff"); } else { - pufftype = PClass::FindClass ("PunchPuff"); + pufftype = PClass::FindActor("PunchPuff"); } P_LineAttack (pmo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, pufftype, true, &linetarget); if (linetarget != NULL) @@ -99,6 +99,8 @@ static bool TryPunch(APlayerPawn *pmo, angle_t angle, int damage, fixed_t power) DEFINE_ACTION_FUNCTION(AActor, A_FPunchAttack) { + PARAM_ACTION_PROLOGUE; + int damage; fixed_t power; int i; @@ -106,7 +108,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FPunchAttack) if (NULL == (player = self->player)) { - return; + return 0; } APlayerPawn *pmo = player->mo; @@ -120,10 +122,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_FPunchAttack) if (pmo->weaponspecial >= 3) { pmo->weaponspecial = 0; - P_SetPsprite (player, ps_weapon, player->ReadyWeapon->FindState ("Fire2")); + P_SetPsprite (player, ps_weapon, player->ReadyWeapon->FindState("Fire2")); S_Sound (pmo, CHAN_VOICE, "*fistgrunt", 1, ATTN_NORM); } - return; + return 0; } } // didn't find any creatures, so try to strike any walls @@ -131,5 +133,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_FPunchAttack) AActor *linetarget; int slope = P_AimLineAttack (pmo, pmo->angle, MELEERANGE, &linetarget); - P_LineAttack (pmo, pmo->angle, MELEERANGE, slope, damage, NAME_Melee, PClass::FindClass("PunchPuff"), true); + P_LineAttack (pmo, pmo->angle, MELEERANGE, slope, damage, NAME_Melee, PClass::FindActor("PunchPuff"), true); + return 0; } diff --git a/src/g_hexen/a_fighterquietus.cpp b/src/g_hexen/a_fighterquietus.cpp index cd3f65607c..5b707ac1e1 100644 --- a/src/g_hexen/a_fighterquietus.cpp +++ b/src/g_hexen/a_fighterquietus.cpp @@ -26,14 +26,14 @@ static FRandom pr_fswordflame ("FSwordFlame"); DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DropWeaponPieces) { - ACTION_PARAM_START(3); - ACTION_PARAM_CLASS(p1, 0); - ACTION_PARAM_CLASS(p2, 1); - ACTION_PARAM_CLASS(p3, 2); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS(p1, AActor); + PARAM_CLASS(p2, AActor); + PARAM_CLASS(p3, AActor); for (int i = 0, j = 0, fineang = 0; i < 3; ++i) { - const PClass *cls = j==0? p1 : j==1? p2 : p3; + PClassActor *cls = j == 0 ? p1 : j == 1 ? p2 : p3; if (cls) { AActor *piece = Spawn (cls, self->Pos(), ALLOW_REPLACE); @@ -48,6 +48,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DropWeaponPieces) } } } + return 0; } @@ -80,17 +81,19 @@ int AFSwordMissile::DoSpecialDamage(AActor *victim, int damage, FName damagetype DEFINE_ACTION_FUNCTION(AActor, A_FSwordAttack) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } P_SpawnPlayerMissile (self, 0, 0, -10*FRACUNIT, RUNTIME_CLASS(AFSwordMissile), self->angle+ANGLE_45/4); P_SpawnPlayerMissile (self, 0, 0, -5*FRACUNIT, RUNTIME_CLASS(AFSwordMissile), self->angle+ANGLE_45/8); @@ -98,6 +101,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FSwordAttack) P_SpawnPlayerMissile (self, 0, 0, 5*FRACUNIT, RUNTIME_CLASS(AFSwordMissile), self->angle-ANGLE_45/8); P_SpawnPlayerMissile (self, 0, 0, 10*FRACUNIT, RUNTIME_CLASS(AFSwordMissile), self->angle-ANGLE_45/4); S_Sound (self, CHAN_WEAPON, "FighterSwordFire", 1, ATTN_NORM); + return 0; } //============================================================================ @@ -108,6 +112,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_FSwordAttack) DEFINE_ACTION_FUNCTION(AActor, A_FSwordFlames) { + PARAM_ACTION_PROLOGUE; + int i; for (i = 1+(pr_fswordflame()&3); i; i--) @@ -117,6 +123,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FSwordFlames) fixed_t zo = ((pr_fswordflame() - 128) << 11); Spawn ("FSwordFlame", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE); } + return 0; } //============================================================================ @@ -127,7 +134,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_FSwordFlames) DEFINE_ACTION_FUNCTION(AActor, A_FighterAttack) { - if (!self->target) return; + PARAM_ACTION_PROLOGUE; + + if (!self->target) return 0; angle_t angle = self->angle; @@ -137,5 +146,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_FighterAttack) P_SpawnMissileAngle (self, RUNTIME_CLASS(AFSwordMissile), angle-ANG45/8, 0); P_SpawnMissileAngle (self, RUNTIME_CLASS(AFSwordMissile), angle-ANG45/4, 0); S_Sound (self, CHAN_WEAPON, "FighterSwordFire", 1, ATTN_NORM); + return 0; } diff --git a/src/g_hexen/a_firedemon.cpp b/src/g_hexen/a_firedemon.cpp index 40f03abbf9..badc0c2f10 100644 --- a/src/g_hexen/a_firedemon.cpp +++ b/src/g_hexen/a_firedemon.cpp @@ -32,25 +32,25 @@ static FRandom pr_firedemonsplotch ("FiredSplotch"); void A_FiredSpawnRock (AActor *actor) { AActor *mo; - const PClass *rtype; + PClassActor *rtype; switch (pr_firedemonrock() % 5) { case 0: - rtype = PClass::FindClass ("FireDemonRock1"); + rtype = PClass::FindActor("FireDemonRock1"); break; case 1: - rtype = PClass::FindClass ("FireDemonRock2"); + rtype = PClass::FindActor("FireDemonRock2"); break; case 2: - rtype = PClass::FindClass ("FireDemonRock3"); + rtype = PClass::FindActor("FireDemonRock3"); break; case 3: - rtype = PClass::FindClass ("FireDemonRock4"); + rtype = PClass::FindActor("FireDemonRock4"); break; case 4: default: - rtype = PClass::FindClass ("FireDemonRock5"); + rtype = PClass::FindActor("FireDemonRock5"); break; } @@ -80,11 +80,14 @@ void A_FiredSpawnRock (AActor *actor) DEFINE_ACTION_FUNCTION(AActor, A_FiredRocks) { + PARAM_ACTION_PROLOGUE; + A_FiredSpawnRock (self); A_FiredSpawnRock (self); A_FiredSpawnRock (self); A_FiredSpawnRock (self); A_FiredSpawnRock (self); + return 0; } //============================================================================ @@ -95,11 +98,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_FiredRocks) DEFINE_ACTION_FUNCTION(AActor, A_SmBounce) { + PARAM_ACTION_PROLOGUE; + // give some more velocity (x,y,&z) self->SetZ(self->floorz + FRACUNIT); self->velz = (2*FRACUNIT) + (pr_smbounce() << 10); self->velx = pr_smbounce()%3<vely = pr_smbounce()%3<target == NULL) - return; - AActor *mo = P_SpawnMissile (self, self->target, PClass::FindClass ("FireDemonMissile")); + return 0; + AActor *mo = P_SpawnMissile (self, self->target, PClass::FindActor("FireDemonMissile")); if (mo) S_Sound (self, CHAN_BODY, "FireDemonAttack", 1, ATTN_NORM); + return 0; } //============================================================================ @@ -124,6 +133,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_FiredAttack) DEFINE_ACTION_FUNCTION(AActor, A_FiredChase) { + PARAM_ACTION_PROLOGUE; + int weaveindex = self->special1; AActor *target = self->target; angle_t ang; @@ -145,7 +156,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FiredChase) if(!self->target || !(self->target->flags&MF_SHOOTABLE)) { // Invalid target P_LookForPlayers (self,true, NULL); - return; + return 0; } // Strafe @@ -193,7 +204,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FiredChase) { self->SetState (self->MissileState); self->flags |= MF_JUSTATTACKED; - return; + return 0; } } else @@ -206,6 +217,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FiredChase) { self->PlayActiveSound (); } + return 0; } //============================================================================ @@ -216,6 +228,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_FiredChase) DEFINE_ACTION_FUNCTION(AActor, A_FiredSplotch) { + PARAM_ACTION_PROLOGUE; + AActor *mo; mo = Spawn ("FireDemonSplotch1", self->Pos(), ALLOW_REPLACE); @@ -232,4 +246,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_FiredSplotch) mo->vely = (pr_firedemonsplotch() - 128) << 11; mo->velz = (pr_firedemonsplotch() << 10) + FRACUNIT*3; } + return 0; } diff --git a/src/g_hexen/a_flechette.cpp b/src/g_hexen/a_flechette.cpp index ef8e27ca19..f26a6b41a1 100644 --- a/src/g_hexen/a_flechette.cpp +++ b/src/g_hexen/a_flechette.cpp @@ -24,15 +24,6 @@ DECLARE_ACTION(A_CheckThrowBomb) // Poison Bag Artifact (Flechette) ------------------------------------------ -class AArtiPoisonBag : public AInventory -{ - DECLARE_CLASS (AArtiPoisonBag, AInventory) -public: - bool HandlePickup (AInventory *item); - AInventory *CreateCopy (AActor *other); - void BeginPlay (); -}; - IMPLEMENT_CLASS (AArtiPoisonBag) // Poison Bag 1 (The Cleric's) ---------------------------------------------- @@ -155,10 +146,10 @@ IMPLEMENT_CLASS (AArtiPoisonBagGiver) bool AArtiPoisonBagGiver::Use (bool pickup) { - const PClass *MissileType = PClass::FindClass((ENamedName) this->GetClass()->Meta.GetMetaInt (ACMETA_MissileName, NAME_None)); - if (MissileType != NULL) + PClassActor *missiletype = PClass::FindActor(this->GetClass()->MissileName); + if (missiletype != NULL) { - AActor *mo = Spawn (MissileType, Owner->Pos(), ALLOW_REPLACE); + AActor *mo = Spawn (missiletype, Owner->Pos(), ALLOW_REPLACE); if (mo != NULL) { if (mo->IsKindOf(RUNTIME_CLASS(AInventory))) @@ -186,10 +177,10 @@ IMPLEMENT_CLASS (AArtiPoisonBagShooter) bool AArtiPoisonBagShooter::Use (bool pickup) { - const PClass *MissileType = PClass::FindClass((ENamedName) this->GetClass()->Meta.GetMetaInt (ACMETA_MissileName, NAME_None)); - if (MissileType != NULL) + PClassActor *missiletype = PClass::FindActor(this->GetClass()->MissileName); + if (missiletype != NULL) { - AActor *mo = P_SpawnPlayerMissile(Owner, MissileType); + AActor *mo = P_SpawnPlayerMissile(Owner, missiletype); if (mo != NULL) { // automatic handling of seeker missiles @@ -209,9 +200,9 @@ bool AArtiPoisonBagShooter::Use (bool pickup) // //============================================================================ -const PClass *GetFlechetteType(AActor *other) +PClassActor *GetFlechetteType(AActor *other) { - const PClass *spawntype = NULL; + PClassActor *spawntype = NULL; if (other->IsKindOf(RUNTIME_CLASS(APlayerPawn))) { spawntype = static_cast(other)->FlechetteType; @@ -273,8 +264,7 @@ AInventory *AArtiPoisonBag::CreateCopy (AActor *other) } AInventory *copy; - - const PClass *spawntype = GetFlechetteType(other); + PClassActor *spawntype = GetFlechetteType(other); copy = static_cast(Spawn (spawntype, 0, 0, 0, NO_REPLACE)); copy->Amount = Amount; copy->MaxAmount = MaxAmount; @@ -353,7 +343,7 @@ int APoisonCloud::DoSpecialDamage (AActor *victim, int damage, FName damagetype) damage = FixedMul(damage, victim->DamageFactor); if (damage > 0) { - damage = DamageTypeDefinition::ApplyMobjDamageFactor(damage, damagetype, victim->GetClass()->ActorInfo->DamageFactors); + damage = DamageTypeDefinition::ApplyMobjDamageFactor(damage, damagetype, victim->GetClass()->DamageFactors); } if (damage > 0) { @@ -382,6 +372,8 @@ int APoisonCloud::DoSpecialDamage (AActor *victim, int damage, FName damagetype) DEFINE_ACTION_FUNCTION(AActor, A_PoisonBagInit) { + PARAM_ACTION_PROLOGUE; + AActor *mo; mo = Spawn (self->PosPlusZ(28*FRACUNIT), ALLOW_REPLACE); @@ -389,6 +381,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_PoisonBagInit) { mo->target = self->target; } + return 0; } //=========================================================================== @@ -399,14 +392,17 @@ DEFINE_ACTION_FUNCTION(AActor, A_PoisonBagInit) DEFINE_ACTION_FUNCTION(AActor, A_PoisonBagCheck) { + PARAM_ACTION_PROLOGUE; + if (--self->special1 <= 0) { self->SetState (self->FindState ("Death")); } else { - return; + return 0; } + return 0; } //=========================================================================== @@ -417,12 +413,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_PoisonBagCheck) DEFINE_ACTION_FUNCTION(AActor, A_PoisonBagDamage) { + PARAM_ACTION_PROLOGUE; + int bobIndex; P_RadiusAttack (self, self->target, 4, 40, self->DamageType, RADF_HURTSOURCE); bobIndex = self->special2; self->AddZ(finesine[bobIndex << BOBTOFINESHIFT] >> 1); self->special2 = (bobIndex + 1) & 63; + return 0; } //=========================================================================== @@ -433,10 +432,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_PoisonBagDamage) DEFINE_ACTION_FUNCTION(AActor, A_CheckThrowBomb) { + PARAM_ACTION_PROLOGUE; + if (--self->health <= 0) { self->SetState (self->FindState(NAME_Death)); } + return 0; } //=========================================================================== @@ -447,6 +449,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckThrowBomb) DEFINE_ACTION_FUNCTION(AActor, A_CheckThrowBomb2) { + PARAM_ACTION_PROLOGUE; + // [RH] Check using actual velocity, although the velz < 2 check still stands //if (abs(self->velx) < FRACUNIT*3/2 && abs(self->vely) < FRACUNIT*3/2 // && self->velz < 2*FRACUNIT) @@ -461,4 +465,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckThrowBomb2) self->flags &= ~MF_MISSILE; } CALL_ACTION(A_CheckThrowBomb, self); + return 0; } diff --git a/src/g_hexen/a_flies.cpp b/src/g_hexen/a_flies.cpp index 05c4ef94c0..b689d7807c 100644 --- a/src/g_hexen/a_flies.cpp +++ b/src/g_hexen/a_flies.cpp @@ -60,6 +60,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_FlySearch) // So search the sectors instead. We can't potentially find something all // the way on the other side of the map and we can't find invisible corpses, // but at least we aren't crippled on maps with lots of stuff going on. + PARAM_ACTION_PROLOGUE; + validcount++; AActor *other = FindCorpse(self, self->Sector, 5); if (other != NULL) @@ -67,16 +69,19 @@ DEFINE_ACTION_FUNCTION(AActor, A_FlySearch) self->target = other; self->SetState(self->FindState("Buzz")); } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_FlyBuzz) { + PARAM_ACTION_PROLOGUE; + AActor *targ = self->target; if (targ == NULL || !(targ->flags & MF_CORPSE) || pr_fly() < 5) { self->SetIdle(); - return; + return 0; } angle_t ang = self->AngleTo(targ); @@ -86,7 +91,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FlyBuzz) if (!P_TryMove(self, self->X() + 6 * finecosine[ang], self->Y() + 6 * finesine[ang], true)) { self->SetIdle(true); - return; + return 0; } if (self->args[0] & 2) { @@ -103,4 +108,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_FlyBuzz) { S_Sound(self, CHAN_VOICE, self->ActiveSound, 0.5f, ATTN_STATIC); } + return 0; } diff --git a/src/g_hexen/a_fog.cpp b/src/g_hexen/a_fog.cpp index a427daa47d..bf2b1c6fc4 100644 --- a/src/g_hexen/a_fog.cpp +++ b/src/g_hexen/a_fog.cpp @@ -27,6 +27,8 @@ static FRandom pr_fogspawn ("FogSpawn"); DEFINE_ACTION_FUNCTION(AActor, A_FogSpawn) { + PARAM_ACTION_PROLOGUE; + static const char *fogs[3] = { "FogPatchSmall", @@ -34,11 +36,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_FogSpawn) "FogPatchLarge" }; - AActor *mo=NULL; + AActor *mo = NULL; angle_t delta; - if (self->special1-- > 0) return; - + if (self->special1-- > 0) + { + return 0; + } self->special1 = self->args[2]; // Reset frequency count mo = Spawn (fogs[pr_fogspawn()%3], self->Pos(), ALLOW_REPLACE); @@ -55,6 +59,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FogSpawn) mo->args[4] = 1; // Set to moving mo->special2 = pr_fogspawn()&63; } + return 0; } //========================================================================== @@ -65,16 +70,21 @@ DEFINE_ACTION_FUNCTION(AActor, A_FogSpawn) DEFINE_ACTION_FUNCTION(AActor, A_FogMove) { + PARAM_ACTION_PROLOGUE; + int speed = self->args[0]<args[4])) return; + if (!self->args[4]) + { + return 0; + } if (self->args[3]-- <= 0) { self->SetState (self->FindState(NAME_Death), true); - return; + return 0; } if ((self->args[3] % 4) == 0) @@ -87,5 +97,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_FogMove) angle = self->angle>>ANGLETOFINESHIFT; self->velx = FixedMul(speed, finecosine[angle]); self->vely = FixedMul(speed, finesine[angle]); + return 0; } diff --git a/src/g_hexen/a_healingradius.cpp b/src/g_hexen/a_healingradius.cpp index d1d39ddd43..32e670e5c3 100644 --- a/src/g_hexen/a_healingradius.cpp +++ b/src/g_hexen/a_healingradius.cpp @@ -30,7 +30,12 @@ IMPLEMENT_CLASS (AArtiHealingRadius) bool AArtiHealingRadius::Use (bool pickup) { bool effective = false; - int mode = Owner->GetClass()->Meta.GetMetaInt(APMETA_HealingRadius); + FName mode; + + if (Owner->IsKindOf(RUNTIME_CLASS(APlayerPawn))) + { + mode = static_cast(Owner->GetClass())->HealingRadiusType; + } for (int i = 0; i < MAXPLAYERS; ++i) { @@ -65,8 +70,8 @@ bool AArtiHealingRadius::Use (bool pickup) { int amount = 50 + (pr_healradius() % 50); - if (players[i].mo->GiveAmmo (PClass::FindClass(NAME_Mana1), amount) || - players[i].mo->GiveAmmo (PClass::FindClass(NAME_Mana2), amount)) + if (players[i].mo->GiveAmmo (dyn_cast(PClass::FindClass(NAME_Mana1)), amount) || + players[i].mo->GiveAmmo (dyn_cast(PClass::FindClass(NAME_Mana2)), amount)) { gotsome = true; } diff --git a/src/g_hexen/a_heresiarch.cpp b/src/g_hexen/a_heresiarch.cpp index e2b8c9ed27..b01490383a 100644 --- a/src/g_hexen/a_heresiarch.cpp +++ b/src/g_hexen/a_heresiarch.cpp @@ -231,6 +231,8 @@ void ASorcBall1::DoFireSpell () DEFINE_ACTION_FUNCTION(AActor, A_SorcSpinBalls) { + PARAM_ACTION_PROLOGUE; + AActor *mo; self->SpawnState += 2; // [RH] Don't spawn balls again @@ -252,6 +254,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcSpinBalls) if (mo) mo->target = self; mo = Spawn("SorcBall3", pos, NO_REPLACE); if (mo) mo->target = self; + return 0; } @@ -263,11 +266,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcSpinBalls) DEFINE_ACTION_FUNCTION(AActor, A_SorcBallOrbit) { + PARAM_ACTION_PROLOGUE; + // [RH] If no parent, then die instead of crashing if (self->target == NULL) { self->SetState (self->FindState(NAME_Pain)); - return; + return 0; } ASorcBall *actor; @@ -279,14 +284,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcBallOrbit) if (!self->IsKindOf (RUNTIME_CLASS(ASorcBall))) { - I_Error ("Corrupted sorcerer:\nTried to use a %s", RUNTIME_TYPE(self)->TypeName.GetChars()); + I_Error ("Corrupted sorcerer:\nTried to use a %s", self->GetClass()->TypeName.GetChars()); } actor = static_cast (self); if (actor->target->health <= 0) { actor->SetState (actor->FindState(NAME_Pain)); - return; + return 0; } baseangle = (angle_t)parent->special1; @@ -311,7 +316,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcBallOrbit) break; case SORC_STOPPING: // Balls stopping - if ((parent->StopBall == RUNTIME_TYPE(actor)) && + if ((parent->StopBall == actor->GetClass()) && (parent->args[1] > SORCBALL_SPEED_ROTATIONS) && (absangle(angle - (parent->angle>>ANGLETOFINESHIFT)) < (30<<5))) { @@ -328,7 +333,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcBallOrbit) break; case SORC_FIRESPELL: // Casting spell - if (parent->StopBall == RUNTIME_TYPE(actor)) + if (parent->StopBall == actor->GetClass()) { // Put sorcerer into special throw spell anim if (parent->health > 0) @@ -339,7 +344,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcBallOrbit) break; case SORC_FIRING_SPELL: - if (parent->StopBall == RUNTIME_TYPE(actor)) + if (parent->StopBall == actor->GetClass()) { if (actor->special2-- <= 0) { @@ -377,6 +382,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcBallOrbit) actor->SetOrigin (pos, true); actor->floorz = parent->floorz; actor->ceilingz = parent->ceilingz; + return 0; } //============================================================================ @@ -389,8 +395,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcBallOrbit) DEFINE_ACTION_FUNCTION(AActor, A_SpeedBalls) { + PARAM_ACTION_PROLOGUE; + self->args[3] = SORC_ACCELERATE; // speed mode self->args[2] = SORCBALL_TERMINAL_SPEED; // target speed + return 0; } @@ -566,7 +575,7 @@ void ASorcBall3::CastSorcererSpell () ang1 = angle - ANGLE_45; ang2 = angle + ANGLE_45; - const PClass *cls = PClass::FindClass("SorcFX3"); + PClassActor *cls = PClass::FindActor("SorcFX3"); if (health < (SpawnHealth()/3)) { // Spawn 2 at a time mo = P_SpawnMissileAngle(parent, cls, ang1, 4*FRACUNIT); @@ -615,7 +624,7 @@ void ASorcBall1::CastSorcererSpell () ang1 = angle + ANGLE_1*70; ang2 = angle - ANGLE_1*70; - const PClass *cls = PClass::FindClass("SorcFX1"); + PClassActor *cls = PClass::FindActor("SorcFX1"); mo = P_SpawnMissileAngle (parent, cls, ang1, 0); if (mo) { @@ -662,7 +671,7 @@ void A_SorcOffense2(AActor *actor) delta = (finesine[index])*SORCFX4_SPREAD_ANGLE; delta = (delta>>FRACBITS)*ANGLE_1; ang1 = actor->angle + delta; - mo = P_SpawnMissileAngle(parent, PClass::FindClass("SorcFX4"), ang1, 0); + mo = P_SpawnMissileAngle(parent, PClass::FindActor("SorcFX4"), ang1, 0); if (mo) { mo->special2 = 35*5/2; // 5 seconds @@ -682,8 +691,11 @@ void A_SorcOffense2(AActor *actor) DEFINE_ACTION_FUNCTION(AActor, A_SorcBossAttack) { + PARAM_ACTION_PROLOGUE; + self->args[3] = SORC_ACCELERATE; self->args[2] = SORCBALL_INITIAL_SPEED; + return 0; } //============================================================================ @@ -696,6 +708,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcBossAttack) DEFINE_ACTION_FUNCTION(AActor, A_SpawnFizzle) { + PARAM_ACTION_PROLOGUE; fixed_t dist = 5*FRACUNIT; fixed_t speed = self->Speed; angle_t rangle; @@ -714,6 +727,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnFizzle) mo->velz = FRACUNIT*2; } } + return 0; } @@ -727,8 +741,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnFizzle) DEFINE_ACTION_FUNCTION(AActor, A_SorcFX1Seek) { + PARAM_ACTION_PROLOGUE; + A_DoBounceCheck (self, "SorcererHeadScream"); P_SeekerMissile (self,ANGLE_1*2,ANGLE_1*6); + return 0; } @@ -750,6 +767,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcFX1Seek) // Split ball in two DEFINE_ACTION_FUNCTION(AActor, A_SorcFX2Split) { + PARAM_ACTION_PROLOGUE; + AActor *mo; mo = Spawn(self->GetClass(), self->Pos(), NO_REPLACE); @@ -769,6 +788,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcFX2Split) mo->SetState (mo->FindState("Orbit")); } self->Destroy (); + return 0; } //============================================================================ @@ -781,6 +801,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcFX2Split) DEFINE_ACTION_FUNCTION(AActor, A_SorcFX2Orbit) { + PARAM_ACTION_PROLOGUE; + angle_t angle; fixedvec3 pos; AActor *parent = self->target; @@ -789,7 +811,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcFX2Orbit) if (parent == NULL) { self->Destroy(); - return; + return 0; } fixed_t dist = parent->radius; @@ -839,6 +861,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcFX2Orbit) self->SetOrigin (pos, true); self->floorz = parent->floorz; self->ceilingz = parent->ceilingz; + return 0; } //============================================================================ @@ -851,6 +874,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcFX2Orbit) DEFINE_ACTION_FUNCTION(AActor, A_SpawnBishop) { + PARAM_ACTION_PROLOGUE; + AActor *mo; mo = Spawn("Bishop", self->Pos(), ALLOW_REPLACE); if (mo) @@ -867,6 +892,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnBishop) } } self->Destroy (); + return 0; } //============================================================================ @@ -877,8 +903,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnBishop) DEFINE_ACTION_FUNCTION(AActor, A_SorcererBishopEntry) { + PARAM_ACTION_PROLOGUE; + Spawn("SorcFX3Explosion", self->Pos(), ALLOW_REPLACE); S_Sound (self, CHAN_VOICE, self->SeeSound, 1, ATTN_NORM); + return 0; } //============================================================================ @@ -891,10 +920,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcererBishopEntry) DEFINE_ACTION_FUNCTION(AActor, A_SorcFX4Check) { + PARAM_ACTION_PROLOGUE; + if (self->special2-- <= 0) { self->SetState (self->FindState(NAME_Death)); } + return 0; } //============================================================================ @@ -907,6 +939,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcFX4Check) DEFINE_ACTION_FUNCTION(AActor, A_SorcBallPop) { + PARAM_ACTION_PROLOGUE; + S_Sound (self, CHAN_BODY, "SorcererBallPop", 1, ATTN_NONE); self->flags &= ~MF_NOGRAVITY; self->gravity = FRACUNIT/8; @@ -916,6 +950,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcBallPop) self->special2 = 4*FRACUNIT; // Initial bounce factor self->args[4] = BOUNCE_TIME_UNIT; // Bounce time unit self->args[3] = 5; // Bounce time in seconds + return 0; } //============================================================================ @@ -948,5 +983,8 @@ void A_DoBounceCheck (AActor *self, const char *sound) DEFINE_ACTION_FUNCTION(AActor, A_BounceCheck) { + PARAM_ACTION_PROLOGUE; + A_DoBounceCheck (self, "SorcererBigBallExplode"); + return 0; } diff --git a/src/g_hexen/a_hexenglobal.h b/src/g_hexen/a_hexenglobal.h index 44ffc6d577..ba68a99885 100644 --- a/src/g_hexen/a_hexenglobal.h +++ b/src/g_hexen/a_hexenglobal.h @@ -29,4 +29,13 @@ class AMageWeapon : public AWeapon public: }; +class AArtiPoisonBag : public AInventory +{ + DECLARE_CLASS (AArtiPoisonBag, AInventory) +public: + bool HandlePickup (AInventory *item); + AInventory *CreateCopy (AActor *other); + void BeginPlay (); +}; + #endif //__A_HEXENGLOBAL_H__ diff --git a/src/g_hexen/a_hexenspecialdecs.cpp b/src/g_hexen/a_hexenspecialdecs.cpp index b79d9f2c23..86addb2cbe 100644 --- a/src/g_hexen/a_hexenspecialdecs.cpp +++ b/src/g_hexen/a_hexenspecialdecs.cpp @@ -55,6 +55,8 @@ void APottery1::HitFloor () DEFINE_ACTION_FUNCTION(AActor, A_PotteryExplode) { + PARAM_ACTION_PROLOGUE; + AActor *mo = NULL; int i; @@ -71,7 +73,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_PotteryExplode) } S_Sound (mo, CHAN_BODY, "PotteryExplode", 1, ATTN_NORM); // Spawn an item? - const PClass *type = P_GetSpawnableType(self->args[0]); + PClassActor *type = P_GetSpawnableType(self->args[0]); if (type != NULL) { if (!((level.flags2 & LEVEL2_NOMONSTERS) || (dmflags & DF_NO_MONSTERS)) @@ -80,6 +82,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_PotteryExplode) Spawn (type, self->Pos(), ALLOW_REPLACE); } } + return 0; } //============================================================================ @@ -90,8 +93,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_PotteryExplode) DEFINE_ACTION_FUNCTION(AActor, A_PotteryChooseBit) { + PARAM_ACTION_PROLOGUE; + self->SetState (self->FindState(NAME_Death) + 1 + 2*(pr_bit()%5)); self->tics = 256+(pr_bit()<<1); + return 0; } //============================================================================ @@ -102,6 +108,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_PotteryChooseBit) DEFINE_ACTION_FUNCTION(AActor, A_PotteryCheck) { + PARAM_ACTION_PROLOGUE; + int i; for(i = 0; i < MAXPLAYERS; i++) @@ -112,10 +120,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_PotteryCheck) if (P_CheckSight (self, pmo) && (absangle(pmo->AngleTo(self) - pmo->angle) <= ANGLE_45)) { // Previous state (pottery bit waiting state) self->SetState (self->state - 1); - return; + return 0; } } } + return 0; } // Lynched corpse (no heart) ------------------------------------------------ @@ -143,10 +152,13 @@ void AZCorpseLynchedNoHeart::PostBeginPlay () DEFINE_ACTION_FUNCTION(AActor, A_CorpseBloodDrip) { + PARAM_ACTION_PROLOGUE; + if (pr_drip() <= 128) { Spawn ("CorpseBloodDrip", self->PosPlusZ(self->height/2), ALLOW_REPLACE); } + return 0; } //============================================================================ @@ -157,6 +169,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_CorpseBloodDrip) DEFINE_ACTION_FUNCTION(AActor, A_CorpseExplode) { + PARAM_ACTION_PROLOGUE; + AActor *mo; int i; @@ -182,6 +196,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CorpseExplode) } S_Sound (self, CHAN_BODY, self->DeathSound, 1, ATTN_IDLE); self->Destroy (); + return 0; } //============================================================================ @@ -192,6 +207,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_CorpseExplode) DEFINE_ACTION_FUNCTION(AActor, A_LeafSpawn) { + PARAM_ACTION_PROLOGUE; + AActor *mo; int i; @@ -200,7 +217,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LeafSpawn) fixed_t xo = (pr_leaf.Random2() << 14); fixed_t yo = (pr_leaf.Random2() << 14); fixed_t zo = (pr_leaf() << 14); - mo = Spawn (pr_leaf()&1 ? PClass::FindClass ("Leaf1") : PClass::FindClass ("Leaf2"), + mo = Spawn (pr_leaf()&1 ? PClass::FindActor ("Leaf1") : PClass::FindActor ("Leaf2"), self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE); if (mo) @@ -210,6 +227,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LeafSpawn) mo->special1 = 0; } } + return 0; } //============================================================================ @@ -220,10 +238,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_LeafSpawn) DEFINE_ACTION_FUNCTION(AActor, A_LeafThrust) { + PARAM_ACTION_PROLOGUE; + if (pr_leafthrust() <= 96) { self->velz += (pr_leafthrust()<<9)+FRACUNIT; } + return 0; } //============================================================================ @@ -234,11 +255,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_LeafThrust) DEFINE_ACTION_FUNCTION(AActor, A_LeafCheck) { + PARAM_ACTION_PROLOGUE; + self->special1++; if (self->special1 >= 20) { self->SetState (NULL); - return; + return 0; } angle_t ang = self->target ? self->target->angle : self->angle; if (pr_leafcheck() > 64) @@ -247,12 +270,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_LeafCheck) { P_ThrustMobj (self, ang, (pr_leafcheck()<<9)+FRACUNIT); } - return; + return 0; } self->SetState (self->SpawnState + 7); self->velz = (pr_leafcheck()<<9)+FRACUNIT; P_ThrustMobj (self, ang, (pr_leafcheck()<<9)+2*FRACUNIT); self->flags |= MF_MISSILE; + return 0; } //=========================================================================== @@ -263,7 +287,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_LeafCheck) DEFINE_ACTION_FUNCTION(AActor, A_PoisonShroom) { + PARAM_ACTION_PROLOGUE; + self->tics = 128+(pr_shroom()<<1); + return 0; } //=========================================================================== @@ -274,6 +301,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_PoisonShroom) DEFINE_ACTION_FUNCTION(AActor, A_SoAExplode) { + PARAM_ACTION_PROLOGUE; + AActor *mo; int i; @@ -292,7 +321,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SoAExplode) } } // Spawn an item? - const PClass *type = P_GetSpawnableType(self->args[0]); + PClassActor *type = P_GetSpawnableType(self->args[0]); if (type != NULL) { if (!((level.flags2 & LEVEL2_NOMONSTERS) || (dmflags & DF_NO_MONSTERS)) @@ -303,6 +332,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SoAExplode) } S_Sound (self, CHAN_BODY, self->DeathSound, 1, ATTN_NORM); self->Destroy (); + return 0; } // Bell --------------------------------------------------------------------- @@ -332,6 +362,8 @@ void AZBell::Activate (AActor *activator) DEFINE_ACTION_FUNCTION(AActor, A_BellReset1) { + PARAM_ACTION_PROLOGUE; + self->flags |= MF_NOGRAVITY; self->height <<= 2; if (self->special) @@ -340,6 +372,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BellReset1) self->args[1], self->args[2], self->args[3], self->args[4]); self->special = 0; } + return 0; } //=========================================================================== @@ -350,9 +383,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_BellReset1) DEFINE_ACTION_FUNCTION(AActor, A_BellReset2) { + PARAM_ACTION_PROLOGUE; + self->flags |= MF_SHOOTABLE; self->flags &= ~MF_CORPSE; self->flags6 &= ~MF6_KILLED; self->health = 5; + return 0; } diff --git a/src/g_hexen/a_iceguy.cpp b/src/g_hexen/a_iceguy.cpp index 75be577bf7..1ddc59f500 100644 --- a/src/g_hexen/a_iceguy.cpp +++ b/src/g_hexen/a_iceguy.cpp @@ -26,6 +26,8 @@ static const char *WispTypes[2] = DEFINE_ACTION_FUNCTION(AActor, A_IceGuyLook) { + PARAM_ACTION_PROLOGUE; + fixed_t dist; fixed_t an; @@ -40,6 +42,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_IceGuyLook) FixedMul(dist, finesine[an]), 60 * FRACUNIT), ALLOW_REPLACE); } + return 0; } //============================================================================ @@ -50,11 +53,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_IceGuyLook) DEFINE_ACTION_FUNCTION(AActor, A_IceGuyChase) { + PARAM_ACTION_PROLOGUE; + fixed_t dist; fixed_t an; AActor *mo; - A_Chase (self); + A_Chase (stack, self); if (pr_iceguychase() < 128) { dist = ((pr_iceguychase()-128)*self->radius)>>7; @@ -72,6 +77,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_IceGuyChase) mo->target = self; } } + return 0; } //============================================================================ @@ -82,13 +88,16 @@ DEFINE_ACTION_FUNCTION(AActor, A_IceGuyChase) DEFINE_ACTION_FUNCTION(AActor, A_IceGuyAttack) { + PARAM_ACTION_PROLOGUE; + if(!self->target) { - return; + return 0; } - P_SpawnMissileXYZ(self->Vec3Angle(self->radius>>1, self->angle+ANG90, 40*FRACUNIT), self, self->target, PClass::FindClass ("IceGuyFX")); - P_SpawnMissileXYZ(self->Vec3Angle(self->radius>>1, self->angle-ANG90, 40*FRACUNIT), self, self->target, PClass::FindClass ("IceGuyFX")); + P_SpawnMissileXYZ(self->Vec3Angle(self->radius>>1, self->angle+ANG90, 40*FRACUNIT), self, self->target, PClass::FindActor ("IceGuyFX")); + P_SpawnMissileXYZ(self->Vec3Angle(self->radius>>1, self->angle-ANG90, 40*FRACUNIT), self, self->target, PClass::FindActor ("IceGuyFX")); S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM); + return 0; } //============================================================================ @@ -99,11 +108,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_IceGuyAttack) DEFINE_ACTION_FUNCTION(AActor, A_IceGuyDie) { + PARAM_ACTION_PROLOGUE; + self->velx = 0; self->vely = 0; self->velz = 0; self->height = self->GetDefault()->height; CALL_ACTION(A_FreezeDeathChunks, self); + return 0; } //============================================================================ @@ -114,17 +126,20 @@ DEFINE_ACTION_FUNCTION(AActor, A_IceGuyDie) DEFINE_ACTION_FUNCTION(AActor, A_IceGuyMissileExplode) { + PARAM_ACTION_PROLOGUE; + AActor *mo; unsigned int i; for (i = 0; i < 8; i++) { mo = P_SpawnMissileAngleZ (self, self->Z()+3*FRACUNIT, - PClass::FindClass("IceGuyFX2"), i*ANG45, (fixed_t)(-0.3*FRACUNIT)); + PClass::FindActor("IceGuyFX2"), i*ANG45, (fixed_t)(-0.3*FRACUNIT)); if (mo) { mo->target = self->target; } } + return 0; } diff --git a/src/g_hexen/a_korax.cpp b/src/g_hexen/a_korax.cpp index 77079d9b6e..b0e57b618e 100644 --- a/src/g_hexen/a_korax.cpp +++ b/src/g_hexen/a_korax.cpp @@ -74,10 +74,10 @@ void A_KSpiritRoam (AActor *); void A_KBolt (AActor *); void A_KBoltRaise (AActor *); -void KoraxFire (AActor *actor, const PClass *type, int arm); +void KoraxFire (AActor *actor, PClassActor *type, int arm); void KSpiritInit (AActor *spirit, AActor *korax); AActor *P_SpawnKoraxMissile (fixed_t x, fixed_t y, fixed_t z, - AActor *source, AActor *dest, const PClass *type); + AActor *source, AActor *dest, PClassActor *type); extern void SpawnSpiritTail (AActor *spirit); @@ -89,6 +89,8 @@ extern void SpawnSpiritTail (AActor *spirit); DEFINE_ACTION_FUNCTION(AActor, A_KoraxChase) { + PARAM_ACTION_PROLOGUE; + AActor *spot; if ((!self->special2) && (self->health <= (self->SpawnHealth()/2))) @@ -103,10 +105,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_KoraxChase) P_StartScript (self, NULL, 249, NULL, NULL, 0, 0); self->special2 = 1; // Don't run again - return; + return 0; } - if (!self->target) return; + if (self->target == NULL) + { + return 0; + } if (pr_koraxchase()<30) { self->SetState (self->MissileState); @@ -140,6 +145,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_KoraxChase) } } } + return 0; } //============================================================================ @@ -150,17 +156,23 @@ DEFINE_ACTION_FUNCTION(AActor, A_KoraxChase) DEFINE_ACTION_FUNCTION(AActor, A_KoraxBonePop) { + PARAM_ACTION_PROLOGUE; + AActor *mo; int i; // Spawn 6 spirits equalangularly for (i = 0; i < 6; ++i) { - mo = P_SpawnMissileAngle (self, PClass::FindClass("KoraxSpirit"), ANGLE_60*i, 5*FRACUNIT); - if (mo) KSpiritInit (mo, self); + mo = P_SpawnMissileAngle (self, PClass::FindActor("KoraxSpirit"), ANGLE_60*i, 5*FRACUNIT); + if (mo) + { + KSpiritInit (mo, self); + } } P_StartScript (self, NULL, 255, NULL, NULL, 0, 0); // Death script + return 0; } //============================================================================ @@ -190,6 +202,8 @@ void KSpiritInit (AActor *spirit, AActor *korax) DEFINE_ACTION_FUNCTION(AActor, A_KoraxDecide) { + PARAM_ACTION_PROLOGUE; + if (pr_koraxdecide()<220) { self->SetState (self->FindState("Attack")); @@ -198,6 +212,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_KoraxDecide) { self->SetState (self->FindState("Command")); } + return 0; } //============================================================================ @@ -208,6 +223,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_KoraxDecide) DEFINE_ACTION_FUNCTION(AActor, A_KoraxMissile) { + PARAM_ACTION_PROLOGUE; + static const struct { const char *type, *sound; } choices[6] = { { "WraithFX1", "WraithMissileFire" }, @@ -220,11 +237,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_KoraxMissile) int type = pr_koraxmissile()%6; int i; - const PClass *info; + PClassActor *info; S_Sound (self, CHAN_VOICE, "KoraxAttack", 1, ATTN_NORM); - info = PClass::FindClass (choices[type].type); + info = PClass::FindActor(choices[type].type); if (info == NULL) { I_Error ("Unknown Korax missile: %s\n", choices[type].type); @@ -236,6 +253,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_KoraxMissile) { KoraxFire (self, info, i); } + return 0; } //============================================================================ @@ -248,6 +266,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_KoraxMissile) DEFINE_ACTION_FUNCTION(AActor, A_KoraxCommand) { + PARAM_ACTION_PROLOGUE; angle_t ang; int numcommands; @@ -271,6 +290,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_KoraxCommand) } P_StartScript (self, NULL, 250+(pr_koraxcommand()%numcommands), NULL, NULL, 0, 0); + return 0; } //============================================================================ @@ -288,7 +308,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_KoraxCommand) // //============================================================================ -void KoraxFire (AActor *actor, const PClass *type, int arm) +void KoraxFire (AActor *actor, PClassActor *type, int arm) { static const int extension[6] = { @@ -405,6 +425,8 @@ void A_KSpiritSeeker (AActor *actor, angle_t thresh, angle_t turnMax) DEFINE_ACTION_FUNCTION(AActor, A_KSpiritRoam) { + PARAM_ACTION_PROLOGUE; + if (self->health-- <= 0) { S_Sound (self, CHAN_VOICE, "SpiritDie", 1, ATTN_NORM); @@ -423,6 +445,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_KSpiritRoam) S_Sound (self, CHAN_VOICE, "SpiritActive", 1, ATTN_NONE); } } + return 0; } //============================================================================ @@ -433,11 +456,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_KSpiritRoam) DEFINE_ACTION_FUNCTION(AActor, A_KBolt) { + PARAM_ACTION_PROLOGUE; + // Countdown lifetime if (self->special1-- <= 0) { self->Destroy (); } + return 0; } //============================================================================ @@ -448,6 +474,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_KBolt) DEFINE_ACTION_FUNCTION(AActor, A_KBoltRaise) { + PARAM_ACTION_PROLOGUE; + AActor *mo; fixed_t z; @@ -466,6 +494,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_KBoltRaise) { // Maybe cap it off here } + return 0; } //============================================================================ @@ -475,7 +504,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_KBoltRaise) //============================================================================ AActor *P_SpawnKoraxMissile (fixed_t x, fixed_t y, fixed_t z, - AActor *source, AActor *dest, const PClass *type) + AActor *source, AActor *dest, PClassActor *type) { AActor *th; angle_t an; diff --git a/src/g_hexen/a_magecone.cpp b/src/g_hexen/a_magecone.cpp index f9d98c78f6..154c765246 100644 --- a/src/g_hexen/a_magecone.cpp +++ b/src/g_hexen/a_magecone.cpp @@ -51,6 +51,8 @@ int AFrostMissile::DoSpecialDamage (AActor *victim, int damage, FName damagetype DEFINE_ACTION_FUNCTION(AActor, A_FireConePL1) { + PARAM_ACTION_PROLOGUE; + angle_t angle; int damage; int slope; @@ -62,14 +64,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireConePL1) if (NULL == (player = self->player)) { - return; + return 0; } AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } S_Sound (self, CHAN_WEAPON, "MageShardsFire", 1, ATTN_NORM); @@ -99,6 +101,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireConePL1) mo->args[0] = 3; // Mark Initial shard as super damage } } + return 0; } //============================================================================ @@ -109,11 +112,16 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireConePL1) DEFINE_ACTION_FUNCTION(AActor, A_ShedShard) { + PARAM_ACTION_PROLOGUE; + AActor *mo; int spawndir = self->special1; int spermcount = self->special2; - if (spermcount <= 0) return; // No sperm left + if (spermcount <= 0) + { + return 0; // No sperm left + } self->special2 = 0; spermcount--; @@ -173,4 +181,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_ShedShard) mo->args[0] = (spermcount==3)?2:0; } } + return 0; } diff --git a/src/g_hexen/a_magelightning.cpp b/src/g_hexen/a_magelightning.cpp index c1dd7d7d00..03cc37ce9f 100644 --- a/src/g_hexen/a_magelightning.cpp +++ b/src/g_hexen/a_magelightning.cpp @@ -126,11 +126,14 @@ int ALightningZap::SpecialMissileHit (AActor *thing) DEFINE_ACTION_FUNCTION(AActor, A_LightningReady) { + PARAM_ACTION_PROLOGUE; + DoReadyWeapon(self); if (pr_lightningready() < 160) { S_Sound (self, CHAN_WEAPON, "MageLightningReady", 1, ATTN_NORM); } + return 0; } //============================================================================ @@ -141,6 +144,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightningReady) DEFINE_ACTION_FUNCTION(AActor, A_LightningClip) { + PARAM_ACTION_PROLOGUE; + AActor *cMo; AActor *target = NULL; int zigZag; @@ -149,7 +154,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightningClip) { if (self->lastenemy == NULL) { - return; + return 0; } self->SetZ(self->floorz); target = self->lastenemy->tracer; @@ -196,6 +201,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightningClip) P_ThrustMobj (self, self->angle, self->Speed>>1); } } + return 0; } @@ -207,18 +213,24 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightningClip) DEFINE_ACTION_FUNCTION(AActor, A_LightningZap) { + PARAM_ACTION_PROLOGUE; - const PClass *lightning=PClass::FindClass((ENamedName) self->GetClass()->Meta.GetMetaInt (ACMETA_MissileName, NAME_LightningZap)); + PClassActor *lightning = PClass::FindActor(self->GetClass()->MissileName); AActor *mo; fixed_t deltaZ; + if (lightning == NULL) + { + lightning = PClass::FindActor(NAME_LightningZap); + } + CALL_ACTION(A_LightningClip, self); self->health -= 8; if (self->health <= 0) { self->SetState (self->FindState(NAME_Death)); - return; + return 0; } if (self->flags3 & MF3_FLOORHUGGER) { @@ -251,6 +263,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightningZap) { S_Sound (self, CHAN_BODY, self->ActiveSound, 1, ATTN_NORM); } + return 0; } //============================================================================ @@ -261,9 +274,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightningZap) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MLightningAttack) { - ACTION_PARAM_START(2); - ACTION_PARAM_CLASS(floor, 0); - ACTION_PARAM_CLASS(ceiling, 1); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS_OPT(floor, AActor) { floor = PClass::FindActor("LightningFloor"); } + PARAM_CLASS_OPT(ceiling, AActor) { ceiling = PClass::FindActor("LightningCeiling"); } AActor *fmo, *cmo; @@ -291,6 +304,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MLightningAttack) weapon->DepleteAmmo (weapon->bAltFire); } } + return 0; } //============================================================================ @@ -301,6 +315,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MLightningAttack) DEFINE_ACTION_FUNCTION(AActor, A_ZapMimic) { + PARAM_ACTION_PROLOGUE; + AActor *mo; mo = self->lastenemy; @@ -316,6 +332,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ZapMimic) self->vely = mo->vely; } } + return 0; } //============================================================================ @@ -326,17 +343,23 @@ DEFINE_ACTION_FUNCTION(AActor, A_ZapMimic) DEFINE_ACTION_FUNCTION(AActor, A_LastZap) { - const PClass *lightning=PClass::FindClass((ENamedName) self->GetClass()->Meta.GetMetaInt (ACMETA_MissileName, NAME_LightningZap)); + PARAM_ACTION_PROLOGUE; + PClassActor *lightning = PClass::FindActor(self->GetClass()->MissileName); AActor *mo; + if (lightning == NULL) + { + lightning = PClass::FindActor(NAME_LightningZap); + } mo = Spawn(lightning, self->Pos(), ALLOW_REPLACE); if (mo) { mo->SetState (mo->FindState (NAME_Death)); mo->velz = 40*FRACUNIT; - mo->Damage = 0; + mo->Damage = NULL; } + return 0; } //============================================================================ @@ -347,6 +370,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_LastZap) DEFINE_ACTION_FUNCTION(AActor, A_LightningRemove) { + PARAM_ACTION_PROLOGUE; + AActor *mo; mo = self->lastenemy; @@ -355,4 +380,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightningRemove) mo->lastenemy = NULL; P_ExplodeMissile (mo, NULL, NULL); } + return 0; } diff --git a/src/g_hexen/a_magestaff.cpp b/src/g_hexen/a_magestaff.cpp index 4df037fc2c..d1ca7e75c9 100644 --- a/src/g_hexen/a_magestaff.cpp +++ b/src/g_hexen/a_magestaff.cpp @@ -119,20 +119,22 @@ void MStaffSpawn (AActor *pmo, angle_t angle) DEFINE_ACTION_FUNCTION(AActor, A_MStaffAttack) { + PARAM_ACTION_PROLOGUE; + angle_t angle; player_t *player; AActor *linetarget; if (NULL == (player = self->player)) { - return; + return 0; } AMWeapBloodscourge *weapon = static_cast (self->player->ReadyWeapon); if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } angle = self->angle; @@ -151,6 +153,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MStaffAttack) MStaffSpawn (self, angle+ANGLE_1*5); S_Sound (self, CHAN_WEAPON, "MageStaffFire", 1, ATTN_NORM); weapon->MStaffCount = 3; + return 0; } //============================================================================ @@ -161,6 +164,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_MStaffAttack) DEFINE_ACTION_FUNCTION(AActor, A_MStaffPalette) { + PARAM_ACTION_PROLOGUE; + if (self->player != NULL) { AMWeapBloodscourge *weapon = static_cast (self->player->ReadyWeapon); @@ -169,6 +174,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MStaffPalette) weapon->MStaffCount--; } } + return 0; } //============================================================================ @@ -179,11 +185,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_MStaffPalette) DEFINE_ACTION_FUNCTION(AActor, A_MStaffTrack) { + PARAM_ACTION_PROLOGUE; + if ((self->tracer == 0) && (pr_mstafftrack()<50)) { self->tracer = P_RoughMonsterSearch (self, 10, true); } P_SeekerMissile (self, ANGLE_1*2, ANGLE_1*10); + return 0; } //============================================================================ @@ -239,13 +248,17 @@ void MStaffSpawn2 (AActor *actor, angle_t angle) DEFINE_ACTION_FUNCTION(AActor, A_MageAttack) { - if (!self->target) return; + PARAM_ACTION_PROLOGUE; + if (self->target == NULL) + { + return 0; + } angle_t angle; angle = self->angle; MStaffSpawn2 (self, angle); MStaffSpawn2 (self, angle-ANGLE_1*5); MStaffSpawn2 (self, angle+ANGLE_1*5); S_Sound (self, CHAN_WEAPON, "MageStaffFire", 1, ATTN_NORM); + return 0; } - diff --git a/src/g_hexen/a_pig.cpp b/src/g_hexen/a_pig.cpp index 21d141b0cd..8ce394a283 100644 --- a/src/g_hexen/a_pig.cpp +++ b/src/g_hexen/a_pig.cpp @@ -60,6 +60,8 @@ void APigPlayer::MorphPlayerThink () DEFINE_ACTION_FUNCTION(AActor, A_SnoutAttack) { + PARAM_ACTION_PROLOGUE; + angle_t angle; int damage; int slope; @@ -69,7 +71,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SnoutAttack) if (NULL == (player = self->player)) { - return; + return 0; } damage = 3+(pr_snoutattack()&3); @@ -85,6 +87,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SnoutAttack) S_Sound(player->mo, CHAN_VOICE, "PigAttack", 1, ATTN_NORM); } } + return 0; } //============================================================================ @@ -95,9 +98,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_SnoutAttack) DEFINE_ACTION_FUNCTION(AActor, A_PigPain) { + PARAM_ACTION_PROLOGUE; + CALL_ACTION(A_Pain, self); if (self->Z() <= self->floorz) { self->velz = FRACUNIT*7/2; } + return 0; } diff --git a/src/g_hexen/a_serpent.cpp b/src/g_hexen/a_serpent.cpp index 39b4382e30..2cb1738c65 100644 --- a/src/g_hexen/a_serpent.cpp +++ b/src/g_hexen/a_serpent.cpp @@ -25,8 +25,11 @@ static FRandom pr_delaygib ("DelayGib"); DEFINE_ACTION_FUNCTION(AActor, A_SerpentUnHide) { + PARAM_ACTION_PROLOGUE; + self->renderflags &= ~RF_INVISIBLE; self->floorclip = 24*FRACUNIT; + return 0; } //============================================================================ @@ -37,8 +40,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentUnHide) DEFINE_ACTION_FUNCTION(AActor, A_SerpentHide) { + PARAM_ACTION_PROLOGUE; + self->renderflags |= RF_INVISIBLE; self->floorclip = 0; + return 0; } //============================================================================ @@ -50,7 +56,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentHide) DEFINE_ACTION_FUNCTION(AActor, A_SerpentRaiseHump) { + PARAM_ACTION_PROLOGUE; + self->floorclip -= 4*FRACUNIT; + return 0; } //============================================================================ @@ -61,7 +70,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentRaiseHump) DEFINE_ACTION_FUNCTION(AActor, A_SerpentLowerHump) { + PARAM_ACTION_PROLOGUE; + self->floorclip += 4*FRACUNIT; + return 0; } //============================================================================ @@ -74,21 +86,23 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentLowerHump) DEFINE_ACTION_FUNCTION(AActor, A_SerpentHumpDecide) { + PARAM_ACTION_PROLOGUE; + if (self->MissileState != NULL) { if (pr_serpenthump() > 30) { - return; + return 0; } else if (pr_serpenthump() < 40) { // Missile attack self->SetState (self->MeleeState); - return; + return 0; } } else if (pr_serpenthump() > 3) { - return; + return 0; } if (!self->CheckMeleeRange ()) { // The hump shouldn't occur when within melee range @@ -102,6 +116,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentHumpDecide) S_Sound (self, CHAN_BODY, "SerpentActive", 1, ATTN_NORM); } } + return 0; } //============================================================================ @@ -112,16 +127,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentHumpDecide) DEFINE_ACTION_FUNCTION(AActor, A_SerpentCheckForAttack) { + PARAM_ACTION_PROLOGUE; + if (!self->target) { - return; + return 0; } if (self->MissileState != NULL) { if (!self->CheckMeleeRange ()) { self->SetState (self->FindState ("Attack")); - return; + return 0; } } if (P_CheckMeleeRange2 (self)) @@ -139,6 +156,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentCheckForAttack) self->SetState (self->FindState ("Attack")); } } + return 0; } //============================================================================ @@ -149,14 +167,17 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentCheckForAttack) DEFINE_ACTION_FUNCTION(AActor, A_SerpentChooseAttack) { + PARAM_ACTION_PROLOGUE; + if (!self->target || self->CheckMeleeRange()) { - return; + return 0; } if (self->MissileState != NULL) { self->SetState (self->MissileState); } + return 0; } //============================================================================ @@ -167,9 +188,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentChooseAttack) DEFINE_ACTION_FUNCTION(AActor, A_SerpentMeleeAttack) { + PARAM_ACTION_PROLOGUE; + if (!self->target) { - return; + return 0; } if (self->CheckMeleeRange ()) { @@ -182,6 +205,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentMeleeAttack) { CALL_ACTION(A_SerpentCheckForAttack, self); } + return 0; } //============================================================================ @@ -192,6 +216,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentMeleeAttack) DEFINE_ACTION_FUNCTION(AActor, A_SerpentSpawnGibs) { + PARAM_ACTION_PROLOGUE; + AActor *mo; static const char *GibTypes[] = { @@ -215,6 +241,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentSpawnGibs) mo->floorclip = 6*FRACUNIT; } } + return 0; } //============================================================================ @@ -225,7 +252,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentSpawnGibs) DEFINE_ACTION_FUNCTION(AActor, A_FloatGib) { + PARAM_ACTION_PROLOGUE; + self->floorclip -= FRACUNIT; + return 0; } //============================================================================ @@ -236,7 +266,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_FloatGib) DEFINE_ACTION_FUNCTION(AActor, A_SinkGib) { + PARAM_ACTION_PROLOGUE; + self->floorclip += FRACUNIT; + return 0; } //============================================================================ @@ -247,7 +280,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_SinkGib) DEFINE_ACTION_FUNCTION(AActor, A_DelayGib) { + PARAM_ACTION_PROLOGUE; + self->tics -= pr_delaygib()>>2; + return 0; } //============================================================================ @@ -258,6 +294,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_DelayGib) DEFINE_ACTION_FUNCTION(AActor, A_SerpentHeadCheck) { + PARAM_ACTION_PROLOGUE; + if (self->Z() <= self->floorz) { if (Terrains[P_GetThingFloorType(self)].IsLiquid) @@ -270,5 +308,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentHeadCheck) self->SetState (self->FindState(NAME_Death)); } } + return 0; } diff --git a/src/g_hexen/a_spike.cpp b/src/g_hexen/a_spike.cpp index 90729a77db..f1538d3d9d 100644 --- a/src/g_hexen/a_spike.cpp +++ b/src/g_hexen/a_spike.cpp @@ -78,16 +78,21 @@ void AThrustFloor::Deactivate (AActor *activator) DEFINE_ACTION_FUNCTION(AActor, A_ThrustInitUp) { + PARAM_ACTION_PROLOGUE; + self->special2 = 5; // Raise speed self->args[0] = 1; // Mark as up self->floorclip = 0; self->flags = MF_SOLID; self->flags2 = MF2_NOTELEPORT|MF2_FLOORCLIP; self->special1 = 0L; + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_ThrustInitDn) { + PARAM_ACTION_PROLOGUE; + self->special2 = 5; // Raise speed self->args[0] = 0; // Mark as down self->floorclip = self->GetDefault()->height; @@ -96,11 +101,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_ThrustInitDn) self->renderflags = RF_INVISIBLE; static_cast(self)->DirtClump = Spawn("DirtClump", self->Pos(), ALLOW_REPLACE); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_ThrustRaise) { + PARAM_ACTION_PROLOGUE; + AThrustFloor *actor = static_cast(self); if (A_RaiseMobj (actor, self->special2*FRACUNIT)) @@ -123,10 +131,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_ThrustRaise) if (pr_thrustraise()<40) P_SpawnDirt (actor, actor->radius); actor->special2++; // Increase raise speed + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_ThrustLower) { + PARAM_ACTION_PROLOGUE; + if (A_SinkMobj (self, 6*FRACUNIT)) { self->args[0] = 0; @@ -135,10 +146,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_ThrustLower) else self->SetState (self->FindState ("ThrustInit1"), true); } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_ThrustImpale) { + PARAM_ACTION_PROLOGUE; + AActor *thing; FBlockThingsIterator it(FBoundingBox(self->X(), self->Y(), self->radius)); while ((thing = it.Next())) @@ -158,5 +172,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_ThrustImpale) P_TraceBleed (newdam > 0 ? newdam : 10001, thing); self->args[1] = 1; // Mark thrust thing as bloody } + return 0; } diff --git a/src/g_hexen/a_summon.cpp b/src/g_hexen/a_summon.cpp index 0fffb6e4ce..9d543a2469 100644 --- a/src/g_hexen/a_summon.cpp +++ b/src/g_hexen/a_summon.cpp @@ -31,7 +31,7 @@ IMPLEMENT_CLASS (AArtiDarkServant) bool AArtiDarkServant::Use (bool pickup) { - AActor *mo = P_SpawnPlayerMissile (Owner, PClass::FindClass ("SummoningDoll")); + AActor *mo = P_SpawnPlayerMissile (Owner, PClass::FindActor("SummoningDoll")); if (mo) { mo->target = Owner; @@ -49,6 +49,8 @@ bool AArtiDarkServant::Use (bool pickup) DEFINE_ACTION_FUNCTION(AActor, A_Summon) { + PARAM_ACTION_PROLOGUE; + AMinotaurFriend *mo; mo = Spawn (self->Pos(), ALLOW_REPLACE); @@ -59,7 +61,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Summon) mo->Destroy (); AActor *arti = Spawn (self->Pos(), ALLOW_REPLACE); if (arti) arti->flags |= MF_DROPPED; - return; + return 0; } mo->StartTime = level.maptime; @@ -79,4 +81,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_Summon) Spawn ("MinotaurSmoke", self->Pos(), ALLOW_REPLACE); S_Sound (self, CHAN_VOICE, mo->ActiveSound, 1, ATTN_NORM); } + return 0; } diff --git a/src/g_hexen/a_teleportother.cpp b/src/g_hexen/a_teleportother.cpp index 0ee5b31b32..1f4b2f7f58 100644 --- a/src/g_hexen/a_teleportother.cpp +++ b/src/g_hexen/a_teleportother.cpp @@ -65,30 +65,41 @@ static void TeloSpawn (AActor *source, const char *type) DEFINE_ACTION_FUNCTION(AActor, A_TeloSpawnA) { + PARAM_ACTION_PROLOGUE; TeloSpawn (self, "TelOtherFX2"); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_TeloSpawnB) { + PARAM_ACTION_PROLOGUE; TeloSpawn (self, "TelOtherFX3"); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_TeloSpawnC) { + PARAM_ACTION_PROLOGUE; TeloSpawn (self, "TelOtherFX4"); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_TeloSpawnD) { + PARAM_ACTION_PROLOGUE; TeloSpawn (self, "TelOtherFX5"); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_CheckTeleRing) { + PARAM_ACTION_PROLOGUE; + if (self->special1-- <= 0) { self->SetState (self->FindState(NAME_Death)); } + return 0; } //=========================================================================== diff --git a/src/g_hexen/a_wraith.cpp b/src/g_hexen/a_wraith.cpp index 3bbe567ac6..b104c599c2 100644 --- a/src/g_hexen/a_wraith.cpp +++ b/src/g_hexen/a_wraith.cpp @@ -29,6 +29,8 @@ static FRandom pr_wraithfx4 ("WraithFX4"); DEFINE_ACTION_FUNCTION(AActor, A_WraithInit) { + PARAM_ACTION_PROLOGUE; + self->AddZ(48<special1 = 0; // index into floatbob + return 0; } //============================================================================ @@ -48,11 +51,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_WraithInit) DEFINE_ACTION_FUNCTION(AActor, A_WraithRaiseInit) { + PARAM_ACTION_PROLOGUE; + self->renderflags &= ~RF_INVISIBLE; self->flags2 &= ~MF2_NONSHOOTABLE; self->flags3 &= ~MF3_DONTBLAST; self->flags |= MF_SHOOTABLE|MF_SOLID; self->floorclip = self->height; + return 0; } //============================================================================ @@ -63,6 +69,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_WraithRaiseInit) DEFINE_ACTION_FUNCTION(AActor, A_WraithRaise) { + PARAM_ACTION_PROLOGUE; + if (A_RaiseMobj (self, 2*FRACUNIT)) { // Reached it's target height @@ -75,6 +83,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_WraithRaise) } P_SpawnDirt (self, self->radius); + return 0; } //============================================================================ @@ -85,6 +94,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_WraithRaise) DEFINE_ACTION_FUNCTION(AActor, A_WraithMelee) { + PARAM_ACTION_PROLOGUE; + int amount; // Steal health from target and give to self @@ -94,6 +105,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_WraithMelee) P_DamageMobj (self->target, self, self, amount, NAME_Melee); self->health += amount; } + return 0; } //============================================================================ @@ -104,6 +116,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_WraithMelee) DEFINE_ACTION_FUNCTION(AActor, A_WraithFX2) { + PARAM_ACTION_PROLOGUE; + AActor *mo; angle_t angle; int i; @@ -130,6 +144,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_WraithFX2) mo->floorclip = 10*FRACUNIT; } } + return 0; } //============================================================================ @@ -142,6 +157,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_WraithFX2) DEFINE_ACTION_FUNCTION(AActor, A_WraithFX3) { + PARAM_ACTION_PROLOGUE; + AActor *mo; int numdropped = pr_wraithfx3()%15; @@ -159,6 +176,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_WraithFX3) mo->target = self; } } + return 0; } //============================================================================ @@ -234,6 +252,8 @@ void A_WraithFX4 (AActor *self) DEFINE_ACTION_FUNCTION(AActor, A_WraithChase) { + PARAM_ACTION_PROLOGUE; + int weaveindex = self->special1; self->AddZ(finesine[weaveindex << BOBTOFINESHIFT] * 8); self->special1 = (weaveindex + 2) & 63; @@ -242,6 +262,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_WraithChase) // P_SetMobjState(self, S_WRAITH_RAISE2); // return; // } - A_Chase (self); + A_Chase (stack, self); A_WraithFX4 (self); + return 0; } diff --git a/src/g_level.h b/src/g_level.h index 2e8e8e4c57..6e1768c3aa 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -45,9 +45,7 @@ struct cluster_info_t; class FScanner; #if defined(_MSC_VER) -#pragma data_seg(".yreg$u") -#pragma data_seg() - +#pragma section(".yreg$u",read) #define MSVC_YSEG __declspec(allocate(".yreg$u")) #define GCC_YSEG #else diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index dfcd2e6141..1b1023fcd2 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -371,12 +371,12 @@ level_info_t *level_info_t::CheckLevelRedirect () { if (RedirectType != NAME_None) { - const PClass *type = PClass::FindClass(RedirectType); + PClassActor *type = PClass::FindActor(RedirectType); if (type != NULL) { for (int i = 0; i < MAXPLAYERS; ++i) { - if (playeringame[i] && players[i].mo->FindInventory (type)) + if (playeringame[i] && players[i].mo->FindInventory(type)) { // check for actual presence of the map. if (P_CheckMapData(RedirectMapName)) diff --git a/src/g_raven/a_artitele.cpp b/src/g_raven/a_artitele.cpp index 9922f75f00..da71c31c84 100644 --- a/src/g_raven/a_artitele.cpp +++ b/src/g_raven/a_artitele.cpp @@ -68,7 +68,7 @@ bool AArtiTeleport::Use (bool pickup) bool P_AutoUseChaosDevice (player_t *player) { - AInventory *arti = player->mo->FindInventory(PClass::FindClass("ArtiTeleport")); + AInventory *arti = player->mo->FindInventory(PClass::FindActor("ArtiTeleport")); if (arti != NULL) { diff --git a/src/g_raven/a_minotaur.cpp b/src/g_raven/a_minotaur.cpp index 5e2edd6341..14757c43b6 100644 --- a/src/g_raven/a_minotaur.cpp +++ b/src/g_raven/a_minotaur.cpp @@ -105,7 +105,7 @@ void AMinotaurFriend::Die (AActor *source, AActor *inflictor, int dmgflags) if (mo == NULL) { - AInventory *power = tracer->FindInventory (PClass::FindClass("PowerMinotaur")); + AInventory *power = tracer->FindInventory(PClass::FindActor("PowerMinotaur")); if (power != NULL) { power->Destroy (); @@ -132,18 +132,23 @@ bool AMinotaurFriend::OkayToSwitchTarget (AActor *other) DEFINE_ACTION_FUNCTION(AActor, A_MinotaurDeath) { + PARAM_ACTION_PROLOGUE; + if (Wads.CheckNumForName ("MNTRF1", ns_sprites) < 0 && Wads.CheckNumForName ("MNTRF0", ns_sprites) < 0) self->SetState(self->FindState ("FadeOut")); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk1) { + PARAM_ACTION_PROLOGUE; + player_t *player; if (!self->target) { - return; + return 0; } S_Sound (self, CHAN_WEAPON, "minotaur/melee", 1, ATTN_NORM); if (self->CheckMeleeRange()) @@ -157,6 +162,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk1) player->deltaviewheight = -16*FRACUNIT; } } + return 0; } //---------------------------------------------------------------------------- @@ -171,6 +177,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk1) DEFINE_ACTION_FUNCTION(AActor, A_MinotaurDecide) { + PARAM_ACTION_PROLOGUE; + bool friendly = !!(self->flags5 & MF5_SUMMONEDMONSTER); angle_t angle; AActor *target; @@ -179,7 +187,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurDecide) target = self->target; if (!target) { - return; + return 0; } if (!friendly) { @@ -218,6 +226,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurDecide) // Don't need to call P_SetMobjState because the current state // falls through to the swing attack } + return 0; } //---------------------------------------------------------------------------- @@ -228,21 +237,25 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurDecide) DEFINE_ACTION_FUNCTION(AActor, A_MinotaurCharge) { + PARAM_ACTION_PROLOGUE; + AActor *puff; - if (!self->target) return; - + if (self->target == NULL) + { + return 0; + } if (self->special1 > 0) { - const PClass *type; + PClassActor *type; if (gameinfo.gametype == GAME_Heretic) { - type = PClass::FindClass ("PhoenixPuff"); + type = PClass::FindActor("PhoenixPuff"); } else { - type = PClass::FindClass ("PunchPuff"); + type = PClass::FindActor("PunchPuff"); } puff = Spawn (type, self->Pos(), ALLOW_REPLACE); puff->velz = 2*FRACUNIT; @@ -254,6 +267,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurCharge) self->flags2 &= ~MF2_INVULNERABLE; self->SetState (self->SeeState); } + return 0; } //---------------------------------------------------------------------------- @@ -266,15 +280,17 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurCharge) DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk2) { + PARAM_ACTION_PROLOGUE; + AActor *mo; angle_t angle; fixed_t velz; fixed_t z; bool friendly = !!(self->flags5 & MF5_SUMMONEDMONSTER); - if (!self->target) + if (self->target == NULL) { - return; + return 0; } S_Sound (self, CHAN_WEAPON, "minotaur/attack2", 1, ATTN_NORM); if (self->CheckMeleeRange()) @@ -283,10 +299,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk2) damage = pr_atk.HitDice (friendly ? 3 : 5); int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); - return; + return 0; } z = self->Z() + 40*FRACUNIT; - const PClass *fx = PClass::FindClass("MinotaurFX1"); + PClassActor *fx = PClass::FindActor("MinotaurFX1"); if (fx) { mo = P_SpawnMissileZ (self, z, self->target, fx); @@ -301,6 +317,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk2) P_SpawnMissileAngleZ (self, z, fx, angle+(ANG45/16), velz); } } + return 0; } //---------------------------------------------------------------------------- @@ -313,13 +330,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk2) DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk3) { + PARAM_ACTION_PROLOGUE; + AActor *mo; player_t *player; bool friendly = !!(self->flags5 & MF5_SUMMONEDMONSTER); if (!self->target) { - return; + return 0; } S_Sound (self, CHAN_VOICE, "minotaur/attack3", 1, ATTN_NORM); if (self->CheckMeleeRange()) @@ -344,7 +363,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk3) } else { - mo = P_SpawnMissile (self, self->target, PClass::FindClass("MinotaurFX2")); + mo = P_SpawnMissile (self, self->target, PClass::FindActor("MinotaurFX2")); if (mo != NULL) { S_Sound (mo, CHAN_WEAPON, "minotaur/attack1", 1, ATTN_NORM); @@ -356,6 +375,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk3) self->SetState (self->FindState ("HammerLoop")); self->special2 = 1; } + return 0; } //---------------------------------------------------------------------------- @@ -366,6 +386,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk3) DEFINE_ACTION_FUNCTION(AActor, A_MntrFloorFire) { + PARAM_ACTION_PROLOGUE; + AActor *mo; self->SetZ(self->floorz); @@ -376,6 +398,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MntrFloorFire) mo->target = self->target; mo->velx = 1; // Force block checking P_CheckMissileSpawn (mo, self->radius); + return 0; } //--------------------------------------------------------------------------- @@ -422,6 +445,8 @@ void P_MinotaurSlam (AActor *source, AActor *target) DEFINE_ACTION_FUNCTION(AActor, A_MinotaurRoam) { + PARAM_ACTION_PROLOGUE; + // In case pain caused him to skip his fade in. self->RenderStyle = STYLE_Normal; @@ -432,7 +457,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurRoam) if (self1->StartTime >= 0 && (level.maptime - self1->StartTime) >= MAULATORTICS) { P_DamageMobj (self1, NULL, NULL, TELEFRAG_DAMAGE, NAME_None); - return; + return 0; } } @@ -454,6 +479,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurRoam) self->movedir = (self->movedir + 7) % 8; FaceMovementDirection (self); } + return 0; } @@ -467,10 +493,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurRoam) DEFINE_ACTION_FUNCTION(AActor, A_MinotaurLook) { + PARAM_ACTION_PROLOGUE; + if (!self->IsKindOf(RUNTIME_CLASS(AMinotaurFriend))) { CALL_ACTION(A_Look, self); - return; + return 0; } AActor *mo = NULL; @@ -531,14 +559,17 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurLook) { self->SetState (self->FindState ("Roam"), true); } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_MinotaurChase) { + PARAM_ACTION_PROLOGUE; + if (!self->IsKindOf(RUNTIME_CLASS(AMinotaurFriend))) { - A_Chase (self); - return; + A_Chase (stack, self); + return 0; } AMinotaurFriend *self1 = static_cast (self); @@ -549,7 +580,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurChase) if (self1->StartTime >= 0 && (level.maptime - self1->StartTime) >= MAULATORTICS) { P_DamageMobj (self1, NULL, NULL, TELEFRAG_DAMAGE, NAME_None); - return; + return 0; } if (pr_minotaurchase() < 30) @@ -559,7 +590,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurChase) !(self1->target->flags&MF_SHOOTABLE)) { // look for a new target self1->SetIdle(); - return; + return 0; } FaceMovementDirection (self1); @@ -573,14 +604,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurChase) S_Sound (self1, CHAN_WEAPON, self1->AttackSound, 1, ATTN_NORM); } self1->SetState (self1->MeleeState); - return; + return 0; } // Missile attack if (self1->MissileState && P_CheckMissileRange(self1)) { self1->SetState (self1->MissileState); - return; + return 0; } // chase towards target @@ -595,5 +626,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurChase) { self1->PlayActiveSound (); } + return 0; } diff --git a/src/g_shared/a_action.cpp b/src/g_shared/a_action.cpp index e4b683e97a..53acad047a 100644 --- a/src/g_shared/a_action.cpp +++ b/src/g_shared/a_action.cpp @@ -82,7 +82,7 @@ void A_Unblock(AActor *self, bool drop) // If the actor has attached metadata for items to drop, drop those. if (drop && !self->IsKindOf (RUNTIME_CLASS (APlayerPawn))) // [GRB] { - FDropItem *di = self->GetDropItems(); + DDropItem *di = self->GetDropItems(); if (di != NULL) { @@ -90,8 +90,11 @@ void A_Unblock(AActor *self, bool drop) { if (di->Name != NAME_None) { - const PClass *ti = PClass::FindClass(di->Name); - if (ti) P_DropItem (self, ti, di->amount, di->probability); + PClassActor *ti = PClass::FindActor(di->Name); + if (ti != NULL) + { + P_DropItem (self, ti, di->Amount, di->Probability); + } } di = di->Next; } @@ -101,12 +104,16 @@ void A_Unblock(AActor *self, bool drop) DEFINE_ACTION_FUNCTION(AActor, A_NoBlocking) { + PARAM_ACTION_PROLOGUE; A_Unblock(self, true); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_Fall) { + PARAM_ACTION_PROLOGUE; A_Unblock(self, true); + return 0; } //========================================================================== @@ -117,8 +124,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_Fall) DEFINE_ACTION_FUNCTION(AActor, A_SetFloorClip) { + PARAM_ACTION_PROLOGUE; + self->flags2 |= MF2_FLOORCLIP; self->AdjustFloorClip (); + return 0; } //========================================================================== @@ -129,8 +139,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_SetFloorClip) DEFINE_ACTION_FUNCTION(AActor, A_UnSetFloorClip) { + PARAM_ACTION_PROLOGUE; + self->flags2 &= ~MF2_FLOORCLIP; self->floorclip = 0; + return 0; } //========================================================================== @@ -141,7 +154,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_UnSetFloorClip) DEFINE_ACTION_FUNCTION(AActor, A_HideThing) { + PARAM_ACTION_PROLOGUE; + self->renderflags |= RF_INVISIBLE; + return 0; } //========================================================================== @@ -152,7 +168,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_HideThing) DEFINE_ACTION_FUNCTION(AActor, A_UnHideThing) { + PARAM_ACTION_PROLOGUE; + self->renderflags &= ~RF_INVISIBLE; + return 0; } //============================================================================ @@ -163,6 +182,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_UnHideThing) DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeath) { + PARAM_ACTION_PROLOGUE; + int t = pr_freezedeath(); self->tics = 75+t+pr_freezedeath(); self->flags |= MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD|MF_ICECORPSE; @@ -196,6 +217,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeath) self->args[1], self->args[2], self->args[3], self->args[4]); self->special = 0; } + return 0; } //========================================================================== @@ -206,8 +228,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeath) DEFINE_ACTION_FUNCTION(AActor, A_GenericFreezeDeath) { + PARAM_ACTION_PROLOGUE; + self->Translation = TRANSLATION(TRANSLATION_Standard, 7); CALL_ACTION(A_FreezeDeath, self); + return 0; } //============================================================================ @@ -218,6 +243,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_GenericFreezeDeath) DEFINE_ACTION_FUNCTION(AActor, A_IceSetTics) { + PARAM_ACTION_PROLOGUE; + int floor; self->tics = 70+(pr_icesettics()&63); @@ -230,6 +257,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_IceSetTics) { self->tics <<= 1; } + return 0; } //============================================================================ @@ -240,6 +268,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_IceSetTics) DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeathChunks) { + PARAM_ACTION_PROLOGUE; int i; int numChunks; @@ -248,7 +277,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeathChunks) if ((self->velx || self->vely || self->velz) && !(self->flags6 & MF6_SHATTERING)) { self->tics = 3*TICRATE; - return; + return 0; } self->velx = self->vely = self->velz = 0; S_Sound (self, CHAN_BODY, "misc/icebreak", 1, ATTN_NORM); @@ -312,6 +341,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeathChunks) A_Unblock(self, true); self->SetState(self->FindState(NAME_Null)); + return 0; } //---------------------------------------------------------------------------- @@ -413,13 +443,20 @@ void DCorpsePointer::Serialize (FArchive &arc) // throw another corpse on the queue DEFINE_ACTION_FUNCTION(AActor, A_QueueCorpse) { + PARAM_ACTION_PROLOGUE; + if (sv_corpsequeuesize > 0) + { new DCorpsePointer (self); + } + return 0; } // Remove an self from the queue (for resurrection) DEFINE_ACTION_FUNCTION(AActor, A_DeQueueCorpse) { + PARAM_ACTION_PROLOGUE; + TThinkerIterator iterator (STAT_CORPSEPOINTER); DCorpsePointer *corpsePtr; @@ -429,9 +466,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_DeQueueCorpse) { corpsePtr->Corpse = NULL; corpsePtr->Destroy (); - return; + return 0; } } + return 0; } //============================================================================ @@ -442,7 +480,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_DeQueueCorpse) DEFINE_ACTION_FUNCTION(AActor, A_SetInvulnerable) { + PARAM_ACTION_PROLOGUE; + self->flags2 |= MF2_INVULNERABLE; + return 0; } //============================================================================ @@ -453,7 +494,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_SetInvulnerable) DEFINE_ACTION_FUNCTION(AActor, A_UnSetInvulnerable) { + PARAM_ACTION_PROLOGUE; + self->flags2 &= ~MF2_INVULNERABLE; + return 0; } //============================================================================ @@ -464,7 +508,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_UnSetInvulnerable) DEFINE_ACTION_FUNCTION(AActor, A_SetReflective) { + PARAM_ACTION_PROLOGUE; + self->flags2 |= MF2_REFLECTIVE; + return 0; } //============================================================================ @@ -475,7 +522,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_SetReflective) DEFINE_ACTION_FUNCTION(AActor, A_UnSetReflective) { + PARAM_ACTION_PROLOGUE; + self->flags2 &= ~MF2_REFLECTIVE; + return 0; } //============================================================================ @@ -486,7 +536,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_UnSetReflective) DEFINE_ACTION_FUNCTION(AActor, A_SetReflectiveInvulnerable) { + PARAM_ACTION_PROLOGUE; + self->flags2 |= MF2_REFLECTIVE|MF2_INVULNERABLE; + return 0; } //============================================================================ @@ -497,7 +550,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_SetReflectiveInvulnerable) DEFINE_ACTION_FUNCTION(AActor, A_UnSetReflectiveInvulnerable) { + PARAM_ACTION_PROLOGUE; + self->flags2 &= ~(MF2_REFLECTIVE|MF2_INVULNERABLE); + return 0; } //========================================================================== @@ -508,8 +564,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_UnSetReflectiveInvulnerable) DEFINE_ACTION_FUNCTION(AActor, A_SetShootable) { + PARAM_ACTION_PROLOGUE; + self->flags2 &= ~MF2_NONSHOOTABLE; self->flags |= MF_SHOOTABLE; + return 0; } //========================================================================== @@ -520,8 +579,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_SetShootable) DEFINE_ACTION_FUNCTION(AActor, A_UnSetShootable) { + PARAM_ACTION_PROLOGUE; + self->flags2 |= MF2_NONSHOOTABLE; self->flags &= ~MF_SHOOTABLE; + return 0; } //=========================================================================== @@ -532,7 +594,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_UnSetShootable) DEFINE_ACTION_FUNCTION(AActor, A_NoGravity) { + PARAM_ACTION_PROLOGUE; + self->flags |= MF_NOGRAVITY; + return 0; } //=========================================================================== @@ -543,8 +608,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_NoGravity) DEFINE_ACTION_FUNCTION(AActor, A_Gravity) { + PARAM_ACTION_PROLOGUE; + self->flags &= ~MF_NOGRAVITY; self->gravity = FRACUNIT; + return 0; } //=========================================================================== @@ -555,8 +623,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_Gravity) DEFINE_ACTION_FUNCTION(AActor, A_LowGravity) { + PARAM_ACTION_PROLOGUE; + self->flags &= ~MF_NOGRAVITY; self->gravity = FRACUNIT/8; + return 0; } //=========================================================================== diff --git a/src/g_shared/a_armor.cpp b/src/g_shared/a_armor.cpp index 0f343e523f..c18f4172aa 100644 --- a/src/g_shared/a_armor.cpp +++ b/src/g_shared/a_armor.cpp @@ -180,7 +180,7 @@ void ABasicArmor::AbsorbDamage (int damage, FName damageType, int &newdamage) // The differences include not using a default value, and of course the way // the damage factor info is obtained. const fixed_t *pdf = NULL; - DmgFactors *df = PClass::FindClass(ArmorType)->ActorInfo->DamageFactors; + DmgFactors *df = PClass::FindActor(ArmorType)->DamageFactors; if (df != NULL && df->CountUsed() != 0) { pdf = df->CheckFactor(damageType); diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index 42b286f531..58aee16fb9 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -369,9 +369,9 @@ void APowerInvulnerable::InitEffect () Super::InitEffect(); Owner->effects &= ~FX_RESPAWNINVUL; Owner->flags2 |= MF2_INVULNERABLE; - if (Mode == NAME_None) + if (Mode == NAME_None && Owner->IsKindOf(RUNTIME_CLASS(APlayerPawn))) { - Mode = (ENamedName)RUNTIME_TYPE(Owner)->Meta.GetMetaInt(APMETA_InvulMode); + Mode = static_cast(Owner->GetClass())->InvulMode; } if (Mode == NAME_Reflective) { @@ -1619,8 +1619,8 @@ void APowerDamage::ModifyDamage(int damage, FName damageType, int &newdamage, bo static const fixed_t def = 4*FRACUNIT; if (!passive && damage > 0) { - const fixed_t * pdf = NULL; - DmgFactors * df = GetClass()->ActorInfo->DamageFactors; + const fixed_t *pdf = NULL; + DmgFactors *df = GetClass()->DamageFactors; if (df != NULL && df->CountUsed() != 0) { pdf = df->CheckFactor(damageType); @@ -1700,7 +1700,7 @@ void APowerProtection::ModifyDamage(int damage, FName damageType, int &newdamage if (passive && damage > 0) { const fixed_t *pdf = NULL; - DmgFactors *df = GetClass()->ActorInfo->DamageFactors; + DmgFactors *df = GetClass()->DamageFactors; if (df != NULL && df->CountUsed() != 0) { pdf = df->CheckFactor(damageType); @@ -1887,9 +1887,9 @@ void APowerMorph::InitEffect( ) if (Owner != NULL && Owner->player != NULL && PlayerClass != NAME_None) { player_t *realplayer = Owner->player; // Remember the identity of the player - const PClass *morph_flash = PClass::FindClass (MorphFlash); - const PClass *unmorph_flash = PClass::FindClass (UnMorphFlash); - const PClass *player_class = PClass::FindClass (PlayerClass); + PClassActor *morph_flash = PClass::FindActor(MorphFlash); + PClassActor *unmorph_flash = PClass::FindActor(UnMorphFlash); + PClassPlayerPawn *player_class = dyn_cast(PClass::FindClass (PlayerClass)); if (P_MorphPlayer(realplayer, realplayer, player_class, -1/*INDEFINITELY*/, MorphStyle, morph_flash, unmorph_flash)) { Owner = realplayer->mo; // Replace the new owner in our owner; safe because we are not attached to anything yet diff --git a/src/g_shared/a_artifacts.h b/src/g_shared/a_artifacts.h index c16a7a0c12..5881fc52fc 100644 --- a/src/g_shared/a_artifacts.h +++ b/src/g_shared/a_artifacts.h @@ -44,7 +44,7 @@ public: virtual bool Use (bool pickup); virtual void Serialize (FArchive &arc); - const PClass *PowerupType; + PClassActor *PowerupType; int EffectTics; // Non-0 to override the powerup's default tics PalEntry BlendColor; // Non-0 to override the powerup's default blend FNameNoInit Mode; // Meaning depends on powerup - used for Invulnerability and Invisibility diff --git a/src/g_shared/a_bridge.cpp b/src/g_shared/a_bridge.cpp index 27dbb0c6b6..1309e46757 100644 --- a/src/g_shared/a_bridge.cpp +++ b/src/g_shared/a_bridge.cpp @@ -92,10 +92,12 @@ void ACustomBridge::Destroy() DEFINE_ACTION_FUNCTION(AActor, A_BridgeOrbit) { + PARAM_ACTION_PROLOGUE; + if (self->target == NULL) { // Don't crash if somebody spawned this into the world // independantly of a Bridge actor. - return; + return 0; } // Set default values // Every five tics, Hexen moved the ball 3/256th of a revolution. @@ -113,18 +115,22 @@ DEFINE_ACTION_FUNCTION(AActor, A_BridgeOrbit) self->SetOrigin(self->target->Vec3Angle(rotationradius, self->angle, 0), true); self->floorz = self->target->floorz; self->ceilingz = self->target->ceilingz; + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BridgeInit) { + PARAM_ACTION_PROLOGUE; + PARAM_CLASS_OPT(balltype, AActor) { balltype = NULL; } + angle_t startangle; AActor *ball; - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(balltype, 0); - - if (balltype == NULL) balltype = PClass::FindClass("BridgeBall"); + if (balltype == NULL) + { + balltype = PClass::FindActor("BridgeBall"); + } startangle = pr_orbit() << 24; @@ -138,6 +144,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BridgeInit) ball->target = self; CALL_ACTION(A_BridgeOrbit, ball); } + return 0; } diff --git a/src/g_shared/a_debris.cpp b/src/g_shared/a_debris.cpp index f60e71595c..359186d81f 100644 --- a/src/g_shared/a_debris.cpp +++ b/src/g_shared/a_debris.cpp @@ -31,7 +31,7 @@ IMPLEMENT_CLASS(AGlassShard) void P_SpawnDirt (AActor *actor, fixed_t radius) { - const PClass *dtype = NULL; + PClassActor *dtype = NULL; AActor *mo; fixed_t zo = (pr_dirt() << 9) + FRACUNIT; @@ -39,7 +39,7 @@ void P_SpawnDirt (AActor *actor, fixed_t radius) char fmt[8]; mysnprintf(fmt, countof(fmt), "Dirt%d", 1 + pr_dirt()%6); - dtype = PClass::FindClass(fmt); + dtype = PClass::FindActor(fmt); if (dtype) { mo = Spawn (dtype, pos, ALLOW_REPLACE); diff --git a/src/g_shared/a_fastprojectile.cpp b/src/g_shared/a_fastprojectile.cpp index 1e536faa81..da71358f98 100644 --- a/src/g_shared/a_fastprojectile.cpp +++ b/src/g_shared/a_fastprojectile.cpp @@ -168,7 +168,7 @@ void AFastProjectile::Effect() { //if (pr_smoke() < 128) // [RH] I think it looks better if it's consistent { - FName name = (ENamedName) this->GetClass()->Meta.GetMetaInt (ACMETA_MissileName, NAME_None); + FName name = GetClass()->MissileName; if (name != NAME_None) { fixed_t hitz = Z()-8*FRACUNIT; @@ -178,9 +178,9 @@ void AFastProjectile::Effect() hitz = floorz; } // Do not clip this offset to the floor. - hitz += GetClass()->Meta.GetMetaFixed (ACMETA_MissileHeight); + hitz += GetClass()->MissileHeight; - const PClass *trail = PClass::FindClass(name); + PClassActor *trail = PClass::FindActor(name); if (trail != NULL) { AActor *act = Spawn (trail, X(), Y(), hitz, ALLOW_REPLACE); diff --git a/src/g_shared/a_keys.cpp b/src/g_shared/a_keys.cpp index 67d0ffb101..d0fcc9e3f5 100644 --- a/src/g_shared/a_keys.cpp +++ b/src/g_shared/a_keys.cpp @@ -14,10 +14,10 @@ struct OneKey { - const PClass *key; + PClassActor *key; int count; - bool check(AActor * owner) + bool check(AActor *owner) { if (owner->IsKindOf(RUNTIME_CLASS(AKey))) { @@ -122,7 +122,7 @@ static const char * keywords_lock[]={ // //=========================================================================== -static void AddOneKey(Keygroup *keygroup, const PClass *mi, FScanner &sc) +static void AddOneKey(Keygroup *keygroup, PClassActor *mi, FScanner &sc) { if (mi) { @@ -159,17 +159,17 @@ static void AddOneKey(Keygroup *keygroup, const PClass *mi, FScanner &sc) // //=========================================================================== -static Keygroup * ParseKeygroup(FScanner &sc) +static Keygroup *ParseKeygroup(FScanner &sc) { - Keygroup * keygroup; - const PClass * mi; + Keygroup *keygroup; + PClassActor *mi; sc.MustGetStringName("{"); keygroup = new Keygroup; while (!sc.CheckString("}")) { sc.MustGetString(); - mi = PClass::FindClass(sc.String); + mi = PClass::FindActor(sc.String); AddOneKey(keygroup, mi, sc); } if (keygroup->anykeylist.Size() == 0) @@ -208,9 +208,9 @@ static void ParseLock(FScanner &sc) int i,r,g,b; int keynum; Lock sink; - Lock * lock=&sink; - Keygroup * keygroup; - const PClass * mi; + Lock *lock = &sink; + Keygroup *keygroup; + PClassActor *mi; sc.MustGetNumber(); keynum = sc.Number; @@ -292,7 +292,7 @@ static void ParseLock(FScanner &sc) break; default: - mi = PClass::FindClass(sc.String); + mi = PClass::FindActor(sc.String); if (mi) { keygroup = new Keygroup; @@ -328,27 +328,27 @@ static void ParseLock(FScanner &sc) static void ClearLocks() { unsigned int i; - for(i=0;iIsDescendantOf(RUNTIME_CLASS(AKey))) + if (PClassActor::AllActorClasses[i]->IsDescendantOf(RUNTIME_CLASS(AKey))) { - AKey *key = static_cast(GetDefaultByType(PClass::m_Types[i])); + AKey *key = static_cast(GetDefaultByType(PClassActor::AllActorClasses[i])); if (key != NULL) { key->KeyNumber = 0; } } } - for(i=0;i<256;i++) + for(i = 0; i < 256; i++) { - if (locks[i]!=NULL) + if (locks[i] != NULL) { delete locks[i]; - locks[i]=NULL; + locks[i] = NULL; } } - currentnumber=0; - keysdone=false; + currentnumber = 0; + keysdone = false; } //=========================================================================== diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index bc63f7bf02..8ec40736a0 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -30,7 +30,7 @@ void InitAllPowerupEffects(AInventory *item); // //--------------------------------------------------------------------------- -bool P_MorphPlayer (player_t *activator, player_t *p, const PClass *spawntype, int duration, int style, const PClass *enter_flash, const PClass *exit_flash) +bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntype, int duration, int style, PClassActor *enter_flash, PClassActor *exit_flash) { AInventory *item; APlayerPawn *morphed; @@ -135,7 +135,7 @@ bool P_MorphPlayer (player_t *activator, player_t *p, const PClass *spawntype, i hxarmor->Slots[1] = 0; hxarmor->Slots[2] = 0; hxarmor->Slots[3] = 0; - hxarmor->Slots[4] = spawntype->Meta.GetMetaFixed (APMETA_Hexenarmor0); + hxarmor->Slots[4] = spawntype->HexenArmor[0]; } else { @@ -241,7 +241,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, mo->Score = pmo->Score; InitAllPowerupEffects(mo->Inventory); - const PClass *exit_flash = player->MorphExitFlash; + PClassActor *exit_flash = player->MorphExitFlash; bool correctweapon = !!(player->MorphStyle & MORPH_LOSEACTUALWEAPON); bool undobydeathsaves = !!(player->MorphStyle & MORPH_UNDOBYDEATHSAVES); @@ -278,8 +278,8 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, // and for the original DOOM status bar. if (player == &players[consoleplayer]) { - const char *face = pmo->GetClass()->Meta.GetMetaString (APMETA_Face); - if (face != NULL && strcmp(face, "None") != 0) + FString face = pmo->GetClass()->Face; + if (face.IsNotEmpty() && strcmp(face, "None") != 0) { // Assume root-level base skin to begin with size_t skinindex = 0; @@ -325,8 +325,8 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, } if (correctweapon) { // Better "lose morphed weapon" semantics - const PClass *morphweapon = PClass::FindClass (pmo->MorphWeapon); - if (morphweapon != NULL && morphweapon->IsDescendantOf (RUNTIME_CLASS(AWeapon))) + PClassActor *morphweapon = PClass::FindActor(pmo->MorphWeapon); + if (morphweapon != NULL && morphweapon->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { AWeapon *OriginalMorphWeapon = static_cast(mo->FindInventory (morphweapon)); if ((OriginalMorphWeapon != NULL) && (OriginalMorphWeapon->GivenAsMorphWeapon)) @@ -356,7 +356,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, AHexenArmor *hxarmor = mo->FindInventory(); if (hxarmor != NULL) { - hxarmor->Slots[4] = mo->GetClass()->Meta.GetMetaFixed (APMETA_Hexenarmor0); + hxarmor->Slots[4] = mo->GetClass()->HexenArmor[0]; } return true; } @@ -369,7 +369,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, // //--------------------------------------------------------------------------- -bool P_MorphMonster (AActor *actor, const PClass *spawntype, int duration, int style, const PClass *enter_flash, const PClass *exit_flash) +bool P_MorphMonster (AActor *actor, PClassActor *spawntype, int duration, int style, PClassActor *enter_flash, PClassActor *exit_flash) { AMorphedMonster *morphed; @@ -470,7 +470,7 @@ bool P_UndoMonsterMorph (AMorphedMonster *beast, bool force) actor->AddToHash (); beast->UnmorphedMe = NULL; DObject::StaticPointerSubstitution (beast, actor); - const PClass *exit_flash = beast->MorphExitFlash; + PClassActor *exit_flash = beast->MorphExitFlash; beast->Destroy (); AActor *eflash = Spawn(exit_flash, beast->PosPlusZ(TELEFOGHEIGHT), ALLOW_REPLACE); if (eflash) @@ -550,7 +550,10 @@ bool P_MorphedDeath(AActor *actor, AActor **morphed, int *morphedstyle, int *mor if (realme->flags4 & MF4_BOSSDEATH) { realme->health = 0; // make sure that A_BossDeath considers it dead. - CALL_ACTION(A_BossDeath, realme); + // FIXME: Use the caller's stack once the whole chain is scriptable. + VMFrameStack stack; + VMValue params[3] = { realme, realme, VMValue(NULL, ATAG_STATE) }; + stack.Call(A_BossDeath_VMPtr, params, countof(params), NULL, 0, NULL); } } fakeme->flags3 |= MF3_STAYMORPHED; // moved here from AMorphedMonster::Die() @@ -607,16 +610,16 @@ IMPLEMENT_CLASS(AMorphProjectile) int AMorphProjectile::DoSpecialDamage (AActor *target, int damage, FName damagetype) { - const PClass *morph_flash = PClass::FindClass (MorphFlash); - const PClass *unmorph_flash = PClass::FindClass (UnMorphFlash); + PClassActor *morph_flash = PClass::FindActor(MorphFlash); + PClassActor *unmorph_flash = PClass::FindActor(UnMorphFlash); if (target->player) { - const PClass *player_class = PClass::FindClass (PlayerClass); + PClassPlayerPawn *player_class = dyn_cast(PClass::FindClass(PlayerClass)); P_MorphPlayer (NULL, target->player, player_class, Duration, MorphStyle, morph_flash, unmorph_flash); } else { - const PClass *monster_class = PClass::FindClass (MonsterClass); + PClassActor *monster_class = PClass::FindActor(MonsterClass); P_MorphMonster (target, monster_class, Duration, MorphStyle, morph_flash, unmorph_flash); } return -1; diff --git a/src/g_shared/a_morph.h b/src/g_shared/a_morph.h index 9272901dd2..467b7e8007 100644 --- a/src/g_shared/a_morph.h +++ b/src/g_shared/a_morph.h @@ -29,16 +29,16 @@ enum MORPH_STANDARDUNDOING = MORPH_UNDOBYTOMEOFPOWER | MORPH_UNDOBYCHAOSDEVICE | MORPH_UNDOBYTIMEOUT, }; -struct PClass; +class PClass; class AActor; class player_t; class AMorphedMonster; -bool P_MorphPlayer (player_t *activator, player_t *player, const PClass *morphclass, int duration = 0, int style = 0, - const PClass *enter_flash = NULL, const PClass *exit_flash = NULL); +bool P_MorphPlayer (player_t *activator, player_t *player, PClassPlayerPawn *morphclass, int duration = 0, int style = 0, + PClassActor *enter_flash = NULL, PClassActor *exit_flash = NULL); bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag = 0, bool force = false); -bool P_MorphMonster (AActor *actor, const PClass *morphclass, int duration = 0, int style = 0, - const PClass *enter_flash = NULL, const PClass *exit_flash = NULL); +bool P_MorphMonster (AActor *actor, PClassActor *morphclass, int duration = 0, int style = 0, + PClassActor *enter_flash = NULL, PClassActor *exit_flash = NULL); bool P_UndoMonsterMorph (AMorphedMonster *beast, bool force = false); bool P_UpdateMorphedMonster (AActor *actor); bool P_MorphedDeath(AActor *actor, AActor **morphed, int *morphedstyle, int *morphedhealth); diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index 0d67489b6f..f6bca12940 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -22,6 +22,41 @@ static FRandom pr_restore ("RestorePos"); +IMPLEMENT_CLASS(PClassInventory) + +PClassInventory::PClassInventory() +{ + GiveQuest = 0; + AltHUDIcon.SetNull(); +} + +void PClassInventory::Derive(PClass *newclass) +{ + assert(newclass->IsKindOf(RUNTIME_CLASS(PClassInventory))); + Super::Derive(newclass); + PClassInventory *newc = static_cast(newclass); + + newc->PickupMessage = PickupMessage; + newc->GiveQuest = GiveQuest; + newc->AltHUDIcon = AltHUDIcon; +} + +IMPLEMENT_CLASS(PClassAmmo) + +PClassAmmo::PClassAmmo() +{ + DropAmount = 0; +} + +void PClassAmmo::Derive(PClass *newclass) +{ + assert(newclass->IsKindOf(RUNTIME_CLASS(PClassAmmo))); + Super::Derive(newclass); + PClassAmmo *newc = static_cast(newclass); + + newc->DropAmount = DropAmount; +} + IMPLEMENT_CLASS (AAmmo) //=========================================================================== @@ -53,15 +88,15 @@ void AAmmo::Serialize (FArchive &arc) // //=========================================================================== -const PClass *AAmmo::GetParentAmmo () const +PClassActor *AAmmo::GetParentAmmo () const { - const PClass *type = GetClass (); + PClass *type = GetClass(); while (type->ParentClass != RUNTIME_CLASS(AAmmo) && type->ParentClass != NULL) { type = type->ParentClass; } - return type; + return static_cast(type); } //=========================================================================== @@ -139,8 +174,7 @@ AInventory *AAmmo::CreateCopy (AActor *other) if (GetClass()->ParentClass != RUNTIME_CLASS(AAmmo) && GetClass() != RUNTIME_CLASS(AAmmo)) { - const PClass *type = GetParentAmmo(); - assert (type->ActorInfo != NULL); + PClassActor *type = GetParentAmmo(); if (!GoAway ()) { Destroy (); @@ -289,11 +323,14 @@ bool P_GiveBody (AActor *actor, int num, int max) DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialThing1) { + PARAM_ACTION_PROLOGUE; + self->renderflags &= ~RF_INVISIBLE; if (static_cast(self)->DoRespawn ()) { S_Sound (self, CHAN_VOICE, "misc/spawn", 1, ATTN_IDLE); } + return 0; } //--------------------------------------------------------------------------- @@ -304,12 +341,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialThing1) DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialThing2) { + PARAM_ACTION_PROLOGUE; + self->flags |= MF_SPECIAL; if (!(self->GetDefault()->flags & MF_NOGRAVITY)) { self->flags &= ~MF_NOGRAVITY; } self->SetState (self->SpawnState); + return 0; } @@ -321,6 +361,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialThing2) DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialDoomThing) { + PARAM_ACTION_PROLOGUE; + self->renderflags &= ~RF_INVISIBLE; self->flags |= MF_SPECIAL; if (!(self->GetDefault()->flags & MF_NOGRAVITY)) @@ -333,6 +375,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialDoomThing) S_Sound (self, CHAN_VOICE, "misc/spawn", 1, ATTN_IDLE); Spawn ("ItemFog", self->Pos(), ALLOW_REPLACE); } + return 0; } //--------------------------------------------------------------------------- @@ -343,6 +386,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialDoomThing) DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialPosition) { + PARAM_ACTION_PROLOGUE; + // Move item back to its original location fixed_t _x, _y; sector_t *sec; @@ -397,6 +442,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialPosition) self->PrevX = self->X(); self->PrevY = self->Y(); self->PrevZ = self->Z(); + return 0; } int AInventory::StaticLastMessageTic; @@ -1079,7 +1125,7 @@ void AInventory::DoPickupSpecial (AActor *toucher) const char *AInventory::PickupMessage () { - return GetClass()->Meta.GetMetaString (AIMETA_PickupMessage); + return GetClass()->PickupMessage; } //=========================================================================== @@ -1306,8 +1352,8 @@ bool AInventory::DoRespawn () void AInventory::GiveQuest (AActor *toucher) { - int quest = GetClass()->Meta.GetMetaInt(AIMETA_GiveQuest); - if (quest>0 && quest<31) + int quest = GetClass()->GiveQuest; + if (quest > 0 && quest <= (int)countof(QuestItemClasses)) { toucher->GiveInventoryType (QuestItemClasses[quest-1]); } @@ -1478,7 +1524,7 @@ bool AInventory::CanPickup (AActor *toucher) if (!toucher) return false; - FActorInfo *ai = GetClass()->ActorInfo; + PClassActor *ai = GetClass(); // Is the item restricted to certain player classes? if (ai->RestrictedToPlayerClass.Size() != 0) { @@ -1607,6 +1653,35 @@ bool ACustomInventory::TryPickup (AActor *&toucher) return useok; } +IMPLEMENT_CLASS(PClassHealth) + +//=========================================================================== +// +// PClassHealth Constructor +// +//=========================================================================== + +PClassHealth::PClassHealth() +{ + LowHealth = 0; +} + +//=========================================================================== +// +// PClassHealth :: Derive +// +//=========================================================================== + +void PClassHealth::Derive(PClass *newclass) +{ + assert(newclass->IsKindOf(RUNTIME_CLASS(PClassHealth))); + Super::Derive(newclass); + PClassHealth *newc = static_cast(newclass); + + newc->LowHealth = LowHealth; + newc->LowHealthMessage = LowHealthMessage; +} + IMPLEMENT_CLASS (AHealth) //=========================================================================== @@ -1616,13 +1691,13 @@ IMPLEMENT_CLASS (AHealth) //=========================================================================== const char *AHealth::PickupMessage () { - int threshold = GetClass()->Meta.GetMetaInt(AIMETA_LowHealth, 0); + int threshold = GetClass()->LowHealth; if (PrevHealth < threshold) { - const char *message = GetClass()->Meta.GetMetaString (AIMETA_LowHealthMessage); + FString message = GetClass()->LowHealthMessage; - if (message != NULL) + if (message.IsNotEmpty()) { return message; } @@ -1752,13 +1827,14 @@ AInventory *ABackpackItem::CreateCopy (AActor *other) { // Find every unique type of ammo. Give it to the player if // he doesn't have it already, and double its maximum capacity. - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - const PClass *type = PClass::m_Types[i]; + PClass *type = PClassActor::AllActorClasses[i]; if (type->ParentClass == RUNTIME_CLASS(AAmmo)) { - AAmmo *ammo = static_cast(other->FindInventory (type)); + PClassActor *atype = static_cast(type); + AAmmo *ammo = static_cast(other->FindInventory(atype)); int amount = static_cast(GetDefaultByType(type))->BackpackAmount; // extra ammo in baby mode and nightmare mode if (!(ItemFlags&IF_IGNORESKILL)) @@ -1768,7 +1844,7 @@ AInventory *ABackpackItem::CreateCopy (AActor *other) if (amount < 0) amount = 0; if (ammo == NULL) { // The player did not have the ammo. Add it. - ammo = static_cast(Spawn (type, 0, 0, 0, NO_REPLACE)); + ammo = static_cast(Spawn(atype, 0, 0, 0, NO_REPLACE)); ammo->Amount = bDepleted ? 0 : amount; if (ammo->BackpackMaxAmount > ammo->MaxAmount) { diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index 413b01db3d..ef693394a0 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -10,6 +10,8 @@ class player_t; class FConfigFile; class AWeapon; +class PClassWeapon; +class PClassPlayerPawn; struct visstyle_t; class FWeaponSlot @@ -20,13 +22,13 @@ public: FWeaponSlot &operator= (const FWeaponSlot &other) { Weapons = other.Weapons; return *this; } void Clear() { Weapons.Clear(); } bool AddWeapon (const char *type); - bool AddWeapon (const PClass *type); + bool AddWeapon (PClassWeapon *type); void AddWeaponList (const char *list, bool clear); AWeapon *PickWeapon (player_t *player, bool checkammo = false); int Size () const { return (int)Weapons.Size(); } - int LocateWeapon (const PClass *type); + int LocateWeapon (PClassWeapon *type); - inline const PClass *GetWeapon (int index) const + inline PClassWeapon *GetWeapon (int index) const { if ((unsigned)index < Weapons.Size()) { @@ -43,7 +45,7 @@ public: private: struct WeaponInfo { - const PClass *Type; + PClassWeapon *Type; fixed_t Position; }; void SetInitialPositions(); @@ -69,25 +71,25 @@ struct FWeaponSlots AWeapon *PickPrevWeapon (player_t *player); void Clear (); - bool LocateWeapon (const PClass *type, int *const slot, int *const index); - ESlotDef AddDefaultWeapon (int slot, const PClass *type); + bool LocateWeapon (PClassWeapon *type, int *const slot, int *const index); + ESlotDef AddDefaultWeapon (int slot, PClassWeapon *type); void AddExtraWeapons(); void SetFromGameInfo(); - void SetFromPlayer(const PClass *type); - void StandardSetup(const PClass *type); - void LocalSetup(const PClass *type); + void SetFromPlayer(PClassPlayerPawn *type); + void StandardSetup(PClassPlayerPawn *type); + void LocalSetup(PClassActor *type); void SendDifferences(int playernum, const FWeaponSlots &other); int RestoreSlots (FConfigFile *config, const char *section); void PrintSettings(); - void AddSlot(int slot, const PClass *type, bool feedback); - void AddSlotDefault(int slot, const PClass *type, bool feedback); + void AddSlot(int slot, PClassWeapon *type, bool feedback); + void AddSlotDefault(int slot, PClassWeapon *type, bool feedback); }; void P_PlaybackKeyConfWeapons(FWeaponSlots *slots); -void Net_WriteWeapon(const PClass *type); -const PClass *Net_ReadWeapon(BYTE **stream); +void Net_WriteWeapon(PClassWeapon *type); +PClassWeapon *Net_ReadWeapon(BYTE **stream); void P_SetupWeapons_ntohton(); void P_WriteDemoWeaponsChunk(BYTE **demo); @@ -99,17 +101,6 @@ void P_ReadDemoWeaponsChunk(BYTE **demo); // A pickup is anything the player can pickup (i.e. weapons, ammo, powerups, etc) -enum -{ - AIMETA_BASE = 0x71000, - AIMETA_PickupMessage, // string - AIMETA_GiveQuest, // optionally give one of the quest items. - AIMETA_DropAmount, // specifies the amount for a dropped ammo item - AIMETA_LowHealth, - AIMETA_LowHealthMessage, - AIMETA_PuzzFailMessage, -}; - enum { IF_ACTIVATABLE = 1<<0, // can be activated @@ -141,9 +132,22 @@ enum }; +class PClassInventory : public PClassActor +{ + DECLARE_CLASS(PClassInventory, PClassActor) +protected: + virtual void Derive(PClass *newclass); +public: + PClassInventory(); + + FString PickupMessage; + int GiveQuest; // Optionally give one of the quest items. + FTextureID AltHUDIcon; +}; + class AInventory : public AActor { - DECLARE_CLASS (AInventory, AActor) + DECLARE_CLASS_WITH_META(AInventory, AActor, PClassInventory) HAS_OBJECT_POINTERS public: virtual void Touch (AActor *toucher); @@ -182,7 +186,7 @@ public: const PClass *SpawnPointClass; // For respawning like Heretic's mace DWORD ItemFlags; - const PClass *PickupFlash; // actor to spawn as pickup flash + PClassActor *PickupFlash; // actor to spawn as pickup flash FSoundIDNoInit PickupSound; @@ -233,43 +237,59 @@ public: }; // Ammo: Something a weapon needs to operate +class PClassAmmo : public PClassInventory +{ + DECLARE_CLASS(PClassAmmo, PClassInventory) +protected: + virtual void Derive(PClass *newclass); +public: + PClassAmmo(); + + int DropAmount; // Specifies the amount for a dropped ammo item. +}; + class AAmmo : public AInventory { - DECLARE_CLASS (AAmmo, AInventory) + DECLARE_CLASS_WITH_META(AAmmo, AInventory, PClassAmmo) public: void Serialize (FArchive &arc); AInventory *CreateCopy (AActor *other); bool HandlePickup (AInventory *item); - const PClass *GetParentAmmo () const; + PClassActor *GetParentAmmo () const; AInventory *CreateTossable (); int BackpackAmount, BackpackMaxAmount; }; // A weapon is just that. -enum +class PClassWeapon : public PClassInventory { - AWMETA_BASE = 0x72000, - AWMETA_SlotNumber, - AWMETA_SlotPriority, + DECLARE_CLASS(PClassWeapon, PClassInventory); +protected: + virtual void Derive(PClass *newclass); +public: + PClassWeapon(); + + int SlotNumber; + fixed_t SlotPriority; }; class AWeapon : public AInventory { - DECLARE_CLASS (AWeapon, AInventory) + DECLARE_CLASS_WITH_META(AWeapon, AInventory, PClassWeapon) HAS_OBJECT_POINTERS public: DWORD WeaponFlags; - const PClass *AmmoType1, *AmmoType2; // Types of ammo used by this weapon + PClassAmmo *AmmoType1, *AmmoType2; // Types of ammo used by this weapon int AmmoGive1, AmmoGive2; // Amount of each ammo to get when picking up weapon int MinAmmo1, MinAmmo2; // Minimum ammo needed to switch to this weapon int AmmoUse1, AmmoUse2; // How much ammo to use with each shot int Kickback; fixed_t YAdjust; // For viewing the weapon fullscreen FSoundIDNoInit UpSound, ReadySound; // Sounds when coming up and idle - const PClass *SisterWeaponType; // Another weapon to pick up with this one - const PClass *ProjectileType; // Projectile used by primary attack - const PClass *AltProjectileType; // Projectile used by alternate attack + PClassWeapon *SisterWeaponType; // Another weapon to pick up with this one + PClassActor *ProjectileType; // Projectile used by primary attack + PClassActor *AltProjectileType; // Projectile used by alternate attack int SelectionOrder; // Lower-numbered weapons get picked first int MinSelAmmo1, MinSelAmmo2; // Ignore in BestWeapon() if inadequate ammo fixed_t MoveCombatDist; // Used by bots, but do they *really* need it? @@ -330,9 +350,9 @@ public: }; protected: - AAmmo *AddAmmo (AActor *other, const PClass *ammotype, int amount); + AAmmo *AddAmmo (AActor *other, PClassActor *ammotype, int amount); bool AddExistingAmmo (AAmmo *ammo, int amount); - AWeapon *AddWeapon (const PClass *weapon); + AWeapon *AddWeapon (PClassWeapon *weapon); }; enum @@ -377,9 +397,21 @@ public: // Health is some item that gives the player health when picked up. +class PClassHealth : public PClassInventory +{ + DECLARE_CLASS(PClassHealth, PClassInventory) +protected: + virtual void Derive(PClass *newclass); +public: + PClassHealth(); + + FString LowHealthMessage; + int LowHealth; +}; + class AHealth : public AInventory { - DECLARE_CLASS (AHealth, AInventory) + DECLARE_CLASS_WITH_META(AHealth, AInventory, PClassHealth) int PrevHealth; public: @@ -482,9 +514,18 @@ protected: }; // PuzzleItems work in conjunction with the UsePuzzleItem special +class PClassPuzzleItem : public PClassInventory +{ + DECLARE_CLASS(PClassPuzzleItem, PClassInventory); +protected: + virtual void Derive(PClass *newclass); +public: + FString PuzzFailMessage; +}; + class APuzzleItem : public AInventory { - DECLARE_CLASS (APuzzleItem, AInventory) + DECLARE_CLASS_WITH_META(APuzzleItem, AInventory, PClassPuzzleItem) public: void Serialize (FArchive &arc); bool ShouldStay (); diff --git a/src/g_shared/a_puzzleitems.cpp b/src/g_shared/a_puzzleitems.cpp index 4bd73ce6a5..0d60ab829f 100644 --- a/src/g_shared/a_puzzleitems.cpp +++ b/src/g_shared/a_puzzleitems.cpp @@ -9,7 +9,16 @@ #include "v_font.h" #include "farchive.h" -IMPLEMENT_CLASS (APuzzleItem) +IMPLEMENT_CLASS(PClassPuzzleItem) + +void PClassPuzzleItem::Derive(PClass *newclass) +{ + Super::Derive(newclass); + assert(newclass->IsKindOf(RUNTIME_CLASS(PClassPuzzleItem))); + static_cast(newclass)->PuzzFailMessage = PuzzFailMessage; +} + +IMPLEMENT_CLASS(APuzzleItem) void APuzzleItem::Serialize (FArchive &arc) { @@ -37,9 +46,9 @@ bool APuzzleItem::Use (bool pickup) S_Sound (Owner, CHAN_VOICE, "*puzzfail", 1, ATTN_IDLE); if (Owner != NULL && Owner->CheckLocalView (consoleplayer)) { - const char *message = GetClass()->Meta.GetMetaString (AIMETA_PuzzFailMessage); - if (message != NULL && *message=='$') message = GStrings[message + 1]; - if (message == NULL) message = GStrings("TXT_USEPUZZLEFAILED"); + FString message = GetClass()->PuzzFailMessage; + if (message.IsNotEmpty() && message[0] == '$') message = GStrings[&message[1]]; + if (message.IsEmpty()) message = GStrings("TXT_USEPUZZLEFAILED"); C_MidPrintBold (SmallFont, message); } return false; diff --git a/src/g_shared/a_randomspawner.cpp b/src/g_shared/a_randomspawner.cpp index 2ba445b7b7..acadbe6dab 100644 --- a/src/g_shared/a_randomspawner.cpp +++ b/src/g_shared/a_randomspawner.cpp @@ -20,7 +20,7 @@ #define MAX_RANDOMSPAWNERS_RECURSION 32 // Should be largely more than enough, honestly. static FRandom pr_randomspawn("RandomSpawn"); -static bool IsMonster(const FDropItem *di) +static bool IsMonster(DDropItem *di) { const PClass *pclass = PClass::FindClass(di->Name); @@ -41,9 +41,9 @@ class ARandomSpawner : public AActor // random spawner's velocity (0...) instead of their own. void BeginPlay() { - FDropItem *di; // di will be our drop item list iterator - FDropItem *drop; // while drop stays as the reference point. - int n=0; + DDropItem *di; // di will be our drop item list iterator + DDropItem *drop; // while drop stays as the reference point. + int n = 0; bool nomonsters = (dmflags & DF_NO_MONSTERS) || (level.flags2 & LEVEL2_NOMONSTERS); Super::BeginPlay(); @@ -56,8 +56,8 @@ class ARandomSpawner : public AActor { if (!nomonsters || !IsMonster(di)) { - if (di->amount < 0) di->amount = 1; // default value is -1, we need a positive value. - n += di->amount; // this is how we can weight the list. + if (di->Amount < 0) di->Amount = 1; // default value is -1, we need a positive value. + n += di->Amount; // this is how we can weight the list. } di = di->Next; } @@ -77,7 +77,7 @@ class ARandomSpawner : public AActor if (di->Name != NAME_None && (!nomonsters || !IsMonster(di))) { - n -= di->amount; + n -= di->Amount; if ((di->Next != NULL) && (n > -1)) di = di->Next; else @@ -95,14 +95,14 @@ class ARandomSpawner : public AActor Destroy(); return; } - else if (pr_randomspawn() <= di->probability) // prob 255 = always spawn, prob 0 = never spawn. + else if (pr_randomspawn() <= di->Probability) // prob 255 = always spawn, prob 0 = almost never spawn. { // Handle replacement here so as to get the proper speed and flags for missiles - const PClass *cls; - cls = PClass::FindClass(di->Name); + PClassActor *cls; + cls = PClass::FindActor(di->Name); if (cls != NULL) { - const PClass *rep = cls->GetReplacement(); + PClassActor *rep = cls->GetReplacement(); if (rep != NULL) { cls = rep; @@ -132,21 +132,29 @@ class ARandomSpawner : public AActor // necessary to them -- such as their source and destination. void PostBeginPlay() { - AActor * newmobj = NULL; - bool boss = false; Super::PostBeginPlay(); - if (Species == NAME_None) - { - Destroy(); - return; + + AActor *newmobj = NULL; + bool boss = false; + + if (Species == NAME_None) + { + Destroy(); + return; } - const PClass * cls = PClass::FindClass(Species); + PClassActor *cls = PClass::FindActor(Species); if (this->flags & MF_MISSILE && target && target->target) // Attempting to spawn a missile. { - if ((tracer == NULL) && (flags2 & MF2_SEEKERMISSILE)) tracer = target->target; + if ((tracer == NULL) && (flags2 & MF2_SEEKERMISSILE)) + { + tracer = target->target; + } newmobj = P_SpawnMissileXYZ(Pos(), target, target->target, cls, false); } - else newmobj = Spawn(cls, Pos(), NO_REPLACE); + else + { + newmobj = Spawn(cls, Pos(), NO_REPLACE); + } if (newmobj != NULL) { // copy everything relevant @@ -200,7 +208,7 @@ class ARandomSpawner : public AActor if ((newmobj->flags4 & MF4_BOSSDEATH) || (newmobj->flags2 & MF2_BOSS)) boss = true; // If a replaced actor has either of those same flags, it's also a boss. - AActor * rep = GetDefaultByType(GetClass()->ActorInfo->GetReplacee()->Class); + AActor *rep = GetDefaultByType(GetClass()->GetReplacee()); if (rep && ((rep->flags4 & MF4_BOSSDEATH) || (rep->flags2 & MF2_BOSS))) boss = true; } @@ -215,7 +223,7 @@ class ARandomSpawner : public AActor Super::Tick(); if (tracer == NULL || tracer->health <= 0) { - CALL_ACTION(A_BossDeath, this); + A_BossDeath(this); Destroy(); } } @@ -223,4 +231,3 @@ class ARandomSpawner : public AActor }; IMPLEMENT_CLASS (ARandomSpawner) - diff --git a/src/g_shared/a_sharedglobal.h b/src/g_shared/a_sharedglobal.h index 8a1c313076..acb4faf0f7 100644 --- a/src/g_shared/a_sharedglobal.h +++ b/src/g_shared/a_sharedglobal.h @@ -215,7 +215,7 @@ public: TObjPtr UnmorphedMe; int UnmorphTime, MorphStyle; - const PClass *MorphExitFlash; + PClassActor *MorphExitFlash; ActorFlags FlagsSave; }; diff --git a/src/g_shared/a_specialspot.cpp b/src/g_shared/a_specialspot.cpp index 1d2747ceb7..2a97949f3a 100644 --- a/src/g_shared/a_specialspot.cpp +++ b/src/g_shared/a_specialspot.cpp @@ -270,7 +270,7 @@ FSpotList *DSpotState::FindSpotList(const PClass *type) bool DSpotState::AddSpot(ASpecialSpot *spot) { - FSpotList *list = FindSpotList(RUNTIME_TYPE(spot)); + FSpotList *list = FindSpotList(spot->GetClass()); if (list != NULL) return list->Add(spot); return false; } @@ -283,7 +283,7 @@ bool DSpotState::AddSpot(ASpecialSpot *spot) bool DSpotState::RemoveSpot(ASpecialSpot *spot) { - FSpotList *list = FindSpotList(RUNTIME_TYPE(spot)); + FSpotList *list = FindSpotList(spot->GetClass()); if (list != NULL) return list->Remove(spot); return false; } @@ -391,36 +391,36 @@ void ASpecialSpot::Destroy() DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnSingleItem) { + PARAM_ACTION_PROLOGUE; + PARAM_CLASS (cls, AActor); + PARAM_INT_OPT (fail_sp) { fail_sp = 0; } + PARAM_INT_OPT (fail_co) { fail_co = 0; } + PARAM_INT_OPT (fail_dm) { fail_dm = 0; } + AActor *spot = NULL; DSpotState *state = DSpotState::GetSpotState(); - if (state != NULL) spot = state->GetRandomSpot(RUNTIME_TYPE(self), true); - if (spot == NULL) return; - - ACTION_PARAM_START(4); - ACTION_PARAM_CLASS(cls, 0); - ACTION_PARAM_INT(fail_sp, 1); - ACTION_PARAM_INT(fail_co, 2); - ACTION_PARAM_INT(fail_dm, 3); + if (state != NULL) spot = state->GetRandomSpot(self->GetClass(), true); + if (spot == NULL) return 0; if (!multiplayer && pr_spawnmace() < fail_sp) { // Sometimes doesn't show up if not in deathmatch - return; + return 0; } if (multiplayer && !deathmatch && pr_spawnmace() < fail_co) { - return; + return 0; } if (deathmatch && pr_spawnmace() < fail_dm) { - return; + return 0; } if (cls == NULL) { - return; + return 0; } AActor *spawned = Spawn(cls, self->Pos(), ALLOW_REPLACE); @@ -436,8 +436,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnSingleItem) } if (spawned->IsKindOf(RUNTIME_CLASS(AInventory))) { - static_cast(spawned)->SpawnPointClass = RUNTIME_TYPE(self); + static_cast(spawned)->SpawnPointClass = self->GetClass(); } } + return 0; } diff --git a/src/g_shared/a_weaponpiece.h b/src/g_shared/a_weaponpiece.h index c07f56f24e..9f495a06e9 100644 --- a/src/g_shared/a_weaponpiece.h +++ b/src/g_shared/a_weaponpiece.h @@ -14,7 +14,7 @@ public: virtual void PlayPickupSound (AActor *toucher); int PieceValue; - const PClass * WeaponClass; + PClassWeapon *WeaponClass; TObjPtr FullWeapon; }; diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index 9c71ab0ea9..c972c7120b 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -31,11 +31,29 @@ FString WeaponSection; TArray KeyConfWeapons; FWeaponSlots *PlayingKeyConf; -TArray Weapons_ntoh; -TMap Weapons_hton; +TArray Weapons_ntoh; +TMap Weapons_hton; static int STACK_ARGS ntoh_cmp(const void *a, const void *b); +IMPLEMENT_CLASS(PClassWeapon) + +PClassWeapon::PClassWeapon() +{ + SlotNumber = -1; + SlotPriority = FIXED_MAX; +} + +void PClassWeapon::Derive(PClass *newclass) +{ + assert(newclass->IsKindOf(RUNTIME_CLASS(PClassWeapon))); + Super::Derive(newclass); + PClassWeapon *newc = static_cast(newclass); + + newc->SlotNumber = SlotNumber; + newc->SlotPriority = SlotPriority; +} + //=========================================================================== // // AWeapon :: Serialize @@ -334,7 +352,7 @@ void AWeapon::AttachToOwner (AActor *other) // //=========================================================================== -AAmmo *AWeapon::AddAmmo (AActor *other, const PClass *ammotype, int amount) +AAmmo *AWeapon::AddAmmo (AActor *other, PClassActor *ammotype, int amount) { AAmmo *ammo; @@ -407,7 +425,7 @@ bool AWeapon::AddExistingAmmo (AAmmo *ammo, int amount) // //=========================================================================== -AWeapon *AWeapon::AddWeapon (const PClass *weapontype) +AWeapon *AWeapon::AddWeapon (PClassWeapon *weapontype) { AWeapon *weap; @@ -708,13 +726,13 @@ void AWeaponGiver::Serialize(FArchive &arc) bool AWeaponGiver::TryPickup(AActor *&toucher) { - FDropItem *di = GetDropItems(); + DDropItem *di = GetDropItems(); AWeapon *weap; if (di != NULL) { - const PClass *ti = PClass::FindClass(di->Name); - if (ti->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + PClassWeapon *ti = dyn_cast(PClass::FindClass(di->Name)); + if (ti != NULL) { if (master == NULL) { @@ -764,10 +782,10 @@ bool AWeaponGiver::TryPickup(AActor *&toucher) bool FWeaponSlot::AddWeapon(const char *type) { - return AddWeapon (PClass::FindClass (type)); + return AddWeapon(static_cast(PClass::FindClass(type))); } -bool FWeaponSlot::AddWeapon(const PClass *type) +bool FWeaponSlot::AddWeapon(PClassWeapon *type) { unsigned int i; @@ -828,7 +846,7 @@ void FWeaponSlot :: AddWeaponList(const char *list, bool clear) // //=========================================================================== -int FWeaponSlot::LocateWeapon(const PClass *type) +int FWeaponSlot::LocateWeapon(PClassWeapon *type) { unsigned int i; @@ -954,7 +972,7 @@ void FWeaponSlot::Sort() for (i = 1; i < (int)Weapons.Size(); ++i) { fixed_t pos = Weapons[i].Position; - const PClass *type = Weapons[i].Type; + PClassWeapon *type = Weapons[i].Type; for (j = i - 1; j >= 0 && Weapons[j].Position > pos; --j) { Weapons[j + 1] = Weapons[j]; @@ -1003,7 +1021,7 @@ void FWeaponSlots::Clear() // //=========================================================================== -ESlotDef FWeaponSlots::AddDefaultWeapon (int slot, const PClass *type) +ESlotDef FWeaponSlots::AddDefaultWeapon (int slot, PClassWeapon *type) { int currSlot, index; @@ -1028,7 +1046,7 @@ ESlotDef FWeaponSlots::AddDefaultWeapon (int slot, const PClass *type) // //=========================================================================== -bool FWeaponSlots::LocateWeapon (const PClass *type, int *const slot, int *const index) +bool FWeaponSlots::LocateWeapon (PClassWeapon *type, int *const slot, int *const index) { int i, j; @@ -1126,7 +1144,7 @@ AWeapon *FWeaponSlots::PickNextWeapon(player_t *player) slot = 0; } } - const PClass *type = Slots[slot].GetWeapon(index); + PClassWeapon *type = Slots[slot].GetWeapon(index); AWeapon *weap = static_cast(player->mo->FindInventory(type)); if (weap != NULL && weap->CheckAmmo(AWeapon::EitherFire, false)) { @@ -1181,7 +1199,7 @@ AWeapon *FWeaponSlots::PickPrevWeapon (player_t *player) } index = Slots[slot].Size() - 1; } - const PClass *type = Slots[slot].GetWeapon(index); + PClassWeapon *type = Slots[slot].GetWeapon(index); AWeapon *weap = static_cast(player->mo->FindInventory(type)); if (weap != NULL && weap->CheckAmmo(AWeapon::EitherFire, false)) { @@ -1213,23 +1231,25 @@ void FWeaponSlots::AddExtraWeapons() } // Append extra weapons to the slots. - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - PClass *cls = PClass::m_Types[i]; + PClass *cls = PClassActor::AllActorClasses[i]; - if (cls->ActorInfo != NULL && - (cls->ActorInfo->GameFilter == GAME_Any || (cls->ActorInfo->GameFilter & gameinfo.gametype)) && - cls->ActorInfo->Replacement == NULL && // Replaced weapons don't get slotted. - cls->IsDescendantOf(RUNTIME_CLASS(AWeapon)) && - !(static_cast(GetDefaultByType(cls))->WeaponFlags & WIF_POWERED_UP) && - !LocateWeapon(cls, NULL, NULL) // Don't duplicate it if it's already present. + if (!cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + { + continue; + } + PClassWeapon *acls = static_cast(cls); + if ((acls->GameFilter == GAME_Any || (acls->GameFilter & gameinfo.gametype)) && + acls->Replacement == NULL && // Replaced weapons don't get slotted. + !(((AWeapon *)(acls->Defaults))->WeaponFlags & WIF_POWERED_UP) && + !LocateWeapon(acls, NULL, NULL) // Don't duplicate it if it's already present. ) { - int slot = cls->Meta.GetMetaInt(AWMETA_SlotNumber, -1); + int slot = acls->SlotNumber; if ((unsigned)slot < NUM_WEAPON_SLOTS) { - fixed_t position = cls->Meta.GetMetaFixed(AWMETA_SlotPriority, INT_MAX); - FWeaponSlot::WeaponInfo info = { cls, position }; + FWeaponSlot::WeaponInfo info = { acls, acls->SlotPriority }; Slots[slot].Weapons.Push(info); } } @@ -1266,7 +1286,7 @@ void FWeaponSlots::SetFromGameInfo() { for (unsigned j = 0; j < gameinfo.DefaultWeaponSlots[i].Size(); i++) { - const PClass *cls = PClass::FindClass(gameinfo.DefaultWeaponSlots[i][j]); + PClassWeapon *cls = dyn_cast(PClass::FindClass(gameinfo.DefaultWeaponSlots[i][j])); if (cls == NULL) { Printf("Unknown weapon class '%s' found in default weapon slot assignments\n", @@ -1291,7 +1311,7 @@ void FWeaponSlots::SetFromGameInfo() // //=========================================================================== -void FWeaponSlots::StandardSetup(const PClass *type) +void FWeaponSlots::StandardSetup(PClassPlayerPawn *type) { SetFromPlayer(type); AddExtraWeapons(); @@ -1311,7 +1331,7 @@ void FWeaponSlots::StandardSetup(const PClass *type) // //=========================================================================== -void FWeaponSlots::LocalSetup(const PClass *type) +void FWeaponSlots::LocalSetup(PClassActor *type) { P_PlaybackKeyConfWeapons(this); if (WeaponSection.IsNotEmpty()) @@ -1384,15 +1404,14 @@ void FWeaponSlots::SendDifferences(int playernum, const FWeaponSlots &other) // //=========================================================================== -void FWeaponSlots::SetFromPlayer(const PClass *type) +void FWeaponSlots::SetFromPlayer(PClassPlayerPawn *type) { Clear(); for (int i = 0; i < NUM_WEAPON_SLOTS; ++i) { - const char *str = type->Meta.GetMetaString(APMETA_Slot0 + i); - if (str != NULL) + if (!type->Slot[i].IsEmpty()) { - Slots[i].AddWeaponList(str, false); + Slots[i].AddWeaponList(type->Slot[i], false); } } } @@ -1503,7 +1522,7 @@ CCMD (setslot) Net_WriteByte(argv.argc()-2); for (int i = 2; i < argv.argc(); i++) { - Net_WriteWeapon(PClass::FindClass(argv[i])); + Net_WriteWeapon(dyn_cast(PClass::FindClass(argv[i]))); } } } @@ -1514,7 +1533,7 @@ CCMD (setslot) // //=========================================================================== -void FWeaponSlots::AddSlot(int slot, const PClass *type, bool feedback) +void FWeaponSlots::AddSlot(int slot, PClassWeapon *type, bool feedback) { if (type != NULL && !Slots[slot].AddWeapon(type) && feedback) { @@ -1532,19 +1551,26 @@ CCMD (addslot) return; } + PClassWeapon *type= dyn_cast(PClass::FindClass(argv[2])); + if (type == NULL) + { + Printf("%s is not a weapon\n", argv[2]); + return; + } + if (ParsingKeyConf) { KeyConfWeapons.Push(argv.args()); } else if (PlayingKeyConf != NULL) { - PlayingKeyConf->AddSlot(int(slot), PClass::FindClass(argv[2]), false); + PlayingKeyConf->AddSlot(int(slot), type, false); } else { Net_WriteByte(DEM_ADDSLOT); Net_WriteByte(slot); - Net_WriteWeapon(PClass::FindClass(argv[2])); + Net_WriteWeapon(type); } } @@ -1567,7 +1593,7 @@ CCMD (weaponsection) // CCMD addslotdefault // //=========================================================================== -void FWeaponSlots::AddSlotDefault(int slot, const PClass *type, bool feedback) +void FWeaponSlots::AddSlotDefault(int slot, PClassWeapon *type, bool feedback) { if (type != NULL && type->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { @@ -1592,7 +1618,7 @@ void FWeaponSlots::AddSlotDefault(int slot, const PClass *type, bool feedback) CCMD (addslotdefault) { - const PClass *type; + PClassWeapon *type; unsigned int slot; if (argv.argc() != 3 || (slot = atoi (argv[1])) >= NUM_WEAPON_SLOTS) @@ -1601,8 +1627,8 @@ CCMD (addslotdefault) return; } - type = PClass::FindClass (argv[2]); - if (type == NULL || !type->IsDescendantOf (RUNTIME_CLASS(AWeapon))) + type = dyn_cast(PClass::FindClass(argv[2])); + if (type == NULL) { Printf ("%s is not a weapon\n", argv[2]); return; @@ -1614,13 +1640,13 @@ CCMD (addslotdefault) } else if (PlayingKeyConf != NULL) { - PlayingKeyConf->AddSlotDefault(int(slot), PClass::FindClass(argv[2]), false); + PlayingKeyConf->AddSlotDefault(int(slot), type, false); } else { Net_WriteByte(DEM_ADDSLOTDEFAULT); Net_WriteByte(slot); - Net_WriteWeapon(PClass::FindClass(argv[2])); + Net_WriteWeapon(type); } } @@ -1657,20 +1683,20 @@ void P_PlaybackKeyConfWeapons(FWeaponSlots *slots) void P_SetupWeapons_ntohton() { unsigned int i; - const PClass *cls; + PClassWeapon *cls; Weapons_ntoh.Clear(); Weapons_hton.Clear(); cls = NULL; Weapons_ntoh.Push(cls); // Index 0 is always NULL. - for (i = 0; i < PClass::m_Types.Size(); ++i) + for (i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - PClass *cls = PClass::m_Types[i]; + PClassActor *cls = PClassActor::AllActorClasses[i]; - if (cls->ActorInfo != NULL && cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { - Weapons_ntoh.Push(cls); + Weapons_ntoh.Push(static_cast(cls)); } } qsort(&Weapons_ntoh[1], Weapons_ntoh.Size() - 1, sizeof(Weapons_ntoh[0]), ntoh_cmp); @@ -1696,10 +1722,10 @@ void P_SetupWeapons_ntohton() static int STACK_ARGS ntoh_cmp(const void *a, const void *b) { - const PClass *c1 = *(const PClass **)a; - const PClass *c2 = *(const PClass **)b; - int g1 = c1->ActorInfo->GameFilter == GAME_Any ? 1 : (c1->ActorInfo->GameFilter & gameinfo.gametype) ? 0 : 2; - int g2 = c2->ActorInfo->GameFilter == GAME_Any ? 1 : (c2->ActorInfo->GameFilter & gameinfo.gametype) ? 0 : 2; + PClassWeapon *c1 = *(PClassWeapon **)a; + PClassWeapon *c2 = *(PClassWeapon **)b; + int g1 = c1->GameFilter == GAME_Any ? 1 : (c1->GameFilter & gameinfo.gametype) ? 0 : 2; + int g2 = c2->GameFilter == GAME_Any ? 1 : (c2->GameFilter & gameinfo.gametype) ? 0 : 2; if (g1 != g2) { return g1 - g2; @@ -1737,7 +1763,7 @@ void P_WriteDemoWeaponsChunk(BYTE **demo) void P_ReadDemoWeaponsChunk(BYTE **demo) { int count, i; - const PClass *type; + PClassWeapon *type; const char *s; count = ReadWord(demo); @@ -1750,7 +1776,7 @@ void P_ReadDemoWeaponsChunk(BYTE **demo) for (i = 1; i < count; ++i) { s = ReadStringConst(demo); - type = PClass::FindClass(s); + type = dyn_cast(PClass::FindClass(s)); // If a demo was recorded with a weapon that is no longer present, // should we report it? Weapons_ntoh[i] = type; @@ -1767,7 +1793,7 @@ void P_ReadDemoWeaponsChunk(BYTE **demo) // //=========================================================================== -void Net_WriteWeapon(const PClass *type) +void Net_WriteWeapon(PClassWeapon *type) { int index, *index_p; @@ -1799,7 +1825,7 @@ void Net_WriteWeapon(const PClass *type) // //=========================================================================== -const PClass *Net_ReadWeapon(BYTE **stream) +PClassWeapon *Net_ReadWeapon(BYTE **stream) { int index; @@ -1823,23 +1849,24 @@ const PClass *Net_ReadWeapon(BYTE **stream) DEFINE_ACTION_FUNCTION_PARAMS(AWeapon, A_ZoomFactor) { - ACTION_PARAM_START(2); - ACTION_PARAM_FLOAT(zoom, 0); - ACTION_PARAM_INT(flags, 1); + PARAM_ACTION_PROLOGUE; + PARAM_FLOAT_OPT (zoom) { zoom = 1; } + PARAM_INT_OPT (flags) { flags = 0; } if (self->player != NULL && self->player->ReadyWeapon != NULL) { - zoom = 1 / clamp(zoom, 0.1f, 50.f); + zoom = 1 / clamp(zoom, 0.1, 50.0); if (flags & 1) { // Make the zoom instant. - self->player->FOV = self->player->DesiredFOV * zoom; + self->player->FOV = float(self->player->DesiredFOV * zoom); } if (flags & 2) { // Disable pitch/yaw scaling. zoom = -zoom; } - self->player->ReadyWeapon->FOVScale = zoom; + self->player->ReadyWeapon->FOVScale = float(zoom); } + return 0; } //=========================================================================== @@ -1850,11 +1877,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AWeapon, A_ZoomFactor) DEFINE_ACTION_FUNCTION_PARAMS(AWeapon, A_SetCrosshair) { - ACTION_PARAM_START(1); - ACTION_PARAM_INT(xhair, 0); + PARAM_ACTION_PROLOGUE; + PARAM_INT(xhair); if (self->player != NULL && self->player->ReadyWeapon != NULL) { self->player->ReadyWeapon->Crosshair = xhair; } + return 0; } diff --git a/src/g_shared/sbar_mugshot.cpp b/src/g_shared/sbar_mugshot.cpp index ea1c8528e2..10e87b1b85 100644 --- a/src/g_shared/sbar_mugshot.cpp +++ b/src/g_shared/sbar_mugshot.cpp @@ -502,7 +502,7 @@ FTexture *FMugShot::GetFace(player_t *player, const char *default_face, int accu } if (CurrentState != NULL) { - const char *skin_face = player->morphTics ? player->MorphedPlayerClass->Meta.GetMetaString(APMETA_Face) : skins[player->userinfo.GetSkin()].face; + const char *skin_face = player->morphTics ? player->MorphedPlayerClass->Face : skins[player->userinfo.GetSkin()].face; return CurrentState->GetCurrentFrameTexture(default_face, skin_face, level, angle); } return NULL; diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index f91d5841cb..ed2a8c29c8 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -150,7 +150,7 @@ class CommandDrawImage : public SBarInfoCommandFlowControl { type = INVENTORYICON; const PClass* item = PClass::FindClass(sc.String); - if(item == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(item)) //must be a kind of Inventory + if(item == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item)) //must be a kind of Inventory { sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); } @@ -412,20 +412,20 @@ class CommandDrawSwitchableImage : public CommandDrawImage return compare != value; } } - // Key species are used to allow altnerates for existing key slots. + // Key species are used to allow alternates for existing key slots. static FName LookupKeySpecies(int keynum) { - for(unsigned int i = 0;i < PClass::m_Types.Size();++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - const PClass *cls = PClass::m_Types[i]; - if(cls->IsDescendantOf(RUNTIME_CLASS(AKey))) + PClassActor *cls = PClassActor::AllActorClasses[i]; + if (cls->IsDescendantOf(RUNTIME_CLASS(AKey))) { AKey *key = (AKey *)GetDefaultByType(cls); - if(key->KeyNumber == keynum) + if (key->KeyNumber == keynum) return cls->TypeName; } } - return FName(); + return NAME_None; } public: @@ -471,7 +471,7 @@ class CommandDrawSwitchableImage : public CommandDrawImage { inventoryItem[0] = sc.String; const PClass* item = PClass::FindClass(sc.String); - if(item == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(item)) //must be a kind of Inventory + if(item == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item)) //must be a kind of Inventory { sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); } @@ -498,7 +498,7 @@ class CommandDrawSwitchableImage : public CommandDrawImage sc.MustGetToken(TK_Identifier); inventoryItem[1] = sc.String; const PClass* item = PClass::FindClass(sc.String); - if(item == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(item)) //must be a kind of Inventory + if(item == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item)) //must be a kind of Inventory { sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); } @@ -529,7 +529,7 @@ class CommandDrawSwitchableImage : public CommandDrawImage drawAlt = 1; //draw off state until we know we have something. for (int i = 0; i < statusBar->CPlayer->weapons.Slots[conditionalValue[0]].Size(); i++) { - const PClass *weap = statusBar->CPlayer->weapons.Slots[conditionalValue[0]].GetWeapon(i); + PClassActor *weap = statusBar->CPlayer->weapons.Slots[conditionalValue[0]].GetWeapon(i); if(weap == NULL) { continue; @@ -616,12 +616,12 @@ class CommandDrawSwitchableImage : public CommandDrawImage } else //check the inventory items and draw selected sprite { - AInventory* item = statusBar->CPlayer->mo->FindInventory(PClass::FindClass(inventoryItem[0])); + AInventory* item = statusBar->CPlayer->mo->FindInventory(PClass::FindActor(inventoryItem[0])); if(item == NULL || !EvaluateOperation(conditionalOperator[0], conditionalValue[0], item->Amount)) drawAlt = 1; if(conditionAnd) { - item = statusBar->CPlayer->mo->FindInventory(PClass::FindClass(inventoryItem[1])); + item = statusBar->CPlayer->mo->FindInventory(PClass::FindActor(inventoryItem[1])); bool secondCondition = item != NULL && EvaluateOperation(conditionalOperator[1], conditionalValue[1], item->Amount); if((item != NULL && secondCondition) && drawAlt == 0) //both { @@ -987,7 +987,7 @@ class CommandDrawString : public SBarInfoCommand SBarInfoCoordinate startX; SBarInfoCoordinate x; SBarInfoCoordinate y; - int cache; /// General purpose cache. + intptr_t cache; /// General purpose cache. StringValueType strValue; int valueArgument; FString str; @@ -996,11 +996,11 @@ class CommandDrawString : public SBarInfoCommand private: void SetStringToTag(AActor *actor) { - if(actor != NULL) + if (actor != NULL) { - if(actor->GetClass()->ClassIndex != cache) + if ((intptr_t)actor->GetClass() != cache) { - cache = actor->GetClass()->ClassIndex; + cache = (intptr_t)actor->GetClass(); str = actor->GetTag(); RealignString(); } @@ -1077,7 +1077,7 @@ class CommandDrawNumber : public CommandDrawString value = AMMO; if(!parenthesized || !sc.CheckToken(TK_StringConst)) sc.MustGetToken(TK_Identifier); - inventoryItem = PClass::FindClass(sc.String); + inventoryItem = PClass::FindActor(sc.String); if(inventoryItem == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo { sc.ScriptMessage("'%s' is not a type of ammo.", sc.String); @@ -1093,7 +1093,7 @@ class CommandDrawNumber : public CommandDrawString value = AMMOCAPACITY; if(!parenthesized || !sc.CheckToken(TK_StringConst)) sc.MustGetToken(TK_Identifier); - inventoryItem = PClass::FindClass(sc.String); + inventoryItem = PClass::FindActor(sc.String); if(inventoryItem == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo { sc.ScriptMessage("'%s' is not a type of ammo.", sc.String); @@ -1159,7 +1159,7 @@ class CommandDrawNumber : public CommandDrawString value = POWERUPTIME; if(!parenthesized || !sc.CheckToken(TK_StringConst)) sc.MustGetToken(TK_Identifier); - inventoryItem = PClass::FindClass(sc.String); + inventoryItem = PClass::FindActor(sc.String); if(inventoryItem == NULL || !RUNTIME_CLASS(APowerupGiver)->IsAncestorOf(inventoryItem)) { sc.ScriptMessage("'%s' is not a type of PowerupGiver.", sc.String); @@ -1171,7 +1171,7 @@ class CommandDrawNumber : public CommandDrawString } if(value == INVENTORY) { - inventoryItem = PClass::FindClass(sc.String); + inventoryItem = PClass::FindActor(sc.String); if(inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(inventoryItem)) //must be a kind of ammo { sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); @@ -1405,7 +1405,7 @@ class CommandDrawNumber : public CommandDrawString case POWERUPTIME: { //Get the PowerupType and check to see if the player has any in inventory. - const PClass* powerupType = ((APowerupGiver*) GetDefaultByType(inventoryItem))->PowerupType; + PClassActor* powerupType = ((APowerupGiver*) GetDefaultByType(inventoryItem))->PowerupType; APowerup* powerup = (APowerup*) statusBar->CPlayer->mo->FindInventory(powerupType); if(powerup != NULL) num = powerup->EffectTics / TICRATE + 1; @@ -1543,7 +1543,7 @@ class CommandDrawNumber : public CommandDrawString EColorRange highTranslation; EColorRange normalTranslation; ValueType value; - const PClass *inventoryItem; + PClassActor *inventoryItem; FString prefixPadding; @@ -2560,7 +2560,7 @@ class CommandDrawBar : public SBarInfoCommand if(!parenthesized || !sc.CheckToken(TK_StringConst)) sc.MustGetToken(TK_Identifier); type = AMMO; - data.inventoryItem = PClass::FindClass(sc.String); + data.inventoryItem = PClass::FindActor(sc.String); if(data.inventoryItem == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(data.inventoryItem)) //must be a kind of ammo { sc.ScriptMessage("'%s' is not a type of ammo.", sc.String); @@ -2587,8 +2587,8 @@ class CommandDrawBar : public SBarInfoCommand type = POWERUPTIME; if(!parenthesized || !sc.CheckToken(TK_StringConst)) - sc.MustGetToken(TK_Identifier); - data.inventoryItem = PClass::FindClass(sc.String); + sc.MustGetToken(TK_Identifier); + data.inventoryItem = PClass::FindActor(sc.String); if(data.inventoryItem == NULL || !RUNTIME_CLASS(APowerupGiver)->IsAncestorOf(data.inventoryItem)) { sc.ScriptMessage("'%s' is not a type of PowerupGiver.", sc.String); @@ -2600,7 +2600,7 @@ class CommandDrawBar : public SBarInfoCommand else { type = INVENTORY; - data.inventoryItem = PClass::FindClass(sc.String); + data.inventoryItem = PClass::FindActor(sc.String); if(data.inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(data.inventoryItem)) { sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); @@ -2758,7 +2758,7 @@ class CommandDrawBar : public SBarInfoCommand { //Get the PowerupType and check to see if the player has any in inventory. APowerupGiver *powerupGiver = (APowerupGiver*) GetDefaultByType(data.inventoryItem); - const PClass *powerupType = powerupGiver->PowerupType; + PClassActor *powerupType = powerupGiver->PowerupType; APowerup *powerup = (APowerup*) statusBar->CPlayer->mo->FindInventory(powerupType); if(powerup != NULL && powerupType != NULL && powerupGiver != NULL) { @@ -2822,7 +2822,7 @@ class CommandDrawBar : public SBarInfoCommand if(sc.CheckToken(TK_Identifier) || (extendedSyntax && sc.CheckToken(TK_StringConst))) //comparing reference { - data.inventoryItem = PClass::FindClass(sc.String); + data.inventoryItem = PClass::FindActor(sc.String); if(data.inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(data.inventoryItem)) //must be a kind of inventory { sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); @@ -2868,7 +2868,7 @@ class CommandDrawBar : public SBarInfoCommand bool useMaximumConstant; union { - const PClass *inventoryItem; + PClassActor *inventoryItem; int value; }; }; @@ -2968,10 +2968,10 @@ class CommandPlayerClass : public SBarInfoCommandFlowControl bool foundClass = false; for(unsigned int c = 0;c < PlayerClasses.Size();c++) { - if(stricmp(sc.String, PlayerClasses[c].Type->Meta.GetMetaString(APMETA_DisplayName)) == 0) + if(stricmp(sc.String, PlayerClasses[c].Type->DisplayName) == 0) { foundClass = true; - classes.Push(PlayerClasses[c].Type->ClassIndex); + classes.Push(PlayerClasses[c].Type); break; } } @@ -2992,7 +2992,7 @@ class CommandPlayerClass : public SBarInfoCommandFlowControl if(statusBar->CPlayer->cls == NULL) return; //No class so we can not continue - int spawnClass = statusBar->CPlayer->cls->ClassIndex; + PClass *spawnClass = statusBar->CPlayer->cls; for(unsigned int i = 0;i < classes.Size();i++) { if(classes[i] == spawnClass) @@ -3004,7 +3004,7 @@ class CommandPlayerClass : public SBarInfoCommandFlowControl SetTruth(false, block, statusBar); } protected: - TArray classes; + TArray classes; }; //////////////////////////////////////////////////////////////////////////////// @@ -3374,7 +3374,7 @@ class CommandInInventory : public SBarInfoCommandFlowControl } for(int i = 0;i < 2;i++) { - item[i] = PClass::FindClass(sc.String); + item[i] = PClass::FindActor(sc.String); if(item[i] == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item[i])) { sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); @@ -3425,7 +3425,7 @@ class CommandInInventory : public SBarInfoCommandFlowControl protected: bool conditionAnd; bool negate; - const PClass *item[2]; + PClassActor *item[2]; int amount[2]; }; diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 344f5b0ec7..349c1e9c5e 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -117,16 +117,14 @@ static int statspace; void AM_GetPosition(fixed_t & x, fixed_t & y); -FTextureID GetHUDIcon(const PClass *cls) +FTextureID GetHUDIcon(PClassInventory *cls) { - FTextureID tex; - tex.texnum = cls->Meta.GetMetaInt(HUMETA_AltIcon, 0); - return tex; + return cls->AltHUDIcon; } -void SetHUDIcon(PClass *cls, FTextureID tex) +void SetHUDIcon(PClassInventory *cls, FTextureID tex) { - cls->Meta.SetMetaInt(HUMETA_AltIcon, tex.GetIndex()); + cls->AltHUDIcon = tex; } //--------------------------------------------------------------------------- @@ -378,32 +376,33 @@ static void DrawArmor(ABasicArmor * barmor, AHexenArmor * harmor, int x, int y) // this doesn't have to be done each frame // //--------------------------------------------------------------------------- -static TArray KeyTypes, UnassignedKeyTypes; +static TArray KeyTypes, UnassignedKeyTypes; static int STACK_ARGS ktcmp(const void * a, const void * b) { - AKey * key1 = (AKey*)GetDefaultByType ( *(const PClass**)a ); - AKey * key2 = (AKey*)GetDefaultByType ( *(const PClass**)b ); + AKey *key1 = (AKey*)GetDefaultByType ( *(PClassActor **)a ); + AKey *key2 = (AKey*)GetDefaultByType ( *(PClassActor **)b ); return key1->KeyNumber - key2->KeyNumber; } static void SetKeyTypes() { - for(unsigned int i=0;iIsDescendantOf(RUNTIME_CLASS(AKey))) { - AKey * key = (AKey*)GetDefaultByType(ti); + PClassActor *tia = static_cast(ti); + AKey *key = (AKey*)GetDefaultByType(tia); if (key->Icon.isValid() && key->KeyNumber>0) { - KeyTypes.Push(ti); + KeyTypes.Push(tia); } else { - UnassignedKeyTypes.Push(ti); + UnassignedKeyTypes.Push(tia); } } } @@ -414,7 +413,7 @@ static void SetKeyTypes() else { // Don't leave the list empty - const PClass * ti = RUNTIME_CLASS(AKey); + PClassActor *ti = RUNTIME_CLASS(AKey); KeyTypes.Push(ti); } } @@ -479,30 +478,30 @@ static int DrawKeys(player_t * CPlayer, int x, int y) int xo=x; int i; int c=0; - AInventory * inv; + AInventory *inv; if (!deathmatch) { - if (KeyTypes.Size()==0) SetKeyTypes(); + if (KeyTypes.Size() == 0) SetKeyTypes(); // First all keys that are assigned to locks (in reverse order of definition) - for(i=KeyTypes.Size()-1;i>=0;i--) + for (i = KeyTypes.Size()-1; i >= 0; i--) { - if ((inv=CPlayer->mo->FindInventory(KeyTypes[i]))) + if ((inv = CPlayer->mo->FindInventory(KeyTypes[i]))) { DrawOneKey(xo, x, y, c, inv); } } // And now the rest - for(i=UnassignedKeyTypes.Size()-1;i>=0;i--) + for (i = UnassignedKeyTypes.Size()-1; i >= 0; i--) { - if ((inv=CPlayer->mo->FindInventory(UnassignedKeyTypes[i]))) + if ((inv = CPlayer->mo->FindInventory(UnassignedKeyTypes[i]))) { DrawOneKey(xo, x, y, c, inv); } } } - if (x==xo && y!=yo) y+=11; + if (x == xo && y != yo) y+=11; return y-11; } @@ -512,14 +511,14 @@ static int DrawKeys(player_t * CPlayer, int x, int y) // Drawing Ammo // //--------------------------------------------------------------------------- -static TArray orderedammos; +static TArray orderedammos; static void AddAmmoToList(AWeapon * weapdef) { for(int i=0; i<2;i++) { - const PClass * ti = i==0? weapdef->AmmoType1 : weapdef->AmmoType2; + PClassAmmo * ti = i==0? weapdef->AmmoType1 : weapdef->AmmoType2; if (ti) { AAmmo * ammodef=(AAmmo*)GetDefaultByType(ti); @@ -559,7 +558,7 @@ static int DrawAmmo(player_t *CPlayer, int x, int y) // Order ammo by use of weapons in the weapon slots for (k = 0; k < NUM_WEAPON_SLOTS; k++) for(j = 0; j < CPlayer->weapons.Slots[k].Size(); j++) { - const PClass *weap = CPlayer->weapons.Slots[k].GetWeapon(j); + PClassActor *weap = CPlayer->weapons.Slots[k].GetWeapon(j); if (weap) { @@ -592,7 +591,7 @@ static int DrawAmmo(player_t *CPlayer, int x, int y) for(i=orderedammos.Size()-1;i>=0;i--) { - const PClass * type = orderedammos[i]; + PClassAmmo * type = orderedammos[i]; AAmmo * ammoitem = (AAmmo*)CPlayer->mo->FindInventory(type); AAmmo * inv = ammoitem? ammoitem : (AAmmo*)GetDefaultByType(orderedammos[i]); @@ -681,7 +680,7 @@ static void DrawOneWeapon(player_t * CPlayer, int x, int & y, AWeapon * weapon) // Powered up weapons and inherited sister weapons are not displayed. if (weapon->WeaponFlags & WIF_POWERED_UP) return; - if (weapon->SisterWeapon && weapon->IsKindOf(RUNTIME_TYPE(weapon->SisterWeapon))) return; + if (weapon->SisterWeapon && weapon->IsKindOf(weapon->SisterWeapon->GetClass())) return; trans=0x6666; if (CPlayer->ReadyWeapon) @@ -705,16 +704,16 @@ static void DrawOneWeapon(player_t * CPlayer, int x, int & y, AWeapon * weapon) } -static void DrawWeapons(player_t * CPlayer, int x, int y) +static void DrawWeapons(player_t *CPlayer, int x, int y) { int k,j; - AInventory * inv; + AInventory *inv; // First draw all weapons in the inventory that are not assigned to a weapon slot - for(inv=CPlayer->mo->Inventory;inv;inv=inv->Inventory) + for(inv = CPlayer->mo->Inventory; inv; inv = inv->Inventory) { if (inv->IsKindOf(RUNTIME_CLASS(AWeapon)) && - !CPlayer->weapons.LocateWeapon(RUNTIME_TYPE(inv), NULL, NULL)) + !CPlayer->weapons.LocateWeapon(static_cast(inv)->GetClass(), NULL, NULL)) { DrawOneWeapon(CPlayer, x, y, static_cast(inv)); } @@ -723,7 +722,7 @@ static void DrawWeapons(player_t * CPlayer, int x, int y) // And now everything in the weapon slots back to front for (k = NUM_WEAPON_SLOTS - 1; k >= 0; k--) for(j = CPlayer->weapons.Slots[k].Size() - 1; j >= 0; j--) { - const PClass *weap = CPlayer->weapons.Slots[k].GetWeapon(j); + PClassActor *weap = CPlayer->weapons.Slots[k].GetWeapon(j); if (weap) { inv=CPlayer->mo->FindInventory(weap); @@ -1180,7 +1179,7 @@ void HUD_InitHud() } else { - const PClass * ti = PClass::FindClass(sc.String); + PClass *ti = PClass::FindClass(sc.String); if (!ti) { Printf("Unknown item class '%s' in ALTHUDCF\n", sc.String); @@ -1199,9 +1198,8 @@ void HUD_InitHud() } else tex.SetInvalid(); - if (ti) SetHUDIcon(const_cast(ti), tex); + if (ti) SetHUDIcon(static_cast(ti), tex); } } } } - diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index 0c74f52b72..ebe4879ac4 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -253,7 +253,7 @@ DBaseStatusBar::DBaseStatusBar (int reltop, int hres, int vres) void DBaseStatusBar::Destroy () { - for (unsigned int i = 0; i < countof(Messages); ++i) + for (size_t i = 0; i < countof(Messages); ++i) { DHUDMessage *msg = Messages[i]; while (msg) @@ -355,7 +355,7 @@ void DBaseStatusBar::MultiplayerChanged () void DBaseStatusBar::Tick () { - for (unsigned int i = 0; i < countof(Messages); ++i) + for (size_t i = 0; i < countof(Messages); ++i) { DHUDMessage *msg = Messages[i]; DHUDMessage **prev = &Messages[i]; @@ -437,7 +437,7 @@ void DBaseStatusBar::AttachMessage (DHUDMessage *msg, DWORD id, int layer) DHUDMessage *DBaseStatusBar::DetachMessage (DHUDMessage *msg) { - for (unsigned int i = 0; i < countof(Messages); ++i) + for (size_t i = 0; i < countof(Messages); ++i) { DHUDMessage *probe = Messages[i]; DHUDMessage **prev = &Messages[i]; @@ -464,7 +464,7 @@ DHUDMessage *DBaseStatusBar::DetachMessage (DHUDMessage *msg) DHUDMessage *DBaseStatusBar::DetachMessage (DWORD id) { - for (unsigned int i = 0; i < countof(Messages); ++i) + for (size_t i = 0; i < countof(Messages); ++i) { DHUDMessage *probe = Messages[i]; DHUDMessage **prev = &Messages[i]; @@ -497,7 +497,7 @@ DHUDMessage *DBaseStatusBar::DetachMessage (DWORD id) void DBaseStatusBar::DetachAllMessages () { - for (unsigned int i = 0; i < countof(Messages); ++i) + for (size_t i = 0; i < countof(Messages); ++i) { DHUDMessage *probe = Messages[i]; @@ -1681,7 +1681,7 @@ void DBaseStatusBar::Serialize (FArchive &arc) } else { - for (unsigned int i = 0; i < countof(Messages); ++i) + for (size_t i = 0; i < countof(Messages); ++i) { arc << Messages[i]; } @@ -1693,7 +1693,7 @@ void DBaseStatusBar::ScreenSizeChanged () st_scale.Callback (); ST_SetNeedRefresh(); - for (unsigned int i = 0; i < countof(Messages); ++i) + for (size_t i = 0; i < countof(Messages); ++i) { DHUDMessage *message = Messages[i]; while (message != NULL) diff --git a/src/g_skill.cpp b/src/g_skill.cpp index f4cb63ea51..c589f44d4d 100644 --- a/src/g_skill.cpp +++ b/src/g_skill.cpp @@ -427,7 +427,7 @@ const char * G_SkillName() const char *name = AllSkills[gameskill].MenuName; player_t *player = &players[consoleplayer]; - const char *playerclass = player->mo->GetClass()->Meta.GetMetaString(APMETA_DisplayName); + const char *playerclass = player->mo->GetClass()->DisplayName; if (playerclass != NULL) { diff --git a/src/g_strife/a_acolyte.cpp b/src/g_strife/a_acolyte.cpp index 6785de1acd..9b84b92bb4 100644 --- a/src/g_strife/a_acolyte.cpp +++ b/src/g_strife/a_acolyte.cpp @@ -27,11 +27,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_HideDecepticon) { + PARAM_ACTION_PROLOGUE; + EV_DoDoor (DDoor::doorClose, NULL, self, 999, 8*FRACUNIT, 0, 0, 0); if (self->target != NULL && self->target->player != NULL) { P_NoiseAlert (self->target, self); } + return 0; } //============================================================================ @@ -42,6 +45,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_HideDecepticon) DEFINE_ACTION_FUNCTION(AActor, A_AcolyteDie) { + PARAM_ACTION_PROLOGUE; + int i; // [RH] Disable translucency here. @@ -49,7 +54,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_AcolyteDie) // Only the Blue Acolyte does extra stuff on death. if (self->GetClass()->TypeName != NAME_AcolyteBlue) - return; + return 0; // Make sure somebody is still alive for (i = 0; i < MAXPLAYERS; ++i) @@ -58,7 +63,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_AcolyteDie) break; } if (i == MAXPLAYERS) - return; + return 0; // Make sure all the other blue acolytes are dead. TThinkerIterator iterator(NAME_AcolyteBlue); @@ -68,7 +73,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_AcolyteDie) { if (other != self && other->health > 0) { // Found a living one - return; + return 0; } } @@ -76,6 +81,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_AcolyteDie) players[i].SetLogNumber (14); S_StopSound (CHAN_VOICE); S_Sound (CHAN_VOICE, "svox/voc14", 1, ATTN_NORM); + return 0; } //============================================================================ @@ -86,9 +92,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_AcolyteDie) DEFINE_ACTION_FUNCTION(AActor, A_BeShadowyFoe) { + PARAM_ACTION_PROLOGUE; + self->RenderStyle = STYLE_Translucent; self->alpha = HR_SHADOW; self->flags &= ~MF_FRIENDLY; + return 0; } //============================================================================ @@ -99,6 +108,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeShadowyFoe) DEFINE_ACTION_FUNCTION(AActor, A_AcolyteBits) { + PARAM_ACTION_PROLOGUE; + if (self->SpawnFlags & MTF_SHADOW) { CALL_ACTION(A_BeShadowyFoe, self); @@ -115,4 +126,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_AcolyteBits) self->RenderStyle.BlendOp = STYLEOP_None; } } + return 0; } diff --git a/src/g_strife/a_alienspectres.cpp b/src/g_strife/a_alienspectres.cpp index c6339f33de..6f590f801d 100644 --- a/src/g_strife/a_alienspectres.cpp +++ b/src/g_strife/a_alienspectres.cpp @@ -16,12 +16,12 @@ static FRandom pr_spectrespawn ("AlienSpectreSpawn"); static FRandom pr_spectrechunk ("212e4"); -AActor *P_SpawnSubMissile (AActor *source, const PClass *type, AActor *target); - //============================================================================ DEFINE_ACTION_FUNCTION(AActor, A_SpectreChunkSmall) { + PARAM_ACTION_PROLOGUE; + AActor *foo = Spawn("AlienChunkSmall", self->PosPlusZ(10*FRACUNIT), ALLOW_REPLACE); if (foo != NULL) @@ -36,10 +36,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpectreChunkSmall) foo->velz = (pr_spectrechunk() & 15) << FRACBITS; } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_SpectreChunkLarge) { + PARAM_ACTION_PROLOGUE; + AActor *foo = Spawn("AlienChunkLarge", self->PosPlusZ(10*FRACUNIT), ALLOW_REPLACE); if (foo != NULL) @@ -54,13 +57,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpectreChunkLarge) foo->velz = (pr_spectrechunk() & 7) << FRACBITS; } - + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_Spectre3Attack) { + PARAM_ACTION_PROLOGUE; + if (self->target == NULL) - return; + return 0; AActor *foo = Spawn("SpectralLightningV2", self->PosPlusZ(32*FRACUNIT), ALLOW_REPLACE); @@ -73,13 +78,16 @@ DEFINE_ACTION_FUNCTION(AActor, A_Spectre3Attack) for (int i = 0; i < 20; ++i) { self->angle += ANGLE_180 / 20; - P_SpawnSubMissile (self, PClass::FindClass("SpectralLightningBall2"), self); + P_SpawnSubMissile (self, PClass::FindActor("SpectralLightningBall2"), self); } self->angle -= ANGLE_180 / 20 * 10; + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_AlienSpectreDeath) { + PARAM_ACTION_PROLOGUE; + AActor *player; char voc[32]; int log; @@ -88,7 +96,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_AlienSpectreDeath) A_Unblock(self, true); // [RH] Need this for Sigil rewarding if (!CheckBossDeath (self)) { - return; + return 0; } for (i = 0, player = NULL; i < MAXPLAYERS; ++i) { @@ -100,7 +108,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_AlienSpectreDeath) } if (player == NULL) { - return; + return 0; } switch (self->GetClass()->TypeName) @@ -184,9 +192,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_AlienSpectreDeath) break; default: - return; + return 0; } mysnprintf (voc, countof(voc), "svox/voc%d", log); S_Sound (CHAN_VOICE, voc, 1, ATTN_NORM); player->player->SetLogNumber (log); + return 0; } diff --git a/src/g_strife/a_crusader.cpp b/src/g_strife/a_crusader.cpp index 8655e10bc6..4cd0383a03 100644 --- a/src/g_strife/a_crusader.cpp +++ b/src/g_strife/a_crusader.cpp @@ -20,66 +20,81 @@ static bool CrusaderCheckRange (AActor *self) DEFINE_ACTION_FUNCTION(AActor, A_CrusaderChoose) { + PARAM_ACTION_PROLOGUE; + if (self->target == NULL) - return; + return 0; if (CrusaderCheckRange (self)) { A_FaceTarget (self); self->angle -= ANGLE_180/16; - P_SpawnMissileZAimed (self, self->Z() + 40*FRACUNIT, self->target, PClass::FindClass("FastFlameMissile")); + P_SpawnMissileZAimed (self, self->Z() + 40*FRACUNIT, self->target, PClass::FindActor("FastFlameMissile")); } else { if (P_CheckMissileRange (self)) { A_FaceTarget (self); - P_SpawnMissileZAimed (self, self->Z() + 56*FRACUNIT, self->target, PClass::FindClass("CrusaderMissile")); + P_SpawnMissileZAimed (self, self->Z() + 56*FRACUNIT, self->target, PClass::FindActor("CrusaderMissile")); self->angle -= ANGLE_45/32; - P_SpawnMissileZAimed (self, self->Z() + 40*FRACUNIT, self->target, PClass::FindClass("CrusaderMissile")); + P_SpawnMissileZAimed (self, self->Z() + 40*FRACUNIT, self->target, PClass::FindActor("CrusaderMissile")); self->angle += ANGLE_45/16; - P_SpawnMissileZAimed (self, self->Z() + 40*FRACUNIT, self->target, PClass::FindClass("CrusaderMissile")); + P_SpawnMissileZAimed (self, self->Z() + 40*FRACUNIT, self->target, PClass::FindActor("CrusaderMissile")); self->angle -= ANGLE_45/16; self->reactiontime += 15; } self->SetState (self->SeeState); } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_CrusaderSweepLeft) { + PARAM_ACTION_PROLOGUE; + self->angle += ANGLE_90/16; - AActor *misl = P_SpawnMissileZAimed (self, self->Z() + 48*FRACUNIT, self->target, PClass::FindClass("FastFlameMissile")); + AActor *misl = P_SpawnMissileZAimed (self, self->Z() + 48*FRACUNIT, self->target, PClass::FindActor("FastFlameMissile")); if (misl != NULL) { misl->velz += FRACUNIT; } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_CrusaderSweepRight) { + PARAM_ACTION_PROLOGUE; + self->angle -= ANGLE_90/16; - AActor *misl = P_SpawnMissileZAimed (self, self->Z() + 48*FRACUNIT, self->target, PClass::FindClass("FastFlameMissile")); + AActor *misl = P_SpawnMissileZAimed (self, self->Z() + 48*FRACUNIT, self->target, PClass::FindActor("FastFlameMissile")); if (misl != NULL) { misl->velz += FRACUNIT; } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_CrusaderRefire) { + PARAM_ACTION_PROLOGUE; + if (self->target == NULL || self->target->health <= 0 || !P_CheckSight (self, self->target)) { self->SetState (self->SeeState); } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_CrusaderDeath) { + PARAM_ACTION_PROLOGUE; + if (CheckBossDeath (self)) { EV_DoFloor (DFloor::floorLowerToLowest, NULL, 667, FRACUNIT, 0, -1, 0, false); } + return 0; } diff --git a/src/g_strife/a_entityboss.cpp b/src/g_strife/a_entityboss.cpp index 04b586b67e..38824d9dc3 100644 --- a/src/g_strife/a_entityboss.cpp +++ b/src/g_strife/a_entityboss.cpp @@ -14,10 +14,13 @@ static FRandom pr_entity ("Entity"); DEFINE_ACTION_FUNCTION(AActor, A_SubEntityDeath) { + PARAM_ACTION_PROLOGUE; + if (CheckBossDeath (self)) { G_ExitLevel (0, false); } + return 0; } void A_SpectralMissile (AActor *self, const char *missilename) @@ -25,7 +28,7 @@ void A_SpectralMissile (AActor *self, const char *missilename) if (self->target != NULL) { AActor *missile = P_SpawnMissileXYZ (self->PosPlusZ(32*FRACUNIT), - self, self->target, PClass::FindClass(missilename), false); + self, self->target, PClass::FindActor(missilename), false); if (missile != NULL) { missile->tracer = self->target; @@ -40,6 +43,8 @@ DECLARE_ACTION(A_Spectre3Attack) DEFINE_ACTION_FUNCTION(AActor, A_EntityAttack) { + PARAM_ACTION_PROLOGUE; + // Apparent Strife bug: Case 5 was unreachable because they used % 5 instead of % 6. // I've fixed that by making case 1 duplicate it, since case 1 did nothing. switch (pr_entity() % 5) @@ -65,11 +70,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_EntityAttack) A_SpectralMissile (self, "SpectralLightningBigBall2"); break; } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_SpawnEntity) { + PARAM_ACTION_PROLOGUE; + AActor *entity = Spawn("EntityBoss", self->PosPlusZ(70*FRACUNIT), ALLOW_REPLACE); if (entity != NULL) { @@ -78,10 +86,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnEntity) entity->velz = 5*FRACUNIT; entity->tracer = self; } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_EntityDeath) { + PARAM_ACTION_PROLOGUE; + AActor *second; fixed_t secondRadius = GetDefaultByName("EntitySecond")->radius * 2; angle_t an; @@ -117,4 +128,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_EntityDeath) second->velx = FixedMul (secondRadius, finecosine[an]) << 2; second->vely = FixedMul (secondRadius, finesine[an]) << 2; A_FaceTarget (second); + return 0; } diff --git a/src/g_strife/a_inquisitor.cpp b/src/g_strife/a_inquisitor.cpp index b93933422f..ae5269929e 100644 --- a/src/g_strife/a_inquisitor.cpp +++ b/src/g_strife/a_inquisitor.cpp @@ -12,8 +12,11 @@ static FRandom pr_inq ("Inquisitor"); DEFINE_ACTION_FUNCTION(AActor, A_InquisitorWalk) { + PARAM_ACTION_PROLOGUE; + S_Sound (self, CHAN_BODY, "inquisitor/walk", 1, ATTN_NORM); - A_Chase (self); + A_Chase (stack, self); + return 0; } bool InquisitorCheckDistance (AActor *self) @@ -27,8 +30,10 @@ bool InquisitorCheckDistance (AActor *self) DEFINE_ACTION_FUNCTION(AActor, A_InquisitorDecide) { + PARAM_ACTION_PROLOGUE; + if (self->target == NULL) - return; + return 0; A_FaceTarget (self); if (!InquisitorCheckDistance (self)) @@ -42,41 +47,47 @@ DEFINE_ACTION_FUNCTION(AActor, A_InquisitorDecide) self->SetState (self->FindState("Jump")); } } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_InquisitorAttack) { + PARAM_ACTION_PROLOGUE; + AActor *proj; if (self->target == NULL) - return; + return 0; A_FaceTarget (self); self->AddZ(32*FRACUNIT); self->angle -= ANGLE_45/32; - proj = P_SpawnMissileZAimed (self, self->Z(), self->target, PClass::FindClass("InquisitorShot")); + proj = P_SpawnMissileZAimed (self, self->Z(), self->target, PClass::FindActor("InquisitorShot")); if (proj != NULL) { proj->velz += 9*FRACUNIT; } self->angle += ANGLE_45/16; - proj = P_SpawnMissileZAimed (self, self->Z(), self->target, PClass::FindClass("InquisitorShot")); + proj = P_SpawnMissileZAimed (self, self->Z(), self->target, PClass::FindActor("InquisitorShot")); if (proj != NULL) { proj->velz += 16*FRACUNIT; } self->AddZ(-32*FRACUNIT); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_InquisitorJump) { + PARAM_ACTION_PROLOGUE; + fixed_t dist; fixed_t speed; angle_t an; if (self->target == NULL) - return; + return 0; S_Sound (self, CHAN_ITEM|CHAN_LOOP, "inquisitor/jump", 1, ATTN_NORM); self->AddZ(64*FRACUNIT); @@ -94,10 +105,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_InquisitorJump) self->velz = (self->target->Z() - self->Z()) / dist; self->reactiontime = 60; self->flags |= MF_NOGRAVITY; + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_InquisitorCheckLand) { + PARAM_ACTION_PROLOGUE; + self->reactiontime--; if (self->reactiontime < 0 || self->velx == 0 || @@ -108,21 +122,24 @@ DEFINE_ACTION_FUNCTION(AActor, A_InquisitorCheckLand) self->reactiontime = 0; self->flags &= ~MF_NOGRAVITY; S_StopSound (self, CHAN_ITEM); - return; + return 0; } if (!S_IsActorPlayingSomething (self, CHAN_ITEM, -1)) { S_Sound (self, CHAN_ITEM|CHAN_LOOP, "inquisitor/jump", 1, ATTN_NORM); } - + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_TossArm) { + PARAM_ACTION_PROLOGUE; + AActor *foo = Spawn("InquisitorArm", self->PosPlusZ(24*FRACUNIT), ALLOW_REPLACE); foo->angle = self->angle - ANGLE_90 + (pr_inq.Random2() << 22); foo->velx = FixedMul (foo->Speed, finecosine[foo->angle >> ANGLETOFINESHIFT]) >> 3; foo->vely = FixedMul (foo->Speed, finesine[foo->angle >> ANGLETOFINESHIFT]) >> 3; foo->velz = pr_inq() << 10; + return 0; } diff --git a/src/g_strife/a_loremaster.cpp b/src/g_strife/a_loremaster.cpp index 1b12c24368..a04d5d171c 100644 --- a/src/g_strife/a_loremaster.cpp +++ b/src/g_strife/a_loremaster.cpp @@ -39,8 +39,11 @@ int ALoreShot::DoSpecialDamage (AActor *victim, int damage, FName damagetype) DEFINE_ACTION_FUNCTION(AActor, A_LoremasterChain) { + PARAM_ACTION_PROLOGUE; + S_Sound (self, CHAN_BODY, "loremaster/active", 1, ATTN_NORM); Spawn("LoreShot2", self->Pos(), ALLOW_REPLACE); Spawn("LoreShot2", self->Vec3Offset(-(self->velx >> 1), -(self->vely >> 1), -(self->velz >> 1)), ALLOW_REPLACE); Spawn("LoreShot2", self->Vec3Offset(-self->velx, -self->vely, -self->velz), ALLOW_REPLACE); + return 0; } diff --git a/src/g_strife/a_oracle.cpp b/src/g_strife/a_oracle.cpp index bdfc52dfa7..521720cd63 100644 --- a/src/g_strife/a_oracle.cpp +++ b/src/g_strife/a_oracle.cpp @@ -10,6 +10,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_WakeOracleSpectre) { + PARAM_ACTION_PROLOGUE; + TThinkerIterator it(NAME_AlienSpectre3); AActor *spectre = it.Next(); @@ -19,5 +21,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_WakeOracleSpectre) spectre->target = self->target; spectre->SetState (spectre->SeeState); } + return 0; } diff --git a/src/g_strife/a_programmer.cpp b/src/g_strife/a_programmer.cpp index 5835b3566c..a0aa24e24f 100644 --- a/src/g_strife/a_programmer.cpp +++ b/src/g_strife/a_programmer.cpp @@ -74,21 +74,24 @@ PalEntry AProgLevelEnder::GetBlend () DEFINE_ACTION_FUNCTION(AActor, A_ProgrammerMelee) { + PARAM_ACTION_PROLOGUE; + int damage; if (self->target == NULL) - return; + return 0; A_FaceTarget (self); if (!self->CheckMeleeRange ()) - return; + return 0; S_Sound (self, CHAN_WEAPON, "programmer/clank", 1, ATTN_NORM); damage = ((pr_prog() % 10) + 1) * 6; int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); + return 0; } //============================================================================ @@ -99,10 +102,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_ProgrammerMelee) DEFINE_ACTION_FUNCTION(AActor, A_SpotLightning) { + PARAM_ACTION_PROLOGUE; + AActor *spot; if (self->target == NULL) - return; + return 0; spot = Spawn("SpectralLightningSpot", self->target->X(), self->target->Y(), self->target->floorz, ALLOW_REPLACE); if (spot != NULL) @@ -112,6 +117,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpotLightning) spot->FriendPlayer = 0; spot->tracer = self->target; } + return 0; } //============================================================================ @@ -122,6 +128,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpotLightning) DEFINE_ACTION_FUNCTION(AActor, A_SpawnProgrammerBase) { + PARAM_ACTION_PROLOGUE; + AActor *foo = Spawn("ProgrammerBase", self->PosPlusZ(24*FRACUNIT), ALLOW_REPLACE); if (foo != NULL) { @@ -130,6 +138,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnProgrammerBase) foo->vely = FixedMul (foo->Speed, finesine[foo->angle >> ANGLETOFINESHIFT]); foo->velz = pr_prog() << 9; } + return 0; } //============================================================================ @@ -140,8 +149,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnProgrammerBase) DEFINE_ACTION_FUNCTION(AActor, A_ProgrammerDeath) { + PARAM_ACTION_PROLOGUE; + if (!CheckBossDeath (self)) - return; + return 0; for (int i = 0; i < MAXPLAYERS; ++i) { @@ -153,4 +164,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_ProgrammerDeath) } // the sky change scripts are now done as special actions in MAPINFO CALL_ACTION(A_BossDeath, self); + return 0; } diff --git a/src/g_strife/a_reaver.cpp b/src/g_strife/a_reaver.cpp index 6cf0d4601a..d92a1b2b58 100644 --- a/src/g_strife/a_reaver.cpp +++ b/src/g_strife/a_reaver.cpp @@ -13,6 +13,8 @@ static FRandom pr_reaverattack ("ReaverAttack"); DEFINE_ACTION_FUNCTION(AActor, A_ReaverRanged) { + PARAM_ACTION_PROLOGUE; + if (self->target != NULL) { angle_t bangle; @@ -30,4 +32,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_ReaverRanged) P_LineAttack (self, angle, MISSILERANGE, pitch, damage, NAME_Hitscan, NAME_StrifePuff); } } + return 0; } diff --git a/src/g_strife/a_rebels.cpp b/src/g_strife/a_rebels.cpp index 6c8652f7c8..26d46cffc3 100644 --- a/src/g_strife/a_rebels.cpp +++ b/src/g_strife/a_rebels.cpp @@ -22,10 +22,12 @@ static FRandom pr_shootgun ("ShootGun"); DEFINE_ACTION_FUNCTION(AActor, A_ShootGun) { + PARAM_ACTION_PROLOGUE; + int pitch; if (self->target == NULL) - return; + return 0; S_Sound (self, CHAN_WEAPON, "monsters/rifle", 1, ATTN_NORM); A_FaceTarget (self); @@ -33,6 +35,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ShootGun) P_LineAttack (self, self->angle + (pr_shootgun.Random2() << 19), MISSILERANGE, pitch, 3*(pr_shootgun() % 5 + 1), NAME_Hitscan, NAME_StrifePuff); + return 0; } // Teleporter Beacon -------------------------------------------------------- @@ -71,6 +74,8 @@ bool ATeleporterBeacon::Use (bool pickup) DEFINE_ACTION_FUNCTION(AActor, A_Beacon) { + PARAM_ACTION_PROLOGUE; + AActor *owner = self->target; AActor *rebel; angle_t an; @@ -79,7 +84,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Beacon) if (!P_TryMove (rebel, rebel->X(), rebel->Y(), true)) { rebel->Destroy (); - return; + return 0; } // Once the rebels start teleporting in, you can't pick up the beacon anymore. self->flags &= ~MF_SPECIAL; @@ -117,4 +122,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_Beacon) { self->SetState(self->FindState(NAME_Death)); } + return 0; } diff --git a/src/g_strife/a_sentinel.cpp b/src/g_strife/a_sentinel.cpp index 550a89ff70..1eb2316afd 100644 --- a/src/g_strife/a_sentinel.cpp +++ b/src/g_strife/a_sentinel.cpp @@ -11,15 +11,17 @@ static FRandom pr_sentinelrefire ("SentinelRefire"); DEFINE_ACTION_FUNCTION(AActor, A_SentinelBob) { + PARAM_ACTION_PROLOGUE; + fixed_t minz, maxz; if (self->flags & MF_INFLOAT) { self->velz = 0; - return; + return 0; } if (self->threshold != 0) - return; + return 0; maxz = self->ceilingz - self->height - 16*FRACUNIT; minz = self->floorz + 96*FRACUNIT; @@ -36,19 +38,22 @@ DEFINE_ACTION_FUNCTION(AActor, A_SentinelBob) self->velz += FRACUNIT; } self->reactiontime = (minz >= self->Z()) ? 4 : 0; + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_SentinelAttack) { + PARAM_ACTION_PROLOGUE; + AActor *missile, *trail; // [BB] Without a target the P_SpawnMissileZAimed call will crash. if (!self->target) { - return; + return 0; } - missile = P_SpawnMissileZAimed (self, self->Z() + 32*FRACUNIT, self->target, PClass::FindClass("SentinelFX2")); + missile = P_SpawnMissileZAimed (self, self->Z() + 32*FRACUNIT, self->target, PClass::FindActor("SentinelFX2")); if (missile != NULL && (missile->velx | missile->vely) != 0) { @@ -67,10 +72,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_SentinelAttack) } missile->AddZ(missile->velz >> 2); } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_SentinelRefire) { + PARAM_ACTION_PROLOGUE; + A_FaceTarget (self); if (pr_sentinelrefire() >= 30) @@ -85,4 +93,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_SentinelRefire) self->SetState (self->SeeState); } } + return 0; } diff --git a/src/g_strife/a_spectral.cpp b/src/g_strife/a_spectral.cpp index 51ed7b0d00..765381e38c 100644 --- a/src/g_strife/a_spectral.cpp +++ b/src/g_strife/a_spectral.cpp @@ -9,8 +9,6 @@ #include "thingdef/thingdef.h" */ -AActor *P_SpawnSubMissile (AActor *source, const PClass *type, AActor *target); - class ASpectralMonster : public AActor { DECLARE_CLASS (ASpectralMonster, AActor) @@ -28,15 +26,20 @@ void ASpectralMonster::Touch (AActor *toucher) DEFINE_ACTION_FUNCTION(AActor, A_SpectralLightningTail) { + PARAM_ACTION_PROLOGUE; + AActor *foo = Spawn("SpectralLightningHTail", self->Vec3Offset(-self->velx, -self->vely, 0), ALLOW_REPLACE); foo->angle = self->angle; foo->FriendPlayer = self->FriendPlayer; + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_SpectralBigBallLightning) { - const PClass *cls = PClass::FindClass("SpectralLightningH3"); + PARAM_ACTION_PROLOGUE; + + PClassActor *cls = PClass::FindActor("SpectralLightningH3"); if (cls) { self->angle += ANGLE_90; @@ -46,12 +49,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpectralBigBallLightning) self->angle += ANGLE_90; P_SpawnSubMissile (self, cls, self->target); } + return 0; } static FRandom pr_zap5 ("Zap5"); DEFINE_ACTION_FUNCTION(AActor, A_SpectralLightning) { + PARAM_ACTION_PROLOGUE; + AActor *flash; if (self->threshold != 0) @@ -64,8 +70,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpectralLightning) pr_zap5.Random2(3) * FRACUNIT * 50, pr_zap5.Random2(3) * FRACUNIT * 50); - flash = Spawn (self->threshold > 25 ? PClass::FindClass(NAME_SpectralLightningV2) : - PClass::FindClass(NAME_SpectralLightningV1), pos.x, pos.y, ONCEILINGZ, ALLOW_REPLACE); + flash = Spawn (self->threshold > 25 ? PClass::FindActor(NAME_SpectralLightningV2) : + PClass::FindActor(NAME_SpectralLightningV1), pos.x, pos.y, ONCEILINGZ, ALLOW_REPLACE); flash->target = self->target; flash->velz = -18*FRACUNIT; @@ -76,6 +82,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpectralLightning) flash->target = self->target; flash->velz = -18*FRACUNIT; flash->FriendPlayer = self->FriendPlayer; + return 0; } // In Strife, this number is stored in the data segment, but it doesn't seem to be @@ -84,6 +91,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpectralLightning) DEFINE_ACTION_FUNCTION(AActor, A_Tracer2) { + PARAM_ACTION_PROLOGUE; + AActor *dest; angle_t exact; fixed_t dist; @@ -92,7 +101,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer2) dest = self->tracer; if (!dest || dest->health <= 0 || self->Speed == 0 || !self->CanSeek(dest)) - return; + return 0; // change angle exact = self->AngleTo(dest); @@ -143,4 +152,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer2) self->velz += FRACUNIT/8; } } + return 0; } diff --git a/src/g_strife/a_stalker.cpp b/src/g_strife/a_stalker.cpp index 6a06bf867b..f5dbb58e62 100644 --- a/src/g_strife/a_stalker.cpp +++ b/src/g_strife/a_stalker.cpp @@ -13,6 +13,8 @@ static FRandom pr_stalker ("Stalker"); DEFINE_ACTION_FUNCTION(AActor, A_StalkerChaseDecide) { + PARAM_ACTION_PROLOGUE; + if (!(self->flags & MF_NOGRAVITY)) { self->SetState (self->FindState("SeeFloor")); @@ -21,10 +23,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_StalkerChaseDecide) { self->SetState (self->FindState("Drop")); } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_StalkerLookInit) { + PARAM_ACTION_PROLOGUE; + FState *state; if (self->flags & MF_NOGRAVITY) { @@ -38,16 +43,22 @@ DEFINE_ACTION_FUNCTION(AActor, A_StalkerLookInit) { self->SetState (state); } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_StalkerDrop) { + PARAM_ACTION_PROLOGUE; + self->flags5 &= ~MF5_NOVERTICALMELEERANGE; self->flags &= ~MF_NOGRAVITY; + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_StalkerAttack) { + PARAM_ACTION_PROLOGUE; + if (self->flags & MF_NOGRAVITY) { self->SetState (self->FindState("Drop")); @@ -63,11 +74,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_StalkerAttack) P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); } } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_StalkerWalk) { + PARAM_ACTION_PROLOGUE; + S_Sound (self, CHAN_BODY, "stalker/walk", 1, ATTN_NORM); - A_Chase (self); + A_Chase (stack, self); + return 0; } diff --git a/src/g_strife/a_strifeglobal.h b/src/g_strife/a_strifeglobal.h index d501485bae..8cc438d43e 100644 --- a/src/g_strife/a_strifeglobal.h +++ b/src/g_strife/a_strifeglobal.h @@ -63,6 +63,6 @@ public: int NumPieces, DownPieces; }; -extern const PClass *QuestItemClasses[31]; +extern PClassActor *QuestItemClasses[31]; #endif diff --git a/src/g_strife/a_strifeitems.cpp b/src/g_strife/a_strifeitems.cpp index 6771080d03..44c009509d 100644 --- a/src/g_strife/a_strifeitems.cpp +++ b/src/g_strife/a_strifeitems.cpp @@ -23,6 +23,8 @@ IMPLEMENT_CLASS(ADegninOre) DEFINE_ACTION_FUNCTION(AActor, A_RemoveForceField) { + PARAM_ACTION_PROLOGUE; + self->flags &= ~MF_SPECIAL; for (int i = 0; i < self->Sector->linecount; ++i) @@ -36,6 +38,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_RemoveForceField) line->sidedef[1]->SetTexture(side_t::mid, FNullTextureID()); } } + return 0; } bool ADegninOre::Use (bool pickup) @@ -78,7 +81,7 @@ bool AHealthTraining::TryPickup (AActor *&toucher) { if (Super::TryPickup (toucher)) { - toucher->GiveInventoryType (PClass::FindClass("GunTraining")); + toucher->GiveInventoryType (PClass::FindActor("GunTraining")); AInventory *coin = Spawn (0,0,0, NO_REPLACE); if (coin != NULL) { @@ -177,6 +180,7 @@ IMPLEMENT_CLASS (ARaiseAlarm) bool ARaiseAlarm::TryPickup (AActor *&toucher) { P_NoiseAlert (toucher, toucher); + VMFrameStack stack1, *stack = &stack1; CALL_ACTION(A_WakeOracleSpectre, toucher); GoAwayAndDie (); return true; @@ -281,7 +285,7 @@ IMPLEMENT_CLASS (AAmmoFillup) bool AAmmoFillup::TryPickup (AActor *&toucher) { - const PClass * clip = PClass::FindClass(NAME_ClipOfBullets); + PClassActor *clip = PClass::FindActor(NAME_ClipOfBullets); if (clip != NULL) { AInventory *item = toucher->FindInventory(clip); diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp index 3145290efb..fc11ba4334 100644 --- a/src/g_strife/a_strifestuff.cpp +++ b/src/g_strife/a_strifestuff.cpp @@ -432,22 +432,30 @@ int AForceFieldGuard::TakeSpecialDamage (AActor *inflictor, AActor *source, int DEFINE_ACTION_FUNCTION(AActor, A_SetShadow) { + PARAM_ACTION_PROLOGUE; + self->flags |= MF_STRIFEx8000000|MF_SHADOW; self->RenderStyle = STYLE_Translucent; self->alpha = HR_SHADOW; + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_ClearShadow) { + PARAM_ACTION_PROLOGUE; + self->flags &= ~(MF_STRIFEx8000000|MF_SHADOW); self->RenderStyle = STYLE_Normal; self->alpha = OPAQUE; + return 0; } static FRandom pr_gethurt ("HurtMe!"); DEFINE_ACTION_FUNCTION(AActor, A_GetHurt) { + PARAM_ACTION_PROLOGUE; + self->flags4 |= MF4_INCOMBAT; if ((pr_gethurt() % 5) == 0) { @@ -458,16 +466,19 @@ DEFINE_ACTION_FUNCTION(AActor, A_GetHurt) { self->Die (self->target, self->target); } + return 0; } // Klaxon Warning Light ----------------------------------------------------- DEFINE_ACTION_FUNCTION(AActor, A_TurretLook) { + PARAM_ACTION_PROLOGUE; + AActor *target; if (self->flags5 & MF5_INCONVERSATION) - return; + return 0; self->threshold = 0; target = self->LastHeard; @@ -479,7 +490,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_TurretLook) self->target = target; if ((self->flags & MF_AMBUSH) && !P_CheckSight (self, target)) { - return; + return 0; } if (self->SeeSound != 0) { @@ -489,10 +500,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_TurretLook) self->threshold = 10; self->SetState (self->SeeState); } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_KlaxonBlare) { + PARAM_ACTION_PROLOGUE; + if (--self->reactiontime < 0) { self->target = NULL; @@ -516,6 +530,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_KlaxonBlare) { S_Sound (self, CHAN_VOICE, "misc/alarm", 1, ATTN_NORM); } + return 0; } // Power Coupling ----------------------------------------------------------- @@ -552,7 +567,7 @@ void APowerCoupling::Die (AActor *source, AActor *inflictor, int dmgflags) players[i].mo->GiveInventoryType (QuestItemClasses[5]); S_Sound (CHAN_VOICE, "svox/voc13", 1, ATTN_NORM); players[i].SetLogNumber (13); - P_DropItem (this, PClass::FindClass("BrokenPowerCoupling"), -1, 256); + P_DropItem (this, PClass::FindActor("BrokenPowerCoupling"), -1, 256); Destroy (); } @@ -579,6 +594,8 @@ IMPLEMENT_CLASS (AMeat) DEFINE_ACTION_FUNCTION(AActor, A_TossGib) { + PARAM_ACTION_PROLOGUE; + const char *gibtype = (self->flags & MF_NOBLOOD) ? "Junk" : "Meat"; AActor *gib = Spawn (gibtype, self->PosPlusZ(24*FRACUNIT), ALLOW_REPLACE); angle_t an; @@ -586,7 +603,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_TossGib) if (gib == NULL) { - return; + return 0; } an = pr_gibtosser() << 24; @@ -595,37 +612,49 @@ DEFINE_ACTION_FUNCTION(AActor, A_TossGib) gib->velx = speed * finecosine[an >> ANGLETOFINESHIFT]; gib->vely = speed * finesine[an >> ANGLETOFINESHIFT]; gib->velz = (pr_gibtosser() & 15) << FRACBITS; + return 0; } //============================================================================ DEFINE_ACTION_FUNCTION(AActor, A_FLoopActiveSound) { + PARAM_ACTION_PROLOGUE; + if (self->ActiveSound != 0 && !(level.time & 7)) { S_Sound (self, CHAN_VOICE, self->ActiveSound, 1, ATTN_NORM); } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_Countdown) { + PARAM_ACTION_PROLOGUE; + if (--self->reactiontime <= 0) { P_ExplodeMissile (self, NULL, NULL); self->flags &= ~MF_SKULLFLY; } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_LoopActiveSound) { + PARAM_ACTION_PROLOGUE; + if (self->ActiveSound != 0 && !S_IsActorPlayingSomething (self, CHAN_VOICE, -1)) { S_Sound (self, CHAN_VOICE|CHAN_LOOP, self->ActiveSound, 1, ATTN_NORM); } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_CheckTerrain) { + PARAM_ACTION_PROLOGUE; + sector_t *sec = self->Sector; if (self->Z() == sec->floorplane.ZatPoint(self)) @@ -644,6 +673,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckTerrain) self->vely += FixedMul (speed, finesine[finean]); } } + return 0; } //============================================================================ @@ -654,6 +684,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckTerrain) DEFINE_ACTION_FUNCTION(AActor, A_ClearSoundTarget) { + PARAM_ACTION_PROLOGUE; + AActor *actor; self->Sector->SoundTarget = NULL; @@ -661,11 +693,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_ClearSoundTarget) { actor->LastHeard = NULL; } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_ItBurnsItBurns) { + PARAM_ACTION_PROLOGUE; + S_Sound (self, CHAN_VOICE, "human/imonfire", 1, ATTN_NORM); if (self->player != NULL && self->player->mo == self) @@ -677,17 +712,23 @@ DEFINE_ACTION_FUNCTION(AActor, A_ItBurnsItBurns) self->player->playerstate = PST_LIVE; self->player->extralight = 3; } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_DropFire) { + PARAM_ACTION_PROLOGUE; + AActor *drop = Spawn("FireDroplet", self->PosPlusZ(24*FRACUNIT), ALLOW_REPLACE); drop->velz = -FRACUNIT; P_RadiusAttack (self, self, 64, 64, NAME_Fire, 0); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_CrispyPlayer) { + PARAM_ACTION_PROLOGUE; + if (self->player != NULL && self->player->mo == self) { self->player->playerstate = PST_DEAD; @@ -695,10 +736,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_CrispyPlayer) self->player->psprites[ps_weapon].state + (self->FindState("FireHandsLower") - self->FindState("FireHands"))); } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_HandLower) { + PARAM_ACTION_PROLOGUE; + if (self->player != NULL) { pspdef_t *psp = &self->player->psprites[ps_weapon]; @@ -709,5 +753,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_HandLower) } if (self->player->extralight > 0) self->player->extralight--; } + return 0; } diff --git a/src/g_strife/a_strifeweapons.cpp b/src/g_strife/a_strifeweapons.cpp index a33521087f..561f527468 100644 --- a/src/g_strife/a_strifeweapons.cpp +++ b/src/g_strife/a_strifeweapons.cpp @@ -94,6 +94,8 @@ void P_DaggerAlert (AActor *target, AActor *emitter) DEFINE_ACTION_FUNCTION(AActor, A_JabDagger) { + PARAM_ACTION_PROLOGUE; + angle_t angle; int damage; int pitch; @@ -126,6 +128,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_JabDagger) { S_Sound (self, CHAN_WEAPON, "misc/swish", 1, ATTN_NORM); } + return 0; } //============================================================================ @@ -143,9 +146,9 @@ enum DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_AlertMonsters) { - ACTION_PARAM_START(1); - ACTION_PARAM_FIXED(maxdist, 0); - ACTION_PARAM_INT(Flags, 1); + PARAM_ACTION_PROLOGUE; + PARAM_FIXED_OPT(maxdist) { maxdist = 0; } + PARAM_INT_OPT(Flags) { Flags = 0; } AActor * target = NULL; AActor * emitter = self; @@ -169,6 +172,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_AlertMonsters) { P_NoiseAlert(target, emitter, false, maxdist); } + return 0; } // Poison Bolt -------------------------------------------------------------- @@ -208,12 +212,15 @@ int APoisonBolt::DoSpecialDamage (AActor *target, int damage, FName damagetype) DEFINE_ACTION_FUNCTION(AActor, A_ClearFlash) { + PARAM_ACTION_PROLOGUE; + player_t *player = self->player; if (player == NULL) - return; + return 0; P_SetPsprite (player, ps_flash, NULL); + return 0; } //============================================================================ @@ -224,10 +231,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_ClearFlash) DEFINE_ACTION_FUNCTION(AActor, A_ShowElectricFlash) { + PARAM_ACTION_PROLOGUE; + if (self->player != NULL) { P_SetPsprite (self->player, ps_flash, self->player->ReadyWeapon->FindState(NAME_Flash)); } + return 0; } //============================================================================ @@ -238,19 +248,19 @@ DEFINE_ACTION_FUNCTION(AActor, A_ShowElectricFlash) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireArrow) { + PARAM_ACTION_PROLOGUE; + PARAM_CLASS(ti, AActor); + angle_t savedangle; - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(ti, 0); - if (self->player == NULL) - return; + return 0; AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } if (ti) @@ -262,6 +272,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireArrow) self->angle = savedangle; S_Sound (self, CHAN_WEAPON, "weapons/xbowshoot", 1, ATTN_NORM); } + return 0; } // Assault Gun -------------------------------------------------------------- @@ -296,6 +307,8 @@ void P_StrifeGunShot (AActor *mo, bool accurate, angle_t pitch) DEFINE_ACTION_FUNCTION(AActor, A_FireAssaultGun) { + PARAM_ACTION_PROLOGUE; + bool accurate; S_Sound (self, CHAN_WEAPON, "weapons/assaultgun", 1, ATTN_NORM); @@ -306,7 +319,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireAssaultGun) if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } self->player->mo->PlayAttacking2 (); accurate = !self->player->refire; @@ -317,6 +330,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireAssaultGun) } P_StrifeGunShot (self, accurate, P_BulletSlope (self)); + return 0; } // Mini-Missile Launcher ---------------------------------------------------- @@ -329,24 +343,27 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireAssaultGun) DEFINE_ACTION_FUNCTION(AActor, A_FireMiniMissile) { + PARAM_ACTION_PROLOGUE; + player_t *player = self->player; angle_t savedangle; if (self->player == NULL) - return; + return 0; AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } savedangle = self->angle; self->angle += pr_minimissile.Random2() << (19 - player->mo->accuracy * 5 / 100); player->mo->PlayAttacking2 (); - P_SpawnPlayerMissile (self, PClass::FindClass("MiniMissile")); + P_SpawnPlayerMissile (self, PClass::FindActor("MiniMissile")); self->angle = savedangle; + return 0; } //============================================================================ @@ -357,15 +374,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMiniMissile) DEFINE_ACTION_FUNCTION(AActor, A_RocketInFlight) { + PARAM_ACTION_PROLOGUE; + AActor *trail; S_Sound (self, CHAN_VOICE, "misc/missileinflight", 1, ATTN_NORM); - P_SpawnPuff (self, PClass::FindClass("MiniMissilePuff"), self->Pos(), self->angle - ANGLE_180, 2, PF_HITTHING); + P_SpawnPuff (self, PClass::FindActor("MiniMissilePuff"), self->Pos(), self->angle - ANGLE_180, 2, PF_HITTHING); trail = Spawn("RocketTrail", self->Vec3Offset(-self->velx, -self->vely, 0), ALLOW_REPLACE); if (trail != NULL) { trail->velz = FRACUNIT; } + return 0; } // Flame Thrower ------------------------------------------------------------ @@ -378,8 +398,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_RocketInFlight) DEFINE_ACTION_FUNCTION(AActor, A_FlameDie) { + PARAM_ACTION_PROLOGUE; + self->flags |= MF_NOGRAVITY; self->velz = (pr_flamedie() & 3) << FRACBITS; + return 0; } //============================================================================ @@ -390,6 +413,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_FlameDie) DEFINE_ACTION_FUNCTION(AActor, A_FireFlamer) { + PARAM_ACTION_PROLOGUE; + player_t *player = self->player; if (player != NULL) @@ -398,17 +423,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireFlamer) if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } player->mo->PlayAttacking2 (); } self->angle += pr_flamethrower.Random2() << 18; - self = P_SpawnPlayerMissile (self, PClass::FindClass("FlameMissile")); + self = P_SpawnPlayerMissile (self, PClass::FindActor("FlameMissile")); if (self != NULL) { self->velz += 5*FRACUNIT; } + return 0; } // Mauler ------------------------------------------------------------------- @@ -424,13 +450,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireFlamer) DEFINE_ACTION_FUNCTION(AActor, A_FireMauler1) { + PARAM_ACTION_PROLOGUE; + if (self->player != NULL) { AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } // Strife apparently didn't show the player shooting. Let's fix that. self->player->mo->PlayAttacking2 (); @@ -453,6 +481,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMauler1) // original. P_LineAttack (self, angle, PLAYERMISSILERANGE, pitch, damage, NAME_Hitscan, NAME_MaulerPuff); } + return 0; } //============================================================================ @@ -465,6 +494,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMauler1) DEFINE_ACTION_FUNCTION(AActor, A_FireMauler2Pre) { + PARAM_ACTION_PROLOGUE; + S_Sound (self, CHAN_WEAPON, "weapons/mauler2charge", 1, ATTN_NORM); if (self->player != NULL) @@ -472,6 +503,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMauler2Pre) self->player->psprites[ps_weapon].sx += pr_mauler2.Random2() << 10; self->player->psprites[ps_weapon].sy += pr_mauler2.Random2() << 10; } + return 0; } //============================================================================ @@ -484,19 +516,22 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMauler2Pre) DEFINE_ACTION_FUNCTION(AActor, A_FireMauler2) { + PARAM_ACTION_PROLOGUE; + if (self->player != NULL) { AWeapon *weapon = self->player->ReadyWeapon; if (weapon != NULL) { if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; } self->player->mo->PlayAttacking2 (); } - P_SpawnPlayerMissile (self, PClass::FindClass("MaulerTorpedo")); + P_SpawnPlayerMissile (self, PClass::FindActor("MaulerTorpedo")); P_DamageMobj (self, self, NULL, 20, self->DamageType); P_ThrustMobj (self, self->angle + ANGLE_180, 0x7D000); + return 0; } //============================================================================ @@ -507,10 +542,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMauler2) // //============================================================================ -AActor *P_SpawnSubMissile (AActor *source, const PClass *type, AActor *target); - DEFINE_ACTION_FUNCTION(AActor, A_MaulerTorpedoWave) { + PARAM_ACTION_PROLOGUE; + AActor *wavedef = GetDefaultByName("MaulerTorpedoWave"); fixed_t savedz; self->angle += ANGLE_180; @@ -525,12 +560,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_MaulerTorpedoWave) for (int i = 0; i < 80; ++i) { self->angle += ANGLE_45/10; - P_SpawnSubMissile (self, PClass::FindClass("MaulerTorpedoWave"), self->target); + P_SpawnSubMissile (self, PClass::FindActor("MaulerTorpedoWave"), self->target); } self->SetZ(savedz); + return 0; } -AActor *P_SpawnSubMissile (AActor *source, const PClass *type, AActor *target) +AActor *P_SpawnSubMissile (AActor *source, PClassActor *type, AActor *target) { AActor *other = Spawn (type, source->Pos(), ALLOW_REPLACE); @@ -586,11 +622,16 @@ int APhosphorousFire::DoSpecialDamage (AActor *target, int damage, FName damaget DEFINE_ACTION_FUNCTION(AActor, A_BurnArea) { + PARAM_ACTION_PROLOGUE; + P_RadiusAttack (self, self->target, 128, 128, self->DamageType, RADF_HURTSOURCE); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_Burnination) { + PARAM_ACTION_PROLOGUE; + self->velz -= 8*FRACUNIT; self->velx += (pr_phburn.Random2 (3)) << FRACBITS; self->vely += (pr_phburn.Random2 (3)) << FRACBITS; @@ -641,7 +682,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Burnination) drop->flags |= MF_DROPPED; } } - + return 0; } //============================================================================ @@ -652,25 +693,25 @@ DEFINE_ACTION_FUNCTION(AActor, A_Burnination) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireGrenade) { + PARAM_ACTION_PROLOGUE; + PARAM_CLASS(grenadetype, AActor); + PARAM_ANGLE(angleofs); + PARAM_STATE(flash) + player_t *player = self->player; AActor *grenade; angle_t an; fixed_t tworadii; AWeapon *weapon; - ACTION_PARAM_START(3); - ACTION_PARAM_CLASS(grenadetype, 0); - ACTION_PARAM_ANGLE(Angle, 1); - ACTION_PARAM_STATE(flash, 2); - if (player == NULL || grenadetype == NULL) - return; + return 0; if ((weapon = player->ReadyWeapon) == NULL) - return; + return 0; if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; + return 0; P_SetPsprite (player, ps_flash, flash); @@ -680,7 +721,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireGrenade) grenade = P_SpawnSubMissile (self, grenadetype, self); self->AddZ(-32*FRACUNIT); if (grenade == NULL) - return; + return 0; if (grenade->SeeSound != 0) { @@ -696,7 +737,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireGrenade) offset.x = FixedMul (finecosine[an], tworadii); offset.y = FixedMul (finesine[an], tworadii); - an = self->angle + Angle; + an = self->angle + angleofs; an >>= ANGLETOFINESHIFT; offset.x += FixedMul (finecosine[an], 15*FRACUNIT); offset.y += FixedMul (finesine[an], 15*FRACUNIT); @@ -704,6 +745,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireGrenade) fixedvec2 newpos = grenade->Vec2Offset(offset.x, offset.y); grenade->SetOrigin(newpos.x, newpos.y, grenade->Z(), false); } + return 0; } // The Almighty Sigil! ------------------------------------------------------ @@ -794,12 +836,15 @@ AInventory *ASigil::CreateCopy (AActor *other) DEFINE_ACTION_FUNCTION(AActor, A_SelectPiece) { + PARAM_ACTION_PROLOGUE; + int pieces = MIN (static_cast(self)->NumPieces, 5); if (pieces > 1) { self->SetState (self->FindState("Spawn")+pieces); } + return 0; } //============================================================================ @@ -817,15 +862,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_SelectPiece) DEFINE_ACTION_FUNCTION(AActor, A_SelectSigilView) { + PARAM_ACTION_PROLOGUE; + int pieces; if (self->player == NULL) { - return; + return 0; } pieces = static_cast(self->player->ReadyWeapon)->NumPieces; P_SetPsprite (self->player, ps_weapon, self->player->psprites[ps_weapon].state + pieces); + return 0; } //============================================================================ @@ -840,11 +888,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_SelectSigilView) DEFINE_ACTION_FUNCTION(AActor, A_SelectSigilDown) { + PARAM_ACTION_PROLOGUE; + int pieces; if (self->player == NULL) { - return; + return 0; } pieces = static_cast(self->player->ReadyWeapon)->DownPieces; static_cast(self->player->ReadyWeapon)->DownPieces = 0; @@ -854,6 +904,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SelectSigilDown) } P_SetPsprite (self->player, ps_weapon, self->player->psprites[ps_weapon].state + pieces); + return 0; } //============================================================================ @@ -866,15 +917,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_SelectSigilDown) DEFINE_ACTION_FUNCTION(AActor, A_SelectSigilAttack) { + PARAM_ACTION_PROLOGUE; + int pieces; if (self->player == NULL) { - return; + return 0; } pieces = static_cast(self->player->ReadyWeapon)->NumPieces; P_SetPsprite (self->player, ps_weapon, self->player->psprites[ps_weapon].state + 4*pieces - 3); + return 0; } //============================================================================ @@ -885,11 +939,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_SelectSigilAttack) DEFINE_ACTION_FUNCTION(AActor, A_SigilCharge) { + PARAM_ACTION_PROLOGUE; + S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM); if (self->player != NULL) { self->player->extralight = 2; } + return 0; } //============================================================================ @@ -900,10 +957,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_SigilCharge) DEFINE_ACTION_FUNCTION(AActor, A_LightInverse) { + PARAM_ACTION_PROLOGUE; + if (self->player != NULL) { self->player->extralight = INT_MIN; } + return 0; } //============================================================================ @@ -914,12 +974,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightInverse) DEFINE_ACTION_FUNCTION(AActor, A_FireSigil1) { + PARAM_ACTION_PROLOGUE; + AActor *spot; player_t *player = self->player; AActor *linetarget; if (player == NULL || player->ReadyWeapon == NULL) - return; + return 0; P_DamageMobj (self, self, NULL, 1*4, 0, DMG_NO_ARMOR); S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM); @@ -947,6 +1009,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil1) spot->SetFriendPlayer(player); spot->target = self; } + return 0; } //============================================================================ @@ -957,15 +1020,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil1) DEFINE_ACTION_FUNCTION(AActor, A_FireSigil2) { + PARAM_ACTION_PROLOGUE; + player_t *player = self->player; if (player == NULL || player->ReadyWeapon == NULL) - return; + return 0; P_DamageMobj (self, self, NULL, 2*4, 0, DMG_NO_ARMOR); S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM); - P_SpawnPlayerMissile (self, PClass::FindClass("SpectralLightningH1")); + P_SpawnPlayerMissile (self, PClass::FindActor("SpectralLightningH1")); + return 0; } //============================================================================ @@ -976,12 +1042,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil2) DEFINE_ACTION_FUNCTION(AActor, A_FireSigil3) { + PARAM_ACTION_PROLOGUE; + AActor *spot; player_t *player = self->player; int i; if (player == NULL || player->ReadyWeapon == NULL) - return; + return 0; P_DamageMobj (self, self, NULL, 3*4, 0, DMG_NO_ARMOR); S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM); @@ -990,13 +1058,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil3) for (i = 0; i < 20; ++i) { self->angle += ANGLE_180/20; - spot = P_SpawnSubMissile (self, PClass::FindClass("SpectralLightningBall1"), self); + spot = P_SpawnSubMissile (self, PClass::FindActor("SpectralLightningBall1"), self); if (spot != NULL) { spot->SetZ(self->Z() + 32*FRACUNIT); } } self->angle -= (ANGLE_180/20)*10; + return 0; } //============================================================================ @@ -1007,12 +1076,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil3) DEFINE_ACTION_FUNCTION(AActor, A_FireSigil4) { + PARAM_ACTION_PROLOGUE; + AActor *spot; player_t *player = self->player; AActor *linetarget; if (player == NULL || player->ReadyWeapon == NULL) - return; + return 0; P_DamageMobj (self, self, NULL, 4*4, 0, DMG_NO_ARMOR); S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM); @@ -1020,7 +1091,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil4) P_BulletSlope (self, &linetarget); if (linetarget != NULL) { - spot = P_SpawnPlayerMissile (self, 0,0,0, PClass::FindClass("SpectralLightningBigV1"), self->angle, &linetarget); + spot = P_SpawnPlayerMissile (self, 0,0,0, PClass::FindActor("SpectralLightningBigV1"), self->angle, &linetarget); if (spot != NULL) { spot->tracer = linetarget; @@ -1028,13 +1099,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil4) } else { - spot = P_SpawnPlayerMissile (self, PClass::FindClass("SpectralLightningBigV1")); + spot = P_SpawnPlayerMissile (self, PClass::FindActor("SpectralLightningBigV1")); if (spot != NULL) { spot->velx += FixedMul (spot->Speed, finecosine[self->angle >> ANGLETOFINESHIFT]); spot->vely += FixedMul (spot->Speed, finesine[self->angle >> ANGLETOFINESHIFT]); } } + return 0; } //============================================================================ @@ -1045,15 +1117,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil4) DEFINE_ACTION_FUNCTION(AActor, A_FireSigil5) { + PARAM_ACTION_PROLOGUE; + player_t *player = self->player; if (player == NULL || player->ReadyWeapon == NULL) - return; + return 0; P_DamageMobj (self, self, NULL, 5*4, 0, DMG_NO_ARMOR); S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM); - P_SpawnPlayerMissile (self, PClass::FindClass("SpectralLightningBigBall1")); + P_SpawnPlayerMissile (self, PClass::FindActor("SpectralLightningBigBall1")); + return 0; } //============================================================================ diff --git a/src/g_strife/a_templar.cpp b/src/g_strife/a_templar.cpp index 282193d48b..968feafe1e 100644 --- a/src/g_strife/a_templar.cpp +++ b/src/g_strife/a_templar.cpp @@ -13,13 +13,15 @@ static FRandom pr_templar ("Templar"); DEFINE_ACTION_FUNCTION(AActor, A_TemplarAttack) { + PARAM_ACTION_PROLOGUE; + int damage; angle_t angle; int pitch; int pitchdiff; if (self->target == NULL) - return; + return 0; S_Sound (self, CHAN_WEAPON, "templar/shoot", 1, ATTN_NORM); A_FaceTarget (self); @@ -32,4 +34,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_TemplarAttack) pitchdiff = pr_templar.Random2() * 332063; P_LineAttack (self, angle, MISSILERANGE+64*FRACUNIT, pitch+pitchdiff, damage, NAME_Hitscan, NAME_MaulerPuff); } + return 0; } diff --git a/src/g_strife/a_thingstoblowup.cpp b/src/g_strife/a_thingstoblowup.cpp index 3e0efe5259..a1899e60b0 100644 --- a/src/g_strife/a_thingstoblowup.cpp +++ b/src/g_strife/a_thingstoblowup.cpp @@ -14,32 +14,35 @@ static FRandom pr_bang4cloud ("Bang4Cloud"); static FRandom pr_lightout ("LightOut"); -extern const PClass *QuestItemClasses[31]; - DEFINE_ACTION_FUNCTION(AActor, A_Bang4Cloud) { + PARAM_ACTION_PROLOGUE; + fixed_t xo = (pr_bang4cloud.Random2() & 3) * 10240; fixed_t yo = (pr_bang4cloud.Random2() & 3) * 10240; - Spawn("Bang4Cloud", self->Vec3Offset(xo, yo, 0), ALLOW_REPLACE); + return 0; } // ------------------------------------------------------------------- DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveQuestItem) { - ACTION_PARAM_START(1); - ACTION_PARAM_INT(questitem, 0); + PARAM_ACTION_PROLOGUE; + PARAM_INT(questitem); // Give one of these quest items to every player in the game - for (int i = 0; i < MAXPLAYERS; ++i) + if (questitem >= 0 && questitem < (int)countof(QuestItemClasses)) { - if (playeringame[i]) + for (int i = 0; i < MAXPLAYERS; ++i) { - AInventory *item = static_cast(Spawn (QuestItemClasses[questitem-1], 0,0,0, NO_REPLACE)); - if (!item->CallTryPickup (players[i].mo)) + if (playeringame[i]) { - item->Destroy (); + AInventory *item = static_cast(Spawn (QuestItemClasses[questitem - 1], 0,0,0, NO_REPLACE)); + if (!item->CallTryPickup (players[i].mo)) + { + item->Destroy (); + } } } } @@ -53,20 +56,26 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveQuestItem) { C_MidPrint (SmallFont, name); } + return 0; } // PowerCrystal ------------------------------------------------------------------- DEFINE_ACTION_FUNCTION(AActor, A_ExtraLightOff) { + PARAM_ACTION_PROLOGUE; + if (self->target != NULL && self->target->player != NULL) { self->target->player->extralight = 0; } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_Explode512) { + PARAM_ACTION_PROLOGUE; + P_RadiusAttack (self, self->target, 512, 512, NAME_None, RADF_HURTSOURCE); if (self->target != NULL && self->target->player != NULL) { @@ -76,10 +85,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_Explode512) // Strife didn't do this next part, but it looks good self->RenderStyle = STYLE_Add; + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_LightGoesOut) { + PARAM_ACTION_PROLOGUE; + AActor *foo; sector_t *sec = self->Sector; vertex_t *spot; @@ -104,4 +116,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightGoesOut) foo->velz = (7 + (pr_lightout() & 3)) << FRACBITS; } } + return 0; } diff --git a/src/g_strife/strife_sbar.cpp b/src/g_strife/strife_sbar.cpp index b69222d366..b7372f9773 100644 --- a/src/g_strife/strife_sbar.cpp +++ b/src/g_strife/strife_sbar.cpp @@ -714,7 +714,7 @@ private: }; for (i = 0; i < 7; ++i) { - const PClass *ammotype = PClass::FindClass(AmmoList[i].AmmoType); + PClassActor *ammotype = PClass::FindActor(AmmoList[i].AmmoType); item = CPlayer->mo->FindInventory (ammotype); if (item == NULL) diff --git a/src/info.cpp b/src/info.cpp index 21eb7896a9..07ae29eb0f 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -42,7 +42,7 @@ #include "v_text.h" #include "gi.h" - +#include "vm.h" #include "actor.h" #include "r_state.h" #include "i_system.h" @@ -50,13 +50,34 @@ #include "templates.h" #include "cmdlib.h" #include "g_level.h" +#include "stats.h" extern void LoadActors (); extern void InitBotStuff(); extern void ClearStrifeTypes(); +TArray PClassActor::AllActorClasses; FRandom FState::pr_statetics("StateTics"); +cycle_t ActionCycles; + +bool FState::CallAction(AActor *self, AActor *stateowner) +{ + if (ActionFunc != NULL) + { + ActionCycles.Clock(); + static VMFrameStack stack; + VMValue params[3] = { self, stateowner, VMValue(this, ATAG_STATE) }; + stack.Call(ActionFunc, params, countof(params), NULL, 0, NULL); + ActionCycles.Unclock(); + return true; + } + else + { + return false; + } +} + //========================================================================== // // @@ -99,13 +120,17 @@ int GetSpriteIndex(const char * spritename, bool add) return (lastindex = (int)sprites.Push (temp)); } +IMPLEMENT_POINTY_CLASS(PClassActor) + DECLARE_POINTER(DropItems) +END_POINTERS //========================================================================== // +// PClassActor :: StaticInit STATIC // //========================================================================== -void FActorInfo::StaticInit () +void PClassActor::StaticInit() { sprites.Clear(); if (sprites.Size() == 0) @@ -135,32 +160,205 @@ void FActorInfo::StaticInit () //========================================================================== // +// PClassActor :: StaticSetActorNums STATIC +// // Called after Dehacked patches are applied // //========================================================================== -void FActorInfo::StaticSetActorNums () +void PClassActor::StaticSetActorNums() { - for (unsigned int i = 0; i < PClass::m_RuntimeActors.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - PClass::m_RuntimeActors[i]->ActorInfo->RegisterIDs (); + static_cast(PClassActor::AllActorClasses[i])->RegisterIDs(); } } //========================================================================== // +// PClassActor Constructor // //========================================================================== -void FActorInfo::RegisterIDs () +PClassActor::PClassActor() { - const PClass *cls = PClass::FindClass(Class->TypeName); + GameFilter = GAME_Any; + SpawnID = 0; + DoomEdNum = -1; + OwnedStates = NULL; + NumOwnedStates = 0; + Replacement = NULL; + Replacee = NULL; + StateList = NULL; + DamageFactors = NULL; + PainChances = NULL; + + DeathHeight = -1; + BurnHeight = -1; + GibHealth = INT_MIN; + WoundHealth = 6; + PoisonDamage = 0; + FastSpeed = FIXED_MIN; + RDFactor = FRACUNIT; + CameraHeight = FIXED_MIN; + BloodType = NAME_Blood; + BloodType2 = NAME_BloodSplatter; + BloodType3 = NAME_AxeBlood; + + DropItems = NULL; + + DontHurtShooter = false; + ExplosionDamage = 128; + ExplosionRadius = -1; + MissileHeight = 32*FRACUNIT; + MeleeDamage = 0; + + // Record this in the master list. + AllActorClasses.Push(this); +} + +//========================================================================== +// +// PClassActor Destructor +// +//========================================================================== + +PClassActor::~PClassActor() +{ + if (OwnedStates != NULL) + { + delete[] OwnedStates; + } + if (DamageFactors != NULL) + { + delete DamageFactors; + } + if (PainChances != NULL) + { + delete PainChances; + } + if (StateList != NULL) + { + StateList->Destroy(); + M_Free(StateList); + } +} + +//========================================================================== +// +// PClassActor :: Derive +// +//========================================================================== + +void PClassActor::Derive(PClass *newclass) +{ + assert(newclass->IsKindOf(RUNTIME_CLASS(PClassActor))); + Super::Derive(newclass); + PClassActor *newa = static_cast(newclass); + + newa->Obituary = Obituary; + newa->HitObituary = HitObituary; + newa->DeathHeight = DeathHeight; + newa->BurnHeight = BurnHeight; + newa->BloodColor = BloodColor; + newa->GibHealth = GibHealth; + newa->WoundHealth = WoundHealth; + newa->PoisonDamage = PoisonDamage; + newa->FastSpeed = FastSpeed; + newa->RDFactor = RDFactor; + newa->CameraHeight = CameraHeight; + newa->HowlSound = HowlSound; + newa->BloodType = BloodType; + newa->BloodType2 = BloodType2; + newa->BloodType3 = BloodType3; + + newa->DropItems = DropItems; + + newa->DontHurtShooter = DontHurtShooter; + newa->ExplosionRadius = ExplosionRadius; + newa->ExplosionDamage = ExplosionDamage; + newa->MeleeDamage = MeleeDamage; + newa->MeleeSound = MeleeSound; + newa->MissileName = MissileName; + newa->MissileHeight = MissileHeight; +} + +//========================================================================== +// +// PClassActor :: PropagateMark +// +//========================================================================== + +size_t PClassActor::PropagateMark() +{ + // Mark state functions + for (int i = 0; i < NumOwnedStates; ++i) + { + if (OwnedStates[i].ActionFunc != NULL) + { + GC::Mark(OwnedStates[i].ActionFunc); + } + } + // Mark damage function + if (Defaults != NULL) + { + GC::Mark(((AActor *)Defaults)->Damage); + } + +// marked += ActorInfo->NumOwnedStates * sizeof(FState); + return Super::PropagateMark(); +} + +//========================================================================== +// +// PClassActor :: InitializeNativeDefaults +// +// This is used by DECORATE to assign ActorInfos to internal classes +// +//========================================================================== + +void PClassActor::InitializeNativeDefaults() +{ + Symbols.SetParentTable(&ParentClass->Symbols); + assert(Defaults == NULL); + Defaults = new BYTE[Size]; + if (ParentClass->Defaults != NULL) + { + memcpy(Defaults, ParentClass->Defaults, ParentClass->Size); + if (Size > ParentClass->Size) + { + memset(Defaults + ParentClass->Size, 0, Size - ParentClass->Size); + } + } + else + { + memset (Defaults, 0, Size); + } +} + +//========================================================================== +// +// PClassActor :: RegisterIDs +// +// Registers this class's SpawnID and DoomEdNum in the appropriate tables. +// +//========================================================================== + +void PClassActor::RegisterIDs() +{ + PClassActor *cls = PClass::FindActor(TypeName); + + if (cls == NULL) + { + Printf(TEXTCOLOR_RED"The actor '%s' has been hidden by a non-actor of the same name\n", TypeName.GetChars()); + return; + } // Conversation IDs have never been filtered by game so we cannot start doing that. if (ConversationID > 0) { StrifeTypes[ConversationID] = cls; - if (cls != Class) + if (cls != this) { Printf(TEXTCOLOR_RED"Conversation ID %d refers to hidden class type '%s'\n", SpawnID, cls->TypeName.GetChars()); } @@ -170,7 +368,7 @@ void FActorInfo::RegisterIDs () if (SpawnID > 0) { SpawnableThings[SpawnID] = cls; - if (cls != Class) + if (cls != this) { Printf(TEXTCOLOR_RED"Spawn ID %d refers to hidden class type '%s'\n", SpawnID, cls->TypeName.GetChars()); } @@ -187,7 +385,7 @@ void FActorInfo::RegisterIDs () ent.Type = cls; ent.Special = -2; // use -2 instead of -1 so that we can recognize DECORATE defined entries and print a warning message if duplicates occur. DoomEdMap.Insert(DoomEdNum, ent); - if (cls != Class) + if (cls != this) { Printf(TEXTCOLOR_RED"Editor number %d refers to hidden class type '%s'\n", DoomEdNum, cls->TypeName.GetChars()); } @@ -197,24 +395,25 @@ void FActorInfo::RegisterIDs () //========================================================================== // +// PClassActor :: GetReplacement // //========================================================================== -FActorInfo *FActorInfo::GetReplacement (bool lookskill) +PClassActor *PClassActor::GetReplacement(bool lookskill) { FName skillrepname; if (lookskill && AllSkills.Size() > (unsigned)gameskill) { - skillrepname = AllSkills[gameskill].GetReplacement(this->Class->TypeName); + skillrepname = AllSkills[gameskill].GetReplacement(TypeName); if (skillrepname != NAME_None && PClass::FindClass(skillrepname) == NULL) { Printf("Warning: incorrect actor name in definition of skill %s: \n" "class %s is replaced by non-existent class %s\n" "Skill replacement will be ignored for this actor.\n", AllSkills[gameskill].Name.GetChars(), - this->Class->TypeName.GetChars(), skillrepname.GetChars()); - AllSkills[gameskill].SetReplacement(this->Class->TypeName, NAME_None); + TypeName.GetChars(), skillrepname.GetChars()); + AllSkills[gameskill].SetReplacement(TypeName, NAME_None); AllSkills[gameskill].SetReplacedBy(skillrepname, NAME_None); lookskill = false; skillrepname = NAME_None; } @@ -225,15 +424,15 @@ FActorInfo *FActorInfo::GetReplacement (bool lookskill) } // The Replacement field is temporarily NULLed to prevent // potential infinite recursion. - FActorInfo *savedrep = Replacement; + PClassActor *savedrep = Replacement; Replacement = NULL; - FActorInfo *rep = savedrep; + PClassActor *rep = savedrep; // Handle skill-based replacement here. It has precedence on DECORATE replacement // in that the skill replacement is applied first, followed by DECORATE replacement // on the actor indicated by the skill replacement. if (lookskill && (skillrepname != NAME_None)) { - rep = PClass::FindClass(skillrepname)->ActorInfo; + rep = PClass::FindActor(skillrepname); } // Now handle DECORATE replacement chain // Skill replacements are not recursive, contrarily to DECORATE replacements @@ -245,24 +444,25 @@ FActorInfo *FActorInfo::GetReplacement (bool lookskill) //========================================================================== // +// PClassActor :: GetReplacee // //========================================================================== -FActorInfo *FActorInfo::GetReplacee (bool lookskill) +PClassActor *PClassActor::GetReplacee(bool lookskill) { FName skillrepname; if (lookskill && AllSkills.Size() > (unsigned)gameskill) { - skillrepname = AllSkills[gameskill].GetReplacedBy(this->Class->TypeName); + skillrepname = AllSkills[gameskill].GetReplacedBy(TypeName); if (skillrepname != NAME_None && PClass::FindClass(skillrepname) == NULL) { Printf("Warning: incorrect actor name in definition of skill %s: \n" "non-existent class %s is replaced by class %s\n" "Skill replacement will be ignored for this actor.\n", AllSkills[gameskill].Name.GetChars(), - skillrepname.GetChars(), this->Class->TypeName.GetChars()); - AllSkills[gameskill].SetReplacedBy(this->Class->TypeName, NAME_None); + skillrepname.GetChars(), TypeName.GetChars()); + AllSkills[gameskill].SetReplacedBy(TypeName, NAME_None); AllSkills[gameskill].SetReplacement(skillrepname, NAME_None); lookskill = false; } @@ -273,23 +473,25 @@ FActorInfo *FActorInfo::GetReplacee (bool lookskill) } // The Replacee field is temporarily NULLed to prevent // potential infinite recursion. - FActorInfo *savedrep = Replacee; + PClassActor *savedrep = Replacee; Replacee = NULL; - FActorInfo *rep = savedrep; + PClassActor *rep = savedrep; if (lookskill && (skillrepname != NAME_None) && (PClass::FindClass(skillrepname) != NULL)) { - rep = PClass::FindClass(skillrepname)->ActorInfo; + rep = PClass::FindActor(skillrepname); } - rep = rep->GetReplacee (false); Replacee = savedrep; + rep = rep->GetReplacee(false); + Replacee = savedrep; return rep; } //========================================================================== // +// PClassActor :: SetDamageFactor // //========================================================================== -void FActorInfo::SetDamageFactor(FName type, fixed_t factor) +void PClassActor::SetDamageFactor(FName type, fixed_t factor) { if (DamageFactors == NULL) { @@ -300,78 +502,23 @@ void FActorInfo::SetDamageFactor(FName type, fixed_t factor) //========================================================================== // +// PClassActor :: SetPainChance // //========================================================================== -void FActorInfo::SetPainChance(FName type, int chance) +void PClassActor::SetPainChance(FName type, int chance) { if (chance >= 0) { - if (PainChances == NULL) PainChances=new PainChanceList; + if (PainChances == NULL) + { + PainChances = new PainChanceList; + } PainChances->Insert(type, MIN(chance, 256)); } - else + else if (PainChances != NULL) { - if (PainChances != NULL) - PainChances->Remove(type); - } -} - -//========================================================================== -// -// -//========================================================================== - -void FActorInfo::SetPainFlash(FName type, PalEntry color) -{ - if (PainFlashes == NULL) - PainFlashes = new PainFlashList; - - PainFlashes->Insert(type, color); -} - -//========================================================================== -// -// -//========================================================================== - -bool FActorInfo::GetPainFlash(FName type, PalEntry *color) const -{ - const FActorInfo *info = this; - - while (info != NULL) - { - if (info->PainFlashes != NULL) - { - PalEntry *flash = info->PainFlashes->CheckKey(type); - if (flash != NULL) - { - *color = *flash; - return true; - } - } - // Try parent class - info = info->Class->ParentClass->ActorInfo; - } - return false; -} - -//========================================================================== -// -// -//========================================================================== - -void FActorInfo::SetColorSet(int index, const FPlayerColorSet *set) -{ - if (set != NULL) - { - if (ColorSets == NULL) ColorSets = new FPlayerColorSetMap; - ColorSets->Insert(index, *set); - } - else - { - if (ColorSets != NULL) - ColorSets->Remove(index); + PainChances->Remove(type); } } @@ -401,24 +548,23 @@ static void SummonActor (int command, int command2, FCommandLine argv) if (argv.argc() > 1) { - const PClass *type = PClass::FindClass (argv[1]); + PClassActor *type = PClass::FindActor(argv[1]); if (type == NULL) { - Printf ("Unknown class '%s'\n", argv[1]); + Printf ("Unknown actor '%s'\n", argv[1]); return; } Net_WriteByte (argv.argc() > 2 ? command2 : command); Net_WriteString (type->TypeName.GetChars()); - if (argv.argc () > 2) { + if (argv.argc () > 2) + { Net_WriteWord (atoi (argv[2])); // angle - if (argv.argc () > 3) Net_WriteWord (atoi (argv[3])); // TID - else Net_WriteWord (0); - if (argv.argc () > 4) Net_WriteByte (atoi (argv[4])); // special - else Net_WriteByte (0); - for(int i = 5; i < 10; i++) { // args[5] - if(i < argv.argc()) Net_WriteLong (atoi (argv[i])); - else Net_WriteLong (0); + Net_WriteWord ((argv.argc() > 3) ? atoi(argv[3]) : 0); // TID + Net_WriteByte ((argv.argc() > 4) ? atoi(argv[4]) : 0); // special + for (int i = 5; i < 10; i++) + { // args[5] + Net_WriteLong((i < argv.argc()) ? atoi(argv[i]) : 0); } } } diff --git a/src/info.h b/src/info.h index 22e3b2f5cd..b567bd05a0 100644 --- a/src/info.h +++ b/src/info.h @@ -43,6 +43,8 @@ #include "dobject.h" #include "doomdef.h" +#include "vm.h" +#include "s_sound.h" #include "m_fixed.h" #include "m_random.h" @@ -63,7 +65,7 @@ enum struct FState { FState *NextState; - actionf_p ActionFunc; + VMFunction *ActionFunc; WORD sprite; SWORD Tics; WORD TicRange; @@ -78,7 +80,6 @@ struct FState BYTE NoDelay:1; // Spawn states executes its action normally BYTE CanRaise:1; // Allows a monster to be resurrected without waiting for an infinate frame BYTE Slow:1; // Inverse of fast - int ParameterIndex; inline int GetFrame() const { @@ -124,33 +125,10 @@ struct FState { Frame = frame - 'A'; } - void SetAction(PSymbolActionFunction *func, bool setdefaultparams = true) - { - if (func != NULL) - { - ActionFunc = func->Function; - if (setdefaultparams) ParameterIndex = func->defaultparameterindex+1; - } - else - { - ActionFunc = NULL; - if (setdefaultparams) ParameterIndex = 0; - } - } - inline bool CallAction(AActor *self, AActor *stateowner, StateCallData *statecall = NULL) - { - if (ActionFunc != NULL) - { - ActionFunc(self, stateowner, this, ParameterIndex-1, statecall); - return true; - } - else - { - return false; - } - } - static const PClass *StaticFindStateOwner (const FState *state); - static const PClass *StaticFindStateOwner (const FState *state, const FActorInfo *info); + void SetAction(VMFunction *func) { ActionFunc = func; } + bool CallAction(AActor *self, AActor *stateowner); + static PClassActor *StaticFindStateOwner (const FState *state); + static PClassActor *StaticFindStateOwner (const FState *state, PClassActor *info); static FRandom pr_statetics; }; @@ -178,35 +156,11 @@ FArchive &operator<< (FArchive &arc, FState *&state); #include "gametype.h" -// Standard pre-defined skin colors -struct FPlayerColorSet -{ - struct ExtraRange - { - BYTE RangeStart, RangeEnd; // colors to remap - BYTE FirstColor, LastColor; // colors to map to - }; - - FName Name; // Name of this color - - int Lump; // Lump to read the translation from, otherwise use next 2 fields - BYTE FirstColor, LastColor; // Describes the range of colors to use for the translation - - BYTE RepresentativeColor; // A palette entry representative of this translation, - // for map arrows and status bar backgrounds and such - BYTE NumExtraRanges; - ExtraRange Extra[6]; -}; - struct DmgFactors : public TMap { fixed_t *CheckFactor(FName type); }; typedef TMap PainChanceList; -typedef TMap PainFlashList; -typedef TMap FPlayerColorSetMap; - - struct DamageTypeDefinition { @@ -230,24 +184,33 @@ public: static int ApplyMobjDamageFactor(int damage, FName type, DmgFactors const * const factors); }; +class DDropItem; +class PClassPlayerPawn; -struct FActorInfo +class PClassActor : public PClass { + DECLARE_CLASS(PClassActor, PClass); + HAS_OBJECT_POINTERS; +protected: + virtual void Derive(PClass *newclass); +public: static void StaticInit (); static void StaticSetActorNums (); - void BuildDefaults (); - void ApplyDefaults (BYTE *defaults); - void RegisterIDs (); + PClassActor(); + ~PClassActor(); + + void BuildDefaults(); + void ApplyDefaults(BYTE *defaults); + void RegisterIDs(); void SetDamageFactor(FName type, fixed_t factor); void SetPainChance(FName type, int chance); - void SetPainFlash(FName type, PalEntry color); - bool GetPainFlash(FName type, PalEntry *color) const; - void SetColorSet(int index, const FPlayerColorSet *set); + size_t PropagateMark(); + void InitializeNativeDefaults(); - FState *FindState (int numnames, FName *names, bool exact=false) const; + FState *FindState(int numnames, FName *names, bool exact=false) const; FState *FindStateByString(const char *name, bool exact=false); - FState *FindState (FName name) const + FState *FindState(FName name) const { return FindState(1, &name); } @@ -257,13 +220,12 @@ struct FActorInfo return state >= OwnedStates && state < OwnedStates + NumOwnedStates; } - FActorInfo *GetReplacement (bool lookskill=true); - FActorInfo *GetReplacee (bool lookskill=true); + PClassActor *GetReplacement(bool lookskill=true); + PClassActor *GetReplacee(bool lookskill=true); - PClass *Class; FState *OwnedStates; - FActorInfo *Replacement; - FActorInfo *Replacee; + PClassActor *Replacement; + PClassActor *Replacee; int NumOwnedStates; BYTE GameFilter; WORD SpawnID; @@ -272,16 +234,51 @@ struct FActorInfo FStateLabels *StateList; DmgFactors *DamageFactors; PainChanceList *PainChances; - PainFlashList *PainFlashes; - FPlayerColorSetMap *ColorSets; - TArray VisibleToPlayerClass; - TArray RestrictedToPlayerClass; - TArray ForbiddenToPlayerClass; + + TArray VisibleToPlayerClass; + TArray RestrictedToPlayerClass; + TArray ForbiddenToPlayerClass; + + FString Obituary; // Player was killed by this actor + FString HitObituary; // Player was killed by this actor in melee + fixed_t DeathHeight; // Height on normal death + fixed_t BurnHeight; // Height on burning death + PalEntry BloodColor; // Colorized blood + int GibHealth; // Negative health below which this monster dies an extreme death + int WoundHealth; // Health needed to enter wound state + int PoisonDamage; // Amount of poison damage + fixed_t FastSpeed; // Speed in fast mode + fixed_t RDFactor; // Radius damage factor + fixed_t CameraHeight; // Height of camera when used as such + FSoundID HowlSound; // Sound being played when electrocuted or poisoned + FName BloodType; // Blood replacement type + FName BloodType2; // Bloopsplatter replacement type + FName BloodType3; // AxeBlood replacement type + + DDropItem *DropItems; + FString SourceLumpName; + + // Old Decorate compatibility stuff + bool DontHurtShooter; + int ExplosionRadius; + int ExplosionDamage; + int MeleeDamage; + FSoundID MeleeSound; + FName MissileName; + fixed_t MissileHeight; + + // For those times when being able to scan every kind of actor is convenient + static TArray AllActorClasses; }; +inline PClassActor *PClass::FindActor(FName name) +{ + return dyn_cast(FindClass(name)); +} + struct FDoomEdEntry { - const PClass *Type; + PClassActor *Type; short Special; signed char ArgsDefined; int Args[5]; @@ -328,4 +325,19 @@ int GetSpriteIndex(const char * spritename, bool add = true); TArray &MakeStateNameList(const char * fname); void AddStateLight(FState *state, const char *lname); +// Standard parameters for all action functons +// self - Actor this action is to operate on (player if a weapon) +// stateowner - Actor this action really belongs to (may be an item) +// callingstate - State this action was called from +#define PARAM_ACTION_PROLOGUE_TYPE(type) \ + PARAM_PROLOGUE; \ + PARAM_OBJECT (self, type); \ + PARAM_OBJECT_OPT (stateowner, AActor) { stateowner = self; } \ + PARAM_STATE_OPT (callingstate) { callingstate = NULL; } \ + +#define PARAM_ACTION_PROLOGUE PARAM_ACTION_PROLOGUE_TYPE(AActor) + +// Number of action paramaters +#define NAP 3 + #endif // __INFO_H__ diff --git a/src/intermission/intermission.cpp b/src/intermission/intermission.cpp index 1dc4b2f1aa..220fab0d95 100644 --- a/src/intermission/intermission.cpp +++ b/src/intermission/intermission.cpp @@ -409,7 +409,7 @@ void DIntermissionScreenCast::Init(FIntermissionAction *desc, bool first) { Super::Init(desc, first); mName = static_cast(desc)->mName; - mClass = PClass::FindClass(static_cast(desc)->mCastClass); + mClass = PClass::FindActor(static_cast(desc)->mCastClass); if (mClass != NULL) mDefaults = GetDefaultByType(mClass); else { @@ -463,7 +463,7 @@ int DIntermissionScreenCast::Responder (event_t *ev) if (mClass != NULL) { FName label[] = {NAME_Death, NAME_Cast}; - caststate = mClass->ActorInfo->FindState(2, label); + caststate = mClass->FindState(2, label); if (caststate == NULL) return -1; casttics = caststate->GetTics(); diff --git a/src/intermission/intermission.h b/src/intermission/intermission.h index dc562c4c5c..8db02c4797 100644 --- a/src/intermission/intermission.h +++ b/src/intermission/intermission.h @@ -229,7 +229,7 @@ class DIntermissionScreenCast : public DIntermissionScreen DECLARE_CLASS (DIntermissionScreenCast, DIntermissionScreen) const char *mName; - const PClass *mClass; + PClassActor *mClass; AActor *mDefaults; TArray mCastSounds; diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index 1d80f13f26..c6bb677b53 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -53,7 +53,7 @@ void cht_DoCheat (player_t *player, int cheat) { - static const char * BeholdPowers[9] = + static const char * const BeholdPowers[9] = { "PowerInvulnerable", "PowerStrength", @@ -65,7 +65,7 @@ void cht_DoCheat (player_t *player, int cheat) "PowerMask", "PowerTargeter", }; - const PClass *type; + PClassActor *type; AInventory *item; const char *msg = ""; char msgbuild[32]; @@ -167,7 +167,7 @@ void cht_DoCheat (player_t *player, int cheat) break; case CHT_MORPH: - msg = cht_Morph (player, PClass::FindClass (gameinfo.gametype == GAME_Heretic ? NAME_ChickenPlayer : NAME_PigPlayer), true); + msg = cht_Morph (player, static_cast(PClass::FindClass (gameinfo.gametype == GAME_Heretic ? NAME_ChickenPlayer : NAME_PigPlayer)), true); break; case CHT_NOTARGET: @@ -198,7 +198,7 @@ void cht_DoCheat (player_t *player, int cheat) case CHT_CHAINSAW: if (player->mo != NULL && player->health >= 0) { - type = PClass::FindClass ("Chainsaw"); + type = PClass::FindActor("Chainsaw"); if (player->mo->FindInventory (type) == NULL) { player->mo->GiveInventoryType (type); @@ -262,7 +262,7 @@ void cht_DoCheat (player_t *player, int cheat) } else if (player->mo != NULL && player->health >= 0) { - item = player->mo->FindInventory (BeholdPowers[i]); + item = player->mo->FindInventory(PClass::FindActor(BeholdPowers[i])); if (item == NULL) { if (i != 0) @@ -543,13 +543,13 @@ void cht_DoCheat (player_t *player, int cheat) Printf ("%s cheats: %s\n", player->userinfo.GetName(), msg); } -const char *cht_Morph (player_t *player, const PClass *morphclass, bool quickundo) +const char *cht_Morph (player_t *player, PClassPlayerPawn *morphclass, bool quickundo) { if (player->mo == NULL) { return ""; } - PClass *oldclass = player->mo->GetClass(); + PClassPlayerPawn *oldclass = player->mo->GetClass(); // Set the standard morph style for the current game int style = MORPH_UNDOBYTOMEOFPOWER; @@ -573,7 +573,7 @@ const char *cht_Morph (player_t *player, const PClass *morphclass, bool quickund return ""; } -void GiveSpawner (player_t *player, const PClass *type, int amount) +void GiveSpawner (player_t *player, PClassInventory *type, int amount) { if (player->mo == NULL || player->health <= 0) { @@ -618,7 +618,7 @@ void cht_Give (player_t *player, const char *name, int amount) { enum { ALL_NO, ALL_YES, ALL_YESYES } giveall; int i; - const PClass *type; + PClassActor *type; if (player != &players[consoleplayer]) Printf ("%s is a cheater: give %s\n", player->userinfo.GetName(), name); @@ -668,10 +668,10 @@ void cht_Give (player_t *player, const char *name, int amount) if (giveall || stricmp (name, "backpack") == 0) { // Select the correct type of backpack based on the game - type = PClass::FindClass(gameinfo.backpacktype); + type = PClass::FindActor(gameinfo.backpacktype); if (type != NULL) { - GiveSpawner (player, type, 1); + GiveSpawner (player, static_cast(type), 1); } if (!giveall) @@ -682,16 +682,17 @@ void cht_Give (player_t *player, const char *name, int amount) { // Find every unique type of ammo. Give it to the player if // he doesn't have it already, and set each to its maximum. - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - const PClass *type = PClass::m_Types[i]; + PClassActor *type = PClassActor::AllActorClasses[i]; if (type->ParentClass == RUNTIME_CLASS(AAmmo)) { - AInventory *ammo = player->mo->FindInventory (type); + PClassAmmo *atype = static_cast(type); + AInventory *ammo = player->mo->FindInventory(atype); if (ammo == NULL) { - ammo = static_cast(Spawn (type, 0, 0, 0, NO_REPLACE)); + ammo = static_cast(Spawn (atype, 0, 0, 0, NO_REPLACE)); ammo->AttachToOwner (player->mo); ammo->Amount = ammo->MaxAmount; } @@ -738,14 +739,14 @@ void cht_Give (player_t *player, const char *name, int amount) if (giveall || stricmp (name, "keys") == 0) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - if (PClass::m_Types[i]->IsDescendantOf (RUNTIME_CLASS(AKey))) + if (PClassActor::AllActorClasses[i]->IsDescendantOf (RUNTIME_CLASS(AKey))) { - AKey *key = (AKey *)GetDefaultByType (PClass::m_Types[i]); + AKey *key = (AKey *)GetDefaultByType (PClassActor::AllActorClasses[i]); if (key->KeyNumber != 0) { - key = static_cast(Spawn (PClass::m_Types[i], 0,0,0, NO_REPLACE)); + key = static_cast(Spawn(static_cast(PClassActor::AllActorClasses[i]), 0,0,0, NO_REPLACE)); if (!key->CallTryPickup (player->mo)) { key->Destroy (); @@ -760,23 +761,22 @@ void cht_Give (player_t *player, const char *name, int amount) if (giveall || stricmp (name, "weapons") == 0) { AWeapon *savedpending = player->PendingWeapon; - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - type = PClass::m_Types[i]; + type = PClassActor::AllActorClasses[i]; // Don't give replaced weapons unless the replacement was done by Dehacked. if (type != RUNTIME_CLASS(AWeapon) && type->IsDescendantOf (RUNTIME_CLASS(AWeapon)) && - (type->GetReplacement() == type || - type->GetReplacement()->IsDescendantOf(RUNTIME_CLASS(ADehackedPickup)))) - + (static_cast(type)->GetReplacement() == type || + static_cast(type)->GetReplacement()->IsDescendantOf(RUNTIME_CLASS(ADehackedPickup)))) { - // Give the weapon only if it is in a weapon slot. - if (player->weapons.LocateWeapon(type, NULL, NULL)) + // Give the weapon only if it belongs to the current game or + if (player->weapons.LocateWeapon(static_cast(type), NULL, NULL)) { AWeapon *def = (AWeapon*)GetDefaultByType (type); if (giveall == ALL_YESYES || !(def->WeaponFlags & WIF_CHEATNOTWEAPON)) { - GiveSpawner (player, type, 1); + GiveSpawner (player, static_cast(type), 1); } } } @@ -789,9 +789,9 @@ void cht_Give (player_t *player, const char *name, int amount) if (giveall || stricmp (name, "artifacts") == 0) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - type = PClass::m_Types[i]; + type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS(AInventory))) { AInventory *def = (AInventory*)GetDefaultByType (type); @@ -803,7 +803,7 @@ void cht_Give (player_t *player, const char *name, int amount) // Do not give replaced items unless using "give everything" if (giveall == ALL_YESYES || type->GetReplacement() == type) { - GiveSpawner (player, type, amount <= 0 ? def->MaxAmount : amount); + GiveSpawner (player, static_cast(type), amount <= 0 ? def->MaxAmount : amount); } } } @@ -814,9 +814,9 @@ void cht_Give (player_t *player, const char *name, int amount) if (giveall || stricmp (name, "puzzlepieces") == 0) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - type = PClass::m_Types[i]; + type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS(APuzzleItem))) { AInventory *def = (AInventory*)GetDefaultByType (type); @@ -825,7 +825,7 @@ void cht_Give (player_t *player, const char *name, int amount) // Do not give replaced items unless using "give everything" if (giveall == ALL_YESYES || type->GetReplacement() == type) { - GiveSpawner (player, type, amount <= 0 ? def->MaxAmount : amount); + GiveSpawner (player, static_cast(type), amount <= 0 ? def->MaxAmount : amount); } } } @@ -837,7 +837,7 @@ void cht_Give (player_t *player, const char *name, int amount) if (giveall) return; - type = PClass::FindClass (name); + type = PClass::FindActor(name); if (type == NULL || !type->IsDescendantOf (RUNTIME_CLASS(AInventory))) { if (player == &players[consoleplayer]) @@ -845,7 +845,7 @@ void cht_Give (player_t *player, const char *name, int amount) } else { - GiveSpawner (player, type, amount); + GiveSpawner (player, static_cast(type), amount); } return; } @@ -853,7 +853,7 @@ void cht_Give (player_t *player, const char *name, int amount) void cht_Take (player_t *player, const char *name, int amount) { bool takeall; - const PClass *type; + PClassActor *type; if (player->mo == NULL || player->health <= 0) { @@ -897,15 +897,16 @@ void cht_Take (player_t *player, const char *name, int amount) if (takeall || stricmp (name, "backpack") == 0) { // Take away all types of backpacks the player might own. - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - const PClass *type = PClass::m_Types[i]; + PClass *type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf(RUNTIME_CLASS (ABackpackItem))) { - AInventory *pack = player->mo->FindInventory (type); + AInventory *pack = player->mo->FindInventory(static_cast(type)); - if (pack) pack->Destroy(); + if (pack) + pack->Destroy(); } } @@ -915,13 +916,13 @@ void cht_Take (player_t *player, const char *name, int amount) if (takeall || stricmp (name, "ammo") == 0) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - const PClass *type = PClass::m_Types[i]; + PClass *type = PClassActor::AllActorClasses[i]; if (type->ParentClass == RUNTIME_CLASS (AAmmo)) { - AInventory *ammo = player->mo->FindInventory (type); + AInventory *ammo = player->mo->FindInventory(static_cast(type)); if (ammo) ammo->Amount = 0; @@ -934,13 +935,13 @@ void cht_Take (player_t *player, const char *name, int amount) if (takeall || stricmp (name, "armor") == 0) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - type = PClass::m_Types[i]; + type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS (AArmor))) { - AActor *armor = player->mo->FindInventory (type); + AActor *armor = player->mo->FindInventory(static_cast(type)); if (armor) armor->Destroy (); @@ -953,13 +954,13 @@ void cht_Take (player_t *player, const char *name, int amount) if (takeall || stricmp (name, "keys") == 0) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - type = PClass::m_Types[i]; + type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS (AKey))) { - AActor *key = player->mo->FindInventory (type); + AActor *key = player->mo->FindInventory(static_cast(type)); if (key) key->Destroy (); @@ -972,14 +973,14 @@ void cht_Take (player_t *player, const char *name, int amount) if (takeall || stricmp (name, "weapons") == 0) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - type = PClass::m_Types[i]; + type = PClassActor::AllActorClasses[i]; if (type != RUNTIME_CLASS(AWeapon) && type->IsDescendantOf (RUNTIME_CLASS (AWeapon))) { - AActor *weapon = player->mo->FindInventory (type); + AActor *weapon = player->mo->FindInventory(static_cast(type)); if (weapon) weapon->Destroy (); @@ -997,9 +998,9 @@ void cht_Take (player_t *player, const char *name, int amount) if (takeall || stricmp (name, "artifacts") == 0) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - type = PClass::m_Types[i]; + type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS (AInventory))) { @@ -1009,7 +1010,7 @@ void cht_Take (player_t *player, const char *name, int amount) !type->IsDescendantOf (RUNTIME_CLASS (AWeapon)) && !type->IsDescendantOf (RUNTIME_CLASS (AKey))) { - AActor *artifact = player->mo->FindInventory (type); + AActor *artifact = player->mo->FindInventory(static_cast(type)); if (artifact) artifact->Destroy (); @@ -1023,13 +1024,13 @@ void cht_Take (player_t *player, const char *name, int amount) if (takeall || stricmp (name, "puzzlepieces") == 0) { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - type = PClass::m_Types[i]; + type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS (APuzzleItem))) { - AActor *puzzlepiece = player->mo->FindInventory (type); + AActor *puzzlepiece = player->mo->FindInventory(static_cast(type)); if (puzzlepiece) puzzlepiece->Destroy (); @@ -1043,7 +1044,7 @@ void cht_Take (player_t *player, const char *name, int amount) if (takeall) return; - type = PClass::FindClass (name); + type = PClass::FindActor (name); if (type == NULL || !type->IsDescendantOf (RUNTIME_CLASS (AInventory))) { if (player == &players[consoleplayer]) diff --git a/src/m_cheat.h b/src/m_cheat.h index d273965ae8..9480b33721 100644 --- a/src/m_cheat.h +++ b/src/m_cheat.h @@ -29,11 +29,12 @@ // [RH] Functions that actually perform the cheating class player_t; -struct PClass; +class PClassPlayerPawn; + void cht_DoCheat (player_t *player, int cheat); void cht_Give (player_t *player, const char *item, int amount=1); void cht_Take (player_t *player, const char *item, int amount=1); void cht_Suicide (player_t *player); -const char *cht_Morph (player_t *player, const PClass *morphclass, bool quickundo); +const char *cht_Morph (player_t *player, PClassPlayerPawn *morphclass, bool quickundo); #endif diff --git a/src/m_fixed.h b/src/m_fixed.h index 71b3981241..e7ced58e36 100644 --- a/src/m_fixed.h +++ b/src/m_fixed.h @@ -137,7 +137,7 @@ inline SDWORD ModDiv (SDWORD num, SDWORD den, SDWORD *dmval) } -#define FLOAT2FIXED(f) xs_Fix<16>::ToFix(f) +#define FLOAT2FIXED(f) ((fixed_t)xs_Fix<16>::ToFix(f)) #define FIXED2FLOAT(f) ((f) / float(65536)) #define FIXED2DBL(f) ((f) / double(65536)) diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index d01f0807f3..c3fb46c0e5 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -352,7 +352,7 @@ void M_SetMenu(FName menu, int param) GameStartupInfo.Episode = -1; GameStartupInfo.PlayerClass = param == -1000? NULL : - param == -1? "Random" : GetPrintableDisplayName(PlayerClasses[param].Type); + param == -1? "Random" : GetPrintableDisplayName(PlayerClasses[param].Type).GetChars(); break; case NAME_Skillmenu: diff --git a/src/menu/playerdisplay.cpp b/src/menu/playerdisplay.cpp index 26e6d3b96a..30e320de9b 100644 --- a/src/menu/playerdisplay.cpp +++ b/src/menu/playerdisplay.cpp @@ -413,8 +413,7 @@ void FListMenuItemPlayerDisplay::UpdateTranslation() if (mPlayerClass != NULL) { PlayerSkin = R_FindSkin (skins[PlayerSkin].name, int(mPlayerClass - &PlayerClasses[0])); - R_GetPlayerTranslation(PlayerColor, - P_GetPlayerColorSet(mPlayerClass->Type->TypeName, PlayerColorset), + R_GetPlayerTranslation(PlayerColor, mPlayerClass->Type->GetColorSet(PlayerColorset), &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); } } @@ -536,9 +535,9 @@ void FListMenuItemPlayerDisplay::Drawer(bool selected) return; } - const char *portrait = mPlayerClass->Type->Meta.GetMetaString(APMETA_Portrait); + FString portrait = mPlayerClass->Type->Portrait; - if (portrait != NULL && !mNoportrait) + if (portrait.IsNotEmpty() && !mNoportrait) { FTextureID texid = TexMan.CheckForTexture(portrait, FTexture::TEX_MiscPatch); if (texid.isValid()) diff --git a/src/menu/playermenu.cpp b/src/menu/playermenu.cpp index e6e25b3947..a716d98f19 100644 --- a/src/menu/playermenu.cpp +++ b/src/menu/playermenu.cpp @@ -687,8 +687,7 @@ void DPlayerMenu::UpdateTranslation() if (PlayerClass != NULL) { PlayerSkin = R_FindSkin (skins[PlayerSkin].name, int(PlayerClass - &PlayerClasses[0])); - R_GetPlayerTranslation(PlayerColor, - P_GetPlayerColorSet(PlayerClass->Type->TypeName, PlayerColorset), + R_GetPlayerTranslation(PlayerColor, PlayerClass->Type->GetColorSet(PlayerColorset), &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); } } @@ -757,11 +756,11 @@ void DPlayerMenu::UpdateColorsets() if (li != NULL) { int sel = 0; - P_EnumPlayerColorSets(PlayerClass->Type->TypeName, &PlayerColorSets); + PlayerClass->Type->EnumColorSets(&PlayerColorSets); li->SetString(0, "Custom"); for(unsigned i=0;iType->TypeName, PlayerColorSets[i]); + FPlayerColorSet *colorset = PlayerClass->Type->GetColorSet(PlayerColorSets[i]); li->SetString(i+1, colorset->Name); } int mycolorset = players[consoleplayer].userinfo.GetColorSet(); @@ -907,7 +906,7 @@ void DPlayerMenu::ClassChanged (FListMenuItem *li) players[consoleplayer].userinfo.PlayerClassNumChanged(gameinfo.norandomplayerclass ? sel : sel-1); PickPlayerClass(); - cvar_set ("playerclass", sel == 0 && !gameinfo.norandomplayerclass ? "Random" : PlayerClass->Type->Meta.GetMetaString (APMETA_DisplayName)); + cvar_set ("playerclass", sel == 0 && !gameinfo.norandomplayerclass ? "Random" : PlayerClass->Type->DisplayName.GetChars()); UpdateSkins(); UpdateColorsets(); diff --git a/src/name.cpp b/src/name.cpp index 36cce25955..5ab361d42f 100644 --- a/src/name.cpp +++ b/src/name.cpp @@ -182,6 +182,7 @@ void FName::NameManager::InitBuckets () // Register built-in names. 'None' must be name 0. for (size_t i = 0; i < countof(PredefinedNames); ++i) { + assert((NULL == FindName(PredefinedNames[i], true)) && "Predefined name already inserted"); FindName (PredefinedNames[i], false); } } diff --git a/src/namedef.h b/src/namedef.h index ae456883cb..d06ca9ccc5 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -5,6 +5,8 @@ xx(Null) xx(Super) xx(Object) xx(Actor) +xx(Class) +xx(ClassClass) xx(Untranslated) @@ -305,6 +307,16 @@ xx(Sqrt) xx(CheckClass) xx(IsPointerEqual) xx(Pick) +xx(Mass) +xx(VelX) +xx(VelY) +xx(VelZ) +xx(Accuracy) +xx(Stamina) +xx(Radius) +xx(ReactionTime) +xx(MeleeRange) +xx(Speed) // Various actor names which are used internally xx(MapSpot) @@ -558,7 +570,6 @@ xx(Color) xx(Red) xx(Green) xx(Blue) -xx(Class) xx(Skin) xx(Gender) xx(Autoaim) @@ -616,3 +627,47 @@ xx(MoveBob) xx(StillBob) xx(PlayerClass) xx(Wi_NoAutostartMap) + +// Decorate compatibility functions +xx(DecoRandom) +xx(DecoFRandom) +xx(DecoCallLineSpecial) +xx(DecoNameToClass) +xx(DecoFindMultiNameState) +xx(DecoFindSingleNameState) +xx(Damage) + +// basic type names +xx(Default) +xx(sByte) +xx(Byte) +xx(Short) +xx(uShort) +xx(Int) +xx(uInt) +xx(Bool) +xx(Float) +xx(Float32) +xx(Float64) +xx(Double) +xx(String) +xx(Vector) +xx(Map) +xx(Array) +xx(Sound) +xx(State) +xx(Fixed) + +xx(Min) +xx(Max) +xx(Min_Normal) +xx(Min_Denormal) +xx(Epsilon) +xx(NaN) +xx(Infinity) +xx(Dig) +xx(Min_Exp) +xx(Max_Exp) +xx(Mant_Dig) +xx(Min_10_Exp) +xx(Max_10_Exp) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 9737f8aa97..11c57de6c7 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -1111,7 +1111,7 @@ static void ClearInventory (AActor *activator) // //============================================================================ -static void DoGiveInv (AActor *actor, const PClass *info, int amount) +static void DoGiveInv (AActor *actor, PClassActor *info, int amount) { AWeapon *savedPendingWeap = actor->player != NULL ? actor->player->PendingWeapon : NULL; @@ -1155,7 +1155,7 @@ static void DoGiveInv (AActor *actor, const PClass *info, int amount) static void GiveInventory (AActor *activator, const char *type, int amount) { - const PClass *info; + PClassActor *info; if (amount <= 0 || type == NULL) { @@ -1165,7 +1165,7 @@ static void GiveInventory (AActor *activator, const char *type, int amount) { type = "BasicArmorPickup"; } - info = PClass::FindClass (type); + info = PClass::FindActor(type); if (info == NULL) { Printf ("ACS: I don't know what %s is.\n", type); @@ -1198,7 +1198,7 @@ static void GiveInventory (AActor *activator, const char *type, int amount) static void TakeInventory (AActor *activator, const char *type, int amount) { - const PClass *info; + PClassActor *info; if (type == NULL) { @@ -1212,7 +1212,7 @@ static void TakeInventory (AActor *activator, const char *type, int amount) { return; } - info = PClass::FindClass (type); + info = PClass::FindActor (type); if (info == NULL) { return; @@ -1239,7 +1239,7 @@ static void TakeInventory (AActor *activator, const char *type, int amount) // //============================================================================ -static bool DoUseInv (AActor *actor, const PClass *info) +static bool DoUseInv (AActor *actor, PClassActor *info) { AInventory *item = actor->FindInventory (info); if (item != NULL) @@ -1274,14 +1274,14 @@ static bool DoUseInv (AActor *actor, const PClass *info) static int UseInventory (AActor *activator, const char *type) { - const PClass *info; + PClassActor *info; int ret = 0; if (type == NULL) { return 0; } - info = PClass::FindClass (type); + info = PClass::FindActor (type); if (info == NULL) { return 0; @@ -1330,7 +1330,7 @@ static int CheckInventory (AActor *activator, const char *type, bool max) return activator->health; } - const PClass *info = PClass::FindClass (type); + PClassActor *info = PClass::FindActor (type); AInventory *item = activator->FindInventory (info); if (max) @@ -3234,7 +3234,7 @@ int DLevelScript::Random (int min, int max) int DLevelScript::ThingCount (int type, int stringid, int tid, int tag) { AActor *actor; - const PClass *kind; + PClassActor *kind; int count = 0; bool replacemented = false; @@ -3250,10 +3250,9 @@ int DLevelScript::ThingCount (int type, int stringid, int tid, int tag) if (type_name == NULL) return 0; - kind = PClass::FindClass (type_name); - if (kind == NULL || kind->ActorInfo == NULL) + kind = PClass::FindActor(type_name); + if (kind == NULL) return 0; - } else { @@ -3305,7 +3304,7 @@ do_count: { // Again, with decorate replacements replacemented = true; - PClass *newkind = kind->GetReplacement(); + PClassActor *newkind = kind->GetReplacement(); if (newkind != kind) { kind = newkind; @@ -3432,7 +3431,7 @@ void DLevelScript::ReplaceTextures (int fromnamei, int tonamei, int flags) int DLevelScript::DoSpawn (int type, fixed_t x, fixed_t y, fixed_t z, int tid, int angle, bool force) { - const PClass *info = PClass::FindClass (FBehavior::StaticLookupString (type)); + PClassActor *info = PClass::FindActor(FBehavior::StaticLookupString (type)); AActor *actor = NULL; int spawncount = 0; @@ -3807,7 +3806,7 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value) break; case APROP_Damage: - actor->Damage = value; + actor->Damage = CreateDamageFunction(value); break; case APROP_Alpha: @@ -4004,7 +4003,7 @@ int DLevelScript::GetActorProperty (int tid, int property) { case APROP_Health: return actor->health; case APROP_Speed: return actor->Speed; - case APROP_Damage: return actor->Damage; // Should this call GetMissileDamage() instead? + case APROP_Damage: return actor->GetMissileDamage(0,1); case APROP_DamageFactor:return actor->DamageFactor; case APROP_DamageMultiplier: return actor->DamageMultiply; case APROP_Alpha: return actor->alpha; @@ -4406,7 +4405,7 @@ static FSoundID GetActorSound(const AActor *actor, int soundtype) case SOUND_Bounce: return actor->BounceSound; case SOUND_WallBounce: return actor->WallBounceSound; case SOUND_CrushPain: return actor->CrushPainSound; - case SOUND_Howl: return actor->GetClass()->Meta.GetMetaInt(AMETA_HowlSound); + case SOUND_Howl: return actor->GetClass()->HowlSound; default: return 0; } } @@ -4557,63 +4556,56 @@ int DLevelScript::LineFromID(int id) } } +bool GetVarAddrType(AActor *self, FName varname, int index, void *&addr, PType *&type) +{ + PField *var = dyn_cast(self->GetClass()->Symbols.FindSymbol(varname, true)); + PArray *arraytype; + BYTE *baddr = reinterpret_cast(self); + + if (var == NULL || (var->Flags & VARF_Native)) + { + return false; + } + type = var->Type; + arraytype = dyn_cast(type); + if (arraytype != NULL) + { + // unwrap contained type + type = arraytype->ElementType; + // offset by index (if in bounds) + if ((unsigned)index < arraytype->ElementCount) + { // out of bounds + return false; + } + baddr += arraytype->ElementSize * index; + } + else if (index != 0) + { // ignore attempts to set indexed values on non-arrays + return false; + } + addr = baddr; + return true; +} + static void SetUserVariable(AActor *self, FName varname, int index, int value) { - PSymbol *sym = self->GetClass()->Symbols.FindSymbol(varname, true); - int max; - PSymbolVariable *var; + void *addr; + PType *type; - if (sym == NULL || sym->SymbolType != SYM_Variable || - !(var = static_cast(sym))->bUserVar) + if (GetVarAddrType(self, varname, index, addr, type)) { - return; - } - if (var->ValueType.Type == VAL_Int) - { - max = 1; - } - else if (var->ValueType.Type == VAL_Array && var->ValueType.BaseType == VAL_Int) - { - max = var->ValueType.size; - } - else - { - return; - } - // Set the value of the specified user variable. - if (index >= 0 && index < max) - { - ((int *)(reinterpret_cast(self) + var->offset))[index] = value; + type->SetValue(addr, value); } } static int GetUserVariable(AActor *self, FName varname, int index) { - PSymbol *sym = self->GetClass()->Symbols.FindSymbol(varname, true); - int max; - PSymbolVariable *var; + void *addr; + PType *type; - if (sym == NULL || sym->SymbolType != SYM_Variable || - !(var = static_cast(sym))->bUserVar) + if (GetVarAddrType(self, varname, index, addr, type)) { - return 0; - } - if (var->ValueType.Type == VAL_Int) - { - max = 1; - } - else if (var->ValueType.Type == VAL_Array && var->ValueType.BaseType == VAL_Int) - { - max = var->ValueType.size; - } - else - { - return 0; - } - // Get the value of the specified user variable. - if (index >= 0 && index < max) - { - return ((int *)(reinterpret_cast(self) + var->offset))[index]; + return type->GetValueInt(addr); } return 0; } @@ -4851,9 +4843,9 @@ static void SetActorTeleFog(AActor *activator, int tid, FString telefogsrc, FStr if (activator != NULL) { if (telefogsrc.IsNotEmpty()) - activator->TeleFogSourceType = PClass::FindClass(telefogsrc); + activator->TeleFogSourceType = PClass::FindActor(telefogsrc); if (telefogdest.IsNotEmpty()) - activator->TeleFogDestType = PClass::FindClass(telefogdest); + activator->TeleFogDestType = PClass::FindActor(telefogdest); } } else @@ -4861,8 +4853,8 @@ static void SetActorTeleFog(AActor *activator, int tid, FString telefogsrc, FStr FActorIterator iterator(tid); AActor *actor; - const PClass *src = PClass::FindClass(telefogsrc); - const PClass * dest = PClass::FindClass(telefogdest); + PClassActor * src = PClass::FindActor(telefogsrc); + PClassActor * dest = PClass::FindActor(telefogdest); while ((actor = iterator.Next())) { if (telefogsrc.IsNotEmpty()) @@ -4998,7 +4990,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) } else { - return actor->GetClass()->Meta.GetMetaFixed(AMETA_CameraHeight, actor->height/2); + return actor->GetCameraHeight(); } } else return 0; @@ -5700,7 +5692,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) const char *type = FBehavior::StaticLookupString(args[1]); int amount = argCount >= 3? args[2] : -1; int chance = argCount >= 4? args[3] : 256; - const PClass *cls = PClass::FindClass(type); + PClassActor *cls = PClass::FindActor(type); int cnt = 0; if (cls != NULL) { @@ -5806,7 +5798,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) case ACSF_GetActorPowerupTics: if (argCount >= 2) { - const PClass *powerupclass = PClass::FindClass(FBehavior::StaticLookupString(args[1])); + PClassActor *powerupclass = PClass::FindActor(FBehavior::StaticLookupString(args[1])); if (powerupclass == NULL || !RUNTIME_CLASS(APowerup)->IsAncestorOf(powerupclass)) { Printf("'%s' is not a type of Powerup.\n", FBehavior::StaticLookupString(args[1])); @@ -5967,7 +5959,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) fixed_t radiusoffset = argCount > 9 ? args[9] : 0; fixed_t pitch = argCount > 10 ? args[10] : 0; - FState *state = argCount > 6 ? activator->GetClass()->ActorInfo->FindStateByString(statename, exact) : 0; + FState *state = argCount > 6 ? activator->GetClass()->FindStateByString(statename, exact) : 0; AActor *reference; if((flags & WARPF_USEPTR) && tid_dest != AAPTR_DEFAULT) @@ -8545,12 +8537,12 @@ scriptwait: case PCD_GETAMMOCAPACITY: if (activator != NULL) { - const PClass *type = PClass::FindClass (FBehavior::StaticLookupString (STACK(1))); + PClass *type = PClass::FindClass (FBehavior::StaticLookupString (STACK(1))); AInventory *item; if (type != NULL && type->ParentClass == RUNTIME_CLASS(AAmmo)) { - item = activator->FindInventory (type); + item = activator->FindInventory (static_cast(type)); if (item != NULL) { STACK(1) = item->MaxAmount; @@ -8574,19 +8566,19 @@ scriptwait: case PCD_SETAMMOCAPACITY: if (activator != NULL) { - const PClass *type = PClass::FindClass (FBehavior::StaticLookupString (STACK(2))); + PClass *type = PClass::FindClass (FBehavior::StaticLookupString (STACK(2))); AInventory *item; if (type != NULL && type->ParentClass == RUNTIME_CLASS(AAmmo)) { - item = activator->FindInventory (type); + item = activator->FindInventory (static_cast(type)); if (item != NULL) { item->MaxAmount = STACK(1); } else { - item = activator->GiveInventoryType (type); + item = activator->GiveInventoryType (static_cast(type)); item->MaxAmount = STACK(1); item->Amount = 0; } @@ -8886,8 +8878,8 @@ scriptwait: } else { - AInventory *item = activator->FindInventory (PClass::FindClass ( - FBehavior::StaticLookupString (STACK(1)))); + AInventory *item = activator->FindInventory (dyn_cast( + PClass::FindClass (FBehavior::StaticLookupString (STACK(1))))); if (item == NULL || !item->IsKindOf (RUNTIME_CLASS(AWeapon))) { @@ -8942,7 +8934,7 @@ scriptwait: case PCD_SETMARINESPRITE: { - const PClass *type = PClass::FindClass (FBehavior::StaticLookupString (STACK(1))); + PClassActor *type = PClass::FindActor(FBehavior::StaticLookupString (STACK(1))); if (type != NULL) { @@ -9174,7 +9166,7 @@ scriptwait: { if (activator != NULL) { - state = activator->GetClass()->ActorInfo->FindStateByString (statename, !!STACK(1)); + state = activator->GetClass()->FindStateByString (statename, !!STACK(1)); if (state != NULL) { activator->SetState (state); @@ -9194,7 +9186,7 @@ scriptwait: while ( (actor = iterator.Next ()) ) { - state = actor->GetClass()->ActorInfo->FindStateByString (statename, !!STACK(1)); + state = actor->GetClass()->FindStateByString (statename, !!STACK(1)); if (state != NULL) { actor->SetState (state); @@ -9258,7 +9250,7 @@ scriptwait: int amount = STACK(4); FName type = FBehavior::StaticLookupString(STACK(3)); FName protection = FName (FBehavior::StaticLookupString(STACK(2)), true); - const PClass *protectClass = PClass::FindClass (protection); + PClassActor *protectClass = PClass::FindActor (protection); int flags = STACK(1); sp -= 5; @@ -9320,15 +9312,15 @@ scriptwait: { int tag = STACK(7); FName playerclass_name = FBehavior::StaticLookupString(STACK(6)); - const PClass *playerclass = PClass::FindClass (playerclass_name); + PClassPlayerPawn *playerclass = dyn_cast(PClass::FindClass (playerclass_name)); FName monsterclass_name = FBehavior::StaticLookupString(STACK(5)); - const PClass *monsterclass = PClass::FindClass (monsterclass_name); + PClassActor *monsterclass = PClass::FindActor(monsterclass_name); int duration = STACK(4); int style = STACK(3); FName morphflash_name = FBehavior::StaticLookupString(STACK(2)); - const PClass *morphflash = PClass::FindClass (morphflash_name); + PClassActor *morphflash = PClass::FindActor(morphflash_name); FName unmorphflash_name = FBehavior::StaticLookupString(STACK(1)); - const PClass *unmorphflash = PClass::FindClass (unmorphflash_name); + PClassActor *unmorphflash = PClass::FindActor(unmorphflash_name); int changes = 0; if (tag == 0) diff --git a/src/p_buildmap.cpp b/src/p_buildmap.cpp index d9074310d9..a7a26e9c82 100644 --- a/src/p_buildmap.cpp +++ b/src/p_buildmap.cpp @@ -895,6 +895,7 @@ void ACustomSprite::BeginPlay () renderflags |= RF_XFLIP; if (cstat & 8) renderflags |= RF_YFLIP; + // set face/wall/floor flags renderflags |= ActorRenderFlags::FromInt (((cstat >> 4) & 3) << 12); } diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 3111bc2d67..7030142c52 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -102,7 +102,7 @@ struct TeaserSpeech static FRandom pr_randomspeech("RandomSpeech"); -void GiveSpawner (player_t *player, const PClass *type); +void GiveSpawner (player_t *player, PClassActor *type); TArray StrifeDialogues; @@ -138,7 +138,7 @@ static FStrifeDialogueNode *PrevNode; // //============================================================================ -void SetStrifeType(int convid, const PClass *Class) +void SetStrifeType(int convid, PClassActor *Class) { StrifeTypes[convid] = Class; } @@ -148,7 +148,7 @@ void ClearStrifeTypes() StrifeTypes.Clear(); } -void SetConversation(int convid, const PClass *Class, int dlgindex) +void SetConversation(int convid, PClassActor *Class, int dlgindex) { if (convid != -1) { @@ -160,9 +160,9 @@ void SetConversation(int convid, const PClass *Class, int dlgindex) } } -const PClass *GetStrifeType (int typenum) +PClassActor *GetStrifeType (int typenum) { - const PClass **ptype = StrifeTypes.CheckKey(typenum); + PClassActor **ptype = StrifeTypes.CheckKey(typenum); if (ptype == NULL) return NULL; else return *ptype; } @@ -322,7 +322,7 @@ static FStrifeDialogueNode *ReadRetailNode (FileReader *lump, DWORD &prevSpeaker FStrifeDialogueNode *node; Speech speech; char fullsound[16]; - const PClass *type; + PClassActor *type; int j; node = new FStrifeDialogueNode; @@ -363,16 +363,16 @@ static FStrifeDialogueNode *ReadRetailNode (FileReader *lump, DWORD &prevSpeaker // The speaker's name, if any. speech.Sound[0] = 0; //speech.Name[16] = 0; - node->SpeakerName = ncopystring (speech.Name); + node->SpeakerName = ncopystring(speech.Name); // The item the speaker should drop when killed. - node->DropType = GetStrifeType (speech.DropType); + node->DropType = dyn_cast(GetStrifeType(speech.DropType)); // Items you need to have to make the speaker use a different node. node->ItemCheck.Resize(3); for (j = 0; j < 3; ++j) { - node->ItemCheck[j].Item = GetStrifeType (speech.ItemCheck[j]); + node->ItemCheck[j].Item = dyn_cast(GetStrifeType(speech.ItemCheck[j])); node->ItemCheck[j].Amount = -1; } node->ItemCheckNode = speech.Link; @@ -396,7 +396,7 @@ static FStrifeDialogueNode *ReadTeaserNode (FileReader *lump, DWORD &prevSpeaker FStrifeDialogueNode *node; TeaserSpeech speech; char fullsound[16]; - const PClass *type; + PClassActor *type; int j; node = new FStrifeDialogueNode; @@ -409,7 +409,7 @@ static FStrifeDialogueNode *ReadTeaserNode (FileReader *lump, DWORD &prevSpeaker // Assign the first instance of a conversation as the default for its // actor, so newly spawned actors will use this conversation by default. - type = GetStrifeType (speech.SpeakerType); + type = GetStrifeType(speech.SpeakerType); node->SpeakerType = type; if ((signed)speech.SpeakerType >= 0 && prevSpeakerType != speech.SpeakerType) @@ -444,7 +444,7 @@ static FStrifeDialogueNode *ReadTeaserNode (FileReader *lump, DWORD &prevSpeaker node->SpeakerName = ncopystring (speech.Name); // The item the speaker should drop when killed. - node->DropType = GetStrifeType (speech.DropType); + node->DropType = dyn_cast(GetStrifeType (speech.DropType)); // Items you need to have to make the speaker use a different node. node->ItemCheck.Resize(3); @@ -509,14 +509,14 @@ static void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses) reply->LogString = NULL; // The item to receive when this reply is used. - reply->GiveType = GetStrifeType (rsp->GiveType); + reply->GiveType = dyn_cast(GetStrifeType (rsp->GiveType)); reply->ActionSpecial = 0; // Do you need anything special for this reply to succeed? reply->ItemCheck.Resize(3); for (k = 0; k < 3; ++k) { - reply->ItemCheck[k].Item = GetStrifeType (rsp->Item[k]); + reply->ItemCheck[k].Item = dyn_cast(GetStrifeType(rsp->Item[k])); reply->ItemCheck[k].Amount = rsp->Count[k]; } @@ -609,7 +609,7 @@ static int FindNode (const FStrifeDialogueNode *node) // //============================================================================ -static bool CheckStrifeItem (player_t *player, const PClass *itemtype, int amount=-1) +static bool CheckStrifeItem (player_t *player, PClassActor *itemtype, int amount=-1) { AInventory *item; @@ -632,7 +632,7 @@ static bool CheckStrifeItem (player_t *player, const PClass *itemtype, int amoun // //============================================================================ -static void TakeStrifeItem (player_t *player, const PClass *itemtype, int amount) +static void TakeStrifeItem (player_t *player, PClassActor *itemtype, int amount) { if (itemtype == NULL || amount == 0) return; diff --git a/src/p_conversation.h b/src/p_conversation.h index 14ec89e53d..59e3829315 100644 --- a/src/p_conversation.h +++ b/src/p_conversation.h @@ -9,11 +9,10 @@ struct FStrifeDialogueReply; class FTexture; struct FBrokenLines; -struct PClass; struct FStrifeDialogueItemCheck { - const PClass *Item; + PClassInventory *Item; int Amount; }; @@ -21,12 +20,12 @@ struct FStrifeDialogueItemCheck struct FStrifeDialogueNode { ~FStrifeDialogueNode (); - const PClass *DropType; + PClassActor *DropType; TArray ItemCheck; int ThisNodeNum; // location of this node in StrifeDialogues int ItemCheckNode; // index into StrifeDialogues - const PClass *SpeakerType; + PClassActor *SpeakerType; char *SpeakerName; FSoundID SpeakerVoice; FTextureID Backdrop; @@ -41,7 +40,7 @@ struct FStrifeDialogueReply ~FStrifeDialogueReply (); FStrifeDialogueReply *Next; - const PClass *GiveType; + PClassActor *GiveType; int ActionSpecial; int Args[5]; TArray ItemCheck; @@ -58,9 +57,9 @@ extern TArray StrifeDialogues; struct MapData; -void SetStrifeType(int convid, const PClass *Class); -void SetConversation(int convid, const PClass *Class, int dlgindex); -const PClass *GetStrifeType (int typenum); +void SetStrifeType(int convid, PClassActor *Class); +void SetConversation(int convid, PClassActor *Class, int dlgindex); +PClassActor *GetStrifeType (int typenum); int GetConversation(int conv_id); int GetConversation(FName classname); diff --git a/src/p_effect.cpp b/src/p_effect.cpp index 62ddb7d3d4..c02e3a97bf 100644 --- a/src/p_effect.cpp +++ b/src/p_effect.cpp @@ -347,7 +347,7 @@ particle_t *JitterParticle (int ttl) return JitterParticle (ttl, 1.0); } // [XA] Added "drift speed" multiplier setting for enhanced railgun stuffs. -particle_t *JitterParticle (int ttl, float drift) +particle_t *JitterParticle (int ttl, double drift) { particle_t *particle = NewParticle (); @@ -624,13 +624,14 @@ void P_DrawSplash2 (int count, fixed_t x, fixed_t y, fixed_t z, angle_t angle, i } } -void P_DrawRailTrail(AActor *source, const TVector3 &start, const TVector3 &end, int color1, int color2, double maxdiff, int flags, const PClass *spawnclass, angle_t angle, int duration, double sparsity, double drift, int SpiralOffset) +void P_DrawRailTrail(AActor *source, const TVector3 &start, const TVector3 &end, int color1, int color2, double maxdiff_d, int flags, PClassActor *spawnclass, angle_t angle, int duration, double sparsity, double drift, int SpiralOffset) { double length, lengthsquared; int steps, i; TAngle deg; TVector3 step, dir, pos, extend; bool fullbright; + float maxdiff = (float)maxdiff_d; dir = end - start; lengthsquared = dir | dir; diff --git a/src/p_effect.h b/src/p_effect.h index d92c77e237..d524e62e43 100644 --- a/src/p_effect.h +++ b/src/p_effect.h @@ -80,7 +80,7 @@ void P_FindParticleSubsectors (); class AActor; particle_t *JitterParticle (int ttl); -particle_t *JitterParticle (int ttl, float drift); +particle_t *JitterParticle (int ttl, double drift); void P_ThinkParticles (void); void P_SpawnParticle(fixed_t x, fixed_t y, fixed_t z, fixed_t velx, fixed_t vely, fixed_t velz, PalEntry color, bool fullbright, BYTE startalpha, BYTE lifetime, WORD size, int fadestep, fixed_t accelx, fixed_t accely, fixed_t accelz); @@ -89,7 +89,7 @@ void P_RunEffects (void); void P_RunEffect (AActor *actor, int effects); -void P_DrawRailTrail(AActor *source, const TVector3 &start, const TVector3 &end, int color1, int color2, double maxdiff = 0, int flags = 0, const PClass *spawnclass = NULL, angle_t angle = 0, int duration = 35, double sparsity = 1.0, double drift = 1.0, int SpiralOffset = 270); +void P_DrawRailTrail(AActor *source, const TVector3 &start, const TVector3 &end, int color1, int color2, double maxdiff = 0, int flags = 0, PClassActor *spawnclass = NULL, angle_t angle = 0, int duration = 35, double sparsity = 1.0, double drift = 1.0, int SpiralOffset = 270); void P_DrawSplash (int count, fixed_t x, fixed_t y, fixed_t z, angle_t angle, int kind); void P_DrawSplash2 (int count, fixed_t x, fixed_t y, fixed_t z, angle_t angle, int updown, int kind); void P_DisconnectEffect (AActor *actor); diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 3c9cb1e177..c3cba64330 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -1729,10 +1729,12 @@ bool P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params) // DEFINE_ACTION_FUNCTION(AActor, A_Look) { + PARAM_ACTION_PROLOGUE; + AActor *targ; if (self->flags5 & MF5_INCONVERSATION) - return; + return 0; // [RH] Set goal now if appropriate if (self->special == Thing_SetGoal && self->args[0] == 0) @@ -1764,7 +1766,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look) if (targ && targ->player && (targ->player->cheats & CF_NOTARGET)) { - return; + return 0; } } @@ -1808,7 +1810,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look) } if (!P_LookForPlayers (self, self->flags4 & MF4_LOOKALLAROUND, NULL)) - return; + return 0; // go into chase state seeyou: @@ -1834,6 +1836,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look) { self->SetState (self->SeeState); } + return 0; } @@ -1846,13 +1849,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx) { - ACTION_PARAM_START(6); - ACTION_PARAM_INT(flags, 0); - ACTION_PARAM_FIXED(minseedist, 1); - ACTION_PARAM_FIXED(maxseedist, 2); - ACTION_PARAM_FIXED(maxheardist, 3); - ACTION_PARAM_DOUBLE(fov_f, 4); - ACTION_PARAM_STATE(seestate, 5); + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_FIXED_OPT (minseedist) { minseedist = 0; } + PARAM_FIXED_OPT (maxseedist) { maxseedist = 0; } + PARAM_FIXED_OPT (maxheardist) { maxheardist = 0; } + PARAM_FLOAT_OPT (fov_f) { fov_f = 0; } + PARAM_STATE_OPT (seestate) { seestate = NULL; } AActor *targ = NULL; // Shuts up gcc fixed_t dist; @@ -1860,17 +1863,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx) FLookExParams params = { fov, minseedist, maxseedist, maxheardist, flags, seestate }; if (self->flags5 & MF5_INCONVERSATION) - return; + return 0; // [RH] Set goal now if appropriate if (self->special == Thing_SetGoal && self->args[0] == 0) { - NActorIterator iterator (NAME_PatrolPoint, self->args[1]); + NActorIterator iterator(NAME_PatrolPoint, self->args[1]); self->special = 0; self->goal = iterator.Next (); self->reactiontime = self->args[2] * TICRATE + level.maptime; - if (self->args[3] == 0) self->flags5 &=~ MF5_CHASEGOAL; - else self->flags5 |= MF5_CHASEGOAL; + if (self->args[3] == 0) + self->flags5 &= ~MF5_CHASEGOAL; + else + self->flags5 |= MF5_CHASEGOAL; } self->threshold = 0; // any shot will wake up @@ -1908,7 +1913,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx) if (targ && targ->player && (targ->player->cheats & CF_NOTARGET)) { - return; + return 0; } } @@ -1982,11 +1987,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx) if (!(flags & LOF_NOSIGHTCHECK)) { if (!P_LookForPlayers(self, true, ¶ms)) - return; + return 0; } else { - return; + return 0; } // go into chase state @@ -2023,6 +2028,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx) } } } + return 0; } // [KS] *** End additions by me *** @@ -2033,9 +2039,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ClearLastHeard) +DEFINE_ACTION_FUNCTION(AActor, A_ClearLastHeard) { + PARAM_ACTION_PROLOGUE; self->LastHeard = NULL; + return 0; } //========================================================================== @@ -2045,20 +2053,22 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ClearLastHeard) //========================================================================== DEFINE_ACTION_FUNCTION(AActor, A_Wander) { + PARAM_ACTION_PROLOGUE; + // [RH] Strife probably clears this flag somewhere, but I couldn't find where. // This seems as good a place as any. self->flags4 &= ~MF4_INCOMBAT; if (self->flags5 & MF5_INCONVERSATION) - return; + return 0; if (self->flags4 & MF4_STANDSTILL) - return; + return 0; if (self->reactiontime != 0) { self->reactiontime--; - return; + return 0; } // turn towards movement direction if not there yet @@ -2081,6 +2091,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Wander) P_RandomChaseDir (self); self->movecount += 5; } + return 0; } @@ -2091,10 +2102,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_Wander) //========================================================================== DEFINE_ACTION_FUNCTION(AActor, A_Look2) { + PARAM_ACTION_PROLOGUE; + AActor *targ; if (self->flags5 & MF5_INCONVERSATION) - return; + return 0; self->threshold = 0; targ = self->LastHeard; @@ -2117,7 +2130,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look2) self->target = targ; self->threshold = 10; self->SetState (self->SeeState); - return; + return 0; } else { @@ -2125,7 +2138,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look2) goto nosee; self->SetState (self->SeeState); self->flags4 |= MF4_INCOMBAT; - return; + return 0; } } nosee: @@ -2137,6 +2150,7 @@ nosee: { self->SetState (self->SpawnState + 3); } + return 0; } //============================================================================= @@ -2152,7 +2166,7 @@ nosee: //============================================================================= #define CLASS_BOSS_STRAFE_RANGE 64*10*FRACUNIT -void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missilestate, bool playactive, bool nightmarefast, bool dontmove) +void A_DoChase (VMFrameStack *stack, AActor *actor, bool fastchase, FState *meleestate, FState *missilestate, bool playactive, bool nightmarefast, bool dontmove) { int delta; @@ -2595,10 +2609,10 @@ static bool P_CheckForResurrection(AActor *self, bool 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"); + PClassActor *archvile = PClass::FindActor("Archvile"); if (archvile != NULL) { - self->SetState(archvile->ActorInfo->FindState(NAME_Heal)); + self->SetState(archvile->FindState(NAME_Heal)); } } S_Sound(corpsehit, CHAN_BODY, "vile/raise", 1, ATTN_IDLE); @@ -2663,53 +2677,62 @@ enum ChaseFlags DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Chase) { - ACTION_PARAM_START(3); - ACTION_PARAM_STATE(melee, 0); - ACTION_PARAM_STATE(missile, 1); - ACTION_PARAM_INT(flags, 2); + PARAM_ACTION_PROLOGUE; + PARAM_STATE_OPT (melee) { melee = NULL; } + PARAM_STATE_OPT (missile) { missile = NULL; } + PARAM_INT_OPT (flags) { flags = 0; } - if (melee != (FState*)-1) + if (numparam >= NAP + 1) { - if (flags & CHF_RESURRECT && P_CheckForResurrection(self, false)) return; + if ((flags & CHF_RESURRECT) && P_CheckForResurrection(self, false)) + return 0; - A_DoChase(self, !!(flags&CHF_FASTCHASE), melee, missile, !(flags&CHF_NOPLAYACTIVE), + A_DoChase(stack, self, !!(flags&CHF_FASTCHASE), melee, missile, !(flags&CHF_NOPLAYACTIVE), !!(flags&CHF_NIGHTMAREFAST), !!(flags&CHF_DONTMOVE)); } else // this is the old default A_Chase { - A_DoChase (self, false, self->MeleeState, self->MissileState, true, gameinfo.nightmarefast, false); + A_DoChase(stack, self, false, self->MeleeState, self->MissileState, true, gameinfo.nightmarefast, false); } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_FastChase) { - A_DoChase (self, true, self->MeleeState, self->MissileState, true, true, false); + PARAM_ACTION_PROLOGUE; + A_DoChase(stack, self, true, self->MeleeState, self->MissileState, true, true, false); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_VileChase) { + PARAM_ACTION_PROLOGUE; if (!P_CheckForResurrection(self, true)) - A_DoChase (self, false, self->MeleeState, self->MissileState, true, gameinfo.nightmarefast, false); + { + A_DoChase(stack, self, false, self->MeleeState, self->MissileState, true, gameinfo.nightmarefast, false); + } + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ExtChase) { - ACTION_PARAM_START(4); - ACTION_PARAM_BOOL(domelee, 0); - ACTION_PARAM_BOOL(domissile, 1); - ACTION_PARAM_BOOL(playactive, 2); - ACTION_PARAM_BOOL(nightmarefast, 3); + PARAM_ACTION_PROLOGUE; + PARAM_BOOL (domelee); + PARAM_BOOL (domissile); + PARAM_BOOL_OPT (playactive) { playactive = true; } + PARAM_BOOL_OPT (nightmarefast) { nightmarefast = false; } // Now that A_Chase can handle state label parameters, this function has become rather useless... - A_DoChase(self, false, - domelee ? self->MeleeState:NULL, domissile ? self->MissileState:NULL, + A_DoChase(stack, self, false, + domelee ? self->MeleeState : NULL, domissile ? self->MissileState : NULL, playactive, nightmarefast, false); + return 0; } // for internal use -void A_Chase(AActor *self) +void A_Chase(VMFrameStack *stack, AActor *self) { - A_DoChase (self, false, self->MeleeState, self->MissileState, true, gameinfo.nightmarefast, false); + A_DoChase(stack, self, false, self->MeleeState, self->MissileState, true, gameinfo.nightmarefast, false); } //============================================================================= @@ -2843,41 +2866,44 @@ void A_FaceTarget(AActor *self) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceTarget) { - ACTION_PARAM_START(6); - ACTION_PARAM_ANGLE(max_turn, 0); - ACTION_PARAM_ANGLE(max_pitch, 1); - ACTION_PARAM_ANGLE(ang_offset, 2); - ACTION_PARAM_ANGLE(pitch_offset, 3); - ACTION_PARAM_INT(flags, 4); - ACTION_PARAM_FIXED(z_add, 5); + PARAM_ACTION_PROLOGUE; + PARAM_ANGLE_OPT(max_turn) { max_turn = 0; } + PARAM_ANGLE_OPT(max_pitch) { max_pitch = 270; } + PARAM_ANGLE_OPT(ang_offset) { ang_offset = 0; } + PARAM_ANGLE_OPT(pitch_offset) { pitch_offset = 0; } + PARAM_INT_OPT(flags) { flags = 0; } + PARAM_FIXED_OPT(z_add) { z_add = 0; } A_Face(self, self->target, max_turn, max_pitch, ang_offset, pitch_offset, flags, z_add); + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceMaster) { - ACTION_PARAM_START(6); - ACTION_PARAM_ANGLE(max_turn, 0); - ACTION_PARAM_ANGLE(max_pitch, 1); - ACTION_PARAM_ANGLE(ang_offset, 2); - ACTION_PARAM_ANGLE(pitch_offset, 3); - ACTION_PARAM_INT(flags, 4); - ACTION_PARAM_FIXED(z_add, 5); + PARAM_ACTION_PROLOGUE; + PARAM_ANGLE_OPT(max_turn) { max_turn = 0; } + PARAM_ANGLE_OPT(max_pitch) { max_pitch = 270; } + PARAM_ANGLE_OPT(ang_offset) { ang_offset = 0; } + PARAM_ANGLE_OPT(pitch_offset) { pitch_offset = 0; } + PARAM_INT_OPT(flags) { flags = 0; } + PARAM_FIXED_OPT(z_add) { z_add = 0; } A_Face(self, self->master, max_turn, max_pitch, ang_offset, pitch_offset, flags, z_add); + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceTracer) { - ACTION_PARAM_START(6); - ACTION_PARAM_ANGLE(max_turn, 0); - ACTION_PARAM_ANGLE(max_pitch, 1); - ACTION_PARAM_ANGLE(ang_offset, 2); - ACTION_PARAM_ANGLE(pitch_offset, 3); - ACTION_PARAM_INT(flags, 4); - ACTION_PARAM_FIXED(z_add, 5); + PARAM_ACTION_PROLOGUE; + PARAM_ANGLE_OPT(max_turn) { max_turn = 0; } + PARAM_ANGLE_OPT(max_pitch) { max_pitch = 270; } + PARAM_ANGLE_OPT(ang_offset) { ang_offset = 0; } + PARAM_ANGLE_OPT(pitch_offset) { pitch_offset = 0; } + PARAM_INT_OPT(flags) { flags = 0; } + PARAM_FIXED_OPT(z_add) { z_add = 0; } A_Face(self, self->tracer, max_turn, max_pitch, ang_offset, pitch_offset, flags, z_add); + return 0; } //=========================================================================== @@ -2889,8 +2915,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceTracer) //=========================================================================== DEFINE_ACTION_FUNCTION(AActor, A_MonsterRail) { + PARAM_ACTION_PROLOGUE; + if (!self->target) - return; + return 0; fixed_t saved_pitch = self->pitch; AActor *linetarget; @@ -2925,10 +2953,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_MonsterRail) P_RailAttack (self, self->GetMissileDamage (0, 1), 0); self->pitch = saved_pitch; + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_Scream) { + PARAM_ACTION_PROLOGUE; if (self->DeathSound) { // Check for bosses. @@ -2942,14 +2972,17 @@ DEFINE_ACTION_FUNCTION(AActor, A_Scream) S_Sound (self, CHAN_VOICE, self->DeathSound, 1, ATTN_NORM); } } + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_XScream) { + PARAM_ACTION_PROLOGUE; if (self->player) S_Sound (self, CHAN_VOICE, "*gibbed", 1, ATTN_NORM); else S_Sound (self, CHAN_VOICE, "misc/gibbed", 1, ATTN_NORM); + return 0; } //=========================================================================== @@ -2960,8 +2993,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_XScream) DEFINE_ACTION_FUNCTION(AActor, A_ScreamAndUnblock) { + PARAM_ACTION_PROLOGUE; CALL_ACTION(A_Scream, self); A_Unblock(self, true); + return 0; } //=========================================================================== @@ -2972,10 +3007,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_ScreamAndUnblock) DEFINE_ACTION_FUNCTION(AActor, A_ActiveSound) { + PARAM_ACTION_PROLOGUE; if (self->ActiveSound) { S_Sound (self, CHAN_VOICE, self->ActiveSound, 1, ATTN_NORM); } + return 0; } //=========================================================================== @@ -2986,8 +3023,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_ActiveSound) DEFINE_ACTION_FUNCTION(AActor, A_ActiveAndUnblock) { + PARAM_ACTION_PROLOGUE; CALL_ACTION(A_ActiveSound, self); A_Unblock(self, true); + return 0; } //--------------------------------------------------------------------------- @@ -3022,7 +3061,12 @@ void ModifyDropAmount(AInventory *inv, int dropamount) else if (inv->IsKindOf (RUNTIME_CLASS(AAmmo))) { // Half ammo when dropped by bad guys. - inv->Amount = inv->GetClass()->Meta.GetMetaInt (AIMETA_DropAmount, MAX(1, FixedMul(inv->Amount, dropammofactor))); + int amount = static_cast(inv->GetClass())->DropAmount; + if (amount <= 0) + { + amount = MAX(1, FixedMul(inv->Amount, dropammofactor)); + } + inv->Amount = amount; inv->ItemFlags |= flagmask; } else if (inv->IsKindOf (RUNTIME_CLASS(AWeaponGiver))) @@ -3052,7 +3096,7 @@ void ModifyDropAmount(AInventory *inv, int dropamount) CVAR(Int, sv_dropstyle, 0, CVAR_SERVERINFO | CVAR_ARCHIVE); -AInventory *P_DropItem (AActor *source, const PClass *type, int dropamount, int chance) +AInventory *P_DropItem (AActor *source, PClassActor *type, int dropamount, int chance) { if (type != NULL && pr_dropitem() <= chance) { @@ -3063,9 +3107,11 @@ AInventory *P_DropItem (AActor *source, const PClass *type, int dropamount, int if (!(i_compatflags & COMPATF_NOTOSSDROPS)) { int style = sv_dropstyle; - if (style==0) style= (gameinfo.gametype == GAME_Strife)? 2:1; - - if (style==2) + if (style == 0) + { + style = (gameinfo.gametype == GAME_Strife) ? 2 : 1; + } + if (style == 2) { spawnz += 24*FRACUNIT; } @@ -3074,7 +3120,7 @@ AInventory *P_DropItem (AActor *source, const PClass *type, int dropamount, int spawnz += source->height / 2; } } - mo = Spawn (type, source->X(), source->Y(), spawnz, ALLOW_REPLACE); + mo = Spawn(type, source->X(), source->Y(), spawnz, ALLOW_REPLACE); if (mo != NULL) { mo->flags |= MF_DROPPED; @@ -3085,7 +3131,7 @@ AInventory *P_DropItem (AActor *source, const PClass *type, int dropamount, int } if (mo->IsKindOf (RUNTIME_CLASS(AInventory))) { - AInventory * inv = static_cast(mo); + AInventory *inv = static_cast(mo); ModifyDropAmount(inv, dropamount); inv->ItemFlags |= IF_TOSSED; if (inv->SpecialDropAction (source)) @@ -3128,6 +3174,8 @@ void P_TossItem (AActor *item) DEFINE_ACTION_FUNCTION(AActor, A_Pain) { + PARAM_ACTION_PROLOGUE; + // [RH] Vary player pain sounds depending on health (ala Quake2) if (self->player && self->player->morphTics == 0) { @@ -3169,15 +3217,17 @@ DEFINE_ACTION_FUNCTION(AActor, A_Pain) { S_Sound (self, CHAN_VOICE, self->PainSound, 1, ATTN_NORM); } + return 0; } // killough 11/98: kill an object DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Die) { - ACTION_PARAM_START(1); - ACTION_PARAM_NAME(damagetype, 0); + PARAM_ACTION_PROLOGUE; + PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } - P_DamageMobj (self, NULL, NULL, self->health, damagetype, DMG_FORCED); + P_DamageMobj(self, NULL, NULL, self->health, damagetype, DMG_FORCED); + return 0; } // @@ -3187,9 +3237,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Die) DEFINE_ACTION_FUNCTION(AActor, A_Detonate) { - int damage = self->GetMissileDamage (0, 1); + PARAM_ACTION_PROLOGUE; + int damage = self->GetMissileDamage(0, 1); P_RadiusAttack (self, self->target, damage, damage, self->DamageType, RADF_HURTSOURCE); P_CheckSplash(self, damage<GetClass()->TypeName; // Ugh... - FName type = self->GetClass()->ActorInfo->GetReplacee()->Class->TypeName; + FName type = self->GetClass()->GetReplacee()->TypeName; // Do generic special death actions first bool checked = false; - for(unsigned i=0; ispecialactions.Size(); i++) + for (unsigned i = 0; i < level.info->specialactions.Size(); i++) { FSpecialAction *sa = &level.info->specialactions[i]; @@ -3326,6 +3378,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_BossDeath) G_ExitLevel (0, false); } +DEFINE_ACTION_FUNCTION(AActor, A_BossDeath) +{ + PARAM_ACTION_PROLOGUE; + A_BossDeath(self); + return 0; +} + //---------------------------------------------------------------------------- // // PROC P_Massacre @@ -3399,6 +3458,7 @@ bool A_RaiseMobj (AActor *actor, fixed_t speed) DEFINE_ACTION_FUNCTION(AActor, A_ClassBossHealth) { + PARAM_ACTION_PROLOGUE; if (multiplayer && !deathmatch) // co-op only { if (!self->special1) @@ -3407,4 +3467,5 @@ DEFINE_ACTION_FUNCTION(AActor, A_ClassBossHealth) self->special1 = true; // has been initialized } } + return 0; } diff --git a/src/p_enemy.h b/src/p_enemy.h index 9ee77caed4..2b6b7fe5e1 100644 --- a/src/p_enemy.h +++ b/src/p_enemy.h @@ -7,7 +7,7 @@ struct sector_t; class AActor; class AInventory; -struct PClass; +class PClass; enum dirtype_t @@ -54,7 +54,7 @@ bool P_CheckMeleeRange2 (AActor *actor); bool P_Move (AActor *actor); bool P_TryWalk (AActor *actor); void P_NewChaseDir (AActor *actor); -AInventory *P_DropItem (AActor *source, const PClass *type, int special, int chance); +AInventory *P_DropItem (AActor *source, PClassActor *type, int special, int chance); void P_TossItem (AActor *item); bool P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params); void A_Weave(AActor *self, int xyspeed, int zspeed, fixed_t xydist, fixed_t zdist); @@ -69,11 +69,11 @@ DECLARE_ACTION(A_NoBlocking) DECLARE_ACTION(A_Scream) DECLARE_ACTION(A_FreezeDeath) DECLARE_ACTION(A_FreezeDeathChunks) -DECLARE_ACTION(A_BossDeath) +void A_BossDeath(AActor *self); -void A_Chase(AActor *self); +void A_Chase(VMFrameStack *stack, AActor *self); void A_FaceTarget(AActor *actor); -void A_Face(AActor *self, AActor *other, angle_t max_turn = 0, angle_t max_pitch = ANGLE_270, angle_t ang_offset = 0, angle_t pitch_offset = 0, int flags = 0, fixed_t pitch_add = 0); +void A_Face(AActor *self, AActor *other, angle_t max_turn = 0, angle_t max_pitch = ANGLE_270, angle_t ang_offset = 0, angle_t pitch_offset = 0, int flags = 0, fixed_t z_add = 0); bool A_RaiseMobj (AActor *, fixed_t speed); bool A_SinkMobj (AActor *, fixed_t speed); diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 0c61b2d7df..b97d17af87 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1,1858 +1,1853 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// $Id:$ -// -// Copyright (C) 1993-1996 by id Software, Inc. -// -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ -// -// DESCRIPTION: -// Handling interactions (i.e., collisions). -// -//----------------------------------------------------------------------------- - - - - -// Data. -#include "doomdef.h" -#include "gstrings.h" - -#include "doomstat.h" - -#include "m_random.h" -#include "i_system.h" -#include "announcer.h" - -#include "am_map.h" - -#include "c_console.h" -#include "c_dispatch.h" - -#include "p_local.h" - -#include "p_lnspec.h" -#include "p_effect.h" -#include "p_acs.h" - -#include "b_bot.h" //Added by MC: - -#include "ravenshared.h" -#include "a_hexenglobal.h" -#include "a_sharedglobal.h" -#include "a_pickups.h" -#include "gi.h" -#include "templates.h" -#include "sbar.h" -#include "s_sound.h" -#include "g_level.h" -#include "d_net.h" -#include "d_netinf.h" - -static FRandom pr_obituary ("Obituary"); -static FRandom pr_botrespawn ("BotRespawn"); -static FRandom pr_killmobj ("ActorDie"); -FRandom pr_damagemobj ("ActorTakeDamage"); -static FRandom pr_lightning ("LightningDamage"); -static FRandom pr_poison ("PoisonDamage"); -static FRandom pr_switcher ("SwitchTarget"); -static FRandom pr_kickbackdir ("KickbackDir"); - -CVAR (Bool, cl_showsprees, true, CVAR_ARCHIVE) -CVAR (Bool, cl_showmultikills, true, CVAR_ARCHIVE) -EXTERN_CVAR (Bool, show_obituaries) - - -FName MeansOfDeath; - -// -// GET STUFF -// - -// -// P_TouchSpecialThing -// -void P_TouchSpecialThing (AActor *special, AActor *toucher) -{ - fixed_t delta = special->Z() - toucher->Z(); - - // The pickup is at or above the toucher's feet OR - // The pickup is below the toucher. - if (delta > toucher->height || delta < MIN(-32*FRACUNIT, -special->height)) - { // out of reach - return; - } - - // Dead thing touching. - // Can happen with a sliding player corpse. - if (toucher->health <= 0) - return; - - //Added by MC: Finished with this destination. - if (toucher->player != NULL && toucher->player->Bot != NULL && special == toucher->player->Bot->dest) - { - toucher->player->Bot->prev = toucher->player->Bot->dest; - toucher->player->Bot->dest = NULL; - } - - special->Touch (toucher); -} - - -// [RH] -// SexMessage: Replace parts of strings with gender-specific pronouns -// -// The following expansions are performed: -// %g -> he/she/it -// %h -> him/her/it -// %p -> his/her/its -// %o -> other (victim) -// %k -> killer -// -void SexMessage (const char *from, char *to, int gender, const char *victim, const char *killer) -{ - static const char *genderstuff[3][3] = - { - { "he", "him", "his" }, - { "she", "her", "her" }, - { "it", "it", "its" } - }; - static const int gendershift[3][3] = - { - { 2, 3, 3 }, - { 3, 3, 3 }, - { 2, 2, 3 } - }; - const char *subst = NULL; - - do - { - if (*from != '%') - { - *to++ = *from; - } - else - { - int gendermsg = -1; - - switch (from[1]) - { - case 'g': gendermsg = 0; break; - case 'h': gendermsg = 1; break; - case 'p': gendermsg = 2; break; - case 'o': subst = victim; break; - case 'k': subst = killer; break; - } - if (subst != NULL) - { - size_t len = strlen (subst); - memcpy (to, subst, len); - to += len; - from++; - subst = NULL; - } - else if (gendermsg < 0) - { - *to++ = '%'; - } - else - { - strcpy (to, genderstuff[gender][gendermsg]); - to += gendershift[gender][gendermsg]; - from++; - } - } - } while (*from++); -} - -// [RH] -// ClientObituary: Show a message when a player dies -// -void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgflags) -{ - FName mod; - const char *message; - const char *messagename; - char gendermessage[1024]; - int gender; - - // No obituaries for non-players, voodoo dolls or when not wanted - if (self->player == NULL || self->player->mo != self || !show_obituaries) - return; - - gender = self->player->userinfo.GetGender(); - - // Treat voodoo dolls as unknown deaths - if (inflictor && inflictor->player && inflictor->player->mo != inflictor) - MeansOfDeath = NAME_None; - - mod = MeansOfDeath; - message = NULL; - messagename = NULL; - - if (attacker == NULL || attacker->player != NULL) - { - if (mod == NAME_Telefrag) - { - if (AnnounceTelefrag (attacker, self)) - return; - } - else - { - if (AnnounceKill (attacker, self)) - return; - } - } - - switch (mod) - { - case NAME_Suicide: messagename = "OB_SUICIDE"; break; - case NAME_Falling: messagename = "OB_FALLING"; break; - case NAME_Crush: messagename = "OB_CRUSH"; break; - case NAME_Exit: messagename = "OB_EXIT"; break; - case NAME_Drowning: messagename = "OB_WATER"; break; - case NAME_Slime: messagename = "OB_SLIME"; break; - case NAME_Fire: if (attacker == NULL) messagename = "OB_LAVA"; break; - } - - // Check for being killed by a voodoo doll. - if (inflictor && inflictor->player && inflictor->player->mo != inflictor) - { - messagename = "OB_VOODOO"; - } - - if (messagename != NULL) - message = GStrings(messagename); - - if (attacker != NULL && message == NULL) - { - if (attacker == self) - { - message = GStrings("OB_KILLEDSELF"); - } - else if (attacker->player == NULL) - { - if (mod == NAME_Telefrag) - { - message = GStrings("OB_MONTELEFRAG"); - } - else if (mod == NAME_Melee) - { - message = attacker->GetClass()->Meta.GetMetaString (AMETA_HitObituary); - if (message == NULL) - { - message = attacker->GetClass()->Meta.GetMetaString (AMETA_Obituary); - } - } - else - { - message = attacker->GetClass()->Meta.GetMetaString (AMETA_Obituary); - } - } - } - - if (message == NULL && attacker != NULL && attacker->player != NULL) - { - if (self->player != attacker->player && self->IsTeammate(attacker)) - { - self = attacker; - gender = self->player->userinfo.GetGender(); - mysnprintf (gendermessage, countof(gendermessage), "OB_FRIENDLY%c", '1' + (pr_obituary() & 3)); - message = GStrings(gendermessage); - } - else - { - if (mod == NAME_Telefrag) message = GStrings("OB_MPTELEFRAG"); - if (message == NULL) - { - if (inflictor != NULL) - { - message = inflictor->GetClass()->Meta.GetMetaString (AMETA_Obituary); - } - if (message == NULL && (dmgflags & DMG_PLAYERATTACK) && attacker->player->ReadyWeapon != NULL) - { - message = attacker->player->ReadyWeapon->GetClass()->Meta.GetMetaString (AMETA_Obituary); - } - if (message == NULL) - { - switch (mod) - { - case NAME_BFGSplash: messagename = "OB_MPBFG_SPLASH"; break; - case NAME_Railgun: messagename = "OB_RAILGUN"; break; - } - if (messagename != NULL) - message = GStrings(messagename); - } - if (message == NULL) - { - message = attacker->GetClass()->Meta.GetMetaString (AMETA_Obituary); - } - } - } - } - else attacker = self; // for the message creation - - if (message != NULL && message[0] == '$') - { - message = GStrings[message+1]; - } - - if (message == NULL) - { - message = GStrings("OB_DEFAULT"); - } - - // [CK] Don't display empty strings - if (message == NULL || strlen(message) <= 0) - return; - - SexMessage (message, gendermessage, gender, - self->player->userinfo.GetName(), attacker->player->userinfo.GetName()); - Printf (PRINT_MEDIUM, "%s\n", gendermessage); -} - - -// -// KillMobj -// -EXTERN_CVAR (Int, fraglimit) - -void AActor::Die (AActor *source, AActor *inflictor, int dmgflags) -{ - // Handle possible unmorph on death - bool wasgibbed = (health < GibHealth()); - - AActor *realthis = NULL; - int realstyle = 0; - int realhealth = 0; - if (P_MorphedDeath(this, &realthis, &realstyle, &realhealth)) - { - if (!(realstyle & MORPH_UNDOBYDEATHSAVES)) - { - if (wasgibbed) - { - int realgibhealth = realthis->GibHealth(); - if (realthis->health >= realgibhealth) - { - realthis->health = realgibhealth -1; // if morphed was gibbed, so must original be (where allowed)l - } - } - realthis->Die(source, inflictor, dmgflags); - } - return; - } - - // [SO] 9/2/02 -- It's rather funny to see an exploded player body with the invuln sparkle active :) - effects &= ~FX_RESPAWNINVUL; - //flags &= ~MF_INVINCIBLE; - - if (debugfile && this->player) - { - 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"); - } - - // [RH] Notify this actor's items. - for (AInventory *item = Inventory; item != NULL; ) - { - AInventory *next = item->Inventory; - item->OwnerDied(); - item = next; - } - - if (flags & MF_MISSILE) - { // [RH] When missiles die, they just explode - P_ExplodeMissile (this, NULL, NULL); - return; - } - // [RH] Set the target to the thing that killed it. Strife apparently does this. - if (source != NULL) - { - target = source; - } - - flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY); - if (!(flags4 & MF4_DONTFALL)) flags&=~MF_NOGRAVITY; - flags |= MF_DROPOFF; - if ((flags3 & MF3_ISMONSTER) || FindState(NAME_Raise) != NULL || IsKindOf(RUNTIME_CLASS(APlayerPawn))) - { // [RH] Only monsters get to be corpses. - // Objects with a raise state should get the flag as well so they can - // be revived by an Arch-Vile. Batman Doom needs this. - // [RC] And disable this if DONTCORPSE is set, of course. - if(!(flags6 & MF6_DONTCORPSE)) flags |= MF_CORPSE; - } - flags6 |= MF6_KILLED; - - // [RH] Allow the death height to be overridden using metadata. - fixed_t metaheight = 0; - if (DamageType == NAME_Fire) - { - metaheight = GetClass()->Meta.GetMetaFixed (AMETA_BurnHeight); - } - if (metaheight == 0) - { - metaheight = GetClass()->Meta.GetMetaFixed (AMETA_DeathHeight); - } - if (metaheight != 0) - { - height = MAX (metaheight, 0); - } - else - { - height >>= 2; - } - - // [RH] If the thing has a special, execute and remove it - // Note that the thing that killed it is considered - // the activator of the script. - // New: In Hexen, the thing that died is the activator, - // so now a level flag selects who the activator gets to be. - // Everything is now moved to P_ActivateThingSpecial(). - if (special && (!(flags & MF_SPECIAL) || (flags3 & MF3_ISMONSTER)) - && !(activationtype & THINGSPEC_NoDeathSpecial)) - { - P_ActivateThingSpecial(this, source, true); - } - - if (CountsAsKill()) - level.killed_monsters++; - - if (source && source->player) - { - if (CountsAsKill()) - { // count for intermission - source->player->killcount++; - } - - // Don't count any frags at level start, because they're just telefrags - // resulting from insufficient deathmatch starts, and it wouldn't be - // fair to count them toward a player's score. - if (player && level.maptime) - { - source->player->frags[player - players]++; - if (player == source->player) // [RH] Cumulative frag count - { - char buff[256]; - - player->fragcount--; - if (deathmatch && player->spreecount >= 5 && cl_showsprees) - { - SexMessage (GStrings("SPREEKILLSELF"), buff, - player->userinfo.GetGender(), player->userinfo.GetName(), - player->userinfo.GetName()); - StatusBar->AttachMessage (new DHUDMessageFadeOut (SmallFont, buff, - 1.5f, 0.2f, 0, 0, CR_WHITE, 3.f, 0.5f), MAKE_ID('K','S','P','R')); - } - } - else - { - if ((dmflags2 & DF2_YES_LOSEFRAG) && deathmatch) - player->fragcount--; - - if (this->IsTeammate(source)) - { - source->player->fragcount--; - } - else - { - ++source->player->fragcount; - ++source->player->spreecount; - } - - if (source->player->morphTics) - { // Make a super chicken - source->GiveInventoryType (RUNTIME_CLASS(APowerWeaponLevel2)); - } - - if (deathmatch && cl_showsprees) - { - const char *spreemsg; - char buff[256]; - - switch (source->player->spreecount) - { - case 5: - spreemsg = GStrings("SPREE5"); - break; - case 10: - spreemsg = GStrings("SPREE10"); - break; - case 15: - spreemsg = GStrings("SPREE15"); - break; - case 20: - spreemsg = GStrings("SPREE20"); - break; - case 25: - spreemsg = GStrings("SPREE25"); - break; - default: - spreemsg = NULL; - break; - } - - if (spreemsg == NULL && player->spreecount >= 5) - { - if (!AnnounceSpreeLoss (this)) - { - SexMessage (GStrings("SPREEOVER"), buff, player->userinfo.GetGender(), - player->userinfo.GetName(), source->player->userinfo.GetName()); - StatusBar->AttachMessage (new DHUDMessageFadeOut (SmallFont, buff, - 1.5f, 0.2f, 0, 0, CR_WHITE, 3.f, 0.5f), MAKE_ID('K','S','P','R')); - } - } - else if (spreemsg != NULL) - { - if (!AnnounceSpree (source)) - { - SexMessage (spreemsg, buff, player->userinfo.GetGender(), - player->userinfo.GetName(), source->player->userinfo.GetName()); - StatusBar->AttachMessage (new DHUDMessageFadeOut (SmallFont, buff, - 1.5f, 0.2f, 0, 0, CR_WHITE, 3.f, 0.5f), MAKE_ID('K','S','P','R')); - } - } - } - } - - // [RH] Multikills - if (player != source->player) - { - source->player->multicount++; - if (source->player->lastkilltime > 0) - { - if (source->player->lastkilltime < level.time - 3*TICRATE) - { - source->player->multicount = 1; - } - - if (deathmatch && - source->CheckLocalView (consoleplayer) && - cl_showmultikills) - { - const char *multimsg; - - switch (source->player->multicount) - { - case 1: - multimsg = NULL; - break; - case 2: - multimsg = GStrings("MULTI2"); - break; - case 3: - multimsg = GStrings("MULTI3"); - break; - case 4: - multimsg = GStrings("MULTI4"); - break; - default: - multimsg = GStrings("MULTI5"); - break; - } - if (multimsg != NULL) - { - char buff[256]; - - if (!AnnounceMultikill (source)) - { - SexMessage (multimsg, buff, player->userinfo.GetGender(), - player->userinfo.GetName(), source->player->userinfo.GetName()); - StatusBar->AttachMessage (new DHUDMessageFadeOut (SmallFont, buff, - 1.5f, 0.8f, 0, 0, CR_RED, 3.f, 0.5f), MAKE_ID('M','K','I','L')); - } - } - } - } - source->player->lastkilltime = level.time; - } - - // [RH] Implement fraglimit - if (deathmatch && fraglimit && - fraglimit <= D_GetFragCount (source->player)) - { - Printf ("%s\n", GStrings("TXT_FRAGLIMIT")); - G_ExitLevel (0, false); - } - } - } - else if (!multiplayer && CountsAsKill()) - { - // count all monster deaths, - // even those caused by other monsters - players[0].killcount++; - } - - if (player) - { - // [RH] Death messages - ClientObituary (this, inflictor, source, dmgflags); - - // Death script execution, care of Skull Tag - FBehavior::StaticStartTypedScripts (SCRIPT_Death, this, true); - - // [RH] Force a delay between death and respawn - player->respawn_time = level.time + TICRATE; - - //Added by MC: Respawn bots - if (bglobal.botnum && !demoplayback) - { - if (player->Bot != NULL) - player->Bot->t_respawn = (pr_botrespawn()%15)+((bglobal.botnum-1)*2)+TICRATE+1; - - //Added by MC: Discard enemies. - for (int i = 0; i < MAXPLAYERS; i++) - { - if (players[i].Bot != NULL && this == players[i].Bot->enemy) - { - if (players[i].Bot->dest == players[i].Bot->enemy) - players[i].Bot->dest = NULL; - players[i].Bot->enemy = NULL; - } - } - - player->spreecount = 0; - player->multicount = 0; - } - - // count environment kills against you - if (!source) - { - player->frags[player - players]++; - player->fragcount--; // [RH] Cumulative frag count - } - - flags &= ~MF_SOLID; - player->playerstate = PST_DEAD; - P_DropWeapon (player); - if (this == players[consoleplayer].camera && automapactive) - { - // don't die in auto map, switch view prior to dying - AM_Stop (); - } - - // [GRB] Clear extralight. When you killed yourself with weapon that - // called A_Light1/2 before it called A_Light0, extraligh remained. - player->extralight = 0; - } - - // [RH] If this is the unmorphed version of another monster, destroy this - // actor, because the morphed version is the one that will stick around in - // the level. - if (flags & MF_UNMORPHED) - { - Destroy (); - return; - } - - - - FState *diestate = NULL; - int gibhealth = GibHealth(); - ActorFlags4 iflags4 = inflictor == NULL ? ActorFlags4::FromInt(0) : inflictor->flags4; - bool extremelydead = ((health < gibhealth || iflags4 & MF4_EXTREMEDEATH) && !(iflags4 & MF4_NOEXTREMEDEATH)); - - // Special check for 'extreme' damage type to ensure that it gets recorded properly as an extreme death for subsequent checks. - if (DamageType == NAME_Extreme) - { - extremelydead = true; - DamageType = NAME_None; - } - - // find the appropriate death state. The order is: - // - // 1. If damagetype is not 'none' and death is extreme, try a damage type specific extreme death state - // 2. If no such state is found or death is not extreme try a damage type specific normal death state - // 3. If damagetype is 'ice' and actor is a monster or player, try the generic freeze death (unless prohibited) - // 4. If no state has been found and death is extreme, try the extreme death state - // 5. If no such state is found or death is not extreme try the regular death state. - // 6. If still no state has been found, destroy the actor immediately. - - if (DamageType != NAME_None) - { - if (extremelydead) - { - FName labels[] = { NAME_Death, NAME_Extreme, DamageType }; - diestate = FindState(3, labels, true); - } - if (diestate == NULL) - { - diestate = FindState (NAME_Death, DamageType, true); - if (diestate != NULL) extremelydead = false; - } - if (diestate == NULL) - { - if (DamageType == NAME_Ice) - { // If an actor doesn't have an ice death, we can still give them a generic one. - - if (!deh.NoAutofreeze && !(flags4 & MF4_NOICEDEATH) && (player || (flags3 & MF3_ISMONSTER))) - { - diestate = FindState(NAME_GenericFreezeDeath); - extremelydead = false; - } - } - } - } - if (diestate == NULL) - { - - // Don't pass on a damage type this actor cannot handle. - // (most importantly, prevent barrels from passing on ice damage.) - // Massacre must be preserved though. - if (DamageType != NAME_Massacre) - { - DamageType = NAME_None; - } - - if (extremelydead) - { // Extreme death - diestate = FindState (NAME_Death, NAME_Extreme, true); - } - if (diestate == NULL) - { // Normal death - extremelydead = false; - diestate = FindState (NAME_Death); - } - } - - if (extremelydead) - { - // We'll only get here if an actual extreme death state was used. - - // For players, mark the appropriate flag. - if (player != NULL) - { - player->cheats |= CF_EXTREMELYDEAD; - } - // If a non-player, mark as extremely dead for the crash state. - else if (health >= gibhealth) - { - health = gibhealth - 1; - } - } - - if (diestate != NULL) - { - SetState (diestate); - - if (tics > 1) - { - tics -= pr_killmobj() & 3; - if (tics < 1) - tics = 1; - } - } - else - { - Destroy(); - } -} - - - - -//--------------------------------------------------------------------------- -// -// PROC P_AutoUseHealth -// -//--------------------------------------------------------------------------- -static int CountHealth(TArray &Items) -{ - int counted = 0; - for(unsigned i = 0; i < Items.Size(); i++) - { - counted += Items[i]->Amount * Items[i]->health; - } - return counted; -} - -static int UseHealthItems(TArray &Items, int &saveHealth) -{ - int saved = 0; - - while (Items.Size() > 0 && saveHealth > 0) - { - int maxhealth = 0; - int index = -1; - - // Find the largest item in the list - for(unsigned i = 0; i < Items.Size(); i++) - { - if (Items[i]->health > maxhealth) - { - index = i; - maxhealth = Items[i]->health; - } - } - - // Now apply the health items, using the same logic as Heretic and Hexen. - int count = (saveHealth + maxhealth-1) / maxhealth; - for(int i = 0; i < count; i++) - { - saved += maxhealth; - saveHealth -= maxhealth; - if (--Items[index]->Amount == 0) - { - Items[index]->DepleteOrDestroy (); - Items.Delete(index); - break; - } - } - } - return saved; -} - -void P_AutoUseHealth(player_t *player, int saveHealth) -{ - TArray NormalHealthItems; - TArray LargeHealthItems; - - for(AInventory *inv = player->mo->Inventory; inv != NULL; inv = inv->Inventory) - { - if (inv->Amount > 0 && inv->IsKindOf(RUNTIME_CLASS(AHealthPickup))) - { - int mode = static_cast(inv)->autousemode; - - if (mode == 1) NormalHealthItems.Push(inv); - else if (mode == 2) LargeHealthItems.Push(inv); - } - } - - int normalhealth = CountHealth(NormalHealthItems); - int largehealth = CountHealth(LargeHealthItems); - - bool skilluse = !!G_SkillProperty(SKILLP_AutoUseHealth); - - if (skilluse && normalhealth >= saveHealth) - { // Use quartz flasks - player->health += UseHealthItems(NormalHealthItems, saveHealth); - } - else if (largehealth >= saveHealth) - { - // Use mystic urns - player->health += UseHealthItems(LargeHealthItems, saveHealth); - } - else if (skilluse && normalhealth + largehealth >= saveHealth) - { // Use mystic urns and quartz flasks - player->health += UseHealthItems(NormalHealthItems, saveHealth); - if (saveHealth > 0) player->health += UseHealthItems(LargeHealthItems, saveHealth); - } - player->mo->health = player->health; -} - -//============================================================================ -// -// P_AutoUseStrifeHealth -// -//============================================================================ -CVAR(Bool, sv_disableautohealth, false, CVAR_ARCHIVE|CVAR_SERVERINFO) - -void P_AutoUseStrifeHealth (player_t *player) -{ - TArray Items; - - for(AInventory *inv = player->mo->Inventory; inv != NULL; inv = inv->Inventory) - { - if (inv->Amount > 0 && inv->IsKindOf(RUNTIME_CLASS(AHealthPickup))) - { - int mode = static_cast(inv)->autousemode; - - if (mode == 3) Items.Push(inv); - } - } - - if (!sv_disableautohealth) - { - while (Items.Size() > 0) - { - int maxhealth = 0; - int index = -1; - - // Find the largest item in the list - for(unsigned i = 0; i < Items.Size(); i++) - { - if (Items[i]->health > maxhealth) - { - index = i; - maxhealth = Items[i]->Amount; - } - } - - while (player->health < 50) - { - if (!player->mo->UseInventory (Items[index])) - break; - } - if (player->health >= 50) return; - // Using all of this item was not enough so delete it and restart with the next best one - Items.Delete(index); - } - } -} - -/* -================= -= -= P_DamageMobj -= -= Damages both enemies and players -= inflictor is the thing that caused the damage -= creature or missile, can be NULL (slime, etc) -= source is the thing to target after taking damage -= creature or NULL -= Source and inflictor are the same for melee attacks -= source can be null for barrel explosions and other environmental stuff -================== -*/ - -static inline bool MustForcePain(AActor *target, AActor *inflictor) -{ - return (!(target->flags5 & MF5_NOPAIN) && inflictor != NULL && - (inflictor->flags6 & MF6_FORCEPAIN) && !(inflictor->flags5 & MF5_PAINLESS)); -} - -static inline bool isFakePain(AActor *target, AActor *inflictor, int damage) -{ - return ((target->flags7 & MF7_ALLOWPAIN && damage > 0) || ((inflictor != NULL) && (inflictor->flags7 & MF7_CAUSEPAIN))); -} - - -// Returns the amount of damage actually inflicted upon the target, or -1 if -// the damage was cancelled. -int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags) -{ - unsigned ang; - player_t *player = NULL; - fixed_t thrust; - int temp; - int painchance = 0; - FState * woundstate = NULL; - PainChanceList * pc = NULL; - bool justhit = false; - bool plrDontThrust = false; - bool invulpain = false; - bool fakedPain = false; - bool forcedPain = false; - int fakeDamage = 0; - int holdDamage = 0; - int rawdamage = damage; - - if (damage < 0) damage = 0; - - if (target == NULL || !((target->flags & MF_SHOOTABLE) || (target->flags6 & MF6_VULNERABLE))) - { // Shouldn't happen - return -1; - } - - //Rather than unnecessarily call the function over and over again, let's be a little more efficient. - fakedPain = (isFakePain(target, inflictor, damage)); - forcedPain = (MustForcePain(target, inflictor)); - - // Spectral targets only take damage from spectral projectiles. - if (target->flags4 & MF4_SPECTRAL && damage < TELEFRAG_DAMAGE) - { - if (inflictor == NULL || !(inflictor->flags4 & MF4_SPECTRAL)) - { - return -1; - } - } - if (target->health <= 0) - { - if (inflictor && mod == NAME_Ice && !(inflictor->flags7 & MF7_ICESHATTER)) - { - return -1; - } - else if (target->flags & MF_ICECORPSE) // frozen - { - target->tics = 1; - target->flags6 |= MF6_SHATTERING; - target->velx = target->vely = target->velz = 0; - } - return -1; - } - // [MC] Changed it to check rawdamage here for consistency, even though that doesn't actually do anything - // different here. At any rate, invulnerable is being checked before type factoring, which is then being - // checked by player cheats/invul/buddha followed by monster buddha. This is inconsistent. Don't let the - // original telefrag damage CHECK (rawdamage) be influenced by outside factors when looking at cheats/invul. - if ((target->flags2 & MF2_INVULNERABLE) && (rawdamage < TELEFRAG_DAMAGE) && (!(flags & DMG_FORCED))) - { // actor is invulnerable - if (target->player == NULL) - { - if (inflictor == NULL || (!(inflictor->flags3 & MF3_FOILINVUL) && !(flags & DMG_FOILINVUL))) - { - if (fakedPain) - { - // big mess here: What do we use for the pain threshold? - // We cannot run the various damage filters below so for consistency it needs to be 0. - damage = 0; - invulpain = true; - goto fakepain; - } - else - return -1; - } - } - else - { - // Players are optionally excluded from getting thrust by damage. - if (static_cast(target)->PlayerFlags & PPF_NOTHRUSTWHENINVUL) - { - if (fakedPain) - plrDontThrust = 1; - else - return -1; - } - } - - } - - if (inflictor != NULL) - { - if (inflictor->flags5 & MF5_PIERCEARMOR) - flags |= DMG_NO_ARMOR; - } - - MeansOfDeath = mod; - // [RH] Andy Baker's Stealth monsters - if (target->flags & MF_STEALTH) - { - target->alpha = OPAQUE; - target->visdir = -1; - } - if (target->flags & MF_SKULLFLY) - { - target->velx = target->vely = target->velz = 0; - } - - player = target->player; - if (!(flags & DMG_FORCED)) // DMG_FORCED skips all special damage checks, TELEFRAG_DAMAGE may not be reduced at all - { - if (target->flags2 & MF2_DORMANT) - { - // Invulnerable, and won't wake up - return -1; - } - - if ((rawdamage < TELEFRAG_DAMAGE) || (target->flags7 & MF7_LAXTELEFRAGDMG)) // TELEFRAG_DAMAGE may only be reduced with LAXTELEFRAGDMG or it may not guarantee its effect. - { - if (player && damage > 1) - { - // Take half damage in trainer mode - damage = FixedMul(damage, G_SkillProperty(SKILLP_DamageFactor)); - } - // Special damage types - if (inflictor) - { - if (inflictor->flags4 & MF4_SPECTRAL) - { - if (player != NULL) - { - if (!deathmatch && inflictor->FriendPlayer > 0) - return -1; - } - else if (target->flags4 & MF4_SPECTRAL) - { - if (inflictor->FriendPlayer == 0 && !target->IsHostile(inflictor)) - return -1; - } - } - - damage = inflictor->DoSpecialDamage(target, damage, mod); - if (damage < 0) - { - return -1; - } - } - - int olddam = damage; - - if (damage > 0 && source != NULL) - { - damage = FixedMul(damage, source->DamageMultiply); - - // Handle active damage modifiers (e.g. PowerDamage) - if (damage > 0 && source->Inventory != NULL) - { - source->Inventory->ModifyDamage(damage, mod, damage, false); - } - } - // Handle passive damage modifiers (e.g. PowerProtection), provided they are not afflicted with protection penetrating powers. - if (damage > 0 && (target->Inventory != NULL) && !(flags & DMG_NO_PROTECT)) - { - target->Inventory->ModifyDamage(damage, mod, damage, true); - } - if (damage > 0 && !(flags & DMG_NO_FACTOR)) - { - damage = FixedMul(damage, target->DamageFactor); - if (damage > 0) - { - damage = DamageTypeDefinition::ApplyMobjDamageFactor(damage, mod, target->GetClass()->ActorInfo->DamageFactors); - } - } - - if (damage >= 0) - { - damage = target->TakeSpecialDamage(inflictor, source, damage, mod); - } - - // '<0' is handled below. This only handles the case where damage gets reduced to 0. - if (damage == 0 && olddam > 0) - { - { // Still allow FORCEPAIN - if (forcedPain) - { - goto dopain; - } - else if (fakedPain) - { - goto fakepain; - } - return -1; - } - } - } - if (target->flags5 & MF5_NODAMAGE) - { - damage = 0; - } - } - if (damage < 0) - { - // any negative value means that something in the above chain has cancelled out all damage and all damage effects, including pain. - return -1; - } - // Push the target unless the source's weapon's kickback is 0. - // (i.e. Gauntlets/Chainsaw) - if (!plrDontThrust && inflictor && inflictor != target // [RH] Not if hurting own self - && !(target->flags & MF_NOCLIP) - && !(inflictor->flags2 & MF2_NODMGTHRUST) - && !(flags & DMG_THRUSTLESS) - && !(target->flags7 & MF7_DONTTHRUST) - && (source == NULL || source->player == NULL || !(source->flags2 & MF2_NODMGTHRUST))) - { - int kickback; - - if (inflictor && inflictor->projectileKickback) - kickback = inflictor->projectileKickback; - else if (!source || !source->player || !source->player->ReadyWeapon) - kickback = gameinfo.defKickback; - else - kickback = source->player->ReadyWeapon->Kickback; - - if (kickback) - { - AActor *origin = (source && (flags & DMG_INFLICTOR_IS_PUFF))? source : inflictor; - - // If the origin and target are in exactly the same spot, choose a random direction. - // (Most likely cause is from telefragging somebody during spawning because they - // haven't moved from their spawn spot at all.) - if (origin->X() == target->X() && origin->Y() == target->Y()) - { - ang = pr_kickbackdir.GenRand32(); - } - else - { - ang = origin->AngleTo(target); - } - - // Calculate this as float to avoid overflows so that the - // clamping that had to be done here can be removed. - double fltthrust; - - fltthrust = mod == NAME_MDK ? 10 : 32; - if (target->Mass > 0) - { - fltthrust = clamp((damage * 0.125 * kickback) / target->Mass, 0., fltthrust); - } - - thrust = FLOAT2FIXED(fltthrust); - - // Don't apply ultra-small damage thrust - if (thrust < FRACUNIT/100) thrust = 0; - - // make fall forwards sometimes - if ((damage < 40) && (damage > target->health) - && (target->Z() - origin->Z() > 64*FRACUNIT) - && (pr_damagemobj()&1) - // [RH] But only if not too fast and not flying - && thrust < 10*FRACUNIT - && !(target->flags & MF_NOGRAVITY) - && (inflictor == NULL || !(inflictor->flags5 & MF5_NOFORWARDFALL)) - ) - { - ang += ANG180; - thrust *= 4; - } - ang >>= ANGLETOFINESHIFT; - if (source && source->player && (flags & DMG_INFLICTOR_IS_PUFF) - && source->player->ReadyWeapon != NULL && - (source->player->ReadyWeapon->WeaponFlags & WIF_STAFF2_KICKBACK)) - { - // Staff power level 2 - target->velx += FixedMul (10*FRACUNIT, finecosine[ang]); - target->vely += FixedMul (10*FRACUNIT, finesine[ang]); - if (!(target->flags & MF_NOGRAVITY)) - { - target->velz += 5*FRACUNIT; - } - } - else - { - target->velx += FixedMul (thrust, finecosine[ang]); - target->vely += FixedMul (thrust, finesine[ang]); - } - } - } - - // [RH] Avoid friendly fire if enabled - if (!(flags & DMG_FORCED) && source != NULL && - ((player && player != source->player) || (!player && target != source)) && - target->IsTeammate (source)) - { - //Use the original damage to check for telefrag amount. Don't let the now-amplified damagetypes do it. - if (rawdamage < TELEFRAG_DAMAGE || (target->flags7 & MF7_LAXTELEFRAGDMG)) - { // Still allow telefragging :-( - damage = (int)((float)damage * level.teamdamage); - if (damage < 0) - { - return damage; - } - else if (damage == 0) - { - if (forcedPain) - { - goto dopain; - } - else if (fakedPain) - { - goto fakepain; - } - return -1; - } - } - } - - // - // player specific - // - if (player) - { - //Added by MC: Lets bots look allround for enemies if they survive an ambush. - if (player->Bot != NULL) - { - player->Bot->allround = true; - } - - // end of game hell hack - if ((target->Sector->Flags & SECF_ENDLEVEL) && damage >= target->health) - { - damage = target->health - 1; - } - - if (!(flags & DMG_FORCED)) - { - // check the real player, not a voodoo doll here for invulnerability effects - if ((rawdamage < TELEFRAG_DAMAGE && ((player->mo->flags2 & MF2_INVULNERABLE) || - (player->cheats & CF_GODMODE))) || - (player->cheats & CF_GODMODE2) || (player->mo->flags5 & MF5_NODAMAGE)) - //Absolutely no hurting if NODAMAGE is involved. Same for GODMODE2. - { // player is invulnerable, so don't hurt him - //Make sure no godmodes and NOPAIN flags are found first. - //Then, check to see if the player has NODAMAGE or ALLOWPAIN, or inflictor has CAUSEPAIN. - if ((player->cheats & CF_GODMODE) || (player->cheats & CF_GODMODE2) || (player->mo->flags5 & MF5_NOPAIN)) - return -1; - else if ((((player->mo->flags7 & MF7_ALLOWPAIN) || (player->mo->flags5 & MF5_NODAMAGE)) || ((inflictor != NULL) && (inflictor->flags7 & MF7_CAUSEPAIN)))) - { - invulpain = true; - goto fakepain; - } - else - return -1; - } - - if (!(flags & DMG_NO_ARMOR) && player->mo->Inventory != NULL) - { - int newdam = damage; - if (damage > 0) - { - player->mo->Inventory->AbsorbDamage(damage, mod, newdam); - } - if ((rawdamage < TELEFRAG_DAMAGE) || (player->mo->flags7 & MF7_LAXTELEFRAGDMG)) //rawdamage is never modified. - { - // if we are telefragging don't let the damage value go below that magic value. Some further checks would fail otherwise. - damage = newdam; - } - - if (damage <= 0) - { - // If MF6_FORCEPAIN is set, make the player enter the pain state. - if (!(target->flags5 & MF5_NOPAIN) && inflictor != NULL && - (inflictor->flags6 & MF6_FORCEPAIN) && !(inflictor->flags5 & MF5_PAINLESS) - && (!(player->mo->flags2 & MF2_INVULNERABLE)) && (!(player->cheats & CF_GODMODE)) && (!(player->cheats & CF_GODMODE2))) - { - goto dopain; - } - return damage; - } - } - - if (damage >= player->health && rawdamage < TELEFRAG_DAMAGE - && (G_SkillProperty(SKILLP_AutoUseHealth) || deathmatch) - && !player->morphTics) - { // Try to use some inventory health - P_AutoUseHealth (player, damage - player->health + 1); - } - } - - player->health -= damage; // mirror mobj health here for Dave - // [RH] Make voodoo dolls and real players record the same health - target->health = player->mo->health -= damage; - if (player->health < 50 && !deathmatch && !(flags & DMG_FORCED)) - { - P_AutoUseStrifeHealth (player); - player->mo->health = player->health; - } - if (player->health <= 0) - { - // [SP] Buddha cheat: if the player is about to die, rescue him to 1 health. - // This does not save the player if damage >= TELEFRAG_DAMAGE, still need to - // telefrag him right? ;) (Unfortunately the damage is "absorbed" by armor, - // but telefragging should still do enough damage to kill the player) - // Ignore players that are already dead. - // [MC]Buddha2 absorbs telefrag damage, and anything else thrown their way. - if (!(flags & DMG_FORCED) && (((player->cheats & CF_BUDDHA2) || (((player->cheats & CF_BUDDHA) || (player->mo->flags7 & MF7_BUDDHA)) && (rawdamage < TELEFRAG_DAMAGE))) && (player->playerstate != PST_DEAD))) - { - // If this is a voodoo doll we need to handle the real player as well. - player->mo->health = target->health = player->health = 1; - } - else - { - player->health = 0; - } - } - player->LastDamageType = mod; - player->attacker = source; - player->damagecount += damage; // add damage after armor / invuln - if (player->damagecount > 100) - { - player->damagecount = 100; // teleport stomp does 10k points... - } - temp = damage < 100 ? damage : 100; - if (player == &players[consoleplayer]) - { - I_Tactile (40,10,40+temp*2); - } - } - else - { - // Armor for monsters. - if (!(flags & (DMG_NO_ARMOR|DMG_FORCED)) && target->Inventory != NULL && damage > 0) - { - int newdam = damage; - target->Inventory->AbsorbDamage (damage, mod, newdam); - damage = newdam; - if (damage <= 0) - { - if (fakedPain) - goto fakepain; - else - return damage; - } - } - - target->health -= damage; - } - - // - // the damage has been dealt; now deal with the consequences - // - target->DamageTypeReceived = mod; - - // If the damaging player has the power of drain, give the player 50% of the damage - // done in health. - if ( source && source->player && source->player->cheats & CF_DRAIN && !(target->flags5 & MF5_DONTDRAIN)) - { - if (!target->player || target->player != source->player) - { - if ( P_GiveBody( source, damage / 2 )) - { - S_Sound( source, CHAN_ITEM, "*drainhealth", 1, ATTN_NORM ); - } - } - } - - - if (target->health <= 0) - { - //[MC]Buddha flag for monsters. - if (!(flags & DMG_FORCED) && ((target->flags7 & MF7_BUDDHA) && (rawdamage < TELEFRAG_DAMAGE) && ((inflictor == NULL || !(inflictor->flags7 & MF7_FOILBUDDHA)) && !(flags & DMG_FOILBUDDHA)))) - { //FOILBUDDHA or Telefrag damage must kill it. - target->health = 1; - } - else - { - - // Death - target->special1 = damage; - - // use inflictor's death type if it got one. - if (inflictor && inflictor->DeathType != NAME_None) mod = inflictor->DeathType; - - // check for special fire damage or ice damage deaths - if (mod == NAME_Fire) - { - if (player && !player->morphTics) - { // Check for flame death - if (!inflictor || - ((target->health > -50) && (damage > 25)) || - !(inflictor->flags5 & MF5_SPECIALFIREDAMAGE)) - { - target->DamageType = NAME_Fire; - } - } - else - { - target->DamageType = NAME_Fire; - } - } - else - { - target->DamageType = mod; - } - if (source && source->tracer && (source->flags5 & MF5_SUMMONEDMONSTER)) - { // Minotaur's kills go to his master - // Make sure still alive and not a pointer to fighter head - if (source->tracer->player && (source->tracer->player->mo == source->tracer)) - { - source = source->tracer; - } - } - target->Die (source, inflictor, flags); - return damage; - } - } - - woundstate = target->FindState(NAME_Wound, mod); - if (woundstate != NULL) - { - int woundhealth = RUNTIME_TYPE(target)->Meta.GetMetaInt (AMETA_WoundHealth, 6); - - if (target->health <= woundhealth) - { - target->SetState (woundstate); - return damage; - } - } - -fakepain: //Needed so we can skip the rest of the above, but still obey the original rules. - - if (!(target->flags5 & MF5_NOPAIN) && (inflictor == NULL || !(inflictor->flags5 & MF5_PAINLESS)) && - (target->player != NULL || !G_SkillProperty(SKILLP_NoPain)) && !(target->flags & MF_SKULLFLY)) - { - pc = target->GetClass()->ActorInfo->PainChances; - painchance = target->PainChance; - if (pc != NULL) - { - int *ppc = pc->CheckKey(mod); - if (ppc != NULL) - { - painchance = *ppc; - } - } - - if (((damage >= target->PainThreshold) && (pr_damagemobj() < painchance)) - || (inflictor != NULL && (inflictor->flags6 & MF6_FORCEPAIN))) - { -dopain: - if (mod == NAME_Electric) - { - if (pr_lightning() < 96) - { - justhit = true; - FState *painstate = target->FindState(NAME_Pain, mod); - if (painstate != NULL) - target->SetState(painstate); - } - else - { // "electrocute" the target - target->renderflags |= RF_FULLBRIGHT; - if ((target->flags3 & MF3_ISMONSTER) && pr_lightning() < 128) - { - target->Howl (); - } - } - } - else - { - justhit = true; - FState *painstate = target->FindState(NAME_Pain, ((inflictor && inflictor->PainType != NAME_None) ? inflictor->PainType : mod)); - if (painstate != NULL) - target->SetState(painstate); - if (mod == NAME_PoisonCloud) - { - if ((target->flags3 & MF3_ISMONSTER) && pr_poison() < 128) - { - target->Howl (); - } - } - } - } - } - //ALLOWPAIN and CAUSEPAIN can still trigger infighting, even if no pain state is worked out. - target->reactiontime = 0; // we're awake now... - if (source) - { - if (source == target->target) - { - target->threshold = BASETHRESHOLD; - if (target->state == target->SpawnState && target->SeeState != NULL) - { - target->SetState (target->SeeState); - } - } - else if (source != target->target && target->OkayToSwitchTarget (source)) - { - // Target actor is not intent on another actor, - // so make him chase after source - - // killough 2/15/98: remember last enemy, to prevent - // sleeping early; 2/21/98: Place priority on players - - if (target->lastenemy == NULL || - (target->lastenemy->player == NULL && target->TIDtoHate == 0) || - target->lastenemy->health <= 0) - { - target->lastenemy = target->target; // remember last enemy - killough - } - target->target = source; - target->threshold = BASETHRESHOLD; - if (target->state == target->SpawnState && target->SeeState != NULL) - { - target->SetState (target->SeeState); - } - } - } - - // killough 11/98: Don't attack a friend, unless hit by that friend. - if (justhit && (target->target == source || !target->target || !target->IsFriend(target->target))) - target->flags |= MF_JUSTHIT; // fight back! - - if (invulpain) //Note that this takes into account all the cheats a player has, in terms of invulnerability. - { - return -1; //NOW we return -1! - } - return damage; -} - -void P_PoisonMobj (AActor *target, AActor *inflictor, AActor *source, int damage, int duration, int period, FName type) -{ - // Check for invulnerability. - if (!(inflictor->flags6 & MF6_POISONALWAYS)) - { - if (target->flags2 & MF2_INVULNERABLE) - { // actor is invulnerable - if (target->player == NULL) - { - if (!(inflictor->flags3 & MF3_FOILINVUL)) - { - return; - } - } - else - { - return; - } - } - } - - target->Poisoner = source; - target->PoisonDamageTypeReceived = type; - target->PoisonPeriodReceived = period; - - if (inflictor->flags6 & MF6_ADDITIVEPOISONDAMAGE) - { - target->PoisonDamageReceived += damage; - } - else - { - target->PoisonDamageReceived = damage; - } - - if (inflictor->flags6 & MF6_ADDITIVEPOISONDURATION) - { - target->PoisonDurationReceived += duration; - } - else - { - target->PoisonDurationReceived = duration; - } - -} - -bool AActor::OkayToSwitchTarget (AActor *other) -{ - if (other == this) - return false; // [RH] Don't hate self (can happen when shooting barrels) - - if (other->flags7 & MF7_NEVERTARGET) - return false; // never EVER target me! - - if (!(other->flags & MF_SHOOTABLE)) - return false; // Don't attack things that can't be hurt - - if ((flags4 & MF4_NOTARGETSWITCH) && target != NULL) - return false; // Don't switch target if not allowed - - if ((master != NULL && other->IsA(master->GetClass())) || // don't attack your master (or others of its type) - (other->master != NULL && IsA(other->master->GetClass()))) // don't attack your minion (or those of others of your type) - { - if (!IsHostile (other) && // allow target switch if other is considered hostile - (other->tid != TIDtoHate || TIDtoHate == 0) && // or has the tid we hate - other->TIDtoHate == TIDtoHate) // or has different hate information - { - return false; - } - } - - if ((other->flags3 & MF3_NOTARGET) && - (other->tid != TIDtoHate || TIDtoHate == 0) && - !IsHostile (other)) - return false; - if (threshold != 0 && !(flags4 & MF4_QUICKTORETALIATE)) - return false; - if (IsFriend (other)) - { // [RH] Friendlies don't target other friendlies - return false; - } - - int infight; - if (flags5 & MF5_NOINFIGHTING) infight=-1; - else infight = G_SkillProperty(SKILLP_Infight); - - if (infight < 0 && other->player == NULL && !IsHostile (other)) - { - return false; // infighting off: Non-friendlies don't target other non-friendlies - } - if (TIDtoHate != 0 && TIDtoHate == other->TIDtoHate) - return false; // [RH] Don't target "teammates" - if (other->player != NULL && (flags4 & MF4_NOHATEPLAYERS)) - return false; // [RH] Don't target players - if (target != NULL && target->health > 0 && - TIDtoHate != 0 && target->tid == TIDtoHate && pr_switcher() < 128 && - P_CheckSight (this, target)) - return false; // [RH] Don't be too quick to give up things we hate - - return true; -} - -//========================================================================== -// -// P_PoisonPlayer - Sets up all data concerning poisoning -// -// poisoner is the object directly responsible for poisoning the player, -// such as a missile. source is the actor responsible for creating the -// poisoner. -// -//========================================================================== - -bool P_PoisonPlayer (player_t *player, AActor *poisoner, AActor *source, int poison) -{ - if((player->cheats&CF_GODMODE) || (player->mo->flags2 & MF2_INVULNERABLE) || (player->cheats & CF_GODMODE2)) - { - return false; - } - if (source != NULL && source->player != player && player->mo->IsTeammate (source)) - { - poison = (int)((float)poison * level.teamdamage); - } - if (poison > 0) - { - player->poisoncount += poison; - player->poisoner = source; - if (poisoner == NULL) - { - player->poisontype = player->poisonpaintype = NAME_None; - } - else - { // We need to record these in case the poisoner disappears before poisoncount reaches 0. - player->poisontype = poisoner->DamageType; - player->poisonpaintype = poisoner->PainType != NAME_None ? poisoner->PainType : poisoner->DamageType; - } - if(player->poisoncount > 100) - { - player->poisoncount = 100; - } - } - return true; -} - -//========================================================================== -// -// P_PoisonDamage - Similar to P_DamageMobj -// -//========================================================================== - -void P_PoisonDamage (player_t *player, AActor *source, int damage, - bool playPainSound) -{ - AActor *target; - - if (player == NULL) - { - return; - } - target = player->mo; - if (target->health <= 0) - { - return; - } - if ((damage < TELEFRAG_DAMAGE && ((target->flags2 & MF2_INVULNERABLE) || - (player->cheats & CF_GODMODE))) || (player->cheats & CF_GODMODE2)) - { // target is invulnerable - return; - } - // Take half damage in trainer mode - damage = FixedMul(damage, G_SkillProperty(SKILLP_DamageFactor)); - // Handle passive damage modifiers (e.g. PowerProtection) - if (target->Inventory != NULL) - { - target->Inventory->ModifyDamage(damage, player->poisontype, damage, true); - } - // Modify with damage factors - damage = FixedMul(damage, target->DamageFactor); - if (damage > 0) - { - damage = DamageTypeDefinition::ApplyMobjDamageFactor(damage, player->poisontype, target->GetClass()->ActorInfo->DamageFactors); - } - if (damage <= 0) - { // Damage was reduced to 0, so don't bother further. - return; - } - if (damage >= player->health - && (G_SkillProperty(SKILLP_AutoUseHealth) || deathmatch) - && !player->morphTics) - { // Try to use some inventory health - P_AutoUseHealth(player, damage - player->health+1); - } - player->health -= damage; // mirror mobj health here for Dave - if (player->health < 50 && !deathmatch) - { - P_AutoUseStrifeHealth(player); - } - if (player->health < 0) - { - player->health = 0; - } - player->attacker = source; - - // - // do the damage - // - target->health -= damage; - if (target->health <= 0) - { // Death - if ((((player->cheats & CF_BUDDHA) || (player->mo->flags7 & MF7_BUDDHA)) && damage < TELEFRAG_DAMAGE) || (player->cheats & CF_BUDDHA2)) - { // [SP] Save the player... - player->health = target->health = 1; - } - else - { - target->special1 = damage; - if (player && !player->morphTics) - { // Check for flame death - if ((player->poisontype == NAME_Fire) && (target->health > -50) && (damage > 25)) - { - target->DamageType = NAME_Fire; - } - else - { - target->DamageType = player->poisontype; - } - } - target->Die(source, source); - return; - } - } - if (!(level.time&63) && playPainSound) - { - FState *painstate = target->FindState(NAME_Pain, player->poisonpaintype); - if (painstate != NULL) - { - target->SetState(painstate); - } - } -/* - if((P_Random() < target->info->painchance) - && !(target->flags&MF_SKULLFLY)) - { - target->flags |= MF_JUSTHIT; // fight back! - P_SetMobjState(target, target->info->painstate); - } -*/ -} - - -CCMD (kill) -{ - if (argv.argc() > 1) - { - if (CheckCheatmode ()) - return; - - if (!stricmp (argv[1], "monsters")) - { - // Kill all the monsters - if (CheckCheatmode ()) - return; - - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_MASSACRE); - } - else - { - Net_WriteByte (DEM_KILLCLASSCHEAT); - Net_WriteString (argv[1]); - } - } - else - { - // If suiciding is disabled, then don't do it. - if (dmflags2 & DF2_NOSUICIDE) - return; - - // Kill the player - Net_WriteByte (DEM_SUICIDE); - } - C_HideConsole (); -} - -CCMD(remove) -{ - if (argv.argc() == 2) - { - if (CheckCheatmode()) - return; - - Net_WriteByte(DEM_REMOVE); - Net_WriteString(argv[1]); - C_HideConsole(); - } - else - { - Printf("Usage: remove \n"); - return; - } - -} \ No newline at end of file +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// $Id:$ +// +// Copyright (C) 1993-1996 by id Software, Inc. +// +// This source is available for distribution and/or modification +// only under the terms of the DOOM Source Code License as +// published by id Software. All rights reserved. +// +// The source is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License +// for more details. +// +// $Log:$ +// +// DESCRIPTION: +// Handling interactions (i.e., collisions). +// +//----------------------------------------------------------------------------- + + + + +// Data. +#include "doomdef.h" +#include "gstrings.h" + +#include "doomstat.h" + +#include "m_random.h" +#include "i_system.h" +#include "announcer.h" + +#include "am_map.h" + +#include "c_console.h" +#include "c_dispatch.h" + +#include "p_local.h" + +#include "p_lnspec.h" +#include "p_effect.h" +#include "p_acs.h" + +#include "b_bot.h" //Added by MC: + +#include "ravenshared.h" +#include "a_hexenglobal.h" +#include "a_sharedglobal.h" +#include "a_pickups.h" +#include "gi.h" +#include "templates.h" +#include "sbar.h" +#include "s_sound.h" +#include "g_level.h" +#include "d_net.h" +#include "d_netinf.h" + +static FRandom pr_obituary ("Obituary"); +static FRandom pr_botrespawn ("BotRespawn"); +static FRandom pr_killmobj ("ActorDie"); +FRandom pr_damagemobj ("ActorTakeDamage"); +static FRandom pr_lightning ("LightningDamage"); +static FRandom pr_poison ("PoisonDamage"); +static FRandom pr_switcher ("SwitchTarget"); +static FRandom pr_kickbackdir ("KickbackDir"); + +CVAR (Bool, cl_showsprees, true, CVAR_ARCHIVE) +CVAR (Bool, cl_showmultikills, true, CVAR_ARCHIVE) +EXTERN_CVAR (Bool, show_obituaries) + + +FName MeansOfDeath; + +// +// GET STUFF +// + +// +// P_TouchSpecialThing +// +void P_TouchSpecialThing (AActor *special, AActor *toucher) +{ + fixed_t delta = special->Z() - toucher->Z(); + + // The pickup is at or above the toucher's feet OR + // The pickup is below the toucher. + if (delta > toucher->height || delta < MIN(-32*FRACUNIT, -special->height)) + { // out of reach + return; + } + + // Dead thing touching. + // Can happen with a sliding player corpse. + if (toucher->health <= 0) + return; + + //Added by MC: Finished with this destination. + if (toucher->player != NULL && toucher->player->Bot != NULL && special == toucher->player->Bot->dest) + { + toucher->player->Bot->prev = toucher->player->Bot->dest; + toucher->player->Bot->dest = NULL; + } + + special->Touch (toucher); +} + + +// [RH] +// SexMessage: Replace parts of strings with gender-specific pronouns +// +// The following expansions are performed: +// %g -> he/she/it +// %h -> him/her/it +// %p -> his/her/its +// %o -> other (victim) +// %k -> killer +// +void SexMessage (const char *from, char *to, int gender, const char *victim, const char *killer) +{ + static const char *genderstuff[3][3] = + { + { "he", "him", "his" }, + { "she", "her", "her" }, + { "it", "it", "its" } + }; + static const int gendershift[3][3] = + { + { 2, 3, 3 }, + { 3, 3, 3 }, + { 2, 2, 3 } + }; + const char *subst = NULL; + + do + { + if (*from != '%') + { + *to++ = *from; + } + else + { + int gendermsg = -1; + + switch (from[1]) + { + case 'g': gendermsg = 0; break; + case 'h': gendermsg = 1; break; + case 'p': gendermsg = 2; break; + case 'o': subst = victim; break; + case 'k': subst = killer; break; + } + if (subst != NULL) + { + size_t len = strlen (subst); + memcpy (to, subst, len); + to += len; + from++; + subst = NULL; + } + else if (gendermsg < 0) + { + *to++ = '%'; + } + else + { + strcpy (to, genderstuff[gender][gendermsg]); + to += gendershift[gender][gendermsg]; + from++; + } + } + } while (*from++); +} + +// [RH] +// ClientObituary: Show a message when a player dies +// +void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgflags) +{ + FName mod; + const char *message; + const char *messagename; + char gendermessage[1024]; + int gender; + + // No obituaries for non-players, voodoo dolls or when not wanted + if (self->player == NULL || self->player->mo != self || !show_obituaries) + return; + + gender = self->player->userinfo.GetGender(); + + // Treat voodoo dolls as unknown deaths + if (inflictor && inflictor->player && inflictor->player->mo != inflictor) + MeansOfDeath = NAME_None; + + mod = MeansOfDeath; + message = NULL; + messagename = NULL; + + if (attacker == NULL || attacker->player != NULL) + { + if (mod == NAME_Telefrag) + { + if (AnnounceTelefrag (attacker, self)) + return; + } + else + { + if (AnnounceKill (attacker, self)) + return; + } + } + + switch (mod) + { + case NAME_Suicide: messagename = "OB_SUICIDE"; break; + case NAME_Falling: messagename = "OB_FALLING"; break; + case NAME_Crush: messagename = "OB_CRUSH"; break; + case NAME_Exit: messagename = "OB_EXIT"; break; + case NAME_Drowning: messagename = "OB_WATER"; break; + case NAME_Slime: messagename = "OB_SLIME"; break; + case NAME_Fire: if (attacker == NULL) messagename = "OB_LAVA"; break; + } + + // Check for being killed by a voodoo doll. + if (inflictor && inflictor->player && inflictor->player->mo != inflictor) + { + messagename = "OB_VOODOO"; + } + + if (messagename != NULL) + message = GStrings(messagename); + + if (attacker != NULL && message == NULL) + { + if (attacker == self) + { + message = GStrings("OB_KILLEDSELF"); + } + else if (attacker->player == NULL) + { + if (mod == NAME_Telefrag) + { + message = GStrings("OB_MONTELEFRAG"); + } + else if (mod == NAME_Melee && attacker->GetClass()->HitObituary.IsNotEmpty()) + { + message = attacker->GetClass()->HitObituary; + } + else if (attacker->GetClass()->Obituary.IsNotEmpty()) + { + message = attacker->GetClass()->Obituary; + } + } + } + + if (message == NULL && attacker != NULL && attacker->player != NULL) + { + if (self->player != attacker->player && self->IsTeammate(attacker)) + { + self = attacker; + gender = self->player->userinfo.GetGender(); + mysnprintf (gendermessage, countof(gendermessage), "OB_FRIENDLY%c", '1' + (pr_obituary() & 3)); + message = GStrings(gendermessage); + } + else + { + if (mod == NAME_Telefrag) message = GStrings("OB_MPTELEFRAG"); + if (message == NULL) + { + if (inflictor != NULL && inflictor->GetClass()->Obituary.IsNotEmpty()) + { + message = inflictor->GetClass()->Obituary; + } + if (message == NULL && (dmgflags & DMG_PLAYERATTACK) && attacker->player->ReadyWeapon != NULL) + { + message = attacker->player->ReadyWeapon->GetClass()->Obituary; + } + if (message == NULL) + { + switch (mod) + { + case NAME_BFGSplash: messagename = "OB_MPBFG_SPLASH"; break; + case NAME_Railgun: messagename = "OB_RAILGUN"; break; + } + if (messagename != NULL) + message = GStrings(messagename); + } + if (message == NULL) + { + message = attacker->GetClass()->Obituary; + } + } + } + } + else attacker = self; // for the message creation + + if (message != NULL && message[0] == '$') + { + message = GStrings[message+1]; + } + + if (message == NULL) + { + message = GStrings("OB_DEFAULT"); + } + + // [CK] Don't display empty strings + if (message == NULL || strlen(message) <= 0) + return; + + SexMessage (message, gendermessage, gender, + self->player->userinfo.GetName(), attacker->player->userinfo.GetName()); + Printf (PRINT_MEDIUM, "%s\n", gendermessage); +} + + +// +// KillMobj +// +EXTERN_CVAR (Int, fraglimit) + +void AActor::Die (AActor *source, AActor *inflictor, int dmgflags) +{ + // Handle possible unmorph on death + bool wasgibbed = (health < GetGibHealth()); + AActor *realthis = NULL; + int realstyle = 0; + int realhealth = 0; + if (P_MorphedDeath(this, &realthis, &realstyle, &realhealth)) + { + if (!(realstyle & MORPH_UNDOBYDEATHSAVES)) + { + if (wasgibbed) + { + int realgibhealth = realthis->GetGibHealth(); + if (realthis->health >= realgibhealth) + { + realthis->health = realgibhealth -1; // if morphed was gibbed, so must original be (where allowed)l + } + } + realthis->Die(source, inflictor, dmgflags); + } + return; + } + + // [SO] 9/2/02 -- It's rather funny to see an exploded player body with the invuln sparkle active :) + effects &= ~FX_RESPAWNINVUL; + //flags &= ~MF_INVINCIBLE; + + if (debugfile && this->player) + { + 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"); + } + + // [RH] Notify this actor's items. + for (AInventory *item = Inventory; item != NULL; ) + { + AInventory *next = item->Inventory; + item->OwnerDied(); + item = next; + } + + if (flags & MF_MISSILE) + { // [RH] When missiles die, they just explode + P_ExplodeMissile (this, NULL, NULL); + return; + } + // [RH] Set the target to the thing that killed it. Strife apparently does this. + if (source != NULL) + { + target = source; + } + + flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY); + if (!(flags4 & MF4_DONTFALL)) flags&=~MF_NOGRAVITY; + flags |= MF_DROPOFF; + if ((flags3 & MF3_ISMONSTER) || FindState(NAME_Raise) != NULL || IsKindOf(RUNTIME_CLASS(APlayerPawn))) + { // [RH] Only monsters get to be corpses. + // Objects with a raise state should get the flag as well so they can + // be revived by an Arch-Vile. Batman Doom needs this. + // [RC] And disable this if DONTCORPSE is set, of course. + if(!(flags6 & MF6_DONTCORPSE)) flags |= MF_CORPSE; + } + flags6 |= MF6_KILLED; + + // [RH] Allow the death height to be overridden using metadata. + fixed_t metaheight = -1; + if (DamageType == NAME_Fire) + { + metaheight = GetClass()->BurnHeight; + } + if (metaheight < 0) + { + metaheight = GetClass()->DeathHeight; + } + if (metaheight < 0) + { + height >>= 2; + } + else + { + height = MAX (metaheight, 0); + } + + // [RH] If the thing has a special, execute and remove it + // Note that the thing that killed it is considered + // the activator of the script. + // New: In Hexen, the thing that died is the activator, + // so now a level flag selects who the activator gets to be. + // Everything is now moved to P_ActivateThingSpecial(). + if (special && (!(flags & MF_SPECIAL) || (flags3 & MF3_ISMONSTER)) + && !(activationtype & THINGSPEC_NoDeathSpecial)) + { + P_ActivateThingSpecial(this, source, true); + } + + if (CountsAsKill()) + level.killed_monsters++; + + if (source && source->player) + { + if (CountsAsKill()) + { // count for intermission + source->player->killcount++; + } + + // Don't count any frags at level start, because they're just telefrags + // resulting from insufficient deathmatch starts, and it wouldn't be + // fair to count them toward a player's score. + if (player && level.maptime) + { + source->player->frags[player - players]++; + if (player == source->player) // [RH] Cumulative frag count + { + char buff[256]; + + player->fragcount--; + if (deathmatch && player->spreecount >= 5 && cl_showsprees) + { + SexMessage (GStrings("SPREEKILLSELF"), buff, + player->userinfo.GetGender(), player->userinfo.GetName(), + player->userinfo.GetName()); + StatusBar->AttachMessage (new DHUDMessageFadeOut (SmallFont, buff, + 1.5f, 0.2f, 0, 0, CR_WHITE, 3.f, 0.5f), MAKE_ID('K','S','P','R')); + } + } + else + { + if ((dmflags2 & DF2_YES_LOSEFRAG) && deathmatch) + player->fragcount--; + + if (this->IsTeammate(source)) + { + source->player->fragcount--; + } + else + { + ++source->player->fragcount; + ++source->player->spreecount; + } + + if (source->player->morphTics) + { // Make a super chicken + source->GiveInventoryType (RUNTIME_CLASS(APowerWeaponLevel2)); + } + + if (deathmatch && cl_showsprees) + { + const char *spreemsg; + char buff[256]; + + switch (source->player->spreecount) + { + case 5: + spreemsg = GStrings("SPREE5"); + break; + case 10: + spreemsg = GStrings("SPREE10"); + break; + case 15: + spreemsg = GStrings("SPREE15"); + break; + case 20: + spreemsg = GStrings("SPREE20"); + break; + case 25: + spreemsg = GStrings("SPREE25"); + break; + default: + spreemsg = NULL; + break; + } + + if (spreemsg == NULL && player->spreecount >= 5) + { + if (!AnnounceSpreeLoss (this)) + { + SexMessage (GStrings("SPREEOVER"), buff, player->userinfo.GetGender(), + player->userinfo.GetName(), source->player->userinfo.GetName()); + StatusBar->AttachMessage (new DHUDMessageFadeOut (SmallFont, buff, + 1.5f, 0.2f, 0, 0, CR_WHITE, 3.f, 0.5f), MAKE_ID('K','S','P','R')); + } + } + else if (spreemsg != NULL) + { + if (!AnnounceSpree (source)) + { + SexMessage (spreemsg, buff, player->userinfo.GetGender(), + player->userinfo.GetName(), source->player->userinfo.GetName()); + StatusBar->AttachMessage (new DHUDMessageFadeOut (SmallFont, buff, + 1.5f, 0.2f, 0, 0, CR_WHITE, 3.f, 0.5f), MAKE_ID('K','S','P','R')); + } + } + } + } + + // [RH] Multikills + if (player != source->player) + { + source->player->multicount++; + if (source->player->lastkilltime > 0) + { + if (source->player->lastkilltime < level.time - 3*TICRATE) + { + source->player->multicount = 1; + } + + if (deathmatch && + source->CheckLocalView (consoleplayer) && + cl_showmultikills) + { + const char *multimsg; + + switch (source->player->multicount) + { + case 1: + multimsg = NULL; + break; + case 2: + multimsg = GStrings("MULTI2"); + break; + case 3: + multimsg = GStrings("MULTI3"); + break; + case 4: + multimsg = GStrings("MULTI4"); + break; + default: + multimsg = GStrings("MULTI5"); + break; + } + if (multimsg != NULL) + { + char buff[256]; + + if (!AnnounceMultikill (source)) + { + SexMessage (multimsg, buff, player->userinfo.GetGender(), + player->userinfo.GetName(), source->player->userinfo.GetName()); + StatusBar->AttachMessage (new DHUDMessageFadeOut (SmallFont, buff, + 1.5f, 0.8f, 0, 0, CR_RED, 3.f, 0.5f), MAKE_ID('M','K','I','L')); + } + } + } + } + source->player->lastkilltime = level.time; + } + + // [RH] Implement fraglimit + if (deathmatch && fraglimit && + fraglimit <= D_GetFragCount (source->player)) + { + Printf ("%s\n", GStrings("TXT_FRAGLIMIT")); + G_ExitLevel (0, false); + } + } + } + else if (!multiplayer && CountsAsKill()) + { + // count all monster deaths, + // even those caused by other monsters + players[0].killcount++; + } + + if (player) + { + // [RH] Death messages + ClientObituary (this, inflictor, source, dmgflags); + + // Death script execution, care of Skull Tag + FBehavior::StaticStartTypedScripts (SCRIPT_Death, this, true); + + // [RH] Force a delay between death and respawn + player->respawn_time = level.time + TICRATE; + + //Added by MC: Respawn bots + if (bglobal.botnum && !demoplayback) + { + if (player->Bot != NULL) + player->Bot->t_respawn = (pr_botrespawn()%15)+((bglobal.botnum-1)*2)+TICRATE+1; + + //Added by MC: Discard enemies. + for (int i = 0; i < MAXPLAYERS; i++) + { + if (players[i].Bot != NULL && this == players[i].Bot->enemy) + { + if (players[i].Bot->dest == players[i].Bot->enemy) + players[i].Bot->dest = NULL; + players[i].Bot->enemy = NULL; + } + } + + player->spreecount = 0; + player->multicount = 0; + } + + // count environment kills against you + if (!source) + { + player->frags[player - players]++; + player->fragcount--; // [RH] Cumulative frag count + } + + flags &= ~MF_SOLID; + player->playerstate = PST_DEAD; + P_DropWeapon (player); + if (this == players[consoleplayer].camera && automapactive) + { + // don't die in auto map, switch view prior to dying + AM_Stop (); + } + + // [GRB] Clear extralight. When you killed yourself with weapon that + // called A_Light1/2 before it called A_Light0, extraligh remained. + player->extralight = 0; + } + + // [RH] If this is the unmorphed version of another monster, destroy this + // actor, because the morphed version is the one that will stick around in + // the level. + if (flags & MF_UNMORPHED) + { + Destroy (); + return; + } + + + + FState *diestate = NULL; + int gibhealth = GetGibHealth(); + ActorFlags4 iflags4 = inflictor == NULL ? ActorFlags4::FromInt(0) : inflictor->flags4; + bool extremelydead = ((health < gibhealth || iflags4 & MF4_EXTREMEDEATH) && !(iflags4 & MF4_NOEXTREMEDEATH)); + + // Special check for 'extreme' damage type to ensure that it gets recorded properly as an extreme death for subsequent checks. + if (DamageType == NAME_Extreme) + { + extremelydead = true; + DamageType = NAME_None; + } + + // find the appropriate death state. The order is: + // + // 1. If damagetype is not 'none' and death is extreme, try a damage type specific extreme death state + // 2. If no such state is found or death is not extreme try a damage type specific normal death state + // 3. If damagetype is 'ice' and actor is a monster or player, try the generic freeze death (unless prohibited) + // 4. If no state has been found and death is extreme, try the extreme death state + // 5. If no such state is found or death is not extreme try the regular death state. + // 6. If still no state has been found, destroy the actor immediately. + + if (DamageType != NAME_None) + { + if (extremelydead) + { + FName labels[] = { NAME_Death, NAME_Extreme, DamageType }; + diestate = FindState(3, labels, true); + } + if (diestate == NULL) + { + diestate = FindState (NAME_Death, DamageType, true); + if (diestate != NULL) extremelydead = false; + } + if (diestate == NULL) + { + if (DamageType == NAME_Ice) + { // If an actor doesn't have an ice death, we can still give them a generic one. + + if (!deh.NoAutofreeze && !(flags4 & MF4_NOICEDEATH) && (player || (flags3 & MF3_ISMONSTER))) + { + diestate = FindState(NAME_GenericFreezeDeath); + extremelydead = false; + } + } + } + } + if (diestate == NULL) + { + + // Don't pass on a damage type this actor cannot handle. + // (most importantly, prevent barrels from passing on ice damage.) + // Massacre must be preserved though. + if (DamageType != NAME_Massacre) + { + DamageType = NAME_None; + } + + if (extremelydead) + { // Extreme death + diestate = FindState (NAME_Death, NAME_Extreme, true); + } + if (diestate == NULL) + { // Normal death + extremelydead = false; + diestate = FindState (NAME_Death); + } + } + + if (extremelydead) + { + // We'll only get here if an actual extreme death state was used. + + // For players, mark the appropriate flag. + if (player != NULL) + { + player->cheats |= CF_EXTREMELYDEAD; + } + // If a non-player, mark as extremely dead for the crash state. + else if (health >= gibhealth) + { + health = gibhealth - 1; + } + } + + if (diestate != NULL) + { + SetState (diestate); + + if (tics > 1) + { + tics -= pr_killmobj() & 3; + if (tics < 1) + tics = 1; + } + } + else + { + Destroy(); + } +} + + + + +//--------------------------------------------------------------------------- +// +// PROC P_AutoUseHealth +// +//--------------------------------------------------------------------------- +static int CountHealth(TArray &Items) +{ + int counted = 0; + for(unsigned i = 0; i < Items.Size(); i++) + { + counted += Items[i]->Amount * Items[i]->health; + } + return counted; +} + +static int UseHealthItems(TArray &Items, int &saveHealth) +{ + int saved = 0; + + while (Items.Size() > 0 && saveHealth > 0) + { + int maxhealth = 0; + int index = -1; + + // Find the largest item in the list + for(unsigned i = 0; i < Items.Size(); i++) + { + if (Items[i]->health > maxhealth) + { + index = i; + maxhealth = Items[i]->health; + } + } + + // Now apply the health items, using the same logic as Heretic and Hexen. + int count = (saveHealth + maxhealth-1) / maxhealth; + for(int i = 0; i < count; i++) + { + saved += maxhealth; + saveHealth -= maxhealth; + if (--Items[index]->Amount == 0) + { + Items[index]->DepleteOrDestroy (); + Items.Delete(index); + break; + } + } + } + return saved; +} + +void P_AutoUseHealth(player_t *player, int saveHealth) +{ + TArray NormalHealthItems; + TArray LargeHealthItems; + + for(AInventory *inv = player->mo->Inventory; inv != NULL; inv = inv->Inventory) + { + if (inv->Amount > 0 && inv->IsKindOf(RUNTIME_CLASS(AHealthPickup))) + { + int mode = static_cast(inv)->autousemode; + + if (mode == 1) NormalHealthItems.Push(inv); + else if (mode == 2) LargeHealthItems.Push(inv); + } + } + + int normalhealth = CountHealth(NormalHealthItems); + int largehealth = CountHealth(LargeHealthItems); + + bool skilluse = !!G_SkillProperty(SKILLP_AutoUseHealth); + + if (skilluse && normalhealth >= saveHealth) + { // Use quartz flasks + player->health += UseHealthItems(NormalHealthItems, saveHealth); + } + else if (largehealth >= saveHealth) + { + // Use mystic urns + player->health += UseHealthItems(LargeHealthItems, saveHealth); + } + else if (skilluse && normalhealth + largehealth >= saveHealth) + { // Use mystic urns and quartz flasks + player->health += UseHealthItems(NormalHealthItems, saveHealth); + if (saveHealth > 0) player->health += UseHealthItems(LargeHealthItems, saveHealth); + } + player->mo->health = player->health; +} + +//============================================================================ +// +// P_AutoUseStrifeHealth +// +//============================================================================ +CVAR(Bool, sv_disableautohealth, false, CVAR_ARCHIVE|CVAR_SERVERINFO) + +void P_AutoUseStrifeHealth (player_t *player) +{ + TArray Items; + + for(AInventory *inv = player->mo->Inventory; inv != NULL; inv = inv->Inventory) + { + if (inv->Amount > 0 && inv->IsKindOf(RUNTIME_CLASS(AHealthPickup))) + { + int mode = static_cast(inv)->autousemode; + + if (mode == 3) Items.Push(inv); + } + } + + if (!sv_disableautohealth) + { + while (Items.Size() > 0) + { + int maxhealth = 0; + int index = -1; + + // Find the largest item in the list + for(unsigned i = 0; i < Items.Size(); i++) + { + if (Items[i]->health > maxhealth) + { + index = i; + maxhealth = Items[i]->Amount; + } + } + + while (player->health < 50) + { + if (!player->mo->UseInventory (Items[index])) + break; + } + if (player->health >= 50) return; + // Using all of this item was not enough so delete it and restart with the next best one + Items.Delete(index); + } + } +} + +/* +================= += += P_DamageMobj += += Damages both enemies and players += inflictor is the thing that caused the damage += creature or missile, can be NULL (slime, etc) += source is the thing to target after taking damage += creature or NULL += Source and inflictor are the same for melee attacks += source can be null for barrel explosions and other environmental stuff +================== +*/ + +static inline bool MustForcePain(AActor *target, AActor *inflictor) +{ + return (!(target->flags5 & MF5_NOPAIN) && inflictor != NULL && + (inflictor->flags6 & MF6_FORCEPAIN) && !(inflictor->flags5 & MF5_PAINLESS)); +} + +static inline bool isFakePain(AActor *target, AActor *inflictor, int damage) +{ + return ((target->flags7 & MF7_ALLOWPAIN && damage > 0) || ((inflictor != NULL) && (inflictor->flags7 & MF7_CAUSEPAIN))); +} + + +// Returns the amount of damage actually inflicted upon the target, or -1 if +// the damage was cancelled. +int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags) +{ + unsigned ang; + player_t *player = NULL; + fixed_t thrust; + int temp; + int painchance = 0; + FState * woundstate = NULL; + PainChanceList * pc = NULL; + bool justhit = false; + bool plrDontThrust = false; + bool invulpain = false; + bool fakedPain = false; + bool forcedPain = false; + int fakeDamage = 0; + int holdDamage = 0; + int rawdamage = damage; + + if (damage < 0) damage = 0; + + if (target == NULL || !((target->flags & MF_SHOOTABLE) || (target->flags6 & MF6_VULNERABLE))) + { // Shouldn't happen + return -1; + } + + //Rather than unnecessarily call the function over and over again, let's be a little more efficient. + fakedPain = (isFakePain(target, inflictor, damage)); + forcedPain = (MustForcePain(target, inflictor)); + + // Spectral targets only take damage from spectral projectiles. + if (target->flags4 & MF4_SPECTRAL && damage < TELEFRAG_DAMAGE) + { + if (inflictor == NULL || !(inflictor->flags4 & MF4_SPECTRAL)) + { + return -1; + } + } + if (target->health <= 0) + { + if (inflictor && mod == NAME_Ice && !(inflictor->flags7 & MF7_ICESHATTER)) + { + return -1; + } + else if (target->flags & MF_ICECORPSE) // frozen + { + target->tics = 1; + target->flags6 |= MF6_SHATTERING; + target->velx = target->vely = target->velz = 0; + } + return -1; + } + // [MC] Changed it to check rawdamage here for consistency, even though that doesn't actually do anything + // different here. At any rate, invulnerable is being checked before type factoring, which is then being + // checked by player cheats/invul/buddha followed by monster buddha. This is inconsistent. Don't let the + // original telefrag damage CHECK (rawdamage) be influenced by outside factors when looking at cheats/invul. + if ((target->flags2 & MF2_INVULNERABLE) && (rawdamage < TELEFRAG_DAMAGE) && (!(flags & DMG_FORCED))) + { // actor is invulnerable + if (target->player == NULL) + { + if (inflictor == NULL || (!(inflictor->flags3 & MF3_FOILINVUL) && !(flags & DMG_FOILINVUL))) + { + if (fakedPain) + { + // big mess here: What do we use for the pain threshold? + // We cannot run the various damage filters below so for consistency it needs to be 0. + damage = 0; + invulpain = true; + goto fakepain; + } + else + return -1; + } + } + else + { + // Players are optionally excluded from getting thrust by damage. + if (static_cast(target)->PlayerFlags & PPF_NOTHRUSTWHENINVUL) + { + if (fakedPain) + plrDontThrust = 1; + else + return -1; + } + } + + } + + if (inflictor != NULL) + { + if (inflictor->flags5 & MF5_PIERCEARMOR) + flags |= DMG_NO_ARMOR; + } + + MeansOfDeath = mod; + // [RH] Andy Baker's Stealth monsters + if (target->flags & MF_STEALTH) + { + target->alpha = OPAQUE; + target->visdir = -1; + } + if (target->flags & MF_SKULLFLY) + { + target->velx = target->vely = target->velz = 0; + } + + player = target->player; + if (!(flags & DMG_FORCED)) // DMG_FORCED skips all special damage checks, TELEFRAG_DAMAGE may not be reduced at all + { + if (target->flags2 & MF2_DORMANT) + { + // Invulnerable, and won't wake up + return -1; + } + + if ((rawdamage < TELEFRAG_DAMAGE) || (target->flags7 & MF7_LAXTELEFRAGDMG)) // TELEFRAG_DAMAGE may only be reduced with LAXTELEFRAGDMG or it may not guarantee its effect. + { + if (player && damage > 1) + { + // Take half damage in trainer mode + damage = FixedMul(damage, G_SkillProperty(SKILLP_DamageFactor)); + } + // Special damage types + if (inflictor) + { + if (inflictor->flags4 & MF4_SPECTRAL) + { + if (player != NULL) + { + if (!deathmatch && inflictor->FriendPlayer > 0) + return -1; + } + else if (target->flags4 & MF4_SPECTRAL) + { + if (inflictor->FriendPlayer == 0 && !target->IsHostile(inflictor)) + return -1; + } + } + + damage = inflictor->DoSpecialDamage(target, damage, mod); + if (damage < 0) + { + return -1; + } + } + + int olddam = damage; + + if (damage > 0 && source != NULL) + { + damage = FixedMul(damage, source->DamageMultiply); + + // Handle active damage modifiers (e.g. PowerDamage) + if (damage > 0 && source->Inventory != NULL) + { + source->Inventory->ModifyDamage(damage, mod, damage, false); + } + } + // Handle passive damage modifiers (e.g. PowerProtection), provided they are not afflicted with protection penetrating powers. + if (damage > 0 && (target->Inventory != NULL) && !(flags & DMG_NO_PROTECT)) + { + target->Inventory->ModifyDamage(damage, mod, damage, true); + } + if (damage > 0 && !(flags & DMG_NO_FACTOR)) + { + damage = FixedMul(damage, target->DamageFactor); + if (damage > 0) + { + damage = DamageTypeDefinition::ApplyMobjDamageFactor(damage, mod, target->GetClass()->DamageFactors); + } + } + + if (damage >= 0) + { + damage = target->TakeSpecialDamage(inflictor, source, damage, mod); + } + + // '<0' is handled below. This only handles the case where damage gets reduced to 0. + if (damage == 0 && olddam > 0) + { + { // Still allow FORCEPAIN + if (forcedPain) + { + goto dopain; + } + else if (fakedPain) + { + goto fakepain; + } + return -1; + } + } + } + if (target->flags5 & MF5_NODAMAGE) + { + damage = 0; + } + } + if (damage < 0) + { + // any negative value means that something in the above chain has cancelled out all damage and all damage effects, including pain. + return -1; + } + // Push the target unless the source's weapon's kickback is 0. + // (i.e. Gauntlets/Chainsaw) + if (!plrDontThrust && inflictor && inflictor != target // [RH] Not if hurting own self + && !(target->flags & MF_NOCLIP) + && !(inflictor->flags2 & MF2_NODMGTHRUST) + && !(flags & DMG_THRUSTLESS) + && !(target->flags7 & MF7_DONTTHRUST) + && (source == NULL || source->player == NULL || !(source->flags2 & MF2_NODMGTHRUST))) + { + int kickback; + + if (inflictor && inflictor->projectileKickback) + kickback = inflictor->projectileKickback; + else if (!source || !source->player || !source->player->ReadyWeapon) + kickback = gameinfo.defKickback; + else + kickback = source->player->ReadyWeapon->Kickback; + + if (kickback) + { + AActor *origin = (source && (flags & DMG_INFLICTOR_IS_PUFF))? source : inflictor; + + // If the origin and target are in exactly the same spot, choose a random direction. + // (Most likely cause is from telefragging somebody during spawning because they + // haven't moved from their spawn spot at all.) + if (origin->X() == target->X() && origin->Y() == target->Y()) + { + ang = pr_kickbackdir.GenRand32(); + } + else + { + ang = origin->AngleTo(target); + } + + // Calculate this as float to avoid overflows so that the + // clamping that had to be done here can be removed. + double fltthrust; + + fltthrust = mod == NAME_MDK ? 10 : 32; + if (target->Mass > 0) + { + fltthrust = clamp((damage * 0.125 * kickback) / target->Mass, 0., fltthrust); + } + + thrust = FLOAT2FIXED(fltthrust); + + // Don't apply ultra-small damage thrust + if (thrust < FRACUNIT/100) thrust = 0; + + // make fall forwards sometimes + if ((damage < 40) && (damage > target->health) + && (target->Z() - origin->Z() > 64*FRACUNIT) + && (pr_damagemobj()&1) + // [RH] But only if not too fast and not flying + && thrust < 10*FRACUNIT + && !(target->flags & MF_NOGRAVITY) + && (inflictor == NULL || !(inflictor->flags5 & MF5_NOFORWARDFALL)) + ) + { + ang += ANG180; + thrust *= 4; + } + ang >>= ANGLETOFINESHIFT; + if (source && source->player && (flags & DMG_INFLICTOR_IS_PUFF) + && source->player->ReadyWeapon != NULL && + (source->player->ReadyWeapon->WeaponFlags & WIF_STAFF2_KICKBACK)) + { + // Staff power level 2 + target->velx += FixedMul (10*FRACUNIT, finecosine[ang]); + target->vely += FixedMul (10*FRACUNIT, finesine[ang]); + if (!(target->flags & MF_NOGRAVITY)) + { + target->velz += 5*FRACUNIT; + } + } + else + { + target->velx += FixedMul (thrust, finecosine[ang]); + target->vely += FixedMul (thrust, finesine[ang]); + } + } + } + + // [RH] Avoid friendly fire if enabled + if (!(flags & DMG_FORCED) && source != NULL && + ((player && player != source->player) || (!player && target != source)) && + target->IsTeammate (source)) + { + //Use the original damage to check for telefrag amount. Don't let the now-amplified damagetypes do it. + if (rawdamage < TELEFRAG_DAMAGE || (target->flags7 & MF7_LAXTELEFRAGDMG)) + { // Still allow telefragging :-( + damage = (int)((float)damage * level.teamdamage); + if (damage < 0) + { + return damage; + } + else if (damage == 0) + { + if (forcedPain) + { + goto dopain; + } + else if (fakedPain) + { + goto fakepain; + } + return -1; + } + } + } + + // + // player specific + // + if (player) + { + //Added by MC: Lets bots look allround for enemies if they survive an ambush. + if (player->Bot != NULL) + { + player->Bot->allround = true; + } + + // end of game hell hack + if ((target->Sector->Flags & SECF_ENDLEVEL) && damage >= target->health) + { + damage = target->health - 1; + } + + if (!(flags & DMG_FORCED)) + { + // check the real player, not a voodoo doll here for invulnerability effects + if ((rawdamage < TELEFRAG_DAMAGE && ((player->mo->flags2 & MF2_INVULNERABLE) || + (player->cheats & CF_GODMODE))) || + (player->cheats & CF_GODMODE2) || (player->mo->flags5 & MF5_NODAMAGE)) + //Absolutely no hurting if NODAMAGE is involved. Same for GODMODE2. + { // player is invulnerable, so don't hurt him + //Make sure no godmodes and NOPAIN flags are found first. + //Then, check to see if the player has NODAMAGE or ALLOWPAIN, or inflictor has CAUSEPAIN. + if ((player->cheats & CF_GODMODE) || (player->cheats & CF_GODMODE2) || (player->mo->flags5 & MF5_NOPAIN)) + return -1; + else if ((((player->mo->flags7 & MF7_ALLOWPAIN) || (player->mo->flags5 & MF5_NODAMAGE)) || ((inflictor != NULL) && (inflictor->flags7 & MF7_CAUSEPAIN)))) + { + invulpain = true; + goto fakepain; + } + else + return -1; + } + + if (!(flags & DMG_NO_ARMOR) && player->mo->Inventory != NULL) + { + int newdam = damage; + if (damage > 0) + { + player->mo->Inventory->AbsorbDamage(damage, mod, newdam); + } + if ((rawdamage < TELEFRAG_DAMAGE) || (player->mo->flags7 & MF7_LAXTELEFRAGDMG)) //rawdamage is never modified. + { + // if we are telefragging don't let the damage value go below that magic value. Some further checks would fail otherwise. + damage = newdam; + } + + if (damage <= 0) + { + // If MF6_FORCEPAIN is set, make the player enter the pain state. + if (!(target->flags5 & MF5_NOPAIN) && inflictor != NULL && + (inflictor->flags6 & MF6_FORCEPAIN) && !(inflictor->flags5 & MF5_PAINLESS) + && (!(player->mo->flags2 & MF2_INVULNERABLE)) && (!(player->cheats & CF_GODMODE)) && (!(player->cheats & CF_GODMODE2))) + { + goto dopain; + } + return damage; + } + } + + if (damage >= player->health && rawdamage < TELEFRAG_DAMAGE + && (G_SkillProperty(SKILLP_AutoUseHealth) || deathmatch) + && !player->morphTics) + { // Try to use some inventory health + P_AutoUseHealth (player, damage - player->health + 1); + } + } + + player->health -= damage; // mirror mobj health here for Dave + // [RH] Make voodoo dolls and real players record the same health + target->health = player->mo->health -= damage; + if (player->health < 50 && !deathmatch && !(flags & DMG_FORCED)) + { + P_AutoUseStrifeHealth (player); + player->mo->health = player->health; + } + if (player->health <= 0) + { + // [SP] Buddha cheat: if the player is about to die, rescue him to 1 health. + // This does not save the player if damage >= TELEFRAG_DAMAGE, still need to + // telefrag him right? ;) (Unfortunately the damage is "absorbed" by armor, + // but telefragging should still do enough damage to kill the player) + // Ignore players that are already dead. + // [MC]Buddha2 absorbs telefrag damage, and anything else thrown their way. + if (!(flags & DMG_FORCED) && (((player->cheats & CF_BUDDHA2) || (((player->cheats & CF_BUDDHA) || (player->mo->flags7 & MF7_BUDDHA)) && (rawdamage < TELEFRAG_DAMAGE))) && (player->playerstate != PST_DEAD))) + { + // If this is a voodoo doll we need to handle the real player as well. + player->mo->health = target->health = player->health = 1; + } + else + { + player->health = 0; + } + } + player->LastDamageType = mod; + player->attacker = source; + player->damagecount += damage; // add damage after armor / invuln + if (player->damagecount > 100) + { + player->damagecount = 100; // teleport stomp does 10k points... + } + temp = damage < 100 ? damage : 100; + if (player == &players[consoleplayer]) + { + I_Tactile (40,10,40+temp*2); + } + } + else + { + // Armor for monsters. + if (!(flags & (DMG_NO_ARMOR|DMG_FORCED)) && target->Inventory != NULL && damage > 0) + { + int newdam = damage; + target->Inventory->AbsorbDamage (damage, mod, newdam); + damage = newdam; + if (damage <= 0) + { + if (fakedPain) + goto fakepain; + else + return damage; + } + } + + target->health -= damage; + } + + // + // the damage has been dealt; now deal with the consequences + // + target->DamageTypeReceived = mod; + + // If the damaging player has the power of drain, give the player 50% of the damage + // done in health. + if ( source && source->player && source->player->cheats & CF_DRAIN && !(target->flags5 & MF5_DONTDRAIN)) + { + if (!target->player || target->player != source->player) + { + if ( P_GiveBody( source, damage / 2 )) + { + S_Sound( source, CHAN_ITEM, "*drainhealth", 1, ATTN_NORM ); + } + } + } + + + if (target->health <= 0) + { + //[MC]Buddha flag for monsters. + if (!(flags & DMG_FORCED) && ((target->flags7 & MF7_BUDDHA) && (rawdamage < TELEFRAG_DAMAGE) && ((inflictor == NULL || !(inflictor->flags7 & MF7_FOILBUDDHA)) && !(flags & DMG_FOILBUDDHA)))) + { //FOILBUDDHA or Telefrag damage must kill it. + target->health = 1; + } + else + { + + // Death + target->special1 = damage; + + // use inflictor's death type if it got one. + if (inflictor && inflictor->DeathType != NAME_None) mod = inflictor->DeathType; + + // check for special fire damage or ice damage deaths + if (mod == NAME_Fire) + { + if (player && !player->morphTics) + { // Check for flame death + if (!inflictor || + ((target->health > -50) && (damage > 25)) || + !(inflictor->flags5 & MF5_SPECIALFIREDAMAGE)) + { + target->DamageType = NAME_Fire; + } + } + else + { + target->DamageType = NAME_Fire; + } + } + else + { + target->DamageType = mod; + } + if (source && source->tracer && (source->flags5 & MF5_SUMMONEDMONSTER)) + { // Minotaur's kills go to his master + // Make sure still alive and not a pointer to fighter head + if (source->tracer->player && (source->tracer->player->mo == source->tracer)) + { + source = source->tracer; + } + } + target->Die (source, inflictor, flags); + return damage; + } + } + + woundstate = target->FindState(NAME_Wound, mod); + if (woundstate != NULL) + { + int woundhealth = target->GetClass()->WoundHealth; + + if (target->health <= woundhealth) + { + target->SetState (woundstate); + return damage; + } + } + +fakepain: //Needed so we can skip the rest of the above, but still obey the original rules. + + if (!(target->flags5 & MF5_NOPAIN) && (inflictor == NULL || !(inflictor->flags5 & MF5_PAINLESS)) && + (target->player != NULL || !G_SkillProperty(SKILLP_NoPain)) && !(target->flags & MF_SKULLFLY)) + { + pc = target->GetClass()->PainChances; + painchance = target->PainChance; + if (pc != NULL) + { + int *ppc = pc->CheckKey(mod); + if (ppc != NULL) + { + painchance = *ppc; + } + } + + if (((damage >= target->PainThreshold) && (pr_damagemobj() < painchance)) + || (inflictor != NULL && (inflictor->flags6 & MF6_FORCEPAIN))) + { +dopain: + if (mod == NAME_Electric) + { + if (pr_lightning() < 96) + { + justhit = true; + FState *painstate = target->FindState(NAME_Pain, mod); + if (painstate != NULL) + target->SetState(painstate); + } + else + { // "electrocute" the target + target->renderflags |= RF_FULLBRIGHT; + if ((target->flags3 & MF3_ISMONSTER) && pr_lightning() < 128) + { + target->Howl (); + } + } + } + else + { + justhit = true; + FState *painstate = target->FindState(NAME_Pain, ((inflictor && inflictor->PainType != NAME_None) ? inflictor->PainType : mod)); + if (painstate != NULL) + target->SetState(painstate); + if (mod == NAME_PoisonCloud) + { + if ((target->flags3 & MF3_ISMONSTER) && pr_poison() < 128) + { + target->Howl (); + } + } + } + } + } + //ALLOWPAIN and CAUSEPAIN can still trigger infighting, even if no pain state is worked out. + target->reactiontime = 0; // we're awake now... + if (source) + { + if (source == target->target) + { + target->threshold = BASETHRESHOLD; + if (target->state == target->SpawnState && target->SeeState != NULL) + { + target->SetState (target->SeeState); + } + } + else if (source != target->target && target->OkayToSwitchTarget (source)) + { + // Target actor is not intent on another actor, + // so make him chase after source + + // killough 2/15/98: remember last enemy, to prevent + // sleeping early; 2/21/98: Place priority on players + + if (target->lastenemy == NULL || + (target->lastenemy->player == NULL && target->TIDtoHate == 0) || + target->lastenemy->health <= 0) + { + target->lastenemy = target->target; // remember last enemy - killough + } + target->target = source; + target->threshold = BASETHRESHOLD; + if (target->state == target->SpawnState && target->SeeState != NULL) + { + target->SetState (target->SeeState); + } + } + } + + // killough 11/98: Don't attack a friend, unless hit by that friend. + if (justhit && (target->target == source || !target->target || !target->IsFriend(target->target))) + target->flags |= MF_JUSTHIT; // fight back! + + if (invulpain) //Note that this takes into account all the cheats a player has, in terms of invulnerability. + { + return -1; //NOW we return -1! + } + return damage; +} + +void P_PoisonMobj (AActor *target, AActor *inflictor, AActor *source, int damage, int duration, int period, FName type) +{ + // Check for invulnerability. + if (!(inflictor->flags6 & MF6_POISONALWAYS)) + { + if (target->flags2 & MF2_INVULNERABLE) + { // actor is invulnerable + if (target->player == NULL) + { + if (!(inflictor->flags3 & MF3_FOILINVUL)) + { + return; + } + } + else + { + return; + } + } + } + + target->Poisoner = source; + target->PoisonDamageTypeReceived = type; + target->PoisonPeriodReceived = period; + + if (inflictor->flags6 & MF6_ADDITIVEPOISONDAMAGE) + { + target->PoisonDamageReceived += damage; + } + else + { + target->PoisonDamageReceived = damage; + } + + if (inflictor->flags6 & MF6_ADDITIVEPOISONDURATION) + { + target->PoisonDurationReceived += duration; + } + else + { + target->PoisonDurationReceived = duration; + } + +} + +bool AActor::OkayToSwitchTarget (AActor *other) +{ + if (other == this) + return false; // [RH] Don't hate self (can happen when shooting barrels) + + if (other->flags7 & MF7_NEVERTARGET) + return false; // never EVER target me! + + if (!(other->flags & MF_SHOOTABLE)) + return false; // Don't attack things that can't be hurt + + if ((flags4 & MF4_NOTARGETSWITCH) && target != NULL) + return false; // Don't switch target if not allowed + + if ((master != NULL && other->IsA(master->GetClass())) || // don't attack your master (or others of its type) + (other->master != NULL && IsA(other->master->GetClass()))) // don't attack your minion (or those of others of your type) + { + if (!IsHostile (other) && // allow target switch if other is considered hostile + (other->tid != TIDtoHate || TIDtoHate == 0) && // or has the tid we hate + other->TIDtoHate == TIDtoHate) // or has different hate information + { + return false; + } + } + + if ((other->flags3 & MF3_NOTARGET) && + (other->tid != TIDtoHate || TIDtoHate == 0) && + !IsHostile (other)) + return false; + if (threshold != 0 && !(flags4 & MF4_QUICKTORETALIATE)) + return false; + if (IsFriend (other)) + { // [RH] Friendlies don't target other friendlies + return false; + } + + int infight; + if (flags5 & MF5_NOINFIGHTING) infight=-1; + else infight = G_SkillProperty(SKILLP_Infight); + + if (infight < 0 && other->player == NULL && !IsHostile (other)) + { + return false; // infighting off: Non-friendlies don't target other non-friendlies + } + if (TIDtoHate != 0 && TIDtoHate == other->TIDtoHate) + return false; // [RH] Don't target "teammates" + if (other->player != NULL && (flags4 & MF4_NOHATEPLAYERS)) + return false; // [RH] Don't target players + if (target != NULL && target->health > 0 && + TIDtoHate != 0 && target->tid == TIDtoHate && pr_switcher() < 128 && + P_CheckSight (this, target)) + return false; // [RH] Don't be too quick to give up things we hate + + return true; +} + +//========================================================================== +// +// P_PoisonPlayer - Sets up all data concerning poisoning +// +// poisoner is the object directly responsible for poisoning the player, +// such as a missile. source is the actor responsible for creating the +// poisoner. +// +//========================================================================== + +bool P_PoisonPlayer (player_t *player, AActor *poisoner, AActor *source, int poison) +{ + if((player->cheats&CF_GODMODE) || (player->mo->flags2 & MF2_INVULNERABLE) || (player->cheats & CF_GODMODE2)) + { + return false; + } + if (source != NULL && source->player != player && player->mo->IsTeammate (source)) + { + poison = (int)((float)poison * level.teamdamage); + } + if (poison > 0) + { + player->poisoncount += poison; + player->poisoner = source; + if (poisoner == NULL) + { + player->poisontype = player->poisonpaintype = NAME_None; + } + else + { // We need to record these in case the poisoner disappears before poisoncount reaches 0. + player->poisontype = poisoner->DamageType; + player->poisonpaintype = poisoner->PainType != NAME_None ? poisoner->PainType : poisoner->DamageType; + } + if(player->poisoncount > 100) + { + player->poisoncount = 100; + } + } + return true; +} + +//========================================================================== +// +// P_PoisonDamage - Similar to P_DamageMobj +// +//========================================================================== + +void P_PoisonDamage (player_t *player, AActor *source, int damage, + bool playPainSound) +{ + AActor *target; + + if (player == NULL) + { + return; + } + target = player->mo; + if (target->health <= 0) + { + return; + } + if ((damage < TELEFRAG_DAMAGE && ((target->flags2 & MF2_INVULNERABLE) || + (player->cheats & CF_GODMODE))) || (player->cheats & CF_GODMODE2)) + { // target is invulnerable + return; + } + // Take half damage in trainer mode + damage = FixedMul(damage, G_SkillProperty(SKILLP_DamageFactor)); + // Handle passive damage modifiers (e.g. PowerProtection) + if (target->Inventory != NULL) + { + target->Inventory->ModifyDamage(damage, player->poisontype, damage, true); + } + // Modify with damage factors + damage = FixedMul(damage, target->DamageFactor); + if (damage > 0) + { + damage = DamageTypeDefinition::ApplyMobjDamageFactor(damage, player->poisontype, target->GetClass()->DamageFactors); + } + if (damage <= 0) + { // Damage was reduced to 0, so don't bother further. + return; + } + if (damage >= player->health + && (G_SkillProperty(SKILLP_AutoUseHealth) || deathmatch) + && !player->morphTics) + { // Try to use some inventory health + P_AutoUseHealth(player, damage - player->health+1); + } + player->health -= damage; // mirror mobj health here for Dave + if (player->health < 50 && !deathmatch) + { + P_AutoUseStrifeHealth(player); + } + if (player->health < 0) + { + player->health = 0; + } + player->attacker = source; + + // + // do the damage + // + target->health -= damage; + if (target->health <= 0) + { // Death + if ((((player->cheats & CF_BUDDHA) || (player->mo->flags7 & MF7_BUDDHA)) && damage < TELEFRAG_DAMAGE) || (player->cheats & CF_BUDDHA2)) + { // [SP] Save the player... + player->health = target->health = 1; + } + else + { + target->special1 = damage; + if (player && !player->morphTics) + { // Check for flame death + if ((player->poisontype == NAME_Fire) && (target->health > -50) && (damage > 25)) + { + target->DamageType = NAME_Fire; + } + else + { + target->DamageType = player->poisontype; + } + } + target->Die(source, source); + return; + } + } + if (!(level.time&63) && playPainSound) + { + FState *painstate = target->FindState(NAME_Pain, player->poisonpaintype); + if (painstate != NULL) + { + target->SetState(painstate); + } + } +/* + if((P_Random() < target->info->painchance) + && !(target->flags&MF_SKULLFLY)) + { + target->flags |= MF_JUSTHIT; // fight back! + P_SetMobjState(target, target->info->painstate); + } +*/ +} + + +CCMD (kill) +{ + if (argv.argc() > 1) + { + if (CheckCheatmode ()) + return; + + if (!stricmp (argv[1], "monsters")) + { + // Kill all the monsters + if (CheckCheatmode ()) + return; + + Net_WriteByte (DEM_GENERICCHEAT); + Net_WriteByte (CHT_MASSACRE); + } + else + { + Net_WriteByte (DEM_KILLCLASSCHEAT); + Net_WriteString (argv[1]); + } + } + else + { + // If suiciding is disabled, then don't do it. + if (dmflags2 & DF2_NOSUICIDE) + return; + + // Kill the player + Net_WriteByte (DEM_SUICIDE); + } + C_HideConsole (); +} + +CCMD(remove) +{ + if (argv.argc() == 2) + { + if (CheckCheatmode()) + return; + + Net_WriteByte(DEM_REMOVE); + Net_WriteString(argv[1]); + C_HideConsole(); + } + else + { + Printf("Usage: remove \n"); + return; + } + +} diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 192a217d87..a54bd8b98e 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -2754,19 +2754,19 @@ FUNC(LS_SetPlayerProperty) // Add or remove a power if (arg2 >= PROP_INVULNERABILITY && arg2 <= PROP_SPEED) { - static const PClass *powers[11] = + static PClass * const *powers[11] = { - RUNTIME_CLASS(APowerInvulnerable), - RUNTIME_CLASS(APowerStrength), - RUNTIME_CLASS(APowerInvisibility), - RUNTIME_CLASS(APowerIronFeet), + &RUNTIME_CLASS_CASTLESS(APowerInvulnerable), + &RUNTIME_CLASS_CASTLESS(APowerStrength), + &RUNTIME_CLASS_CASTLESS(APowerInvisibility), + &RUNTIME_CLASS_CASTLESS(APowerIronFeet), NULL, // MapRevealer - RUNTIME_CLASS(APowerLightAmp), - RUNTIME_CLASS(APowerWeaponLevel2), - RUNTIME_CLASS(APowerFlight), + &RUNTIME_CLASS_CASTLESS(APowerLightAmp), + &RUNTIME_CLASS_CASTLESS(APowerWeaponLevel2), + &RUNTIME_CLASS_CASTLESS(APowerFlight), NULL, NULL, - RUNTIME_CLASS(APowerSpeed) + &RUNTIME_CLASS_CASTLESS(APowerSpeed) }; int power = arg2 - PROP_INVULNERABILITY; @@ -2781,7 +2781,7 @@ FUNC(LS_SetPlayerProperty) { // Give power to activator if (power != 4) { - APowerup *item = static_cast(it->GiveInventoryType (powers[power])); + APowerup *item = static_cast(it->GiveInventoryType(static_cast(*powers[power]))); if (item != NULL && power == 0 && arg1 == 1) { item->BlendColor = MakeSpecialColormap(INVERSECOLORMAP); @@ -2796,7 +2796,7 @@ FUNC(LS_SetPlayerProperty) { // Take power from activator if (power != 4) { - AInventory *item = it->FindInventory (powers[power], true); + AInventory *item = it->FindInventory(static_cast(*powers[power]), true); if (item != NULL) { item->Destroy (); @@ -2821,7 +2821,7 @@ FUNC(LS_SetPlayerProperty) { // Give power if (power != 4) { - APowerup *item = static_cast(players[i].mo->GiveInventoryType (powers[power])); + APowerup *item = static_cast(players[i].mo->GiveInventoryType (static_cast(*powers[power]))); if (item != NULL && power == 0 && arg1 == 1) { item->BlendColor = MakeSpecialColormap(INVERSECOLORMAP); @@ -2836,7 +2836,7 @@ FUNC(LS_SetPlayerProperty) { // Take power if (power != 4) { - AInventory *item = players[i].mo->FindInventory (powers[power]); + AInventory *item = players[i].mo->FindInventory (static_cast(*powers[power])); if (item != NULL) { item->Destroy (); diff --git a/src/p_local.h b/src/p_local.h index 395a05990c..1064abbf9d 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -133,8 +133,8 @@ enum EPuffFlags PF_NORANDOMZ = 16 }; -AActor *P_SpawnPuff (AActor *source, const PClass *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags = 0, AActor *vict = NULL); -inline AActor *P_SpawnPuff(AActor *source, const PClass *pufftype, const fixedvec3 &pos, angle_t dir, int updown, int flags = 0, AActor *vict = NULL) +AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags = 0, AActor *vict = NULL); +inline AActor *P_SpawnPuff(AActor *source, PClassActor *pufftype, const fixedvec3 &pos, angle_t dir, int updown, int flags = 0, AActor *vict = NULL) { return P_SpawnPuff(source, pufftype, pos.x, pos.y, pos.z, dir, updown, flags, vict); } @@ -149,26 +149,30 @@ void P_RipperBlood (AActor *mo, AActor *bleeder); int P_GetThingFloorType (AActor *thing); void P_ExplodeMissile (AActor *missile, line_t *explodeline, AActor *target); -AActor *P_SpawnMissile (AActor* source, AActor* dest, const PClass *type, AActor* owner = NULL); -AActor *P_SpawnMissileZ (AActor* source, fixed_t z, AActor* dest, const PClass *type); -AActor *P_SpawnMissileXYZ (fixed_t x, fixed_t y, fixed_t z, AActor *source, AActor *dest, const PClass *type, bool checkspawn = true, AActor *owner = NULL); -inline AActor *P_SpawnMissileXYZ(const fixedvec3 &pos, AActor *source, AActor *dest, const PClass *type, bool checkspawn = true, AActor *owner = NULL) +AActor *P_OldSpawnMissile(AActor *source, AActor *owner, AActor *dest, PClassActor *type); +AActor *P_SpawnMissile (AActor* source, AActor* dest, PClassActor *type, AActor* owner = NULL); +AActor *P_SpawnMissileZ (AActor* source, fixed_t z, AActor* dest, PClassActor *type); +AActor *P_SpawnMissileXYZ (fixed_t x, fixed_t y, fixed_t z, AActor *source, AActor *dest, PClassActor *type, bool checkspawn = true, AActor *owner = NULL); +inline AActor *P_SpawnMissileXYZ(const fixedvec3 &pos, AActor *source, AActor *dest, PClassActor *type, bool checkspawn = true, AActor *owner = NULL) { return P_SpawnMissileXYZ(pos.x, pos.y, pos.z, source, dest, type, checkspawn, owner); } -AActor *P_SpawnMissileAngle (AActor *source, const PClass *type, angle_t angle, fixed_t velz); -AActor *P_SpawnMissileAngleSpeed (AActor *source, const PClass *type, angle_t angle, fixed_t velz, fixed_t speed); -AActor *P_SpawnMissileAngleZ (AActor *source, fixed_t z, const PClass *type, angle_t angle, fixed_t velz); -AActor *P_SpawnMissileAngleZSpeed (AActor *source, fixed_t z, const PClass *type, angle_t angle, fixed_t velz, fixed_t speed, AActor *owner=NULL, bool checkspawn = true); -AActor *P_SpawnMissileZAimed (AActor *source, fixed_t z, AActor *dest, const PClass *type); +AActor *P_SpawnMissileAngle (AActor *source, PClassActor *type, angle_t angle, fixed_t velz); +AActor *P_SpawnMissileAngleSpeed (AActor *source, PClassActor *type, angle_t angle, fixed_t velz, fixed_t speed); +AActor *P_SpawnMissileAngleZ (AActor *source, fixed_t z, PClassActor *type, angle_t angle, fixed_t velz); +AActor *P_SpawnMissileAngleZSpeed (AActor *source, fixed_t z, PClassActor *type, angle_t angle, fixed_t velz, fixed_t speed, AActor *owner=NULL, bool checkspawn = true); +AActor *P_SpawnMissileZAimed (AActor *source, fixed_t z, AActor *dest, PClassActor *type); -AActor *P_SpawnPlayerMissile (AActor* source, const PClass *type); -AActor *P_SpawnPlayerMissile (AActor *source, const PClass *type, angle_t angle); -AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, const PClass *type, angle_t angle, +AActor *P_SpawnPlayerMissile (AActor* source, PClassActor *type); +AActor *P_SpawnPlayerMissile (AActor *source, PClassActor *type, angle_t angle); +AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, PClassActor *type, angle_t angle, AActor **pLineTarget = NULL, AActor **MissileActor = NULL, bool nofreeaim = false, bool noautoaim = false); void P_CheckFakeFloorTriggers (AActor *mo, fixed_t oldz, bool oldz_has_viewheight=false); +AActor *P_SpawnSubMissile (AActor *source, PClassActor *type, AActor *target); // Strife uses it + + // // [RH] P_THINGS // @@ -186,7 +190,7 @@ void P_Thing_SetVelocity(AActor *actor, fixed_t vx, fixed_t vy, fixed_t vz, bool void P_RemoveThing(AActor * actor); bool P_Thing_Raise(AActor *thing, AActor *raiser); bool P_Thing_CanRaise(AActor *thing); -const PClass *P_GetSpawnableType(int spawnnum); +PClassActor *P_GetSpawnableType(int spawnnum); void InitSpawnablesFromMapinfo(); int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, fixed_t zofs, angle_t angle, int flags, fixed_t heightoffset, fixed_t radiusoffset, angle_t pitch); @@ -532,7 +536,7 @@ enum // P_LineAttack flags LAF_NOIMPACTDECAL = 4 }; -AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, const PClass *pufftype, int flags = 0, AActor **victim = NULL, int *actualdamage = NULL); +AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, PClassActor *pufftype, int flags = 0, AActor **victim = NULL, int *actualdamage = NULL); AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, FName pufftype, int flags = 0, AActor **victim = NULL, int *actualdamage = NULL); AActor *P_LinePickActor (AActor *t1, angle_t angle, fixed_t distance, int pitch, ActorFlags actorMask, DWORD wallMask); void P_TraceBleed (int damage, fixed_t x, fixed_t y, fixed_t z, AActor *target, angle_t angle, int pitch); @@ -542,7 +546,7 @@ void P_TraceBleed (int damage, AActor *target); // random direction version bool P_HitFloor (AActor *thing); bool P_HitWater (AActor *thing, sector_t *sec, fixed_t splashx = FIXED_MIN, fixed_t splashy = FIXED_MIN, fixed_t splashz=FIXED_MIN, bool checkabove = false, bool alert = true, bool force = false); void P_CheckSplash(AActor *self, fixed_t distance); -void P_RailAttack (AActor *source, int damage, int offset_xy, fixed_t offset_z = 0, int color1 = 0, int color2 = 0, double maxdiff = 0, int flags = 0, const PClass *puff = NULL, angle_t angleoffset = 0, angle_t pitchoffset = 0, fixed_t distance = 8192*FRACUNIT, int duration = 0, double sparsity = 1.0, double drift = 1.0, const PClass *spawnclass = NULL, int SpiralOffset = 270); // [RH] Shoot a railgun +void P_RailAttack (AActor *source, int damage, int offset_xy, fixed_t offset_z = 0, int color1 = 0, int color2 = 0, double maxdiff = 0, int flags = 0, PClassActor *puff = NULL, angle_t angleoffset = 0, angle_t pitchoffset = 0, fixed_t distance = 8192*FRACUNIT, int duration = 0, double sparsity = 1.0, double drift = 1.0, PClassActor *spawnclass = NULL, int SpiralOffset = 270); // [RH] Shoot a railgun enum // P_RailAttack / A_RailAttack / A_CustomRailgun / P_DrawRailTrail flags { diff --git a/src/p_map.cpp b/src/p_map.cpp index 31f31e16c2..6c95fd6f8f 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -3655,7 +3655,7 @@ static ETraceStatus CheckForActor(FTraceResults &res, void *userdata) //========================================================================== AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance, - int pitch, int damage, FName damageType, const PClass *pufftype, int flags, AActor **victim, int *actualdamage) + int pitch, int damage, FName damageType, PClassActor *pufftype, int flags, AActor **victim, int *actualdamage) { fixed_t vx, vy, vz, shootz; FTraceResults trace; @@ -3919,7 +3919,7 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance, AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, FName pufftype, int flags, AActor **victim, int *actualdamage) { - const PClass * type = PClass::FindClass(pufftype); + PClassActor *type = PClass::FindActor(pufftype); if (victim != NULL) { *victim = NULL; @@ -4180,7 +4180,7 @@ static ETraceStatus ProcessRailHit(FTraceResults &res, void *userdata) // // //========================================================================== -void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, int color1, int color2, double maxdiff, int railflags, const PClass *puffclass, angle_t angleoffset, angle_t pitchoffset, fixed_t distance, int duration, double sparsity, double drift, const PClass *spawnclass, int SpiralOffset) +void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, int color1, int color2, double maxdiff, int railflags, PClassActor *puffclass, angle_t angleoffset, angle_t pitchoffset, fixed_t distance, int duration, double sparsity, double drift, PClassActor *spawnclass, int SpiralOffset) { fixed_t vx, vy, vz; angle_t angle, pitch; @@ -4188,7 +4188,10 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i FTraceResults trace; fixed_t shootz; - if (puffclass == NULL) puffclass = PClass::FindClass(NAME_BulletPuff); + if (puffclass == NULL) + { + puffclass = PClass::FindActor(NAME_BulletPuff); + } pitch = ((angle_t)(-source->pitch) + pitchoffset) >> ANGLETOFINESHIFT; angle = (source->angle + angleoffset) >> ANGLETOFINESHIFT; @@ -4837,7 +4840,7 @@ void P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bo { points = points * splashfactor; } - points *= thing->GetClass()->Meta.GetMetaFixed(AMETA_RDFactor, FRACUNIT) / (double)FRACUNIT; + points *= thing->GetClass()->RDFactor / (float)FRACUNIT; // points and bombdamage should be the same sign if (((points * bombdamage) > 0) && P_CheckSight(thing, bombspot, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY)) @@ -4913,7 +4916,7 @@ void P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bo int damage = Scale(bombdamage, bombdistance - dist, bombdistance); damage = (int)((double)damage * splashfactor); - damage = Scale(damage, thing->GetClass()->Meta.GetMetaFixed(AMETA_RDFactor, FRACUNIT), FRACUNIT); + damage = Scale(damage, thing->GetClass()->RDFactor, FRACUNIT); if (damage > 0) { int newdam = P_DamageMobj(thing, bombspot, bombsource, damage, bombmod); @@ -5128,10 +5131,9 @@ void P_DoCrunch(AActor *thing, FChangePosition *cpos) if (!(thing->flags&MF_NOBLOOD)) { PalEntry bloodcolor = thing->GetBloodColor(); - const PClass *bloodcls = thing->GetBloodType(); - - P_TraceBleed(newdam > 0 ? newdam : cpos->crushchange, thing); - + PClassActor *bloodcls = thing->GetBloodType(); + + P_TraceBleed (newdam > 0 ? newdam : cpos->crushchange, thing); if (bloodcls != NULL) { AActor *mo; @@ -5692,7 +5694,7 @@ msecnode_t *P_AddSecnode(sector_t *s, AActor *thing, msecnode_t *nextnode) if (s == 0) { - I_FatalError("AddSecnode of 0 for %s\n", thing->_StaticType.TypeName.GetChars()); + I_FatalError("AddSecnode of 0 for %s\n", thing->GetClass()->TypeName.GetChars()); } node = nextnode; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 789c468d13..f83f156922 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -135,6 +135,7 @@ IMPLEMENT_POINTY_CLASS (AActor) DECLARE_POINTER (LastHeard) DECLARE_POINTER (master) DECLARE_POINTER (Poisoner) + DECLARE_POINTER (Damage) END_POINTERS AActor::~AActor () @@ -143,6 +144,79 @@ 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(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 +// +//========================================================================== + void AActor::Serialize (FArchive &arc) { Super::Serialize (arc); @@ -189,8 +263,19 @@ void AActor::Serialize (FArchive &arc) << vely << velz << tics - << state - << Damage; + << state; + if (arc.IsStoring()) + { + int dmg; + dmg = CalcDamageValue(Damage); + arc << dmg; + } + else + { + int dmg; + arc << dmg; + Damage = UncalcDamageValue(dmg, GetDefault()->Damage); + } if (SaveVersion >= 4530) { P_SerializeTerrain(arc, floorterrain); @@ -525,7 +610,16 @@ bool AActor::SetState (FState *newstate, bool nofunction) { // Check whether the called action function resulted in destroying the actor if (ObjectFlags & OF_EuthanizeMe) + { return false; + } + if (ObjectFlags & OF_StateChanged) + { // The action was an A_Jump-style function that wants to change the next state. + ObjectFlags &= ~OF_StateChanged; + newstate = state; + tics = 0; // make sure we loop and set the new state properly + continue; + } } newstate = newstate->GetNextState(); } while (tics == 0); @@ -601,7 +695,7 @@ void AActor::RemoveInventory(AInventory *item) // //============================================================================ -bool AActor::TakeInventory(const PClass *itemclass, int amount, bool fromdecorate, bool notakeinfinite) +bool AActor::TakeInventory(PClassActor *itemclass, int amount, bool fromdecorate, bool notakeinfinite) { AInventory *item = FindInventory(itemclass); @@ -754,13 +848,14 @@ AInventory *AActor::DropInventory (AInventory *item) // //============================================================================ -AInventory *AActor::FindInventory (const PClass *type, bool subclass) +AInventory *AActor::FindInventory (PClassActor *type, bool subclass) { AInventory *item; - if (type == NULL) return NULL; - - assert (type->ActorInfo != NULL); + if (type == NULL) + { + return NULL; + } for (item = Inventory; item != NULL; item = item->Inventory) { if (!subclass) @@ -783,7 +878,7 @@ AInventory *AActor::FindInventory (const PClass *type, bool subclass) AInventory *AActor::FindInventory (FName type) { - return FindInventory(PClass::FindClass(type)); + return FindInventory(PClass::FindActor(type)); } //============================================================================ @@ -792,7 +887,7 @@ AInventory *AActor::FindInventory (FName type) // //============================================================================ -AInventory *AActor::GiveInventoryType (const PClass *type) +AInventory *AActor::GiveInventoryType (PClassActor *type) { AInventory *item = NULL; @@ -816,7 +911,7 @@ AInventory *AActor::GiveInventoryType (const PClass *type) // //============================================================================ -bool AActor::GiveAmmo (const PClass *type, int amount) +bool AActor::GiveAmmo (PClassAmmo *type, int amount) { if (type != NULL) { @@ -1011,24 +1106,24 @@ bool AActor::IsVisibleToPlayer() const return true; if (VisibleToTeam != 0 && teamplay && - (signed)(VisibleToTeam-1) != players[consoleplayer].userinfo.GetTeam()) + (signed)(VisibleToTeam-1) != players[consoleplayer].userinfo.GetTeam() ) return false; const player_t* pPlayer = players[consoleplayer].camera->player; - if(pPlayer && pPlayer->mo && GetClass()->ActorInfo->VisibleToPlayerClass.Size() > 0) + if (pPlayer && pPlayer->mo && GetClass()->VisibleToPlayerClass.Size() > 0) { bool visible = false; - for(unsigned int i = 0;i < GetClass()->ActorInfo->VisibleToPlayerClass.Size();++i) + for(unsigned int i = 0;i < GetClass()->VisibleToPlayerClass.Size();++i) { - const PClass *cls = GetClass()->ActorInfo->VisibleToPlayerClass[i]; - if(cls && pPlayer->mo->GetClass()->IsDescendantOf(cls)) + PClassPlayerPawn *cls = GetClass()->VisibleToPlayerClass[i]; + if (cls && pPlayer->mo->GetClass()->IsDescendantOf(cls)) { visible = true; break; } } - if(!visible) + if (!visible) return false; } @@ -1122,7 +1217,7 @@ bool AActor::Grind(bool items) { if (this->flags4 & MF4_BOSSDEATH) { - CALL_ACTION(A_BossDeath, this); + A_BossDeath(this); } flags &= ~MF_SOLID; flags3 |= MF3_DONTGIB; @@ -1140,10 +1235,10 @@ bool AActor::Grind(bool items) { if (this->flags4 & MF4_BOSSDEATH) { - CALL_ACTION(A_BossDeath, this); + A_BossDeath(this); } - const PClass *i = PClass::FindClass("RealGibs"); + PClassActor *i = PClass::FindActor("RealGibs"); if (i != NULL) { @@ -2684,7 +2779,7 @@ void P_NightmareRespawn (AActor *mobj) // spawn it x = mobj->SpawnPoint[0]; y = mobj->SpawnPoint[1]; - mo = AActor::StaticSpawn(RUNTIME_TYPE(mobj), x, y, z, NO_REPLACE, true); + mo = AActor::StaticSpawn(mobj->GetClass(), x, y, z, NO_REPLACE, true); if (z == ONFLOORZ) { @@ -2924,27 +3019,40 @@ CCMD(utid) int AActor::GetMissileDamage (int mask, int add) { - if ((Damage & 0xC0000000) == 0x40000000) - { - return EvalExpressionI (Damage & 0x3FFFFFFF, this); - } - if (Damage == 0) + if (Damage == NULL) { return 0; } + VMFrameStack stack; + VMValue param = this; + VMReturn results[2]; + + int amount, calculated = false; + + results[0].IntAt(&amount); + results[1].IntAt(&calculated); + + if (stack.Call(Damage, ¶m, 1, results, 2) < 1) + { // No results + return 0; + } + if (calculated) + { + return amount; + } else if (mask == 0) { - return add * Damage; + return add * amount; } else { - return ((pr_missiledamage() & mask) + add) * Damage; + return ((pr_missiledamage() & mask) + add) * amount; } } void AActor::Howl () { - int howl = GetClass()->Meta.GetMetaInt(AMETA_HowlSound); + FSoundID howl = GetClass()->HowlSound; if (!S_IsActorPlayingSomething(this, CHAN_BODY, howl)) { S_Sound (this, CHAN_BODY, howl, 1, ATTN_NORM); @@ -3603,7 +3711,8 @@ void AActor::Tick () // won't hurt anything. Don't do this if damage is 0! That way, you can // still have missiles that go straight up and down through actors without // damaging anything. - if ((flags & MF_MISSILE) && (velx|vely) == 0 && Damage != 0) + // (for backwards compatibility this must check for lack of damage function, not for zero damage!) + if ((flags & MF_MISSILE) && (velx|vely) == 0 && Damage != NULL) { velx = 1; } @@ -3941,25 +4050,21 @@ bool AActor::UpdateWaterLevel (fixed_t oldz, bool dosplash) // //========================================================================== -AActor *AActor::StaticSpawn (const PClass *type, fixed_t ix, fixed_t iy, fixed_t iz, replace_t allowreplacement, bool SpawningMapThing) +AActor *AActor::StaticSpawn (PClassActor *type, fixed_t ix, fixed_t iy, fixed_t iz, replace_t allowreplacement, bool SpawningMapThing) { if (type == NULL) { I_Error ("Tried to spawn a class-less actor\n"); } - if (type->ActorInfo == NULL) - { - I_Error ("%s is not an actor\n", type->TypeName.GetChars()); - } - if (allowreplacement) + { type = type->GetReplacement(); - + } AActor *actor; - actor = static_cast(const_cast(type)->CreateNew ()); + actor = static_cast(const_cast(type)->CreateNew ()); // Set default dialogue actor->ConversationRoot = GetConversation(actor->GetClass()->TypeName); @@ -4004,11 +4109,10 @@ AActor *AActor::StaticSpawn (const PClass *type, fixed_t ix, fixed_t iy, fixed_t actor->frame = st->GetFrame(); actor->renderflags = (actor->renderflags & ~RF_FULLBRIGHT) | ActorRenderFlags::FromInt (st->GetFullbright()); actor->touching_sectorlist = NULL; // NULL head of sector list // phares 3/13/98 - if (G_SkillProperty(SKILLP_FastMonsters)) - actor->Speed = actor->GetClass()->Meta.GetMetaFixed(AMETA_FastSpeed, actor->Speed); + if (G_SkillProperty(SKILLP_FastMonsters) && actor->GetClass()->FastSpeed >= 0) + actor->Speed = actor->GetClass()->FastSpeed; actor->DamageMultiply = FRACUNIT; - // set subsector and/or block links actor->LinkToWorld (SpawningMapThing); @@ -4144,7 +4248,11 @@ AActor *Spawn (FName classname, fixed_t x, fixed_t y, fixed_t z, replace_t allow { I_Error("Attempt to spawn actor of unknown type '%s'\n", classname.GetChars()); } - return AActor::StaticSpawn (cls, x, y, z, allowreplacement); + if (!cls->IsKindOf(RUNTIME_CLASS(PClassActor))) + { + I_Error("Attempt to spawn non-actor of type '%s'\n", classname.GetChars()); + } + return AActor::StaticSpawn (const_cast(static_cast(cls)), x, y, z, allowreplacement); } void AActor::LevelSpawned () @@ -4652,7 +4760,7 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags) // [RH] position is used to weed out unwanted start spots AActor *P_SpawnMapThing (FMapThing *mthing, int position) { - const PClass *i; + PClassActor *i; int mask; AActor *mobj; fixed_t x, y, z; @@ -4672,8 +4780,8 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) mentry = DoomEdMap.CheckKey(0); if (mentry == NULL) // we need a valid entry for the rest of this function so if we can't find a default, let's exit right away. { - return NULL; - } + return NULL; + } } if (mentry->Type == NULL && mentry->Special <= 0) { @@ -4706,18 +4814,18 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) case SMT_PolySpawn: case SMT_PolySpawnCrush: case SMT_PolySpawnHurt: - { - polyspawns_t *polyspawn = new polyspawns_t; - polyspawn->next = polyspawns; - polyspawn->x = mthing->x; - polyspawn->y = mthing->y; - polyspawn->angle = mthing->angle; + { + polyspawns_t *polyspawn = new polyspawns_t; + polyspawn->next = polyspawns; + polyspawn->x = mthing->x; + polyspawn->y = mthing->y; + polyspawn->angle = mthing->angle; polyspawn->type = mentry->Special; - polyspawns = polyspawn; + polyspawns = polyspawn; if (mentry->Special != SMT_PolyAnchor) - po_NumPolyobjs++; - return NULL; - } + po_NumPolyobjs++; + return NULL; + } case SMT_Player1Start: case SMT_Player2Start: @@ -4734,8 +4842,8 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) default: break; - } } + } if (pnum == -1 || (level.flags & LEVEL_FILTERSTARTS)) { @@ -4829,24 +4937,25 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) // [RH] If the thing's corresponding sprite has no frames, also map // it to the unknown thing. - // Handle decorate replacements explicitly here - // to check for missing frames in the replacement object. + // Handle decorate replacements explicitly here + // to check for missing frames in the replacement object. i = mentry->Type->GetReplacement(); - const AActor *defaults = GetDefaultByType (i); - if (defaults->SpawnState == NULL || - sprites[defaults->SpawnState->sprite].numframes == 0) - { - // We don't load mods for shareware games so we'll just ignore - // missing actors. Heretic needs this since the shareware includes - // the retail weapons in Deathmatch. - if (gameinfo.flags & GI_SHAREWARE) - return NULL; + const AActor *defaults = GetDefaultByType (i); + if (defaults->SpawnState == NULL || + sprites[defaults->SpawnState->sprite].numframes == 0) + { + // We don't load mods for shareware games so we'll just ignore + // missing actors. Heretic needs this since the shareware includes + // the retail weapons in Deathmatch. + if (gameinfo.flags & GI_SHAREWARE) + return NULL; - Printf ("%s at (%i, %i) has no frames\n", - i->TypeName.GetChars(), mthing->x>>FRACBITS, mthing->y>>FRACBITS); - i = PClass::FindClass("Unknown"); - } + Printf ("%s at (%i, %i) has no frames\n", + i->TypeName.GetChars(), mthing->x>>FRACBITS, mthing->y>>FRACBITS); + i = PClass::FindActor("Unknown"); + assert(i->IsKindOf(RUNTIME_CLASS(PClassActor))); + } const AActor *info = GetDefaultByType (i); @@ -5009,7 +5118,7 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) // P_SpawnPuff // -AActor *P_SpawnPuff (AActor *source, const PClass *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags, AActor *vict) +AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags, AActor *vict) { AActor *puff; @@ -5092,7 +5201,7 @@ void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AAc { AActor *th; PalEntry bloodcolor = originator->GetBloodColor(); - const PClass *bloodcls = originator->GetBloodType(); + PClassActor *bloodcls = originator->GetBloodType(); int bloodtype = cl_bloodtype; @@ -5146,25 +5255,26 @@ void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AAc advance = 2; } - PClass *cls = th->GetClass(); + PClassActor *cls = th->GetClass(); while (cls != RUNTIME_CLASS(AActor)) { - FActorInfo *ai = cls->ActorInfo; int checked_advance = advance; - if (ai->OwnsState(th->SpawnState)) + if (cls->OwnsState(th->SpawnState)) { for (; checked_advance > 0; --checked_advance) { // [RH] Do not set to a state we do not own. - if (ai->OwnsState(th->SpawnState + checked_advance)) + if (cls->OwnsState(th->SpawnState + checked_advance)) { th->SetState(th->SpawnState + checked_advance); goto statedone; } } } - cls = cls->ParentClass; + // We can safely assume the ParentClass is of type PClassActor + // since we stop when we see the Actor base class. + cls = static_cast(cls->ParentClass); } } @@ -5185,7 +5295,7 @@ void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AAc void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator) { PalEntry bloodcolor = originator->GetBloodColor(); - const PClass *bloodcls = originator->GetBloodType(1); + PClassActor *bloodcls = originator->GetBloodType(1); int bloodtype = cl_bloodtype; @@ -5225,7 +5335,7 @@ void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator) void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator) { PalEntry bloodcolor = originator->GetBloodColor(); - const PClass *bloodcls = originator->GetBloodType(2); + PClassActor *bloodcls = originator->GetBloodType(2); int bloodtype = cl_bloodtype; @@ -5265,7 +5375,7 @@ void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator) void P_RipperBlood (AActor *mo, AActor *bleeder) { PalEntry bloodcolor = bleeder->GetBloodColor(); - const PClass *bloodcls = bleeder->GetBloodType(); + PClassActor *bloodcls = bleeder->GetBloodType(); fixed_t xo = (pr_ripperblood.Random2() << 12); fixed_t yo = (pr_ripperblood.Random2() << 12); @@ -5375,20 +5485,20 @@ bool P_HitWater (AActor * thing, sector_t * sec, fixed_t x, fixed_t y, fixed_t z { for (unsigned int i = 0; ie->XFloor.ffloors.Size(); i++) { - F3DFloor * rover = sec->e->XFloor.ffloors[i]; - if (!(rover->flags & FF_EXISTS)) continue; - fixed_t planez = rover->top.plane->ZatPoint(x, y); + F3DFloor * rover = sec->e->XFloor.ffloors[i]; + if (!(rover->flags & FF_EXISTS)) continue; + fixed_t planez = rover->top.plane->ZatPoint(x, y); if (z > planez - FRACUNIT / 2 && z < planez + FRACUNIT / 2) // allow minor imprecisions - { + { if (rover->flags & (FF_SOLID | FF_SWIMMABLE)) - { + { terrainnum = rover->model->GetTerrain(rover->top.isceiling); - goto foundone; - } + goto foundone; } - planez = rover->bottom.plane->ZatPoint(x, y); - if (planez < z && !(planez < thing->floorz)) return false; } + planez = rover->bottom.plane->ZatPoint(x, y); + if (planez < z && !(planez < thing->floorz)) return false; + } } hsec = sec->GetHeightSec(); if (force || hsec == NULL || !(hsec->MoreFlags & SECF_CLIPFAKEPLANES)) @@ -5661,11 +5771,12 @@ void P_PlaySpawnSound(AActor *missile, AActor *spawner) } } -static fixed_t GetDefaultSpeed(const PClass *type) +static fixed_t GetDefaultSpeed(PClassActor *type) { - if (type == NULL) return 0; - else if (G_SkillProperty(SKILLP_FastMonsters)) - return type->Meta.GetMetaFixed(AMETA_FastSpeed, GetDefaultByType(type)->Speed); + if (type == NULL) + return 0; + else if (G_SkillProperty(SKILLP_FastMonsters) && type->FastSpeed >= 0) + return type->FastSpeed; else return GetDefaultByType(type)->Speed; } @@ -5679,7 +5790,7 @@ static fixed_t GetDefaultSpeed(const PClass *type) // //--------------------------------------------------------------------------- -AActor *P_SpawnMissile (AActor *source, AActor *dest, const PClass *type, AActor *owner) +AActor *P_SpawnMissile (AActor *source, AActor *dest, PClassActor *type, AActor *owner) { if (source == NULL) { @@ -5689,7 +5800,7 @@ AActor *P_SpawnMissile (AActor *source, AActor *dest, const PClass *type, AActor source, dest, type, true, owner); } -AActor *P_SpawnMissileZ (AActor *source, fixed_t z, AActor *dest, const PClass *type) +AActor *P_SpawnMissileZ (AActor *source, fixed_t z, AActor *dest, PClassActor *type) { if (source == NULL) { @@ -5699,7 +5810,7 @@ AActor *P_SpawnMissileZ (AActor *source, fixed_t z, AActor *dest, const PClass * } AActor *P_SpawnMissileXYZ (fixed_t x, fixed_t y, fixed_t z, - AActor *source, AActor *dest, const PClass *type, bool checkspawn, AActor *owner) + AActor *source, AActor *dest, PClassActor *type, bool checkspawn, AActor *owner) { if (source == NULL) { @@ -5774,7 +5885,7 @@ AActor *P_SpawnMissileXYZ (fixed_t x, fixed_t y, fixed_t z, return (!checkspawn || P_CheckMissileSpawn (th, source->radius)) ? th : NULL; } -AActor * P_OldSpawnMissile(AActor * source, AActor * owner, AActor * dest, const PClass *type) +AActor *P_OldSpawnMissile(AActor *source, AActor *owner, AActor *dest, PClassActor *type) { if (source == NULL) { @@ -5818,7 +5929,7 @@ AActor * P_OldSpawnMissile(AActor * source, AActor * owner, AActor * dest, const // //--------------------------------------------------------------------------- -AActor *P_SpawnMissileAngle (AActor *source, const PClass *type, +AActor *P_SpawnMissileAngle (AActor *source, PClassActor *type, angle_t angle, fixed_t velz) { if (source == NULL) @@ -5830,13 +5941,13 @@ AActor *P_SpawnMissileAngle (AActor *source, const PClass *type, } AActor *P_SpawnMissileAngleZ (AActor *source, fixed_t z, - const PClass *type, angle_t angle, fixed_t velz) + PClassActor *type, angle_t angle, fixed_t velz) { return P_SpawnMissileAngleZSpeed (source, z, type, angle, velz, GetDefaultSpeed (type)); } -AActor *P_SpawnMissileZAimed (AActor *source, fixed_t z, AActor *dest, const PClass *type) +AActor *P_SpawnMissileZAimed (AActor *source, fixed_t z, AActor *dest, PClassActor *type) { if (source == NULL) { @@ -5869,7 +5980,7 @@ AActor *P_SpawnMissileZAimed (AActor *source, fixed_t z, AActor *dest, const PCl // //--------------------------------------------------------------------------- -AActor *P_SpawnMissileAngleSpeed (AActor *source, const PClass *type, +AActor *P_SpawnMissileAngleSpeed (AActor *source, PClassActor *type, angle_t angle, fixed_t velz, fixed_t speed) { if (source == NULL) @@ -5881,7 +5992,7 @@ AActor *P_SpawnMissileAngleSpeed (AActor *source, const PClass *type, } AActor *P_SpawnMissileAngleZSpeed (AActor *source, fixed_t z, - const PClass *type, angle_t angle, fixed_t velz, fixed_t speed, AActor *owner, bool checkspawn) + PClassActor *type, angle_t angle, fixed_t velz, fixed_t speed, AActor *owner, bool checkspawn) { if (source == NULL) { @@ -5922,7 +6033,7 @@ AActor *P_SpawnMissileAngleZSpeed (AActor *source, fixed_t z, ================ */ -AActor *P_SpawnPlayerMissile (AActor *source, const PClass *type) +AActor *P_SpawnPlayerMissile (AActor *source, PClassActor *type) { if (source == NULL) { @@ -5931,13 +6042,13 @@ AActor *P_SpawnPlayerMissile (AActor *source, const PClass *type) return P_SpawnPlayerMissile (source, 0, 0, 0, type, source->angle); } -AActor *P_SpawnPlayerMissile (AActor *source, const PClass *type, angle_t angle) +AActor *P_SpawnPlayerMissile (AActor *source, PClassActor *type, angle_t angle) { return P_SpawnPlayerMissile (source, 0, 0, 0, type, angle); } AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, - const PClass *type, angle_t angle, AActor **pLineTarget, AActor **pMissileActor, + PClassActor *type, angle_t angle, AActor **pLineTarget, AActor **pMissileActor, bool nofreeaim, bool noautoaim) { static const int angdiff[3] = { -(1<<26), 1<<26, 0 }; @@ -6101,14 +6212,14 @@ FName AActor::GetSpecies() return Species; } - const PClass *thistype = GetClass(); + PClassActor *thistype = GetClass(); if (GetDefaultByType(thistype)->flags3 & MF3_ISMONSTER) { while (thistype->ParentClass) { if (GetDefaultByType(thistype->ParentClass)->flags3 & MF3_ISMONSTER) - thistype = thistype->ParentClass; + thistype = static_cast(thistype->ParentClass); else break; } @@ -6229,11 +6340,6 @@ int AActor::TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FN return (death == NULL) ? -1 : damage; } -int AActor::GibHealth() -{ - return -abs(GetClass()->Meta.GetMetaInt (AMETA_GibHealth, FixedMul(SpawnHealth(), gameinfo.gibfactor))); -} - void AActor::Crash() { // [RC] Weird that this forces the Crash state regardless of flag. @@ -6247,7 +6353,7 @@ void AActor::Crash() if (DamageType != NAME_None) { - if (health < GibHealth()) + if (health < GetGibHealth()) { // Extreme death FName labels[] = { NAME_Crash, NAME_Extreme, DamageType }; crashstate = FindState (3, labels, true); @@ -6259,13 +6365,13 @@ void AActor::Crash() } if (crashstate == NULL) { - if (health < GibHealth()) + if (health < GetGibHealth()) { // Extreme death - crashstate = FindState (NAME_Crash, NAME_Extreme); + crashstate = FindState(NAME_Crash, NAME_Extreme); } else { // Normal death - crashstate = FindState (NAME_Crash); + crashstate = FindState(NAME_Crash); } } if (crashstate != NULL) SetState(crashstate); @@ -6283,7 +6389,7 @@ void AActor::SetIdle(bool nofunction) SetState(idle, nofunction); } -int AActor::SpawnHealth() +int AActor::SpawnHealth() const { int defhealth = StartHealth ? StartHealth : GetDefault()->health; if (!(flags3 & MF3_ISMONSTER) || defhealth == 0) @@ -6345,15 +6451,28 @@ void AActor::Revive() } } -FDropItem *AActor::GetDropItems() +int AActor::GetGibHealth() const { - unsigned int index = GetClass()->Meta.GetMetaInt (ACMETA_DropItems) - 1; + int gibhealth = GetClass()->GibHealth; - if (index < DropItemList.Size()) + if (gibhealth != INT_MIN) { - return DropItemList[index]; + return -abs(gibhealth); } - return NULL; + else + { + return -FixedMul(SpawnHealth(), gameinfo.gibfactor); + } +} + +fixed_t AActor::GetCameraHeight() const +{ + return GetClass()->CameraHeight == FIXED_MIN ? height / 2 : GetClass()->CameraHeight; +} + +DDropItem *AActor::GetDropItems() const +{ + return GetClass()->DropItems; } fixed_t AActor::GetGravity() const @@ -6437,31 +6556,9 @@ void AActor::ClearCounters() // DropItem handling // //---------------------------------------------------------------------------- -FDropItemPtrArray DropItemList; - -void FreeDropItemChain(FDropItem *chain) -{ - while (chain != NULL) - { - FDropItem *next = chain->Next; - delete chain; - chain = next; - } -} - -void FDropItemPtrArray::Clear() -{ - for (unsigned int i = 0; i < Size(); ++i) - { - FreeDropItemChain ((*this)[i]); - } - TArray::Clear(); -} - -int StoreDropItemChain(FDropItem *chain) -{ - return DropItemList.Push (chain) + 1; -} +IMPLEMENT_POINTY_CLASS(DDropItem) + DECLARE_POINTER(Next) +END_POINTERS void PrintMiscActorInfo(AActor *query) { diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index ca629fe1b2..7d52210cef 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -567,14 +567,15 @@ void DoReadyWeapon(AActor *self) DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_WeaponReady) { - ACTION_PARAM_START(1); - ACTION_PARAM_INT(paramflags, 0); + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT(flags) { flags = 0; } - DoReadyWeaponToSwitch(self, !(paramflags & WRF_NoSwitch)); - if ((paramflags & WRF_NoFire) != WRF_NoFire) DoReadyWeaponToFire(self, !(paramflags & WRF_NoPrimary), !(paramflags & WRF_NoSecondary)); - if (!(paramflags & WRF_NoBob)) DoReadyWeaponToBob(self); - DoReadyWeaponToGeneric(self, paramflags); - DoReadyWeaponDisableSwitch(self, paramflags & WRF_DisableSwitch); + DoReadyWeaponToSwitch(self, !(flags & WRF_NoSwitch)); + if ((flags & WRF_NoFire) != WRF_NoFire) DoReadyWeaponToFire(self, !(flags & WRF_NoPrimary), !(flags & WRF_NoSecondary)); + if (!(flags & WRF_NoBob)) DoReadyWeaponToBob(self); + DoReadyWeaponToGeneric(self, flags); + DoReadyWeaponDisableSwitch(self, flags & WRF_DisableSwitch); + return 0; } //--------------------------------------------------------------------------- @@ -683,7 +684,7 @@ static void P_CheckWeaponButtons (player_t *player) { P_SetPsprite(player, ps_weapon, state); return; - } + } } } } @@ -698,10 +699,10 @@ static void P_CheckWeaponButtons (player_t *player) DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_ReFire) { - ACTION_PARAM_START(1) - ACTION_PARAM_STATE(state, 0); - + PARAM_ACTION_PROLOGUE; + PARAM_STATE_OPT(state) { state = NULL; } A_ReFire(self, state); + return 0; } void A_ReFire(AActor *self, FState *state) @@ -736,12 +737,14 @@ void A_ReFire(AActor *self, FState *state) DEFINE_ACTION_FUNCTION(AInventory, A_ClearReFire) { + PARAM_ACTION_PROLOGUE; player_t *player = self->player; if (NULL != player) { player->refire = 0; } + return 0; } //--------------------------------------------------------------------------- @@ -756,12 +759,15 @@ DEFINE_ACTION_FUNCTION(AInventory, A_ClearReFire) DEFINE_ACTION_FUNCTION(AInventory, A_CheckReload) { + PARAM_ACTION_PROLOGUE; + if (self->player != NULL) { self->player->ReadyWeapon->CheckAmmo ( self->player->ReadyWeapon->bAltFire ? AWeapon::AltFire : AWeapon::PrimaryFire, true); } + return 0; } //--------------------------------------------------------------------------- @@ -772,12 +778,14 @@ DEFINE_ACTION_FUNCTION(AInventory, A_CheckReload) DEFINE_ACTION_FUNCTION(AInventory, A_Lower) { + PARAM_ACTION_PROLOGUE; + player_t *player = self->player; pspdef_t *psp; if (NULL == player) { - return; + return 0; } psp = &player->psprites[ps_weapon]; if (player->morphTics || player->cheats & CF_INSTANTWEAPSWITCH) @@ -790,7 +798,7 @@ DEFINE_ACTION_FUNCTION(AInventory, A_Lower) } if (psp->sy < WEAPONBOTTOM) { // Not lowered all the way yet - return; + return 0; } if (player->playerstate == PST_DEAD) { // Player is dead, so don't bring up a pending weapon @@ -798,11 +806,12 @@ DEFINE_ACTION_FUNCTION(AInventory, A_Lower) // Player is dead, so keep the weapon off screen P_SetPsprite (player, ps_weapon, NULL); - return; + return 0; } // [RH] Clear the flash state. Only needed for Strife. P_SetPsprite (player, ps_flash, NULL); P_BringUpWeapon (player); + return 0; } //--------------------------------------------------------------------------- @@ -813,27 +822,29 @@ DEFINE_ACTION_FUNCTION(AInventory, A_Lower) DEFINE_ACTION_FUNCTION(AInventory, A_Raise) { + PARAM_ACTION_PROLOGUE; + if (self == NULL) { - return; + return 0; } player_t *player = self->player; pspdef_t *psp; if (NULL == player) { - return; + return 0; } if (player->PendingWeapon != WP_NOCHANGE) { P_DropWeapon(player); - return; + return 0; } psp = &player->psprites[ps_weapon]; psp->sy -= RAISESPEED; if (psp->sy > WEAPONTOP) { // Not raised all the way yet - return; + return 0; } psp->sy = WEAPONTOP; if (player->ReadyWeapon != NULL) @@ -844,6 +855,7 @@ DEFINE_ACTION_FUNCTION(AInventory, A_Raise) { player->psprites[ps_weapon].state = NULL; } + return 0; } @@ -859,24 +871,33 @@ enum GF_Flags DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_GunFlash) { - ACTION_PARAM_START(2) - ACTION_PARAM_STATE(flash, 0); - ACTION_PARAM_INT(Flags, 1); + PARAM_ACTION_PROLOGUE; + PARAM_STATE_OPT(flash) { flash = NULL; } + PARAM_INT_OPT (flags) { flags = 0; } player_t *player = self->player; if (NULL == player) { - return; + return 0; + } + if (!(flags & GFF_NOEXTCHANGE)) + { + player->mo->PlayAttacking2 (); } - if(!(Flags & GFF_NOEXTCHANGE)) player->mo->PlayAttacking2 (); - if (flash == NULL) { - if (player->ReadyWeapon->bAltFire) flash = player->ReadyWeapon->FindState(NAME_AltFlash); - if (flash == NULL) flash = player->ReadyWeapon->FindState(NAME_Flash); + if (player->ReadyWeapon->bAltFire) + { + flash = player->ReadyWeapon->FindState(NAME_AltFlash); + } + if (flash == NULL) + { + flash = player->ReadyWeapon->FindState(NAME_Flash); + } } P_SetPsprite (player, ps_flash, flash); + return 0; } @@ -924,7 +945,7 @@ angle_t P_BulletSlope (AActor *mo, AActor **pLineTarget) // // P_GunShot // -void P_GunShot (AActor *mo, bool accurate, const PClass *pufftype, angle_t pitch) +void P_GunShot (AActor *mo, bool accurate, PClassActor *pufftype, angle_t pitch) { angle_t angle; int damage; @@ -942,37 +963,47 @@ void P_GunShot (AActor *mo, bool accurate, const PClass *pufftype, angle_t pitch DEFINE_ACTION_FUNCTION(AInventory, A_Light0) { + PARAM_ACTION_PROLOGUE; + if (self->player != NULL) { self->player->extralight = 0; } + return 0; } DEFINE_ACTION_FUNCTION(AInventory, A_Light1) { + PARAM_ACTION_PROLOGUE; + if (self->player != NULL) { self->player->extralight = 1; } + return 0; } DEFINE_ACTION_FUNCTION(AInventory, A_Light2) { + PARAM_ACTION_PROLOGUE; + if (self->player != NULL) { self->player->extralight = 2; } + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_Light) { - ACTION_PARAM_START(1); - ACTION_PARAM_INT(light, 0); + PARAM_ACTION_PROLOGUE; + PARAM_INT(light); if (self->player != NULL) { self->player->extralight = clamp(light, -20, 20); } + return 0; } //------------------------------------------------------------------------ @@ -1054,7 +1085,7 @@ void P_MovePsprites (player_t *player) // Check custom buttons P_CheckWeaponButtons(player); - } + } } FArchive &operator<< (FArchive &arc, pspdef_t &def) diff --git a/src/p_pspr.h b/src/p_pspr.h index ca9b45ee82..a9eec48b6a 100644 --- a/src/p_pspr.h +++ b/src/p_pspr.h @@ -89,12 +89,12 @@ void P_FireWeapon (player_t *player); void P_DropWeapon (player_t *player); void P_BobWeapon (player_t *player, pspdef_t *psp, fixed_t *x, fixed_t *y); angle_t P_BulletSlope (AActor *mo, AActor **pLineTarget = NULL); -void P_GunShot (AActor *mo, bool accurate, const PClass *pufftype, angle_t pitch); +void P_GunShot (AActor *mo, bool accurate, PClassActor *pufftype, angle_t pitch); -void DoReadyWeapon(AActor * self); -void DoReadyWeaponToBob(AActor * self); -void DoReadyWeaponToFire(AActor * self, bool primary = true, bool secondary = true); -void DoReadyWeaponToSwitch(AActor * self, bool switchable = true); +void DoReadyWeapon(AActor *self); +void DoReadyWeaponToBob(AActor *self); +void DoReadyWeaponToFire(AActor *self, bool primary = true, bool secondary = true); +void DoReadyWeaponToSwitch(AActor *self, bool switchable = true); DECLARE_ACTION(A_Raise) void A_ReFire(AActor *self, FState *state = NULL); diff --git a/src/p_setup.cpp b/src/p_setup.cpp index c915c31ecb..f5de28c8aa 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1687,21 +1687,18 @@ static void SetMapThingUserData(AActor *actor, unsigned udi) { FName varname = MapThingsUserData[udi].Property; int value = MapThingsUserData[udi].Value; - PSymbol *sym = actor->GetClass()->Symbols.FindSymbol(varname, true); - PSymbolVariable *var; + PField *var = dyn_cast(actor->GetClass()->Symbols.FindSymbol(varname, true)); udi++; - if (sym == NULL || sym->SymbolType != SYM_Variable || - !(var = static_cast(sym))->bUserVar || - var->ValueType.Type != VAL_Int) + if (var == NULL || (var->Flags & VARF_Native) || !var->Type->IsKindOf(RUNTIME_CLASS(PBasicType))) { DPrintf("%s is not a user variable in class %s\n", varname.GetChars(), actor->GetClass()->TypeName.GetChars()); } else { // Set the value of the specified user variable. - *(int *)(reinterpret_cast(actor) + var->offset) = value; + var->Type->SetValue(reinterpret_cast(actor) + var->Offset, value); } } } diff --git a/src/p_spec.cpp b/src/p_spec.cpp index b49dd43afb..d0aa26135e 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -497,7 +497,7 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector) // //============================================================================ -static void DoSectorDamage(AActor *actor, sector_t *sec, int amount, FName type, const PClass *protectClass, int flags) +static void DoSectorDamage(AActor *actor, sector_t *sec, int amount, FName type, PClassActor *protectClass, int flags) { if (!(actor->flags & MF_SHOOTABLE)) return; @@ -520,7 +520,7 @@ static void DoSectorDamage(AActor *actor, sector_t *sec, int amount, FName type, P_DamageMobj (actor, NULL, NULL, amount, type); } -void P_SectorDamage(int tag, int amount, FName type, const PClass *protectClass, int flags) +void P_SectorDamage(int tag, int amount, FName type, PClassActor *protectClass, int flags) { FSectorTagIterator itr(tag); int secnum; diff --git a/src/p_spec.h b/src/p_spec.h index b4a88b5670..efe7566789 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -171,7 +171,7 @@ bool P_PredictLine (line_t *ld, AActor *mo, int side, int activationType); void P_PlayerInSpecialSector (player_t *player, sector_t * sector=NULL); void P_PlayerOnSpecialFlat (player_t *player, int floorType); -void P_SectorDamage(int tag, int amount, FName type, const PClass *protectClass, int flags); +void P_SectorDamage(int tag, int amount, FName type, PClassActor *protectClass, int flags); void P_SetSectorFriction (int tag, int amount, bool alterFlag); inline fixed_t FrictionToMoveFactor(fixed_t friction) diff --git a/src/p_states.cpp b/src/p_states.cpp index 3ba0ae14f3..c554837c11 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -61,7 +61,7 @@ FArchive &operator<< (FArchive &arc, FState *&state) { - const PClass *info; + PClassActor *info; if (arc.IsStoring ()) { @@ -77,7 +77,7 @@ FArchive &operator<< (FArchive &arc, FState *&state) if (info != NULL) { arc.UserWriteClass (info); - arc.WriteCount ((DWORD)(state - info->ActorInfo->OwnedStates)); + arc.WriteCount ((DWORD)(state - info->OwnedStates)); } else { @@ -95,22 +95,18 @@ FArchive &operator<< (FArchive &arc, FState *&state) } else { - const PClass *info; + PClassActor *info; DWORD ofs; - arc.UserReadClass (info); + arc.UserReadClass(info); ofs = arc.ReadCount (); if (ofs == NULL_STATE_INDEX && info == RUNTIME_CLASS(AActor)) { state = NULL; } - else if (info->ActorInfo != NULL) - { - state = info->ActorInfo->OwnedStates + ofs; - } else { - state = NULL; + state = info->OwnedStates + ofs; } } return arc; @@ -122,15 +118,15 @@ FArchive &operator<< (FArchive &arc, FState *&state) // //========================================================================== -const PClass *FState::StaticFindStateOwner (const FState *state) +PClassActor *FState::StaticFindStateOwner (const FState *state) { - for (unsigned int i = 0; i < PClass::m_RuntimeActors.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - FActorInfo *info = PClass::m_RuntimeActors[i]->ActorInfo; + PClassActor *info = PClassActor::AllActorClasses[i]; if (state >= info->OwnedStates && state < info->OwnedStates + info->NumOwnedStates) { - return info->Class; + return info; } } @@ -144,16 +140,16 @@ const PClass *FState::StaticFindStateOwner (const FState *state) // //========================================================================== -const PClass *FState::StaticFindStateOwner (const FState *state, const FActorInfo *info) +PClassActor *FState::StaticFindStateOwner (const FState *state, PClassActor *info) { while (info != NULL) { if (state >= info->OwnedStates && state < info->OwnedStates + info->NumOwnedStates) { - return info->Class; + return info; } - info = info->Class->ParentClass->ActorInfo; + info = dyn_cast(info->ParentClass); } return NULL; } @@ -166,18 +162,18 @@ const PClass *FState::StaticFindStateOwner (const FState *state, const FActorInf FStateLabel *FStateLabels::FindLabel (FName label) { - return const_cast(BinarySearch (Labels, NumLabels, &FStateLabel::Label, label)); + return const_cast(BinarySearch(Labels, NumLabels, &FStateLabel::Label, label)); } void FStateLabels::Destroy () { - for(int i=0; iDestroy(); - free (Labels[i].Children); // These are malloc'd, not new'd! - Labels[i].Children=NULL; + free(Labels[i].Children); // These are malloc'd, not new'd! + Labels[i].Children = NULL; } } } @@ -193,16 +189,19 @@ void FStateLabels::Destroy () bool AActor::HasSpecialDeathStates () const { - const FActorInfo *info = GetClass()->ActorInfo; + const PClassActor *info = static_cast(GetClass()); if (info->StateList != NULL) { FStateLabel *slabel = info->StateList->FindLabel (NAME_Death); if (slabel != NULL && slabel->Children != NULL) { - for(int i=0;iChildren->NumLabels;i++) + for(int i = 0; i < slabel->Children->NumLabels; i++) { - if (slabel->Children->Labels[i].State != NULL) return true; + if (slabel->Children->Labels[i].State != NULL) + { + return true; + } } } } @@ -219,10 +218,10 @@ TArray &MakeStateNameList(const char * fname) { static TArray namelist(3); FName firstpart, secondpart; - char * c; + char *c; // Handle the old names for the existing death states - char * name = copystring(fname); + char *name = copystring(fname); firstpart = strtok(name, "."); switch (firstpart) { @@ -246,14 +245,17 @@ TArray &MakeStateNameList(const char * fname) namelist.Clear(); namelist.Push(firstpart); - if (secondpart!=NAME_None) namelist.Push(secondpart); + if (secondpart != NAME_None) + { + namelist.Push(secondpart); + } - while ((c = strtok(NULL, "."))!=NULL) + while ((c = strtok(NULL, ".")) != NULL) { FName cc = c; namelist.Push(cc); } - delete [] name; + delete[] name; return namelist; } @@ -272,7 +274,7 @@ TArray &MakeStateNameList(const char * fname) // has names, ignore it. If the argument list still has names, remember it. // //=========================================================================== -FState *FActorInfo::FindState (int numnames, FName *names, bool exact) const +FState *PClassActor::FindState(int numnames, FName *names, bool exact) const { FStateLabels *labels = StateList; FState *best = NULL; @@ -287,7 +289,7 @@ FState *FActorInfo::FindState (int numnames, FName *names, bool exact) const while (labels != NULL && count < numnames) { label = *names++; - slabel = labels->FindLabel (label); + slabel = labels->FindLabel(label); if (slabel != NULL) { @@ -300,7 +302,10 @@ FState *FActorInfo::FindState (int numnames, FName *names, bool exact) const break; } } - if (count < numnames && exact) return NULL; + if (count < numnames && exact) + { + return NULL; + } } return best; } @@ -311,7 +316,7 @@ FState *FActorInfo::FindState (int numnames, FName *names, bool exact) const // //========================================================================== -FState *FActorInfo::FindStateByString(const char *name, bool exact) +FState *PClassActor::FindStateByString(const char *name, bool exact) { TArray &namelist = MakeStateNameList(name); return FindState(namelist.Size(), &namelist[0], exact); @@ -330,7 +335,10 @@ FStateDefine *FStateDefinitions::FindStateLabelInList(TArray & lis { for(unsigned i = 0; i & lis // //========================================================================== -FStateDefine * FStateDefinitions::FindStateAddress(const char *name) +FStateDefine *FStateDefinitions::FindStateAddress(const char *name) { FStateDefine *statedef = NULL; TArray &namelist = MakeStateNameList(name); @@ -370,7 +378,7 @@ FStateDefine * FStateDefinitions::FindStateAddress(const char *name) // //========================================================================== -void FStateDefinitions::SetStateLabel (const char *statename, FState *state, BYTE defflags) +void FStateDefinitions::SetStateLabel(const char *statename, FState *state, BYTE defflags) { FStateDefine *std = FindStateAddress(statename); std->State = state; @@ -383,7 +391,7 @@ void FStateDefinitions::SetStateLabel (const char *statename, FState *state, BYT // //========================================================================== -void FStateDefinitions::AddStateLabel (const char *statename) +void FStateDefinitions::AddStateLabel(const char *statename) { intptr_t index = StateArray.Size(); FStateDefine *std = FindStateAddress(statename); @@ -418,20 +426,23 @@ int FStateDefinitions::GetStateLabelIndex (FName statename) // //========================================================================== -FState * FStateDefinitions::FindState(const char * name) +FState *FStateDefinitions::FindState(const char * name) { - FStateDefine * statedef=NULL; + FStateDefine *statedef = NULL; TArray &namelist = MakeStateNameList(name); - TArray * statelist = &StateLabels; - for(unsigned i=0;i *statelist = &StateLabels; + for(unsigned i = 0; i < namelist.Size(); i++) { statedef = FindStateLabelInList(*statelist, namelist[i], false); - if (statedef == NULL) return NULL; + if (statedef == NULL) + { + return NULL; + } statelist = &statedef->Children; } - return statedef? statedef->State : NULL; + return statedef ? statedef->State : NULL; } //========================================================================== @@ -440,17 +451,17 @@ FState * FStateDefinitions::FindState(const char * name) // //========================================================================== -static int STACK_ARGS labelcmp(const void * a, const void * b) +static int STACK_ARGS labelcmp(const void *a, const void *b) { - FStateLabel * A = (FStateLabel *)a; - FStateLabel * B = (FStateLabel *)b; + FStateLabel *A = (FStateLabel *)a; + FStateLabel *B = (FStateLabel *)b; return ((int)A->Label - (int)B->Label); } -FStateLabels * FStateDefinitions::CreateStateLabelList(TArray & statelist) +FStateLabels *FStateDefinitions::CreateStateLabelList(TArray & statelist) { // First delete all empty labels from the list - for (int i=statelist.Size()-1;i>=0;i--) + for (int i = statelist.Size() - 1; i >= 0; i--) { if (statelist[i].Label == NAME_None || (statelist[i].State == NULL && statelist[i].Children.Size() == 0)) { @@ -458,11 +469,13 @@ FStateLabels * FStateDefinitions::CreateStateLabelList(TArray & st } } - int count=statelist.Size(); + int count = statelist.Size(); - if (count == 0) return NULL; - - FStateLabels * list = (FStateLabels*)M_Malloc(sizeof(FStateLabels)+(count-1)*sizeof(FStateLabel)); + if (count == 0) + { + return NULL; + } + FStateLabels *list = (FStateLabels*)M_Malloc(sizeof(FStateLabels)+(count-1)*sizeof(FStateLabel)); list->NumLabels = count; for (int i=0;i & st // //=========================================================================== -void FStateDefinitions::InstallStates(FActorInfo *info, AActor *defaults) +void FStateDefinitions::InstallStates(PClassActor *info, AActor *defaults) { // First ensure we have a valid spawn state. FState *state = FindState("Spawn"); @@ -522,7 +535,7 @@ void FStateDefinitions::InstallStates(FActorInfo *info, AActor *defaults) void FStateDefinitions::MakeStateList(const FStateLabels *list, TArray &dest) { dest.Clear(); - if (list != NULL) for(int i=0;iNumLabels;i++) + if (list != NULL) for (int i = 0; i < list->NumLabels; i++) { FStateDefine def; @@ -537,16 +550,16 @@ void FStateDefinitions::MakeStateList(const FStateLabels *list, TArrayActorInfo != NULL && cls->ActorInfo->StateList != NULL) + if (cls != NULL && cls->StateList != NULL) { - MakeStateList(cls->ActorInfo->StateList, StateLabels); + MakeStateList(cls->StateList, StateLabels); } else { @@ -564,7 +577,7 @@ void FStateDefinitions::MakeStateDefines(const PClass *cls) void FStateDefinitions::AddStateDefines(const FStateLabels *list) { - if (list != NULL) for(int i=0;iNumLabels;i++) + if (list != NULL) for(int i = 0; i < list->NumLabels; i++) { if (list->Labels[i].Children == NULL) { @@ -632,9 +645,9 @@ void FStateDefinitions::RetargetStates (intptr_t count, const char *target) // //========================================================================== -FState *FStateDefinitions::ResolveGotoLabel (AActor *actor, const PClass *mytype, char *name) +FState *FStateDefinitions::ResolveGotoLabel (AActor *actor, PClassActor *mytype, char *name) { - const PClass *type=mytype; + PClassActor *type = mytype; FState *state; char *namestart = name; char *label, *offset, *pt; @@ -651,13 +664,13 @@ FState *FStateDefinitions::ResolveGotoLabel (AActor *actor, const PClass *mytype // superclass, or it may be the name of any class that this one derives from. if (stricmp (classname, "Super") == 0) { - type = type->ParentClass; - actor = GetDefaultByType (type); + type = dyn_cast(type->ParentClass); + actor = GetDefaultByType(type); } else { // first check whether a state of the desired name exists - const PClass *stype = PClass::FindClass (classname); + PClass *stype = PClass::FindClass (classname); if (stype == NULL) { I_Error ("%s is an unknown class.", classname); @@ -673,7 +686,7 @@ FState *FStateDefinitions::ResolveGotoLabel (AActor *actor, const PClass *mytype } if (type != stype) { - type = stype; + type = static_cast(stype); actor = GetDefaultByType (type); } } @@ -689,8 +702,14 @@ FState *FStateDefinitions::ResolveGotoLabel (AActor *actor, const PClass *mytype v = offset ? strtol (offset, NULL, 0) : 0; // Get the state's address. - if (type==mytype) state = FindState (label); - else state = type->ActorInfo->FindStateByString(label, true); + if (type == mytype) + { + state = FindState (label); + } + else + { + state = type->FindStateByString(label, true); + } if (state != NULL) { @@ -716,17 +735,20 @@ FState *FStateDefinitions::ResolveGotoLabel (AActor *actor, const PClass *mytype // //========================================================================== -void FStateDefinitions::FixStatePointers (FActorInfo *actor, TArray & list) +void FStateDefinitions::FixStatePointers (PClassActor *actor, TArray & list) { - for(unsigned i=0;iOwnedStates + v - 1; list[i].DefineFlags = SDF_STATE; } - if (list[i].Children.Size() > 0) FixStatePointers(actor, list[i].Children); + if (list[i].Children.Size() > 0) + { + FixStatePointers(actor, list[i].Children); + } } } @@ -738,13 +760,13 @@ void FStateDefinitions::FixStatePointers (FActorInfo *actor, TArray & list) +void FStateDefinitions::ResolveGotoLabels (PClassActor *actor, AActor *defaults, TArray & list) { - for(unsigned i=0;iClass, (char *)list[i].State); + list[i].State = ResolveGotoLabel (defaults, actor, (char *)list[i].State); list[i].DefineFlags = SDF_STATE; } if (list[i].Children.Size() > 0) ResolveGotoLabels(actor, defaults, list[i].Children); @@ -855,15 +877,17 @@ bool FStateDefinitions::SetLoop() //========================================================================== // // AddStates -// adds some state to the current definition set +// +// Adds some state to the current definition set. Returns the number of +// states added. Positive = no errors, negative = errors. // //========================================================================== -bool FStateDefinitions::AddStates(FState *state, const char *framechars) +int FStateDefinitions::AddStates(FState *state, const char *framechars) { bool error = false; int frame = 0; - + int count = 0; while (*framechars) { bool noframe = false; @@ -885,13 +909,14 @@ bool FStateDefinitions::AddStates(FState *state, const char *framechars) state->Frame = frame; state->SameFrame = noframe; StateArray.Push(*state); + ++count; // NODELAY flag is not carried past the first state state->NoDelay = false; } laststate = &StateArray[StateArray.Size() - 1]; laststatebeforelabel = laststate; - return !error; + return !error ? count : -count; } //========================================================================== @@ -901,7 +926,7 @@ bool FStateDefinitions::AddStates(FState *state, const char *framechars) // //========================================================================== -int FStateDefinitions::FinishStates (FActorInfo *actor, AActor *defaults) +int FStateDefinitions::FinishStates(PClassActor *actor, AActor *defaults) { int count = StateArray.Size(); @@ -926,11 +951,11 @@ int FStateDefinitions::FinishStates (FActorInfo *actor, AActor *defaults) // resolve labels and jumps switch (realstates[i].DefineFlags) { - case SDF_STOP: // stop + case SDF_STOP: // stop realstates[i].NextState = NULL; break; - case SDF_WAIT: // wait + case SDF_WAIT: // wait realstates[i].NextState = &realstates[i]; break; @@ -943,7 +968,7 @@ int FStateDefinitions::FinishStates (FActorInfo *actor, AActor *defaults) break; case SDF_LABEL: - realstates[i].NextState = ResolveGotoLabel(defaults, actor->Class, (char *)realstates[i].NextState); + realstates[i].NextState = ResolveGotoLabel(defaults, actor, (char *)realstates[i].NextState); break; } } @@ -953,7 +978,6 @@ int FStateDefinitions::FinishStates (FActorInfo *actor, AActor *defaults) // Fix state pointers that are gotos ResolveGotoLabels(actor, defaults, StateLabels); } - return count; } @@ -970,7 +994,7 @@ void DumpStateHelper(FStateLabels *StateList, const FString &prefix) { if (StateList->Labels[i].State != NULL) { - const PClass *owner = FState::StaticFindStateOwner(StateList->Labels[i].State); + const PClassActor *owner = FState::StaticFindStateOwner(StateList->Labels[i].State); if (owner == NULL) { Printf(PRINT_LOG, "%s%s: invalid\n", prefix.GetChars(), StateList->Labels[i].Label.GetChars()); @@ -978,7 +1002,7 @@ void DumpStateHelper(FStateLabels *StateList, const FString &prefix) else { Printf(PRINT_LOG, "%s%s: %s.%d\n", prefix.GetChars(), StateList->Labels[i].Label.GetChars(), - owner->TypeName.GetChars(), int(StateList->Labels[i].State - owner->ActorInfo->OwnedStates)); + owner->TypeName.GetChars(), int(StateList->Labels[i].State - owner->OwnedStates)); } } if (StateList->Labels[i].Children != NULL) @@ -990,10 +1014,10 @@ void DumpStateHelper(FStateLabels *StateList, const FString &prefix) CCMD(dumpstates) { - for (unsigned int i = 0; i < PClass::m_RuntimeActors.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - FActorInfo *info = PClass::m_RuntimeActors[i]->ActorInfo; - Printf(PRINT_LOG, "State labels for %s\n", info->Class->TypeName.GetChars()); + PClassActor *info = PClassActor::AllActorClasses[i]; + Printf(PRINT_LOG, "State labels for %s\n", info->TypeName.GetChars()); DumpStateHelper(info->StateList, ""); Printf(PRINT_LOG, "----------------------------\n"); } diff --git a/src/p_teleport.cpp b/src/p_teleport.cpp index 254d341300..a6dcbf7f3d 100644 --- a/src/p_teleport.cpp +++ b/src/p_teleport.cpp @@ -89,7 +89,6 @@ void P_SpawnTeleportFog(AActor *mobj, fixed_t x, fixed_t y, fixed_t z, bool befo if (mo != NULL && setTarget) mo->target = mobj; - } // diff --git a/src/p_terrain.h b/src/p_terrain.h index dab4904b66..3bc1836bf3 100644 --- a/src/p_terrain.h +++ b/src/p_terrain.h @@ -37,7 +37,7 @@ #include "s_sound.h" #include "textures/textures.h" -struct PClass; +class PClass; extern WORD DefaultTerrainType; @@ -89,9 +89,9 @@ struct FSplashDef FName Name; FSoundID SmallSplashSound; FSoundID NormalSplashSound; - const PClass *SmallSplash; - const PClass *SplashBase; - const PClass *SplashChunk; + PClassActor *SmallSplash; + PClassActor *SplashBase; + PClassActor *SplashChunk; BYTE ChunkXVelShift; BYTE ChunkYVelShift; BYTE ChunkZVelShift; diff --git a/src/p_things.cpp b/src/p_things.cpp index be28ed98da..14ca85aa35 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -56,7 +56,7 @@ static FRandom pr_leadtarget ("LeadTarget"); bool P_Thing_Spawn (int tid, AActor *source, int type, angle_t angle, bool fog, int newtid) { int rtn = 0; - const PClass *kind; + PClassActor *kind; AActor *spot, *mobj; FActorIterator iterator (tid); @@ -68,7 +68,7 @@ bool P_Thing_Spawn (int tid, AActor *source, int type, angle_t angle, bool fog, // Handle decorate replacements. kind = kind->GetReplacement(); - if ((GetDefaultByType (kind)->flags3 & MF3_ISMONSTER) && + if ((GetDefaultByType(kind)->flags3 & MF3_ISMONSTER) && ((dmflags & DF_NO_MONSTERS) || (level.flags2 & LEVEL2_NOMONSTERS))) return false; @@ -175,7 +175,7 @@ bool P_Thing_Projectile (int tid, AActor *source, int type, const char *type_nam bool leadTarget) { int rtn = 0; - const PClass *kind; + PClassActor *kind; AActor *spot, *mobj, *targ = forcedest; FActorIterator iterator (tid); double fspeed = speed; @@ -187,9 +187,9 @@ bool P_Thing_Projectile (int tid, AActor *source, int type, const char *type_nam } else { - kind = PClass::FindClass(type_name); + kind = PClass::FindActor(type_name); } - if (kind == NULL || kind->ActorInfo == NULL) + if (kind == NULL) { return false; } @@ -197,7 +197,7 @@ bool P_Thing_Projectile (int tid, AActor *source, int type, const char *type_nam // Handle decorate replacements. kind = kind->GetReplacement(); - defflags3 = GetDefaultByType (kind)->flags3; + defflags3 = GetDefaultByType(kind)->flags3; if ((defflags3 & MF3_ISMONSTER) && ((dmflags & DF_NO_MONSTERS) || (level.flags2 & LEVEL2_NOMONSTERS))) return false; @@ -513,19 +513,19 @@ void P_Thing_SetVelocity(AActor *actor, fixed_t vx, fixed_t vy, fixed_t vz, bool } } -const PClass *P_GetSpawnableType(int spawnnum) +PClassActor *P_GetSpawnableType(int spawnnum) { if (spawnnum < 0) { // A named arg from a UDMF map FName spawnname = FName(ENamedName(-spawnnum)); if (spawnname.IsValidName()) { - return PClass::FindClass(spawnname); + return PClass::FindActor(spawnname); } } else { // A numbered arg from a Hexen or UDMF map - const PClass **type = SpawnableThings.CheckKey(spawnnum); + PClassActor **type = SpawnableThings.CheckKey(spawnnum); if (type != NULL) { return *type; @@ -651,10 +651,10 @@ void InitClassMap(FClassMap &themap, SpawnMap &thedata) while (it.NextPair(pair)) { - const PClass *cls = NULL; + PClassActor *cls = NULL; if (pair->Value.classname != NAME_None) { - cls = PClass::FindClass(pair->Value.classname); + cls = PClass::FindActor(pair->Value.classname); if (cls == NULL) { Printf(TEXTCOLOR_RED "Script error, \"%s\" line %d:\nUnknown actor class %s\n", @@ -806,4 +806,4 @@ int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, } caller->SetOrigin(old, true); return false; -} \ No newline at end of file +} diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp index 99ac071e89..7bc6a90fa5 100644 --- a/src/p_usdf.cpp +++ b/src/p_usdf.cpp @@ -41,6 +41,7 @@ #include "doomerrors.h" #include "cmdlib.h" #include "actor.h" +#include "a_pickups.h" #include "w_wad.h" #define Zd 1 @@ -50,11 +51,11 @@ class USDFParser : public UDMFParserBase { //=========================================================================== // - // Checks an actor type (different representation depending on manespace) + // Checks an actor type (different representation depending on namespace) // //=========================================================================== - const PClass *CheckActorType(const char *key) + PClassActor *CheckActorType(const char *key) { if (namespace_bits == St) { @@ -62,17 +63,12 @@ class USDFParser : public UDMFParserBase } else if (namespace_bits == Zd) { - const PClass *cls = PClass::FindClass(CheckString(key)); + PClassActor *cls = PClass::FindActor(CheckString(key)); if (cls == NULL) { sc.ScriptMessage("Unknown actor class '%s'", key); return NULL; } - if (!cls->IsDescendantOf(RUNTIME_CLASS(AActor))) - { - sc.ScriptMessage("'%s' is not an actor type", key); - return NULL; - } return cls; } return NULL; @@ -96,7 +92,7 @@ class USDFParser : public UDMFParserBase switch(key) { case NAME_Item: - check.Item = CheckActorType(key); + check.Item = dyn_cast(CheckActorType(key)); break; case NAME_Amount: @@ -258,7 +254,7 @@ class USDFParser : public UDMFParserBase switch(key) { case NAME_Item: - check.Item = CheckActorType(key); + check.Item = dyn_cast(CheckActorType(key)); break; case NAME_Count: @@ -370,7 +366,7 @@ class USDFParser : public UDMFParserBase bool ParseConversation() { - const PClass *type = NULL; + PClassActor *type = NULL; int dlgid = -1; unsigned int startpos = StrifeDialogues.Size(); diff --git a/src/p_user.cpp b/src/p_user.cpp index c4c5948580..a680e56154 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -129,26 +129,26 @@ bool FPlayerClass::CheckSkin (int skin) // //=========================================================================== -const char *GetPrintableDisplayName(const PClass *cls) +FString GetPrintableDisplayName(PClassPlayerPawn *cls) { // Fixme; This needs a decent way to access the string table without creating a mess. - const char *name = cls->Meta.GetMetaString(APMETA_DisplayName); - return name; + // [RH] ???? + return cls->DisplayName; } -bool ValidatePlayerClass(const PClass *ti, const char *name) +bool ValidatePlayerClass(PClassActor *ti, const char *name) { - if (!ti) + if (ti == NULL) { - Printf ("Unknown player class '%s'\n", name); + Printf("Unknown player class '%s'\n", name); return false; } - else if (!ti->IsDescendantOf (RUNTIME_CLASS (APlayerPawn))) + else if (!ti->IsDescendantOf(RUNTIME_CLASS(APlayerPawn))) { - Printf ("Invalid player class '%s'\n", name); + Printf("Invalid player class '%s'\n", name); return false; } - else if (ti->Meta.GetMetaString (APMETA_DisplayName) == NULL) + else if (static_cast(ti)->DisplayName.IsEmpty()) { Printf ("Missing displayname for player class '%s'\n", name); return false; @@ -161,18 +161,18 @@ void SetupPlayerClasses () FPlayerClass newclass; PlayerClasses.Clear(); - for (unsigned i=0; iflags6 & MF6_NOMENU)) + newclass.Flags = 0; + newclass.Type = static_cast(cls); + if ((GetDefaultByType(cls)->flags6 & MF6_NOMENU)) { newclass.Flags |= PCF_NOMENU; } - PlayerClasses.Push (newclass); + PlayerClasses.Push(newclass); } } } @@ -189,17 +189,17 @@ CCMD (addplayerclass) { if (ParsingKeyConf && argv.argc () > 1) { - const PClass *ti = PClass::FindClass (argv[1]); + PClassActor *ti = PClass::FindActor(argv[1]); if (ValidatePlayerClass(ti, argv[1])) { FPlayerClass newclass; - newclass.Type = ti; + newclass.Type = static_cast(ti); newclass.Flags = 0; int arg = 2; - while (arg < argv.argc ()) + while (arg < argv.argc()) { if (!stricmp (argv[arg], "nomenu")) { @@ -212,7 +212,6 @@ CCMD (addplayerclass) arg++; } - PlayerClasses.Push (newclass); } } @@ -224,7 +223,7 @@ CCMD (playerclasses) { Printf ("%3d: Class = %s, Name = %s\n", i, PlayerClasses[i].Type->TypeName.GetChars(), - PlayerClasses[i].Type->Meta.GetMetaString (APMETA_DisplayName)); + PlayerClasses[i].Type->DisplayName.GetChars()); } } @@ -498,6 +497,90 @@ int player_t::GetSpawnClass() return static_cast(GetDefaultByType(type))->SpawnMask; } +//=========================================================================== +// +// PClassPlayerPawn +// +//=========================================================================== + +IMPLEMENT_CLASS(PClassPlayerPawn) + +PClassPlayerPawn::PClassPlayerPawn() +{ + for (size_t i = 0; i < countof(HexenArmor); ++i) + { + HexenArmor[i] = 0; + } + ColorRangeStart = 0; + ColorRangeEnd = 0; +} + +void PClassPlayerPawn::Derive(PClass *newclass) +{ + assert(newclass->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); + Super::Derive(newclass); + PClassPlayerPawn *newp = static_cast(newclass); + size_t i; + + newp->DisplayName = DisplayName; + newp->SoundClass = SoundClass; + newp->Face = Face; + newp->InvulMode = InvulMode; + newp->HealingRadiusType = HealingRadiusType; + newp->ColorRangeStart = ColorRangeStart; + newp->ColorRangeEnd = ColorRangeEnd; + newp->ColorSets = ColorSets; + for (i = 0; i < countof(HexenArmor); ++i) + { + newp->HexenArmor[i] = HexenArmor[i]; + } + for (i = 0; i < countof(Slot); ++i) + { + newp->Slot[i] = Slot[i]; + } +} + +static int STACK_ARGS intcmp(const void *a, const void *b) +{ + return *(const int *)a - *(const int *)b; +} + +void PClassPlayerPawn::EnumColorSets(TArray *out) +{ + out->Clear(); + FPlayerColorSetMap::Iterator it(ColorSets); + FPlayerColorSetMap::Pair *pair; + + while (it.NextPair(pair)) + { + out->Push(pair->Key); + } + qsort(&(*out)[0], out->Size(), sizeof(int), intcmp); +} + +//========================================================================== +// +// +//========================================================================== + +bool PClassPlayerPawn::GetPainFlash(FName type, PalEntry *color) const +{ + const PClassPlayerPawn *info = this; + + while (info != NULL) + { + const PalEntry *flash = info->PainFlashes.CheckKey(type); + if (flash != NULL) + { + *color = *flash; + return true; + } + // Try parent class + info = dyn_cast(info->ParentClass); + } + return false; +} + //=========================================================================== // // player_t :: SendPitchLimits @@ -834,7 +917,7 @@ bool APlayerPawn::UseInventory (AInventory *item) // //=========================================================================== -AWeapon *APlayerPawn::BestWeapon (const PClass *ammotype) +AWeapon *APlayerPawn::BestWeapon(PClassAmmo *ammotype) { AWeapon *bestMatch = NULL; int bestOrder = INT_MAX; @@ -896,7 +979,7 @@ AWeapon *APlayerPawn::BestWeapon (const PClass *ammotype) // //=========================================================================== -AWeapon *APlayerPawn::PickNewWeapon (const PClass *ammotype) +AWeapon *APlayerPawn::PickNewWeapon(PClassAmmo *ammotype) { AWeapon *best = BestWeapon (ammotype); @@ -924,7 +1007,7 @@ AWeapon *APlayerPawn::PickNewWeapon (const PClass *ammotype) // //=========================================================================== -void APlayerPawn::CheckWeaponSwitch(const PClass *ammotype) +void APlayerPawn::CheckWeaponSwitch(PClassAmmo *ammotype) { if (!player->userinfo.GetNeverSwitch() && player->PendingWeapon == WP_NOCHANGE && @@ -951,14 +1034,14 @@ void APlayerPawn::CheckWeaponSwitch(const PClass *ammotype) void APlayerPawn::GiveDeathmatchInventory() { - for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - if (PClass::m_Types[i]->IsDescendantOf (RUNTIME_CLASS(AKey))) + if (PClassActor::AllActorClasses[i]->IsDescendantOf (RUNTIME_CLASS(AKey))) { - AKey *key = (AKey *)GetDefaultByType (PClass::m_Types[i]); + AKey *key = (AKey *)GetDefaultByType (PClassActor::AllActorClasses[i]); if (key->KeyNumber != 0) { - key = static_cast(Spawn (PClass::m_Types[i], 0,0,0, NO_REPLACE)); + key = static_cast(Spawn(static_cast(PClassActor::AllActorClasses[i]), 0,0,0, NO_REPLACE)); if (!key->CallTryPickup (this)) { key->Destroy (); @@ -1105,8 +1188,8 @@ const char *APlayerPawn::GetSoundClass() const } // [GRB] - const char *sclass = GetClass ()->Meta.GetMetaString (APMETA_SoundClass); - return sclass != NULL ? sclass : "player"; + PClassPlayerPawn *pclass = GetClass(); + return pclass->SoundClass.IsNotEmpty() ? pclass->SoundClass : "player"; } //=========================================================================== @@ -1220,18 +1303,14 @@ void APlayerPawn::GiveDefaultInventory () // HexenArmor must always be the first item in the inventory because // it provides player class based protection that should not affect // any other protection item. - fixed_t hx[5]; - for(int i=0;i<5;i++) - { - hx[i] = GetClass()->Meta.GetMetaFixed(APMETA_Hexenarmor0+i); - } - GiveInventoryType (RUNTIME_CLASS(AHexenArmor)); + PClassPlayerPawn *myclass = GetClass(); + GiveInventoryType(RUNTIME_CLASS(AHexenArmor)); AHexenArmor *harmor = FindInventory(); - harmor->Slots[4] = hx[0]; - harmor->SlotsIncrement[0] = hx[1]; - harmor->SlotsIncrement[1] = hx[2]; - harmor->SlotsIncrement[2] = hx[3]; - harmor->SlotsIncrement[3] = hx[4]; + harmor->Slots[4] = myclass->HexenArmor[0]; + for (int i = 0; i < 4; ++i) + { + harmor->SlotsIncrement[i] = myclass->HexenArmor[i + 1]; + } // BasicArmor must come right after that. It should not affect any // other protection item as well but needs to process the damage @@ -1243,25 +1322,25 @@ void APlayerPawn::GiveDefaultInventory () AddInventory (barmor); // Now add the items from the DECORATE definition - FDropItem *di = GetDropItems(); + DDropItem *di = GetDropItems(); while (di) { - const PClass *ti = PClass::FindClass (di->Name); + PClassActor *ti = PClass::FindActor (di->Name); if (ti) { AInventory *item = FindInventory (ti); if (item != NULL) { item->Amount = clamp( - item->Amount + (di->amount ? di->amount : ((AInventory *)item->GetDefault ())->Amount), + item->Amount + (di->Amount ? di->Amount : ((AInventory *)item->GetDefault ())->Amount), 0, item->MaxAmount); } else { item = static_cast(Spawn (ti, 0,0,0, NO_REPLACE)); - item->ItemFlags|=IF_IGNORESKILL; // no skill multiplicators here - item->Amount = di->amount; + item->ItemFlags |= IF_IGNORESKILL; // no skill multiplicators here + item->Amount = di->Amount; if (item->IsKindOf (RUNTIME_CLASS (AWeapon))) { // To allow better control any weapon is emptied of @@ -1298,7 +1377,7 @@ void APlayerPawn::MorphPlayerThink () void APlayerPawn::ActivateMorphWeapon () { - const PClass *morphweapon = PClass::FindClass (MorphWeapon); + PClassActor *morphweapon = PClass::FindActor (MorphWeapon); player->PendingWeapon = WP_NOCHANGE; player->psprites[ps_weapon].sy = WEAPONTOP; @@ -1358,7 +1437,7 @@ void APlayerPawn::Die (AActor *source, AActor *inflictor, int dmgflags) AInventory *item; // kgDROP - start - modified copy from a_action.cpp - FDropItem *di = weap->GetDropItems(); + DDropItem *di = weap->GetDropItems(); if (di != NULL) { @@ -1366,8 +1445,8 @@ void APlayerPawn::Die (AActor *source, AActor *inflictor, int dmgflags) { if (di->Name != NAME_None) { - const PClass *ti = PClass::FindClass(di->Name); - if (ti) P_DropItem (player->mo, ti, di->amount, di->probability); + PClassActor *ti = PClass::FindActor(di->Name); + if (ti) P_DropItem (player->mo, ti, di->Amount, di->Probability); } di = di->Next; } @@ -1466,6 +1545,8 @@ void APlayerPawn::TweakSpeeds (int &forward, int &side) DEFINE_ACTION_FUNCTION(AActor, A_PlayerScream) { + PARAM_ACTION_PROLOGUE; + int sound = 0; int chan = CHAN_VOICE; @@ -1479,7 +1560,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_PlayerScream) { S_Sound (self, CHAN_VOICE, "*death", 1, ATTN_NORM); } - return; + return 0; } // Handle the different player death screams @@ -1528,6 +1609,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_PlayerScream) } } S_Sound (self, chan, sound, 1, ATTN_NORM); + return 0; } @@ -1539,17 +1621,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_PlayerScream) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SkullPop) { - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(spawntype, 0); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS_OPT(spawntype, APlayerChunk) { spawntype = NULL; } APlayerPawn *mo; player_t *player; // [GRB] Parameterized version - if (!spawntype || !spawntype->IsDescendantOf (RUNTIME_CLASS (APlayerChunk))) + if (spawntype == NULL || !spawntype->IsDescendantOf(RUNTIME_CLASS(APlayerChunk))) { - spawntype = PClass::FindClass("BloodySkull"); - if (spawntype == NULL) return; + spawntype = dyn_cast(PClass::FindClass("BloodySkull")); + if (spawntype == NULL) + return 0; } self->flags &= ~MF_SOLID; @@ -1577,6 +1660,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SkullPop) players[i].camera = mo; } } + return 0; } //---------------------------------------------------------------------------- @@ -1587,10 +1671,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SkullPop) DEFINE_ACTION_FUNCTION(AActor, A_CheckPlayerDone) { + PARAM_ACTION_PROLOGUE; + if (self->player == NULL) { - self->Destroy (); + self->Destroy(); } + return 0; } //=========================================================================== @@ -2202,8 +2289,8 @@ void P_PlayerThink (player_t *player) if (debugfile && !(player->cheats & CF_PREDICTING)) { - fprintf (debugfile, "tic %d for pl %td: (%d, %d, %d, %u) b:%02x p:%d y:%d f:%d s:%d u:%d\n", - gametic, player-players, player->mo->X(), player->mo->Y(), player->mo->Z(), + fprintf (debugfile, "tic %d for pl %d: (%d, %d, %d, %u) b:%02x p:%d y:%d f:%d s:%d u:%d\n", + gametic, (int)(player-players), player->mo->X(), player->mo->Y(), player->mo->Z(), player->mo->angle>>ANGLETOFINESHIFT, player->cmd.ucmd.buttons, player->cmd.ucmd.pitch, player->cmd.ucmd.yaw, player->cmd.ucmd.forwardmove, player->cmd.ucmd.sidemove, player->cmd.ucmd.upmove); @@ -3162,55 +3249,6 @@ void player_t::Serialize (FArchive &arc) } } - -static FPlayerColorSetMap *GetPlayerColors(FName classname) -{ - const PClass *cls = PClass::FindClass(classname); - - if (cls != NULL) - { - FActorInfo *inf = cls->ActorInfo; - - if (inf != NULL) - { - return inf->ColorSets; - } - } - return NULL; -} - -FPlayerColorSet *P_GetPlayerColorSet(FName classname, int setnum) -{ - FPlayerColorSetMap *map = GetPlayerColors(classname); - if (map == NULL) - { - return NULL; - } - return map->CheckKey(setnum); -} - -static int STACK_ARGS intcmp(const void *a, const void *b) -{ - return *(const int *)a - *(const int *)b; -} - -void P_EnumPlayerColorSets(FName classname, TArray *out) -{ - out->Clear(); - FPlayerColorSetMap *map = GetPlayerColors(classname); - if (map != NULL) - { - FPlayerColorSetMap::Iterator it(*map); - FPlayerColorSetMap::Pair *pair; - - while (it.NextPair(pair)) - { - out->Push(pair->Key); - } - qsort(&(*out)[0], out->Size(), sizeof(int), intcmp); - } -} - bool P_IsPlayerTotallyFrozen(const player_t *player) { return diff --git a/src/r_data/sprites.cpp b/src/r_data/sprites.cpp index ebf4699da6..e01aad7255 100644 --- a/src/r_data/sprites.cpp +++ b/src/r_data/sprites.cpp @@ -515,7 +515,7 @@ void R_InitSkins (void) int lastlump; int aliasid; bool remove; - const PClass *basetype, *transtype; + PClassPlayerPawn *basetype, *transtype; key[sizeof(key)-1] = 0; i = PlayerClasses.Size () - 1; @@ -600,11 +600,11 @@ void R_InitSkins (void) else if (0 == stricmp (key, "game")) { if (gameinfo.gametype == GAME_Heretic) - basetype = PClass::FindClass (NAME_HereticPlayer); + basetype = dyn_cast(PClass::FindActor(NAME_HereticPlayer)); else if (gameinfo.gametype == GAME_Strife) - basetype = PClass::FindClass (NAME_StrifePlayer); + basetype = dyn_cast(PClass::FindActor(NAME_StrifePlayer)); else - basetype = PClass::FindClass (NAME_DoomPlayer); + basetype = dyn_cast(PClass::FindActor(NAME_DoomPlayer)); transtype = basetype; @@ -612,7 +612,7 @@ void R_InitSkins (void) { if (gameinfo.gametype & GAME_DoomChex) { - transtype = PClass::FindClass (NAME_HereticPlayer); + transtype = dyn_cast(PClass::FindActor(NAME_HereticPlayer)); skins[i].othergame = true; } else if (gameinfo.gametype != GAME_Heretic) @@ -631,7 +631,7 @@ void R_InitSkins (void) { if (gameinfo.gametype == GAME_Heretic) { - transtype = PClass::FindClass (NAME_DoomPlayer); + transtype = dyn_cast(PClass::FindActor(NAME_DoomPlayer)); skins[i].othergame = true; } else if (!(gameinfo.gametype & GAME_DoomChex)) @@ -707,12 +707,12 @@ void R_InitSkins (void) { if (gameinfo.gametype & GAME_DoomChex) { - basetype = transtype = PClass::FindClass (NAME_DoomPlayer); + basetype = transtype = dyn_cast(PClass::FindActor(NAME_DoomPlayer)); } else if (gameinfo.gametype == GAME_Heretic) { - basetype = PClass::FindClass (NAME_HereticPlayer); - transtype = PClass::FindClass (NAME_DoomPlayer); + basetype = dyn_cast(PClass::FindActor(NAME_HereticPlayer)); + transtype = dyn_cast(PClass::FindActor(NAME_DoomPlayer)); skins[i].othergame = true; } else @@ -723,17 +723,18 @@ void R_InitSkins (void) if (!remove) { - skins[i].range0start = transtype->Meta.GetMetaInt (APMETA_ColorRange) & 0xff; - skins[i].range0end = transtype->Meta.GetMetaInt (APMETA_ColorRange) >> 8; + skins[i].range0start = transtype->ColorRangeStart; + skins[i].range0end = transtype->ColorRangeEnd; remove = true; for (j = 0; j < (int)PlayerClasses.Size (); j++) { - const PClass *type = PlayerClasses[j].Type; + PClassPlayerPawn *type = PlayerClasses[j].Type; if (type->IsDescendantOf (basetype) && - GetDefaultByType (type)->SpawnState->sprite == GetDefaultByType (basetype)->SpawnState->sprite && - type->Meta.GetMetaInt (APMETA_ColorRange) == basetype->Meta.GetMetaInt (APMETA_ColorRange)) + GetDefaultByType(type)->SpawnState->sprite == GetDefaultByType(basetype)->SpawnState->sprite && + type->ColorRangeStart == basetype->ColorRangeStart && + type->ColorRangeEnd == basetype->ColorRangeEnd) { PlayerClasses[j].Skins.Push ((int)i); remove = false; @@ -931,9 +932,9 @@ void R_InitSprites () memset (skins, 0, sizeof(*skins) * numskins); for (i = 0; i < numskins; i++) { // Assume Doom skin by default - const PClass *type = PlayerClasses[0].Type; - skins[i].range0start = type->Meta.GetMetaInt (APMETA_ColorRange) & 255; - skins[i].range0end = type->Meta.GetMetaInt (APMETA_ColorRange) >> 8; + PClassPlayerPawn *type = PlayerClasses[0].Type; + skins[i].range0start = type->ColorRangeStart; + skins[i].range0end = type->ColorRangeEnd; skins[i].ScaleX = GetDefaultByType (type)->scaleX; skins[i].ScaleY = GetDefaultByType (type)->scaleY; } @@ -947,11 +948,11 @@ void R_InitSprites () // [GRB] Each player class has its own base skin for (i = 0; i < PlayerClasses.Size (); i++) { - const PClass *basetype = PlayerClasses[i].Type; - const char *pclassface = basetype->Meta.GetMetaString (APMETA_Face); + PClassPlayerPawn *basetype = PlayerClasses[i].Type; + FString classface = basetype->Face; strcpy (skins[i].name, "Base"); - if (pclassface == NULL || strcmp(pclassface, "None") == 0) + if (classface.IsEmpty() || strcmp(classface, "None") == 0) { skins[i].face[0] = 'S'; skins[i].face[1] = 'T'; @@ -960,10 +961,10 @@ void R_InitSprites () } else { - strcpy(skins[i].face, pclassface); + strcpy(skins[i].face, classface); } - skins[i].range0start = basetype->Meta.GetMetaInt (APMETA_ColorRange) & 255; - skins[i].range0end = basetype->Meta.GetMetaInt (APMETA_ColorRange) >> 8; + skins[i].range0start = basetype->ColorRangeStart; + skins[i].range0end = basetype->ColorRangeEnd; skins[i].ScaleX = GetDefaultByType (basetype)->scaleX; skins[i].ScaleY = GetDefaultByType (basetype)->scaleY; skins[i].sprite = GetDefaultByType (basetype)->SpawnState->sprite; diff --git a/src/r_things.cpp b/src/r_things.cpp index b209fb2842..8b22631353 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -134,6 +134,7 @@ BYTE *OffscreenColorBuffer; FCoverageBuffer *OffscreenCoverageBuffer; // + // GAME FUNCTIONS // int MaxVisSprites; @@ -151,6 +152,7 @@ static int vsprcount; static void R_ProjectWallSprite(AActor *thing, fixed_t fx, fixed_t fy, fixed_t fz, FTextureID picnum, fixed_t xscale, fixed_t yscale, INTBOOL flip); + void R_DeinitSprites() { // Free vissprites @@ -331,6 +333,11 @@ void R_DrawVisSprite (vissprite_t *vis) fixed_t xiscale; ESPSResult mode; + if (vis->xscale == 0 || vis->yscale == 0) + { // scaled to 0; can't see + return; + } + dc_colormap = vis->Style.colormap; mode = R_SetPatchStyle (vis->Style.RenderStyle, vis->Style.alpha, vis->Translation, vis->FillColor); diff --git a/src/r_utility.cpp b/src/r_utility.cpp index d4d3ec97b5..540ab740a8 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -841,7 +841,7 @@ void R_SetupFrame (AActor *actor) { iview->nviewx = camera->X(); iview->nviewy = camera->Y(); - iview->nviewz = camera->player ? camera->player->viewz : camera->Z() + camera->GetClass()->Meta.GetMetaFixed(AMETA_CameraHeight); + iview->nviewz = camera->player ? camera->player->viewz : camera->Z() + camera->GetCameraHeight(); viewsector = camera->Sector; r_showviewer = false; } diff --git a/src/s_sound.cpp b/src/s_sound.cpp index ec94117e4d..a2d69fbd5b 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -1086,11 +1086,11 @@ static FSoundChan *S_StartSound(AActor *actor, const sector_t *sec, const FPolyO { SoundListener listener; S_SetListener(listener, players[consoleplayer].camera); - chan = (FSoundChan*)GSnd->StartSound3D (sfx->data, &listener, volume, rolloff, attenuation, pitch, basepriority, pos, vel, channel, startflags, NULL); + chan = (FSoundChan*)GSnd->StartSound3D (sfx->data, &listener, float(volume), rolloff, float(attenuation), pitch, basepriority, pos, vel, channel, startflags, NULL); } else { - chan = (FSoundChan*)GSnd->StartSound (sfx->data, volume, pitch, startflags, NULL); + chan = (FSoundChan*)GSnd->StartSound (sfx->data, float(volume), pitch, startflags, NULL); } } if (chan == NULL && (chanflags & CHAN_LOOP)) @@ -1112,13 +1112,13 @@ static FSoundChan *S_StartSound(AActor *actor, const sector_t *sec, const FPolyO chan->SoundID = sound_id; chan->OrgID = FSoundID(org_id); chan->EntChannel = channel; - chan->Volume = volume; + chan->Volume = float(volume); chan->ChanFlags |= chanflags; chan->NearLimit = near_limit; chan->LimitRange = limit_range; chan->Pitch = pitch; chan->Priority = basepriority; - chan->DistanceScale = attenuation; + chan->DistanceScale = float(attenuation); chan->SourceType = type; switch (type) { diff --git a/src/sc_man.cpp b/src/sc_man.cpp index 9babe2e9cd..03b52a0502 100644 --- a/src/sc_man.cpp +++ b/src/sc_man.cpp @@ -119,6 +119,7 @@ FScanner &FScanner::operator=(const FScanner &other) LastGotLine = other.LastGotLine; CMode = other.CMode; Escape = other.Escape; + StateMode = other.StateMode; // Copy public members if (other.String == other.StringBuffer) @@ -275,6 +276,7 @@ void FScanner::PrepareScript () LastGotLine = 1; CMode = false; Escape = true; + StateMode = 0; StringBuffer[0] = '\0'; BigStringBuffer = ""; } @@ -390,6 +392,34 @@ void FScanner::SetEscape (bool esc) Escape = esc; } +//========================================================================== +// +// FScanner :: SetStateMode +// +// Enters state mode. This mode is very permissive for identifiers, which +// it returns as TOK_NonWhitespace. The only character sequences that are +// not returned as such are these: +// +// * stop +// * wait +// * fail +// * loop +// * goto - Automatically exits state mode after it's seen. +// * : +// * ; +// * } - Automatically exits state mode after it's seen. +// +// Quoted strings are returned as TOK_NonWhitespace, minus the quotes. In +// addition, any two consecutive sequences of TOK_NonWhitespace also exit +// state mode. +// +//========================================================================== + +void FScanner::SetStateMode(bool stately) +{ + StateMode = stately ? 2 : 0; +} + //========================================================================== // // FScanner::ScanString @@ -513,8 +543,19 @@ bool FScanner::GetToken () else if (TokenType == TK_IntConst) { char *stopper; - Number = strtol(String, &stopper, 0); - Float = Number; + // Check for unsigned + if (String[StringLen - 1] == 'u' || String[StringLen - 1] == 'U' || + String[StringLen - 2] == 'u' || String[StringLen - 2] == 'U') + { + TokenType = TK_UIntConst; + Number = strtoul(String, &stopper, 0); + Float = (unsigned)Number; + } + else + { + Number = strtol(String, &stopper, 0); + Float = Number; + } } else if (TokenType == TK_FloatConst) { @@ -878,7 +919,7 @@ FString FScanner::TokenName (int token, const char *string) //========================================================================== // -// FScanner::ScriptError +// FScanner::GetMessageLine // //========================================================================== diff --git a/src/sc_man.h b/src/sc_man.h index ba84cd00c6..6e0a710ba4 100644 --- a/src/sc_man.h +++ b/src/sc_man.h @@ -27,6 +27,7 @@ public: void SetCMode(bool cmode); void SetEscape(bool esc); + void SetStateMode(bool stately); const SavedPos SavePos(); void RestorePos(const SavedPos &pos); @@ -97,6 +98,7 @@ protected: const char *LastGotPtr; int LastGotLine; bool CMode; + BYTE StateMode; bool Escape; }; diff --git a/src/sc_man_scanner.re b/src/sc_man_scanner.re index 519ee4a1e7..d1d05b9298 100644 --- a/src/sc_man_scanner.re +++ b/src/sc_man_scanner.re @@ -36,7 +36,7 @@ std2: L = [a-zA-Z_]; H = [a-fA-F0-9]; E = [Ee] [+-]? D+; - FS = [fFlL]; + FS = [fF]; IS = [uUlL]; ESC = [\\] ([abcfnrtv?'"\\] | "x" H+ | O+); @@ -49,9 +49,34 @@ std2: TOK2 = (NWS\STOP1); TOKC2 = (NWS\STOPC); */ - if (tokens) // A well-defined scanner, based on the c.re example. - { #define RET(x) TokenType = x; goto normal_token; + if (tokens && StateMode != 0) + { + /*!re2c + "/*" { goto comment; } /* C comment */ + "//" (any\"\n")* "\n" { goto newline; } /* C++ comment */ + + (["](([\\]["])|[^"])*["]) { RET(TK_StringConst); } + 'stop' { RET(TK_Stop); } + 'wait' { RET(TK_Wait); } + 'fail' { RET(TK_Fail); } + 'loop' { RET(TK_Loop); } + 'goto' { StateMode = 0; RET(TK_Goto); } + ":" { RET(':'); } + ";" { RET(';'); } + "}" { StateMode = 0; RET('}'); } + + WSP+ { goto std1; } + "\n" { goto newline; } + + TOKS = (NWS\[/":;}]); + TOKS* ([/] (TOKS\[*]) TOKS*)* + { RET(TK_NonWhitespace); } + + */ + } + else if (tokens) // A well-defined scanner, based on the c.re example. + { /*!re2c "/*" { goto comment; } /* C comment */ "//" (any\"\n")* "\n" { goto newline; } /* C++ comment */ @@ -146,9 +171,11 @@ std2: 'is' { RET(TK_Is); } 'replaces' { RET(TK_Replaces); } - - /* Needed for decorate action functions */ + 'states' { RET(TK_States); } + 'meta' { RET(TK_Meta); } + 'deprecated' { RET(TK_Deprecated); } 'action' { RET(TK_Action); } + 'readonly' { RET(TK_ReadOnly); } /* other DECORATE top level keywords */ '#include' { RET(TK_Include); } @@ -163,7 +190,7 @@ std2: L (L|D)* { RET(TK_Identifier); } - ("0" [xX] H+ IS?) | ("0" D+ IS?) | (D+ IS?) + ("0" [xX] H+ IS?IS?) | ("0" D+ IS?IS?) | (D+ IS?IS?) { RET(TK_IntConst); } (D+ E FS?) | (D* "." D+ E? FS?) | (D+ "." D* E? FS?) @@ -202,6 +229,7 @@ std2: "~==" { RET(TK_ApproxEq); } "<>=" { RET(TK_LtGtEq); } "**" { RET(TK_MulMul); } + "::" { RET(TK_ColonColon); } ";" { RET(';'); } "{" { RET('{'); } "}" { RET('}'); } @@ -354,6 +382,10 @@ normal_token: { memcpy (StringBuffer, tok+1, StringLen); } + if (StateMode && TokenType == TK_StringConst) + { + TokenType = TK_NonWhitespace; + } } else { @@ -366,6 +398,17 @@ normal_token: memcpy (StringBuffer, tok, StringLen); } } + if (tokens && StateMode) + { // State mode is exited after two consecutive TK_NonWhitespace tokens + if (TokenType == TK_NonWhitespace) + { + StateMode--; + } + else + { + StateMode = 2; + } + } if (StringLen < MAX_STRING_SIZE) { String = StringBuffer; diff --git a/src/sc_man_tokens.h b/src/sc_man_tokens.h index afceaa856c..1665a1caec 100644 --- a/src/sc_man_tokens.h +++ b/src/sc_man_tokens.h @@ -2,7 +2,10 @@ xx(TK_Identifier, "identifier") xx(TK_StringConst, "string constant") xx(TK_NameConst, "name constant") xx(TK_IntConst, "integer constant") +xx(TK_UIntConst, "unsigned constant") xx(TK_FloatConst, "float constant") +xx(TK_NonWhitespace, "non-whitespace") +xx(TK_ColonColon, "'::'") xx(TK_DotDot, "'..'") xx(TK_Ellipsis, "'...'") xx(TK_RShiftEq, "'>>='") @@ -114,6 +117,7 @@ xx(TK_Abs, "'abs'") xx(TK_Random, "'random'") xx(TK_Random2, "'random2'") xx(TK_FRandom, "'frandom'") + xx(TK_Is, "'is'") xx(TK_Replaces, "'replaces'") xx(TK_Vector, "'vector'") @@ -124,4 +128,11 @@ xx(TK_SizeOf, "'sizeof'") xx(TK_AlignOf, "'alignof'") xx(TK_RandomPick, "'randompick'") xx(TK_FRandomPick, "'frandompick'") +xx(TK_States, "'states'") +xx(TK_Loop, "'loop'") +xx(TK_Fail, "'fail'") +xx(TK_Wait, "'wait'") +xx(TK_Meta, "'meta'") +xx(TK_Deprecated, "'deprecated'") +xx(TK_ReadOnly, "'readonly'") #undef xx diff --git a/src/sound/fmod_wrap.h b/src/sound/fmod_wrap.h index be676d9ddc..56e40a19ff 100644 --- a/src/sound/fmod_wrap.h +++ b/src/sound/fmod_wrap.h @@ -49,7 +49,7 @@ namespace FMOD FMOD global system functions (optional). */ inline FMOD_RESULT Memory_Initialize(void *poolmem, int poollen, FMOD_MEMORY_ALLOCCALLBACK useralloc, FMOD_MEMORY_REALLOCCALLBACK userrealloc, FMOD_MEMORY_FREECALLBACK userfree, FMOD_MEMORY_TYPE memtypeflags = (FMOD_MEMORY_NORMAL | FMOD_MEMORY_XBOX360_PHYSICAL)) { return FMOD_Memory_Initialize(poolmem, poollen, useralloc, userrealloc, userfree, memtypeflags); } - //inline FMOD_RESULT Memory_GetStats(int *currentalloced, int *maxalloced) { return FMOD_Memory_GetStats(currentalloced, maxalloced); } + //inline FMOD_RESULT Memory_GetStats (int *currentalloced, int *maxalloced) { return FMOD_Memory_GetStats(currentalloced, maxalloced); } inline FMOD_RESULT Debug_SetLevel(FMOD_DEBUGLEVEL level) { return FMOD_Debug_SetLevel(level); } inline FMOD_RESULT Debug_GetLevel(FMOD_DEBUGLEVEL *level) { return FMOD_Debug_GetLevel(level); } inline FMOD_RESULT File_SetDiskBusy(int busy) { return FMOD_File_SetDiskBusy(busy); } diff --git a/src/tarray.h b/src/tarray.h index dac824800f..d62d75e286 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -52,6 +52,14 @@ class FArchive; // TArray ------------------------------------------------------------------- +// Must match TArray's layout. +struct FArray +{ + void *Array; + unsigned int Most; + unsigned int Count; +}; + // T is the type stored in the array. // TT is the type returned by operator(). template @@ -120,6 +128,22 @@ public: Most = 0; } } + // Check equality of two arrays + bool operator==(const TArray &other) const + { + if (Count != other.Count) + { + return false; + } + for (unsigned int i = 0; i < Count; ++i) + { + if (Array[i] != other.Array[i]) + { + return false; + } + } + return true; + } // Return a reference to an element T &operator[] (size_t index) const { @@ -358,6 +382,15 @@ public: delete (*this)[i]; } } + void DeleteAndClear() + { + for (unsigned int i = 0; i < TArray::Size(); ++i) + { + if ((*this)[i] != NULL) + delete (*this)[i]; + } + this->Clear(); + } }; // TAutoGrowArray ----------------------------------------------------------- @@ -428,11 +461,41 @@ template struct THashTraits { // Returns the hash value for a key. hash_t Hash(const KT key) { return (hash_t)(intptr_t)key; } + hash_t Hash(double key) + { + hash_t keyhash[2]; + memcpy(&keyhash, &key, sizeof(keyhash)); + return keyhash[0] ^ keyhash[1]; + } // Compares two keys, returning zero if they are the same. int Compare(const KT left, const KT right) { return left != right; } }; +template<> struct THashTraits +{ + // Use all bits when hashing singles instead of converting them to ints. + hash_t Hash(float key) + { + hash_t keyhash; + memcpy(&keyhash, &key, sizeof(keyhash)); + return keyhash; + } + int Compare(float left, float right) { return left != right; } +}; + +template<> struct THashTraits +{ + // Use all bits when hashing doubles instead of converting them to ints. + hash_t Hash(double key) + { + hash_t keyhash[2]; + memcpy(&keyhash, &key, sizeof(keyhash)); + return keyhash[0] ^ keyhash[1]; + } + int Compare(double left, double right) { return left != right; } +}; + template struct TValueTraits { // Initializes a value for TMap. If a regular constructor isn't @@ -443,6 +506,15 @@ template struct TValueTraits } }; +// Must match layout of TMap +struct FMap +{ + void *Nodes; + void *LastFree; + hash_t Size; + hash_t NumUsed; +}; + template class TMapIterator; template class TMapConstIterator; diff --git a/src/textures/textures.h b/src/textures/textures.h index cb3680ead1..157f8555fe 100644 --- a/src/textures/textures.h +++ b/src/textures/textures.h @@ -7,7 +7,7 @@ class FBitmap; struct FRemapTable; struct FCopyInfo; class FScanner; -struct PClass; +class PClassInventory; class FArchive; // Texture IDs @@ -18,7 +18,7 @@ class FTextureID { friend class FTextureManager; friend FArchive &operator<< (FArchive &arc, FTextureID &tex); - friend FTextureID GetHUDIcon(const PClass *cls); + friend FTextureID GetHUDIcon(PClassInventory *cls); friend void R_InitSpriteDefs (); public: diff --git a/src/thingdef/olddecorations.cpp b/src/thingdef/olddecorations.cpp index d4db28e96e..541f3602c2 100644 --- a/src/thingdef/olddecorations.cpp +++ b/src/thingdef/olddecorations.cpp @@ -102,7 +102,7 @@ IMPLEMENT_CLASS (AFakeInventory) static void ParseInsideDecoration (Baggage &bag, AActor *defaults, FExtraInfo &extra, EDefinitionType def, FScanner &sc, TArray &StateArray); -static void ParseSpriteFrames (FActorInfo *info, TArray &states, FScanner &sc); +static void ParseSpriteFrames (PClassActor *info, TArray &states, FScanner &sc); // PRIVATE DATA DEFINITIONS ------------------------------------------------ @@ -145,24 +145,22 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) Baggage bag; TArray StateArray; FExtraInfo extra; - FActorInfo *info; - PClass *type; - PClass *parent; + PClassActor *type; + PClassActor *parent; FName typeName; - if (def == DEF_Pickup) parent = RUNTIME_CLASS(AFakeInventory); - else parent = RUNTIME_CLASS(AActor); + parent = (def == DEF_Pickup) ? RUNTIME_CLASS(AFakeInventory) : RUNTIME_CLASS(AActor); sc.MustGetString(); typeName = FName(sc.String); - type = parent->CreateDerivedClass (typeName, parent->Size); + type = static_cast(parent->CreateDerivedClass (typeName, parent->Size)); ResetBaggage(&bag, parent); - info = bag.Info = type->ActorInfo; + bag.Info = type; #ifdef _DEBUG bag.ClassName = type->TypeName; #endif - info->GameFilter = GAME_Any; + type->GameFilter = GAME_Any; sc.MustGetStringName("{"); memset (&extra, 0, sizeof(extra)); @@ -191,16 +189,16 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) // Make a copy of the final frozen frame for A_FreezeDeathChunks FState icecopy = StateArray[extra.IceDeathEnd-1]; StateArray.Push (icecopy); - info->NumOwnedStates += 1; + type->NumOwnedStates += 1; } - info->OwnedStates = new FState[info->NumOwnedStates]; - memcpy (info->OwnedStates, &StateArray[0], info->NumOwnedStates * sizeof(info->OwnedStates[0])); - if (info->NumOwnedStates == 1) + type->OwnedStates = new FState[type->NumOwnedStates]; + memcpy (type->OwnedStates, &StateArray[0], type->NumOwnedStates * sizeof(type->OwnedStates[0])); + if (type->NumOwnedStates == 1) { - info->OwnedStates->Tics = -1; - info->OwnedStates->TicRange = 0; - info->OwnedStates->Misc1 = 0; + type->OwnedStates->Tics = -1; + type->OwnedStates->TicRange = 0; + type->OwnedStates->Misc1 = 0; } else { @@ -209,56 +207,59 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) // Spawn states loop endlessly for (i = extra.SpawnStart; i < extra.SpawnEnd-1; ++i) { - info->OwnedStates[i].NextState = &info->OwnedStates[i+1]; + type->OwnedStates[i].NextState = &type->OwnedStates[i+1]; } - info->OwnedStates[i].NextState = &info->OwnedStates[extra.SpawnStart]; + type->OwnedStates[i].NextState = &type->OwnedStates[extra.SpawnStart]; // Death states are one-shot and freeze on the final state if (extra.DeathEnd != 0) { for (i = extra.DeathStart; i < extra.DeathEnd-1; ++i) { - info->OwnedStates[i].NextState = &info->OwnedStates[i+1]; + type->OwnedStates[i].NextState = &type->OwnedStates[i+1]; } if (extra.bDiesAway || def == DEF_Projectile) { - info->OwnedStates[i].NextState = NULL; + type->OwnedStates[i].NextState = NULL; } else { - info->OwnedStates[i].Tics = -1; - info->OwnedStates[i].TicRange = 0; - info->OwnedStates[i].Misc1 = 0; + type->OwnedStates[i].Tics = -1; + type->OwnedStates[i].TicRange = 0; + type->OwnedStates[i].Misc1 = 0; } if (def == DEF_Projectile) { if (extra.bExplosive) { - info->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_Explode")); + type->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_Explode")->Variants[0].Implementation); } } else { // The first frame plays the death sound and // the second frame makes it nonsolid. - info->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_Scream")); + type->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_Scream")->Variants[0].Implementation); if (extra.bSolidOnDeath) { } else if (extra.DeathStart + 1 < extra.DeathEnd) { - info->OwnedStates[extra.DeathStart+1].SetAction(FindGlobalActionFunction("A_NoBlocking")); + type->OwnedStates[extra.DeathStart+1].SetAction(FindGlobalActionFunction("A_NoBlocking")->Variants[0].Implementation); } else { - info->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_ScreamAndUnblock")); + type->OwnedStates[extra.DeathStart].SetAction(FindGlobalActionFunction("A_ScreamAndUnblock")->Variants[0].Implementation); } - if (extra.DeathHeight == 0) extra.DeathHeight = ((AActor*)(type->Defaults))->height; - info->Class->Meta.SetMetaFixed (AMETA_DeathHeight, extra.DeathHeight); + if (extra.DeathHeight == 0) + { + extra.DeathHeight = ((AActor*)(type->Defaults))->height; + } + type->DeathHeight = extra.DeathHeight; } - bag.statedef.SetStateLabel("Death", &info->OwnedStates[extra.DeathStart]); + bag.statedef.SetStateLabel("Death", &type->OwnedStates[extra.DeathStart]); } // Burn states are the same as death states, except they can optionally terminate @@ -266,38 +267,38 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) { for (i = extra.FireDeathStart; i < extra.FireDeathEnd-1; ++i) { - info->OwnedStates[i].NextState = &info->OwnedStates[i+1]; + type->OwnedStates[i].NextState = &type->OwnedStates[i+1]; } if (extra.bBurnAway) { - info->OwnedStates[i].NextState = NULL; + type->OwnedStates[i].NextState = NULL; } else { - info->OwnedStates[i].Tics = -1; - info->OwnedStates[i].TicRange = 0; - info->OwnedStates[i].Misc1 = 0; + type->OwnedStates[i].Tics = -1; + type->OwnedStates[i].TicRange = 0; + type->OwnedStates[i].Misc1 = 0; } // The first frame plays the burn sound and // the second frame makes it nonsolid. - info->OwnedStates[extra.FireDeathStart].SetAction(FindGlobalActionFunction("A_ActiveSound")); + type->OwnedStates[extra.FireDeathStart].SetAction(FindGlobalActionFunction("A_ActiveSound")->Variants[0].Implementation); if (extra.bSolidOnBurn) { } else if (extra.FireDeathStart + 1 < extra.FireDeathEnd) { - info->OwnedStates[extra.FireDeathStart+1].SetAction(FindGlobalActionFunction("A_NoBlocking")); + type->OwnedStates[extra.FireDeathStart+1].SetAction(FindGlobalActionFunction("A_NoBlocking")->Variants[0].Implementation); } else { - info->OwnedStates[extra.FireDeathStart].SetAction(FindGlobalActionFunction("A_ActiveAndUnblock")); + type->OwnedStates[extra.FireDeathStart].SetAction(FindGlobalActionFunction("A_ActiveAndUnblock")->Variants[0].Implementation); } if (extra.BurnHeight == 0) extra.BurnHeight = ((AActor*)(type->Defaults))->height; - type->Meta.SetMetaFixed (AMETA_BurnHeight, extra.BurnHeight); + type->BurnHeight = extra.BurnHeight; - bag.statedef.SetStateLabel("Burn", &info->OwnedStates[extra.FireDeathStart]); + bag.statedef.SetStateLabel("Burn", &type->OwnedStates[extra.FireDeathStart]); } // Ice states are similar to burn and death, except their final frame enters @@ -306,25 +307,25 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) { for (i = extra.IceDeathStart; i < extra.IceDeathEnd-1; ++i) { - info->OwnedStates[i].NextState = &info->OwnedStates[i+1]; + type->OwnedStates[i].NextState = &type->OwnedStates[i+1]; } - info->OwnedStates[i].NextState = &info->OwnedStates[info->NumOwnedStates-1]; - info->OwnedStates[i].Tics = 5; - info->OwnedStates[i].TicRange = 0; - info->OwnedStates[i].Misc1 = 0; - info->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeath")); + type->OwnedStates[i].NextState = &type->OwnedStates[type->NumOwnedStates-1]; + type->OwnedStates[i].Tics = 5; + type->OwnedStates[i].TicRange = 0; + type->OwnedStates[i].Misc1 = 0; + type->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeath")->Variants[0].Implementation); - i = info->NumOwnedStates - 1; - info->OwnedStates[i].NextState = &info->OwnedStates[i]; - info->OwnedStates[i].Tics = 1; - info->OwnedStates[i].TicRange = 0; - info->OwnedStates[i].Misc1 = 0; - info->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeathChunks")); - bag.statedef.SetStateLabel("Ice", &info->OwnedStates[extra.IceDeathStart]); + i = type->NumOwnedStates - 1; + type->OwnedStates[i].NextState = &type->OwnedStates[i]; + type->OwnedStates[i].Tics = 1; + type->OwnedStates[i].TicRange = 0; + type->OwnedStates[i].Misc1 = 0; + type->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeathChunks")->Variants[0].Implementation); + bag.statedef.SetStateLabel("Ice", &type->OwnedStates[extra.IceDeathStart]); } else if (extra.bGenericIceDeath) { - bag.statedef.SetStateLabel("Ice", RUNTIME_CLASS(AActor)->ActorInfo->FindState(NAME_GenericFreezeDeath)); + bag.statedef.SetStateLabel("Ice", RUNTIME_CLASS(AActor)->FindState(NAME_GenericFreezeDeath)); } } if (def == DEF_BreakableDecoration) @@ -335,8 +336,8 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) { ((AActor *)(type->Defaults))->flags |= MF_DROPOFF|MF_MISSILE; } - bag.statedef.SetStateLabel("Spawn", &info->OwnedStates[extra.SpawnStart]); - bag.statedef.InstallStates (info, ((AActor *)(type->Defaults))); + bag.statedef.SetStateLabel("Spawn", &type->OwnedStates[extra.SpawnStart]); + bag.statedef.InstallStates (type, ((AActor *)(type->Defaults))); } //========================================================================== @@ -478,23 +479,23 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults, else if (def == DEF_Projectile && sc.Compare ("ExplosionRadius")) { sc.MustGetNumber (); - bag.Info->Class->Meta.SetMetaInt(ACMETA_ExplosionRadius, sc.Number); + bag.Info->ExplosionRadius = sc.Number; extra.bExplosive = true; } else if (def == DEF_Projectile && sc.Compare ("ExplosionDamage")) { sc.MustGetNumber (); - bag.Info->Class->Meta.SetMetaInt(ACMETA_ExplosionDamage, sc.Number); + bag.Info->ExplosionDamage = sc.Number; extra.bExplosive = true; } else if (def == DEF_Projectile && sc.Compare ("DoNotHurtShooter")) { - bag.Info->Class->Meta.SetMetaInt(ACMETA_DontHurtShooter, true); + bag.Info->DontHurtShooter = true; } else if (def == DEF_Projectile && sc.Compare ("Damage")) { sc.MustGetNumber (); - defaults->Damage = sc.Number; + defaults->Damage = CreateDamageFunction(sc.Number); } else if (def == DEF_Projectile && sc.Compare ("DamageType")) { @@ -574,7 +575,7 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults, else if (def == DEF_Pickup && sc.Compare ("PickupMessage")) { sc.MustGetString (); - bag.Info->Class->Meta.SetMetaString(AIMETA_PickupMessage, sc.String); + static_cast(bag.Info)->PickupMessage = sc.String; } else if (def == DEF_Pickup && sc.Compare ("Respawns")) { @@ -645,7 +646,7 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults, // "10:A, 15:B, 8:C, 6:B" //========================================================================== -static void ParseSpriteFrames (FActorInfo *info, TArray &states, FScanner &sc) +static void ParseSpriteFrames (PClassActor *info, TArray &states, FScanner &sc) { FState state; char *token = strtok (sc.String, ",\t\n\r"); diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index a609b5e93f..c0097a0531 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -63,33 +63,35 @@ #include "thingdef.h" #include "thingdef_exp.h" #include "a_sharedglobal.h" +#include "vmbuilder.h" +#include "stats.h" + +TDeletingArray ActorDamageFuncs; // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- void InitThingdef(); void ParseDecorate (FScanner &sc); // STATIC FUNCTION PROTOTYPES -------------------------------------------- -const PClass *QuestItemClasses[31]; -PSymbolTable GlobalSymbols; +PClassActor *QuestItemClasses[31]; //========================================================================== // // Starts a new actor definition // //========================================================================== -FActorInfo *CreateNewActor(const FScriptPosition &sc, FName typeName, FName parentName, bool native) +PClassActor *CreateNewActor(const FScriptPosition &sc, FName typeName, FName parentName, bool native) { - const PClass *replacee = NULL; - PClass *ti = NULL; - FActorInfo *info = NULL; + PClassActor *replacee = NULL; + PClassActor *ti = NULL; - PClass *parent = RUNTIME_CLASS(AActor); + PClassActor *parent = RUNTIME_CLASS(AActor); if (parentName != NAME_None) { - parent = const_cast (PClass::FindClass (parentName)); + parent = PClass::FindActor(parentName); - const PClass *p = parent; + PClassActor *p = parent; while (p != NULL) { if (p->TypeName == typeName) @@ -97,7 +99,7 @@ FActorInfo *CreateNewActor(const FScriptPosition &sc, FName typeName, FName pare sc.Message(MSG_ERROR, "'%s' inherits from a class with the same name", typeName.GetChars()); break; } - p = p->ParentClass; + p = dyn_cast(p->ParentClass); } if (parent == NULL) @@ -110,19 +112,16 @@ FActorInfo *CreateNewActor(const FScriptPosition &sc, FName typeName, FName pare sc.Message(MSG_ERROR, "Parent type '%s' is not an actor in %s", parentName.GetChars(), typeName.GetChars()); parent = RUNTIME_CLASS(AActor); } - else if (parent->ActorInfo == NULL) - { - sc.Message(MSG_ERROR, "uninitialized parent type '%s' in %s", parentName.GetChars(), typeName.GetChars()); - parent = RUNTIME_CLASS(AActor); - } } if (native) { - ti = (PClass*)PClass::FindClass(typeName); + ti = PClass::FindActor(typeName); if (ti == NULL) { - sc.Message(MSG_ERROR, "Unknown native class '%s'", typeName.GetChars()); + extern void DumpTypeTable(); + DumpTypeTable(); + sc.Message(MSG_ERROR, "Unknown native actor '%s'", typeName.GetChars()); goto create; } else if (ti != RUNTIME_CLASS(AActor) && ti->ParentClass->NativeClass() != parent->NativeClass()) @@ -131,47 +130,39 @@ FActorInfo *CreateNewActor(const FScriptPosition &sc, FName typeName, FName pare parent = RUNTIME_CLASS(AActor); goto create; } - else if (ti->ActorInfo != NULL) + else if (ti->Defaults != NULL) { sc.Message(MSG_ERROR, "Redefinition of internal class '%s'", typeName.GetChars()); goto create; } - ti->InitializeActorInfo(); - info = ti->ActorInfo; + ti->InitializeNativeDefaults(); } else { create: - ti = parent->CreateDerivedClass (typeName, parent->Size); - info = ti->ActorInfo; + ti = static_cast(parent->CreateDerivedClass (typeName, parent->Size)); } // Copy class lists from parent - info->ForbiddenToPlayerClass = parent->ActorInfo->ForbiddenToPlayerClass; - info->RestrictedToPlayerClass = parent->ActorInfo->RestrictedToPlayerClass; - info->VisibleToPlayerClass = parent->ActorInfo->VisibleToPlayerClass; + ti->ForbiddenToPlayerClass = parent->ForbiddenToPlayerClass; + ti->RestrictedToPlayerClass = parent->RestrictedToPlayerClass; + ti->VisibleToPlayerClass = parent->VisibleToPlayerClass; - if (parent->ActorInfo->DamageFactors != NULL) + if (parent->DamageFactors != NULL) { // copy damage factors from parent - info->DamageFactors = new DmgFactors; - *info->DamageFactors = *parent->ActorInfo->DamageFactors; + ti->DamageFactors = new DmgFactors; + *ti->DamageFactors = *parent->DamageFactors; } - if (parent->ActorInfo->PainChances != NULL) + if (parent->PainChances != NULL) { // copy pain chances from parent - info->PainChances = new PainChanceList; - *info->PainChances = *parent->ActorInfo->PainChances; + ti->PainChances = new PainChanceList; + *ti->PainChances = *parent->PainChances; } - if (parent->ActorInfo->ColorSets != NULL) - { - // copy color sets from parent - info->ColorSets = new FPlayerColorSetMap; - *info->ColorSets = *parent->ActorInfo->ColorSets; - } - info->Replacee = info->Replacement = NULL; - info->DoomEdNum = -1; - return info; + ti->Replacee = ti->Replacement = NULL; + ti->DoomEdNum = -1; + return ti; } //========================================================================== @@ -180,28 +171,23 @@ FActorInfo *CreateNewActor(const FScriptPosition &sc, FName typeName, FName pare // //========================================================================== -void SetReplacement(FScanner &sc, FActorInfo *info, FName replaceName) +void SetReplacement(FScanner &sc, PClassActor *info, FName replaceName) { // Check for "replaces" if (replaceName != NAME_None) { // Get actor name - const PClass *replacee = PClass::FindClass (replaceName); + PClassActor *replacee = PClass::FindActor(replaceName); if (replacee == NULL) { - sc.ScriptMessage("Replaced type '%s' not found for %s", replaceName.GetChars(), info->Class->TypeName.GetChars()); - return; - } - else if (replacee->ActorInfo == NULL) - { - sc.ScriptMessage("Replaced type '%s' for %s is not an actor", replaceName.GetChars(), info->Class->TypeName.GetChars()); + sc.ScriptMessage("Replaced type '%s' not found for %s", replaceName.GetChars(), info->TypeName.GetChars()); return; } if (replacee != NULL) { - replacee->ActorInfo->Replacement = info; - info->Replacee = replacee->ActorInfo; + replacee->Replacement = info; + info->Replacee = replacee; } } @@ -213,10 +199,9 @@ void SetReplacement(FScanner &sc, FActorInfo *info, FName replaceName) // //========================================================================== -void FinishActor(const FScriptPosition &sc, FActorInfo *info, Baggage &bag) +void FinishActor(const FScriptPosition &sc, PClassActor *info, Baggage &bag) { - PClass *ti = info->Class; - AActor *defaults = (AActor*)ti->Defaults; + AActor *defaults = (AActor*)info->Defaults; try { @@ -232,31 +217,21 @@ void FinishActor(const FScriptPosition &sc, FActorInfo *info, Baggage &bag) bag.statedef.MakeStateDefines(NULL); if (bag.DropItemSet) { - if (bag.DropItemList == NULL) - { - if (ti->Meta.GetMetaInt (ACMETA_DropItems) != 0) - { - ti->Meta.SetMetaInt (ACMETA_DropItems, 0); - } - } - else - { - ti->Meta.SetMetaInt (ACMETA_DropItems, - StoreDropItemChain(bag.DropItemList)); - } + info->DropItems = bag.DropItemList; + GC::WriteBarrier(info, info->DropItems); } - if (ti->IsDescendantOf (RUNTIME_CLASS(AInventory))) + if (info->IsDescendantOf (RUNTIME_CLASS(AInventory))) { defaults->flags |= MF_SPECIAL; } // Weapons must be checked for all relevant states. They may crash the game otherwise. - if (ti->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (info->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { - FState * ready = ti->ActorInfo->FindState(NAME_Ready); - FState * select = ti->ActorInfo->FindState(NAME_Select); - FState * deselect = ti->ActorInfo->FindState(NAME_Deselect); - FState * fire = ti->ActorInfo->FindState(NAME_Fire); + FState *ready = info->FindState(NAME_Ready); + FState *select = info->FindState(NAME_Select); + FState *deselect = info->FindState(NAME_Deselect); + FState *fire = info->FindState(NAME_Fire); // Consider any weapon without any valid state abstract and don't output a warning // This is for creating base classes for weapon groups that only set up some properties. @@ -264,19 +239,19 @@ void FinishActor(const FScriptPosition &sc, FActorInfo *info, Baggage &bag) { if (!ready) { - sc.Message(MSG_ERROR, "Weapon %s doesn't define a ready state.\n", ti->TypeName.GetChars()); + sc.Message(MSG_ERROR, "Weapon %s doesn't define a ready state.\n", info->TypeName.GetChars()); } if (!select) { - sc.Message(MSG_ERROR, "Weapon %s doesn't define a select state.\n", ti->TypeName.GetChars()); + sc.Message(MSG_ERROR, "Weapon %s doesn't define a select state.\n", info->TypeName.GetChars()); } if (!deselect) { - sc.Message(MSG_ERROR, "Weapon %s doesn't define a deselect state.\n", ti->TypeName.GetChars()); + sc.Message(MSG_ERROR, "Weapon %s doesn't define a deselect state.\n", info->TypeName.GetChars()); } if (!fire) { - sc.Message(MSG_ERROR, "Weapon %s doesn't define a fire state.\n", ti->TypeName.GetChars()); + sc.Message(MSG_ERROR, "Weapon %s doesn't define a fire state.\n", info->TypeName.GetChars()); } } } @@ -288,16 +263,83 @@ void FinishActor(const FScriptPosition &sc, FActorInfo *info, Baggage &bag) // //========================================================================== +static void DumpFunction(FILE *dump, VMScriptFunction *sfunc, const char *label, int labellen) +{ + const char *marks = "======================================================="; + fprintf(dump, "\n%.*s %s %.*s", MAX(3, 38 - labellen / 2), marks, label, MAX(3, 38 - labellen / 2), marks); + fprintf(dump, "\nInteger regs: %-3d Float regs: %-3d Address regs: %-3d String regs: %-3d\nStack size: %d\n", + sfunc->NumRegD, sfunc->NumRegF, sfunc->NumRegA, sfunc->NumRegS, sfunc->MaxParam); + VMDumpConstants(dump, sfunc); + fprintf(dump, "\nDisassembly @ %p:\n", sfunc->Code); + VMDisasm(dump, sfunc->Code, sfunc->CodeSize, sfunc); +} + static void FinishThingdef() { - int errorcount = StateParams.ResolveAll(); + int errorcount = 0; + unsigned i; + int codesize = 0; - for (unsigned i = 0;i < PClass::m_Types.Size(); i++) +#if 1 + FILE *dump = fopen("disasm.txt", "w"); +#else + FILE *dump = NULL; +#endif + for (i = 0; i < StateTempCalls.Size(); ++i) { - PClass * ti = PClass::m_Types[i]; + FStateTempCall *tcall = StateTempCalls[i]; + VMFunction *func; - // Skip non-actors - if (!ti->IsDescendantOf(RUNTIME_CLASS(AActor))) continue; + assert(tcall->Code != NULL); + + // Can we call this function directly without wrapping it in an + // anonymous function? e.g. Are we passing any parameters to it? + func = tcall->Code->GetDirectFunction(); + if (func == NULL) + { + FCompileContext ctx(tcall->ActorClass); + tcall->Code = static_cast(tcall->Code->Resolve(ctx)); + + // Make sure resolving it didn't obliterate it. + if (tcall->Code != NULL) + { + VMFunctionBuilder buildit; + + // Allocate registers used to pass parameters in. + // self, stateowner, state (all are pointers) + buildit.Registers[REGT_POINTER].Get(3); + + // Emit a tail call via FxVMFunctionCall + tcall->Code->Emit(&buildit, true); + + VMScriptFunction *sfunc = buildit.MakeFunction(); + sfunc->NumArgs = NAP; + func = sfunc; + + if (dump != NULL) + { + char label[64]; + int labellen = mysnprintf(label, countof(label), "Function %s.States[%d] (*%d)", + tcall->ActorClass->TypeName.GetChars(), tcall->FirstState, tcall->NumStates); + DumpFunction(dump, sfunc, label, labellen); + codesize += sfunc->CodeSize; + } + } + } + if (tcall->Code != NULL) + { + delete tcall->Code; + tcall->Code = NULL; + for (int k = 0; k < tcall->NumStates; ++k) + { + tcall->ActorClass->OwnedStates[tcall->FirstState + k].SetAction(func); + } + } + } + + for (i = 0; i < PClassActor::AllActorClasses.Size(); i++) + { + PClassActor *ti = PClassActor::AllActorClasses[i]; if (ti->Size == (unsigned)-1) { @@ -314,18 +356,56 @@ static void FinishThingdef() errorcount++; continue; } + + if (def->Damage != NULL) + { + FxDamageValue *dmg = (FxDamageValue *)ActorDamageFuncs[(uintptr_t)def->Damage - 1]; + VMScriptFunction *sfunc; + sfunc = dmg->GetFunction(); + if (sfunc == NULL) + { + FCompileContext ctx(ti); + dmg->Resolve(ctx); + VMFunctionBuilder buildit; + buildit.Registers[REGT_POINTER].Get(1); // The self pointer + dmg->Emit(&buildit); + sfunc = buildit.MakeFunction(); + sfunc->NumArgs = 1; + // Save this function in case this damage value was reused + // (which happens quite easily with inheritance). + dmg->SetFunction(sfunc); + } + def->Damage = sfunc; + + if (dump != NULL && sfunc != NULL) + { + char label[64]; + int labellen = mysnprintf(label, countof(label), "Function %s.Damage", + ti->TypeName.GetChars()); + DumpFunction(dump, sfunc, label, labellen); + codesize += sfunc->CodeSize; + } + } + } + if (dump != NULL) + { + fprintf(dump, "\n*************************************************************************\n%i code bytes\n", codesize * 4); + fclose(dump); } if (errorcount > 0) { I_Error("%d errors during actor postprocessing", errorcount); } + ActorDamageFuncs.DeleteAndClear(); + StateTempCalls.DeleteAndClear(); + // Since these are defined in DECORATE now the table has to be initialized here. - for(int i=0;i<31;i++) + for(int i = 0; i < 31; i++) { char fmt[20]; mysnprintf(fmt, countof(fmt), "QuestItem%d", i+1); - QuestItemClasses[i] = PClass::FindClass(fmt); + QuestItemClasses[i] = PClass::FindActor(fmt); } } @@ -342,10 +422,10 @@ static void FinishThingdef() void LoadActors () { int lastlump, lump; + cycle_t timer; - StateParams.Clear(); - GlobalSymbols.ReleaseSymbols(); - DropItemList.Clear(); + timer.Reset(); timer.Clock(); + ActorDamageFuncs.Clear(); FScriptPosition::ResetErrorCounter(); InitThingdef(); lastlump = 0; @@ -359,5 +439,36 @@ void LoadActors () I_Error("%d errors while parsing DECORATE scripts", FScriptPosition::ErrorCounter); } FinishThingdef(); + timer.Unclock(); + Printf("DECORATE parsing took %.2f ms\n", timer.TimeMS()); + // Base time: ~52 ms } + +//========================================================================== +// +// CreateDamageFunction +// +// Creates a damage function suitable for a constant, non-expressioned +// value. +// +//========================================================================== + +VMScriptFunction *CreateDamageFunction(int dmg) +{ + if (dmg == 0) + { + // For zero damage, do not create a function so that the special collision detection case still works as before. + return NULL; + } + else + { + VMFunctionBuilder build; + build.Registers[REGT_POINTER].Get(1); // The self pointer + build.EmitRetInt(0, false, dmg); + build.EmitRetInt(1, true, 0); + VMScriptFunction *sfunc = build.MakeFunction(); + sfunc->NumArgs = 1; + return sfunc; + } +} diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index e60c746cde..d8c13174a7 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -26,8 +26,8 @@ struct FFlagDef }; FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2); -void HandleDeprecatedFlags(AActor *defaults, FActorInfo *info, bool set, int index); -bool CheckDeprecatedFlags(const AActor *actor, FActorInfo *info, int index); +void HandleDeprecatedFlags(AActor *defaults, PClassActor *info, bool set, int index); +bool CheckDeprecatedFlags(const AActor *actor, PClassActor *info, int index); const char *GetFlagName(unsigned int flagnum, int flagoffset); void ModActorFlag(AActor *actor, FFlagDef *fd, bool set); INTBOOL CheckActorFlag(const AActor *actor, FFlagDef *fd); @@ -76,13 +76,13 @@ class FStateDefinitions static FStateDefine *FindStateLabelInList(TArray &list, FName name, bool create); static FStateLabels *CreateStateLabelList(TArray &statelist); static void MakeStateList(const FStateLabels *list, TArray &dest); - static void RetargetStatePointers (intptr_t count, const char *target, TArray & statelist); + static void RetargetStatePointers(intptr_t count, const char *target, TArray & statelist); FStateDefine *FindStateAddress(const char *name); FState *FindState(const char *name); - FState *ResolveGotoLabel (AActor *actor, const PClass *mytype, char *name); - static void FixStatePointers (FActorInfo *actor, TArray & list); - void ResolveGotoLabels (FActorInfo *actor, AActor *defaults, TArray & list); + FState *ResolveGotoLabel(AActor *actor, PClassActor *mytype, char *name); + static void FixStatePointers(PClassActor *actor, TArray & list); + void ResolveGotoLabels(PClassActor *actor, AActor *defaults, TArray & list); public: @@ -93,13 +93,13 @@ public: lastlabel = -1; } - void SetStateLabel (const char * statename, FState * state, BYTE defflags = SDF_STATE); - void AddStateLabel (const char * statename); + void SetStateLabel(const char *statename, FState *state, BYTE defflags = SDF_STATE); + void AddStateLabel(const char *statename); int GetStateLabelIndex (FName statename); - void InstallStates(FActorInfo *info, AActor *defaults); - int FinishStates (FActorInfo *actor, AActor *defaults); + void InstallStates(PClassActor *info, AActor *defaults); + int FinishStates(PClassActor *actor, AActor *defaults); - void MakeStateDefines(const PClass *cls); + void MakeStateDefines(const PClassActor *cls); void AddStateDefines(const FStateLabels *list); void RetargetStates (intptr_t count, const char *target); @@ -107,9 +107,8 @@ public: bool SetStop(); bool SetWait(); bool SetLoop(); - bool AddStates(FState *state, const char *framechars); + int AddStates(FState *state, const char *framechars); int GetStateCount() const { return StateArray.Size(); } - }; //========================================================================== @@ -118,58 +117,43 @@ public: // //========================================================================== -struct FStateExpression +struct FStateTempCall { - FxExpression *expr; - const PClass *owner; - bool constant; - bool cloned; + FStateTempCall() : ActorClass(NULL), Code(NULL), FirstState(0), NumStates(0) {} + + PClassActor *ActorClass; + class FxTailable *Code; + int FirstState; + int NumStates; }; - -class FStateExpressions -{ - TArray expressions; - -public: - ~FStateExpressions() { Clear(); } - void Clear(); - int Add(FxExpression *x, const PClass *o, bool c); - int Reserve(int num, const PClass *cls); - void Set(int num, FxExpression *x, bool cloned = false); - void Copy(int dest, int src, int cnt); - int ResolveAll(); - FxExpression *Get(int no); - unsigned int Size() { return expressions.Size(); } -}; - -extern FStateExpressions StateParams; - +extern TDeletingArray StateTempCalls; +extern TDeletingArray ActorDamageFuncs; //========================================================================== // // Extra info maintained while defining an actor. // //========================================================================== -struct FDropItem; +class DDropItem; struct Baggage { #ifdef _DEBUG FString ClassName; // This is here so that during debugging the class name can be seen #endif - FActorInfo *Info; + PClassActor *Info; bool DropItemSet; bool StateSet; int CurrentState; int Lumpnum; FStateDefinitions statedef; - FDropItem *DropItemList; + DDropItem *DropItemList; FScriptPosition ScriptPosition; }; -inline void ResetBaggage (Baggage *bag, const PClass *stateclass) +inline void ResetBaggage (Baggage *bag, PClassActor *stateclass) { bag->DropItemList = NULL; bag->DropItemSet = false; @@ -178,6 +162,14 @@ inline void ResetBaggage (Baggage *bag, const PClass *stateclass) bag->statedef.MakeStateDefines(stateclass); } +//========================================================================== +// +// Damage function creation +// +//========================================================================== + +VMScriptFunction *CreateDamageFunction(int dmg); + //========================================================================== // // Action function lookup @@ -188,14 +180,19 @@ struct AFuncDesc { const char *Name; actionf_p Function; + VMNativeFunction **VMPointer; }; AFuncDesc *FindFunction(const char * string); -void ParseStates(FScanner &sc, FActorInfo *actor, AActor *defaults, Baggage &bag); +void ParseStates(FScanner &sc, PClassActor *actor, AActor *defaults, Baggage &bag); +void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray &out_params, + PFunction *afd, FString statestring, FStateDefinitions *statedef); +FxTailable *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag); +class FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestring, Baggage &bag); -PSymbolActionFunction *FindGlobalActionFunction(const char *name); +PFunction *FindGlobalActionFunction(const char *name); //========================================================================== // @@ -203,12 +200,12 @@ PSymbolActionFunction *FindGlobalActionFunction(const char *name); // //========================================================================== -FActorInfo *CreateNewActor(const FScriptPosition &sc, FName typeName, FName parentName, bool native); -void SetReplacement(FScanner &sc, FActorInfo *info, FName replaceName); +PClassActor *CreateNewActor(const FScriptPosition &sc, FName typeName, FName parentName, bool native); +void SetReplacement(FScanner &sc, PClassActor *info, FName replaceName); void HandleActorFlag(FScanner &sc, Baggage &bag, const char *part1, const char *part2, int mod); -void FinishActor(const FScriptPosition &sc, FActorInfo *info, Baggage &bag); -FxExpression *ParseParameter(FScanner &sc, PClass *cls, char type, bool constant); +void FinishActor(const FScriptPosition &sc, PClassActor *info, Baggage &bag); +FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool constant); enum @@ -228,21 +225,6 @@ enum DEPF_INTERHUBSTRIP, }; -enum -{ - ACMETA_BASE = 0x83000, - ACMETA_DropItems, // Int (index into DropItemList) - ACMETA_ExplosionDamage, - ACMETA_ExplosionRadius, - ACMETA_DontHurtShooter, - ACMETA_MeleeSound, - ACMETA_MeleeDamage, - ACMETA_MissileName, - ACMETA_MissileHeight, - ACMETA_Lump, -}; - - // Types of old style decorations enum EDefinitionType { @@ -253,10 +235,9 @@ enum EDefinitionType }; #if defined(_MSC_VER) -#pragma data_seg(".areg$u") -#pragma data_seg(".greg$u") -#pragma data_seg(".mreg$u") -#pragma data_seg() +#pragma section(".areg$u",read) +#pragma section(".greg$u",read) +#pragma section(".mreg$u",read) #define MSVC_ASEG __declspec(allocate(".areg$u")) #define GCC_ASEG @@ -279,9 +260,10 @@ union FPropParam int i; float f; const char *s; + FxExpression *exp; }; -typedef void (*PropHandler)(AActor *defaults, FActorInfo *info, Baggage &bag, FPropParam *params); +typedef void (*PropHandler)(AActor *defaults, PClassActor *info, Baggage &bag, FPropParam *params); enum ECategory { @@ -293,37 +275,28 @@ struct FPropertyInfo { const char *name; const char *params; - const PClass *cls; + const PClass * const *cls; PropHandler Handler; int category; }; -struct FVariableInfo -{ - const char *name; - intptr_t address; - const PClass *owner; -}; - - FPropertyInfo *FindProperty(const char * string); -FVariableInfo *FindVariable(const char * string, const PClass *cls); 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, FActorInfo *info, Baggage &bag, FPropParam *params); \ + 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(A##clas), (PropHandler)Handler_##name##_##paramlist##_##clas, cat }; \ + { #name, #paramlist, &RUNTIME_CLASS_CASTLESS(A##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, FActorInfo *info, Baggage &bag, FPropParam *params) + 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, FActorInfo *info, Baggage &bag, FPropParam *params); \ + 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(A##clas), (PropHandler)Handler_##name##_##paramlist##_##clas, cat }; \ +{ #prefix"."#name, #paramlist, &RUNTIME_CLASS_CASTLESS(A##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, FActorInfo *info, Baggage &bag, FPropParam *params) + static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, PClassActor *info, Baggage &bag, FPropParam *params) #define DEFINE_PROPERTY(name, paramlist, clas) DEFINE_PROPERTY_BASE(name, paramlist, clas, CAT_PROPERTY) @@ -337,6 +310,9 @@ int MatchString (const char *in, const char **strings); #define PROP_STRING_PARM(var, no) \ const char *var = params[(no)+1].s; +#define PROP_EXP_PARM(var, no) \ + FxExpression *var = params[(no)+1].exp; + #define PROP_INT_PARM(var, no) \ int var = params[(no)+1].i; @@ -350,92 +326,36 @@ int MatchString (const char *in, const char **strings); int var = params[(no)+1].i== 0? params[(no)+2].i : V_GetColor(NULL, params[(no)+2].s); -#define DEFINE_GLOBAL_VARIABLE(name) \ - static FVariableInfo GlobalDef__##name = { #name, intptr_t(&name), NULL }; \ - MSVC_MSEG FVariableInfo *infoptr_GlobalDef__##name GCC_MSEG = &GlobalDef__##name; - -#define DEFINE_MEMBER_VARIABLE(name, cls) \ - static FVariableInfo GlobalDef__##name = { #name, static_cast(myoffsetof(cls, name)), RUNTIME_CLASS(cls) }; \ - MSVC_MSEG FVariableInfo *infoptr_GlobalDef__##name GCC_MSEG = &GlobalDef__##name; - -#define DEFINE_MEMBER_VARIABLE_ALIAS(name, alias, cls) \ - static FVariableInfo GlobalDef__##name = { #name, static_cast(myoffsetof(cls, alias)), RUNTIME_CLASS(cls) }; \ - MSVC_MSEG FVariableInfo *infoptr_GlobalDef__##name GCC_MSEG = &GlobalDef__##name; - - - - -struct StateCallData -{ - FState *State; - bool Result; -}; - // Macros to handle action functions. These are here so that I don't have to // change every single use in case the parameters change. -#define DECLARE_ACTION(name) void AF_##name(AActor *self, AActor *stateowner, FState *, int, StateCallData *); -#define DECLARE_ACTION_PARAMS(name) void AFP_##name(AActor *self, AActor *stateowner, FState *, int, StateCallData *); +#define DECLARE_ACTION(name) extern VMNativeFunction *name##_VMPtr; // This distinction is here so that CALL_ACTION produces errors when trying to // access a function that requires parameters. #define DEFINE_ACTION_FUNCTION(cls, name) \ - void AF_##name (AActor *self, AActor *stateowner, FState *, int, StateCallData *); \ - static AFuncDesc info_##cls##_##name = { #name, AF_##name }; \ - MSVC_ASEG AFuncDesc *infoptr_##cls##_##name GCC_ASEG = &info_##cls##_##name; \ - void AF_##name (AActor *self, AActor *stateowner, FState *CallingState, int, StateCallData *statecall) + static int AF_##name(VM_ARGS); \ + VMNativeFunction *name##_VMPtr; \ + static const AFuncDesc cls##_##name##_Hook = { #name, AF_##name, &name##_VMPtr }; \ + extern AFuncDesc const *const cls##_##name##_HookPtr; \ + MSVC_ASEG AFuncDesc const *const cls##_##name##_HookPtr GCC_ASEG = &cls##_##name##_Hook; \ + static int AF_##name(VM_ARGS) -#define DEFINE_ACTION_FUNCTION_PARAMS(cls, name) \ - void AFP_##name (AActor *self, AActor *stateowner, FState *CallingState, int ParameterIndex, StateCallData *statecall); \ - static AFuncDesc info_##cls##_##name = { #name, AFP_##name }; \ - MSVC_ASEG AFuncDesc *infoptr_##cls##_##name GCC_ASEG = &info_##cls##_##name; \ - void AFP_##name (AActor *self, AActor *stateowner, FState *CallingState, int ParameterIndex, StateCallData *statecall) +#define DEFINE_ACTION_FUNCTION_PARAMS(cls, name) DEFINE_ACTION_FUNCTION(cls, name) -#define DECLARE_PARAMINFO AActor *self, AActor *stateowner, FState *CallingState, int ParameterIndex, StateCallData *statecall -#define PUSH_PARAMINFO self, stateowner, CallingState, ParameterIndex, statecall +//#define DECLARE_PARAMINFO AActor *self, AActor *stateowner, FState *CallingState, int ParameterIndex, StateCallData *statecall +//#define PUSH_PARAMINFO self, stateowner, CallingState, ParameterIndex, statecall -#define CALL_ACTION(name,self) AF_##name(self, self, NULL, 0, NULL) +#define CALL_ACTION(name,self) { /*AF_##name(self, self, NULL, 0, NULL)*/ \ + VMValue params[3] = { self, self, VMValue(NULL, ATAG_STATE) }; \ + stack->Call(name##_VMPtr, params, countof(params), NULL, 0, NULL); \ + } -int EvalExpressionI (DWORD x, AActor *self); -int EvalExpressionCol (DWORD x, AActor *self); -FSoundID EvalExpressionSnd (DWORD x, AActor *self); -double EvalExpressionF (DWORD x, AActor *self); -fixed_t EvalExpressionFix (DWORD x, AActor *self); -FState *EvalExpressionState (DWORD x, AActor *self); -const PClass *EvalExpressionClass (DWORD x, AActor *self); -FName EvalExpressionName (DWORD x, AActor *self); - -#define ACTION_PARAM_START(count) - -#define ACTION_PARAM_INT(var, i) \ - int var = EvalExpressionI(ParameterIndex+i, self); -#define ACTION_PARAM_BOOL(var,i) \ - bool var = !!EvalExpressionI(ParameterIndex+i, self); -#define ACTION_PARAM_FIXED(var,i) \ - fixed_t var = EvalExpressionFix(ParameterIndex+i, self); -#define ACTION_PARAM_FLOAT(var,i) \ - float var = float(EvalExpressionF(ParameterIndex+i, self)); -#define ACTION_PARAM_DOUBLE(var,i) \ - double var = EvalExpressionF(ParameterIndex+i, self); -#define ACTION_PARAM_CLASS(var,i) \ - const PClass *var = EvalExpressionClass(ParameterIndex+i, self); -#define ACTION_PARAM_STATE(var,i) \ - FState *var = EvalExpressionState(ParameterIndex+i, stateowner); -#define ACTION_PARAM_COLOR(var,i) \ - PalEntry var = EvalExpressionCol(ParameterIndex+i, self); -#define ACTION_PARAM_SOUND(var,i) \ - FSoundID var = EvalExpressionSnd(ParameterIndex+i, self); -#define ACTION_PARAM_STRING(var,i) \ - const char *var = EvalExpressionName(ParameterIndex+i, self); -#define ACTION_PARAM_NAME(var,i) \ - FName var = EvalExpressionName(ParameterIndex+i, self); -#define ACTION_PARAM_ANGLE(var,i) \ - angle_t var = angle_t(EvalExpressionF(ParameterIndex+i, self)*ANGLE_90/90.f); - -#define ACTION_SET_RESULT(v) if (statecall != NULL) statecall->Result = v; +#define ACTION_SET_RESULT(v) do { if (numret > 0) { assert(ret != NULL); ret->SetInt(v); numret = 1; } } while(0) +#define ACTION_OR_RESULT(v) do { if (numret > 0) { assert(ret != NULL); ret->SetInt(*(int *)ret->Location | int(v)); numret = 1; } } while(0) // Checks to see what called the current action function -#define ACTION_CALL_FROM_ACTOR() (CallingState == self->state) -#define ACTION_CALL_FROM_WEAPON() (self->player && CallingState != self->state && statecall == NULL) -#define ACTION_CALL_FROM_INVENTORY() (statecall != NULL) +#define ACTION_CALL_FROM_ACTOR() (callingstate == self->state) +#define ACTION_CALL_FROM_WEAPON() (self->player && callingstate != self->state && !(stateowner->flags5 & MF5_INSTATECALL)) +#define ACTION_CALL_FROM_INVENTORY() (!(stateowner->flags5 & MF5_INSTATECALL)) #endif diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 8608915f4c..ba5bc7f47d 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1,5 +1,5 @@ /* -** thingdef.cpp +** thingdef_codeptr.cpp ** ** Code pointers for Actor definitions ** @@ -74,7 +74,8 @@ #include "p_setup.h" #include "gstrings.h" -AActor *SingleActorFromTID (int tid, AActor *defactor); +AActor *SingleActorFromTID(int tid, AActor *defactor); + static FRandom pr_camissile ("CustomActorfire"); static FRandom pr_camelee ("CustomMelee"); @@ -100,46 +101,120 @@ static FRandom pr_teleport("A_Teleport"); // //========================================================================== -bool ACustomInventory::CallStateChain (AActor *actor, FState * State) +bool ACustomInventory::CallStateChain (AActor *actor, FState *state) { - StateCallData StateCall; - bool result = false; + INTBOOL result = false; int counter = 0; + int retval, numret; + VMReturn ret; + ret.IntAt(&retval); + VMValue params[3] = { actor, this, 0 }; - while (State != NULL) + this->flags5 |= MF5_INSTATECALL; + FState *savedstate = this->state; + + while (state != NULL) { - // Assume success. The code pointer will set this to false if necessary - StateCall.State = State; - StateCall.Result = true; - if (State->CallAction(actor, this, &StateCall)) - { - // collect all the results. Even one successful call signifies overall success. - result |= StateCall.Result; - } + this->state = state; + if (state->ActionFunc != NULL) + { + VMFrameStack stack; + + params[2] = VMValue(state, ATAG_STATE); + retval = true; // assume success + numret = stack.Call(state->ActionFunc, params, countof(params), &ret, 1); + // As long as even one state succeeds, the whole chain succeeds unless aborted below. + result |= retval; + } // Since there are no delays it is a good idea to check for infinite loops here! counter++; if (counter >= 10000) break; - if (StateCall.State == State) + if (this->state == state) { - // Abort immediately if the state jumps to itself! - if (State == State->GetNextState()) - { - return false; + FState *next = state->GetNextState(); + + if (state == next) + { // Abort immediately if the state jumps to itself! + result = false; + break; } // If both variables are still the same there was no jump // so we must advance to the next state. - State = State->GetNextState(); + state = next; } else { - State = StateCall.State; + state = this->state; } } - return result; + this->flags5 &= ~MF5_INSTATECALL; + this->state = savedstate; + return !!result; +} + +//========================================================================== +// +// CheckClass +// +// NON-ACTION function to check a pointer's class. +// +//========================================================================== + +DEFINE_ACTION_FUNCTION(AActor, CheckClass) +{ + if (numret > 0) + { + assert(ret != NULL); + PARAM_PROLOGUE; + PARAM_OBJECT (self, AActor); + PARAM_CLASS (checktype, AActor); + PARAM_INT_OPT (pick_pointer) { pick_pointer = AAPTR_DEFAULT; } + PARAM_BOOL_OPT (match_superclass) { match_superclass = false; } + + self = COPY_AAPTR(self, pick_pointer); + if (self == NULL) + { + ret->SetInt(false); + } + else if (match_superclass) + { + ret->SetInt(self->IsKindOf(checktype)); + } + else + { + ret->SetInt(self->GetClass() == checktype); + } + return 1; + } + return 0; +} + +//========================================================================== +// +// IsPointerEqual +// +// NON-ACTION function to check if two pointers are equal. +// +//========================================================================== + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, IsPointerEqual) +{ + if (numret > 0) + { + assert(ret != NULL); + PARAM_PROLOGUE; + PARAM_OBJECT (self, AActor); + PARAM_INT (ptr_select1); + PARAM_INT (ptr_select2); + + ret->SetInt(COPY_AAPTR(self, ptr_select1) == COPY_AAPTR(self, ptr_select2)); + return 1; + } + return 0; } //========================================================================== @@ -155,11 +230,11 @@ bool ACustomInventory::CallStateChain (AActor *actor, FState * State) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RearrangePointers) { - ACTION_PARAM_START(4); - ACTION_PARAM_INT(ptr_target, 0); - ACTION_PARAM_INT(ptr_master, 1); - ACTION_PARAM_INT(ptr_tracer, 2); - ACTION_PARAM_INT(flags, 3); + PARAM_ACTION_PROLOGUE; + PARAM_INT (ptr_target); + PARAM_INT_OPT (ptr_master) { ptr_master = AAPTR_DEFAULT; } + PARAM_INT_OPT (ptr_tracer) { ptr_tracer = AAPTR_TRACER; } + PARAM_INT_OPT (flags) { flags = 0; } // Rearrange pointers internally @@ -213,6 +288,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RearrangePointers) self->tracer = NULL; break; } + return 0; } //========================================================================== @@ -234,29 +310,35 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RearrangePointers) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TransferPointer) { - ACTION_PARAM_START(5); - ACTION_PARAM_INT(ptr_source, 0); - ACTION_PARAM_INT(ptr_recipient, 1); - ACTION_PARAM_INT(ptr_sourcefield, 2); - ACTION_PARAM_INT(ptr_recipientfield, 3); - ACTION_PARAM_INT(flags, 4); + PARAM_ACTION_PROLOGUE; + PARAM_INT (ptr_source); + PARAM_INT (ptr_recipient); + PARAM_INT (ptr_sourcefield); + PARAM_INT_OPT (ptr_recipientfield) { ptr_recipientfield = AAPTR_DEFAULT; } + PARAM_INT_OPT (flags) { flags = 0; } AActor *source, *recipient; // Exchange pointers with actors to whom you have pointers (or with yourself, if you must) - source = COPY_AAPTR(self, ptr_source); - COPY_AAPTR_NOT_NULL(self, recipient, ptr_recipient); // pick an actor to store the provided pointer value + recipient = COPY_AAPTR(self, ptr_recipient); // pick an actor to store the provided pointer value + if (recipient == NULL) + { + return 0; + } // convert source from dataprovider to data - source = COPY_AAPTR(source, ptr_sourcefield); - - if (source == recipient) source = NULL; // The recipient should not acquire a pointer to itself; will write NULL - - if (ptr_recipientfield == AAPTR_DEFAULT) ptr_recipientfield = ptr_sourcefield; // If default: Write to same field as data was read from - + if (source == recipient) + { // The recepient should not acquire a pointer to itself; will write NULL} + source = NULL; + } + if (ptr_recipientfield == AAPTR_DEFAULT) + { // If default: Write to same field as data was read from + ptr_recipientfield = ptr_sourcefield; + } ASSIGN_AAPTR(recipient, ptr_recipientfield, source, flags); + return 0; } //========================================================================== @@ -271,14 +353,20 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TransferPointer) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CopyFriendliness) { - ACTION_PARAM_START(1); - ACTION_PARAM_INT(ptr_source, 0); + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT (ptr_source) { ptr_source = AAPTR_MASTER; } - if (self->player) return; + if (self->player != NULL) + { + return 0; + } - AActor *source; - COPY_AAPTR_NOT_NULL(self, source, ptr_source); - self->CopyFriendliness(source, false, false); // No change in current target or health + AActor *source = COPY_AAPTR(self, ptr_source); + if (source != NULL) + { // No change in current target or health + self->CopyFriendliness(source, false, false); + } + return 0; } //========================================================================== @@ -288,22 +376,30 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CopyFriendliness) //========================================================================== DEFINE_ACTION_FUNCTION(AActor, A_SetSolid) { + PARAM_ACTION_PROLOGUE; self->flags |= MF_SOLID; + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_UnsetSolid) { + PARAM_ACTION_PROLOGUE; self->flags &= ~MF_SOLID; + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_SetFloat) { + PARAM_ACTION_PROLOGUE; self->flags |= MF_FLOAT; + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_UnsetFloat) { + PARAM_ACTION_PROLOGUE; self->flags &= ~(MF_FLOAT|MF_INFLOAT); + return 0; } //========================================================================== @@ -312,7 +408,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_UnsetFloat) // //========================================================================== static void DoAttack (AActor *self, bool domelee, bool domissile, - int MeleeDamage, FSoundID MeleeSound, const PClass *MissileType,fixed_t MissileHeight) + int MeleeDamage, FSoundID MeleeSound, PClassActor *MissileType,fixed_t MissileHeight) { if (self->target == NULL) return; @@ -345,37 +441,46 @@ static void DoAttack (AActor *self, bool domelee, bool domissile, DEFINE_ACTION_FUNCTION(AActor, A_MeleeAttack) { - int MeleeDamage = self->GetClass()->Meta.GetMetaInt (ACMETA_MeleeDamage, 0); - FSoundID MeleeSound = self->GetClass()->Meta.GetMetaInt (ACMETA_MeleeSound, 0); + PARAM_ACTION_PROLOGUE; + int MeleeDamage = self->GetClass()->MeleeDamage; + FSoundID MeleeSound = self->GetClass()->MeleeSound; DoAttack(self, true, false, MeleeDamage, MeleeSound, NULL, 0); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_MissileAttack) { - const PClass *MissileType=PClass::FindClass((ENamedName) self->GetClass()->Meta.GetMetaInt (ACMETA_MissileName, NAME_None)); - fixed_t MissileHeight= self->GetClass()->Meta.GetMetaFixed (ACMETA_MissileHeight, 32*FRACUNIT); + PARAM_ACTION_PROLOGUE; + PClassActor *MissileType = PClass::FindActor(self->GetClass()->MissileName); + fixed_t MissileHeight = self->GetClass()->MissileHeight; DoAttack(self, false, true, 0, 0, MissileType, MissileHeight); + return 0; } DEFINE_ACTION_FUNCTION(AActor, A_ComboAttack) { - int MeleeDamage = self->GetClass()->Meta.GetMetaInt (ACMETA_MeleeDamage, 0); - FSoundID MeleeSound = self->GetClass()->Meta.GetMetaInt (ACMETA_MeleeSound, 0); - const PClass *MissileType=PClass::FindClass((ENamedName) self->GetClass()->Meta.GetMetaInt (ACMETA_MissileName, NAME_None)); - fixed_t MissileHeight= self->GetClass()->Meta.GetMetaFixed (ACMETA_MissileHeight, 32*FRACUNIT); + PARAM_ACTION_PROLOGUE; + int MeleeDamage = self->GetClass()->MeleeDamage; + FSoundID MeleeSound = self->GetClass()->MeleeSound; + PClassActor *MissileType = PClass::FindActor(self->GetClass()->MissileName); + fixed_t MissileHeight = self->GetClass()->MissileHeight; DoAttack(self, true, true, MeleeDamage, MeleeSound, MissileType, MissileHeight); + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BasicAttack) { - ACTION_PARAM_START(4); - ACTION_PARAM_INT(MeleeDamage, 0); - ACTION_PARAM_SOUND(MeleeSound, 1); - ACTION_PARAM_CLASS(MissileType, 2); - ACTION_PARAM_FIXED(MissileHeight, 3); + PARAM_ACTION_PROLOGUE; + PARAM_INT (melee_damage); + PARAM_SOUND (melee_sound); + PARAM_CLASS (missile_type, AActor); + PARAM_FIXED (missile_height); - if (MissileType == NULL) return; - DoAttack(self, true, true, MeleeDamage, MeleeSound, MissileType, MissileHeight); + if (missile_type != NULL) + { + DoAttack(self, true, true, melee_damage, melee_sound, missile_type, missile_height); + } + return 0; } //========================================================================== @@ -386,32 +491,34 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BasicAttack) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlaySound) { - ACTION_PARAM_START(5); - ACTION_PARAM_SOUND(soundid, 0); - ACTION_PARAM_INT(channel, 1); - ACTION_PARAM_FLOAT(volume, 2); - ACTION_PARAM_BOOL(looping, 3); - ACTION_PARAM_FLOAT(attenuation, 4); + PARAM_ACTION_PROLOGUE; + PARAM_SOUND_OPT (soundid) { soundid = "weapons/pistol"; } + PARAM_INT_OPT (channel) { channel = CHAN_BODY; } + PARAM_FLOAT_OPT (volume) { volume = 1; } + PARAM_BOOL_OPT (looping) { looping = false; } + PARAM_FLOAT_OPT (attenuation) { attenuation = ATTN_NORM; } if (!looping) { - S_Sound (self, channel, soundid, volume, attenuation); + S_Sound (self, channel, soundid, (float)volume, (float)attenuation); } else { if (!S_IsActorPlayingSomething (self, channel&7, soundid)) { - S_Sound (self, channel | CHAN_LOOP, soundid, volume, attenuation); + S_Sound (self, channel | CHAN_LOOP, soundid, (float)volume, (float)attenuation); } } + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StopSound) { - ACTION_PARAM_START(1); - ACTION_PARAM_INT(slot, 0); + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT(slot) { slot = CHAN_VOICE; } S_StopSound(self, slot); + return 0; } //========================================================================== @@ -425,19 +532,20 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StopSound) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlayWeaponSound) { - ACTION_PARAM_START(1); - ACTION_PARAM_SOUND(soundid, 0); + PARAM_ACTION_PROLOGUE; + PARAM_SOUND(soundid); - S_Sound (self, CHAN_WEAPON, soundid, 1, ATTN_NORM); + S_Sound(self, CHAN_WEAPON, soundid, 1, ATTN_NORM); + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlaySoundEx) { - ACTION_PARAM_START(4); - ACTION_PARAM_SOUND(soundid, 0); - ACTION_PARAM_NAME(channel, 1); - ACTION_PARAM_BOOL(looping, 2); - ACTION_PARAM_INT(attenuation_raw, 3); + PARAM_ACTION_PROLOGUE; + PARAM_SOUND (soundid); + PARAM_NAME (channel); + PARAM_BOOL_OPT (looping) { looping = false; } + PARAM_INT_OPT (attenuation_raw) { attenuation_raw = 0; } float attenuation; switch (attenuation_raw) @@ -465,17 +573,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlaySoundEx) S_Sound (self, (int(channel) - NAME_Auto) | CHAN_LOOP, soundid, 1, attenuation); } } + return 0; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StopSoundEx) { - ACTION_PARAM_START(1); - ACTION_PARAM_NAME(channel, 0); + PARAM_ACTION_PROLOGUE; + PARAM_NAME(channel); if (channel > NAME_Auto && channel <= NAME_SoundSlot7) { S_StopSound (self, int(channel) - NAME_Auto); } + return 0; } //========================================================================== @@ -492,12 +602,12 @@ enum }; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SeekerMissile) { - ACTION_PARAM_START(5); - ACTION_PARAM_INT(ang1, 0); - ACTION_PARAM_INT(ang2, 1); - ACTION_PARAM_INT(flags, 2); - ACTION_PARAM_INT(chance, 3); - ACTION_PARAM_INT(distance, 4); + PARAM_ACTION_PROLOGUE; + PARAM_INT(ang1); + PARAM_INT(ang2); + PARAM_INT_OPT(flags) { flags = 0; } + PARAM_INT_OPT(chance) { chance = 50; } + PARAM_INT_OPT(distance) { distance = 10; } if ((flags & SMF_LOOK) && (self->tracer == 0) && (pr_seekermissile()tracer = NULL; } } + return 0; } //========================================================================== @@ -519,11 +630,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SeekerMissile) //========================================================================== DEFINE_ACTION_FUNCTION(AActor, A_BulletAttack) { + PARAM_ACTION_PROLOGUE; + int i; int bangle; int slope; - if (!self->target) return; + if (!self->target) return 0; A_FaceTarget (self); bangle = self->angle; @@ -538,6 +651,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BulletAttack) P_LineAttack(self, angle, MISSILERANGE, slope, damage, NAME_Hitscan, NAME_BulletPuff); } + return 0; } @@ -546,36 +660,43 @@ DEFINE_ACTION_FUNCTION(AActor, A_BulletAttack) // Do the state jump // //========================================================================== -static void DoJump(AActor * self, FState * CallingState, FState *jumpto, StateCallData *statecall) +static void DoJump(AActor *self, AActor *stateowner, FState *callingstate, FState *jumpto) { if (jumpto == NULL) return; - if (statecall != NULL) + if (stateowner->flags5 & MF5_INSTATECALL) { - statecall->State = jumpto; + stateowner->state = jumpto; } - else if (self->player != NULL && CallingState == self->player->psprites[ps_weapon].state) + else if (self->player != NULL && callingstate == self->player->psprites[ps_weapon].state) { P_SetPsprite(self->player, ps_weapon, jumpto); } - else if (self->player != NULL && CallingState == self->player->psprites[ps_flash].state) + else if (self->player != NULL && callingstate == self->player->psprites[ps_flash].state) { P_SetPsprite(self->player, ps_flash, jumpto); } - else if (CallingState == self->state) + else if (callingstate == self->state) { - self->SetState (jumpto); + // Rather than using self->SetState(jumpto) to set the state, + // set the state directly. Since this function is only called by + // action functions, which are only called by SetState(), we + // know that somewhere above us in the stack, a SetState() + // call is waiting for us to return. We use the flag OF_StateChanged + // to cause it to bypass the normal next state mechanism and use + // the one we set here instead. + self->state = jumpto; + self->ObjectFlags |= OF_StateChanged; } else - { - // something went very wrong. This should never happen. + { // something went very wrong. This should never happen. assert(false); } } // This is just to avoid having to directly reference the internally defined // CallingState and statecall parameters in the code below. -#define ACTION_JUMP(offset) DoJump(self, CallingState, offset, statecall) +#define ACTION_JUMP(offset) DoJump(self, stateowner, callingstate, offset) //========================================================================== // @@ -584,17 +705,19 @@ static void DoJump(AActor * self, FState * CallingState, FState *jumpto, StateCa //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Jump) { - ACTION_PARAM_START(3); - ACTION_PARAM_INT(count, 0); - ACTION_PARAM_INT(maxchance, 1); + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT(maxchance) { maxchance = 256; } - if (count >= 2 && (maxchance >= 256 || pr_cajump() < maxchance)) + paramnum++; // Increment paramnum to point at the first jump target + int count = numparam - paramnum; + if (count > 0 && (maxchance >= 256 || pr_cajump() < maxchance)) { - int jumps = 2 + (count == 2? 0 : (pr_cajump() % (count - 1))); - ACTION_PARAM_STATE(jumpto, jumps); + int jumpnum = (count == 1 ? 0 : (pr_cajump() % count)); + PARAM_STATE_AT(paramnum + jumpnum, jumpto); ACTION_JUMP(jumpto); } ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! + return numret; } //========================================================================== @@ -604,21 +727,21 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Jump) //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfHealthLower) { - ACTION_PARAM_START(3); - ACTION_PARAM_INT(health, 0); - ACTION_PARAM_STATE(jump, 1); - ACTION_PARAM_INT(ptr_selector, 2); + PARAM_ACTION_PROLOGUE; + PARAM_INT (health); + PARAM_STATE (jump); + PARAM_INT_OPT (ptr_selector) { ptr_selector = AAPTR_DEFAULT; } AActor *measured; measured = COPY_AAPTR(self, ptr_selector); - - if (measured && measured->health < health) + + if (measured != NULL && measured->health < health) { ACTION_JUMP(jump); } - ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! + return numret; } //========================================================================== @@ -628,14 +751,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfHealthLower) //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetOutsideMeleeRange) { - ACTION_PARAM_START(1); - ACTION_PARAM_STATE(jump, 0); + PARAM_ACTION_PROLOGUE; + PARAM_STATE(jump); if (!self->CheckMeleeRange()) { ACTION_JUMP(jump); } ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! + return numret; } //========================================================================== @@ -645,32 +769,34 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetOutsideMeleeRange) //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInsideMeleeRange) { - ACTION_PARAM_START(1); - ACTION_PARAM_STATE(jump, 0); + PARAM_ACTION_PROLOGUE; + PARAM_STATE(jump); if (self->CheckMeleeRange()) { ACTION_JUMP(jump); } ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! + return numret; } + //========================================================================== // // State jump function // //========================================================================== -void DoJumpIfCloser(AActor *target, DECLARE_PARAMINFO) +static int DoJumpIfCloser(AActor *target, VM_ARGS) { - ACTION_PARAM_START(3); - ACTION_PARAM_FIXED(dist, 0); - ACTION_PARAM_STATE(jump, 1); - ACTION_PARAM_BOOL(noz, 2); + PARAM_ACTION_PROLOGUE; + PARAM_FIXED (dist); + PARAM_STATE (jump); + PARAM_BOOL_OPT(noz) { noz = false; } ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! // No target - no jump if (!target) - return; + return numret; if (self->AproxDistance(target) < dist && (noz || ((self->Z() > target->Z() && self->Z() - target->Top() < dist) || @@ -678,13 +804,16 @@ void DoJumpIfCloser(AActor *target, DECLARE_PARAMINFO) { ACTION_JUMP(jump); } + return numret; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfCloser) { + PARAM_ACTION_PROLOGUE; + AActor *target; - if (!self->player) + if (self->player == NULL) { target = self->target; } @@ -693,17 +822,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfCloser) // Does the player aim at something that can be shot? P_BulletSlope(self, &target); } - DoJumpIfCloser(target, PUSH_PARAMINFO); + return DoJumpIfCloser(target, VM_ARGS_NAMES); } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTracerCloser) { - DoJumpIfCloser(self->tracer, PUSH_PARAMINFO); + PARAM_ACTION_PROLOGUE; + return DoJumpIfCloser(self->tracer, VM_ARGS_NAMES); } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfMasterCloser) { - DoJumpIfCloser(self->master, PUSH_PARAMINFO); + PARAM_ACTION_PROLOGUE; + return DoJumpIfCloser(self->master, VM_ARGS_NAMES); } //========================================================================== @@ -711,43 +842,53 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfMasterCloser) // State jump function // //========================================================================== -void DoJumpIfInventory(AActor * owner, DECLARE_PARAMINFO) +int DoJumpIfInventory(AActor *owner, AActor *self, AActor *stateowner, FState *callingstate, VMValue *param, int numparam, VMReturn *ret, int numret) { - ACTION_PARAM_START(4); - ACTION_PARAM_CLASS(Type, 0); - ACTION_PARAM_INT(ItemAmount, 1); - ACTION_PARAM_STATE(JumpOffset, 2); - ACTION_PARAM_INT(setowner, 3); + int paramnum = NAP-1; + PARAM_CLASS (itemtype, AInventory); + PARAM_INT (itemamount); + PARAM_STATE (label); + PARAM_INT_OPT (setowner) { setowner = AAPTR_DEFAULT; } ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - if (!Type) return; - COPY_AAPTR_NOT_NULL(owner, owner, setowner); // returns if owner ends up being NULL - - AInventory *Item = owner->FindInventory(Type); - - if (Item) + if (itemtype == NULL) { - if (ItemAmount > 0) + return numret; + } + owner = COPY_AAPTR(owner, setowner); + if (owner == NULL) + { + return numret; + } + + AInventory *item = owner->FindInventory(itemtype); + + if (item) + { + if (itemamount > 0) { - if (Item->Amount >= ItemAmount) - ACTION_JUMP(JumpOffset); + if (item->Amount >= itemamount) + ACTION_JUMP(label); } - else if (Item->Amount >= Item->MaxAmount) + else if (item->Amount >= item->MaxAmount) { - ACTION_JUMP(JumpOffset); + ACTION_JUMP(label); } } + return numret; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInventory) { - DoJumpIfInventory(self, PUSH_PARAMINFO); + PARAM_ACTION_PROLOGUE; + return DoJumpIfInventory(self, self, stateowner, callingstate, param, numparam, ret, numret); } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetInventory) { - DoJumpIfInventory(self->target, PUSH_PARAMINFO); + PARAM_ACTION_PROLOGUE; + return DoJumpIfInventory(self->target, self, stateowner, callingstate, param, numparam, ret, numret); } //========================================================================== @@ -757,17 +898,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetInventory) //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfArmorType) { - ACTION_PARAM_START(3); - ACTION_PARAM_NAME(Type, 0); - ACTION_PARAM_STATE(JumpOffset, 1); - ACTION_PARAM_INT(amount, 2); + PARAM_ACTION_PROLOGUE; + PARAM_NAME (type); + PARAM_STATE (label); + PARAM_INT_OPT(amount) { amount = 1; } ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - ABasicArmor * armor = (ABasicArmor *) self->FindInventory(NAME_BasicArmor); + ABasicArmor *armor = (ABasicArmor *)self->FindInventory(NAME_BasicArmor); - if (armor && armor->ArmorType == Type && armor->Amount >= amount) - ACTION_JUMP(JumpOffset); + if (armor && armor->ArmorType == type && armor->Amount >= amount) + ACTION_JUMP(label); + return numret; } //========================================================================== @@ -784,27 +926,25 @@ enum DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Explode) { - ACTION_PARAM_START(8); - ACTION_PARAM_INT(damage, 0); - ACTION_PARAM_INT(distance, 1); - ACTION_PARAM_INT(flags, 2); - ACTION_PARAM_BOOL(alert, 3); - ACTION_PARAM_INT(fulldmgdistance, 4); - ACTION_PARAM_INT(nails, 5); - ACTION_PARAM_INT(naildamage, 6); - ACTION_PARAM_CLASS(pufftype, 7); + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT (damage) { damage = -1; } + PARAM_INT_OPT (distance) { distance = -1; } + PARAM_INT_OPT (flags) { flags = XF_HURTSOURCE; } + PARAM_BOOL_OPT (alert) { alert = false; } + PARAM_INT_OPT (fulldmgdistance) { fulldmgdistance = 0; } + PARAM_INT_OPT (nails) { nails = 0; } + PARAM_INT_OPT (naildamage) { naildamage = 10; } + PARAM_CLASS_OPT (pufftype, AActor) { pufftype = PClass::FindActor(NAME_BulletPuff); } if (damage < 0) // get parameters from metadata { - damage = self->GetClass()->Meta.GetMetaInt (ACMETA_ExplosionDamage, 128); - distance = self->GetClass()->Meta.GetMetaInt (ACMETA_ExplosionRadius, damage); - flags = !self->GetClass()->Meta.GetMetaInt (ACMETA_DontHurtShooter); + damage = self->GetClass()->ExplosionDamage; + distance = self->GetClass()->ExplosionRadius; + flags = !self->GetClass()->DontHurtShooter; alert = false; } - else - { - if (distance <= 0) distance = damage; - } + if (distance <= 0) distance = damage; + // NailBomb effect, from SMMU but not from its source code: instead it was implemented and // generalized from the documentation at http://www.doomworld.com/eternity/engine/codeptrs.html @@ -828,6 +968,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Explode) validcount++; P_RecursiveSound (self->Sector, self->target, false, 0); } + return 0; } //========================================================================== @@ -845,11 +986,11 @@ enum DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusThrust) { - ACTION_PARAM_START(3); - ACTION_PARAM_INT(force, 0); - ACTION_PARAM_INT(distance, 1); - ACTION_PARAM_INT(flags, 2); - ACTION_PARAM_INT(fullthrustdistance, 3); + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT (force) { force = 128; } + PARAM_INT_OPT (distance) { distance = -1; } + PARAM_INT_OPT (flags) { flags = RTF_AFFECTSOURCE; } + PARAM_INT_OPT (fullthrustdistance) { fullthrustdistance = 0; } bool sourcenothrust = false; @@ -870,6 +1011,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusThrust) { self->target->flags2 |= MF2_NODMGTHRUST; } + return 0; } //========================================================================== @@ -879,17 +1021,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusThrust) //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CallSpecial) { - ACTION_PARAM_START(6); - ACTION_PARAM_INT(special, 0); - ACTION_PARAM_INT(arg1, 1); - ACTION_PARAM_INT(arg2, 2); - ACTION_PARAM_INT(arg3, 3); - ACTION_PARAM_INT(arg4, 4); - ACTION_PARAM_INT(arg5, 5); + PARAM_ACTION_PROLOGUE; + PARAM_INT (special); + PARAM_INT_OPT (arg1) { arg1 = 0; } + PARAM_INT_OPT (arg2) { arg2 = 0; } + PARAM_INT_OPT (arg3) { arg3 = 0; } + PARAM_INT_OPT (arg4) { arg4 = 0; } + PARAM_INT_OPT (arg5) { arg5 = 0; } bool res = !!P_ExecuteSpecial(special, NULL, self, false, arg1, arg2, arg3, arg4, arg5); ACTION_SET_RESULT(res); + return numret; } //========================================================================== @@ -912,14 +1055,14 @@ enum CM_Flags DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMissile) { - ACTION_PARAM_START(7); - ACTION_PARAM_CLASS(ti, 0); - ACTION_PARAM_FIXED(spawnheight, 1); - ACTION_PARAM_INT(spawnofs_xy, 2); - ACTION_PARAM_ANGLE(angle, 3); - ACTION_PARAM_INT(flags, 4); - ACTION_PARAM_ANGLE(pitch, 5); - ACTION_PARAM_INT(ptr, 6); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS (ti, AActor); + PARAM_FIXED_OPT (spawnheight) { spawnheight = 32*FRACUNIT; } + PARAM_INT_OPT (spawnofs_xy) { spawnofs_xy = 0; } + PARAM_ANGLE_OPT (angle) { angle = 0; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_ANGLE_OPT (pitch) { pitch = 0; } + PARAM_INT_OPT (ptr) { ptr = AAPTR_TARGET; } AActor *ref = COPY_AAPTR(self, ptr); @@ -1043,6 +1186,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMissile) if (self->SeeState != NULL && (self->health > 0 || !(self->flags3 & MF3_ISMONSTER))) self->SetState(self->SeeState); } + return 0; } //========================================================================== @@ -1061,15 +1205,15 @@ enum CBA_Flags DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack) { - ACTION_PARAM_START(8); - ACTION_PARAM_ANGLE(spread_xy, 0); - ACTION_PARAM_ANGLE(spread_z, 1); - ACTION_PARAM_INT(numbullets, 2); - ACTION_PARAM_INT(damageperbullet, 3); - ACTION_PARAM_CLASS(pufftype, 4); - ACTION_PARAM_FIXED(range, 5); - ACTION_PARAM_INT(flags, 6); - ACTION_PARAM_INT(ptr, 7); + PARAM_ACTION_PROLOGUE; + PARAM_ANGLE (spread_xy); + PARAM_ANGLE (spread_z); + PARAM_INT (numbullets); + PARAM_INT (damageperbullet); + PARAM_CLASS_OPT (pufftype, AActor) { pufftype = PClass::FindActor(NAME_BulletPuff); } + PARAM_FIXED_OPT (range) { range = MISSILERANGE; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_INT_OPT (ptr) { ptr = AAPTR_TARGET; } AActor *ref = COPY_AAPTR(self, ptr); @@ -1089,8 +1233,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack) } bangle = self->angle; - if (!pufftype) pufftype = PClass::FindClass(NAME_BulletPuff); - if (!(flags & CBAF_NOPITCH)) bslope = P_AimLineAttack (self, bangle, MISSILERANGE); S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM); @@ -1118,6 +1260,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack) P_LineAttack(self, angle, range, slope, damage, NAME_Hitscan, pufftype, laflags); } } + return 0; } //========================================================================== @@ -1127,18 +1270,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack) //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMeleeAttack) { - ACTION_PARAM_START(5); - ACTION_PARAM_INT(damage, 0); - ACTION_PARAM_SOUND(meleesound, 1); - ACTION_PARAM_SOUND(misssound, 2); - ACTION_PARAM_NAME(damagetype, 3); - ACTION_PARAM_BOOL(bleed, 4); + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT (damage) { damage = 0; } + PARAM_SOUND_OPT (meleesound) { meleesound = 0; } + PARAM_SOUND_OPT (misssound) { misssound = 0; } + PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } + PARAM_BOOL_OPT (bleed) { bleed = true; } if (damagetype == NAME_None) damagetype = NAME_Melee; // Melee is the default type if (!self->target) - return; + return 0; A_FaceTarget (self); if (self->CheckMeleeRange ()) @@ -1154,6 +1297,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMeleeAttack) if (misssound) S_Sound (self, CHAN_WEAPON, misssound, 1, ATTN_NORM); } + return 0; } //========================================================================== @@ -1163,16 +1307,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMeleeAttack) //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomComboAttack) { - ACTION_PARAM_START(6); - ACTION_PARAM_CLASS(ti, 0); - ACTION_PARAM_FIXED(spawnheight, 1); - ACTION_PARAM_INT(damage, 2); - ACTION_PARAM_SOUND(meleesound, 3); - ACTION_PARAM_NAME(damagetype, 4); - ACTION_PARAM_BOOL(bleed, 5); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS (ti, AActor); + PARAM_FIXED (spawnheight); + PARAM_INT (damage); + PARAM_SOUND_OPT (meleesound) { meleesound = 0; } + PARAM_NAME_OPT (damagetype) { damagetype = NAME_Melee; } + PARAM_BOOL_OPT (bleed) { bleed = true; } if (!self->target) - return; + return 0; A_FaceTarget (self); if (self->CheckMeleeRange()) @@ -1202,6 +1346,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomComboAttack) P_CheckMissileSpawn(missile, self->radius); } } + return 0; } //========================================================================== @@ -1211,17 +1356,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomComboAttack) //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfNoAmmo) { - ACTION_PARAM_START(1); - ACTION_PARAM_STATE(jump, 0); + PARAM_ACTION_PROLOGUE; + PARAM_STATE(jump); ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - if (!ACTION_CALL_FROM_WEAPON()) return; + if (!ACTION_CALL_FROM_WEAPON()) + return numret; if (!self->player->ReadyWeapon->CheckAmmo(self->player->ReadyWeapon->bAltFire, false, true)) { ACTION_JUMP(jump); } - + return numret; } @@ -1242,16 +1388,16 @@ enum FB_Flags DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets) { - ACTION_PARAM_START(7); - ACTION_PARAM_ANGLE(spread_xy, 0); - ACTION_PARAM_ANGLE(spread_z, 1); - ACTION_PARAM_INT(numbullets, 2); - ACTION_PARAM_INT(damageperbullet, 3); - ACTION_PARAM_CLASS(pufftype, 4); - ACTION_PARAM_INT(flags, 5); - ACTION_PARAM_FIXED(range, 6); + PARAM_ACTION_PROLOGUE; + PARAM_ANGLE (spread_xy); + PARAM_ANGLE (spread_z); + PARAM_INT (numbullets); + PARAM_INT (damageperbullet); + PARAM_CLASS_OPT (pufftype, AActor) { pufftype = NULL; } + PARAM_INT_OPT (flags) { flags = FBF_USEAMMO; } + PARAM_FIXED_OPT (range) { range = 0; } - if (!self->player) return; + if (!self->player) return 0; player_t *player = self->player; AWeapon *weapon = player->ReadyWeapon; @@ -1264,7 +1410,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets) if ((flags & FBF_USEAMMO) && weapon && ACTION_CALL_FROM_WEAPON()) { if (!weapon->DepleteAmmo(weapon->bAltFire, true)) - return; // out of ammo + return 0; // out of ammo } if (range == 0) @@ -1276,7 +1422,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets) bangle = self->angle; if (pufftype == NULL) - pufftype = PClass::FindClass(NAME_BulletPuff); + pufftype = PClass::FindActor(NAME_BulletPuff); if (weapon != NULL) { @@ -1320,6 +1466,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets) P_LineAttack(self, angle, range, slope, damage, NAME_Hitscan, pufftype, laflags); } } + return 0; } @@ -1336,17 +1483,17 @@ enum FP_Flags }; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireCustomMissile) { - ACTION_PARAM_START(7); - ACTION_PARAM_CLASS(ti, 0); - ACTION_PARAM_ANGLE(angle, 1); - ACTION_PARAM_BOOL(useammo, 2); - ACTION_PARAM_INT(spawnofs_xy, 3); - ACTION_PARAM_FIXED(spawnheight, 4); - ACTION_PARAM_INT(flags, 5); - ACTION_PARAM_ANGLE(pitch, 6); - - if (!self->player) return; + PARAM_ACTION_PROLOGUE; + PARAM_CLASS (ti, AActor); + PARAM_ANGLE_OPT (angle) { angle = 0; } + PARAM_BOOL_OPT (useammo) { useammo = true; } + PARAM_INT_OPT (spawnofs_xy) { spawnofs_xy = 0; } + PARAM_FIXED_OPT (spawnheight) { spawnheight = 0; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_ANGLE_OPT (pitch) { pitch = 0; } + if (!self->player) + return 0; player_t *player = self->player; AWeapon *weapon = player->ReadyWeapon; @@ -1356,7 +1503,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireCustomMissile) if (useammo && ACTION_CALL_FROM_WEAPON() && weapon) { if (!weapon->DepleteAmmo(weapon->bAltFire, true)) - return; // out of ammo + return 0; // out of ammo } if (ti) @@ -1395,6 +1542,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireCustomMissile) } } } + return 0; } @@ -1418,22 +1566,23 @@ enum DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) { - ACTION_PARAM_START(8); - ACTION_PARAM_INT(damage, 0); - ACTION_PARAM_BOOL(norandom, 1); - ACTION_PARAM_INT(flags, 2); - ACTION_PARAM_CLASS(pufftype, 3); - ACTION_PARAM_FIXED(range, 4); - ACTION_PARAM_FIXED(lifesteal, 5); - ACTION_PARAM_INT(lifestealmax, 6); - ACTION_PARAM_CLASS(armorbonustype, 7); - ACTION_PARAM_SOUND(MeleeSound, 8); - ACTION_PARAM_SOUND(MissSound, 9); + PARAM_ACTION_PROLOGUE; + PARAM_INT (damage); + PARAM_BOOL_OPT (norandom) { norandom = false; } + PARAM_INT_OPT (flags) { flags = CPF_USEAMMO; } + PARAM_CLASS_OPT (pufftype, AActor) { pufftype = NULL; } + PARAM_FIXED_OPT (range) { range = 0; } + PARAM_FIXED_OPT (lifesteal) { lifesteal = 0; } + PARAM_INT_OPT (lifestealmax) { lifestealmax = 0; } + PARAM_CLASS_OPT (armorbonustype, ABasicArmorBonus) { armorbonustype = NULL; } + PARAM_SOUND_OPT (MeleeSound) { MeleeSound = ""; } + PARAM_SOUND_OPT (MissSound) { MissSound = ""; } - if (!self->player) return; + if (!self->player) + return 0; - player_t *player=self->player; - AWeapon * weapon=player->ReadyWeapon; + player_t *player = self->player; + AWeapon *weapon = player->ReadyWeapon; angle_t angle; @@ -1453,11 +1602,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) if ((flags & CPF_USEAMMO) && linetarget && weapon && ACTION_CALL_FROM_WEAPON()) { if (!weapon->DepleteAmmo(weapon->bAltFire, true)) - return; // out of ammo + return 0; // out of ammo } if (pufftype == NULL) - pufftype = PClass::FindClass(NAME_BulletPuff); + pufftype = PClass::FindActor(NAME_BulletPuff); int puffFlags = LAF_ISMELEEATTACK | ((flags & CPF_NORANDOMPUFFZ) ? LAF_NORANDOMPUFFZ : 0); P_LineAttack (self, angle, range, pitch, damage, NAME_Melee, pufftype, puffFlags, &linetarget, &actualdamage); @@ -1474,7 +1623,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) { if (armorbonustype == NULL) { - armorbonustype = PClass::FindClass("ArmorBonus"); + armorbonustype = dyn_cast(PClass::FindClass("ArmorBonus")); } if (armorbonustype != NULL) { @@ -1511,6 +1660,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) if (flags & CPF_PULLIN) self->flags |= MF_JUSTATTACKED; if (flags & CPF_DAGGER) P_DaggerAlert (self, linetarget); } + return 0; } @@ -1521,29 +1671,30 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack) { - ACTION_PARAM_START(17); - ACTION_PARAM_INT(damage, 0); - ACTION_PARAM_INT(spawnofs_xy, 1); - ACTION_PARAM_BOOL(useammo, 2); - ACTION_PARAM_COLOR(color1, 3); - ACTION_PARAM_COLOR(color2, 4); - ACTION_PARAM_INT(flags, 5); - ACTION_PARAM_DOUBLE(maxdiff, 6); - ACTION_PARAM_CLASS(pufftype, 7); - ACTION_PARAM_ANGLE(spread_xy, 8); - ACTION_PARAM_ANGLE(spread_z, 9); - ACTION_PARAM_FIXED(range, 10); - ACTION_PARAM_INT(duration, 11); - ACTION_PARAM_DOUBLE(sparsity, 12); - ACTION_PARAM_DOUBLE(driftspeed, 13); - ACTION_PARAM_CLASS(spawnclass, 14); - ACTION_PARAM_FIXED(spawnofs_z, 15); - ACTION_PARAM_INT(SpiralOffset, 16); + PARAM_ACTION_PROLOGUE; + PARAM_INT (damage); + PARAM_INT_OPT (spawnofs_xy) { spawnofs_xy = 0; } + PARAM_BOOL_OPT (useammo) { useammo = true; } + PARAM_COLOR_OPT (color1) { color1 = 0; } + PARAM_COLOR_OPT (color2) { color2 = 0; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_FLOAT_OPT (maxdiff) { maxdiff = 0; } + PARAM_CLASS_OPT (pufftype, AActor) { pufftype = PClass::FindActor(NAME_BulletPuff); } + PARAM_ANGLE_OPT (spread_xy) { spread_xy = 0; } + PARAM_ANGLE_OPT (spread_z) { spread_z = 0; } + PARAM_FIXED_OPT (range) { range = 0; } + PARAM_INT_OPT (duration) { duration = 0; } + PARAM_FLOAT_OPT (sparsity) { sparsity = 1; } + PARAM_FLOAT_OPT (driftspeed) { driftspeed = 1; } + PARAM_CLASS_OPT (spawnclass, AActor){ spawnclass = NULL; } + PARAM_FIXED_OPT (spawnofs_z) { spawnofs_z = 0; } + PARAM_INT_OPT (SpiralOffset) { SpiralOffset = 270; } if (range == 0) range = 8192*FRACUNIT; if (sparsity == 0) sparsity=1.0; - if (!self->player) return; + if (self->player == NULL) + return 0; AWeapon *weapon = self->player->ReadyWeapon; @@ -1551,7 +1702,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack) if (useammo && weapon != NULL && ACTION_CALL_FROM_WEAPON()) { if (!weapon->DepleteAmmo(weapon->bAltFire, true)) - return; // out of ammo + return 0; // out of ammo } angle_t angle; @@ -1569,6 +1720,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack) } P_RailAttack (self, damage, spawnofs_xy, spawnofs_z, color1, color2, maxdiff, flags, pufftype, angle, slope, range, duration, sparsity, driftspeed, spawnclass, SpiralOffset); + return 0; } //========================================================================== @@ -1586,24 +1738,24 @@ enum DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) { - ACTION_PARAM_START(17); - ACTION_PARAM_INT(damage, 0); - ACTION_PARAM_INT(spawnofs_xy, 1); - ACTION_PARAM_COLOR(color1, 2); - ACTION_PARAM_COLOR(color2, 3); - ACTION_PARAM_INT(flags, 4); - ACTION_PARAM_INT(aim, 5); - ACTION_PARAM_DOUBLE(maxdiff, 6); - ACTION_PARAM_CLASS(pufftype, 7); - ACTION_PARAM_ANGLE(spread_xy, 8); - ACTION_PARAM_ANGLE(spread_z, 9); - ACTION_PARAM_FIXED(range, 10); - ACTION_PARAM_INT(duration, 11); - ACTION_PARAM_DOUBLE(sparsity, 12); - ACTION_PARAM_DOUBLE(driftspeed, 13); - ACTION_PARAM_CLASS(spawnclass, 14); - ACTION_PARAM_FIXED(spawnofs_z, 15); - ACTION_PARAM_INT(SpiralOffset, 16); + PARAM_ACTION_PROLOGUE; + PARAM_INT (damage); + PARAM_INT_OPT (spawnofs_xy) { spawnofs_xy = 0; } + PARAM_COLOR_OPT (color1) { color1 = 0; } + PARAM_COLOR_OPT (color2) { color2 = 0; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_INT_OPT (aim) { aim = CRF_DONTAIM; } + PARAM_FLOAT_OPT (maxdiff) { maxdiff = 0; } + PARAM_CLASS_OPT (pufftype, AActor) { pufftype = PClass::FindActor(NAME_BulletPuff); } + PARAM_ANGLE_OPT (spread_xy) { spread_xy = 0; } + PARAM_ANGLE_OPT (spread_z) { spread_z = 0; } + PARAM_FIXED_OPT (range) { range = 0; } + PARAM_INT_OPT (duration) { duration = 0; } + PARAM_FLOAT_OPT (sparsity) { sparsity = 1; } + PARAM_FLOAT_OPT (driftspeed) { driftspeed = 1; } + PARAM_CLASS_OPT (spawnclass, AActor){ spawnclass = NULL; } + PARAM_FIXED_OPT (spawnofs_z) { spawnofs_z = 0; } + PARAM_INT_OPT (SpiralOffset) { SpiralOffset = 270; } if (range == 0) range = 8192*FRACUNIT; if (sparsity == 0) sparsity = 1; @@ -1616,7 +1768,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) if (aim && self->target == NULL) { - return; + return 0; } // [RH] Andy Baker's stealth monsters if (self->flags & MF_STEALTH) @@ -1686,6 +1838,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) self->SetXYZ(savedpos); self->angle = saved_angle; self->pitch = saved_pitch; + return 0; } //=========================================================================== @@ -1694,28 +1847,36 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) // //=========================================================================== -static void DoGiveInventory(AActor * receiver, bool use_aaptr, DECLARE_PARAMINFO) +static int DoGiveInventory(AActor *receiver, bool orresult, VM_ARGS) { - ACTION_PARAM_START(2+use_aaptr); - ACTION_PARAM_CLASS(mi, 0); - ACTION_PARAM_INT(amount, 1); + int paramnum = NAP-1; + PARAM_CLASS (mi, AInventory); + PARAM_INT_OPT (amount) { amount = 1; } - if (use_aaptr) + if (!orresult) { - ACTION_PARAM_INT(setreceiver, 2); - COPY_AAPTR_NOT_NULL(receiver, receiver, setreceiver); + PARAM_INT_OPT(setreceiver) { setreceiver = AAPTR_DEFAULT; } + receiver = COPY_AAPTR(receiver, setreceiver); + } + if (receiver == NULL) + { // If there's nothing to receive it, it's obviously a fail, right? + ACTION_SET_RESULT(false); + return numret; } - bool res=true; + bool res = true; - if (amount==0) amount=1; + if (amount <= 0) + { + amount = 1; + } if (mi) { - AInventory *item = static_cast(Spawn (mi, 0, 0, 0, NO_REPLACE)); - if (!item) + AInventory *item = static_cast(Spawn(mi, 0, 0, 0, NO_REPLACE)); + if (item == NULL) { ACTION_SET_RESULT(false); - return; + return numret; } if (item->IsKindOf(RUNTIME_CLASS(AHealth))) { @@ -1727,51 +1888,80 @@ static void DoGiveInventory(AActor * receiver, bool use_aaptr, DECLARE_PARAMINFO } item->flags |= MF_DROPPED; item->ClearCounters(); - if (!item->CallTryPickup (receiver)) + if (!item->CallTryPickup(receiver)) { - item->Destroy (); + item->Destroy(); res = false; } - else res = true; + else + { + res = true; + } } - else res = false; - ACTION_SET_RESULT(res); - + else + { + res = false; + } + if (!orresult) + { + ACTION_SET_RESULT(res); + } + else + { + ACTION_OR_RESULT(res); + } + return numret; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveInventory) { - DoGiveInventory(self, true, PUSH_PARAMINFO); + PARAM_ACTION_PROLOGUE; + return DoGiveInventory(self, false, VM_ARGS_NAMES); } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveToTarget) { - DoGiveInventory(self->target, true, PUSH_PARAMINFO); -} + PARAM_ACTION_PROLOGUE; + return DoGiveInventory(self->target, false, VM_ARGS_NAMES); +} DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveToChildren) { - TThinkerIterator it; - AActor * mo; + PARAM_ACTION_PROLOGUE; + TThinkerIterator it; + AActor *mo; + + ACTION_SET_RESULT(false); while ((mo = it.Next())) { - if (mo->master == self) DoGiveInventory(mo, false, PUSH_PARAMINFO); + if (mo->master == self) + { + numret = DoGiveInventory(mo, true, VM_ARGS_NAMES); + } } + return numret; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveToSiblings) { - TThinkerIterator it; - AActor * mo; + PARAM_ACTION_PROLOGUE; + TThinkerIterator it; + AActor *mo; + + ACTION_SET_RESULT(false); if (self->master != NULL) { while ((mo = it.Next())) { - if (mo->master == self->master && mo != self) DoGiveInventory(mo, false, PUSH_PARAMINFO); + if (mo->master == self->master && mo != self) + { + numret = DoGiveInventory(mo, true, VM_ARGS_NAMES); + } } } + return numret; } //=========================================================================== @@ -1785,51 +1975,77 @@ enum TIF_NOTAKEINFINITE = 1, }; -void DoTakeInventory(AActor * receiver, bool use_aaptr, DECLARE_PARAMINFO) +int DoTakeInventory(AActor *receiver, bool orresult, VM_ARGS) { - ACTION_PARAM_START(3+use_aaptr); - ACTION_PARAM_CLASS(item, 0); - ACTION_PARAM_INT(amount, 1); - ACTION_PARAM_INT(flags, 2); + int paramnum = NAP-1; + PARAM_CLASS (itemtype, AInventory); + PARAM_INT_OPT (amount) { amount = 0; } + PARAM_INT_OPT (flags) { flags = 0; } - if (!item) + if (itemtype == NULL) + { + ACTION_SET_RESULT(true); + return numret; + } + if (!orresult) + { + PARAM_INT_OPT(setreceiver) { setreceiver = AAPTR_DEFAULT; } + receiver = COPY_AAPTR(receiver, setreceiver); + } + if (receiver == NULL) { ACTION_SET_RESULT(false); - return; - } - if (use_aaptr) - { - ACTION_PARAM_INT(setreceiver, 3); - COPY_AAPTR_NOT_NULL(receiver, receiver, setreceiver); + return numret; } - bool res = receiver->TakeInventory(item, amount, true, (flags & TIF_NOTAKEINFINITE) != 0); - ACTION_SET_RESULT(res); + bool res = receiver->TakeInventory(itemtype, amount, true, (flags & TIF_NOTAKEINFINITE) != 0); + + if (!orresult) + { + ACTION_SET_RESULT(res); + } + else + { + ACTION_OR_RESULT(res); + } + return numret; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TakeInventory) { - DoTakeInventory(self, true, PUSH_PARAMINFO); + PARAM_ACTION_PROLOGUE; + return DoTakeInventory(self, false, VM_ARGS_NAMES); } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TakeFromTarget) { - DoTakeInventory(self->target, true, PUSH_PARAMINFO); + PARAM_ACTION_PROLOGUE; + return DoTakeInventory(self->target, false, VM_ARGS_NAMES); } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TakeFromChildren) { + PARAM_ACTION_PROLOGUE; + ACTION_SET_RESULT(false); + TThinkerIterator it; AActor * mo; while ((mo = it.Next())) { - if (mo->master == self) DoTakeInventory(mo, false, PUSH_PARAMINFO); + if (mo->master == self) + { + DoTakeInventory(mo, true, VM_ARGS_NAMES); + } } + return numret; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TakeFromSiblings) { + PARAM_ACTION_PROLOGUE; + ACTION_SET_RESULT(false); + TThinkerIterator it; AActor * mo; @@ -1837,9 +2053,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TakeFromSiblings) { while ((mo = it.Next())) { - if (mo->master == self->master && mo != self) DoTakeInventory(mo, false, PUSH_PARAMINFO); + if (mo->master == self->master && mo != self) + { + DoTakeInventory(mo, true, VM_ARGS_NAMES); + } } } + return numret; } //=========================================================================== @@ -2061,42 +2281,49 @@ static bool InitSpawnedItem(AActor *self, AActor *mo, int flags) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItem) { - ACTION_PARAM_START(5); - ACTION_PARAM_CLASS(missile, 0); - ACTION_PARAM_FIXED(distance, 1); - ACTION_PARAM_FIXED(zheight, 2); - ACTION_PARAM_BOOL(useammo, 3); - ACTION_PARAM_BOOL(transfer_translation, 4); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS_OPT (missile, AActor) { missile = PClass::FindActor("Unknown"); } + PARAM_FIXED_OPT (distance) { distance = 0; } + PARAM_FIXED_OPT (zheight) { zheight = 0; } + PARAM_BOOL_OPT (useammo) { useammo = true; } + PARAM_BOOL_OPT (transfer_translation) { transfer_translation = false; } - if (!missile) + if (missile == NULL) { ACTION_SET_RESULT(false); - return; + return numret; } + ACTION_SET_RESULT(true); // Don't spawn monsters if this actor has been massacred - if (self->DamageType == NAME_Massacre && GetDefaultByType(missile)->flags3&MF3_ISMONSTER) return; + if (self->DamageType == NAME_Massacre && (GetDefaultByType(missile)->flags3 & MF3_ISMONSTER)) + { + return numret; + } - if (distance==0) + if (distance == 0) { // use the minimum distance that does not result in an overlap - distance=(self->radius+GetDefaultByType(missile)->radius)>>FRACBITS; + distance = (self->radius + GetDefaultByType(missile)->radius) >> FRACBITS; } if (ACTION_CALL_FROM_WEAPON()) { - // Used from a weapon so use some ammo - AWeapon * weapon=self->player->ReadyWeapon; + // Used from a weapon, so use some ammo + AWeapon *weapon = self->player->ReadyWeapon; - if (!weapon) return; - if (useammo && !weapon->DepleteAmmo(weapon->bAltFire)) return; + if (weapon == NULL) + return numret; + if (useammo && !weapon->DepleteAmmo(weapon->bAltFire)) + return numret; } - AActor * mo = Spawn( missile, self->Vec3Angle(distance, self->angle, -self->floorclip + self->GetBobOffset() + zheight), ALLOW_REPLACE); + AActor *mo = Spawn( missile, self->Vec3Angle(distance, self->angle, -self->floorclip + self->GetBobOffset() + zheight), ALLOW_REPLACE); int flags = (transfer_translation ? SIXF_TRANSFERTRANSLATION : 0) + (useammo ? SIXF_SETMASTER : 0); bool res = InitSpawnedItem(self, mo, flags); ACTION_SET_RESULT(res); // for an inventory item's use state + return numret; } //=========================================================================== @@ -2108,29 +2335,32 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItem) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItemEx) { - ACTION_PARAM_START(11); - ACTION_PARAM_CLASS(missile, 0); - ACTION_PARAM_FIXED(xofs, 1); - ACTION_PARAM_FIXED(yofs, 2); - ACTION_PARAM_FIXED(zofs, 3); - ACTION_PARAM_FIXED(xvel, 4); - ACTION_PARAM_FIXED(yvel, 5); - ACTION_PARAM_FIXED(zvel, 6); - ACTION_PARAM_ANGLE(angle, 7); - ACTION_PARAM_INT(flags, 8); - ACTION_PARAM_INT(chance, 9); - ACTION_PARAM_INT(tid, 10); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS (missile, AActor); + PARAM_FIXED_OPT (xofs) { xofs = 0; } + PARAM_FIXED_OPT (yofs) { yofs = 0; } + PARAM_FIXED_OPT (zofs) { zofs = 0; } + PARAM_FIXED_OPT (xvel) { xvel = 0; } + PARAM_FIXED_OPT (yvel) { yvel = 0; } + PARAM_FIXED_OPT (zvel) { zvel = 0; } + PARAM_ANGLE_OPT (angle) { angle = 0; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_INT_OPT (chance) { chance = 0; } + PARAM_INT_OPT (tid) { tid = 0; } - if (!missile) + if (missile == NULL) { ACTION_SET_RESULT(false); - return; + return numret; } - if (chance > 0 && pr_spawnitemex() 0 && pr_spawnitemex() < chance) + return numret; // Don't spawn monsters if this actor has been massacred - if (self->DamageType == NAME_Massacre && GetDefaultByType(missile)->flags3&MF3_ISMONSTER) return; + if (self->DamageType == NAME_Massacre && (GetDefaultByType(missile)->flags3 & MF3_ISMONSTER)) + return numret; fixedvec2 pos; @@ -2187,6 +2417,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItemEx) } mo->angle = angle; } + return numret; } //=========================================================================== @@ -2198,26 +2429,29 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItemEx) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ThrowGrenade) { - ACTION_PARAM_START(5); - ACTION_PARAM_CLASS(missile, 0); - ACTION_PARAM_FIXED(zheight, 1); - ACTION_PARAM_FIXED(xyvel, 2); - ACTION_PARAM_FIXED(zvel, 3); - ACTION_PARAM_BOOL(useammo, 4); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS (missile, AActor); + PARAM_FIXED_OPT (zheight) { zheight = 0; } + PARAM_FIXED_OPT (xyvel) { xyvel = 0; } + PARAM_FIXED_OPT (zvel) { zvel = 0; } + PARAM_BOOL_OPT (useammo) { useammo = true; } - if (missile == NULL) return; + ACTION_SET_RESULT(true); + if (missile == NULL) + return numret; if (ACTION_CALL_FROM_WEAPON()) { // Used from a weapon, so use some ammo AWeapon *weapon = self->player->ReadyWeapon; - if (!weapon) return; - if (useammo && !weapon->DepleteAmmo(weapon->bAltFire)) return; + if (weapon == NULL) + return numret; + if (useammo && !weapon->DepleteAmmo(weapon->bAltFire)) + return numret; } - - AActor * bo; + AActor *bo; bo = Spawn(missile, self->PosPlusZ(-self->floorclip + self->GetBobOffset() + zheight + 35*FRACUNIT + (self->player? self->player->crouchoffset : 0)), @@ -2254,7 +2488,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ThrowGrenade) bo->target = self; P_CheckMissileSpawn (bo, self->radius); } - else ACTION_SET_RESULT(false); + else + { + ACTION_SET_RESULT(false); + } + return numret; } @@ -2265,13 +2503,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ThrowGrenade) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Recoil) { - ACTION_PARAM_START(1); - ACTION_PARAM_FIXED(xyvel, 0); + PARAM_ACTION_PROLOGUE; + PARAM_FIXED(xyvel); angle_t angle = self->angle + ANG180; angle >>= ANGLETOFINESHIFT; self->velx += FixedMul(xyvel, finecosine[angle]); self->vely += FixedMul(xyvel, finesine[angle]); + return 0; } @@ -2282,16 +2521,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Recoil) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SelectWeapon) { - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(cls, 0); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS(cls, AWeapon); if (cls == NULL || self->player == NULL) { ACTION_SET_RESULT(false); - return; + return numret; } - AWeapon * weaponitem = static_cast(self->FindInventory(cls)); + AWeapon *weaponitem = static_cast(self->FindInventory(cls)); if (weaponitem != NULL && weaponitem->IsKindOf(RUNTIME_CLASS(AWeapon))) { @@ -2299,9 +2538,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SelectWeapon) { self->player->PendingWeapon = weaponitem; } + ACTION_SET_RESULT(true); } - else ACTION_SET_RESULT(false); - + else + { + ACTION_SET_RESULT(false); + } + return numret; } @@ -2314,14 +2557,14 @@ EXTERN_CVAR(Float, con_midtime) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Print) { - ACTION_PARAM_START(3); - ACTION_PARAM_STRING(text, 0); - ACTION_PARAM_FLOAT(time, 1); - ACTION_PARAM_NAME(fontname, 2); + PARAM_ACTION_PROLOGUE; + PARAM_STRING (text); + PARAM_FLOAT_OPT (time) { time = 0; } + PARAM_NAME_OPT (fontname) { fontname = NAME_None; } - if (text[0] == '$') text = GStrings(text+1); + if (text[0] == '$') text = GStrings(&text[1]); if (self->CheckLocalView (consoleplayer) || - (self->target!=NULL && self->target->CheckLocalView (consoleplayer))) + (self->target != NULL && self->target->CheckLocalView (consoleplayer))) { float saved = con_midtime; FFont *font = NULL; @@ -2332,14 +2575,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Print) } if (time > 0) { - con_midtime = time; + con_midtime = float(time); } - FString formatted = strbin1(text); C_MidPrint(font != NULL ? font : SmallFont, formatted.GetChars()); con_midtime = saved; } ACTION_SET_RESULT(false); // Prints should never set the result for inventory state chains! + return numret; } //=========================================================================== @@ -2350,28 +2593,28 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Print) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PrintBold) { - ACTION_PARAM_START(3); - ACTION_PARAM_STRING(text, 0); - ACTION_PARAM_FLOAT(time, 1); - ACTION_PARAM_NAME(fontname, 2); + PARAM_ACTION_PROLOGUE; + PARAM_STRING (text); + PARAM_FLOAT_OPT (time) { time = 0; } + PARAM_NAME_OPT (fontname) { fontname = NAME_None; } float saved = con_midtime; FFont *font = NULL; - if (text[0] == '$') text = GStrings(text+1); + if (text[0] == '$') text = GStrings(&text[1]); if (fontname != NAME_None) { font = V_GetFont(fontname); } if (time > 0) { - con_midtime = time; + con_midtime = float(time); } - FString formatted = strbin1(text); C_MidPrintBold(font != NULL ? font : SmallFont, formatted.GetChars()); con_midtime = saved; ACTION_SET_RESULT(false); // Prints should never set the result for inventory state chains! + return numret; } //=========================================================================== @@ -2382,13 +2625,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PrintBold) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Log) { - ACTION_PARAM_START(1); - ACTION_PARAM_STRING(text, 0); + PARAM_ACTION_PROLOGUE; + PARAM_STRING(text); - if (text[0] == '$') text = GStrings(text+1); + if (text[0] == '$') text = GStrings(&text[1]); FString formatted = strbin1(text); Printf("%s\n", formatted.GetChars()); ACTION_SET_RESULT(false); // Prints should never set the result for inventory state chains! + return numret; } //========================================================================= @@ -2399,10 +2643,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Log) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LogInt) { - ACTION_PARAM_START(1); - ACTION_PARAM_INT(num, 0); + PARAM_ACTION_PROLOGUE; + PARAM_INT(num); Printf("%d\n", num); ACTION_SET_RESULT(false); // Prints should never set the result for inventory state chains! + return numret; } //=========================================================================== @@ -2412,15 +2657,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LogInt) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTranslucent) { - ACTION_PARAM_START(2); - ACTION_PARAM_FIXED(alpha, 0); - ACTION_PARAM_INT(mode, 1); + PARAM_ACTION_PROLOGUE; + PARAM_FIXED (alpha); + PARAM_INT_OPT (mode) { mode = 0; } mode = mode == 0 ? STYLE_Translucent : mode == 2 ? STYLE_Fuzzy : STYLE_Add; self->RenderStyle.Flags &= ~STYLEF_Alpha1; self->alpha = clamp(alpha, 0, FRACUNIT); self->RenderStyle = ERenderStyle(mode); + return 0; } //=========================================================================== @@ -2439,9 +2685,9 @@ enum FadeFlags DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeIn) { - ACTION_PARAM_START(1); - ACTION_PARAM_FIXED(reduce, 0); - ACTION_PARAM_INT(flags, 1); + PARAM_ACTION_PROLOGUE; + PARAM_FIXED_OPT(reduce) { reduce = FRACUNIT/10; } + PARAM_INT_OPT(flags) { flags = 0; } if (reduce == 0) { @@ -2461,6 +2707,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeIn) P_RemoveThing(self); } } + return 0; } //=========================================================================== @@ -2472,9 +2719,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeIn) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeOut) { - ACTION_PARAM_START(2); - ACTION_PARAM_FIXED(reduce, 0); - ACTION_PARAM_INT(flags, 1); + PARAM_ACTION_PROLOGUE; + PARAM_FIXED_OPT(reduce) { reduce = FRACUNIT/10; } + PARAM_INT_OPT(flags) { flags = FTF_REMOVE; } if (reduce == 0) { @@ -2493,6 +2740,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeOut) P_RemoveThing(self); } } + return 0; } //=========================================================================== @@ -2505,10 +2753,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeOut) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeTo) { - ACTION_PARAM_START(3); - ACTION_PARAM_FIXED(target, 0); - ACTION_PARAM_FIXED(amount, 1); - ACTION_PARAM_INT(flags, 2); + PARAM_ACTION_PROLOGUE; + PARAM_FIXED (target); + PARAM_FIXED_OPT (amount) { amount = fixed_t(0.1*FRACUNIT); } + PARAM_INT_OPT (flags) { flags = 0; } self->RenderStyle.Flags &= ~STYLEF_Alpha1; @@ -2538,6 +2786,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeTo) { P_RemoveThing(self); } + return 0; } //=========================================================================== @@ -2549,21 +2798,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeTo) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetScale) { - ACTION_PARAM_START(3); - ACTION_PARAM_FIXED(scalex, 0); - ACTION_PARAM_FIXED(scaley, 1); - ACTION_PARAM_INT(ptr, 2); + PARAM_ACTION_PROLOGUE; + PARAM_FIXED (scalex); + PARAM_FIXED_OPT (scaley) { scaley = scalex; } + PARAM_INT_OPT (ptr) { ptr = AAPTR_DEFAULT; } AActor *ref = COPY_AAPTR(self, ptr); - if (!ref) + if (ref != NULL) { - ACTION_SET_RESULT(false); - return; + ref->scaleX = scalex; + ref->scaleY = scaley; } - - ref->scaleX = scalex; - ref->scaleY = scaley ? scaley : scalex; + return 0; } //=========================================================================== @@ -2575,10 +2822,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetScale) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetMass) { - ACTION_PARAM_START(2); - ACTION_PARAM_INT(mass, 0); + PARAM_ACTION_PROLOGUE; + PARAM_INT (mass); self->Mass = mass; + return 0; } //=========================================================================== @@ -2588,16 +2836,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetMass) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnDebris) { + PARAM_ACTION_PROLOGUE; + PARAM_CLASS (debris, AActor); + PARAM_BOOL_OPT (transfer_translation) { transfer_translation = false; } + PARAM_FIXED_OPT (mult_h) { mult_h = FRACUNIT; } + PARAM_FIXED_OPT (mult_v) { mult_v = FRACUNIT; } int i; - AActor * mo; + AActor *mo; - ACTION_PARAM_START(4); - ACTION_PARAM_CLASS(debris, 0); - ACTION_PARAM_BOOL(transfer_translation, 1); - ACTION_PARAM_FIXED(mult_h, 2); - ACTION_PARAM_FIXED(mult_v, 3); - - if (debris == NULL) return; + if (debris == NULL) + return 0; // only positive values make sense here if (mult_v <= 0) @@ -2617,15 +2865,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnDebris) { mo->Translation = self->Translation; } - if (i < mo->GetClass()->ActorInfo->NumOwnedStates) + if (i < mo->GetClass()->NumOwnedStates) { - mo->SetState(mo->GetClass()->ActorInfo->OwnedStates + i); + mo->SetState (mo->GetClass()->OwnedStates + i); } mo->velz = FixedMul(mult_v, ((pr_spawndebris()&7)+5)*FRACUNIT); mo->velx = FixedMul(mult_h, pr_spawndebris.Random2()<<(FRACBITS-6)); mo->vely = FixedMul(mult_h, pr_spawndebris.Random2()<<(FRACBITS-6)); } } + return 0; } //=========================================================================== @@ -2635,37 +2884,37 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnDebris) //=========================================================================== enum SPFflag { - SPF_FULLBRIGHT = 1, - SPF_RELPOS = 1 << 1, - SPF_RELVEL = 1 << 2, - SPF_RELACCEL = 1 << 3, - SPF_RELANG = 1 << 4, + SPF_FULLBRIGHT = 1, + SPF_RELPOS = 1 << 1, + SPF_RELVEL = 1 << 2, + SPF_RELACCEL = 1 << 3, + SPF_RELANG = 1 << 4, }; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnParticle) { - ACTION_PARAM_START(15); - ACTION_PARAM_COLOR(color, 0); - ACTION_PARAM_INT(flags, 1); - ACTION_PARAM_INT(lifetime, 2); - ACTION_PARAM_INT(size, 3); - ACTION_PARAM_ANGLE(angle, 4); - ACTION_PARAM_FIXED(xoff, 5); - ACTION_PARAM_FIXED(yoff, 6); - ACTION_PARAM_FIXED(zoff, 7); - ACTION_PARAM_FIXED(xvel, 8); - ACTION_PARAM_FIXED(yvel, 9); - ACTION_PARAM_FIXED(zvel, 10); - ACTION_PARAM_FIXED(accelx, 11); - ACTION_PARAM_FIXED(accely, 12); - ACTION_PARAM_FIXED(accelz, 13); - ACTION_PARAM_FIXED(startalphaf, 14); - ACTION_PARAM_FIXED(fadestepf, 15); - - BYTE startalpha = (BYTE)Scale(clamp(startalphaf, 0, FRACUNIT), 255, FRACUNIT); - int fadestep = fadestepf < 0? -1 : Scale(clamp(fadestepf, 0, FRACUNIT), 255, FRACUNIT); - lifetime = clamp(lifetime, 0, 255); // Clamp to byte - size = clamp(size, 0, 65535); // Clamp to word + PARAM_ACTION_PROLOGUE; + PARAM_COLOR (color); + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_INT_OPT (lifetime) { lifetime = 35; } + PARAM_INT_OPT (size) { size = 1; } + PARAM_ANGLE_OPT (angle) { angle = 0; } + PARAM_FIXED_OPT (xoff) { xoff = 0; } + PARAM_FIXED_OPT (yoff) { yoff = 0; } + PARAM_FIXED_OPT (zoff) { zoff = 0; } + PARAM_FIXED_OPT (xvel) { xvel = 0; } + PARAM_FIXED_OPT (yvel) { yvel = 0; } + PARAM_FIXED_OPT (zvel) { zvel = 0; } + PARAM_FIXED_OPT (accelx) { accelx = 0; } + PARAM_FIXED_OPT (accely) { accely = 0; } + PARAM_FIXED_OPT (accelz) { accelz = 0; } + PARAM_FIXED_OPT (startalphaf) { startalphaf = FRACUNIT; } + PARAM_FIXED_OPT (fadestepf) { fadestepf = -FRACUNIT; } + + BYTE startalpha = (BYTE)(clamp(startalphaf, 0, FRACUNIT) * 255 / FRACUNIT); + int fadestep = fadestepf < 0 ? -1 : clamp(fadestepf, 0, FRACUNIT) * 255 / FRACUNIT; + lifetime = clamp(lifetime, 0, 255); // Clamp to byte + size = clamp(size, 0, 65535); // Clamp to word if (lifetime != 0) { @@ -2695,9 +2944,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnParticle) pos = self->Vec3Offset(xoff, yoff, zoff); P_SpawnParticle(pos.x, pos.y, pos.z, xvel, yvel, zvel, color, !!(flags & SPF_FULLBRIGHT), startalpha, lifetime, size, fadestep, accelx, accely, accelz); } + return 0; } - //=========================================================================== // // A_CheckSight @@ -2706,8 +2955,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnParticle) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSight) { - ACTION_PARAM_START(1); - ACTION_PARAM_STATE(jump, 0); + PARAM_ACTION_PROLOGUE; + PARAM_STATE(jump); ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! @@ -2718,18 +2967,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSight) // Always check sight from each player. if (P_CheckSight(players[i].mo, self, SF_IGNOREVISIBILITY)) { - return; + return numret; } // If a player is viewing from a non-player, then check that too. if (players[i].camera != NULL && players[i].camera->player == NULL && P_CheckSight(players[i].camera, self, SF_IGNOREVISIBILITY)) { - return; + return numret; } } } ACTION_JUMP(jump); + return numret; } //=========================================================================== @@ -2777,10 +3027,10 @@ static bool DoCheckSightOrRange(AActor *self, AActor *camera, double range, bool DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSightOrRange) { - ACTION_PARAM_START(3); - double range = EvalExpressionF(ParameterIndex+0, self); - ACTION_PARAM_STATE(jump, 1); - ACTION_PARAM_BOOL(twodi, 2); + PARAM_ACTION_PROLOGUE; + PARAM_FLOAT(range); + PARAM_STATE(jump); + PARAM_BOOL_OPT(twodi) { twodi = false; } ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! @@ -2792,17 +3042,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSightOrRange) // Always check from each player. if (DoCheckSightOrRange(self, players[i].mo, range, twodi)) { - return; + return numret; } // If a player is viewing from a non-player, check that too. if (players[i].camera != NULL && players[i].camera->player == NULL && DoCheckSightOrRange(self, players[i].camera, range, twodi)) { - return; + return numret; } } } ACTION_JUMP(jump); + return numret; } //=========================================================================== @@ -2844,10 +3095,10 @@ static bool DoCheckRange(AActor *self, AActor *camera, double range, bool twodi) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckRange) { - ACTION_PARAM_START(3); - double range = EvalExpressionF(ParameterIndex+0, self); - ACTION_PARAM_STATE(jump, 1); - ACTION_PARAM_BOOL(twodi, 2); + PARAM_ACTION_PROLOGUE; + PARAM_FLOAT(range); + PARAM_STATE(jump); + PARAM_BOOL_OPT(twodi) { twodi = false; } ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! @@ -2859,17 +3110,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckRange) // Always check from each player. if (DoCheckRange(self, players[i].mo, range, twodi)) { - return; + return numret; } // If a player is viewing from a non-player, check that too. if (players[i].camera != NULL && players[i].camera->player == NULL && DoCheckRange(self, players[i].camera, range, twodi)) { - return; + return numret; } } } ACTION_JUMP(jump); + return numret; } @@ -2880,17 +3132,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckRange) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DropInventory) { - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(drop, 0); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS(drop, AInventory); if (drop) { - AInventory * inv = self->FindInventory(drop); + AInventory *inv = self->FindInventory(drop); if (inv) { self->DropInventory(inv); } } + return 0; } @@ -2901,20 +3154,23 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DropInventory) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetBlend) { - ACTION_PARAM_START(4); - ACTION_PARAM_COLOR(color, 0); - ACTION_PARAM_FLOAT(alpha, 1); - ACTION_PARAM_INT(tics, 2); - ACTION_PARAM_COLOR(color2, 3); + PARAM_ACTION_PROLOGUE; + PARAM_COLOR (color); + PARAM_FLOAT (alpha); + PARAM_INT (tics); + PARAM_COLOR_OPT (color2) { color2 = 0; } - if (color == MAKEARGB(255,255,255,255)) color=0; - if (color2 == MAKEARGB(255,255,255,255)) color2=0; - if (!color2.a) + if (color == MAKEARGB(255,255,255,255)) + color = 0; + if (color2 == MAKEARGB(255,255,255,255)) + color2 = 0; + if (color2.a == 0) color2 = color; - new DFlashFader(color.r/255.0f, color.g/255.0f, color.b/255.0f, alpha, - color2.r/255.0f, color2.g/255.0f, color2.b/255.0f, 0, - (float)tics/TICRATE, self); + new DFlashFader(color.r/255.f, color.g/255.f, color.b/255.f, float(alpha), + color2.r/255.f, color2.g/255.f, color2.b/255.f, 0, + float(tics)/TICRATE, self); + return 0; } @@ -2925,13 +3181,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetBlend) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIf) { - ACTION_PARAM_START(2); - ACTION_PARAM_BOOL(expression, 0); - ACTION_PARAM_STATE(jump, 1); + PARAM_ACTION_PROLOGUE; + PARAM_BOOL (condition); + PARAM_STATE (jump); ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - if (expression) ACTION_JUMP(jump); - + if (condition) + ACTION_JUMP(jump); + return numret; } //=========================================================================== @@ -2941,29 +3198,33 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIf) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CountdownArg) { - ACTION_PARAM_START(2); - ACTION_PARAM_INT(cnt, 0); - ACTION_PARAM_STATE(state, 1); + PARAM_ACTION_PROLOGUE; + PARAM_INT(argnum); + PARAM_STATE_OPT(state) { state = self->FindState(NAME_Death); } - if (cnt<0 || cnt>=5) return; - if (!self->args[cnt]--) + if (argnum > 0 && argnum < (int)countof(self->args)) { - if (self->flags&MF_MISSILE) + if (!self->args[argnum]--) { - P_ExplodeMissile(self, NULL, NULL); - } - else if (self->flags&MF_SHOOTABLE) - { - P_DamageMobj (self, NULL, NULL, self->health, NAME_None, DMG_FORCED); + if (self->flags & MF_MISSILE) + { + P_ExplodeMissile(self, NULL, NULL); + } + else if (self->flags & MF_SHOOTABLE) + { + P_DamageMobj(self, NULL, NULL, self->health, NAME_None, DMG_FORCED); + } + else + { + self->SetState(self->FindState(NAME_Death)); + } } else { - // can't use "Death" as default parameter with current DECORATE parser. - if (state == NULL) state = self->FindState(NAME_Death); self->SetState(state); } } - + return 0; } //============================================================================ @@ -2974,13 +3235,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CountdownArg) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Burst) { - ACTION_PARAM_START(1); - ACTION_PARAM_CLASS(chunk, 0); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS(chunk, AActor); int i, numChunks; AActor * mo; - if (chunk == NULL) return; + if (chunk == NULL) + { + return 0; + } self->velx = self->vely = self->velz = 0; self->height = self->GetDefault()->height; @@ -3018,6 +3282,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Burst) A_Unblock(self, true); self->Destroy (); + return 0; } //=========================================================================== @@ -3028,35 +3293,35 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Burst) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckFloor) { - ACTION_PARAM_START(1); - ACTION_PARAM_STATE(jump, 0); + PARAM_ACTION_PROLOGUE; + PARAM_STATE(jump); ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! if (self->Z() <= self->floorz) { ACTION_JUMP(jump); } - + return numret; } //=========================================================================== // // A_CheckCeiling -// [GZ] Totally copied on A_CheckFloor, jumps if actor touches ceiling +// [GZ] Totally copied from A_CheckFloor, jumps if actor touches ceiling // //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckCeiling) { - ACTION_PARAM_START(1); - ACTION_PARAM_STATE(jump, 0); + PARAM_ACTION_PROLOGUE; + PARAM_STATE(jump); ACTION_SET_RESULT(false); if (self->Top() >= self->ceilingz) // Height needs to be counted { ACTION_JUMP(jump); } - + return numret; } //=========================================================================== @@ -3067,12 +3332,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckCeiling) //=========================================================================== DEFINE_ACTION_FUNCTION(AActor, A_Stop) { + PARAM_ACTION_PROLOGUE; self->velx = self->vely = self->velz = 0; if (self->player && self->player->mo == self && !(self->player->cheats & CF_PREDICTING)) { self->player->mo->PlayIdle(); self->player->velx = self->player->vely = 0; } + return 0; } static void CheckStopped(AActor *self) @@ -3093,7 +3360,7 @@ static void CheckStopped(AActor *self) // //=========================================================================== -extern void AF_A_RestoreSpecialPosition(DECLARE_PARAMINFO); +DECLARE_ACTION(A_RestoreSpecialPosition) enum RS_Flags { @@ -3104,10 +3371,12 @@ enum RS_Flags DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Respawn) { - ACTION_PARAM_START(1); - ACTION_PARAM_INT(flags, 0); + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT(flags) { flags = RSF_FOG; } + bool oktorespawn = false; fixedvec3 pos = self->Pos(); + self->flags |= MF_SOLID; self->height = self->GetDefault()->height; self->radius = self->GetDefault()->radius; @@ -3169,6 +3438,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Respawn) { self->flags &= ~MF_SOLID; } + return 0; } @@ -3180,8 +3450,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Respawn) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlayerSkinCheck) { - ACTION_PARAM_START(1); - ACTION_PARAM_STATE(jump, 0); + PARAM_ACTION_PROLOGUE; + PARAM_STATE(jump); ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! if (self->player != NULL && @@ -3189,6 +3459,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlayerSkinCheck) { ACTION_JUMP(jump); } + return numret; } //=========================================================================== @@ -3198,10 +3469,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlayerSkinCheck) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetGravity) { - ACTION_PARAM_START(1); - ACTION_PARAM_FIXED(val, 0); + PARAM_ACTION_PROLOGUE; + PARAM_FIXED(gravity); - self->gravity = clamp (val, 0, FRACUNIT*10); + self->gravity = clamp(gravity, 0, FRACUNIT*10); + return 0; } @@ -3215,9 +3487,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetGravity) DEFINE_ACTION_FUNCTION(AActor, A_ClearTarget) { + PARAM_ACTION_PROLOGUE; self->target = NULL; self->LastHeard = NULL; self->lastenemy = NULL; + return 0; } //========================================================================== @@ -3360,18 +3634,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) fixedvec3 pos; fixed_t vx, vy, vz; - ACTION_PARAM_START(9); - - ACTION_PARAM_STATE(jump, 0); - ACTION_PARAM_INT(flags, 1); - ACTION_PARAM_FIXED(range, 2); - ACTION_PARAM_FIXED(minrange, 3); + PARAM_ACTION_PROLOGUE; + PARAM_STATE (jump); + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_FIXED_OPT (range) { range = 0; } + PARAM_FIXED_OPT (minrange) { minrange = 0; } { - ACTION_PARAM_ANGLE(angle, 4); - ACTION_PARAM_ANGLE(pitch, 5); - ACTION_PARAM_FIXED(offsetheight, 6); - ACTION_PARAM_FIXED(offsetwidth, 7); - ACTION_PARAM_INT(ptr_target, 8); + PARAM_ANGLE_OPT (angle) { angle = 0; } + PARAM_ANGLE_OPT (pitch) { pitch = 0; } + PARAM_FIXED_OPT (offsetheight) { offsetheight = 0; } + PARAM_FIXED_OPT (offsetwidth) { offsetwidth = 0; } + PARAM_INT_OPT (ptr_target) { ptr_target = AAPTR_DEFAULT; } ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! @@ -3418,7 +3691,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) if (range && !(flags & CLOFF_CHECKPARTIAL)) { - if (distance > range) return; + if (distance > range) + return numret; } { @@ -3469,7 +3743,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) pos.x = xy.x; pos.y = xy.y; } - else return; + else + { + return numret; + } angle >>= ANGLETOFINESHIFT; pitch >>= ANGLETOFINESHIFT; @@ -3510,7 +3787,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) { if (minrange > 0 && trace.Distance < minrange) { - return; + return numret; } if ((trace.HitType == TRACE_HitActor) && (trace.Actor != NULL) && !(lof_data.BadActor)) { @@ -3518,9 +3795,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) if (flags & (CLOFF_SETMASTER)) self->master = trace.Actor; if (flags & (CLOFF_SETTRACER)) self->tracer = trace.Actor; } - ACTION_JUMP(jump); } + return numret; } //========================================================================== @@ -3540,9 +3817,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) enum JLOS_flags { - JLOSF_PROJECTILE = 1, + JLOSF_PROJECTILE = 1 << 0, JLOSF_NOSIGHT = 1 << 1, - JLOSF_CLOSENOFOV = 1 << 2, + JLOSF_CLOSENOFOV = 1 << 2, JLOSF_CLOSENOSIGHT = 1 << 3, JLOSF_CLOSENOJUMP = 1 << 4, JLOSF_DEADNOJUMP = 1 << 5, @@ -3557,12 +3834,12 @@ enum JLOS_flags DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) { - ACTION_PARAM_START(5); - ACTION_PARAM_STATE(jump, 0); - ACTION_PARAM_ANGLE(fov, 1); - ACTION_PARAM_INT(flags, 2); - ACTION_PARAM_FIXED(dist_max, 3); - ACTION_PARAM_FIXED(dist_close, 4); + PARAM_ACTION_PROLOGUE; + PARAM_STATE (jump); + PARAM_ANGLE_OPT (fov) { fov = 0; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_FIXED_OPT (dist_max) { dist_max = 0; } + PARAM_FIXED_OPT (dist_close) { dist_close = 0; } angle_t an; AActor *target, *viewport; @@ -3590,11 +3867,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) } if (target == NULL) - return; // [KS] Let's not call P_CheckSight unnecessarily in this case. + return numret; // [KS] Let's not call P_CheckSight unnecessarily in this case. if ((flags & JLOSF_DEADNOJUMP) && (target->health <= 0)) { - return; + return numret; } doCheckSight = !(flags & JLOSF_NOSIGHT); @@ -3604,7 +3881,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) // Does the player aim at something that can be shot? P_AimLineAttack(self, self->angle, MISSILERANGE, &target, (flags & JLOSF_NOAUTOAIM) ? ANGLE_1/2 : 0); - if (!target) return; + if (!target) return numret; switch (flags & (JLOSF_TARGETLOS|JLOSF_FLIPFOV)) { @@ -3626,19 +3903,22 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) } // [FDARI] If target is not a combatant, don't jump - if ( (flags & JLOSF_COMBATANTONLY) && (!target->player) && !(target->flags3 & MF3_ISMONSTER)) return; + if ( (flags & JLOSF_COMBATANTONLY) && (!target->player) && !(target->flags3 & MF3_ISMONSTER)) + return numret; // [FDARI] If actors share team, don't jump - if ((flags & JLOSF_ALLYNOJUMP) && self->IsFriend(target)) return; + if ((flags & JLOSF_ALLYNOJUMP) && self->IsFriend(target)) + return numret; fixed_t distance = self->AproxDistance3D(target); - if (dist_max && (distance > dist_max)) return; + if (dist_max && (distance > dist_max)) + return numret; if (dist_close && (distance < dist_close)) { if (flags & JLOSF_CLOSENOJUMP) - return; + return numret; if (flags & JLOSF_CLOSENOFOV) fov = 0; @@ -3651,7 +3931,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) else { viewport = self; } if (doCheckSight && !P_CheckSight (viewport, target, SF_IGNOREVISIBILITY)) - return; + return numret; if (flags & JLOSF_FLIPFOV) { @@ -3665,12 +3945,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) if (an > (fov / 2) && an < (ANGLE_MAX - (fov / 2))) { - return; // [KS] Outside of FOV - return + return numret; // [KS] Outside of FOV - return } } ACTION_JUMP(jump); + return numret; } @@ -3683,12 +3964,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) { - ACTION_PARAM_START(5); - ACTION_PARAM_STATE(jump, 0); - ACTION_PARAM_ANGLE(fov, 1); - ACTION_PARAM_INT(flags, 2); - ACTION_PARAM_FIXED(dist_max, 3); - ACTION_PARAM_FIXED(dist_close, 4); + PARAM_ACTION_PROLOGUE; + PARAM_STATE (jump); + PARAM_ANGLE_OPT (fov) { fov = 0; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_FIXED_OPT (dist_max) { dist_max = 0; } + PARAM_FIXED_OPT (dist_close) { dist_close = 0; } angle_t an; AActor *target; @@ -3711,20 +3992,29 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) target = self->target; } - if (!target) return; // [KS] Let's not call P_CheckSight unnecessarily in this case. + if (target == NULL) + { // [KS] Let's not call P_CheckSight unnecessarily in this case. + return numret; + } - if ((flags & JLOSF_DEADNOJUMP) && (target->health <= 0)) return; + if ((flags & JLOSF_DEADNOJUMP) && (target->health <= 0)) + { + return numret; + } fixed_t distance = self->AproxDistance3D(target); - if (dist_max && (distance > dist_max)) return; + if (dist_max && (distance > dist_max)) + { + return numret; + } bool doCheckSight = !(flags & JLOSF_NOSIGHT); if (dist_close && (distance < dist_close)) { if (flags & JLOSF_CLOSENOJUMP) - return; + return numret; if (flags & JLOSF_CLOSENOFOV) fov = 0; @@ -3739,14 +4029,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) if (an > (fov / 2) && an < (ANGLE_MAX - (fov / 2))) { - return; // [KS] Outside of FOV - return + return numret; // [KS] Outside of FOV - return } } - if (doCheckSight && !P_CheckSight (target, self, SF_IGNOREVISIBILITY)) - return; + return numret; ACTION_JUMP(jump); + return numret; } //=========================================================================== @@ -3757,20 +4047,22 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckForReload) { + PARAM_ACTION_PROLOGUE; + if ( self->player == NULL || self->player->ReadyWeapon == NULL ) - return; + return 0; - ACTION_PARAM_START(2); - ACTION_PARAM_INT(count, 0); - ACTION_PARAM_STATE(jump, 1); - ACTION_PARAM_BOOL(dontincrement, 2) + PARAM_INT (count); + PARAM_STATE (jump); + PARAM_BOOL_OPT (dontincrement) { dontincrement = false; } - if (count <= 0) return; + if (count <= 0) + return 0; AWeapon *weapon = self->player->ReadyWeapon; int ReloadCounter = weapon->ReloadCounter; - if(!dontincrement || ReloadCounter != 0) + if (!dontincrement || ReloadCounter != 0) ReloadCounter = (weapon->ReloadCounter+1) % count; else // 0 % 1 = 1? So how do we check if the weapon was never fired? We should only do this when we're not incrementing the counter though. ReloadCounter = 1; @@ -3789,6 +4081,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckForReload) if (!dontincrement) weapon->ReloadCounter = ReloadCounter; + return 0; } //=========================================================================== @@ -3799,11 +4092,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckForReload) DEFINE_ACTION_FUNCTION(AActor, A_ResetReloadCounter) { - if ( self->player == NULL || self->player->ReadyWeapon == NULL ) - return; + PARAM_ACTION_PROLOGUE; + + if (self->player == NULL || self->player->ReadyWeapon == NULL) + return 0; AWeapon *weapon = self->player->ReadyWeapon; weapon->ReloadCounter = 0; + return 0; } //=========================================================================== @@ -3813,22 +4109,22 @@ DEFINE_ACTION_FUNCTION(AActor, A_ResetReloadCounter) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeFlag) { - ACTION_PARAM_START(2); - ACTION_PARAM_STRING(flagname, 0); - ACTION_PARAM_BOOL(expression, 1); + PARAM_ACTION_PROLOGUE; + PARAM_STRING (flagname); + PARAM_BOOL (value); - const char *dot = strchr (flagname, '.'); + const char *dot = strchr(flagname, '.'); FFlagDef *fd; - const PClass *cls = self->GetClass(); + PClassActor *cls = self->GetClass(); if (dot != NULL) { - FString part1(flagname, dot-flagname); - fd = FindFlag (cls, part1, dot+1); + FString part1(flagname.GetChars(), dot - flagname); + fd = FindFlag(cls, part1, dot + 1); } else { - fd = FindFlag (cls, flagname, NULL); + fd = FindFlag(cls, flagname, NULL); } if (fd != NULL) @@ -3843,7 +4139,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeFlag) if (fd->structoffset == -1) { - HandleDeprecatedFlags(self, cls->ActorInfo, expression, fd->flagbit); + HandleDeprecatedFlags(self, cls, value, fd->flagbit); } else { @@ -3853,7 +4149,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeFlag) bool linkchange = flagp == &self->flags && (fd->flagbit == MF_NOBLOCKMAP || fd->flagbit == MF_NOSECTOR); if (linkchange) self->UnlinkFromWorld(); - ModActorFlag(self, fd, expression); + ModActorFlag(self, fd, value); if (linkchange) self->LinkToWorld(); } kill_after = self->CountsAsKill(); @@ -3899,8 +4195,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeFlag) } else { - Printf("Unknown flag '%s' in '%s'\n", flagname, cls->TypeName.GetChars()); + Printf("Unknown flag '%s' in '%s'\n", flagname.GetChars(), cls->TypeName.GetChars()); } + return 0; } //=========================================================================== @@ -3911,40 +4208,42 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeFlag) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckFlag) { - ACTION_PARAM_START(3); - ACTION_PARAM_STRING(flagname, 0); - ACTION_PARAM_STATE(jumpto, 1); - ACTION_PARAM_INT(checkpointer, 2); + PARAM_ACTION_PROLOGUE; + PARAM_STRING (flagname); + PARAM_STATE (jumpto); + PARAM_INT_OPT (checkpointer) { checkpointer = AAPTR_DEFAULT; } ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - AActor *owner; + AActor *owner = COPY_AAPTR(self, checkpointer); + if (owner == NULL) + { + return numret; + } - COPY_AAPTR_NOT_NULL(self, owner, checkpointer); - if (CheckActorFlag(owner, flagname)) { ACTION_JUMP(jumpto); } + return numret; } + //=========================================================================== // // A_RaiseMaster // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RaiseMaster) +DEFINE_ACTION_FUNCTION(AActor, A_RaiseMaster) { - ACTION_PARAM_START(1); - ACTION_PARAM_BOOL(copy, 0); + PARAM_ACTION_PROLOGUE; + PARAM_BOOL_OPT(copy) { copy = false; } if (self->master != NULL) { - if (copy) - P_Thing_Raise(self->master, self); - else - P_Thing_Raise(self->master, NULL); + P_Thing_Raise(self->master, copy ? self : NULL); } + return 0; } //=========================================================================== @@ -3952,10 +4251,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RaiseMaster) // A_RaiseChildren // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RaiseChildren) +DEFINE_ACTION_FUNCTION(AActor, A_RaiseChildren) { - ACTION_PARAM_START(1); - ACTION_PARAM_BOOL(copy, 0); + PARAM_ACTION_PROLOGUE; + PARAM_BOOL_OPT(copy) { copy = false; } + TThinkerIterator it; AActor *mo; @@ -3963,12 +4263,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RaiseChildren) { if (mo->master == self) { - if (copy) - P_Thing_Raise(mo, self); - else - P_Thing_Raise(mo, NULL); + P_Thing_Raise(mo, copy ? self : NULL); } } + return 0; } //=========================================================================== @@ -3976,10 +4274,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RaiseChildren) // A_RaiseSiblings // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RaiseSiblings) +DEFINE_ACTION_FUNCTION(AActor, A_RaiseSiblings) { - ACTION_PARAM_START(1); - ACTION_PARAM_BOOL(copy, 0); + PARAM_ACTION_PROLOGUE; + PARAM_BOOL_OPT(copy) { copy = false; } + TThinkerIterator it; AActor *mo; @@ -3989,24 +4288,24 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RaiseSiblings) { if (mo->master == self->master && mo != self) { - if (copy) - P_Thing_Raise(mo, self); - else - P_Thing_Raise(mo, NULL); + P_Thing_Raise(mo, copy ? self : NULL); } } } + return 0; } - -//=========================================================================== -// + + //=========================================================================== + // // [TP] A_FaceConsolePlayer // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS (AActor, A_FaceConsolePlayer) { - ACTION_PARAM_START (1); - ACTION_PARAM_ANGLE (MaxTurnAngle, 0); +DEFINE_ACTION_FUNCTION_PARAMS (AActor, A_FaceConsolePlayer) +{ + PARAM_ACTION_PROLOGUE; + PARAM_ANGLE_OPT(max_turn_angle) { max_turn_angle = 0; } // NOTE: It does nothing for zdoom. + return 0; } //=========================================================================== @@ -4018,15 +4317,15 @@ DEFINE_ACTION_FUNCTION_PARAMS (AActor, A_FaceConsolePlayer) { //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MonsterRefire) { - ACTION_PARAM_START(2); - ACTION_PARAM_INT(prob, 0); - ACTION_PARAM_STATE(jump, 1); + PARAM_ACTION_PROLOGUE; + PARAM_INT (prob); + PARAM_STATE (jump); ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - A_FaceTarget (self); + A_FaceTarget(self); if (pr_monsterrefire() < prob) - return; + return numret; if (self->target == NULL || P_HitFriend (self) @@ -4035,6 +4334,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MonsterRefire) { ACTION_JUMP(jump); } + return numret; } //=========================================================================== @@ -4053,18 +4353,17 @@ enum DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetAngle) { - ACTION_PARAM_START(3); - ACTION_PARAM_ANGLE(angle, 0); - ACTION_PARAM_INT(flags, 1); - ACTION_PARAM_INT(ptr, 2); + PARAM_ACTION_PROLOGUE; + PARAM_ANGLE_OPT(angle) { angle = 0; } + PARAM_INT_OPT(flags) { flags = 0; } + PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } AActor *ref = COPY_AAPTR(self, ptr); - if (ref == NULL) + if (ref != NULL) { - ACTION_SET_RESULT(false); - return; + ref->SetAngle(angle, !!(flags & SPF_INTERPOLATE)); } - ref->SetAngle(angle, !!(flags & SPF_INTERPOLATE)); + return 0; } //=========================================================================== @@ -4077,20 +4376,37 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetAngle) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetPitch) { - ACTION_PARAM_START(3); - ACTION_PARAM_ANGLE(pitch, 0); - ACTION_PARAM_INT(flags, 1); - ACTION_PARAM_INT(ptr, 2); + PARAM_ACTION_PROLOGUE; + PARAM_ANGLE(pitch); + PARAM_INT_OPT(flags) { flags = 0; } + PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } AActor *ref = COPY_AAPTR(self, ptr); - if (!ref) + if (ref == NULL) { - ACTION_SET_RESULT(false); - return; + return 0; + } + + if (ref->player != NULL || (flags & SPF_FORCECLAMP)) + { // clamp the pitch we set + int min, max; + + if (ref->player != NULL) + { + min = ref->player->MinPitch; + max = ref->player->MaxPitch; + } + else + { + min = -ANGLE_90 + (1 << ANGLETOFINESHIFT); + max = ANGLE_90 - (1 << ANGLETOFINESHIFT); + } + pitch = clamp(pitch, min, max); } ref->SetPitch(pitch, !!(flags & SPF_INTERPOLATE), !!(flags & SPF_FORCECLAMP)); + return 0; } //=========================================================================== @@ -4103,19 +4419,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetPitch) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRoll) { - ACTION_PARAM_START(3); - ACTION_PARAM_ANGLE(roll, 0); - ACTION_PARAM_INT(flags, 1); - ACTION_PARAM_INT(ptr, 2); - + PARAM_ACTION_PROLOGUE; + PARAM_ANGLE (roll); + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_INT_OPT (ptr) { ptr = AAPTR_DEFAULT; } AActor *ref = COPY_AAPTR(self, ptr); - if (!ref) + if (ref != NULL) { - ACTION_SET_RESULT(false); - return; + ref->SetRoll(roll, !!(flags & SPF_INTERPOLATE)); } - ref->SetRoll(roll, !!(flags & SPF_INTERPOLATE)); + return 0; } //=========================================================================== @@ -4128,16 +4442,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRoll) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ScaleVelocity) { - ACTION_PARAM_START(2); - ACTION_PARAM_FIXED(scale, 0); - ACTION_PARAM_INT(ptr, 1); + PARAM_ACTION_PROLOGUE; + PARAM_FIXED(scale); + PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } AActor *ref = COPY_AAPTR(self, ptr); - if (!ref) + if (ref == NULL) { - ACTION_SET_RESULT(false); - return; + return 0; } INTBOOL was_moving = ref->velx | ref->vely | ref->velz; @@ -4152,6 +4465,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ScaleVelocity) { CheckStopped(ref); } + return 0; } //=========================================================================== @@ -4162,19 +4476,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ScaleVelocity) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeVelocity) { - ACTION_PARAM_START(5); - ACTION_PARAM_FIXED(x, 0); - ACTION_PARAM_FIXED(y, 1); - ACTION_PARAM_FIXED(z, 2); - ACTION_PARAM_INT(flags, 3); - ACTION_PARAM_INT(ptr, 4); + PARAM_ACTION_PROLOGUE; + PARAM_FIXED_OPT (x) { x = 0; } + PARAM_FIXED_OPT (y) { y = 0; } + PARAM_FIXED_OPT (z) { z = 0; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_INT_OPT (ptr) { ptr = AAPTR_DEFAULT; } AActor *ref = COPY_AAPTR(self, ptr); - if (!ref) + if (ref == NULL) { - ACTION_SET_RESULT(false); - return; + return 0; } INTBOOL was_moving = ref->velx | ref->vely | ref->velz; @@ -4205,6 +4518,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeVelocity) { CheckStopped(ref); } + return 0; } //=========================================================================== @@ -4215,15 +4529,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeVelocity) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetArg) { - ACTION_PARAM_START(2); - ACTION_PARAM_INT(pos, 0); - ACTION_PARAM_INT(value, 1); + PARAM_ACTION_PROLOGUE; + PARAM_INT(pos); + PARAM_INT(value); // Set the value of the specified arg if ((size_t)pos < countof(self->args)) { self->args[pos] = value; } + return 0; } //=========================================================================== @@ -4234,13 +4549,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetArg) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpecial) { - ACTION_PARAM_START(6); - ACTION_PARAM_INT(spec, 0); - ACTION_PARAM_INT(arg0, 1); - ACTION_PARAM_INT(arg1, 2); - ACTION_PARAM_INT(arg2, 3); - ACTION_PARAM_INT(arg3, 4); - ACTION_PARAM_INT(arg4, 5); + PARAM_ACTION_PROLOGUE; + PARAM_INT (spec); + PARAM_INT_OPT (arg0) { arg0 = 0; } + PARAM_INT_OPT (arg1) { arg1 = 0; } + PARAM_INT_OPT (arg2) { arg2 = 0; } + PARAM_INT_OPT (arg3) { arg3 = 0; } + PARAM_INT_OPT (arg4) { arg4 = 0; } self->special = spec; self->args[0] = arg0; @@ -4248,6 +4563,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpecial) self->args[2] = arg2; self->args[3] = arg3; self->args[4] = arg4; + return 0; } //=========================================================================== @@ -4258,23 +4574,21 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpecial) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserVar) { - ACTION_PARAM_START(2); - ACTION_PARAM_NAME(varname, 0); - ACTION_PARAM_INT(value, 1); + PARAM_ACTION_PROLOGUE; + PARAM_NAME (varname); + PARAM_INT (value); - PSymbol *sym = self->GetClass()->Symbols.FindSymbol(varname, true); - PSymbolVariable *var; + PField *var = dyn_cast(self->GetClass()->Symbols.FindSymbol(varname, true)); - if (sym == NULL || sym->SymbolType != SYM_Variable || - !(var = static_cast(sym))->bUserVar || - var->ValueType.Type != VAL_Int) + if (var == NULL || (var->Flags & VARF_Native) || !var->Type->IsKindOf(RUNTIME_CLASS(PBasicType))) { Printf("%s is not a user variable in class %s\n", varname.GetChars(), self->GetClass()->TypeName.GetChars()); - return; + return 0; } // Set the value of the specified user variable. - *(int *)(reinterpret_cast(self) + var->offset) = value; + var->Type->SetValue(reinterpret_cast(self) + var->Offset, value); + return 0; } //=========================================================================== @@ -4285,30 +4599,31 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserVar) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserArray) { - ACTION_PARAM_START(3); - ACTION_PARAM_NAME(varname, 0); - ACTION_PARAM_INT(pos, 1); - ACTION_PARAM_INT(value, 2); + PARAM_ACTION_PROLOGUE; + PARAM_NAME (varname); + PARAM_INT (pos); + PARAM_INT (value); - PSymbol *sym = self->GetClass()->Symbols.FindSymbol(varname, true); - PSymbolVariable *var; + PField *var = dyn_cast(self->GetClass()->Symbols.FindSymbol(varname, true)); - if (sym == NULL || sym->SymbolType != SYM_Variable || - !(var = static_cast(sym))->bUserVar || - var->ValueType.Type != VAL_Array || var->ValueType.BaseType != VAL_Int) + if (var == NULL || (var->Flags & VARF_Native) || + !var->Type->IsKindOf(RUNTIME_CLASS(PArray)) || + !static_cast(var->Type)->ElementType->IsKindOf(RUNTIME_CLASS(PBasicType))) { Printf("%s is not a user array in class %s\n", varname.GetChars(), self->GetClass()->TypeName.GetChars()); - return; + return 0; } - if (pos < 0 || pos >= var->ValueType.size) + PArray *arraytype = static_cast(var->Type); + if ((unsigned)pos >= arraytype->ElementCount) { Printf("%d is out of bounds in array %s in class %s\n", pos, varname.GetChars(), self->GetClass()->TypeName.GetChars()); - return; + return 0; } // Set the value of the specified user array at index pos. - ((int *)(reinterpret_cast(self) + var->offset))[pos] = value; + arraytype->ElementType->SetValue(reinterpret_cast(self) + var->Offset + arraytype->ElementSize * pos, value); + return 0; } //=========================================================================== @@ -4340,27 +4655,26 @@ enum T_Flags DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) { - ACTION_PARAM_START(7); - ACTION_PARAM_STATE(teleport_state, 0); - ACTION_PARAM_CLASS(target_type, 1); - ACTION_PARAM_CLASS(fog_type, 2); - ACTION_PARAM_INT(flags, 3); - ACTION_PARAM_FIXED(mindist, 4); - ACTION_PARAM_FIXED(maxdist, 5); - ACTION_PARAM_INT(ptr, 6); + PARAM_ACTION_PROLOGUE; + PARAM_STATE_OPT (teleport_state) { teleport_state = NULL; } + PARAM_CLASS_OPT (target_type, ASpecialSpot) { target_type = PClass::FindActor("BossSpot"); } + PARAM_CLASS_OPT (fog_type, AActor) { fog_type = PClass::FindActor("TeleportFog"); } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_FIXED_OPT (mindist) { mindist = 128 << FRACBITS; } + PARAM_FIXED_OPT (maxdist) { maxdist = 128 << FRACBITS; } + PARAM_INT_OPT (ptr) { ptr = AAPTR_DEFAULT; } AActor *ref = COPY_AAPTR(self, ptr); + ACTION_SET_RESULT(false); if (!ref) { - ACTION_SET_RESULT(false); - return; + return numret; } if ((ref->flags2 & MF2_NOTELEPORT) && !(flags & TF_OVERRIDE)) { - ACTION_SET_RESULT(false); - return; + return numret; } // Randomly choose not to teleport like A_Srcr2Decide. @@ -4378,29 +4692,29 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) chanceindex = countof(chance) - 1; } - if (pr_teleport() >= chance[chanceindex]) return; + if (pr_teleport() >= chance[chanceindex]) + { + return numret; + } } DSpotState *state = DSpotState::GetSpotState(); if (state == NULL) { - ACTION_SET_RESULT(false); - return; + return numret; } if (target_type == NULL) { - target_type = PClass::FindClass("BossSpot"); + target_type = PClass::FindActor("BossSpot"); } AActor * spot = state->GetSpotWithMinMaxDistance(target_type, ref->X(), ref->Y(), mindist, maxdist); - if (spot == NULL) + if (spot == NULL) { - ACTION_SET_RESULT(false); - return; + return numret; } - // [MC] By default, the function adjusts the actor's Z if it's below the floor or above the ceiling. // This can be an issue as actors designed to maintain specific z positions wind up teleporting // anyway when they should not, such as a floor rising above or ceiling lowering below the position @@ -4410,8 +4724,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) fixed_t posz = (flags & TF_USESPOTZ) ? spot->Z() : spot->floorz; if ((posz + ref->height > spot->ceilingz) || (posz < spot->floorz)) { - ACTION_SET_RESULT(false); - return; + return numret; } } fixedvec3 prev = ref->Pos(); @@ -4481,13 +4794,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) teleport_state = self->FindState("Teleport"); // If still nothing, then return. if (teleport_state == NULL) - return; + { + return numret; + } } ACTION_JUMP(teleport_state); - return; + return numret; } } ACTION_SET_RESULT(tele_result); + return numret; } //=========================================================================== @@ -4498,9 +4814,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Turn) { - ACTION_PARAM_START(1); - ACTION_PARAM_ANGLE(angle, 0); + PARAM_ACTION_PROLOGUE; + PARAM_ANGLE_OPT(angle) { angle = 0; } self->angle += angle; + return 0; } //=========================================================================== @@ -4511,13 +4828,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Turn) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Quake) { - ACTION_PARAM_START(5); - ACTION_PARAM_INT(intensity, 0); - ACTION_PARAM_INT(duration, 1); - ACTION_PARAM_INT(damrad, 2); - ACTION_PARAM_INT(tremrad, 3); - ACTION_PARAM_SOUND(sound, 4); + PARAM_ACTION_PROLOGUE; + PARAM_INT (intensity); + PARAM_INT (duration); + PARAM_INT (damrad); + PARAM_INT (tremrad); + PARAM_SOUND_OPT (sound) { sound = "world/quake"; } + P_StartQuake(self, 0, intensity, duration, damrad, tremrad, sound); + return 0; } //=========================================================================== @@ -4530,19 +4849,20 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Quake) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_QuakeEx) { - ACTION_PARAM_START(11); - ACTION_PARAM_INT(intensityX, 0); - ACTION_PARAM_INT(intensityY, 1); - ACTION_PARAM_INT(intensityZ, 2); - ACTION_PARAM_INT(duration, 3); - ACTION_PARAM_INT(damrad, 4); - ACTION_PARAM_INT(tremrad, 5); - ACTION_PARAM_SOUND(sound, 6); - ACTION_PARAM_INT(flags, 7); - ACTION_PARAM_DOUBLE(mulWaveX, 8); - ACTION_PARAM_DOUBLE(mulWaveY, 9); - ACTION_PARAM_DOUBLE(mulWaveZ, 10); + PARAM_ACTION_PROLOGUE; + PARAM_INT(intensityX); + PARAM_INT(intensityY); + PARAM_INT(intensityZ); + PARAM_INT(duration); + PARAM_INT(damrad); + PARAM_INT(tremrad); + PARAM_SOUND_OPT (sound) { sound = "world/quake"; } + PARAM_INT_OPT(flags) { flags = 0; } + PARAM_FLOAT_OPT(mulWaveX) { mulWaveX = 1.; } + PARAM_FLOAT_OPT(mulWaveY) { mulWaveY = 1.; } + PARAM_FLOAT_OPT(mulWaveZ) { mulWaveZ = 1.; } P_StartQuakeXYZ(self, 0, intensityX, intensityY, intensityZ, duration, damrad, tremrad, sound, flags, mulWaveX, mulWaveY, mulWaveZ); + return 0; } //=========================================================================== @@ -4601,12 +4921,13 @@ void A_Weave(AActor *self, int xyspeed, int zspeed, fixed_t xydist, fixed_t zdis DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Weave) { - ACTION_PARAM_START(4); - ACTION_PARAM_INT(xspeed, 0); - ACTION_PARAM_INT(yspeed, 1); - ACTION_PARAM_FIXED(xdist, 2); - ACTION_PARAM_FIXED(ydist, 3); + PARAM_ACTION_PROLOGUE; + PARAM_INT (xspeed); + PARAM_INT (yspeed); + PARAM_FIXED (xdist); + PARAM_FIXED (ydist); A_Weave(self, xspeed, yspeed, xdist, ydist); + return 0; } @@ -4620,14 +4941,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Weave) // //=========================================================================== - DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LineEffect) { - ACTION_PARAM_START(2); - ACTION_PARAM_INT(special, 0); - ACTION_PARAM_INT(tag, 1); + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT(special) { special = 0; } + PARAM_INT_OPT(tag) { tag = 0; } - line_t junk; maplinedef_t oldjunk; + line_t junk; + maplinedef_t oldjunk; bool res = false; if (!(self->flags6 & MF6_LINEDONE)) // Unless already used up { @@ -4642,6 +4963,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LineEffect) } } ACTION_SET_RESULT(res); + return numret; } //========================================================================== @@ -4657,27 +4979,26 @@ enum WolfAttackFlags DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack) { - ACTION_PARAM_START(9); - ACTION_PARAM_INT(flags, 0); - ACTION_PARAM_SOUND(sound, 1); - ACTION_PARAM_FIXED(snipe, 2); - ACTION_PARAM_INT(maxdamage, 3); - ACTION_PARAM_INT(blocksize, 4); - ACTION_PARAM_INT(pointblank, 5); - ACTION_PARAM_INT(longrange, 6); - ACTION_PARAM_FIXED(runspeed, 7); - ACTION_PARAM_CLASS(pufftype, 8); + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_SOUND_OPT (sound) { sound = "weapons/pistol"; } + PARAM_FIXED_OPT (snipe) { snipe = FRACUNIT; } + PARAM_INT_OPT (maxdamage) { maxdamage = 64; } + PARAM_INT_OPT (blocksize) { blocksize = 128; } + PARAM_INT_OPT (pointblank) { pointblank = 2; } + PARAM_INT_OPT (longrange) { longrange = 4; } + PARAM_FIXED_OPT (runspeed) { runspeed = 160*FRACUNIT; } + PARAM_CLASS_OPT (pufftype, AActor) { pufftype = PClass::FindActor(NAME_BulletPuff); } if (!self->target) - return; + return 0; // Enemy can't see target if (!P_CheckSight(self, self->target)) - return; + return 0; A_FaceTarget (self); - // Target can dodge if it can see enemy angle_t angle = self->target->AngleTo(self) - self->target->angle; angle >>= 24; @@ -4730,7 +5051,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack) || (self->target->flags2 & (MF2_INVULNERABLE|MF2_DORMANT))); if (flags & WAF_USEPUFF && pufftype) { - AActor * dpuff = GetDefaultByType(pufftype->GetReplacement()); + AActor *dpuff = GetDefaultByType(pufftype->GetReplacement()); mod = dpuff->DamageType; if (dpuff->flags2 & MF2_THRUGHOST && self->target->flags3 & MF3_GHOST) @@ -4757,6 +5078,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack) // And finally, let's play the sound S_Sound (self, CHAN_WEAPON, sound, 1, ATTN_NORM); + return 0; } @@ -4768,22 +5090,21 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) { - ACTION_PARAM_START(10); - - ACTION_PARAM_INT(destination_selector, 0); - ACTION_PARAM_FIXED(xofs, 1); - ACTION_PARAM_FIXED(yofs, 2); - ACTION_PARAM_FIXED(zofs, 3); - ACTION_PARAM_ANGLE(angle, 4); - ACTION_PARAM_INT(flags, 5); - ACTION_PARAM_STATE(success_state, 6); - ACTION_PARAM_FIXED(heightoffset, 7); - ACTION_PARAM_FIXED(radiusoffset, 8); - ACTION_PARAM_ANGLE(pitch, 9); + PARAM_ACTION_PROLOGUE; + PARAM_INT(destination_selector); + PARAM_FIXED_OPT(xofs) { xofs = 0; } + PARAM_FIXED_OPT(yofs) { yofs = 0; } + PARAM_FIXED_OPT(zofs) { zofs = 0; } + PARAM_ANGLE_OPT(angle) { angle = 0; } + PARAM_INT_OPT(flags) { flags = 0; } + PARAM_STATE_OPT(success_state) { success_state = NULL; } + PARAM_FIXED_OPT(heightoffset) { heightoffset = 0; } + PARAM_FIXED_OPT(radiusoffset) { radiusoffset = 0; } + PARAM_ANGLE_OPT(pitch) { pitch = 0; } AActor *reference; - - if((flags & WARPF_USETID)) + + if ((flags & WARPF_USETID)) { reference = SingleActorFromTID(destination_selector, self); } @@ -4796,7 +5117,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) if (!reference) { ACTION_SET_RESULT(false); - return; + return numret; } if (P_Thing_Warp(self, reference, xofs, yofs, zofs, angle, flags, heightoffset, radiusoffset, pitch)) @@ -4806,7 +5127,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! // in this case, you have the statejump to help you handle all the success anyway. ACTION_JUMP(success_state); - return; + return numret; } ACTION_SET_RESULT(true); @@ -4815,7 +5136,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) { ACTION_SET_RESULT(false); } - + return numret; } //========================================================================== @@ -4832,101 +5153,94 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedExecuteWithResult) { - ACTION_PARAM_START(5); - - ACTION_PARAM_NAME(scriptname, 0); - ACTION_PARAM_INT(arg1, 1); - ACTION_PARAM_INT(arg2, 2); - ACTION_PARAM_INT(arg3, 3); - ACTION_PARAM_INT(arg4, 4); - - bool res = !!P_ExecuteSpecial(ACS_ExecuteWithResult, NULL, self, false, -scriptname, arg1, arg2, arg3, arg4); + PARAM_ACTION_PROLOGUE; + PARAM_NAME (scriptname); + PARAM_INT_OPT (arg1) { arg1 = 0; } + PARAM_INT_OPT (arg2) { arg2 = 0; } + PARAM_INT_OPT (arg3) { arg3 = 0; } + PARAM_INT_OPT (arg4) { arg4 = 0; } + int res = P_ExecuteSpecial(ACS_ExecuteWithResult, NULL, self, false, -scriptname, arg1, arg2, arg3, arg4); ACTION_SET_RESULT(res); + return numret; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedExecute) { - ACTION_PARAM_START(5); - - ACTION_PARAM_NAME(scriptname, 0); - ACTION_PARAM_INT(mapnum, 1); - ACTION_PARAM_INT(arg1, 2); - ACTION_PARAM_INT(arg2, 3); - ACTION_PARAM_INT(arg3, 4); - - bool res = !!P_ExecuteSpecial(ACS_Execute, NULL, self, false, -scriptname, mapnum, arg1, arg2, arg3); + PARAM_ACTION_PROLOGUE; + PARAM_NAME (scriptname); + PARAM_INT_OPT (mapnum) { mapnum = 0; } + PARAM_INT_OPT (arg1) { arg1 = 0; } + PARAM_INT_OPT (arg2) { arg2 = 0; } + PARAM_INT_OPT (arg3) { arg3 = 0; } + int res = P_ExecuteSpecial(ACS_Execute, NULL, self, false, -scriptname, mapnum, arg1, arg2, arg3); ACTION_SET_RESULT(res); + return numret; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedExecuteAlways) { - ACTION_PARAM_START(5); - - ACTION_PARAM_NAME(scriptname, 0); - ACTION_PARAM_INT(mapnum, 1); - ACTION_PARAM_INT(arg1, 2); - ACTION_PARAM_INT(arg2, 3); - ACTION_PARAM_INT(arg3, 4); - - bool res = !!P_ExecuteSpecial(ACS_ExecuteAlways, NULL, self, false, -scriptname, mapnum, arg1, arg2, arg3); + PARAM_ACTION_PROLOGUE; + PARAM_NAME (scriptname); + PARAM_INT_OPT (mapnum) { mapnum = 0; } + PARAM_INT_OPT (arg1) { arg1 = 0; } + PARAM_INT_OPT (arg2) { arg2 = 0; } + PARAM_INT_OPT (arg3) { arg3 = 0; } + int res = P_ExecuteSpecial(ACS_ExecuteAlways, NULL, self, false, -scriptname, mapnum, arg1, arg2, arg3); ACTION_SET_RESULT(res); + return numret; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedLockedExecute) { - ACTION_PARAM_START(5); - - ACTION_PARAM_NAME(scriptname, 0); - ACTION_PARAM_INT(mapnum, 1); - ACTION_PARAM_INT(arg1, 2); - ACTION_PARAM_INT(arg2, 3); - ACTION_PARAM_INT(lock, 4); - - bool res = !!P_ExecuteSpecial(ACS_LockedExecute, NULL, self, false, -scriptname, mapnum, arg1, arg2, lock); + PARAM_ACTION_PROLOGUE; + PARAM_NAME (scriptname); + PARAM_INT_OPT (mapnum) { mapnum = 0; } + PARAM_INT_OPT (arg1) { arg1 = 0; } + PARAM_INT_OPT (arg2) { arg2 = 0; } + PARAM_INT_OPT (lock) { lock = 0; } + int res = P_ExecuteSpecial(ACS_LockedExecute, NULL, self, false, -scriptname, mapnum, arg1, arg2, lock); ACTION_SET_RESULT(res); + return numret; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedLockedExecuteDoor) { - ACTION_PARAM_START(5); - - ACTION_PARAM_NAME(scriptname, 0); - ACTION_PARAM_INT(mapnum, 1); - ACTION_PARAM_INT(arg1, 2); - ACTION_PARAM_INT(arg2, 3); - ACTION_PARAM_INT(lock, 4); - - bool res = !!P_ExecuteSpecial(ACS_LockedExecuteDoor, NULL, self, false, -scriptname, mapnum, arg1, arg2, lock); + PARAM_ACTION_PROLOGUE; + PARAM_NAME (scriptname); + PARAM_INT_OPT (mapnum) { mapnum = 0; } + PARAM_INT_OPT (arg1) { arg1 = 0; } + PARAM_INT_OPT (arg2) { arg2 = 0; } + PARAM_INT_OPT (lock) { lock = 0; } + int res = P_ExecuteSpecial(ACS_LockedExecuteDoor, NULL, self, false, -scriptname, mapnum, arg1, arg2, lock); ACTION_SET_RESULT(res); + return numret; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedSuspend) { - ACTION_PARAM_START(2); - - ACTION_PARAM_NAME(scriptname, 0); - ACTION_PARAM_INT(mapnum, 1); - - bool res = !!P_ExecuteSpecial(ACS_Suspend, NULL, self, false, -scriptname, mapnum, 0, 0, 0); + PARAM_ACTION_PROLOGUE; + PARAM_NAME (scriptname); + PARAM_INT_OPT (mapnum) { mapnum = 0; } + int res = P_ExecuteSpecial(ACS_Suspend, NULL, self, false, -scriptname, mapnum, 0, 0, 0); ACTION_SET_RESULT(res); + return numret; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedTerminate) { - ACTION_PARAM_START(2); - - ACTION_PARAM_NAME(scriptname, 0); - ACTION_PARAM_INT(mapnum, 1); - - bool res = !!P_ExecuteSpecial(ACS_Terminate, NULL, self, false, -scriptname, mapnum, 0, 0, 0); + PARAM_ACTION_PROLOGUE; + PARAM_NAME (scriptname); + PARAM_INT_OPT (mapnum) { mapnum = 0; } + int res = P_ExecuteSpecial(ACS_Terminate, NULL, self, false, -scriptname, mapnum, 0, 0, 0); ACTION_SET_RESULT(res); + return numret; } @@ -4937,12 +5251,13 @@ static bool DoCheckSpecies(AActor *mo, FName filterSpecies, bool exclude) return exclude ? (actorSpecies != filterSpecies) : (actorSpecies == filterSpecies); } -static bool DoCheckClass(AActor *mo, const PClass *filterClass, bool exclude) +static bool DoCheckClass(AActor *mo, PClassActor *filterClass, bool exclude) { const PClass *actorClass = mo->GetClass(); if (filterClass == NULL) return true; return exclude ? (actorClass != filterClass) : (actorClass == filterClass); } + //========================================================================== // // A_RadiusGive(item, distance, flags, amount, filter, species) @@ -4975,7 +5290,7 @@ enum RadiusGiveFlags RGF_EITHER = 1 << 17, }; -static bool DoRadiusGive(AActor *self, AActor *thing, const PClass *item, int amount, fixed_t distance, int flags, const PClass *filter, FName species, fixed_t mindist) +static bool DoRadiusGive(AActor *self, AActor *thing, PClassActor *item, int amount, fixed_t distance, int flags, PClassActor *filter, FName species, fixed_t mindist) { // [MC] We only want to make an exception for missiles here. Nothing else. bool missilePass = !!((flags & RGF_MISSILES) && thing->isMissile()); @@ -4989,14 +5304,13 @@ static bool DoRadiusGive(AActor *self, AActor *thing, const PClass *item, int am if (!missilePass) return false; } - //[MC] Check for a filter, species, and the related exfilter/expecies/either flag(s). bool filterpass = DoCheckClass(thing, filter, !!(flags & RGF_EXFILTER)), speciespass = DoCheckSpecies(thing, species, !!(flags & RGF_EXSPECIES)); if ((flags & RGF_EITHER) ? (!(filterpass || speciespass)) : (!(filterpass && speciespass))) { - if (thing != self) //Don't let filter and species obstruct RGF_GIVESELF. + if (thing != self) //Don't let filter and species obstruct RGF_GIVESELF. return false; } @@ -5021,7 +5335,7 @@ static bool DoRadiusGive(AActor *self, AActor *thing, const PClass *item, int am return false; } - //Next, actor flag checking. + //Next, actor flag checking. bool selfPass = !!((flags & RGF_GIVESELF) && thing == self); bool corpsePass = !!((flags & RGF_CORPSES) && thing->flags & MF_CORPSE); bool killedPass = !!((flags & RGF_KILLED) && thing->flags6 & MF6_KILLED); @@ -5104,20 +5418,20 @@ static bool DoRadiusGive(AActor *self, AActor *thing, const PClass *item, int am DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) { - ACTION_PARAM_START(7); - ACTION_PARAM_CLASS(item, 0); - ACTION_PARAM_FIXED(distance, 1); - ACTION_PARAM_INT(flags, 2); - ACTION_PARAM_INT(amount, 3); - ACTION_PARAM_CLASS(filter, 4); - ACTION_PARAM_NAME(species, 5); - ACTION_PARAM_FIXED(mindist, 6); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS (item, AInventory); + PARAM_FIXED (distance); + PARAM_INT (flags); + PARAM_INT_OPT (amount) { amount = 0; } + PARAM_CLASS_OPT (filter, AActor) { filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } + PARAM_FIXED_OPT (mindist) { mindist = 0; } // We need a valid item, valid targets, and a valid range if (item == NULL || (flags & RGF_MASK) == 0 || !flags || distance <= 0 || mindist >= distance) { ACTION_SET_RESULT(false); - return; + return numret; } if (amount == 0) @@ -5131,7 +5445,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) TThinkerIterator it; while ((thing = it.Next())) { - if (DoRadiusGive(self, thing, item, amount, distance, flags, filter, species, mindist)) given = true; + given |= DoRadiusGive(self, thing, item, amount, distance, flags, filter, species, mindist); } } else @@ -5139,10 +5453,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) FBlockThingsIterator it(FBoundingBox(self->X(), self->Y(), distance)); while ((thing = it.Next())) { - if (DoRadiusGive(self, thing, item, amount, distance, flags, filter, species, mindist)) given = true; + given |= DoRadiusGive(self, thing, item, amount, distance, flags, filter, species, mindist); } } ACTION_SET_RESULT(given); + return numret; } //=========================================================================== @@ -5152,25 +5467,25 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSpecies) { - ACTION_PARAM_START(3); - ACTION_PARAM_STATE(jump, 0); - ACTION_PARAM_NAME(species, 1); - ACTION_PARAM_INT(ptr, 2); + PARAM_ACTION_PROLOGUE; + PARAM_STATE(jump); + PARAM_NAME_OPT(species) { species = NAME_None; } + PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } AActor *mobj = COPY_AAPTR(self, ptr); ACTION_SET_RESULT(false); - //Needs at least one state jump to work. - if (!mobj) + // Needs at least one state jump to work. + if (mobj == NULL) { - return; + return numret; } if (jump && mobj->GetSpecies() == species) ACTION_JUMP(jump); + return numret; } - //========================================================================== // // A_SetTics @@ -5179,22 +5494,23 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSpecies) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTics) { - ACTION_PARAM_START(1); - ACTION_PARAM_INT(tics_to_set, 0); + PARAM_ACTION_PROLOGUE; + PARAM_INT(tics_to_set); if (stateowner != self && self->player != NULL && stateowner->IsKindOf(RUNTIME_CLASS(AWeapon))) { // Is this a weapon? Need to check psp states for a match, then. Blah. for (int i = 0; i < NUMPSPRITES; ++i) { - if (self->player->psprites[i].state == CallingState) + if (self->player->psprites[i].state == callingstate) { self->player->psprites[i].tics = tics_to_set; - return; + return 0; } } } // Just set tics for self. self->tics = tics_to_set; + return 0; } //========================================================================== @@ -5205,10 +5521,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTics) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetDamageType) { - ACTION_PARAM_START(1); - ACTION_PARAM_NAME(damagetype, 0); + PARAM_ACTION_PROLOGUE; + PARAM_NAME(damagetype); self->DamageType = damagetype; + return 0; } //========================================================================== @@ -5219,12 +5536,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetDamageType) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DropItem) { - ACTION_PARAM_START(3); - ACTION_PARAM_CLASS(spawntype, 0); - ACTION_PARAM_INT(amount, 1); - ACTION_PARAM_INT(chance, 2); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS (spawntype, AActor); + PARAM_INT_OPT (amount) { amount = -1; } + PARAM_INT_OPT (chance) { chance = 256; } P_DropItem(self, spawntype, amount, chance); + return 0; } //========================================================================== @@ -5234,19 +5552,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DropItem) //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpeed) { - ACTION_PARAM_START(2); - ACTION_PARAM_FIXED(speed, 0); - ACTION_PARAM_INT(ptr, 1); + PARAM_ACTION_PROLOGUE; + PARAM_INT(speed); + PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } AActor *ref = COPY_AAPTR(self, ptr); - if (!ref) + if (ref != NULL) { - ACTION_SET_RESULT(false); - return; + ref->Speed = speed; } - - ref->Speed = speed; + return 0; } //========================================================================== @@ -5256,19 +5572,20 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpeed) //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetFloatSpeed) { - ACTION_PARAM_START(2); - ACTION_PARAM_FIXED(speed, 0); - ACTION_PARAM_INT(ptr, 1); + PARAM_ACTION_PROLOGUE; + PARAM_INT(speed); + PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } AActor *ref = COPY_AAPTR(self, ptr); if (!ref) { ACTION_SET_RESULT(false); - return; + return 0; } ref->FloatSpeed = speed; + return 0; } //========================================================================== @@ -5278,19 +5595,20 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetFloatSpeed) //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetPainThreshold) { - ACTION_PARAM_START(2); - ACTION_PARAM_INT(threshold, 0); - ACTION_PARAM_INT(ptr, 1); + PARAM_ACTION_PROLOGUE; + PARAM_INT(threshold); + PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } AActor *ref = COPY_AAPTR(self, ptr); if (!ref) { ACTION_SET_RESULT(false); - return; + return numret; } ref->PainThreshold = threshold; + return numret; } //=========================================================================== @@ -5322,7 +5640,7 @@ enum DMSS DMSS_EITHER = 256, //Allow either type or species to be affected. }; -static void DoDamage(AActor *dmgtarget, AActor *self, int amount, FName DamageType, int flags, const PClass *filter, FName species) +static void DoDamage(AActor *dmgtarget, AActor *self, int amount, FName DamageType, int flags, PClassActor *filter, FName species) { bool filterpass = DoCheckClass(dmgtarget, filter, !!(flags & DMSS_EXFILTER)), speciespass = DoCheckSpecies(dmgtarget, species, !!(flags & DMSS_EXSPECIES)); @@ -5343,8 +5661,9 @@ static void DoDamage(AActor *dmgtarget, AActor *self, int amount, FName DamageTy dmgFlags |= DMG_NO_PROTECT; if (amount > 0) - P_DamageMobj(dmgtarget, self, self, amount, DamageType, dmgFlags); //Should wind up passing them through just fine. - + { //Should wind up passing them through just fine. + P_DamageMobj(dmgtarget, self, self, amount, DamageType, dmgFlags); + } else if (amount < 0) { amount = -amount; @@ -5360,14 +5679,15 @@ static void DoDamage(AActor *dmgtarget, AActor *self, int amount, FName DamageTy //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageSelf) { - ACTION_PARAM_START(5); - ACTION_PARAM_INT(amount, 0); - ACTION_PARAM_NAME(DamageType, 1); - ACTION_PARAM_INT(flags, 2); - ACTION_PARAM_CLASS(filter, 3); - ACTION_PARAM_NAME(species, 4); + PARAM_ACTION_PROLOGUE; + PARAM_INT (amount); + PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } - DoDamage(self, self, amount, DamageType, flags, filter, species); + DoDamage(self, self, amount, damagetype, flags, filter, species); + return 0; } //=========================================================================== @@ -5377,17 +5697,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageSelf) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageTarget) { - ACTION_PARAM_START(5); - ACTION_PARAM_INT(amount, 0); - ACTION_PARAM_NAME(DamageType, 1); - ACTION_PARAM_INT(flags, 2); - ACTION_PARAM_CLASS(filter, 3); - ACTION_PARAM_NAME(species, 4); + PARAM_ACTION_PROLOGUE; + PARAM_INT (amount); + PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } if (self->target != NULL) - { - DoDamage(self->target, self, amount, DamageType, flags, filter, species); - } + DoDamage(self->target, self, amount, damagetype, flags, filter, species); + return 0; } //=========================================================================== @@ -5397,17 +5716,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageTarget) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageTracer) { - ACTION_PARAM_START(5); - ACTION_PARAM_INT(amount, 0); - ACTION_PARAM_NAME(DamageType, 1); - ACTION_PARAM_INT(flags, 2); - ACTION_PARAM_CLASS(filter, 3); - ACTION_PARAM_NAME(species, 4); + PARAM_ACTION_PROLOGUE; + PARAM_INT (amount); + PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } if (self->tracer != NULL) - { - DoDamage(self->tracer, self, amount, DamageType, flags, filter, species); - } + DoDamage(self->tracer, self, amount, damagetype, flags, filter, species); + return 0; } //=========================================================================== @@ -5417,17 +5735,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageTracer) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageMaster) { - ACTION_PARAM_START(5); - ACTION_PARAM_INT(amount, 0); - ACTION_PARAM_NAME(DamageType, 1); - ACTION_PARAM_INT(flags, 2); - ACTION_PARAM_CLASS(filter, 3); - ACTION_PARAM_NAME(species, 4); + PARAM_ACTION_PROLOGUE; + PARAM_INT (amount); + PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } if (self->master != NULL) - { - DoDamage(self->master, self, amount, DamageType, flags, filter, species); - } + DoDamage(self->master, self, amount, damagetype, flags, filter, species); + return 0; } //=========================================================================== @@ -5437,23 +5754,22 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageMaster) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageChildren) { - ACTION_PARAM_START(5); - ACTION_PARAM_INT(amount, 0); - ACTION_PARAM_NAME(DamageType, 1); - ACTION_PARAM_INT(flags, 2); - ACTION_PARAM_CLASS(filter, 3); - ACTION_PARAM_NAME(species, 4); + PARAM_ACTION_PROLOGUE; + PARAM_INT (amount); + PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } TThinkerIterator it; - AActor * mo; + AActor *mo; while ( (mo = it.Next()) ) { if (mo->master == self) - { - DoDamage(mo, self, amount, DamageType, flags, filter, species); - } + DoDamage(mo, self, amount, damagetype, flags, filter, species); } + return 0; } //=========================================================================== @@ -5463,26 +5779,25 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageChildren) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageSiblings) { - ACTION_PARAM_START(5); - ACTION_PARAM_INT(amount, 0); - ACTION_PARAM_NAME(DamageType, 1); - ACTION_PARAM_INT(flags, 2); - ACTION_PARAM_CLASS(filter, 3); - ACTION_PARAM_NAME(species, 4); + PARAM_ACTION_PROLOGUE; + PARAM_INT (amount); + PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } TThinkerIterator it; - AActor * mo; + AActor *mo; if (self->master != NULL) { while ((mo = it.Next())) { if (mo->master == self->master && mo != self) - { - DoDamage(mo, self, amount, DamageType, flags, filter, species); - } + DoDamage(mo, self, amount, damagetype, flags, filter, species); } } + return 0; } @@ -5502,7 +5817,7 @@ enum KILS KILS_EITHER = 1 << 6, }; -static void DoKill(AActor *killtarget, AActor *self, FName damagetype, int flags, const PClass *filter, FName species) +static void DoKill(AActor *killtarget, AActor *self, FName damagetype, int flags, PClassActor *filter, FName species) { bool filterpass = DoCheckClass(killtarget, filter, !!(flags & KILS_EXFILTER)), speciespass = DoCheckSpecies(killtarget, species, !!(flags & KILS_EXSPECIES)); @@ -5514,7 +5829,6 @@ static void DoKill(AActor *killtarget, AActor *self, FName damagetype, int flags dmgFlags |= DMG_FOILINVUL; if (KILS_FOILBUDDHA) dmgFlags |= DMG_FOILBUDDHA; - if ((killtarget->flags & MF_MISSILE) && (flags & KILS_KILLMISSILES)) { @@ -5543,16 +5857,15 @@ static void DoKill(AActor *killtarget, AActor *self, FName damagetype, int flags //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillTarget) { - ACTION_PARAM_START(4); - ACTION_PARAM_NAME(damagetype, 0); - ACTION_PARAM_INT(flags, 1); - ACTION_PARAM_CLASS(filter, 2); - ACTION_PARAM_NAME(species, 3); + PARAM_ACTION_PROLOGUE; + PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } if (self->target != NULL) - { DoKill(self->target, self, damagetype, flags, filter, species); - } + return 0; } //=========================================================================== @@ -5562,16 +5875,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillTarget) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillTracer) { - ACTION_PARAM_START(4); - ACTION_PARAM_NAME(damagetype, 0); - ACTION_PARAM_INT(flags, 1); - ACTION_PARAM_CLASS(filter, 2); - ACTION_PARAM_NAME(species, 3); + PARAM_ACTION_PROLOGUE; + PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } if (self->tracer != NULL) - { DoKill(self->tracer, self, damagetype, flags, filter, species); - } + return 0; } //=========================================================================== @@ -5581,16 +5893,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillTracer) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillMaster) { - ACTION_PARAM_START(4); - ACTION_PARAM_NAME(damagetype, 0); - ACTION_PARAM_INT(flags, 1); - ACTION_PARAM_CLASS(filter, 2); - ACTION_PARAM_NAME(species, 3); + PARAM_ACTION_PROLOGUE; + PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } if (self->master != NULL) - { DoKill(self->master, self, damagetype, flags, filter, species); - } + return 0; } //=========================================================================== @@ -5600,11 +5911,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillMaster) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillChildren) { - ACTION_PARAM_START(4); - ACTION_PARAM_NAME(damagetype, 0); - ACTION_PARAM_INT(flags, 1); - ACTION_PARAM_CLASS(filter, 2); - ACTION_PARAM_NAME(species, 3); + PARAM_ACTION_PROLOGUE; + PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } TThinkerIterator it; AActor *mo; @@ -5616,6 +5927,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillChildren) DoKill(mo, self, damagetype, flags, filter, species); } } + return 0; } //=========================================================================== @@ -5625,11 +5937,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillChildren) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillSiblings) { - ACTION_PARAM_START(4); - ACTION_PARAM_NAME(damagetype, 0); - ACTION_PARAM_INT(flags, 1); - ACTION_PARAM_CLASS(filter, 2); - ACTION_PARAM_NAME(species, 3); + PARAM_ACTION_PROLOGUE; + PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } TThinkerIterator it; AActor *mo; @@ -5644,6 +5956,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillSiblings) } } } + return 0; } //=========================================================================== @@ -5663,7 +5976,7 @@ enum RMVF_flags RMVF_EITHER = 1 << 6, }; -static void DoRemove(AActor *removetarget, int flags, const PClass *filter, FName species) +static void DoRemove(AActor *removetarget, int flags, PClassActor *filter, FName species) { bool filterpass = DoCheckClass(removetarget, filter, !!(flags & RMVF_EXFILTER)), speciespass = DoCheckSpecies(removetarget, species, !!(flags & RMVF_EXSPECIES)); @@ -5695,15 +6008,16 @@ static void DoRemove(AActor *removetarget, int flags, const PClass *filter, FNam //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveTarget) { - ACTION_PARAM_START(2); - ACTION_PARAM_INT(flags, 0); - ACTION_PARAM_CLASS(filter, 1); - ACTION_PARAM_NAME(species, 2); - + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT(flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } + if (self->target != NULL) { DoRemove(self->target, flags, filter, species); } + return 0; } //=========================================================================== @@ -5713,15 +6027,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveTarget) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveTracer) { - ACTION_PARAM_START(2); - ACTION_PARAM_INT(flags, 0); - ACTION_PARAM_CLASS(filter, 1); - ACTION_PARAM_NAME(species, 2); - + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT(flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } + if (self->tracer != NULL) { DoRemove(self->tracer, flags, filter, species); } + return 0; } //=========================================================================== @@ -5731,15 +6046,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveTracer) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveMaster) { - ACTION_PARAM_START(2); - ACTION_PARAM_INT(flags, 0); - ACTION_PARAM_CLASS(filter, 1); - ACTION_PARAM_NAME(species, 2); - + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } + if (self->master != NULL) { DoRemove(self->master, flags, filter, species); } + return 0; } //=========================================================================== @@ -5749,14 +6065,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveMaster) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveChildren) { + PARAM_ACTION_PROLOGUE; + PARAM_BOOL_OPT (removeall) { removeall = false; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } + TThinkerIterator it; AActor *mo; - ACTION_PARAM_START(4); - ACTION_PARAM_BOOL(removeall, 0); - ACTION_PARAM_INT(flags, 1); - ACTION_PARAM_CLASS(filter, 2); - ACTION_PARAM_NAME(species, 3); - while ((mo = it.Next()) != NULL) { @@ -5765,6 +6081,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveChildren) DoRemove(mo, flags, filter, species); } } + return 0; } //=========================================================================== @@ -5774,13 +6091,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveChildren) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveSiblings) { + PARAM_ACTION_PROLOGUE; + PARAM_BOOL_OPT (removeall) { removeall = false; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } + TThinkerIterator it; AActor *mo; - ACTION_PARAM_START(4); - ACTION_PARAM_BOOL(removeall, 0); - ACTION_PARAM_INT(flags, 1); - ACTION_PARAM_CLASS(filter, 2); - ACTION_PARAM_NAME(species, 3); if (self->master != NULL) { @@ -5792,6 +6110,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveSiblings) } } } + return 0; } //=========================================================================== @@ -5801,17 +6120,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveSiblings) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Remove) { - ACTION_PARAM_START(4); - ACTION_PARAM_INT(removee, 0); - ACTION_PARAM_INT(flags, 1); - ACTION_PARAM_CLASS(filter, 2); - ACTION_PARAM_NAME(species, 3); + PARAM_ACTION_PROLOGUE; + PARAM_INT (removee); + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } AActor *reference = COPY_AAPTR(self, removee); if (reference != NULL) { DoRemove(reference, flags, filter, species); } + return 0; } //=========================================================================== @@ -5824,12 +6144,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Remove) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTeleFog) { - ACTION_PARAM_START(2); - ACTION_PARAM_CLASS(oldpos, 0); - ACTION_PARAM_CLASS(newpos, 1); + PARAM_ACTION_PROLOGUE; + PARAM_CLASS(oldpos, AActor); + PARAM_CLASS(newpos, AActor); self->TeleFogSourceType = oldpos; self->TeleFogDestType = newpos; + return 0; } //=========================================================================== @@ -5841,12 +6162,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTeleFog) DEFINE_ACTION_FUNCTION(AActor, A_SwapTeleFog) { + PARAM_ACTION_PROLOGUE; if ((self->TeleFogSourceType != self->TeleFogDestType)) //Does nothing if they're the same. { - const PClass *temp = self->TeleFogSourceType; + PClassActor *temp = self->TeleFogSourceType; self->TeleFogSourceType = self->TeleFogDestType; self->TeleFogDestType = temp; } + return 0; } //=========================================================================== @@ -5858,12 +6181,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_SwapTeleFog) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetFloatBobPhase) { - ACTION_PARAM_START(1); - ACTION_PARAM_INT(bob, 0); + PARAM_ACTION_PROLOGUE; + PARAM_INT(bob); //Respect float bob phase limits. if (self && (bob >= 0 && bob <= 63)) + { self->FloatBobPhase = bob; + } + return 0; } //=========================================================================== @@ -5875,15 +6201,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetFloatBobPhase) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetHealth) { - ACTION_PARAM_START(2); - ACTION_PARAM_INT(health, 0); - ACTION_PARAM_INT(ptr, 1); + PARAM_ACTION_PROLOGUE; + PARAM_INT (health); + PARAM_INT_OPT (ptr) { ptr = AAPTR_DEFAULT; } AActor *mobj = COPY_AAPTR(self, ptr); if (!mobj) { - return; + return 0; } player_t *player = mobj->player; @@ -5901,6 +6227,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetHealth) else mobj->health = health; } + return 0; } //=========================================================================== @@ -5912,14 +6239,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetHealth) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ResetHealth) { - ACTION_PARAM_START(1); - ACTION_PARAM_INT(ptr, 0); + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } AActor *mobj = COPY_AAPTR(self, ptr); if (!mobj) { - return; + return 0; } player_t *player = mobj->player; @@ -5931,6 +6258,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ResetHealth) { mobj->health = mobj->SpawnHealth(); } + return 0; } //=========================================================================== @@ -5946,27 +6274,26 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ResetHealth) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfHigherOrLower) { - ACTION_PARAM_START(6); - ACTION_PARAM_STATE(high, 0); - ACTION_PARAM_STATE(low, 1); - ACTION_PARAM_FIXED(offsethigh, 2); - ACTION_PARAM_FIXED(offsetlow, 3); - ACTION_PARAM_BOOL(includeHeight, 4); - ACTION_PARAM_INT(ptr, 5); + PARAM_ACTION_PROLOGUE; + PARAM_STATE(high); + PARAM_STATE(low); + PARAM_FIXED_OPT(offsethigh) { offsethigh = 0; } + PARAM_FIXED_OPT(offsetlow) { offsetlow = 0; } + PARAM_BOOL_OPT(includeHeight) { includeHeight = true; } + PARAM_INT_OPT(ptr) { ptr = AAPTR_TARGET; } AActor *mobj = COPY_AAPTR(self, ptr); - if (!mobj || (mobj == self)) //AAPTR_DEFAULT is completely useless in this regard. - { - return; - } ACTION_SET_RESULT(false); //No inventory jump chains please. - + if (mobj != NULL && mobj != self) //AAPTR_DEFAULT is completely useless in this regard. + { if ((high) && (mobj->Z() > ((includeHeight ? self->height : 0) + self->Z() + offsethigh))) - ACTION_JUMP(high); + ACTION_JUMP(high); else if ((low) && (mobj->Z() + (includeHeight ? mobj->height : 0)) < (self->Z() + offsetlow)) - ACTION_JUMP(low); + ACTION_JUMP(low); + } + return numret; } //=========================================================================== @@ -5976,17 +6303,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfHigherOrLower) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpecies) { - ACTION_PARAM_START(2); - ACTION_PARAM_NAME(species, 0); - ACTION_PARAM_INT(ptr, 1); + PARAM_ACTION_PROLOGUE; + PARAM_NAME(species); + PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } + AActor *mobj = COPY_AAPTR(self, ptr); if (!mobj) { ACTION_SET_RESULT(false); - return; + return 0; } mobj->Species = species; + return 0; } //=========================================================================== @@ -5997,9 +6326,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpecies) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRipperLevel) { - ACTION_PARAM_START(1); - ACTION_PARAM_INT(level, 0); + PARAM_ACTION_PROLOGUE; + PARAM_INT(level); self->RipperLevel = level; + return 0; } //=========================================================================== @@ -6010,9 +6340,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRipperLevel) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRipMin) { - ACTION_PARAM_START(1); - ACTION_PARAM_INT(min, 0); - self->RipLevelMin = min; + PARAM_ACTION_PROLOGUE; + PARAM_INT(min); + self->RipLevelMin = min; + return 0; } //=========================================================================== @@ -6023,9 +6354,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRipMin) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRipMax) { - ACTION_PARAM_START(1); - ACTION_PARAM_INT(max, 0); + PARAM_ACTION_PROLOGUE; + PARAM_INT(max); self->RipLevelMax = max; + return 0; } //========================================================================== @@ -6037,7 +6369,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRipMax) //========================================================================== enum CPXFflags { - CPXF_ANCESTOR = 1, + CPXF_ANCESTOR = 1 << 0, CPXF_LESSOREQUAL = 1 << 1, CPXF_NOZ = 1 << 2, CPXF_COUNTDEAD = 1 << 3, @@ -6053,26 +6385,27 @@ enum CPXFflags }; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckProximity) { - ACTION_PARAM_START(6); - ACTION_PARAM_STATE(jump, 0); - ACTION_PARAM_CLASS(classname, 1); - ACTION_PARAM_FIXED(distance, 2); - ACTION_PARAM_INT(count, 3); - ACTION_PARAM_INT(flags, 4); - ACTION_PARAM_INT(ptr, 5); + PARAM_ACTION_PROLOGUE; + PARAM_STATE(jump); + PARAM_CLASS(classname, AActor); + PARAM_FIXED(distance); + PARAM_INT_OPT(count) { count = 1; } + PARAM_INT(flags) { flags = 0; } + PARAM_INT(ptr) { ptr = AAPTR_DEFAULT; } ACTION_SET_RESULT(false); //No inventory chain results please. + if (!jump) { if (!(flags & (CPXF_SETTARGET | CPXF_SETMASTER | CPXF_SETTRACER))) - return; + return numret; } AActor *ref = COPY_AAPTR(self, ptr); //We need these to check out. - if (!ref || !classname || (distance <= 0)) - return; + if (!ref || !classname || distance <= 0) + return numret; int counter = 0; bool result = false; @@ -6118,17 +6451,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckProximity) if ((flags & CPXF_CLOSEST) && (current < closer)) { dist = mo; - closer = current; //This actor's closer. Set the new standard. + closer = current; //This actor's closer. Set the new standard. } else if ((flags & CPXF_FARTHEST) && (current > farther)) { dist = mo; farther = current; } - else if (!dist) + else if (!dist) dist = mo; //Just get the first one and call it quits if there's nothing selected. } - if (mo->flags6 & MF6_KILLED) { if (!(flags & (CPXF_COUNTDEAD | CPXF_DEADONLY))) @@ -6160,15 +6492,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckProximity) { if (flags & CPXF_SETONPTR) { - if (flags & CPXF_SETTARGET) ref->target = dist; - if (flags & CPXF_SETMASTER) ref->master = dist; - if (flags & CPXF_SETTRACER) ref->tracer = dist; + if (flags & CPXF_SETTARGET) ref->target = dist; + if (flags & CPXF_SETMASTER) ref->master = dist; + if (flags & CPXF_SETTRACER) ref->tracer = dist; } else { - if (flags & CPXF_SETTARGET) self->target = dist; - if (flags & CPXF_SETMASTER) self->master = dist; - if (flags & CPXF_SETTRACER) self->tracer = dist; + if (flags & CPXF_SETTARGET) self->target = dist; + if (flags & CPXF_SETMASTER) self->master = dist; + if (flags & CPXF_SETTRACER) self->tracer = dist; } } @@ -6177,12 +6509,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckProximity) else if (counter < count) result = !!((flags & CPXF_LESSOREQUAL) && !(flags & CPXF_EXACT)); - if (!jump) return; - - if (result) + if (result && jump) { ACTION_JUMP(jump); } + return numret; } /*=========================================================================== @@ -6205,10 +6536,10 @@ enum CBF DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckBlock) { - ACTION_PARAM_START(3); - ACTION_PARAM_STATE(block, 0); - ACTION_PARAM_INT(flags, 1); - ACTION_PARAM_INT(ptr, 2); + PARAM_ACTION_PROLOGUE; + PARAM_STATE(block) + PARAM_INT_OPT(flags) { flags = 0; } + PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } AActor *mobj = COPY_AAPTR(self, ptr); @@ -6216,12 +6547,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckBlock) //Needs at least one state jump to work. if (!mobj) { - return; + return numret; } //Nothing to block it so skip the rest. bool checker = (flags & CBF_DROPOFF) ? P_CheckMove(mobj, mobj->X(), mobj->Y()) : P_TestMobjLocation(mobj); - if (checker) return; + if (checker) return numret; if (mobj->BlockingMobj) { @@ -6238,13 +6569,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckBlock) //this point. I.e. A_CheckBlock("",CBF_SETTRACER) is like having CBF_NOLINES. //It gets the mobj blocking, if any, and doesn't jump at all. if (!block) - return; + return numret; //[MC] Easiest way to tell if an actor is blocking it, use the pointers. if (mobj->BlockingMobj || (!(flags & CBF_NOLINES) && mobj->BlockingLine != NULL)) { ACTION_JUMP(block); } + return numret; } //=========================================================================== @@ -6261,12 +6593,12 @@ enum FMDFlags }; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceMovementDirection) { - ACTION_PARAM_START(5); - ACTION_PARAM_ANGLE(offset, 0); - ACTION_PARAM_ANGLE(anglelimit, 1); - ACTION_PARAM_ANGLE(pitchlimit, 2); - ACTION_PARAM_INT(flags, 3); - ACTION_PARAM_INT(ptr, 4); + PARAM_ACTION_PROLOGUE; + PARAM_ANGLE_OPT(offset) { offset = 0; } + PARAM_ANGLE_OPT(anglelimit) { anglelimit = 0; } + PARAM_ANGLE_OPT(pitchlimit) { pitchlimit = 0; } + PARAM_INT_OPT(flags) { flags = 0; } + PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } AActor *mobj = COPY_AAPTR(self, ptr); @@ -6274,16 +6606,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceMovementDirection) if (!mobj || ((flags & FMDF_NOPITCH) && (flags & FMDF_NOANGLE))) { ACTION_SET_RESULT(false); - return; + return numret; } - + //Don't bother calculating this if we don't have any horizontal movement. if (!(flags & FMDF_NOANGLE) && (mobj->velx != 0 || mobj->vely != 0)) { - angle_t current = mobj->angle; + angle_t current = mobj->angle; const angle_t angle = R_PointToAngle2(0, 0, mobj->velx, mobj->vely); //Done because using anglelimit directly causes a signed/unsigned mismatch. - const angle_t limit = anglelimit; + const angle_t limit = anglelimit; //Code borrowed from A_Face*. if (limit > 0 && (absangle(current - angle) > limit)) @@ -6308,7 +6640,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceMovementDirection) } else mobj->SetAngle(angle + ANGLE_180 + offset, !!(flags & FMDF_INTERPOLATE)); - } else mobj->SetAngle(angle + offset, !!(flags & FMDF_INTERPOLATE)); @@ -6327,11 +6658,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceMovementDirection) // of a better way to convert from angle_t to fixed_t properly so I // used this instead. fixed_t plimit = fixed_t(pitchlimit); - + if (abs(current - pitch) > plimit) { fixed_t max = 0; - + if (current > pitch) { max = MIN(plimit, (current - pitch)); @@ -6348,12 +6679,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceMovementDirection) { mobj->SetPitch(pitch, !!(flags & FMDF_INTERPOLATE)); } - + } else { mobj->SetPitch(pitch, !!(flags & FMDF_INTERPOLATE)); } } -} - + return numret; +} \ No newline at end of file diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index f9a282c768..8581ca8b2c 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -46,7 +46,6 @@ static TArray properties; static TArray AFTable; -static TArray variables; //========================================================================== // @@ -376,13 +375,13 @@ static FFlagDef PowerSpeedFlagDefs[] = DEFINE_FLAG(PSF, NOTRAIL, APowerSpeed, SpeedFlags), }; -static const struct FFlagList { const PClass *Type; FFlagDef *Defs; int NumDefs; } FlagLists[] = +static const struct FFlagList { const PClass * const *Type; FFlagDef *Defs; int NumDefs; } FlagLists[] = { - { RUNTIME_CLASS(AActor), ActorFlagDefs, countof(ActorFlagDefs) }, - { RUNTIME_CLASS(AInventory), InventoryFlagDefs, countof(InventoryFlagDefs) }, - { RUNTIME_CLASS(AWeapon), WeaponFlagDefs, countof(WeaponFlagDefs) }, - { RUNTIME_CLASS(APlayerPawn), PlayerPawnFlagDefs, countof(PlayerPawnFlagDefs) }, - { RUNTIME_CLASS(APowerSpeed), PowerSpeedFlagDefs, countof(PowerSpeedFlagDefs) }, + { &RUNTIME_CLASS_CASTLESS(AActor), ActorFlagDefs, countof(ActorFlagDefs) }, + { &RUNTIME_CLASS_CASTLESS(AInventory), InventoryFlagDefs, countof(InventoryFlagDefs) }, + { &RUNTIME_CLASS_CASTLESS(AWeapon), WeaponFlagDefs, countof(WeaponFlagDefs) }, + { &RUNTIME_CLASS_CASTLESS(APlayerPawn), PlayerPawnFlagDefs, countof(PlayerPawnFlagDefs) }, + { &RUNTIME_CLASS_CASTLESS(APowerSpeed), PowerSpeedFlagDefs, countof(PowerSpeedFlagDefs) }, }; #define NUM_FLAG_LISTS (countof(FlagLists)) @@ -430,7 +429,7 @@ FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2) { // Search all lists for (i = 0; i < NUM_FLAG_LISTS; ++i) { - if (type->IsDescendantOf (FlagLists[i].Type)) + if (type->IsDescendantOf (*FlagLists[i].Type)) { def = FindFlag (FlagLists[i].Defs, FlagLists[i].NumDefs, part1); if (def != NULL) @@ -444,9 +443,9 @@ FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2) { // Search just the named list for (i = 0; i < NUM_FLAG_LISTS; ++i) { - if (stricmp (FlagLists[i].Type->TypeName.GetChars(), part1) == 0) + if (stricmp ((*FlagLists[i].Type)->TypeName.GetChars(), part1) == 0) { - if (type->IsDescendantOf (FlagLists[i].Type)) + if (type->IsDescendantOf (*FlagLists[i].Type)) { return FindFlag (FlagLists[i].Defs, FlagLists[i].NumDefs, part2); } @@ -469,7 +468,7 @@ FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2) const char *GetFlagName(unsigned int flagnum, int flagoffset) { - for(unsigned i = 0; i < countof(ActorFlagDefs); i++) + for(size_t i = 0; i < countof(ActorFlagDefs); i++) { if (ActorFlagDefs[i].flagbit == flagnum && ActorFlagDefs[i].structoffset == flagoffset) { @@ -540,55 +539,15 @@ AFuncDesc *FindFunction(const char * string) } -//========================================================================== -// -// Find a variable by name using a binary search -// -//========================================================================== - -FVariableInfo *FindVariable(const char * string, const PClass *cls) -{ - int min = 0, max = variables.Size()-1; - - while (min <= max) - { - int mid = (min + max) / 2; - int lexval; - - if (cls < variables[mid]->owner) lexval = -1; - else if (cls > variables[mid]->owner) lexval = 1; - else lexval = stricmp (string, variables[mid]->name); - - if (lexval == 0) - { - return variables[mid]; - } - else if (lexval > 0) - { - min = mid + 1; - } - else - { - max = mid - 1; - } - } - return NULL; -} - - //========================================================================== // // Find an action function in AActor's table // //========================================================================== -PSymbolActionFunction *FindGlobalActionFunction(const char *name) +PFunction *FindGlobalActionFunction(const char *name) { - PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol(name, false); - if (sym != NULL && sym->SymbolType == SYM_ActionFunction) - return static_cast(sym); - else - return NULL; + return dyn_cast(RUNTIME_CLASS(AActor)->Symbols.FindSymbol(name, false)); } @@ -613,15 +572,6 @@ static int STACK_ARGS funccmp(const void * a, const void * b) return stricmp( ((AFuncDesc*)a)->Name, ((AFuncDesc*)b)->Name); } -static int STACK_ARGS varcmp(const void * a, const void * b) -{ - FVariableInfo *A = *(FVariableInfo**)a; - FVariableInfo *B = *(FVariableInfo**)b; - if (A->owner < B->owner) return -1; - if (A->owner > B->owner) return 1; - return stricmp(A->name, B->name); -} - //========================================================================== // // Initialization @@ -650,29 +600,55 @@ void InitThingdef() } // Create a sorted list of native action functions + AFTable.Clear(); if (AFTable.Size() == 0) { FAutoSegIterator probe(ARegHead, ARegTail); while (*++probe != NULL) { - AFTable.Push(*(AFuncDesc *)*probe); + AFuncDesc *afunc = (AFuncDesc *)*probe; + assert(afunc->VMPointer != NULL); + *(afunc->VMPointer) = new VMNativeFunction(afunc->Function, afunc->Name); + AFTable.Push(*afunc); } AFTable.ShrinkToFit(); qsort(&AFTable[0], AFTable.Size(), sizeof(AFTable[0]), funccmp); } - // Create a sorted list of native variables - if (variables.Size() == 0) - { - FAutoSegIterator probe(MRegHead, MRegTail); - - while (*++probe != NULL) - { - variables.Push((FVariableInfo *)*probe); - } - variables.ShrinkToFit(); - qsort(&variables[0], variables.Size(), sizeof(variables[0]), varcmp); - } + // Define some member variables we feel like exposing to the user + PSymbolTable &symt = RUNTIME_CLASS(AActor)->Symbols; + PType *array5 = NewArray(TypeSInt32, 5); + symt.AddSymbol(new PField(NAME_Alpha, TypeFixed, VARF_Native, myoffsetof(AActor,alpha))); + symt.AddSymbol(new PField(NAME_Angle, TypeAngle, VARF_Native, myoffsetof(AActor,angle))); + symt.AddSymbol(new PField(NAME_Args, array5, VARF_Native, myoffsetof(AActor,args))); + symt.AddSymbol(new PField(NAME_CeilingZ, TypeFixed, VARF_Native, myoffsetof(AActor,ceilingz))); + symt.AddSymbol(new PField(NAME_FloorZ, TypeFixed, VARF_Native, myoffsetof(AActor,floorz))); + symt.AddSymbol(new PField(NAME_Health, TypeSInt32, VARF_Native, myoffsetof(AActor,health))); + symt.AddSymbol(new PField(NAME_Mass, TypeSInt32, VARF_Native, myoffsetof(AActor,Mass))); + symt.AddSymbol(new PField(NAME_Pitch, TypeAngle, VARF_Native, myoffsetof(AActor,pitch))); + symt.AddSymbol(new PField(NAME_Roll, TypeAngle, VARF_Native, myoffsetof(AActor,roll))); + symt.AddSymbol(new PField(NAME_Special, TypeSInt32, VARF_Native, myoffsetof(AActor,special))); + symt.AddSymbol(new PField(NAME_TID, TypeSInt32, VARF_Native, myoffsetof(AActor,tid))); + symt.AddSymbol(new PField(NAME_TIDtoHate, TypeSInt32, VARF_Native, myoffsetof(AActor,TIDtoHate))); + symt.AddSymbol(new PField(NAME_WaterLevel, TypeSInt32, VARF_Native, myoffsetof(AActor,waterlevel))); + symt.AddSymbol(new PField(NAME_X, TypeFixed, VARF_Native, myoffsetof(AActor,__pos.x))); // must remain read-only! + symt.AddSymbol(new PField(NAME_Y, TypeFixed, VARF_Native, myoffsetof(AActor,__pos.y))); // must remain read-only! + symt.AddSymbol(new PField(NAME_Z, TypeFixed, VARF_Native, myoffsetof(AActor,__pos.z))); // must remain read-only! + symt.AddSymbol(new PField(NAME_VelX, TypeFixed, VARF_Native, myoffsetof(AActor,velx))); + symt.AddSymbol(new PField(NAME_VelY, TypeFixed, VARF_Native, myoffsetof(AActor,vely))); + symt.AddSymbol(new PField(NAME_VelZ, TypeFixed, VARF_Native, myoffsetof(AActor,velz))); + symt.AddSymbol(new PField(NAME_MomX, TypeFixed, VARF_Native, myoffsetof(AActor,velx))); + symt.AddSymbol(new PField(NAME_MomY, TypeFixed, VARF_Native, myoffsetof(AActor,vely))); + symt.AddSymbol(new PField(NAME_MomZ, TypeFixed, VARF_Native, myoffsetof(AActor,velz))); + symt.AddSymbol(new PField(NAME_ScaleX, TypeFixed, VARF_Native, myoffsetof(AActor,scaleX))); + symt.AddSymbol(new PField(NAME_ScaleY, TypeFixed, VARF_Native, myoffsetof(AActor,scaleY))); + symt.AddSymbol(new PField(NAME_Score, TypeSInt32, VARF_Native, myoffsetof(AActor,Score))); + symt.AddSymbol(new PField(NAME_Accuracy, TypeSInt32, VARF_Native, myoffsetof(AActor,accuracy))); + symt.AddSymbol(new PField(NAME_Stamina, TypeSInt32, VARF_Native, myoffsetof(AActor,stamina))); + symt.AddSymbol(new PField(NAME_Height, TypeFixed, VARF_Native, myoffsetof(AActor,height))); + symt.AddSymbol(new PField(NAME_Radius, TypeFixed, VARF_Native, myoffsetof(AActor,radius))); + symt.AddSymbol(new PField(NAME_ReactionTime,TypeSInt32, VARF_Native, myoffsetof(AActor,reactiontime))); + symt.AddSymbol(new PField(NAME_MeleeRange, TypeFixed, VARF_Native, myoffsetof(AActor,meleerange))); + symt.AddSymbol(new PField(NAME_Speed, TypeFixed, VARF_Native, myoffsetof(AActor,Speed))); } - diff --git a/src/thingdef/thingdef_exp.cpp b/src/thingdef/thingdef_exp.cpp index 5422d1a7c1..e198ec20b8 100644 --- a/src/thingdef/thingdef_exp.cpp +++ b/src/thingdef/thingdef_exp.cpp @@ -57,34 +57,32 @@ FRandom pr_exrandom ("EX_Random"); // [GRB] Parses an expression and stores it into Expression array // -static FxExpression *ParseExpressionM (FScanner &sc, const PClass *cls); -static FxExpression *ParseExpressionL (FScanner &sc, const PClass *cls); -static FxExpression *ParseExpressionK (FScanner &sc, const PClass *cls); -static FxExpression *ParseExpressionJ (FScanner &sc, const PClass *cls); -static FxExpression *ParseExpressionI (FScanner &sc, const PClass *cls); -static FxExpression *ParseExpressionH (FScanner &sc, const PClass *cls); -static FxExpression *ParseExpressionG (FScanner &sc, const PClass *cls); -static FxExpression *ParseExpressionF (FScanner &sc, const PClass *cls); -static FxExpression *ParseExpressionE (FScanner &sc, const PClass *cls); -static FxExpression *ParseExpressionD (FScanner &sc, const PClass *cls); -static FxExpression *ParseExpressionC (FScanner &sc, const PClass *cls); -static FxExpression *ParseExpressionB (FScanner &sc, const PClass *cls); -static FxExpression *ParseExpressionA (FScanner &sc, const PClass *cls); -static FxExpression *ParseExpression0 (FScanner &sc, const PClass *cls); +static FxExpression *ParseExpressionM (FScanner &sc, PClassActor *cls); +static FxExpression *ParseExpressionL (FScanner &sc, PClassActor *cls); +static FxExpression *ParseExpressionK (FScanner &sc, PClassActor *cls); +static FxExpression *ParseExpressionJ (FScanner &sc, PClassActor *cls); +static FxExpression *ParseExpressionI (FScanner &sc, PClassActor *cls); +static FxExpression *ParseExpressionH (FScanner &sc, PClassActor *cls); +static FxExpression *ParseExpressionG (FScanner &sc, PClassActor *cls); +static FxExpression *ParseExpressionF (FScanner &sc, PClassActor *cls); +static FxExpression *ParseExpressionE (FScanner &sc, PClassActor *cls); +static FxExpression *ParseExpressionD (FScanner &sc, PClassActor *cls); +static FxExpression *ParseExpressionC (FScanner &sc, PClassActor *cls); +static FxExpression *ParseExpressionB (FScanner &sc, PClassActor *cls); +static FxExpression *ParseExpressionA (FScanner &sc, PClassActor *cls); +static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls); -FxExpression *ParseExpression (FScanner &sc, PClass *cls) +FxExpression *ParseExpression (FScanner &sc, PClassActor *cls) { FxExpression *data = ParseExpressionM (sc, cls); - FCompileContext ctx; - ctx.cls = cls; - ctx.lax = true; + FCompileContext ctx(cls); data = data->Resolve(ctx); return data; } -static FxExpression *ParseExpressionM (FScanner &sc, const PClass *cls) +static FxExpression *ParseExpressionM (FScanner &sc, PClassActor *cls) { FxExpression *condition = ParseExpressionL (sc, cls); @@ -101,7 +99,7 @@ static FxExpression *ParseExpressionM (FScanner &sc, const PClass *cls) } } -static FxExpression *ParseExpressionL (FScanner &sc, const PClass *cls) +static FxExpression *ParseExpressionL (FScanner &sc, PClassActor *cls) { FxExpression *tmp = ParseExpressionK (sc, cls); @@ -113,7 +111,7 @@ static FxExpression *ParseExpressionL (FScanner &sc, const PClass *cls) return tmp; } -static FxExpression *ParseExpressionK (FScanner &sc, const PClass *cls) +static FxExpression *ParseExpressionK (FScanner &sc, PClassActor *cls) { FxExpression *tmp = ParseExpressionJ (sc, cls); @@ -125,7 +123,7 @@ static FxExpression *ParseExpressionK (FScanner &sc, const PClass *cls) return tmp; } -static FxExpression *ParseExpressionJ (FScanner &sc, const PClass *cls) +static FxExpression *ParseExpressionJ (FScanner &sc, PClassActor *cls) { FxExpression *tmp = ParseExpressionI (sc, cls); @@ -137,7 +135,7 @@ static FxExpression *ParseExpressionJ (FScanner &sc, const PClass *cls) return tmp; } -static FxExpression *ParseExpressionI (FScanner &sc, const PClass *cls) +static FxExpression *ParseExpressionI (FScanner &sc, PClassActor *cls) { FxExpression *tmp = ParseExpressionH (sc, cls); @@ -149,7 +147,7 @@ static FxExpression *ParseExpressionI (FScanner &sc, const PClass *cls) return tmp; } -static FxExpression *ParseExpressionH (FScanner &sc, const PClass *cls) +static FxExpression *ParseExpressionH (FScanner &sc, PClassActor *cls) { FxExpression *tmp = ParseExpressionG (sc, cls); @@ -161,7 +159,7 @@ static FxExpression *ParseExpressionH (FScanner &sc, const PClass *cls) return tmp; } -static FxExpression *ParseExpressionG (FScanner &sc, const PClass *cls) +static FxExpression *ParseExpressionG (FScanner &sc, PClassActor *cls) { FxExpression *tmp = ParseExpressionF (sc, cls); @@ -175,7 +173,7 @@ static FxExpression *ParseExpressionG (FScanner &sc, const PClass *cls) return tmp; } -static FxExpression *ParseExpressionF (FScanner &sc, const PClass *cls) +static FxExpression *ParseExpressionF (FScanner &sc, PClassActor *cls) { FxExpression *tmp = ParseExpressionE (sc, cls); @@ -189,7 +187,7 @@ static FxExpression *ParseExpressionF (FScanner &sc, const PClass *cls) return tmp; } -static FxExpression *ParseExpressionE (FScanner &sc, const PClass *cls) +static FxExpression *ParseExpressionE (FScanner &sc, PClassActor *cls) { FxExpression *tmp = ParseExpressionD (sc, cls); @@ -203,7 +201,7 @@ static FxExpression *ParseExpressionE (FScanner &sc, const PClass *cls) return tmp; } -static FxExpression *ParseExpressionD (FScanner &sc, const PClass *cls) +static FxExpression *ParseExpressionD (FScanner &sc, PClassActor *cls) { FxExpression *tmp = ParseExpressionC (sc, cls); @@ -217,7 +215,7 @@ static FxExpression *ParseExpressionD (FScanner &sc, const PClass *cls) return tmp; } -static FxExpression *ParseExpressionC (FScanner &sc, const PClass *cls) +static FxExpression *ParseExpressionC (FScanner &sc, PClassActor *cls) { FxExpression *tmp = ParseExpressionB (sc, cls); @@ -231,7 +229,7 @@ static FxExpression *ParseExpressionC (FScanner &sc, const PClass *cls) return tmp; } -static FxExpression *ParseExpressionB (FScanner &sc, const PClass *cls) +static FxExpression *ParseExpressionB (FScanner &sc, PClassActor *cls) { sc.GetToken(); switch(sc.TokenType) @@ -260,7 +258,7 @@ static FxExpression *ParseExpressionB (FScanner &sc, const PClass *cls) // //========================================================================== -static FxExpression *ParseExpressionA (FScanner &sc, const PClass *cls) +static FxExpression *ParseExpressionA (FScanner &sc, PClassActor *cls) { FxExpression *base_expr = ParseExpression0 (sc, cls); @@ -311,7 +309,7 @@ static FxExpression *ParseExpressionA (FScanner &sc, const PClass *cls) -static FxExpression *ParseExpression0 (FScanner &sc, const PClass *cls) +static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) { FScriptPosition scpos(sc); if (sc.CheckToken('(')) @@ -462,16 +460,21 @@ static FxExpression *ParseExpression0 (FScanner &sc, const PClass *cls) FName identifier = FName(sc.String); if (sc.CheckToken('(')) { - FArgumentList *args = NULL; + FArgumentList *args = new FArgumentList; + PFunction *func = dyn_cast(cls->Symbols.FindSymbol(identifier, true)); try { - if (!sc.CheckToken(')')) + if (func != NULL) + { + sc.UnGet(); + ParseFunctionParameters(sc, cls, *args, func, "", NULL); + return new FxVMFunctionCall(func, args, sc); + } + else if (!sc.CheckToken(')')) { - args = new FArgumentList; do { args->Push(ParseExpressionM (sc, cls)); - } while (sc.CheckToken(',')); sc.MustGetToken(')'); diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 40f5d4dc76..d1f7e75da3 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -42,13 +42,14 @@ #include "m_random.h" + #define CHECKRESOLVED() if (isresolved) return this; isresolved=true; #define SAFE_DELETE(p) if (p!=NULL) { delete p; p=NULL; } #define RESOLVE(p,c) if (p!=NULL) p = p->Resolve(c) #define ABORT(p) if (!(p)) { delete this; return NULL; } #define SAFE_RESOLVE(p,c) RESOLVE(p,c); ABORT(p) -extern PSymbolTable GlobalSymbols; +class VMFunctionBuilder; //========================================================================== // @@ -58,20 +59,16 @@ extern PSymbolTable GlobalSymbols; struct FCompileContext { - const PClass *cls; - bool lax; - bool isconst; + PClassActor *cls; - FCompileContext(const PClass *_cls = NULL, bool _lax = false, bool _isconst = false) + FCompileContext(PClassActor *_cls = NULL) { cls = _cls; - lax = _lax; - isconst = _isconst; } PSymbol *FindInClass(FName identifier) { - return cls? cls->Symbols.FindSymbol(identifier, true) : NULL; + return cls ? cls->Symbols.FindSymbol(identifier, true) : NULL; } PSymbol *FindGlobal(FName identifier) { @@ -95,6 +92,57 @@ struct ExpVal void *pointer; }; + ExpVal() + { + Type = VAL_Int; + Int = 0; + } + + ~ExpVal() + { + if (Type == VAL_String) + { + ((FString *)&pointer)->~FString(); + } + } + + ExpVal(const FString &str) + { + Type = VAL_String; + ::new(&pointer) FString(str); + } + + ExpVal(const ExpVal &o) + { + Type = o.Type; + if (o.Type == VAL_String) + { + ::new(&pointer) FString(*(FString *)&o.pointer); + } + else + { + memcpy(&Float, &o.Float, 8); + } + } + + ExpVal &operator=(const ExpVal &o) + { + if (Type == VAL_String) + { + ((FString *)&pointer)->~FString(); + } + Type = o.Type; + if (o.Type == VAL_String) + { + ::new(&pointer) FString(*(FString *)&o.pointer); + } + else + { + memcpy(&Float, &o.Float, 8); + } + return *this; + } + int GetInt() const { return Type == VAL_Int? Int : Type == VAL_Float? int(Float) : 0; @@ -105,43 +153,33 @@ struct ExpVal return Type == VAL_Int? double(Int) : Type == VAL_Float? Float : 0; } + const FString GetString() const + { + return Type == VAL_String ? *(FString *)&pointer : Type == VAL_Name ? FString(FName(ENamedName(Int)).GetChars()) : ""; + } + bool GetBool() const { return (Type == VAL_Int || Type == VAL_Sound) ? !!Int : Type == VAL_Float? Float!=0. : false; } - template T *GetPointer() const - { - return Type == VAL_Object || Type == VAL_Pointer? (T*)pointer : NULL; - } - - FSoundID GetSoundID() const - { - return Type == VAL_Sound? Int : 0; - } - - int GetColor() const - { - return Type == VAL_Color? Int : 0; - } - FName GetName() const { return Type == VAL_Name? ENamedName(Int) : NAME_None; } - - FState *GetState() const - { - return Type == VAL_State? (FState*)pointer : NULL; - } - - const PClass *GetClass() const - { - return Type == VAL_Class? (const PClass *)pointer : NULL; - } - }; +struct ExpEmit +{ + ExpEmit() : RegNum(0), RegType(REGT_NIL), Konst(false), Fixed(false) {} + ExpEmit(int reg, int type) : RegNum(reg), RegType(type), Konst(false), Fixed(false) {} + ExpEmit(int reg, int type, bool konst) : RegNum(reg), RegType(type), Konst(konst), Fixed(false) {} + ExpEmit(VMFunctionBuilder *build, int type); + void Free(VMFunctionBuilder *build); + void Reuse(VMFunctionBuilder *build); + + BYTE RegNum, RegType, Konst:1, Fixed:1; +}; //========================================================================== // @@ -163,16 +201,28 @@ public: virtual FxExpression *Resolve(FCompileContext &ctx); FxExpression *ResolveAsBoolean(FCompileContext &ctx); - virtual ExpVal EvalExpression (AActor *self); virtual bool isConstant() const; virtual void RequestAddress(); + virtual ExpEmit Emit(VMFunctionBuilder *build); + FScriptPosition ScriptPosition; FExpressionType ValueType; bool isresolved; }; +class FxParameter : public FxExpression +{ + FxExpression *Operand; + +public: + FxParameter(FxExpression*); + ~FxParameter(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxIdentifier @@ -262,6 +312,13 @@ public: isresolved = true; } + FxConstant(const FString &str, const FScriptPosition &pos) : FxExpression(pos) + { + ValueType = VAL_String; + value = ExpVal(str); + isresolved = true; + } + FxConstant(ExpVal cv, const FScriptPosition &pos) : FxExpression(pos) { value = cv; @@ -290,7 +347,12 @@ public: { return true; } - ExpVal EvalExpression (AActor *self); + + ExpVal GetValue() const + { + return value; + } + ExpEmit Emit(VMFunctionBuilder *build); }; @@ -310,16 +372,9 @@ public: ~FxIntCast(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; - -//========================================================================== -// -// -// -//========================================================================== - class FxFloatCast : public FxExpression { FxExpression *basex; @@ -330,9 +385,10 @@ public: ~FxFloatCast(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; + //========================================================================== // // FxSign @@ -347,6 +403,7 @@ public: FxPlusSign(FxExpression*); ~FxPlusSign(); FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -363,7 +420,7 @@ public: FxMinusSign(FxExpression*); ~FxMinusSign(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -380,7 +437,7 @@ public: FxUnaryNotBitwise(FxExpression*); ~FxUnaryNotBitwise(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -397,7 +454,7 @@ public: FxUnaryNotBoolean(FxExpression*); ~FxUnaryNotBoolean(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -416,6 +473,7 @@ public: FxBinary(int, FxExpression*, FxExpression*); ~FxBinary(); bool ResolveLR(FCompileContext& ctx, bool castnumeric); + void Promote(FCompileContext &ctx); }; //========================================================================== @@ -430,7 +488,7 @@ public: FxAddSub(int, FxExpression*, FxExpression*); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -445,7 +503,7 @@ public: FxMulDiv(int, FxExpression*, FxExpression*); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -460,7 +518,7 @@ public: FxCompareRel(int, FxExpression*, FxExpression*); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -475,7 +533,7 @@ public: FxCompareEq(int, FxExpression*, FxExpression*); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -490,7 +548,7 @@ public: FxBinaryInt(int, FxExpression*, FxExpression*); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -510,7 +568,7 @@ public: ~FxBinaryLogical(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -530,7 +588,7 @@ public: ~FxConditional(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -549,7 +607,7 @@ public: ~FxAbs(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -561,7 +619,7 @@ public: class FxRandom : public FxExpression { protected: - FRandom * rng; + FRandom *rng; FxExpression *min, *max; public: @@ -570,7 +628,7 @@ public: ~FxRandom(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -582,16 +640,16 @@ public: class FxRandomPick : public FxExpression { protected: - FRandom * rng; - TDeletingArray min; + FRandom *rng; + TDeletingArray choices; public: - FxRandomPick(FRandom *, TArray mi, bool floaty, const FScriptPosition &pos); + FxRandomPick(FRandom *, TArray &expr, bool floaty, const FScriptPosition &pos); ~FxRandomPick(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression(AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -604,7 +662,7 @@ class FxFRandom : public FxRandom { public: FxFRandom(FRandom *, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos); - ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -624,28 +682,10 @@ public: ~FxRandom2(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; -//========================================================================== -// -// FxGlobalVariable -// -//========================================================================== - -class FxGlobalVariable : public FxExpression -{ -public: - PSymbolVariable *var; - bool AddressRequested; - - FxGlobalVariable(PSymbolVariable*, const FScriptPosition&); - FxExpression *Resolve(FCompileContext&); - void RequestAddress(); - ExpVal EvalExpression (AActor *self); -}; - //========================================================================== // // FxClassMember @@ -656,14 +696,14 @@ class FxClassMember : public FxExpression { public: FxExpression *classx; - PSymbolVariable *membervar; + PField *membervar; bool AddressRequested; - FxClassMember(FxExpression*, PSymbolVariable*, const FScriptPosition&); + FxClassMember(FxExpression*, PField*, const FScriptPosition&); ~FxClassMember(); FxExpression *Resolve(FCompileContext&); void RequestAddress(); - ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -677,7 +717,21 @@ class FxSelf : public FxExpression public: FxSelf(const FScriptPosition&); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); +}; + +//========================================================================== +// +// FxDamage +// +//========================================================================== + +class FxDamage : public FxExpression +{ +public: + FxDamage(const FScriptPosition&); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -697,7 +751,7 @@ public: ~FxArrayElement(); FxExpression *Resolve(FCompileContext&); //void RequestAddress(); - ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; @@ -740,7 +794,7 @@ public: FxActionSpecialCall(FxExpression *self, int special, FArgumentList *args, const FScriptPosition &pos); ~FxActionSpecialCall(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -751,41 +805,92 @@ public: class FxGlobalFunctionCall : public FxExpression { -public: - typedef FxExpression *(*Creator)(FName, FArgumentList *, const FScriptPosition &); - struct CreatorAdder - { - CreatorAdder(FName methodname, Creator creator) - { - FxGlobalFunctionCall::AddCreator(methodname, creator); - } - }; - - static void AddCreator(FName methodname, Creator creator); - static FxExpression *StaticCreate(FName methodname, FArgumentList *args, const FScriptPosition &pos); - -protected: FName Name; FArgumentList *ArgList; +public: + FxGlobalFunctionCall(FName fname, FArgumentList *args, const FScriptPosition &pos); ~FxGlobalFunctionCall(); - - FxExpression *ResolveArgs(FCompileContext &, unsigned min, unsigned max, bool numeric); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); }; -#define GLOBALFUNCTION_DEFINE(CLASS) \ -FxGlobalFunctionCall_##CLASS(FName methodname, FArgumentList *args, const FScriptPosition &pos) \ -: FxGlobalFunctionCall(methodname, args, pos) {} \ -static FxExpression *StaticCreate(FName methodname, FArgumentList *args, const FScriptPosition &pos) \ - {return new FxGlobalFunctionCall_##CLASS(methodname, args, pos);} +//========================================================================== +// +// FxTailable +// +// An expression that can produce a tail call +// +//========================================================================== -#define GLOBALFUNCTION_ADDER(CLASS) GLOBALFUNCTION_ADDER_NAMED(CLASS, CLASS) +class FxTailable : public FxExpression +{ +public: + FxTailable(const FScriptPosition &pos) : FxExpression(pos) {} + virtual ExpEmit Emit(VMFunctionBuilder *build, bool tailcall) = 0; + ExpEmit Emit(VMFunctionBuilder *build); + virtual VMFunction *GetDirectFunction(); +}; -#define GLOBALFUNCTION_ADDER_NAMED(CLASS,NAME) \ -static FxGlobalFunctionCall::CreatorAdder FxGlobalFunctionCall_##NAME##Adder \ -(NAME_##NAME, FxGlobalFunctionCall_##CLASS::StaticCreate) +//========================================================================== +// +// FxVMFunctionCall +// +//========================================================================== +class FxVMFunctionCall : public FxTailable +{ + PFunction *Function; + FArgumentList *ArgList; + PType *ReturnType; + +public: + FxVMFunctionCall(PFunction *func, FArgumentList *args, const FScriptPosition &pos); + ~FxVMFunctionCall(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build, bool tailcall); + unsigned GetArgCount() { return ArgList == NULL ? 0 : ArgList->Size(); } + VMFunction *GetVMFunction() { return Function->Variants[0].Implementation; } + VMFunction *GetDirectFunction(); +}; + +//========================================================================== +// +// FxSequence +// +//========================================================================== + +class FxSequence : public FxTailable +{ + TDeletingArray Expressions; + +public: + FxSequence(const FScriptPosition &pos) : FxTailable(pos) {} + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build, bool tailcall); + void Add(FxTailable *expr) { if (expr != NULL) Expressions.Push(expr); } + VMFunction *GetDirectFunction(); +}; + +//========================================================================== +// +// FxIfStatement +// +//========================================================================== + +class FxIfStatement : public FxTailable +{ + FxExpression *Condition; + FxTailable *WhenTrue; + FxTailable *WhenFalse; + +public: + FxIfStatement(FxExpression *cond, FxTailable *true_part, FxTailable *false_part, const FScriptPosition &pos); + ~FxIfStatement(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build, bool tailcall); +}; //========================================================================== // @@ -803,7 +908,7 @@ public: FxClassTypeCast(const PClass *dtype, FxExpression *x); ~FxClassTypeCast(); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -833,18 +938,40 @@ public: class FxMultiNameState : public FxExpression { - const PClass *scope; + PClassActor *scope; TArray names; public: FxMultiNameState(const char *statestring, const FScriptPosition &pos); FxExpression *Resolve(FCompileContext&); - ExpVal EvalExpression (AActor *self); + ExpEmit Emit(VMFunctionBuilder *build); +}; + +//========================================================================== +// +// +// +//========================================================================== + +class FxDamageValue : public FxExpression +{ + FxExpression *val; + bool Calculated; + VMScriptFunction *MyFunction; + +public: + + FxDamageValue(FxExpression *v, bool calc); + ~FxDamageValue(); + FxExpression *Resolve(FCompileContext&); + + ExpEmit Emit(VMFunctionBuilder *build); + VMScriptFunction *GetFunction() const { return MyFunction; } + void SetFunction(VMScriptFunction *func) { MyFunction = func; } }; - -FxExpression *ParseExpression (FScanner &sc, PClass *cls); +FxExpression *ParseExpression (FScanner &sc, PClassActor *cls); #endif diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 6267ae6d9b..a877a4e1ab 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -37,6 +37,7 @@ ** */ +#include #include "actor.h" #include "sc_man.h" #include "tarray.h" @@ -50,197 +51,51 @@ #include "doomstat.h" #include "thingdef_exp.h" #include "m_fixed.h" +#include "vmbuilder.h" -int testglobalvar = 1337; // just for having one global variable to test with -DEFINE_GLOBAL_VARIABLE(testglobalvar) - -// Accessible actor member variables -DEFINE_MEMBER_VARIABLE(alpha, AActor) -DEFINE_MEMBER_VARIABLE(angle, AActor) -DEFINE_MEMBER_VARIABLE(args, AActor) -DEFINE_MEMBER_VARIABLE(ceilingz, AActor) -DEFINE_MEMBER_VARIABLE(floorz, AActor) -DEFINE_MEMBER_VARIABLE(health, AActor) -DEFINE_MEMBER_VARIABLE(Mass, AActor) -DEFINE_MEMBER_VARIABLE(pitch, AActor) -DEFINE_MEMBER_VARIABLE(special, AActor) -DEFINE_MEMBER_VARIABLE(special1, AActor) -DEFINE_MEMBER_VARIABLE(special2, AActor) -DEFINE_MEMBER_VARIABLE(tid, AActor) -DEFINE_MEMBER_VARIABLE(TIDtoHate, AActor) -DEFINE_MEMBER_VARIABLE(waterlevel, AActor) -DEFINE_MEMBER_VARIABLE_ALIAS(x, __pos.x, AActor) -DEFINE_MEMBER_VARIABLE_ALIAS(y, __pos.y, AActor) -DEFINE_MEMBER_VARIABLE_ALIAS(z, __pos.z, AActor) -DEFINE_MEMBER_VARIABLE(velx, AActor) -DEFINE_MEMBER_VARIABLE(vely, AActor) -DEFINE_MEMBER_VARIABLE(velz, AActor) -DEFINE_MEMBER_VARIABLE_ALIAS(momx, velx, AActor) -DEFINE_MEMBER_VARIABLE_ALIAS(momy, vely, AActor) -DEFINE_MEMBER_VARIABLE_ALIAS(momz, velz, AActor) -DEFINE_MEMBER_VARIABLE(scaleX, AActor) -DEFINE_MEMBER_VARIABLE(scaleY, AActor) -DEFINE_MEMBER_VARIABLE(Damage, AActor) -DEFINE_MEMBER_VARIABLE(Score, AActor) -DEFINE_MEMBER_VARIABLE(accuracy, AActor) -DEFINE_MEMBER_VARIABLE(stamina, AActor) -DEFINE_MEMBER_VARIABLE(height, AActor) -DEFINE_MEMBER_VARIABLE(radius, AActor) -DEFINE_MEMBER_VARIABLE(reactiontime, AActor) -DEFINE_MEMBER_VARIABLE(meleerange, AActor) -DEFINE_MEMBER_VARIABLE(Speed, AActor) -DEFINE_MEMBER_VARIABLE(roll, AActor) - - -//========================================================================== -// -// EvalExpression -// [GRB] Evaluates previously stored expression -// -//========================================================================== - - -int EvalExpressionI (DWORD xi, AActor *self) +ExpEmit::ExpEmit(VMFunctionBuilder *build, int type) +: RegNum(build->Registers[type].Get(1)), RegType(type), Konst(false), Fixed(false) { - FxExpression *x = StateParams.Get(xi); - if (x == NULL) return 0; - - return x->EvalExpression (self).GetInt(); } -int EvalExpressionCol (DWORD xi, AActor *self) +void ExpEmit::Free(VMFunctionBuilder *build) { - FxExpression *x = StateParams.Get(xi); - if (x == NULL) return 0; - - return x->EvalExpression (self).GetColor(); -} - -FSoundID EvalExpressionSnd (DWORD xi, AActor *self) -{ - FxExpression *x = StateParams.Get(xi); - if (x == NULL) return 0; - - return x->EvalExpression (self).GetSoundID(); -} - -double EvalExpressionF (DWORD xi, AActor *self) -{ - FxExpression *x = StateParams.Get(xi); - if (x == NULL) return 0; - - return x->EvalExpression (self).GetFloat(); -} - -fixed_t EvalExpressionFix (DWORD xi, AActor *self) -{ - FxExpression *x = StateParams.Get(xi); - if (x == NULL) return 0; - - ExpVal val = x->EvalExpression (self); - - switch (val.Type) + if (!Fixed && !Konst && RegType <= REGT_TYPE) { - default: - return 0; - case VAL_Int: - return val.Int << FRACBITS; - case VAL_Float: - return fixed_t(val.Float*FRACUNIT); + build->Registers[RegType].Return(RegNum, 1); } } -FName EvalExpressionName (DWORD xi, AActor *self) +void ExpEmit::Reuse(VMFunctionBuilder *build) { - FxExpression *x = StateParams.Get(xi); - if (x == NULL) return 0; - - return x->EvalExpression (self).GetName(); -} - -const PClass * EvalExpressionClass (DWORD xi, AActor *self) -{ - FxExpression *x = StateParams.Get(xi); - if (x == NULL) return 0; - - return x->EvalExpression (self).GetClass(); -} - -FState *EvalExpressionState (DWORD xi, AActor *self) -{ - FxExpression *x = StateParams.Get(xi); - if (x == NULL) return 0; - - return x->EvalExpression (self).GetState(); -} - - -//========================================================================== -// -// -// -//========================================================================== - -static ExpVal GetVariableValue (void *address, FExpressionType &type) -{ - // NOTE: This cannot access native variables of types - // char, short and float. These need to be redefined if necessary! - ExpVal ret; - - switch(type.Type) + if (!Fixed && !Konst) { - case VAL_Int: - ret.Type = VAL_Int; - ret.Int = *(int*)address; - break; - - case VAL_Sound: - ret.Type = VAL_Sound; - ret.Int = *(FSoundID*)address; - break; - - case VAL_Name: - ret.Type = VAL_Name; - ret.Int = *(FName*)address; - break; - - case VAL_Color: - ret.Type = VAL_Color; - ret.Int = *(int*)address; - break; - - case VAL_Bool: - ret.Type = VAL_Int; - ret.Int = *(bool*)address; - break; - - case VAL_Float: - ret.Type = VAL_Float; - ret.Float = *(double*)address; - break; - - case VAL_Fixed: - ret.Type = VAL_Float; - ret.Float = (*(fixed_t*)address) / 65536.; - break; - - case VAL_Angle: - ret.Type = VAL_Float; - ret.Float = (*(angle_t*)address) * 90./ANGLE_90; // intentionally not using ANGLE_1 - break; - - case VAL_Object: - case VAL_Class: - ret.Type = ExpValType(type.Type); // object and class pointers don't retain their specific class information as values - ret.pointer = *(void**)address; - break; - - default: - ret.Type = VAL_Unknown; - ret.pointer = NULL; - break; + bool success = build->Registers[RegType].Reuse(RegNum); + assert(success && "Attempt to reuse a register that is already in use"); } - return ret; +} + +//========================================================================== +// +// FindDecorateBuiltinFunction +// +// Returns the symbol for a decorate utility function. If not found, create +// it and install it in Actor. +// +//========================================================================== + +static PSymbol *FindDecorateBuiltinFunction(FName funcname, VMNativeFunction::NativeCallType func) +{ + PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol(funcname, false); + if (sym == NULL) + { + PSymbolVMFunction *symfunc = new PSymbolVMFunction(funcname); + VMNativeFunction *calldec = new VMNativeFunction(func, funcname); + symfunc->Function = calldec; + sym = symfunc; + RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); + } + return sym; } //========================================================================== @@ -249,14 +104,10 @@ static ExpVal GetVariableValue (void *address, FExpressionType &type) // //========================================================================== -ExpVal FxExpression::EvalExpression (AActor *self) +ExpEmit FxExpression::Emit (VMFunctionBuilder *build) { - ScriptPosition.Message(MSG_ERROR, "Unresolved expression found"); - ExpVal val; - - val.Type = VAL_Int; - val.Int = 0; - return val; + ScriptPosition.Message(MSG_ERROR, "Unemitted expression found"); + return ExpEmit(); } @@ -321,16 +172,91 @@ void FxExpression::RequestAddress() ScriptPosition.Message(MSG_ERROR, "invalid dereference\n"); } - //========================================================================== // // // //========================================================================== -ExpVal FxConstant::EvalExpression (AActor *self) +FxParameter::FxParameter(FxExpression *operand) +: FxExpression(operand->ScriptPosition) { - return value; + Operand = operand; + ValueType = operand->ValueType; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxParameter::~FxParameter() +{ + SAFE_DELETE(Operand); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxParameter::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Operand, ctx); + ValueType = Operand->ValueType; + return this; +} + +ExpEmit FxParameter::Emit(VMFunctionBuilder *build) +{ + if (Operand->isConstant()) + { + ExpVal val = static_cast(Operand)->GetValue(); + if (val.Type == VAL_Int || val.Type == VAL_Sound || val.Type == VAL_Name || val.Type == VAL_Color) + { + build->EmitParamInt(val.Int); + } + else if (val.Type == VAL_Float) + { + build->Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, build->GetConstantFloat(val.Float)); + } + else if (val.Type == VAL_Class || val.Type == VAL_Object) + { + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(val.pointer, ATAG_OBJECT)); + } + else if (val.Type == VAL_State) + { + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(val.pointer, ATAG_STATE)); + } + else if (val.Type == VAL_String) + { + build->Emit(OP_PARAM, 0, REGT_STRING | REGT_KONST, build->GetConstantString(val.GetString())); + } + else + { + build->Emit(OP_PARAM, 0, REGT_NIL, 0); + ScriptPosition.Message(MSG_ERROR, "Cannot emit needed constant"); + } + } + else + { + ExpEmit where = Operand->Emit(build); + + if (where.RegType == REGT_NIL) + { + ScriptPosition.Message(MSG_ERROR, "Attempted to pass a non-value"); + build->Emit(OP_PARAM, 0, where.RegType, where.RegNum); + } + else + { + build->Emit(OP_PARAM, 0, where.RegType, where.RegNum); + where.Free(build); + } + } + return ExpEmit(); } //========================================================================== @@ -342,20 +268,19 @@ ExpVal FxConstant::EvalExpression (AActor *self) FxExpression *FxConstant::MakeConstant(PSymbol *sym, const FScriptPosition &pos) { FxExpression *x; - if (sym->SymbolType == SYM_Const) + PSymbolConstNumeric *csym = dyn_cast(sym); + if (csym != NULL) { - PSymbolConst *csym = static_cast(sym); - switch(csym->ValueType) + if (csym->ValueType->IsA(RUNTIME_CLASS(PInt))) { - case VAL_Int: x = new FxConstant(csym->Value, pos); - break; - - case VAL_Float: + } + else if (csym->ValueType->IsA(RUNTIME_CLASS(PFloat))) + { x = new FxConstant(csym->Float, pos); - break; - - default: + } + else + { pos.Message(MSG_ERROR, "Invalid constant '%s'\n", csym->SymbolName.GetChars()); return NULL; } @@ -368,7 +293,44 @@ FxExpression *FxConstant::MakeConstant(PSymbol *sym, const FScriptPosition &pos) return x; } +ExpEmit FxConstant::Emit(VMFunctionBuilder *build) +{ + ExpEmit out; + out.Konst = true; + if (value.Type == VAL_Int || value.Type == VAL_Sound || value.Type == VAL_Name || value.Type == VAL_Color) + { + out.RegType = REGT_INT; + out.RegNum = build->GetConstantInt(value.Int); + } + else if (value.Type == VAL_Float) + { + out.RegType = REGT_FLOAT; + out.RegNum = build->GetConstantFloat(value.Float); + } + else if (value.Type == VAL_Class || value.Type == VAL_Object) + { + out.RegType = REGT_POINTER; + out.RegNum = build->GetConstantAddress(value.pointer, ATAG_OBJECT); + } + else if (value.Type == VAL_State) + { + out.RegType = REGT_POINTER; + out.RegNum = build->GetConstantAddress(value.pointer, ATAG_STATE); + } + else if (value.Type == VAL_String) + { + out.RegType = REGT_STRING; + out.RegNum = build->GetConstantString(value.GetString()); + } + else + { + ScriptPosition.Message(MSG_ERROR, "Cannot emit needed constant"); + out.RegType = REGT_NIL; + out.RegNum = 0; + } + return out; +} //========================================================================== // @@ -416,7 +378,7 @@ FxExpression *FxIntCast::Resolve(FCompileContext &ctx) { if (basex->isConstant()) { - ExpVal constval = basex->EvalExpression(NULL); + ExpVal constval = static_cast(basex)->GetValue(); FxExpression *x = new FxConstant(constval.GetInt(), ScriptPosition); delete this; return x; @@ -437,15 +399,17 @@ FxExpression *FxIntCast::Resolve(FCompileContext &ctx) // //========================================================================== -ExpVal FxIntCast::EvalExpression (AActor *self) +ExpEmit FxIntCast::Emit(VMFunctionBuilder *build) { - ExpVal baseval = basex->EvalExpression(self); - baseval.Int = baseval.GetInt(); - baseval.Type = VAL_Int; - return baseval; + ExpEmit from = basex->Emit(build); + assert(!from.Konst); + assert(basex->ValueType == VAL_Float); + from.Free(build); + ExpEmit to(build, REGT_INT); + build->Emit(OP_CAST, to.RegNum, from.RegNum, CAST_F2I); + return to; } - //========================================================================== // // @@ -455,7 +419,7 @@ ExpVal FxIntCast::EvalExpression (AActor *self) FxFloatCast::FxFloatCast(FxExpression *x) : FxExpression(x->ScriptPosition) { - basex = x; + basex=x; ValueType = VAL_Float; } @@ -492,7 +456,7 @@ FxExpression *FxFloatCast::Resolve(FCompileContext &ctx) { if (basex->isConstant()) { - ExpVal constval = basex->EvalExpression(NULL); + ExpVal constval = static_cast(basex)->GetValue(); FxExpression *x = new FxConstant(constval.GetFloat(), ScriptPosition); delete this; return x; @@ -513,15 +477,17 @@ FxExpression *FxFloatCast::Resolve(FCompileContext &ctx) // //========================================================================== -ExpVal FxFloatCast::EvalExpression (AActor *self) +ExpEmit FxFloatCast::Emit(VMFunctionBuilder *build) { - ExpVal baseval = basex->EvalExpression(self); - baseval.Float = baseval.GetFloat(); - baseval.Type = VAL_Float; - return baseval; + ExpEmit from = basex->Emit(build); + assert(!from.Konst); + assert(basex->ValueType == VAL_Int); + from.Free(build); + ExpEmit to(build, REGT_FLOAT); + build->Emit(OP_CAST, to.RegNum, from.RegNum, CAST_I2F); + return to; } - //========================================================================== // // @@ -571,6 +537,11 @@ FxExpression *FxPlusSign::Resolve(FCompileContext& ctx) } } +ExpEmit FxPlusSign::Emit(VMFunctionBuilder *build) +{ + return Operand->Emit(build); +} + //========================================================================== // // @@ -609,7 +580,7 @@ FxExpression *FxMinusSign::Resolve(FCompileContext& ctx) { if (Operand->isConstant()) { - ExpVal val = Operand->EvalExpression(NULL); + ExpVal val = static_cast(Operand)->GetValue(); FxExpression *e = val.Type == VAL_Int? new FxConstant(-val.Int, ScriptPosition) : new FxConstant(-val.Float, ScriptPosition); @@ -633,24 +604,24 @@ FxExpression *FxMinusSign::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxMinusSign::EvalExpression (AActor *self) +ExpEmit FxMinusSign::Emit(VMFunctionBuilder *build) { - ExpVal ret; - + assert(ValueType.Type == Operand->ValueType.Type); + ExpEmit from = Operand->Emit(build); + assert(from.Konst == 0); + // Do it in-place. if (ValueType == VAL_Int) { - ret.Int = -Operand->EvalExpression(self).GetInt(); - ret.Type = VAL_Int; + build->Emit(OP_NEG, from.RegNum, from.RegNum, 0); } else { - ret.Float = -Operand->EvalExpression(self).GetFloat(); - ret.Type = VAL_Float; + assert(ValueType == VAL_Float); + build->Emit(OP_NEG, from.RegNum, from.RegNum, 0); } - return ret; + return from; } - //========================================================================== // // @@ -685,7 +656,7 @@ FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx) CHECKRESOLVED(); SAFE_RESOLVE(Operand, ctx); - if (Operand->ValueType == VAL_Float && ctx.lax) + if (Operand->ValueType == VAL_Float /* lax */) { // DECORATE allows floats here so cast them to int. Operand = new FxIntCast(Operand); @@ -706,7 +677,7 @@ FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx) if (Operand->isConstant()) { - int result = ~Operand->EvalExpression(NULL).GetInt(); + int result = ~static_cast(Operand)->GetValue().GetInt(); FxExpression *e = new FxConstant(result, ScriptPosition); delete this; return e; @@ -721,13 +692,15 @@ FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxUnaryNotBitwise::EvalExpression (AActor *self) +ExpEmit FxUnaryNotBitwise::Emit(VMFunctionBuilder *build) { - ExpVal ret; - - ret.Int = ~Operand->EvalExpression(self).GetInt(); - ret.Type = VAL_Int; - return ret; + assert(ValueType.Type == Operand->ValueType.Type); + assert(ValueType == VAL_Int); + ExpEmit from = Operand->Emit(build); + assert(from.Konst == 0); + // Do it in-place. + build->Emit(OP_NOT, from.RegNum, from.RegNum, 0); + return from; } //========================================================================== @@ -777,7 +750,7 @@ FxExpression *FxUnaryNotBoolean::Resolve(FCompileContext& ctx) { if (Operand->isConstant()) { - bool result = !Operand->EvalExpression(NULL).GetBool(); + bool result = !static_cast(Operand)->GetValue().GetBool(); FxExpression *e = new FxConstant(result, ScriptPosition); delete this; return e; @@ -799,13 +772,34 @@ FxExpression *FxUnaryNotBoolean::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxUnaryNotBoolean::EvalExpression (AActor *self) +ExpEmit FxUnaryNotBoolean::Emit(VMFunctionBuilder *build) { - ExpVal ret; + ExpEmit from = Operand->Emit(build); + assert(!from.Konst); + ExpEmit to(build, REGT_INT); + from.Free(build); - ret.Int = !Operand->EvalExpression(self).GetBool(); - ret.Type = VAL_Int; - return ret; + // Preload result with 0. + build->Emit(OP_LI, to.RegNum, 0, 0); + + // Check source against 0. + if (from.RegType == REGT_INT) + { + build->Emit(OP_EQ_R, 0, from.RegNum, to.RegNum); + } + else if (from.RegType == REGT_FLOAT) + { + build->Emit(OP_EQF_K, 0, from.RegNum, build->GetConstantFloat(0)); + } + else if (from.RegNum == REGT_POINTER) + { + build->Emit(OP_EQA_K, 0, from.RegNum, build->GetConstantAddress(NULL, ATAG_GENERIC)); + } + build->Emit(OP_JMP, 1); + + // Reload result with 1 if the comparison fell through. + build->Emit(OP_LI, to.RegNum, 1); + return to; } //========================================================================== @@ -878,6 +872,17 @@ bool FxBinary::ResolveLR(FCompileContext& ctx, bool castnumeric) return true; } +void FxBinary::Promote(FCompileContext &ctx) +{ + if (left->ValueType == VAL_Float && right->ValueType == VAL_Int) + { + right = (new FxFloatCast(right))->Resolve(ctx); + } + else if (left->ValueType == VAL_Int && right->ValueType == VAL_Float) + { + left = (new FxFloatCast(left))->Resolve(ctx); + } +} //========================================================================== // @@ -912,8 +917,8 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx) if (ValueType == VAL_Float) { double v; - double v1 = left->EvalExpression(NULL).GetFloat(); - double v2 = right->EvalExpression(NULL).GetFloat(); + double v1 = static_cast(left)->GetValue().GetFloat(); + double v2 = static_cast(right)->GetValue().GetFloat(); v = Operator == '+'? v1 + v2 : Operator == '-'? v1 - v2 : 0; @@ -925,8 +930,8 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx) else { int v; - int v1 = left->EvalExpression(NULL).GetInt(); - int v2 = right->EvalExpression(NULL).GetInt(); + int v1 = static_cast(left)->GetValue().GetInt(); + int v2 = static_cast(right)->GetValue().GetInt(); v = Operator == '+'? v1 + v2 : Operator == '-'? v1 - v2 : 0; @@ -937,6 +942,7 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx) } } + Promote(ctx); return this; } @@ -946,30 +952,61 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxAddSub::EvalExpression (AActor *self) +ExpEmit FxAddSub::Emit(VMFunctionBuilder *build) { - ExpVal ret; - - if (ValueType == VAL_Float) + assert(Operator == '+' || Operator == '-'); + ExpEmit op1 = left->Emit(build); + ExpEmit op2 = right->Emit(build); + if (Operator == '+') { - double v1 = left->EvalExpression(self).GetFloat(); - double v2 = right->EvalExpression(self).GetFloat(); - - ret.Type = VAL_Float; - ret.Float = Operator == '+'? v1 + v2 : - Operator == '-'? v1 - v2 : 0; + // Since addition is commutative, only the second operand may be a constant. + if (op1.Konst) + { + swapvalues(op1, op2); + } + assert(!op1.Konst); + op1.Free(build); + op2.Free(build); + if (ValueType == VAL_Float) + { + assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); + ExpEmit to(build, REGT_FLOAT); + build->Emit(op2.Konst ? OP_ADDF_RK : OP_ADDF_RR, to.RegNum, op1.RegNum, op2.RegNum); + return to; + } + else + { + assert(ValueType == VAL_Int); + assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT); + ExpEmit to(build, REGT_INT); + build->Emit(op2.Konst ? OP_ADD_RK : OP_ADD_RR, to.RegNum, op1.RegNum, op2.RegNum); + return to; + } } else { - int v1 = left->EvalExpression(self).GetInt(); - int v2 = right->EvalExpression(self).GetInt(); - - ret.Type = VAL_Int; - ret.Int = Operator == '+'? v1 + v2 : - Operator == '-'? v1 - v2 : 0; - + // Subtraction is not commutative, so either side may be constant (but not both). + assert(!op1.Konst || !op2.Konst); + op1.Free(build); + op2.Free(build); + if (ValueType == VAL_Float) + { + assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); + ExpEmit to(build, REGT_FLOAT); + build->Emit(op1.Konst ? OP_SUBF_KR : op2.Konst ? OP_SUBF_RK : OP_SUBF_RR, + to.RegNum, op1.RegNum, op2.RegNum); + return to; + } + else + { + assert(ValueType == VAL_Int); + assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT); + ExpEmit to(build, REGT_INT); + build->Emit(op1.Konst ? OP_SUB_KR : op2.Konst ? OP_SUB_RK : OP_SUB_RR, + to.RegNum, op1.RegNum, op2.RegNum); + return to; + } } - return ret; } //========================================================================== @@ -1006,8 +1043,8 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx) if (ValueType == VAL_Float) { double v; - double v1 = left->EvalExpression(NULL).GetFloat(); - double v2 = right->EvalExpression(NULL).GetFloat(); + double v1 = static_cast(left)->GetValue().GetFloat(); + double v2 = static_cast(right)->GetValue().GetFloat(); if (Operator != '*' && v2 == 0) { @@ -1027,8 +1064,8 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx) else { int v; - int v1 = left->EvalExpression(NULL).GetInt(); - int v2 = right->EvalExpression(NULL).GetInt(); + int v1 = static_cast(left)->GetValue().GetInt(); + int v2 = static_cast(right)->GetValue().GetInt(); if (Operator != '*' && v2 == 0) { @@ -1047,6 +1084,7 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx) } } + Promote(ctx); return this; } @@ -1057,42 +1095,64 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxMulDiv::EvalExpression (AActor *self) +ExpEmit FxMulDiv::Emit(VMFunctionBuilder *build) { - ExpVal ret; + ExpEmit op1 = left->Emit(build); + ExpEmit op2 = right->Emit(build); - if (ValueType == VAL_Float) + if (Operator == '*') { - double v1 = left->EvalExpression(self).GetFloat(); - double v2 = right->EvalExpression(self).GetFloat(); - - if (Operator != '*' && v2 == 0) + // Multiplication is commutative, so only the second operand may be constant. + if (op1.Konst) { - I_Error("Division by 0"); + swapvalues(op1, op2); + } + assert(!op1.Konst); + op1.Free(build); + op2.Free(build); + if (ValueType == VAL_Float) + { + assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); + ExpEmit to(build, REGT_FLOAT); + build->Emit(op2.Konst ? OP_MULF_RK : OP_MULF_RR, to.RegNum, op1.RegNum, op2.RegNum); + return to; + } + else + { + assert(ValueType == VAL_Int); + assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT); + ExpEmit to(build, REGT_INT); + build->Emit(op2.Konst ? OP_MUL_RK : OP_MUL_RR, to.RegNum, op1.RegNum, op2.RegNum); + return to; } - - ret.Type = VAL_Float; - ret.Float = Operator == '*'? v1 * v2 : - Operator == '/'? v1 / v2 : - Operator == '%'? fmod(v1, v2) : 0; } else { - int v1 = left->EvalExpression(self).GetInt(); - int v2 = right->EvalExpression(self).GetInt(); - - if (Operator != '*' && v2 == 0) + // Division is not commutative, so either side may be constant (but not both). + assert(!op1.Konst || !op2.Konst); + assert(Operator == '%' || Operator == '/'); + op1.Free(build); + op2.Free(build); + if (ValueType == VAL_Float) { - I_Error("Division by 0"); + assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); + ExpEmit to(build, REGT_FLOAT); + build->Emit(Operator == '/' ? (op1.Konst ? OP_DIVF_KR : op2.Konst ? OP_DIVF_RK : OP_DIVF_RR) + : (op1.Konst ? OP_MODF_KR : op2.Konst ? OP_MODF_RK : OP_MODF_RR), + to.RegNum, op1.RegNum, op2.RegNum); + return to; + } + else + { + assert(ValueType == VAL_Int); + assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT); + ExpEmit to(build, REGT_INT); + build->Emit(Operator == '/' ? (op1.Konst ? OP_DIV_KR : op2.Konst ? OP_DIV_RK : OP_DIV_RR) + : (op1.Konst ? OP_MOD_KR : op2.Konst ? OP_MOD_RK : OP_MOD_RR), + to.RegNum, op1.RegNum, op2.RegNum); + return to; } - - ret.Type = VAL_Int; - ret.Int = Operator == '*'? v1 * v2 : - Operator == '/'? v1 / v2 : - Operator == '%'? v1 % v2 : 0; - } - return ret; } //========================================================================== @@ -1129,8 +1189,8 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx) if (ValueType == VAL_Float) { - double v1 = left->EvalExpression(NULL).GetFloat(); - double v2 = right->EvalExpression(NULL).GetFloat(); + double v1 = static_cast(left)->GetValue().GetFloat(); + double v2 = static_cast(right)->GetValue().GetFloat(); v = Operator == '<'? v1 < v2 : Operator == '>'? v1 > v2 : Operator == TK_Geq? v1 >= v2 : @@ -1138,8 +1198,8 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx) } else { - int v1 = left->EvalExpression(NULL).GetInt(); - int v2 = right->EvalExpression(NULL).GetInt(); + int v1 = static_cast(left)->GetValue().GetInt(); + int v2 = static_cast(right)->GetValue().GetInt(); v = Operator == '<'? v1 < v2 : Operator == '>'? v1 > v2 : Operator == TK_Geq? v1 >= v2 : @@ -1149,6 +1209,7 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx) delete this; return e; } + Promote(ctx); ValueType = VAL_Int; return this; } @@ -1160,33 +1221,53 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxCompareRel::EvalExpression (AActor *self) +ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build) { - ExpVal ret; - - ret.Type = VAL_Int; - - if (left->ValueType == VAL_Float || right->ValueType == VAL_Float) + ExpEmit op1 = left->Emit(build); + ExpEmit op2 = right->Emit(build); + assert(op1.RegType == op2.RegType); + assert(op1.RegType == REGT_INT || op1.RegType == REGT_FLOAT); + assert(!op1.Konst || !op2.Konst); + assert(Operator == '<' || Operator == '>' || Operator == TK_Geq || Operator == TK_Leq); + static const VM_UBYTE InstrMap[][4] = { - double v1 = left->EvalExpression(self).GetFloat(); - double v2 = right->EvalExpression(self).GetFloat(); - ret.Int = Operator == '<'? v1 < v2 : - Operator == '>'? v1 > v2 : - Operator == TK_Geq? v1 >= v2 : - Operator == TK_Leq? v1 <= v2 : 0; + { OP_LT_RR, OP_LTF_RR, 0 }, // < + { OP_LE_RR, OP_LEF_RR, 1 }, // > + { OP_LT_RR, OP_LTF_RR, 1 }, // >= + { OP_LE_RR, OP_LEF_RR, 0 } // <= + }; + int instr, check, index; + ExpEmit to(build, REGT_INT); + + index = Operator == '<' ? 0 : + Operator == '>' ? 1 : + Operator == TK_Geq ? 2 : 3; + instr = InstrMap[index][op1.RegType == REGT_INT ? 0 : 1]; + check = InstrMap[index][2]; + if (op2.Konst) + { + instr += 1; } else { - int v1 = left->EvalExpression(self).GetInt(); - int v2 = right->EvalExpression(self).GetInt(); - ret.Int = Operator == '<'? v1 < v2 : - Operator == '>'? v1 > v2 : - Operator == TK_Geq? v1 >= v2 : - Operator == TK_Leq? v1 <= v2 : 0; + op2.Free(build); + } + if (op1.Konst) + { + instr += 2; + } + else + { + op1.Free(build); } - return ret; -} + // See FxUnaryNotBoolean for comments, since it's the same thing. + build->Emit(OP_LI, to.RegNum, 0, 0); + build->Emit(instr, check, op1.RegNum, op2.RegNum); + build->Emit(OP_JMP, 1); + build->Emit(OP_LI, to.RegNum, 1); + return to; +} //========================================================================== // @@ -1240,20 +1321,21 @@ cont: if (ValueType == VAL_Float) { - double v1 = left->EvalExpression(NULL).GetFloat(); - double v2 = right->EvalExpression(NULL).GetFloat(); + double v1 = static_cast(left)->GetValue().GetFloat(); + double v2 = static_cast(right)->GetValue().GetFloat(); v = Operator == TK_Eq? v1 == v2 : v1 != v2; } else { - int v1 = left->EvalExpression(NULL).GetInt(); - int v2 = right->EvalExpression(NULL).GetInt(); + int v1 = static_cast(left)->GetValue().GetInt(); + int v2 = static_cast(right)->GetValue().GetInt(); v = Operator == TK_Eq? v1 == v2 : v1 != v2; } FxExpression *e = new FxConstant(v, ScriptPosition); delete this; return e; } + Promote(ctx); ValueType = VAL_Int; return this; } @@ -1264,32 +1346,43 @@ cont: // //========================================================================== -ExpVal FxCompareEq::EvalExpression (AActor *self) +ExpEmit FxCompareEq::Emit(VMFunctionBuilder *build) { - ExpVal ret; + ExpEmit op1 = left->Emit(build); + ExpEmit op2 = right->Emit(build); + assert(op1.RegType == op2.RegType); + assert(op1.RegType == REGT_INT || op1.RegType == REGT_FLOAT || op1.RegType == REGT_POINTER); + int instr; - ret.Type = VAL_Int; - - if (left->ValueType == VAL_Float || right->ValueType == VAL_Float) + // Only the second operand may be constant. + if (op1.Konst) { - double v1 = left->EvalExpression(self).GetFloat(); - double v2 = right->EvalExpression(self).GetFloat(); - ret.Int = Operator == TK_Eq? v1 == v2 : v1 != v2; + swapvalues(op1, op2); } - else if (ValueType == VAL_Int) + assert(!op1.Konst); + + ExpEmit to(build, REGT_INT); + + instr = op1.RegType == REGT_INT ? OP_EQ_R : + op1.RegType == REGT_FLOAT ? OP_EQF_R : + OP_EQA_R; + op1.Free(build); + if (!op2.Konst) { - int v1 = left->EvalExpression(self).GetInt(); - int v2 = right->EvalExpression(self).GetInt(); - ret.Int = Operator == TK_Eq? v1 == v2 : v1 != v2; + op2.Free(build); } else { - // Implement pointer comparison - ret.Int = 0; + instr += 1; } - return ret; -} + // See FxUnaryNotBoolean for comments, since it's the same thing. + build->Emit(OP_LI, to.RegNum, 0, 0); + build->Emit(instr, Operator != TK_Eq, op1.RegNum, op2.RegNum); + build->Emit(OP_JMP, 1); + build->Emit(OP_LI, to.RegNum, 1); + return to; +} //========================================================================== // @@ -1314,7 +1407,7 @@ FxExpression *FxBinaryInt::Resolve(FCompileContext& ctx) CHECKRESOLVED(); if (!ResolveLR(ctx, false)) return NULL; - if (ctx.lax && ValueType == VAL_Float) + if (ValueType == VAL_Float /* lax */) { // For DECORATE which allows floats here. if (left->ValueType != VAL_Int) @@ -1343,8 +1436,8 @@ FxExpression *FxBinaryInt::Resolve(FCompileContext& ctx) } else if (left->isConstant() && right->isConstant()) { - int v1 = left->EvalExpression(NULL).GetInt(); - int v2 = right->EvalExpression(NULL).GetInt(); + int v1 = static_cast(left)->GetValue().GetInt(); + int v2 = static_cast(right)->GetValue().GetInt(); FxExpression *e = new FxConstant( Operator == TK_LShift? v1 << v2 : @@ -1366,23 +1459,77 @@ FxExpression *FxBinaryInt::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxBinaryInt::EvalExpression (AActor *self) +ExpEmit FxBinaryInt::Emit(VMFunctionBuilder *build) { - int v1 = left->EvalExpression(self).GetInt(); - int v2 = right->EvalExpression(self).GetInt(); + assert(left->ValueType == VAL_Int); + assert(right->ValueType == VAL_Int); + static const VM_UBYTE InstrMap[][4] = + { + { OP_SLL_RR, OP_SLL_KR, OP_SLL_RI }, // TK_LShift + { OP_SRA_RR, OP_SRA_KR, OP_SRA_RI }, // TK_RShift + { OP_SRL_RR, OP_SRL_KR, OP_SRL_RI }, // TK_URShift + { OP_AND_RR, 0, OP_AND_RK }, // '&' + { OP_OR_RR, 0, OP_OR_RK }, // '|' + { OP_XOR_RR, 0, OP_XOR_RK }, // '^' + }; + int index, instr, rop; + ExpEmit op1, op2; - ExpVal ret; - - ret.Type = VAL_Int; - ret.Int = - Operator == TK_LShift? v1 << v2 : - Operator == TK_RShift? v1 >> v2 : - Operator == TK_URShift? int((unsigned int)(v1) >> v2) : - Operator == '&'? v1 & v2 : - Operator == '|'? v1 | v2 : - Operator == '^'? v1 ^ v2 : 0; - - return ret; + index = Operator == TK_LShift ? 0 : + Operator == TK_RShift ? 1 : + Operator == TK_URShift ? 2 : + Operator == '&' ? 3 : + Operator == '|' ? 4 : + Operator == '^' ? 5 : -1; + assert(index >= 0); + op1 = left->Emit(build); + if (index < 3) + { // Shift instructions use right-hand immediates instead of constant registers. + if (right->isConstant()) + { + rop = static_cast(right)->GetValue().GetInt(); + op2.Konst = true; + } + else + { + op2 = right->Emit(build); + assert(!op2.Konst); + op2.Free(build); + rop = op2.RegNum; + } + } + else + { // The other operators only take a constant on the right-hand side. + op2 = right->Emit(build); + if (op1.Konst) + { + swapvalues(op1, op2); + } + assert(!op1.Konst); + rop = op2.RegNum; + op2.Free(build); + } + if (!op1.Konst) + { + op1.Free(build); + if (!op2.Konst) + { + instr = InstrMap[index][0]; + } + else + { + instr = InstrMap[index][2]; + } + } + else + { + assert(!op2.Konst); + instr = InstrMap[index][1]; + } + assert(instr != 0); + ExpEmit to(build, REGT_INT); + build->Emit(instr, to.RegNum, op1.RegNum, rop); + return to; } //========================================================================== @@ -1431,8 +1578,8 @@ FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx) int b_left=-1, b_right=-1; - if (left->isConstant()) b_left = left->EvalExpression(NULL).GetBool(); - if (right->isConstant()) b_right = right->EvalExpression(NULL).GetBool(); + if (left->isConstant()) b_left = static_cast(left)->GetValue().GetBool(); + if (right->isConstant()) b_right = static_cast(right)->GetValue().GetBool(); // Do some optimizations. This will throw out all sub-expressions that are not // needed to retrieve the final result. @@ -1494,6 +1641,14 @@ FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx) return x; } } + if (left->ValueType != VAL_Int && left->ValueType != VAL_Sound) + { + left = new FxIntCast(left); + } + if (right->ValueType != VAL_Int && right->ValueType != VAL_Sound) + { + right = new FxIntCast(right); + } return this; } @@ -1503,25 +1658,59 @@ FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxBinaryLogical::EvalExpression (AActor *self) +ExpEmit FxBinaryLogical::Emit(VMFunctionBuilder *build) { - bool b_left = left->EvalExpression(self).GetBool(); - ExpVal ret; - - ret.Type = VAL_Int; - ret.Int = false; + // This is not the "right" way to do these, but it works for now. + // (Problem: No information sharing is done between nodes to reduce the + // code size if you have something like a1 && a2 && a3 && ... && an.) + assert(left->ValueType == VAL_Int && right->ValueType == VAL_Int); + ExpEmit op1 = left->Emit(build); + assert(!op1.Konst); + int zero = build->GetConstantInt(0); + op1.Free(build); if (Operator == TK_AndAnd) { - ret.Int = (b_left && right->EvalExpression(self).GetBool()); - } - else if (Operator == TK_OrOr) - { - ret.Int = (b_left || right->EvalExpression(self).GetBool()); - } - return ret; -} + build->Emit(OP_EQ_K, 1, op1.RegNum, zero); + // If op1 is 0, skip evaluation of op2. + size_t patchspot = build->Emit(OP_JMP, 0, 0, 0); + // Evaluate op2. + ExpEmit op2 = right->Emit(build); + assert(!op2.Konst); + op2.Free(build); + + ExpEmit to(build, REGT_INT); + build->Emit(OP_EQ_K, 0, op2.RegNum, zero); + build->Emit(OP_JMP, 2); + build->Emit(OP_LI, to.RegNum, 1); + build->Emit(OP_JMP, 1); + size_t target = build->Emit(OP_LI, to.RegNum, 0); + build->Backpatch(patchspot, target); + return to; + } + else + { + assert(Operator == TK_OrOr); + build->Emit(OP_EQ_K, 0, op1.RegNum, zero); + // If op1 is not 0, skip evaluation of op2. + size_t patchspot = build->Emit(OP_JMP, 0, 0, 0); + + // Evaluate op2. + ExpEmit op2 = right->Emit(build); + assert(!op2.Konst); + op2.Free(build); + + ExpEmit to(build, REGT_INT); + build->Emit(OP_EQ_K, 1, op2.RegNum, zero); + build->Emit(OP_JMP, 2); + build->Emit(OP_LI, to.RegNum, 0); + build->Emit(OP_JMP, 1); + size_t target = build->Emit(OP_LI, to.RegNum, 1); + build->Backpatch(patchspot, target); + return to; + } +} //========================================================================== // @@ -1572,7 +1761,7 @@ FxExpression *FxConditional::Resolve(FCompileContext& ctx) if (condition->isConstant()) { - ExpVal condval = condition->EvalExpression(NULL); + ExpVal condval = static_cast(condition)->GetValue(); bool result = condval.GetBool(); FxExpression *e = result? truex:falsex; @@ -1582,6 +1771,20 @@ FxExpression *FxConditional::Resolve(FCompileContext& ctx) return e; } + if (ValueType == VAL_Float) + { + if (truex->ValueType != VAL_Float) + { + truex = new FxFloatCast(truex); + RESOLVE(truex, ctx); + } + if (falsex->ValueType != VAL_Float) + { + falsex = new FxFloatCast(falsex); + RESOLVE(falsex, ctx); + } + } + return this; } @@ -1591,13 +1794,76 @@ FxExpression *FxConditional::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxConditional::EvalExpression (AActor *self) +ExpEmit FxConditional::Emit(VMFunctionBuilder *build) { - ExpVal condval = condition->EvalExpression(self); - bool result = condval.GetBool(); + ExpEmit out; - FxExpression *e = result? truex:falsex; - return e->EvalExpression(self); + // The true and false expressions ought to be assigned to the + // same temporary instead of being copied to it. Oh well; good enough + // for now. + ExpEmit cond = condition->Emit(build); + assert(cond.RegType == REGT_INT && !cond.Konst); + + // Test condition. + build->Emit(OP_EQ_K, 1, cond.RegNum, build->GetConstantInt(0)); + size_t patchspot = build->Emit(OP_JMP, 0); + + // Evaluate true expression. + if (truex->isConstant() && truex->ValueType == VAL_Int) + { + out = ExpEmit(build, REGT_INT); + build->EmitLoadInt(out.RegNum, static_cast(truex)->GetValue().GetInt()); + } + else + { + ExpEmit trueop = truex->Emit(build); + if (trueop.Konst) + { + assert(trueop.RegType == REGT_FLOAT); + out = ExpEmit(build, REGT_FLOAT); + build->Emit(OP_LKF, out.RegNum, trueop.RegNum); + } + else + { + // Use the register returned by the true condition as the + // target for the false condition. + out = trueop; + } + } + + // Evaluate false expression. + build->BackpatchToHere(patchspot); + if (falsex->isConstant() && falsex->ValueType == VAL_Int) + { + build->EmitLoadInt(out.RegNum, static_cast(falsex)->GetValue().GetInt()); + } + else + { + ExpEmit falseop = falsex->Emit(build); + if (falseop.Konst) + { + assert(falseop.RegType == REGT_FLOAT); + build->Emit(OP_LKF, out.RegNum, falseop.RegNum); + } + else + { + // Move result from the register returned by "false" to the one + // returned by "true" so that only one register is returned by + // this tree. + falseop.Free(build); + if (falseop.RegType == REGT_INT) + { + build->Emit(OP_MOVE, out.RegNum, falseop.RegNum, 0); + } + else + { + assert(falseop.RegType == REGT_FLOAT); + build->Emit(OP_MOVEF, out.RegNum, falseop.RegNum, 0); + } + } + } + + return out; } //========================================================================== @@ -1643,7 +1909,7 @@ FxExpression *FxAbs::Resolve(FCompileContext &ctx) } else if (val->isConstant()) { - ExpVal value = val->EvalExpression(NULL); + ExpVal value = static_cast(val)->GetValue(); switch (value.Type) { case VAL_Int: @@ -1673,21 +1939,21 @@ FxExpression *FxAbs::Resolve(FCompileContext &ctx) // //========================================================================== -ExpVal FxAbs::EvalExpression (AActor *self) +ExpEmit FxAbs::Emit(VMFunctionBuilder *build) { - ExpVal value = val->EvalExpression(self); - switch (value.Type) + ExpEmit absofsteal = val->Emit(build); + assert(!absofsteal.Konst); + ExpEmit out(build, absofsteal.RegType); + if (absofsteal.RegType == REGT_INT) { - default: - case VAL_Int: - value.Int = abs(value.Int); - break; - - case VAL_Float: - value.Float = fabs(value.Float); - break; + build->Emit(OP_ABS, out.RegNum, absofsteal.RegNum, 0); } - return value; + else + { + assert(absofsteal.RegType == REGT_FLOAT); + build->Emit(OP_FLOP, out.RegNum, absofsteal.RegNum, FLOP_ABS); + } + return out; } //========================================================================== @@ -1700,8 +1966,8 @@ FxRandom::FxRandom(FRandom * r, FxExpression *mi, FxExpression *ma, const FScrip { if (mi != NULL && ma != NULL) { - min = new FxIntCast(mi); - max = new FxIntCast(ma); + min = new FxParameter(new FxIntCast(mi)); + max = new FxParameter(new FxIntCast(ma)); } else min = max = NULL; rng = r; @@ -1734,6 +2000,8 @@ FxExpression *FxRandom::Resolve(FCompileContext &ctx) RESOLVE(min, ctx); RESOLVE(max, ctx); ABORT(min && max); + assert(min->ValueType == ValueType.Type); + assert(max->ValueType == ValueType.Type); } return this; }; @@ -1745,28 +2013,55 @@ FxExpression *FxRandom::Resolve(FCompileContext &ctx) // //========================================================================== -ExpVal FxRandom::EvalExpression (AActor *self) +int DecoRandom(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) { - ExpVal val; - val.Type = VAL_Int; + assert(numparam >= 1 && numparam <= 3); + FRandom *rng = reinterpret_cast(param[0].a); + if (numparam == 1) + { + ret->SetInt((*rng)()); + } + else if (numparam == 2) + { + int maskval = param[1].i; + ret->SetInt(rng->Random2(maskval)); + } + else if (numparam == 3) + { + int min = param[1].i, max = param[2].i; + if (max < min) + { + swapvalues(max, min); + } + ret->SetInt((*rng)(max - min + 1) + min); + } + return 1; +} +ExpEmit FxRandom::Emit(VMFunctionBuilder *build) +{ + // Call DecoRandom to generate a random number. + VMFunction *callfunc; + PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoRandom, DecoRandom); + + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); + assert(((PSymbolVMFunction *)sym)->Function != NULL); + callfunc = ((PSymbolVMFunction *)sym)->Function; + + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); if (min != NULL && max != NULL) { - int minval = min->EvalExpression (self).GetInt(); - int maxval = max->EvalExpression (self).GetInt(); - - if (maxval < minval) - { - swapvalues (maxval, minval); - } - - val.Int = (*rng)(maxval - minval + 1) + minval; + min->Emit(build); + max->Emit(build); + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); } else { - val.Int = (*rng)(); + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 1, 1); } - return val; + ExpEmit out(build, REGT_INT); + build->Emit(OP_RESULT, 0, REGT_INT, out.RegNum); + return out; } //========================================================================== @@ -1774,21 +2069,22 @@ ExpVal FxRandom::EvalExpression (AActor *self) // // //========================================================================== -FxRandomPick::FxRandomPick(FRandom * r, TArray mi, bool floaty, const FScriptPosition &pos) +FxRandomPick::FxRandomPick(FRandom *r, TArray &expr, bool floaty, const FScriptPosition &pos) : FxExpression(pos) { - for (unsigned int index = 0; index < mi.Size(); index++) + assert(expr.Size() > 0); + choices.Resize(expr.Size()); + for (unsigned int index = 0; index < expr.Size(); index++) { - FxExpression *casted; if (floaty) { - casted = new FxFloatCast(mi[index]); + choices[index] = new FxFloatCast(expr[index]); } else { - casted = new FxIntCast(mi[index]); + choices[index] = new FxIntCast(expr[index]); } - min.Push(casted); + } rng = r; ValueType = floaty ? VAL_Float : VAL_Int; @@ -1813,10 +2109,11 @@ FxRandomPick::~FxRandomPick() FxExpression *FxRandomPick::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); - for (unsigned int index = 0; index < min.Size(); index++) + for (unsigned int index = 0; index < choices.Size(); index++) { - RESOLVE(min[index], ctx); - ABORT(min[index]); + RESOLVE(choices[index], ctx); + ABORT(choices[index]); + assert(choices[index]->ValueType == ValueType.Type); } return this; }; @@ -1824,33 +2121,114 @@ FxExpression *FxRandomPick::Resolve(FCompileContext &ctx) //========================================================================== // +// FxPick :: Emit // +// The expression: +// a = pick[rng](i_0, i_1, i_2, ..., i_n) +// [where i_x is a complete expression and not just a value] +// is syntactic sugar for: +// +// switch(random[rng](0, n)) { +// case 0: a = i_0; +// case 1: a = i_1; +// case 2: a = i_2; +// ... +// case n: a = i_n; +// } // //========================================================================== -ExpVal FxRandomPick::EvalExpression(AActor *self) +ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build) { - ExpVal val; - int max = min.Size(); - if (max > 0) +#pragma message("FxRandomPick::Emit: Floating point part needs reviewing!") + unsigned i; + + assert(choices.Size() > 0); + + // Call DecoRandom to generate a random number. + VMFunction *callfunc; + PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoRandom, DecoRandom); + + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); + assert(((PSymbolVMFunction *)sym)->Function != NULL); + callfunc = ((PSymbolVMFunction *)sym)->Function; + + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); + build->EmitParamInt(0); + build->EmitParamInt(choices.Size() - 1); + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); + + ExpEmit resultreg(build, REGT_INT); + build->Emit(OP_RESULT, 0, REGT_INT, resultreg.RegNum); + build->Emit(OP_IJMP, resultreg.RegNum, 0); + + // Free the result register now. The simple code generation algorithm should + // automatically pick it as the destination register for each case. + resultreg.Free(build); + + // Allocate space for the jump table. + size_t jumptable = build->Emit(OP_JMP, 0); + for (i = 1; i < choices.Size(); ++i) { - int select = (*rng)(max); - val = min[select]->EvalExpression(self); + build->Emit(OP_JMP, 0); } - /* Is a default even important when the parser requires at least one - * choice? Why do we do this? */ - else if (ValueType == VAL_Int) + + // Emit each case + TArray finishes(choices.Size() - 1); + for (unsigned i = 0; i < choices.Size(); ++i) { - val.Type = VAL_Int; - val.Int = (*rng)(); + build->BackpatchToHere(jumptable + i); + if (choices[i]->isConstant()) + { + if (ValueType == VAL_Int) + { + int val = static_cast(choices[i])->GetValue().GetInt(); + build->EmitLoadInt(resultreg.RegNum, val); + } + else + { + double val = static_cast(choices[i])->GetValue().GetFloat(); + build->Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, build->GetConstantFloat(val)); + build->ParamChange(-1); // all params should use the same register here. + } + } + else + { + ExpEmit casereg = choices[i]->Emit(build); + if (casereg.RegNum != resultreg.RegNum) + { // The result of the case is in a different register from what + // was expected. Copy it to the one we wanted. + + resultreg.Reuse(build); // This is really just for the assert in Reuse() + if (ValueType == VAL_Int) + { + build->Emit(OP_MOVE, resultreg.RegNum, casereg.RegNum, 0); + } + else + { + build->Emit(OP_MOVEF, resultreg.RegNum, casereg.RegNum, 0); + } + resultreg.Free(build); + } + // Free this register so the remaining cases can use it. + casereg.Free(build); + } + // All but the final case needs a jump to the end of the expression's code. + if (i + 1 < choices.Size()) + { + size_t loc = build->Emit(OP_JMP, 0); + finishes.Push(loc); + } } - else + // Backpatch each case (except the last, since it ends here) to jump to here. + for (i = 0; i < choices.Size() - 1; ++i) { - val.Type = VAL_Float; - val.Float = (*rng)(0x40000000) / double(0x40000000); + build->BackpatchToHere(finishes[i]); } - assert(val.Type == ValueType.Type); - return val; + // The result register needs to be in-use when we return. + // It should have been freed earlier, so restore its in-use flag. + resultreg.Reuse(build); + return resultreg; } //========================================================================== @@ -1863,8 +2241,8 @@ FxFRandom::FxFRandom(FRandom *r, FxExpression *mi, FxExpression *ma, const FScri { if (mi != NULL && ma != NULL) { - min = mi; - max = ma; + min = new FxParameter(new FxFloatCast(mi)); + max = new FxParameter(new FxFloatCast(ma)); } ValueType = VAL_Float; } @@ -1875,30 +2253,54 @@ FxFRandom::FxFRandom(FRandom *r, FxExpression *mi, FxExpression *ma, const FScri // //========================================================================== -ExpVal FxFRandom::EvalExpression (AActor *self) +int DecoFRandom(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) { - ExpVal val; - val.Type = VAL_Float; + assert(numparam == 1 || numparam == 3); + FRandom *rng = reinterpret_cast(param[0].a); + int random = (*rng)(0x40000000); double frandom = random / double(0x40000000); - if (min != NULL && max != NULL) + if (numparam == 3) { - double minval = min->EvalExpression (self).GetFloat(); - double maxval = max->EvalExpression (self).GetFloat(); - - if (maxval < minval) + double min = param[1].f, max = param[2].f; + if (max < min) { - swapvalues (maxval, minval); + swapvalues(max, min); } - - val.Float = frandom * (maxval - minval) + minval; + ret->SetFloat(frandom * (max - min) + min); } else { - val.Float = frandom; + ret->SetFloat(frandom); } - return val; + return 1; +} + +ExpEmit FxFRandom::Emit(VMFunctionBuilder *build) +{ + // Call the DecoFRandom function to generate a floating point random number.. + VMFunction *callfunc; + PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoFRandom, DecoFRandom); + + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); + assert(((PSymbolVMFunction *)sym)->Function != NULL); + callfunc = ((PSymbolVMFunction *)sym)->Function; + + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); + if (min != NULL && max != NULL) + { + min->Emit(build); + max->Emit(build); + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); + } + else + { + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 1, 1); + } + ExpEmit out(build, REGT_FLOAT); + build->Emit(OP_RESULT, 0, REGT_FLOAT, out.RegNum); + return out; } //========================================================================== @@ -1913,6 +2315,7 @@ FxRandom2::FxRandom2(FRandom *r, FxExpression *m, const FScriptPosition &pos) rng = r; if (m) mask = new FxIntCast(m); else mask = new FxConstant(-1, pos); + mask = new FxParameter(mask); ValueType = VAL_Int; } @@ -1946,14 +2349,22 @@ FxExpression *FxRandom2::Resolve(FCompileContext &ctx) // //========================================================================== -ExpVal FxRandom2::EvalExpression (AActor *self) +ExpEmit FxRandom2::Emit(VMFunctionBuilder *build) { - ExpVal maskval = mask->EvalExpression(self); - int imaskval = maskval.GetInt(); + // Call the DecoRandom function to generate the random number. + VMFunction *callfunc; + PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoRandom, DecoRandom); - maskval.Type = VAL_Int; - maskval.Int = rng->Random2(imaskval); - return maskval; + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); + assert(((PSymbolVMFunction *)sym)->Function != NULL); + callfunc = ((PSymbolVMFunction *)sym)->Function; + + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); + mask->Emit(build); + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1); + ExpEmit out(build, REGT_INT); + build->Emit(OP_RESULT, 0, REGT_INT, out.RegNum); + return out; } //========================================================================== @@ -1987,15 +2398,15 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) // see if the current class (if valid) defines something with this name. if ((sym = ctx.FindInClass(Identifier)) != NULL) { - if (sym->SymbolType == SYM_Const) + if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) { ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as class constant\n", Identifier.GetChars()); newex = FxConstant::MakeConstant(sym, ScriptPosition); } - else if (sym->SymbolType == SYM_Variable) + else if (sym->IsKindOf(RUNTIME_CLASS(PField))) { - PSymbolVariable *vsym = static_cast(sym); - ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as member variable, index %d\n", Identifier.GetChars(), vsym->offset); + PField *vsym = static_cast(sym); + ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as member variable, index %d\n", Identifier.GetChars(), vsym->Offset); newex = new FxClassMember((new FxSelf(ScriptPosition))->Resolve(ctx), vsym, ScriptPosition); } else @@ -2003,20 +2414,19 @@ 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) { - if (sym->SymbolType == SYM_Const) + if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) { ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as global constant\n", Identifier.GetChars()); newex = FxConstant::MakeConstant(sym, ScriptPosition); } - else if (sym->SymbolType == SYM_Variable) // global variables will always be native - { - PSymbolVariable *vsym = static_cast(sym); - ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as global variable, address %d\n", Identifier.GetChars(), vsym->offset); - newex = new FxGlobalVariable(vsym, ScriptPosition); - } else { ScriptPosition.Message(MSG_ERROR, "Invalid global identifier '%s'\n", Identifier.GetChars()); @@ -2093,94 +2503,71 @@ FxExpression *FxSelf::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxSelf::EvalExpression (AActor *self) +ExpEmit FxSelf::Emit(VMFunctionBuilder *build) { - ExpVal ret; - - ret.Type = VAL_Object; - ret.pointer = self; - return ret; + // self is always the first pointer passed to the function + ExpEmit me(0, REGT_POINTER); + me.Fixed = true; + return me; } + //========================================================================== // // // //========================================================================== -FxGlobalVariable::FxGlobalVariable(PSymbolVariable *mem, const FScriptPosition &pos) +FxDamage::FxDamage(const FScriptPosition &pos) : FxExpression(pos) { - var = mem; - AddressRequested = false; } //========================================================================== // -// +// FxDamage :: Resolve // //========================================================================== -void FxGlobalVariable::RequestAddress() -{ - AddressRequested = true; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxGlobalVariable::Resolve(FCompileContext&) +FxExpression *FxDamage::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); - switch (var->ValueType.Type) - { - case VAL_Int: - case VAL_Bool: - ValueType = VAL_Int; - break; - - case VAL_Float: - case VAL_Fixed: - case VAL_Angle: - ValueType = VAL_Float; - break; - - case VAL_Object: - case VAL_Class: - ValueType = var->ValueType; - break; - - default: - ScriptPosition.Message(MSG_ERROR, "Invalid type for global variable"); - delete this; - return NULL; - } + ValueType = VAL_Int; return this; } //========================================================================== // +// FxDamage :: Emit // +// Call this actor's damage function, if it has one // //========================================================================== -ExpVal FxGlobalVariable::EvalExpression (AActor *self) +ExpEmit FxDamage::Emit(VMFunctionBuilder *build) { - ExpVal ret; - - if (!AddressRequested) - { - ret = GetVariableValue((void*)var->offset, var->ValueType); - } - else - { - ret.pointer = (void*)var->offset; - ret.Type = VAL_Pointer; - } - return ret; + 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(0, 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; } @@ -2190,7 +2577,7 @@ ExpVal FxGlobalVariable::EvalExpression (AActor *self) // //========================================================================== -FxClassMember::FxClassMember(FxExpression *x, PSymbolVariable* mem, const FScriptPosition &pos) +FxClassMember::FxClassMember(FxExpression *x, PField* mem, const FScriptPosition &pos) : FxExpression(pos) { classx = x; @@ -2238,71 +2625,76 @@ FxExpression *FxClassMember::Resolve(FCompileContext &ctx) delete this; return NULL; } - switch (membervar->ValueType.Type) + PType *type = membervar->Type; + PArray *arraytype = dyn_cast(type); + + if (arraytype != NULL) + { + type = arraytype->ElementType; + } + if (type->IsKindOf(RUNTIME_CLASS(PPointer))) + { + ValueType = VAL_Object; + } + else if (type->IsKindOf(RUNTIME_CLASS(PInt))) { - case VAL_Int: - case VAL_Bool: ValueType = VAL_Int; - break; - - case VAL_Float: - case VAL_Fixed: - case VAL_Angle: + } + else if (type->IsKindOf(RUNTIME_CLASS(PFloat))) + { ValueType = VAL_Float; - break; - - case VAL_Object: - case VAL_Class: - case VAL_Array: - ValueType = membervar->ValueType; - break; - - default: + } + else + { ScriptPosition.Message(MSG_ERROR, "Invalid type for member variable %s", membervar->SymbolName.GetChars()); delete this; return NULL; } + if (arraytype != NULL) + { + ValueType.MakeArray(arraytype->ElementCount); + } return this; } -//========================================================================== -// -// -// -//========================================================================== - -ExpVal FxClassMember::EvalExpression (AActor *self) +ExpEmit FxClassMember::Emit(VMFunctionBuilder *build) { - char *object = NULL; - if (classx->ValueType == VAL_Class) + ExpEmit obj = classx->Emit(build); + assert(obj.RegType == REGT_POINTER); + + if (AddressRequested) { - // not implemented yet - } - else - { - object = classx->EvalExpression(self).GetPointer(); - } - if (object == NULL) - { - I_Error("Accessing member variable without valid object"); + if (membervar->Offset == 0) + { + return obj; + } + obj.Free(build); + ExpEmit out(build, REGT_POINTER); + build->Emit(OP_ADDA_RK, out.RegNum, obj.RegNum, build->GetConstantInt((int)membervar->Offset)); + return out; } - ExpVal ret; - - if (!AddressRequested) + int offsetreg = build->GetConstantInt((int)membervar->Offset); + ExpEmit loc, tmp; + + if (obj.Konst) { - ret = GetVariableValue(object + membervar->offset, membervar->ValueType); + // If the situation where we are dereferencing a constant + // pointer is common, then it would probably be worthwhile + // to add new opcodes for those. But as of right now, I + // don't expect it to be a particularly common case. + ExpEmit newobj(build, REGT_POINTER); + build->Emit(OP_LKP, newobj.RegNum, obj.RegNum); + obj = newobj; } - else - { - ret.pointer = object + membervar->offset; - ret.Type = VAL_Pointer; - } - return ret; + + loc = ExpEmit(build, membervar->Type->GetRegType()); + build->Emit(membervar->Type->GetLoadOp(), loc.RegNum, obj.RegNum, offsetreg); + obj.Free(build); + return loc; } - //========================================================================== // // @@ -2354,7 +2746,7 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) SAFE_RESOLVE(Array,ctx); SAFE_RESOLVE(index,ctx); - if (index->ValueType == VAL_Float && ctx.lax) + if (index->ValueType == VAL_Float /* lax */) { // DECORATE allows floats here so cast them to int. index = new FxIntCast(index); @@ -2397,24 +2789,38 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) // //========================================================================== -ExpVal FxArrayElement::EvalExpression (AActor *self) +ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) { - int * arraystart = Array->EvalExpression(self).GetPointer(); - int indexval = index->EvalExpression(self).GetInt(); - - if (indexval < 0 || indexval >= Array->ValueType.size) + ExpEmit start = Array->Emit(build); + ExpEmit dest(build, REGT_INT); + if (start.Konst) { - I_Error("Array index out of bounds"); + ExpEmit tmpstart(build, REGT_POINTER); + build->Emit(OP_LKP, tmpstart.RegNum, start.RegNum); + start = tmpstart; } - - ExpVal ret; - - ret.Int = arraystart[indexval]; - ret.Type = VAL_Int; - return ret; + if (index->isConstant()) + { + int indexval = static_cast(index)->GetValue().GetInt(); + if (indexval < 0 || indexval >= Array->ValueType.size) + { + I_Error("Array index out of bounds"); + } + indexval <<= 2; + build->Emit(OP_LW, dest.RegNum, start.RegNum, build->GetConstantInt(indexval)); + } + else + { + ExpEmit indexv(index->Emit(build)); + build->Emit(OP_SLL_RI, indexv.RegNum, indexv.RegNum, 2); + build->Emit(OP_BOUND, indexv.RegNum, Array->ValueType.size); + build->Emit(OP_LW_R, dest.RegNum, start.RegNum, indexv.RegNum); + indexv.Free(build); + } + start.Free(build); + return dest; } - //========================================================================== // // @@ -2449,6 +2855,22 @@ FxFunctionCall::~FxFunctionCall() FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) { + // There's currently only 3 global functions. + // If this changes later, it won't be here! + if (MethodName == NAME_Sin || MethodName == NAME_Cos || MethodName == NAME_Sqrt) + { + if (Self != NULL) + { + ScriptPosition.Message(MSG_ERROR, "Global functions cannot have a self pointer"); + delete this; + return NULL; + } + FxExpression *x = new FxGlobalFunctionCall(MethodName, ArgList, ScriptPosition); + ArgList = NULL; + delete this; + return x->Resolve(ctx); + } + int min, max, special; if (MethodName == NAME_ACS_NamedExecuteWithResult || MethodName == NAME_CallACS) { @@ -2482,19 +2904,6 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) delete this; return x->Resolve(ctx); } - else - { - if (Self != NULL) - { - ScriptPosition.Message(MSG_ERROR, "Global variables cannot have a self pointer"); - delete this; - return NULL; - } - FxExpression *x = FxGlobalFunctionCall::StaticCreate(MethodName, ArgList, ScriptPosition); - ArgList = NULL; - delete this; - return x->Resolve(ctx); - } ScriptPosition.Message(MSG_ERROR, "Call to unknown function '%s'", MethodName.GetChars()); delete this; @@ -2558,7 +2967,7 @@ FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx) } else if ((*ArgList)[i]->ValueType != VAL_Int) { - if (ctx.lax && ((*ArgList)[i]->ValueType == VAL_Float)) + if ((*ArgList)[i]->ValueType == VAL_Float /* lax */) { (*ArgList)[i] = new FxIntCast((*ArgList)[i]); } @@ -2586,35 +2995,234 @@ FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx) // //========================================================================== -ExpVal FxActionSpecialCall::EvalExpression (AActor *self) +int DecoCallLineSpecial(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) { - int v[5] = {0,0,0,0,0}; - int special = Special; + assert(numparam > 2 && numparam < 7); + assert(numret == 1); + assert(param[0].Type == REGT_INT); + assert(param[1].Type == REGT_POINTER); + int v[5] = { 0 }; - if (Self != NULL) + for (int i = 2; i < numparam; ++i) { - self = Self->EvalExpression(self).GetPointer(); + v[i - 2] = param[i].i; } + ret->SetInt(LineSpecials[param[0].i](NULL, reinterpret_cast(param[1].a), false, v[0], v[1], v[2], v[3], v[4])); + return 1; +} +ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) +{ + assert(Self == NULL); + unsigned i = 0; + + build->Emit(OP_PARAMI, abs(Special)); // pass special number + build->Emit(OP_PARAM, 0, REGT_POINTER, 0); // pass self if (ArgList != NULL) { - for(unsigned i = 0; i < ArgList->Size(); i++) + for (; i < ArgList->Size(); ++i) { - if (special < 0) + FxExpression *argex = (*ArgList)[i]; + if (Special < 0 && i == 0) { - special = -special; - v[i] = -(*ArgList)[i]->EvalExpression(self).GetName(); + assert(argex->ValueType == VAL_Name); + assert(argex->isConstant()); + build->EmitParamInt(-static_cast(argex)->GetValue().GetName()); } else { - v[i] = (*ArgList)[i]->EvalExpression(self).GetInt(); + assert(argex->ValueType == VAL_Int); + if (argex->isConstant()) + { + build->EmitParamInt(static_cast(argex)->GetValue().GetInt()); + } + else + { + ExpEmit arg(argex->Emit(build)); + build->Emit(OP_PARAM, 0, arg.RegType, arg.RegNum); + arg.Free(build); + } } } } - ExpVal ret; - ret.Type = VAL_Int; - ret.Int = P_ExecuteSpecial(special, NULL, self, false, v[0], v[1], v[2], v[3], v[4]); - return ret; + // Call the DecoCallLineSpecial function to perform the desired special. + VMFunction *callfunc; + PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoCallLineSpecial, DecoCallLineSpecial); + + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); + assert(((PSymbolVMFunction *)sym)->Function != NULL); + callfunc = ((PSymbolVMFunction *)sym)->Function; + + ExpEmit dest(build, REGT_INT); + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2 + i, 1); + build->Emit(OP_RESULT, 0, REGT_INT, dest.RegNum); + return dest; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxTailable::Emit(VMFunctionBuilder *build) +{ + return Emit(build, false); +} + +//========================================================================== +// +// +// +//========================================================================== + +VMFunction *FxTailable::GetDirectFunction() +{ + return NULL; +} + +//========================================================================== +// +// FxVMFunctionCall +// +//========================================================================== + +FxVMFunctionCall::FxVMFunctionCall(PFunction *func, FArgumentList *args, const FScriptPosition &pos) +: FxTailable(pos) +{ + Function = func; + ArgList = args; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxVMFunctionCall::~FxVMFunctionCall() +{ + SAFE_DELETE(ArgList); +} + +//========================================================================== +// +// FxVMFunctionCall :: Resolve +// +//========================================================================== + +FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + bool failed = false; + + if (ArgList != NULL) + { + for (unsigned i = 0; i < ArgList->Size(); i++) + { + (*ArgList)[i] = (*ArgList)[i]->Resolve(ctx); + if ((*ArgList)[i] == NULL) failed = true; + } + } + if (failed) + { + delete this; + return NULL; + } + TArray &rets = Function->Variants[0].Proto->ReturnTypes; + if (rets.Size() == 0) + { + ReturnType = TypeVoid; + } + else + { + ReturnType = rets[0]; + // If more types are added to ParseNativeFunction(), add them here too. + if (rets[0] == TypeSInt32) ValueType = VAL_Int; + else if (rets[0] == TypeFloat64) ValueType = VAL_Float; + else if (rets[0] == TypeAngle) ValueType = VAL_Angle; + else if (rets[0] == TypeFixed) ValueType = VAL_Fixed; + else + { + ValueType = VAL_Int; + assert(0 && "Unhandled return type in FxVMFunctionCall::Resolve"); + } + } + return this; +} + +//========================================================================== +// +// Assumption: This call is being made to generate code inside an action +// method, so the first three address registers are all set up for such a +// function. (self, stateowner, callingstate) +// +//========================================================================== + +ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build, bool tailcall) +{ + assert(build->Registers[REGT_POINTER].GetMostUsed() >= 3); + int count = GetArgCount(); + + // Emit code to pass implied parameters + if (Function->Flags & VARF_Method) + { + build->Emit(OP_PARAM, 0, REGT_POINTER, 0); + count += 1; + } + if (Function->Flags & VARF_Action) + { + build->Emit(OP_PARAM, 0, REGT_POINTER, 1); + build->Emit(OP_PARAM, 0, REGT_POINTER, 2); + count += 2; + } + // Emit code to pass explicit parameters + if (ArgList != NULL) + { + for (unsigned i = 0; i < ArgList->Size(); ++i) + { + (*ArgList)[i]->Emit(build); + } + } + // Get a constant register for this function + int funcaddr = build->GetConstantAddress(Function->Variants[0].Implementation, ATAG_OBJECT); + // Emit the call + if (tailcall) + { // Tail call + build->Emit(OP_TAIL_K, funcaddr, count, 0); + return ExpEmit(); + } + else if (ReturnType != TypeVoid) + { // Call, expecting one result + assert(ReturnType != NULL); + ExpEmit reg(build, ReturnType->GetRegType()); + build->Emit(OP_CALL_K, funcaddr, count, 1); + build->Emit(OP_RESULT, 0, reg.RegType, reg.RegNum); + return reg; + } + else + { // Call, expecting no results + build->Emit(OP_CALL_K, funcaddr, count, 0); + return ExpEmit(); + } +} + +//========================================================================== +// +// FxVMFunctionCall :: GetDirectFunction +// +// If the function is not passed any explicit arguments, returns the +// function. Otherwise returns NULL. +// +//========================================================================== + +VMFunction *FxVMFunctionCall::GetDirectFunction() +{ + if (GetArgCount() == 0) + { + return GetVMFunction(); + } + return NULL; } //========================================================================== @@ -2641,10 +3249,238 @@ FxGlobalFunctionCall::~FxGlobalFunctionCall() SAFE_DELETE(ArgList); } +FxExpression *FxGlobalFunctionCall::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + + if (ArgList == NULL || ArgList->Size() != 1) + { + ScriptPosition.Message(MSG_ERROR, "%s only has one parameter", Name.GetChars()); + delete this; + return NULL; + } + + (*ArgList)[0] = (*ArgList)[0]->Resolve(ctx); + if ((*ArgList)[0] == NULL) + { + delete this; + return NULL; + } + + if (!(*ArgList)[0]->ValueType.isNumeric()) + { + ScriptPosition.Message(MSG_ERROR, "numeric value expected for parameter"); + delete this; + return NULL; + } + if ((*ArgList)[0]->isConstant()) + { + double v = static_cast((*ArgList)[0])->GetValue().GetFloat(); + if (Name == NAME_Sqrt) + { + v = sqrt(v); + } + else + { + v *= M_PI / 180.0; // convert from degrees to radians + v = (Name == NAME_Sin) ? sin(v) : cos(v); + } + FxExpression *x = new FxConstant(v, ScriptPosition); + delete this; + return x; + } + if ((*ArgList)[0]->ValueType == VAL_Int) + { + (*ArgList)[0] = new FxFloatCast((*ArgList)[0]); + } + ValueType = VAL_Float; + return this; +} //========================================================================== // // +//========================================================================== + +ExpEmit FxGlobalFunctionCall::Emit(VMFunctionBuilder *build) +{ + ExpEmit v = (*ArgList)[0]->Emit(build); + assert(!v.Konst && v.RegType == REGT_FLOAT); + + build->Emit(OP_FLOP, v.RegNum, v.RegNum, + (Name == NAME_Sqrt) ? FLOP_SQRT : + (Name == NAME_Sin) ? FLOP_SIN_DEG : + FLOP_COS_DEG); + return v; +} + +//========================================================================== +// +// FxSequence :: Resolve +// +//========================================================================== + +FxExpression *FxSequence::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + for (unsigned i = 0; i < Expressions.Size(); ++i) + { + if (NULL == (Expressions[i] = static_cast(Expressions[i]->Resolve(ctx)))) + { + delete this; + return NULL; + } + } + return this; +} + +//========================================================================== +// +// FxSequence :: Emit +// +//========================================================================== + +ExpEmit FxSequence::Emit(VMFunctionBuilder *build, bool tailcall) +{ + for (unsigned i = 0; i < Expressions.Size(); ++i) + { + ExpEmit v = Expressions[i]->Emit(build, tailcall ? i == Expressions.Size()-1 : false); + // Throw away any result. We don't care about it. + v.Free(build); + } + return ExpEmit(); +} + +//========================================================================== +// +// FxSequence :: GetDirectFunction +// +//========================================================================== + +VMFunction *FxSequence::GetDirectFunction() +{ + if (Expressions.Size() == 1) + { + return Expressions[0]->GetDirectFunction(); + } + return NULL; +} + +//========================================================================== +// +// FxIfStatement +// +//========================================================================== + +FxIfStatement::FxIfStatement(FxExpression *cond, FxTailable *true_part, + FxTailable *false_part, const FScriptPosition &pos) +: FxTailable(pos) +{ + Condition = cond; + WhenTrue = true_part; + WhenFalse = false_part; + assert(cond != NULL); +} + +FxIfStatement::~FxIfStatement() +{ + SAFE_DELETE(Condition); + SAFE_DELETE(WhenTrue); + SAFE_DELETE(WhenFalse); +} + +FxExpression *FxIfStatement::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + if (WhenTrue == NULL && WhenFalse == NULL) + { // We don't do anything either way, so disappear + delete this; + return NULL; + } + Condition = Condition->ResolveAsBoolean(ctx); + ABORT(Condition); + if (WhenTrue != NULL) + { + WhenTrue = static_cast(WhenTrue->Resolve(ctx)); + ABORT(WhenTrue); + } + if (WhenFalse != NULL) + { + WhenFalse = static_cast(WhenFalse->Resolve(ctx)); + ABORT(WhenFalse); + } + ValueType = VAL_Unknown; + + if (Condition->isConstant()) + { + ExpVal condval = static_cast(Condition)->GetValue(); + bool result = condval.GetBool(); + + FxTailable *e = result ? WhenTrue : WhenFalse; + delete (result ? WhenFalse : WhenTrue); + WhenTrue = WhenFalse = NULL; + delete this; + return e; + } + return this; +} + +ExpEmit FxIfStatement::Emit(VMFunctionBuilder *build, bool tailcall) +{ + ExpEmit v; + size_t jumpspot; + FxTailable *path1, *path2; + int condcheck; + + // This is pretty much copied from FxConditional, except we don't + // keep any results. + ExpEmit cond = Condition->Emit(build); + assert(cond.RegType == REGT_INT && !cond.Konst); + + if (WhenTrue != NULL) + { + path1 = WhenTrue; + path2 = WhenFalse; + condcheck = 1; + } + else + { + // When there is only a false path, reverse the condition so we can + // treat it as a true path. + assert(WhenFalse != NULL); + path1 = WhenFalse; + path2 = NULL; + condcheck = 0; + } + + // Test condition. + build->Emit(OP_EQ_K, condcheck, cond.RegNum, build->GetConstantInt(0)); + jumpspot = build->Emit(OP_JMP, 0); + cond.Free(build); + + // Evaluate first path + v = path1->Emit(build, tailcall); + v.Free(build); + if (path2 != NULL) + { + size_t path1jump = build->Emit(OP_JMP, 0); + // Evaluate second path + build->BackpatchToHere(jumpspot); + v = path2->Emit(build, tailcall); + v.Free(build); + jumpspot = path1jump; + } + build->BackpatchToHere(jumpspot); + if (tailcall) + { + // When tailcall is true, execution is not expected to get past + // this if statement, so issue a RET. + build->Emit(OP_RET, RET_FINAL, REGT_NIL, 0); + } + return ExpEmit(); +} + +//========================================================================== // //========================================================================== @@ -2686,7 +3522,7 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx) if (basex->isConstant()) { - FName clsname = basex->EvalExpression(NULL).GetName(); + FName clsname = static_cast(basex)->GetValue().GetName(); const PClass *cls = NULL; if (clsname != NAME_None) @@ -2694,12 +3530,7 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx) cls = PClass::FindClass(clsname); if (cls == NULL) { - if (!ctx.lax) - { - ScriptPosition.Message(MSG_ERROR,"Unknown class name '%s'", clsname.GetChars()); - delete this; - return NULL; - } + /* lax */ // Since this happens in released WADs it must pass without a terminal error... :( ScriptPosition.Message(MSG_WARNING, "Unknown class name '%s'", @@ -2729,23 +3560,52 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx) // //========================================================================== -ExpVal FxClassTypeCast::EvalExpression (AActor *self) +int DecoNameToClass(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) { - FName clsname = basex->EvalExpression(NULL).GetName(); + assert(numparam == 2); + assert(numret == 1); + assert(param[0].Type == REGT_INT); + assert(param[1].Type == REGT_POINTER); + assert(ret->RegType == REGT_POINTER); + + FName clsname = ENamedName(param[0].i); const PClass *cls = PClass::FindClass(clsname); + const PClass *desttype = reinterpret_cast(param[0].a); if (!cls->IsDescendantOf(desttype)) { Printf("class '%s' is not compatible with '%s'", clsname.GetChars(), desttype->TypeName.GetChars()); cls = NULL; } - - ExpVal ret; - ret.Type = VAL_Class; - ret.pointer = (void*)cls; - return ret; + ret->SetPointer(const_cast(cls), ATAG_OBJECT); + return 1; } +ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build) +{ + if (basex->ValueType != VAL_Name) + { + return ExpEmit(build->GetConstantAddress(NULL, ATAG_OBJECT), REGT_POINTER, true); + } + ExpEmit clsname = basex->Emit(build); + assert(!clsname.Konst); + ExpEmit dest(build, REGT_POINTER); + build->Emit(OP_PARAM, 0, clsname.RegType, clsname.RegNum); + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(const_cast(desttype), ATAG_OBJECT)); + + // Call the DecoNameToClass function to convert from 'name' to class. + VMFunction *callfunc; + PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoNameToClass, DecoNameToClass); + + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); + assert(((PSymbolVMFunction *)sym)->Function != NULL); + callfunc = ((PSymbolVMFunction *)sym)->Function; + + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1); + build->Emit(OP_RESULT, 0, REGT_POINTER, dest.RegNum); + clsname.Free(build); + return dest; +} //========================================================================== // @@ -2756,19 +3616,19 @@ ExpVal FxClassTypeCast::EvalExpression (AActor *self) FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); - if (ctx.cls->ActorInfo == NULL || ctx.cls->ActorInfo->NumOwnedStates == 0) + if (ctx.cls->NumOwnedStates == 0) { // This can't really happen assert(false); } - if (ctx.cls->ActorInfo->NumOwnedStates <= index) + if (ctx.cls->NumOwnedStates <= index) { ScriptPosition.Message(MSG_ERROR, "%s: Attempt to jump to non existing state index %d", ctx.cls->TypeName.GetChars(), index); delete this; return NULL; } - FxExpression *x = new FxConstant(ctx.cls->ActorInfo->OwnedStates + index, ScriptPosition); + FxExpression *x = new FxConstant(ctx.cls->OwnedStates + index, ScriptPosition); delete this; return x; } @@ -2816,11 +3676,11 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) } else if (names[0] == NAME_Super) { - scope = ctx.cls->ParentClass; + scope = dyn_cast(ctx.cls->ParentClass); } else { - scope = PClass::FindClass(names[0]); + scope = PClass::FindActor(names[0]); if (scope == NULL) { ScriptPosition.Message(MSG_ERROR, "Unknown class '%s' in state label", names[0].GetChars()); @@ -2840,21 +3700,11 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) // If the label is class specific we can resolve it right here if (names[1] != NAME_None) { - if (scope->ActorInfo == NULL) - { - ScriptPosition.Message(MSG_ERROR, "'%s' has no actorinfo", names[0].GetChars()); - delete this; - return NULL; - } - destination = scope->ActorInfo->FindState(names.Size()-1, &names[1], false); + destination = scope->FindState(names.Size()-1, &names[1], false); if (destination == NULL) { - ScriptPosition.Message(ctx.lax? MSG_WARNING:MSG_ERROR, "Unknown state jump destination"); - if (!ctx.lax) - { - delete this; - return NULL; - } + ScriptPosition.Message(MSG_WARNING, "Unknown state jump destination"); + /* lax */ return this; } } @@ -2874,89 +3724,82 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) // //========================================================================== -ExpVal FxMultiNameState::EvalExpression (AActor *self) +static int DoFindState(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, FName *names, int numnames) { - ExpVal ret; - ret.Type = VAL_State; - ret.pointer = self->GetClass()->ActorInfo->FindState(names.Size(), &names[0]); - if (ret.pointer == NULL) + PARAM_OBJECT_AT(0, self, AActor); + FState *state = self->GetClass()->FindState(numparam - 1, names); + if (state == NULL) { - const char *dot=""; + const char *dot = ""; Printf("Jump target '"); - for (unsigned int i=0;iGetClass()->TypeName.GetChars()); } - return ret; + ret->SetPointer(state, ATAG_STATE); + return 1; } - - -//========================================================================== -// -// NOTE: I don't expect any of the following to survive Doomscript ;) -// -//========================================================================== - -FStateExpressions StateParams; - - -//========================================================================== -// -// -// -//========================================================================== - -void FStateExpressions::Clear() +// Find a state with any number of dots in its name. +int DecoFindMultiNameState(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) { - for(unsigned i=0; i 1); + assert(numret == 1); + assert(ret->RegType == REGT_POINTER); + + FName *names = (FName *)alloca((numparam - 1) * sizeof(FName)); + for (int i = 1; i < numparam; ++i) { - if (expressions[i].expr != NULL && !expressions[i].cloned) - { - delete expressions[i].expr; - } + PARAM_NAME_AT(i, zaname); + names[i - 1] = zaname; } - expressions.Clear(); + return DoFindState(stack, param, numparam, ret, names, numparam - 1); } -//========================================================================== -// -// -// -//========================================================================== - -int FStateExpressions::Add(FxExpression *x, const PClass *o, bool c) +// Find a state without any dots in its name. +int DecoFindSingleNameState(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) { - int idx = expressions.Reserve(1); - FStateExpression &exp = expressions[idx]; - exp.expr = x; - exp.owner = o; - exp.constant = c; - exp.cloned = false; - return idx; + assert(numparam == 2); + assert(numret == 1); + assert(ret->RegType == REGT_POINTER); + + PARAM_NAME_AT(1, zaname); + return DoFindState(stack, param, numparam, ret, &zaname, 1); } -//========================================================================== -// -// -// -//========================================================================== - -int FStateExpressions::Reserve(int num, const PClass *cls) +ExpEmit FxMultiNameState::Emit(VMFunctionBuilder *build) { - int idx = expressions.Reserve(num); - FStateExpression *exp = &expressions[idx]; - for(int i=0; iEmit(OP_PARAM, 0, REGT_POINTER, 1); // pass stateowner + for (unsigned i = 0; i < names.Size(); ++i) { - exp[i].expr = NULL; - exp[i].owner = cls; - exp[i].constant = false; - exp[i].cloned = false; + build->EmitParamInt(names[i]); } - return idx; + + // For one name, use the DecoFindSingleNameState function. For more than + // one name, use the DecoFindMultiNameState function. + VMFunction *callfunc; + PSymbol *sym; + + if (names.Size() == 1) + { + sym = FindDecorateBuiltinFunction(NAME_DecoFindSingleNameState, DecoFindSingleNameState); + } + else + { + sym = FindDecorateBuiltinFunction(NAME_DecoFindMultiNameState, DecoFindMultiNameState); + } + + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); + assert(((PSymbolVMFunction *)sym)->Function != NULL); + callfunc = ((PSymbolVMFunction *)sym)->Function; + + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), names.Size() + 1, 1); + build->Emit(OP_RESULT, 0, REGT_POINTER, dest.RegNum); + return dest; } //========================================================================== @@ -2965,94 +3808,54 @@ int FStateExpressions::Reserve(int num, const PClass *cls) // //========================================================================== -void FStateExpressions::Set(int num, FxExpression *x, bool cloned) +FxDamageValue::FxDamageValue(FxExpression *v, bool calc) +: FxExpression(v->ScriptPosition) { - if (num >= 0 && num < int(Size())) + val = v; + ValueType = VAL_Unknown; + Calculated = calc; + MyFunction = NULL; + + if (!calc) { - assert(expressions[num].expr == NULL || expressions[num].cloned); - expressions[num].expr = x; - expressions[num].cloned = cloned; + assert(v->isConstant() && "Non-calculated damage must be constant"); } } -//========================================================================== -// -// -// -//========================================================================== - -void FStateExpressions::Copy(int dest, int src, int cnt) +FxDamageValue::~FxDamageValue() { - for(int i=0; iValueType.isNumeric()) { - if (expressions[i].cloned) - { - // Now that everything coming before has been resolved we may copy the actual pointer. - unsigned ii = unsigned((intptr_t)expressions[i].expr); - expressions[i].expr = expressions[ii].expr; - } - else if (expressions[i].expr != NULL) - { - ctx.cls = expressions[i].owner; - ctx.isconst = expressions[i].constant; - expressions[i].expr = expressions[i].expr->Resolve(ctx); - if (expressions[i].expr == NULL) - { - errorcount++; - } - else if (expressions[i].constant && !expressions[i].expr->isConstant()) - { - expressions[i].expr->ScriptPosition.Message(MSG_ERROR, "Constant expression expected"); - errorcount++; - } - } + ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); + delete this; + return NULL; } - - for(unsigned i=0; iisresolved) - { - expressions[i].expr->ScriptPosition.Message(MSG_ERROR, "Expression at index %d not resolved\n", i); - errorcount++; - } - } - } - - return errorcount; + return this; } -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FStateExpressions::Get(int num) +// This is a highly-specialized "expression" type that emits a complete function. +ExpEmit FxDamageValue::Emit(VMFunctionBuilder *build) { - if (num >= 0 && num < int(Size())) - return expressions[num].expr; - return NULL; -} + if (val->isConstant()) + { + build->EmitRetInt(0, false, static_cast(val)->GetValue().Int); + } + else + { + ExpEmit emitval = val->Emit(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); + return ExpEmit(); +} diff --git a/src/thingdef/thingdef_function.cpp b/src/thingdef/thingdef_function.cpp deleted file mode 100644 index fcc9360170..0000000000 --- a/src/thingdef/thingdef_function.cpp +++ /dev/null @@ -1,296 +0,0 @@ -/* -** thingdef_function.cpp -** -** Expression function evaluation. -** -**--------------------------------------------------------------------------- -** Copyright 2012 David Hill -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** 4. When not used as part of ZDoom or a ZDoom derivative, this code will be -** covered by the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 3 of the License, or (at -** your option) any later version. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -*/ - -#include - -#include "tables.h" -#include "tarray.h" -#include "thingdef.h" -#include "thingdef_exp.h" -#include "actor.h" -#include "actorptrselect.h" - -static TMap CreatorMap; - -//========================================================================== -// -// FxGlobalFunctionCall::AddCreator -// -//========================================================================== - -void FxGlobalFunctionCall::AddCreator(FName methodname, Creator creator) -{ - CreatorMap.Insert(methodname, creator); -} - - -//========================================================================== -// -// FxGlobalFunctionCall::ResolveArgs -// -// Handles common Resolve processing of args. -// -//========================================================================== - -FxExpression *FxGlobalFunctionCall::ResolveArgs(FCompileContext &ctx, unsigned min, unsigned max, bool numeric) -{ - unsigned i = ArgList ? ArgList->Size() : 0; - - if (i < min || i > max) - { - ScriptPosition.Message(MSG_ERROR, "%s expects %u to %u parameters", Name.GetChars(), min, max); - delete this; - return NULL; - } - - while (i--) - { - if (!((*ArgList)[i] = (*ArgList)[i]->Resolve(ctx))) - { - delete this; - return NULL; - } - - if (numeric && !(*ArgList)[i]->ValueType.isNumeric()) - { - ScriptPosition.Message(MSG_ERROR, "numeric value expected for parameter"); - delete this; - return NULL; - } - } - - return this; -} - -//========================================================================== -// -// FxGlobalFunctionCall::StaticCreate -// -//========================================================================== - -FxExpression *FxGlobalFunctionCall::StaticCreate -(FName methodname, FArgumentList *args, const FScriptPosition &pos) -{ - Creator *creator = CreatorMap.CheckKey(methodname); - - if (!creator) - { - pos.Message(MSG_ERROR, "Call to unknown function '%s'", methodname.GetChars()); - return NULL; - } - - return (*creator)(methodname, args, pos); -} - -//========================================================================== -// -// Function: cos/sin -// -//========================================================================== - -class FxGlobalFunctionCall_Cos : public FxGlobalFunctionCall -{ -public: - GLOBALFUNCTION_DEFINE(Cos); - - FxExpression *Resolve(FCompileContext& ctx) - { - CHECKRESOLVED(); - - ValueType = VAL_Float; - return ResolveArgs(ctx, 1, 1, true); - } - - ExpVal EvalExpression(AActor *self) - { - double v = (*ArgList)[0]->EvalExpression(self).GetFloat(); - ExpVal ret; - ret.Type = VAL_Float; - - // shall we use the CRT's sin and cos functions? - angle_t angle = angle_t(v * ANGLE_90/90.); - if (Name == NAME_Sin) ret.Float = FIXED2DBL (finesine[angle>>ANGLETOFINESHIFT]); - else ret.Float = FIXED2DBL (finecosine[angle>>ANGLETOFINESHIFT]); - return ret; - } -}; - -GLOBALFUNCTION_ADDER(Cos); -GLOBALFUNCTION_ADDER_NAMED(Cos, Sin); - -//========================================================================== -// -// Function: sqrt -// -//========================================================================== - -class FxGlobalFunctionCall_Sqrt : public FxGlobalFunctionCall -{ -public: - GLOBALFUNCTION_DEFINE(Sqrt); - - FxExpression *Resolve(FCompileContext& ctx) - { - CHECKRESOLVED(); - - if (!ResolveArgs(ctx, 1, 1, true)) - return NULL; - - ValueType = VAL_Float; - return this; - } - - ExpVal EvalExpression(AActor *self) - { - ExpVal ret; - ret.Type = VAL_Float; - ret.Float = sqrt((*ArgList)[0]->EvalExpression(self).GetFloat()); - return ret; - } -}; - -GLOBALFUNCTION_ADDER(Sqrt); - -//========================================================================== -// -// Function: checkclass -// -//========================================================================== - -class FxGlobalFunctionCall_CheckClass : public FxGlobalFunctionCall -{ - public: - GLOBALFUNCTION_DEFINE(CheckClass); - - FxExpression *Resolve(FCompileContext& ctx) - { - CHECKRESOLVED(); - - if (!ResolveArgs(ctx, 1, 3, false)) - return NULL; - - for (int i = ArgList->Size(); i > 1;) - { - if (!(*ArgList)[--i]->ValueType.isNumeric()) - { - ScriptPosition.Message(MSG_ERROR, "numeric value expected for parameter"); - delete this; - return NULL; - } - } - - switch ((*ArgList)[0]->ValueType.Type) - { - case VAL_Class: case VAL_Name:break; - default: - ScriptPosition.Message(MSG_ERROR, "actor class expected for parameter"); - delete this; - return NULL; - } - - ValueType = VAL_Float; - return this; - } - - ExpVal EvalExpression(AActor *self) - { - ExpVal ret; - ret.Type = VAL_Int; - - const PClass * checkclass; - { - ExpVal v = (*ArgList)[0]->EvalExpression(self); - checkclass = v.GetClass(); - if (!checkclass) - { - checkclass = PClass::FindClass(v.GetName()); - if (!checkclass) { ret.Int = 0; return ret; } - } - } - - bool match_superclass = false; - int pick_pointer = AAPTR_DEFAULT; - - switch (ArgList->Size()) - { - case 3: match_superclass = (*ArgList)[2]->EvalExpression(self).GetBool(); - case 2: pick_pointer = (*ArgList)[1]->EvalExpression(self).GetInt(); - } - - self = COPY_AAPTR(self, pick_pointer); - if (!self){ ret.Int = 0; return ret; } - ret.Int = match_superclass ? checkclass->IsAncestorOf(self->GetClass()) : checkclass == self->GetClass(); - return ret; - } - }; - -GLOBALFUNCTION_ADDER(CheckClass); - -//========================================================================== -// -// Function: ispointerequal -// -//========================================================================== - -class FxGlobalFunctionCall_IsPointerEqual : public FxGlobalFunctionCall -{ - public: - GLOBALFUNCTION_DEFINE(IsPointerEqual); - - FxExpression *Resolve(FCompileContext& ctx) - { - CHECKRESOLVED(); - - if (!ResolveArgs(ctx, 2, 2, true)) - return NULL; - - ValueType = VAL_Int; - return this; - } - - ExpVal EvalExpression(AActor *self) - { - ExpVal ret; - ret.Type = VAL_Int; - ret.Int = COPY_AAPTR(self, (*ArgList)[0]->EvalExpression(self).GetInt()) == COPY_AAPTR(self, (*ArgList)[1]->EvalExpression(self).GetInt()); - return ret; - } -}; - -GLOBALFUNCTION_ADDER(IsPointerEqual); \ No newline at end of file diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index 61922feaf9..1db878bfa8 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -67,37 +67,56 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def); // //========================================================================== -FxExpression *ParseParameter(FScanner &sc, PClass *cls, char type, bool constant) +FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool constant) { FxExpression *x = NULL; int v; - switch(type) + if (type == TypeSound) { - case 'S': - case 's': // Sound name sc.MustGetString(); x = new FxConstant(FSoundID(sc.String), sc); - break; - - case 'M': - case 'm': // Actor name + } + else if (type == TypeSInt32 || type == TypeFloat64) + { + x = ParseExpression (sc, cls); + if (constant && !x->isConstant()) + { + sc.ScriptMessage("Default parameter must be constant."); + FScriptPosition::ErrorCounter++; + } + // Do automatic coercion between ints and floats. + if (type == TypeSInt32) + { + if (x->ValueType != VAL_Int) + { + x = new FxIntCast(x); + } + } + else + { + if (x->ValueType != VAL_Float) + { + x = new FxFloatCast(x); + } + } + } + else if (type == TypeName || type == TypeString) + { sc.SetEscape(true); sc.MustGetString(); sc.SetEscape(false); - x = new FxClassTypeCast(RUNTIME_CLASS(AActor), new FxConstant(FName(sc.String), sc)); - break; - - case 'T': - case 't': // String - sc.SetEscape(true); - sc.MustGetString(); - sc.SetEscape(false); - x = new FxConstant(sc.String[0]? FName(sc.String) : NAME_None, sc); - break; - - case 'C': - case 'c': // Color + if (type == TypeName) + { + x = new FxConstant(sc.String[0] ? FName(sc.String) : NAME_None, sc); + } + else + { + x = new FxConstant(strbin1(sc.String), sc); + } + } + else if (type == TypeColor) + { sc.MustGetString (); if (sc.Compare("none")) { @@ -113,16 +132,12 @@ FxExpression *ParseParameter(FScanner &sc, PClass *cls, char type, bool constant // 0 needs to be the default so we have to mark the color. v = MAKEARGB(1, RPART(c), GPART(c), BPART(c)); } - { - ExpVal val; - val.Type = VAL_Color; - val.Int = v; - x = new FxConstant(val, sc); - break; - } - - case 'L': - case 'l': + ExpVal val; + val.Type = VAL_Color; + val.Int = v; + x = new FxConstant(val, sc); + } + else if (type == TypeState) { // This forces quotation marks around the state name. sc.MustGetToken(TK_StringConst); @@ -142,24 +157,18 @@ FxExpression *ParseParameter(FScanner &sc, PClass *cls, char type, bool constant { x = new FxMultiNameState(sc.String, sc); } - break; } - - case 'X': - case 'x': - case 'Y': - case 'y': - x = ParseExpression (sc, cls); - if (constant && !x->isConstant()) - { - sc.ScriptMessage("Default parameter must be constant."); - FScriptPosition::ErrorCounter++; - } - break; - - default: - assert(false); - return NULL; + else if (type->GetClass() == RUNTIME_CLASS(PClassPointer)) + { // Actor name + sc.SetEscape(true); + sc.MustGetString(); + sc.SetEscape(false); + x = new FxClassTypeCast(static_cast(type)->ClassRestriction, new FxConstant(FName(sc.String), sc)); + } + else + { + assert(false && "Unknown parameter type"); + x = NULL; } return x; } @@ -172,7 +181,7 @@ FxExpression *ParseParameter(FScanner &sc, PClass *cls, char type, bool constant // //========================================================================== -static void ParseConstant (FScanner &sc, PSymbolTable * symt, PClass *cls) +static void ParseConstant (FScanner &sc, PSymbolTable *symt, PClassActor *cls) { // Read the type and make sure it's int or float. if (sc.CheckToken(TK_Int) || sc.CheckToken(TK_Float)) @@ -184,25 +193,33 @@ static void ParseConstant (FScanner &sc, PSymbolTable * symt, PClass *cls) FxExpression *expr = ParseExpression (sc, cls); sc.MustGetToken(';'); - ExpVal val = expr->EvalExpression(NULL); - delete expr; - PSymbolConst *sym = new PSymbolConst(symname); - if (type == TK_Int) + if (!expr->isConstant()) { - sym->ValueType = VAL_Int; - sym->Value = val.GetInt(); + sc.ScriptMessage("Constant definition is not a constant"); + FScriptPosition::ErrorCounter++; } else { - sym->ValueType = VAL_Float; - sym->Float = val.GetFloat(); - } - if (symt->AddSymbol (sym) == NULL) - { - delete sym; - sc.ScriptMessage ("'%s' is already defined in '%s'.", - symname.GetChars(), cls? cls->TypeName.GetChars() : "Global"); - FScriptPosition::ErrorCounter++; + ExpVal val = static_cast(expr)->GetValue(); + delete expr; + PSymbolConstNumeric *sym; + if (type == TK_Int) + { + sym = new PSymbolConstNumeric(symname, TypeSInt32); + sym->Value = val.GetInt(); + } + else + { + sym = new PSymbolConstNumeric(symname, TypeFloat64); + sym->Float = val.GetFloat(); + } + if (symt->AddSymbol (sym) == NULL) + { + delete sym; + sc.ScriptMessage ("'%s' is already defined in '%s'.", + symname.GetChars(), cls? cls->TypeName.GetChars() : "Global"); + FScriptPosition::ErrorCounter++; + } } } else @@ -220,7 +237,7 @@ static void ParseConstant (FScanner &sc, PSymbolTable * symt, PClass *cls) // //========================================================================== -static void ParseEnum (FScanner &sc, PSymbolTable *symt, PClass *cls) +static void ParseEnum (FScanner &sc, PSymbolTable *symt, PClassActor *cls) { int currvalue = 0; @@ -232,11 +249,18 @@ static void ParseEnum (FScanner &sc, PSymbolTable *symt, PClass *cls) if (sc.CheckToken('=')) { FxExpression *expr = ParseExpression (sc, cls); - currvalue = expr->EvalExpression(NULL).GetInt(); + if (!expr->isConstant()) + { + sc.ScriptMessage("'%s' must be constant", symname.GetChars()); + FScriptPosition::ErrorCounter++; + } + else + { + currvalue = static_cast(expr)->GetValue().GetInt(); + } delete expr; } - PSymbolConst *sym = new PSymbolConst(symname); - sym->ValueType = VAL_Int; + PSymbolConstNumeric *sym = new PSymbolConstNumeric(symname, TypeSInt32); sym->Value = currvalue; if (symt->AddSymbol (sym) == NULL) { @@ -255,19 +279,175 @@ static void ParseEnum (FScanner &sc, PSymbolTable *symt, PClass *cls) //========================================================================== // -// ParseNativeVariable +// ParseArgListDef // -// Parses a native variable declaration. +// Parses the argument list from a function declaration. // //========================================================================== -static void ParseNativeVariable (FScanner &sc, PSymbolTable * symt, PClass *cls) +static void ParseArgListDef(FScanner &sc, PClassActor *cls, + TArray &args, TArray &argflags) { - FExpressionType valuetype; + if (!sc.CheckToken(')')) + { + while (sc.TokenType != ')') + { + int flags = 0; + PType *type = NULL; + PClass *restrict = NULL; + + // Retrieve flags before type name + for (;;) + { + if (sc.CheckToken(TK_Coerce) || sc.CheckToken(TK_Native)) + { + } + else + { + break; + } + } + // Read the variable type + sc.MustGetAnyToken(); + switch (sc.TokenType) + { + case TK_Bool: + case TK_Int: + type = TypeSInt32; + break; + + case TK_Float: + type = TypeFloat64; + break; + + case TK_Sound: type = TypeSound; break; + case TK_String: type = TypeString; break; + case TK_Name: type = TypeName; break; + case TK_State: type = TypeState; break; + case TK_Color: type = TypeColor; break; + case TK_Class: + sc.MustGetToken('<'); + sc.MustGetToken(TK_Identifier); // Get class name + restrict = PClass::FindClass(sc.String); + if (restrict == NULL) + { + sc.ScriptMessage("Unknown class type %s", sc.String); + FScriptPosition::ErrorCounter++; + } + else + { + type = NewClassPointer(restrict); + } + sc.MustGetToken('>'); + break; + case TK_Ellipsis: + // Making the final type NULL signals a varargs function. + type = NULL; + sc.MustGetToken(')'); + sc.UnGet(); + break; + default: + sc.ScriptMessage ("Unknown variable type %s", sc.TokenName(sc.TokenType, sc.String).GetChars()); + type = TypeSInt32; + FScriptPosition::ErrorCounter++; + break; + } + // Read the optional variable name + if (!sc.CheckToken(',') && !sc.CheckToken(')')) + { + sc.MustGetToken(TK_Identifier); + } + else + { + sc.UnGet(); + } + + if (sc.CheckToken('=')) + { + flags |= VARF_Optional; + FxExpression *def = ParseParameter(sc, cls, type, true); + delete def; + } + + args.Push(type); + argflags.Push(flags); + sc.MustGetAnyToken(); + if (sc.TokenType != ',' && sc.TokenType != ')') + { + sc.ScriptError ("Expected ',' or ')' but got %s instead", sc.TokenName(sc.TokenType, sc.String).GetChars()); + } + } + } + sc.MustGetToken(';'); +} + +//========================================================================== +// +// ParseFunctionDef +// +// Parses a native function's parameters and adds it to the class, +// if possible. +// +//========================================================================== + +void ParseFunctionDef(FScanner &sc, PClassActor *cls, FName funcname, + TArray &rets, DWORD funcflags) +{ + assert(cls != NULL); + + const AFuncDesc *afd; + TArray args; + TArray argflags; + + afd = FindFunction(funcname); + if (afd == NULL) + { + sc.ScriptMessage ("The function '%s' has not been exported from the executable.", funcname.GetChars()); + FScriptPosition::ErrorCounter++; + } + sc.MustGetToken('('); + + if (funcflags & VARF_Method) + { + args.Push(NewClassPointer(cls)), argflags.Push(0); // implied self pointer + } + if (funcflags & VARF_Action) + { + args.Push(NewClassPointer(RUNTIME_CLASS(AActor))), argflags.Push(0); // implied stateowner pointer + args.Push(TypeState), argflags.Push(0); // implied callingstate pointer + } + ParseArgListDef(sc, cls, args, argflags); + + if (afd != NULL) + { + PFunction *sym = new PFunction(funcname); + sym->AddVariant(NewPrototype(rets, args), argflags, *(afd->VMPointer)); + sym->Flags = funcflags; + if (cls->Symbols.AddSymbol(sym) == NULL) + { + delete sym; + sc.ScriptMessage ("'%s' is already defined in class '%s'.", + funcname.GetChars(), cls->TypeName.GetChars()); + FScriptPosition::ErrorCounter++; + } + } +} + +//========================================================================== +// +// ParseNativeFunction +// +// Parses a non-action function declaration. +// +//========================================================================== + +static void ParseNativeFunction(FScanner &sc, PClassActor *cls) +{ + TArray rets(1); if (sc.LumpNum == -1 || Wads.GetLumpFile(sc.LumpNum) > 0) { - sc.ScriptMessage ("variables can only be imported by internal class and actor definitions!"); + sc.ScriptMessage ("functions can only be declared by native actors!"); FScriptPosition::ErrorCounter++; } @@ -276,66 +456,34 @@ static void ParseNativeVariable (FScanner &sc, PSymbolTable * symt, PClass *cls) switch (sc.TokenType) { case TK_Int: - valuetype = VAL_Int; + case TK_Bool: + rets.Push(TypeSInt32); break; case TK_Float: - valuetype = VAL_Float; + rets.Push(TypeFloat64); break; case TK_Angle_t: - valuetype = VAL_Angle; + rets.Push(TypeAngle); break; case TK_Fixed_t: - valuetype = VAL_Fixed; - break; - - case TK_Bool: - valuetype = VAL_Bool; + rets.Push(TypeFixed); break; case TK_Identifier: - valuetype = VAL_Object; + rets.Push(NewPointer(RUNTIME_CLASS(DObject))); // Todo: Object type sc.ScriptError("Object type variables not implemented yet!"); break; default: - sc.ScriptError("Invalid variable type %s", sc.String); + sc.ScriptError("Invalid return type %s", sc.String); return; } - sc.MustGetToken(TK_Identifier); - FName symname = sc.String; - if (sc.CheckToken('[')) - { - FxExpression *expr = ParseExpression (sc, cls); - int maxelems = expr->EvalExpression(NULL).GetInt(); - delete expr; - sc.MustGetToken(']'); - valuetype.MakeArray(maxelems); - } - sc.MustGetToken(';'); - - const FVariableInfo *vi = FindVariable(symname, cls); - if (vi == NULL) - { - sc.ScriptError("Unknown native variable '%s'", symname.GetChars()); - } - - PSymbolVariable *sym = new PSymbolVariable(symname); - sym->offset = vi->address; // todo - sym->ValueType = valuetype; - sym->bUserVar = false; - - if (symt->AddSymbol (sym) == NULL) - { - delete sym; - sc.ScriptMessage ("'%s' is already defined in '%s'.", - symname.GetChars(), cls? cls->TypeName.GetChars() : "Global"); - FScriptPosition::ErrorCounter++; - } + ParseFunctionDef(sc, cls, sc.String, rets, VARF_Method); } //========================================================================== @@ -346,9 +494,10 @@ static void ParseNativeVariable (FScanner &sc, PSymbolTable * symt, PClass *cls) // //========================================================================== -static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClass *cls) +static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cls) { - FExpressionType valuetype; + PType *type; + int maxelems = 1; // Only non-native classes may have user variables. if (!cls->bRuntimeClass) @@ -363,7 +512,7 @@ static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClass *cls) sc.ScriptMessage("User variables must be of type int"); FScriptPosition::ErrorCounter++; } - valuetype = VAL_Int; + type = TypeSInt32; sc.MustGetToken(TK_Identifier); // For now, restrict user variables to those that begin with "user_" to guarantee @@ -374,24 +523,7 @@ static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClass *cls) FScriptPosition::ErrorCounter++; } - - FName symname = sc.String; - if (sc.CheckToken('[')) - { - FxExpression *expr = ParseExpression(sc, cls); - int maxelems = expr->EvalExpression(NULL).GetInt(); - delete expr; - sc.MustGetToken(']'); - if (maxelems <= 0) - { - sc.ScriptMessage("Array size must be positive"); - FScriptPosition::ErrorCounter++; - maxelems = 1; - } - valuetype.MakeArray(maxelems); - } - sc.MustGetToken(';'); // We must ensure that we do not define duplicates, even when they come from a parent table. if (symt->FindSymbol(symname, true) != NULL) @@ -402,10 +534,32 @@ static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClass *cls) return; } - PSymbolVariable *sym = new PSymbolVariable(symname); - sym->offset = cls->Extend(sizeof(int) * (valuetype.Type == VAL_Array ? valuetype.size : 1)); - sym->ValueType = valuetype; - sym->bUserVar = true; + if (sc.CheckToken('[')) + { + FxExpression *expr = ParseExpression(sc, cls); + if (!expr->isConstant()) + { + sc.ScriptMessage("Array size must be a constant"); + FScriptPosition::ErrorCounter++; + maxelems = 1; + } + else + { + maxelems = static_cast(expr)->GetValue().GetInt(); + } + sc.MustGetToken(']'); + if (maxelems <= 0) + { + sc.ScriptMessage("Array size must be positive"); + FScriptPosition::ErrorCounter++; + maxelems = 1; + } + type = NewArray(type, maxelems); + } + sc.MustGetToken(';'); + + PField *sym = new PField(symname, type, 0); + sym->Offset = cls->Extend(sizeof(int) * maxelems); if (symt->AddSymbol(sym) == NULL) { delete sym; @@ -443,9 +597,9 @@ void HandleActorFlag(FScanner &sc, Baggage &bag, const char *part1, const char * { FFlagDef *fd; - if ( (fd = FindFlag (bag.Info->Class, part1, part2)) ) + if ( (fd = FindFlag (bag.Info, part1, part2)) ) { - AActor *defaults = (AActor*)bag.Info->Class->Defaults; + AActor *defaults = (AActor*)bag.Info->Defaults; if (fd->structoffset == -1) // this is a deprecated flag that has been changed into a real property { HandleDeprecatedFlags(defaults, bag.Info, mod=='+', fd->flagbit); @@ -565,17 +719,17 @@ static int ParseThingActivation (FScanner &sc) static FState *CheckState(FScanner &sc, PClass *type) { - int v=0; + int v = 0; if (sc.GetString() && !sc.Crossed) { if (sc.Compare("0")) return NULL; else if (sc.Compare("PARENT")) { - FState * state = NULL; + FState *state = NULL; sc.MustGetString(); - FActorInfo * info = type->ParentClass->ActorInfo; + PClassActor *info = dyn_cast(type->ParentClass); if (info != NULL) { @@ -595,15 +749,17 @@ static FState *CheckState(FScanner &sc, PClass *type) } } - if (state == NULL && v==0) return NULL; - - if (v!=0 && state==NULL) + if (state == NULL && v==0) + { + return NULL; + } + if (v != 0 && state==NULL) { sc.ScriptMessage("Attempt to get invalid state from actor %s\n", type->ParentClass->TypeName.GetChars()); FScriptPosition::ErrorCounter++; return NULL; } - state+=v; + state += v; return state; } else @@ -647,16 +803,26 @@ static bool ParsePropertyParams(FScanner &sc, FPropertyInfo *prop, AActor *defau switch ((*p) & 223) { case 'X': // Expression in parentheses or number. - - if (sc.CheckString ("(")) { - FxExpression *x = ParseExpression(sc, bag.Info->Class); - conv.i = 0x40000000 | StateParams.Add(x, bag.Info->Class, false); + FxExpression *x = NULL; + + if (sc.CheckString ("(")) + { + x = new FxDamageValue(new FxIntCast(ParseExpression(sc, bag.Info)), true); + sc.MustGetStringName(")"); + } + else + { + sc.MustGetNumber(); + if (sc.Number != 0) + { + x = new FxDamageValue(new FxConstant(sc.Number, bag.ScriptPosition), false); + } + } + conv.exp = x; params.Push(conv); - sc.MustGetStringName(")"); - break; } - // fall through + break; case 'I': sc.MustGetNumber(); @@ -832,29 +998,19 @@ static void ParseActorProperty(FScanner &sc, Baggage &bag) if (prop != NULL) { - if (bag.Info->Class->IsDescendantOf(prop->cls)) + if (bag.Info->IsDescendantOf(*prop->cls)) { - ParsePropertyParams(sc, prop, (AActor *)bag.Info->Class->Defaults, bag); + 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(), (*prop->cls)->TypeName.GetChars()); FScriptPosition::ErrorCounter++; } } - else if (!propname.CompareNoCase("States")) - { - if (bag.StateSet) - { - sc.ScriptMessage("'%s' contains multiple state declarations", bag.Info->Class->TypeName.GetChars()); - FScriptPosition::ErrorCounter++; - } - ParseStates(sc, bag.Info, (AActor *)bag.Info->Class->Defaults, bag); - bag.StateSet=true; - } else if (MatchString(propname, statenames) != -1) { - bag.statedef.SetStateLabel(propname, CheckState (sc, bag.Info->Class)); + bag.statedef.SetStateLabel(propname, CheckState (sc, bag.Info)); } else { @@ -872,154 +1028,27 @@ static void ParseActorProperty(FScanner &sc, Baggage &bag) // //========================================================================== -static void ParseActionDef (FScanner &sc, PClass *cls) +static void ParseActionDef (FScanner &sc, PClassActor *cls) { - enum - { - OPTIONAL = 1 - }; - unsigned int error = 0; - const AFuncDesc *afd; FName funcname; - FString args; - TArray DefaultParams; - bool hasdefaults = false; + TArray rets; if (sc.LumpNum == -1 || Wads.GetLumpFile(sc.LumpNum) > 0) { sc.ScriptMessage ("Action functions can only be imported by internal class and actor definitions!"); - ++error; + FScriptPosition::ErrorCounter++; } sc.MustGetToken(TK_Native); + // check for a return value + if (sc.CheckToken(TK_Int) || sc.CheckToken(TK_Bool)) + { + rets.Push(TypeSInt32); + } sc.MustGetToken(TK_Identifier); funcname = sc.String; - afd = FindFunction(sc.String); - if (afd == NULL) - { - sc.ScriptMessage ("The function '%s' has not been exported from the executable.", sc.String); - ++error; - } - sc.MustGetToken('('); - if (!sc.CheckToken(')')) - { - while (sc.TokenType != ')') - { - int flags = 0; - char type = '@'; - - // Retrieve flags before type name - for (;;) - { - if (sc.CheckToken(TK_Coerce) || sc.CheckToken(TK_Native)) - { - } - else - { - break; - } - } - // Read the variable type - sc.MustGetAnyToken(); - switch (sc.TokenType) - { - case TK_Bool: - case TK_Int: - type = 'x'; - break; - - case TK_Float: - type = 'y'; - break; - - case TK_Sound: type = 's'; break; - case TK_String: type = 't'; break; - case TK_Name: type = 't'; break; - case TK_State: type = 'l'; break; - case TK_Color: type = 'c'; break; - case TK_Class: - sc.MustGetToken('<'); - sc.MustGetToken(TK_Identifier); // Skip class name, since the parser doesn't care - sc.MustGetToken('>'); - type = 'm'; - break; - case TK_Ellipsis: - type = '+'; - sc.MustGetToken(')'); - sc.UnGet(); - break; - default: - sc.ScriptMessage ("Unknown variable type %s", sc.TokenName(sc.TokenType, sc.String).GetChars()); - type = 'x'; - FScriptPosition::ErrorCounter++; - break; - } - // Read the optional variable name - if (!sc.CheckToken(',') && !sc.CheckToken(')')) - { - sc.MustGetToken(TK_Identifier); - } - else - { - sc.UnGet(); - } - - FxExpression *def; - if (sc.CheckToken('=')) - { - hasdefaults = true; - flags |= OPTIONAL; - def = ParseParameter(sc, cls, type, true); - } - else - { - def = NULL; - } - DefaultParams.Push(def); - - if (!(flags & OPTIONAL) && type != '+') - { - type -= 'a' - 'A'; - } - args += type; - sc.MustGetAnyToken(); - if (sc.TokenType != ',' && sc.TokenType != ')') - { - sc.ScriptError ("Expected ',' or ')' but got %s instead", sc.TokenName(sc.TokenType, sc.String).GetChars()); - } - } - } - sc.MustGetToken(';'); - if (afd != NULL) - { - PSymbolActionFunction *sym = new PSymbolActionFunction(funcname); - sym->Arguments = args; - sym->Function = afd->Function; - if (hasdefaults) - { - sym->defaultparameterindex = StateParams.Size(); - for(unsigned int i = 0; i < DefaultParams.Size(); i++) - { - StateParams.Add(DefaultParams[i], cls, true); - } - } - else - { - sym->defaultparameterindex = -1; - } - if (error) - { - FScriptPosition::ErrorCounter += error; - } - else if (cls->Symbols.AddSymbol (sym) == NULL) - { - delete sym; - sc.ScriptMessage ("'%s' is already defined in class '%s'.", - funcname.GetChars(), cls->TypeName.GetChars()); - FScriptPosition::ErrorCounter++; - } - } + ParseFunctionDef(sc, cls, funcname, rets, VARF_Method | VARF_Action); } //========================================================================== @@ -1027,7 +1056,7 @@ static void ParseActionDef (FScanner &sc, PClass *cls) // Starts a new actor definition // //========================================================================== -static FActorInfo *ParseActorHeader(FScanner &sc, Baggage *bag) +static PClassActor *ParseActorHeader(FScanner &sc, Baggage *bag) { FName typeName; FName parentName; @@ -1108,13 +1137,13 @@ static FActorInfo *ParseActorHeader(FScanner &sc, Baggage *bag) try { - FActorInfo *info = CreateNewActor(sc, typeName, parentName, native); - info->DoomEdNum = DoomEdNum > 0? DoomEdNum : -1; - info->Class->Meta.SetMetaString (ACMETA_Lump, Wads.GetLumpFullPath(sc.LumpNum)); + PClassActor *info = CreateNewActor(sc, typeName, parentName, native); + info->DoomEdNum = DoomEdNum > 0 ? DoomEdNum : -1; + info->SourceLumpName = Wads.GetLumpFullPath(sc.LumpNum); SetReplacement(sc, info, replaceName); - ResetBaggage (bag, info->Class->ParentClass); + ResetBaggage (bag, info == RUNTIME_CLASS(AActor) ? NULL : static_cast(info->ParentClass)); bag->Info = info; bag->Lumpnum = sc.LumpNum; #ifdef _DEBUG @@ -1136,7 +1165,7 @@ static FActorInfo *ParseActorHeader(FScanner &sc, Baggage *bag) //========================================================================== static void ParseActor(FScanner &sc) { - FActorInfo * info=NULL; + PClassActor *info = NULL; Baggage bag; info = ParseActorHeader(sc, &bag); @@ -1146,36 +1175,46 @@ static void ParseActor(FScanner &sc) switch (sc.TokenType) { case TK_Action: - ParseActionDef (sc, info->Class); + ParseActionDef (sc, info); break; case TK_Const: - ParseConstant (sc, &info->Class->Symbols, info->Class); + ParseConstant (sc, &info->Symbols, info); break; case TK_Enum: - ParseEnum (sc, &info->Class->Symbols, info->Class); + ParseEnum (sc, &info->Symbols, info); break; case TK_Native: - ParseNativeVariable (sc, &info->Class->Symbols, info->Class); + ParseNativeFunction (sc, info); break; case TK_Var: - ParseUserVariable (sc, &info->Class->Symbols, info->Class); + ParseUserVariable (sc, &info->Symbols, info); break; case TK_Identifier: ParseActorProperty(sc, bag); break; + case TK_States: + if (bag.StateSet) + { + sc.ScriptMessage("'%s' contains multiple state declarations", bag.Info->TypeName.GetChars()); + FScriptPosition::ErrorCounter++; + } + ParseStates(sc, bag.Info, (AActor *)bag.Info->Defaults, bag); + bag.StateSet = true; + break; + case '+': case '-': ParseActorFlag(sc, bag, sc.TokenType); break; default: - sc.ScriptError("Unexpected '%s' in definition of '%s'", sc.String, bag.Info->Class->TypeName.GetChars()); + sc.ScriptError("Unexpected '%s' in definition of '%s'", sc.String, bag.Info->TypeName.GetChars()); break; } } @@ -1275,10 +1314,6 @@ void ParseDecorate (FScanner &sc) ParseEnum (sc, &GlobalSymbols, NULL); break; - case TK_Native: - ParseNativeVariable(sc, &GlobalSymbols, NULL); - break; - case ';': // ';' is the start of a comment in the non-cmode parser which // is used to parse parts of the DECORATE lump. If we don't add diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index fd0636a707..fef2c075aa 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -76,7 +76,7 @@ // Gets a class pointer and performs an error check for correct type // //========================================================================== -static const PClass *FindClassTentative(const char *name, const char *ancestor) +static PClassActor *FindClassTentative(const char *name, PClass *ancestor) { // "" and "none" mean 'no class' if (name == NULL || *name == 0 || !stricmp(name, "none")) @@ -84,15 +84,29 @@ static const PClass *FindClassTentative(const char *name, const char *ancestor) return NULL; } - const PClass *anc = PClass::FindClass(ancestor); - assert(anc != NULL); // parent classes used here should always be natively defined - const PClass *cls = const_cast(anc)->FindClassTentative(name); - assert (cls != NULL); // cls can not ne NULL here - if (!cls->IsDescendantOf(anc)) + PClass *cls = ancestor->FindClassTentative(name); + assert(cls != NULL); // cls can not be NULL here + if (!cls->IsDescendantOf(ancestor)) { - I_Error("%s does not inherit from %s\n", name, ancestor); + I_Error("%s does not inherit from %s\n", name, ancestor->TypeName.GetChars()); } - return cls; + return static_cast(cls); +} +static AAmmo::MetaClass *FindClassTentativeAmmo(const char *name) +{ + return static_cast(FindClassTentative(name, RUNTIME_CLASS(AAmmo))); +} +static AWeapon::MetaClass *FindClassTentativeWeapon(const char *name) +{ + return static_cast(FindClassTentative(name, RUNTIME_CLASS(AWeapon))); +} +static APowerup::MetaClass *FindClassTentativePowerup(const char *name) +{ + return static_cast(FindClassTentative(name, RUNTIME_CLASS(APowerup))); +} +static APlayerPawn::MetaClass *FindClassTentativePlayerPawn(const char *name) +{ + return static_cast(FindClassTentative(name, RUNTIME_CLASS(APlayerPawn))); } //========================================================================== @@ -158,7 +172,7 @@ INTBOOL CheckActorFlag(const AActor *owner, FFlagDef *fd) { if (fd->structoffset == -1) { - return CheckDeprecatedFlags(owner, owner->GetClass()->ActorInfo, fd->flagbit); + return CheckDeprecatedFlags(owner, owner->GetClass(), fd->flagbit); } else #ifdef __BIG_ENDIAN__ @@ -217,7 +231,7 @@ INTBOOL CheckActorFlag(const AActor *owner, const char *flagname, bool printerro // properties is not recommended // //=========================================================================== -void HandleDeprecatedFlags(AActor *defaults, FActorInfo *info, bool set, int index) +void HandleDeprecatedFlags(AActor *defaults, PClassActor *info, bool set, int index) { switch (index) { @@ -258,7 +272,7 @@ void HandleDeprecatedFlags(AActor *defaults, FActorInfo *info, bool set, int ind case DEPF_PICKUPFLASH: if (set) { - static_cast(defaults)->PickupFlash = FindClassTentative("PickupFlash", "Actor"); + static_cast(defaults)->PickupFlash = FindClassTentative("PickupFlash", RUNTIME_CLASS(AActor)); } else { @@ -282,7 +296,7 @@ void HandleDeprecatedFlags(AActor *defaults, FActorInfo *info, bool set, int ind // //=========================================================================== -bool CheckDeprecatedFlags(const AActor *actor, FActorInfo *info, int index) +bool CheckDeprecatedFlags(const AActor *actor, PClassActor *info, int index) { // A deprecated flag is false if // a) it hasn't been added here @@ -435,10 +449,10 @@ DEFINE_INFO_PROPERTY(conversationid, IiI, Actor) //========================================================================== DEFINE_PROPERTY(skip_super, 0, Actor) { - if (info->Class->IsDescendantOf(RUNTIME_CLASS(AInventory))) + if (info->IsDescendantOf(RUNTIME_CLASS(AInventory))) { bag.ScriptPosition.Message(MSG_WARNING, - "'skip_super' in definition of inventory item '%s' ignored.", info->Class->TypeName.GetChars() ); + "'skip_super' in definition of inventory item '%s' ignored.", info->TypeName.GetChars() ); return; } if (bag.StateSet) @@ -449,10 +463,6 @@ DEFINE_PROPERTY(skip_super, 0, Actor) } memcpy ((void *)defaults, (void *)GetDefault(), sizeof(AActor)); - if (bag.DropItemList != NULL) - { - FreeDropItemChain (bag.DropItemList); - } ResetBaggage (&bag, RUNTIME_CLASS(AActor)); } @@ -480,7 +490,8 @@ DEFINE_PROPERTY(health, I, Actor) DEFINE_PROPERTY(gibhealth, I, Actor) { PROP_INT_PARM(id, 0); - info->Class->Meta.SetMetaInt (AMETA_GibHealth, id); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast(info)->GibHealth = id; } //========================================================================== @@ -489,7 +500,8 @@ DEFINE_PROPERTY(gibhealth, I, Actor) DEFINE_PROPERTY(woundhealth, I, Actor) { PROP_INT_PARM(id, 0); - info->Class->Meta.SetMetaInt (AMETA_WoundHealth, id); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast(info)->WoundHealth = id; } //========================================================================== @@ -537,7 +549,7 @@ DEFINE_PROPERTY(painthreshold, I, Actor) //========================================================================== DEFINE_PROPERTY(damage, X, Actor) { - PROP_INT_PARM(id, 0); + PROP_EXP_PARM(id, 0); // 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 @@ -545,7 +557,16 @@ DEFINE_PROPERTY(damage, X, Actor) // compatibility reasons, expressions must be enclosed within // parentheses. - defaults->Damage = id; + // Store this expression here for now. It will be converted to a function + // later once all actors have been processed. + if (id == NULL) + { + defaults->Damage = NULL; + } + else + { + defaults->Damage = (VMFunction *)(uintptr_t)(ActorDamageFuncs.Push(id) + 1); + } } //========================================================================== @@ -731,7 +752,8 @@ DEFINE_PROPERTY(activesound, S, Actor) DEFINE_PROPERTY(howlsound, S, Actor) { PROP_STRING_PARM(str, 0); - info->Class->Meta.SetMetaInt (AMETA_HowlSound, S_FindSound(str)); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast(info)->HowlSound = str; } //========================================================================== @@ -757,24 +779,25 @@ DEFINE_PROPERTY(dropitem, S_i_i, Actor) bag.DropItemList = NULL; } - FDropItem *di = new FDropItem; + DDropItem *di = new DDropItem; - di->Name =type; - di->probability=255; - di->amount=-1; + di->Name = type; + di->Probability = 255; + di->Amount = -1; if (PROP_PARM_COUNT > 1) { PROP_INT_PARM(prob, 1); - di->probability = prob; + di->Probability = prob; if (PROP_PARM_COUNT > 2) { PROP_INT_PARM(amt, 2); - di->amount = amt; + di->Amount = amt; } } di->Next = bag.DropItemList; bag.DropItemList = di; + GC::WriteBarrier(di); } //========================================================================== @@ -823,7 +846,8 @@ DEFINE_PROPERTY(alpha, F, Actor) DEFINE_PROPERTY(obituary, S, Actor) { PROP_STRING_PARM(str, 0); - info->Class->Meta.SetMetaString (AMETA_Obituary, str); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast(info)->Obituary = str; } //========================================================================== @@ -832,7 +856,8 @@ DEFINE_PROPERTY(obituary, S, Actor) DEFINE_PROPERTY(hitobituary, S, Actor) { PROP_STRING_PARM(str, 0); - info->Class->Meta.SetMetaString (AMETA_HitObituary, str); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast(info)->HitObituary = str; } //========================================================================== @@ -840,7 +865,8 @@ DEFINE_PROPERTY(hitobituary, S, Actor) //========================================================================== DEFINE_PROPERTY(donthurtshooter, 0, Actor) { - info->Class->Meta.SetMetaInt (ACMETA_DontHurtShooter, true); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast(info)->DontHurtShooter = true; } //========================================================================== @@ -849,7 +875,8 @@ DEFINE_PROPERTY(donthurtshooter, 0, Actor) DEFINE_PROPERTY(explosionradius, I, Actor) { PROP_INT_PARM(id, 0); - info->Class->Meta.SetMetaInt (ACMETA_ExplosionRadius, id); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast(info)->ExplosionRadius = id; } //========================================================================== @@ -858,7 +885,8 @@ DEFINE_PROPERTY(explosionradius, I, Actor) DEFINE_PROPERTY(explosiondamage, I, Actor) { PROP_INT_PARM(id, 0); - info->Class->Meta.SetMetaInt (ACMETA_ExplosionDamage, id); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast(info)->ExplosionDamage = id; } //========================================================================== @@ -867,9 +895,8 @@ DEFINE_PROPERTY(explosiondamage, I, Actor) DEFINE_PROPERTY(deathheight, F, Actor) { PROP_FIXED_PARM(h, 0); - // AActor::Die() uses a height of 0 to mean "cut the height to 1/4", - // so if a height of 0 is desired, store it as -1. - info->Class->Meta.SetMetaFixed (AMETA_DeathHeight, h <= 0 ? -1 : h); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast(info)->DeathHeight = MAX(0, h); } //========================================================================== @@ -878,8 +905,8 @@ DEFINE_PROPERTY(deathheight, F, Actor) DEFINE_PROPERTY(burnheight, F, Actor) { PROP_FIXED_PARM(h, 0); - // The note above for AMETA_DeathHeight also applies here. - info->Class->Meta.SetMetaFixed (AMETA_BurnHeight, h <= 0 ? -1 : h); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast(info)->BurnHeight = MAX(0, h); } //========================================================================== @@ -906,7 +933,8 @@ DEFINE_PROPERTY(meleethreshold, F, Actor) DEFINE_PROPERTY(meleedamage, I, Actor) { PROP_INT_PARM(id, 0); - info->Class->Meta.SetMetaInt (ACMETA_MeleeDamage, id); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast(info)->MeleeDamage = id; } //========================================================================== @@ -924,7 +952,8 @@ DEFINE_PROPERTY(meleerange, F, Actor) DEFINE_PROPERTY(meleesound, S, Actor) { PROP_STRING_PARM(str, 0); - info->Class->Meta.SetMetaInt (ACMETA_MeleeSound, S_FindSound(str)); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast(info)->MeleeSound = str; } //========================================================================== @@ -933,7 +962,8 @@ DEFINE_PROPERTY(meleesound, S, Actor) DEFINE_PROPERTY(missiletype, S, Actor) { PROP_STRING_PARM(str, 0); - info->Class->Meta.SetMetaInt (ACMETA_MissileName, FName(str)); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast(info)->MissileName = str; } //========================================================================== @@ -942,7 +972,8 @@ DEFINE_PROPERTY(missiletype, S, Actor) DEFINE_PROPERTY(missileheight, F, Actor) { PROP_FIXED_PARM(id, 0); - info->Class->Meta.SetMetaFixed (ACMETA_MissileHeight, id); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast(info)->MissileHeight = id; } //========================================================================== @@ -1012,7 +1043,8 @@ DEFINE_PROPERTY(bloodcolor, C, Actor) PalEntry pe = color; pe.a = CreateBloodTranslation(pe); - info->Class->Meta.SetMetaInt (AMETA_BloodColor, pe); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast(info)->BloodColor = pe; } @@ -1025,23 +1057,26 @@ DEFINE_PROPERTY(bloodtype, Sss, Actor) PROP_STRING_PARM(str1, 1) PROP_STRING_PARM(str2, 2) + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + PClassActor *ainfo = static_cast(info); + FName blood = str; // normal blood - info->Class->Meta.SetMetaInt (AMETA_BloodType, blood); + ainfo->BloodType = blood; if (PROP_PARM_COUNT > 1) { blood = str1; } // blood splatter - info->Class->Meta.SetMetaInt (AMETA_BloodType2, blood); + ainfo->BloodType2 = blood; if (PROP_PARM_COUNT > 2) { blood = str2; } // axe blood - info->Class->Meta.SetMetaInt (AMETA_BloodType3, blood); + ainfo->BloodType3 = blood; } //========================================================================== @@ -1244,7 +1279,8 @@ DEFINE_PROPERTY(poisondamagetype, S, Actor) DEFINE_PROPERTY(fastspeed, F, Actor) { PROP_FIXED_PARM(i, 0); - info->Class->Meta.SetMetaFixed (AMETA_FastSpeed, i); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast(info)->FastSpeed = i; } //========================================================================== @@ -1253,7 +1289,8 @@ DEFINE_PROPERTY(fastspeed, F, Actor) DEFINE_PROPERTY(radiusdamagefactor, F, Actor) { PROP_FIXED_PARM(i, 0); - info->Class->Meta.SetMetaFixed (AMETA_RDFactor, i); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast(info)->RDFactor = i; } //========================================================================== @@ -1262,7 +1299,8 @@ DEFINE_PROPERTY(radiusdamagefactor, F, Actor) DEFINE_PROPERTY(cameraheight, F, Actor) { PROP_FIXED_PARM(i, 0); - info->Class->Meta.SetMetaFixed (AMETA_CameraHeight, i); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast(info)->CameraHeight = i; } //========================================================================== @@ -1382,7 +1420,7 @@ DEFINE_PROPERTY(visibletoplayerclass, Ssssssssssssssssssss, Actor) { PROP_STRING_PARM(n, i); if (*n != 0) - info->VisibleToPlayerClass.Push(FindClassTentative(n, "PlayerPawn")); + info->VisibleToPlayerClass.Push(FindClassTentativePlayerPawn(n)); } } @@ -1410,7 +1448,8 @@ DEFINE_PROPERTY(stamina, I, Actor) DEFINE_PROPERTY(telefogsourcetype, S, Actor) { PROP_STRING_PARM(str, 0); - defaults->TeleFogSourceType = FindClassTentative(str,"Actor"); + + defaults->TeleFogSourceType = FindClassTentative(str, RUNTIME_CLASS(AActor)); } //========================================================================== @@ -1419,7 +1458,8 @@ DEFINE_PROPERTY(telefogsourcetype, S, Actor) DEFINE_PROPERTY(telefogdesttype, S, Actor) { PROP_STRING_PARM(str, 0); - defaults->TeleFogDestType = FindClassTentative(str, "Actor"); + + defaults->TeleFogDestType = FindClassTentative(str, RUNTIME_CLASS(AActor)); } //========================================================================== @@ -1477,7 +1517,7 @@ DEFINE_CLASS_PROPERTY(restrictedto, Ssssssssssssssssssss, Inventory) { PROP_STRING_PARM(n, i); if (*n != 0) - info->RestrictedToPlayerClass.Push(FindClassTentative(n, "PlayerPawn")); + info->RestrictedToPlayerClass.Push(FindClassTentativePlayerPawn(n)); } } @@ -1491,7 +1531,7 @@ DEFINE_CLASS_PROPERTY(forbiddento, Ssssssssssssssssssss, Inventory) { PROP_STRING_PARM(n, i); if (*n != 0) - info->ForbiddenToPlayerClass.Push(FindClassTentative(n, "PlayerPawn")); + info->ForbiddenToPlayerClass.Push(FindClassTentativePlayerPawn(n)); } } @@ -1519,7 +1559,8 @@ DEFINE_CLASS_PROPERTY(backpackmaxamount, I, Ammo) DEFINE_CLASS_PROPERTY(dropamount, I, Ammo) { PROP_INT_PARM(i, 0); - info->Class->Meta.SetMetaInt (AIMETA_DropAmount, i); + assert(info->IsKindOf(RUNTIME_CLASS(PClassAmmo))); + static_cast(info)->DropAmount = i; } //========================================================================== @@ -1557,11 +1598,11 @@ DEFINE_CLASS_PROPERTY(saveamount, I, Armor) PROP_INT_PARM(i, 0); // Special case here because this property has to work for 2 unrelated classes - if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup))) + if (info->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup))) { ((ABasicArmorPickup*)defaults)->SaveAmount=i; } - else if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus))) + else if (info->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus))) { ((ABasicArmorBonus*)defaults)->SaveAmount=i; } @@ -1580,11 +1621,11 @@ DEFINE_CLASS_PROPERTY(savepercent, F, Armor) i = clamp(i, 0, 100*FRACUNIT)/100; // Special case here because this property has to work for 2 unrelated classes - if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup))) + if (info->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup))) { ((ABasicArmorPickup*)defaults)->SavePercent = i; } - else if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus))) + else if (info->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus))) { ((ABasicArmorBonus*)defaults)->SavePercent = i; } @@ -1602,11 +1643,11 @@ DEFINE_CLASS_PROPERTY(maxabsorb, I, Armor) PROP_INT_PARM(i, 0); // Special case here because this property has to work for 2 unrelated classes - if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup))) + if (info->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup))) { ((ABasicArmorPickup*)defaults)->MaxAbsorb = i; } - else if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus))) + else if (info->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus))) { ((ABasicArmorBonus*)defaults)->MaxAbsorb = i; } @@ -1624,11 +1665,11 @@ DEFINE_CLASS_PROPERTY(maxfullabsorb, I, Armor) PROP_INT_PARM(i, 0); // Special case here because this property has to work for 2 unrelated classes - if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup))) + if (info->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup))) { ((ABasicArmorPickup*)defaults)->MaxFullAbsorb = i; } - else if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus))) + else if (info->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus))) { ((ABasicArmorBonus*)defaults)->MaxFullAbsorb = i; } @@ -1669,7 +1710,7 @@ DEFINE_CLASS_PROPERTY(icon, S, Inventory) !(gameinfo.flags&GI_SHAREWARE) && Wads.GetLumpFile(bag.Lumpnum) != 0) { bag.ScriptPosition.Message(MSG_WARNING, - "Icon '%s' for '%s' not found\n", i, info->Class->TypeName.GetChars()); + "Icon '%s' for '%s' not found\n", i, info->TypeName.GetChars()); } } } @@ -1708,7 +1749,7 @@ DEFINE_CLASS_PROPERTY(defmaxamount, 0, Inventory) DEFINE_CLASS_PROPERTY(pickupflash, S, Inventory) { PROP_STRING_PARM(str, 0); - defaults->PickupFlash = FindClassTentative(str, "Actor"); + defaults->PickupFlash = FindClassTentative(str, RUNTIME_CLASS(AActor)); } //========================================================================== @@ -1717,7 +1758,8 @@ DEFINE_CLASS_PROPERTY(pickupflash, S, Inventory) DEFINE_CLASS_PROPERTY(pickupmessage, T, Inventory) { PROP_STRING_PARM(str, 0); - info->Class->Meta.SetMetaString(AIMETA_PickupMessage, str); + assert(info->IsKindOf(RUNTIME_CLASS(PClassInventory))); + static_cast(info)->PickupMessage = str; } //========================================================================== @@ -1760,7 +1802,8 @@ DEFINE_CLASS_PROPERTY(usesound, S, Inventory) DEFINE_CLASS_PROPERTY(givequest, I, Inventory) { PROP_INT_PARM(i, 0); - info->Class->Meta.SetMetaInt(AIMETA_GiveQuest, i); + assert(info->IsKindOf(RUNTIME_CLASS(PClassInventory))); + static_cast(info)->GiveQuest = i; } //========================================================================== @@ -1770,8 +1813,9 @@ DEFINE_CLASS_PROPERTY(lowmessage, IT, Health) { PROP_INT_PARM(i, 0); PROP_STRING_PARM(str, 1); - info->Class->Meta.SetMetaInt(AIMETA_LowHealth, i); - info->Class->Meta.SetMetaString(AIMETA_LowHealthMessage, str); + assert(info->IsKindOf(RUNTIME_CLASS(PClassHealth))); + static_cast(info)->LowHealth = i; + static_cast(info)->LowHealthMessage = str; } //========================================================================== @@ -1798,7 +1842,8 @@ DEFINE_CLASS_PROPERTY(number, I, PuzzleItem) DEFINE_CLASS_PROPERTY(failmessage, T, PuzzleItem) { PROP_STRING_PARM(str, 0); - info->Class->Meta.SetMetaString(AIMETA_PuzzFailMessage, str); + assert(info->IsKindOf(RUNTIME_CLASS(PClassPuzzleItem))); + static_cast(info)->PuzzFailMessage = str; } //========================================================================== @@ -1835,7 +1880,7 @@ DEFINE_CLASS_PROPERTY(ammotype, S, Weapon) { PROP_STRING_PARM(str, 0); if (!stricmp(str, "none") || *str == 0) defaults->AmmoType1 = NULL; - else defaults->AmmoType1 = FindClassTentative(str, "Ammo"); + else defaults->AmmoType1 = FindClassTentativeAmmo(str); } //========================================================================== @@ -1845,7 +1890,7 @@ DEFINE_CLASS_PROPERTY(ammotype1, S, Weapon) { PROP_STRING_PARM(str, 0); if (!stricmp(str, "none") || *str == 0) defaults->AmmoType1 = NULL; - else defaults->AmmoType1 = FindClassTentative(str, "Ammo"); + else defaults->AmmoType1 = FindClassTentativeAmmo(str); } //========================================================================== @@ -1855,7 +1900,7 @@ DEFINE_CLASS_PROPERTY(ammotype2, S, Weapon) { PROP_STRING_PARM(str, 0); if (!stricmp(str, "none") || *str == 0) defaults->AmmoType1 = NULL; - else defaults->AmmoType2 = FindClassTentative(str, "Ammo"); + else defaults->AmmoType2 = FindClassTentativeAmmo(str); } //========================================================================== @@ -1944,7 +1989,7 @@ DEFINE_CLASS_PROPERTY(minselectionammo2, I, Weapon) DEFINE_CLASS_PROPERTY(sisterweapon, S, Weapon) { PROP_STRING_PARM(str, 0); - defaults->SisterWeaponType = FindClassTentative(str, "Weapon"); + defaults->SisterWeaponType = FindClassTentativeWeapon(str); } //========================================================================== @@ -2017,7 +2062,8 @@ DEFINE_CLASS_PROPERTY(bobrangey, F, Weapon) DEFINE_CLASS_PROPERTY(slotnumber, I, Weapon) { PROP_INT_PARM(i, 0); - info->Class->Meta.SetMetaInt(AWMETA_SlotNumber, i); + assert(info->IsKindOf(RUNTIME_CLASS(PClassWeapon))); + static_cast(info)->SlotNumber = i; } //========================================================================== @@ -2026,7 +2072,8 @@ DEFINE_CLASS_PROPERTY(slotnumber, I, Weapon) DEFINE_CLASS_PROPERTY(slotpriority, F, Weapon) { PROP_FIXED_PARM(i, 0); - info->Class->Meta.SetMetaFixed(AWMETA_SlotPriority, i); + assert(info->IsKindOf(RUNTIME_CLASS(PClassWeapon))); + static_cast(info)->SlotPriority = i; } //========================================================================== @@ -2053,7 +2100,7 @@ DEFINE_CLASS_PROPERTY(number, I, WeaponPiece) DEFINE_CLASS_PROPERTY(weapon, S, WeaponPiece) { PROP_STRING_PARM(str, 0); - defaults->WeaponClass = FindClassTentative(str, "Weapon"); + defaults->WeaponClass = FindClassTentativeWeapon(str); } //========================================================================== @@ -2065,13 +2112,13 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, color, C_f, Inventory) "INVERSEMAP", "GOLDMAP", "REDMAP", "GREENMAP", "BLUEMAP", NULL }; int alpha; - PalEntry * pBlendColor; + PalEntry *pBlendColor; - if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerup))) + if (info->IsDescendantOf(RUNTIME_CLASS(APowerup))) { pBlendColor = &((APowerup*)defaults)->BlendColor; } - else if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerupGiver))) + else if (info->IsDescendantOf(RUNTIME_CLASS(APowerupGiver))) { pBlendColor = &((APowerupGiver*)defaults)->BlendColor; } @@ -2095,7 +2142,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, color, C_f, Inventory) *pBlendColor = MakeSpecialColormap(v); return; } - else if (!stricmp(name, "none") && info->Class->IsDescendantOf(RUNTIME_CLASS(APowerupGiver))) + else if (!stricmp(name, "none") && info->IsDescendantOf(RUNTIME_CLASS(APowerupGiver))) { *pBlendColor = MakeSpecialColormap(65535); return; @@ -2122,11 +2169,11 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, colormap, FFFfff, Inventory) { PalEntry * pBlendColor; - if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerup))) + if (info->IsDescendantOf(RUNTIME_CLASS(APowerup))) { pBlendColor = &((APowerup*)defaults)->BlendColor; } - else if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerupGiver))) + else if (info->IsDescendantOf(RUNTIME_CLASS(APowerupGiver))) { pBlendColor = &((APowerupGiver*)defaults)->BlendColor; } @@ -2166,11 +2213,11 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, duration, I, Inventory) { int *pEffectTics; - if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerup))) + if (info->IsDescendantOf(RUNTIME_CLASS(APowerup))) { pEffectTics = &((APowerup*)defaults)->EffectTics; } - else if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerupGiver))) + else if (info->IsDescendantOf(RUNTIME_CLASS(APowerupGiver))) { pEffectTics = &((APowerupGiver*)defaults)->EffectTics; } @@ -2191,11 +2238,11 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, strength, F, Inventory) { fixed_t *pStrength; - if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerup))) + if (info->IsDescendantOf(RUNTIME_CLASS(APowerup))) { pStrength = &((APowerup*)defaults)->Strength; } - else if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerupGiver))) + else if (info->IsDescendantOf(RUNTIME_CLASS(APowerupGiver))) { pStrength = &((APowerupGiver*)defaults)->Strength; } @@ -2215,11 +2262,11 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, mode, S, Inventory) { PROP_STRING_PARM(str, 0); FName *pMode; - if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerup))) + if (info->IsDescendantOf(RUNTIME_CLASS(APowerup))) { pMode = &((APowerup*)defaults)->Mode; } - else if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerupGiver))) + else if (info->IsDescendantOf(RUNTIME_CLASS(APowerupGiver))) { pMode = &((APowerupGiver*)defaults)->Mode; } @@ -2240,12 +2287,12 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, type, S, PowerupGiver) // Yuck! What was I thinking when I decided to prepend "Power" to the name? // Now it's too late to change it... - const PClass *cls = PClass::FindClass(str); + PClassActor *cls = PClass::FindActor(str); if (cls == NULL || !cls->IsDescendantOf(RUNTIME_CLASS(APowerup))) { FString st; st.Format("%s%s", strnicmp(str, "power", 5)? "Power" : "", str); - cls = FindClassTentative(st, "Powerup"); + cls = FindClassTentativePowerup(st); } defaults->PowerupType = cls; @@ -2263,7 +2310,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, type, S, PowerupGiver) DEFINE_CLASS_PROPERTY_PREFIX(player, displayname, S, PlayerPawn) { PROP_STRING_PARM(str, 0); - info->Class->Meta.SetMetaString (APMETA_DisplayName, str); + assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); + static_cast(info)->DisplayName = str; } //========================================================================== @@ -2275,7 +2323,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, soundclass, S, PlayerPawn) FString tmp = str; tmp.ReplaceChars (' ', '_'); - info->Class->Meta.SetMetaString (APMETA_SoundClass, tmp); + assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); + static_cast(info)->SoundClass = tmp; } //========================================================================== @@ -2291,7 +2340,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, face, S, PlayerPawn) { bag.ScriptPosition.Message(MSG_WARNING, "Invalid face '%s' for '%s';\nSTF replacement codes must be 3 characters.\n", - tmp.GetChars(), info->Class->TypeName.GetChars ()); + tmp.GetChars(), info->TypeName.GetChars ()); } bool valid = ( @@ -2303,10 +2352,11 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, face, S, PlayerPawn) { bag.ScriptPosition.Message(MSG_WARNING, "Invalid face '%s' for '%s';\nSTF replacement codes must be alphanumeric.\n", - tmp.GetChars(), info->Class->TypeName.GetChars ()); + tmp.GetChars(), info->TypeName.GetChars ()); } - info->Class->Meta.SetMetaString (APMETA_Face, tmp); + assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); + static_cast(info)->Face = tmp; } //========================================================================== @@ -2320,7 +2370,9 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorrange, I_I, PlayerPawn) if (start > end) swapvalues (start, end); - info->Class->Meta.SetMetaInt (APMETA_ColorRange, (start & 255) | ((end & 255) << 8)); + assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); + static_cast(info)->ColorRangeStart = start; + static_cast(info)->ColorRangeEnd = end; } //========================================================================== @@ -2375,7 +2427,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorset, ISIIIiiiiiiiiiiiiiiiiiiiiiiii, Pl } else { - info->SetColorSet(setnum, &color); + assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); + static_cast(info)->ColorSets.Insert(setnum, color); } } @@ -2401,7 +2454,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorsetfile, ISSI, PlayerPawn) } else if (color.Lump >= 0) { - info->SetColorSet(setnum, &color); + assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); + static_cast(info)->ColorSets.Insert(setnum, color); } } @@ -2418,7 +2472,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, clearcolorset, I, PlayerPawn) } else { - info->SetColorSet(setnum, NULL); + assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); + static_cast(info)->ColorSets.Remove(setnum); } } @@ -2588,7 +2643,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, morphweapon, S, PlayerPawn) DEFINE_CLASS_PROPERTY_PREFIX(player, flechettetype, S, PlayerPawn) { PROP_STRING_PARM(str, 0); - defaults->FlechetteType = FindClassTentative(str, "ArtiPoisonBag"); + defaults->FlechetteType = FindClassTentative(str, RUNTIME_CLASS(AArtiPoisonBag)); } //========================================================================== @@ -2601,7 +2656,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, scoreicon, S, PlayerPawn) if (!defaults->ScoreIcon.isValid()) { bag.ScriptPosition.Message(MSG_WARNING, - "Icon '%s' for '%s' not found\n", z, info->Class->TypeName.GetChars ()); + "Icon '%s' for '%s' not found\n", z, info->TypeName.GetChars ()); } } @@ -2652,7 +2707,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, damagescreencolor, Cfs, PlayerPawn) PROP_STRING_PARM(type, 3); color.a = BYTE(255 * clamp(a, 0.f, 1.f)); - info->SetPainFlash(type, color); + assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); + static_cast(info)->PainFlashes.Insert(type, color); } } @@ -2672,18 +2728,19 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn) bag.DropItemList = NULL; } - FDropItem * di=new FDropItem; + DDropItem *di = new DDropItem; di->Name = str; - di->probability = 255; - di->amount = 1; + di->Probability = 255; + di->Amount = 1; if (PROP_PARM_COUNT > 1) { PROP_INT_PARM(amt, 1); - di->amount = amt; + di->Amount = amt; } di->Next = bag.DropItemList; bag.DropItemList = di; + GC::WriteBarrier(di); } //========================================================================== @@ -2692,7 +2749,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn) DEFINE_CLASS_PROPERTY_PREFIX(player, invulnerabilitymode, S, PlayerPawn) { PROP_STRING_PARM(str, 0); - info->Class->Meta.SetMetaInt (APMETA_InvulMode, (FName)str); + assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); + static_cast(info)->InvulMode = str; } //========================================================================== @@ -2701,7 +2759,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, invulnerabilitymode, S, PlayerPawn) DEFINE_CLASS_PROPERTY_PREFIX(player, healradiustype, S, PlayerPawn) { PROP_STRING_PARM(str, 0); - info->Class->Meta.SetMetaInt (APMETA_HealingRadius, (FName)str); + assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); + static_cast(info)->HealingRadiusType = str; } //========================================================================== @@ -2709,10 +2768,11 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, healradiustype, S, PlayerPawn) //========================================================================== DEFINE_CLASS_PROPERTY_PREFIX(player, hexenarmor, FFFFF, PlayerPawn) { - for (int i=0;i<5;i++) + assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); + for (int i = 0; i < 5; i++) { PROP_FIXED_PARM(val, i); - info->Class->Meta.SetMetaFixed (APMETA_Hexenarmor0+i, val); + static_cast(info)->HexenArmor[i] = val; } } @@ -2721,8 +2781,9 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, hexenarmor, FFFFF, PlayerPawn) //========================================================================== DEFINE_CLASS_PROPERTY_PREFIX(player, portrait, S, PlayerPawn) { + assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); PROP_STRING_PARM(val, 0); - info->Class->Meta.SetMetaString (APMETA_Portrait, val); + static_cast(info)->Portrait = val; } //========================================================================== @@ -2732,6 +2793,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, weaponslot, ISsssssssssssssssssssssssssssss { PROP_INT_PARM(slot, 0); + assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); if (slot < 0 || slot > 9) { I_Error("Slot must be between 0 and 9."); @@ -2745,7 +2807,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, weaponslot, ISsssssssssssssssssssssssssssss PROP_STRING_PARM(str, i); weapons << ' ' << str; } - info->Class->Meta.SetMetaString(APMETA_Slot0 + slot, &weapons[1]); + static_cast(info)->Slot[slot] = &weapons[1]; } } diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index eb740aad28..a44fa1ed15 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -58,18 +58,7 @@ #include "version.h" #include "templates.h" -//========================================================================== -//*** -// PrepareStateParameters -// creates an empty parameter list for a parameterized function call -// -//========================================================================== -int PrepareStateParameters(FState * state, int numparams, const PClass *cls) -{ - int paramindex=StateParams.Reserve(numparams, cls); - state->ParameterIndex = paramindex+1; - return paramindex; -} +TDeletingArray StateTempCalls; //========================================================================== //*** @@ -77,7 +66,7 @@ int PrepareStateParameters(FState * state, int numparams, const PClass *cls) // handles action specials as code pointers // //========================================================================== -bool DoActionSpecials(FScanner &sc, FState & state, Baggage &bag) +FxVMFunctionCall *DoActionSpecials(FScanner &sc, FState & state, Baggage &bag) { int i; int min_args, max_args; @@ -87,23 +76,21 @@ bool DoActionSpecials(FScanner &sc, FState & state, Baggage &bag) if (special > 0 && min_args >= 0) { - - int paramindex=PrepareStateParameters(&state, 6, bag.Info->Class); - - StateParams.Set(paramindex, new FxConstant(special, sc)); + FArgumentList *args = new FArgumentList; + args->Push(new FxParameter(new FxConstant(special, sc))); + i = 0; // Make this consistent with all other parameter parsing if (sc.CheckToken('(')) { - for (i = 0; i < 5;) + while (i < 5) { - StateParams.Set(paramindex+i+1, ParseExpression (sc, bag.Info->Class)); + args->Push(new FxParameter(new FxIntCast(ParseExpression(sc, bag.Info)))); i++; if (!sc.CheckToken (',')) break; } sc.MustGetToken (')'); } - else i=0; if (i < min_args) { @@ -113,11 +100,9 @@ bool DoActionSpecials(FScanner &sc, FState & state, Baggage &bag) { sc.ScriptError ("Too many arguments to %s", specname.GetChars()); } - - state.SetAction(FindGlobalActionFunction("A_CallSpecial"), false); - return true; + return new FxVMFunctionCall(FindGlobalActionFunction("A_CallSpecial"), args, sc); } - return false; + return NULL; } //========================================================================== @@ -151,11 +136,13 @@ static FString ParseStateString(FScanner &sc) // parses a state block // //========================================================================== -void ParseStates(FScanner &sc, FActorInfo * actor, AActor * defaults, Baggage &bag) +void ParseStates(FScanner &sc, PClassActor * actor, AActor * defaults, Baggage &bag) { FString statestring; FState state; - char lastsprite[5]=""; + char lastsprite[5] = ""; + FStateTempCall *tcall = NULL; + FArgumentList *args = NULL; sc.MustGetStringName ("{"); sc.SetEscape(false); // disable escape sequences in the state parser @@ -234,10 +221,13 @@ do_stop: state.sprite = GetSpriteIndex(statestring); state.Misc1 = state.Misc2 = 0; - state.ParameterIndex = 0; sc.MustGetString(); statestring = sc.String; + if (tcall == NULL) + { + tcall = new FStateTempCall; + } if (sc.CheckString("RANDOM")) { int min, max; @@ -263,7 +253,7 @@ do_stop: state.TicRange = 0; } - while (sc.GetString() && !sc.Crossed) + while (sc.GetString() && (!sc.Crossed || sc.Compare("{"))) { if (sc.Compare("BRIGHT")) { @@ -324,133 +314,236 @@ do_stop: continue; } - // Make the action name lowercase - strlwr (sc.String); - - if (DoActionSpecials(sc, state, bag)) - { - goto endofstate; - } - - FName funcname = FName(sc.String, true); - PSymbol *sym = bag.Info->Class->Symbols.FindSymbol (funcname, true); - if (sym != NULL && sym->SymbolType == SYM_ActionFunction) - { - PSymbolActionFunction *afd = static_cast(sym); - state.SetAction(afd, false); - if (!afd->Arguments.IsEmpty()) - { - const char *params = afd->Arguments.GetChars(); - int numparams = (int)afd->Arguments.Len(); - - int v; - - if (!islower(*params)) - { - sc.MustGetStringName("("); - } - else - { - if (!sc.CheckString("(")) - { - state.ParameterIndex = afd->defaultparameterindex+1; - goto endofstate; - } - } - - int paramindex = PrepareStateParameters(&state, numparams, bag.Info->Class); - int paramstart = paramindex; - bool varargs = params[numparams - 1] == '+'; - int varargcount = 0; - - if (varargs) - { - paramindex++; - } - else if (afd->defaultparameterindex > -1) - { - StateParams.Copy(paramindex, afd->defaultparameterindex, int(afd->Arguments.Len())); - } - - while (*params) - { - FxExpression *x; - if ((*params == 'l' || *params == 'L') && sc.CheckNumber()) - { - // Special case: State label as an offset - if (sc.Number > 0 && statestring.Len() > 1) - { - sc.ScriptError("You cannot use state jumps commands with a jump offset on multistate definitions\n"); - } - - v=sc.Number; - if (v<0) - { - sc.ScriptError("Negative jump offsets are not allowed"); - } - - if (v > 0) - { - x = new FxStateByIndex(bag.statedef.GetStateCount() + v, sc); - } - else - { - x = new FxConstant((FState*)NULL, sc); - } - } - else - { - // Use the generic parameter parser for everything else - x = ParseParameter(sc, bag.Info->Class, *params, false); - } - StateParams.Set(paramindex++, x); - params++; - if (varargs) - { - varargcount++; - } - if (*params) - { - if (*params == '+') - { - if (sc.CheckString(")")) - { - StateParams.Set(paramstart, new FxConstant(varargcount, sc)); - goto endofstate; - } - params--; - StateParams.Reserve(1, bag.Info->Class); - } - else if ((islower(*params) || *params=='!') && sc.CheckString(")")) - { - goto endofstate; - } - sc.MustGetStringName (","); - } - } - sc.MustGetStringName(")"); - } - else - { - sc.MustGetString(); - if (sc.Compare("(")) - { - sc.ScriptError("You cannot pass parameters to '%s'\n", funcname.GetChars()); - } - sc.UnGet(); - } - goto endofstate; - } - sc.ScriptError("Invalid state parameter %s\n", sc.String); + tcall->Code = ParseActions(sc, state, statestring, bag); + goto endofstate; } sc.UnGet(); endofstate: - if (!bag.statedef.AddStates(&state, statestring)) + int count = bag.statedef.AddStates(&state, statestring); + if (count < 0) { sc.ScriptError ("Invalid frame character string '%s'", statestring.GetChars()); + count = -count; + } + if (tcall->Code != NULL) + { + tcall->ActorClass = actor; + tcall->FirstState = bag.statedef.GetStateCount() - count; + tcall->NumStates = count; + StateTempCalls.Push(tcall); + tcall = NULL; } } } + if (tcall != NULL) + { + delete tcall; + } + if (args != NULL) + { + delete args; + } sc.SetEscape(true); // re-enable escape sequences } +//========================================================================== +// +// ParseActions +// +//========================================================================== + +FxTailable *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag) +{ + // If it's not a '{', then it should be a single action. + // Otherwise, it's a sequence of actions. + if (!sc.Compare("{")) + { + return ParseAction(sc, state, statestring, bag); + } + + const FScriptPosition pos(sc); + + FxSequence *seq = NULL; + sc.MustGetString(); + while (!sc.Compare("}")) + { + FxTailable *add; + if (sc.Compare("if")) + { // Hangle an if statement + FxExpression *cond; + FxTailable *true_part, *false_part = NULL; + sc.MustGetStringName("("); + cond = ParseExpression(sc, bag.Info); + sc.MustGetStringName(")"); + sc.MustGetStringName("{"); // braces are mandatory + true_part = ParseActions(sc, state, statestring, bag); + sc.MustGetString(); + if (sc.Compare("else")) + { + sc.MustGetStringName("{"); // braces are still mandatory + false_part = ParseActions(sc, state, statestring, bag); + sc.MustGetString(); + } + add = new FxIfStatement(cond, true_part, false_part, sc); + } + else + { // Handle a regular action function call + add = ParseAction(sc, state, statestring, bag); + sc.MustGetStringName(";"); + sc.MustGetString(); + } + // Only return a sequence if it has actual content. + if (add != NULL) + { + if (seq == NULL) + { + seq = new FxSequence(pos); + } + seq->Add(add); + } + } + return seq; +} + +//========================================================================== +// +// ParseAction +// +//========================================================================== + +FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestring, Baggage &bag) +{ + FxVMFunctionCall *call; + + // Make the action name lowercase + strlwr (sc.String); + + call = DoActionSpecials(sc, state, bag); + if (call != NULL) + { + return call; + } + + PFunction *afd = dyn_cast(bag.Info->Symbols.FindSymbol(FName(sc.String, true), true)); + if (afd != NULL) + { + FArgumentList *args = new FArgumentList; + ParseFunctionParameters(sc, bag.Info, *args, afd, statestring, &bag.statedef); + call = new FxVMFunctionCall(afd, args->Size() > 0 ? args : NULL, sc); + if (args->Size() == 0) + { + delete args; + } + return call; + } + sc.ScriptError("Invalid state parameter %s\n", sc.String); + return NULL; +} + +//========================================================================== +// +// ParseFunctionParameters +// +// Parses the parameters for a VM function. Called by both ParseStates +// (which will set statestring and statedef) and by ParseExpression0 (which +// will not set them). The first token returned by the scanner when entering +// this function should be '('. +// +//========================================================================== + +void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray &out_params, + PFunction *afd, FString statestring, FStateDefinitions *statedef) +{ + const TArray ¶ms = afd->Variants[0].Proto->ArgumentTypes; + const TArray ¶mflags = afd->Variants[0].ArgFlags; + int numparams = (int)params.Size(); + int pnum = 0; + bool zeroparm; + + if (afd->Flags & VARF_Method) + { + numparams--; + pnum++; + } + if (afd->Flags & VARF_Action) + { + numparams -= 2; + pnum += 2; + } + assert(numparams >= 0); + zeroparm = numparams == 0; + if (numparams > 0 && !(paramflags[pnum] & VARF_Optional)) + { + sc.MustGetStringName("("); + } + else + { + if (!sc.CheckString("(")) + { + return; + } + } + while (numparams > 0) + { + FxExpression *x; + if (statedef != NULL && params[pnum] == TypeState && sc.CheckNumber()) + { + // Special case: State label as an offset + if (sc.Number > 0 && statestring.Len() > 1) + { + sc.ScriptError("You cannot use state jumps commands with a jump offset on multistate definitions\n"); + } + + int v = sc.Number; + if (v < 0) + { + sc.ScriptError("Negative jump offsets are not allowed"); + } + + if (v > 0) + { + x = new FxStateByIndex(statedef->GetStateCount() + v, sc); + } + else + { + x = new FxConstant((FState*)NULL, sc); + } + } + else + { + // Use the generic parameter parser for everything else + x = ParseParameter(sc, cls, params[pnum], false); + } + out_params.Push(new FxParameter(x)); + pnum++; + numparams--; + if (numparams > 0) + { + if (params[pnum] == NULL) + { // varargs function + if (sc.CheckString(")")) + { + return; + } + pnum--; + numparams++; + } + else if ((paramflags[pnum] & VARF_Optional) && sc.CheckString(")")) + { + return; + } + sc.MustGetStringName (","); + } + } + if (zeroparm) + { + if (!sc.CheckString(")")) + { + sc.ScriptError("You cannot pass parameters to '%s'\n", afd->SymbolName.GetChars()); + } + } + else + { + sc.MustGetStringName(")"); + } +} diff --git a/src/thingdef/thingdef_type.h b/src/thingdef/thingdef_type.h index 721cab61f9..706b2ba7a1 100644 --- a/src/thingdef/thingdef_type.h +++ b/src/thingdef/thingdef_type.h @@ -14,10 +14,10 @@ enum ExpValType VAL_Array, // Array (very limited right now) VAL_Object, // Object reference VAL_Class, // Class reference - VAL_Pointer, // Dereferenced variable (only used for addressing arrays for now.) VAL_Sound, // Sound identifier. Internally it's an int. VAL_Name, // A Name - VAL_Color, // A color. + VAL_String, // A string + VAL_Color, // A color VAL_State, // A State pointer // only used for accessing external variables to ensure proper conversion diff --git a/src/v_blend.cpp b/src/v_blend.cpp index 0faa501ce9..05b1cffea8 100644 --- a/src/v_blend.cpp +++ b/src/v_blend.cpp @@ -121,7 +121,7 @@ void V_AddPlayerBlend (player_t *CPlayer, float blend[4], float maxinvalpha, int } PalEntry painFlash = CPlayer->mo->DamageFade; - CPlayer->mo->GetClass()->ActorInfo->GetPainFlash(CPlayer->mo->DamageTypeReceived, &painFlash); + CPlayer->mo->GetClass()->GetPainFlash(CPlayer->mo->DamageTypeReceived, &painFlash); if (painFlash.a != 0) { diff --git a/src/win32/i_main.cpp b/src/win32/i_main.cpp index 8b6521ad57..3836af3f8e 100644 --- a/src/win32/i_main.cpp +++ b/src/win32/i_main.cpp @@ -1284,7 +1284,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE nothing, LPSTR cmdline, int n _CrtSetDbgFlag (_CrtSetDbgFlag(0) | _CRTDBG_LEAK_CHECK_DF); // Use this to break at a specific allocation number. - //_crtBreakAlloc = 77624; + //_crtBreakAlloc = 53039; #endif DoMain (hInstance); diff --git a/src/win32/i_rawps2.cpp b/src/win32/i_rawps2.cpp index 84fb605c64..0ca3145040 100644 --- a/src/win32/i_rawps2.cpp +++ b/src/win32/i_rawps2.cpp @@ -1293,6 +1293,10 @@ void I_StartupRawPS2() { JoyDevices[INPUT_RawPS2] = joys; } + else + { + delete joys; + } } } } diff --git a/src/win32/i_xinput.cpp b/src/win32/i_xinput.cpp index 3d85f48a0d..9ad28b7272 100644 --- a/src/win32/i_xinput.cpp +++ b/src/win32/i_xinput.cpp @@ -783,6 +783,10 @@ void I_StartupXInput() { JoyDevices[INPUT_XInput] = joys; } + else + { + delete joys; + } } } } diff --git a/src/zscript/ast.cpp b/src/zscript/ast.cpp new file mode 100644 index 0000000000..bc1966142c --- /dev/null +++ b/src/zscript/ast.cpp @@ -0,0 +1,830 @@ +#include "dobject.h" +#include "sc_man.h" +#include "memarena.h" +#include "zcc_parser.h" +#include "zcc-parse.h" + +class FLispString; +extern void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FLispString &, ZCC_TreeNode *); + +static const char *BuiltInTypeNames[] = +{ + "sint8", "uint8", + "sint16", "uint16", + "sint32", "uint32", + "intauto", + + "bool", + "float32", "float64", "floatauto", + "string", + "vector2", + "vector3", + "vector4", + "name", + "usertype" +}; + +class FLispString +{ +public: + operator FString &() { return Str; } + + FLispString() + { + NestDepth = Column = 0; + WrapWidth = 72; + NeedSpace = false; + ConsecOpens = 0; + } + + void Open(const char *label) + { + size_t labellen = label != NULL ? strlen(label) : 0; + CheckWrap(labellen + 1 + NeedSpace); + if (NeedSpace) + { + Str << ' '; + ConsecOpens = 0; + } + Str << '('; + ConsecOpens++; + if (label != NULL) + { + Str.AppendCStrPart(label, labellen); + } + Column += labellen + 1 + NeedSpace; + NestDepth++; + NeedSpace = (label != NULL); + } + void Close() + { + assert(NestDepth != 0); + Str << ')'; + Column++; + NestDepth--; + NeedSpace = true; + } + void Break() + { + // Don't break if not needed. + if (Column != NestDepth) + { + if (NeedSpace) + { + ConsecOpens = 0; + } + else + { // Move hanging ( characters to the new line + Str.Truncate(long(Str.Len() - ConsecOpens)); + NestDepth -= ConsecOpens; + } + Str << '\n'; + Column = NestDepth; + NeedSpace = false; + if (NestDepth > 0) + { + Str.AppendFormat("%*s", (int)NestDepth, ""); + } + if (ConsecOpens > 0) + { + for (size_t i = 0; i < ConsecOpens; ++i) + { + Str << '('; + } + NestDepth += ConsecOpens; + } + } + } + bool CheckWrap(size_t len) + { + if (len + Column > WrapWidth) + { + Break(); + return true; + } + return false; + } + void Add(const char *str, size_t len) + { + CheckWrap(len + NeedSpace); + if (NeedSpace) + { + Str << ' '; + } + Str.AppendCStrPart(str, len); + Column += len + NeedSpace; + NeedSpace = true; + } + void Add(const char *str) + { + Add(str, strlen(str)); + } + void Add(FString &str) + { + Add(str.GetChars(), str.Len()); + } + void AddName(FName name) + { + size_t namelen = strlen(name.GetChars()); + CheckWrap(namelen + 2 + NeedSpace); + if (NeedSpace) + { + NeedSpace = false; + Str << ' '; + } + Str << '\'' << name.GetChars() << '\''; + Column += namelen + 2 + NeedSpace; + NeedSpace = true; + } + void AddChar(char c) + { + Add(&c, 1); + } + void AddInt(int i, bool un=false) + { + char buf[16]; + size_t len; + if (!un) + { + len = mysnprintf(buf, countof(buf), "%d", i); + } + else + { + len = mysnprintf(buf, countof(buf), "%uu", i); + } + Add(buf, len); + } + void AddHex(unsigned x) + { + char buf[10]; + size_t len = mysnprintf(buf, countof(buf), "%08x", x); + Add(buf, len); + } + void AddFloat(double f, bool single) + { + char buf[32]; + size_t len = mysnprintf(buf, countof(buf), "%.4f", f); + if (single) + { + buf[len++] = 'f'; + buf[len] = '\0'; + } + Add(buf, len); + } +private: + FString Str; + size_t NestDepth; + size_t Column; + size_t WrapWidth; + size_t ConsecOpens; + bool NeedSpace; +}; + +static void PrintNode(FLispString &out, ZCC_TreeNode *node) +{ + assert(TreeNodePrinter[NUM_AST_NODE_TYPES-1] != NULL); + if (node->NodeType >= 0 && node->NodeType < NUM_AST_NODE_TYPES) + { + TreeNodePrinter[node->NodeType](out, node); + } + else + { + out.Open("unknown-node-type"); + out.AddInt(node->NodeType); + out.Close(); + } +} + +static void PrintNodes(FLispString &out, ZCC_TreeNode *node, bool newlist=true, bool addbreaks=false) +{ + ZCC_TreeNode *p; + + if (node == NULL) + { + out.Add("nil", 3); + } + else + { + if (newlist) + { + out.Open(NULL); + } + p = node; + do + { + if (addbreaks) + { + out.Break(); + } + PrintNode(out, p); + p = p->SiblingNext; + } while (p != node); + if (newlist) + { + out.Close(); + } + } +} + +static void PrintBuiltInType(FLispString &out, EZCCBuiltinType type) +{ + assert(ZCC_NUM_BUILT_IN_TYPES == countof(BuiltInTypeNames)); + if (unsigned(type) >= unsigned(ZCC_NUM_BUILT_IN_TYPES)) + { + char buf[30]; + size_t len = mysnprintf(buf, countof(buf), "bad-type-%u", type); + out.Add(buf, len); + } + else + { + out.Add(BuiltInTypeNames[type]); + } +} + +static void PrintIdentifier(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_Identifier *inode = (ZCC_Identifier *)node; + out.Open("identifier"); + out.AddName(inode->Id); + out.Close(); +} + +static void PrintStringConst(FLispString &out, FString str) +{ + FString outstr; + outstr << '"'; + for (size_t i = 0; i < str.Len(); ++i) + { + if (str[i] == '"') + { + outstr << "\""; + } + else if (str[i] == '\\') + { + outstr << "\\\\"; + } + else if (str[i] >= 32) + { + outstr << str[i]; + } + else + { + outstr.AppendFormat("\\x%02X", str[i]); + } + } + outstr << '"'; + out.Add(outstr); +} + +static void PrintClass(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_Class *cnode = (ZCC_Class *)node; + out.Break(); + out.Open("class"); + out.AddName(cnode->ClassName); + PrintNodes(out, cnode->ParentName); + PrintNodes(out, cnode->Replaces); + out.AddHex(cnode->Flags); + PrintNodes(out, cnode->Body, false, true); + out.Close(); +} + +static void PrintStruct(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_Struct *snode = (ZCC_Struct *)node; + out.Break(); + out.Open("struct"); + out.AddName(snode->StructName); + PrintNodes(out, snode->Body, false, true); + out.Close(); +} + +static void PrintEnum(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_Enum *enode = (ZCC_Enum *)node; + out.Break(); + out.Open("enum"); + out.AddName(enode->EnumName); + PrintBuiltInType(out, enode->EnumType); + out.Add(enode->Elements == NULL ? "nil" : "...", 3); + out.Close(); +} + +static void PrintEnumTerminator(FLispString &out, ZCC_TreeNode *node) +{ + out.Open("enum-term"); + out.Close(); +} + +static void PrintStates(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_States *snode = (ZCC_States *)node; + out.Break(); + out.Open("states"); + PrintNodes(out, snode->Body, false, true); + out.Close(); +} + +static void PrintStatePart(FLispString &out, ZCC_TreeNode *node) +{ + out.Open("state-part"); + out.Close(); +} + +static void PrintStateLabel(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_StateLabel *snode = (ZCC_StateLabel *)node; + out.Open("state-label"); + out.AddName(snode->Label); + out.Close(); +} + +static void PrintStateStop(FLispString &out, ZCC_TreeNode *node) +{ + out.Open("state-stop"); + out.Close(); +} + +static void PrintStateWait(FLispString &out, ZCC_TreeNode *node) +{ + out.Open("state-wait"); + out.Close(); +} + +static void PrintStateFail(FLispString &out, ZCC_TreeNode *node) +{ + out.Open("state-fail"); + out.Close(); +} + +static void PrintStateLoop(FLispString &out, ZCC_TreeNode *node) +{ + out.Open("state-loop"); + out.Close(); +} + +static void PrintStateGoto(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_StateGoto *snode = (ZCC_StateGoto *)node; + out.Open("state-goto"); + PrintNodes(out, snode->Label); + PrintNodes(out, snode->Offset); + out.Close(); +} + +static void PrintStateLine(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_StateLine *snode = (ZCC_StateLine *)node; + out.Open("state-line"); + out.Add(snode->Sprite, 4); + if (snode->bBright) + { + out.Add("bright", 6); + } + out.Add(*(snode->Frames)); + PrintNodes(out, snode->Offset); + PrintNodes(out, snode->Action, false); + out.Close(); +} + +static void PrintVarName(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_VarName *vnode = (ZCC_VarName *)node; + out.Open("var-name"); + PrintNodes(out, vnode->ArraySize); + out.AddName(vnode->Name); + out.Close(); +} + +static void PrintType(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_Type *tnode = (ZCC_Type *)node; + out.Open("bad-type"); + PrintNodes(out, tnode->ArraySize); + out.Close(); +} + +static void PrintBasicType(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_BasicType *tnode = (ZCC_BasicType *)node; + out.Open("basic-type"); + PrintNodes(out, tnode->ArraySize); + PrintBuiltInType(out, tnode->Type); + if (tnode->Type == ZCC_UserType) + { + PrintNodes(out, tnode->UserType, false); + } + out.Close(); +} + +static void PrintMapType(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_MapType *tnode = (ZCC_MapType *)node; + out.Open("map-type"); + PrintNodes(out, tnode->ArraySize); + PrintNodes(out, tnode->KeyType); + PrintNodes(out, tnode->ValueType); + out.Close(); +} + +static void PrintDynArrayType(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_DynArrayType *tnode = (ZCC_DynArrayType *)node; + out.Open("dyn-array-type"); + PrintNodes(out, tnode->ArraySize); + PrintNodes(out, tnode->ElementType); + out.Close(); +} + +static void PrintClassType(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_ClassType *tnode = (ZCC_ClassType *)node; + out.Open("class-type"); + PrintNodes(out, tnode->ArraySize); + PrintNodes(out, tnode->Restriction); + out.Close(); +} + +static void OpenExprType(FLispString &out, EZCCExprType type) +{ + char buf[32]; + + if (unsigned(type) < PEX_COUNT_OF) + { + mysnprintf(buf, countof(buf), "expr-%s", ZCC_OpInfo[type].OpName); + } + else + { + mysnprintf(buf, countof(buf), "bad-pex-%u", type); + } + out.Open(buf); +} + +static void PrintExpression(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_Expression *enode = (ZCC_Expression *)node; + OpenExprType(out, enode->Operation); + out.Close(); +} + +static void PrintExprID(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_ExprID *enode = (ZCC_ExprID *)node; + assert(enode->Operation == PEX_ID); + out.Open("expr-id"); + out.AddName(enode->Identifier); + out.Close(); +} + +static void PrintExprTypeRef(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_ExprTypeRef *enode = (ZCC_ExprTypeRef *)node; + assert(enode->Operation == PEX_TypeRef); + out.Open("expr-type-ref"); + if (enode->RefType == TypeSInt8) { out.Add("sint8"); } + else if (enode->RefType == TypeUInt8) { out.Add("uint8"); } + else if (enode->RefType == TypeSInt16) { out.Add("sint16"); } + else if (enode->RefType == TypeSInt32) { out.Add("sint32"); } + else if (enode->RefType == TypeFloat32) { out.Add("float32"); } + else if (enode->RefType == TypeFloat64) { out.Add("float64"); } + else if (enode->RefType == TypeString) { out.Add("string"); } + else if (enode->RefType == TypeName) { out.Add("name"); } + else if (enode->RefType == TypeColor) { out.Add("color"); } + else if (enode->RefType == TypeSound) { out.Add("sound"); } + else { out.Add("other"); } + out.Close(); +} + +static void PrintExprConstant(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_ExprConstant *enode = (ZCC_ExprConstant *)node; + assert(enode->Operation == PEX_ConstValue); + out.Open("expr-const"); + if (enode->Type == TypeString) + { + PrintStringConst(out, *enode->StringVal); + } + else if (enode->Type == TypeFloat64) + { + out.AddFloat(enode->DoubleVal, false); + } + else if (enode->Type == TypeFloat32) + { + out.AddFloat(enode->DoubleVal, true); + } + else if (enode->Type == TypeName) + { + out.AddName(ENamedName(enode->IntVal)); + } + else if (enode->Type->IsKindOf(RUNTIME_CLASS(PInt))) + { + out.AddInt(enode->IntVal, static_cast(enode->Type)->Unsigned); + } + out.Close(); +} + +static void PrintExprFuncCall(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_ExprFuncCall *enode = (ZCC_ExprFuncCall *)node; + assert(enode->Operation == PEX_FuncCall); + out.Open("expr-func-call"); + PrintNodes(out, enode->Function); + PrintNodes(out, enode->Parameters, false); + out.Close(); +} + +static void PrintExprMemberAccess(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_ExprMemberAccess *enode = (ZCC_ExprMemberAccess *)node; + assert(enode->Operation == PEX_MemberAccess); + out.Open("expr-member-access"); + PrintNodes(out, enode->Left); + out.AddName(enode->Right); + out.Close(); +} + +static void PrintExprUnary(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_ExprUnary *enode = (ZCC_ExprUnary *)node; + OpenExprType(out, enode->Operation); + PrintNodes(out, enode->Operand, false); + out.Close(); +} + +static void PrintExprBinary(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_ExprBinary *enode = (ZCC_ExprBinary *)node; + OpenExprType(out, enode->Operation); + PrintNodes(out, enode->Left); + PrintNodes(out, enode->Right); + out.Close(); +} + +static void PrintExprTrinary(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_ExprTrinary *enode = (ZCC_ExprTrinary *)node; + OpenExprType(out, enode->Operation); + PrintNodes(out, enode->Test); + PrintNodes(out, enode->Left); + PrintNodes(out, enode->Right); + out.Close(); +} + +static void PrintFuncParam(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_FuncParm *pnode = (ZCC_FuncParm *)node; + out.Break(); + out.Open("func-parm"); + out.AddName(pnode->Label); + PrintNodes(out, pnode->Value, false); + out.Close(); +} + +static void PrintStatement(FLispString &out, ZCC_TreeNode *node) +{ + out.Open("statement"); + out.Close(); +} + +static void PrintCompoundStmt(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_CompoundStmt *snode = (ZCC_CompoundStmt *)node; + out.Break(); + out.Open("compound-stmt"); + PrintNodes(out, snode->Content, false, true); + out.Close(); +} + +static void PrintContinueStmt(FLispString &out, ZCC_TreeNode *node) +{ + out.Break(); + out.Open("continue-stmt"); + out.Close(); +} + +static void PrintBreakStmt(FLispString &out, ZCC_TreeNode *node) +{ + out.Break(); + out.Open("break-stmt"); + out.Close(); +} + +static void PrintReturnStmt(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_ReturnStmt *snode = (ZCC_ReturnStmt *)node; + out.Break(); + out.Open("return-stmt"); + PrintNodes(out, snode->Values, false); + out.Close(); +} + +static void PrintExpressionStmt(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_ExpressionStmt *snode = (ZCC_ExpressionStmt *)node; + out.Break(); + out.Open("expression-stmt"); + PrintNodes(out, snode->Expression, false); + out.Close(); +} + +static void PrintIterationStmt(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_IterationStmt *snode = (ZCC_IterationStmt *)node; + out.Break(); + out.Open("iteration-stmt"); + out.Add((snode->CheckAt == ZCC_IterationStmt::Start) ? "start" : "end"); + out.Break(); + PrintNodes(out, snode->LoopCondition); + out.Break(); + PrintNodes(out, snode->LoopBumper); + out.Break(); + PrintNodes(out, snode->LoopStatement); + out.Close(); +} + +static void PrintIfStmt(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_IfStmt *snode = (ZCC_IfStmt *)node; + out.Break(); + out.Open("if-stmt"); + PrintNodes(out, snode->Condition); + out.Break(); + PrintNodes(out, snode->TruePath); + out.Break(); + PrintNodes(out, snode->FalsePath); + out.Close(); +} + +static void PrintSwitchStmt(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_SwitchStmt *snode = (ZCC_SwitchStmt *)node; + out.Break(); + out.Open("switch-stmt"); + PrintNodes(out, snode->Condition); + out.Break(); + PrintNodes(out, snode->Content, false); + out.Close(); +} + +static void PrintCaseStmt(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_CaseStmt *snode = (ZCC_CaseStmt *)node; + out.Break(); + out.Open("case-stmt"); + PrintNodes(out, snode->Condition, false); + out.Close(); +} + +static void BadAssignOp(FLispString &out, int op) +{ + char buf[32]; + size_t len = mysnprintf(buf, countof(buf), "assign-op-%d", op); + out.Add(buf, len); +} + +static void PrintAssignStmt(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_AssignStmt *snode = (ZCC_AssignStmt *)node; + out.Open("assign-stmt"); + switch (snode->AssignOp) + { + case ZCC_EQ: out.AddChar('='); break; + case ZCC_MULEQ: out.Add("*=", 2); break; + case ZCC_DIVEQ: out.Add("/=", 2); break; + case ZCC_MODEQ: out.Add("%=", 2); break; + case ZCC_ADDEQ: out.Add("+=", 2); break; + case ZCC_SUBEQ: out.Add("-=", 2); break; + case ZCC_LSHEQ: out.Add("<<=", 2); break; + case ZCC_RSHEQ: out.Add(">>=", 2); break; + case ZCC_ANDEQ: out.Add("&=", 2); break; + case ZCC_OREQ: out.Add("|=", 2); break; + case ZCC_XOREQ: out.Add("^=", 2); break; + default: BadAssignOp(out, snode->AssignOp); break; + } + PrintNodes(out, snode->Dests); + PrintNodes(out, snode->Sources); + out.Close(); +} + +static void PrintLocalVarStmt(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_LocalVarStmt *snode = (ZCC_LocalVarStmt *)node; + out.Open("local-var-stmt"); + PrintNodes(out, snode->Type); + PrintNodes(out, snode->Vars); + PrintNodes(out, snode->Inits); + out.Close(); +} + +static void PrintFuncParamDecl(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_FuncParamDecl *dnode = (ZCC_FuncParamDecl *)node; + out.Break(); + out.Open("func-param-decl"); + PrintNodes(out, dnode->Type); + out.AddName(dnode->Name); + out.AddHex(dnode->Flags); + out.Close(); +} + +static void PrintConstantDef(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_ConstantDef *dnode = (ZCC_ConstantDef *)node; + out.Break(); + out.Open("constant-def"); + out.AddName(dnode->Name); + PrintNodes(out, dnode->Value, false); + out.Close(); +} + +static void PrintDeclarator(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_Declarator *dnode = (ZCC_Declarator *)node; + out.Break(); + out.Open("declarator"); + out.AddHex(dnode->Flags); + PrintNodes(out, dnode->Type); + out.Close(); +} + +static void PrintVarDeclarator(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_VarDeclarator *dnode = (ZCC_VarDeclarator *)node; + out.Break(); + out.Open("var-declarator"); + out.AddHex(dnode->Flags); + PrintNodes(out, dnode->Type); + PrintNodes(out, dnode->Names); + out.Close(); +} + +static void PrintFuncDeclarator(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_FuncDeclarator *dnode = (ZCC_FuncDeclarator *)node; + out.Break(); + out.Open("func-declarator"); + out.AddHex(dnode->Flags); + PrintNodes(out, dnode->Type); + out.AddName(dnode->Name); + PrintNodes(out, dnode->Params); + PrintNodes(out, dnode->Body, false); + out.Close(); +} + +void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FLispString &, ZCC_TreeNode *) = +{ + PrintIdentifier, + PrintClass, + PrintStruct, + PrintEnum, + PrintEnumTerminator, + PrintStates, + PrintStatePart, + PrintStateLabel, + PrintStateStop, + PrintStateWait, + PrintStateFail, + PrintStateLoop, + PrintStateGoto, + PrintStateLine, + PrintVarName, + PrintType, + PrintBasicType, + PrintMapType, + PrintDynArrayType, + PrintClassType, + PrintExpression, + PrintExprID, + PrintExprTypeRef, + PrintExprConstant, + PrintExprFuncCall, + PrintExprMemberAccess, + PrintExprUnary, + PrintExprBinary, + PrintExprTrinary, + PrintFuncParam, + PrintStatement, + PrintCompoundStmt, + PrintContinueStmt, + PrintBreakStmt, + PrintReturnStmt, + PrintExpressionStmt, + PrintIterationStmt, + PrintIfStmt, + PrintSwitchStmt, + PrintCaseStmt, + PrintAssignStmt, + PrintLocalVarStmt, + PrintFuncParamDecl, + PrintConstantDef, + PrintDeclarator, + PrintVarDeclarator, + PrintFuncDeclarator +}; + +FString ZCC_PrintAST(ZCC_TreeNode *root) +{ + FLispString out; + PrintNodes(out, root); + return out; +} diff --git a/src/zscript/vm.h b/src/zscript/vm.h new file mode 100644 index 0000000000..1bbded8612 --- /dev/null +++ b/src/zscript/vm.h @@ -0,0 +1,951 @@ +#ifndef VM_H +#define VM_H + +#include "zstring.h" +#include "dobject.h" + +#define MAX_RETURNS 8 // Maximum number of results a function called by script code can return +#define MAX_TRY_DEPTH 8 // Maximum number of nested TRYs in a single function + + +typedef unsigned char VM_UBYTE; +typedef signed char VM_SBYTE; +typedef unsigned short VM_UHALF; +typedef signed short VM_SHALF; +typedef unsigned int VM_UWORD; +typedef signed int VM_SWORD; +typedef VM_UBYTE VM_ATAG; + +#define VM_EPSILON (1/1024.0) + +union VMOP +{ + struct + { + VM_UBYTE op, a, b, c; + }; + struct + { + VM_SBYTE pad0, as, bs, cs; + }; + struct + { + VM_SWORD pad1:8, i24:24; + }; + struct + { + VM_SWORD pad2:16, i16:16; + }; + struct + { + VM_UHALF pad3, i16u; + }; + VM_UWORD word; + + // Interesting fact: VC++ produces better code for i16 when it's defined + // as a bitfield than when it's defined as two discrete units. + // Compare: + // mov eax,dword ptr [op] ; As two discrete units + // shr eax,10h + // movsx eax,ax + // versus: + // mov eax,dword ptr [op] ; As a bitfield + // sar eax,10h +}; + +enum +{ +#include "vmops.h" +NUM_OPS +}; + +// Flags for A field of CMPS +enum +{ + CMP_CHECK = 1, + + CMP_EQ = 0, + CMP_LT = 2, + CMP_LE = 4, + CMP_METHOD_MASK = 6, + + CMP_BK = 8, + CMP_CK = 16, + CMP_APPROX = 32, +}; + +// Floating point operations for FLOP +enum +{ + FLOP_ABS, + FLOP_NEG, + FLOP_EXP, + FLOP_LOG, + FLOP_LOG10, + FLOP_SQRT, + FLOP_CEIL, + FLOP_FLOOR, + + FLOP_ACOS, // This group works with radians + FLOP_ASIN, + FLOP_ATAN, + FLOP_COS, + FLOP_SIN, + FLOP_TAN, + + FLOP_ACOS_DEG, // This group works with degrees + FLOP_ASIN_DEG, + FLOP_ATAN_DEG, + FLOP_COS_DEG, + FLOP_SIN_DEG, + FLOP_TAN_DEG, + + FLOP_COSH, + FLOP_SINH, + FLOP_TANH, +}; + +// Cast operations +enum +{ + CAST_I2F, + CAST_I2S, + CAST_F2I, + CAST_F2S, + CAST_P2S, + CAST_S2I, + CAST_S2F, +}; + +// Register types for VMParam +enum +{ + REGT_INT = 0, + REGT_FLOAT = 1, + REGT_STRING = 2, + REGT_POINTER = 3, + REGT_TYPE = 3, + + REGT_KONST = 4, + REGT_MULTIREG = 8, // (e.g. a vector) + REGT_ADDROF = 32, // used with PARAM: pass address of this register + + REGT_NIL = 255 // parameter was omitted +}; + +#define RET_FINAL (0x80) // Used with RET and RETI in the destination slot: this is the final return value + + +// Tags for address registers +enum +{ + ATAG_GENERIC, // pointer to something; we don't care what + ATAG_OBJECT, // pointer to an object; will be followed by GC + + // The following are all for documentation during debugging and are + // functionally no different than ATAG_GENERIC. + + ATAG_FRAMEPOINTER, // pointer to extra stack frame space for this function + ATAG_DREGISTER, // pointer to a data register + ATAG_FREGISTER, // pointer to a float register + ATAG_SREGISTER, // pointer to a string register + ATAG_AREGISTER, // pointer to an address register + + ATAG_STATE, // pointer to FState + ATAG_RNG, // pointer to FRandom +}; + +class VMFunction : public DObject +{ + DECLARE_ABSTRACT_CLASS(VMFunction, DObject); +public: + bool Native; + FName Name; + + VMFunction() : Native(false), Name(NAME_None) {} + VMFunction(FName name) : Native(false), Name(name) {} +}; + +enum EVMOpMode +{ + MODE_ASHIFT = 0, + MODE_BSHIFT = 4, + MODE_CSHIFT = 8, + MODE_BCSHIFT = 12, + + MODE_ATYPE = 15 << MODE_ASHIFT, + MODE_BTYPE = 15 << MODE_BSHIFT, + MODE_CTYPE = 15 << MODE_CSHIFT, + MODE_BCTYPE = 31 << MODE_BCSHIFT, + + MODE_I = 0, + MODE_F, + MODE_S, + MODE_P, + MODE_V, + MODE_X, + MODE_KI, + MODE_KF, + MODE_KS, + MODE_KP, + MODE_KV, + MODE_UNUSED, + MODE_IMMS, + MODE_IMMZ, + MODE_JOINT, + MODE_CMP, + + MODE_PARAM, + MODE_THROW, + MODE_CATCH, + MODE_CAST, + + MODE_AI = MODE_I << MODE_ASHIFT, + MODE_AF = MODE_F << MODE_ASHIFT, + MODE_AS = MODE_S << MODE_ASHIFT, + MODE_AP = MODE_P << MODE_ASHIFT, + MODE_AV = MODE_V << MODE_ASHIFT, + MODE_AX = MODE_X << MODE_ASHIFT, + MODE_AKP = MODE_KP << MODE_ASHIFT, + MODE_AUNUSED = MODE_UNUSED << MODE_ASHIFT, + MODE_AIMMS = MODE_IMMS << MODE_ASHIFT, + MODE_AIMMZ = MODE_IMMZ << MODE_ASHIFT, + MODE_ACMP = MODE_CMP << MODE_ASHIFT, + + MODE_BI = MODE_I << MODE_BSHIFT, + MODE_BF = MODE_F << MODE_BSHIFT, + MODE_BS = MODE_S << MODE_BSHIFT, + MODE_BP = MODE_P << MODE_BSHIFT, + MODE_BV = MODE_V << MODE_BSHIFT, + MODE_BX = MODE_X << MODE_BSHIFT, + MODE_BKI = MODE_KI << MODE_BSHIFT, + MODE_BKF = MODE_KF << MODE_BSHIFT, + MODE_BKS = MODE_KS << MODE_BSHIFT, + MODE_BKP = MODE_KP << MODE_BSHIFT, + MODE_BKV = MODE_KV << MODE_BSHIFT, + MODE_BUNUSED = MODE_UNUSED << MODE_BSHIFT, + MODE_BIMMS = MODE_IMMS << MODE_BSHIFT, + MODE_BIMMZ = MODE_IMMZ << MODE_BSHIFT, + + MODE_CI = MODE_I << MODE_CSHIFT, + MODE_CF = MODE_F << MODE_CSHIFT, + MODE_CS = MODE_S << MODE_CSHIFT, + MODE_CP = MODE_P << MODE_CSHIFT, + MODE_CV = MODE_V << MODE_CSHIFT, + MODE_CX = MODE_X << MODE_CSHIFT, + MODE_CKI = MODE_KI << MODE_CSHIFT, + MODE_CKF = MODE_KF << MODE_CSHIFT, + MODE_CKS = MODE_KS << MODE_CSHIFT, + MODE_CKP = MODE_KP << MODE_CSHIFT, + MODE_CKV = MODE_KV << MODE_CSHIFT, + MODE_CUNUSED = MODE_UNUSED << MODE_CSHIFT, + MODE_CIMMS = MODE_IMMS << MODE_CSHIFT, + MODE_CIMMZ = MODE_IMMZ << MODE_CSHIFT, + + MODE_BCJOINT = (MODE_JOINT << MODE_BSHIFT) | (MODE_JOINT << MODE_CSHIFT), + MODE_BCKI = MODE_KI << MODE_BCSHIFT, + MODE_BCKF = MODE_KF << MODE_BCSHIFT, + MODE_BCKS = MODE_KS << MODE_BCSHIFT, + MODE_BCKP = MODE_KP << MODE_BCSHIFT, + MODE_BCIMMS = MODE_IMMS << MODE_BCSHIFT, + MODE_BCIMMZ = MODE_IMMZ << MODE_BCSHIFT, + MODE_BCPARAM = MODE_PARAM << MODE_BCSHIFT, + MODE_BCTHROW = MODE_THROW << MODE_BCSHIFT, + MODE_BCCATCH = MODE_CATCH << MODE_BCSHIFT, + MODE_BCCAST = MODE_CAST << MODE_BCSHIFT, + + MODE_ABCJOINT = (MODE_JOINT << MODE_ASHIFT) | MODE_BCJOINT, +}; + +struct VMOpInfo +{ + const char *Name; + int Mode; +}; + +extern const VMOpInfo OpInfo[NUM_OPS]; + +struct VMReturn +{ + void *Location; + VM_SHALF TagOfs; // for pointers: Offset from Location to ATag; set to 0 if the caller is native code and doesn't care + VM_UBYTE RegType; // Same as VMParam RegType, except REGT_KONST is invalid; only used by asserts + + void SetInt(int val) + { + assert(RegType == REGT_INT); + *(int *)Location = val; + } + void SetFloat(double val) + { + assert(RegType == REGT_FLOAT); + *(double *)Location = val; + } + void SetVector(const double val[3]) + { + //assert(RegType == REGT_FLOAT); + ((double *)Location)[0] = val[0]; + ((double *)Location)[1] = val[1]; + ((double *)Location)[2] = val[2]; + } + void SetString(const FString &val) + { + assert(RegType == REGT_STRING); + *(FString *)Location = val; + } + void SetPointer(void *val, int tag) + { + assert(RegType == REGT_POINTER); + *(void **)Location = val; + if (TagOfs != 0) + { + *((VM_ATAG *)Location + TagOfs) = tag; + } + } + + void IntAt(int *loc) + { + Location = loc; + TagOfs = 0; + RegType = REGT_INT; + } + void FloatAt(double *loc) + { + Location = loc; + TagOfs = 0; + RegType = REGT_FLOAT; + } + void StringAt(FString *loc) + { + Location = loc; + TagOfs = 0; + RegType = REGT_STRING; + } + void PointerAt(void **loc) + { + Location = loc; + TagOfs = 0; + RegType = REGT_POINTER; + } +}; + +struct VMRegisters; + + +struct VMValue +{ + union + { + int i; + struct { void *a; int atag; }; + double f; + struct { int pad[3]; VM_UBYTE Type; }; + struct { int foo[4]; } biggest; + }; + + // Unfortunately, FString cannot be used directly. + // Fortunately, it is relatively simple. + FString &s() { return *(FString *)&a; } + const FString &s() const { return *(FString *)&a; } + + VMValue() + { + a = NULL; + Type = REGT_NIL; + } + ~VMValue() + { + Kill(); + } + VMValue(const VMValue &o) + { + biggest = o.biggest; + if (Type == REGT_STRING) + { + ::new(&s()) FString(o.s()); + } + } + VMValue(int v) + { + i = v; + Type = REGT_INT; + } + VMValue(double v) + { + f = v; + Type = REGT_FLOAT; + } + VMValue(const char *s) + { + ::new(&a) FString(s); + Type = REGT_STRING; + } + VMValue(const FString &s) + { + ::new(&a) FString(s); + Type = REGT_STRING; + } + VMValue(DObject *v) + { + a = v; + atag = ATAG_OBJECT; + Type = REGT_POINTER; + } + VMValue(void *v) + { + a = v; + atag = ATAG_GENERIC; + Type = REGT_POINTER; + } + VMValue(void *v, int tag) + { + a = v; + atag = tag; + Type = REGT_POINTER; + } + VMValue &operator=(const VMValue &o) + { + if (o.Type == REGT_STRING) + { + if (Type == REGT_STRING) + { + s() = o.s(); + } + else + { + new(&s()) FString(o.s()); + Type = REGT_STRING; + } + } + else + { + Kill(); + biggest = o.biggest; + } + return *this; + } + VMValue &operator=(int v) + { + Kill(); + i = v; + Type = REGT_INT; + return *this; + } + VMValue &operator=(double v) + { + Kill(); + f = v; + Type = REGT_FLOAT; + return *this; + } + VMValue &operator=(const FString &v) + { + if (Type == REGT_STRING) + { + s() = v; + } + else + { + ::new(&s()) FString(v); + Type = REGT_STRING; + } + return *this; + } + VMValue &operator=(const char *v) + { + if (Type == REGT_STRING) + { + s() = v; + } + else + { + ::new(&s()) FString(v); + Type = REGT_STRING; + } + return *this; + } + VMValue &operator=(DObject *v) + { + Kill(); + a = v; + atag = ATAG_OBJECT; + Type = REGT_POINTER; + return *this; + } + void SetPointer(void *v, VM_ATAG atag=ATAG_GENERIC) + { + Kill(); + a = v; + this->atag = atag; + Type = REGT_POINTER; + } + void SetNil() + { + Kill(); + Type = REGT_NIL; + } + bool operator==(const VMValue &o) + { + return Test(o) == 0; + } + bool operator!=(const VMValue &o) + { + return Test(o) != 0; + } + bool operator< (const VMValue &o) + { + return Test(o) < 0; + } + bool operator<=(const VMValue &o) + { + return Test(o) <= 0; + } + bool operator> (const VMValue &o) + { + return Test(o) > 0; + } + bool operator>=(const VMValue &o) + { + return Test(o) >= 0; + } + int Test(const VMValue &o, int inexact=false) + { + double diff; + + if (Type == o.Type) + { + switch(Type) + { + case REGT_NIL: + return 0; + + case REGT_INT: + return i - o.i; + + case REGT_FLOAT: + diff = f - o.f; +do_double: if (inexact) + { + return diff < -VM_EPSILON ? -1 : diff > VM_EPSILON ? 1 : 0; + } + return diff < 0 ? -1 : diff > 0 ? 1 : 0; + + case REGT_STRING: + return inexact ? s().CompareNoCase(o.s()) : s().Compare(o.s()); + + case REGT_POINTER: + return int((const VM_UBYTE *)a - (const VM_UBYTE *)o.a); + } + assert(0); // Should not get here + return 2; + } + if (Type == REGT_FLOAT && o.Type == REGT_INT) + { + diff = f - o.i; + goto do_double; + } + if (Type == REGT_INT && o.Type == REGT_FLOAT) + { + diff = i - o.f; + goto do_double; + } + // Bad comparison + return 2; + } + FString ToString() + { + if (Type == REGT_STRING) + { + return s(); + } + else if (Type == REGT_NIL) + { + return "nil"; + } + FString t; + if (Type == REGT_INT) + { + t.Format ("%d", i); + } + else if (Type == REGT_FLOAT) + { + t.Format ("%.14g", f); + } + else if (Type == REGT_POINTER) + { + // FIXME + t.Format ("Object: %p", a); + } + return t; + } + int ToInt() + { + if (Type == REGT_INT) + { + return i; + } + if (Type == REGT_FLOAT) + { + return int(f); + } + if (Type == REGT_STRING) + { + return s().ToLong(); + } + // FIXME + return 0; + } + double ToDouble() + { + if (Type == REGT_FLOAT) + { + return f; + } + if (Type == REGT_INT) + { + return i; + } + if (Type == REGT_STRING) + { + return s().ToDouble(); + } + // FIXME + return 0; + } + void Kill() + { + if (Type == REGT_STRING) + { + s().~FString(); + } + } +}; + +// VM frame layout: +// VMFrame header +// parameter stack - 16 byte boundary, 16 bytes each +// double registers - 8 bytes each +// string registers - 4 or 8 bytes each +// address registers - 4 or 8 bytes each +// data registers - 4 bytes each +// address register tags-1 byte each +// extra space - 16 byte boundary +struct VMFrame +{ + VMFrame *ParentFrame; + VMFunction *Func; + VM_UBYTE NumRegD; + VM_UBYTE NumRegF; + VM_UBYTE NumRegS; + VM_UBYTE NumRegA; + VM_UHALF MaxParam; + VM_UHALF NumParam; // current number of parameters + + static int FrameSize(int numregd, int numregf, int numregs, int numrega, int numparam, int numextra) + { + int size = (sizeof(VMFrame) + 15) & ~15; + size += numparam * sizeof(VMValue); + size += numregf * sizeof(double); + size += numrega * (sizeof(void *) + sizeof(VM_UBYTE)); + size += numregs * sizeof(FString); + size += numregd * sizeof(int); + if (numextra != 0) + { + size = (size + 15) & ~15; + size += numextra; + } + return size; + } + + int *GetRegD() const + { + return (int *)(GetRegA() + NumRegA); + } + + double *GetRegF() const + { + return (double *)(GetParam() + MaxParam); + } + + FString *GetRegS() const + { + return (FString *)(GetRegF() + NumRegF); + } + + void **GetRegA() const + { + return (void **)(GetRegS() + NumRegS); + } + + VM_ATAG *GetRegATag() const + { + return (VM_ATAG *)(GetRegD() + NumRegD); + } + + VMValue *GetParam() const + { + assert(((size_t)this & 15) == 0 && "VM frame is unaligned"); + return (VMValue *)(((size_t)(this + 1) + 15) & ~15); + } + + void *GetExtra() const + { + VM_ATAG *ptag = GetRegATag(); + ptrdiff_t ofs = ptag - (VM_ATAG *)this; + return (VM_UBYTE *)this + ((ofs + NumRegA + 15) & ~15); + } + + void GetAllRegs(int *&d, double *&f, FString *&s, void **&a, VM_ATAG *&atag, VMValue *¶m) const + { + // Calling the individual functions produces suboptimal code. :( + param = GetParam(); + f = (double *)(param + MaxParam); + s = (FString *)(f + NumRegF); + a = (void **)(s + NumRegS); + d = (int *)(a + NumRegA); + atag = (VM_ATAG *)(d + NumRegD); + } + + void InitRegS(); +}; + +struct VMRegisters +{ + VMRegisters(const VMFrame *frame) + { + frame->GetAllRegs(d, f, s, a, atag, param); + } + + VMRegisters(const VMRegisters &o) + : d(o.d), f(o.f), s(o.s), a(o.a), atag(o.atag), param(o.param) + { } + + int *d; + double *f; + FString *s; + void **a; + VM_ATAG *atag; + VMValue *param; +}; + +struct VMException : public DObject +{ + DECLARE_CLASS(VMException, DObject); +}; + +union FVoidObj +{ + DObject *o; + void *v; +}; + +class VMScriptFunction : public VMFunction +{ + DECLARE_CLASS(VMScriptFunction, VMFunction); +public: + VMScriptFunction(FName name=NAME_None); + ~VMScriptFunction(); + size_t PropagateMark(); + void Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta); + + VM_ATAG *KonstATags() { return (VM_UBYTE *)(KonstA + NumKonstA); } + const VM_ATAG *KonstATags() const { return (VM_UBYTE *)(KonstA + NumKonstA); } + + VMOP *Code; + int *KonstD; + double *KonstF; + FString *KonstS; + FVoidObj *KonstA; + int ExtraSpace; + int CodeSize; // Size of code in instructions (not bytes) + VM_UBYTE NumRegD; + VM_UBYTE NumRegF; + VM_UBYTE NumRegS; + VM_UBYTE NumRegA; + VM_UBYTE NumKonstD; + VM_UBYTE NumKonstF; + VM_UBYTE NumKonstS; + VM_UBYTE NumKonstA; + VM_UHALF MaxParam; // Maximum number of parameters this function has on the stack at once + VM_UBYTE NumArgs; // Number of arguments this function takes +}; + +class VMFrameStack +{ +public: + VMFrameStack(); + ~VMFrameStack(); + VMFrame *AllocFrame(int numregd, int numregf, int numregs, int numrega); + VMFrame *AllocFrame(VMScriptFunction *func); + VMFrame *PopFrame(); + VMFrame *TopFrame() + { + assert(Blocks != NULL && Blocks->LastFrame != NULL); + return Blocks->LastFrame; + } + int Call(VMFunction *func, VMValue *params, int numparams, VMReturn *results, int numresults, VMException **trap=NULL); +private: + enum { BLOCK_SIZE = 4096 }; // Default block size + struct BlockHeader + { + BlockHeader *NextBlock; + VMFrame *LastFrame; + VM_UBYTE *FreeSpace; + int BlockSize; + + void InitFreeSpace() + { + FreeSpace = (VM_UBYTE *)(((size_t)(this + 1) + 15) & ~15); + } + }; + BlockHeader *Blocks; + BlockHeader *UnusedBlocks; + VMFrame *Alloc(int size); +}; + +class VMNativeFunction : public VMFunction +{ + DECLARE_CLASS(VMNativeFunction, VMFunction); +public: + typedef int (*NativeCallType)(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret); + + VMNativeFunction() : NativeCall(NULL) { Native = true; } + VMNativeFunction(NativeCallType call) : NativeCall(call) { Native = true; } + VMNativeFunction(NativeCallType call, FName name) : VMFunction(name), NativeCall(call) { Native = true; } + + // Return value is the number of results. + NativeCallType NativeCall; +}; + +class VMParamFiller +{ +public: + VMParamFiller(const VMFrame *frame) : Reg(frame), RegD(0), RegF(0), RegS(0), RegA(0) {} + VMParamFiller(const VMRegisters *reg) : Reg(*reg), RegD(0), RegF(0), RegS(0), RegA(0) {} + + void ParamInt(int val) + { + Reg.d[RegD++] = val; + } + + void ParamFloat(double val) + { + Reg.f[RegF++] = val; + } + + void ParamString(FString &val) + { + Reg.s[RegS++] = val; + } + + void ParamString(const char *val) + { + Reg.s[RegS++] = val; + } + + void ParamObject(DObject *obj) + { + Reg.a[RegA] = obj; + Reg.atag[RegA] = ATAG_OBJECT; + RegA++; + } + + void ParamPointer(void *ptr, VM_ATAG atag) + { + Reg.a[RegA] = ptr; + Reg.atag[RegA] = atag; + RegA++; + } + +private: + const VMRegisters Reg; + int RegD, RegF, RegS, RegA; +}; + + +enum EVMEngine +{ + VMEngine_Default, + VMEngine_Unchecked, + VMEngine_Checked +}; + +void VMSelectEngine(EVMEngine engine); +extern int (*VMExec)(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret); +void VMFillParams(VMValue *params, VMFrame *callee, int numparam); + +void VMDumpConstants(FILE *out, const VMScriptFunction *func); +void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction *func); + +// Use this in the prototype for a native function. +#define VM_ARGS VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret +#define VM_ARGS_NAMES stack, param, numparam, ret, numret + +// Use these to collect the parameters in a native function. +// variable name at position

+ +// For required parameters. +#define PARAM_INT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); int x = param[p].i; +#define PARAM_BOOL_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); bool x = !!param[p].i; +#define PARAM_NAME_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FName x = ENamedName(param[p].i); +#define PARAM_SOUND_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FSoundID x = param[p].i; +#define PARAM_COLOR_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); PalEntry x; x.d = param[p].i; +#define PARAM_FLOAT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_FLOAT); double x = param[p].f; +#define PARAM_FIXED_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_FLOAT); fixed_t x = FLOAT2FIXED(param[p].f); +#define PARAM_ANGLE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_FLOAT); angle_t x = angle_t(param[p].f * (ANGLE_90 / 90.0)); +#define PARAM_STRING_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_STRING); FString x = param[p].s(); +#define PARAM_STATE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATE || param[p].a == NULL)); FState *x = (FState *)param[p].a; +#define PARAM_POINTER_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)param[p].a; +#define PARAM_OBJECT_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); type *x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); +#define PARAM_CLASS_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); base::MetaClass *x = (base::MetaClass *)param[p].a; assert(x != NULL && x->IsDescendantOf(RUNTIME_CLASS(base))); + +// For optional paramaters. These have dangling elses for you to fill in the default assignment. e.g.: +// PARAM_INT_OPT(0,myint) { myint = 55; } +// Just make sure to fill it in when using these macros, because the compiler isn't likely +// to give useful error messages if you don't. +#define PARAM_INT_OPT_AT(p,x) int x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_INT); x = param[p].i; } else +#define PARAM_BOOL_OPT_AT(p,x) bool x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_INT); x = !!param[p].i; } else +#define PARAM_NAME_OPT_AT(p,x) FName x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_INT); x = ENamedName(param[p].i); } else +#define PARAM_SOUND_OPT_AT(p,x) FSoundID x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_INT); x = FSoundID(param[p].i); } else +#define PARAM_COLOR_OPT_AT(p,x) PalEntry x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_INT); x.d = param[p].i; } else +#define PARAM_FLOAT_OPT_AT(p,x) double x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_FLOAT); x = param[p].f; } else +#define PARAM_FIXED_OPT_AT(p,x) fixed_t x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_FLOAT); x = FLOAT2FIXED(param[p].f); } else +#define PARAM_ANGLE_OPT_AT(p,x) angle_t x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_FLOAT); x = angle_t(param[p].f * (ANGLE_90 / 90.0)); } else +#define PARAM_STRING_OPT_AT(p,x) FString x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_STRING); x = param[p].s(); } else +#define PARAM_STATE_OPT_AT(p,x) FState *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATE || param[p].a == NULL)); x = (FState *)param[p].a; } else +#define PARAM_POINTER_OPT_AT(p,x,type) type *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER); x = (type *)param[p].a; } else +#define PARAM_OBJECT_OPT_AT(p,x,type) type *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); } else +#define PARAM_CLASS_OPT_AT(p,x,base) base::MetaClass *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); x = (base::MetaClass *)param[p].a; assert(x != NULL && x->IsDescendantOf(RUNTIME_CLASS(base))); } else + +// The above, but with an automatically increasing position index. +#define PARAM_PROLOGUE int paramnum = -1; + +#define PARAM_INT(x) ++paramnum; PARAM_INT_AT(paramnum,x) +#define PARAM_BOOL(x) ++paramnum; PARAM_BOOL_AT(paramnum,x) +#define PARAM_NAME(x) ++paramnum; PARAM_NAME_AT(paramnum,x) +#define PARAM_SOUND(x) ++paramnum; PARAM_SOUND_AT(paramnum,x) +#define PARAM_COLOR(x) ++paramnum; PARAM_COLOR_AT(paramnum,x) +#define PARAM_FLOAT(x) ++paramnum; PARAM_FLOAT_AT(paramnum,x) +#define PARAM_FIXED(x) ++paramnum; PARAM_FIXED_AT(paramnum,x) +#define PARAM_ANGLE(x) ++paramnum; PARAM_ANGLE_AT(paramnum,x) +#define PARAM_STRING(x) ++paramnum; PARAM_STRING_AT(paramnum,x) +#define PARAM_STATE(x) ++paramnum; PARAM_STATE_AT(paramnum,x) +#define PARAM_POINTER(x,type) ++paramnum; PARAM_POINTER_AT(paramnum,x,type) +#define PARAM_OBJECT(x,type) ++paramnum; PARAM_OBJECT_AT(paramnum,x,type) +#define PARAM_CLASS(x,base) ++paramnum; PARAM_CLASS_AT(paramnum,x,base) + +#define PARAM_INT_OPT(x) ++paramnum; PARAM_INT_OPT_AT(paramnum,x) +#define PARAM_BOOL_OPT(x) ++paramnum; PARAM_BOOL_OPT_AT(paramnum,x) +#define PARAM_NAME_OPT(x) ++paramnum; PARAM_NAME_OPT_AT(paramnum,x) +#define PARAM_SOUND_OPT(x) ++paramnum; PARAM_SOUND_OPT_AT(paramnum,x) +#define PARAM_COLOR_OPT(x) ++paramnum; PARAM_COLOR_OPT_AT(paramnum,x) +#define PARAM_FLOAT_OPT(x) ++paramnum; PARAM_FLOAT_OPT_AT(paramnum,x) +#define PARAM_FIXED_OPT(x) ++paramnum; PARAM_FIXED_OPT_AT(paramnum,x) +#define PARAM_ANGLE_OPT(x) ++paramnum; PARAM_ANGLE_OPT_AT(paramnum,x) +#define PARAM_STRING_OPT(x) ++paramnum; PARAM_STRING_OPT_AT(paramnum,x) +#define PARAM_STATE_OPT(x) ++paramnum; PARAM_STATE_OPT_AT(paramnum,x) +#define PARAM_POINTER_OPT(x,type) ++paramnum; PARAM_POINTER_OPT_AT(paramnum,x,type) +#define PARAM_OBJECT_OPT(x,type) ++paramnum; PARAM_OBJECT_OPT_AT(paramnum,x,type) +#define PARAM_CLASS_OPT(x,base) ++paramnum; PARAM_CLASS_OPT_AT(paramnum,x,base) + +#endif diff --git a/src/zscript/vmbuilder.cpp b/src/zscript/vmbuilder.cpp new file mode 100644 index 0000000000..d17efc1d98 --- /dev/null +++ b/src/zscript/vmbuilder.cpp @@ -0,0 +1,591 @@ +#include "vmbuilder.h" + +//========================================================================== +// +// VMFunctionBuilder - Constructor +// +//========================================================================== + +VMFunctionBuilder::VMFunctionBuilder() +{ + NumIntConstants = 0; + NumFloatConstants = 0; + NumAddressConstants = 0; + NumStringConstants = 0; + MaxParam = 0; + ActiveParam = 0; +} + +//========================================================================== +// +// VMFunctionBuilder - Destructor +// +//========================================================================== + +VMFunctionBuilder::~VMFunctionBuilder() +{ +} + +//========================================================================== +// +// VMFunctionBuilder :: MakeFunction +// +// Creates a new VMScriptFunction out of the data passed to this class. +// +//========================================================================== + +VMScriptFunction *VMFunctionBuilder::MakeFunction() +{ + VMScriptFunction *func = new VMScriptFunction; + + func->Alloc(Code.Size(), NumIntConstants, NumFloatConstants, NumStringConstants, NumAddressConstants); + + // Copy code block. + memcpy(func->Code, &Code[0], Code.Size() * sizeof(VMOP)); + + // Create constant tables. + if (NumIntConstants > 0) + { + FillIntConstants(func->KonstD); + } + if (NumFloatConstants > 0) + { + FillFloatConstants(func->KonstF); + } + if (NumAddressConstants > 0) + { + FillAddressConstants(func->KonstA, func->KonstATags()); + } + if (NumStringConstants > 0) + { + FillStringConstants(func->KonstS); + } + + // Assign required register space. + func->NumRegD = Registers[REGT_INT].MostUsed; + func->NumRegF = Registers[REGT_FLOAT].MostUsed; + func->NumRegA = Registers[REGT_POINTER].MostUsed; + func->NumRegS = Registers[REGT_STRING].MostUsed; + func->MaxParam = MaxParam; + + // Technically, there's no reason why we can't end the function with + // entries on the parameter stack, but it means the caller probably + // did something wrong. + assert(ActiveParam == 0); + + return func; +} + +//========================================================================== +// +// VMFunctionBuilder :: FillIntConstants +// +//========================================================================== + +void VMFunctionBuilder::FillIntConstants(int *konst) +{ + TMapIterator it(IntConstants); + TMap::Pair *pair; + + while (it.NextPair(pair)) + { + konst[pair->Value] = pair->Key; + } +} + +//========================================================================== +// +// VMFunctionBuilder :: FillFloatConstants +// +//========================================================================== + +void VMFunctionBuilder::FillFloatConstants(double *konst) +{ + TMapIterator it(FloatConstants); + TMap::Pair *pair; + + while (it.NextPair(pair)) + { + konst[pair->Value] = pair->Key; + } +} + +//========================================================================== +// +// VMFunctionBuilder :: FillAddressConstants +// +//========================================================================== + +void VMFunctionBuilder::FillAddressConstants(FVoidObj *konst, VM_ATAG *tags) +{ + TMapIterator it(AddressConstants); + TMap::Pair *pair; + + while (it.NextPair(pair)) + { + konst[pair->Value.KonstNum].v = pair->Key; + tags[pair->Value.KonstNum] = pair->Value.Tag; + } +} + +//========================================================================== +// +// VMFunctionBuilder :: FillStringConstants +// +//========================================================================== + +void VMFunctionBuilder::FillStringConstants(FString *konst) +{ + TMapIterator it(StringConstants); + TMap::Pair *pair; + + while (it.NextPair(pair)) + { + konst[pair->Value] = pair->Key; + } +} + +//========================================================================== +// +// VMFunctionBuilder :: GetConstantInt +// +// Returns a constant register initialized with the given value, or -1 if +// there were no more constants free. +// +//========================================================================== + +int VMFunctionBuilder::GetConstantInt(int val) +{ + int *locp = IntConstants.CheckKey(val); + if (locp != NULL) + { + return *locp; + } + else + { + int loc = NumIntConstants++; + IntConstants.Insert(val, loc); + return loc; + } +} + +//========================================================================== +// +// VMFunctionBuilder :: GetConstantFloat +// +// Returns a constant register initialized with the given value, or -1 if +// there were no more constants free. +// +//========================================================================== + +int VMFunctionBuilder::GetConstantFloat(double val) +{ + int *locp = FloatConstants.CheckKey(val); + if (locp != NULL) + { + return *locp; + } + else + { + int loc = NumFloatConstants++; + FloatConstants.Insert(val, loc); + return loc; + } +} + +//========================================================================== +// +// VMFunctionBuilder :: GetConstantString +// +// Returns a constant register initialized with the given value, or -1 if +// there were no more constants free. +// +//========================================================================== + +int VMFunctionBuilder::GetConstantString(FString val) +{ + int *locp = StringConstants.CheckKey(val); + if (locp != NULL) + { + return *locp; + } + else + { + int loc = NumStringConstants++; + StringConstants.Insert(val, loc); + return loc; + } +} + +//========================================================================== +// +// VMFunctionBuilder :: GetConstantAddress +// +// Returns a constant register initialized with the given value, or -1 if +// there were no more constants free. +// +//========================================================================== + +int VMFunctionBuilder::GetConstantAddress(void *ptr, VM_ATAG tag) +{ + if (ptr == NULL) + { // Make all NULL pointers generic. (Or should we allow typed NULLs?) + tag = ATAG_GENERIC; + } + AddrKonst *locp = AddressConstants.CheckKey(ptr); + if (locp != NULL) + { + // There should only be one tag associated with a memory location. + assert(locp->Tag == tag); + return locp->KonstNum; + } + else + { + AddrKonst loc = { NumAddressConstants++, tag }; + AddressConstants.Insert(ptr, loc); + return loc.KonstNum; + } +} + +//========================================================================== +// +// VMFunctionBuilder :: ParamChange +// +// Adds delta to ActiveParam and keeps track of MaxParam. +// +//========================================================================== + +void VMFunctionBuilder::ParamChange(int delta) +{ + assert(delta > 0 || -delta <= ActiveParam); + ActiveParam += delta; + if (ActiveParam > MaxParam) + { + MaxParam = ActiveParam; + } +} + +//========================================================================== +// +// VMFunctionBuilder :: RegAvailability - Constructor +// +//========================================================================== + +VMFunctionBuilder::RegAvailability::RegAvailability() +{ + memset(Used, 0, sizeof(Used)); + MostUsed = 0; +} + +//========================================================================== +// +// VMFunctionBuilder :: RegAvailability :: Get +// +// Gets one or more unused registers. If getting multiple registers, they +// will all be consecutive. Returns -1 if there were not enough consecutive +// registers to satisfy the request. +// +// Preference is given to low-numbered registers in an attempt to keep +// the maximum register count low so as to preserve VM stack space when this +// function is executed. +// +//========================================================================== + +int VMFunctionBuilder::RegAvailability::Get(int count) +{ + VM_UWORD mask; + int i, firstbit; + + // Getting fewer than one register makes no sense, and + // the algorithm used here can only obtain ranges of up to 32 bits. + if (count < 1 || count > 32) + { + return -1; + } + + mask = count == 32 ? ~0u : (1 << count) - 1; + + for (i = 0; i < 256/32; ++i) + { + // Find the first word with free registers + VM_UWORD bits = Used[i]; + if (bits != ~0u) + { + // Are there enough consecutive bits to satisfy the request? + // Search by 16, then 8, then 1 bit at a time for the first + // free register. + if ((bits & 0xFFFF) == 0xFFFF) + { + firstbit = ((bits & 0xFF0000) == 0xFF0000) ? 24 : 16; + } + else + { + firstbit = ((bits & 0xFF) == 0xFF) ? 8 : 0; + } + for (; firstbit < 32; ++firstbit) + { + if (((bits >> firstbit) & mask) == 0) + { + if (firstbit + count <= 32) + { // Needed bits all fit in one word, so we got it. + if (firstbit + count > MostUsed) + { + MostUsed = firstbit + count; + } + Used[i] |= mask << firstbit; + return i * 32 + firstbit; + } + // Needed bits span two words, so check the next word. + else if (i < 256/32 - 1) + { // There is a next word. + if (((Used[i + 1]) & (mask >> (32 - firstbit))) == 0) + { // The next word has the needed open space, too. + if (firstbit + count > MostUsed) + { + MostUsed = firstbit + count; + } + Used[i] |= mask << firstbit; + Used[i + 1] |= mask >> (32 - firstbit); + return i * 32 + firstbit; + } + else + { // Skip to the next word, because we know we won't find + // what we need if we stay inside this one. All bits + // from firstbit to the end of the word are 0. If the + // next word does not start with the x amount of 0's, we + // need to satisfy the request, then it certainly won't + // have the x+1 0's we would need if we started at + // firstbit+1 in this one. + firstbit = 32; + } + } + else + { // Out of words. + break; + } + } + } + } + } + // No room! + return -1; +} + +//========================================================================== +// +// VMFunctionBuilder :: RegAvailibity :: Return +// +// Marks a range of registers as free again. +// +//========================================================================== + +void VMFunctionBuilder::RegAvailability::Return(int reg, int count) +{ + assert(count >= 1 && count <= 32); + assert(reg >= 0 && reg + count <= 256); + + VM_UWORD mask, partialmask; + int firstword, firstbit; + + mask = count == 32 ? ~0u : (1 << count) - 1; + firstword = reg / 32; + firstbit = reg & 31; + + if (firstbit + count <= 32) + { // Range is all in one word. + mask <<= firstbit; + // If we are trying to return registers that are already free, + // it probably means that the caller messed up somewhere. + assert((Used[firstword] & mask) == mask); + Used[firstword] &= ~mask; + } + else + { // Range is in two words. + partialmask = mask << firstbit; + assert((Used[firstword] & partialmask) == partialmask); + Used[firstword] &= ~partialmask; + + partialmask = mask >> (32 - firstbit); + assert((Used[firstword + 1] & partialmask) == partialmask); + Used[firstword + 1] &= ~partialmask; + } +} + +//========================================================================== +// +// VMFunctionBuilder :: RegAvailability :: Reuse +// +// Marks an unused register as in-use. Returns false if the register is +// already in use or true if it was successfully reused. +// +//========================================================================== + +bool VMFunctionBuilder::RegAvailability::Reuse(int reg) +{ + assert(reg >= 0 && reg <= 255); + assert(reg < MostUsed && "Attempt to reuse a register that was never used"); + + VM_UWORD mask = 1 << (reg & 31); + int word = reg / 32; + + if (Used[word] & mask) + { // It's already in use! + return false; + } + Used[word] |= mask; + return true; +} + +//========================================================================== +// +// VMFunctionBuilder :: Emit +// +// Just dumbly output an instruction. Returns instruction position, not +// byte position. (Because all instructions are exactly four bytes long.) +// +//========================================================================== + +size_t VMFunctionBuilder::Emit(int opcode, int opa, int opb, int opc) +{ + assert(opcode >= 0 && opcode < NUM_OPS); + assert(opa >= 0 && opa <= 255); + assert(opb >= 0 && opb <= 255); + assert(opc >= 0 && opc <= 255); + if (opcode == OP_PARAM) + { + ParamChange(1); + } + else if (opcode == OP_CALL || opcode == OP_CALL_K || opcode == OP_TAIL || opcode == OP_TAIL_K) + { + ParamChange(-opb); + } + VMOP op; + op.op = opcode; + op.a = opa; + op.b = opb; + op.c = opc; + return Code.Push(op); +} + +size_t VMFunctionBuilder::Emit(int opcode, int opa, VM_SHALF opbc) +{ + assert(opcode >= 0 && opcode < NUM_OPS); + assert(opa >= 0 && opa <= 255); + //assert(opbc >= -32768 && opbc <= 32767); always true due to parameter's width + VMOP op; + op.op = opcode; + op.a = opa; + op.i16 = opbc; + return Code.Push(op); +} + +size_t VMFunctionBuilder::Emit(int opcode, int opabc) +{ + assert(opcode >= 0 && opcode < NUM_OPS); + assert(opabc >= -(1 << 23) && opabc <= (1 << 24) - 1); + if (opcode == OP_PARAMI) + { + ParamChange(1); + } + VMOP op; + op.op = opcode; + op.i24 = opabc; + return Code.Push(op); +} + +//========================================================================== +// +// VMFunctionBuilder :: EmitParamInt +// +// Passes a constant integer parameter, using either PARAMI and an immediate +// value or PARAM and a constant register, as appropriate. +// +//========================================================================== + +size_t VMFunctionBuilder::EmitParamInt(int value) +{ + // Immediates for PARAMI must fit in 24 bits. + if (((value << 8) >> 8) == value) + { + return Emit(OP_PARAMI, value); + } + else + { + return Emit(OP_PARAM, 0, REGT_INT | REGT_KONST, GetConstantInt(value)); + } +} + +//========================================================================== +// +// VMFunctionBuilder :: EmitLoadInt +// +// Loads an integer constant into a register, using either an immediate +// value or a constant register, as appropriate. +// +//========================================================================== + +size_t VMFunctionBuilder::EmitLoadInt(int regnum, int value) +{ + assert(regnum >= 0 && regnum < Registers[REGT_INT].MostUsed); + if (value >= -32768 && value <= 32767) + { + return Emit(OP_LI, regnum, value); + } + else + { + return Emit(OP_LK, regnum, GetConstantInt(value)); + } +} + +//========================================================================== +// +// VMFunctionBuilder :: EmitRetInt +// +// Returns an integer, using either an immediate value or a constant +// register, as appropriate. +// +//========================================================================== + +size_t VMFunctionBuilder::EmitRetInt(int retnum, bool final, int value) +{ + assert(retnum >= 0 && retnum <= 127); + if (value >= -32768 && value <= 32767) + { + return Emit(OP_RETI, retnum | (final << 7), value); + } + else + { + return Emit(OP_RET, retnum | (final << 7), REGT_INT | REGT_KONST, GetConstantInt(value)); + } +} + +//========================================================================== +// +// VMFunctionBuilder :: Backpatch +// +// Store a JMP instruction at that points at . +// +//========================================================================== + +void VMFunctionBuilder::Backpatch(size_t loc, size_t target) +{ + assert(loc < Code.Size()); + int offset = int(target - loc - 1); + assert(((offset << 8) >> 8) == offset); + Code[loc].op = OP_JMP; + Code[loc].i24 = offset; +} + +//========================================================================== +// +// VMFunctionBuilder :: BackpatchToHere +// +// Store a JMP instruction at that points to the current code gen +// location. +// +//========================================================================== + +void VMFunctionBuilder::BackpatchToHere(size_t loc) +{ + Backpatch(loc, Code.Size()); +} diff --git a/src/zscript/vmbuilder.h b/src/zscript/vmbuilder.h new file mode 100644 index 0000000000..ee15e49cf6 --- /dev/null +++ b/src/zscript/vmbuilder.h @@ -0,0 +1,84 @@ +#ifndef VMUTIL_H +#define VMUTIL_H + +#include "vm.h" + +class VMFunctionBuilder +{ +public: + // Keeps track of which registers are available by way of a bitmask table. + class RegAvailability + { + public: + RegAvailability(); + int GetMostUsed() { return MostUsed; } + int Get(int count); // Returns the first register in the range + void Return(int reg, int count); + bool Reuse(int regnum); + + private: + VM_UWORD Used[256/32]; // Bitmap of used registers (bit set means reg is used) + int MostUsed; + + friend class VMFunctionBuilder; + }; + + VMFunctionBuilder(); + ~VMFunctionBuilder(); + + VMScriptFunction *MakeFunction(); + + // Returns the constant register holding the value. + int GetConstantInt(int val); + int GetConstantFloat(double val); + int GetConstantAddress(void *ptr, VM_ATAG tag); + int GetConstantString(FString str); + + // Returns the address of the newly-emitted instruction. + size_t Emit(int opcode, int opa, int opb, int opc); + size_t Emit(int opcode, int opa, VM_SHALF opbc); + size_t Emit(int opcode, int opabc); + size_t EmitParamInt(int value); + size_t EmitLoadInt(int regnum, int value); + size_t EmitRetInt(int retnum, bool final, int value); + + void Backpatch(size_t addr, size_t target); + void BackpatchToHere(size_t addr); + + // Write out complete constant tables. + void FillIntConstants(int *konst); + void FillFloatConstants(double *konst); + void FillAddressConstants(FVoidObj *konst, VM_ATAG *tags); + void FillStringConstants(FString *strings); + + // PARAM increases ActiveParam; CALL decreases it. + void ParamChange(int delta); + + // Track available registers. + RegAvailability Registers[4]; + +private: + struct AddrKonst + { + int KonstNum; + VM_ATAG Tag; + }; + // These map from the constant value to its position in the constant table. + TMap IntConstants; + TMap FloatConstants; + TMap AddressConstants; + TMap StringConstants; + + int NumIntConstants; + int NumFloatConstants; + int NumAddressConstants; + int NumStringConstants; + + int MaxParam; + int ActiveParam; + + TArray Code; + +}; + +#endif diff --git a/src/zscript/vmdisasm.cpp b/src/zscript/vmdisasm.cpp new file mode 100644 index 0000000000..2509b60a99 --- /dev/null +++ b/src/zscript/vmdisasm.cpp @@ -0,0 +1,556 @@ +#include "vm.h" +#include "c_console.h" + +#define NOP MODE_AUNUSED | MODE_BUNUSED | MODE_CUNUSED + +#define LI MODE_AI | MODE_BCJOINT | MODE_BCIMMS +#define LKI MODE_AI | MODE_BCJOINT | MODE_BCKI +#define LKF MODE_AF | MODE_BCJOINT | MODE_BCKF +#define LKS MODE_AS | MODE_BCJOINT | MODE_BCKS +#define LKP MODE_AP | MODE_BCJOINT | MODE_BCKP +#define LFP MODE_AP | MODE_BUNUSED | MODE_CUNUSED + +#define RIRPKI MODE_AI | MODE_BP | MODE_CKI +#define RIRPRI MODE_AI | MODE_BP | MODE_CI +#define RFRPKI MODE_AF | MODE_BP | MODE_CKI +#define RFRPRI MODE_AF | MODE_BP | MODE_CI +#define RSRPKI MODE_AS | MODE_BP | MODE_CKI +#define RSRPRI MODE_AS | MODE_BP | MODE_CI +#define RPRPKI MODE_AP | MODE_BP | MODE_CKI +#define RPRPRI MODE_AP | MODE_BP | MODE_CI +#define RVRPKI MODE_AV | MODE_BP | MODE_CKI +#define RVRPRI MODE_AV | MODE_BP | MODE_CI +#define RIRPI8 MODE_AI | MODE_BP | MODE_CIMMZ + +#define RPRIKI MODE_AP | MODE_BI | MODE_CKI +#define RPRIRI MODE_AP | MODE_BI | MODE_CI +#define RPRFKI MODE_AP | MODE_BF | MODE_CKI +#define RPRFRI MODE_AP | MODE_BF | MODE_CI +#define RPRSKI MODE_AP | MODE_BS | MODE_CKI +#define RPRSRI MODE_AP | MODE_BS | MODE_CI +#define RPRPKI MODE_AP | MODE_BP | MODE_CKI +#define RPRPRI MODE_AP | MODE_BP | MODE_CI +#define RPRVKI MODE_AP | MODE_BV | MODE_CKI +#define RPRVRI MODE_AP | MODE_BV | MODE_CI +#define RPRII8 MODE_AP | MODE_BI | MODE_CIMMZ + +#define RIRI MODE_AI | MODE_BI | MODE_CUNUSED +#define RFRF MODE_AF | MODE_BF | MODE_CUNUSED +#define RSRS MODE_AS | MODE_BS | MODE_CUNUSED +#define RPRP MODE_AP | MODE_BP | MODE_CUNUSED +#define RXRXI8 MODE_AX | MODE_BX | MODE_CIMMZ +#define RPRPRP MODE_AP | MODE_BP | MODE_CP +#define RPRPKP MODE_AP | MODE_BP | MODE_CKP + +#define RII16 MODE_AI | MODE_BCJOINT | MODE_BCIMMS +#define I24 MODE_ABCJOINT +#define I8 MODE_AIMMZ | MODE_BUNUSED | MODE_CUNUSED +#define I8I16 MODE_AIMMZ | MODE_BCIMMZ +#define __BCP MODE_AUNUSED | MODE_BCJOINT | MODE_BCPARAM +#define RPI8 MODE_AP | MODE_BIMMZ | MODE_CUNUSED +#define KPI8 MODE_AKP | MODE_BIMMZ | MODE_CUNUSED +#define RPI8I8 MODE_AP | MODE_BIMMZ | MODE_CIMMZ +#define KPI8I8 MODE_AKP | MODE_BIMMZ | MODE_CIMMZ +#define I8BCP MODE_AIMMZ | MODE_BCJOINT | MODE_BCPARAM +#define THROW MODE_AIMMZ | MODE_BCTHROW +#define CATCH MODE_AIMMZ | MODE_BCCATCH +#define CAST MODE_AX | MODE_BX | MODE_CIMMZ | MODE_BCCAST + +#define RSRSRS MODE_AS | MODE_BS | MODE_CS +#define RIRS MODE_AI | MODE_BS | MODE_CUNUSED +#define I8RXRX MODE_AIMMZ | MODE_BX | MODE_CX + +#define RIRIRI MODE_AI | MODE_BI | MODE_CI +#define RIRII8 MODE_AI | MODE_BI | MODE_CIMMZ +#define RIRIKI MODE_AI | MODE_BI | MODE_CKI +#define RIKIRI MODE_AI | MODE_BKI | MODE_CI +#define RIKII8 MODE_AI | MODE_BKI | MODE_CIMMZ +#define RIRIIs MODE_AI | MODE_BI | MODE_CIMMS +#define RIRI MODE_AI | MODE_BI | MODE_CUNUSED +#define I8RIRI MODE_AIMMZ | MODE_BI | MODE_CI +#define I8RIKI MODE_AIMMZ | MODE_BI | MODE_CKI +#define I8KIRI MODE_AIMMZ | MODE_BKI | MODE_CI + +#define RFRFRF MODE_AF | MODE_BF | MODE_CF +#define RFRFKF MODE_AF | MODE_BF | MODE_CKF +#define RFKFRF MODE_AF | MODE_BKF | MODE_CF +#define I8RFRF MODE_AIMMZ | MODE_BF | MODE_CF +#define I8RFKF MODE_AIMMZ | MODE_BF | MODE_CKF +#define I8KFRF MODE_AIMMZ | MODE_BKF | MODE_CF +#define RFRFI8 MODE_AF | MODE_BF | MODE_CIMMZ + +#define RVRV MODE_AV | MODE_BV | MODE_CUNUSED +#define RVRVRV MODE_AV | MODE_BV | MODE_CV +#define RVRVKV MODE_AV | MODE_BV | MODE_CKV +#define RVKVRV MODE_AV | MODE_BKV | MODE_CV +#define RFRV MODE_AF | MODE_BV | MODE_CUNUSED +#define I8RVRV MODE_AIMMZ | MODE_BV | MODE_CV +#define I8RVKV MODE_AIMMZ | MODE_BV | MODE_CKV + +#define RPRPRI MODE_AP | MODE_BP | MODE_CI +#define RPRPKI MODE_AP | MODE_BP | MODE_CKI +#define RIRPRP MODE_AI | MODE_BP | MODE_CP +#define I8RPRP MODE_AIMMZ | MODE_BP | MODE_CP +#define I8RPKP MODE_AIMMZ | MODE_BP | MODE_CKP + +#define CIRR MODE_ACMP | MODE_BI | MODE_CI +#define CIRK MODE_ACMP | MODE_BI | MODE_CKI +#define CIKR MODE_ACMP | MODE_BKI | MODE_CI +#define CFRR MODE_ACMP | MODE_BF | MODE_CF +#define CFRK MODE_ACMP | MODE_BF | MODE_CKF +#define CFKR MODE_ACMP | MODE_BKF | MODE_CF +#define CVRR MODE_ACMP | MODE_BV | MODE_CV +#define CVRK MODE_ACMP | MODE_BV | MODE_CKV +#define CPRR MODE_ACMP | MODE_BP | MODE_CP +#define CPRK MODE_ACMP | MODE_BP | MODE_CKP + +const VMOpInfo OpInfo[NUM_OPS] = +{ +#define xx(op, name, mode) { #name, mode } +#include "vmops.h" +}; + +static const char *const FlopNames[] = +{ + "abs", + "neg", + "exp", + "log", + "log10", + "sqrt", + "ceil", + "floor", + + "acos rad", + "asin rad", + "atan rad", + "cos rad", + "sin rad", + "tan rad", + + "acos deg", + "asin deg", + "atan deg", + "cos deg", + "sin deg", + "tan deg", + + "cosh", + "sinh", + "tanh", +}; + +static int print_reg(FILE *out, int col, int arg, int mode, int immshift, const VMScriptFunction *func); + +static int printf_wrapper(FILE *f, const char *fmt, ...) +{ + va_list argptr; + int count; + + va_start(argptr, fmt); + if (f == NULL) + { + count = VPrintf(PRINT_HIGH, fmt, argptr); + } + else + { + count = vfprintf(f, fmt, argptr); + } + va_end(argptr); + return count; +} + +void VMDumpConstants(FILE *out, const VMScriptFunction *func) +{ + char tmp[21]; + int i, j, k, kk; + + if (func->KonstD != NULL && func->NumKonstD != 0) + { + printf_wrapper(out, "\nConstant integers:\n"); + kk = (func->NumKonstD + 3) / 4; + for (i = 0; i < kk; ++i) + { + for (j = 0, k = i; j < 4 && k < func->NumKonstD; j++, k += kk) + { + mysnprintf(tmp, countof(tmp), "%3d. %d", k, func->KonstD[k]); + printf_wrapper(out, "%-20s", tmp); + } + printf_wrapper(out, "\n"); + } + } + if (func->KonstF != NULL && func->NumKonstF != 0) + { + printf_wrapper(out, "\nConstant floats:\n"); + kk = (func->NumKonstF + 3) / 4; + for (i = 0; i < kk; ++i) + { + for (j = 0, k = i; j < 4 && k < func->NumKonstF; j++, k += kk) + { + mysnprintf(tmp, countof(tmp), "%3d. %.16f", k, func->KonstF[k]); + printf_wrapper(out, "%-20s", tmp); + } + printf_wrapper(out, "\n"); + } + } + if (func->KonstA != NULL && func->NumKonstA != 0) + { + printf_wrapper(out, "\nConstant addresses:\n"); + kk = (func->NumKonstA + 3) / 4; + for (i = 0; i < kk; ++i) + { + for (j = 0, k = i; j < 4 && k < func->NumKonstA; j++, k += kk) + { + mysnprintf(tmp, countof(tmp), "%3d. %p:%d", k, func->KonstA[k].v, func->KonstATags()[k]); + printf_wrapper(out, "%-20s", tmp); + } + printf_wrapper(out, "\n"); + } + } + if (func->KonstS != NULL && func->NumKonstS != 0) + { + printf_wrapper(out, "\nConstant strings:\n"); + for (i = 0; i < func->NumKonstS; ++i) + { + printf_wrapper(out, "%3d. %s\n", i, func->KonstS[i].GetChars()); + } + } +} + +void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction *func) +{ + VMFunction *callfunc; + const char *callname; + const char *name; + int col; + int mode; + int a; + bool cmp; + char cmpname[8]; + + for (int i = 0; i < codesize; ++i) + { + name = OpInfo[code[i].op].Name; + mode = OpInfo[code[i].op].Mode; + a = code[i].a; + cmp = (mode & MODE_ATYPE) == MODE_ACMP; + + // String comparison encodes everything in a single instruction. + if (code[i].op == OP_CMPS) + { + switch (a & CMP_METHOD_MASK) + { + case CMP_EQ: name = "beq"; break; + case CMP_LT: name = "blt"; break; + case CMP_LE: name = "ble"; break; + } + mode = MODE_AIMMZ; + mode |= (a & CMP_BK) ? MODE_BKS : MODE_BS; + mode |= (a & CMP_CK) ? MODE_CKS : MODE_CS; + a &= CMP_CHECK | CMP_APPROX; + cmp = true; + } + if (cmp) + { // Comparison instruction. Modify name for inverted test. + if (!(a & CMP_CHECK)) + { + strcpy(cmpname, name); + if (name[1] == 'e') + { // eq -> ne + cmpname[1] = 'n', cmpname[2] = 'e'; + } + else if (name[2] == 't') + { // lt -> ge + cmpname[1] = 'g', cmpname[2] = 'e'; + } + else + { // le -> gt + cmpname[1] = 'g', cmpname[2] = 't'; + } + name = cmpname; + } + } + printf_wrapper(out, "%08x: %02x%02x%02x%02x %-8s", i << 2, code[i].op, code[i].a, code[i].b, code[i].c, name); + col = 0; + switch (code[i].op) + { + case OP_JMP: + case OP_TRY: + col = printf_wrapper(out, "%08x", (i + 1 + code[i].i24) << 2); + break; + + case OP_PARAMI: + col = printf_wrapper(out, "%d", code[i].i24); + break; + + case OP_CALL_K: + case OP_TAIL_K: + callfunc = (VMFunction *)func->KonstA[code[i].a].o; + callname = callfunc->Name != NAME_None ? callfunc->Name : "[anonfunc]"; + col = printf_wrapper(out, "%.23s,%d", callname, code[i].b); + if (code[i].op == OP_CALL_K) + { + col += printf_wrapper(out, ",%d", code[i].c); + } + break; + + case OP_RET: + if (code[i].b != REGT_NIL) + { + if (a == RET_FINAL) + { + col = print_reg(out, 0, code[i].i16u, MODE_PARAM, 16, func); + } + else + { + col = print_reg(out, 0, a & ~RET_FINAL, (mode & MODE_ATYPE) >> MODE_ASHIFT, 24, func); + col += print_reg(out, col, code[i].i16u, MODE_PARAM, 16, func); + if (a & RET_FINAL) + { + col += printf_wrapper(out, " [final]"); + } + } + } + break; + + case OP_RETI: + if (a == RET_FINAL) + { + col = printf_wrapper(out, "%d", code[i].i16); + } + else + { + col = print_reg(out, 0, a & ~RET_FINAL, (mode & MODE_ATYPE) >> MODE_ASHIFT, 24, func); + col += print_reg(out, col, code[i].i16, MODE_IMMS, 16, func); + if (a & RET_FINAL) + { + col += printf_wrapper(out, " [final]"); + } + } + break; + + case OP_FLOP: + col = printf_wrapper(out, "f%d,f%d,%d", code[i].a, code[i].b, code[i].c); + if (code[i].c < countof(FlopNames)) + { + col += printf_wrapper(out, " [%s]", FlopNames[code[i].c]); + } + break; + + default: + if ((mode & MODE_BCTYPE) == MODE_BCCAST) + { + switch (code[i].c) + { + case CAST_I2F: + mode = MODE_AF | MODE_BI | MODE_CUNUSED; + break; + case CAST_I2S: + mode = MODE_AS | MODE_BI | MODE_CUNUSED; + break; + case CAST_F2I: + mode = MODE_AI | MODE_BF | MODE_CUNUSED; + break; + case CAST_F2S: + mode = MODE_AS | MODE_BF | MODE_CUNUSED; + break; + case CAST_P2S: + mode = MODE_AS | MODE_BP | MODE_CUNUSED; + break; + case CAST_S2I: + mode = MODE_AI | MODE_BS | MODE_CUNUSED; + break; + case CAST_S2F: + mode = MODE_AF | MODE_BS | MODE_CUNUSED; + break; + default: + mode = MODE_AX | MODE_BX | MODE_CIMMZ; + break; + } + } + col = print_reg(out, 0, a, (mode & MODE_ATYPE) >> MODE_ASHIFT, 24, func); + if ((mode & MODE_BCTYPE) == MODE_BCTHROW) + { + mode = (code[i].a == 0) ? (MODE_BP | MODE_CUNUSED) : (MODE_BKP | MODE_CUNUSED); + } + else if ((mode & MODE_BCTYPE) == MODE_BCCATCH) + { + switch (code[i].a) + { + case 0: + mode = MODE_BUNUSED | MODE_CUNUSED; + break; + case 1: + mode = MODE_BUNUSED | MODE_CP; + break; + case 2: + mode = MODE_BP | MODE_CP; + break; + case 3: + mode = MODE_BKP | MODE_CP; + break; + default: + mode = MODE_BIMMZ | MODE_CIMMZ; + break; + } + } + if ((mode & (MODE_BTYPE | MODE_CTYPE)) == MODE_BCJOINT) + { + col += print_reg(out, col, code[i].i16u, (mode & MODE_BCTYPE) >> MODE_BCSHIFT, 16, func); + } + else + { + col += print_reg(out, col, code[i].b, (mode & MODE_BTYPE) >> MODE_BSHIFT, 24, func); + col += print_reg(out, col, code[i].c, (mode & MODE_CTYPE) >> MODE_CSHIFT, 24, func); + } + break; + } + if (cmp && i + 1 < codesize) + { + if (code[i+1].op != OP_JMP) + { // comparison instructions must be followed by jump + col += printf_wrapper(out, " => *!*!*!*\n"); + } + else + { + col += printf_wrapper(out, " => %08x", (i + 2 + code[i+1].i24) << 2); + } + } + if (col > 30) + { + col = 30; + } + printf_wrapper(out, "%*c", 30 - col, ';'); + if (!cmp && (code[i].op == OP_JMP || code[i].op == OP_TRY || code[i].op == OP_PARAMI)) + { + printf_wrapper(out, "%d\n", code[i].i24); + } + else + { + printf_wrapper(out, "%d,%d,%d", code[i].a, code[i].b, code[i].c); + if (cmp && i + 1 < codesize && code[i+1].op == OP_JMP) + { + printf_wrapper(out, ",%d\n", code[++i].i24); + } + else if (code[i].op == OP_CALL_K || code[i].op == OP_TAIL_K) + { + printf_wrapper(out, " [%p]\n", callfunc); + } + else + { + printf_wrapper(out, "\n"); + } + } + } +} + +static int print_reg(FILE *out, int col, int arg, int mode, int immshift, const VMScriptFunction *func) +{ + if (mode == MODE_UNUSED || mode == MODE_CMP) + { + return 0; + } + if (col > 0) + { + col = printf_wrapper(out, ","); + } + switch(mode) + { + case MODE_I: + return col+printf_wrapper(out, "d%d", arg); + case MODE_F: + return col+printf_wrapper(out, "f%d", arg); + case MODE_S: + return col+printf_wrapper(out, "s%d", arg); + case MODE_P: + return col+printf_wrapper(out, "a%d", arg); + case MODE_V: + return col+printf_wrapper(out, "v%d", arg); + + case MODE_KI: + if (func != NULL) + { + return col+printf_wrapper(out, "%d", func->KonstD[arg]); + } + return printf_wrapper(out, "kd%d", arg); + case MODE_KF: + if (func != NULL) + { + return col+printf_wrapper(out, "%g", func->KonstF[arg]); + } + return col+printf_wrapper(out, "kf%d", arg); + case MODE_KS: + if (func != NULL) + { + return col+printf_wrapper(out, "\"%.27s\"", func->KonstS[arg].GetChars()); + } + return col+printf_wrapper(out, "ks%d", arg); + case MODE_KP: + if (func != NULL) + { + return col+printf_wrapper(out, "%p", func->KonstA[arg]); + } + return col+printf_wrapper(out, "ka%d", arg); + case MODE_KV: + if (func != NULL) + { + return col+printf_wrapper(out, "(%f,%f,%f)", func->KonstF[arg], func->KonstF[arg+1], func->KonstF[arg+2]); + } + return col+printf_wrapper(out, "kv%d", arg); + + case MODE_IMMS: + return col+printf_wrapper(out, "%d", (arg << immshift) >> immshift); + + case MODE_IMMZ: + return col+printf_wrapper(out, "%d", arg); + + case MODE_PARAM: + { + int regtype, regnum; +#ifdef __BIG_ENDIAN__ + regtype = (arg >> 8) & 255; + regnum = arg & 255; +#else + regtype = arg & 255; + regnum = (arg >> 8) & 255; +#endif + switch (regtype & (REGT_TYPE | REGT_KONST | REGT_MULTIREG)) + { + case REGT_INT: + return col+printf_wrapper(out, "d%d", regnum); + case REGT_FLOAT: + return col+printf_wrapper(out, "f%d", regnum); + case REGT_STRING: + return col+printf_wrapper(out, "s%d", regnum); + case REGT_POINTER: + return col+printf_wrapper(out, "a%d", regnum); + case REGT_FLOAT | REGT_MULTIREG: + return col+printf_wrapper(out, "v%d", regnum); + case REGT_INT | REGT_KONST: + return col+print_reg(out, 0, regnum, MODE_KI, 0, func); + case REGT_FLOAT | REGT_KONST: + return col+print_reg(out, 0, regnum, MODE_KF, 0, func); + case REGT_STRING | REGT_KONST: + return col+print_reg(out, 0, regnum, MODE_KS, 0, func); + case REGT_POINTER | REGT_KONST: + return col+print_reg(out, 0, regnum, MODE_KP, 0, func); + case REGT_FLOAT | REGT_MULTIREG | REGT_KONST: + return col+print_reg(out, 0, regnum, MODE_KV, 0, func); + default: + if (regtype == REGT_NIL) + { + return col+printf_wrapper(out, "nil"); + } + return col+printf_wrapper(out, "param[t=%d,%c,%c,n=%d]", + regtype & REGT_TYPE, + regtype & REGT_KONST ? 'k' : 'r', + regtype & REGT_MULTIREG ? 'm' : 's', + regnum); + } + } + + default: + return col+printf_wrapper(out, "$%d", arg); + } + return col; +} diff --git a/src/zscript/vmexec.cpp b/src/zscript/vmexec.cpp new file mode 100644 index 0000000000..ceecf5e011 --- /dev/null +++ b/src/zscript/vmexec.cpp @@ -0,0 +1,191 @@ +#include +#include "vm.h" + +#define IMPLEMENT_VMEXEC + +#if !defined(COMPGOTO) && defined(__GNUC__) +#define COMPGOTO 1 +#endif + +#if COMPGOTO +#define OP(x) x +#define NEXTOP do { unsigned op = pc->op; a = pc->a; pc++; goto *ops[op]; } while(0) +#else +#define OP(x) case OP_##x +#define NEXTOP break +#endif + +#define luai_nummod(a,b) ((a) - floor((a)/(b))*(b)) + +#define A (pc[-1].a) +#define B (pc[-1].b) +#define C (pc[-1].c) +#define Cs (pc[-1].cs) +#define BC (pc[-1].i16u) +#define BCs (pc[-1].i16) +#define ABCs (pc[-1].i24) +#define JMPOFS(x) ((x)->i24) + +#define KC (konstd[C]) +#define RC (reg.d[C]) + +#define PA (reg.a[A]) +#define PB (reg.a[B]) + +#define ASSERTD(x) assert((unsigned)(x) < f->NumRegD) +#define ASSERTF(x) assert((unsigned)(x) < f->NumRegF) +#define ASSERTA(x) assert((unsigned)(x) < f->NumRegA) +#define ASSERTS(x) assert((unsigned)(x) < f->NumRegS) + +#define ASSERTKD(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstD) +#define ASSERTKF(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstF) +#define ASSERTKA(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstA) +#define ASSERTKS(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstS) + +#define THROW(x) + +#define CMPJMP(test) \ + if ((test) == (a & CMP_CHECK)) { \ + assert(pc->op == OP_JMP); \ + pc += 1 + JMPOFS(pc); \ + } else { \ + pc += 1; \ + } + +enum +{ + X_READ_NIL, + X_WRITE_NIL, + X_TOO_MANY_TRIES, + X_ARRAY_OUT_OF_BOUNDS +}; + +#define GETADDR(a,o,x) \ + if (a == NULL) { THROW(x); } \ + ptr = (VM_SBYTE *)a + o + +static const VM_UWORD ZapTable[16] = +{ + 0x00000000, 0x000000FF, 0x0000FF00, 0x0000FFFF, + 0x00FF0000, 0x00FF00FF, 0x00FFFF00, 0x00FFFFFF, + 0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF, + 0xFFFF0000, 0xFFFF00FF, 0xFFFFFF00, 0xFFFFFFFF +}; + +#ifdef NDEBUG +#define WAS_NDEBUG 1 +#else +#define WAS_NDEBUG 0 +#endif + +#if WAS_NDEBUG +#undef NDEBUG +#endif +#undef assert +#include +struct VMExec_Checked +{ +#include "vmexec.h" +}; +#if WAS_NDEBUG +#define NDEBUG +#endif + +#if !WAS_NDEBUG +#define NDEBUG +#endif +#undef assert +#include +struct VMExec_Unchecked +{ +#include "vmexec.h" +}; +#if !WAS_NDEBUG +#undef NDEBUG +#endif +#undef assert +#include + +int (*VMExec)(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret) = +#ifdef NDEBUG +VMExec_Unchecked::Exec +#else +VMExec_Checked::Exec +#endif +; + +//=========================================================================== +// +// VMSelectEngine +// +// Selects the VM engine, either checked or unchecked. Default will decide +// based on the NDEBUG preprocessor definition. +// +//=========================================================================== + +void VMSelectEngine(EVMEngine engine) +{ + switch (engine) + { + case VMEngine_Default: +#ifdef NDEBUG + VMExec = VMExec_Unchecked::Exec; +#else +#endif + VMExec = VMExec_Checked::Exec; + break; + case VMEngine_Unchecked: + VMExec = VMExec_Unchecked::Exec; + break; + case VMEngine_Checked: + VMExec = VMExec_Checked::Exec; + break; + } +} + +//=========================================================================== +// +// VMFillParams +// +// Takes parameters from the parameter stack and stores them in the callee's +// registers. +// +//=========================================================================== + +void VMFillParams(VMValue *params, VMFrame *callee, int numparam) +{ + unsigned int regd, regf, regs, rega; + VMScriptFunction *calleefunc = static_cast(callee->Func); + const VMRegisters calleereg(callee); + + assert(calleefunc != NULL && !calleefunc->Native); + assert(numparam == calleefunc->NumArgs); + assert(REGT_INT == 0 && REGT_FLOAT == 1 && REGT_STRING == 2 && REGT_POINTER == 3); + + regd = regf = regs = rega = 0; + for (int i = 0; i < numparam; ++i) + { + VMValue &p = params[i]; + if (p.Type < REGT_STRING) + { + if (p.Type == REGT_INT) + { + calleereg.d[regd++] = p.i; + } + else // p.Type == REGT_FLOAT + { + calleereg.f[regf++] = p.f; + } + } + else if (p.Type == REGT_STRING) + { + calleereg.s[regs++] = p.s(); + } + else + { + assert(p.Type == REGT_POINTER); + calleereg.a[rega] = p.a; + calleereg.atag[rega++] = p.atag; + } + } +} diff --git a/src/zscript/vmexec.h b/src/zscript/vmexec.h new file mode 100644 index 0000000000..01c0e28de8 --- /dev/null +++ b/src/zscript/vmexec.h @@ -0,0 +1,1600 @@ +#ifndef IMPLEMENT_VMEXEC +#error vmexec.h must not be #included outside vmexec.cpp. Use vm.h instead. +#endif + + +static int Exec(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret) +{ +#if COMPGOTO + static const void * const ops[256] = + { +#define xx(op,sym,mode) &&op +#include "vmops.h" + }; +#endif + const VMOP *exception_frames[MAX_TRY_DEPTH]; + int try_depth = 0; + VMFrame *f = stack->TopFrame(); + VMScriptFunction *sfunc; + const VMRegisters reg(f); + const int *konstd; + const double *konstf; + const FString *konsts; + const FVoidObj *konsta; + const VM_ATAG *konstatag; + + if (f->Func != NULL && !f->Func->Native) + { + sfunc = static_cast(f->Func); + konstd = sfunc->KonstD; + konstf = sfunc->KonstF; + konsts = sfunc->KonstS; + konsta = sfunc->KonstA; + konstatag = sfunc->KonstATags(); + } + else + { + sfunc = NULL; + konstd = NULL; + konstf = NULL; + konsts = NULL; + konsta = NULL; + konstatag = NULL; + } + + void *ptr; + double fb, fc; + const double *fbp, *fcp; + int a, b, c; + +begin: + try + { +#if !COMPGOTO + VM_UBYTE op; + for(;;) switch(op = pc->op, a = pc->a, pc++, op) +#else + NEXTOP; +#endif + { + OP(LI): + ASSERTD(a); + reg.d[a] = BCs; + NEXTOP; + OP(LK): + ASSERTD(a); ASSERTKD(BC); + reg.d[a] = konstd[BC]; + NEXTOP; + OP(LKF): + ASSERTF(a); ASSERTKF(BC); + reg.f[a] = konstf[BC]; + NEXTOP; + OP(LKS): + ASSERTS(a); ASSERTKS(BC); + reg.s[a] = konsts[BC]; + NEXTOP; + OP(LKP): + ASSERTA(a); ASSERTKA(BC); + reg.a[a] = konsta[BC].v; + reg.atag[a] = konstatag[BC]; + NEXTOP; + OP(LFP): + ASSERTA(a); assert(sfunc != NULL); assert(sfunc->ExtraSpace > 0); + reg.a[a] = f->GetExtra(); + reg.atag[a] = ATAG_FRAMEPOINTER; + NEXTOP; + + OP(LB): + ASSERTD(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PB,KC,X_READ_NIL); + reg.d[a] = *(VM_SBYTE *)ptr; + NEXTOP; + OP(LB_R): + ASSERTD(a); ASSERTA(B); ASSERTD(C); + GETADDR(PB,RC,X_READ_NIL); + reg.d[a] = *(VM_SBYTE *)ptr; + NEXTOP; + OP(LH): + ASSERTD(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PB,KC,X_READ_NIL); + reg.d[a] = *(VM_SHALF *)ptr; + NEXTOP; + OP(LH_R): + ASSERTD(a); ASSERTA(B); ASSERTD(C); + GETADDR(PB,RC,X_READ_NIL); + reg.d[a] = *(VM_SHALF *)ptr; + NEXTOP; + OP(LW): + ASSERTD(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PB,KC,X_READ_NIL); + reg.d[a] = *(VM_SWORD *)ptr; + NEXTOP; + OP(LW_R): + ASSERTD(a); ASSERTA(B); ASSERTD(C); + GETADDR(PB,RC,X_READ_NIL); + reg.d[a] = *(VM_SWORD *)ptr; + NEXTOP; + OP(LBU): + ASSERTD(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PB,KC,X_READ_NIL); + reg.d[a] = *(VM_UBYTE *)ptr; + NEXTOP; + OP(LBU_R): + ASSERTD(a); ASSERTA(B); ASSERTD(C); + GETADDR(PB,RC,X_READ_NIL); + reg.d[a] = *(VM_UBYTE *)ptr; + NEXTOP; + OP(LHU): + ASSERTD(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PB,KC,X_READ_NIL); + reg.d[a] = *(VM_UHALF *)ptr; + NEXTOP; + OP(LHU_R): + ASSERTD(a); ASSERTA(B); ASSERTD(C); + GETADDR(PB,RC,X_READ_NIL); + reg.d[a] = *(VM_UHALF *)ptr; + NEXTOP; + + OP(LSP): + ASSERTF(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PB,KC,X_READ_NIL); + reg.f[a] = *(float *)ptr; + NEXTOP; + OP(LSP_R): + ASSERTF(a); ASSERTA(B); ASSERTD(C); + GETADDR(PB,RC,X_READ_NIL); + reg.f[a] = *(float *)ptr; + NEXTOP; + OP(LDP): + ASSERTF(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PB,KC,X_READ_NIL); + reg.f[a] = *(double *)ptr; + NEXTOP; + OP(LDP_R): + ASSERTF(a); ASSERTA(B); ASSERTD(C); + GETADDR(PB,RC,X_READ_NIL); + reg.f[a] = *(double *)ptr; + NEXTOP; + + OP(LS): + ASSERTS(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PB,KC,X_READ_NIL); + reg.s[a] = *(FString *)ptr; + NEXTOP; + OP(LS_R): + ASSERTS(a); ASSERTA(B); ASSERTD(C); + GETADDR(PB,RC,X_READ_NIL); + reg.s[a] = *(FString *)ptr; + NEXTOP; + OP(LO): + ASSERTA(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PB,KC,X_READ_NIL); + reg.a[a] = *(void **)ptr; + reg.atag[a] = ATAG_OBJECT; + NEXTOP; + OP(LO_R): + ASSERTA(a); ASSERTA(B); ASSERTD(C); + GETADDR(PB,RC,X_READ_NIL); + reg.a[a] = *(void **)ptr; + reg.atag[a] = ATAG_OBJECT; + NEXTOP; + OP(LP): + ASSERTA(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PB,KC,X_READ_NIL); + reg.a[a] = *(void **)ptr; + reg.atag[a] = ATAG_GENERIC; + NEXTOP; + OP(LP_R): + ASSERTA(a); ASSERTA(B); ASSERTD(C); + GETADDR(PB,RC,X_READ_NIL); + reg.a[a] = *(void **)ptr; + reg.atag[a] = ATAG_GENERIC; + NEXTOP; + OP(LV): + ASSERTF(a+2); ASSERTA(B); ASSERTKD(C); + GETADDR(PB,KC,X_READ_NIL); + { + float *v = (float *)ptr; + reg.f[a] = v[0]; + reg.f[a+1] = v[1]; + reg.f[a+2] = v[2]; + } + NEXTOP; + OP(LV_R): + ASSERTF(a+2); ASSERTA(B); ASSERTD(C); + GETADDR(PB,RC,X_READ_NIL); + { + float *v = (float *)ptr; + reg.f[a] = v[0]; + reg.f[a+1] = v[1]; + reg.f[a+2] = v[2]; + } + NEXTOP; + OP(LX): + ASSERTF(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PB,KC,X_READ_NIL); + reg.f[a] = *(VM_SWORD *)ptr / 65536.0; + NEXTOP; + OP(LX_R): + ASSERTF(a); ASSERTA(B); ASSERTD(C); + GETADDR(PB,RC,X_READ_NIL); + reg.f[a] = *(VM_SWORD *)ptr / 65536.0; + NEXTOP; + OP(LANG): + ASSERTF(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PB,KC,X_READ_NIL); + reg.f[a] = (*(VM_UWORD *)ptr >> 1) * (180.0 / 0x40000000); // BAM -> deg + NEXTOP; + OP(LANG_R): + ASSERTF(a); ASSERTA(B); ASSERTD(C); + GETADDR(PB,RC,X_READ_NIL); + reg.f[a] = (*(VM_UWORD *)ptr >> 1) * (180.0 / 0x40000000); + NEXTOP; + OP(LBIT): + ASSERTD(a); ASSERTA(B); + GETADDR(PB,0,X_READ_NIL); + reg.d[a] = !!(*(VM_UBYTE *)ptr & C); + NEXTOP; + + OP(SB): + ASSERTA(a); ASSERTD(B); ASSERTKD(C); + GETADDR(PA,KC,X_WRITE_NIL); + *(VM_SBYTE *)ptr = reg.d[B]; + NEXTOP; + OP(SB_R): + ASSERTA(a); ASSERTD(B); ASSERTD(C); + GETADDR(PA,RC,X_WRITE_NIL); + *(VM_SBYTE *)ptr = reg.d[B]; + NEXTOP; + OP(SH): + ASSERTA(a); ASSERTD(B); ASSERTKD(C); + GETADDR(PA,KC,X_WRITE_NIL); + *(VM_SHALF *)ptr = reg.d[B]; + NEXTOP; + OP(SH_R): + ASSERTA(a); ASSERTD(B); ASSERTD(C); + GETADDR(PA,RC,X_WRITE_NIL); + *(VM_SHALF *)ptr = reg.d[B]; + NEXTOP; + OP(SW): + ASSERTA(a); ASSERTD(B); ASSERTKD(C); + GETADDR(PA,KC,X_WRITE_NIL); + *(VM_SWORD *)ptr = reg.d[B]; + NEXTOP; + OP(SW_R): + ASSERTA(a); ASSERTD(B); ASSERTD(C); + GETADDR(PA,RC,X_WRITE_NIL); + *(VM_SWORD *)ptr = reg.d[B]; + NEXTOP; + OP(SSP): + ASSERTA(a); ASSERTF(B); ASSERTKD(C); + GETADDR(PA,KC,X_WRITE_NIL); + *(float *)ptr = (float)reg.f[B]; + NEXTOP; + OP(SSP_R): + ASSERTA(a); ASSERTF(B); ASSERTD(C); + GETADDR(PA,RC,X_WRITE_NIL); + *(float *)ptr = (float)reg.f[B]; + NEXTOP; + OP(SDP): + ASSERTA(a); ASSERTF(B); ASSERTKD(C); + GETADDR(PA,KC,X_WRITE_NIL); + *(double *)ptr = reg.f[B]; + NEXTOP; + OP(SDP_R): + ASSERTA(a); ASSERTF(B); ASSERTD(C); + GETADDR(PA,RC,X_WRITE_NIL); + *(double *)ptr = reg.f[B]; + NEXTOP; + OP(SS): + ASSERTA(a); ASSERTS(B); ASSERTKD(C); + GETADDR(PA,KC,X_WRITE_NIL); + *(FString *)ptr = reg.s[B]; + NEXTOP; + OP(SS_R): + ASSERTA(a); ASSERTS(B); ASSERTD(C); + GETADDR(PA,RC,X_WRITE_NIL); + *(FString *)ptr = reg.s[B]; + NEXTOP; + OP(SP): + ASSERTA(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PA,KC,X_WRITE_NIL); + *(void **)ptr = reg.a[B]; + NEXTOP; + OP(SP_R): + ASSERTA(a); ASSERTA(B); ASSERTD(C); + GETADDR(PA,RC,X_WRITE_NIL); + *(void **)ptr = reg.a[B]; + NEXTOP; + OP(SV): + ASSERTA(a); ASSERTF(B+2); ASSERTKD(C); + GETADDR(PA,KC,X_WRITE_NIL); + { + float *v = (float *)ptr; + v[0] = (float)reg.f[B]; + v[1] = (float)reg.f[B+1]; + v[2] = (float)reg.f[B+2]; + } + NEXTOP; + OP(SV_R): + ASSERTA(a); ASSERTF(B+2); ASSERTD(C); + GETADDR(PA,RC,X_WRITE_NIL); + { + float *v = (float *)ptr; + v[0] = (float)reg.f[B]; + v[1] = (float)reg.f[B+1]; + v[2] = (float)reg.f[B+2]; + } + NEXTOP; + OP(SX): + ASSERTA(a); ASSERTF(B); ASSERTKD(C); + GETADDR(PA,KC,X_WRITE_NIL); + *(VM_SWORD *)ptr = (VM_SWORD)(reg.f[B] * 65536.0); + NEXTOP; + OP(SX_R): + ASSERTA(a); ASSERTF(B); ASSERTD(C); + GETADDR(PA,RC,X_WRITE_NIL); + *(VM_SWORD *)ptr = (VM_SWORD)(reg.f[B] * 65536.0); + NEXTOP; + OP(SANG): + ASSERTA(a); ASSERTF(B); ASSERTKD(C); + GETADDR(PA,KC,X_WRITE_NIL); + *(VM_UWORD *)ptr = (VM_UWORD)(reg.f[B] * ((1<<30) / 180.0)) << 1; // deg -> BAM + NEXTOP; + OP(SANG_R): + ASSERTA(a); ASSERTF(B); ASSERTD(C); + GETADDR(PA,RC,X_WRITE_NIL); + *(VM_UWORD *)ptr = (VM_UWORD)(reg.f[B] * ((1<<30) / 180.0)) << 1; + NEXTOP; + + OP(SBIT): + ASSERTA(a); ASSERTD(B); + GETADDR(PA,0,X_WRITE_NIL); + if (reg.d[B]) + { + *(VM_UBYTE *)ptr |= C; + } + else + { + *(VM_UBYTE *)ptr &= ~C; + } + NEXTOP; + + OP(MOVE): + ASSERTD(a); ASSERTD(B); + reg.d[a] = reg.d[B]; + NEXTOP; + OP(MOVEF): + ASSERTF(a); ASSERTF(B); + reg.f[a] = reg.f[B]; + NEXTOP; + OP(MOVES): + ASSERTS(a); ASSERTS(B); + reg.s[a] = reg.s[B]; + NEXTOP; + OP(MOVEA): + ASSERTA(a); ASSERTA(B); + reg.a[a] = reg.a[B]; + reg.atag[a] = reg.atag[B]; + NEXTOP; + OP(CAST): + if (C == CAST_I2F) + { + ASSERTF(a); ASSERTD(B); + reg.f[A] = reg.d[B]; + } + else if (C == CAST_F2I) + { + ASSERTD(a); ASSERTF(B); + reg.d[A] = (int)reg.f[B]; + } + else + { + DoCast(reg, f, a, B, C); + } + NEXTOP; + OP(DYNCAST_R): + // UNDONE + NEXTOP; + OP(DYNCAST_K): + // UNDONE + NEXTOP; + + OP(TEST): + ASSERTD(a); + if (reg.d[a] != BC) + { + pc++; + } + NEXTOP; + OP(JMP): + pc += JMPOFS(pc - 1); + NEXTOP; + OP(IJMP): + ASSERTD(a); + pc += (BCs + reg.d[a]); + assert(pc->op == OP_JMP); + pc += 1 + JMPOFS(pc); + NEXTOP; + OP(PARAMI): + assert(f->NumParam < sfunc->MaxParam); + { + VMValue *param = ®.param[f->NumParam++]; + ::new(param) VMValue(ABCs); + } + NEXTOP; + OP(PARAM): + assert(f->NumParam < sfunc->MaxParam); + { + VMValue *param = ®.param[f->NumParam++]; + b = B; + if (b == REGT_NIL) + { + ::new(param) VMValue(); + } + else + { + switch(b & (REGT_TYPE | REGT_KONST | REGT_ADDROF)) + { + case REGT_INT: + assert(C < f->NumRegD); + ::new(param) VMValue(reg.d[C]); + break; + case REGT_INT | REGT_ADDROF: + assert(C < f->NumRegD); + ::new(param) VMValue(®.d[C], ATAG_DREGISTER); + break; + case REGT_INT | REGT_KONST: + assert(C < sfunc->NumKonstD); + ::new(param) VMValue(konstd[C]); + break; + case REGT_STRING: + assert(C < f->NumRegS); + ::new(param) VMValue(reg.s[C]); + break; + case REGT_STRING | REGT_ADDROF: + assert(C < f->NumRegS); + ::new(param) VMValue(®.s[C], ATAG_SREGISTER); + break; + case REGT_STRING | REGT_KONST: + assert(C < sfunc->NumKonstS); + ::new(param) VMValue(konsts[C]); + break; + case REGT_POINTER: + assert(C < f->NumRegA); + ::new(param) VMValue(reg.a[C], reg.atag[C]); + break; + case REGT_POINTER | REGT_ADDROF: + assert(C < f->NumRegA); + ::new(param) VMValue(®.a[C], ATAG_AREGISTER); + break; + case REGT_POINTER | REGT_KONST: + assert(C < sfunc->NumKonstA); + ::new(param) VMValue(konsta[C].v, konstatag[C]); + break; + case REGT_FLOAT: + if (b & REGT_MULTIREG) + { + assert(C < f->NumRegF - 2); + assert(f->NumParam < sfunc->MaxParam - 1); + ::new(param) VMValue(reg.f[C]); + ::new(param+1) VMValue(reg.f[C+1]); + ::new(param+2) VMValue(reg.f[C+2]); + f->NumParam += 2; + } + else + { + assert(C < f->NumRegF); + ::new(param) VMValue(reg.f[C]); + } + break; + case REGT_FLOAT | REGT_ADDROF: + assert(C < f->NumRegF); + ::new(param) VMValue(®.f[C], ATAG_FREGISTER); + break; + case REGT_FLOAT | REGT_KONST: + if (b & REGT_MULTIREG) + { + assert(C < sfunc->NumKonstF - 2); + assert(f->NumParam < sfunc->MaxParam - 1); + ::new(param) VMValue(konstf[C]); + ::new(param+1) VMValue(konstf[C+1]); + ::new(param+2) VMValue(konstf[C+2]); + f->NumParam += 2; + } + else + { + assert(C < sfunc->NumKonstF); + ::new(param) VMValue(konstf[C]); + } + break; + default: + assert(0); + break; + } + } + } + NEXTOP; + OP(CALL_K): + ASSERTKA(a); + assert(konstatag[a] == ATAG_OBJECT); + ptr = konsta[a].o; + goto Do_CALL; + OP(CALL): + ASSERTA(a); + ptr = reg.a[a]; + Do_CALL: + assert(B <= f->NumParam); + assert(C <= MAX_RETURNS); + { + VMFunction *call = (VMFunction *)ptr; + VMReturn returns[MAX_RETURNS]; + int numret; + + FillReturns(reg, f, returns, pc, C); + if (call->Native) + { + numret = static_cast(call)->NativeCall(stack, reg.param + f->NumParam - B, B, returns, C); + } + else + { + VMScriptFunction *script = static_cast(call); + VMFrame *newf = stack->AllocFrame(script); + VMFillParams(reg.param + f->NumParam - B, newf, B); + try + { + numret = Exec(stack, script->Code, returns, C); + } + catch(...) + { + stack->PopFrame(); + throw; + } + stack->PopFrame(); + } + assert(numret == C); + for (b = B; b != 0; --b) + { + reg.param[--f->NumParam].~VMValue(); + } + pc += C; // Skip RESULTs + } + NEXTOP; + OP(TAIL_K): + ASSERTKA(a); + assert(konstatag[a] == ATAG_OBJECT); + ptr = konsta[a].o; + goto Do_TAILCALL; + OP(TAIL): + ASSERTA(a); + ptr = reg.a[a]; + Do_TAILCALL: + // Whereas the CALL instruction uses its third operand to specify how many return values + // it expects, TAIL ignores its third operand and uses whatever was passed to this Exec call. + assert(B <= f->NumParam); + assert(C <= MAX_RETURNS); + { + VMFunction *call = (VMFunction *)ptr; + + if (call->Native) + { + return static_cast(call)->NativeCall(stack, reg.param + f->NumParam - B, B, ret, numret); + } + else + { // FIXME: Not a true tail call + VMScriptFunction *script = static_cast(call); + VMFrame *newf = stack->AllocFrame(script); + VMFillParams(reg.param + f->NumParam - B, newf, B); + try + { + numret = Exec(stack, script->Code, ret, numret); + } + catch(...) + { + stack->PopFrame(); + throw; + } + stack->PopFrame(); + return numret; + } + } + NEXTOP; + OP(RET): + if (B == REGT_NIL) + { // No return values + return 0; + } + assert(ret != NULL || numret == 0); + { + int retnum = a & ~RET_FINAL; + if (retnum < numret) + { + SetReturn(reg, f, &ret[retnum], B, C); + } + if (a & RET_FINAL) + { + return retnum < numret ? retnum + 1 : numret; + } + } + NEXTOP; + OP(RETI): + assert(ret != NULL || numret == 0); + { + int retnum = a & ~RET_FINAL; + if (retnum < numret) + { + ret[retnum].SetInt(BCs); + } + if (a & RET_FINAL) + { + return retnum < numret ? retnum + 1 : numret; + } + } + NEXTOP; + OP(RESULT): + // This instruction is just a placeholder to indicate where a return + // value should be stored. It does nothing on its own and should not + // be executed. + assert(0); + NEXTOP; + + OP(TRY): + assert(try_depth < MAX_TRY_DEPTH); + if (try_depth >= MAX_TRY_DEPTH) + { + THROW(X_TOO_MANY_TRIES); + } + assert((pc + JMPOFS(pc - 1))->op == OP_CATCH); + exception_frames[try_depth++] = pc + JMPOFS(pc - 1); + NEXTOP; + OP(UNTRY): + assert(a <= try_depth); + try_depth -= a; + NEXTOP; + OP(THROW): + if (a == 0) + { + ASSERTA(B); + throw((VMException *)reg.a[B]); + } + else + { + ASSERTKA(B); + assert(konstatag[B] == ATAG_OBJECT); + throw((VMException *)konsta[B].o); + } + NEXTOP; + OP(CATCH): + // This instruction is handled by our own catch handler and should + // not be executed by the normal VM code. + assert(0); + NEXTOP; + + OP(BOUND): + if (reg.d[a] >= BC) + { + THROW(X_ARRAY_OUT_OF_BOUNDS); + } + NEXTOP; + + OP(CONCAT): + ASSERTS(a); ASSERTS(B); ASSERTS(C); + { + FString *rB = ®.s[B]; + FString *rC = ®.s[C]; + FString concat(*rB); + for (++rB; rB <= rC; ++rB) + { + concat += *rB; + } + reg.s[a] = concat; + } + NEXTOP; + OP(LENS): + ASSERTD(a); ASSERTS(B); + reg.d[a] = (int)reg.s[B].Len(); + NEXTOP; + + OP(CMPS): + // String comparison is a fairly expensive operation, so I've + // chosen to conserve a few opcodes by condensing all the + // string comparisons into a single one. + { + const FString *b, *c; + int test, method; + bool cmp; + + if (a & CMP_BK) + { + ASSERTKS(B); + b = &konsts[B]; + } + else + { + ASSERTS(B); + b = ®.s[B]; + } + if (a & CMP_CK) + { + ASSERTKS(C); + c = &konsts[C]; + } + else + { + ASSERTS(C); + c = ®.s[C]; + } + test = (a & CMP_APPROX) ? b->CompareNoCase(*c) : b->Compare(*c); + method = a & CMP_METHOD_MASK; + if (method == CMP_EQ) + { + cmp = !test; + } + else if (method == CMP_LT) + { + cmp = (test < 0); + } + else + { + assert(method == CMP_LE); + cmp = (test <= 0); + } + if (cmp == (a & CMP_CHECK)) + { + assert(pc->op == OP_JMP); + pc += 1 + JMPOFS(pc); + } + else + { + pc += 1; + } + } + NEXTOP; + + OP(SLL_RR): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] << reg.d[C]; + NEXTOP; + OP(SLL_RI): + ASSERTD(a); ASSERTD(B); assert(C <= 31); + reg.d[a] = reg.d[B] << C; + NEXTOP; + OP(SLL_KR): + ASSERTD(a); ASSERTKD(B); ASSERTD(C); + reg.d[a] = konstd[B] << reg.d[C]; + NEXTOP; + + OP(SRL_RR): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = (unsigned)reg.d[B] >> reg.d[C]; + NEXTOP; + OP(SRL_RI): + ASSERTD(a); ASSERTD(B); assert(C <= 31); + reg.d[a] = (unsigned)reg.d[B] >> C; + NEXTOP; + OP(SRL_KR): + ASSERTD(a); ASSERTKD(B); ASSERTD(C); + reg.d[a] = (unsigned)konstd[B] >> C; + NEXTOP; + + OP(SRA_RR): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] >> reg.d[C]; + NEXTOP; + OP(SRA_RI): + ASSERTD(a); ASSERTD(B); assert(C <= 31); + reg.d[a] = reg.d[B] >> C; + NEXTOP; + OP(SRA_KR): + ASSERTD(a); ASSERTKD(B); ASSERTD(C); + reg.d[a] = konstd[B] >> reg.d[C]; + NEXTOP; + + OP(ADD_RR): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] + reg.d[C]; + NEXTOP; + OP(ADD_RK): + ASSERTD(a); ASSERTD(B); ASSERTKD(C); + reg.d[a] = reg.d[B] + konstd[C]; + NEXTOP; + OP(ADDI): + ASSERTD(a); ASSERTD(B); + reg.d[a] = reg.d[B] + Cs; + NEXTOP; + + OP(SUB_RR): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] - reg.d[C]; + NEXTOP; + OP(SUB_RK): + ASSERTD(a); ASSERTD(B); ASSERTKD(C); + reg.d[a] = reg.d[B] - konstd[C]; + NEXTOP; + OP(SUB_KR): + ASSERTD(a); ASSERTKD(B); ASSERTD(C); + reg.d[a] = konstd[B] - reg.d[C]; + NEXTOP; + + OP(MUL_RR): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] * reg.d[C]; + NEXTOP; + OP(MUL_RK): + ASSERTD(a); ASSERTD(B); ASSERTKD(C); + reg.d[a] = reg.d[B] * konstd[C]; + NEXTOP; + + OP(DIV_RR): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] / reg.d[C]; + NEXTOP; + OP(DIV_RK): + ASSERTD(a); ASSERTD(B); ASSERTKD(C); + reg.d[a] = reg.d[B] / konstd[C]; + NEXTOP; + OP(DIV_KR): + ASSERTD(a); ASSERTKD(B); ASSERTD(C); + reg.d[a] = konstd[B] / reg.d[C]; + NEXTOP; + + OP(MOD_RR): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] % reg.d[C]; + NEXTOP; + OP(MOD_RK): + ASSERTD(a); ASSERTD(B); ASSERTKD(C); + reg.d[a] = reg.d[B] % konstd[C]; + NEXTOP; + OP(MOD_KR): + ASSERTD(a); ASSERTKD(B); ASSERTD(C); + reg.d[a] = konstd[B] % reg.d[C]; + NEXTOP; + + OP(AND_RR): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] & reg.d[C]; + NEXTOP; + OP(AND_RK): + ASSERTD(a); ASSERTD(B); ASSERTKD(C); + reg.d[a] = reg.d[B] & konstd[C]; + NEXTOP; + + OP(OR_RR): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] | reg.d[C]; + NEXTOP; + OP(OR_RK): + ASSERTD(a); ASSERTD(B); ASSERTKD(C); + reg.d[a] = reg.d[B] | konstd[C]; + NEXTOP; + + OP(XOR_RR): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] ^ reg.d[C]; + NEXTOP; + OP(XOR_RK): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] ^ konstd[C]; + NEXTOP; + + OP(MIN_RR): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] < reg.d[C] ? reg.d[B] : reg.d[C]; + NEXTOP; + OP(MIN_RK): + ASSERTD(a); ASSERTD(B); ASSERTKD(C); + reg.d[a] = reg.d[B] < konstd[C] ? reg.d[B] : konstd[C]; + NEXTOP; + OP(MAX_RR): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] > reg.d[C] ? reg.d[B] : reg.d[C]; + NEXTOP; + OP(MAX_RK): + ASSERTD(a); ASSERTD(B); ASSERTKD(C); + reg.d[a] = reg.d[B] > konstd[C] ? reg.d[B] : konstd[C]; + NEXTOP; + + OP(ABS): + ASSERTD(a); ASSERTD(B); + reg.d[a] = abs(reg.d[B]); + NEXTOP; + + OP(NEG): + ASSERTD(a); ASSERTD(B); + reg.d[a] = -reg.d[B]; + NEXTOP; + + OP(NOT): + ASSERTD(a); ASSERTD(B); + reg.d[a] = ~reg.d[B]; + NEXTOP; + + OP(SEXT): + ASSERTD(a); ASSERTD(B); + reg.d[a] = (VM_SWORD)(reg.d[B] << C) >> C; + NEXTOP; + + OP(ZAP_R): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] & ZapTable[(reg.d[C] & 15) ^ 15]; + NEXTOP; + OP(ZAP_I): + ASSERTD(a); ASSERTD(B); + reg.d[a] = reg.d[B] & ZapTable[(C & 15) ^ 15]; + NEXTOP; + OP(ZAPNOT_R): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + reg.d[a] = reg.d[B] & ZapTable[reg.d[C] & 15]; + NEXTOP; + OP(ZAPNOT_I): + ASSERTD(a); ASSERTD(B); + reg.d[a] = reg.d[B] & ZapTable[C & 15]; + NEXTOP; + + OP(EQ_R): + ASSERTD(B); ASSERTD(C); + CMPJMP(reg.d[B] == reg.d[C]); + NEXTOP; + OP(EQ_K): + ASSERTD(B); ASSERTKD(C); + CMPJMP(reg.d[B] == konstd[C]); + NEXTOP; + OP(LT_RR): + ASSERTD(B); ASSERTD(C); + CMPJMP(reg.d[B] < reg.d[C]); + NEXTOP; + OP(LT_RK): + ASSERTD(B); ASSERTKD(C); + CMPJMP(reg.d[B] < konstd[C]); + NEXTOP; + OP(LT_KR): + ASSERTKD(B); ASSERTD(C); + CMPJMP(konstd[B] < reg.d[C]); + NEXTOP; + OP(LE_RR): + ASSERTD(B); ASSERTD(C); + CMPJMP(reg.d[B] <= reg.d[C]); + NEXTOP; + OP(LE_RK): + ASSERTD(B); ASSERTKD(C); + CMPJMP(reg.d[B] <= konstd[C]); + NEXTOP; + OP(LE_KR): + ASSERTKD(B); ASSERTD(C); + CMPJMP(konstd[B] <= reg.d[C]); + NEXTOP; + OP(LTU_RR): + ASSERTD(B); ASSERTD(C); + CMPJMP((VM_UWORD)reg.d[B] < (VM_UWORD)reg.d[C]); + NEXTOP; + OP(LTU_RK): + ASSERTD(B); ASSERTKD(C); + CMPJMP((VM_UWORD)reg.d[B] < (VM_UWORD)konstd[C]); + NEXTOP; + OP(LTU_KR): + ASSERTKD(B); ASSERTD(C); + CMPJMP((VM_UWORD)konstd[B] < (VM_UWORD)reg.d[C]); + NEXTOP; + OP(LEU_RR): + ASSERTD(B); ASSERTD(C); + CMPJMP((VM_UWORD)reg.d[B] <= (VM_UWORD)reg.d[C]); + NEXTOP; + OP(LEU_RK): + ASSERTD(B); ASSERTKD(C); + CMPJMP((VM_UWORD)reg.d[B] <= (VM_UWORD)konstd[C]); + NEXTOP; + OP(LEU_KR): + ASSERTKD(B); ASSERTD(C); + CMPJMP((VM_UWORD)konstd[B] <= (VM_UWORD)reg.d[C]); + NEXTOP; + + OP(ADDF_RR): + ASSERTF(a); ASSERTF(B); ASSERTF(C); + reg.f[a] = reg.f[B] + reg.f[C]; + NEXTOP; + OP(ADDF_RK): + ASSERTF(a); ASSERTF(B); ASSERTKF(C); + reg.f[a] = reg.f[B] + konstf[C]; + NEXTOP; + + OP(SUBF_RR): + ASSERTF(a); ASSERTF(B); ASSERTF(C); + reg.f[a] = reg.f[B] - reg.f[C]; + NEXTOP; + OP(SUBF_RK): + ASSERTF(a); ASSERTF(B); ASSERTKF(C); + reg.f[a] = reg.f[B] - konstf[C]; + NEXTOP; + OP(SUBF_KR): + ASSERTF(a); ASSERTKF(B); ASSERTF(C); + reg.f[a] = konstf[B] - reg.f[C]; + NEXTOP; + + OP(MULF_RR): + ASSERTF(a); ASSERTF(B); ASSERTF(C); + reg.f[a] = reg.f[B] * reg.f[C]; + NEXTOP; + OP(MULF_RK): + ASSERTF(a); ASSERTF(B); ASSERTKF(C); + reg.f[a] = reg.f[B] * konstf[C]; + NEXTOP; + + OP(DIVF_RR): + ASSERTF(a); ASSERTF(B); ASSERTF(C); + reg.f[a] = reg.f[B] / reg.f[C]; + NEXTOP; + OP(DIVF_RK): + ASSERTF(a); ASSERTF(B); ASSERTKF(C); + reg.f[a] = reg.f[B] / konstf[C]; + NEXTOP; + OP(DIVF_KR): + ASSERTF(a); ASSERTKF(B); ASSERTF(C); + reg.f[a] = konstf[B] / reg.f[C]; + NEXTOP; + + OP(MODF_RR): + ASSERTF(a); ASSERTF(B); ASSERTF(C); + fb = reg.f[B]; fc = reg.f[C]; + Do_MODF: + reg.f[a] = luai_nummod(fb, fc); + NEXTOP; + OP(MODF_RK): + ASSERTF(a); ASSERTF(B); ASSERTKF(C); + fb = reg.f[B]; fc = konstf[C]; + goto Do_MODF; + NEXTOP; + OP(MODF_KR): + ASSERTF(a); ASSERTKF(B); ASSERTF(C); + fb = konstf[B]; fc = reg.f[C]; + goto Do_MODF; + NEXTOP; + + OP(POWF_RR): + ASSERTF(a); ASSERTF(B); ASSERTF(C); + reg.f[a] = pow(reg.f[B], reg.f[C]); + NEXTOP; + OP(POWF_RK): + ASSERTF(a); ASSERTF(B); ASSERTKF(C); + reg.f[a] = pow(reg.f[B], konstf[C]); + NEXTOP; + OP(POWF_KR): + ASSERTF(a); ASSERTKF(B); ASSERTF(C); + reg.f[a] = pow(konstf[B], reg.f[C]); + NEXTOP; + + OP(MINF_RR): + ASSERTF(a); ASSERTF(B); ASSERTF(C); + reg.f[a] = reg.f[B] < reg.f[C] ? reg.f[B] : reg.f[C]; + NEXTOP; + OP(MINF_RK): + ASSERTF(a); ASSERTF(B); ASSERTKF(C); + reg.f[a] = reg.f[B] < konstf[C] ? reg.f[B] : konstf[C]; + NEXTOP; + OP(MAXF_RR): + ASSERTF(a); ASSERTF(B); ASSERTF(C); + reg.f[a] = reg.f[B] > reg.f[C] ? reg.f[B] : reg.f[C]; + NEXTOP; + OP(MAXF_RK): + ASSERTF(a); ASSERTF(B); ASSERTKF(C); + reg.f[a] = reg.f[B] > konstf[C] ? reg.f[B] : konstf[C]; + NEXTOP; + + OP(FLOP): + ASSERTF(a); ASSERTF(B); + fb = reg.f[B]; + reg.f[a] = (C == FLOP_ABS) ? fabs(fb) : (C == FLOP_NEG) ? -fb : DoFLOP(C, fb); + NEXTOP; + + OP(EQF_R): + ASSERTF(B); ASSERTF(C); + if (a & CMP_APPROX) + { + CMPJMP(fabs(reg.f[C] - reg.f[B]) < VM_EPSILON); + } + else + { + CMPJMP(reg.f[C] == reg.f[B]); + } + NEXTOP; + OP(EQF_K): + ASSERTF(B); ASSERTKF(C); + if (a & CMP_APPROX) + { + CMPJMP(fabs(konstf[C] - reg.f[B]) < VM_EPSILON); + } + else + { + CMPJMP(konstf[C] == reg.f[B]); + } + NEXTOP; + OP(LTF_RR): + ASSERTF(B); ASSERTF(C); + if (a & CMP_APPROX) + { + CMPJMP((reg.f[B] - reg.f[C]) < -VM_EPSILON); + } + else + { + CMPJMP(reg.f[B] < reg.f[C]); + } + NEXTOP; + OP(LTF_RK): + ASSERTF(B); ASSERTKF(C); + if (a & CMP_APPROX) + { + CMPJMP((reg.f[B] - konstf[C]) < -VM_EPSILON); + } + else + { + CMPJMP(reg.f[B] < konstf[C]); + } + NEXTOP; + OP(LTF_KR): + ASSERTKF(B); ASSERTF(C); + if (a & CMP_APPROX) + { + CMPJMP((konstf[B] - reg.f[C]) < -VM_EPSILON); + } + else + { + CMPJMP(konstf[B] < reg.f[C]); + } + NEXTOP; + OP(LEF_RR): + ASSERTF(B); ASSERTF(C); + if (a & CMP_APPROX) + { + CMPJMP((reg.f[B] - reg.f[C]) <= -VM_EPSILON); + } + else + { + CMPJMP(reg.f[B] <= reg.f[C]); + } + NEXTOP; + OP(LEF_RK): + ASSERTF(B); ASSERTKF(C); + if (a & CMP_APPROX) + { + CMPJMP((reg.f[B] - konstf[C]) <= -VM_EPSILON); + } + else + { + CMPJMP(reg.f[B] <= konstf[C]); + } + NEXTOP; + OP(LEF_KR): + ASSERTKF(B); ASSERTF(C); + if (a & CMP_APPROX) + { + CMPJMP((konstf[B] - reg.f[C]) <= -VM_EPSILON); + } + else + { + CMPJMP(konstf[B] <= reg.f[C]); + } + NEXTOP; + + OP(NEGV): + ASSERTF(a+2); ASSERTF(B+2); + reg.f[a] = -reg.f[B]; + reg.f[a+1] = -reg.f[B+1]; + reg.f[a+2] = -reg.f[B+2]; + NEXTOP; + + OP(ADDV_RR): + ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C+2); + fcp = ®.f[C]; + Do_ADDV: + fbp = ®.f[B]; + reg.f[a] = fbp[0] + fcp[0]; + reg.f[a+1] = fbp[1] + fcp[1]; + reg.f[a+2] = fbp[2] + fcp[2]; + NEXTOP; + OP(ADDV_RK): + fcp = &konstf[C]; + goto Do_ADDV; + + OP(SUBV_RR): + ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C+2); + fbp = ®.f[B]; + fcp = ®.f[C]; + Do_SUBV: + reg.f[a] = fbp[0] - fcp[0]; + reg.f[a+1] = fbp[1] - fcp[1]; + reg.f[a+2] = fbp[2] - fcp[2]; + NEXTOP; + OP(SUBV_RK): + ASSERTF(a+2); ASSERTF(B+2); ASSERTKF(C+2); + fbp = ®.f[B]; + fcp = &konstf[C]; + goto Do_SUBV; + OP(SUBV_KR): + ASSERTF(A+2); ASSERTKF(B+2); ASSERTF(C+2); + fbp = &konstf[B]; + fcp = ®.f[C]; + goto Do_SUBV; + + OP(DOTV_RR): + ASSERTF(a); ASSERTF(B+2); ASSERTF(C+2); + reg.f[a] = reg.f[B] * reg.f[C] + reg.f[B+1] * reg.f[C+1] + reg.f[B+2] * reg.f[C+2]; + NEXTOP; + OP(DOTV_RK): + ASSERTF(a); ASSERTF(B+2); ASSERTKF(C+2); + reg.f[a] = reg.f[B] * konstf[C] + reg.f[B+1] * konstf[C+1] + reg.f[B+2] * konstf[C+2]; + NEXTOP; + + OP(CROSSV_RR): + ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C+2); + fbp = ®.f[B]; + fcp = ®.f[C]; + Do_CROSSV: + { + double t[3]; + t[2] = fbp[0] * fcp[1] - fbp[1] * fcp[0]; + t[1] = fbp[2] * fcp[0] - fbp[0] * fcp[2]; + t[0] = fbp[1] * fcp[2] - fbp[2] * fcp[1]; + reg.f[a] = t[0]; reg.f[a+1] = t[1]; reg.f[a+2] = t[2]; + } + NEXTOP; + OP(CROSSV_RK): + ASSERTF(a+2); ASSERTF(B+2); ASSERTKF(C+2); + fbp = ®.f[B]; + fcp = &konstf[C]; + goto Do_CROSSV; + OP(CROSSV_KR): + ASSERTF(a+2); ASSERTKF(B+2); ASSERTF(C+2); + fbp = ®.f[B]; + fcp = &konstf[C]; + goto Do_CROSSV; + + OP(MULVF_RR): + ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C); + fc = reg.f[C]; + fbp = ®.f[B]; + Do_MULV: + reg.f[a] = fbp[0] * fc; + reg.f[a+1] = fbp[1] * fc; + reg.f[a+2] = fbp[2] * fc; + NEXTOP; + OP(MULVF_RK): + ASSERTF(a+2); ASSERTF(B+2); ASSERTKF(C); + fc = konstf[C]; + fbp = ®.f[B]; + goto Do_MULV; + OP(MULVF_KR): + ASSERTF(a+2); ASSERTKF(B+2); ASSERTF(C); + fc = reg.f[C]; + fbp = &konstf[B]; + goto Do_MULV; + + OP(LENV): + ASSERTF(a); ASSERTF(B+2); + reg.f[a] = sqrt(reg.f[B] * reg.f[B] + reg.f[B+1] * reg.f[B+1] + reg.f[B+2] * reg.f[B+2]); + NEXTOP; + + OP(EQV_R): + ASSERTF(B+2); ASSERTF(C+2); + fcp = ®.f[C]; + Do_EQV: + if (a & CMP_APPROX) + { + CMPJMP(fabs(reg.f[B ] - fcp[0]) < VM_EPSILON && + fabs(reg.f[B+1] - fcp[1]) < VM_EPSILON && + fabs(reg.f[B+2] - fcp[2]) < VM_EPSILON); + } + else + { + CMPJMP(reg.f[B] == fcp[0] && reg.f[B+1] == fcp[1] && reg.f[B+2] == fcp[2]); + } + NEXTOP; + OP(EQV_K): + ASSERTF(B+2); ASSERTKF(C+2); + fcp = &konstf[C]; + goto Do_EQV; + + OP(ADDA_RR): + ASSERTA(a); ASSERTA(B); ASSERTD(C); + c = reg.d[C]; + Do_ADDA: + if (reg.a[B] == NULL) // Leave NULL pointers as NULL pointers + { + c = 0; + } + reg.a[a] = (VM_UBYTE *)reg.a[B] + c; + reg.atag[a] = c == 0 ? reg.atag[B] : (int)ATAG_GENERIC; + NEXTOP; + OP(ADDA_RK): + ASSERTA(a); ASSERTA(B); ASSERTKD(C); + c = konstd[C]; + goto Do_ADDA; + + OP(SUBA): + ASSERTD(a); ASSERTA(B); ASSERTA(C); + reg.d[a] = (VM_UWORD)((VM_UBYTE *)reg.a[B] - (VM_UBYTE *)reg.a[C]); + NEXTOP; + + OP(EQA_R): + ASSERTA(B); ASSERTA(C); + CMPJMP(reg.a[B] == reg.a[C]); + NEXTOP; + OP(EQA_K): + ASSERTA(B); ASSERTKA(C); + CMPJMP(reg.a[B] == konsta[C].v); + NEXTOP; + + OP(NOP): + NEXTOP; + } + } + catch(VMException *exception) + { + // Try to find a handler for the exception. + PClass *extype = exception->GetClass(); + + while(--try_depth >= 0) + { + pc = exception_frames[try_depth]; + assert(pc->op == OP_CATCH); + while (pc->a > 1) + { + // CATCH must be followed by JMP if it doesn't terminate a catch chain. + assert(pc[1].op == OP_JMP); + + PClass *type; + int b = pc->b; + + if (pc->a == 2) + { + ASSERTA(b); + type = (PClass *)reg.a[b]; + } + else + { + assert(pc->a == 3); + ASSERTKA(b); + assert(konstatag[b] == ATAG_OBJECT); + type = (PClass *)konsta[b].o; + } + ASSERTA(pc->c); + if (type == extype) + { + // Found a handler. Store the exception in pC, skip the JMP, + // and begin executing its code. + reg.a[pc->c] = exception; + reg.atag[pc->c] = ATAG_OBJECT; + pc += 2; + goto begin; + } + // This catch didn't handle it. Try the next one. + pc += 1 + JMPOFS(pc + 1); + assert(pc->op == OP_CATCH); + } + if (pc->a == 1) + { + // Catch any type of VMException. This terminates the chain. + ASSERTA(pc->c); + reg.a[pc->c] = exception; + reg.atag[pc->c] = ATAG_OBJECT; + pc += 1; + goto begin; + } + // This frame failed. Try the next one out. + } + // Nothing caught it. Rethrow and let somebody else deal with it. + throw; + } + return 0; +} + +static double DoFLOP(int flop, double v) +{ + switch(flop) + { + case FLOP_ABS: return fabs(v); + case FLOP_NEG: return -v; + case FLOP_EXP: return exp(v); + case FLOP_LOG: return log(v); + case FLOP_LOG10: return log10(v); + case FLOP_SQRT: return sqrt(v); + case FLOP_CEIL: return ceil(v); + case FLOP_FLOOR: return floor(v); + + case FLOP_ACOS: return acos(v); + case FLOP_ASIN: return asin(v); + case FLOP_ATAN: return atan(v); + case FLOP_COS: return cos(v); + case FLOP_SIN: return sin(v); + case FLOP_TAN: return tan(v); + + case FLOP_ACOS_DEG: return acos(v) * (180 / M_PI); + case FLOP_ASIN_DEG: return asin(v) * (180 / M_PI); + case FLOP_ATAN_DEG: return atan(v) * (180 / M_PI); + case FLOP_COS_DEG: return cos(v * (M_PI / 180)); + case FLOP_SIN_DEG: return sin(v * (M_PI / 180)); + case FLOP_TAN_DEG: return tan(v * (M_PI / 180)); + + case FLOP_COSH: return cosh(v); + case FLOP_SINH: return sinh(v); + case FLOP_TANH: return tanh(v); + } + assert(0); + return 0; +} + +static void DoCast(const VMRegisters ®, const VMFrame *f, int a, int b, int cast) +{ + switch (cast) + { + case CAST_I2F: + ASSERTF(a); ASSERTD(b); + reg.f[a] = reg.d[b]; + break; + case CAST_I2S: + ASSERTS(a); ASSERTD(b); + reg.s[a].Format("%d", reg.d[b]); + break; + + case CAST_F2I: + ASSERTD(a); ASSERTF(b); + reg.d[a] = (int)reg.f[b]; + break; + case CAST_F2S: + ASSERTS(a); ASSERTD(b); + reg.s[a].Format("%.14g", reg.f[b]); + break; + + case CAST_P2S: + ASSERTS(a); ASSERTA(b); + reg.s[a].Format("%s<%p>", reg.atag[b] == ATAG_OBJECT ? "Object" : "Pointer", reg.a[b]); + break; + + case CAST_S2I: + ASSERTD(a); ASSERTS(b); + reg.d[a] = (VM_SWORD)reg.s[b].ToLong(); + break; + case CAST_S2F: + ASSERTF(a); ASSERTS(b); + reg.f[a] = reg.s[b].ToDouble(); + break; + + default: + assert(0); + } +} + +//=========================================================================== +// +// FillReturns +// +// Fills in an array of pointers to locations to store return values in. +// +//=========================================================================== + +static void FillReturns(const VMRegisters ®, VMFrame *frame, VMReturn *returns, const VMOP *retval, int numret) +{ + int i, type, regnum; + VMReturn *ret; + + assert(REGT_INT == 0 && REGT_FLOAT == 1 && REGT_STRING == 2 && REGT_POINTER == 3); + + for (i = 0, ret = returns; i < numret; ++i, ++ret, ++retval) + { + assert(retval->op == OP_RESULT); // opcode + ret->TagOfs = 0; + ret->RegType = type = retval->b; + regnum = retval->c; + assert(!(type & REGT_KONST)); + type &= REGT_TYPE; + if (type < REGT_STRING) + { + if (type == REGT_INT) + { + assert(regnum < frame->NumRegD); + ret->Location = ®.d[regnum]; + } + else // type == REGT_FLOAT + { + assert(regnum < frame->NumRegF); + ret->Location = ®.f[regnum]; + } + } + else if (type == REGT_STRING) + { + assert(regnum < frame->NumRegS); + ret->Location = ®.s[regnum]; + } + else + { + assert(type == REGT_POINTER); + assert(regnum < frame->NumRegA); + ret->Location = ®.a[regnum]; + ret->TagOfs = (VM_SHALF)(&frame->GetRegATag()[regnum] - (VM_ATAG *)ret->Location); + } + } +} + +//=========================================================================== +// +// SetReturn +// +// Used by script code to set a return value. +// +//=========================================================================== + +static void SetReturn(const VMRegisters ®, VMFrame *frame, VMReturn *ret, VM_UBYTE regtype, int regnum) +{ + const void *src; + VMScriptFunction *func = static_cast(frame->Func); + + assert(func != NULL && !func->Native); + assert((regtype & ~REGT_KONST) == ret->RegType); + + switch (regtype & REGT_TYPE) + { + case REGT_INT: + assert(!(regtype & REGT_MULTIREG)); + if (regtype & REGT_KONST) + { + assert(regnum < func->NumKonstD); + src = &func->KonstD[regnum]; + } + else + { + assert(regnum < frame->NumRegD); + src = ®.d[regnum]; + } + ret->SetInt(*(int *)src); + break; + + case REGT_FLOAT: + if (regtype & REGT_KONST) + { + assert(regnum + ((regtype & REGT_KONST) ? 2u : 0u) < func->NumKonstF); + src = &func->KonstF[regnum]; + } + else + { + assert(regnum + ((regtype & REGT_KONST) ? 2u : 0u) < frame->NumRegF); + src = ®.f[regnum]; + } + if (regtype & REGT_MULTIREG) + { + ret->SetVector((double *)src); + } + else + { + ret->SetFloat(*(double *)src); + } + break; + + case REGT_STRING: + assert(!(regtype & REGT_MULTIREG)); + if (regtype & REGT_KONST) + { + assert(regnum < func->NumKonstS); + src = &func->KonstS[regnum]; + } + else + { + assert(regnum < frame->NumRegS); + src = ®.s[regnum]; + } + ret->SetString(*(const FString *)src); + break; + + case REGT_POINTER: + assert(!(regtype & REGT_MULTIREG)); + if (regtype & REGT_KONST) + { + assert(regnum < func->NumKonstA); + ret->SetPointer(func->KonstA[regnum].v, func->KonstATags()[regnum]); + } + else + { + assert(regnum < frame->NumRegA); + ret->SetPointer(reg.a[regnum], reg.atag[regnum]); + } + break; + } +} diff --git a/src/zscript/vmframe.cpp b/src/zscript/vmframe.cpp new file mode 100644 index 0000000000..82affc0531 --- /dev/null +++ b/src/zscript/vmframe.cpp @@ -0,0 +1,416 @@ +#include +#include "vm.h" + +IMPLEMENT_CLASS(VMException) +IMPLEMENT_ABSTRACT_CLASS(VMFunction) +IMPLEMENT_CLASS(VMScriptFunction) +IMPLEMENT_CLASS(VMNativeFunction) + +VMScriptFunction::VMScriptFunction(FName name) +{ + Native = false; + Name = name; + Code = NULL; + KonstD = NULL; + KonstF = NULL; + KonstS = NULL; + KonstA = NULL; + ExtraSpace = 0; + CodeSize = 0; + NumRegD = 0; + NumRegF = 0; + NumRegS = 0; + NumRegA = 0; + NumKonstD = 0; + NumKonstF = 0; + NumKonstS = 0; + NumKonstA = 0; + MaxParam = 0; + NumArgs = 0; +} + +VMScriptFunction::~VMScriptFunction() +{ + if (Code != NULL) + { + if (KonstS != NULL) + { + for (int i = 0; i < NumKonstS; ++i) + { + KonstS[i].~FString(); + } + } + M_Free(Code); + } +} + +void VMScriptFunction::Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta) +{ + assert(Code == NULL); + assert(numops > 0); + assert(numkonstd >= 0 && numkonstd <= 255); + assert(numkonstf >= 0 && numkonstf <= 255); + assert(numkonsts >= 0 && numkonsts <= 255); + assert(numkonsta >= 0 && numkonsta <= 255); + void *mem = M_Malloc(numops * sizeof(VMOP) + + numkonstd * sizeof(int) + + numkonstf * sizeof(double) + + numkonsts * sizeof(FString) + + numkonsta * (sizeof(FVoidObj) + 1)); + Code = (VMOP *)mem; + mem = (void *)((VMOP *)mem + numops); + + if (numkonstd > 0) + { + KonstD = (int *)mem; + mem = (void *)((int *)mem + numkonstd); + } + else + { + KonstD = NULL; + } + if (numkonstf > 0) + { + KonstF = (double *)mem; + mem = (void *)((double *)mem + numkonstf); + } + else + { + KonstF = NULL; + } + if (numkonsts > 0) + { + KonstS = (FString *)mem; + for (int i = 0; i < numkonsts; ++i) + { + ::new(&KonstS[i]) FString; + } + mem = (void *)((FString *)mem + numkonsts); + } + else + { + KonstS = NULL; + } + if (numkonsta > 0) + { + KonstA = (FVoidObj *)mem; + } + else + { + KonstA = NULL; + } + CodeSize = numops; + NumKonstD = numkonstd; + NumKonstF = numkonstf; + NumKonstS = numkonsts; + NumKonstA = numkonsta; +} + +size_t VMScriptFunction::PropagateMark() +{ + if (KonstA != NULL) + { + FVoidObj *konsta = KonstA; + VM_UBYTE *atag = KonstATags(); + for (int count = NumKonstA; count > 0; --count) + { + if (*atag++ == ATAG_OBJECT) + { + GC::Mark(konsta->o); + } + konsta++; + } + } + return NumKonstA * sizeof(void *) + Super::PropagateMark(); +} + +//=========================================================================== +// +// VMFrame :: InitRegS +// +// Initialize the string registers of a newly-allocated VMFrame. +// +//=========================================================================== + +void VMFrame::InitRegS() +{ + FString *regs = GetRegS(); + for (int i = 0; i < NumRegS; ++i) + { + ::new(®s[i]) FString; + } +} + +//=========================================================================== +// +// VMFrameStack - Constructor +// +//=========================================================================== + +VMFrameStack::VMFrameStack() +{ + Blocks = NULL; + UnusedBlocks = NULL; +} + +//=========================================================================== +// +// VMFrameStack - Destructor +// +//=========================================================================== + +VMFrameStack::~VMFrameStack() +{ + while (PopFrame() != NULL) + { } + if (Blocks != NULL) + { + BlockHeader *block, *next; + for (block = Blocks; block != NULL; block = next) + { + next = block->NextBlock; + delete[] (VM_UBYTE *)block; + } + } + if (UnusedBlocks != NULL) + { + BlockHeader *block, *next; + for (block = UnusedBlocks; block != NULL; block = next) + { + next = block->NextBlock; + delete[] (VM_UBYTE *)block; + } + } + Blocks = NULL; + UnusedBlocks = NULL; +} + +//=========================================================================== +// +// VMFrameStack :: AllocFrame +// +// Allocates a frame from the stack with the desired number of registers. +// +//=========================================================================== + +VMFrame *VMFrameStack::AllocFrame(int numregd, int numregf, int numregs, int numrega) +{ + assert((unsigned)numregd < 255); + assert((unsigned)numregf < 255); + assert((unsigned)numregs < 255); + assert((unsigned)numrega < 255); + // To keep the arguments to this function simpler, it assumes that every + // register might be used as a parameter for a single call. + int numparam = numregd + numregf + numregs + numrega; + int size = VMFrame::FrameSize(numregd, numregf, numregs, numrega, numparam, 0); + VMFrame *frame = Alloc(size); + frame->NumRegD = numregd; + frame->NumRegF = numregf; + frame->NumRegS = numregs; + frame->NumRegA = numrega; + frame->MaxParam = numparam; + frame->InitRegS(); + return frame; +} + +//=========================================================================== +// +// VMFrameStack :: AllocFrame +// +// Allocates a frame from the stack suitable for calling a particular +// function. +// +//=========================================================================== + +VMFrame *VMFrameStack::AllocFrame(VMScriptFunction *func) +{ + int size = VMFrame::FrameSize(func->NumRegD, func->NumRegF, func->NumRegS, func->NumRegA, + func->MaxParam, func->ExtraSpace); + VMFrame *frame = Alloc(size); + frame->Func = func; + frame->NumRegD = func->NumRegD; + frame->NumRegF = func->NumRegF; + frame->NumRegS = func->NumRegS; + frame->NumRegA = func->NumRegA; + frame->MaxParam = func->MaxParam; + frame->Func = func; + frame->InitRegS(); + return frame; +} + +//=========================================================================== +// +// VMFrameStack :: Alloc +// +// Allocates space for a frame. Its size will be rounded up to a multiple +// of 16 bytes. +// +//=========================================================================== + +VMFrame *VMFrameStack::Alloc(int size) +{ + BlockHeader *block; + VMFrame *frame, *parent; + + size = (size + 15) & ~15; + block = Blocks; + if (block != NULL) + { + parent = block->LastFrame; + } + else + { + parent = NULL; + } + if (block == NULL || ((VM_UBYTE *)block + block->BlockSize) < (block->FreeSpace + size)) + { // Not enough space. Allocate a new block. + int blocksize = ((sizeof(BlockHeader) + 15) & ~15) + size; + BlockHeader **blockp; + if (blocksize < BLOCK_SIZE) + { + blocksize = BLOCK_SIZE; + } + for (blockp = &UnusedBlocks, block = *blockp; block != NULL; block = block->NextBlock) + { + if (block->BlockSize >= blocksize) + { + break; + } + } + if (block != NULL) + { + *blockp = block->NextBlock; + } + else + { + block = (BlockHeader *)new VM_UBYTE[blocksize]; + block->BlockSize = blocksize; + } + block->InitFreeSpace(); + block->LastFrame = NULL; + block->NextBlock = Blocks; + Blocks = block; + } + frame = (VMFrame *)block->FreeSpace; + memset(frame, 0, size); + frame->ParentFrame = parent; + block->FreeSpace += size; + block->LastFrame = frame; + return frame; +} + + +//=========================================================================== +// +// VMFrameStack :: PopFrame +// +// Pops the top frame off the stack, returning a pointer to the new top +// frame. +// +//=========================================================================== + +VMFrame *VMFrameStack::PopFrame() +{ + if (Blocks == NULL) + { + return NULL; + } + VMFrame *frame = Blocks->LastFrame; + if (frame == NULL) + { + return NULL; + } + // Free any string registers this frame had. + FString *regs = frame->GetRegS(); + for (int i = frame->NumRegS; i != 0; --i) + { + (regs++)->~FString(); + } + // Free any parameters this frame left behind. + VMValue *param = frame->GetParam(); + for (int i = frame->NumParam; i != 0; --i) + { + (param++)->~VMValue(); + } + VMFrame *parent = frame->ParentFrame; + if (parent == NULL) + { + // Popping the last frame off the stack. + if (Blocks != NULL) + { + assert(Blocks->NextBlock == NULL); + Blocks->LastFrame = NULL; + Blocks->InitFreeSpace(); + } + return NULL; + } + if ((VM_UBYTE *)parent < (VM_UBYTE *)Blocks || (VM_UBYTE *)parent >= (VM_UBYTE *)Blocks + Blocks->BlockSize) + { // Parent frame is in a different block, so move this one to the unused list. + BlockHeader *next = Blocks->NextBlock; + assert(next != NULL); + assert((VM_UBYTE *)parent >= (VM_UBYTE *)next && (VM_UBYTE *)parent < (VM_UBYTE *)next + next->BlockSize); + Blocks->NextBlock = UnusedBlocks; + UnusedBlocks = Blocks; + Blocks = next; + } + else + { + Blocks->LastFrame = parent; + Blocks->FreeSpace = (VM_UBYTE *)frame; + } + return parent; +} + +//=========================================================================== +// +// VMFrameStack :: Call +// +// Calls a function, either native or scripted. If an exception occurs while +// executing, the stack is cleaned up. If trap is non-NULL, it is set to the +// VMException that was caught and the return value is negative. Otherwise, +// any caught exceptions will be rethrown. Under normal termination, the +// return value is the number of results from the function. +// +//=========================================================================== + +int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMReturn *results, int numresults, VMException **trap) +{ + bool allocated = false; + try + { + if (func->Native) + { + return static_cast(func)->NativeCall(this, params, numparams, results, numresults); + } + else + { + AllocFrame(static_cast(func)); + allocated = true; + VMFillParams(params, TopFrame(), numparams); + int numret = VMExec(this, static_cast(func)->Code, results, numresults); + PopFrame(); + return numret; + } + } + catch (VMException *exception) + { + if (allocated) + { + PopFrame(); + } + if (trap != NULL) + { + *trap = exception; + return -1; + } + throw; + } + catch (...) + { + if (allocated) + { + PopFrame(); + } + throw; + } +} diff --git a/src/zscript/vmops.h b/src/zscript/vmops.h new file mode 100644 index 0000000000..998a4eb0cf --- /dev/null +++ b/src/zscript/vmops.h @@ -0,0 +1,221 @@ +#ifndef xx +#define xx(op, name, mode) OP_##op +#endif + +xx(NOP, nop, NOP), // no operation + +// Load constants. +xx(LI, li, LI), // load immediate signed 16-bit constant +xx(LK, lk, LKI), // load integer constant +xx(LKF, lk, LKF), // load float constant +xx(LKS, lk, LKS), // load string constant +xx(LKP, lk, LKP), // load pointer constant +xx(LFP, lf, LFP), // load frame pointer + +// Load from memory. rA = *(rB + rkC) +xx(LB, lb, RIRPKI), // load byte +xx(LB_R, lb, RIRPRI), +xx(LH, lh, RIRPKI), // load halfword +xx(LH_R, lh, RIRPRI), +xx(LW, lw, RIRPKI), // load word +xx(LW_R, lw, RIRPRI), +xx(LBU, lbu, RIRPKI), // load byte unsigned +xx(LBU_R, lbu, RIRPRI), +xx(LHU, lhu, RIRPKI), // load halfword unsigned +xx(LHU_R, lhu, RIRPRI), +xx(LSP, lsp, RFRPKI), // load single-precision fp +xx(LSP_R, lsp, RFRPRI), +xx(LDP, ldp, RFRPKI), // load double-precision fp +xx(LDP_R, ldp, RFRPRI), +xx(LS, ls, RSRPKI), // load string +xx(LS_R, ls, RSRPRI), +xx(LO, lo, RPRPKI), // load object +xx(LO_R, lo, RPRPRI), +xx(LP, lp, RPRPKI), // load pointer +xx(LP_R, lp, RPRPRI), +xx(LV, lv, RVRPKI), // load vector +xx(LV_R, lv, RVRPRI), +xx(LX, lx, RFRPKI), // load fixed point +xx(LX_R, lx, RFRPRI), +xx(LANG, lang, RFRPKI), // load angle +xx(LANG_R, lang, RFRPRI), + +xx(LBIT, lbit, RIRPI8), // rA = !!(*rB & C) -- *rB is a byte + +// Store instructions. *(rA + rkC) = rB +xx(SB, sb, RPRIKI), // store byte +xx(SB_R, sb, RPRIRI), +xx(SH, sh, RPRIKI), // store halfword +xx(SH_R, sh, RPRIRI), +xx(SW, sw, RPRIKI), // store word +xx(SW_R, sw, RPRIRI), +xx(SSP, ssp, RPRFKI), // store single-precision fp +xx(SSP_R, ssp, RPRFRI), +xx(SDP, sdp, RPRFKI), // store double-precision fp +xx(SDP_R, sdp, RPRFRI), +xx(SS, ss, RPRSKI), // store string +xx(SS_R, ss, RPRSRI), +xx(SP, sp, RPRPKI), // store pointer +xx(SP_R, sp, RPRPRI), +xx(SV, sv, RPRVKI), // store vector +xx(SV_R, sv, RPRVRI), +xx(SX, sx, RPRFKI), // store fixed point +xx(SX_R, sx, RPRFRI), +xx(SANG, sang, RPRFKI), // store angle +xx(SANG_R, sang, RPRFRI), + +xx(SBIT, sbit, RPRII8), // *rA |= C if rB is true, *rA &= ~C otherwise + +// Move instructions. +xx(MOVE, mov, RIRI), // dA = dB +xx(MOVEF, mov, RFRF), // fA = fB +xx(MOVES, mov, RSRS), // sA = sB +xx(MOVEA, mov, RPRP), // aA = aB +xx(CAST, cast, CAST), // xA = xB, conversion specified by C +xx(DYNCAST_R, dyncast,RPRPRP), // aA = aB after casting to rkC (specifying a class) +xx(DYNCAST_K, dyncast,RPRPKP), + +// Control flow. +xx(TEST, test, RII16), // if (dA != BC) then pc++ +xx(JMP, jmp, I24), // pc += ABC -- The ABC fields contain a signed 24-bit offset. +xx(IJMP, ijmp, RII16), // pc += dA + BC -- BC is a signed offset. The target instruction must be a JMP. +xx(PARAM, param, __BCP), // push parameter encoded in BC for function call (B=regtype, C=regnum) +xx(PARAMI, parami, I24), // push immediate, signed integer for function call +xx(CALL, call, RPI8I8), // Call function pkA with parameter count B and expected result count C +xx(CALL_K, call, KPI8I8), +xx(TAIL, tail, RPI8), // Call+Ret in a single instruction +xx(TAIL_K, tail, KPI8), +xx(RESULT, result, __BCP), // Result should go in register encoded in BC (in caller, after CALL) +xx(RET, ret, I8BCP), // Copy value from register encoded in BC to return value A, possibly returning +xx(RETI, reti, I8I16), // Copy immediate from BC to return value A, possibly returning +xx(TRY, try, I24), // When an exception is thrown, start searching for a handler at pc + ABC +xx(UNTRY, untry, I8), // Pop A entries off the exception stack +xx(THROW, throw, THROW), // A == 0: Throw exception object pB + // A != 0: Throw exception object pkB +xx(CATCH, catch, CATCH), // A == 0: continue search on next try + // A == 1: continue execution at instruction immediately following CATCH (catches any exception) + // A == 2: (pB == ) then pc++ ; next instruction must JMP to another CATCH + // A == 3: (pkB == ) then pc++ ; next instruction must JMP to another CATCH + // for A > 0, exception is stored in pC +xx(BOUND, bound, RII16), // if rA >= BC, throw exception + +// String instructions. +xx(CONCAT, concat, RSRSRS), // sA = sB.. ... ..sC +xx(LENS, lens, RIRS), // dA = sB.Length +xx(CMPS, cmps, I8RXRX), // if ((skB op skC) != (A & 1)) then pc++ + +// Integer math. +xx(SLL_RR, sll, RIRIRI), // dA = dkB << diC +xx(SLL_RI, sll, RIRII8), +xx(SLL_KR, sll, RIKIRI), +xx(SRL_RR, srl, RIRIRI), // dA = dkB >> diC -- unsigned +xx(SRL_RI, srl, RIRII8), +xx(SRL_KR, srl, RIKIRI), +xx(SRA_RR, sra, RIRIRI), // dA = dkB >> diC -- signed +xx(SRA_RI, sra, RIRII8), +xx(SRA_KR, sra, RIKIRI), +xx(ADD_RR, add, RIRIRI), // dA = dB + dkC +xx(ADD_RK, add, RIRIKI), +xx(ADDI, addi, RIRIIs), // dA = dB + C -- C is a signed 8-bit constant +xx(SUB_RR, sub, RIRIRI), // dA = dkB - dkC +xx(SUB_RK, sub, RIRIKI), +xx(SUB_KR, sub, RIKIRI), +xx(MUL_RR, mul, RIRIRI), // dA = dB * dkC +xx(MUL_RK, mul, RIRIKI), +xx(DIV_RR, div, RIRIRI), // dA = dkB / dkC +xx(DIV_RK, div, RIRIKI), +xx(DIV_KR, div, RIKIRI), +xx(MOD_RR, mod, RIRIRI), // dA = dkB % dkC +xx(MOD_RK, mod, RIRIKI), +xx(MOD_KR, mod, RIKIRI), +xx(AND_RR, and, RIRIRI), // dA = dB & dkC +xx(AND_RK, and, RIRIKI), +xx(OR_RR, or, RIRIRI), // dA = dB | dkC +xx(OR_RK, or, RIRIKI), +xx(XOR_RR, xor, RIRIRI), // dA = dB ^ dkC +xx(XOR_RK, xor, RIRIKI), +xx(MIN_RR, min, RIRIRI), // dA = min(dB,dkC) +xx(MIN_RK, min, RIRIKI), +xx(MAX_RR, max, RIRIRI), // dA = max(dB,dkC) +xx(MAX_RK, max, RIRIKI), +xx(ABS, abs, RIRI), // dA = abs(dB) +xx(NEG, neg, RIRI), // dA = -dB +xx(NOT, not, RIRI), // dA = ~dB +xx(SEXT, sext, RIRII8), // dA = dB, sign extended by shifting left then right by C +xx(ZAP_R, zap, RIRIRI), // dA = dB, with bytes zeroed where bits in C/dC are one +xx(ZAP_I, zap, RIRII8), +xx(ZAPNOT_R, zapnot, RIRIRI), // dA = dB, with bytes zeroed where bits in C/dC are zero +xx(ZAPNOT_I, zapnot, RIRII8), +xx(EQ_R, beq, CIRR), // if ((dB == dkC) != A) then pc++ +xx(EQ_K, beq, CIRK), +xx(LT_RR, blt, CIRR), // if ((dkB < dkC) != A) then pc++ +xx(LT_RK, blt, CIRK), +xx(LT_KR, blt, CIKR), +xx(LE_RR, ble, CIRR), // if ((dkB <= dkC) != A) then pc++ +xx(LE_RK, ble, CIRK), +xx(LE_KR, ble, CIKR), +xx(LTU_RR, bltu, CIRR), // if ((dkB < dkC) != A) then pc++ -- unsigned +xx(LTU_RK, bltu, CIRK), +xx(LTU_KR, bltu, CIKR), +xx(LEU_RR, bleu, CIRR), // if ((dkB <= dkC) != A) then pc++ -- unsigned +xx(LEU_RK, bleu, CIRK), +xx(LEU_KR, bleu, CIKR), + +// Double-precision floating point math. +xx(ADDF_RR, add, RFRFRF), // fA = fB + fkC +xx(ADDF_RK, add, RFRFKF), +xx(SUBF_RR, sub, RFRFRF), // fA = fkB - fkC +xx(SUBF_RK, sub, RFRFKF), +xx(SUBF_KR, sub, RFKFRF), +xx(MULF_RR, mul, RFRFRF), // fA = fB * fkC +xx(MULF_RK, mul, RFRFKF), +xx(DIVF_RR, div, RFRFRF), // fA = fkB / fkC +xx(DIVF_RK, div, RFRFKF), +xx(DIVF_KR, div, RFKFRF), +xx(MODF_RR, mod, RFRFRF), // fA = fkB % fkC +xx(MODF_RK, mod, RFRFKF), +xx(MODF_KR, mod, RFKFRF), +xx(POWF_RR, pow, RFRFRF), // fA = fkB ** fkC +xx(POWF_RK, pow, RFRFKF), +xx(POWF_KR, pow, RFKFRF), +xx(MINF_RR, min, RFRFRF), // fA = min(fB),fkC) +xx(MINF_RK, min, RFRFKF), +xx(MAXF_RR, max, RFRFRF), // fA = max(fB),fkC) +xx(MAXF_RK, max, RFRFKF), +xx(FLOP, flop, RFRFI8), // fA = f(fB), where function is selected by C +xx(EQF_R, beq, CFRR), // if ((fB == fkC) != (A & 1)) then pc++ +xx(EQF_K, beq, CFRK), +xx(LTF_RR, blt, CFRR), // if ((fkB < fkC) != (A & 1)) then pc++ +xx(LTF_RK, blt, CFRK), +xx(LTF_KR, blt, CFKR), +xx(LEF_RR, ble, CFRR), // if ((fkb <= fkC) != (A & 1)) then pc++ +xx(LEF_RK, ble, CFRK), +xx(LEF_KR, ble, CFKR), + +// Vector math. +xx(NEGV, negv, RVRV), // vA = -vB +xx(ADDV_RR, addv, RVRVRV), // vA = vB + vkC +xx(ADDV_RK, addv, RVRVKV), +xx(SUBV_RR, subv, RVRVRV), // vA = vkB - vkC +xx(SUBV_RK, subv, RVRVKV), +xx(SUBV_KR, subv, RVKVRV), +xx(DOTV_RR, dotv, RVRVRV), // va = vB dot vkC +xx(DOTV_RK, dotv, RVRVKV), +xx(CROSSV_RR, crossv, RVRVRV), // vA = vkB cross vkC +xx(CROSSV_RK, crossv, RVRVKV), +xx(CROSSV_KR, crossv, RVKVRV), +xx(MULVF_RR, mulv, RVRVRV), // vA = vkB * fkC +xx(MULVF_RK, mulv, RVRVKV), +xx(MULVF_KR, mulv, RVKVRV), +xx(LENV, lenv, RFRV), // fA = vB.Length +xx(EQV_R, beqv, CVRR), // if ((vB == vkC) != A) then pc++ (inexact if A & 32) +xx(EQV_K, beqv, CVRK), + +// Pointer math. +xx(ADDA_RR, add, RPRPRI), // pA = pB + dkC +xx(ADDA_RK, add, RPRPKI), +xx(SUBA, sub, RIRPRP), // dA = pB - pC +xx(EQA_R, beq, CPRR), // if ((pB == pkC) != A) then pc++ +xx(EQA_K, beq, CPRK), + +#undef xx diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon new file mode 100644 index 0000000000..6f3de56cb8 --- /dev/null +++ b/src/zscript/zcc-parse.lemon @@ -0,0 +1,1493 @@ +%include +{ +// Allocates a new AST node off the parse state's arena. +#define NEW_AST_NODE(type,name,tok) \ + ZCC_##type *name = static_cast(stat->InitNode(sizeof(ZCC_##type), AST_##type)); \ + SetNodeLine(name, tok) + +static void SetNodeLine(ZCC_TreeNode *name, ZCCToken &tok) +{ + name->SourceLoc = tok.SourceLoc; +} + +static void SetNodeLine(ZCC_TreeNode *name, ZCC_TreeNode *node) +{ + name->SourceLoc = node->SourceLoc; +} + +static void SetNodeLine(ZCC_TreeNode *name, int line) +{ + name->SourceLoc = line; +} + +// If a is non-null, appends b to a. Otherwise, sets a to b. +#define SAFE_APPEND(a,b) \ + if (a == NULL) a = b; else a->AppendSibling(b); + +#define UNARY_EXPR(X,T) NEW_AST_NODE(ExprUnary, expr1, X); expr1->Operation = T; expr1->Operand = X; expr1->Type = NULL +#define BINARY_EXPR(X,Y,T) NEW_AST_NODE(ExprBinary, expr2, X); expr2->Operation = T; expr2->Type = NULL; expr2->Left = X; expr2->Right = Y + +#define NEW_INTCONST_NODE(name,type,val,tok) \ + NEW_AST_NODE(ExprConstant, name, tok); \ + name->Operation = PEX_ConstValue; \ + name->Type = type; \ + name->IntVal = val + + struct ClassFlagsBlock { + VM_UWORD Flags; + ZCC_Identifier *Replaces; + }; + + struct StateOpts { + ZCC_Expression *Offset; + bool Bright; + }; + + struct VarOrFun + { + ZCC_VarName *VarNames; + ZCC_FuncParamDecl *FuncParams; + ZCC_CompoundStmt *FuncBody; + ENamedName FuncName; + int FuncFlags; + int SourceLoc; + }; +} + +%token_prefix ZCC_ +%token_type { ZCCToken } +%token_destructor {} // just to avoid a compiler warning +%name ZCCParse +%extra_argument { ZCCParseState *stat } +%syntax_error +{ + FString unexpected, expecting; + + int i; + int stateno = yypParser->yystack[yypParser->yyidx].stateno; + + unexpected << "Unexpected " << ZCCTokenName(yymajor); + + // Determine all the terminals that the parser would have accepted at this point + // (see yy_find_shift_action). This list can get quite long. Is it worthwhile to + // print it when not debugging the grammar, or would that be too confusing to + // the average user? + if (stateno < YY_SHIFT_MAX && (i = yy_shift_ofst[stateno])!=YY_SHIFT_USE_DFLT) + { + for (int j = 1; j < YYERRORSYMBOL; ++j) + { + int k = i + j; + if (k >= 0 && k < YY_SZ_ACTTAB && yy_lookahead[k] == j) + { + expecting << (expecting.IsEmpty() ? "Expecting " : " or ") << ZCCTokenName(j); + } + } + } + stat->sc.ScriptMessage("%s\n%s\n", unexpected.GetChars(), expecting.GetChars()); +} +%parse_accept { stat->sc.ScriptMessage("input accepted\n"); } +%parse_failure { /**failed = true;*/ } + +%nonassoc EQ MULEQ DIVEQ MODEQ ADDEQ SUBEQ LSHEQ RSHEQ ANDEQ OREQ XOREQ. +%right QUESTION COLON. +%left OROR. +%left ANDAND. +%left EQEQ NEQ APPROXEQ. +%left LT GT LTEQ GTEQ LTGTEQ IS. +%left DOTDOT. +%left OR. /* Note that this is like the Ruby precedence for these */ +%left XOR. /* three operators and not the C precedence, since */ +%left AND. /* they are higher priority than the comparisons. */ +%left LSH RSH. +%left SUB ADD. +%left MUL DIV MOD CROSSPROD DOTPROD. +%left POW. +%right UNARY ADDADD SUBSUB. +%left DOT LPAREN LBRACKET. +%left SCOPE. + +%type declarator {ZCC_Declarator *} +%type declarator_no_fun {ZCC_Declarator *} +%type opt_func_body {ZCC_CompoundStmt *} +%type function_body {ZCC_CompoundStmt *} + +main ::= translation_unit(A). { stat->TopNode = A; stat->sc.ScriptMessage("Parse complete\n"); } + +%type translation_unit {ZCC_TreeNode *} +translation_unit(X) ::= . { X = NULL; } +translation_unit(X) ::= translation_unit(A) external_declaration(B). { SAFE_APPEND(A,B); X = A; } +translation_unit(X) ::= translation_unit(A) EOF. { X = A; } +translation_unit(X) ::= error. { X = NULL; } + +%type external_declaration {ZCC_TreeNode *} +external_declaration(X) ::= class_definition(A). { X = A; } +external_declaration(X) ::= struct_def(A). { X = A; } +external_declaration(X) ::= enum_def(A). { X = A; } +external_declaration(X) ::= const_def(A). { X = A; } + +/* Optional bits. */ +opt_semicolon ::= . +opt_semicolon ::= SEMICOLON. + +opt_comma ::= . +opt_comma ::= COMMA. + +%type opt_expr{ZCC_Expression *} +opt_expr(X) ::= . +{ + X = NULL; +} +opt_expr(X) ::= expr(A). +{ + X = A; +} + + +/************ Class Definition ************/ +/* Can only occur at global scope. */ + +%type class_definition{ZCC_Class *} +%type class_head{ZCC_Class *} +%type class_innards{ZCC_TreeNode *} +%type class_member{ZCC_TreeNode *} +%type class_body{ZCC_TreeNode *} + +class_definition(X) ::= class_head(A) class_body(B). +{ + A->Body = B; + X = A; +} + +class_head(X) ::= CLASS(T) IDENTIFIER(A) class_ancestry(B) class_flags(C). +{ + NEW_AST_NODE(Class,head,T); + head->ClassName = A.Name(); + head->ParentName = B; + head->Flags = C.Flags; + head->Replaces = C.Replaces; + X = head; +} + +%type class_ancestry{ZCC_Identifier *} +class_ancestry(X) ::= . { X = NULL; } +class_ancestry(X) ::= COLON dottable_id(A). { X = A; } + +%type class_flags{ClassFlagsBlock} +class_flags(X) ::= . { X.Flags = 0; X.Replaces = NULL; } +class_flags(X) ::= class_flags(A) ABSTRACT. { X.Flags = A.Flags | 0/*FIXME*/; X.Replaces = A.Replaces; } +class_flags(X) ::= class_flags(A) NATIVE. { X.Flags = A.Flags | 0/*FIXME*/; X.Replaces = A.Replaces; } +class_flags(X) ::= class_flags(A) REPLACES dottable_id(B). { X.Flags = A.Flags; X.Replaces = B; } + +/*----- Dottable Identifier -----*/ +// This can be either a single identifier or two identifiers connected by a . + +%type dottable_id{ZCC_Identifier *} + +dottable_id(X) ::= IDENTIFIER(A). +{ + NEW_AST_NODE(Identifier,id,A); + id->Id = A.Name(); + X = id; +} +dottable_id(X) ::= dottable_id(A) DOT IDENTIFIER(B). +{ + NEW_AST_NODE(Identifier,id2,A); + id2->Id = B.Name(); + A->AppendSibling(id2); + X = A; +} + +/*------ Class Body ------*/ +// Body is a list of: +// * variable definitions +// * function definitions +// * enum definitions +// * struct definitions +// * state definitions +// * constants +// * defaults + +class_body(X) ::= SEMICOLON class_innards(A) EOF. { X = A; } +class_body(X) ::= LBRACE class_innards(A) RBRACE. { X = A; } + +class_innards(X) ::= . { X = NULL; } +class_innards(X) ::= class_innards(A) class_member(B). { SAFE_APPEND(A,B); X = A; } + +%type struct_def{ZCC_Struct *} +%type enum_def {ZCC_Enum *} +%type states_def {ZCC_States *} +%type const_def {ZCC_ConstantDef *} + +class_member(X) ::= declarator(A). { X = A; } +class_member(X) ::= enum_def(A). { X = A; } +class_member(X) ::= struct_def(A). { X = A; } +class_member(X) ::= states_def(A). { X = A; } +class_member(X) ::= default_def(A). { X = A; } +class_member(X) ::= const_def(A). { X = A; } + +/*----- Struct Definition -----*/ +/* Structs can define variables and enums. */ + +%type opt_struct_body{ZCC_TreeNode *} +%type struct_body{ZCC_TreeNode *} +%type struct_member{ZCC_TreeNode *} + +struct_def(X) ::= STRUCT(T) IDENTIFIER(A) LBRACE opt_struct_body(B) RBRACE opt_semicolon. +{ + NEW_AST_NODE(Struct,def,T); + def->StructName = A.Name(); + def->Body = B; + X = def; +} + +opt_struct_body(X) ::= . { X = NULL; } +opt_struct_body(X) ::= struct_body(A). { X = A; } + +struct_body(X) ::= error. { X = NULL; } +struct_body(X) ::= struct_member(A). { X = A; } +struct_body(X) ::= struct_member(A) struct_body(B). { X = A; A->AppendSibling(B); } + +struct_member(X) ::= declarator_no_fun(A). { X = A; } +struct_member(X) ::= enum_def(A). { X = A; } + +/*----- Constant Definition ------*/ +/* Like UnrealScript, a constant's type is implied by its value's type. */ +const_def(X) ::= CONST(T) IDENTIFIER(A) EQ expr(B) SEMICOLON. +{ + NEW_AST_NODE(ConstantDef,def,T); + def->Name = A.Name(); + def->Value = B; + def->Symbol = NULL; + X = def; +} + + +/*----- Enum Definition -----*/ +/* Enumerators are lists of named integers. */ + +%type enum_list {ZCC_ConstantDef *} +%type opt_enum_list {ZCC_ConstantDef *} +%type enumerator {ZCC_ConstantDef *} + +enum_def(X) ::= ENUM(T) IDENTIFIER(A) enum_type(B) LBRACE opt_enum_list(C) RBRACE(U) opt_semicolon. +{ + NEW_AST_NODE(Enum,def,T); + def->EnumName = A.Name(); + def->EnumType = (EZCCBuiltinType)B.Int; + def->Elements = C; + + // If the first element does not have an explicit value, make it 0. + if (C != NULL) + { + ZCC_ConstantDef *node = C, *prev = node; + + if (node->Value == NULL) + { + NEW_INTCONST_NODE(zero, TypeSInt32, 0, C); + node->Value = zero; + } + for (node = static_cast(node->SiblingNext); + node != C; + prev = node, node = static_cast(node->SiblingNext)) + { + assert(node->NodeType == AST_ConstantDef); + // Leave explicit values alone. + if (node->Value != NULL) + { + continue; + } + // Compute implicit values by adding one to the preceding value. + assert(prev->Value != NULL); + // If the preceding node is a constant, then we can do this now. + if (prev->Value->Operation == PEX_ConstValue && prev->Value->Type->IsA(RUNTIME_CLASS(PInt))) + { + NEW_INTCONST_NODE(cval, prev->Value->Type, static_cast(prev->Value)->IntVal + 1, node); + node->Value = cval; + } + // Otherwise, create a new addition expression to add 1. + else + { + NEW_INTCONST_NODE(one, TypeSInt32, 1, T); + NEW_AST_NODE(ExprID, label, node); + label->Operation = PEX_ID; + label->Identifier = prev->Name; + label->Type = NULL; + + BINARY_EXPR(label, one, PEX_Add); + node->Value = expr2; + } + } + // Add a new terminating node, to indicate that the ConstantDefs for this enum are done. + NEW_AST_NODE(EnumTerminator,term,U); + C->AppendSibling(term); + } + if (C != NULL) + { + def->AppendSibling(C); + } + X = def; +} + +enum_type(X) ::= . { X.Int = ZCC_IntAuto; X.SourceLoc = stat->sc.GetMessageLine(); } +enum_type(X) ::= COLON int_type(A). { X = A; } + +enum_list(X) ::= error. { X = NULL; } +enum_list(X) ::= enumerator(A). { X = A; } +enum_list(X) ::= enum_list(A) COMMA enumerator(B). { X = A; A->AppendSibling(B); } + +opt_enum_list(X) ::= . { X = NULL; } +opt_enum_list(X) ::= enum_list(A) opt_comma. { X = A; } + +enumerator(X) ::= IDENTIFIER(A). +{ + NEW_AST_NODE(ConstantDef,node,A); + node->Name = A.Name(); + node->Value = NULL; + node->Symbol = NULL; + X = node; +} +enumerator(X) ::= IDENTIFIER(A) EQ expr(B). /* Expression must be constant. */ +{ + NEW_AST_NODE(ConstantDef,node,A); + node->Name = A.Name(); + node->Value = B; + node->Symbol = NULL; + X = node; +} + +/************ States ************/ + +%type states_body {ZCC_StatePart *} +%type state_line {ZCC_StatePart *} +%type state_label {ZCC_StatePart *} +%type state_flow {ZCC_StatePart *} +%type state_flow_type {ZCC_StatePart *} +%type state_goto_offset {ZCC_Expression *} +%type state_action {ZCC_TreeNode *} +%type state_call {ZCC_ExprFuncCall *} +%type state_call_params {ZCC_FuncParm *} + +%type state_opts {StateOpts} + +states_def(X) ::= STATES(T) scanner_mode LBRACE states_body(A) RBRACE. +{ + NEW_AST_NODE(States,def,T); + def->Body = A; + X = def; +} + +/* We use a special scanner mode to allow for sprite names and frame characters + * to not be quoted even if they contain special characters. The scanner_mode + * nonterminal is used to enter this mode. The scanner automatically leaves it + * upon pre-defined conditions. See the comments by FScanner::SetStateMode(). + * + * Note that rules are reduced *after* one token of lookahead has been + * consumed, so this nonterminal must be placed one token before we want it to + * take effect. For example, in states_def above, the scanner mode will be + * set immediately after LBRACE is consumed, rather than immediately after + * STATES is consumed. + */ +scanner_mode ::= . { stat->sc.SetStateMode(true); } + +states_body(X) ::= . { X = NULL; } +states_body(X) ::= error. { X = NULL; } +states_body(X) ::= states_body(A) state_line(B). { SAFE_APPEND(A,B); X = A; } +states_body(X) ::= states_body(A) state_label(B). { SAFE_APPEND(A,B); X = A; } +states_body(X) ::= states_body(A) state_flow(B). { SAFE_APPEND(A,B); X = A; } + +state_label(X) ::= NWS(A) COLON. +{ + NEW_AST_NODE(StateLabel, label, A); + label->Label = A.Name(); + X = label; +} + +state_flow(X) ::= state_flow_type(A) scanner_mode SEMICOLON. { X = A; } + +state_flow_type(X) ::= STOP(A). { NEW_AST_NODE(StateStop, flow, A); X = flow; } +state_flow_type(X) ::= WAIT(A). { NEW_AST_NODE(StateWait, flow, A); X = flow; } +state_flow_type(X) ::= FAIL(A). { NEW_AST_NODE(StateFail, flow, A); X = flow; } +state_flow_type(X) ::= LOOP(A). { NEW_AST_NODE(StateLoop, flow, A); X = flow; } +state_flow_type(X) ::= GOTO(T) dottable_id(A) state_goto_offset(B). +{ + NEW_AST_NODE(StateGoto, flow, T); + flow->Label = A; + flow->Offset = B; + X = flow; +} + +state_goto_offset(X) ::= . { X = NULL; } +state_goto_offset(X) ::= PLUS expr(A). { X = A; } /* Must evaluate to a non-negative integer constant. */ + +state_line(X) ::= NWS(A) NWS(B) expr state_opts(C) state_action(D). +{ + NEW_AST_NODE(StateLine, line, A); + const char *sprite = FName(A.Name()).GetChars(); + if (strlen(sprite) != 4) + { + Printf("Sprite name '%s' must be four characters", sprite); + } + else + { + memcpy(line->Sprite, sprite, 4); + } + line->Frames = stat->Strings.Alloc(FName(B.Name()).GetChars()); + line->bBright = C.Bright; + line->Offset = C.Offset; + line->Action = D; + X = line; +} + +state_opts(X) ::= . { StateOpts opts; opts.Offset = NULL; opts.Bright = false; X = opts; } +state_opts(X) ::= state_opts(A) BRIGHT. { A.Bright = true; X = A; } +state_opts(X) ::= state_opts(A) OFFSET LPAREN expr(B) COMMA expr(C) RPAREN. { A.Offset = B; B->AppendSibling(C); X = A; } +state_opts(X) ::= state_opts(A) LIGHT LPAREN light_list RPAREN. { X = A; } + +light_list ::= STRCONST. +light_list ::= light_list COMMA STRCONST. + +/* A state action can be either a compound statement or a single action function call. */ +state_action(X) ::= LBRACE statement_list(A) scanner_mode RBRACE. { X = A; } +state_action(X) ::= LBRACE error scanner_mode RBRACE. { X = NULL; } +state_action(X) ::= state_call(A) scanner_mode SEMICOLON. { X = A; } + +state_call(X) ::= . { X = NULL; } +state_call(X) ::= IDENTIFIER(A) state_call_params(B). +{ + NEW_AST_NODE(ExprFuncCall, expr, A); + NEW_AST_NODE(ExprID, func, A); + + func->Operation = PEX_ID; + func->Identifier = A.Name(); + expr->Operation = PEX_FuncCall; + expr->Function = func; + expr->Parameters = B; + X = expr; +} + +state_call_params(X) ::= . { X = NULL; } +state_call_params(X) ::= LPAREN func_expr_list(A) RPAREN. { X = A; } + +/* Definition of a default class instance. */ +%type default_def {ZCC_CompoundStmt *} +default_def(X) ::= DEFAULT compound_statement(A). { X = A; } + +/* Type names */ +%type type_name {ZCC_BasicType *} + +int_type(X) ::= SBYTE(T). { X.Int = ZCC_SInt8; X.SourceLoc = T.SourceLoc; } +int_type(X) ::= BYTE(T). { X.Int = ZCC_UInt8; X.SourceLoc = T.SourceLoc; } +int_type(X) ::= SHORT(T). { X.Int = ZCC_SInt16; X.SourceLoc = T.SourceLoc; } +int_type(X) ::= USHORT(T). { X.Int = ZCC_UInt16; X.SourceLoc = T.SourceLoc; } +int_type(X) ::= INT(T). { X.Int = ZCC_SInt32; X.SourceLoc = T.SourceLoc; } +int_type(X) ::= UINT(T). { X.Int = ZCC_UInt32; X.SourceLoc = T.SourceLoc; } + +type_name1(X) ::= BOOL(T). { X.Int = ZCC_Bool; X.SourceLoc = T.SourceLoc; } +type_name1(X) ::= int_type(A). { X = A; } +type_name1(X) ::= FLOAT(T). { X.Int = ZCC_FloatAuto; X.SourceLoc = T.SourceLoc; } +type_name1(X) ::= DOUBLE(T). { X.Int = ZCC_Float64; X.SourceLoc = T.SourceLoc; } +type_name1(X) ::= STRING(T). { X.Int = ZCC_String; X.SourceLoc = T.SourceLoc; } +type_name1(X) ::= VECTOR(T) vector_size(A). { X.Int = A.Int; X.SourceLoc = T.SourceLoc; } +type_name1(X) ::= NAME(T). { X.Int = ZCC_Name; X.SourceLoc = T.SourceLoc; } + +type_name(X) ::= type_name1(A). +{ + NEW_AST_NODE(BasicType, type, A); + type->Type = (EZCCBuiltinType)A.Int; + type->UserType = NULL; + X = type; +} +type_name(X) ::= IDENTIFIER(A). /* User-defined type (struct, enum, or class) */ +{ + NEW_AST_NODE(BasicType, type, A); + NEW_AST_NODE(Identifier, id, A); + type->Type = ZCC_UserType; + type->UserType = id; + id->Id = A.Name(); + X = type; +} +type_name(X) ::= DOT dottable_id(A). +{ + NEW_AST_NODE(BasicType, type, A); + type->Type = ZCC_UserType; + type->UserType = A; + X = type; +} + +/* Vectors can be 2, 3, or 4 entries long. Default is a 3D vector. + * (Well, actually, I'm not sure if 4D ones are going to happen + * straight away.) + */ +vector_size(X) ::= . { X.Int = ZCC_Vector3; X.SourceLoc = stat->sc.GetMessageLine(); } +vector_size(X) ::= LT intconst(A) GT. +{ + if (A.Int >= 2 && A.Int <= 4) + { + X.Int = ZCC_Vector2 + A.Int - 2; + } + else + { + X.Int = ZCC_Vector3; + stat->sc.ScriptMessage("Invalid vector size %d\n", A.Int); + } + X.SourceLoc = A.SourceLoc; +} +intconst(X) ::= INTCONST(A). { X = A; } +intconst(X) ::= UINTCONST(A). { X = A; } + +/* Type names can also be used as identifiers in contexts where type names + * are not normally allowed. */ +%fallback IDENTIFIER + SBYTE BYTE SHORT USHORT INT UINT BOOL FLOAT DOUBLE STRING VECTOR NAME MAP ARRAY VOID. + +/* Aggregate types */ +%type aggregate_type {ZCC_Type *} +%type type {ZCC_Type *} +%type type_list {ZCC_Type *} +%type type_list_or_void {ZCC_Type *} +%type type_or_array {ZCC_Type *} +%type class_restrictor {ZCC_Identifier *} +%type array_size{ZCC_Expression *} +%type array_size_expr{ZCC_Expression *} + +aggregate_type(X) ::= MAP(T) LT type_or_array(A) COMMA type_or_array(B) GT. /* Hash table */ +{ + NEW_AST_NODE(MapType,map,T); + map->KeyType = A; + map->ValueType = B; + X = map; +} + +aggregate_type(X) ::= ARRAY(T) LT type_or_array(A) GT. /* TArray */ +{ + NEW_AST_NODE(DynArrayType,arr,T); + arr->ElementType = A; + X = arr; +} + +aggregate_type(X) ::= CLASS(T) class_restrictor(A). /* class */ +{ + NEW_AST_NODE(ClassType,cls,T); + cls->Restriction = A; + X = cls; +} +class_restrictor(X) ::= . { X = NULL; } +class_restrictor(X) ::= LT dottable_id(A) GT. { X = A; } + +type(X) ::= type_name(A). { X = A; A->ArraySize = NULL; } +type(X) ::= aggregate_type(A). { X = A; A->ArraySize = NULL; } + +type_or_array(X) ::= type(A). { X = A; } +type_or_array(X) ::= type(A) array_size(B). { X = A; A->ArraySize = B; } + +type_list(X) ::= type_or_array(A). { X = A; }/* A comma-separated list of types */ +type_list(X) ::= type_list(A) COMMA type_or_array(B). { X = A; A->AppendSibling(B); } + +type_list_or_void(X) ::= VOID. { X = NULL; } +type_list_or_void(X) ::= type_list(A). { X = A; } + +array_size_expr(X) ::= LBRACKET opt_expr(A) RBRACKET. +{ + if (A == NULL) + { + NEW_AST_NODE(Expression,nil,A); + nil->Operation = PEX_Nil; + nil->Type = NULL; + X = nil; + } + else + { + X = A; + } +} +array_size(X) ::= array_size_expr(A). +{ + X = A; +} +array_size(X) ::= array_size(A) array_size_expr(B). +{ + A->AppendSibling(B); + X = A; +} + +%type variables_or_function {VarOrFun} + +/* Multiple type names are only valid for functions. */ +declarator(X) ::= decl_flags(A) type_list_or_void(B) variables_or_function(C). +{ + if (C.FuncName == NAME_None && C.VarNames == NULL) + { // An error. A message was already printed. + X = NULL; + } + else if (C.FuncName != NAME_None) + { // A function + NEW_AST_NODE(FuncDeclarator, decl, A.SourceLoc); + decl->Type = B; + decl->Params = C.FuncParams; + decl->Name = C.FuncName; + decl->Flags = A.Int | C.FuncFlags; + decl->Body = C.FuncBody; + X = decl; + } + else if (B != NULL && B->SiblingNext == B) + { // A variable + NEW_AST_NODE(VarDeclarator, decl, A.SourceLoc); + decl->Type = B; + decl->Names = C.VarNames; + decl->Flags = A.Int; + X = decl; + } + else + { // An invalid + if (B == NULL) + { + stat->sc.ScriptMessage("Variables may not be of type void.\n"); + } + else + { + stat->sc.ScriptMessage("Variables may be of only one type.\n"); + } + X = NULL; + } +} +declarator_no_fun(X) ::= decl_flags(A) type(B) variable_list(C). +{ + NEW_AST_NODE(VarDeclarator, decl, A.SourceLoc ? A.SourceLoc : B->SourceLoc); + decl->Type = B; + decl->Names = C; + decl->Flags = A.Int; + X = decl; +} + +// Need to split it up like this to avoid parsing conflicts. +variables_or_function(X) ::= IDENTIFIER(A) LPAREN func_params(B) RPAREN func_const(C) opt_func_body(D). /* Function */ +{ + VarOrFun fun; + + fun.VarNames = NULL; + fun.FuncParams = B; + fun.FuncFlags = C.Int; + fun.FuncName = A.Name(); + fun.FuncBody = D; + fun.SourceLoc = A.SourceLoc; + X = fun; +} +variables_or_function(X) ::= variable_list(A) SEMICOLON. +{ + VarOrFun var; + + var.VarNames = A; + var.FuncParams = NULL; + var.FuncFlags = 0; + var.FuncName = NAME_None; + var.FuncBody = NULL; + var.SourceLoc = A->SourceLoc; + X = var; +} +variables_or_function(X) ::= error SEMICOLON(T). +{ + VarOrFun bad; + bad.VarNames = NULL; + bad.FuncParams = NULL; + bad.FuncFlags = 0; + bad.FuncName = NAME_None; + bad.FuncBody = NULL; + bad.SourceLoc = T.SourceLoc; + X = bad; +} + +/*----- Variable Names -----*/ + +%type variable_name{ZCC_VarName *} +%type variable_list{ZCC_VarName *} + +variable_name(X) ::= IDENTIFIER(A). +{ + NEW_AST_NODE(VarName,var,A); + var->Name = ENamedName(A.Int); + var->ArraySize = NULL; + X = var; +} +variable_name(X) ::= IDENTIFIER(A) array_size(B). +{ + NEW_AST_NODE(VarName,var,A); + var->Name = ENamedName(A.Int); + var->ArraySize = B; + X = var; +} + +variable_list(X) ::= variable_name(A). +{ + X = A; +} +variable_list(X) ::= variable_list(A) COMMA variable_name(B). +{ + A->AppendSibling(B); + X = A; +} + +decl_flags(X) ::= . { X.Int = 0; X.SourceLoc = 0; } +decl_flags(X) ::= decl_flags(A) NATIVE(T). { X.Int = A.Int | ZCC_Native; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } +decl_flags(X) ::= decl_flags(A) STATIC(T). { X.Int = A.Int | ZCC_Static; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } +decl_flags(X) ::= decl_flags(A) PRIVATE(T). { X.Int = A.Int | ZCC_Private; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } +decl_flags(X) ::= decl_flags(A) PROTECTED(T). { X.Int = A.Int | ZCC_Protected; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } +decl_flags(X) ::= decl_flags(A) LATENT(T). { X.Int = A.Int | ZCC_Latent; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } +decl_flags(X) ::= decl_flags(A) FINAL(T). { X.Int = A.Int | ZCC_Final; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } +decl_flags(X) ::= decl_flags(A) META(T). { X.Int = A.Int | ZCC_Meta; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } +decl_flags(X) ::= decl_flags(A) ACTION(T). { X.Int = A.Int | ZCC_Action; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } +decl_flags(X) ::= decl_flags(A) READONLY(T). { X.Int = A.Int | ZCC_ReadOnly; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } +decl_flags(X) ::= decl_flags(A) DEPRECATED(T). { X.Int = A.Int | ZCC_Deprecated; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } + +func_const(X) ::= . { X.Int = 0; X.SourceLoc = stat->sc.GetMessageLine(); } +func_const(X) ::= CONST(T). { X.Int = ZCC_FuncConst; X.SourceLoc = T.SourceLoc; } + +opt_func_body(X) ::= SEMICOLON. { X = NULL; } +opt_func_body(X) ::= function_body(A). { X = A; } + +%type func_params {ZCC_FuncParamDecl *} +%type func_param_list {ZCC_FuncParamDecl *} +%type func_param {ZCC_FuncParamDecl *} + +func_params(X) ::= . /* empty */ { X = NULL; } +func_params(X) ::= VOID. { X = NULL; } +func_params(X) ::= func_param_list(A). { X = A; } + +func_param_list(X) ::= func_param(A). { X = A; } +func_param_list(X) ::= func_param_list(A) COMMA func_param(B). { X = A; A->AppendSibling(B); } + +func_param(X) ::= func_param_flags(A) type(B) IDENTIFIER(C). +{ + NEW_AST_NODE(FuncParamDecl,parm,A.SourceLoc ? A.SourceLoc : B->SourceLoc); + parm->Type = B; + parm->Name = C.Name(); + parm->Flags = A.Int; + X = parm; +} + +func_param_flags(X) ::= . { X.Int = 0; X.SourceLoc = 0; } +func_param_flags(X) ::= func_param_flags(A) IN(T). { X.Int = A.Int | ZCC_In; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } +func_param_flags(X) ::= func_param_flags(A) OUT(T). { X.Int = A.Int | ZCC_Out; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } +func_param_flags(X) ::= func_param_flags(A) OPTIONAL(T). { X.Int = A.Int | ZCC_Optional; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } + +/************ Expressions ************/ + +/* We use default to access a class's default instance. */ +%fallback IDENTIFIER + DEFAULT. + +%type expr{ZCC_Expression *} +%type primary{ZCC_Expression *} +%type unary_expr{ZCC_Expression *} +%type constant{ZCC_ExprConstant *} + +/*----- Primary Expressions -----*/ + +primary(X) ::= IDENTIFIER(A). +{ + NEW_AST_NODE(ExprID, expr, A); + expr->Operation = PEX_ID; + expr->Identifier = A.Name(); + expr->Type = NULL; + X = expr; +} +primary(X) ::= SUPER(T). +{ + NEW_AST_NODE(Expression, expr, T); + expr->Operation = PEX_Super; + expr->Type = NULL; + X = expr; +} +primary(X) ::= constant(A). +{ + X = A; +} +primary(X) ::= SELF(T). +{ + NEW_AST_NODE(Expression, expr, T); + expr->Operation = PEX_Self; + expr->Type = NULL; + X = expr; +} +primary(X) ::= LPAREN expr(A) RPAREN. +{ + X = A; +} +primary ::= LPAREN error RPAREN. +primary(X) ::= primary(A) LPAREN func_expr_list(B) RPAREN. [DOT] // Function call +{ + NEW_AST_NODE(ExprFuncCall, expr, A); + expr->Operation = PEX_FuncCall; + expr->Type = NULL; + expr->Function = A; + expr->Parameters = B; + X = expr; +} +primary(X) ::= primary(A) LBRACKET expr(B) RBRACKET. [DOT] // Array access +{ + NEW_AST_NODE(ExprBinary, expr, B); + expr->Operation = PEX_ArrayAccess; + expr->Type = NULL; + expr->Left = A; + expr->Right = B; + X = expr; +} +primary(X) ::= primary(A) DOT IDENTIFIER(B). // Member access +{ + NEW_AST_NODE(ExprMemberAccess, expr, B); + expr->Operation = PEX_MemberAccess; + expr->Type = NULL; + expr->Left = A; + expr->Right = ENamedName(B.Int); + X = expr; +} +primary(X) ::= primary(A) ADDADD. /* postfix++ */ +{ + UNARY_EXPR(A,PEX_PostInc); + X = expr1; +} +primary(X) ::= primary(A) SUBSUB. /* postfix-- */ +{ + UNARY_EXPR(A,PEX_PostDec); + X = expr1; +} +/* +primary(X) ::= SCOPE primary(B). +{ + BINARY_EXPR(NULL,B,PEX_Scope); + X = expr2; +} +*/ +/*----- Unary Expressions -----*/ + +unary_expr(X) ::= primary(A). +{ + X = A; +} +unary_expr(X) ::= SUB unary_expr(A). [UNARY] +{ + ZCC_ExprConstant *con = static_cast(A); + if (A->Operation == PEX_ConstValue && (con->Type->IsA(RUNTIME_CLASS(PInt)) || con->Type->IsA(RUNTIME_CLASS(PFloat)))) + { // For constants, manipulate the child node directly, and don't create a new node. + if (con->Type->IsA(RUNTIME_CLASS(PInt))) + { + con->IntVal = -con->IntVal; + } + else + { + con->DoubleVal = -con->DoubleVal; + } + X = A; + } + else + { // For everything else, create a new node and do the negation later. + UNARY_EXPR(A,PEX_Negate); + X = expr1; + } +} +unary_expr(X) ::= ADD unary_expr(A). [UNARY] +{ + // Even though this is really a no-op, we still need to make a node for + // it so we can type check that it is being applied to something numeric. + // But we can do that right now for constant numerals. + ZCC_ExprConstant *con = static_cast(A); + if (A->Operation != PEX_ConstValue || (!con->Type->IsA(RUNTIME_CLASS(PInt)) && !con->Type->IsA(RUNTIME_CLASS(PFloat)))) + { + UNARY_EXPR(A,PEX_AntiNegate); + X = expr1; + } + else + { + X = A; + } +} +unary_expr(X) ::= SUBSUB unary_expr(A). [UNARY] +{ + UNARY_EXPR(A,PEX_PreDec); + X = expr1; +} +unary_expr(X) ::= ADDADD unary_expr(A). [UNARY] +{ + UNARY_EXPR(A,PEX_PreInc); + X = expr1; +} +unary_expr(X) ::= TILDE unary_expr(A). [UNARY] +{ + UNARY_EXPR(A,PEX_BitNot); + X = expr1; +} +unary_expr(X) ::= BANG unary_expr(A). [UNARY] +{ + UNARY_EXPR(A,PEX_BoolNot); + X = expr1; +} +unary_expr(X) ::= SIZEOF unary_expr(A). [UNARY] +{ + UNARY_EXPR(A,PEX_SizeOf); + X = expr1; +} +unary_expr(X) ::= ALIGNOF unary_expr(A). [UNARY] +{ + UNARY_EXPR(A,PEX_AlignOf); + X = expr1; +} + +/* Due to parsing conflicts, C-style casting is not supported. You + * must use C++ function call-style casting instead. + */ + +/*----- Binary Expressions -----*/ + +expr(X) ::= unary_expr(A). +{ + X = A; +} +expr(X) ::= expr(A) ADD expr(B). /* a + b */ +{ + BINARY_EXPR(A,B,PEX_Add); + X = expr2; +} +expr(X) ::= expr(A) SUB expr(B). /* a - b */ +{ + BINARY_EXPR(A,B,PEX_Sub); + X = expr2; +} +expr(X) ::= expr(A) MUL expr(B). /* a * b */ +{ + BINARY_EXPR(A,B,PEX_Mul); + X = expr2; +} +expr(X) ::= expr(A) DIV expr(B). /* a / b */ +{ + BINARY_EXPR(A,B,PEX_Div); + X = expr2; +} +expr(X) ::= expr(A) MOD expr(B). /* a % b */ +{ + BINARY_EXPR(A,B,PEX_Mod); + X = expr2; +} +expr(X) ::= expr(A) POW expr(B). /* a ** b */ +{ + BINARY_EXPR(A,B,PEX_Pow); + X = expr2; +} +expr(X) ::= expr(A) CROSSPROD expr(B). /* a cross b */ +{ + BINARY_EXPR(A,B,PEX_CrossProduct); + X = expr2; +} +expr(X) ::= expr(A) DOTPROD expr(B). /* a dot b */ +{ + BINARY_EXPR(A,B,PEX_DotProduct); + X = expr2; +} +expr(X) ::= expr(A) LSH expr(B). /* a << b */ +{ + BINARY_EXPR(A,B,PEX_LeftShift); + X = expr2; +} +expr(X) ::= expr(A) RSH expr(B). /* a >> b */ +{ + BINARY_EXPR(A,B,PEX_RightShift); + X = expr2; +} +expr(X) ::= expr(A) DOTDOT expr(B). /* a .. b */ +{ + BINARY_EXPR(A,B,PEX_Concat); + X = expr2; +} + +expr(X) ::= expr(A) LT expr(B). /* a < b */ +{ + BINARY_EXPR(A,B,PEX_LT); + X = expr2; +} +expr(X) ::= expr(A) GT expr(B). /* a > b */ +{ + BINARY_EXPR(A,B,PEX_LTEQ); + UNARY_EXPR(expr2,PEX_BoolNot); + X = expr1; +} +expr(X) ::= expr(A) LTEQ expr(B). /* a <= b */ +{ + BINARY_EXPR(A,B,PEX_LTEQ); + X = expr2; +} +expr(X) ::= expr(A) GTEQ expr(B). /* a >= b */ +{ + BINARY_EXPR(A,B,PEX_LT); + UNARY_EXPR(expr1,PEX_BoolNot); + X = expr1; +} +expr(X) ::= expr(A) LTGTEQ expr(B). /* a <>= b */ +{ + BINARY_EXPR(A,B,PEX_LTGTEQ); + X = expr2; +} +expr(X) ::= expr(A) IS expr(B). /* a is b */ +{ + BINARY_EXPR(A,B,PEX_Is); + X = expr2; +} + +expr(X) ::= expr(A) EQEQ expr(B). /* a == b */ +{ + BINARY_EXPR(A,B,PEX_EQEQ); + X = expr2; +} +expr(X) ::= expr(A) NEQ expr(B). /* a != b */ +{ + BINARY_EXPR(A,B,PEX_EQEQ); + UNARY_EXPR(expr2,PEX_BoolNot); + X = expr1; +} +expr(X) ::= expr(A) APPROXEQ expr(B). /* a ~== b */ +{ + BINARY_EXPR(A,B,PEX_APREQ); + X = expr2; +} + +expr(X) ::= expr(A) AND expr(B). /* a & b */ +{ + BINARY_EXPR(A,B,PEX_BitAnd); + X = expr2; +} +expr(X) ::= expr(A) XOR expr(B). /* a ^ b */ +{ + BINARY_EXPR(A,B,PEX_BitXor); + X = expr2; +} +expr(X) ::= expr(A) OR expr(B). /* a | b */ +{ + BINARY_EXPR(A,B,PEX_BitOr); + X = expr2; +} +expr(X) ::= expr(A) ANDAND expr(B). /* a && b */ +{ + BINARY_EXPR(A,B,PEX_BoolAnd); + X = expr2; +} +expr(X) ::= expr(A) OROR expr(B). /* a || b */ +{ + BINARY_EXPR(A,B,PEX_BoolOr); + X = expr2; +} + +expr(X) ::= expr(A) SCOPE expr(B). +{ + BINARY_EXPR(A,B,PEX_Scope); + X = expr2; +} + +/*----- Trinary Expression -----*/ + +expr(X) ::= expr(A) QUESTION expr(B) COLON expr(C). +{ + NEW_AST_NODE(ExprTrinary, expr, A); + expr->Operation = PEX_Trinary; + expr->Type = NULL; + expr->Test = A; + expr->Left = B; + expr->Right = C; + X = expr; +} + +/************ Expression Lists ***********/ + +%type expr_list{ZCC_Expression *} + +expr_list(X) ::= expr(A). +{ + X = A; +} +expr_list(X) ::= expr_list(A) COMMA expr(B). +{ + X = A; + A->AppendSibling(B); +} + +/*----- Function argument lists -----*/ + +/* A function expression list can also specify a parameter's name, + * but once you do that, all remaining parameters must also be named. + * We let higher-level code handle this to keep this file simpler. */ +%type func_expr_list{ZCC_FuncParm *} +%type func_expr_item{ZCC_FuncParm *} +%type named_expr{ZCC_FuncParm *} + +func_expr_list(X) ::= func_expr_item(A). +{ + X = A; +} +func_expr_list(X) ::= func_expr_list(A) COMMA(T) func_expr_item(B). +{ + // Omitted parameters still need to appear as nodes in the list. + if (A == NULL) + { + NEW_AST_NODE(FuncParm,nil_a,T); + nil_a->Value = NULL; + nil_a->Label = NAME_None; + A = nil_a; + } + if (B == NULL) + { + NEW_AST_NODE(FuncParm,nil_b,T); + nil_b->Value = NULL; + nil_b->Label = NAME_None; + B = nil_b; + } + X = A; + A->AppendSibling(B); +} + +func_expr_item(X) ::= . +{ + X = NULL; +} +func_expr_item(X) ::= named_expr(A). +{ + X = A; +} + +named_expr(X) ::= IDENTIFIER(A) COLON expr(B). +{ + NEW_AST_NODE(FuncParm, parm, A); + parm->Value = B; + parm->Label = ENamedName(A.Int); + X = parm; +} +named_expr(X) ::= expr(B). +{ + NEW_AST_NODE(FuncParm, parm, B); + parm->Value = B; + parm->Label = NAME_None; + X = parm; +} + +/************ Constants ************/ + +/* Allow C-like concatenation of adjacent string constants. */ +%type string_constant{ZCC_ExprConstant *} + +string_constant(X) ::= STRCONST(A). +{ + NEW_AST_NODE(ExprConstant, strconst, A); + strconst->Operation = PEX_ConstValue; + strconst->Type = TypeString; + strconst->StringVal = A.String; + X = strconst; +} +string_constant(X) ::= string_constant(A) STRCONST(B). +{ + NEW_AST_NODE(ExprConstant, strconst, A); + strconst->Operation = PEX_ConstValue; + strconst->Type = TypeString; + strconst->StringVal = stat->Strings.Alloc(*(A->StringVal) + *(B.String)); + X = strconst; +} + +constant(X) ::= string_constant(A). +{ + X = A; +} +constant(X) ::= INTCONST(A). +{ + NEW_INTCONST_NODE(intconst, TypeSInt32, A.Int, A); + X = intconst; +} +constant(X) ::= UINTCONST(A). +{ + NEW_INTCONST_NODE(intconst, TypeUInt32, A.Int, A); + X = intconst; +} +constant(X) ::= FLOATCONST(A). +{ + NEW_AST_NODE(ExprConstant, floatconst, A); + floatconst->Operation = PEX_ConstValue; + floatconst->Type = TypeFloat64; + floatconst->DoubleVal = A.Float; + X = floatconst; +} +constant(X) ::= NAMECONST(A). +{ + NEW_AST_NODE(ExprConstant, floatconst, A); + floatconst->Operation = PEX_ConstValue; + floatconst->Type = TypeName; + floatconst->IntVal = A.Int; + X = floatconst; +} +constant(X) ::= FALSE(A). +{ + NEW_INTCONST_NODE(boolconst, TypeBool, false, A); + X = boolconst; +} +constant(X) ::= TRUE(A). +{ + NEW_INTCONST_NODE(boolconst, TypeBool, true, A); + X = boolconst; +} + +/************ Statements ************/ + +function_body(X) ::= compound_statement(A). { X = A; } + +%type statement{ZCC_Statement *} +statement(X) ::= SEMICOLON. { X = NULL; } +statement(X) ::= labeled_statement(A). { X = A; } +statement(X) ::= compound_statement(A). { X = A; } +statement(X) ::= expression_statement(A) SEMICOLON. { X = A; } +statement(X) ::= selection_statement(A). { X = A; } +statement(X) ::= iteration_statement(A). { X = A; } +statement(X) ::= jump_statement(A). { X = A; } +statement(X) ::= assign_statement(A) SEMICOLON. { X = A; } +statement(X) ::= local_var(A) SEMICOLON. { X = A; } +statement(X) ::= error SEMICOLON. { X = NULL; } + +/*----- Jump Statements -----*/ + +%type jump_statement{ZCC_Statement *} + +jump_statement(A) ::= CONTINUE(T) SEMICOLON. +{ + NEW_AST_NODE(ContinueStmt, stmt, T); + A = stmt; +} +jump_statement(A) ::= BREAK(T) SEMICOLON. +{ + NEW_AST_NODE(BreakStmt, stmt, T); + A = stmt; +} +jump_statement(A) ::= RETURN(T) SEMICOLON. +{ + NEW_AST_NODE(ReturnStmt, stmt, T); + stmt->Values = NULL; + A = stmt; +} +jump_statement(A) ::= RETURN(T) expr_list(X) SEMICOLON. +{ + NEW_AST_NODE(ReturnStmt, stmt, T); + stmt->Values = X; + A = stmt; +} + +/*----- Compound Statements -----*/ + +%type compound_statement{ZCC_CompoundStmt *} +%type statement_list{ZCC_Statement *} + +compound_statement(X) ::= LBRACE(T) RBRACE. +{ + NEW_AST_NODE(CompoundStmt,stmt,T); + stmt->Content = NULL; + X = stmt; +} +compound_statement(X) ::= LBRACE(T) statement_list(A) RBRACE. +{ + NEW_AST_NODE(CompoundStmt,stmt,T); + stmt->Content = A; + X = stmt; +} +compound_statement(X) ::= LBRACE(T) error RBRACE. +{ + NEW_AST_NODE(CompoundStmt,stmt,T); + stmt->Content = NULL; + X = stmt; +} + +statement_list(X) ::= statement(A). +{ + X = A; +} +statement_list(X) ::= statement_list(A) statement(B). +{ + SAFE_APPEND(A,B); + X = A; +} + +/*----- Expression Statements -----*/ + +%type expression_statement{ZCC_ExpressionStmt *} + +expression_statement(X) ::= expr(A). +{ + NEW_AST_NODE(ExpressionStmt, stmt, A); + stmt->Expression = A; + X = stmt; +} + +/*----- Iteration Statements -----*/ + +%type iteration_statement{ZCC_Statement *} + +// while/until (expr) statement +iteration_statement(X) ::= while_or_until(TY) LPAREN expr(EX) RPAREN statement(ST). +{ + NEW_AST_NODE(IterationStmt, iter, TY); + if (TY.Int == ZCC_UNTIL) + { // Negate the loop condition + UNARY_EXPR(EX,PEX_BoolNot); + iter->LoopCondition = expr1; + } + else + { + iter->LoopCondition = EX; + } + iter->LoopStatement = ST; + iter->LoopBumper = NULL; + iter->CheckAt = ZCC_IterationStmt::Start; + X = iter; +} +// do statement while/until (expr) +iteration_statement(X) ::= DO(T) statement(ST) while_or_until(TY) LPAREN expr(EX) RPAREN. +{ + NEW_AST_NODE(IterationStmt, iter, T); + if (TY.Int == ZCC_UNTIL) + { // Negate the loop condition + UNARY_EXPR(EX,PEX_BoolNot); + iter->LoopCondition = expr1; + } + else + { + iter->LoopCondition = EX; + } + iter->LoopStatement = ST; + iter->LoopBumper = NULL; + iter->CheckAt = ZCC_IterationStmt::End; + X = iter; +} +// for (init; cond; bump) statement +iteration_statement(X) ::= FOR(T) LPAREN for_init(IN) SEMICOLON opt_expr(EX) SEMICOLON for_bump(DO) RPAREN statement(ST). +{ + NEW_AST_NODE(IterationStmt, iter, T); + iter->LoopCondition = EX; + iter->LoopStatement = ST; + iter->LoopBumper = DO; + iter->CheckAt = ZCC_IterationStmt::Start; + // The initialization expression appears outside the loop + // for_init may be NULL if there is no initialization. + SAFE_APPEND(IN, iter); + // And the whole thing gets wrapped inside a compound statement in case the loop + // initializer defined any variables. + NEW_AST_NODE(CompoundStmt, wrap, T); + wrap->Content = IN; + X = wrap; +} + +while_or_until(X) ::= WHILE(T). +{ + X.Int = ZCC_WHILE; + X.SourceLoc = T.SourceLoc; +} +while_or_until(X) ::= UNTIL(T). +{ + X.Int = ZCC_UNTIL; + X.SourceLoc = T.SourceLoc; +} + +%type for_init{ZCC_Statement *} +for_init(X) ::= local_var(A). { X = A; } +for_init(X) ::= for_bump(A). { X = A; } + +%type for_bump{ZCC_Statement *} +for_bump(X) ::= . { X = NULL; } +for_bump(X) ::= expression_statement(A). { X = A; } +for_bump(X) ::= assign_statement(A). { X = A; } + +/*----- If Statements -----*/ + +/* Resolve the shift-reduce conflict here in favor of the shift. + * This is the default behavior, but using precedence symbols + * lets us do it without warnings. + */ +%left IF. +%left ELSE. +%type selection_statement{ZCC_Statement *} +%type if_front{ZCC_IfStmt *} + +selection_statement(X) ::= if_front(A). [IF] +{ + X = A; +} +selection_statement(X) ::= if_front(A) ELSE statement(B). [ELSE] +{ + A->FalsePath = B; + X = A; +} + +if_front(X) ::= IF(T) LPAREN expr(A) RPAREN statement(B). +{ + NEW_AST_NODE(IfStmt,stmt,T); + stmt->Condition = A; + stmt->TruePath = B; + stmt->FalsePath = NULL; + X = stmt; +} + +/*----- Switch Statements -----*/ + +selection_statement(X) ::= SWITCH(T) LPAREN expr(A) RPAREN statement(B). +{ + NEW_AST_NODE(SwitchStmt,stmt,T); + stmt->Condition = A; + stmt->Content = B; + X = stmt; +} + +/*----- Case Label "Statements" -----*/ + +%type labeled_statement{ZCC_CaseStmt *} + +labeled_statement(X) ::= CASE(T) expr(A) COLON. +{ + NEW_AST_NODE(CaseStmt,stmt,T); + stmt->Condition = A; + X = stmt; +} +labeled_statement(X) ::= DEFAULT(T) COLON. +{ + NEW_AST_NODE(CaseStmt,stmt,T); + stmt->Condition = NULL; + X = stmt; +} + +/*----- Assignment Statements -----*/ + +%type assign_statement{ZCC_AssignStmt *} + +assign_statement(X) ::= expr_list(A) assign_op(OP) expr_list(B). [EQ] +{ + NEW_AST_NODE(AssignStmt,stmt,OP); + stmt->AssignOp = OP.Int; + stmt->Dests = A; + stmt->Sources = B; + X = stmt; +} + +assign_op(X) ::= EQ(T). { X.Int = ZCC_EQ; X.SourceLoc = T.SourceLoc; } +assign_op(X) ::= MULEQ(T). { X.Int = ZCC_MULEQ; X.SourceLoc = T.SourceLoc; } +assign_op(X) ::= DIVEQ(T). { X.Int = ZCC_DIVEQ; X.SourceLoc = T.SourceLoc; } +assign_op(X) ::= MODEQ(T). { X.Int = ZCC_MODEQ; X.SourceLoc = T.SourceLoc; } +assign_op(X) ::= ADDEQ(T). { X.Int = ZCC_ADDEQ; X.SourceLoc = T.SourceLoc; } +assign_op(X) ::= SUBEQ(T). { X.Int = ZCC_SUBEQ; X.SourceLoc = T.SourceLoc; } +assign_op(X) ::= LSHEQ(T). { X.Int = ZCC_LSHEQ; X.SourceLoc = T.SourceLoc; } +assign_op(X) ::= RSHEQ(T). { X.Int = ZCC_RSHEQ; X.SourceLoc = T.SourceLoc; } +assign_op(X) ::= ANDEQ(T). { X.Int = ZCC_ANDEQ; X.SourceLoc = T.SourceLoc; } +assign_op(X) ::= OREQ(T). { X.Int = ZCC_OREQ; X.SourceLoc = T.SourceLoc; } +assign_op(X) ::= XOREQ(T). { X.Int = ZCC_XOREQ; X.SourceLoc = T.SourceLoc; } + +/*----- Local Variable Definition "Statements" -----*/ + +%type local_var{ZCC_LocalVarStmt *} + +local_var(X) ::= type(A) variable_list(B) var_init(C). +{ + NEW_AST_NODE(LocalVarStmt,vardef,A); + vardef->Type = A; + vardef->Vars = B; + vardef->Inits = C; + X = vardef; +} + +%type var_init{ZCC_Expression *} +var_init(X) ::= . { X = NULL; } +var_init(X) ::= EQ expr_list(A). { X = A; } diff --git a/src/zscript/zcc_compile.cpp b/src/zscript/zcc_compile.cpp new file mode 100644 index 0000000000..5a3276a071 --- /dev/null +++ b/src/zscript/zcc_compile.cpp @@ -0,0 +1,601 @@ +#include "dobject.h" +#include "sc_man.h" +#include "c_console.h" +#include "c_dispatch.h" +#include "w_wad.h" +#include "cmdlib.h" +#include "m_alloc.h" +#include "zcc_parser.h" +#include "zcc_compile.h" +#include "v_text.h" +#include "gdtoa.h" + +#define DEFINING_CONST ((PSymbolConst *)(void *)1) + +//========================================================================== +// +// ZCCCompiler Constructor +// +//========================================================================== + +ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols) +: Outer(_outer), Symbols(_symbols), AST(ast), ErrorCount(0), WarnCount(0) +{ + // Group top-level nodes by type + if (ast.TopNode != NULL) + { + ZCC_TreeNode *node = ast.TopNode; + do + { + switch (node->NodeType) + { + case AST_Class: + if (AddNamedNode(static_cast(node)->ClassName, node)) + { + Classes.Push(static_cast(node)); + } + break; + + case AST_Struct: + if (AddNamedNode(static_cast(node)->StructName, node)) + { + Structs.Push(static_cast(node)); + } + break; + + case AST_Enum: break; + case AST_EnumTerminator:break; + + case AST_ConstantDef: + if (AddNamedNode(static_cast(node)->Name, node)) + { + Constants.Push(static_cast(node)); + } + break; + + default: + assert(0 && "Unhandled AST node type"); + break; + } + node = node->SiblingNext; + } + while (node != ast.TopNode); + } +} + +//========================================================================== +// +// ZCCCompiler :: AddNamedNode +// +// Keeps track of definition nodes by their names. Ensures that all names +// in this scope are unique. +// +//========================================================================== + +bool ZCCCompiler::AddNamedNode(FName name, ZCC_TreeNode *node) +{ + ZCC_TreeNode **check = NamedNodes.CheckKey(name); + if (check != NULL && *check != NULL) + { + Message(node, ERR_symbol_redefinition, "Attempt to redefine '%s'", name.GetChars()); + Message(*check, ERR_original_definition, " Original definition is here"); + return false; + } + else + { + NamedNodes.Insert(name, node); + return true; + } +} + +//========================================================================== +// +// ZCCCompiler :: Message +// +// Prints a warning or error message, and increments the appropriate +// counter. +// +//========================================================================== + +void ZCCCompiler::Message(ZCC_TreeNode *node, EZCCError errnum, const char *msg, ...) +{ + FString composed; + + composed.Format("%s%s, line %d: ", + errnum & ZCCERR_ERROR ? TEXTCOLOR_RED : TEXTCOLOR_ORANGE, + node->SourceName->GetChars(), node->SourceLoc); + + va_list argptr; + va_start(argptr, msg); + composed.VAppendFormat(msg, argptr); + va_end(argptr); + + composed += '\n'; + PrintString(PRINT_HIGH, composed); + + if (errnum & ZCCERR_ERROR) + { + ErrorCount++; + } + else + { + WarnCount++; + } +} + +//========================================================================== +// +// ZCCCompiler :: Compile +// +// Compile everything defined at this level. +// +//========================================================================== + +int ZCCCompiler::Compile() +{ + CompileConstants(); + return ErrorCount; +} + +//========================================================================== +// +// ZCCCompiler :: CompileConstants +// +// Make symbols from every constant defined at this level. +// +//========================================================================== + +void ZCCCompiler::CompileConstants() +{ + for (unsigned i = 0; i < Constants.Size(); ++i) + { + ZCC_ConstantDef *def = Constants[i]; + if (def->Symbol == NULL) + { + CompileConstant(def); + } + } +} + +//========================================================================== +// +// ZCCCompiler :: CompileConstant +// +// For every constant definition, evaluate its value (which should result +// in a constant), and create a symbol for it. Simplify() uses recursion +// to resolve constants used before their declarations. +// +//========================================================================== + +PSymbolConst *ZCCCompiler::CompileConstant(ZCC_ConstantDef *def) +{ + assert(def->Symbol == NULL); + + def->Symbol = DEFINING_CONST; // avoid recursion + ZCC_Expression *val = Simplify(def->Value); + def->Value = val; + PSymbolConst *sym = NULL; + if (val->NodeType == AST_ExprConstant) + { + ZCC_ExprConstant *cval = static_cast(val); + if (cval->Type == TypeString) + { + sym = new PSymbolConstString(def->Name, *(cval->StringVal)); + } + else if (cval->Type->IsA(RUNTIME_CLASS(PInt))) + { + sym = new PSymbolConstNumeric(def->Name, cval->Type, cval->IntVal); + } + else if (cval->Type->IsA(RUNTIME_CLASS(PFloat))) + { + sym = new PSymbolConstNumeric(def->Name, cval->Type, cval->DoubleVal); + } + else + { + Message(def->Value, ERR_bad_const_def_type, "Bad type for constant definiton"); + } + } + else + { + Message(def->Value, ERR_const_def_not_constant, "Constant definition requires a constant value"); + } + if (sym == NULL) + { + // Create a dummy constant so we don't make any undefined value warnings. + sym = new PSymbolConstNumeric(def->Name, TypeError, 0); + } + def->Symbol = sym; + PSymbol *addsym = Symbols.AddSymbol(sym); + assert(NULL != addsym && "Symbol was redefined (but we shouldn't have even had the chance to do so)"); + return sym; +} + + +//========================================================================== +// +// ZCCCompiler :: Simplify +// +// For an expression, +// Evaluate operators whose arguments are both constants, replacing it +// with a new constant. +// For a binary operator with one constant argument, put it on the right- +// hand operand, where permitted. +// Perform automatic type promotion. +// +//========================================================================== + +ZCC_Expression *ZCCCompiler::Simplify(ZCC_Expression *root) +{ + if (root->NodeType == AST_ExprUnary) + { + return SimplifyUnary(static_cast(root)); + } + else if (root->NodeType == AST_ExprBinary) + { + return SimplifyBinary(static_cast(root)); + } + else if (root->Operation == PEX_ID) + { + return IdentifyIdentifier(static_cast(root)); + } + else if (root->Operation == PEX_MemberAccess) + { + return SimplifyMemberAccess(static_cast(root)); + } + else if (root->Operation == PEX_FuncCall) + { + return SimplifyFunctionCall(static_cast(root)); + } + return root; +} + +//========================================================================== +// +// ZCCCompiler :: SimplifyUnary +// +//========================================================================== + +ZCC_Expression *ZCCCompiler::SimplifyUnary(ZCC_ExprUnary *unary) +{ + unary->Operand = Simplify(unary->Operand); + ZCC_OpProto *op = PromoteUnary(unary->Operation, unary->Operand); + if (op == NULL) + { // Oh, poo! + unary->Type = TypeError; + } + else if (unary->Operand->Operation == PEX_ConstValue) + { + return op->EvalConst1(static_cast(unary->Operand)); + } + return unary; +} + +//========================================================================== +// +// ZCCCompiler :: SimplifyBinary +// +//========================================================================== + +ZCC_Expression *ZCCCompiler::SimplifyBinary(ZCC_ExprBinary *binary) +{ + binary->Left = Simplify(binary->Left); + binary->Right = Simplify(binary->Right); + ZCC_OpProto *op = PromoteBinary(binary->Operation, binary->Left, binary->Right); + if (op == NULL) + { + binary->Type = TypeError; + } + else if (binary->Left->Operation == PEX_ConstValue && + binary->Right->Operation == PEX_ConstValue) + { + return op->EvalConst2(static_cast(binary->Left), + static_cast(binary->Right), AST.Strings); + } + return binary; +} + +//========================================================================== +// +// ZCCCompiler :: SimplifyMemberAccess +// +//========================================================================== + +ZCC_Expression *ZCCCompiler::SimplifyMemberAccess(ZCC_ExprMemberAccess *dotop) +{ + dotop->Left = Simplify(dotop->Left); + + if (dotop->Left->Operation == PEX_TypeRef) + { // Type refs can be evaluated now. + PType *ref = static_cast(dotop->Left)->RefType; + PSymbol *sym = ref->Symbols.FindSymbol(dotop->Right, true); + if (sym == NULL) + { + Message(dotop, ERR_not_a_member, "'%s' is not a valid member", FName(dotop->Right).GetChars()); + } + else + { + ZCC_Expression *expr = NodeFromSymbol(sym, dotop); + if (expr == NULL) + { + Message(dotop, ERR_bad_symbol, "Unhandled symbol type encountered"); + } + else + { + return expr; + } + } + } + return dotop; +} + +//========================================================================== +// +// ZCCCompiler :: SimplifyFunctionCall +// +// This may replace a function call with cast(s), since they look like the +// same thing to the parser. +// +//========================================================================== + +ZCC_Expression *ZCCCompiler::SimplifyFunctionCall(ZCC_ExprFuncCall *callop) +{ + ZCC_FuncParm *parm; + int parmcount = 0; + + callop->Function = Simplify(callop->Function); + parm = callop->Parameters; + if (parm != NULL) + { + do + { + parmcount++; + assert(parm->NodeType == AST_FuncParm); + parm->Value = Simplify(parm->Value); + parm = static_cast(parm->SiblingNext); + } + while (parm != callop->Parameters); + } + // If the left side is a type ref, then this is actually a cast + // and not a function call. + if (callop->Function->Operation == PEX_TypeRef) + { + if (parmcount != 1) + { + Message(callop, ERR_cast_needs_1_parm, "Type cast requires one parameter"); + callop->ToErrorNode(); + } + else + { + PType *dest = static_cast(callop->Function)->RefType; + const PType::Conversion *route[CONVERSION_ROUTE_SIZE]; + int routelen = parm->Value->Type->FindConversion(dest, route, countof(route)); + if (routelen < 0) + { + // FIXME: Need real type names + Message(callop, ERR_cast_not_possible, "Cannot convert type 1 to type 2"); + callop->ToErrorNode(); + } + else + { + ZCC_Expression *val = ApplyConversion(parm->Value, route, routelen); + assert(val->Type == dest); + return val; + } + } + } + return callop; +} + +//========================================================================== +// +// ZCCCompiler :: PromoteUnary +// +// Converts the operand into a format preferred by the operator. +// +//========================================================================== + +ZCC_OpProto *ZCCCompiler::PromoteUnary(EZCCExprType op, ZCC_Expression *&expr) +{ + if (expr->Type == TypeError) + { + return NULL; + } + const PType::Conversion *route[CONVERSION_ROUTE_SIZE]; + int routelen = countof(route); + ZCC_OpProto *proto = ZCC_OpInfo[op].FindBestProto(expr->Type, route, routelen); + + if (proto != NULL) + { + expr = ApplyConversion(expr, route, routelen); + } + return proto; +} + +//========================================================================== +// +// ZCCCompiler :: PromoteBinary +// +// Converts the operands into a format (hopefully) compatible with the +// operator. +// +//========================================================================== + +ZCC_OpProto *ZCCCompiler::PromoteBinary(EZCCExprType op, ZCC_Expression *&left, ZCC_Expression *&right) +{ + // If either operand is of type 'error', the result is also 'error' + if (left->Type == TypeError || right->Type == TypeError) + { + return NULL; + } + const PType::Conversion *route1[CONVERSION_ROUTE_SIZE], *route2[CONVERSION_ROUTE_SIZE]; + int route1len = countof(route1), route2len = countof(route2); + ZCC_OpProto *proto = ZCC_OpInfo[op].FindBestProto(left->Type, route1, route1len, right->Type, route2, route2len); + if (proto != NULL) + { + left = ApplyConversion(left, route1, route1len); + right = ApplyConversion(right, route2, route2len); + } + return proto; +} + +//========================================================================== +// +// ZCCCompiler :: ApplyConversion +// +//========================================================================== + +ZCC_Expression *ZCCCompiler::ApplyConversion(ZCC_Expression *expr, const PType::Conversion **route, int routelen) +{ + for (int i = 0; i < routelen; ++i) + { + if (expr->Operation != PEX_ConstValue) + { + expr = AddCastNode(route[i]->TargetType, expr); + } + else + { + route[i]->ConvertConstant(static_cast(expr), AST.Strings); + } + } + return expr; +} + +//========================================================================== +// +// ZCCCompiler :: AddCastNode +// +//========================================================================== + +ZCC_Expression *ZCCCompiler::AddCastNode(PType *type, ZCC_Expression *expr) +{ + assert(expr->Operation != PEX_ConstValue && "Expression must not be constant"); + // TODO: add a node here + return expr; +} + +//========================================================================== +// +// ZCCCompiler :: IdentifyIdentifier +// +// Returns a node that represents what the identifer stands for. +// +//========================================================================== + +ZCC_Expression *ZCCCompiler::IdentifyIdentifier(ZCC_ExprID *idnode) +{ + // First things first: Check the symbol table. + PSymbol *sym; + if (NULL != (sym = Symbols.FindSymbol(idnode->Identifier, true))) + { + ZCC_Expression *node = NodeFromSymbol(sym, idnode); + if (node != NULL) + { + return node; + } + } + else + { // Check nodes that haven't had symbols created for them yet. + ZCC_TreeNode **node = NamedNodes.CheckKey(idnode->Identifier); + if (node != NULL && *node != NULL) + { + if ((*node)->NodeType == AST_ConstantDef) + { + ZCC_ConstantDef *def = static_cast(*node); + PSymbolConst *sym = def->Symbol; + + if (sym == DEFINING_CONST) + { + Message(idnode, ERR_recursive_definition, "Definition of '%s' is infinitely recursive", FName(idnode->Identifier).GetChars()); + sym = NULL; + } + else + { + assert(sym == NULL); + sym = CompileConstant(def); + } + return NodeFromSymbolConst(sym, idnode); + } + } + } + // Identifier didn't refer to anything good, so type error it. + idnode->ToErrorNode(); + return idnode; +} + +//========================================================================== +// +// ZCCCompiler :: NodeFromSymbol +// +//========================================================================== + +ZCC_Expression *ZCCCompiler::NodeFromSymbol(PSymbol *sym, ZCC_Expression *source) +{ + if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) + { + return NodeFromSymbolConst(static_cast(sym), source); + } + else if (sym->IsKindOf(RUNTIME_CLASS(PSymbolType))) + { + return NodeFromSymbolType(static_cast(sym), source); + } + return NULL; +} + +//========================================================================== +// +// ZCCCompiler :: NodeFromSymbolConst +// +// Returns a new AST constant node with the symbol's content. +// +//========================================================================== + +ZCC_ExprConstant *ZCCCompiler::NodeFromSymbolConst(PSymbolConst *sym, ZCC_Expression *idnode) +{ + ZCC_ExprConstant *val = static_cast(AST.InitNode(sizeof(*val), AST_ExprConstant, idnode)); + val->Operation = PEX_ConstValue; + if (sym == NULL) + { + val->Type = TypeError; + val->IntVal = 0; + } + else if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConstString))) + { + val->StringVal = AST.Strings.Alloc(static_cast(sym)->Str); + val->Type = TypeString; + } + else + { + val->Type = sym->ValueType; + if (val->Type != TypeError) + { + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric))); + if (sym->ValueType->IsKindOf(RUNTIME_CLASS(PInt))) + { + val->IntVal = static_cast(sym)->Value; + } + else + { + assert(sym->ValueType->IsKindOf(RUNTIME_CLASS(PFloat))); + val->DoubleVal = static_cast(sym)->Float; + } + } + } + return val; +} + +//========================================================================== +// +// ZCCCompiler :: NodeFromSymbolType +// +// Returns a new AST type ref node with the symbol's content. +// +//========================================================================== + +ZCC_ExprTypeRef *ZCCCompiler::NodeFromSymbolType(PSymbolType *sym, ZCC_Expression *idnode) +{ + ZCC_ExprTypeRef *ref = static_cast(AST.InitNode(sizeof(*ref), AST_ExprTypeRef, idnode)); + ref->Operation = PEX_TypeRef; + ref->RefType = sym->Type; + ref->Type = NewClassPointer(RUNTIME_CLASS(PType)); + return ref; +} diff --git a/src/zscript/zcc_compile.h b/src/zscript/zcc_compile.h new file mode 100644 index 0000000000..c8933ff5fe --- /dev/null +++ b/src/zscript/zcc_compile.h @@ -0,0 +1,55 @@ +#ifndef ZCC_COMPILE_H +#define ZCC_COMPILE_H + +#include "zcc_errors.h" + +class ZCCCompiler +{ +public: + ZCCCompiler(ZCC_AST &tree, DObject *outer, PSymbolTable &symbols); + int Compile(); + +private: + void CompileConstants(); + PSymbolConst *CompileConstant(ZCC_ConstantDef *def); + + TArray Constants; + TArray Structs; + TArray Classes; + TMap NamedNodes; + + bool AddNamedNode(FName name, ZCC_TreeNode *node); + + ZCC_Expression *Simplify(ZCC_Expression *root); + ZCC_Expression *SimplifyUnary(ZCC_ExprUnary *unary); + ZCC_Expression *SimplifyBinary(ZCC_ExprBinary *binary); + ZCC_Expression *SimplifyMemberAccess(ZCC_ExprMemberAccess *dotop); + ZCC_Expression *SimplifyFunctionCall(ZCC_ExprFuncCall *callop); + ZCC_OpProto *PromoteUnary(EZCCExprType op, ZCC_Expression *&expr); + ZCC_OpProto *PromoteBinary(EZCCExprType op, ZCC_Expression *&left, ZCC_Expression *&right); + + void PromoteToInt(ZCC_Expression *&expr); + void PromoteToUInt(ZCC_Expression *&expr); + void PromoteToDouble(ZCC_Expression *&expr); + void PromoteToString(ZCC_Expression *&expr); + + ZCC_Expression *ApplyConversion(ZCC_Expression *expr, const PType::Conversion **route, int routelen); + ZCC_Expression *AddCastNode(PType *type, ZCC_Expression *expr); + + ZCC_Expression *IdentifyIdentifier(ZCC_ExprID *idnode); + ZCC_Expression *NodeFromSymbol(PSymbol *sym, ZCC_Expression *source); + ZCC_ExprConstant *NodeFromSymbolConst(PSymbolConst *sym, ZCC_Expression *idnode); + ZCC_ExprTypeRef *NodeFromSymbolType(PSymbolType *sym, ZCC_Expression *idnode); + + void Message(ZCC_TreeNode *node, EZCCError errnum, const char *msg, ...); + + DObject *Outer; + PSymbolTable &Symbols; + ZCC_AST &AST; + int ErrorCount; + int WarnCount; +}; + +void ZCC_InitConversions(); + +#endif diff --git a/src/zscript/zcc_errors.h b/src/zscript/zcc_errors.h new file mode 100644 index 0000000000..cb38a00d58 --- /dev/null +++ b/src/zscript/zcc_errors.h @@ -0,0 +1,14 @@ +#define ZCCERR_ERROR 0x40000000 + +enum EZCCError +{ + ERR_const_def_not_constant = 20000 | ZCCERR_ERROR, + ERR_bad_const_def_type = 20001 | ZCCERR_ERROR, + ERR_symbol_redefinition = 20002 | ZCCERR_ERROR, + ERR_original_definition = 20003 | ZCCERR_ERROR, + ERR_recursive_definition = 20004 | ZCCERR_ERROR, + ERR_not_a_member = 20005 | ZCCERR_ERROR, + ERR_bad_symbol = 20006 | ZCCERR_ERROR, + ERR_cast_needs_1_parm = 20007 | ZCCERR_ERROR, + ERR_cast_not_possible = 20008 | ZCCERR_ERROR, +}; diff --git a/src/zscript/zcc_expr.cpp b/src/zscript/zcc_expr.cpp new file mode 100644 index 0000000000..3ab977a2f7 --- /dev/null +++ b/src/zscript/zcc_expr.cpp @@ -0,0 +1,704 @@ +#include "dobject.h" +#include "sc_man.h" +#include "c_console.h" +#include "c_dispatch.h" +#include "w_wad.h" +#include "cmdlib.h" +#include "m_alloc.h" +#include "zcc_parser.h" +#include "templates.h" + +#define luai_nummod(a,b) ((a) - floor((a)/(b))*(b)) + +static void FtoD(ZCC_ExprConstant *expr, FSharedStringArena &str_arena); + +ZCC_OpInfoType ZCC_OpInfo[PEX_COUNT_OF] = +{ +#define xx(a,z) { #a, NULL }, +#include "zcc_exprlist.h" +}; + +// Structures used for initializing operator overloads +struct OpProto1 +{ + EZCCExprType Op; + PType **Type; + EvalConst1op EvalConst; +}; + +struct OpProto2 +{ + EZCCExprType Op; + PType **Res, **Ltype, **Rtype; + EvalConst2op EvalConst; +}; + +void ZCC_OpInfoType::AddProto(PType *res, PType *optype, EvalConst1op evalconst) +{ + ZCC_OpProto *proto = new ZCC_OpProto(res, optype, NULL); + proto->EvalConst1 = evalconst; + proto->Next = Protos; + Protos = proto; +} + +void ZCC_OpInfoType::AddProto(PType *res, PType *ltype, PType *rtype, EvalConst2op evalconst) +{ + assert(ltype != NULL); + ZCC_OpProto *proto = new ZCC_OpProto(res, ltype, rtype); + proto->EvalConst2 = evalconst; + proto->Next = Protos; + Protos = proto; +} + +//========================================================================== +// +// ZCC_OpInfoType :: FindBestProto (Unary) +// +// Finds the "best" prototype for this operand type. Best is defined as the +// one that requires the fewest conversions. Also returns the conversion +// route necessary to get from the input type to the desired type. +// +//========================================================================== + +ZCC_OpProto *ZCC_OpInfoType::FindBestProto(PType *optype, const PType::Conversion **route, int &numslots) +{ + assert(optype != NULL); + + const PType::Conversion *routes[2][CONVERSION_ROUTE_SIZE]; + const PType::Conversion **best_route = NULL; + int cur_route = 0; + ZCC_OpProto *best_proto = NULL; + int best_dist = INT_MAX; + + // Find the best prototype. + for (ZCC_OpProto *proto = Protos; best_dist != 0 && proto != NULL; proto = proto->Next) + { + if (proto->Type2 != NULL) + { // Not a unary prototype. + continue; + } + int dist = optype->FindConversion(proto->Type1, routes[cur_route], CONVERSION_ROUTE_SIZE); + if (dist >= 0 && dist < best_dist) + { + best_dist = dist; + best_proto = proto; + best_route = routes[cur_route]; + cur_route ^= 1; + } + } + // Copy best conversion route to the caller's array. + if (best_route != NULL && route != NULL && numslots > 0) + { + numslots = MIN(numslots, best_dist); + if (numslots > 0) + { + memcpy(route, best_route, sizeof(*route) * numslots); + } + } + return best_proto; +} + +//========================================================================== +// +// ZCC_OpInfoType :: FindBestProto (Binary) +// +// Finds the "best" prototype for the given operand types. Here, best is +// defined as the one that requires the fewest conversions for *one* of the +// operands. For prototypes with matching distances, the first one found +// is used. ZCC_InitOperators() initializes the prototypes in order such +// that this will result in the precedences: double > uint > int +// +//========================================================================== + +ZCC_OpProto *ZCC_OpInfoType::FindBestProto( + PType *left, const PType::Conversion **route1, int &numslots1, + PType *right, const PType::Conversion **route2, int &numslots2) +{ + assert(left != NULL && right != NULL); + + const PType::Conversion *routes[2][2][CONVERSION_ROUTE_SIZE]; + const PType::Conversion **best_route1 = NULL, **best_route2 = NULL; + int cur_route1 = 0, cur_route2 = 0; + int best_dist1 = INT_MAX, best_dist2 = INT_MAX; + + ZCC_OpProto *best_proto = NULL; + int best_low_dist = INT_MAX; + + for (ZCC_OpProto *proto = Protos; best_low_dist != 0 && proto != NULL; proto = proto->Next) + { + if (proto->Type2 == NULL) + { // Not a binary prototype + continue; + } + int dist1 = left->FindConversion(proto->Type1, routes[0][cur_route1], CONVERSION_ROUTE_SIZE); + int dist2 = right->FindConversion(proto->Type2, routes[1][cur_route2], CONVERSION_ROUTE_SIZE); + if (dist1 < 0 || dist2 < 0) + { // one or both operator types are unreachable + continue; + } + // Do not count F32->F64 conversions in the distance comparisons. If we do, then + // [[float32 (op) int]] will choose the integer version instead of the floating point + // version, which we do not want. + int test_dist1 = dist1, test_dist2 = dist2; + if (routes[0][cur_route1][0]->ConvertConstant == FtoD) + { + test_dist1--; + } + if (routes[1][cur_route2][0]->ConvertConstant == FtoD) + { + test_dist2--; + } + int dist = MIN(test_dist1, test_dist2); + if (dist < best_low_dist) + { + best_low_dist = dist; + best_proto = proto; + best_dist1 = dist1; + best_dist2 = dist2; + best_route1 = routes[0][cur_route1]; + best_route2 = routes[1][cur_route2]; + cur_route1 ^= 1; + cur_route2 ^= 1; + } + } + // Copy best conversion route to the caller's arrays. + if (best_route1 != NULL && route1 != NULL && numslots1 > 0) + { + numslots1 = MIN(numslots1, best_dist1); + if (numslots1 > 0) + { + memcpy(route1, best_route1, sizeof(*route1) * numslots1); + } + } + if (best_route2 != NULL && route2 != NULL && numslots2 > 0) + { + numslots2 = MIN(numslots2, best_dist2); + if (numslots2 > 0) + { + memcpy(route2, best_route2, sizeof(*route2) * numslots2); + } + } + return best_proto; +} + +static ZCC_ExprConstant *EvalIncFloat64(ZCC_ExprConstant *val) +{ + val->DoubleVal++; + return val; +} + +static ZCC_ExprConstant *EvalIncInt32(ZCC_ExprConstant *val) +{ + val->IntVal++; + return val; +} + +static ZCC_ExprConstant *EvalDecFloat64(ZCC_ExprConstant *val) +{ + val->DoubleVal--; + return val; +} + +static ZCC_ExprConstant *EvalDecInt32(ZCC_ExprConstant *val) +{ + val->IntVal--; + return val; +} + +static ZCC_ExprConstant *EvalNegateFloat64(ZCC_ExprConstant *val) +{ + val->DoubleVal = -val->DoubleVal; + return val; +} + +static ZCC_ExprConstant *EvalNegateInt32(ZCC_ExprConstant *val) +{ + val->IntVal = -val->IntVal; + return val; +} + +static ZCC_ExprConstant *EvalIdentity(ZCC_ExprConstant *val) +{ + return val; +} + +static ZCC_ExprConstant *EvalBitNot(ZCC_ExprConstant *val) +{ + val->IntVal = ~val->IntVal; + return val; +} + +static ZCC_ExprConstant *EvalBoolNot(ZCC_ExprConstant *val) +{ + val->IntVal = !val->IntVal; + return val; +} + +static ZCC_ExprConstant *EvalAddFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->DoubleVal += r->DoubleVal; + return l; +} + +static ZCC_ExprConstant *EvalAddInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal += r->IntVal; + return l; +} + +static ZCC_ExprConstant *EvalSubFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->DoubleVal -= r->DoubleVal; + return l; +} + +static ZCC_ExprConstant *EvalSubInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal -= r->IntVal; + return l; +} + +static ZCC_ExprConstant *EvalMulFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->DoubleVal *= r->DoubleVal; + return l; +} + +static ZCC_ExprConstant *EvalMulUInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->UIntVal *= r->UIntVal; + return l; +} + +static ZCC_ExprConstant *EvalMulSInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal *= r->IntVal; + return l; +} + +static ZCC_ExprConstant *EvalDivFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->DoubleVal /= r->DoubleVal; + return l; +} + +static ZCC_ExprConstant *EvalDivUInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->UIntVal /= r->UIntVal; + return l; +} + +static ZCC_ExprConstant *EvalDivSInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal /= r->IntVal; + return l; +} + +static ZCC_ExprConstant *EvalModFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->DoubleVal = luai_nummod(l->DoubleVal, r->DoubleVal); + return l; +} + +static ZCC_ExprConstant *EvalModUInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->UIntVal %= r->UIntVal; + return l; +} + +static ZCC_ExprConstant *EvalModSInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal %= r->IntVal; + return l; +} + +static ZCC_ExprConstant *EvalPow(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->DoubleVal = pow(l->DoubleVal, r->DoubleVal); + return l; +} + +static ZCC_ExprConstant *EvalConcat(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &strings) +{ + FString str = *l->StringVal + *r->StringVal; + l->StringVal = strings.Alloc(str); + return l; +} + +static ZCC_ExprConstant *EvalBitAnd(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal &= r->IntVal; + return l; +} + +static ZCC_ExprConstant *EvalBitOr(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal |= r->IntVal; + return l; +} + +static ZCC_ExprConstant *EvalBitXor(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal ^= r->IntVal; + return l; +} + +static ZCC_ExprConstant *EvalBoolAnd(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal = l->IntVal && r->IntVal; + return l; +} + +static ZCC_ExprConstant *EvalBoolOr(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal = l->IntVal || r->IntVal; + return l; +} + +static ZCC_ExprConstant *EvalSHL(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal <<= r->UIntVal; + return l; +} + +static ZCC_ExprConstant *EvalSHR_S(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal >>= r->UIntVal; + return l; +} + +static ZCC_ExprConstant *EvalSHR_U(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->UIntVal >>= r->UIntVal; + return l; +} + +static ZCC_ExprConstant *EvalLTSInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal = l->IntVal < r->IntVal; + l->Type = TypeBool; + return l; +} + +static ZCC_ExprConstant *EvalLTUInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal = l->UIntVal < r->UIntVal; + l->Type = TypeBool; + return l; +} + +static ZCC_ExprConstant *EvalLTFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal = l->DoubleVal < r->DoubleVal; + l->Type = TypeBool; + return l; +} + +static ZCC_ExprConstant *EvalLTEQSInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal = l->IntVal <= r->IntVal; + l->Type = TypeBool; + return l; +} + +static ZCC_ExprConstant *EvalLTEQUInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal = l->UIntVal <= r->UIntVal; + l->Type = TypeBool; + return l; +} + +static ZCC_ExprConstant *EvalLTEQFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal = l->DoubleVal <= r->DoubleVal; + l->Type = TypeBool; + return l; +} + +static ZCC_ExprConstant *EvalEQEQSInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal = l->IntVal == r->IntVal; + l->Type = TypeBool; + return l; +} + +static ZCC_ExprConstant *EvalEQEQUInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal = l->UIntVal == r->UIntVal; + l->Type = TypeBool; + return l; +} + +static ZCC_ExprConstant *EvalEQEQFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal = l->DoubleVal == r->DoubleVal; + l->Type = TypeBool; + return l; +} + +static ZCC_ExprConstant *EvalLTGTEQSInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal = l->IntVal < r->IntVal ? -1 : l->IntVal == r->IntVal ? 0 : 1; + return l; +} + +static ZCC_ExprConstant *EvalLTGTEQUInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal = l->UIntVal < r->UIntVal ? -1 : l->UIntVal == r->UIntVal ? 0 : 1; + l->Type = TypeSInt32; + return l; +} + +static ZCC_ExprConstant *EvalLTGTEQFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) +{ + l->IntVal = l->DoubleVal < r->DoubleVal ? -1 : l->DoubleVal == r->DoubleVal ? 0 : 1; + l->Type = TypeSInt32; + return l; +} + +void ZCC_InitOperators() +{ + // Prototypes are added from lowest to highest conversion precedence. + + // Unary operators + static const OpProto1 UnaryOpInit[] = + { + { PEX_PostInc , (PType **)&TypeSInt32, EvalIdentity }, + { PEX_PostInc , (PType **)&TypeUInt32, EvalIdentity }, + { PEX_PostInc , (PType **)&TypeFloat64, EvalIdentity }, + + { PEX_PostDec , (PType **)&TypeSInt32, EvalIdentity }, + { PEX_PostDec , (PType **)&TypeUInt32, EvalIdentity }, + { PEX_PostDec , (PType **)&TypeFloat64, EvalIdentity }, + + { PEX_PreInc , (PType **)&TypeSInt32, EvalIncInt32 }, + { PEX_PreInc , (PType **)&TypeUInt32, EvalIncInt32 }, + { PEX_PreInc , (PType **)&TypeFloat64, EvalIncFloat64 }, + + { PEX_PreDec , (PType **)&TypeSInt32, EvalDecInt32 }, + { PEX_PreDec , (PType **)&TypeUInt32, EvalDecInt32 }, + { PEX_PreDec , (PType **)&TypeFloat64, EvalDecFloat64 }, + + { PEX_Negate , (PType **)&TypeSInt32, EvalNegateInt32 }, + { PEX_Negate , (PType **)&TypeFloat64, EvalNegateFloat64 }, + + { PEX_AntiNegate , (PType **)&TypeSInt32, EvalIdentity }, + { PEX_AntiNegate , (PType **)&TypeUInt32, EvalIdentity }, + { PEX_AntiNegate , (PType **)&TypeFloat64, EvalIdentity }, + + { PEX_BitNot , (PType **)&TypeSInt32, EvalBitNot }, + { PEX_BitNot , (PType **)&TypeUInt32, EvalBitNot }, + + { PEX_BoolNot , (PType **)&TypeBool, EvalBoolNot }, + }; + for (size_t i = 0; i < countof(UnaryOpInit); ++i) + { + ZCC_OpInfo[UnaryOpInit[i].Op].AddProto(*UnaryOpInit[i].Type, *UnaryOpInit[i].Type, UnaryOpInit[i].EvalConst); + } + + // Binary operators + static const OpProto2 BinaryOpInit[] = + { + { PEX_Add , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalAddInt32 }, + { PEX_Add , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalAddInt32 }, + { PEX_Add , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalAddFloat64 }, + + { PEX_Sub , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalSubInt32 }, + { PEX_Sub , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalSubInt32 }, + { PEX_Sub , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalSubFloat64 }, + + { PEX_Mul , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalMulSInt32 }, + { PEX_Mul , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalMulUInt32 }, + { PEX_Mul , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalMulFloat64 }, + + { PEX_Div , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalDivSInt32 }, + { PEX_Div , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalDivUInt32 }, + { PEX_Div , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalDivFloat64 }, + + { PEX_Mod , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalModSInt32 }, + { PEX_Mod , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalModUInt32 }, + { PEX_Mod , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalModFloat64 }, + + { PEX_Pow , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalPow }, + + { PEX_Concat , (PType **)&TypeString, (PType **)&TypeString, (PType **)&TypeString, EvalConcat }, + + { PEX_BitAnd , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalBitAnd }, + { PEX_BitAnd , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalBitAnd }, + + { PEX_BitOr , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalBitOr }, + { PEX_BitOr , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalBitOr }, + + { PEX_BitXor , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalBitXor }, + { PEX_BitXor , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalBitXor }, + + { PEX_BoolAnd , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalBoolAnd }, + { PEX_BoolAnd , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalBoolAnd }, + + { PEX_BoolOr , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalBoolOr }, + { PEX_BoolOr , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalBoolOr }, + + { PEX_LeftShift , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeUInt32, EvalSHL }, + { PEX_LeftShift , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalSHL }, + + { PEX_RightShift , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeUInt32, EvalSHR_S }, + { PEX_RightShift , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalSHR_U }, + + { PEX_LT , (PType **)&TypeBool, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalLTSInt32 }, + { PEX_LT , (PType **)&TypeBool, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalLTUInt32 }, + { PEX_LT , (PType **)&TypeBool, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalLTFloat64 }, + + { PEX_LTEQ , (PType **)&TypeBool, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalLTEQSInt32 }, + { PEX_LTEQ , (PType **)&TypeBool, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalLTEQUInt32 }, + { PEX_LTEQ , (PType **)&TypeBool, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalLTEQFloat64 }, + + { PEX_EQEQ , (PType **)&TypeBool, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalEQEQSInt32 }, + { PEX_EQEQ , (PType **)&TypeBool, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalEQEQUInt32 }, + { PEX_EQEQ , (PType **)&TypeBool, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalEQEQFloat64 }, + + { PEX_LTGTEQ , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalLTGTEQSInt32 }, + { PEX_LTGTEQ , (PType **)&TypeSInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalLTGTEQUInt32 }, + { PEX_LTGTEQ , (PType **)&TypeSInt32, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalLTGTEQFloat64 }, + }; + for (size_t i = 0; i < countof(BinaryOpInit); ++i) + { + ZCC_OpInfo[BinaryOpInit[i].Op].AddProto(*BinaryOpInit[i].Res, *BinaryOpInit[i].Ltype, *BinaryOpInit[i].Rtype, BinaryOpInit[i].EvalConst); + } +} + +static void IntToS32(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + // Integers always fill out the full sized 32-bit field, so converting + // from a smaller sized integer to a 32-bit one is as simple as changing + // the type field. + expr->Type = TypeSInt32; +} + +static void S32toS8(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + expr->IntVal = ((expr->IntVal << 24) >> 24); + expr->Type = TypeSInt8; +} + +static void S32toS16(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + expr->IntVal = ((expr->IntVal << 16) >> 16); + expr->Type = TypeSInt16; +} + +static void S32toU8(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + expr->IntVal &= 0xFF; + expr->Type = TypeUInt8; +} + +static void S32toU16(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + expr->IntVal &= 0xFFFF; + expr->Type = TypeUInt16; +} + +static void S32toU32(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + expr->Type = TypeUInt32; +} + +static void S32toD(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + expr->DoubleVal = expr->IntVal; + expr->Type = TypeFloat64; +} + +static void DtoS32(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + expr->IntVal = (int)expr->DoubleVal; + expr->Type = TypeSInt32; +} + +static void U32toD(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + expr->DoubleVal = expr->UIntVal; + expr->Type = TypeFloat64; +} + +static void DtoU32(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + expr->UIntVal = (unsigned int)expr->DoubleVal; + expr->Type = TypeUInt32; +} + +static void FtoD(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + // Constant single precision numbers are stored as doubles. + assert(expr->Type == TypeFloat32); + expr->Type = TypeFloat64; +} + +static void DtoF(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + // Truncate double precision to single precision. + float poop = (float)expr->DoubleVal; + expr->DoubleVal = poop; + expr->Type = TypeFloat32; +} + +static void S32toS(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + char str[16]; + int len = mysnprintf(str, countof(str), "%i", expr->IntVal); + expr->StringVal = str_arena.Alloc(str, len); + expr->Type = TypeString; +} + +static void U32toS(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + char str[16]; + int len = mysnprintf(str, countof(str), "%u", expr->UIntVal); + expr->StringVal = str_arena.Alloc(str, len); + expr->Type = TypeString; +} + +static void DtoS(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) +{ + // Convert to a string with enough precision such that converting + // back to a double will not lose any data. + char str[64]; + IGNORE_FORMAT_PRE + int len = mysnprintf(str, countof(str), "%H", expr->DoubleVal); + IGNORE_FORMAT_POST + expr->StringVal = str_arena.Alloc(str, len); + expr->Type = TypeString; +} + +//========================================================================== +// +// ZCC_InitConversions +// +//========================================================================== + +void ZCC_InitConversions() +{ + TypeUInt8->AddConversion(TypeSInt32, IntToS32); + TypeSInt8->AddConversion(TypeSInt32, IntToS32); + TypeUInt16->AddConversion(TypeSInt32, IntToS32); + TypeSInt16->AddConversion(TypeSInt32, IntToS32); + + TypeUInt32->AddConversion(TypeSInt32, IntToS32); + TypeUInt32->AddConversion(TypeFloat64, U32toD); + TypeUInt32->AddConversion(TypeString, U32toS); + + TypeSInt32->AddConversion(TypeUInt8, S32toU8); + TypeSInt32->AddConversion(TypeSInt8, S32toS8); + TypeSInt32->AddConversion(TypeSInt16, S32toS16); + TypeSInt32->AddConversion(TypeUInt16, S32toU16); + TypeSInt32->AddConversion(TypeUInt32, S32toU32); + TypeSInt32->AddConversion(TypeFloat64, S32toD); + TypeSInt32->AddConversion(TypeString, S32toS); + + TypeFloat32->AddConversion(TypeFloat64, FtoD); + + TypeFloat64->AddConversion(TypeUInt32, DtoU32); + TypeFloat64->AddConversion(TypeSInt32, DtoS32); + TypeFloat64->AddConversion(TypeFloat32, DtoF); + TypeFloat64->AddConversion(TypeString, DtoS); +} diff --git a/src/zscript/zcc_exprlist.h b/src/zscript/zcc_exprlist.h new file mode 100644 index 0000000000..e36aedea63 --- /dev/null +++ b/src/zscript/zcc_exprlist.h @@ -0,0 +1,57 @@ +// Name n-ary +xx(Nil, ) + +xx(ID, ) +xx(Super, ) +xx(Self, ) +xx(ConstValue, ) +xx(FuncCall, ) +xx(ArrayAccess, ) +xx(MemberAccess, ) +xx(TypeRef, ) + +xx(PostInc, ) +xx(PostDec, ) + +xx(PreInc, ) +xx(PreDec, ) +xx(Negate, ) +xx(AntiNegate, ) +xx(BitNot, ) +xx(BoolNot, ) +xx(SizeOf, ) +xx(AlignOf, ) + +xx(Add, ) +xx(Sub, ) +xx(Mul, ) +xx(Div, ) +xx(Mod, ) +xx(Pow, ) +xx(CrossProduct, ) +xx(DotProduct, ) +xx(LeftShift, ) +xx(RightShift, ) +xx(Concat, ) + +xx(LT, ) +xx(LTEQ, ) +xx(LTGTEQ, ) +xx(Is, ) + +xx(EQEQ, ) +xx(APREQ, ) + +xx(BitAnd, ) +xx(BitOr, ) +xx(BitXor, ) +xx(BoolAnd, ) +xx(BoolOr, ) + +xx(Scope, ) + +xx(Trinary, ) + +xx(Cast, ) + +#undef xx diff --git a/src/zscript/zcc_parser.cpp b/src/zscript/zcc_parser.cpp new file mode 100644 index 0000000000..b79de0f626 --- /dev/null +++ b/src/zscript/zcc_parser.cpp @@ -0,0 +1,327 @@ +#include "dobject.h" +#include "sc_man.h" +#include "c_console.h" +#include "c_dispatch.h" +#include "w_wad.h" +#include "cmdlib.h" +#include "m_alloc.h" +#include "zcc_parser.h" +#include "zcc_compile.h" + +static FString ZCCTokenName(int terminal); + +#include "zcc-parse.h" +#include "zcc-parse.c" + +struct TokenMapEntry +{ + SWORD TokenType; + WORD TokenName; + TokenMapEntry(SWORD a, WORD b) + : TokenType(a), TokenName(b) + { } +}; +static TMap TokenMap; +static SWORD BackTokenMap[YYERRORSYMBOL]; // YYERRORSYMBOL immediately follows the terminals described by the grammar + +#define TOKENDEF2(sc, zcc, name) { TokenMapEntry tme(zcc, name); TokenMap.Insert(sc, tme); } BackTokenMap[zcc] = sc +#define TOKENDEF(sc, zcc) TOKENDEF2(sc, zcc, NAME_None) + +static void InitTokenMap() +{ + TOKENDEF ('=', ZCC_EQ); + TOKENDEF (TK_MulEq, ZCC_MULEQ); + TOKENDEF (TK_DivEq, ZCC_DIVEQ); + TOKENDEF (TK_ModEq, ZCC_MODEQ); + TOKENDEF (TK_AddEq, ZCC_ADDEQ); + TOKENDEF (TK_SubEq, ZCC_SUBEQ); + TOKENDEF (TK_LShiftEq, ZCC_LSHEQ); + TOKENDEF (TK_RShiftEq, ZCC_RSHEQ); + TOKENDEF (TK_AndEq, ZCC_ANDEQ); + TOKENDEF (TK_OrEq, ZCC_OREQ); + TOKENDEF (TK_XorEq, ZCC_XOREQ); + TOKENDEF ('?', ZCC_QUESTION); + TOKENDEF (':', ZCC_COLON); + TOKENDEF (TK_OrOr, ZCC_OROR); + TOKENDEF (TK_AndAnd, ZCC_ANDAND); + TOKENDEF (TK_Eq, ZCC_EQEQ); + TOKENDEF (TK_Neq, ZCC_NEQ); + TOKENDEF (TK_ApproxEq, ZCC_APPROXEQ); + TOKENDEF ('<', ZCC_LT); + TOKENDEF ('>', ZCC_GT); + TOKENDEF (TK_Leq, ZCC_LTEQ); + TOKENDEF (TK_Geq, ZCC_GTEQ); + TOKENDEF (TK_LtGtEq, ZCC_LTGTEQ); + TOKENDEF (TK_Is, ZCC_IS); + TOKENDEF (TK_DotDot, ZCC_DOTDOT); + TOKENDEF ('|', ZCC_OR); + TOKENDEF ('^', ZCC_XOR); + TOKENDEF ('&', ZCC_AND); + TOKENDEF (TK_LShift, ZCC_LSH); + TOKENDEF (TK_RShift, ZCC_RSH); + TOKENDEF ('-', ZCC_SUB); + TOKENDEF ('+', ZCC_ADD); + TOKENDEF ('*', ZCC_MUL); + TOKENDEF ('/', ZCC_DIV); + TOKENDEF ('%', ZCC_MOD); + TOKENDEF (TK_Cross, ZCC_CROSSPROD); + TOKENDEF (TK_Dot, ZCC_DOTPROD); + TOKENDEF (TK_MulMul, ZCC_POW); + TOKENDEF (TK_Incr, ZCC_ADDADD); + TOKENDEF (TK_Decr, ZCC_SUBSUB); + TOKENDEF ('.', ZCC_DOT); + TOKENDEF ('(', ZCC_LPAREN); + TOKENDEF (')', ZCC_RPAREN); + TOKENDEF (TK_ColonColon, ZCC_SCOPE); + TOKENDEF (';', ZCC_SEMICOLON); + TOKENDEF (',', ZCC_COMMA); + TOKENDEF (TK_Class, ZCC_CLASS); + TOKENDEF (TK_Abstract, ZCC_ABSTRACT); + TOKENDEF (TK_Native, ZCC_NATIVE); + TOKENDEF (TK_Replaces, ZCC_REPLACES); + TOKENDEF (TK_Static, ZCC_STATIC); + TOKENDEF (TK_Private, ZCC_PRIVATE); + TOKENDEF (TK_Protected, ZCC_PROTECTED); + TOKENDEF (TK_Latent, ZCC_LATENT); + TOKENDEF (TK_Final, ZCC_FINAL); + TOKENDEF (TK_Meta, ZCC_META); + TOKENDEF (TK_Deprecated, ZCC_DEPRECATED); + TOKENDEF (TK_ReadOnly, ZCC_READONLY); + TOKENDEF ('{', ZCC_LBRACE); + TOKENDEF ('}', ZCC_RBRACE); + TOKENDEF (TK_Struct, ZCC_STRUCT); + TOKENDEF (TK_Enum, ZCC_ENUM); + TOKENDEF2(TK_SByte, ZCC_SBYTE, NAME_sByte); + TOKENDEF2(TK_Byte, ZCC_BYTE, NAME_Byte); + TOKENDEF2(TK_Short, ZCC_SHORT, NAME_Short); + TOKENDEF2(TK_UShort, ZCC_USHORT, NAME_uShort); + TOKENDEF2(TK_Int, ZCC_INT, NAME_Int); + TOKENDEF2(TK_UInt, ZCC_UINT, NAME_uInt); + TOKENDEF2(TK_Bool, ZCC_BOOL, NAME_Bool); + TOKENDEF2(TK_Float, ZCC_FLOAT, NAME_Float); + TOKENDEF2(TK_Double, ZCC_DOUBLE, NAME_Double); + TOKENDEF2(TK_String, ZCC_STRING, NAME_String); + TOKENDEF2(TK_Vector, ZCC_VECTOR, NAME_Vector); + TOKENDEF2(TK_Name, ZCC_NAME, NAME_Name); + TOKENDEF2(TK_Map, ZCC_MAP, NAME_Map); + TOKENDEF2(TK_Array, ZCC_ARRAY, NAME_Array); + TOKENDEF (TK_Void, ZCC_VOID); + TOKENDEF (TK_True, ZCC_TRUE); + TOKENDEF (TK_False, ZCC_FALSE); + TOKENDEF ('[', ZCC_LBRACKET); + TOKENDEF (']', ZCC_RBRACKET); + TOKENDEF (TK_In, ZCC_IN); + TOKENDEF (TK_Out, ZCC_OUT); + TOKENDEF (TK_Optional, ZCC_OPTIONAL); + TOKENDEF (TK_Super, ZCC_SUPER); + TOKENDEF (TK_Self, ZCC_SELF); + TOKENDEF ('~', ZCC_TILDE); + TOKENDEF ('!', ZCC_BANG); + TOKENDEF (TK_SizeOf, ZCC_SIZEOF); + TOKENDEF (TK_AlignOf, ZCC_ALIGNOF); + TOKENDEF (TK_Continue, ZCC_CONTINUE); + TOKENDEF (TK_Break, ZCC_BREAK); + TOKENDEF (TK_Return, ZCC_RETURN); + TOKENDEF (TK_Do, ZCC_DO); + TOKENDEF (TK_For, ZCC_FOR); + TOKENDEF (TK_While, ZCC_WHILE); + TOKENDEF (TK_Until, ZCC_UNTIL); + TOKENDEF (TK_If, ZCC_IF); + TOKENDEF (TK_Else, ZCC_ELSE); + TOKENDEF (TK_Switch, ZCC_SWITCH); + TOKENDEF (TK_Case, ZCC_CASE); + TOKENDEF2(TK_Default, ZCC_DEFAULT, NAME_Default); + TOKENDEF (TK_Const, ZCC_CONST); + TOKENDEF (TK_Stop, ZCC_STOP); + TOKENDEF (TK_Wait, ZCC_WAIT); + TOKENDEF (TK_Fail, ZCC_FAIL); + TOKENDEF (TK_Loop, ZCC_LOOP); + TOKENDEF (TK_Goto, ZCC_GOTO); + TOKENDEF (TK_States, ZCC_STATES); + + TOKENDEF (TK_Identifier, ZCC_IDENTIFIER); + TOKENDEF (TK_StringConst, ZCC_STRCONST); + TOKENDEF (TK_NameConst, ZCC_NAMECONST); + TOKENDEF (TK_IntConst, ZCC_INTCONST); + TOKENDEF (TK_UIntConst, ZCC_UINTCONST); + TOKENDEF (TK_FloatConst, ZCC_FLOATCONST); + TOKENDEF (TK_NonWhitespace, ZCC_NWS); + + ZCC_InitOperators(); + ZCC_InitConversions(); +} +#undef TOKENDEF +#undef TOKENDEF2 + +static void DoParse(const char *filename) +{ + if (TokenMap.CountUsed() == 0) + { + InitTokenMap(); + } + + FScanner sc; + void *parser; + int tokentype; + int lump; + bool failed; + ZCCToken value; + + lump = Wads.CheckNumForFullName(filename, true); + if (lump >= 0) + { + sc.OpenLumpNum(lump); + } + else if (FileExists(filename)) + { + sc.OpenFile(filename); + } + else + { + Printf("Could not find script lump '%s'\n", filename); + return; + } + + parser = ZCCParseAlloc(malloc); + failed = false; +#ifdef _DEBUG + FILE *f = fopen("trace.txt", "w"); + char prompt = '\0'; + ZCCParseTrace(f, &prompt); +#endif + ZCCParseState state(sc); + + while (sc.GetToken()) + { + value.SourceLoc = sc.GetMessageLine(); + if (sc.TokenType == TK_StringConst) + { + value.String = state.Strings.Alloc(sc.String, sc.StringLen); + tokentype = ZCC_STRCONST; + } + else if (sc.TokenType == TK_NameConst) + { + value.Int = sc.Name; + tokentype = ZCC_NAMECONST; + } + else if (sc.TokenType == TK_IntConst) + { + value.Int = sc.Number; + tokentype = ZCC_INTCONST; + } + else if (sc.TokenType == TK_UIntConst) + { + value.Int = sc.Number; + tokentype = ZCC_UINTCONST; + } + else if (sc.TokenType == TK_FloatConst) + { + value.Float = sc.Float; + tokentype = ZCC_FLOATCONST; + } + else if (sc.TokenType == TK_Identifier) + { + value.Int = FName(sc.String); + tokentype = ZCC_IDENTIFIER; + } + else if (sc.TokenType == TK_NonWhitespace) + { + value.Int = FName(sc.String); + tokentype = ZCC_NWS; + } + else + { + TokenMapEntry *zcctoken = TokenMap.CheckKey(sc.TokenType); + if (zcctoken != NULL) + { + tokentype = zcctoken->TokenType; + value.Int = zcctoken->TokenName; + } + else + { + sc.ScriptMessage("Unexpected token %s.\n", sc.TokenName(sc.TokenType).GetChars()); + break; + } + } + ZCCParse(parser, tokentype, value, &state); + if (failed) + { + sc.ScriptMessage("Parse failed\n"); + break; + } + } + value.Int = -1; + ZCCParse(parser, ZCC_EOF, value, &state); + ZCCParse(parser, 0, value, &state); + ZCCParseFree(parser, free); + + PSymbolTable symbols(&GlobalSymbols); + ZCCCompiler cc(state, NULL, symbols); + cc.Compile(); +#ifdef _DEBUG + if (f != NULL) + { + fclose(f); + } + FString ast = ZCC_PrintAST(state.TopNode); + FString astfile = ExtractFileBase(filename, false); + astfile << ".ast"; + f = fopen(astfile, "w"); + if (f != NULL) + { + fputs(ast.GetChars(), f); + fclose(f); + } +#endif +} + +CCMD(parse) +{ + if (argv.argc() == 2) + { + DoParse(argv[1]); + } +} + +static FString ZCCTokenName(int terminal) +{ + if (terminal == ZCC_EOF) + { + return "end of file"; + } + int sc_token; + if (terminal > 0 && terminal < (int)countof(BackTokenMap)) + { + sc_token = BackTokenMap[terminal]; + if (sc_token == 0) + { // This token was not initialized. Whoops! + sc_token = -terminal; + } + } + else + { // This should never happen. + sc_token = -terminal; + } + return FScanner::TokenName(sc_token); +} + +ZCC_TreeNode *ZCC_AST::InitNode(size_t size, EZCCTreeNodeType type, ZCC_TreeNode *basis) +{ + ZCC_TreeNode *node = (ZCC_TreeNode *)SyntaxArena.Alloc(size); + node->SiblingNext = node; + node->SiblingPrev = node; + node->NodeType = type; + if (basis != NULL) + { + node->SourceName = basis->SourceName; + node->SourceLoc = basis->SourceLoc; + } + return node; +} + +ZCC_TreeNode *ZCCParseState::InitNode(size_t size, EZCCTreeNodeType type) +{ + ZCC_TreeNode *node = ZCC_AST::InitNode(size, type, NULL); + node->SourceName = Strings.Alloc(sc.ScriptName); + return node; +} diff --git a/src/zscript/zcc_parser.h b/src/zscript/zcc_parser.h new file mode 100644 index 0000000000..6512ee0f77 --- /dev/null +++ b/src/zscript/zcc_parser.h @@ -0,0 +1,516 @@ +#ifndef ZCC_PARSER_H +#define ZCC_PARSER_H + +#include "memarena.h" + +struct ZCCToken +{ + union + { + int Int; + double Float; + FString *String; + }; + int SourceLoc; + + ENamedName Name() { return ENamedName(Int); } +}; + +// Variable / Function modifiers +enum +{ + ZCC_Native = 1 << 0, + ZCC_Static = 1 << 1, + ZCC_Private = 1 << 2, + ZCC_Protected = 1 << 3, + ZCC_Latent = 1 << 4, + ZCC_Final = 1 << 5, + ZCC_Meta = 1 << 6, + ZCC_Action = 1 << 7, + ZCC_Deprecated = 1 << 8, + ZCC_ReadOnly = 1 << 9, + ZCC_FuncConst = 1 << 10, +}; + +// Function parameter modifiers +enum +{ + ZCC_In = 1 << 0, + ZCC_Out = 1 << 1, + ZCC_Optional = 1 << 2, +}; + + + +// Syntax tree structures. +enum EZCCTreeNodeType +{ + AST_Identifier, + AST_Class, + AST_Struct, + AST_Enum, + AST_EnumTerminator, + AST_States, + AST_StatePart, + AST_StateLabel, + AST_StateStop, + AST_StateWait, + AST_StateFail, + AST_StateLoop, + AST_StateGoto, + AST_StateLine, + AST_VarName, + AST_Type, + AST_BasicType, + AST_MapType, + AST_DynArrayType, + AST_ClassType, + AST_Expression, + AST_ExprID, + AST_ExprTypeRef, + AST_ExprConstant, + AST_ExprFuncCall, + AST_ExprMemberAccess, + AST_ExprUnary, + AST_ExprBinary, + AST_ExprTrinary, + AST_FuncParm, + AST_Statement, + AST_CompoundStmt, + AST_ContinueStmt, + AST_BreakStmt, + AST_ReturnStmt, + AST_ExpressionStmt, + AST_IterationStmt, + AST_IfStmt, + AST_SwitchStmt, + AST_CaseStmt, + AST_AssignStmt, + AST_LocalVarStmt, + AST_FuncParamDecl, + AST_ConstantDef, + AST_Declarator, + AST_VarDeclarator, + AST_FuncDeclarator, + + NUM_AST_NODE_TYPES +}; + +enum EZCCBuiltinType +{ + ZCC_SInt8, + ZCC_UInt8, + ZCC_SInt16, + ZCC_UInt16, + ZCC_SInt32, + ZCC_UInt32, + ZCC_IntAuto, // for enums, autoselect appropriately sized int + + ZCC_Bool, + ZCC_Float32, + ZCC_Float64, + ZCC_FloatAuto, // 32-bit in structs/classes, 64-bit everywhere else + ZCC_String, + ZCC_Vector2, + ZCC_Vector3, + ZCC_Vector4, + ZCC_Name, + ZCC_UserType, + + ZCC_NUM_BUILT_IN_TYPES +}; + +enum EZCCExprType +{ +#define xx(a,z) PEX_##a, +#include "zcc_exprlist.h" + + PEX_COUNT_OF +}; + +struct ZCC_TreeNode +{ + // This tree node's siblings are stored in a circular linked list. + // When you get back to this node, you know you've been through + // the whole list. + ZCC_TreeNode *SiblingNext; + ZCC_TreeNode *SiblingPrev; + + // can't use FScriptPosition, because the string wouldn't have a chance to + // destruct if we did that. + FString *SourceName; + int SourceLoc; + + // Node type is one of the node types above, which corresponds with + // one of the structures below. + EZCCTreeNodeType NodeType; + + // Appends a sibling to this node's sibling list. + void AppendSibling(ZCC_TreeNode *sibling) + { + if (sibling == NULL) + { + return; + } + + // Check integrity of our sibling list. + assert(SiblingPrev->SiblingNext == this); + assert(SiblingNext->SiblingPrev == this); + + // Check integrity of new sibling list. + assert(sibling->SiblingPrev->SiblingNext = sibling); + assert(sibling->SiblingNext->SiblingPrev = sibling); + + ZCC_TreeNode *siblingend = sibling->SiblingPrev; + SiblingPrev->SiblingNext = sibling; + sibling->SiblingPrev = SiblingPrev; + SiblingPrev = siblingend; + siblingend->SiblingNext = this; + } +}; + +struct ZCC_Identifier : ZCC_TreeNode +{ + ENamedName Id; +}; + +struct ZCC_Class : ZCC_TreeNode +{ + ENamedName ClassName; + ZCC_Identifier *ParentName; + ZCC_Identifier *Replaces; + VM_UWORD Flags; + ZCC_TreeNode *Body; +}; + +struct ZCC_Struct : ZCC_TreeNode +{ + ENamedName StructName; + ZCC_TreeNode *Body; +}; + +struct ZCC_Enum : ZCC_TreeNode +{ + ENamedName EnumName; + EZCCBuiltinType EnumType; + struct ZCC_ConstantDef *Elements; +}; + +struct ZCC_EnumTerminator : ZCC_TreeNode +{ +}; + +struct ZCC_States : ZCC_TreeNode +{ + struct ZCC_StatePart *Body; +}; + +struct ZCC_StatePart : ZCC_TreeNode +{ +}; + +struct ZCC_StateLabel : ZCC_StatePart +{ + ENamedName Label; +}; + +struct ZCC_StateStop : ZCC_StatePart +{ +}; + +struct ZCC_StateWait : ZCC_StatePart +{ +}; + +struct ZCC_StateFail : ZCC_StatePart +{ +}; + +struct ZCC_StateLoop : ZCC_StatePart +{ +}; + +struct ZCC_Expression : ZCC_TreeNode +{ + EZCCExprType Operation; + PType *Type; + + // Repurposes this node as an error node + void ToErrorNode() + { + Type = TypeError; + Operation = PEX_Nil; + NodeType = AST_Expression; + } +}; + +struct ZCC_StateGoto : ZCC_StatePart +{ + ZCC_Identifier *Label; + ZCC_Expression *Offset; +}; + +struct ZCC_StateLine : ZCC_StatePart +{ + char Sprite[4]; + BITFIELD bBright:1; + FString *Frames; + ZCC_Expression *Offset; + ZCC_TreeNode *Action; +}; + +struct ZCC_VarName : ZCC_TreeNode +{ + ENamedName Name; + ZCC_Expression *ArraySize; // NULL if not an array +}; + +struct ZCC_Type : ZCC_TreeNode +{ + ZCC_Expression *ArraySize; // NULL if not an array +}; + +struct ZCC_BasicType : ZCC_Type +{ + EZCCBuiltinType Type; + ZCC_Identifier *UserType; +}; + +struct ZCC_MapType : ZCC_Type +{ + ZCC_Type *KeyType; + ZCC_Type *ValueType; +}; + +struct ZCC_DynArrayType : ZCC_Type +{ + ZCC_Type *ElementType; +}; + +struct ZCC_ClassType : ZCC_Type +{ + ZCC_Identifier *Restriction; +}; + +struct ZCC_ExprID : ZCC_Expression +{ + ENamedName Identifier; +}; + +struct ZCC_ExprTypeRef : ZCC_Expression +{ + PType *RefType; +}; + +struct ZCC_ExprConstant : ZCC_Expression +{ + union + { + FString *StringVal; + int IntVal; + unsigned int UIntVal; + double DoubleVal; + }; +}; + +struct ZCC_FuncParm : ZCC_TreeNode +{ + ZCC_Expression *Value; + ENamedName Label; +}; + +struct ZCC_ExprFuncCall : ZCC_Expression +{ + ZCC_Expression *Function; + ZCC_FuncParm *Parameters; +}; + +struct ZCC_ExprMemberAccess : ZCC_Expression +{ + ZCC_Expression *Left; + ENamedName Right; +}; + +struct ZCC_ExprUnary : ZCC_Expression +{ + ZCC_Expression *Operand; +}; + +struct ZCC_ExprBinary : ZCC_Expression +{ + ZCC_Expression *Left; + ZCC_Expression *Right; +}; + +struct ZCC_ExprTrinary : ZCC_Expression +{ + ZCC_Expression *Test; + ZCC_Expression *Left; + ZCC_Expression *Right; +}; + +struct ZCC_Statement : ZCC_TreeNode +{ +}; + +struct ZCC_CompoundStmt : ZCC_Statement +{ + ZCC_Statement *Content; +}; + +struct ZCC_ContinueStmt : ZCC_Statement +{ +}; + +struct ZCC_BreakStmt : ZCC_Statement +{ +}; + +struct ZCC_ReturnStmt : ZCC_Statement +{ + ZCC_Expression *Values; +}; + +struct ZCC_ExpressionStmt : ZCC_Statement +{ + ZCC_Expression *Expression; +}; + +struct ZCC_IterationStmt : ZCC_Statement +{ + ZCC_Expression *LoopCondition; + ZCC_Statement *LoopStatement; + ZCC_Statement *LoopBumper; + + // Should the loop condition be checked at the + // start of the loop (before the LoopStatement) + // or at the end (after the LoopStatement)? + enum { Start, End } CheckAt; +}; + +struct ZCC_IfStmt : ZCC_Statement +{ + ZCC_Expression *Condition; + ZCC_Statement *TruePath; + ZCC_Statement *FalsePath; +}; + +struct ZCC_SwitchStmt : ZCC_Statement +{ + ZCC_Expression *Condition; + ZCC_Statement *Content; +}; + +struct ZCC_CaseStmt : ZCC_Statement +{ + // A NULL Condition represents the default branch + ZCC_Expression *Condition; +}; + +struct ZCC_AssignStmt : ZCC_Statement +{ + ZCC_Expression *Dests; + ZCC_Expression *Sources; + int AssignOp; +}; + +struct ZCC_LocalVarStmt : ZCC_Statement +{ + ZCC_Type *Type; + ZCC_VarName *Vars; + ZCC_Expression *Inits; +}; + +struct ZCC_FuncParamDecl : ZCC_TreeNode +{ + ZCC_Type *Type; + ENamedName Name; + int Flags; +}; + +struct ZCC_ConstantDef : ZCC_TreeNode +{ + ENamedName Name; + ZCC_Expression *Value; + PSymbolConst *Symbol; +}; + +struct ZCC_Declarator : ZCC_TreeNode +{ + ZCC_Type *Type; + int Flags; +}; + +// A variable in a class or struct. +struct ZCC_VarDeclarator : ZCC_Declarator +{ + ZCC_VarName *Names; +}; + +// A function in a class. +struct ZCC_FuncDeclarator : ZCC_Declarator +{ + ZCC_FuncParamDecl *Params; + ENamedName Name; + ZCC_Statement *Body; +}; + +typedef ZCC_ExprConstant *(*EvalConst1op)(ZCC_ExprConstant *); +typedef ZCC_ExprConstant *(*EvalConst2op)(ZCC_ExprConstant *, ZCC_ExprConstant *, FSharedStringArena &); + +struct ZCC_OpProto +{ + ZCC_OpProto *Next; + PType *ResType; + PType *Type1; + PType *Type2; + union + { + EvalConst1op EvalConst1; + EvalConst2op EvalConst2; + }; + + ZCC_OpProto(PType *res, PType *t1, PType *t2) + : ResType(res), Type1(t1), Type2(t2) {} +}; + +struct ZCC_OpInfoType +{ + const char *OpName; + ZCC_OpProto *Protos; + + void AddProto(PType *res, PType *optype, EvalConst1op evalconst); + void AddProto(PType *res, PType *left, PType *right, EvalConst2op evalconst); + + ZCC_OpProto *FindBestProto(PType *optype, const PType::Conversion **route, int &numslots); + ZCC_OpProto *FindBestProto(PType *left, const PType::Conversion **route1, int &numslots, + PType *right, const PType::Conversion **route2, int &numslots2); +}; + +#define CONVERSION_ROUTE_SIZE 8 + +FString ZCC_PrintAST(ZCC_TreeNode *root); + +void ZCC_InitOperators(); + +extern ZCC_OpInfoType ZCC_OpInfo[PEX_COUNT_OF]; + +struct ZCC_AST +{ + ZCC_AST() : TopNode(NULL) {} + ZCC_TreeNode *InitNode(size_t size, EZCCTreeNodeType type, ZCC_TreeNode *basis); + + FSharedStringArena Strings; + FMemArena SyntaxArena; + struct ZCC_TreeNode *TopNode; +}; + +struct ZCCParseState : public ZCC_AST +{ + ZCCParseState(FScanner &scanner) : sc(scanner) {} + ZCC_TreeNode *InitNode(size_t size, EZCCTreeNodeType type); + + FScanner ≻ +}; + +#endif diff --git a/src/zstrformat.cpp b/src/zstrformat.cpp index c048595ab8..7433dd574a 100644 --- a/src/zstrformat.cpp +++ b/src/zstrformat.cpp @@ -638,6 +638,12 @@ namespace StringFormat } goto fp_begin; } + else if (type == 'H') + { // %H is an extension that behaves similarly to %g, except it automatically + // selects precision based on whatever will produce the smallest string. + expchar = 'e'; + goto fp_begin; + } #if 0 // The hdtoa function provided with FreeBSD uses a hexadecimal FP constant. // Microsoft's compiler does not support these, so I would need to hack it @@ -690,7 +696,7 @@ fp_begin: precision = DEFPREC; } dblarg = va_arg(arglist, double); - obuff = dtoaresult = dtoa(dblarg, expchar ? 2 : 3, precision, &expt, &signflag, &dtoaend); + obuff = dtoaresult = dtoa(dblarg, type != 'H' ? (expchar ? 2 : 3) : 0, precision, &expt, &signflag, &dtoaend); //fp_common: decimal_point = localeconv()->decimal_point; flags |= F_SIGNED; @@ -742,6 +748,22 @@ fp_begin: } } } + else if (type == 'H') + { + if (expt > -(ndig + 2) && expt <= (ndig + 4)) + { // Make %H smell like %f + expchar = '\0'; + precision = ndig - expt; + if (precision < 0) + { + precision = 0; + } + } + else + {// Make %H smell like %e + precision = ndig; + } + } if (expchar) { expsize = exponent(expstr, expt - 1, expchar); diff --git a/src/zstring.h b/src/zstring.h index 82c38142c5..90c80e752a 100644 --- a/src/zstring.h +++ b/src/zstring.h @@ -348,14 +348,12 @@ inline FName::FName(const FString &text, bool noCreate) { Index = NameData.FindN inline FName &FName::operator = (const FString &text) { Index = NameData.FindName (text, text.Len(), false); return *this; } inline FName &FNameNoInit::operator = (const FString &text) { Index = NameData.FindName (text, text.Len(), false); return *this; } -// Hash for TMap -extern unsigned int SuperFastHash(const char *data, size_t len); +// Hash FStrings on their contents. (used by TMap) +extern unsigned int SuperFastHash (const char *data, size_t len); template<> struct THashTraits { - hash_t Hash(const FString &key) { return (hash_t)SuperFastHash(key, key.Len()+1); } - + hash_t Hash(const FString &key) { return (hash_t)SuperFastHash(key, key.Len()); } // Compares two keys, returning zero if they are the same. int Compare(const FString &left, const FString &right) { return left.Compare(right); } }; - #endif diff --git a/src/zzautozend.cpp b/src/zzautozend.cpp index 023f8c733c..54a506756d 100644 --- a/src/zzautozend.cpp +++ b/src/zzautozend.cpp @@ -37,34 +37,27 @@ #if defined(_MSC_VER) -#pragma data_seg(".areg$z") -void *ARegTail = 0; +#pragma section(".areg$z",read) +__declspec(allocate(".areg$z")) void *const ARegTail = 0; -#pragma data_seg(".creg$z") -void *CRegTail = 0; +#pragma section(".creg$z",read) +__declspec(allocate(".creg$z")) void *const CRegTail = 0; -#pragma data_seg(".greg$z") -void *GRegTail = 0; - -#pragma data_seg(".mreg$z") -void *MRegTail = 0; - -#pragma data_seg(".yreg$z") -void *YRegTail = 0; - -#pragma data_seg() +#pragma section(".greg$z",read) +__declspec(allocate(".greg$z")) void *const GRegTail = 0; +#pragma section(".yreg$z",read) +__declspec(allocate(".yreg$z")) void *const YRegTail = 0; #elif defined(__GNUC__) #include "doomtype.h" -void *ARegTail __attribute__((section(SECTION_AREG))) = 0; -void *CRegTail __attribute__((section(SECTION_CREG))) = 0; -void *GRegTail __attribute__((section(SECTION_GREG))) = 0; -void *MRegTail __attribute__((section(SECTION_MREG))) = 0; -void *YRegTail __attribute__((section(SECTION_YREG))) = 0; +void *const ARegTail __attribute__((section(SECTION_AREG))) = 0; +void *const CRegTail __attribute__((section(SECTION_CREG))) = 0; +void *const GRegTail __attribute__((section(SECTION_GREG))) = 0; +void *const YRegTail __attribute__((section(SECTION_YREG))) = 0; #else diff --git a/tools/lemon/lemon.c b/tools/lemon/lemon.c index 651e43f208..c6eea3c10c 100644 --- a/tools/lemon/lemon.c +++ b/tools/lemon/lemon.c @@ -6,9 +6,9 @@ ** ** The author of this program disclaims copyright. ** -** This file is based on version 1.43 of lemon.c from the SQLite -** source tree, with modifications to make it work nicer when run -** by Developer Studio. +** This file is based on version 1.69 of lemon.c from the SQLite +** CVS, with modifications to make it work nicer when run +** from Developer Studio. */ #include #include @@ -40,6 +40,13 @@ extern int access(); static void *msort(void *list, void *next, int (*cmp)()); +/* +** Compilers are getting increasingly pedantic about type conversions +** as C evolves ever closer to Ada.... To work around the latest problems +** we have to define the following variant of strlen(). +*/ +#define lemonStrlen(X) ((int)strlen(X)) + /******** From the file "action.h" *************************************/ static struct action *Action_new(void); static struct action *Action_sort(struct action *); @@ -133,13 +140,13 @@ struct symbol { RIGHT, NONE, UNK - } assoc; /* Associativity if predecence is defined */ + } assoc; /* Associativity if precedence is defined */ char *firstset; /* First-set for all rules of this symbol */ Boolean lambda; /* True if NT and can generate an empty string */ int useCnt; /* Number of times used */ char *destructor; /* Code which executes whenever this symbol is ** popped from the stack during error processing */ - int destructorln; /* Line number of destructor code */ + int destLineno; /* Line number for start of destructor */ char *datatype; /* The data type of information held by this ** object. Only used if type==NONTERMINAL */ int dtnum; /* The data type number. In the parser, the value @@ -217,7 +224,7 @@ struct action { struct state { struct config *bp; /* The basis configurations for this state */ struct config *cfp; /* All configurations in this set */ - int statenum; /* Sequencial number for this state */ + int statenum; /* Sequential number for this state */ struct action *ap; /* Array of actions for this state */ int nTknAct, nNtAct; /* Number of actions on terminals and nonterminals */ int iTknOfst, iNtOfst; /* yy_action[] offset for terminals and nonterms */ @@ -255,28 +262,21 @@ struct lemon { char *start; /* Name of the start symbol for the grammar */ char *stacksize; /* Size of the parser stack */ char *include; /* Code to put at the start of the C file */ - int includeln; /* Line number for start of include code */ char *error; /* Code to execute when an error is seen */ - int errorln; /* Line number for start of error code */ char *overflow; /* Code to execute on a stack overflow */ - int overflowln; /* Line number for start of overflow code */ char *failure; /* Code to execute on parser failure */ - int failureln; /* Line number for start of failure code */ char *accept; /* Code to execute when the parser excepts */ - int acceptln; /* Line number for the start of accept code */ char *extracode; /* Code appended to the generated file */ - int extracodeln; /* Line number for the start of the extra code */ char *tokendest; /* Code to execute to destroy token data */ - int tokendestln; /* Line number for token destroyer code */ char *vardest; /* Code for the default non-terminal destructor */ - int vardestln; /* Line number for default non-term destructor code*/ char *filename; /* Name of the input file */ char *outname; /* Name of the current output file */ char *tokenprefix; /* A prefix added to token names in the .h file */ int nconflict; /* Number of parsing conflicts */ int tablesize; /* Size of the parse tables */ int basisflag; /* Print only basis configurations */ - int has_fallback; /* True if any %fallback is seen in the grammer */ + int has_fallback; /* True if any %fallback is seen in the grammar */ + int nolinenosflag; /* True if #line statements should not be printed */ char *argv0; /* Name of the program */ }; @@ -633,7 +633,8 @@ struct lemon *lemp; if( rp->lhs->lambda ) continue; for(i=0; inrhs; i++){ struct symbol *sp = rp->rhs[i]; - if( sp->type!=TERMINAL || sp->lambda==LEMON_FALSE ) break; + assert( sp->type==NONTERMINAL || sp->lambda==LEMON_FALSE ); + if( sp->lambda==LEMON_FALSE ) break; } if( i==rp->nrhs ){ rp->lhs->lambda = LEMON_TRUE; @@ -998,7 +999,7 @@ struct lemon *lemp; } /* Resolve a conflict between the two given actions. If the -** conflict can't be resolve, return non-zero. +** conflict can't be resolved, return non-zero. ** ** NO LONGER TRUE: ** To resolve a conflict, first look to see if either action @@ -1345,13 +1346,13 @@ void ErrorMsg(const char *filename, int lineno, const char *format, ...){ sprintf(prefix,"%.*s: ",PREFIXLIMIT-10,filename); } #endif - prefixsize = strlen(prefix); + prefixsize = lemonStrlen(prefix); availablewidth = LINEWIDTH - prefixsize; /* Generate the error message */ vsprintf(errmsg,format,ap); va_end(ap); - errmsgsize = strlen(errmsg); + errmsgsize = lemonStrlen(errmsg); /* Remove trailing '\n's from the error message. */ while( errmsgsize>0 && errmsg[errmsgsize-1]=='\n' ){ errmsg[--errmsgsize] = 0; @@ -1395,7 +1396,7 @@ static void handle_D_option(char *z){ exit(1); } paz = &azDefine[nDefine-1]; - *paz = malloc( strlen(z)+1 ); + *paz = malloc( lemonStrlen(z)+1 ); if( *paz==0 ){ fprintf(stderr,"out of memory\n"); exit(1); @@ -1418,12 +1419,14 @@ char **argv; static int quiet = 0; static int statistics = 0; static int mhflag = 0; + static int nolinenosflag = 0; static struct s_options options[] = { {OPT_FLAG, "b", (char*)&basisflag, "Print only the basis in report."}, {OPT_FLAG, "c", (char*)&compress, "Don't compress the action table."}, {OPT_FSTR, "D", (char*)handle_D_option, "Define an %ifdef macro."}, {OPT_FLAG, "g", (char*)&rpflag, "Print grammar without actions."}, - {OPT_FLAG, "m", (char*)&mhflag, "Output a makeheaders compatible file"}, + {OPT_FLAG, "m", (char*)&mhflag, "Output a makeheaders compatible file."}, + {OPT_FLAG, "l", (char*)&nolinenosflag, "Do not print #line statements."}, {OPT_FLAG, "q", (char*)&quiet, "(Quiet) Don't print the report file."}, {OPT_FLAG, "s", (char*)&statistics, "Print parser stats to standard output."}, @@ -1452,6 +1455,7 @@ char **argv; lem.argv0 = argv[0]; lem.filename = OptArg(0); lem.basisflag = basisflag; + lem.nolinenosflag = nolinenosflag; Symbol_new("$"); lem.errsym = Symbol_new("error"); lem.errsym->useCnt = 0; @@ -1667,10 +1671,10 @@ FILE *err; int i; size_t spcnt; if( argv[0] ) fprintf(err,"%s",argv[0]); - spcnt = strlen(argv[0]) + 1; + spcnt = lemonStrlen(argv[0]) + 1; for(i=1; i%*s %s\n",op[i].label, - (int)(max-strlen(op[i].label)-9),"",op[i].message); + (int)(max-lemonStrlen(op[i].label)-9),"",op[i].message); break; case OPT_DBL: case OPT_FDBL: fprintf(errstream," %s=%*s %s\n",op[i].label, - (int)(max-strlen(op[i].label)-6),"",op[i].message); + (int)(max-lemonStrlen(op[i].label)-6),"",op[i].message); break; case OPT_STR: case OPT_FSTR: fprintf(errstream," %s=%*s %s\n",op[i].label, - (int)(max-strlen(op[i].label)-8),"",op[i].message); + (int)(max-lemonStrlen(op[i].label)-8),"",op[i].message); break; } } @@ -1979,7 +1983,8 @@ struct pstate { struct rule *prevrule; /* Previous rule parsed */ char *declkeyword; /* Keyword of a declaration */ char **declargslot; /* Where the declaration argument should be put */ - int *decllnslot; /* Where the declaration linenumber is put */ + int insertLineMacro; /* Add #line before declaration insert */ + int *decllinenoslot; /* Where to write declaration line number */ enum e_assoc declassoc; /* Assign this association to decl arguments */ int preccounter; /* Assign this precedence to decl arguments */ struct rule *firstrule; /* Pointer to first rule in the grammar */ @@ -2014,7 +2019,7 @@ struct pstate *psp; }else if( x[0]=='{' ){ if( psp->prevrule==0 ){ ErrorMsg(psp->filename,psp->tokenlineno, -"There is not prior rule opon which to attach the code \ +"There is no prior rule upon which to attach the code \ fragment which begins on this line."); psp->errorcnt++; }else if( psp->prevrule->code!=0 ){ @@ -2212,46 +2217,46 @@ to follow the previous rule."); if( isalpha(x[0]) ){ psp->declkeyword = x; psp->declargslot = 0; - psp->decllnslot = 0; + psp->decllinenoslot = 0; + psp->insertLineMacro = 1; psp->state = WAITING_FOR_DECL_ARG; if( strcmp(x,"name")==0 ){ psp->declargslot = &(psp->gp->name); + psp->insertLineMacro = 0; }else if( strcmp(x,"include")==0 ){ psp->declargslot = &(psp->gp->include); - psp->decllnslot = &psp->gp->includeln; }else if( strcmp(x,"code")==0 ){ psp->declargslot = &(psp->gp->extracode); - psp->decllnslot = &psp->gp->extracodeln; }else if( strcmp(x,"token_destructor")==0 ){ psp->declargslot = &psp->gp->tokendest; - psp->decllnslot = &psp->gp->tokendestln; }else if( strcmp(x,"default_destructor")==0 ){ psp->declargslot = &psp->gp->vardest; - psp->decllnslot = &psp->gp->vardestln; }else if( strcmp(x,"token_prefix")==0 ){ psp->declargslot = &psp->gp->tokenprefix; + psp->insertLineMacro = 0; }else if( strcmp(x,"syntax_error")==0 ){ psp->declargslot = &(psp->gp->error); - psp->decllnslot = &psp->gp->errorln; }else if( strcmp(x,"parse_accept")==0 ){ psp->declargslot = &(psp->gp->accept); - psp->decllnslot = &psp->gp->acceptln; }else if( strcmp(x,"parse_failure")==0 ){ psp->declargslot = &(psp->gp->failure); - psp->decllnslot = &psp->gp->failureln; }else if( strcmp(x,"stack_overflow")==0 ){ psp->declargslot = &(psp->gp->overflow); - psp->decllnslot = &psp->gp->overflowln; }else if( strcmp(x,"extra_argument")==0 ){ psp->declargslot = &(psp->gp->arg); + psp->insertLineMacro = 0; }else if( strcmp(x,"token_type")==0 ){ psp->declargslot = &(psp->gp->tokentype); + psp->insertLineMacro = 0; }else if( strcmp(x,"default_type")==0 ){ psp->declargslot = &(psp->gp->vartype); + psp->insertLineMacro = 0; }else if( strcmp(x,"stack_size")==0 ){ psp->declargslot = &(psp->gp->stacksize); + psp->insertLineMacro = 0; }else if( strcmp(x,"start_symbol")==0 ){ psp->declargslot = &(psp->gp->start); + psp->insertLineMacro = 0; }else if( strcmp(x,"left")==0 ){ psp->preccounter++; psp->declassoc = LEFT; @@ -2295,7 +2300,8 @@ to follow the previous rule."); }else{ struct symbol *sp = Symbol_new(x); psp->declargslot = &sp->destructor; - psp->decllnslot = &sp->destructorln; + psp->decllinenoslot = &sp->destLineno; + psp->insertLineMacro = 1; psp->state = WAITING_FOR_DECL_ARG; } break; @@ -2308,7 +2314,7 @@ to follow the previous rule."); }else{ struct symbol *sp = Symbol_new(x); psp->declargslot = &sp->datatype; - psp->decllnslot = 0; + psp->insertLineMacro = 0; psp->state = WAITING_FOR_DECL_ARG; } break; @@ -2333,18 +2339,56 @@ to follow the previous rule."); } break; case WAITING_FOR_DECL_ARG: - if( (x[0]=='{' || x[0]=='\"' || isalnum(x[0])) ){ - if( *(psp->declargslot)!=0 ){ - ErrorMsg(psp->filename,psp->tokenlineno, - "The argument \"%s\" to declaration \"%%%s\" is not the first.", - x[0]=='\"' ? &x[1] : x,psp->declkeyword); - psp->errorcnt++; - psp->state = RESYNC_AFTER_DECL_ERROR; - }else{ - *(psp->declargslot) = (x[0]=='\"' || x[0]=='{') ? &x[1] : x; - if( psp->decllnslot ) *psp->decllnslot = psp->tokenlineno; - psp->state = WAITING_FOR_DECL_OR_RULE; - } + if( x[0]=='{' || x[0]=='\"' || isalnum(x[0]) ){ + char *zOld, *zNew, *zBuf, *z; + int nOld, n, nLine, nNew, nBack; + int addLineMacro; + char zLine[50]; + zNew = x; + if( zNew[0]=='"' || zNew[0]=='{' ) zNew++; + nNew = lemonStrlen(zNew); + if( *psp->declargslot ){ + zOld = *psp->declargslot; + }else{ + zOld = ""; + } + nOld = lemonStrlen(zOld); + n = nOld + nNew + 20; + addLineMacro = !psp->gp->nolinenosflag && psp->insertLineMacro && + (psp->decllinenoslot==0 || psp->decllinenoslot[0]!=0); + if( addLineMacro ){ + for(z=psp->filename, nBack=0; *z; z++){ + if( *z=='\\' ) nBack++; + } + sprintf(zLine, "#line %d ", psp->tokenlineno); + nLine = lemonStrlen(zLine); + n += nLine + lemonStrlen(psp->filename) + nBack; + } + *psp->declargslot = zBuf = realloc(*psp->declargslot, n); + zBuf += nOld; + if( addLineMacro ){ + if( nOld && zBuf[-1]!='\n' ){ + *(zBuf++) = '\n'; + } + memcpy(zBuf, zLine, nLine); + zBuf += nLine; + *(zBuf++) = '"'; + for(z=psp->filename; *z; z++){ + if( *z=='\\' ){ + *(zBuf++) = '\\'; + } + *(zBuf++) = *z; + } + *(zBuf++) = '"'; + *(zBuf++) = '\n'; + } + if( psp->decllinenoslot && psp->decllinenoslot[0]==0 ){ + psp->decllinenoslot[0] = psp->tokenlineno; + } + memcpy(zBuf, zNew, nNew); + zBuf += nNew; + *zBuf = 0; + psp->state = WAITING_FOR_DECL_OR_RULE; }else{ ErrorMsg(psp->filename,psp->tokenlineno, "Illegal argument to %%%s: %s",psp->declkeyword,x); @@ -2401,7 +2445,7 @@ to follow the previous rule."); } } -/* Run the proprocessor over the input file text. The global variables +/* Run the preprocessor over the input file text. The global variables ** azDefine[0] through azDefine[nDefine-1] contains the names of all defined ** macros. This routine looks for "%ifdef" and "%ifndef" and "%endif" and ** comments them out. Text in between is also commented out as appropriate. @@ -2432,7 +2476,7 @@ static void preprocess_input(char *z){ for(n=0; z[j+n] && !isspace(z[j+n]); n++){} exclude = 1; for(k=0; kerrorcnt++; - fclose(fp); + fclose(fp); return; } if( fread(filebuf,1,filesize,fp)!=filesize ){ ErrorMsg(ps.filename,0,"Can't read in all %d bytes of this file.", filesize); free(filebuf); - fclose(fp); gp->errorcnt++; + fclose(fp); return; } fclose(fp); @@ -2706,7 +2750,7 @@ char *suffix; char *name; char *cp; - name = malloc( strlen(lemp->filename) + strlen(suffix) + 5 ); + name = malloc( lemonStrlen(lemp->filename) + lemonStrlen(suffix) + 5 ); if( name==0 ){ fprintf(stderr,"Can't allocate space for a filename.\n"); exit(1); @@ -2751,7 +2795,7 @@ struct lemon *lemp; maxlen = 10; for(i=0; insymbol; i++){ sp = lemp->symbols[i]; - len = (int)strlen(sp->name); + len = lemonStrlen(sp->name); if( len>maxlen ) maxlen = len; } ncolumns = 76/(maxlen+5); @@ -2959,7 +3003,7 @@ int modemask; char c; #ifdef __WIN32__ - for (cp = argv0 + strlen(argv0); cp-- > argv0; ) + for (cp = argv0 + lemonStrlen(argv0); cp-- > argv0; ) { if( *cp == '\\' || *cp == '/' ) break; @@ -2970,18 +3014,18 @@ int modemask; if( cp ){ c = *cp; *cp = 0; - path = (char *)malloc( strlen(argv0) + strlen(name) + 2 ); + path = (char *)malloc( lemonStrlen(argv0) + lemonStrlen(name) + 2 ); if( path ) sprintf(path,"%s/%s",argv0,name); *cp = c; }else{ extern char *getenv(); pathlist = getenv("PATH"); if( pathlist==0 ) pathlist = ".:/bin:/usr/bin"; - path = (char *)malloc( strlen(pathlist)+strlen(name)+2 ); + path = (char *)malloc( lemonStrlen(pathlist)+lemonStrlen(name)+2 ); if( path!=0 ){ while( *pathlist ){ cp = strchr(pathlist,':'); - if( cp==0 ) cp = &pathlist[strlen(pathlist)]; + if( cp==0 ) cp = &pathlist[lemonStrlen(pathlist)]; c = *cp; *cp = 0; sprintf(path,"%s/%s",pathlist,name); @@ -3112,16 +3156,13 @@ char *filename; } /* Print a string to the file and keep the linenumber up to date */ -PRIVATE void tplt_print(out,lemp,str,strln,lineno) +PRIVATE void tplt_print(out,lemp,str,lineno) FILE *out; struct lemon *lemp; char *str; -int strln; int *lineno; { if( str==0 ) return; - tplt_linedir(out,strln,lemp->filename); - (*lineno)++; while( *str ){ if( *str=='\n' ) (*lineno)++; putc(*str,out); @@ -3131,8 +3172,10 @@ int *lineno; putc('\n',out); (*lineno)++; } - tplt_linedir(out,*lineno+1,lemp->outname); - (*lineno)+=1; + if (!lemp->nolinenosflag) { + (*lineno)++; tplt_linedir(out,*lineno,lemp->outname); + } + return; } @@ -3148,21 +3191,18 @@ int *lineno; { char *cp = 0; - int linecnt = 0; if( sp->type==TERMINAL ){ cp = lemp->tokendest; if( cp==0 ) return; - tplt_linedir(out,lemp->tokendestln,lemp->filename); - fprintf(out,"{"); + fprintf(out,"{\n"); (*lineno)++; }else if( sp->destructor ){ cp = sp->destructor; - tplt_linedir(out,sp->destructorln,lemp->filename); - fprintf(out,"{"); + fprintf(out,"{\n"); (*lineno)++; + if (!lemp->nolinenosflag) { (*lineno)++; tplt_linedir(out,sp->destLineno,lemp->filename); } }else if( lemp->vardest ){ cp = lemp->vardest; if( cp==0 ) return; - tplt_linedir(out,lemp->vardestln,lemp->filename); - fprintf(out,"{"); + fprintf(out,"{\n"); (*lineno)++; }else{ assert( 0 ); /* Cannot happen */ } @@ -3172,12 +3212,14 @@ int *lineno; cp++; continue; } - if( *cp=='\n' ) linecnt++; + if( *cp=='\n' ) (*lineno)++; fputc(*cp,out); } - (*lineno) += 3 + linecnt; - fprintf(out,"}\n"); - tplt_linedir(out,*lineno,lemp->outname); + fprintf(out,"\n"); (*lineno)++; + if (!lemp->nolinenosflag) { + (*lineno)++; tplt_linedir(out,*lineno,lemp->outname); + } + fprintf(out,"}\n"); (*lineno)++; return; } @@ -3225,7 +3267,7 @@ PRIVATE char *append_str(char *zText, int n, int p1, int p2, int bNoSubst){ used += n; assert( used>=0 ); } - n = (int)strlen(zText); + n = lemonStrlen(zText); } if( n+sizeof(zInt)*2+used >= (size_t)alloced ){ alloced = n + sizeof(zInt)*2 + used + 200; @@ -3238,7 +3280,7 @@ PRIVATE char *append_str(char *zText, int n, int p1, int p2, int bNoSubst){ sprintf(zInt, "%d", p1); p1 = p2; strcpy(&z[used], zInt); - used += (int)strlen(&z[used]); + used += lemonStrlen(&z[used]); zText++; n--; }else{ @@ -3325,7 +3367,7 @@ PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){ lemp->errorcnt++; }else if( rp->rhsalias[i]==0 ){ if( has_destructor(rp->rhs[i],lemp) ){ - append_str(" yy_destructor(%d,&yymsp[%d].minor);\n", 0, + append_str(" yy_destructor(yypParser,%d,&yymsp[%d].minor);\n", 0, rp->rhs[i]->index,i-rp->nrhs+1,0); }else{ /* No destructor defined for this term */ @@ -3349,18 +3391,16 @@ struct lemon *lemp; int *lineno; { char *cp; - int linecnt = 0; /* Generate code to do the reduce action */ if( rp->code ){ - tplt_linedir(out,rp->line,lemp->filename); + if (!lemp->nolinenosflag) { (*lineno)++; tplt_linedir(out,rp->line,lemp->filename); } fprintf(out,"{%s",rp->code); for(cp=rp->code; *cp; cp++){ - if( *cp=='\n' ) linecnt++; + if( *cp=='\n' ) (*lineno)++; } /* End loop */ - (*lineno) += 3 + linecnt; - fprintf(out,"}\n"); - tplt_linedir(out,*lineno,lemp->outname); + fprintf(out,"}\n"); (*lineno)++; + if (!lemp->nolinenosflag) { (*lineno)++; tplt_linedir(out,*lineno,lemp->outname); } } /* End if( rp->code ) */ return; @@ -3391,15 +3431,19 @@ int mhflag; /* True if generating makeheaders output */ /* Allocate and initialize types[] and allocate stddt[] */ arraysize = lemp->nsymbol * 2; types = (char**)calloc( arraysize, sizeof(char*) ); + if( types==0 ){ + fprintf(stderr,"Out of memory.\n"); + exit(1); + } maxdtlength = 0; if( lemp->vartype ){ - maxdtlength = (int)strlen(lemp->vartype); + maxdtlength = lemonStrlen(lemp->vartype); } for(i=0; insymbol; i++){ int len; struct symbol *sp = lemp->symbols[i]; if( sp->datatype==0 ) continue; - len = (int)strlen(sp->datatype); + len = lemonStrlen(sp->datatype); if( len>maxdtlength ) maxdtlength = len; } stddt = (char*)malloc( maxdtlength*2 + 1 ); @@ -3432,6 +3476,10 @@ int mhflag; /* True if generating makeheaders output */ while( *cp ) stddt[j++] = *cp++; while( j>0 && isspace(stddt[j-1]) ) j--; stddt[j] = 0; + if( lemp->tokentype && strcmp(stddt, lemp->tokentype)==0 ){ + sp->dtnum = 0; + continue; + } hash = 0; for(j=0; stddt[j]; j++){ hash = hash*53 + stddt[j]; @@ -3447,7 +3495,7 @@ int mhflag; /* True if generating makeheaders output */ } if( types[hash]==0 ){ sp->dtnum = hash + 1; - types[hash] = (char*)malloc( strlen(stddt)+1 ); + types[hash] = (char*)malloc( lemonStrlen(stddt)+1 ); if( types[hash]==0 ){ fprintf(stderr,"Out of memory.\n"); exit(1); @@ -3464,6 +3512,7 @@ int mhflag; /* True if generating makeheaders output */ lemp->tokentype?lemp->tokentype:"void*"); lineno++; if( mhflag ){ fprintf(out,"#endif\n"); lineno++; } fprintf(out,"typedef union {\n"); lineno++; + fprintf(out," int yyinit;\n"); lineno++; fprintf(out," %sTOKENTYPE yy0;\n",name); lineno++; for(i=0; iname,in,out,&lineno); /* Generate the include code, if any */ - tplt_print(out,lemp,lemp->include,lemp->includeln,&lineno); + tplt_print(out,lemp,lemp->include,&lineno); if( mhflag ){ char *name = file_makename(lemp, ".h"); fprintf(out,"#include \"%s\"\n", name); lineno++; @@ -3594,7 +3643,7 @@ int mhflag; /* Output in makeheaders format if true */ /* Generate the defines */ fprintf(out,"#define YYCODETYPE %s\n", - minimum_size_type(0, lemp->nsymbol+5)); lineno++; + minimum_size_type(0, lemp->nsymbol+1)); lineno++; fprintf(out,"#define YYNOCODE %d\n",lemp->nsymbol+1); lineno++; fprintf(out,"#define YYACTIONTYPE %s\n", minimum_size_type(0, lemp->nstate+lemp->nrule+5)); lineno++; @@ -3616,7 +3665,7 @@ int mhflag; /* Output in makeheaders format if true */ name = lemp->name ? lemp->name : "Parse"; if( lemp->arg && lemp->arg[0] ){ size_t i; - i = strlen(lemp->arg); + i = lemonStrlen(lemp->arg); while( i>=1 && isspace(lemp->arg[i-1]) ) i--; while( i>=1 && (isalnum(lemp->arg[i-1]) || lemp->arg[i-1]=='_') ) i--; fprintf(out,"#define %sARG_SDECL %s;\n",name,lemp->arg); lineno++; @@ -3809,7 +3858,9 @@ int mhflag; /* Output in makeheaders format if true */ /* Generate the table of fallback tokens. */ if( lemp->has_fallback ){ - for(i=0; interminal; i++){ + int mx = lemp->nterminal - 1; + while( mx>0 && lemp->symbols[mx]->fallback==0 ){ mx--; } + for(i=0; i<=mx; i++){ struct symbol *p = lemp->symbols[i]; if( p->fallback==0 ){ fprintf(out, " 0, /* %10s => nothing */\n", p->name); @@ -3833,7 +3884,7 @@ int mhflag; /* Output in makeheaders format if true */ tplt_xfer(lemp->name,in,out,&lineno); /* Generate a table containing a text string that describes every - ** rule in the rule set of the grammer. This information is used + ** rule in the rule set of the grammar. This information is used ** when tracing REDUCE actions. */ for(i=0, rp=lemp->rule; rp; rp=rp->next, i++){ @@ -3849,11 +3900,15 @@ int mhflag; /* Output in makeheaders format if true */ ** (In other words, generate the %destructor actions) */ if( lemp->tokendest ){ + int once = 1; for(i=0; insymbol; i++){ struct symbol *sp = lemp->symbols[i]; if( sp==0 || sp->type!=TERMINAL ) continue; - fprintf(out," case %d: /* %s */\n", - sp->index, sp->name); lineno++; + if( once ){ + fprintf(out, " /* TERMINAL Destructor */\n"); lineno++; + once = 0; + } + fprintf(out," case %d: /* %s */\n", sp->index, sp->name); lineno++; } for(i=0; insymbol && lemp->symbols[i]->type!=TERMINAL; i++); if( insymbol ){ @@ -3863,24 +3918,27 @@ int mhflag; /* Output in makeheaders format if true */ } if( lemp->vardest ){ struct symbol *dflt_sp = 0; + int once = 1; for(i=0; insymbol; i++){ struct symbol *sp = lemp->symbols[i]; if( sp==0 || sp->type==TERMINAL || sp->index<=0 || sp->destructor!=0 ) continue; - fprintf(out," case %d: /* %s */\n", - sp->index, sp->name); lineno++; + if( once ){ + fprintf(out, " /* Default NON-TERMINAL Destructor */\n"); lineno++; + once = 0; + } + fprintf(out," case %d: /* %s */\n", sp->index, sp->name); lineno++; dflt_sp = sp; } if( dflt_sp!=0 ){ emit_destructor_code(out,dflt_sp,lemp,&lineno); - fprintf(out," break;\n"); lineno++; } + fprintf(out," break;\n"); lineno++; } for(i=0; insymbol; i++){ struct symbol *sp = lemp->symbols[i]; if( sp==0 || sp->type==TERMINAL || sp->destructor==0 ) continue; - fprintf(out," case %d: /* %s */\n", - sp->index, sp->name); lineno++; + fprintf(out," case %d: /* %s */\n", sp->index, sp->name); lineno++; /* Combine duplicate destructors into a single case */ for(j=i+1; jnsymbol; j++){ @@ -3900,7 +3958,7 @@ int mhflag; /* Output in makeheaders format if true */ tplt_xfer(lemp->name,in,out,&lineno); /* Generate code which executes whenever the parser stack overflows */ - tplt_print(out,lemp,lemp->overflow,lemp->overflowln,&lineno); + tplt_print(out,lemp,lemp->overflow,&lineno); tplt_xfer(lemp->name,in,out,&lineno); /* Generate the table of rule information @@ -3917,39 +3975,53 @@ int mhflag; /* Output in makeheaders format if true */ for(rp=lemp->rule; rp; rp=rp->next){ translate_code(lemp, rp); } + /* First output rules other than the default: rule */ for(rp=lemp->rule; rp; rp=rp->next){ - struct rule *rp2; + struct rule *rp2; /* Other rules with the same action */ if( rp->code==0 ) continue; + if( rp->code[0]=='\n' && rp->code[1]==0 ) continue; /* Will be default: */ fprintf(out," case %d: /* ",rp->index); writeRuleText(out, rp); - fprintf(out, " */\n"); lineno++; + fprintf(out," */\n"); lineno++; for(rp2=rp->next; rp2; rp2=rp2->next){ if( rp2->code==rp->code ){ fprintf(out," case %d: /*",rp2->index); writeRuleText(out, rp2); - fprintf(out," */\n"); lineno++; + fprintf(out, " */ yytestcase(yyruleno==%d);\n", rp2->index); lineno++; rp2->code = 0; } } emit_code(out,rp,lemp,&lineno); fprintf(out," break;\n"); lineno++; + rp->code = 0; } + /* Finally, output the default: rule. We choose as the default: all + ** empty actions. */ + fprintf(out," default:\n"); lineno++; + for(rp=lemp->rule; rp; rp=rp->next){ + if( rp->code==0 ) continue; + assert( rp->code[0]=='\n' && rp->code[1]==0 ); + fprintf(out," /* (%d) ", rp->index); + writeRuleText(out, rp); + fprintf(out," */ yytestcase(yyruleno==%d);\n", rp->index); lineno++; + } + fprintf(out," break;\n"); lineno++; tplt_xfer(lemp->name,in,out,&lineno); /* Generate code which executes if a parse fails */ - tplt_print(out,lemp,lemp->failure,lemp->failureln,&lineno); + tplt_print(out,lemp,lemp->failure,&lineno); tplt_xfer(lemp->name,in,out,&lineno); /* Generate code which executes when a syntax error occurs */ - tplt_print(out,lemp,lemp->error,lemp->errorln,&lineno); + tplt_print(out,lemp,lemp->error,&lineno); tplt_xfer(lemp->name,in,out,&lineno); /* Generate code which executes when the parser accepts its input */ - tplt_print(out,lemp,lemp->accept,lemp->acceptln,&lineno); + tplt_print(out,lemp,lemp->accept,&lineno); tplt_xfer(lemp->name,in,out,&lineno); /* Append any addition code the user desires */ - tplt_print(out,lemp,lemp->extracode,lemp->extracodeln,&lineno); + tplt_print(out,lemp,lemp->extracode,&lineno); acttab_free(&pActtab); fclose(in); @@ -3971,12 +4043,14 @@ struct lemon *lemp; else prefix = ""; in = file_open(lemp,".h","rb"); if( in ){ + int nextChar; for(i=1; interminal && fgets(line,LINESIZE,in); i++){ sprintf(pattern,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i); if( strcmp(line,pattern) ) break; } + nextChar = fgetc(in); fclose(in); - if( i==lemp->nterminal ){ + if( i==lemp->nterminal && nextChar==EOF ){ /* No change in the file. Don't rewrite it. */ /* (not the best idea if you use make tools that check the date! */ /*return;*/ @@ -4038,7 +4112,7 @@ struct lemon *lemp; /* Do not make a default if the number of rules to default ** is not at least 1 or if the wildcard token is a possbile - ** lookahed. + ** lookahead. */ if( nbest<1 || usesWildcard ) continue; @@ -4206,7 +4280,7 @@ char *y; if( y==0 ) return 0; z = Strsafe_find(y); - if( z==0 && (z=malloc( strlen(y)+1 ))!=0 ){ + if( z==0 && (z=malloc( lemonStrlen(y)+1 ))!=0 ){ strcpy(z,y); Strsafe_insert(z); } @@ -4353,6 +4427,7 @@ char *x; sp->firstset = 0; sp->lambda = LEMON_FALSE; sp->destructor = 0; + sp->destLineno = 0; sp->datatype = 0; sp->useCnt = 0; Symbol_insert(sp,sp->name); diff --git a/tools/lemon/lempar.c b/tools/lemon/lempar.c index c6c032ca94..6e9bf92c27 100644 --- a/tools/lemon/lempar.c +++ b/tools/lemon/lempar.c @@ -1,8 +1,8 @@ /* Driver template for the LEMON parser generator. ** The author disclaims copyright to this source code. */ -/* First off, code is included which follows the "include" declaration -** in the input file. */ +/* First off, code is included that follows the "include" declaration +** in the input grammar file. */ #include #include #include @@ -69,7 +69,24 @@ #define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1) #define YY_ERROR_ACTION (YYNSTATE+YYNRULE) -/* Next are that tables used to determine what action to take based on the +/* The yyzerominor constant is used to initialize instances of +** YYMINORTYPE objects to zero. */ +static const YYMINORTYPE yyzerominor = { 0 }; + +/* Define the yytestcase() macro to be a no-op if is not already defined +** otherwise. +** +** Applications can choose to define yytestcase() in the %include section +** to a macro that can assist in verifying code coverage. For production +** code the yytestcase() macro should be turned off. But it is useful +** for testing. +*/ +#ifndef yytestcase +# define yytestcase(X) +#endif + + +/* Next are the tables used to determine what action to take based on the ** current state and lookahead token. These tables are used to implement ** functions that take a state number and lookahead value and return an ** action integer. @@ -124,7 +141,7 @@ ** ** %fallback ID X Y Z. ** -** appears in the grammer, then ID becomes a fallback token for X, Y, +** appears in the grammar, then ID becomes a fallback token for X, Y, ** and Z. Whenever one of the tokens X, Y, or Z is input to the parser ** but it does not parse, the type of the token is changed to ID and ** the parse is retried before an error is thrown. @@ -148,11 +165,11 @@ static const YYCODETYPE yyFallback[] = { ** It is sometimes called the "minor" token. */ struct yyStackEntry { - int stateno; /* The state-number */ - int major; /* The major token value. This is the code - ** number for the token at this stack level */ - YYMINORTYPE minor; /* The user-supplied minor token value. This - ** is the value of the token */ + YYACTIONTYPE stateno; /* The state-number */ + YYCODETYPE major; /* The major token value. This is the code + ** number for the token at this stack level */ + YYMINORTYPE minor; /* The user-supplied minor token value. This + ** is the value of the token */ }; typedef struct yyStackEntry yyStackEntry; @@ -160,6 +177,9 @@ typedef struct yyStackEntry yyStackEntry; ** the following structure */ struct yyParser { int yyidx; /* Index of top element in stack */ +#ifdef YYTRACKMAXSTACKDEPTH + int yyidxMax; /* Maximum value of yyidx */ +#endif int yyerrcnt; /* Shifts left before out of the error */ ParseARG_SDECL /* A place to hold %extra_argument */ #if YYSTACKDEPTH<=0 @@ -259,7 +279,12 @@ void *ParseAlloc(void *(CDECL *mallocProc)(size_t)){ pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) ); if( pParser ){ pParser->yyidx = -1; +#ifdef YYTRACKMAXSTACKDEPTH + pParser->yyidxMax = 0; +#endif #if YYSTACKDEPTH<=0 + pParser->yystack = NULL; + pParser->yystksz = 0; yyGrowStack(pParser); #endif } @@ -271,7 +296,12 @@ void *ParseAlloc(void *(CDECL *mallocProc)(size_t)){ ** "yymajor" is the symbol code, and "yypminor" is a pointer to ** the value. */ -static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){ +static void yy_destructor( + yyParser *yypParser, /* The parser */ + YYCODETYPE yymajor, /* Type code for object to destroy */ + YYMINORTYPE *yypminor /* The object to be destroyed */ +){ + ParseARG_FETCH; switch( yymajor ){ /* Here is inserted the actions which take place when a ** terminal or non-terminal is destroyed. This can happen @@ -309,7 +339,7 @@ static int yy_pop_parser_stack(yyParser *pParser){ } #endif yymajor = yytos->major; - yy_destructor( yymajor, &yytos->minor); + yy_destructor(pParser, yymajor, &yytos->minor); pParser->yyidx--; return yymajor; } @@ -339,6 +369,16 @@ void ParseFree( (*freeProc)((void*)pParser); } +/* +** Return the peak depth of the stack for a parser. +*/ +#ifdef YYTRACKMAXSTACKDEPTH +int ParseStackPeak(void *p){ + yyParser *pParser = (yyParser*)p; + return pParser->yyidxMax; +} +#endif + /* ** Find the appropriate action for a parser given the terminal ** look-ahead token iLookAhead. @@ -362,7 +402,7 @@ static int yy_find_shift_action( if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){ if( iLookAhead>0 ){ #ifdef YYFALLBACK - int iFallback; /* Fallback token */ + YYCODETYPE iFallback; /* Fallback token */ if( iLookAheadYY_REDUCE_MAX || - (i = yy_reduce_ofst[stateno])==YY_REDUCE_USE_DFLT ){ +#ifdef YYERRORSYMBOL + if( stateno>YY_REDUCE_MAX ){ return yy_default[stateno]; } +#else + assert( stateno<=YY_REDUCE_MAX ); +#endif + i = yy_reduce_ofst[stateno]; assert( i!=YY_REDUCE_USE_DFLT ); assert( iLookAhead!=YYNOCODE ); i += iLookAhead; +#ifdef YYERRORSYMBOL if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){ return yy_default[stateno]; - }else{ - return yy_action[i]; } +#else + assert( i>=0 && iyyidx>=0 ) yy_pop_parser_stack(yypParser); /* Here code is inserted which will execute if the parser - ** stack every overflows */ + ** stack ever overflows */ %% ParseARG_STORE; /* Suppress warning about unused %extra_argument var */ } @@ -448,10 +495,15 @@ static void yy_shift( yyParser *yypParser, /* The parser to be shifted */ int yyNewState, /* The new state to shift in */ int yyMajor, /* The major token to shift in */ - YYMINORTYPE *yypMinor /* Pointer ot the minor token to shift in */ + YYMINORTYPE *yypMinor /* Pointer to the minor token to shift in */ ){ yyStackEntry *yytos; yypParser->yyidx++; +#ifdef YYTRACKMAXSTACKDEPTH + if( yypParser->yyidx>yypParser->yyidxMax ){ + yypParser->yyidxMax = yypParser->yyidx; + } +#endif #if YYSTACKDEPTH>0 if( yypParser->yyidx>=YYSTACKDEPTH ){ yyStackOverflow(yypParser, yypMinor); @@ -467,8 +519,8 @@ static void yy_shift( } #endif yytos = &yypParser->yystack[yypParser->yyidx]; - yytos->stateno = yyNewState; - yytos->major = yyMajor; + yytos->stateno = (YYACTIONTYPE)yyNewState; + yytos->major = (YYCODETYPE)yyMajor; yytos->minor = *yypMinor; #ifndef NDEBUG if( yyTraceFILE && yypParser->yyidx>0 ){ @@ -531,8 +583,8 @@ static void yy_reduce( ** from wireshark this week. Clearly they are stressing Lemon in ways ** that it has not been previously stressed... (SQLite ticket #2172) */ - memset(&yygotominor, 0, sizeof(yygotominor)); - + /*memset(&yygotominor, 0, sizeof(yygotominor));*/ + yygotominor = yyzerominor; switch( yyruleno ){ /* Beginning here are the reduction cases. A typical example @@ -548,7 +600,7 @@ static void yy_reduce( yygoto = yyRuleInfo[yyruleno].lhs; yysize = yyRuleInfo[yyruleno].nrhs; yypParser->yyidx -= yysize; - yyact = yy_find_reduce_action(yymsp[-yysize].stateno,yygoto); + yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto); if( yyact < YYNSTATE ){ #ifdef NDEBUG /* If we are not debugging and the reduce action popped at least @@ -558,8 +610,8 @@ static void yy_reduce( if( yysize ){ yypParser->yyidx++; yymsp -= yysize-1; - yymsp->stateno = yyact; - yymsp->major = yygoto; + yymsp->stateno = (YYACTIONTYPE)yyact; + yymsp->major = (YYCODETYPE)yygoto; yymsp->minor = yygotominor; }else #endif @@ -575,6 +627,7 @@ static void yy_reduce( /* ** The following code executes when the parse fails */ +#ifndef YYNOERRORRECOVERY static void yy_parse_failed( yyParser *yypParser /* The parser */ ){ @@ -590,6 +643,7 @@ static void yy_parse_failed( %% ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ } +#endif /* YYNOERRORRECOVERY */ /* ** The following code executes when a syntax error first occurs. @@ -662,7 +716,8 @@ void Parse( if( yypParser->yyidx<0 ){ #if YYSTACKDEPTH<=0 if( yypParser->yystksz <=0 ){ - memset(&yyminorunion, 0, sizeof(yyminorunion)); + /*memset(&yyminorunion, 0, sizeof(yyminorunion));*/ + yyminorunion = yyzerominor; yyStackOverflow(yypParser, &yyminorunion); return; } @@ -683,7 +738,7 @@ void Parse( #endif do{ - yyact = yy_find_shift_action(yypParser,yymajor); + yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor); if( yyactyyidx < 0 || yymajor==0 ){ - yy_destructor(yymajor,&yyminorunion); + yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); yy_parse_failed(yypParser); yymajor = YYNOCODE; }else if( yymx!=YYERRORSYMBOL ){ @@ -756,6 +811,18 @@ void Parse( } yypParser->yyerrcnt = 3; yyerrorhit = 1; +#elif defined(YYNOERRORRECOVERY) + /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to + ** do any kind of error recovery. Instead, simply invoke the syntax + ** error routine and continue going as if nothing had happened. + ** + ** Applications can set this macro (for example inside %include) if + ** they intend to abandon the parse upon the first syntax error seen. + */ + yy_syntax_error(yypParser,yymajor,yyminorunion); + yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); + yymajor = YYNOCODE; + #else /* YYERRORSYMBOL is not defined */ /* This is what we do if the grammar does not define ERROR: ** @@ -770,7 +837,7 @@ void Parse( yy_syntax_error(yypParser,yymajor,yyminorunion); } yypParser->yyerrcnt = 3; - yy_destructor(yymajor,&yyminorunion); + yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); if( yyendofinput ){ yy_parse_failed(yypParser); } diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 08e376e617..1f7efd8955 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -32,43 +32,11 @@ ACTOR Actor native //: Thinker RipLevelMin 0 RipLevelMax 0 - // Variables for the expression evaluator - // NOTE: fixed_t and angle_t are only used here to ensure proper conversion - // Internally they are handled as floats. - // Variables must be native. - native fixed_t alpha; - native angle_t angle; - native int args[5]; - native fixed_t ceilingz; - native fixed_t floorz; - native int health; - native int mass; - native angle_t pitch; - native int special; - native int tid; - native int TIDtoHate; - native int waterlevel; - native int damage; - native fixed_t x; - native fixed_t y; - native fixed_t z; - native fixed_t velx; - native fixed_t vely; - native fixed_t velz; - native fixed_t momx; // alias for velx - native fixed_t momy; // alias for vely - native fixed_t momz; // alias for velz - native fixed_t scaleX; - native fixed_t scaleY; - native int score; - native int accuracy; - native int stamina; - native fixed_t height; - native fixed_t radius; - native int reactiontime; - native fixed_t meleerange; - native fixed_t speed; - native angle_t roll; + // Functions + native bool CheckClass(class checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false); + native bool IsPointerEqual(int ptr_select1, int ptr_select2); + + // Action functions // Meh, MBF redundant functions. Only for DeHackEd support. action native A_Turn(float angle = 0); @@ -76,7 +44,7 @@ ACTOR Actor native //: Thinker // End of MBF redundant functions. action native A_MonsterRail(); - action native A_BFGSpray(class spraytype = "BFGExtra", int numrays = 40, int damagecount = 15, float angle = 90, float distance = 16*64, float vrange = 32, int damage = 0); + action native A_BFGSpray(class spraytype = "BFGExtra", int numrays = 40, int damagecount = 15, float/*angle*/ angle = 90, float distance = 16*64, float/*angle*/ vrange = 32, int damage = 0); action native A_Pain(); action native A_NoBlocking(); action native A_XScream(); @@ -173,7 +141,7 @@ ACTOR Actor native //: Thinker action native A_BishopMissileWeave(); action native A_CStaffMissileSlither(); action native A_PlayerScream(); - action native A_SkullPop(class skulltype = "BloodySkull"); + action native A_SkullPop(class skulltype = "BloodySkull"); action native A_CheckPlayerDone(); action native A_Wander(); @@ -209,8 +177,8 @@ ACTOR Actor native //: Thinker action native A_SeekerMissile(int threshold, int turnmax, int flags = 0, int chance = 50, int distance = 10); action native A_Jump(int chance = 256, state label, ...); action native A_CustomMissile(class missiletype, float spawnheight = 32, int spawnofs_xy = 0, float angle = 0, int flags = 0, float pitch = 0, int ptr = AAPTR_TARGET); - action native A_CustomBulletAttack(float spread_xy, float spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", float range = 0, int flags = 0, int ptr = AAPTR_TARGET); - action native A_CustomRailgun(int damage, int spawnofs_xy = 0, color color1 = "", color color2 = "", int flags = 0, bool aim = false, float maxdiff = 0, class pufftype = "BulletPuff", float spread_xy = 0, float spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class spawnclass = "none", float spawnofs_z = 0, int spiraloffset = 270); + action native A_CustomBulletAttack(float/*angle*/ spread_xy, float/*angle*/ spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", float range = 0, int flags = 0, int ptr = AAPTR_TARGET); + action native A_CustomRailgun(int damage, int spawnofs_xy = 0, color color1 = "", color color2 = "", int flags = 0, int aim = 0, float maxdiff = 0, class pufftype = "BulletPuff", float/*angle*/ spread_xy = 0, float/*angle*/ spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class spawnclass = "none", float spawnofs_z = 0, int spiraloffset = 270); action native A_JumpIfHealthLower(int health, state label, int ptr_selector = AAPTR_DEFAULT); action native A_JumpIfCloser(float distance, state label, bool noz = false); action native A_JumpIfTracerCloser(float distance, state label, bool noz = false); @@ -218,13 +186,13 @@ ACTOR Actor native //: Thinker action native A_JumpIfTargetOutsideMeleeRange(state label); action native A_JumpIfTargetInsideMeleeRange(state label); action native A_JumpIfInventory(class itemtype, int itemamount, state label, int owner = AAPTR_DEFAULT); - action native A_JumpIfArmorType(string Type, state label, int amount = 1); + action native A_JumpIfArmorType(name Type, state label, int amount = 1); action native A_GiveInventory(class itemtype, int amount = 0, int giveto = AAPTR_DEFAULT); action native A_TakeInventory(class itemtype, int amount = 0, int flags = 0, int giveto = AAPTR_DEFAULT); action native A_SpawnItem(class itemtype = "Unknown", float distance = 0, float zheight = 0, bool useammo = true, bool transfer_translation = false); action native A_SpawnItemEx(class itemtype, float xofs = 0, float yofs = 0, float zofs = 0, float xvel = 0, float yvel = 0, float zvel = 0, float angle = 0, int flags = 0, int failchance = 0, int tid=0); - action native A_Print(string whattoprint, float time = 0, string fontname = ""); - action native A_PrintBold(string whattoprint, float time = 0, string fontname = ""); + action native A_Print(string whattoprint, float time = 0, name fontname = ""); + action native A_PrintBold(string whattoprint, float time = 0, name fontname = ""); action native A_Log(string whattoprint); action native A_LogInt(int whattoprint); action native A_SetTranslucent(float alpha, int style = 0); @@ -276,8 +244,8 @@ ACTOR Actor native //: Thinker action native A_ClearLastHeard(); action native A_ClearTarget(); action native A_CheckLOF(state jump, int flags = 0, float range = 0, float minrange = 0, float angle = 0, float pitch = 0, float offsetheight = 0, float offsetwidth = 0, int ptr_target = AAPTR_DEFAULT); - action native A_JumpIfTargetInLOS (state label, float fov = 0, int flags = 0, float dist_max = 0, float dist_close = 0); - action native A_JumpIfInTargetLOS (state label, float fov = 0, int flags = 0, float dist_max = 0, float dist_close = 0); + action native A_JumpIfTargetInLOS (state label, float/*angle*/ fov = 0, int flags = 0, float dist_max = 0, float dist_close = 0); + action native A_JumpIfInTargetLOS (state label, float/*angle*/ fov = 0, int flags = 0, float dist_max = 0, float dist_close = 0); action native A_SelectWeapon(class whichweapon); action native A_Punch(); action native A_Feathers(); @@ -293,7 +261,7 @@ ACTOR Actor native //: Thinker action native A_MonsterRefire(int chance, state label); action native A_SetAngle(float angle = 0, int flags = 0, int ptr = AAPTR_DEFAULT); action native A_SetPitch(float pitch, int flags = 0, int ptr = AAPTR_DEFAULT); - action native A_SetRoll(float roll, int flags = 0, int ptr = AAPTR_DEFAULT); + action native A_SetRoll(float/*angle*/ roll, int flags = 0, int ptr = AAPTR_DEFAULT); action native A_ScaleVelocity(float scale, int ptr = AAPTR_DEFAULT); action native A_ChangeVelocity(float x = 0, float y = 0, float z = 0, int flags = 0, int ptr = AAPTR_DEFAULT); action native A_SetArg(int pos, int value); @@ -349,13 +317,13 @@ ACTOR Actor native //: Thinker action native A_TransferPointer(int ptr_source, int ptr_recepient, int sourcefield, int recepientfield=AAPTR_DEFAULT, int flags=0); action native A_CopyFriendliness(int ptr_source = AAPTR_MASTER); - action native ACS_NamedExecute(string script, int mapnum=0, int arg1=0, int arg2=0, int arg3=0); - action native ACS_NamedSuspend(string script, int mapnum=0); - action native ACS_NamedTerminate(string script, int mapnum=0); - action native ACS_NamedLockedExecute(string script, int mapnum=0, int arg1=0, int arg2=0, int lock=0); - action native ACS_NamedLockedExecuteDoor(string script, int mapnum=0, int arg1=0, int arg2=0, int lock=0); - action native ACS_NamedExecuteWithResult(string script, int arg1=0, int arg2=0, int arg3=0, int arg4=0); - action native ACS_NamedExecuteAlways(string script, int mapnum=0, int arg1=0, int arg2=0, int arg3=0); + action native ACS_NamedExecute(name script, int mapnum=0, int arg1=0, int arg2=0, int arg3=0); + action native ACS_NamedSuspend(name script, int mapnum=0); + action native ACS_NamedTerminate(name script, int mapnum=0); + action native ACS_NamedLockedExecute(name script, int mapnum=0, int arg1=0, int arg2=0, int lock=0); + action native ACS_NamedLockedExecuteDoor(name script, int mapnum=0, int arg1=0, int arg2=0, int lock=0); + action native ACS_NamedExecuteWithResult(name script, int arg1=0, int arg2=0, int arg3=0, int arg4=0); + action native ACS_NamedExecuteAlways(name script, int mapnum=0, int arg1=0, int arg2=0, int arg3=0); States { diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index ad90e71d85..1fd824989b 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -537,7 +537,3 @@ enum FMDF_INTERPOLATE = 1 << 1, FMDF_NOANGLE = 1 << 2, }; - -// This is only here to provide one global variable for testing. -native int testglobalvar; - diff --git a/wadsrc/static/actors/shared/inventory.txt b/wadsrc/static/actors/shared/inventory.txt index a44515efb5..ee9a354463 100644 --- a/wadsrc/static/actors/shared/inventory.txt +++ b/wadsrc/static/actors/shared/inventory.txt @@ -9,9 +9,9 @@ ACTOR Inventory native action native A_JumpIfNoAmmo(state label); action native A_CustomPunch(int damage, bool norandom = false, int flags = CPF_USEAMMO, class pufftype = "BulletPuff", float range = 0, float lifesteal = 0, int lifestealmax = 0, class armorbonustype = "ArmorBonus", sound MeleeSound = "", sound MissSound = ""); - action native A_FireBullets(float spread_xy, float spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", int flags = 1, float range = 0); + action native A_FireBullets(float/*angle*/ spread_xy, float/*angle*/ spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", int flags = 1, float range = 0); action native A_FireCustomMissile(class missiletype, float angle = 0, bool useammo = true, int spawnofs_xy = 0, float spawnheight = 0, int flags = 0, float pitch = 0); - action native A_RailAttack(int damage, int spawnofs_xy = 0, int useammo = true, color color1 = "", color color2 = "", int flags = 0, float maxdiff = 0, class pufftype = "BulletPuff", float spread_xy = 0, float spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class spawnclass = "none", float spawnofs_z = 0, int spiraloffset = 270); + action native A_RailAttack(int damage, int spawnofs_xy = 0, bool useammo = true, color color1 = "", color color2 = "", int flags = 0, float maxdiff = 0, class pufftype = "BulletPuff", float/*angle*/ spread_xy = 0, float/*angle*/ spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class spawnclass = "none", float spawnofs_z = 0, int spiraloffset = 270); action native A_Light(int extralight); action native A_Light0(); action native A_Light1(); @@ -41,7 +41,7 @@ ACTOR Inventory native action native A_ClearReFire(); action native A_CheckReload(); action native A_GunFlash(state flash = "", int flags = 0); - action native A_Saw(sound fullsound = "weapons/sawfull", sound hitsound = "weapons/sawhit", int damage = 2, class pufftype = "BulletPuff", int flags = 0, float range = 0, float spread_xy = 2.8125, float spread_z = 0, float lifesteal = 0, int lifestealmax = 0, class armorbonustype = "ArmorBonus"); + action native A_Saw(sound fullsound = "weapons/sawfull", sound hitsound = "weapons/sawhit", int damage = 2, class pufftype = "BulletPuff", int flags = 0, float range = 0, float/*angle*/ spread_xy = 2.8125, float/*angle*/ spread_z = 0, float lifesteal = 0, int lifestealmax = 0, class armorbonustype = "ArmorBonus"); action native A_CheckForReload(int counter, state label, bool dontincrement = false); action native A_ResetReloadCounter(); action native A_RestoreSpecialPosition(); diff --git a/wadsrc/static/actors/shared/sharedmisc.txt b/wadsrc/static/actors/shared/sharedmisc.txt index 69b1abb15b..b3c3d13ec1 100644 --- a/wadsrc/static/actors/shared/sharedmisc.txt +++ b/wadsrc/static/actors/shared/sharedmisc.txt @@ -148,6 +148,7 @@ ACTOR RandomSpawner native ACTOR FastProjectile native { Projectile + MissileHeight 0 } // Sector flag setter ------------------------------------------------------ diff --git a/zdoom.vcproj b/zdoom.vcproj index 597b56f2f1..e000f153df 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -56,7 +56,7 @@ FavorSizeOrSpeed="1" OmitFramePointers="true" WholeProgramOptimization="false" - AdditionalIncludeDirectories="src\win32;src\sound;src;zlib;src\g_shared;src\g_doom;src\g_raven;src\g_heretic;src\g_hexen;src\g_strife;"jpeg-6b";"game-music-emu";gdtoa;bzip2;lzma\C" + AdditionalIncludeDirectories="src\zscript;src\win32;src\sound;src;zlib;src\g_shared;src\g_doom;src\g_raven;src\g_heretic;src\g_hexen;src\g_strife;"jpeg-6b";"game-music-emu";gdtoa;bzip2;lzma\C" PreprocessorDefinitions="NDEBUG,WIN32,_WIN32,_WINDOWS,HAVE_STRUPR,HAVE_FILELENGTH;NO_VA_COPY,BACKPATCH,HAVE_FLUIDSYNTH,DYN_FLUIDSYNTH,NO_OPENAL" StringPooling="true" ExceptionHandling="1" @@ -180,7 +180,7 @@ EnableIntrinsicFunctions="true" FavorSizeOrSpeed="1" OmitFramePointers="true" - AdditionalIncludeDirectories="src\win32;src\sound;src;zlib;src\g_shared;src\g_doom;src\g_raven;src\g_heretic;src\g_hexen;src\g_strife;"jpeg-6b";game-music-emu;gdtoa;bzip2;lzma\C" + AdditionalIncludeDirectories="src\zscript;src\win32;src\sound;src;zlib;src\g_shared;src\g_doom;src\g_raven;src\g_heretic;src\g_hexen;src\g_strife;"jpeg-6b";game-music-emu;gdtoa;bzip2;lzma\C" PreprocessorDefinitions="NDEBUG,WIN32,_WIN32,_WINDOWS,HAVE_STRUPR,HAVE_FILELENGTH;NO_VA_COPY,NO_OPENAL" StringPooling="true" RuntimeLibrary="0" @@ -291,7 +291,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -3821,10 +3973,6 @@ RelativePath=".\src\thingdef\thingdef_expression.cpp" > - -