diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index f61ad34bb..d89a89576 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -5824,6 +5824,15 @@ AActor *P_SpawnMissile (AActor *source, AActor *dest, PClassActor *type, AActor return P_SpawnMissileXYZ (source->PosPlusZ(32 + source->GetBobOffset()), source, dest, type, true, owner); } +DEFINE_ACTION_FUNCTION(AActor, P_SpawnMissile) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(dest, AActor); + PARAM_CLASS(type, AActor); + PARAM_OBJECT_OPT(owner, AActor) { owner = self; } + ACTION_RETURN_OBJECT(P_SpawnMissile(self, dest, type, owner)); +} + AActor *P_SpawnMissileZ (AActor *source, double z, AActor *dest, PClassActor *type) { if (source == NULL) diff --git a/src/sc_man_scanner.re b/src/sc_man_scanner.re index caeb18f8c..cc9968ae3 100644 --- a/src/sc_man_scanner.re +++ b/src/sc_man_scanner.re @@ -151,7 +151,7 @@ std2: 'transient' { RET(TK_Transient); } 'final' { RET(TK_Final); } 'throws' { RET(TK_Throws); } - 'extends' { RET(TK_Extends); } + 'extend' { RET(TK_Extend); } 'public' { RET(TK_Public); } 'protected' { RET(TK_Protected); } 'private' { RET(TK_Private); } diff --git a/src/sc_man_tokens.h b/src/sc_man_tokens.h index 69927883c..19d331301 100644 --- a/src/sc_man_tokens.h +++ b/src/sc_man_tokens.h @@ -89,7 +89,7 @@ xx(TK_Transient, "'transient'") xx(TK_Volatile, "'volatile'") xx(TK_Final, "'final'") xx(TK_Throws, "'throws'") -xx(TK_Extends, "'extends'") +xx(TK_Extend, "'extend'") xx(TK_Public, "'public'") xx(TK_Protected, "'protected'") xx(TK_Private, "'private'") diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index a37b7449b..12ce01273 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -1013,6 +1013,7 @@ struct AFuncDesc #define ACTION_RETURN_STATE(v) do { FState *state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state, ATAG_STATE); return 1; } return 0; } while(0) +#define ACTION_RETURN_OBJECT(v) do { auto state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state, ATAG_OBJECT); return 1; } return 0; } while(0) #define ACTION_RETURN_FLOAT(v) do { double u = v; if (numret > 0) { assert(ret != nullptr); ret->SetFloat(u); return 1; } return 0; } while(0) #define ACTION_RETURN_INT(v) do { int u = v; if (numret > 0) { assert(ret != NULL); ret->SetInt(u); return 1; } return 0; } while(0) #define ACTION_RETURN_BOOL(v) ACTION_RETURN_INT(v) diff --git a/src/scripting/zscript/zcc-parse.lemon b/src/scripting/zscript/zcc-parse.lemon index eeeba6295..fc34fd2d7 100644 --- a/src/scripting/zscript/zcc-parse.lemon +++ b/src/scripting/zscript/zcc-parse.lemon @@ -171,6 +171,18 @@ class_definition(X) ::= class_head(A) class_body(B). X = A; /*X-overwrites-A*/ } +class_head(X) ::= EXTEND CLASS(T) IDENTIFIER(A). +{ + NEW_AST_NODE(Class,head,T); + head->NodeName = A.Name(); + head->ParentName = nullptr; + head->Flags = ZCC_Extension; + head->Replaces = nullptr; + head->Type = nullptr; + head->Symbol = nullptr; + X = head; +} + class_head(X) ::= CLASS(T) IDENTIFIER(A) class_ancestry(B) class_flags(C). { NEW_AST_NODE(Class,head,T); diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index ed85ab6b3..8389975ef 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -61,8 +61,29 @@ void ZCCCompiler::ProcessClass(ZCC_Class *cnode, PSymbolTreeNode *treenode) { - Classes.Push(new ZCC_ClassWork(static_cast<ZCC_Class *>(cnode), treenode)); - auto cls = Classes.Last(); + ZCC_ClassWork *cls = nullptr; + // If this is a class extension, put the new node directly into the existing class. + if (cnode->Flags == ZCC_Extension) + { + for (auto clss : Classes) + { + if (clss->NodeName() == cnode->NodeName) + { + cls = clss; + break; + } + } + if (cls == nullptr) + { + Error(cnode, "Class %s cannot be found in the current translation unit."); + return; + } + } + else + { + Classes.Push(new ZCC_ClassWork(static_cast<ZCC_Class *>(cnode), treenode)); + cls = Classes.Last(); + } auto node = cnode->Body; PSymbolTreeNode *childnode; @@ -220,6 +241,12 @@ ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols, switch (node->NodeType) { case AST_Class: + // a class extension should not check the tree node symbols. + if (static_cast<ZCC_Class *>(node)->Flags == ZCC_Extension) + { + ProcessClass(static_cast<ZCC_Class *>(node), tnode); + break; + } case AST_Struct: case AST_ConstantDef: case AST_Enum: diff --git a/src/scripting/zscript/zcc_parser.cpp b/src/scripting/zscript/zcc_parser.cpp index 7d4edf78a..bc7857630 100644 --- a/src/scripting/zscript/zcc_parser.cpp +++ b/src/scripting/zscript/zcc_parser.cpp @@ -198,6 +198,7 @@ static void InitTokenMap() TOKENDEF (TK_Offset, ZCC_OFFSET); TOKENDEF (TK_CanRaise, ZCC_CANRAISE); TOKENDEF (TK_Light, ZCC_LIGHT); + TOKENDEF (TK_Extend, ZCC_EXTEND); ZCC_InitOperators(); ZCC_InitConversions(); diff --git a/src/scripting/zscript/zcc_parser.h b/src/scripting/zscript/zcc_parser.h index 503ef7e9e..ca8c3f3cb 100644 --- a/src/scripting/zscript/zcc_parser.h +++ b/src/scripting/zscript/zcc_parser.h @@ -32,6 +32,7 @@ enum ZCC_ReadOnly = 1 << 9, ZCC_FuncConst = 1 << 10, ZCC_Abstract = 1 << 11, + ZCC_Extension = 1 << 12, }; // Function parameter modifiers diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 5144a1bd0..502b8d0cf 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -47,6 +47,9 @@ class Actor : Thinker native } // Functions + native Actor P_SpawnMissile(Actor dest, class<Actor> type, Actor owner = null); + + // DECORATE compatible functions native bool CheckClass(class<Actor> checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false); native bool IsPointerEqual(int ptr_select1, int ptr_select2); native int CountInv(class<Inventory> itemtype, int ptr_select = AAPTR_DEFAULT); @@ -112,8 +115,8 @@ class Actor : Thinker native native void A_BetaSkullAttack(); native void A_Metal(); native void A_SpidRefire(); - native void A_BabyMetal(); - native void A_BspiAttack(); + //native void A_BabyMetal(); + //native void A_BspiAttack(); native void A_Hoof(); native void A_CyberAttack(); native void A_PainAttack(class<Actor> spawntype = "LostSoul", float angle = 0, int flags = 0, int limit = -1);