From e559109419e0d33c70eb968d99db237066b64142 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 15 Nov 2016 16:00:35 +0100 Subject: [PATCH 001/185] - made the floating point truncation warning a debug message because I can see this becoming more a hassle than an asset. --- src/scripting/codegeneration/codegen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index f45bea5e3..8909dd31b 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -848,7 +848,7 @@ FxExpression *FxIntCast::Resolve(FCompileContext &ctx) } else if (!NoWarn) { - ScriptPosition.Message(MSG_WARNING, "Truncation of floating point value"); + ScriptPosition.Message(MSG_DEBUGWARN, "Truncation of floating point value"); } return this; From 4cc7d95ba5f33c8fa357adda863d39aca8d93d4b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 15 Nov 2016 16:05:42 +0100 Subject: [PATCH 002/185] - fixed: A_ZoomFactor and A_SetCrosshair need to be declared 'action'. --- src/g_shared/a_weapons.cpp | 4 ++-- wadsrc/static/zscript/shared/inventory.txt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index 9063c6c2c..9fc2334c4 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -1925,7 +1925,7 @@ PClassWeapon *Net_ReadWeapon(BYTE **stream) DEFINE_ACTION_FUNCTION_PARAMS(AWeapon, A_ZoomFactor) { - PARAM_SELF_PROLOGUE(AActor); + PARAM_ACTION_PROLOGUE(AActor); PARAM_FLOAT_DEF(zoom); PARAM_INT_DEF(flags); @@ -1953,7 +1953,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AWeapon, A_ZoomFactor) DEFINE_ACTION_FUNCTION_PARAMS(AWeapon, A_SetCrosshair) { - PARAM_SELF_PROLOGUE(AActor); + PARAM_ACTION_PROLOGUE(AActor); PARAM_INT(xhair); if (self->player != NULL && self->player->ReadyWeapon != NULL) diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index 377463adc..12f30c484 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -473,11 +473,11 @@ class Weapon : StateProvider native Stop; } - native void A_ZoomFactor(float scale = 1, int flags = 0); + native action void A_ZoomFactor(float scale = 1, int flags = 0); + native action void A_SetCrosshair(int xhair); const ZOOM_INSTANT = 1; const ZOOM_NOSCALETURNING = 2; - native void A_SetCrosshair(int xhair); } class WeaponGiver : Weapon native From 1d006b37c3a96f7ba05ceb6268f6430c6734201a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 15 Nov 2016 17:41:49 +0100 Subject: [PATCH 003/185] - fixed: The distance check in CheckIfCloser used the wrong variable. --- wadsrc/static/zscript/actor_checks.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/zscript/actor_checks.txt b/wadsrc/static/zscript/actor_checks.txt index 806539753..3ad4255d7 100644 --- a/wadsrc/static/zscript/actor_checks.txt +++ b/wadsrc/static/zscript/actor_checks.txt @@ -35,7 +35,7 @@ extend class Actor { if (!targ) return false; return - (Distance2D(target) < dist && (noz || + (Distance2D(targ) < dist && (noz || ((pos.z > targ.pos.z && pos.z - targ.pos.z - targ.height < dist) || (pos.z <= targ.pos.z && targ.pos.z - pos.z - height < dist) ) From f2ec266eec6cff1ee1353eda952989533acf2e43 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Tue, 15 Nov 2016 11:38:03 -0600 Subject: [PATCH 004/185] Fixed: Actors with NOINTERACTION shouldn't waste time continuously applying NOBLOCKMAP if it has it already and not moving. --- src/p_mobj.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 3e2011878..2183f8cb9 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3373,11 +3373,14 @@ void AActor::Tick () } } - UnlinkFromWorld (); - flags |= MF_NOBLOCKMAP; - SetXYZ(Vec3Offset(Vel)); - CheckPortalTransition(false); - LinkToWorld (); + if (!Vel.isZero() || !(flags & MF_NOBLOCKMAP)) + { + UnlinkFromWorld(); + flags |= MF_NOBLOCKMAP; + SetXYZ(Vec3Offset(Vel)); + CheckPortalTransition(false); + LinkToWorld(); + } } else { From a2e17c0ab57409f4c068ba57e9d144dd30710dd8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 15 Nov 2016 21:38:12 +0100 Subject: [PATCH 005/185] - implemented usage restrictions for action functions. --- src/dobjtype.cpp | 3 +- src/dobjtype.h | 5 +- src/scripting/codegeneration/codegen.cpp | 89 +++++++++++++++++------- src/scripting/thingdef.cpp | 2 +- src/scripting/zscript/ast.cpp | 12 ++++ src/scripting/zscript/zcc-parse.lemon | 78 +++++++++++++++------ src/scripting/zscript/zcc_compile.cpp | 50 +++++++++++-- src/scripting/zscript/zcc_parser.h | 8 +++ 8 files changed, 189 insertions(+), 58 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 2c88da92a..5e56bab56 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2489,7 +2489,7 @@ size_t PFunction::PropagateMark() // //========================================================================== -unsigned PFunction::AddVariant(PPrototype *proto, TArray &argflags, TArray &argnames, VMFunction *impl, int flags) +unsigned PFunction::AddVariant(PPrototype *proto, TArray &argflags, TArray &argnames, VMFunction *impl, int flags, int useflags) { Variant variant; @@ -2497,6 +2497,7 @@ unsigned PFunction::AddVariant(PPrototype *proto, TArray &argflags, TArra assert(Variants.Size() == 0); variant.Flags = flags; + variant.UseFlags = useflags; variant.Proto = proto; variant.ArgFlags = std::move(argflags); variant.ArgNames = std::move(argnames); diff --git a/src/dobjtype.h b/src/dobjtype.h index 1ca5df832..186cb8117 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -724,13 +724,14 @@ public: VMFunction *Implementation; TArray ArgFlags; // Should be the same length as Proto->ArgumentTypes TArray ArgNames; // we need the names to access them later when the function gets compiled. - DWORD Flags; + uint32_t Flags; + int UseFlags; PClass *SelfClass; }; TArray Variants; PClass *OwningClass = nullptr; - unsigned AddVariant(PPrototype *proto, TArray &argflags, TArray &argnames, VMFunction *impl, int flags); + unsigned AddVariant(PPrototype *proto, TArray &argflags, TArray &argnames, VMFunction *impl, int flags, int useflags); int GetImplicitArgs() { if (Variants[0].Flags & VARF_Action) return 3; diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 8909dd31b..b64e0c439 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -5931,6 +5931,42 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) return dest; } +//========================================================================== +// +// Checks if a function may be called from the current context. +// +//========================================================================== + +static bool CheckFunctionCompatiblity(FScriptPosition &ScriptPosition, PFunction *caller, PFunction *callee) +{ + if (callee->Variants[0].Flags & VARF_Method) + { + // The called function must support all usage modes of the current function. It may support more, but must not support less. + if ((callee->Variants[0].UseFlags & caller->Variants[0].UseFlags) != caller->Variants[0].UseFlags) + { + ScriptPosition.Message(MSG_ERROR, "Function %s incompatible with current context\n", callee->SymbolName.GetChars()); + return false; + } + + if (!(caller->Variants[0].Flags & VARF_Method)) + { + ScriptPosition.Message(MSG_ERROR, "Call to non-static function %s from a static context", callee->SymbolName.GetChars()); + return false; + } + else + { + auto callingself = caller->Variants[0].SelfClass; + auto calledself = callee->Variants[0].SelfClass; + if (!callingself->IsDescendantOf(calledself)) + { + ScriptPosition.Message(MSG_ERROR, "Call to member function %s with incompatible self pointer.", callee->SymbolName.GetChars()); + return false; + } + } + } + return true; +} + //========================================================================== // // @@ -6008,39 +6044,15 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) PFunction *afd = FindClassMemberFunction(ctx.Class, ctx.Class, MethodName, ScriptPosition, &error); - // Action functions in state providers need special treatment because self is of type Actor here. - if (afd != nullptr && ctx.Class->IsDescendantOf(RUNTIME_CLASS(AStateProvider)) && (ctx.Function->Variants[0].Flags & VARF_Action)) - { - // Only accept static and action functions from the current class. Calling a member function will require explicit use of 'invoker'. - if ((afd->Variants[0].Flags & (VARF_Method|VARF_Action)) == VARF_Method) - { - // Everything else that may be used here must pass the selfclass check, i.e. it must be reachable from Actor. - // Note that FuncClass is still the current item because for symbol privacy checks this is relevant. - afd = FindClassMemberFunction(ctx.Function->Variants[0].SelfClass, ctx.Class, MethodName, ScriptPosition, &error); - if (afd == nullptr) - { - ScriptPosition.Message(MSG_ERROR, "Unable to call non-action function %s from here. Please use 'invoker.%s' to call it.", MethodName.GetChars(), MethodName.GetChars()); - delete this; - return nullptr; - } - } - } - - if (error) - { - delete this; - return nullptr; - } - if (afd != nullptr) { - if (ctx.Function->Variants[0].Flags & VARF_Static && !(afd->Variants[0].Flags & VARF_Static)) + if (!CheckFunctionCompatiblity(ScriptPosition, ctx.Function, afd)) { - ScriptPosition.Message(MSG_ERROR, "Call to non-static function %s from a static context", MethodName.GetChars()); delete this; return nullptr; } - auto self = !(afd->Variants[0].Flags & VARF_Static)? new FxSelf(ScriptPosition) : nullptr; + + auto self = (afd->Variants[0].Flags & VARF_Method)? new FxSelf(ScriptPosition) : nullptr; auto x = new FxVMFunctionCall(self, afd, ArgList, ScriptPosition, false); delete this; return x->Resolve(ctx); @@ -6338,6 +6350,7 @@ isresolved: delete this; return nullptr; } + if (staticonly && (afd->Variants[0].Flags & VARF_Method)) { if (!ctx.Class->IsDescendantOf(cls)) @@ -6355,6 +6368,28 @@ isresolved: } } + if (afd->Variants[0].Flags & VARF_Method) + { + if (Self->ExprType == EFX_Self) + { + if (!CheckFunctionCompatiblity(ScriptPosition, ctx.Function, afd)) + { + delete this; + return nullptr; + } + } + else + { + // Functions with no Actor usage may not be called through a pointer because they will lose their context. + if (!(afd->Variants[0].UseFlags & SUF_ACTOR)) + { + ScriptPosition.Message(MSG_ERROR, "Function %s cannot be used with a non-self object\n", afd->SymbolName.GetChars()); + delete this; + return nullptr; + } + } + } + // do not pass the self pointer to static functions. auto self = (afd->Variants[0].Flags & VARF_Method) ? Self : nullptr; auto x = new FxVMFunctionCall(self, afd, ArgList, ScriptPosition, staticonly|novirtual); diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index bf6b08ea7..3abce216d 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -170,7 +170,7 @@ PFunction *CreateAnonymousFunction(PClass *containingclass, PType *returntype, i SetImplicitArgs(&args, &argflags, &argnames, containingclass, fflags, flags); PFunction *sym = new PFunction(containingclass, NAME_None); // anonymous functions do not have names. - sym->AddVariant(NewPrototype(rets, args), argflags, argnames, nullptr, fflags); + sym->AddVariant(NewPrototype(rets, args), argflags, argnames, nullptr, fflags, flags); return sym; } diff --git a/src/scripting/zscript/ast.cpp b/src/scripting/zscript/ast.cpp index c24867837..89cc9487e 100644 --- a/src/scripting/zscript/ast.cpp +++ b/src/scripting/zscript/ast.cpp @@ -820,6 +820,7 @@ static void PrintFuncDeclarator(FLispString &out, ZCC_TreeNode *node) out.Break(); out.Open("func-declarator"); out.AddHex(dnode->Flags); + PrintNodes(out, dnode->UseFlags); PrintNodes(out, dnode->Type); out.AddName(dnode->Name); PrintNodes(out, dnode->Params); @@ -827,6 +828,16 @@ static void PrintFuncDeclarator(FLispString &out, ZCC_TreeNode *node) out.Close(); } +static void PrintDeclFlags(FLispString &out, ZCC_TreeNode *node) +{ + auto dnode = (ZCC_DeclFlags *)node; + out.Break(); + out.Open("decl-flags"); + out.AddHex(dnode->Flags); + PrintNodes(out, dnode->Id); + out.Close(); +} + static void PrintFlagStmt(FLispString &out, ZCC_TreeNode *node) { auto dnode = (ZCC_FlagStmt *)node; @@ -901,6 +912,7 @@ void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FLispString &, ZCC_TreeNode * PrintFlagStmt, PrintPropertyStmt, PrintVectorInitializer, + PrintDeclFlags, }; FString ZCC_PrintAST(ZCC_TreeNode *root) diff --git a/src/scripting/zscript/zcc-parse.lemon b/src/scripting/zscript/zcc-parse.lemon index a29d3d943..f152cfdd5 100644 --- a/src/scripting/zscript/zcc-parse.lemon +++ b/src/scripting/zscript/zcc-parse.lemon @@ -814,20 +814,21 @@ declarator(X) ::= decl_flags(A) type_list_or_void(B) variables_or_function(C). } else if (C.FuncName != NAME_None) { // A function - NEW_AST_NODE(FuncDeclarator, decl, A.SourceLoc); + NEW_AST_NODE(FuncDeclarator, decl, A == nullptr? C.SourceLoc : A->SourceLoc); decl->Type = B; decl->Params = C.FuncParams; decl->Name = C.FuncName; - decl->Flags = A.Int | C.FuncFlags; + decl->UseFlags = A == nullptr? nullptr : A->Id; + decl->Flags = (A == nullptr? 0 : A->Flags) | C.FuncFlags; decl->Body = C.FuncBody; X = decl; } else if (B != NULL && B->SiblingNext == B) { // A variable - NEW_AST_NODE(VarDeclarator, decl, A.SourceLoc); + NEW_AST_NODE(VarDeclarator, decl, A == nullptr? B->SourceLoc : A->SourceLoc); decl->Type = B; decl->Names = C.VarNames; - decl->Flags = A.Int; + decl->Flags = (A == nullptr? 0 : A->Flags); X = decl; } else @@ -845,10 +846,10 @@ declarator(X) ::= decl_flags(A) type_list_or_void(B) variables_or_function(C). } declarator_no_fun(X) ::= decl_flags(A) type(B) variable_list(C) SEMICOLON. { - NEW_AST_NODE(VarDeclarator, decl, A.SourceLoc ? A.SourceLoc : B->SourceLoc); + NEW_AST_NODE(VarDeclarator, decl, A != nullptr? A->SourceLoc : B->SourceLoc); decl->Type = B; decl->Names = C; - decl->Flags = A.Int; + decl->Flags = A == nullptr? 0 : A->Flags; X = decl; } @@ -916,19 +917,52 @@ variable_list(X) ::= variable_list(A) COMMA variable_name(B). X = A; /*X-overwrites-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; } -decl_flags(X) ::= decl_flags(A) VIRTUAL(T). { X.Int = A.Int | ZCC_Virtual; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } -decl_flags(X) ::= decl_flags(A) OVERRIDE(T). { X.Int = A.Int | ZCC_Override; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } +%type decl_flags { ZCC_DeclFlags * } +decl_flags(X) ::= . { X = NULL; } +decl_flags(X) ::= decl_flags(F) decl_flag(A). +{ + if (F == nullptr) + { + NEW_AST_NODE(DeclFlags,nil_f,A); + X = nil_f; + X->Id = nullptr; + X->Flags = A.Int; + } + else + { + X = F; + X->Flags |= A.Int; + } +} + + +decl_flags(X) ::= decl_flags(F) ACTION(B) states_opts(A). +{ + if (F == nullptr) + { + NEW_AST_NODE(DeclFlags,nil_f,B.SourceLoc); + X = nil_f; + X->Flags = ZCC_Action; + } + else + { + X = F; + X->Flags |= ZCC_Action; + } + X->Id = A; +} + +decl_flag(X) ::= NATIVE(T). { X.Int = ZCC_Native; X.SourceLoc = T.SourceLoc; } +decl_flag(X) ::= STATIC(T). { X.Int = ZCC_Static; X.SourceLoc = T.SourceLoc; } +decl_flag(X) ::= PRIVATE(T). { X.Int = ZCC_Private; X.SourceLoc = T.SourceLoc; } +decl_flag(X) ::= PROTECTED(T). { X.Int = ZCC_Protected; X.SourceLoc = T.SourceLoc; } +decl_flag(X) ::= LATENT(T). { X.Int = ZCC_Latent; X.SourceLoc = T.SourceLoc; } +decl_flag(X) ::= FINAL(T). { X.Int = ZCC_Final; X.SourceLoc = T.SourceLoc; } +decl_flag(X) ::= META(T). { X.Int = ZCC_Meta; X.SourceLoc = T.SourceLoc; } +decl_flag(X) ::= READONLY(T). { X.Int = ZCC_ReadOnly; X.SourceLoc = T.SourceLoc; } +decl_flag(X) ::= DEPRECATED(T). { X.Int = ZCC_Deprecated; X.SourceLoc = T.SourceLoc; } +decl_flag(X) ::= VIRTUAL(T). { X.Int = ZCC_Virtual; X.SourceLoc = T.SourceLoc; } +decl_flag(X) ::= OVERRIDE(T). { X.Int = ZCC_Override; X.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; } @@ -979,9 +1013,9 @@ func_param(X) ::= func_param_flags(A) type(B) IDENTIFIER(C) EQ expr(D). } 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; } +func_param_flags(X) ::= func_param_flags(A) IN(T). { X.Int = A.Int | ZCC_In; X.SourceLoc = T.SourceLoc; } +func_param_flags(X) ::= func_param_flags(A) OUT(T). { X.Int = A.Int | ZCC_Out; X.SourceLoc = T.SourceLoc; } +func_param_flags(X) ::= func_param_flags(A) OPTIONAL(T). { X.Int = A.Int | ZCC_Optional; X.SourceLoc = T.SourceLoc; } /************ Expressions ************/ diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 57475c50e..6cf719d3d 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2051,6 +2051,35 @@ void ZCCCompiler::InitFunctions() uint32_t varflags = VARF_Method; int implicitargs = 1; AFuncDesc *afd = nullptr; + int useflags = SUF_ACTOR | SUF_OVERLAY | SUF_WEAPON | SUF_ITEM; + if (f->UseFlags != nullptr) + { + useflags = 0; + auto p = f->UseFlags; + do + { + switch (p->Id) + { + case NAME_Actor: + useflags |= SUF_ACTOR; + break; + case NAME_Overlay: + useflags |= SUF_OVERLAY; + break; + case NAME_Weapon: + useflags |= SUF_WEAPON; + break; + case NAME_Item: + useflags |= SUF_ITEM; + break; + default: + Error(p, "Unknown Action qualifier %s", FName(p->Id).GetChars()); + break; + } + + p = static_cast(p->SiblingNext); + } while (p != f->UseFlags); + } // map to implementation flags. if (f->Flags & ZCC_Private) varflags |= VARF_Private; @@ -2058,9 +2087,22 @@ void ZCCCompiler::InitFunctions() if (f->Flags & ZCC_Deprecated) varflags |= VARF_Deprecated; if (f->Flags & ZCC_Virtual) varflags |= VARF_Virtual; if (f->Flags & ZCC_Override) varflags |= VARF_Override; - if (f->Flags & ZCC_Action) varflags |= VARF_Action|VARF_Final, implicitargs = 3; // Action implies Final. + if (f->Flags & ZCC_Action) + { + varflags |= VARF_Final; // Action implies Final. + if (useflags & (SUF_OVERLAY | SUF_WEAPON | SUF_ITEM)) + { + varflags |= VARF_Action; + implicitargs = 3; + } + else + { + implicitargs = 1; + } + } if (f->Flags & ZCC_Static) varflags = (varflags & ~VARF_Method) | VARF_Final, implicitargs = 0; // Static implies Final. + if (varflags & VARF_Override) varflags &= ~VARF_Virtual; // allow 'virtual override'. // Only one of these flags may be used. static int exclude[] = { ZCC_Virtual, ZCC_Override, ZCC_Action, ZCC_Static }; @@ -2096,9 +2138,7 @@ void ZCCCompiler::InitFunctions() (*afd->VMPointer)->ImplicitArgs = BYTE(implicitargs); } } - // Todo: parse these values from the definition - int tempuseflags = (varflags & VARF_Action) ? SUF_WEAPON | SUF_ITEM | SUF_OVERLAY | SUF_ACTOR : SUF_ACTOR; - SetImplicitArgs(&args, &argflags, &argnames, c->Type(), varflags, tempuseflags); + SetImplicitArgs(&args, &argflags, &argnames, c->Type(), varflags, useflags); argdefaults.Resize(argnames.Size()); auto p = f->Params; bool hasoptionals = false; @@ -2225,7 +2265,7 @@ void ZCCCompiler::InitFunctions() } PFunction *sym = new PFunction(c->Type(), f->Name); - sym->AddVariant(NewPrototype(rets, args), argflags, argnames, afd == nullptr? nullptr : *(afd->VMPointer), varflags); + sym->AddVariant(NewPrototype(rets, args), argflags, argnames, afd == nullptr? nullptr : *(afd->VMPointer), varflags, useflags); c->Type()->Symbols.ReplaceSymbol(sym); if (!(f->Flags & ZCC_Native)) diff --git a/src/scripting/zscript/zcc_parser.h b/src/scripting/zscript/zcc_parser.h index 1a187af82..ffff78cb8 100644 --- a/src/scripting/zscript/zcc_parser.h +++ b/src/scripting/zscript/zcc_parser.h @@ -101,6 +101,7 @@ enum EZCCTreeNodeType AST_FlagStmt, AST_PropertyStmt, AST_VectorValue, + AST_DeclFlags, NUM_AST_NODE_TYPES }; @@ -473,6 +474,12 @@ struct ZCC_FuncParamDecl : ZCC_TreeNode int Flags; }; +struct ZCC_DeclFlags : ZCC_TreeNode +{ + ZCC_Identifier *Id; + int Flags; +}; + struct ZCC_ConstantDef : ZCC_NamedNode { ZCC_Expression *Value; @@ -498,6 +505,7 @@ struct ZCC_FuncDeclarator : ZCC_Declarator ZCC_FuncParamDecl *Params; ENamedName Name; ZCC_Statement *Body; + ZCC_Identifier *UseFlags; }; struct ZCC_Default : ZCC_CompoundStmt From 633da6e5d874825ee95508e48f70afac8772305b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 16 Nov 2016 01:36:21 +0100 Subject: [PATCH 006/185] - scriptified two of the Acolyte's functions. - added a DActorIterator class. - fixed: It was not possible to have functions of the same name in two different classes because the name they were searched for was not qualified by the class. Changed so that the class name is included now, but to avoid renaming several hundreds of functions all at once, if the search fails, it will repeat with 'Actor' as class name. This commit contains preparations for scriptifying Hexen's Dragon, but that doesn't work yet so it's not included. --- src/CMakeLists.txt | 1 - src/actor.h | 4 + src/d_dehacked.cpp | 22 +- src/g_doom/a_bossbrain.cpp | 2 +- src/g_doom/a_doomweaps.cpp | 6 +- src/g_doom/a_scriptedmarine.cpp | 10 +- src/g_heretic/a_hereticmisc.cpp | 4 +- src/g_heretic/a_hereticweaps.cpp | 4 +- src/g_hexen/a_blastradius.cpp | 2 +- src/g_hexen/a_fighterquietus.cpp | 2 +- src/g_hexen/a_magelightning.cpp | 2 +- src/g_shared/a_bridge.cpp | 2 +- src/g_shared/a_specialspot.cpp | 2 +- src/g_shared/a_weapons.cpp | 4 +- src/g_strife/a_acolyte.cpp | 44 ---- src/g_strife/a_strifeweapons.cpp | 6 +- src/g_strife/a_thingstoblowup.cpp | 2 +- src/p_actionfunctions.cpp | 258 +++++++++++------------ src/p_enemy.cpp | 10 +- src/p_mobj.cpp | 51 +++++ src/p_pspr.cpp | 20 +- src/p_states.cpp | 2 +- src/p_user.cpp | 2 +- src/scripting/codegeneration/codegen.cpp | 2 +- src/scripting/thingdef.h | 2 +- src/scripting/thingdef_data.cpp | 41 ++-- src/scripting/vm/vm.h | 17 +- src/scripting/zscript/zcc_compile.cpp | 2 +- wadsrc/static/zscript/actor.txt | 2 + wadsrc/static/zscript/base.txt | 7 + wadsrc/static/zscript/constants.txt | 19 ++ wadsrc/static/zscript/strife/acolyte.txt | 40 +++- 32 files changed, 334 insertions(+), 260 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ecc28a57d..8e5c022cb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -881,7 +881,6 @@ set( NOT_COMPILED_SOURCE_FILES g_hexen/a_clericholy.cpp g_hexen/a_clericmace.cpp g_hexen/a_clericstaff.cpp - g_hexen/a_dragon.cpp g_hexen/a_fighteraxe.cpp g_hexen/a_fighterhammer.cpp g_hexen/a_fighterplayer.cpp diff --git a/src/actor.h b/src/actor.h index 122839850..d8bb1a897 100644 --- a/src/actor.h +++ b/src/actor.h @@ -1442,6 +1442,10 @@ public: return base; } + void Reinit() + { + base = nullptr; + } private: AActor *base; int id; diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 880cd7dfe..d0addb095 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -185,17 +185,17 @@ DECLARE_ACTION(A_FireRailgun) // Default ammo use of the various weapon attacks static AmmoPerAttack AmmoPerAttacks[] = { - { &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}, + { &AActor_A_Punch_VMPtr, 0}, + { &AActor_A_FirePistol_VMPtr, 1}, + { &AActor_A_FireShotgun_VMPtr, 1}, + { &AActor_A_FireShotgun2_VMPtr, 2}, + { &AActor_A_FireCGun_VMPtr, 1}, + { &AActor_A_FireMissile_VMPtr, 1}, + { &AActor_A_Saw_VMPtr, 0}, + { &AActor_A_FirePlasma_VMPtr, 1}, + { &AActor_A_FireBFG_VMPtr, -1}, // uses deh.BFGCells + { &AActor_A_FireOldBFG_VMPtr, 1}, + { &AActor_A_FireRailgun_VMPtr, 1}, { NULL, 0} }; diff --git a/src/g_doom/a_bossbrain.cpp b/src/g_doom/a_bossbrain.cpp index 5807ce175..8adb5c1df 100644 --- a/src/g_doom/a_bossbrain.cpp +++ b/src/g_doom/a_bossbrain.cpp @@ -14,7 +14,7 @@ static FRandom pr_spawnfly ("SpawnFly"); -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BrainSpit) +DEFINE_ACTION_FUNCTION(AActor, A_BrainSpit) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS_DEF(spawntype, AActor); diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp index bc962800f..108a730c4 100644 --- a/src/g_doom/a_doomweaps.cpp +++ b/src/g_doom/a_doomweaps.cpp @@ -113,7 +113,7 @@ enum SAW_Flags SF_STEALARMOR = 128, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw) +DEFINE_ACTION_FUNCTION(AActor, A_Saw) { PARAM_ACTION_PROLOGUE(AActor); PARAM_SOUND_DEF (fullsound) @@ -454,7 +454,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMissile) // // A_FireSTGrenade: not exactly backported from ST, but should work the same // -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireSTGrenade) +DEFINE_ACTION_FUNCTION(AActor, A_FireSTGrenade) { PARAM_ACTION_PROLOGUE(AActor); PARAM_CLASS_DEF(grenade, AActor); @@ -607,7 +607,7 @@ enum BFG_Flags BFGF_MISSILEORIGIN = 2, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray) +DEFINE_ACTION_FUNCTION(AActor, A_BFGSpray) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS_DEF (spraytype, AActor) diff --git a/src/g_doom/a_scriptedmarine.cpp b/src/g_doom/a_scriptedmarine.cpp index da2c7f791..e270af6b5 100644 --- a/src/g_doom/a_scriptedmarine.cpp +++ b/src/g_doom/a_scriptedmarine.cpp @@ -148,7 +148,7 @@ void AScriptedMarine::Tick () // //============================================================================ -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Refire) +DEFINE_ACTION_FUNCTION(AActor, A_M_Refire) { PARAM_SELF_PROLOGUE(AActor); PARAM_BOOL_DEF(ignoremissile); @@ -247,7 +247,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MarineLook) // //============================================================================ -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Saw) +DEFINE_ACTION_FUNCTION(AActor, A_M_Saw) { PARAM_SELF_PROLOGUE(AActor); PARAM_SOUND_DEF (fullsound) @@ -345,7 +345,7 @@ static void MarinePunch(AActor *self, int damagemul) } } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Punch) +DEFINE_ACTION_FUNCTION(AActor, A_M_Punch) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT(mult); @@ -382,7 +382,7 @@ void P_GunShot2 (AActor *mo, bool accurate, DAngle pitch, PClassActor *pufftype) // //============================================================================ -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_FirePistol) +DEFINE_ACTION_FUNCTION(AActor, A_M_FirePistol) { PARAM_SELF_PROLOGUE(AActor); PARAM_BOOL(accurate); @@ -481,7 +481,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_FireShotgun2) // //============================================================================ -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_FireCGun) +DEFINE_ACTION_FUNCTION(AActor, A_M_FireCGun) { PARAM_SELF_PROLOGUE(AActor); PARAM_BOOL(accurate); diff --git a/src/g_heretic/a_hereticmisc.cpp b/src/g_heretic/a_hereticmisc.cpp index 35b24eb93..6af969842 100644 --- a/src/g_heretic/a_hereticmisc.cpp +++ b/src/g_heretic/a_hereticmisc.cpp @@ -42,7 +42,7 @@ static FRandom pr_volcimpact ("VolcBallImpact"); // //---------------------------------------------------------------------------- -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PodPain) +DEFINE_ACTION_FUNCTION(AActor, A_PodPain) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS_DEF (gootype, AActor) @@ -97,7 +97,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_RemovePod) #define MAX_GEN_PODS 16 -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MakePod) +DEFINE_ACTION_FUNCTION(AActor, A_MakePod) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS_DEF(podtype, AActor) diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp index a888be884..4d3a0b0e8 100644 --- a/src/g_heretic/a_hereticweaps.cpp +++ b/src/g_heretic/a_hereticweaps.cpp @@ -59,7 +59,7 @@ extern bool P_AutoUseChaosDevice (player_t *player); // //---------------------------------------------------------------------------- -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StaffAttack) +DEFINE_ACTION_FUNCTION(AActor, A_StaffAttack) { PARAM_ACTION_PROLOGUE(AActor); @@ -245,7 +245,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireCrossbowPL2) // //--------------------------------------------------------------------------- -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GauntletAttack) +DEFINE_ACTION_FUNCTION(AActor, A_GauntletAttack) { PARAM_ACTION_PROLOGUE(AActor); diff --git a/src/g_hexen/a_blastradius.cpp b/src/g_hexen/a_blastradius.cpp index f8bc60a7f..0776e107f 100644 --- a/src/g_hexen/a_blastradius.cpp +++ b/src/g_hexen/a_blastradius.cpp @@ -93,7 +93,7 @@ enum // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS (AActor, A_Blast) +DEFINE_ACTION_FUNCTION (AActor, A_Blast) { PARAM_ACTION_PROLOGUE(AActor); PARAM_INT_DEF (blastflags) diff --git a/src/g_hexen/a_fighterquietus.cpp b/src/g_hexen/a_fighterquietus.cpp index 8f73ef48e..adba8d235 100644 --- a/src/g_hexen/a_fighterquietus.cpp +++ b/src/g_hexen/a_fighterquietus.cpp @@ -24,7 +24,7 @@ static FRandom pr_fswordflame ("FSwordFlame"); // //============================================================================ -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DropWeaponPieces) +DEFINE_ACTION_FUNCTION(AActor, A_DropWeaponPieces) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS(p1, AActor); diff --git a/src/g_hexen/a_magelightning.cpp b/src/g_hexen/a_magelightning.cpp index b06d22ce5..2a744db75 100644 --- a/src/g_hexen/a_magelightning.cpp +++ b/src/g_hexen/a_magelightning.cpp @@ -255,7 +255,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LightningZap) // //============================================================================ -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MLightningAttack) +DEFINE_ACTION_FUNCTION(AActor, A_MLightningAttack) { PARAM_ACTION_PROLOGUE(AActor); PARAM_CLASS_DEF(floor, AActor); diff --git a/src/g_shared/a_bridge.cpp b/src/g_shared/a_bridge.cpp index ab0df27e1..8ce23b68e 100644 --- a/src/g_shared/a_bridge.cpp +++ b/src/g_shared/a_bridge.cpp @@ -119,7 +119,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BridgeOrbit) } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BridgeInit) +DEFINE_ACTION_FUNCTION(AActor, A_BridgeInit) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS_DEF(balltype, AActor); diff --git a/src/g_shared/a_specialspot.cpp b/src/g_shared/a_specialspot.cpp index 86d0b5e8a..92306ce6b 100644 --- a/src/g_shared/a_specialspot.cpp +++ b/src/g_shared/a_specialspot.cpp @@ -377,7 +377,7 @@ void ASpecialSpot::Destroy() // will build a list of all mace spots in the level and spawn a // mace. The rest of the spots will do nothing. -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnSingleItem) +DEFINE_ACTION_FUNCTION(AActor, A_SpawnSingleItem) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS (cls, AActor); diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index 9fc2334c4..2d159eb7d 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -1923,7 +1923,7 @@ PClassWeapon *Net_ReadWeapon(BYTE **stream) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AWeapon, A_ZoomFactor) +DEFINE_ACTION_FUNCTION(AWeapon, A_ZoomFactor) { PARAM_ACTION_PROLOGUE(AActor); PARAM_FLOAT_DEF(zoom); @@ -1951,7 +1951,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AWeapon, A_ZoomFactor) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AWeapon, A_SetCrosshair) +DEFINE_ACTION_FUNCTION(AWeapon, A_SetCrosshair) { PARAM_ACTION_PROLOGUE(AActor); PARAM_INT(xhair); diff --git a/src/g_strife/a_acolyte.cpp b/src/g_strife/a_acolyte.cpp index a21c06619..f0ed0c414 100644 --- a/src/g_strife/a_acolyte.cpp +++ b/src/g_strife/a_acolyte.cpp @@ -84,47 +84,3 @@ DEFINE_ACTION_FUNCTION(AActor, A_AcolyteDie) return 0; } -//============================================================================ -// -// A_BeShadowyFoe -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_BeShadowyFoe) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->RenderStyle = STYLE_Translucent; - self->Alpha = HR_SHADOW; - self->flags &= ~MF_FRIENDLY; - return 0; -} - -//============================================================================ -// -// A_AcolyteBits -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_AcolyteBits) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (self->SpawnFlags & MTF_SHADOW) - { - CALL_ACTION(A_BeShadowyFoe, self); - } - if (self->SpawnFlags & MTF_ALTSHADOW) - { - //self->flags |= MF_STRIFEx8000000; - if (self->flags & MF_SHADOW) - { - // I dunno. - } - else - { - self->RenderStyle.BlendOp = STYLEOP_None; - } - } - return 0; -} diff --git a/src/g_strife/a_strifeweapons.cpp b/src/g_strife/a_strifeweapons.cpp index 4dad52de4..56eb06597 100644 --- a/src/g_strife/a_strifeweapons.cpp +++ b/src/g_strife/a_strifeweapons.cpp @@ -144,7 +144,7 @@ enum AMF_EMITFROMTARGET = 4, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_AlertMonsters) +DEFINE_ACTION_FUNCTION(AActor, A_AlertMonsters) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT_DEF(maxdist); @@ -246,7 +246,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ShowElectricFlash) // //============================================================================ -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireArrow) +DEFINE_ACTION_FUNCTION(AActor, A_FireArrow) { PARAM_ACTION_PROLOGUE(AActor); PARAM_CLASS(ti, AActor); @@ -686,7 +686,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Burnination) // //============================================================================ -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireGrenade) +DEFINE_ACTION_FUNCTION(AActor, A_FireGrenade) { PARAM_ACTION_PROLOGUE(AActor); PARAM_CLASS(grenadetype, AActor); diff --git a/src/g_strife/a_thingstoblowup.cpp b/src/g_strife/a_thingstoblowup.cpp index 5e1bc42d2..08670d484 100644 --- a/src/g_strife/a_thingstoblowup.cpp +++ b/src/g_strife/a_thingstoblowup.cpp @@ -26,7 +26,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Bang4Cloud) // ------------------------------------------------------------------- -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveQuestItem) +DEFINE_ACTION_FUNCTION(AActor, A_GiveQuestItem) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT(questitem); diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index d59b45256..2d219fc38 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -306,7 +306,7 @@ DEFINE_ACTION_FUNCTION(AActor, GetMissileDamage) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, CountInv) +DEFINE_ACTION_FUNCTION(AActor, CountInv) { if (numret > 0) { @@ -337,7 +337,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, CountInv) // NON-ACTION function to get the distance in double. // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetDistance) +DEFINE_ACTION_FUNCTION(AActor, GetDistance) { if (numret > 0) { @@ -380,7 +380,7 @@ enum GAFlags GAF_SWITCH = 1 << 1, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetAngle) +DEFINE_ACTION_FUNCTION(AActor, GetAngle) { if (numret > 0) { @@ -413,7 +413,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetAngle) // GetSpawnHealth // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetSpawnHealth) +DEFINE_ACTION_FUNCTION(AActor, GetSpawnHealth) { if (numret > 0) { @@ -429,7 +429,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetSpawnHealth) // GetGibHealth // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetGibHealth) +DEFINE_ACTION_FUNCTION(AActor, GetGibHealth) { if (numret > 0) { @@ -446,7 +446,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetGibHealth) // // NON-ACTION function returns the sprite angle of a pointer. //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetSpriteAngle) +DEFINE_ACTION_FUNCTION(AActor, GetSpriteAngle) { if (numret > 0) { @@ -475,7 +475,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetSpriteAngle) // // NON-ACTION function returns the sprite rotation of a pointer. //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetSpriteRotation) +DEFINE_ACTION_FUNCTION(AActor, GetSpriteRotation) { if (numret > 0) { @@ -515,7 +515,7 @@ enum GZFlags GZF_NO3DFLOOR = 1 << 5, // Pass all 3D floors. }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetZAt) +DEFINE_ACTION_FUNCTION(AActor, GetZAt) { if (numret > 0) { @@ -603,7 +603,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetZAt) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetCrouchFactor) +DEFINE_ACTION_FUNCTION(AActor, GetCrouchFactor) { if (numret > 0) { @@ -633,7 +633,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetCrouchFactor) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetCVar) +DEFINE_ACTION_FUNCTION(AActor, GetCVar) { if (numret > 0) { @@ -663,7 +663,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetCVar) // Takes a pointer as anyone may or may not be a player. //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetPlayerInput) +DEFINE_ACTION_FUNCTION(AActor, GetPlayerInput) { if (numret > 0) { @@ -696,7 +696,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetPlayerInput) // Takes a pointer as anyone may or may not be a player. //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, CountProximity) +DEFINE_ACTION_FUNCTION(AActor, CountProximity) { if (numret > 0) { @@ -731,21 +731,21 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, CountProximity) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, __decorate_internal_int__) +DEFINE_ACTION_FUNCTION(AActor, __decorate_internal_int__) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT(returnme); ACTION_RETURN_INT(returnme); } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, __decorate_internal_bool__) +DEFINE_ACTION_FUNCTION(AActor, __decorate_internal_bool__) { PARAM_SELF_PROLOGUE(AActor); PARAM_BOOL(returnme); ACTION_RETURN_BOOL(returnme); } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, __decorate_internal_float__) +DEFINE_ACTION_FUNCTION(AActor, __decorate_internal_float__) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT(returnme); @@ -768,7 +768,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, __decorate_internal_float__) //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RearrangePointers) +DEFINE_ACTION_FUNCTION(AActor, A_RearrangePointers) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (ptr_target); @@ -848,7 +848,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RearrangePointers) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TransferPointer) +DEFINE_ACTION_FUNCTION(AActor, A_TransferPointer) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (ptr_source); @@ -891,7 +891,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TransferPointer) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CopyFriendliness) +DEFINE_ACTION_FUNCTION(AActor, A_CopyFriendliness) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT_DEF (ptr_source); @@ -974,7 +974,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ComboAttack) return 0; } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BasicAttack) +DEFINE_ACTION_FUNCTION(AActor, A_BasicAttack) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (melee_damage); @@ -995,7 +995,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BasicAttack) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlaySound) +DEFINE_ACTION_FUNCTION(AActor, A_PlaySound) { PARAM_SELF_PROLOGUE(AActor); PARAM_SOUND_DEF (soundid); @@ -1019,7 +1019,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlaySound) return 0; } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StopSound) +DEFINE_ACTION_FUNCTION(AActor, A_StopSound) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT_DEF(slot); @@ -1037,7 +1037,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StopSound) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlaySoundEx) +DEFINE_ACTION_FUNCTION(AActor, A_PlaySoundEx) { PARAM_SELF_PROLOGUE(AActor); PARAM_SOUND (soundid); @@ -1074,7 +1074,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlaySoundEx) return 0; } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StopSoundEx) +DEFINE_ACTION_FUNCTION(AActor, A_StopSoundEx) { PARAM_SELF_PROLOGUE(AActor); PARAM_NAME(channel); @@ -1098,7 +1098,7 @@ enum SMF_PRECISE = 2, SMF_CURSPEED = 4, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SeekerMissile) +DEFINE_ACTION_FUNCTION(AActor, A_SeekerMissile) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT(ang1); @@ -1155,7 +1155,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BulletAttack) // State jump function // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Jump) +DEFINE_ACTION_FUNCTION(AActor, A_Jump) { PARAM_ACTION_PROLOGUE(AActor); PARAM_INT(maxchance); @@ -1219,7 +1219,7 @@ DEFINE_ACTION_FUNCTION(AActor, CheckInventory) // State jump function // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, CheckArmorType) +DEFINE_ACTION_FUNCTION(AActor, CheckArmorType) { PARAM_SELF_PROLOGUE(AActor); PARAM_NAME (type); @@ -1244,7 +1244,7 @@ enum XF_NOSPLASH = 16, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Explode) +DEFINE_ACTION_FUNCTION(AActor, A_Explode) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT_DEF (damage); @@ -1313,7 +1313,7 @@ enum RTF_NOTMISSILE = 4, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusThrust) +DEFINE_ACTION_FUNCTION(AActor, A_RadiusThrust) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT_DEF (force); @@ -1353,7 +1353,7 @@ enum RDSF_BFGDAMAGE = 1, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusDamageSelf) +DEFINE_ACTION_FUNCTION(AActor, A_RadiusDamageSelf) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT_DEF(damage); @@ -1414,7 +1414,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusDamageSelf) // Execute a line special / script // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CallSpecial) +DEFINE_ACTION_FUNCTION(AActor, A_CallSpecial) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (special); @@ -1447,7 +1447,7 @@ enum CM_Flags CMF_ABSOLUTEANGLE = 128 }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMissile) +DEFINE_ACTION_FUNCTION(AActor, A_CustomMissile) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS (ti, AActor); @@ -1596,7 +1596,7 @@ enum CBA_Flags static void AimBulletMissile(AActor *proj, AActor *puff, int flags, bool temp, bool cba); -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack) +DEFINE_ACTION_FUNCTION(AActor, A_CustomBulletAttack) { PARAM_SELF_PROLOGUE(AActor); PARAM_ANGLE (spread_xy); @@ -1688,7 +1688,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack) // A fully customizable melee attack // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMeleeAttack) +DEFINE_ACTION_FUNCTION(AActor, A_CustomMeleeAttack) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT_DEF (damage); @@ -1725,7 +1725,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMeleeAttack) // A fully customizable combo attack // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomComboAttack) +DEFINE_ACTION_FUNCTION(AActor, A_CustomComboAttack) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS (ti, AActor); @@ -1775,7 +1775,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomComboAttack) // State jump function // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfNoAmmo) +DEFINE_ACTION_FUNCTION(AActor, A_JumpIfNoAmmo) { PARAM_ACTION_PROLOGUE(AActor); PARAM_STATE_ACTION(jump); @@ -1846,7 +1846,7 @@ static void AimBulletMissile(AActor *proj, AActor *puff, int flags, bool temp, b } } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets) +DEFINE_ACTION_FUNCTION(AActor, A_FireBullets) { PARAM_ACTION_PROLOGUE(AActor); PARAM_ANGLE (spread_xy); @@ -1976,7 +1976,7 @@ enum FP_Flags FPF_TRANSFERTRANSLATION = 2, FPF_NOAUTOAIM = 4, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireCustomMissile) +DEFINE_ACTION_FUNCTION(AActor, A_FireCustomMissile) { PARAM_ACTION_PROLOGUE(AActor); PARAM_CLASS (ti, AActor); @@ -2053,7 +2053,7 @@ enum CPF_STEALARMOR = 32, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) +DEFINE_ACTION_FUNCTION(AActor, A_CustomPunch) { PARAM_ACTION_PROLOGUE(AActor); PARAM_INT (damage); @@ -2157,7 +2157,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) // customizable railgun attack function // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack) +DEFINE_ACTION_FUNCTION(AActor, A_RailAttack) { PARAM_ACTION_PROLOGUE(AActor); PARAM_INT (damage); @@ -2236,7 +2236,7 @@ enum CRF_EXPLICITANGLE = 4, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) +DEFINE_ACTION_FUNCTION(AActor, A_CustomRailgun) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (damage); @@ -2409,19 +2409,19 @@ static bool DoGiveInventory(AActor *receiver, bool orresult, VM_ARGS) return false; } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveInventory) +DEFINE_ACTION_FUNCTION(AActor, A_GiveInventory) { PARAM_SELF_PROLOGUE(AActor); ACTION_RETURN_BOOL(DoGiveInventory(self, false, VM_ARGS_NAMES)); } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveToTarget) +DEFINE_ACTION_FUNCTION(AActor, A_GiveToTarget) { PARAM_SELF_PROLOGUE(AActor); ACTION_RETURN_BOOL(DoGiveInventory(self->target, false, VM_ARGS_NAMES)); } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveToChildren) +DEFINE_ACTION_FUNCTION(AActor, A_GiveToChildren) { PARAM_SELF_PROLOGUE(AActor); @@ -2439,7 +2439,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveToChildren) ACTION_RETURN_INT(count); } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveToSiblings) +DEFINE_ACTION_FUNCTION(AActor, A_GiveToSiblings) { PARAM_SELF_PROLOGUE(AActor); @@ -2466,7 +2466,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveToSiblings) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetInventory) +DEFINE_ACTION_FUNCTION(AActor, A_SetInventory) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS(itemtype, AInventory); @@ -2585,19 +2585,19 @@ bool DoTakeInventory(AActor *receiver, bool orresult, VM_ARGS) return receiver->TakeInventory(itemtype, amount, true, (flags & TIF_NOTAKEINFINITE) != 0); } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TakeInventory) +DEFINE_ACTION_FUNCTION(AActor, A_TakeInventory) { PARAM_SELF_PROLOGUE(AActor); ACTION_RETURN_BOOL(DoTakeInventory(self, false, VM_ARGS_NAMES)); } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TakeFromTarget) +DEFINE_ACTION_FUNCTION(AActor, A_TakeFromTarget) { PARAM_SELF_PROLOGUE(AActor); ACTION_RETURN_BOOL(DoTakeInventory(self->target, false, VM_ARGS_NAMES)); } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TakeFromChildren) +DEFINE_ACTION_FUNCTION(AActor, A_TakeFromChildren) { PARAM_SELF_PROLOGUE(AActor); TThinkerIterator it; @@ -2614,7 +2614,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TakeFromChildren) ACTION_RETURN_INT(count); } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TakeFromSiblings) +DEFINE_ACTION_FUNCTION(AActor, A_TakeFromSiblings) { PARAM_SELF_PROLOGUE(AActor); TThinkerIterator it; @@ -2850,7 +2850,7 @@ static bool InitSpawnedItem(AActor *self, AActor *mo, int flags) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItem) +DEFINE_ACTION_FUNCTION(AActor, A_SpawnItem) { PARAM_ACTION_PROLOGUE(AActor); PARAM_CLASS_DEF (missile, AActor) @@ -2898,7 +2898,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItem) // Enhanced spawning function // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItemEx) +DEFINE_ACTION_FUNCTION(AActor, A_SpawnItemEx) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS (missile, AActor); @@ -2982,7 +2982,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItemEx) // Throws a grenade (like Hexen's fighter flechette) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ThrowGrenade) +DEFINE_ACTION_FUNCTION(AActor, A_ThrowGrenade) { PARAM_ACTION_PROLOGUE(AActor); PARAM_CLASS (missile, AActor); @@ -3060,7 +3060,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ThrowGrenade) // A_Recoil // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Recoil) +DEFINE_ACTION_FUNCTION(AActor, A_Recoil) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT(xyvel); @@ -3079,7 +3079,7 @@ enum SW_Flags { SWF_SELECTPRIORITY = 1, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SelectWeapon) +DEFINE_ACTION_FUNCTION(AActor, A_SelectWeapon) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS(cls, AWeapon); @@ -3124,7 +3124,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SelectWeapon) //=========================================================================== EXTERN_CVAR(Float, con_midtime) -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Print) +DEFINE_ACTION_FUNCTION(AActor, A_Print) { PARAM_SELF_PROLOGUE(AActor); PARAM_STRING (text); @@ -3159,7 +3159,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Print) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PrintBold) +DEFINE_ACTION_FUNCTION(AActor, A_PrintBold) { PARAM_SELF_PROLOGUE(AActor); PARAM_STRING (text); @@ -3190,7 +3190,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PrintBold) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Log) +DEFINE_ACTION_FUNCTION(AActor, A_Log) { PARAM_SELF_PROLOGUE(AActor); PARAM_STRING(text); @@ -3207,7 +3207,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Log) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LogInt) +DEFINE_ACTION_FUNCTION(AActor, A_LogInt) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT(num); @@ -3221,7 +3221,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LogInt) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LogFloat) +DEFINE_ACTION_FUNCTION(AActor, A_LogFloat) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT(num); @@ -3236,7 +3236,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LogFloat) // A_SetTranslucent // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTranslucent) +DEFINE_ACTION_FUNCTION(AActor, A_SetTranslucent) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT (alpha); @@ -3255,7 +3255,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTranslucent) // A_SetRenderStyle // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRenderStyle) +DEFINE_ACTION_FUNCTION(AActor, A_SetRenderStyle) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT(alpha); @@ -3280,7 +3280,7 @@ enum FadeFlags FTF_CLAMP = 1 << 1, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeIn) +DEFINE_ACTION_FUNCTION(AActor, A_FadeIn) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT_DEF(reduce); @@ -3315,7 +3315,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeIn) // fades the actor out and destroys it when done // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeOut) +DEFINE_ACTION_FUNCTION(AActor, A_FadeOut) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT_DEF(reduce); @@ -3349,7 +3349,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeOut) // destroys it if so desired // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeTo) +DEFINE_ACTION_FUNCTION(AActor, A_FadeTo) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT (target); @@ -3392,7 +3392,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeTo) // A_SpawnDebris // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnDebris) +DEFINE_ACTION_FUNCTION(AActor, A_SpawnDebris) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS (debris, AActor); @@ -3448,7 +3448,7 @@ enum SPFflag SPF_NOTIMEFREEZE = 1 << 5, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnParticle) +DEFINE_ACTION_FUNCTION(AActor, A_SpawnParticle) { PARAM_SELF_PROLOGUE(AActor); PARAM_COLOR (color); @@ -3509,7 +3509,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnParticle) // jumps if no player can see this actor // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, CheckIfSeen) +DEFINE_ACTION_FUNCTION(AActor, CheckIfSeen) { PARAM_SELF_PROLOGUE(AActor); @@ -3577,7 +3577,7 @@ static bool DoCheckSightOrRange(AActor *self, AActor *camera, double range, bool return false; } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, CheckSightOrRange) +DEFINE_ACTION_FUNCTION(AActor, CheckSightOrRange) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT(range); @@ -3605,7 +3605,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, CheckSightOrRange) } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, CheckRange) +DEFINE_ACTION_FUNCTION(AActor, CheckRange) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT(range); @@ -3638,7 +3638,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, CheckRange) // Inventory drop // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DropInventory) +DEFINE_ACTION_FUNCTION(AActor, A_DropInventory) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS(drop, AInventory); @@ -3660,7 +3660,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DropInventory) // A_SetBlend // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetBlend) +DEFINE_ACTION_FUNCTION(AActor, A_SetBlend) { PARAM_SELF_PROLOGUE(AActor); PARAM_COLOR (color); @@ -3688,7 +3688,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetBlend) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CountdownArg) +DEFINE_ACTION_FUNCTION(AActor, A_CountdownArg) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT(cnt); @@ -3720,7 +3720,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CountdownArg) // //============================================================================ -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Burst) +DEFINE_ACTION_FUNCTION(AActor, A_Burst) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS(chunk, AActor); @@ -3816,7 +3816,7 @@ enum RS_Flags RSF_TELEFRAG=4, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Respawn) +DEFINE_ACTION_FUNCTION(AActor, A_Respawn) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT_DEF(flags); @@ -4033,7 +4033,7 @@ ETraceStatus CheckLOFTraceFunc(FTraceResults &trace, void *userdata) return TRACE_Abort; } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, CheckLOF) +DEFINE_ACTION_FUNCTION(AActor, CheckLOF) { // Check line of fire @@ -4234,7 +4234,7 @@ enum JLOS_flags JLOSF_CHECKTRACER = 1 << 12, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, CheckIfTargetInLOS) +DEFINE_ACTION_FUNCTION(AActor, CheckIfTargetInLOS) { PARAM_SELF_PROLOGUE(AActor); PARAM_ANGLE_DEF (fov) @@ -4371,7 +4371,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, CheckIfTargetInLOS) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, CheckIfInTargetLOS) +DEFINE_ACTION_FUNCTION(AActor, CheckIfInTargetLOS) { PARAM_SELF_PROLOGUE(AActor); PARAM_ANGLE_DEF (fov) @@ -4451,7 +4451,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, CheckIfInTargetLOS) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckForReload) +DEFINE_ACTION_FUNCTION(AActor, A_CheckForReload) { PARAM_ACTION_PROLOGUE(AActor); @@ -4521,7 +4521,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ResetReloadCounter) // A_ChangeFlag // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeFlag) +DEFINE_ACTION_FUNCTION(AActor, A_ChangeFlag) { PARAM_SELF_PROLOGUE(AActor); PARAM_STRING (flagname); @@ -4537,7 +4537,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeFlag) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, CheckFlag) +DEFINE_ACTION_FUNCTION(AActor, CheckFlag) { PARAM_SELF_PROLOGUE(AActor); PARAM_STRING (flagname); @@ -4548,7 +4548,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, CheckFlag) } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeCountFlags) +DEFINE_ACTION_FUNCTION(AActor, A_ChangeCountFlags) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT_DEF(kill); @@ -4655,7 +4655,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_RaiseSiblings) // Keep firing unless target got out of sight // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MonsterRefire) +DEFINE_ACTION_FUNCTION(AActor, A_MonsterRefire) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (prob); @@ -4691,7 +4691,7 @@ enum }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetAngle) +DEFINE_ACTION_FUNCTION(AActor, A_SetAngle) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT_DEF(angle); @@ -4714,7 +4714,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetAngle) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetPitch) +DEFINE_ACTION_FUNCTION(AActor, A_SetPitch) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT(pitch); @@ -4738,7 +4738,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetPitch) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRoll) +DEFINE_ACTION_FUNCTION(AActor, A_SetRoll) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT (roll); @@ -4761,7 +4761,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRoll) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ScaleVelocity) +DEFINE_ACTION_FUNCTION(AActor, A_ScaleVelocity) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT(scale); @@ -4793,7 +4793,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ScaleVelocity) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeVelocity) +DEFINE_ACTION_FUNCTION(AActor, A_ChangeVelocity) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT_DEF (x) @@ -4855,7 +4855,7 @@ static PField *GetVar(DObject *self, FName varname) return var; } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserVar) +DEFINE_ACTION_FUNCTION(AActor, A_SetUserVar) { PARAM_SELF_PROLOGUE(DObject); PARAM_NAME (varname); @@ -4870,7 +4870,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserVar) return 0; } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserVarFloat) +DEFINE_ACTION_FUNCTION(AActor, A_SetUserVarFloat) { PARAM_SELF_PROLOGUE(DObject); PARAM_NAME (varname); @@ -4912,7 +4912,7 @@ static PField *GetArrayVar(DObject *self, FName varname, int pos) return var; } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserArray) +DEFINE_ACTION_FUNCTION(AActor, A_SetUserArray) { PARAM_SELF_PROLOGUE(DObject); PARAM_NAME (varname); @@ -4929,7 +4929,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserArray) return 0; } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserArrayFloat) +DEFINE_ACTION_FUNCTION(AActor, A_SetUserArrayFloat) { PARAM_SELF_PROLOGUE(DObject); PARAM_NAME (varname); @@ -4973,7 +4973,7 @@ enum T_Flags TF_SENSITIVEZ = 0x00000800, // Fail if the actor wouldn't fit in the position (for Z). }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) +DEFINE_ACTION_FUNCTION(AActor, A_Teleport) { PARAM_ACTION_PROLOGUE(AActor); PARAM_STATE_DEF (teleport_state) @@ -5149,7 +5149,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Quake) +DEFINE_ACTION_FUNCTION(AActor, A_Quake) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (intensity); @@ -5170,7 +5170,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Quake) // take flags. //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_QuakeEx) +DEFINE_ACTION_FUNCTION(AActor, A_QuakeEx) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT(intensityX); @@ -5241,7 +5241,7 @@ void A_Weave(AActor *self, int xyspeed, int zspeed, double xydist, double zdist) } } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Weave) +DEFINE_ACTION_FUNCTION(AActor, A_Weave) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (xspeed); @@ -5263,7 +5263,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Weave) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LineEffect) +DEFINE_ACTION_FUNCTION(AActor, A_LineEffect) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT_DEF(special); @@ -5298,7 +5298,7 @@ enum WolfAttackFlags WAF_USEPUFF = 2, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack) +DEFINE_ACTION_FUNCTION(AActor, A_WolfAttack) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT_DEF (flags) @@ -5403,7 +5403,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) +DEFINE_ACTION_FUNCTION(AActor, A_Warp) { PARAM_ACTION_PROLOGUE(AActor); PARAM_INT(destination_selector); @@ -5655,7 +5655,7 @@ static bool DoRadiusGive(AActor *self, AActor *thing, PClassActor *item, int amo return false; } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) +DEFINE_ACTION_FUNCTION(AActor, A_RadiusGive) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS (item, AInventory); @@ -5708,7 +5708,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTics) +DEFINE_ACTION_FUNCTION(AActor, A_SetTics) { PARAM_ACTION_PROLOGUE(AActor); PARAM_INT(tics_to_set); @@ -5737,7 +5737,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTics) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DropItem) +DEFINE_ACTION_FUNCTION(AActor, A_DropItem) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS (spawntype, AActor); @@ -5818,7 +5818,7 @@ static void DoDamage(AActor *dmgtarget, AActor *inflictor, AActor *source, int a // // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageSelf) +DEFINE_ACTION_FUNCTION(AActor, A_DamageSelf) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (amount); @@ -5841,7 +5841,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageSelf) // // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageTarget) +DEFINE_ACTION_FUNCTION(AActor, A_DamageTarget) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (amount); @@ -5865,7 +5865,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageTarget) // // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageTracer) +DEFINE_ACTION_FUNCTION(AActor, A_DamageTracer) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (amount); @@ -5889,7 +5889,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageTracer) // // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageMaster) +DEFINE_ACTION_FUNCTION(AActor, A_DamageMaster) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (amount); @@ -5913,7 +5913,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageMaster) // // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageChildren) +DEFINE_ACTION_FUNCTION(AActor, A_DamageChildren) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (amount); @@ -5943,7 +5943,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageChildren) // // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageSiblings) +DEFINE_ACTION_FUNCTION(AActor, A_DamageSiblings) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (amount); @@ -6026,7 +6026,7 @@ static void DoKill(AActor *killtarget, AActor *inflictor, AActor *source, FName // A_KillTarget(damagetype, int flags) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillTarget) +DEFINE_ACTION_FUNCTION(AActor, A_KillTarget) { PARAM_SELF_PROLOGUE(AActor); PARAM_NAME_DEF (damagetype) @@ -6049,7 +6049,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillTarget) // A_KillTracer(damagetype, int flags) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillTracer) +DEFINE_ACTION_FUNCTION(AActor, A_KillTracer) { PARAM_SELF_PROLOGUE(AActor); PARAM_NAME_DEF (damagetype) @@ -6072,7 +6072,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillTracer) // A_KillMaster(damagetype, int flags) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillMaster) +DEFINE_ACTION_FUNCTION(AActor, A_KillMaster) { PARAM_SELF_PROLOGUE(AActor); PARAM_NAME_DEF (damagetype) @@ -6095,7 +6095,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillMaster) // A_KillChildren(damagetype, int flags) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillChildren) +DEFINE_ACTION_FUNCTION(AActor, A_KillChildren) { PARAM_SELF_PROLOGUE(AActor); PARAM_NAME_DEF (damagetype) @@ -6126,7 +6126,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillChildren) // A_KillSiblings(damagetype, int flags) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillSiblings) +DEFINE_ACTION_FUNCTION(AActor, A_KillSiblings) { PARAM_SELF_PROLOGUE(AActor); PARAM_NAME_DEF (damagetype) @@ -6202,7 +6202,7 @@ static void DoRemove(AActor *removetarget, int flags, PClassActor *filter, FName // A_RemoveTarget // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveTarget) +DEFINE_ACTION_FUNCTION(AActor, A_RemoveTarget) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT_DEF(flags); @@ -6221,7 +6221,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveTarget) // A_RemoveTracer // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveTracer) +DEFINE_ACTION_FUNCTION(AActor, A_RemoveTracer) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT_DEF(flags); @@ -6240,7 +6240,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveTracer) // A_RemoveMaster // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveMaster) +DEFINE_ACTION_FUNCTION(AActor, A_RemoveMaster) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT_DEF(flags); @@ -6259,7 +6259,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveMaster) // A_RemoveChildren // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveChildren) +DEFINE_ACTION_FUNCTION(AActor, A_RemoveChildren) { PARAM_SELF_PROLOGUE(AActor); PARAM_BOOL_DEF(removeall); @@ -6285,7 +6285,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveChildren) // A_RemoveSiblings // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveSiblings) +DEFINE_ACTION_FUNCTION(AActor, A_RemoveSiblings) { PARAM_SELF_PROLOGUE(AActor); PARAM_BOOL_DEF(removeall); @@ -6314,7 +6314,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveSiblings) // A_Remove // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Remove) +DEFINE_ACTION_FUNCTION(AActor, A_Remove) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT(removee); @@ -6338,7 +6338,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Remove) // Takes a name of the classes for the source and destination. //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTeleFog) +DEFINE_ACTION_FUNCTION(AActor, A_SetTeleFog) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS(oldpos, AActor); @@ -6383,7 +6383,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SwapTeleFog) // Takes a pointer as well. //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetHealth) +DEFINE_ACTION_FUNCTION(AActor, A_SetHealth) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (health); @@ -6421,7 +6421,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetHealth) // Takes a pointer. //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ResetHealth) +DEFINE_ACTION_FUNCTION(AActor, A_ResetHealth) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT_DEF(ptr); @@ -6450,7 +6450,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ResetHealth) // // Sets the species of the calling actor('s pointer). //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpecies) +DEFINE_ACTION_FUNCTION(AActor, A_SetSpecies) { PARAM_SELF_PROLOGUE(AActor); PARAM_NAME(species); @@ -6474,7 +6474,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpecies) // changes the default threshold which the actor resets to once it switches // targets and doesn't have the +QUICKTORETALIATE flag. //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetChaseThreshold) +DEFINE_ACTION_FUNCTION(AActor, A_SetChaseThreshold) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT(threshold); @@ -6501,7 +6501,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetChaseThreshold) // Checks to see if a certain actor class is close to the // actor/pointer within distance, in numbers. //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, CheckProximity) +DEFINE_ACTION_FUNCTION(AActor, CheckProximity) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS(classname, AActor); @@ -6534,7 +6534,7 @@ enum CBF CBF_ABSOLUTEANGLE = 1 << 8, //Absolute angle for offsets. }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, CheckBlock) +DEFINE_ACTION_FUNCTION(AActor, CheckBlock) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT_DEF(flags) @@ -6633,7 +6633,7 @@ enum FMDFlags FMDF_INTERPOLATE = 1 << 1, FMDF_NOANGLE = 1 << 2, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceMovementDirection) +DEFINE_ACTION_FUNCTION(AActor, A_FaceMovementDirection) { PARAM_SELF_PROLOGUE(AActor); PARAM_ANGLE_DEF(offset) @@ -6727,7 +6727,7 @@ enum CPSFFlags CPSF_NOFRAME = 1 << 1, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CopySpriteFrame) +DEFINE_ACTION_FUNCTION(AActor, A_CopySpriteFrame) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT(from); @@ -6762,7 +6762,7 @@ enum VRFFlags VRF_NOPITCHEND = 1 << 3, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetVisibleRotation) +DEFINE_ACTION_FUNCTION(AActor, A_SetVisibleRotation) { PARAM_SELF_PROLOGUE(AActor); PARAM_ANGLE_DEF(anglestart) @@ -6805,7 +6805,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetVisibleRotation) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTranslation) +DEFINE_ACTION_FUNCTION(AActor, A_SetTranslation) { PARAM_SELF_PROLOGUE(AActor); PARAM_STRING(trname); diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index cbddb4840..d36a8de9d 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -1942,7 +1942,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx) +DEFINE_ACTION_FUNCTION(AActor, A_LookEx) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT_DEF (flags) @@ -2159,7 +2159,7 @@ enum ChaseFlags CHF_STOPIFBLOCKED = 256, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Wander) +DEFINE_ACTION_FUNCTION(AActor, A_Wander) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT_DEF(flags); @@ -2801,7 +2801,7 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Chase) +DEFINE_ACTION_FUNCTION(AActor, A_Chase) { PARAM_SELF_PROLOGUE(AActor); PARAM_STATE_DEF (melee) @@ -2840,7 +2840,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_VileChase) return 0; } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ExtChase) +DEFINE_ACTION_FUNCTION(AActor, A_ExtChase) { PARAM_SELF_PROLOGUE(AActor); PARAM_BOOL (domelee); @@ -2980,7 +2980,7 @@ void A_FaceTarget(AActor *self) A_Face(self, self->target); } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Face) +DEFINE_ACTION_FUNCTION(AActor, A_Face) { PARAM_SELF_PROLOGUE(AActor); PARAM_OBJECT(faceto, AActor) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index ce74684cc..408cdbf91 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3098,6 +3098,13 @@ void AActor::RemoveFromHash () tid = 0; } +DEFINE_ACTION_FUNCTION(AActor, RemoveFromHash) +{ + PARAM_SELF_PROLOGUE(AActor); + self->RemoveFromHash(); + return 0; +} + //========================================================================== // // P_IsTIDUsed @@ -6886,6 +6893,42 @@ void AActor::SetTranslation(const char *trname) // silently ignore if the name does not exist, this would create some insane message spam otherwise. } + +class DActorIterator : public DObject, public NActorIterator +{ + DECLARE_CLASS(DActorIterator, DObject) + +public: + DActorIterator(PClassActor *cls= nullptr, int tid = 0) + : NActorIterator(cls, tid) + { + } +}; + +IMPLEMENT_CLASS(DActorIterator, false, false, false, false); +DEFINE_ACTION_FUNCTION(DActorIterator, Create) +{ + PARAM_PROLOGUE; + PARAM_INT_DEF(tid); + PARAM_CLASS_DEF(type, AActor); + ACTION_RETURN_OBJECT(new DActorIterator(type, tid)); +} + +DEFINE_ACTION_FUNCTION(DActorIterator, Next) +{ + PARAM_SELF_PROLOGUE(DActorIterator); + ACTION_RETURN_OBJECT(self->Next()); +} + +DEFINE_ACTION_FUNCTION(DActorIterator, Reinit) +{ + PARAM_SELF_PROLOGUE(DActorIterator); + self->Reinit(); + return 0; +} + + + DEFINE_ACTION_FUNCTION(AActor, deltaangle) // should this be global? { PARAM_PROLOGUE; @@ -6894,6 +6937,14 @@ DEFINE_ACTION_FUNCTION(AActor, deltaangle) // should this be global? ACTION_RETURN_FLOAT(deltaangle(DAngle(a1), DAngle(a2)).Degrees); } +DEFINE_ACTION_FUNCTION(AActor, absangle) // should this be global? +{ + PARAM_PROLOGUE; + PARAM_FLOAT(a1); + PARAM_FLOAT(a2); + ACTION_RETURN_FLOAT(absangle(DAngle(a1), DAngle(a2)).Degrees); +} + DEFINE_ACTION_FUNCTION(AActor, Distance2D) { PARAM_SELF_PROLOGUE(AActor); diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 1bb0db909..5a76f0b55 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -772,7 +772,7 @@ void DoReadyWeapon(AActor *self) DoReadyWeaponToGeneric(self, ~0); } -DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_WeaponReady) +DEFINE_ACTION_FUNCTION(AStateProvider, A_WeaponReady) { PARAM_ACTION_PROLOGUE(AActor); PARAM_INT_DEF(flags); @@ -904,7 +904,7 @@ static void P_CheckWeaponButtons (player_t *player) // //--------------------------------------------------------------------------- -DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_ReFire) +DEFINE_ACTION_FUNCTION(AStateProvider, A_ReFire) { PARAM_ACTION_PROLOGUE(AActor); PARAM_STATE_ACTION_DEF(state); @@ -942,7 +942,7 @@ void A_ReFire(AActor *self, FState *state) } } -DEFINE_ACTION_FUNCTION(AInventory, A_ClearReFire) +DEFINE_ACTION_FUNCTION(AStateProvider, A_ClearReFire) { PARAM_ACTION_PROLOGUE(AActor); player_t *player = self->player; @@ -964,7 +964,7 @@ DEFINE_ACTION_FUNCTION(AInventory, A_ClearReFire) // //--------------------------------------------------------------------------- -DEFINE_ACTION_FUNCTION(AInventory, A_CheckReload) +DEFINE_ACTION_FUNCTION(AStateProvider, A_CheckReload) { PARAM_ACTION_PROLOGUE(AActor); @@ -1152,7 +1152,7 @@ DEFINE_ACTION_FUNCTION(AActor, OverlayID) // //--------------------------------------------------------------------------- -DEFINE_ACTION_FUNCTION(AInventory, A_Lower) +DEFINE_ACTION_FUNCTION(AStateProvider, A_Lower) { PARAM_ACTION_PROLOGUE(AActor); @@ -1200,7 +1200,7 @@ DEFINE_ACTION_FUNCTION(AInventory, A_Lower) // //--------------------------------------------------------------------------- -DEFINE_ACTION_FUNCTION(AInventory, A_Raise) +DEFINE_ACTION_FUNCTION(AActor, A_Raise) { PARAM_ACTION_PROLOGUE(AActor); @@ -1241,7 +1241,7 @@ DEFINE_ACTION_FUNCTION(AInventory, A_Raise) // //--------------------------------------------------------------------------- -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Overlay) +DEFINE_ACTION_FUNCTION(AActor, A_Overlay) { PARAM_ACTION_PROLOGUE(AActor); PARAM_INT (layer); @@ -1261,7 +1261,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Overlay) ACTION_RETURN_BOOL(true); } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ClearOverlays) +DEFINE_ACTION_FUNCTION(AActor, A_ClearOverlays) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT_DEF(start); @@ -1312,7 +1312,7 @@ enum GF_Flags GFF_NOEXTCHANGE = 1, }; -DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_GunFlash) +DEFINE_ACTION_FUNCTION(AStateProvider, A_GunFlash) { PARAM_ACTION_PROLOGUE(AActor); PARAM_STATE_ACTION_DEF(flash); @@ -1415,7 +1415,7 @@ void P_GunShot (AActor *mo, bool accurate, PClassActor *pufftype, DAngle pitch) P_LineAttack (mo, angle, PLAYERMISSILERANGE, pitch, damage, NAME_Hitscan, pufftype); } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Light) +DEFINE_ACTION_FUNCTION(AActor, A_Light) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT(light); diff --git a/src/p_states.cpp b/src/p_states.cpp index f7f237c77..ac7121f49 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -343,7 +343,7 @@ DEFINE_ACTION_FUNCTION(AActor, FindState) } // same as above but context aware. -DEFINE_ACTION_FUNCTION_PARAMS(AActor, ResolveState) +DEFINE_ACTION_FUNCTION(AActor, ResolveState) { PARAM_ACTION_PROLOGUE(AActor); PARAM_STATE_ACTION(newstate); diff --git a/src/p_user.cpp b/src/p_user.cpp index 6b0b2cfe6..8c8858b63 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -1626,7 +1626,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_PlayerScream) // //---------------------------------------------------------------------------- -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SkullPop) +DEFINE_ACTION_FUNCTION(AActor, A_SkullPop) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS_DEF(spawntype, APlayerChunk); diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index b64e0c439..e33986550 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -7962,7 +7962,7 @@ FxExpression *FxReturnStatement::Resolve(FCompileContext &ctx) else { // If we already know the real return type we need at least try to cast the value to its proper type (unless in an anonymous function.) - if (ctx.ReturnProto != nullptr && ctx.Function->SymbolName != NAME_None) + if (ctx.ReturnProto != nullptr && ctx.ReturnProto->ReturnTypes.Size() > 0 && ctx.Function->SymbolName != NAME_None) { Value = new FxTypeCast(Value, ctx.ReturnProto->ReturnTypes[0], false, false); Value = Value->Resolve(ctx); diff --git a/src/scripting/thingdef.h b/src/scripting/thingdef.h index 7218a84e6..5992dba04 100644 --- a/src/scripting/thingdef.h +++ b/src/scripting/thingdef.h @@ -147,7 +147,7 @@ inline void ResetBaggage (Baggage *bag, PClassActor *stateclass) // //========================================================================== -AFuncDesc *FindFunction(const char * string); +AFuncDesc *FindFunction(PClass *cls, const char * string); FxExpression *ParseExpression(FScanner &sc, PClassActor *cls, bool mustresolve = false); diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 4ccc72748..8de1aaff8 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -571,28 +571,33 @@ FPropertyInfo *FindProperty(const char * string) // //========================================================================== -AFuncDesc *FindFunction(const char * string) +AFuncDesc *FindFunction(PClass *cls, const char * string) { - int min = 0, max = AFTable.Size()-1; - - while (min <= max) + for (int i = 0; i < 2; i++) { - int mid = (min + max) / 2; - int lexval = stricmp (string, AFTable[mid].Name); - if (lexval == 0) + if (i == 1 && !cls->IsDescendantOf(RUNTIME_CLASS(AActor))) break; + FStringf fullname("%s_%s", i == 0 ? cls->TypeName.GetChars() : "Actor", string); + int min = 0, max = AFTable.Size() - 1; + + while (min <= max) { - return &AFTable[mid]; - } - else if (lexval > 0) - { - min = mid + 1; - } - else - { - max = mid - 1; + int mid = (min + max) / 2; + int lexval = stricmp(fullname, AFTable[mid].Name + 1); + if (lexval == 0) + { + return &AFTable[mid]; + } + else if (lexval > 0) + { + min = mid + 1; + } + else + { + max = mid - 1; + } } } - return NULL; + return nullptr; } @@ -627,7 +632,7 @@ static int propcmp(const void * a, const void * b) static int funccmp(const void * a, const void * b) { - return stricmp( ((AFuncDesc*)a)->Name, ((AFuncDesc*)b)->Name); + return stricmp(((AFuncDesc*)a)->Name + 1, ((AFuncDesc*)b)->Name + 1); // +1 to get past the prefix letter of the native class name, which gets omitted by the FName for the class. } //========================================================================== diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 2f98c8d81..ae867a975 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -1020,26 +1020,21 @@ struct AFuncDesc // 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) extern VMNativeFunction *name##_VMPtr; +#define DECLARE_ACTION(name) extern VMNativeFunction *AActor_##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) \ - static int AF_##name(VM_ARGS); \ - VMNativeFunction *name##_VMPtr; \ - static const AFuncDesc cls##_##name##_Hook = { #name, AF_##name, &name##_VMPtr }; \ + static int AF_##cls##_##name(VM_ARGS); \ + VMNativeFunction *cls##_##name##_VMPtr; \ + static const AFuncDesc cls##_##name##_Hook = { #cls "_" #name, AF_##cls##_##name, &cls##_##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) 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 + static int AF_##cls##_##name(VM_ARGS) class AActor; void CallAction(VMFrameStack *stack, VMFunction *vmfunc, AActor *self); -#define CALL_ACTION(name, self) CallAction(stack, name##_VMPtr, self); +#define CALL_ACTION(name, self) CallAction(stack, AActor_##name##_VMPtr, self); #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) diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 6cf719d3d..aec8f5853 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2128,7 +2128,7 @@ void ZCCCompiler::InitFunctions() if (f->Flags & ZCC_Native) { varflags |= VARF_Native; - afd = FindFunction(FName(f->Name).GetChars()); + afd = FindFunction(c->Type(), FName(f->Name).GetChars()); if (afd == nullptr) { Error(f, "The function '%s' has not been exported from the executable.", FName(f->Name).GetChars()); diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 8e8b2fdd8..f28045764 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -63,7 +63,9 @@ class Actor : Thinker native native static readonly GetDefaultByType(class cls); native static float deltaangle(float ang1, float ang2); + native static float absangle(float ang1, float ang2); native static float GetDefaultSpeed(class type); + native void RemoveFromHash(); native float GetBobOffset(float frac = 0); native void SetDamage(int dmg); native static bool isDehState(state st); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 33c1c6135..6cf2835e8 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -20,6 +20,13 @@ class ThinkerIterator : Object native native void Reinit(); } +class ActorIterator : Object native +{ + native static ActorIterator Create(int tid, class type = "Actor"); + native Actor Next(); + native void Reinit(); +} + class DropItem : Object native { /* native fields listed for reference only for now diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index 5e47bbc7e..3f7a26461 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -898,3 +898,22 @@ const HR_SHADOW = (0x6800 / 65536.); // Hexen's TINTTAB is the same as Heretic's, just reversed. const HX_SHADOW = (0x9800 / 65536.); const HX_ALTSHADOW = (0x6800 / 65536.); + +enum EMapThingFlags +{ + MTF_AMBUSH = 0x0008, // Thing is deaf + MTF_DORMANT = 0x0010, // Thing is dormant (use Thing_Activate) + + MTF_SINGLE = 0x0100, // Thing appears in single-player games + MTF_COOPERATIVE = 0x0200, // Thing appears in cooperative games + MTF_DEATHMATCH = 0x0400, // Thing appears in deathmatch games + + MTF_SHADOW = 0x0800, + MTF_ALTSHADOW = 0x1000, + MTF_FRIENDLY = 0x2000, + MTF_STANDSTILL = 0x4000, + MTF_STRIFESOMETHING = 0x8000, + + MTF_SECRET = 0x080000, // Secret pickup + MTF_NOINFIGHTING = 0x100000, +}; diff --git a/wadsrc/static/zscript/strife/acolyte.txt b/wadsrc/static/zscript/strife/acolyte.txt index 0c1305b57..9a6b0105a 100644 --- a/wadsrc/static/zscript/strife/acolyte.txt +++ b/wadsrc/static/zscript/strife/acolyte.txt @@ -26,8 +26,6 @@ class Acolyte : StrifeHumanoid Obituary "$OB_ACOLYTE"; } - native void A_BeShadowyFoe (); - native void A_AcolyteBits (); native void A_AcolyteDie (); States @@ -76,6 +74,44 @@ class Acolyte : StrifeHumanoid GIBS L 1400; Stop; } + + //============================================================================ + // + // A_BeShadowyFoe + // + //============================================================================ + + void A_BeShadowyFoe() + { + A_SetRenderStyle(HR_SHADOW, STYLE_Translucent); + bFriendly = false; + } + + //============================================================================ + // + // A_AcolyteBits + // + //============================================================================ + + void A_AcolyteBits() + { + if (SpawnFlags & MTF_SHADOW) + { + A_BeShadowyFoe(); + } + if (SpawnFlags & MTF_ALTSHADOW) + { + if (bShadow) + { + // I dunno. + } + else + { + A_SetRenderStyle(0, STYLE_None); + } + } + } + } From 76a74e0364fe12171ad7ae307f54161f777faa69 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 16 Nov 2016 19:18:21 +0100 Subject: [PATCH 007/185] - scriptified Hexen's Dragon. - fixed several places in the code generator that did not consider locked registers for local variables: array indices, abs and floating point builtin functions. - added some debug aids to the bounds opcode. Just triggering an exception here which loses all relevant info is perfectly useless in a debug situation. --- src/g_hexen/a_dragon.cpp | 311 ----------------------- src/g_hexen/a_hexenmisc.cpp | 1 - src/scripting/codegeneration/codegen.cpp | 78 ++++-- src/scripting/vm/vmexec.h | 2 + wadsrc/static/zscript/hexen/dragon.txt | 282 +++++++++++++++++++- 5 files changed, 327 insertions(+), 347 deletions(-) delete mode 100644 src/g_hexen/a_dragon.cpp diff --git a/src/g_hexen/a_dragon.cpp b/src/g_hexen/a_dragon.cpp deleted file mode 100644 index b79d92b36..000000000 --- a/src/g_hexen/a_dragon.cpp +++ /dev/null @@ -1,311 +0,0 @@ -/* -#include "actor.h" -#include "info.h" -#include "p_enemy.h" -#include "p_local.h" -#include "a_action.h" -#include "m_random.h" -#include "s_sound.h" -#include "vm.h" -*/ - -static FRandom pr_dragonseek ("DragonSeek"); -static FRandom pr_dragonflight ("DragonFlight"); -static FRandom pr_dragonflap ("DragonFlap"); -static FRandom pr_dragonfx2 ("DragonFX2"); - -DECLARE_ACTION(A_DragonFlight) - -//============================================================================ -// -// DragonSeek -// -//============================================================================ - -static void DragonSeek (AActor *actor, DAngle thresh, DAngle turnMax) -{ - int dir; - double dist; - DAngle delta; - AActor *target; - int i; - DAngle bestAngle; - DAngle angleToSpot, angleToTarget; - AActor *mo; - - target = actor->tracer; - if(target == NULL) - { - return; - } - dir = P_FaceMobj (actor, target, &delta); - if (delta > thresh) - { - delta /= 2; - if (delta > turnMax) - { - delta = turnMax; - } - } - if (dir) - { // Turn clockwise - actor->Angles.Yaw += delta; - } - else - { // Turn counter clockwise - actor->Angles.Yaw -= delta; - } - actor->VelFromAngle(); - - dist = actor->DistanceBySpeed(target, actor->Speed); - if (actor->Top() < target->Z() || - target->Top() < actor->Z()) - { - actor->Vel.Z = (target->Z() - actor->Z()) / dist; - } - if (target->flags&MF_SHOOTABLE && pr_dragonseek() < 64) - { // attack the destination mobj if it's attackable - AActor *oldTarget; - - if (absangle(actor->Angles.Yaw, actor->AngleTo(target)) < 22.5) - { - oldTarget = actor->target; - actor->target = target; - if (actor->CheckMeleeRange ()) - { - int damage = pr_dragonseek.HitDice (10); - int newdam = P_DamageMobj (actor->target, actor, actor, damage, NAME_Melee); - P_TraceBleed (newdam > 0 ? newdam : damage, actor->target, actor); - S_Sound (actor, CHAN_WEAPON, actor->AttackSound, 1, ATTN_NORM); - } - else if (pr_dragonseek() < 128 && P_CheckMissileRange(actor)) - { - P_SpawnMissile(actor, target, PClass::FindActor("DragonFireball")); - S_Sound (actor, CHAN_WEAPON, actor->AttackSound, 1, ATTN_NORM); - } - actor->target = oldTarget; - } - } - if (dist < 4) - { // Hit the target thing - if (actor->target && pr_dragonseek() < 200) - { - AActor *bestActor = NULL; - bestAngle = 360.; - angleToTarget = actor->AngleTo(actor->target); - for (i = 0; i < 5; i++) - { - if (!target->args[i]) - { - continue; - } - FActorIterator iterator (target->args[i]); - mo = iterator.Next (); - if (mo == NULL) - { - continue; - } - angleToSpot = actor->AngleTo(mo); - DAngle diff = absangle(angleToSpot, angleToTarget); - if (diff < bestAngle) - { - bestAngle = diff; - bestActor = mo; - } - } - if (bestActor != NULL) - { - actor->tracer = bestActor; - } - } - else - { - // [RH] Don't lock up if the dragon doesn't have any - // targets defined - for (i = 0; i < 5; ++i) - { - if (target->args[i] != 0) - { - break; - } - } - if (i < 5) - { - do - { - i = (pr_dragonseek()>>2)%5; - } while(!target->args[i]); - FActorIterator iterator (target->args[i]); - actor->tracer = iterator.Next (); - } - } - } -} - -//============================================================================ -// -// A_DragonInitFlight -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_DragonInitFlight) -{ - PARAM_SELF_PROLOGUE(AActor); - - FActorIterator iterator (self->tid); - - do - { // find the first tid identical to the dragon's tid - self->tracer = iterator.Next (); - if (self->tracer == NULL) - { - self->SetState (self->SpawnState); - return 0; - } - } while (self->tracer == self); - self->RemoveFromHash (); - return 0; -} - -//============================================================================ -// -// A_DragonFlight -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_DragonFlight) -{ - PARAM_SELF_PROLOGUE(AActor); - - DAngle angle; - - DragonSeek (self, 4., 8.); - if (self->target) - { - if(!(self->target->flags&MF_SHOOTABLE)) - { // target died - self->target = NULL; - return 0; - } - angle = absangle(self->Angles.Yaw, self->AngleTo(self->target)); - if (angle <22.5 && self->CheckMeleeRange()) - { - int damage = pr_dragonflight.HitDice (8); - int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); - S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM); - } - else if (angle <= 20) - { - self->SetState (self->MissileState); - S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM); - } - } - else - { - P_LookForPlayers (self, true, NULL); - } - return 0; -} - -//============================================================================ -// -// A_DragonFlap -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_DragonFlap) -{ - PARAM_SELF_PROLOGUE(AActor); - - CALL_ACTION(A_DragonFlight, self); - if (pr_dragonflap() < 240) - { - S_Sound (self, CHAN_BODY, "DragonWingflap", 1, ATTN_NORM); - } - else - { - self->PlayActiveSound (); - } - return 0; -} - -//============================================================================ -// -// A_DragonAttack -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_DragonAttack) -{ - PARAM_SELF_PROLOGUE(AActor); - - P_SpawnMissile (self, self->target, PClass::FindActor("DragonFireball")); - return 0; -} - -//============================================================================ -// -// A_DragonFX2 -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_DragonFX2) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo; - int i; - int delay; - - delay = 16+(pr_dragonfx2()>>3); - for (i = 1+(pr_dragonfx2()&3); i; i--) - { - double xo = (pr_dragonfx2() - 128) / 4.; - double yo = (pr_dragonfx2() - 128) / 4.; - double zo = (pr_dragonfx2() - 128) / 16.; - - mo = Spawn ("DragonExplosion", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE); - if (mo) - { - mo->tics = delay+(pr_dragonfx2()&3)*i*2; - mo->target = self->target; - } - } - return 0; -} - -//============================================================================ -// -// A_DragonPain -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_DragonPain) -{ - PARAM_SELF_PROLOGUE(AActor); - - CALL_ACTION(A_Pain, self); - if (!self->tracer) - { // no destination spot yet - self->SetState (self->SeeState); - } - return 0; -} - -//============================================================================ -// -// A_DragonCheckCrash -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_DragonCheckCrash) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (self->Z() <= self->floorz) - { - self->SetState (self->FindState ("Crash")); - } - return 0; -} diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp index 1a635ff71..f1f4a86fe 100644 --- a/src/g_hexen/a_hexenmisc.cpp +++ b/src/g_hexen/a_hexenmisc.cpp @@ -33,7 +33,6 @@ #include "a_clericholy.cpp" #include "a_clericmace.cpp" #include "a_clericstaff.cpp" -#include "a_dragon.cpp" #include "a_fighteraxe.cpp" #include "a_fighterhammer.cpp" #include "a_fighterplayer.cpp" diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index e33986550..44d7cda88 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -1670,19 +1670,23 @@ ExpEmit FxMinusSign::Emit(VMFunctionBuilder *build) { assert(ValueType == Operand->ValueType); ExpEmit from = Operand->Emit(build); + ExpEmit to; assert(from.Konst == 0); assert(ValueType->GetRegCount() == from.RegCount); // Do it in-place, unless a local variable if (from.Fixed) { - ExpEmit to = ExpEmit(build, from.RegType, from.RegCount); - build->Emit(Operand->ValueType->GetMoveOp(), to.RegNum, from.RegNum); - from = to; + to = ExpEmit(build, from.RegType, from.RegCount); + from.Free(build); + } + else + { + to = from; } if (ValueType->GetRegType() == REGT_INT) { - build->Emit(OP_NEG, from.RegNum, from.RegNum, 0); + build->Emit(OP_NEG, to.RegNum, from.RegNum, 0); } else { @@ -1690,20 +1694,20 @@ ExpEmit FxMinusSign::Emit(VMFunctionBuilder *build) switch (from.RegCount) { case 1: - build->Emit(OP_FLOP, from.RegNum, from.RegNum, FLOP_NEG); + build->Emit(OP_FLOP, to.RegNum, from.RegNum, FLOP_NEG); break; case 2: - build->Emit(OP_NEGV2, from.RegNum, from.RegNum); + build->Emit(OP_NEGV2, to.RegNum, from.RegNum); break; case 3: - build->Emit(OP_NEGV3, from.RegNum, from.RegNum); + build->Emit(OP_NEGV3, to.RegNum, from.RegNum); break; } } - return from; + return to; } //========================================================================== @@ -4255,19 +4259,31 @@ FxExpression *FxAbs::Resolve(FCompileContext &ctx) ExpEmit FxAbs::Emit(VMFunctionBuilder *build) { - ExpEmit absofsteal = val->Emit(build); - assert(!absofsteal.Konst); - ExpEmit out(build, absofsteal.RegType); - if (absofsteal.RegType == REGT_INT) + assert(ValueType == val->ValueType); + ExpEmit from = val->Emit(build); + ExpEmit to; + assert(from.Konst == 0); + assert(ValueType->GetRegCount() == 1); + // Do it in-place, unless a local variable + if (from.Fixed) { - build->Emit(OP_ABS, out.RegNum, absofsteal.RegNum, 0); + to = ExpEmit(build, from.RegType); + from.Free(build); } else { - assert(absofsteal.RegType == REGT_FLOAT); - build->Emit(OP_FLOP, out.RegNum, absofsteal.RegNum, FLOP_ABS); + to = from; } - return out; + + if (ValueType->GetRegType() == REGT_INT) + { + build->Emit(OP_ABS, to.RegNum, from.RegNum, 0); + } + else + { + build->Emit(OP_FLOP, to.RegNum, from.RegNum, FLOP_ABS); + } + return to; } //========================================================================== @@ -5898,6 +5914,7 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) else { ExpEmit indexv(index->Emit(build)); + ExpEmit indexwork = indexv.Fixed ? ExpEmit(build, indexv.RegType) : indexv; int shiftbits = 0; while (1u << shiftbits < arraytype->ElementSize) { @@ -5907,19 +5924,19 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) build->Emit(OP_BOUND, indexv.RegNum, arraytype->ElementCount); if (shiftbits > 0) { - build->Emit(OP_SLL_RI, indexv.RegNum, indexv.RegNum, shiftbits); + build->Emit(OP_SLL_RI, indexwork.RegNum, indexv.RegNum, shiftbits); } if (AddressRequested) { - build->Emit(OP_ADDA_RR, start.RegNum, start.RegNum, indexv.RegNum); + build->Emit(OP_ADDA_RR, start.RegNum, start.RegNum, indexwork.RegNum); } else { build->Emit(arraytype->ElementType->GetLoadOp() + 1, // added 1 to use the *_R version that - dest.RegNum, start.RegNum, indexv.RegNum); // takes the offset from a register + dest.RegNum, start.RegNum, indexwork.RegNum); // takes the offset from a register } - indexv.Free(build); + indexwork.Free(build); } if (AddressRequested) { @@ -6955,13 +6972,26 @@ FxExpression *FxFlopFunctionCall::Resolve(FCompileContext& ctx) ExpEmit FxFlopFunctionCall::Emit(VMFunctionBuilder *build) { - ExpEmit v = ArgList[0]->Emit(build); - assert(!v.Konst && v.RegType == REGT_FLOAT); + assert(ValueType == ArgList[0]->ValueType); + ExpEmit from = ArgList[0]->Emit(build); + ExpEmit to; + assert(from.Konst == 0); + assert(ValueType->GetRegCount() == 1); + // Do it in-place, unless a local variable + if (from.Fixed) + { + to = ExpEmit(build, from.RegType); + from.Free(build); + } + else + { + to = from; + } - build->Emit(OP_FLOP, v.RegNum, v.RegNum, FxFlops[Index].Flop); + build->Emit(OP_FLOP, to.RegNum, from.RegNum, FxFlops[Index].Flop); ArgList.Clear(); ArgList.ShrinkToFit(); - return v; + return to; } diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 02e0db3de..fcdb2eb8b 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -696,6 +696,8 @@ begin: OP(BOUND): if (reg.d[a] >= BC) { + assert(false); + Printf("Array access out of bounds: Max. index = %u, current index = %u\n", BC, reg.d[a]); THROW(X_ARRAY_OUT_OF_BOUNDS); } NEXTOP; diff --git a/wadsrc/static/zscript/hexen/dragon.txt b/wadsrc/static/zscript/hexen/dragon.txt index 6df3da943..ed6e86d4a 100644 --- a/wadsrc/static/zscript/hexen/dragon.txt +++ b/wadsrc/static/zscript/hexen/dragon.txt @@ -1,6 +1,4 @@ - // Dragon ------------------------------------------------------------------- - class Dragon : Actor { Default @@ -23,13 +21,6 @@ class Dragon : Actor Obituary "$OB_DRAGON"; } - native void A_DragonInitFlight(); - native void A_DragonFlap(); - native void A_DragonFlight(); - native void A_DragonPain(); - native void A_DragonAttack(); - native void A_DragonCheckCrash(); - States { Spawn: @@ -58,6 +49,253 @@ class Dragon : Actor DRAG M -1; Stop; } + + //============================================================================ + // + // DragonSeek + // + //============================================================================ + + private void DragonSeek (double thresh, double turnMax) + { + double dist; + double delta; + Actor targ; + int i; + double bestAngle; + double angleToSpot, angleToTarget; + Actor mo; + + targ = tracer; + if(targ == null) + { + return; + } + + double diff = deltaangle(angle, AngleTo(targ)); + delta = abs(diff); + + if (delta > thresh) + { + delta /= 2; + if (delta > turnMax) + { + delta = turnMax; + } + } + if (diff > 0) + { // Turn clockwise + angle = angle + delta; + } + else + { // Turn counter clockwise + angle = angle - delta; + } + VelFromAngle(); + + dist = DistanceBySpeed(targ, Speed); + if (pos.z + height < targ.pos.z || targ.pos.z + targ.height < pos.z) + { + Vel.Z = (targ.pos.z - pos.z) / dist; + } + if (targ.bShootable && random[DragonSeek]() < 64) + { // attack the destination mobj if it's attackable + Actor oldTarget; + + if (absangle(angle, AngleTo(targ)) < 22.5) + { + oldTarget = target; + target = targ; + if (CheckMeleeRange ()) + { + int damage = random[DragonSeek](1, 8) * 10; + int newdam = target.DamageMobj (self, self, damage, 'Melee'); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + A_PlaySound (AttackSound, CHAN_WEAPON); + } + else if (random[DragonSeek]() < 128 && CheckMissileRange()) + { + SpawnMissile(targ, "DragonFireball"); + A_PlaySound (AttackSound, CHAN_WEAPON); + } + target = oldTarget; + } + } + if (dist < 4) + { // Hit the target thing + if (target && random[DragonSeek]() < 200) + { + Actor bestActor = null; + bestAngle = 360.; + angleToTarget = AngleTo(target); + for (i = 0; i < 5; i++) + { + if (!targ.args[i]) + { + continue; + } + ActorIterator iter = ActorIterator.Create(targ.args[i]); + mo = iter.Next (); + if (mo == null) + { + continue; + } + angleToSpot = AngleTo(mo); + double diff = absangle(angleToSpot, angleToTarget); + if (diff < bestAngle) + { + bestAngle = diff; + bestActor = mo; + } + } + if (bestActor != null) + { + tracer = bestActor; + } + } + else + { + // [RH] Don't lock up if the dragon doesn't have any + // targs defined + for (i = 0; i < 5; ++i) + { + if (targ.args[i] != 0) + { + break; + } + } + if (i < 5) + { + do + { + i = (random[DragonSeek]() >> 2) % 5; + } while(!targ.args[i]); + ActorIterator iter = ActorIterator.Create(targ.args[i]); + tracer = iter.Next (); + } + } + } + } + + //============================================================================ + // + // A_DragonInitFlight + // + //============================================================================ + + void A_DragonInitFlight() + { + ActorIterator iter = ActorIterator.Create(tid); + + do + { // find the first tid identical to the dragon's tid + tracer = iter.Next (); + if (tracer == null) + { + SetState (SpawnState); + return; + } + } while (tracer == self); + RemoveFromHash (); + } + + //============================================================================ + // + // A_DragonFlight + // + //============================================================================ + + void A_DragonFlight() + { + double ang; + + DragonSeek (4., 8.); + if (target) + { + if(!target.bShootable) + { // target died + target = null; + return; + } + ang = absangle(angle, AngleTo(target)); + if (ang <22.5 && CheckMeleeRange()) + { + int damage = random[DragonFlight](1, 8) * 8; + int newdam = target.DamageMobj (self, self, damage, 'Melee'); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + A_PlaySound (AttackSound, CHAN_WEAPON); + } + else if (ang <= 20) + { + SetState (MissileState); + A_PlaySound (AttackSound, CHAN_WEAPON); + } + } + else + { + LookForPlayers (true); + } + } + + //============================================================================ + // + // A_DragonFlap + // + //============================================================================ + + void A_DragonFlap() + { + A_DragonFlight(); + if (random[DragonFlight]() < 240) + { + A_PlaySound ("DragonWingflap", CHAN_BODY); + } + else + { + PlayActiveSound (); + } + } + + //============================================================================ + // + // A_DragonAttack + // + //============================================================================ + + void A_DragonAttack() + { + SpawnMissile (target, "DragonFireball"); + } + + + //============================================================================ + // + // A_DragonPain + // + //============================================================================ + + void A_DragonPain() + { + A_Pain(); + if (!tracer) + { // no destination spot yet + SetState (SeeState); + } + } + + //============================================================================ + // + // A_DragonCheckCrash + // + //============================================================================ + + void A_DragonCheckCrash() + { + if (pos.z < floorz) + { + SetStateLabel ("Crash"); + } + } } // Dragon Fireball ---------------------------------------------------------- @@ -77,8 +315,6 @@ class DragonFireball : Actor DeathSound "DragonFireballExplode"; } - native void A_DragonFX2(); - States { Spawn: @@ -90,6 +326,30 @@ class DragonFireball : Actor DRFX KL 3 Bright; Stop; } + + //============================================================================ + // + // A_DragonFX2 + // + //============================================================================ + + void A_DragonFX2() + { + int delay = 16+(random[DragonFX2]()>>3); + for (int i = random[DragonFX2](1, 4); i; i--) + { + double xo = (random[DragonFX2]() - 128) / 4.; + double yo = (random[DragonFX2]() - 128) / 4.; + double zo = (random[DragonFX2]() - 128) / 16.; + + Actor mo = Spawn ("DragonExplosion", Vec3Offset(xo, yo, zo), ALLOW_REPLACE); + if (mo) + { + mo.tics = delay + (random[DragonFX2](0, 3)) * i*2; + mo.target = target; + } + } + } } // Dragon Fireball Secondary Explosion -------------------------------------- From 60d93008ba53edb1e26562893f31bff5869935ae Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Wed, 16 Nov 2016 11:47:45 -0600 Subject: [PATCH 008/185] Exported TryMove. --- src/p_map.cpp | 8 ++++++++ wadsrc/static/zscript/actor.txt | 1 + 2 files changed, 9 insertions(+) diff --git a/src/p_map.cpp b/src/p_map.cpp index d7bffa589..b904dc1d4 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -2498,6 +2498,14 @@ bool P_TryMove(AActor *thing, const DVector2 &pos, return P_TryMove(thing, pos, dropoff, onfloor, tm); } +DEFINE_ACTION_FUNCTION(AActor, TryMove) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT_DEF(x); + PARAM_FLOAT_DEF(y); + PARAM_INT(dropoff); + ACTION_RETURN_BOOL(P_TryMove(self, DVector2(x, y), dropoff)); +} //========================================================================== diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index f28045764..9980d28f5 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -97,6 +97,7 @@ class Actor : Thinker native native bool CheckSight(Actor target, int flags = 0); native bool HitFriend(); native bool MonsterMove(); + native bool TryMove(vector2 newpos, int dropoff); native void NewChaseDir(); native bool CheckMissileRange(); native bool SetState(state st, bool nofunction = false); From af3bda3f2a1dbfc7bdb7ea30ce66f76a12a9f401 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Wed, 16 Nov 2016 12:29:06 -0600 Subject: [PATCH 009/185] Removed _DEF. --- src/p_map.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index b904dc1d4..3f0edc8d7 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -2501,8 +2501,8 @@ bool P_TryMove(AActor *thing, const DVector2 &pos, DEFINE_ACTION_FUNCTION(AActor, TryMove) { PARAM_SELF_PROLOGUE(AActor); - PARAM_FLOAT_DEF(x); - PARAM_FLOAT_DEF(y); + PARAM_FLOAT(x); + PARAM_FLOAT(y); PARAM_INT(dropoff); ACTION_RETURN_BOOL(P_TryMove(self, DVector2(x, y), dropoff)); } From 063e94971dba8093855d41422d1e866bc0ad2a28 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 16 Nov 2016 19:46:36 +0100 Subject: [PATCH 010/185] - removed incorrect _DEF. --- src/p_mobj.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 408cdbf91..52541a669 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -6909,7 +6909,7 @@ IMPLEMENT_CLASS(DActorIterator, false, false, false, false); DEFINE_ACTION_FUNCTION(DActorIterator, Create) { PARAM_PROLOGUE; - PARAM_INT_DEF(tid); + PARAM_INT(tid); PARAM_CLASS_DEF(type, AActor); ACTION_RETURN_OBJECT(new DActorIterator(type, tid)); } From 7a29e6cfdcf70bd36916de8d5a766910c49d4792 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 16 Nov 2016 20:00:25 +0100 Subject: [PATCH 011/185] - scriptified Hexen's fog. --- src/CMakeLists.txt | 1 - src/g_hexen/a_fog.cpp | 99 ----------------------------- src/g_hexen/a_hexenmisc.cpp | 1 - wadsrc/static/zscript/hexen/fog.txt | 85 ++++++++++++++++++++++++- 4 files changed, 83 insertions(+), 103 deletions(-) delete mode 100644 src/g_hexen/a_fog.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8e5c022cb..f1fc1bab5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -887,7 +887,6 @@ set( NOT_COMPILED_SOURCE_FILES g_hexen/a_fighterquietus.cpp g_hexen/a_flechette.cpp g_hexen/a_flies.cpp - g_hexen/a_fog.cpp g_hexen/a_healingradius.cpp g_hexen/a_heresiarch.cpp g_hexen/a_hexenspecialdecs.cpp diff --git a/src/g_hexen/a_fog.cpp b/src/g_hexen/a_fog.cpp deleted file mode 100644 index 6b2bc9706..000000000 --- a/src/g_hexen/a_fog.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* -#include "m_random.h" -#include "p_local.h" -#include "vm.h" -*/ - -static FRandom pr_fogspawn ("FogSpawn"); - -//========================================================================== -// Fog Variables: -// -// args[0] Speed (0..10) of fog -// args[1] Angle of spread (0..128) -// args[2] Frequency of spawn (1..10) -// args[3] Lifetime countdown -// args[4] Boolean: fog moving? -// special1 Internal: Counter for spawn frequency -// WeaveIndexZ Internal: Index into floatbob table -// -//========================================================================== - -//========================================================================== -// -// A_FogSpawn -// -//========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_FogSpawn) -{ - PARAM_SELF_PROLOGUE(AActor); - - static const char *fogs[3] = - { - "FogPatchSmall", - "FogPatchMedium", - "FogPatchLarge" - }; - - AActor *mo = NULL; - int delta; - - if (self->special1-- > 0) - { - return 0; - } - self->special1 = self->args[2]; // Reset frequency count - - mo = Spawn (fogs[pr_fogspawn()%3], self->Pos(), ALLOW_REPLACE); - - if (mo) - { - delta = self->args[1]; - if (delta==0) delta=1; - mo->Angles.Yaw = self->Angles.Yaw + (((pr_fogspawn() % delta) - (delta >> 1)) * (360 / 256.)); - mo->target = self; - if (self->args[0] < 1) self->args[0] = 1; - mo->args[0] = (pr_fogspawn() % (self->args[0]))+1; // Random speed - mo->args[3] = self->args[3]; // Set lifetime - mo->args[4] = 1; // Set to moving - mo->WeaveIndexZ = pr_fogspawn()&63; - } - return 0; -} - -//========================================================================== -// -// A_FogMove -// -//========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_FogMove) -{ - PARAM_SELF_PROLOGUE(AActor); - - double speed = self->args[0]; - int weaveindex; - - if (!self->args[4]) - { - return 0; - } - - if (self->args[3]-- <= 0) - { - self->SetState (self->FindState(NAME_Death), true); - return 0; - } - - if ((self->args[3] % 4) == 0) - { - weaveindex = self->WeaveIndexZ; - self->AddZ(BobSin(weaveindex) / 2); - self->WeaveIndexZ = (weaveindex + 1) & 63; - } - - self->VelFromAngle(speed); - return 0; -} - diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp index f1f4a86fe..9003405e4 100644 --- a/src/g_hexen/a_hexenmisc.cpp +++ b/src/g_hexen/a_hexenmisc.cpp @@ -39,7 +39,6 @@ #include "a_fighterquietus.cpp" #include "a_flechette.cpp" #include "a_flies.cpp" -#include "a_fog.cpp" #include "a_healingradius.cpp" #include "a_heresiarch.cpp" #include "a_hexenspecialdecs.cpp" diff --git a/wadsrc/static/zscript/hexen/fog.txt b/wadsrc/static/zscript/hexen/fog.txt index 93b5e9593..276cf2d73 100644 --- a/wadsrc/static/zscript/hexen/fog.txt +++ b/wadsrc/static/zscript/hexen/fog.txt @@ -1,3 +1,15 @@ +//========================================================================== +// Fog Variables: +// +// args[0] Speed (0..10) of fog +// args[1] Angle of spread (0..128) +// args[2] Frequency of spawn (1..10) +// args[3] Lifetime countdown +// args[4] Boolean: fog moving? +// special1 Internal: Counter for spawn frequency +// WeaveIndexZ Internal: Index into floatbob table +// +//========================================================================== // Fog Spawner -------------------------------------------------------------- @@ -11,7 +23,6 @@ class FogSpawner : Actor +INVISIBLE } - native void A_FogSpawn(); States { @@ -19,6 +30,45 @@ class FogSpawner : Actor TNT1 A 20 A_FogSpawn; Loop; } + + //========================================================================== + // + // A_FogSpawn + // + //========================================================================== + + void A_FogSpawn() + { + if (special1-- > 0) + { + return; + } + special1 = args[2]; // Reset frequency count + + class fog; + switch (random[FogSpawn](0,2)) + { + default: + case 0: fog = "FogPatchSmall"; break; + case 1: fog = "FogPatchMedium"; break; + case 2: fog = "FogPatchLarge"; break; + } + Actor mo = Spawn (fog, Pos, ALLOW_REPLACE); + + if (mo) + { + int delta = args[1]; + if (delta == 0) delta = 1; + mo.angle = angle + (((random[FogSpawn]() % delta) - (delta >> 1)) * (360 / 256.)); + mo.target = self; + if (args[0] < 1) args[0] = 1; + mo.args[0] = (random[FogSpawn]() % (args[0]))+1; // Random speed + mo.args[3] = args[3]; // Set lifetime + mo.args[4] = 1; // Set to moving + mo.WeaveIndexZ = random[FogSpawn](0, 63); + } + } + } // Small Fog Patch ---------------------------------------------------------- @@ -34,7 +84,6 @@ class FogPatchSmall : Actor Alpha 0.6; } - native void A_FogMove(); States { @@ -45,6 +94,37 @@ class FogPatchSmall : Actor FOGS E 5; Stop; } + + //========================================================================== + // + // A_FogMove + // + //========================================================================== + + void A_FogMove() + { + double speed = args[0]; + int weaveindex; + + if (!args[4]) + { + return; + } + + if (args[3]-- <= 0) + { + SetStateLabel ('Death', true); + return; + } + + if ((args[3] % 4) == 0) + { + weaveindex = WeaveIndexZ; + AddZ(BobSin(weaveindex) / 2); + WeaveIndexZ = (weaveindex + 1) & 63; + } + VelFromAngle(speed); + } } // Medium Fog Patch --------------------------------------------------------- @@ -76,3 +156,4 @@ class FogPatchLarge : FogPatchMedium Goto Super::Death; } } + From df43ee96cea8085fa1d8da0be05f39095b58bda7 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 16 Nov 2016 21:12:16 +0100 Subject: [PATCH 012/185] - fixed a lost '='. - scriptified A_TimeBomb. --- src/g_heretic/a_hereticartifacts.cpp | 12 ------------ src/p_mobj.cpp | 3 ++- wadsrc/static/zscript/actor.txt | 2 +- wadsrc/static/zscript/heretic/hereticartifacts.txt | 9 +++++++-- wadsrc/static/zscript/hexen/dragon.txt | 2 +- wadsrc/static/zscript/hexen/flechette.txt | 9 +++++++-- 6 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/g_heretic/a_hereticartifacts.cpp b/src/g_heretic/a_hereticartifacts.cpp index 169d0e771..f2ad18b2f 100644 --- a/src/g_heretic/a_hereticartifacts.cpp +++ b/src/g_heretic/a_hereticartifacts.cpp @@ -44,18 +44,6 @@ bool AArtiTomeOfPower::Use (bool pickup) // Time bomb ---------------------------------------------------------------- -DEFINE_ACTION_FUNCTION(AActor, A_TimeBomb) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->AddZ(32, false); - self->RenderStyle = STYLE_Add; - self->Alpha = 1.; - P_RadiusAttack (self, self->target, 128, 128, self->DamageType, RADF_HURTSOURCE); - P_CheckSplash(self, 128); - return 0; -} - class AArtiTimeBomb : public AInventory { DECLARE_CLASS (AArtiTimeBomb, AInventory) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 52541a669..abbd057d7 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -6956,7 +6956,8 @@ DEFINE_ACTION_FUNCTION(AActor, AddZ) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT(addz); - self->AddZ(addz); + PARAM_BOOL_DEF(moving); + self->AddZ(addz, moving); return 0; } diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 9980d28f5..7b6b63672 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -108,7 +108,7 @@ class Actor : Thinker native native void UnlinkFromWorld(); native bool CanSeek(Actor target); native double AngleTo(Actor target, bool absolute = false); - native void AddZ(float zadd); + native void AddZ(float zadd, bool moving = true); native void SetZ(float z); native vector3 Vec3Offset(float x, float y, float z, bool absolute = false); native vector3 Vec3Angle(float length, float angle, float z = 0, bool absolute = false); diff --git a/wadsrc/static/zscript/heretic/hereticartifacts.txt b/wadsrc/static/zscript/heretic/hereticartifacts.txt index e239748ff..50a25008a 100644 --- a/wadsrc/static/zscript/heretic/hereticartifacts.txt +++ b/wadsrc/static/zscript/heretic/hereticartifacts.txt @@ -80,8 +80,6 @@ Class ActivatedTimeBomb : Actor DeathSound "misc/timebomb"; } - native void A_Timebomb(); - States { Spawn: @@ -91,6 +89,13 @@ Class ActivatedTimeBomb : Actor XPL1 BCDEF 4 BRIGHT; Stop; } + + void A_TimeBomb() + { + AddZ(32, false); + A_SetRenderStyle(1., STYLE_Add); + A_Explode(); + } } diff --git a/wadsrc/static/zscript/hexen/dragon.txt b/wadsrc/static/zscript/hexen/dragon.txt index ed6e86d4a..6082d1c61 100644 --- a/wadsrc/static/zscript/hexen/dragon.txt +++ b/wadsrc/static/zscript/hexen/dragon.txt @@ -291,7 +291,7 @@ class Dragon : Actor void A_DragonCheckCrash() { - if (pos.z < floorz) + if (pos.z <= floorz) { SetStateLabel ("Crash"); } diff --git a/wadsrc/static/zscript/hexen/flechette.txt b/wadsrc/static/zscript/hexen/flechette.txt index 6f7b3a818..c02477064 100644 --- a/wadsrc/static/zscript/hexen/flechette.txt +++ b/wadsrc/static/zscript/hexen/flechette.txt @@ -37,8 +37,6 @@ class FireBomb : Actor DeathSound "FlechetteExplode"; } - native void A_TimeBomb(); - States { Spawn: @@ -50,6 +48,13 @@ class FireBomb : Actor XPL1 BCDEF 4 Bright; Stop; } + + void A_TimeBomb() + { + AddZ(32, false); + A_SetRenderStyle(1., STYLE_Add); + A_Explode(); + } } // Throwing Bomb (Flechette used by Fighter) -------------------------------- From 21a1d5ffc80517c45e3f76dc541b8bb98bde402e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 17 Nov 2016 00:44:43 +0100 Subject: [PATCH 013/185] - scriptified Hexen's Wraith and parts of the Spike. --- src/CMakeLists.txt | 1 - src/g_hexen/a_hexenmisc.cpp | 1 - src/g_hexen/a_spike.cpp | 101 +--------- src/g_hexen/a_wraith.cpp | 258 ------------------------- src/g_shared/a_debris.cpp | 24 --- src/g_shared/a_sharedglobal.h | 1 - src/p_enemy.cpp | 41 ---- src/p_enemy.h | 3 - src/p_mobj.cpp | 6 +- wadsrc/static/zscript/actor.txt | 62 ++++++ wadsrc/static/zscript/hexen/spike.txt | 77 +++++++- wadsrc/static/zscript/hexen/wraith.txt | 223 ++++++++++++++++++++- 12 files changed, 354 insertions(+), 444 deletions(-) delete mode 100644 src/g_hexen/a_wraith.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f1fc1bab5..c5f307d56 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -900,7 +900,6 @@ set( NOT_COMPILED_SOURCE_FILES g_hexen/a_spike.cpp g_hexen/a_summon.cpp g_hexen/a_teleportother.cpp - g_hexen/a_wraith.cpp g_strife/a_acolyte.cpp g_strife/a_alienspectres.cpp g_strife/a_coin.cpp diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp index 9003405e4..21227e848 100644 --- a/src/g_hexen/a_hexenmisc.cpp +++ b/src/g_hexen/a_hexenmisc.cpp @@ -52,4 +52,3 @@ #include "a_spike.cpp" #include "a_summon.cpp" #include "a_teleportother.cpp" -#include "a_wraith.cpp" diff --git a/src/g_hexen/a_spike.cpp b/src/g_hexen/a_spike.cpp index 9b2cb5d6e..be28e38df 100644 --- a/src/g_hexen/a_spike.cpp +++ b/src/g_hexen/a_spike.cpp @@ -20,28 +20,13 @@ static FRandom pr_thrustraise ("ThrustRaise"); class AThrustFloor : public AActor { DECLARE_CLASS (AThrustFloor, AActor) - HAS_OBJECT_POINTERS public: - void Serialize(FSerializer &arc); - void Activate (AActor *activator); void Deactivate (AActor *activator); - - TObjPtr DirtClump; }; -IMPLEMENT_CLASS(AThrustFloor, false, true, false, false) - -IMPLEMENT_POINTERS_START(AThrustFloor) - IMPLEMENT_POINTER(DirtClump) -IMPLEMENT_POINTERS_END - -void AThrustFloor::Serialize(FSerializer &arc) -{ - Super::Serialize (arc); - arc("dirtclump", DirtClump); -} +IMPLEMENT_CLASS(AThrustFloor, false, false, false, false) void AThrustFloor::Activate (AActor *activator) { @@ -68,90 +53,6 @@ void AThrustFloor::Deactivate (AActor *activator) } } -//=========================================================================== -// -// Thrust floor stuff -// -// Thrust Spike Variables -// DirtClump pointer to dirt clump actor -// special2 speed of raise -// args[0] 0 = lowered, 1 = raised -// args[1] 0 = normal, 1 = bloody -//=========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_ThrustInitUp) -{ - PARAM_SELF_PROLOGUE(AActor); - - 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_SELF_PROLOGUE(AActor); - - self->special2 = 5; // Raise speed - self->args[0] = 0; // Mark as down - self->Floorclip = self->GetDefault()->Height; - self->flags = 0; - self->flags2 = MF2_NOTELEPORT|MF2_FLOORCLIP; - self->renderflags = RF_INVISIBLE; - static_cast(self)->DirtClump = - Spawn("DirtClump", self->Pos(), ALLOW_REPLACE); - return 0; -} - - -DEFINE_ACTION_FUNCTION(AActor, A_ThrustRaise) -{ - PARAM_SELF_PROLOGUE(AActor); - - AThrustFloor *actor = static_cast(self); - - if (A_RaiseMobj (actor, self->special2)) - { // Reached it's target height - actor->args[0] = 1; - if (actor->args[1]) - actor->SetState (actor->FindState ("BloodThrustInit2"), true); - else - actor->SetState (actor->FindState ("ThrustInit2"), true); - } - - // Lose the dirt clump - if ((actor->Floorclip < actor->Height) && actor->DirtClump) - { - actor->DirtClump->Destroy (); - actor->DirtClump = NULL; - } - - // Spawn some dirt - if (pr_thrustraise()<40) - P_SpawnDirt (actor, actor->radius); - actor->special2++; // Increase raise speed - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_ThrustLower) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (A_SinkMobj (self, 6)) - { - self->args[0] = 0; - if (self->args[1]) - self->SetState (self->FindState ("BloodThrustInit1"), true); - else - self->SetState (self->FindState ("ThrustInit1"), true); - } - return 0; -} - DEFINE_ACTION_FUNCTION(AActor, A_ThrustImpale) { PARAM_SELF_PROLOGUE(AActor); diff --git a/src/g_hexen/a_wraith.cpp b/src/g_hexen/a_wraith.cpp deleted file mode 100644 index fcd0d75f3..000000000 --- a/src/g_hexen/a_wraith.cpp +++ /dev/null @@ -1,258 +0,0 @@ -/* -#include "actor.h" -#include "info.h" -#include "p_local.h" -#include "s_sound.h" -#include "p_enemy.h" -#include "a_action.h" -#include "m_random.h" -#include "a_sharedglobal.h" -#include "vm.h" -*/ - -static FRandom pr_stealhealth ("StealHealth"); -static FRandom pr_wraithfx2 ("WraithFX2"); -static FRandom pr_wraithfx3 ("WraithFX3"); -static FRandom pr_wraithfx4 ("WraithFX4"); - -//============================================================================ -// -// A_WraithInit -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_WraithInit) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->AddZ(48); - - // [RH] Make sure the wraith didn't go into the ceiling - if (self->Top() > self->ceilingz) - { - self->SetZ(self->ceilingz - self->Height); - } - - self->WeaveIndexZ = 0; // index into floatbob - return 0; -} - -//============================================================================ -// -// A_WraithRaiseInit -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_WraithRaiseInit) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->renderflags &= ~RF_INVISIBLE; - self->flags2 &= ~MF2_NONSHOOTABLE; - self->flags3 &= ~MF3_DONTBLAST; - self->flags |= MF_SHOOTABLE|MF_SOLID; - self->Floorclip = self->Height; - return 0; -} - -//============================================================================ -// -// A_WraithRaise -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_WraithRaise) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (A_RaiseMobj (self, 2)) - { - // Reached it's target height - // [RH] Once a buried wraith is fully raised, it should be - // morphable, right? - self->flags3 &= ~(MF3_DONTMORPH|MF3_SPECIALFLOORCLIP); - self->SetState (self->FindState("Chase")); - // [RH] Reset PainChance to a normal wraith's. - self->PainChance = GetDefaultByName ("Wraith")->PainChance; - } - - P_SpawnDirt (self, self->radius); - return 0; -} - -//============================================================================ -// -// A_WraithMelee -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_WraithMelee) -{ - PARAM_SELF_PROLOGUE(AActor); - - int amount; - - // Steal health from target and give to self - if (self->CheckMeleeRange() && (pr_stealhealth()<220)) - { - amount = pr_stealhealth.HitDice (2); - P_DamageMobj (self->target, self, self, amount, NAME_Melee); - self->health += amount; - } - return 0; -} - -//============================================================================ -// -// A_WraithFX2 - spawns sparkle tail of missile -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_WraithFX2) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo; - DAngle angle; - int i; - - for (i = 2; i; --i) - { - mo = Spawn ("WraithFX2", self->Pos(), ALLOW_REPLACE); - if(mo) - { - angle = pr_wraithfx2() * (360 / 1024.f); - if (pr_wraithfx2() >= 128) - { - angle = -angle; - } - angle += self->Angles.Yaw; - mo->Vel.X = ((pr_wraithfx2() / 512.) + 1) * angle.Cos(); - mo->Vel.Y = ((pr_wraithfx2() / 512.) + 1) * angle.Sin(); - mo->Vel.Z = 0; - mo->target = self; - mo->Floorclip = 10; - } - } - return 0; -} - -//============================================================================ -// -// A_WraithFX3 -// -// Spawn an FX3 around the self during attacks -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_WraithFX3) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo; - int numdropped = pr_wraithfx3() % 15; - - while (numdropped-- > 0) - { - double xo = (pr_wraithfx3() - 128) / 32.; - double yo = (pr_wraithfx3() - 128) / 32.; - double zo = pr_wraithfx3() / 64.; - - mo = Spawn("WraithFX3", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE); - if (mo) - { - mo->floorz = self->floorz; - mo->ceilingz = self->ceilingz; - mo->target = self; - } - } - return 0; -} - -//============================================================================ -// -// A_WraithFX4 -// -// Spawn an FX4 during movement -// -//============================================================================ - -void A_WraithFX4 (AActor *self) -{ - AActor *mo; - int chance = pr_wraithfx4(); - bool spawn4, spawn5; - - if (chance < 10) - { - spawn4 = true; - spawn5 = false; - } - else if (chance < 20) - { - spawn4 = false; - spawn5 = true; - } - else if (chance < 25) - { - spawn4 = true; - spawn5 = true; - } - else - { - spawn4 = false; - spawn5 = false; - } - - if (spawn4) - { - double xo = (pr_wraithfx4() - 128) / 16.; - double yo = (pr_wraithfx4() - 128) / 16.; - double zo = (pr_wraithfx4() / 64.); - - mo = Spawn ("WraithFX4", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE); - if (mo) - { - mo->floorz = self->floorz; - mo->ceilingz = self->ceilingz; - mo->target = self; - } - } - if (spawn5) - { - double xo = (pr_wraithfx4() - 128) / 32.; - double yo = (pr_wraithfx4() - 128) / 32.; - double zo = (pr_wraithfx4() / 64.); - - mo = Spawn ("WraithFX5", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE); - if (mo) - { - mo->floorz = self->floorz; - mo->ceilingz = self->ceilingz; - mo->target = self; - } - } -} - -//============================================================================ -// -// A_WraithChase -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_WraithChase) -{ - PARAM_SELF_PROLOGUE(AActor); - - int weaveindex = self->WeaveIndexZ; - self->AddZ(BobSin(weaveindex)); - self->WeaveIndexZ = (weaveindex + 2) & 63; -// if (self->Floorclip > 0) -// { -// P_SetMobjState(self, S_WRAITH_RAISE2); -// return; -// } - A_Chase (stack, self); - A_WraithFX4 (self); - return 0; -} diff --git a/src/g_shared/a_debris.cpp b/src/g_shared/a_debris.cpp index 3be3c2240..d3d69d7f6 100644 --- a/src/g_shared/a_debris.cpp +++ b/src/g_shared/a_debris.cpp @@ -3,8 +3,6 @@ #include "m_random.h" #include "m_fixed.h" -static FRandom pr_dirt ("SpawnDirt"); - // Stained glass ------------------------------------------------------------ class AGlassShard : public AActor @@ -27,25 +25,3 @@ public: IMPLEMENT_CLASS(AGlassShard, false, false, false, false) -// Dirt stuff - -void P_SpawnDirt (AActor *actor, double radius) -{ - PClassActor *dtype = NULL; - AActor *mo; - - double zo = pr_dirt() / 128. + 1; - DVector3 pos = actor->Vec3Angle(radius, pr_dirt() * (360./256), zo); - - char fmt[8]; - mysnprintf(fmt, countof(fmt), "Dirt%d", 1 + pr_dirt()%6); - dtype = PClass::FindActor(fmt); - if (dtype) - { - mo = Spawn (dtype, pos, ALLOW_REPLACE); - if (mo) - { - mo->Vel.Z = pr_dirt() / 64.; - } - } -} diff --git a/src/g_shared/a_sharedglobal.h b/src/g_shared/a_sharedglobal.h index c00cd8cf0..65f9d90b6 100644 --- a/src/g_shared/a_sharedglobal.h +++ b/src/g_shared/a_sharedglobal.h @@ -10,7 +10,6 @@ struct side_t; struct F3DFloor; class DBaseDecal; -void P_SpawnDirt (AActor *actor, double radius); class DBaseDecal *ShootDecal(const FDecalTemplate *tpl, AActor *basisactor, sector_t *sec, double x, double y, double z, DAngle angle, double tracedist, bool permanent); class DBaseDecal : public DThinker diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index d36a8de9d..6bb96ef30 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -3468,47 +3468,6 @@ int P_Massacre () return killcount; } -// -// A_SinkMobj -// Sink a mobj incrementally into the floor -// - -bool A_SinkMobj (AActor *actor, double speed) -{ - if (actor->Floorclip < actor->Height) - { - actor->Floorclip += speed; - return false; - } - return true; -} - -// -// A_RaiseMobj -// Raise a mobj incrementally from the floor to -// - -bool A_RaiseMobj (AActor *actor, double speed) -{ - bool done = true; - - // Raise a mobj from the ground - if (actor->Floorclip > 0) - { - actor->Floorclip -= speed; - if (actor->Floorclip <= 0) - { - actor->Floorclip = 0; - done = true; - } - else - { - done = false; - } - } - return done; // Reached target height -} - DEFINE_ACTION_FUNCTION(AActor, A_ClassBossHealth) { PARAM_SELF_PROLOGUE(AActor); diff --git a/src/p_enemy.h b/src/p_enemy.h index 7f4424fd6..c4a966344 100644 --- a/src/p_enemy.h +++ b/src/p_enemy.h @@ -75,9 +75,6 @@ void A_Chase(VMFrameStack *stack, AActor *self); void A_FaceTarget(AActor *actor); void A_Face(AActor *self, AActor *other, DAngle max_turn = 0., DAngle max_pitch = 270., DAngle ang_offset = 0., DAngle pitch_offset = 0., int flags = 0, double z_add = 0); -bool A_RaiseMobj (AActor *, double speed); -bool A_SinkMobj (AActor *, double speed); - bool CheckBossDeath (AActor *); int P_Massacre (); bool P_CheckMissileRange (AActor *actor); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index abbd057d7..9c36e861c 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -204,8 +204,8 @@ void AActor::InitNativeFields() meta->AddNativeField("fillcolor", TypeColor, myoffsetof(AActor, fillcolor)); meta->AddNativeField("Sector", TypeSector, myoffsetof(AActor, Sector)); //meta->AddNativeField("Subsector", TypeSubsector, myoffsetof(AActor, subsector)); - meta->AddNativeField(NAME_CeilingZ, TypeFloat64, myoffsetof(AActor, ceilingz), VARF_ReadOnly); - meta->AddNativeField(NAME_FloorZ, TypeFloat64, myoffsetof(AActor, floorz), VARF_ReadOnly); + meta->AddNativeField(NAME_CeilingZ, TypeFloat64, myoffsetof(AActor, ceilingz)); + meta->AddNativeField(NAME_FloorZ, TypeFloat64, myoffsetof(AActor, floorz)); meta->AddNativeField("DropoffZ", TypeFloat64, myoffsetof(AActor, dropoffz), VARF_ReadOnly); meta->AddNativeField("floorsector", TypeSector, myoffsetof(AActor, floorsector)); meta->AddNativeField("floorpic", TypeSInt32, myoffsetof(AActor, floorpic)); // Do we need a variable type 'texture' to do this? @@ -225,7 +225,7 @@ void AActor::InitNativeFields() meta->AddNativeField("specialf1", TypeFloat64, myoffsetof(AActor, specialf1)); meta->AddNativeField("specialf2", TypeFloat64, myoffsetof(AActor, specialf2)); meta->AddNativeField("weaponspecial", TypeSInt32, myoffsetof(AActor, weaponspecial)); - meta->AddNativeField(NAME_Health, TypeSInt32, myoffsetof(AActor, health), VARF_ReadOnly); + meta->AddNativeField(NAME_Health, TypeSInt32, myoffsetof(AActor, health)); meta->AddNativeField("movedir", TypeUInt8, myoffsetof(AActor, movedir)); meta->AddNativeField("visdir", TypeSInt8, myoffsetof(AActor, visdir)); meta->AddNativeField("movecount", TypeSInt16, myoffsetof(AActor, movecount)); diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 7b6b63672..f20a0b19e 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -268,6 +268,68 @@ class Actor : Thinker native DamageMobj(null, null, health, damagetype, DMG_FORCED); } + void SpawnDirt (double radius) + { + class dtype; + switch (random[Dirt](0, 5)) + { + case 0: dtype = "Dirt1"; break; + case 1: dtype = "Dirt2"; break; + case 2: dtype = "Dirt3"; break; + case 3: dtype = "Dirt4"; break; + case 4: dtype = "Dirt5"; break; + default: dtype = "Dirt6"; break; + } + + double zo = random[Dirt]() / 128. + 1; + Vector3 pos = Vec3Angle(radius, random[Dirt]() * (360./256), zo); + + Actor mo = Spawn (dtype, pos, ALLOW_REPLACE); + if (mo) + { + mo.Vel.Z = random[Dirt]() / 64.; + } + } + + // + // A_SinkMobj + // Sink a mobj incrementally into the floor + // + + bool SinkMobj (double speed) + { + if (Floorclip < Height) + { + Floorclip += speed; + return false; + } + return true; + } + + // + // A_RaiseMobj + // Raise a mobj incrementally from the floor to + // + + bool RaiseMobj (double speed) + { + // Raise a mobj from the ground + if (Floorclip > 0) + { + Floorclip -= speed; + if (Floorclip <= 0) + { + Floorclip = 0; + return true; + } + else + { + return false; + } + } + return true; + } + native void A_Face(Actor faceto, float max_turn = 0, float max_pitch = 270, float ang_offset = 0, float pitch_offset = 0, int flags = 0, float z_ofs = 0); diff --git a/wadsrc/static/zscript/hexen/spike.txt b/wadsrc/static/zscript/hexen/spike.txt index 58f763ccc..8d418d55a 100644 --- a/wadsrc/static/zscript/hexen/spike.txt +++ b/wadsrc/static/zscript/hexen/spike.txt @@ -26,11 +26,7 @@ class ThrustFloor : Actor native Height 128; } - native void A_ThrustRaise(); native void A_ThrustImpale(); - native void A_ThrustLower(); - native void A_ThrustInitDn(); - native void A_ThrustInitUp(); States { @@ -81,6 +77,79 @@ class ThrustFloor : Actor native TSPK B 2 A_ThrustImpale; Loop; } + + //=========================================================================== + // + // Thrust floor stuff + // + // Thrust Spike Variables + // master pointer to dirt clump actor + // special2 speed of raise + // args[0] 0 = lowered, 1 = raised + // args[1] 0 = normal, 1 = bloody + //=========================================================================== + + void A_ThrustInitUp() + { + special2 = 5; // Raise speed + args[0] = 1; // Mark as up + Floorclip = 0; + bSolid = true; + bNoTeleport = true; + bFloorClip = true; + special1 = 0; + } + + void A_ThrustInitDn() + { + special2 = 5; // Raise speed + args[0] = 0; // Mark as down + Floorclip = Default.Height; + bSolid = false; + bNoTeleport = true; + bFloorClip = true; + bInvisible = true; + master = Spawn("DirtClump", Pos, ALLOW_REPLACE); + } + + + void A_ThrustRaise() + { + if (RaiseMobj (special2)) + { // Reached it's target height + args[0] = 1; + if (args[1]) + SetStateLabel ("BloodThrustInit2", true); + else + SetStateLabel ("ThrustInit2", true); + } + + // Lose the dirt clump + if ((Floorclip < Height) && master) + { + master.Destroy (); + master = null; + } + + // Spawn some dirt + if (random[Thrustraise]()<40) + SpawnDirt (radius); + special2++; // Increase raise speed + } + + void A_ThrustLower() + { + if (SinkMobj (6)) + { + args[0] = 0; + if (args[1]) + SetStateLabel ("BloodThrustInit1", true); + else + SetStateLabel ("ThrustInit1", true); + } + } + + } // Spike up ----------------------------------------------------------------- diff --git a/wadsrc/static/zscript/hexen/wraith.txt b/wadsrc/static/zscript/hexen/wraith.txt index 86df72d94..42a81ae6c 100644 --- a/wadsrc/static/zscript/hexen/wraith.txt +++ b/wadsrc/static/zscript/hexen/wraith.txt @@ -23,11 +23,6 @@ class Wraith : Actor Obituary "$OB_WRAITH"; } - native void A_WraithInit(); - native void A_WraithChase(); - native void A_WraithFX3(); - native void A_WraithMelee(); - States { Spawn: @@ -78,6 +73,150 @@ class Wraith : Actor WRT2 I 1 A_FreezeDeathChunks; Wait; } + + //============================================================================ + // + // A_WraithInit + // + //============================================================================ + + void A_WraithInit() + { + AddZ(48); + + // [RH] Make sure the wraith didn't go into the ceiling + if (pos.z + height > ceilingz) + { + SetZ(ceilingz - Height); + } + + WeaveIndexZ = 0; // index into floatbob + } + + + //============================================================================ + // + // A_WraithChase + // + //============================================================================ + + void A_WraithChase() + { + int weaveindex = WeaveIndexZ; + AddZ(BobSin(weaveindex)); + WeaveIndexZ = (weaveindex + 2) & 63; + A_Chase (); + A_WraithFX4 (); + } + + //============================================================================ + // + // A_WraithFX3 + // + // Spawn an FX3 around the wraith during attacks + // + //============================================================================ + + void A_WraithFX3() + { + int numdropped = random[WraithFX3](0,14); + + while (numdropped-- > 0) + { + double xo = (random[WraithFX3]() - 128) / 32.; + double yo = (random[WraithFX3]() - 128) / 32.; + double zo = random[WraithFX3]() / 64.; + + Actor mo = Spawn("WraithFX3", Vec3Offset(xo, yo, zo), ALLOW_REPLACE); + if (mo) + { + mo.floorz = floorz; + mo.ceilingz = ceilingz; + mo.target = self; + } + } + } + + //============================================================================ + // + // A_WraithFX4 + // + // Spawn an FX4 during movement + // + //============================================================================ + + void A_WraithFX4 () + { + int chance = random[WraithFX4](); + bool spawn4, spawn5; + + if (chance < 10) + { + spawn4 = true; + spawn5 = false; + } + else if (chance < 20) + { + spawn4 = false; + spawn5 = true; + } + else if (chance < 25) + { + spawn4 = true; + spawn5 = true; + } + else + { + spawn4 = false; + spawn5 = false; + } + + if (spawn4) + { + double xo = (random[WraithFX4]() - 128) / 16.; + double yo = (random[WraithFX4]() - 128) / 16.; + double zo = (random[WraithFX4]() / 64.); + + Actor mo = Spawn ("WraithFX4", Vec3Offset(xo, yo, zo), ALLOW_REPLACE); + if (mo) + { + mo.floorz = floorz; + mo.ceilingz = ceilingz; + mo.target = self; + } + } + if (spawn5) + { + double xo = (random[WraithFX4]() - 128) / 32.; + double yo = (random[WraithFX4]() - 128) / 32.; + double zo = (random[WraithFX4]() / 64.); + + Actor mo = Spawn ("WraithFX5", Vec3Offset(xo, yo, zo), ALLOW_REPLACE); + if (mo) + { + mo.floorz = floorz; + mo.ceilingz = ceilingz; + mo.target = self; + } + } + } + + //============================================================================ + // + // A_WraithMelee + // + //============================================================================ + + void A_WraithMelee() + { + // Steal health from target and give to self + if (CheckMeleeRange() && (random[StealHealth]()<220)) + { + int amount = random[StealHealth](1, 8) * 2; + target.DamageMobj (self, self, amount, 'Melee'); + health += amount; + } + } } // Buried wraith ------------------------------------------------------------ @@ -97,8 +236,6 @@ class WraithBuried : Wraith PainChance 0; } - native void A_WraithRaiseInit(); - native void A_WraithRaise(); States { @@ -113,6 +250,47 @@ class WraithBuried : Wraith Chase: Goto Super::See; } + + //============================================================================ + // + // A_WraithRaiseInit + // + //============================================================================ + + void A_WraithRaiseInit() + { + bInvisible = false; + bNonShootable = false; + bDontBlast = false; + bShootable = true; + bSolid = true; + Floorclip = Height; + } + + //============================================================================ + // + // A_WraithRaise + // + //============================================================================ + + void A_WraithRaise() + { + if (RaiseMobj (2)) + { + // Reached it's target height + // [RH] Once a buried wraith is fully raised, it should be + // morphable, right? + bDontMorph = false; + bSpecialFloorClip = false; + SetStateLabel ("Chase"); + // [RH] Reset PainChance to a normal wraith's. + PainChance = GetDefaultByType("Wraith").PainChance; + } + + SpawnDirt (radius); + } + + } // Wraith FX 1 -------------------------------------------------------------- @@ -133,7 +311,6 @@ class WraithFX1 : Actor DeathSound "WraithMissileExplode"; } - native void A_WraithFX2(); States { @@ -150,6 +327,36 @@ class WraithFX1 : Actor WRBL I 3 Bright; Stop; } + + //============================================================================ + // + // A_WraithFX2 - spawns sparkle tail of missile + // + //============================================================================ + + void A_WraithFX2() + { + for (int i = 2; i; --i) + { + Actor mo = Spawn ("WraithFX2", Pos, ALLOW_REPLACE); + if(mo) + { + double newangle = random[WraithFX2]() * (360 / 1024.f); + if (random[WraithFX2]() >= 128) + { + newangle = -newangle; + } + newangle += angle; + mo.Vel.X = ((random[WraithFX2]() / 512.) + 1) * cos(newangle); + mo.Vel.Y = ((random[WraithFX2]() / 512.) + 1) * sin(newangle); + mo.Vel.Z = 0; + mo.target = self; + mo.Floorclip = 10; + } + } + } + + } // Wraith FX 2 -------------------------------------------------------------- From 30e6e8e25f10bfba6c151163356a60443982a3ec Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 17 Nov 2016 11:16:00 +0100 Subject: [PATCH 014/185] - added bookkeeping info to types for allowing data on the stack that requires construction and destruction. - removed unused PVector type. --- src/dobjtype.cpp | 198 +++++++++++++++++++++++++++++++++++------------ src/dobjtype.h | 36 +++++---- 2 files changed, 170 insertions(+), 64 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 5e56bab56..b9d518abf 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -541,7 +541,6 @@ void PType::StaticInit() 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); @@ -1870,6 +1869,39 @@ void PArray::SetDefaultValue(void *base, unsigned offset, TArray } } +//========================================================================== +// +// PArray :: InitializeValue +// This is needed for local array variables +// +//========================================================================== + +void PArray::InitializeValue(void *addr, const void *def) const +{ + char *caddr = (char*)addr; + char *cdef = (char*)def; + for (unsigned i = 0; i < ElementCount; ++i) + { + ElementType->InitializeValue(caddr + i * ElementSize, cdef + i * ElementSize); + } +} + +//========================================================================== +// +// PArray :: DestroyValue +// This is needed for local array variables +// +//========================================================================== + +void PArray::DestroyValue(void *addr) const +{ + char *caddr = (char*)addr; + for (unsigned i = 0; i < ElementCount; ++i) + { + ElementType->DestroyValue(caddr + i * ElementSize); + } +} + //========================================================================== // // NewArray @@ -1891,56 +1923,6 @@ PArray *NewArray(PType *type, unsigned int count) return (PArray *)atype; } -/* PVector ****************************************************************/ - -IMPLEMENT_CLASS(PVector, false, false, false, false) - -//========================================================================== -// -// PVector - Default Constructor -// -//========================================================================== - -PVector::PVector() -: PArray(TypeFloat32, 3) -{ - mDescriptiveName = "Vector"; -} - -//========================================================================== -// -// PVector - Parameterized Constructor -// -//========================================================================== - -PVector::PVector(unsigned int size) -: PArray(TypeFloat32, size) -{ - mDescriptiveName.Format("Vector<%d>", 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_CLASS(PDynArray, false, true, false, false) @@ -2003,6 +1985,28 @@ void PDynArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const id2 = 0; } +//========================================================================== +// +// PDynArray :: InitializeValue +// +//========================================================================== + +void PDynArray::InitializeValue(void *addr, const void *def) const +{ + // DynArrays are not implemented yet. +} + +//========================================================================== +// +// PDynArray :: DestroyValue +// +//========================================================================== + +void PDynArray::DestroyValue(void *addr) const +{ + // DynArrays are not implemented yet. +} + //========================================================================== // // NewDynArray @@ -2087,6 +2091,28 @@ void PMap::GetTypeIDs(intptr_t &id1, intptr_t &id2) const id2 = (intptr_t)ValueType; } +//========================================================================== +// +// PMap :: InitializeValue +// +//========================================================================== + +void PMap::InitializeValue(void *addr, const void *def) const +{ + // Maps are not implemented yet. +} + +//========================================================================== +// +// PMap :: DestroyValue +// +//========================================================================== + +void PMap::DestroyValue(void *addr) const +{ + // Maps are not implemented yet. +} + //========================================================================== // // NewMap @@ -2309,6 +2335,76 @@ size_t PStruct::PropagateMark() return Fields.Size() * sizeof(void*) + Super::PropagateMark(); } +//========================================================================== +// +// PStruct :: InitializeValue +// This is needed for local array variables +// +//========================================================================== + +void PStruct::InitializeValue(void *addr, const void *def) const +{ + char *caddr = (char*)addr; + char *cdef = (char*)def; + + for (auto tao : SpecialInits) + { + tao.first->InitializeValue(caddr + tao.second, cdef + tao.second); + } +} + +//========================================================================== +// +// PStruct :: DestroyValue +// This is needed for local array variables +// +//========================================================================== + +void PStruct::DestroyValue(void *addr) const +{ + char *caddr = (char*)addr; + for (auto tao : SpecialInits) + { + tao.first->DestroyValue(caddr + tao.second); + } +} + + +//========================================================================== +// +// PStruct :: InitializeSpecialInits +// +// Initialize special field list. +// +//========================================================================== + +void PStruct::InitializeSpecialInits() +{ + // and initialize our own special values. + auto it = Symbols.GetIterator(); + PSymbolTable::MapType::Pair *pair; + + while (it.NextPair(pair)) + { + auto field = dyn_cast(pair->Value); + if (field != nullptr && !(field->Flags & VARF_Native)) + { + field->Type->SetDefaultValue(nullptr, unsigned(field->Offset), &SpecialInits); + } + } +} + +//========================================================================== +// +// PStruct :: RequireConstruction +// +//========================================================================== + +bool PStruct::RequireConstruction() const +{ + return SpecialInits.Size() > 0; +} + //========================================================================== // // NewStruct diff --git a/src/dobjtype.h b/src/dobjtype.h index 186cb8117..dcf316fec 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -256,6 +256,9 @@ public: // Initialize the value, if needed (e.g. strings) virtual void InitializeValue(void *addr, const void *def) const; + // This is for stack variables that may need construction/destruction at runtime + virtual bool RequireConstruction() const { return false; } + // Destroy the value, if needed (e.g. strings) virtual void DestroyValue(void *addr) const; @@ -489,6 +492,7 @@ public: void SetDefaultValue(void *base, unsigned offset, TArray *special=NULL) const override; void InitializeValue(void *addr, const void *def) const override; void DestroyValue(void *addr) const override; + virtual bool RequireConstruction() const override { return true; } }; // Variations of integer types ---------------------------------------------- @@ -626,22 +630,14 @@ public: bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; void SetDefaultValue(void *base, unsigned offset, TArray *special) const override; + void InitializeValue(void *addr, const void *def) const override; + void DestroyValue(void *addr) const override; + bool RequireConstruction() const override { return ElementType->RequireConstruction(); } 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); @@ -653,6 +649,9 @@ public: virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; + void InitializeValue(void *addr, const void *def) const override; + void DestroyValue(void *addr) const override; + bool RequireConstruction() const override { return true; } protected: PDynArray(); }; @@ -669,6 +668,9 @@ public: virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; + void InitializeValue(void *addr, const void *def) const override; + void DestroyValue(void *addr) const override; + bool RequireConstruction() const override { return true; } protected: PMap(); }; @@ -676,6 +678,10 @@ protected: class PStruct : public PNamedType { DECLARE_CLASS(PStruct, PNamedType); + +protected: + TArray SpecialInits; + public: PStruct(FName name, PTypeBase *outer); @@ -693,6 +699,12 @@ public: static void WriteFields(FSerializer &ar, const void *addr, const TArray &fields); bool ReadFields(FSerializer &ar, void *addr) const; + + void InitializeValue(void *addr, const void *def) const override; + void DestroyValue(void *addr) const override; + bool RequireConstruction() const override; + void InitializeSpecialInits(); + protected: PStruct(); }; @@ -759,7 +771,6 @@ class PClass : public PStruct protected: // We unravel _WITH_META here just as we did for PType. enum { MetaClassNum = CLASSREG_PClassClass }; - TArray SpecialInits; void Derive(PClass *newclass, FName name); void InitializeSpecials(void *addr) const; void SetSuper(); @@ -889,7 +900,6 @@ struct FTypeTable 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); From d86f03e2e00bce5f95b87ce77b393891ef3993fc Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 17 Nov 2016 13:10:19 +0100 Subject: [PATCH 015/185] - reverted most of the last commit after realizing that trying to manage constructing/destructing per variable is not going to work because it'd require some extensive exception management in the compiled VM code. - instead add a list of SpecialInits to VMScriptFunction so this can be done transparently when setting up and popping the stack frame. The only drawback is that this requires permanent allocation of stack objects for the entire lifetime of a function but this is a relatively small tradeoff for significantly reduced maintenance work throughout. - removed most #include "vm.h", because nearly all files already pull this in through dobject.h. --- src/d_dehacked.cpp | 1 - src/d_main.cpp | 1 - src/dobjgc.cpp | 1 - src/dobjtype.cpp | 147 ------------------------------- src/dobjtype.h | 28 +----- src/g_doom/a_doommisc.cpp | 2 - src/g_heretic/a_hereticmisc.cpp | 2 - src/g_hexen/a_hexenmisc.cpp | 2 - src/g_shared/a_action.cpp | 1 - src/g_shared/a_bridge.cpp | 1 - src/g_shared/a_pickups.cpp | 1 - src/g_shared/a_randomspawner.cpp | 1 - src/g_shared/a_specialspot.cpp | 1 - src/g_shared/a_weapons.cpp | 1 - src/info.cpp | 2 - src/info.h | 1 - src/p_actionfunctions.cpp | 2 - src/p_enemy.cpp | 2 - src/p_enemy.h | 2 +- src/p_mobj.cpp | 1 - src/p_pspr.cpp | 1 - src/p_pspr.h | 1 - src/p_states.cpp | 1 - src/p_user.cpp | 1 - src/scripting/thingdef.h | 1 - src/scripting/vm/vm.h | 8 +- src/scripting/vm/vmbuilder.h | 2 +- src/scripting/vm/vmdisasm.cpp | 2 +- src/scripting/vm/vmexec.cpp | 2 +- src/scripting/vm/vmframe.cpp | 71 +++++++++------ 30 files changed, 55 insertions(+), 235 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index d0addb095..8d3a13580 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -70,7 +70,6 @@ #include "doomerrors.h" #include "p_effect.h" #include "serializer.h" -#include "vm.h" #include "thingdef.h" #include "info.h" #include "v_text.h" diff --git a/src/d_main.cpp b/src/d_main.cpp index d7757ddf4..dad2b86d9 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -109,7 +109,6 @@ #include "p_local.h" #include "autosegs.h" #include "fragglescript/t_fs.h" -#include "vm.h" EXTERN_CVAR(Bool, hud_althud) void DrawHUD(); diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index fa8723e90..40ef7b784 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -77,7 +77,6 @@ #include "r_utility.h" #include "menu/menu.h" #include "intermission/intermission.h" -#include "vm.h" // MACROS ------------------------------------------------------------------ diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index b9d518abf..1597494d9 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -1869,39 +1869,6 @@ void PArray::SetDefaultValue(void *base, unsigned offset, TArray } } -//========================================================================== -// -// PArray :: InitializeValue -// This is needed for local array variables -// -//========================================================================== - -void PArray::InitializeValue(void *addr, const void *def) const -{ - char *caddr = (char*)addr; - char *cdef = (char*)def; - for (unsigned i = 0; i < ElementCount; ++i) - { - ElementType->InitializeValue(caddr + i * ElementSize, cdef + i * ElementSize); - } -} - -//========================================================================== -// -// PArray :: DestroyValue -// This is needed for local array variables -// -//========================================================================== - -void PArray::DestroyValue(void *addr) const -{ - char *caddr = (char*)addr; - for (unsigned i = 0; i < ElementCount; ++i) - { - ElementType->DestroyValue(caddr + i * ElementSize); - } -} - //========================================================================== // // NewArray @@ -1985,28 +1952,6 @@ void PDynArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const id2 = 0; } -//========================================================================== -// -// PDynArray :: InitializeValue -// -//========================================================================== - -void PDynArray::InitializeValue(void *addr, const void *def) const -{ - // DynArrays are not implemented yet. -} - -//========================================================================== -// -// PDynArray :: DestroyValue -// -//========================================================================== - -void PDynArray::DestroyValue(void *addr) const -{ - // DynArrays are not implemented yet. -} - //========================================================================== // // NewDynArray @@ -2091,28 +2036,6 @@ void PMap::GetTypeIDs(intptr_t &id1, intptr_t &id2) const id2 = (intptr_t)ValueType; } -//========================================================================== -// -// PMap :: InitializeValue -// -//========================================================================== - -void PMap::InitializeValue(void *addr, const void *def) const -{ - // Maps are not implemented yet. -} - -//========================================================================== -// -// PMap :: DestroyValue -// -//========================================================================== - -void PMap::DestroyValue(void *addr) const -{ - // Maps are not implemented yet. -} - //========================================================================== // // NewMap @@ -2335,76 +2258,6 @@ size_t PStruct::PropagateMark() return Fields.Size() * sizeof(void*) + Super::PropagateMark(); } -//========================================================================== -// -// PStruct :: InitializeValue -// This is needed for local array variables -// -//========================================================================== - -void PStruct::InitializeValue(void *addr, const void *def) const -{ - char *caddr = (char*)addr; - char *cdef = (char*)def; - - for (auto tao : SpecialInits) - { - tao.first->InitializeValue(caddr + tao.second, cdef + tao.second); - } -} - -//========================================================================== -// -// PStruct :: DestroyValue -// This is needed for local array variables -// -//========================================================================== - -void PStruct::DestroyValue(void *addr) const -{ - char *caddr = (char*)addr; - for (auto tao : SpecialInits) - { - tao.first->DestroyValue(caddr + tao.second); - } -} - - -//========================================================================== -// -// PStruct :: InitializeSpecialInits -// -// Initialize special field list. -// -//========================================================================== - -void PStruct::InitializeSpecialInits() -{ - // and initialize our own special values. - auto it = Symbols.GetIterator(); - PSymbolTable::MapType::Pair *pair; - - while (it.NextPair(pair)) - { - auto field = dyn_cast(pair->Value); - if (field != nullptr && !(field->Flags & VARF_Native)) - { - field->Type->SetDefaultValue(nullptr, unsigned(field->Offset), &SpecialInits); - } - } -} - -//========================================================================== -// -// PStruct :: RequireConstruction -// -//========================================================================== - -bool PStruct::RequireConstruction() const -{ - return SpecialInits.Size() > 0; -} - //========================================================================== // // NewStruct diff --git a/src/dobjtype.h b/src/dobjtype.h index dcf316fec..0062c56ab 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -5,10 +5,10 @@ #error You must #include "dobject.h" to get dobjtype.h #endif -#include "vm.h" - typedef std::pair FTypeAndOffset; +#include "vm.h" + // Variable/parameter/field flags ------------------------------------------- // Making all these different storage types use a common set of flags seems @@ -256,9 +256,6 @@ public: // Initialize the value, if needed (e.g. strings) virtual void InitializeValue(void *addr, const void *def) const; - // This is for stack variables that may need construction/destruction at runtime - virtual bool RequireConstruction() const { return false; } - // Destroy the value, if needed (e.g. strings) virtual void DestroyValue(void *addr) const; @@ -492,7 +489,6 @@ public: void SetDefaultValue(void *base, unsigned offset, TArray *special=NULL) const override; void InitializeValue(void *addr, const void *def) const override; void DestroyValue(void *addr) const override; - virtual bool RequireConstruction() const override { return true; } }; // Variations of integer types ---------------------------------------------- @@ -630,9 +626,6 @@ public: bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; void SetDefaultValue(void *base, unsigned offset, TArray *special) const override; - void InitializeValue(void *addr, const void *def) const override; - void DestroyValue(void *addr) const override; - bool RequireConstruction() const override { return ElementType->RequireConstruction(); } protected: PArray(); @@ -649,9 +642,6 @@ public: virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; - void InitializeValue(void *addr, const void *def) const override; - void DestroyValue(void *addr) const override; - bool RequireConstruction() const override { return true; } protected: PDynArray(); }; @@ -668,9 +658,6 @@ public: virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; - void InitializeValue(void *addr, const void *def) const override; - void DestroyValue(void *addr) const override; - bool RequireConstruction() const override { return true; } protected: PMap(); }; @@ -678,10 +665,6 @@ protected: class PStruct : public PNamedType { DECLARE_CLASS(PStruct, PNamedType); - -protected: - TArray SpecialInits; - public: PStruct(FName name, PTypeBase *outer); @@ -699,12 +682,6 @@ public: static void WriteFields(FSerializer &ar, const void *addr, const TArray &fields); bool ReadFields(FSerializer &ar, void *addr) const; - - void InitializeValue(void *addr, const void *def) const override; - void DestroyValue(void *addr) const override; - bool RequireConstruction() const override; - void InitializeSpecialInits(); - protected: PStruct(); }; @@ -771,6 +748,7 @@ class PClass : public PStruct protected: // We unravel _WITH_META here just as we did for PType. enum { MetaClassNum = CLASSREG_PClassClass }; + TArray SpecialInits; void Derive(PClass *newclass, FName name); void InitializeSpecials(void *addr) const; void SetSuper(); diff --git a/src/g_doom/a_doommisc.cpp b/src/g_doom/a_doommisc.cpp index eabf887f0..30fd6c671 100644 --- a/src/g_doom/a_doommisc.cpp +++ b/src/g_doom/a_doommisc.cpp @@ -7,7 +7,6 @@ #include "gi.h" #include "doomstat.h" #include "gstrings.h" -#include "vm.h" #include "g_level.h" #include "p_enemy.h" #include "a_doomglobal.h" @@ -19,7 +18,6 @@ #include "p_maputl.h" #include "serializer.h" #include "g_shared/a_pickups.h" -#include "vm.h" // Include all the other Doom stuff here to reduce compile time #include "a_bossbrain.cpp" diff --git a/src/g_heretic/a_hereticmisc.cpp b/src/g_heretic/a_hereticmisc.cpp index 6af969842..17cd4df09 100644 --- a/src/g_heretic/a_hereticmisc.cpp +++ b/src/g_heretic/a_hereticmisc.cpp @@ -6,7 +6,6 @@ #include "p_local.h" #include "s_sound.h" #include "gstrings.h" -#include "vm.h" #include "p_enemy.h" #include "a_specialspot.h" #include "g_level.h" @@ -18,7 +17,6 @@ #include "a_morph.h" #include "p_spec.h" #include "serializer.h" -#include "vm.h" // Include all the other Heretic stuff here to reduce compile time #include "a_chicken.cpp" diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp index 21227e848..c87c9e46d 100644 --- a/src/g_hexen/a_hexenmisc.cpp +++ b/src/g_hexen/a_hexenmisc.cpp @@ -7,7 +7,6 @@ #include "a_sharedglobal.h" #include "a_hexenglobal.h" #include "i_system.h" -#include "vm.h" #include "gi.h" #include "g_level.h" #include "p_enemy.h" @@ -24,7 +23,6 @@ #include "p_maputl.h" #include "p_spec.h" #include "serializer.h" -#include "vm.h" // Include all the Hexen stuff here to reduce compile time #include "a_blastradius.cpp" diff --git a/src/g_shared/a_action.cpp b/src/g_shared/a_action.cpp index edd97a6d4..a371e4ad5 100644 --- a/src/g_shared/a_action.cpp +++ b/src/g_shared/a_action.cpp @@ -1,5 +1,4 @@ #include "actor.h" -#include "vm.h" #include "p_conversation.h" #include "p_lnspec.h" #include "a_action.h" diff --git a/src/g_shared/a_bridge.cpp b/src/g_shared/a_bridge.cpp index 8ce23b68e..c4b452f77 100644 --- a/src/g_shared/a_bridge.cpp +++ b/src/g_shared/a_bridge.cpp @@ -2,7 +2,6 @@ #include "info.h" #include "gi.h" #include "m_random.h" -#include "vm.h" static FRandom pr_orbit ("Orbit"); diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index 223a2f75f..fbc5ea509 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -14,7 +14,6 @@ #include "a_strifeglobal.h" #include "a_morph.h" #include "a_specialspot.h" -#include "vm.h" #include "g_level.h" #include "g_game.h" #include "doomstat.h" diff --git a/src/g_shared/a_randomspawner.cpp b/src/g_shared/a_randomspawner.cpp index 2b2c82956..40fdd0745 100644 --- a/src/g_shared/a_randomspawner.cpp +++ b/src/g_shared/a_randomspawner.cpp @@ -14,7 +14,6 @@ #include "statnums.h" #include "gstrings.h" #include "a_action.h" -#include "vm.h" #include "v_text.h" #include "doomstat.h" #include "doomdata.h" diff --git a/src/g_shared/a_specialspot.cpp b/src/g_shared/a_specialspot.cpp index 92306ce6b..c094ee8ba 100644 --- a/src/g_shared/a_specialspot.cpp +++ b/src/g_shared/a_specialspot.cpp @@ -37,7 +37,6 @@ #include "p_local.h" #include "statnums.h" #include "i_system.h" -#include "vm.h" #include "doomstat.h" #include "serializer.h" #include "a_pickups.h" diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index 2d159eb7d..4a947cbee 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -13,7 +13,6 @@ #include "cmdlib.h" #include "templates.h" #include "sbar.h" -#include "vm.h" #include "doomstat.h" #include "g_level.h" #include "d_net.h" diff --git a/src/info.cpp b/src/info.cpp index e771108c3..8ef594d1b 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -43,7 +43,6 @@ #include "v_text.h" #include "gi.h" -#include "vm.h" #include "actor.h" #include "r_state.h" #include "i_system.h" @@ -52,7 +51,6 @@ #include "cmdlib.h" #include "g_level.h" #include "stats.h" -#include "vm.h" #include "thingdef.h" #include "d_player.h" #include "doomerrors.h" diff --git a/src/info.h b/src/info.h index 0b7d4dfc3..5af51f34b 100644 --- a/src/info.h +++ b/src/info.h @@ -43,7 +43,6 @@ #include "dobject.h" #include "doomdef.h" -#include "vm.h" #include "s_sound.h" #include "m_fixed.h" diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 2d219fc38..37a2d533e 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -61,7 +61,6 @@ #include "c_console.h" #include "doomerrors.h" #include "a_sharedglobal.h" -#include "vm.h" #include "v_video.h" #include "v_font.h" #include "doomstat.h" @@ -77,7 +76,6 @@ #include "p_maputl.h" #include "p_spec.h" #include "templates.h" -#include "vm.h" #include "v_text.h" #include "thingdef.h" #include "math/cmath.h" diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 6bb96ef30..db237e8bb 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -43,7 +43,6 @@ #include "p_enemy.h" #include "a_sharedglobal.h" #include "a_action.h" -#include "vm.h" #include "d_dehacked.h" #include "g_level.h" #include "r_utility.h" @@ -53,7 +52,6 @@ #include "p_spec.h" #include "p_checkposition.h" #include "math/cmath.h" -#include "vm.h" #include "gi.h" diff --git a/src/p_enemy.h b/src/p_enemy.h index c4a966344..a9aa40dc2 100644 --- a/src/p_enemy.h +++ b/src/p_enemy.h @@ -1,7 +1,7 @@ #ifndef __P_ENEMY_H__ #define __P_ENEMY_H__ -#include "vm.h" +#include "dobject.h" #include "vectors.h" struct sector_t; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 9c36e861c..02c2a3578 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -53,7 +53,6 @@ #include "a_action.h" #include "a_keys.h" #include "p_conversation.h" -#include "vm.h" #include "g_game.h" #include "teaminfo.h" #include "r_data/r_translate.h" diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 5a76f0b55..1ba452b2b 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -25,7 +25,6 @@ #include "gi.h" #include "p_pspr.h" #include "templates.h" -#include "vm.h" #include "g_level.h" #include "d_player.h" #include "serializer.h" diff --git a/src/p_pspr.h b/src/p_pspr.h index 3f819714c..d75f08b06 100644 --- a/src/p_pspr.h +++ b/src/p_pspr.h @@ -25,7 +25,6 @@ // Basic data types. // Needs fixed point, and BAM angles. -//#include "vm.h" #define WEAPONBOTTOM 128. diff --git a/src/p_states.cpp b/src/p_states.cpp index ac7121f49..a49d30af2 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -39,7 +39,6 @@ #include "i_system.h" #include "c_dispatch.h" #include "v_text.h" -#include "vm.h" #include "thingdef.h" // stores indices for symbolic state labels for some old-style DECORATE functions. diff --git a/src/p_user.cpp b/src/p_user.cpp index 8c8858b63..11fe487b9 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -48,7 +48,6 @@ #include "doomdef.h" #include "c_dispatch.h" #include "tarray.h" -#include "vm.h" #include "g_level.h" #include "d_net.h" #include "gstrings.h" diff --git a/src/scripting/thingdef.h b/src/scripting/thingdef.h index 5992dba04..a2c224558 100644 --- a/src/scripting/thingdef.h +++ b/src/scripting/thingdef.h @@ -6,7 +6,6 @@ #include "s_sound.h" #include "sc_man.h" #include "cmdlib.h" -#include "vm.h" class FScanner; diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index ae867a975..d82411d51 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -2,7 +2,6 @@ #define VM_H #include "zstring.h" -#include "dobject.h" #include "autosegs.h" #include "vectors.h" @@ -815,6 +814,12 @@ public: VM_UHALF MaxParam; // Maximum number of parameters this function has on the stack at once VM_UBYTE NumArgs; // Number of arguments this function takes FString PrintableName; // so that the VM can print meaningful info if something in this function goes wrong. + TArray SpecialInits; // list of all contents on the extra stack which require construction and destruction + + void InitExtra(void *addr); + void DestroyExtra(void *addr); + void SetExtraSpecial(PType *type, unsigned offset); + int AllocExtraStack(PType *type); }; class VMFrameStack @@ -822,7 +827,6 @@ class VMFrameStack public: VMFrameStack(); ~VMFrameStack(); - VMFrame *AllocFrame(int numregd, int numregf, int numregs, int numrega); VMFrame *AllocFrame(VMScriptFunction *func); VMFrame *PopFrame(); VMFrame *TopFrame() diff --git a/src/scripting/vm/vmbuilder.h b/src/scripting/vm/vmbuilder.h index 5394dec32..a5013dc57 100644 --- a/src/scripting/vm/vmbuilder.h +++ b/src/scripting/vm/vmbuilder.h @@ -1,7 +1,7 @@ #ifndef VMUTIL_H #define VMUTIL_H -#include "vm.h" +#include "dobject.h" class VMFunctionBuilder { diff --git a/src/scripting/vm/vmdisasm.cpp b/src/scripting/vm/vmdisasm.cpp index 49c929f05..48b6d168b 100644 --- a/src/scripting/vm/vmdisasm.cpp +++ b/src/scripting/vm/vmdisasm.cpp @@ -31,7 +31,7 @@ ** */ -#include "vm.h" +#include "dobject.h" #include "c_console.h" #include "templates.h" diff --git a/src/scripting/vm/vmexec.cpp b/src/scripting/vm/vmexec.cpp index 57ce48a95..8f8559d93 100644 --- a/src/scripting/vm/vmexec.cpp +++ b/src/scripting/vm/vmexec.cpp @@ -34,7 +34,7 @@ #include #include #include -#include "vm.h" +#include "dobject.h" #include "xs_Float.h" #include "math/cmath.h" diff --git a/src/scripting/vm/vmframe.cpp b/src/scripting/vm/vmframe.cpp index 3a593861c..e5a302606 100644 --- a/src/scripting/vm/vmframe.cpp +++ b/src/scripting/vm/vmframe.cpp @@ -32,7 +32,7 @@ */ #include -#include "vm.h" +#include "dobject.h" IMPLEMENT_CLASS(VMException, false, false, false, false) IMPLEMENT_CLASS(VMFunction, true, true, false, false) @@ -162,6 +162,38 @@ size_t VMScriptFunction::PropagateMark() return NumKonstA * sizeof(void *) + Super::PropagateMark(); } +void VMScriptFunction::InitExtra(void *addr) +{ + char *caddr = (char*)addr; + + for (auto tao : SpecialInits) + { + tao.first->InitializeValue(caddr + tao.second, nullptr); + } +} + +void VMScriptFunction::DestroyExtra(void *addr) +{ + char *caddr = (char*)addr; + + for (auto tao : SpecialInits) + { + tao.first->DestroyValue(caddr + tao.second); + } +} + +void VMScriptFunction::SetExtraSpecial(PType *type, unsigned offset) +{ + type->SetDefaultValue(nullptr, offset, &SpecialInits); +} + +int VMScriptFunction::AllocExtraStack(PType *type) +{ + int address = ((ExtraSpace + type->Align - 1) / type->Align) * type->Align; + ExtraSpace = address + type->Size; + return address; +} + //=========================================================================== // // VMFrame :: InitRegS @@ -223,34 +255,6 @@ VMFrameStack::~VMFrameStack() 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 @@ -273,6 +277,10 @@ VMFrame *VMFrameStack::AllocFrame(VMScriptFunction *func) frame->MaxParam = func->MaxParam; frame->Func = func; frame->InitRegS(); + if (func->SpecialInits.Size()) + { + func->InitExtra(frame->GetExtra()); + } return frame; } @@ -358,6 +366,11 @@ VMFrame *VMFrameStack::PopFrame() { return NULL; } + auto Func = static_cast(frame->Func); + if (Func->SpecialInits.Size()) + { + Func->DestroyExtra(frame->GetExtra()); + } // Free any string registers this frame had. FString *regs = frame->GetRegS(); for (int i = frame->NumRegS; i != 0; --i) From 2cc48ec378e438eaba6f79a78be90b2cc1585482 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 17 Nov 2016 16:44:41 +0100 Subject: [PATCH 016/185] - implemented code generation for stack variables. - fixed code generation for using local variables as array index. This must use a different register for the array element offset because the original register may not be overwritten. --- src/p_mobj.cpp | 7 + src/scripting/codegeneration/codegen.cpp | 292 ++++++++++++++++++----- src/scripting/codegeneration/codegen.h | 35 ++- src/scripting/vm/vm.h | 2 +- src/scripting/vm/vmbuilder.cpp | 7 + src/scripting/vm/vmbuilder.h | 16 ++ src/scripting/vm/vmframe.cpp | 6 +- src/scripting/zscript/zcc_compile.cpp | 40 ++-- wadsrc/static/zscript/actor.txt | 1 + 9 files changed, 310 insertions(+), 96 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 02c2a3578..8029e24c0 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -6829,6 +6829,13 @@ const char *AActor::GetTag(const char *def) const } } +DEFINE_ACTION_FUNCTION(AActor, GetTag) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_STRING(def); + ACTION_RETURN_STRING(self->GetTag(def.Len() == 0? nullptr : def.GetChars())); +} + void AActor::SetTag(const char *def) { if (def == NULL || *def == 0) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 44d7cda88..c522b2145 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -5084,9 +5084,18 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) FxLocalVariableDeclaration *local = ctx.FindLocalVariable(Identifier); if (local != nullptr) { - auto x = new FxLocalVariable(local, ScriptPosition); - delete this; - return x->Resolve(ctx); + if (local->ValueType->GetRegType() != REGT_NIL) + { + auto x = new FxLocalVariable(local, ScriptPosition); + delete this; + return x->Resolve(ctx); + } + else + { + auto x = new FxStackVariable(local->ValueType, local->StackOffset, ScriptPosition); + delete this; + return x->Resolve(ctx); + } } if (Identifier == NAME_Default) @@ -5584,6 +5593,106 @@ ExpEmit FxGlobalVariable::Emit(VMFunctionBuilder *build) } +//========================================================================== +// +// +// +//========================================================================== + +FxStackVariable::FxStackVariable(PType *type, int offset, const FScriptPosition &pos) + : FxExpression(EFX_StackVariable, pos) +{ + membervar = new PField(NAME_None, type, 0, offset); + AddressRequested = false; + AddressWritable = true; // must be true unless classx tells us otherwise if requested. +} + +//========================================================================== +// +// force delete the PField because we know we won't need it anymore +// and it won't get GC'd until the compiler finishes. +// +//========================================================================== + +FxStackVariable::~FxStackVariable() +{ + // Q: Is this good or bad? Needs testing if this is fine or better left to the GC anyway. DObject's destructor is anything but cheap. + membervar->ObjectFlags |= OF_YesReallyDelete; + delete membervar; +} + +//========================================================================== +// +// +//========================================================================== + +void FxStackVariable::ReplaceField(PField *newfield) +{ + membervar->ObjectFlags |= OF_YesReallyDelete; + delete membervar; + membervar = newfield; +} + +//========================================================================== +// +// +// +//========================================================================== + +bool FxStackVariable::RequestAddress(FCompileContext &ctx, bool *writable) +{ + AddressRequested = true; + if (writable != nullptr) *writable = AddressWritable && !ctx.CheckReadOnly(membervar->Flags); + return true; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxStackVariable::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + ValueType = membervar->Type; + return this; +} + +ExpEmit FxStackVariable::Emit(VMFunctionBuilder *build) +{ + int offsetreg = -1; + + if (membervar->Offset != 0) offsetreg = build->GetConstantInt((int)membervar->Offset); + + if (AddressRequested) + { + ExpEmit obj(build, REGT_POINTER); + if (offsetreg >= 0) + { + build->Emit(OP_ADDA_RK, obj.RegNum, build->FramePointer.RegNum, offsetreg); + return obj; + } + else return build->FramePointer; + } + ExpEmit loc(build, membervar->Type->GetRegType(), membervar->Type->GetRegCount()); + + if (membervar->BitValue == -1) + { + if (offsetreg == -1) offsetreg = build->GetConstantInt(0); + build->Emit(membervar->Type->GetLoadOp(), loc.RegNum, build->FramePointer.RegNum, offsetreg); + } + else + { + ExpEmit obj(build, REGT_POINTER); + if (offsetreg >= 0) build->Emit(OP_ADDA_RK, obj.RegNum, build->FramePointer.RegNum, offsetreg); + obj.Free(build); + build->Emit(OP_LBIT, loc.RegNum, obj.RegNum, 1 << membervar->BitValue); + } + return loc; +} + + //========================================================================== // // @@ -5684,6 +5793,16 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) classx = nullptr; return x; } + else if (classx->ExprType == EFX_StackVariable) + { + auto parentfield = static_cast(classx)->membervar; + auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset, membervar->BitValue); + static_cast(classx)->ReplaceField(newfield); + classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. + auto x = classx->Resolve(ctx); + classx = nullptr; + return x; + } else if (classx->ExprType == EFX_LocalVariable && classx->IsVector()) // vectors are a special case because they are held in registers { // since this is a vector, all potential things that may get here are single float or an xy-vector. @@ -5831,7 +5950,7 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) return nullptr; } } - if (index->ValueType->GetRegType() != REGT_INT && index->ValueType != TypeName) + if (!index->IsInteger()) { ScriptPosition.Message(MSG_ERROR, "Array index must be integer"); delete this; @@ -5854,16 +5973,10 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) delete this; return nullptr; } + // Todo: optimize out the array. } ValueType = arraytype->ElementType; - if (ValueType->GetRegType() != REGT_INT && ValueType->GetRegType() != REGT_FLOAT) - { - // int arrays only for now - ScriptPosition.Message(MSG_ERROR, "Only numeric arrays are supported."); - delete this; - return nullptr; - } if (!Array->RequestAddress(ctx, &AddressWritable)) { ScriptPosition.Message(MSG_ERROR, "Unable to dereference array."); @@ -5902,7 +6015,18 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) { if (indexval != 0) { - build->Emit(OP_ADDA_RK, start.RegNum, start.RegNum, build->GetConstantInt(indexval)); + if (!start.Fixed) + { + build->Emit(OP_ADDA_RK, start.RegNum, start.RegNum, build->GetConstantInt(indexval)); + } + else + { + // do not clobber local variables. + ExpEmit temp(build, start.RegType); + build->Emit(OP_ADDA_RK, temp.RegNum, start.RegNum, build->GetConstantInt(indexval)); + start.Free(build); + start = temp; + } } } else @@ -5915,21 +6039,40 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) { ExpEmit indexv(index->Emit(build)); ExpEmit indexwork = indexv.Fixed ? ExpEmit(build, indexv.RegType) : indexv; + build->Emit(OP_BOUND, indexv.RegNum, arraytype->ElementCount); + int shiftbits = 0; while (1u << shiftbits < arraytype->ElementSize) { shiftbits++; } - assert(1u << shiftbits == arraytype->ElementSize && "Element sizes other than power of 2 are not implemented"); - build->Emit(OP_BOUND, indexv.RegNum, arraytype->ElementCount); - if (shiftbits > 0) + if (1u << shiftbits == arraytype->ElementSize) { - build->Emit(OP_SLL_RI, indexwork.RegNum, indexv.RegNum, shiftbits); + if (shiftbits > 0) + { + build->Emit(OP_SLL_RI, indexwork.RegNum, indexv.RegNum, shiftbits); + } + } + else + { + // A shift won't do, so use a multiplication + build->Emit(OP_MUL_RK, indexwork.RegNum, indexv.RegNum, build->GetConstantInt(arraytype->ElementSize)); } if (AddressRequested) { - build->Emit(OP_ADDA_RR, start.RegNum, start.RegNum, indexwork.RegNum); + if (!start.Fixed) + { + build->Emit(OP_ADDA_RR, start.RegNum, start.RegNum, indexwork.RegNum); + } + else + { + // do not clobber local variables. + ExpEmit temp(build, start.RegType); + build->Emit(OP_ADDA_RR, temp.RegNum, start.RegNum, indexwork.RegNum); + start.Free(build); + start = temp; + } } else { @@ -8413,7 +8556,7 @@ FxLocalVariableDeclaration::FxLocalVariableDeclaration(PType *type, FName name, VarFlags = varflags; Name = name; RegCount = type == TypeVector2 ? 2 : type == TypeVector3 ? 3 : 1; - Init = initval == nullptr? nullptr : new FxTypeCast(initval, type, false); + Init = initval; } FxLocalVariableDeclaration::~FxLocalVariableDeclaration() @@ -8424,75 +8567,96 @@ FxLocalVariableDeclaration::~FxLocalVariableDeclaration() FxExpression *FxLocalVariableDeclaration::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); - SAFE_RESOLVE_OPT(Init, ctx); if (ctx.Block == nullptr) { ScriptPosition.Message(MSG_ERROR, "Variable declaration outside compound statement"); delete this; return nullptr; } + if (ValueType->RegType == REGT_NIL) + { + auto sfunc = static_cast(ctx.Function->Variants[0].Implementation); + StackOffset = sfunc->AllocExtraStack(ValueType); + // Todo: Process the compound initializer once implemented. + } + else + { + if (Init) Init = new FxTypeCast(Init, ValueType, false); + SAFE_RESOLVE_OPT(Init, ctx); + } ctx.Block->LocalVars.Push(this); return this; } ExpEmit FxLocalVariableDeclaration::Emit(VMFunctionBuilder *build) { - if (Init == nullptr) + if (ValueType->RegType != REGT_NIL) { - RegNum = build->Registers[ValueType->GetRegType()].Get(RegCount); - } - else - { - ExpEmit emitval = Init->Emit(build); - - int regtype = emitval.RegType; - if (regtype < REGT_INT || regtype > REGT_TYPE) + if (Init == nullptr) { - ScriptPosition.Message(MSG_ERROR, "Attempted to assign a non-value"); - return ExpEmit(); - } - if (emitval.Konst) - { - auto constval = static_cast(Init); - RegNum = build->Registers[regtype].Get(1); - switch (regtype) - { - default: - case REGT_INT: - build->Emit(OP_LK, RegNum, build->GetConstantInt(constval->GetValue().GetInt())); - break; - - case REGT_FLOAT: - build->Emit(OP_LKF, RegNum, build->GetConstantFloat(constval->GetValue().GetFloat())); - break; - - case REGT_POINTER: - build->Emit(OP_LKP, RegNum, build->GetConstantAddress(constval->GetValue().GetPointer(), ATAG_GENERIC)); - break; - - case REGT_STRING: - build->Emit(OP_LKS, RegNum, build->GetConstantString(constval->GetValue().GetString())); - } - emitval.Free(build); - } - else if (Init->ExprType != EFX_LocalVariable) - { - // take over the register that got allocated while emitting the Init expression. - RegNum = emitval.RegNum; + RegNum = build->Registers[ValueType->GetRegType()].Get(RegCount); } else { - ExpEmit out(build, emitval.RegType, emitval.RegCount); - build->Emit(ValueType->GetMoveOp(), out.RegNum, emitval.RegNum); - RegNum = out.RegNum; + ExpEmit emitval = Init->Emit(build); + + int regtype = emitval.RegType; + if (regtype < REGT_INT || regtype > REGT_TYPE) + { + ScriptPosition.Message(MSG_ERROR, "Attempted to assign a non-value"); + return ExpEmit(); + } + if (emitval.Konst) + { + auto constval = static_cast(Init); + RegNum = build->Registers[regtype].Get(1); + switch (regtype) + { + default: + case REGT_INT: + build->Emit(OP_LK, RegNum, build->GetConstantInt(constval->GetValue().GetInt())); + break; + + case REGT_FLOAT: + build->Emit(OP_LKF, RegNum, build->GetConstantFloat(constval->GetValue().GetFloat())); + break; + + case REGT_POINTER: + build->Emit(OP_LKP, RegNum, build->GetConstantAddress(constval->GetValue().GetPointer(), ATAG_GENERIC)); + break; + + case REGT_STRING: + build->Emit(OP_LKS, RegNum, build->GetConstantString(constval->GetValue().GetString())); + } + emitval.Free(build); + } + else if (Init->ExprType != EFX_LocalVariable) + { + // take over the register that got allocated while emitting the Init expression. + RegNum = emitval.RegNum; + } + else + { + ExpEmit out(build, emitval.RegType, emitval.RegCount); + build->Emit(ValueType->GetMoveOp(), out.RegNum, emitval.RegNum); + RegNum = out.RegNum; + } } } + else + { + // Init arrays and structs. + } return ExpEmit(); } void FxLocalVariableDeclaration::Release(VMFunctionBuilder *build) { // Release the register after the containing block gets closed - assert(RegNum != -1); - build->Registers[ValueType->GetRegType()].Return(RegNum, RegCount); + if(RegNum != -1) + { + build->Registers[ValueType->GetRegType()].Return(RegNum, RegCount); + } + // Stack space will not be released because that would make controlled destruction impossible. + // For that all local stack variables need to live for the entire execution of a function. } diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index f1778512f..84ddfcdd8 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -44,6 +44,7 @@ #include "sc_man.h" #include "s_sound.h" #include "actor.h" +#include "vmbuilder.h" #define CHECKRESOLVED() if (isresolved) return this; isresolved=true; @@ -202,17 +203,6 @@ struct ExpVal } }; -struct ExpEmit -{ - ExpEmit() : RegNum(0), RegType(REGT_NIL), RegCount(1), Konst(false), Fixed(false), Final(false), Target(false) {} - ExpEmit(int reg, int type, bool konst = false, bool fixed = false) : RegNum(reg), RegType(type), RegCount(1), Konst(konst), Fixed(fixed), Final(false), Target(false) {} - ExpEmit(VMFunctionBuilder *build, int type, int count = 1); - void Free(VMFunctionBuilder *build); - void Reuse(VMFunctionBuilder *build); - - BYTE RegNum, RegType, RegCount, Konst:1, Fixed:1, Final:1, Target:1; -}; - enum EFxType { EFX_Expression, @@ -282,6 +272,7 @@ enum EFxType EFX_DynamicCast, EFX_GlobalVariable, EFX_Super, + EFX_StackVariable, EFX_COUNT }; @@ -1234,6 +1225,27 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// FxLocalVariable +// +//========================================================================== + +class FxStackVariable : public FxExpression +{ +public: + PField *membervar; + bool AddressRequested; + bool AddressWritable; + + FxStackVariable(PType *type, int offset, const FScriptPosition&); + ~FxStackVariable(); + void ReplaceField(PField *newfield); + FxExpression *Resolve(FCompileContext&); + bool RequestAddress(FCompileContext &ctx, bool *writable); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxSelf @@ -1746,6 +1758,7 @@ class FxLocalVariableDeclaration : public FxExpression int VarFlags; int RegCount; public: + int StackOffset = -1; int RegNum = -1; FxLocalVariableDeclaration(PType *type, FName name, FxExpression *initval, int varflags, const FScriptPosition &p); diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index d82411d51..c9f75f214 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -818,7 +818,6 @@ public: void InitExtra(void *addr); void DestroyExtra(void *addr); - void SetExtraSpecial(PType *type, unsigned offset); int AllocExtraStack(PType *type); }; @@ -1047,6 +1046,7 @@ void CallAction(VMFrameStack *stack, VMFunction *vmfunc, AActor *self); #define ACTION_RETURN_VEC3(v) do { DVector3 u = v; if (numret > 0) { assert(ret != nullptr); ret[0].SetVector(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) +#define ACTION_RETURN_STRING(v) do { FString u = v; if (numret > 0) { assert(ret != NULL); ret->SetString(u); return 1; } return 0; } while(0) // Checks to see what called the current action function #define ACTION_CALL_FROM_ACTOR() (stateinfo == nullptr || stateinfo->mStateType == STATE_Actor) diff --git a/src/scripting/vm/vmbuilder.cpp b/src/scripting/vm/vmbuilder.cpp index 19d89fc6f..721ff5fab 100644 --- a/src/scripting/vm/vmbuilder.cpp +++ b/src/scripting/vm/vmbuilder.cpp @@ -718,6 +718,13 @@ void FFunctionBuildList::Build() FScriptPosition::StrictErrors = !item.FromDecorate; item.Code = item.Code->Resolve(ctx); + // If we need extra space, load the frame pointer into a register so that we do not have to call the wasteful LFP instruction more than once. + if (item.Function->ExtraSpace > 0) + { + buildit.FramePointer = ExpEmit(&buildit, REGT_POINTER); + buildit.FramePointer.Fixed = true; + buildit.Emit(OP_LFP, buildit.FramePointer.RegNum); + } // Make sure resolving it didn't obliterate it. if (item.Code != nullptr) diff --git a/src/scripting/vm/vmbuilder.h b/src/scripting/vm/vmbuilder.h index a5013dc57..d69c97707 100644 --- a/src/scripting/vm/vmbuilder.h +++ b/src/scripting/vm/vmbuilder.h @@ -3,6 +3,19 @@ #include "dobject.h" +class VMFunctionBuilder; + +struct ExpEmit +{ + ExpEmit() : RegNum(0), RegType(REGT_NIL), RegCount(1), Konst(false), Fixed(false), Final(false), Target(false) {} + ExpEmit(int reg, int type, bool konst = false, bool fixed = false) : RegNum(reg), RegType(type), RegCount(1), Konst(konst), Fixed(fixed), Final(false), Target(false) {} + ExpEmit(VMFunctionBuilder *build, int type, int count = 1); + void Free(VMFunctionBuilder *build); + void Reuse(VMFunctionBuilder *build); + + BYTE RegNum, RegType, RegCount, Konst:1, Fixed : 1, Final : 1, Target : 1; +}; + class VMFunctionBuilder { public: @@ -63,6 +76,9 @@ public: // amount of implicit parameters so that proper code can be emitted for method calls int NumImplicits; + // keep the frame pointer, if needed, in a register because the LFP opcode is hideously inefficient, requiring more than 20 instructions on x64. + ExpEmit FramePointer; + private: struct AddrKonst { diff --git a/src/scripting/vm/vmframe.cpp b/src/scripting/vm/vmframe.cpp index e5a302606..b20c8ac89 100644 --- a/src/scripting/vm/vmframe.cpp +++ b/src/scripting/vm/vmframe.cpp @@ -182,15 +182,11 @@ void VMScriptFunction::DestroyExtra(void *addr) } } -void VMScriptFunction::SetExtraSpecial(PType *type, unsigned offset) -{ - type->SetDefaultValue(nullptr, offset, &SpecialInits); -} - int VMScriptFunction::AllocExtraStack(PType *type) { int address = ((ExtraSpace + type->Align - 1) / type->Align) * type->Align; ExtraSpace = address + type->Size; + type->SetDefaultValue(nullptr, address, &SpecialInits); return address; } diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index aec8f5853..596b7d8c4 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2970,29 +2970,39 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) auto loc = static_cast(ast); auto node = loc->Vars; FxSequence *list = new FxSequence(*ast); + + PType *ztype = DetermineType(ConvertClass, node, node->Name, loc->Type, true, false); + + if (loc->Type->ArraySize != nullptr) + { + ztype = ResolveArraySize(ztype, loc->Type->ArraySize, &ConvertClass->Symbols); + } + do { - // Type determination must be done for each field to properly handle array definitions. - PType *type = DetermineType(ConvertClass, node, node->Name, loc->Type, true, false); - if (type->IsKindOf(RUNTIME_CLASS(PArray))) + PType *type; + + if (node->ArraySize != nullptr) { - Error(loc, "Local array variables not implemented yet."); + type = ResolveArraySize(ztype, node->ArraySize, &ConvertClass->Symbols); } else { - FxExpression *val; - if (node->InitIsArray) - { - Error(node, "Tried to initialize %s with an array", FName(node->Name).GetChars()); - val = nullptr; - } - else - { - val = node->Init ? ConvertNode(node->Init) : nullptr; - } - list->Add(new FxLocalVariableDeclaration(type, node->Name, val, 0, *node)); // todo: Handle flags in the grammar. + type = ztype; } + FxExpression *val; + if (node->InitIsArray) + { + Error(node, "Compound initializer not implemented yet"); + val = nullptr; + } + else + { + val = node->Init ? ConvertNode(node->Init) : nullptr; + } + list->Add(new FxLocalVariableDeclaration(type, node->Name, val, 0, *node)); // todo: Handle flags in the grammar. + node = static_cast(node->SiblingNext); } while (node != loc->Vars); return list; diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index f20a0b19e..043ab3ed4 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -66,6 +66,7 @@ class Actor : Thinker native native static float absangle(float ang1, float ang2); native static float GetDefaultSpeed(class type); native void RemoveFromHash(); + native string GetTag(string defstr = ""); native float GetBobOffset(float frac = 0); native void SetDamage(int dmg); native static bool isDehState(state st); From 8205e6cf08a05be474eafdde302570873567c622 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 17 Nov 2016 18:06:56 +0100 Subject: [PATCH 017/185] - optimize access to array members with constant index. Like with struct members this can be combined with the outer index/address. - fixed register allocation with array indices and stack variables. --- src/scripting/codegeneration/codegen.cpp | 69 +++++++++++++++++------- 1 file changed, 51 insertions(+), 18 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index c522b2145..f7eadbe90 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -5667,13 +5667,16 @@ ExpEmit FxStackVariable::Emit(VMFunctionBuilder *build) if (AddressRequested) { - ExpEmit obj(build, REGT_POINTER); if (offsetreg >= 0) { + ExpEmit obj(build, REGT_POINTER); build->Emit(OP_ADDA_RK, obj.RegNum, build->FramePointer.RegNum, offsetreg); return obj; } - else return build->FramePointer; + else + { + return build->FramePointer; + } } ExpEmit loc(build, membervar->Type->GetRegType(), membervar->Type->GetRegCount()); @@ -5973,7 +5976,39 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) delete this; return nullptr; } - // Todo: optimize out the array. + + // if this is an array within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset. + if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember) + { + auto parentfield = static_cast(Array)->membervar; + // PFields are garbage collected so this will be automatically taken care of later. + auto newfield = new PField(NAME_None, arraytype->ElementType, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset); + static_cast(Array)->membervar = newfield; + Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. + auto x = Array->Resolve(ctx); + Array = nullptr; + return x; + } + else if (Array->ExprType == EFX_GlobalVariable) + { + auto parentfield = static_cast(Array)->membervar; + auto newfield = new PField(NAME_None, arraytype->ElementType, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset); + static_cast(Array)->membervar = newfield; + Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. + auto x = Array->Resolve(ctx); + Array = nullptr; + return x; + } + else if (Array->ExprType == EFX_StackVariable) + { + auto parentfield = static_cast(Array)->membervar; + auto newfield = new PField(NAME_None, arraytype->ElementType, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset); + static_cast(Array)->ReplaceField(newfield); + Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. + auto x = Array->Resolve(ctx); + Array = nullptr; + return x; + } } ValueType = arraytype->ElementType; @@ -5996,7 +6031,6 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) { ExpEmit start = Array->Emit(build); PArray *const arraytype = static_cast(Array->ValueType); - ExpEmit dest(build, arraytype->ElementType->GetRegType()); if (start.Konst) { @@ -6028,11 +6062,14 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) start = temp; } } + return start; } else { - build->Emit(arraytype->ElementType->GetLoadOp(), dest.RegNum, - start.RegNum, build->GetConstantInt(indexval)); + start.Free(build); + ExpEmit dest(build, ValueType->GetRegType()); + build->Emit(arraytype->ElementType->GetLoadOp(), dest.RegNum, start.RegNum, build->GetConstantInt(indexval)); + return dest; } } else @@ -6059,6 +6096,7 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) build->Emit(OP_MUL_RK, indexwork.RegNum, indexv.RegNum, build->GetConstantInt(arraytype->ElementSize)); } + indexwork.Free(build); if (AddressRequested) { if (!start.Fixed) @@ -6067,28 +6105,23 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) } else { + start.Free(build); // do not clobber local variables. ExpEmit temp(build, start.RegType); build->Emit(OP_ADDA_RR, temp.RegNum, start.RegNum, indexwork.RegNum); - start.Free(build); start = temp; } + return start; } else { - build->Emit(arraytype->ElementType->GetLoadOp() + 1, // added 1 to use the *_R version that - dest.RegNum, start.RegNum, indexwork.RegNum); // takes the offset from a register + start.Free(build); + ExpEmit dest(build, ValueType->GetRegType()); + // added 1 to use the *_R version that takes the offset from a register + build->Emit(arraytype->ElementType->GetLoadOp() + 1, dest.RegNum, start.RegNum, indexwork.RegNum); + return dest; } - indexwork.Free(build); } - if (AddressRequested) - { - dest.Free(build); - return start; - } - - start.Free(build); - return dest; } //========================================================================== From 022228d8a94e295a16a39051a4ed1b342c6c18ef Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 17 Nov 2016 19:30:30 +0100 Subject: [PATCH 018/185] - fixed code generation of class type cast for local variables. --- src/scripting/codegeneration/codegen.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index f7eadbe90..0c559e850 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -3884,7 +3884,6 @@ int BuiltinTypeCheck(VMFrameStack *stack, VMValue *param, TArray &defau ExpEmit FxTypeCheck::Emit(VMFunctionBuilder *build) { - ExpEmit out(build, REGT_INT); EmitParameter(build, left, ScriptPosition); EmitParameter(build, right, ScriptPosition); @@ -3905,6 +3904,7 @@ ExpEmit FxTypeCheck::Emit(VMFunctionBuilder *build) return call; } + ExpEmit out(build, REGT_INT); build->Emit(OP_RESULT, 0, REGT_INT, out.RegNum); return out; } @@ -3963,11 +3963,13 @@ FxExpression *FxDynamicCast::Resolve(FCompileContext& ctx) ExpEmit FxDynamicCast::Emit(VMFunctionBuilder *build) { - ExpEmit out = expr->Emit(build); + ExpEmit in = expr->Emit(build); + ExpEmit out = in.Fixed ? ExpEmit(build, in.RegType) : in; ExpEmit check(build, REGT_INT); assert(out.RegType == REGT_POINTER); - build->Emit(OP_PARAM, 0, REGT_POINTER, out.RegNum); + if (in.Fixed) build->Emit(OP_MOVEA, out.RegNum, in.RegNum); + build->Emit(OP_PARAM, 0, REGT_POINTER, in.RegNum); build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(CastType, ATAG_OBJECT)); PSymbol *sym = FindBuiltinFunction(NAME_BuiltinTypeCheck, BuiltinTypeCheck); From 3bcd85eb8a08d407ff28be24578b34fec763fd26 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 17 Nov 2016 20:31:53 +0100 Subject: [PATCH 019/185] added class pointer casts. Due to grammar problems the type has to be put into parentheses to get the class token out of the global parsing namespace: class myclass = (class)(GetClass()); --- src/namedef.h | 1 + src/scripting/codegeneration/codegen.cpp | 101 +++++++++++++++++++++++ src/scripting/codegeneration/codegen.h | 20 +++++ src/scripting/zscript/ast.cpp | 11 +++ src/scripting/zscript/zcc-parse.lemon | 8 ++ src/scripting/zscript/zcc_compile.cpp | 18 ++++ src/scripting/zscript/zcc_exprlist.h | 1 + src/scripting/zscript/zcc_parser.h | 7 ++ 8 files changed, 167 insertions(+) diff --git a/src/namedef.h b/src/namedef.h index e9324d44b..01859d01a 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -683,6 +683,7 @@ xx(BuiltinFindMultiNameState) xx(BuiltinFindSingleNameState) xx(BuiltinHandleRuntimeState) xx(BuiltinGetDefault) +xx(BuiltinClassCast) xx(Damage) // basic type names diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 0c559e850..d63db0f8d 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -8382,6 +8382,107 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build) return dest; } +//========================================================================== +// +//========================================================================== + +FxClassPtrCast::FxClassPtrCast(PClass *dtype, FxExpression *x) + : FxExpression(EFX_ClassPtrCast, x->ScriptPosition) +{ + ValueType = NewClassPointer(dtype); + desttype = dtype; + basex = x; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxClassPtrCast::~FxClassPtrCast() +{ + SAFE_DELETE(basex); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxClassPtrCast::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(basex, ctx); + + if (basex->ValueType == TypeNullPtr) + { + basex->ValueType = ValueType; + auto x = basex; + basex = nullptr; + delete this; + return x; + } + auto to = static_cast(ValueType); + if (basex->ValueType->GetClass() == RUNTIME_CLASS(PClassPointer)) + { + auto from = static_cast(basex->ValueType); + // Downcast is always ok. + if (from->ClassRestriction->IsDescendantOf(to->ClassRestriction)) + { + basex->ValueType = to; + auto x = basex; + basex = nullptr; + delete this; + return x; + } + // Upcast needs a runtime check. + else if (to->ClassRestriction->IsDescendantOf(from->ClassRestriction)) + { + return this; + } + } + // Everything else is an error. + ScriptPosition.Message(MSG_ERROR, "Cannot cast %s to %s. The types are incompatible.", basex->ValueType->DescriptiveName(), to->DescriptiveName()); + delete this; + return nullptr; +} + +//========================================================================== +// +// +// +//========================================================================== + +int BuiltinClassCast(VMFrameStack *stack, VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret) +{ + PARAM_PROLOGUE; + PARAM_CLASS(from, DObject); + PARAM_CLASS(to, DObject); + ACTION_RETURN_OBJECT(from->IsDescendantOf(to) ? from : nullptr); +} + +ExpEmit FxClassPtrCast::Emit(VMFunctionBuilder *build) +{ + ExpEmit clsname = basex->Emit(build); + + build->Emit(OP_PARAM, 0, clsname.RegType, clsname.RegNum); + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(desttype, ATAG_OBJECT)); + + VMFunction *callfunc; + PSymbol *sym = FindBuiltinFunction(NAME_BuiltinClassCast, BuiltinClassCast); + + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); + assert(((PSymbolVMFunction *)sym)->Function != nullptr); + callfunc = ((PSymbolVMFunction *)sym)->Function; + clsname.Free(build); + ExpEmit dest(build, REGT_POINTER); + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1); + build->Emit(OP_RESULT, 0, REGT_POINTER, dest.RegNum); + return dest; +} + //========================================================================== // // Symbolic state labels. diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index 84ddfcdd8..0ec3491bb 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -258,6 +258,7 @@ enum EFxType EFX_JumpStatement, EFX_ReturnStatement, EFX_ClassTypeCast, + EFX_ClassPtrCast, EFX_StateByIndex, EFX_RuntimeStateIndex, EFX_MultiNameState, @@ -1668,6 +1669,25 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// +// +//========================================================================== + +class FxClassPtrCast : public FxExpression +{ + PClass *desttype; + FxExpression *basex; + +public: + + FxClassPtrCast(PClass *dtype, FxExpression *x); + ~FxClassPtrCast(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // Only used to resolve the old jump by index feature of DECORATE diff --git a/src/scripting/zscript/ast.cpp b/src/scripting/zscript/ast.cpp index 89cc9487e..d8945ca3b 100644 --- a/src/scripting/zscript/ast.cpp +++ b/src/scripting/zscript/ast.cpp @@ -585,6 +585,16 @@ static void PrintExprFuncCall(FLispString &out, ZCC_TreeNode *node) out.Close(); } +static void PrintExprClassCast(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_ClassCast *enode = (ZCC_ClassCast *)node; + assert(enode->Operation == PEX_ClassCast); + out.Open("expr-class-cast"); + out.AddName(enode->ClassName); + PrintNodes(out, enode->Parameters, false); + out.Close(); +} + static void PrintExprMemberAccess(FLispString &out, ZCC_TreeNode *node) { ZCC_ExprMemberAccess *enode = (ZCC_ExprMemberAccess *)node; @@ -913,6 +923,7 @@ void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FLispString &, ZCC_TreeNode * PrintPropertyStmt, PrintVectorInitializer, PrintDeclFlags, + PrintExprClassCast, }; FString ZCC_PrintAST(ZCC_TreeNode *root) diff --git a/src/scripting/zscript/zcc-parse.lemon b/src/scripting/zscript/zcc-parse.lemon index f152cfdd5..c88cab481 100644 --- a/src/scripting/zscript/zcc-parse.lemon +++ b/src/scripting/zscript/zcc-parse.lemon @@ -1080,6 +1080,14 @@ primary(X) ::= primary(A) LPAREN func_expr_list(B) RPAREN. [DOT] // Function ca expr->Parameters = B; X = expr; } +primary(X) ::= LPAREN CLASS LT IDENTIFIER(A) GT RPAREN LPAREN func_expr_list(B) RPAREN. [DOT] // class type cast +{ + NEW_AST_NODE(ClassCast, expr, A); + expr->Operation = PEX_ClassCast; + expr->ClassName = ENamedName(A.Int); + expr->Parameters = B; + X = expr; +} primary(X) ::= primary(A) LBRACKET expr(B) RBRACKET. [DOT] // Array access { NEW_AST_NODE(ExprBinary, expr, B); diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 596b7d8c4..baf76027b 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2766,6 +2766,24 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) break; } + case AST_ClassCast: + { + auto cc = static_cast(ast); + if (cc->Parameters == nullptr || cc->Parameters->SiblingNext != cc->Parameters) + { + Error(cc, "Class type cast requires exactly one parameter"); + return new FxNop(*ast); // return something so that the compiler can continue. + } + auto cls = PClass::FindClass(cc->ClassName); + if (cls == nullptr) + { + Error(cc, "Unknown class %s", FName(cc->ClassName).GetChars()); + return new FxNop(*ast); // return something so that the compiler can continue. + } + return new FxClassPtrCast(cls, ConvertNode(cc->Parameters)); + } + + case AST_ExprMemberAccess: { auto memaccess = static_cast(ast); diff --git a/src/scripting/zscript/zcc_exprlist.h b/src/scripting/zscript/zcc_exprlist.h index b565c00fb..faf6af6a4 100644 --- a/src/scripting/zscript/zcc_exprlist.h +++ b/src/scripting/zscript/zcc_exprlist.h @@ -8,6 +8,7 @@ xx(ConstValue, TK_Const) xx(FuncCall, '(') xx(ArrayAccess, TK_Array) xx(MemberAccess, '.') +xx(ClassCast, TK_Class) xx(TypeRef, TK_Class) xx(Vector, TK_Vector2) diff --git a/src/scripting/zscript/zcc_parser.h b/src/scripting/zscript/zcc_parser.h index ffff78cb8..070bef449 100644 --- a/src/scripting/zscript/zcc_parser.h +++ b/src/scripting/zscript/zcc_parser.h @@ -102,6 +102,7 @@ enum EZCCTreeNodeType AST_PropertyStmt, AST_VectorValue, AST_DeclFlags, + AST_ClassCast, NUM_AST_NODE_TYPES }; @@ -366,6 +367,12 @@ struct ZCC_ExprFuncCall : ZCC_Expression ZCC_FuncParm *Parameters; }; +struct ZCC_ClassCast : ZCC_Expression +{ + ENamedName ClassName; + ZCC_FuncParm *Parameters; +}; + struct ZCC_ExprMemberAccess : ZCC_Expression { ZCC_Expression *Left; From e4dfb13d25cdbcaa4ba1de3b9e7952aa4261bd5d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 17 Nov 2016 20:41:59 +0100 Subject: [PATCH 020/185] - fixed: OP_LO was missing a read barrier. --- src/scripting/vm/vmexec.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index fcdb2eb8b..6cc0d40cd 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -175,7 +175,7 @@ begin: OP(LO): ASSERTA(a); ASSERTA(B); ASSERTKD(C); GETADDR(PB,KC,X_READ_NIL); - reg.a[a] = *(DObject **)ptr; + reg.a[a] = GC::ReadBarrier(*(DObject **)ptr); reg.atag[a] = ATAG_OBJECT; NEXTOP; OP(LO_R): From 6461f5995b684c0232520538fcb40880a9566ef5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 17 Nov 2016 22:21:08 +0100 Subject: [PATCH 021/185] - fixed: Script defined pointers were not added to the FlatPointers array. --- src/dobjtype.cpp | 105 ++++++++++++++++++++++++++++++++++++++++------- src/dobjtype.h | 7 ++++ 2 files changed, 98 insertions(+), 14 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 1597494d9..609fed8c1 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -419,6 +419,16 @@ void PType::SetDefaultValue(void *base, unsigned offset, TArray { } +//========================================================================== +// +// PType :: SetDefaultValue +// +//========================================================================== + +void PType::SetPointer(void *base, unsigned offset, TArray *stroffs) const +{ +} + //========================================================================== // // PType :: InitializeValue @@ -1550,6 +1560,21 @@ void PPointer::GetTypeIDs(intptr_t &id1, intptr_t &id2) const id2 = 0; } +//========================================================================== +// +// PPointer :: SetDefaultValue +// +//========================================================================== + +void PPointer::SetPointer(void *base, unsigned offset, TArray *special) const +{ + if (PointedType != nullptr && PointedType->IsKindOf(RUNTIME_CLASS(PClass))) + { + // Add to the list of pointers for this class. + special->Push(offset); + } +} + //========================================================================== // // PPointer :: WriteValue @@ -1869,6 +1894,20 @@ void PArray::SetDefaultValue(void *base, unsigned offset, TArray } } +//========================================================================== +// +// PArray :: SetDefaultValue +// +//========================================================================== + +void PArray::SetPointer(void *base, unsigned offset, TArray *special) const +{ + for (unsigned i = 0; i < ElementCount; ++i) + { + ElementType->SetPointer(base, offset + i*ElementSize, special); + } +} + //========================================================================== // // NewArray @@ -2104,6 +2143,23 @@ void PStruct::SetDefaultValue(void *base, unsigned offset, TArray *special) const +{ + for (const PField *field : Fields) + { + if (!(field->Flags & VARF_Native)) + { + field->Type->SetPointer(base, unsigned(offset + field->Offset), special); + } + } +} + //========================================================================== // // PStruct :: WriteValue @@ -3045,14 +3101,9 @@ void PClass::InitializeDefaults() assert(ParentClass != NULL); ParentClass->InitializeSpecials(Defaults); - // and initialize our own special values. - auto it = Symbols.GetIterator(); - PSymbolTable::MapType::Pair *pair; - - while (it.NextPair(pair)) + for (const PField *field : Fields) { - auto field = dyn_cast(pair->Value); - if (field != nullptr && !(field->Flags & VARF_Native)) + if (!(field->Flags & VARF_Native)) { field->Type->SetDefaultValue(Defaults, unsigned(field->Offset), &SpecialInits); } @@ -3270,7 +3321,7 @@ void PClass::BuildFlatPointers () return; } else if (ParentClass == NULL) - { // No parent: FlatPointers is the same as Pointers. + { // No parent (i.e. DObject: FlatPointers is the same as Pointers. if (Pointers == NULL) { // No pointers: Make FlatPointers a harmless non-NULL. FlatPointers = &TheEnd; @@ -3283,7 +3334,19 @@ void PClass::BuildFlatPointers () else { ParentClass->BuildFlatPointers (); - if (Pointers == NULL) + + TArray ScriptPointers; + + // Collect all pointers in scripted fields. These are not part of the Pointers list. + for (auto field : Fields) + { + if (!(field->Flags & VARF_Native)) + { + field->Type->SetPointer(Defaults, unsigned(field->Offset), &ScriptPointers); + } + } + + if (Pointers == nullptr && ScriptPointers.Size() == 0) { // No new pointers: Just use the same FlatPointers as the parent. FlatPointers = ParentClass->FlatPointers; } @@ -3291,20 +3354,34 @@ void PClass::BuildFlatPointers () { // New pointers: Create a new FlatPointers array and add them. int numPointers, numSuperPointers; - // Count pointers defined by this class. - for (numPointers = 0; Pointers[numPointers] != ~(size_t)0; numPointers++) - { } + if (Pointers != nullptr) + { + // Count pointers defined by this class. + for (numPointers = 0; Pointers[numPointers] != ~(size_t)0; numPointers++) + { + } + } + else numPointers = 0; + // Count pointers defined by superclasses. for (numSuperPointers = 0; ParentClass->FlatPointers[numSuperPointers] != ~(size_t)0; numSuperPointers++) { } // Concatenate them into a new array - size_t *flat = new size_t[numPointers + numSuperPointers + 1]; + size_t *flat = new size_t[numPointers + numSuperPointers + ScriptPointers.Size() + 1]; if (numSuperPointers > 0) { memcpy (flat, ParentClass->FlatPointers, sizeof(size_t)*numSuperPointers); } - memcpy (flat + numSuperPointers, Pointers, sizeof(size_t)*(numPointers+1)); + if (numPointers > 0) + { + memcpy(flat + numSuperPointers, Pointers, sizeof(size_t)*numPointers); + } + if (ScriptPointers.Size() > 0) + { + memcpy(flat + numSuperPointers + numPointers, &ScriptPointers[0], sizeof(size_t) * ScriptPointers.Size()); + } + flat[numSuperPointers + numPointers + ScriptPointers.Size()] = ~(size_t)0; FlatPointers = flat; } } diff --git a/src/dobjtype.h b/src/dobjtype.h index 0062c56ab..bf4608c7b 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -252,6 +252,7 @@ public: // initialization when the object is created and destruction when the // object is destroyed. virtual void SetDefaultValue(void *base, unsigned offset, TArray *special=NULL) const; + virtual void SetPointer(void *base, unsigned offset, TArray *ptrofs = NULL) const; // Initialize the value, if needed (e.g. strings) virtual void InitializeValue(void *addr, const void *def) const; @@ -552,6 +553,7 @@ public: virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; + void SetPointer(void *base, unsigned offset, TArray *special = NULL) const override; void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; @@ -569,6 +571,9 @@ public: class PClass *ClassRestriction; + // this is only here to block PPointer's implementation + void SetPointer(void *base, unsigned offset, TArray *special = NULL) const override {} + virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; protected: @@ -626,6 +631,7 @@ public: bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; void SetDefaultValue(void *base, unsigned offset, TArray *special) const override; + void SetPointer(void *base, unsigned offset, TArray *special) const override; protected: PArray(); @@ -679,6 +685,7 @@ public: void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; void SetDefaultValue(void *base, unsigned offset, TArray *specials) const override; + void SetPointer(void *base, unsigned offset, TArray *specials) const override; static void WriteFields(FSerializer &ar, const void *addr, const TArray &fields); bool ReadFields(FSerializer &ar, void *addr) const; From 8650d6806ee348b4382b67cbacf8d696223ac642 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 18 Nov 2016 00:42:04 +0100 Subject: [PATCH 022/185] - script export of player_t. - replaced __alignof with the standard alignof equivalent. --- src/dobjtype.cpp | 22 +++---- src/p_mobj.cpp | 5 +- src/p_user.cpp | 113 ++++++++++++++++++++++++++++++++ src/scripting/thingdef_data.cpp | 2 + 4 files changed, 128 insertions(+), 14 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 609fed8c1..32fd30c67 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -1223,7 +1223,7 @@ IMPLEMENT_CLASS(PString, false, false, false, false) //========================================================================== PString::PString() -: PBasicType(sizeof(FString), __alignof(FString)) +: PBasicType(sizeof(FString), alignof(FString)) { mDescriptiveName = "String"; storeOp = OP_SS; @@ -1323,7 +1323,7 @@ PName::PName() : PInt(sizeof(FName), true, false) { mDescriptiveName = "Name"; - assert(sizeof(FName) == __alignof(FName)); + assert(sizeof(FName) == alignof(FName)); } //========================================================================== @@ -1373,7 +1373,7 @@ PSound::PSound() : PInt(sizeof(FSoundID), true) { mDescriptiveName = "Sound"; - assert(sizeof(FSoundID) == __alignof(FSoundID)); + assert(sizeof(FSoundID) == alignof(FSoundID)); } //========================================================================== @@ -1423,7 +1423,7 @@ PColor::PColor() : PInt(sizeof(PalEntry), true) { mDescriptiveName = "Color"; - assert(sizeof(PalEntry) == __alignof(PalEntry)); + assert(sizeof(PalEntry) == alignof(PalEntry)); } /* PStateLabel *****************************************************************/ @@ -1453,7 +1453,7 @@ IMPLEMENT_CLASS(PStatePointer, false, false, false, false) //========================================================================== PStatePointer::PStatePointer() -: PBasicType(sizeof(FState *), __alignof(FState *)) +: PBasicType(sizeof(FState *), alignof(FState *)) { mDescriptiveName = "State"; storeOp = OP_SP; @@ -1501,7 +1501,7 @@ IMPLEMENT_POINTERS_END //========================================================================== PPointer::PPointer() -: PBasicType(sizeof(void *), __alignof(void *)), PointedType(NULL), IsConst(false) +: PBasicType(sizeof(void *), alignof(void *)), PointedType(NULL), IsConst(false) { mDescriptiveName = "NullPointer"; SetOps(); @@ -1514,7 +1514,7 @@ PPointer::PPointer() //========================================================================== PPointer::PPointer(PType *pointsat, bool isconst) -: PBasicType(sizeof(void *), __alignof(void *)), PointedType(pointsat), IsConst(isconst) +: PBasicType(sizeof(void *), alignof(void *)), PointedType(pointsat), IsConst(isconst) { mDescriptiveName.Format("Pointer<%s%s>", pointsat->DescriptiveName(), isconst? "readonly " : ""); SetOps(); @@ -1948,7 +1948,7 @@ PDynArray::PDynArray() { mDescriptiveName = "DynArray"; Size = sizeof(FArray); - Align = __alignof(FArray); + Align = alignof(FArray); } //========================================================================== @@ -1962,7 +1962,7 @@ PDynArray::PDynArray(PType *etype) { mDescriptiveName.Format("DynArray<%s>", etype->DescriptiveName()); Size = sizeof(FArray); - Align = __alignof(FArray); + Align = alignof(FArray); } //========================================================================== @@ -2032,7 +2032,7 @@ PMap::PMap() { mDescriptiveName = "Map"; Size = sizeof(FMap); - Align = __alignof(FMap); + Align = alignof(FMap); } //========================================================================== @@ -2046,7 +2046,7 @@ PMap::PMap(PType *keytype, PType *valtype) { mDescriptiveName.Format("Map<%s, %s>", keytype->DescriptiveName(), valtype->DescriptiveName()); Size = sizeof(FMap); - Align = __alignof(FMap); + Align = alignof(FMap); } //========================================================================== diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 8029e24c0..59b4c43e9 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -158,12 +158,11 @@ extern FFlagDef ActorFlagDefs[]; void AActor::InitNativeFields() { - PType *TypePlayer = NewPointer(TypeVoid); // placeholder PType *TypeActor = NewPointer(RUNTIME_CLASS(AActor)); PType *TypeActorClass = NewClassPointer(RUNTIME_CLASS(AActor)); PType *TypeInventory = NewPointer(RUNTIME_CLASS(AInventory)); - PStruct *sstruct = NewStruct("Sector", nullptr); - auto TypeSector = NewPointer(sstruct); + PType *TypePlayer = NewPointer(NewStruct("Player", nullptr)); + auto TypeSector = NewPointer(NewStruct("Sector", nullptr)); PType *array5 = NewArray(TypeSInt32, 5); auto meta = RUNTIME_CLASS(AActor); diff --git a/src/p_user.cpp b/src/p_user.cpp index 11fe487b9..00e58e5ef 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -3119,3 +3119,116 @@ bool P_IsPlayerTotallyFrozen(const player_t *player) player->cheats & CF_TOTALLYFROZEN || ((level.flags2 & LEVEL2_FROZEN) && player->timefreezer == 0); } + + +//========================================================================== +// +// sets up the script-side version of players +// Since this is a global variable and the script compiler does +// not allow defining them, it will be fully set up here. +// +//========================================================================== + +void P_InitPlayerForScript() +{ + PStruct *pstruct = NewStruct("Player", nullptr); + pstruct->Size = sizeof(player_t); + pstruct->Align = alignof(player_t); + PArray *parray = NewArray(pstruct, MAXPLAYERS); + pstruct->Size = 0; // make sure it cannot be instantiated in the script. + PField *playerf = new PField("players", pstruct, VARF_Native | VARF_Static, (intptr_t)&players); + GlobalSymbols.AddSymbol(playerf); + + PType *TypeActor = NewPointer(RUNTIME_CLASS(AActor)); + PType *TypePlayerPawn = NewPointer(RUNTIME_CLASS(APlayerPawn)); + PType *TypeWeapon = NewPointer(RUNTIME_CLASS(AWeapon)); + PType *TypeClassActor = NewClassPointer(RUNTIME_CLASS(AActor)); + PType *TypeClassPlayerPawn = NewClassPointer(RUNTIME_CLASS(APlayerPawn)); + PType *TypeClassWeapon = NewClassPointer(RUNTIME_CLASS(AWeapon)); + + //ticcmd_t cmd; + //usercmd_t original_cmd; + //userinfo_t userinfo; // [RH] who is this? + //FWeaponSlots weapons; + pstruct->AddNativeField("mo", TypePlayerPawn, myoffsetof(player_t, mo), VARF_ReadOnly); + pstruct->AddNativeField("playerstate", TypeUInt8, myoffsetof(player_t, playerstate)); + pstruct->AddNativeField("original_oldbuttons", TypeUInt32, myoffsetof(player_t, original_oldbuttons)); + pstruct->AddNativeField("cls", TypeClassPlayerPawn, myoffsetof(player_t, cls), VARF_ReadOnly); + pstruct->AddNativeField("DesiredFOV", TypeFloat32, myoffsetof(player_t, DesiredFOV)); + pstruct->AddNativeField("FOV", TypeFloat32, myoffsetof(player_t, FOV), VARF_ReadOnly); + pstruct->AddNativeField("viewz", TypeFloat64, myoffsetof(player_t, viewz)); + pstruct->AddNativeField("viewheight", TypeFloat64, myoffsetof(player_t, viewheight)); + pstruct->AddNativeField("deltaviewheight", TypeFloat64, myoffsetof(player_t, deltaviewheight)); + pstruct->AddNativeField("bob", TypeFloat64, myoffsetof(player_t, bob)); + pstruct->AddNativeField("vel", TypeVector2, myoffsetof(player_t, Vel)); + pstruct->AddNativeField("centering", TypeBool, myoffsetof(player_t, centering)); + pstruct->AddNativeField("turnticks", TypeUInt8, myoffsetof(player_t, turnticks)); + pstruct->AddNativeField("attackdown", TypeBool, myoffsetof(player_t, attackdown)); + pstruct->AddNativeField("usedown", TypeBool, myoffsetof(player_t, usedown)); + pstruct->AddNativeField("oldbuttons", TypeUInt32, myoffsetof(player_t, oldbuttons)); + pstruct->AddNativeField("health", TypeSInt32, myoffsetof(player_t, health)); + pstruct->AddNativeField("inventorytics", TypeSInt32, myoffsetof(player_t, inventorytics)); + pstruct->AddNativeField("CurrentPlayerClass", TypeUInt8, myoffsetof(player_t, CurrentPlayerClass)); + pstruct->AddNativeField("frags", NewArray(TypeSInt32, MAXPLAYERS), myoffsetof(player_t, frags)); + pstruct->AddNativeField("fragcount", TypeSInt32, myoffsetof(player_t, fragcount)); + pstruct->AddNativeField("lastkilltime", TypeSInt32, myoffsetof(player_t, lastkilltime)); + pstruct->AddNativeField("multicount", TypeUInt8, myoffsetof(player_t, multicount)); + pstruct->AddNativeField("spreecount", TypeUInt8, myoffsetof(player_t, spreecount)); + pstruct->AddNativeField("WeaponState", TypeUInt16, myoffsetof(player_t, WeaponState)); + pstruct->AddNativeField("ReadyWeapon", TypeWeapon, myoffsetof(player_t, ReadyWeapon)); + pstruct->AddNativeField("PendingWeapon", TypeWeapon, myoffsetof(player_t, PendingWeapon)); + pstruct->AddNativeField("psprites", NewPointer(RUNTIME_CLASS(DPSprite)), myoffsetof(player_t, psprites)); + pstruct->AddNativeField("cheats", TypeSInt32, myoffsetof(player_t, cheats)); + pstruct->AddNativeField("timefreezer", TypeSInt32, myoffsetof(player_t, timefreezer)); + pstruct->AddNativeField("refire", TypeSInt16, myoffsetof(player_t, refire)); + pstruct->AddNativeField("inconsistent", TypeSInt16, myoffsetof(player_t, inconsistant)); + pstruct->AddNativeField("waiting", TypeSInt32, myoffsetof(player_t, waiting)); + pstruct->AddNativeField("killcount", TypeSInt32, myoffsetof(player_t, killcount)); + pstruct->AddNativeField("itemcount", TypeSInt32, myoffsetof(player_t, itemcount)); + pstruct->AddNativeField("secretcount", TypeSInt32, myoffsetof(player_t, secretcount)); + pstruct->AddNativeField("damagecount", TypeSInt32, myoffsetof(player_t, damagecount)); + pstruct->AddNativeField("bonuscount", TypeSInt32, myoffsetof(player_t, bonuscount)); + pstruct->AddNativeField("hazardcount", TypeSInt32, myoffsetof(player_t, hazardcount)); + pstruct->AddNativeField("hazardinterval", TypeSInt32, myoffsetof(player_t, hazardinterval)); + pstruct->AddNativeField("hazardtype", TypeName, myoffsetof(player_t, hazardtype)); + pstruct->AddNativeField("poisoncount", TypeSInt32, myoffsetof(player_t, poisoncount)); + pstruct->AddNativeField("poisontype", TypeName, myoffsetof(player_t, poisontype)); + pstruct->AddNativeField("poisonpaintype", TypeName, myoffsetof(player_t, poisonpaintype)); + pstruct->AddNativeField("poisoner", TypeActor, myoffsetof(player_t, poisoner)); + pstruct->AddNativeField("attacker", TypeActor, myoffsetof(player_t, attacker)); + pstruct->AddNativeField("extralight", TypeSInt32, myoffsetof(player_t, extralight)); + pstruct->AddNativeField("fixedcolormap", TypeSInt16, myoffsetof(player_t, fixedcolormap)); + pstruct->AddNativeField("fixedlightlevel", TypeSInt16, myoffsetof(player_t, fixedlightlevel)); + pstruct->AddNativeField("morphtics", TypeSInt32, myoffsetof(player_t, morphTics)); + pstruct->AddNativeField("MorphedPlayerClass", TypeClassPlayerPawn, myoffsetof(player_t, MorphedPlayerClass)); + pstruct->AddNativeField("MorphStyle", TypeSInt32, myoffsetof(player_t, MorphStyle)); + pstruct->AddNativeField("MorphExitFlash", TypeClassActor, myoffsetof(player_t, MorphExitFlash)); + pstruct->AddNativeField("PremorphWeapon", TypeClassWeapon, myoffsetof(player_t, PremorphWeapon)); + pstruct->AddNativeField("chickenPeck", TypeSInt32, myoffsetof(player_t, chickenPeck)); + pstruct->AddNativeField("jumpTics", TypeSInt32, myoffsetof(player_t, jumpTics)); + pstruct->AddNativeField("onground", TypeBool, myoffsetof(player_t, onground)); + pstruct->AddNativeField("respawn_time", TypeSInt32, myoffsetof(player_t, respawn_time)); + pstruct->AddNativeField("camera", TypeActor, myoffsetof(player_t, camera)); + pstruct->AddNativeField("air_finished", TypeSInt32, myoffsetof(player_t, air_finished)); + pstruct->AddNativeField("LastDamageType", TypeName, myoffsetof(player_t, LastDamageType)); + pstruct->AddNativeField("MUSINFOactor", TypeActor, myoffsetof(player_t, MUSINFOactor)); + pstruct->AddNativeField("MUSINFOtics", TypeSInt8, myoffsetof(player_t, MUSINFOtics)); + pstruct->AddNativeField("settings_controller", TypeBool, myoffsetof(player_t, settings_controller)); + pstruct->AddNativeField("crouching", TypeSInt8, myoffsetof(player_t, crouching)); + pstruct->AddNativeField("crouchdir", TypeSInt8, myoffsetof(player_t, crouchdir)); + pstruct->AddNativeField("bot", NewPointer(RUNTIME_CLASS(DBot)), myoffsetof(player_t, Bot)); + pstruct->AddNativeField("BlendR", TypeFloat32, myoffsetof(player_t, BlendR)); + pstruct->AddNativeField("BlendG", TypeFloat32, myoffsetof(player_t, BlendG)); + pstruct->AddNativeField("BlendB", TypeFloat32, myoffsetof(player_t, BlendB)); + pstruct->AddNativeField("BlendA", TypeFloat32, myoffsetof(player_t, BlendA)); + pstruct->AddNativeField("LogText", TypeString, myoffsetof(player_t, LogText)); + pstruct->AddNativeField("MinPitch", TypeFloat64, myoffsetof(player_t, MinPitch)); + pstruct->AddNativeField("MaxPitch", TypeFloat64, myoffsetof(player_t, MaxPitch)); + pstruct->AddNativeField("crouchfactor", TypeFloat64, myoffsetof(player_t, crouchfactor)); + pstruct->AddNativeField("crouchoffset", TypeFloat64, myoffsetof(player_t, crouchoffset)); + pstruct->AddNativeField("crouchviewdelta", TypeFloat64, myoffsetof(player_t, crouchviewdelta)); + pstruct->AddNativeField("ConversationNPC", TypeActor, myoffsetof(player_t, ConversationNPC)); + pstruct->AddNativeField("ConversationPC", TypeActor, myoffsetof(player_t, ConversationPC)); + pstruct->AddNativeField("ConversationNPCAngle", TypeFloat64, myoffsetof(player_t, ConversationNPCAngle)); + pstruct->AddNativeField("ConversationFaceTalker", TypeBool, myoffsetof(player_t, ConversationFaceTalker)); +} \ No newline at end of file diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 8de1aaff8..95dc0bdce 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -641,6 +641,7 @@ static int funccmp(const void * a, const void * b) // //========================================================================== void G_InitLevelLocalsForScript(); +void P_InitPlayerForScript(); void InitThingdef() { @@ -687,6 +688,7 @@ void InitThingdef() sstruct->AddNativeField("soundtarget", TypeActor, myoffsetof(sector_t, SoundTarget)); G_InitLevelLocalsForScript(); + P_InitPlayerForScript(); FAutoSegIterator probe(CRegHead, CRegTail); From a00181c89946d150fdabf08c2f7e3eba0aae86a7 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 18 Nov 2016 11:28:15 +0100 Subject: [PATCH 023/185] - started refactoring binary operators by starting to movw the relevant parts or ResolveLR into the respective Resolve methods. FxAddSub complete. This one-size-fits all function has become too unwieldy with all its special cases and makes improvements harder than necessary. --- src/scripting/codegeneration/codegen.cpp | 72 +++++++++++++++--------- 1 file changed, 45 insertions(+), 27 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index d63db0f8d..515569ae6 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -2377,10 +2377,6 @@ bool FxBinary::ResolveLR(FCompileContext& ctx, bool castnumeric) { switch (Operator) { - case '+': - // later - break; - case '<': case '>': case TK_Geq: @@ -2421,22 +2417,6 @@ bool FxBinary::ResolveLR(FCompileContext& ctx, bool castnumeric) { switch (Operator) { - case '+': - case '-': - // a vector2 can be added to or subtracted from a vector 3 but it needs to be the right operand. - if (left->ValueType == right->ValueType || (left->ValueType == TypeVector3 && right->ValueType == TypeVector2)) - { - ValueType = left->ValueType; - return true; - } - else - { - ScriptPosition.Message(MSG_ERROR, "Incompatible operands for operator %c", Operator); - delete this; - return false; - } - break; - case '/': if (right->IsVector()) { @@ -2592,16 +2572,55 @@ FxAddSub::FxAddSub(int o, FxExpression *l, FxExpression *r) FxExpression *FxAddSub::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); - if (!ResolveLR(ctx, true)) - return nullptr; - if (!IsNumeric() && !IsVector()) + RESOLVE(left, ctx); + RESOLVE(right, ctx); + if (!left || !right) { - ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); delete this; - return nullptr; + return false; } - else if (left->isConstant() && right->isConstant()) + + if (left->IsVector() && right->IsVector()) + { + // a vector2 can be added to or subtracted from a vector 3 but it needs to be the right operand. + if (left->ValueType == right->ValueType || (left->ValueType == TypeVector3 && right->ValueType == TypeVector2)) + { + ValueType = left->ValueType; + } + else + { + ScriptPosition.Message(MSG_ERROR, "Incompatible operands for %s", Operator == '+' ? "addition" : "subtraction"); + delete this; + return nullptr; + } + } + else if (left->IsNumeric() && right->IsNumeric()) + { + // Addition and subtraction of unsigned ints results in an unsigned int. (16 and 8 bit values never get here, they get promoted to regular ints elsewhere already.) + if (left->ValueType == TypeUInt32 && right->ValueType == TypeUInt32) + { + ValueType = TypeUInt32; + } + else if (left->ValueType->GetRegType() == REGT_INT && right->ValueType->GetRegType() == REGT_INT) + { + ValueType = TypeSInt32; // Addition and subtraction forces all integer-derived types to signed int. + } + else + { + ValueType = TypeFloat64; + Promote(ctx); + } + } + else + { + // To check: It may be that this could pass in DECORATE, although setting TypeVoid here would pretty much prevent that. + ScriptPosition.Message(MSG_ERROR, "Incompatible operands for %s", Operator == '+' ? "addition" : "subtraction"); + delete this; + return false; + } + + if (left->isConstant() && right->isConstant()) { if (IsFloat()) { @@ -2631,7 +2650,6 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx) } } - Promote(ctx); return this; } From b6801d526b10236700f59565c54c2a6dc6ca2e96 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 18 Nov 2016 11:53:18 +0100 Subject: [PATCH 024/185] - same as last commit for FxMulDiv and FxPow. - some streamlining of FxAddSub. --- src/scripting/codegeneration/codegen.cpp | 189 ++++++++++++++--------- 1 file changed, 117 insertions(+), 72 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 515569ae6..418fc4a5f 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -2417,39 +2417,6 @@ bool FxBinary::ResolveLR(FCompileContext& ctx, bool castnumeric) { switch (Operator) { - case '/': - if (right->IsVector()) - { - // For division, the vector must be the first operand. - ScriptPosition.Message(MSG_ERROR, "Incompatible operands for division"); - delete this; - return false; - } - case '*': - if (left->IsVector()) - { - right = new FxFloatCast(right); - right = right->Resolve(ctx); - if (right == nullptr) - { - delete this; - return false; - } - ValueType = left->ValueType; - } - else - { - left = new FxFloatCast(left); - left = left->Resolve(ctx); - if (left == nullptr) - { - delete this; - return false; - } - ValueType = right->ValueType; - } - break; - case TK_Eq: case TK_Neq: if (left->ValueType != right->ValueType) @@ -2540,15 +2507,34 @@ bool FxBinary::ResolveLR(FCompileContext& ctx, bool castnumeric) return true; } +//========================================================================== +// +// +// +//========================================================================== + void FxBinary::Promote(FCompileContext &ctx) { - if (left->ValueType->GetRegType() == REGT_FLOAT && right->ValueType->GetRegType() == REGT_INT) + // math operations of unsigned ints results in an unsigned int. (16 and 8 bit values never get here, they get promoted to regular ints elsewhere already.) + if (left->ValueType == TypeUInt32 && right->ValueType == TypeUInt32) { - right = (new FxFloatCast(right))->Resolve(ctx); + ValueType = TypeUInt32; } - else if (left->ValueType->GetRegType() == REGT_INT && right->ValueType->GetRegType() == REGT_FLOAT) + else if (left->IsInteger() && right->IsInteger()) { - left = (new FxFloatCast(left))->Resolve(ctx); + ValueType = TypeSInt32; // Addition and subtraction forces all integer-derived types to signed int. + } + else + { + ValueType = TypeFloat64; + if (left->IsFloat() && right->IsInteger()) + { + right = (new FxFloatCast(right))->Resolve(ctx); + } + else if (left->IsInteger() && right->IsFloat()) + { + left = (new FxFloatCast(left))->Resolve(ctx); + } } } @@ -2590,34 +2576,17 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx) } else { - ScriptPosition.Message(MSG_ERROR, "Incompatible operands for %s", Operator == '+' ? "addition" : "subtraction"); - delete this; - return nullptr; + goto error; } } else if (left->IsNumeric() && right->IsNumeric()) { - // Addition and subtraction of unsigned ints results in an unsigned int. (16 and 8 bit values never get here, they get promoted to regular ints elsewhere already.) - if (left->ValueType == TypeUInt32 && right->ValueType == TypeUInt32) - { - ValueType = TypeUInt32; - } - else if (left->ValueType->GetRegType() == REGT_INT && right->ValueType->GetRegType() == REGT_INT) - { - ValueType = TypeSInt32; // Addition and subtraction forces all integer-derived types to signed int. - } - else - { - ValueType = TypeFloat64; - Promote(ctx); - } + Promote(ctx); } else { // To check: It may be that this could pass in DECORATE, although setting TypeVoid here would pretty much prevent that. - ScriptPosition.Message(MSG_ERROR, "Incompatible operands for %s", Operator == '+' ? "addition" : "subtraction"); - delete this; - return false; + goto error; } if (left->isConstant() && right->isConstant()) @@ -2651,6 +2620,11 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx) } } return this; + +error: + ScriptPosition.Message(MSG_ERROR, "Incompatible operands for %s", Operator == '+' ? "addition" : "subtraction"); + delete this; + return nullptr; } //========================================================================== @@ -2750,16 +2724,70 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); - if (!ResolveLR(ctx, true)) - return nullptr; - - if (!IsNumeric() && !IsVector()) + RESOLVE(left, ctx); + RESOLVE(right, ctx); + if (!left || !right) { - ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); delete this; - return nullptr; + return false; } - else if (left->isConstant() && right->isConstant()) + + if (left->IsVector() || right->IsVector()) + { + switch (Operator) + { + case '/': + // For division, the vector must be the first operand. + if (right->IsVector()) goto error; + + case '*': + if (left->IsVector() && right->IsNumeric()) + { + if (right->IsInteger()) + { + right = new FxFloatCast(right); + right = right->Resolve(ctx); + if (right == nullptr) + { + delete this; + return false; + } + } + ValueType = left->ValueType; + } + else if (right->IsVector() && left->IsNumeric()) + { + if (left->IsInteger()) + { + left = new FxFloatCast(left); + left = left->Resolve(ctx); + if (left == nullptr) + { + delete this; + return false; + } + } + ValueType = right->ValueType; + } + break; + + default: + // Vector modulus is not permitted + goto error; + + } + } + else if (left->IsNumeric() && right->IsNumeric()) + { + Promote(ctx); + } + else + { + // To check: It may be that this could pass in DECORATE, although setting TypeVoid here would pretty much prevent that. + goto error; + } + + if (left->isConstant() && right->isConstant()) { if (IsFloat()) { @@ -2805,8 +2833,13 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx) } } - Promote(ctx); return this; + +error: + ScriptPosition.Message(MSG_ERROR, "Incompatible operands for %s", Operator == '*' ? "multiplication" : Operator == '%' ? "modulus" : "division"); + delete this; + return nullptr; + } @@ -2818,7 +2851,6 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx) ExpEmit FxMulDiv::Emit(VMFunctionBuilder *build) { - // allocate the result first so that the operation does not leave gaps in the register set. ExpEmit op1 = left->Emit(build); ExpEmit op2 = right->Emit(build); @@ -2919,15 +2951,29 @@ FxExpression *FxPow::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); - if (!ResolveLR(ctx, true)) - return nullptr; - - if (!IsNumeric()) + RESOLVE(left, ctx); + RESOLVE(right, ctx); + if (!left || !right) { - ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); + delete this; + return false; + } + if (!left->IsNumeric() || !right->IsNumeric()) + { + ScriptPosition.Message(MSG_ERROR, "Numeric type expected for '**'"); delete this; return nullptr; } + if (!left->IsFloat()) + { + left = (new FxFloatCast(left))->Resolve(ctx); + ABORT(left); + } + if (!right->IsFloat()) + { + right = (new FxFloatCast(right))->Resolve(ctx); + ABORT(right); + } if (left->isConstant() && right->isConstant()) { double v1 = static_cast(left)->GetValue().GetFloat(); @@ -2937,7 +2983,6 @@ FxExpression *FxPow::Resolve(FCompileContext& ctx) return this; } - //========================================================================== // // From d9953eb3bddc2881a40564ad0cd5aeb70b97af0f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 18 Nov 2016 12:23:58 +0100 Subject: [PATCH 025/185] - cleaned up FxCompareRel::Resolve. Also added unsigned integer support to it and FxMulDiv (these, aside from the float cast, are the only two operations where this is important.) --- src/scripting/codegeneration/codegen.cpp | 90 +++++++++++++++++++----- src/scripting/codegeneration/codegen.h | 9 ++- 2 files changed, 80 insertions(+), 19 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 418fc4a5f..c18548bdc 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -2922,9 +2922,18 @@ ExpEmit FxMulDiv::Emit(VMFunctionBuilder *build) { assert(ValueType->GetRegType() == REGT_INT); assert(op1.RegType == REGT_INT && op2.RegType == 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); + if (ValueType == TypeUInt32) + { + build->Emit(Operator == '/' ? (op1.Konst ? OP_DIVU_KR : op2.Konst ? OP_DIVU_RK : OP_DIVU_RR) + : (op1.Konst ? OP_MODU_KR : op2.Konst ? OP_MODU_RK : OP_MODU_RR), + to.RegNum, op1.RegNum, op2.RegNum); + } + else + { + 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; } } @@ -3024,16 +3033,51 @@ FxCompareRel::FxCompareRel(int o, FxExpression *l, FxExpression *r) FxExpression *FxCompareRel::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); - if (!ResolveLR(ctx, true)) - return nullptr; - if (!IsNumeric()) + RESOLVE(left, ctx); + RESOLVE(right, ctx); + if (!left || !right) { - ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); delete this; return nullptr; } - else if (left->isConstant() && right->isConstant()) + + if (left->ValueType == TypeString || right->ValueType == TypeString) + { + if (left->ValueType != TypeString) + { + left = new FxStringCast(left); + left = left->Resolve(ctx); + if (left == nullptr) + { + delete this; + return nullptr; + } + } + if (right->ValueType != TypeString) + { + right = new FxStringCast(right); + right = right->Resolve(ctx); + if (right == nullptr) + { + delete this; + return nullptr; + } + } + ValueType == TypeString; + } + else if (left->IsNumeric() && right->IsNumeric()) + { + Promote(ctx); + } + else + { + ScriptPosition.Message(MSG_ERROR, "Incompatible operands for relative comparison"); + delete this; + return nullptr; + } + + if (left->isConstant() && right->isConstant()) { int v; @@ -3056,20 +3100,29 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx) Operator == TK_Geq? v1 >= v2 : Operator == TK_Leq? v1 <= v2 : 0; } - else + else if (ValueType == TypeUInt32) { - int v1 = static_cast(left)->GetValue().GetInt(); - int v2 = static_cast(right)->GetValue().GetInt(); + int v1 = static_cast(left)->GetValue().GetUInt(); + int v2 = static_cast(right)->GetValue().GetUInt(); v = Operator == '<'? v1 < v2 : Operator == '>'? v1 > v2 : Operator == TK_Geq? v1 >= v2 : Operator == TK_Leq? v1 <= v2 : 0; } + else + { + 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 : + Operator == TK_Leq ? v1 <= v2 : 0; + } FxExpression *e = new FxConstant(v, ScriptPosition); delete this; return e; } - Promote(ctx); + CompareType = ValueType; // needs to be preserved for detection of unsigned compare. ValueType = TypeBool; return this; } @@ -3124,10 +3177,10 @@ ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build) assert(Operator == '<' || Operator == '>' || Operator == TK_Geq || Operator == TK_Leq); static const VM_UBYTE InstrMap[][4] = { - { 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 } // <= + { OP_LT_RR, OP_LTF_RR, OP_LTU_RR, 0 }, // < + { OP_LE_RR, OP_LEF_RR, OP_LEU_RR, 1 }, // > + { OP_LT_RR, OP_LTF_RR, OP_LTU_RR, 1 }, // >= + { OP_LE_RR, OP_LEF_RR, OP_LEU_RR, 0 } // <= }; int instr, check; ExpEmit to(build, REGT_INT); @@ -3135,8 +3188,9 @@ ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build) Operator == '>' ? 1 : Operator == TK_Geq ? 2 : 3; - instr = InstrMap[index][op1.RegType == REGT_INT ? 0 : 1]; - check = InstrMap[index][2]; + int mode = op1.RegType == REGT_FLOAT ? 1 : CompareType == TypeUInt32 ? 2 : 0; + instr = InstrMap[index][mode]; + check = InstrMap[index][3]; if (op2.Konst) { instr += 1; diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index 0ec3491bb..5f7791e3e 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -169,10 +169,16 @@ struct ExpVal return regtype == REGT_INT ? Int : regtype == REGT_FLOAT ? int(Float) : 0; } + unsigned GetUInt() const + { + int regtype = Type->GetRegType(); + return regtype == REGT_INT ? unsigned(Int) : regtype == REGT_FLOAT ? unsigned(Float) : 0; + } + double GetFloat() const { int regtype = Type->GetRegType(); - return regtype == REGT_INT ? double(Int) : regtype == REGT_FLOAT ? Float : 0; + return regtype == REGT_INT ? (Type == TypeUInt32? double(unsigned(Int)) : double(Int)) : regtype == REGT_FLOAT ? Float : 0; } void *GetPointer() const @@ -864,6 +870,7 @@ public: class FxCompareRel : public FxBinary { + PType *CompareType; public: FxCompareRel(int, FxExpression*, FxExpression*); From f71aad4cdde28b4cb487481e103615623b3fb7ca Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 18 Nov 2016 14:19:55 +0100 Subject: [PATCH 026/185] - cleanup of the remaining FxBinary operators. - changed FxCompareEq with strings and other types that can be cast to from a string always convert the string to the other type before comparing. --- src/scripting/codegeneration/codegen.cpp | 473 +++++++++++------------ src/scripting/codegeneration/codegen.h | 22 +- src/scripting/decorate/thingdef_exp.cpp | 20 +- src/scripting/zscript/zcc_compile.cpp | 8 +- 4 files changed, 260 insertions(+), 263 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index c18548bdc..e57303c0a 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -838,7 +838,7 @@ FxExpression *FxIntCast::Resolve(FCompileContext &ctx) { ExpVal constval = static_cast(basex)->GetValue(); FxExpression *x = new FxConstant(constval.GetInt(), ScriptPosition); - if (!NoWarn && constval.GetInt() != constval.GetFloat()) + if (constval.GetInt() != constval.GetFloat()) { ScriptPosition.Message(MSG_WARNING, "Truncation of floating point constant %f", constval.GetFloat()); } @@ -2363,157 +2363,7 @@ FxBinary::~FxBinary() // //========================================================================== -bool FxBinary::ResolveLR(FCompileContext& ctx, bool castnumeric) -{ - RESOLVE(left, ctx); - RESOLVE(right, ctx); - if (!left || !right) - { - delete this; - return false; - } - - if (left->ValueType == TypeString || right->ValueType == TypeString) - { - switch (Operator) - { - case '<': - case '>': - case TK_Geq: - case TK_Leq: - case TK_Eq: - case TK_Neq: - case TK_ApproxEq: - if (left->ValueType != TypeString) - { - left = new FxStringCast(left); - left = left->Resolve(ctx); - if (left == nullptr) - { - delete this; - return false; - } - } - if (right->ValueType != TypeString) - { - right = new FxStringCast(right); - right = right->Resolve(ctx); - if (right == nullptr) - { - delete this; - return false; - } - } - ValueType = TypeBool; - break; - - default: - ScriptPosition.Message(MSG_ERROR, "Incompatible operands for comparison"); - delete this; - return false; - } - } - else if (left->IsVector() || right->IsVector()) - { - switch (Operator) - { - case TK_Eq: - case TK_Neq: - if (left->ValueType != right->ValueType) - { - ScriptPosition.Message(MSG_ERROR, "Incompatible operands for comparison"); - delete this; - return false; - } - ValueType = TypeBool; - break; - - default: - ScriptPosition.Message(MSG_ERROR, "Incompatible operation for vector type"); - delete this; - return false; - - } - } - else if (left->ValueType == TypeBool && right->ValueType == TypeBool) - { - if (Operator == '&' || Operator == '|' || Operator == '^' || ctx.FromDecorate) - { - ValueType = TypeBool; - } - else - { - ValueType = TypeSInt32; // math operations on bools result in integers. - } - } - else if (left->ValueType == TypeName && right->ValueType == TypeName) - { - // pointers can only be compared for equality. - if (Operator == TK_Eq || Operator == TK_Neq) - { - ValueType = TypeBool; - return true; - } - else - { - ScriptPosition.Message(MSG_ERROR, "Invalid operation for names"); - delete this; - return false; - } - } - else if (left->IsNumeric() && right->IsNumeric()) - { - if (left->ValueType->GetRegType() == REGT_INT && right->ValueType->GetRegType() == REGT_INT) - { - ValueType = TypeSInt32; - } - else - { - ValueType = TypeFloat64; - } - } - else if (left->ValueType->GetRegType() == REGT_POINTER) - { - if (left->ValueType == right->ValueType || right->ValueType == TypeNullPtr || left->ValueType == TypeNullPtr || - AreCompatiblePointerTypes(left->ValueType, right->ValueType)) - { - // pointers can only be compared for equality. - if (Operator == TK_Eq || Operator == TK_Neq) - { - ValueType = TypeBool; - return true; - } - else - { - ScriptPosition.Message(MSG_ERROR, "Invalid operation for pointers"); - delete this; - return false; - } - } - } - else - { - // To check: It may be that this could pass in DECORATE, although setting TypeVoid here would pretty much prevent that. - ScriptPosition.Message(MSG_ERROR, "Incompatible operator"); - delete this; - return false; - } - assert(ValueType != nullptr && ValueType < (PType*)0xfffffffffffffff); - - if (castnumeric) - { - // later! - } - return true; -} - -//========================================================================== -// -// -// -//========================================================================== - -void FxBinary::Promote(FCompileContext &ctx) +bool FxBinary::Promote(FCompileContext &ctx, bool forceint) { // math operations of unsigned ints results in an unsigned int. (16 and 8 bit values never get here, they get promoted to regular ints elsewhere already.) if (left->ValueType == TypeUInt32 && right->ValueType == TypeUInt32) @@ -2524,7 +2374,7 @@ void FxBinary::Promote(FCompileContext &ctx) { ValueType = TypeSInt32; // Addition and subtraction forces all integer-derived types to signed int. } - else + else if (!forceint) { ValueType = TypeFloat64; if (left->IsFloat() && right->IsInteger()) @@ -2536,6 +2386,34 @@ void FxBinary::Promote(FCompileContext &ctx) left = (new FxFloatCast(left))->Resolve(ctx); } } + else if (ctx.FromDecorate) + { + // For DECORATE which allows floats here. ZScript does not. + if (left->IsFloat()) + { + left = new FxIntCast(left, ctx.FromDecorate); + left = left->Resolve(ctx); + } + if (right->IsFloat()) + { + right = new FxIntCast(right, ctx.FromDecorate); + right = right->Resolve(ctx); + } + if (left == nullptr || right == nullptr) + { + delete this; + return false; + } + ValueType = TypeSInt32; + + } + else + { + ScriptPosition.Message(MSG_ERROR, "Integer operand expected"); + delete this; + return false; + } + return true; } //========================================================================== @@ -3064,7 +2942,7 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx) return nullptr; } } - ValueType == TypeString; + ValueType = TypeString; } else if (left->IsNumeric() && right->IsNumeric()) { @@ -3238,24 +3116,66 @@ FxExpression *FxCompareEq::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); - if (!ResolveLR(ctx, true)) - return nullptr; - + RESOLVE(left, ctx); + RESOLVE(right, ctx); if (!left || !right) { delete this; return nullptr; } - if (!IsNumeric() && !IsPointer() && !IsVector() && ValueType != TypeName) + if (left->ValueType != right->ValueType) // identical types are always comparable, if they can be placed in a register, so we can save most checks if this is the case. { - ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); - delete this; - return nullptr; + // Special cases: Compare strings and names with names, sounds, colors, state labels and class types. + // These are all types a string can be implicitly cast into, so for convenience, so they should when doing a comparison. + if ((left->ValueType == TypeString || left->ValueType == TypeName) && + (right->ValueType == TypeName || right->ValueType == TypeSound || right->ValueType == TypeColor || right->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) || right->ValueType == TypeStateLabel)) + { + left = new FxTypeCast(left, right->ValueType, false, true); + left = left->Resolve(ctx); + ABORT(left); + ValueType = right->ValueType; + } + else if ((right->ValueType == TypeString || right->ValueType == TypeName) && + (left->ValueType == TypeName || left->ValueType == TypeSound || left->ValueType == TypeColor || left->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) || left->ValueType == TypeStateLabel)) + { + right = new FxTypeCast(right, left->ValueType, false, true); + right = right->Resolve(ctx); + ABORT(right); + ValueType = left->ValueType; + } + else if (left->IsNumeric() && right->IsNumeric()) + { + Promote(ctx); + } + else if (left->ValueType->GetRegType() == REGT_POINTER && right->ValueType->GetRegType() == REGT_POINTER) + { + if (left->ValueType != right->ValueType && right->ValueType != TypeNullPtr && left->ValueType != TypeNullPtr && + !AreCompatiblePointerTypes(left->ValueType, right->ValueType)) + { + goto error; + } + } + else + { + goto error; + } + } + else if (left->ValueType->GetRegType() == REGT_NIL) + { + goto error; + } + else + { + ValueType = left->ValueType; + } + + if (Operator == TK_ApproxEq && ValueType->GetRegType() != REGT_FLOAT && ValueType->GetRegType() != REGT_STRING) + { + // Only floats, vectors and strings have handling for '~==', for all other types this is an error. + goto error; } - if (Operator == TK_ApproxEq && left->ValueType->GetRegType() != REGT_FLOAT && left->ValueType->GetRegType() != REGT_STRING) - Operator = TK_Eq; if (left->isConstant() && right->isConstant()) { int v; @@ -3357,9 +3277,13 @@ FxExpression *FxCompareEq::Resolve(FCompileContext& ctx) } } } - Promote(ctx); ValueType = TypeBool; return this; + +error: + ScriptPosition.Message(MSG_ERROR, "Incompatible operands for %s comparison", Operator == TK_Eq ? "==" : Operator == TK_Neq ? "!=" : "~=="); + delete this; + return nullptr; } //========================================================================== @@ -3435,7 +3359,7 @@ ExpEmit FxCompareEq::Emit(VMFunctionBuilder *build) // //========================================================================== -FxBinaryInt::FxBinaryInt(int o, FxExpression *l, FxExpression *r) +FxBitOp::FxBitOp(int o, FxExpression *l, FxExpression *r) : FxBinary(o, l, r) { ValueType = TypeSInt32; @@ -3447,48 +3371,39 @@ FxBinaryInt::FxBinaryInt(int o, FxExpression *l, FxExpression *r) // //========================================================================== -FxExpression *FxBinaryInt::Resolve(FCompileContext& ctx) +FxExpression *FxBitOp::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); - if (!ResolveLR(ctx, false)) - return nullptr; - if (IsFloat() && ctx.FromDecorate) + RESOLVE(left, ctx); + RESOLVE(right, ctx); + if (!left || !right) { - // For DECORATE which allows floats here. ZScript does not. - if (left->ValueType->GetRegType() != REGT_INT) - { - left = new FxIntCast(left, ctx.FromDecorate); - left = left->Resolve(ctx); - } - if (right->ValueType->GetRegType() != REGT_INT) - { - right = new FxIntCast(right, ctx.FromDecorate); - right = right->Resolve(ctx); - } - if (left == nullptr || right == nullptr) - { - delete this; - return nullptr; - } - ValueType = TypeSInt32; + delete this; + return false; } - if (ValueType->GetRegType() != REGT_INT) + if (left->ValueType == TypeBool && right->ValueType == TypeBool) { - ScriptPosition.Message(MSG_ERROR, "Integer type expected"); + ValueType = TypeBool; + } + else if (left->IsNumeric() && right->IsNumeric()) + { + if (!Promote(ctx, true)) return nullptr; + } + else + { + ScriptPosition.Message(MSG_ERROR, "Incompatible operands for bit operation"); delete this; return nullptr; } - else if (left->isConstant() && right->isConstant()) + + if (left->isConstant() && right->isConstant()) { int v1 = static_cast(left)->GetValue().GetInt(); int v2 = static_cast(right)->GetValue().GetInt(); FxExpression *e = new FxConstant( - 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, ScriptPosition); @@ -3505,7 +3420,98 @@ FxExpression *FxBinaryInt::Resolve(FCompileContext& ctx) // //========================================================================== -ExpEmit FxBinaryInt::Emit(VMFunctionBuilder *build) +ExpEmit FxBitOp::Emit(VMFunctionBuilder *build) +{ + assert(left->ValueType->GetRegType() == REGT_INT); + assert(right->ValueType->GetRegType() == REGT_INT); + int instr, rop; + ExpEmit op1, op2; + + op1 = left->Emit(build); + op2 = right->Emit(build); + if (op1.Konst) + { + swapvalues(op1, op2); + } + assert(!op1.Konst); + rop = op2.RegNum; + op2.Free(build); + op1.Free(build); + + instr = Operator == '&' ? OP_AND_RR : + Operator == '|' ? OP_OR_RR : + Operator == '^' ? OP_XOR_RR : -1; + + assert(instr > 0); + ExpEmit to(build, REGT_INT); + build->Emit(instr + op2.Konst, to.RegNum, op1.RegNum, rop); + return to; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxShift::FxShift(int o, FxExpression *l, FxExpression *r) + : FxBinary(o, l, r) +{ + ValueType = TypeSInt32; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxShift::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + RESOLVE(left, ctx); + RESOLVE(right, ctx); + if (!left || !right) + { + delete this; + return false; + } + + if (left->IsNumeric() && right->IsNumeric()) + { + if (!Promote(ctx, true)) return nullptr; + if (ValueType == TypeUInt32 && Operator == TK_RShift) Operator = TK_URShift; + } + else + { + ScriptPosition.Message(MSG_ERROR, "Incompatible operands for shift operation"); + delete this; + return nullptr; + } + + if (left->isConstant() && right->isConstant()) + { + int v1 = static_cast(left)->GetValue().GetInt(); + int v2 = static_cast(right)->GetValue().GetInt(); + + FxExpression *e = new FxConstant( + Operator == TK_LShift ? v1 << v2 : + Operator == TK_RShift ? v1 >> v2 : + Operator == TK_URShift ? int((unsigned int)(v1) >> v2) : 0, ScriptPosition); + + delete this; + return e; + } + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxShift::Emit(VMFunctionBuilder *build) { assert(left->ValueType->GetRegType() == REGT_INT); assert(right->ValueType->GetRegType() == REGT_INT); @@ -3514,65 +3520,41 @@ ExpEmit FxBinaryInt::Emit(VMFunctionBuilder *build) { 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; index = Operator == TK_LShift ? 0 : Operator == TK_RShift ? 1 : - Operator == TK_URShift ? 2 : - Operator == '&' ? 3 : - Operator == '|' ? 4 : - Operator == '^' ? 5 : -1; + Operator == TK_URShift ? 2 : -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; - } + + // Shift instructions use right-hand immediates instead of constant registers. + if (right->isConstant()) + { + rop = static_cast(right)->GetValue().GetInt(); + op2.Konst = true; } 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; + assert(!op2.Konst); op2.Free(build); + rop = op2.RegNum; } + if (!op1.Konst) { op1.Free(build); - if (!op2.Konst) - { - instr = InstrMap[index][0]; - } - else - { - instr = InstrMap[index][2]; - } + instr = InstrMap[index][op2.Konst? 0:2]; } else { assert(!op2.Konst); instr = InstrMap[index][1]; } - assert(instr != 0); + assert(instr > 0); ExpEmit to(build, REGT_INT); build->Emit(instr, to.RegNum, op1.RegNum, rop); return to; @@ -3599,30 +3581,27 @@ FxLtGtEq::FxLtGtEq(FxExpression *l, FxExpression *r) FxExpression *FxLtGtEq::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); - if (!ResolveLR(ctx, true)) - return nullptr; - if (!left->IsNumeric() || !right->IsNumeric()) + RESOLVE(left, ctx); + RESOLVE(right, ctx); + if (!left || !right) + { + delete this; + return false; + } + + if (left->IsNumeric() && right->IsNumeric()) + { + Promote(ctx); + } + else { ScriptPosition.Message(MSG_ERROR, "<>= expects two numeric operands"); delete this; return nullptr; } - if (left->ValueType->GetRegType() != right->ValueType->GetRegType()) - { - if (left->ValueType->GetRegType() == REGT_INT) - { - left = new FxFloatCast(left); - SAFE_RESOLVE(left, ctx); - } - if (right->ValueType->GetRegType() == REGT_INT) - { - right = new FxFloatCast(left); - SAFE_RESOLVE(left, ctx); - } - } - else if (left->isConstant() && right->isConstant()) + if (left->isConstant() && right->isConstant()) { // let's cut this short and always compare doubles. For integers the result will be exactly the same as with an integer comparison, either signed or unsigned. auto v1 = static_cast(left)->GetValue().GetFloat(); diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index 5f7791e3e..df0634b43 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -813,8 +813,7 @@ public: FxBinary(int, FxExpression*, FxExpression*); ~FxBinary(); - bool ResolveLR(FCompileContext& ctx, bool castnumeric); - void Promote(FCompileContext &ctx); + bool Promote(FCompileContext &ctx, bool forceint = false); }; //========================================================================== @@ -899,11 +898,26 @@ public: // //========================================================================== -class FxBinaryInt : public FxBinary +class FxBitOp : public FxBinary { public: - FxBinaryInt(int, FxExpression*, FxExpression*); + FxBitOp(int, FxExpression*, FxExpression*); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + +//========================================================================== +// +// FxBinary +// +//========================================================================== + +class FxShift : public FxBinary +{ +public: + + FxShift(int, FxExpression*, FxExpression*); FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); }; diff --git a/src/scripting/decorate/thingdef_exp.cpp b/src/scripting/decorate/thingdef_exp.cpp index 2d69be340..e7d217609 100644 --- a/src/scripting/decorate/thingdef_exp.cpp +++ b/src/scripting/decorate/thingdef_exp.cpp @@ -139,27 +139,27 @@ static FxExpression *ParseExpressionM (FScanner &sc, PClassActor *cls) break; case TK_LShiftEq: - exp = new FxBinaryInt(TK_LShift, left, nullptr); + exp = new FxShift(TK_LShift, left, nullptr); break; case TK_RShiftEq: - exp = new FxBinaryInt(TK_RShift, left, nullptr); + exp = new FxShift(TK_RShift, left, nullptr); break; case TK_URShiftEq: - exp = new FxBinaryInt(TK_URShift, left, nullptr); + exp = new FxShift(TK_URShift, left, nullptr); break; case TK_AndEq: - exp = new FxBinaryInt('&', left, nullptr); + exp = new FxBitOp('&', left, nullptr); break; case TK_XorEq: - exp = new FxBinaryInt('^', left, nullptr); + exp = new FxBitOp('^', left, nullptr); break; case TK_OrEq: - exp = new FxBinaryInt('|', left, nullptr); + exp = new FxBitOp('|', left, nullptr); break; default: @@ -207,7 +207,7 @@ static FxExpression *ParseExpressionJ (FScanner &sc, PClassActor *cls) while (sc.CheckToken('|')) { FxExpression *right = ParseExpressionI (sc, cls); - tmp = new FxBinaryInt('|', tmp, right); + tmp = new FxBitOp('|', tmp, right); } return tmp; } @@ -219,7 +219,7 @@ static FxExpression *ParseExpressionI (FScanner &sc, PClassActor *cls) while (sc.CheckToken('^')) { FxExpression *right = ParseExpressionH (sc, cls); - tmp = new FxBinaryInt('^', tmp, right); + tmp = new FxBitOp('^', tmp, right); } return tmp; } @@ -231,7 +231,7 @@ static FxExpression *ParseExpressionH (FScanner &sc, PClassActor *cls) while (sc.CheckToken('&')) { FxExpression *right = ParseExpressionG (sc, cls); - tmp = new FxBinaryInt('&', tmp, right); + tmp = new FxBitOp('&', tmp, right); } return tmp; } @@ -272,7 +272,7 @@ static FxExpression *ParseExpressionE (FScanner &sc, PClassActor *cls) { int token = sc.TokenType; FxExpression *right = ParseExpressionD (sc, cls); - tmp = new FxBinaryInt(token, tmp, right); + tmp = new FxShift(token, tmp, right); } if (!sc.End) sc.UnGet(); return tmp; diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index baf76027b..206e2dd88 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2902,10 +2902,12 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) case PEX_LeftShift: case PEX_RightShift: case PEX_URightShift: + return new FxShift(tok, left, right); + case PEX_BitAnd: case PEX_BitOr: case PEX_BitXor: - return new FxBinaryInt(tok, left, right); + return new FxBitOp(tok, left, right); case PEX_BoolOr: case PEX_BoolAnd: @@ -2937,10 +2939,12 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) case PEX_LshAssign: case PEX_RshAssign: case PEX_URshAssign: + return ModifyAssign(new FxShift(tok, new FxAssignSelf(*ast), right), left); + case PEX_AndAssign: case PEX_OrAssign: case PEX_XorAssign: - return ModifyAssign(new FxBinaryInt(tok, new FxAssignSelf(*ast), right), left); + return ModifyAssign(new FxBitOp(tok, new FxAssignSelf(*ast), right), left); case PEX_LTGTEQ: return new FxLtGtEq(left, right); From 24481781b4a20b40189a9f810ab5487bc8723d0b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 18 Nov 2016 14:50:21 +0100 Subject: [PATCH 027/185] - added missing unsigned casts to the VM. - make the pointer to string cast a bit more useful by using the actual object's type rather than 'Object' which can be a great asset when debugging. - fixed a few bad asserts. --- src/scripting/codegeneration/codegen.cpp | 6 +++--- src/scripting/vm/vm.h | 3 +++ src/scripting/vm/vmdisasm.cpp | 3 +++ src/scripting/vm/vmexec.h | 14 +++++++++++++- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index e57303c0a..c8cf6b740 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -871,7 +871,7 @@ ExpEmit FxIntCast::Emit(VMFunctionBuilder *build) assert(basex->ValueType->GetRegType() == REGT_FLOAT); from.Free(build); ExpEmit to(build, REGT_INT); - build->Emit(OP_CAST, to.RegNum, from.RegNum, CAST_F2I); + build->Emit(OP_CAST, to.RegNum, from.RegNum, ValueType == TypeUInt32? CAST_F2U : CAST_F2I); return to; } @@ -962,7 +962,7 @@ ExpEmit FxFloatCast::Emit(VMFunctionBuilder *build) assert(basex->ValueType->GetRegType() == REGT_INT); from.Free(build); ExpEmit to(build, REGT_FLOAT); - build->Emit(OP_CAST, to.RegNum, from.RegNum, CAST_I2F); + build->Emit(OP_CAST, to.RegNum, from.RegNum, basex->ValueType == TypeUInt32? CAST_U2F : CAST_I2F); return to; } @@ -3554,7 +3554,7 @@ ExpEmit FxShift::Emit(VMFunctionBuilder *build) assert(!op2.Konst); instr = InstrMap[index][1]; } - assert(instr > 0); + assert(instr != 0); ExpEmit to(build, REGT_INT); build->Emit(instr, to.RegNum, op1.RegNum, rop); return to; diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index c9f75f214..4e833cf0b 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -111,7 +111,10 @@ enum { CAST_I2F, CAST_I2S, + CAST_U2F, + CAST_U2S, CAST_F2I, + CAST_F2U, CAST_F2S, CAST_P2S, CAST_S2I, diff --git a/src/scripting/vm/vmdisasm.cpp b/src/scripting/vm/vmdisasm.cpp index 48b6d168b..d39723dea 100644 --- a/src/scripting/vm/vmdisasm.cpp +++ b/src/scripting/vm/vmdisasm.cpp @@ -381,15 +381,18 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction switch (code[i].c) { case CAST_I2F: + case CAST_U2F: mode = MODE_AF | MODE_BI | MODE_CUNUSED; break; case CAST_Co2S: case CAST_So2S: case CAST_N2S: case CAST_I2S: + case CAST_U2S: mode = MODE_AS | MODE_BI | MODE_CUNUSED; break; case CAST_F2I: + case CAST_F2U: mode = MODE_AI | MODE_BF | MODE_CUNUSED; break; case CAST_F2S: diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 6cc0d40cd..673582bda 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -1658,15 +1658,27 @@ static void DoCast(const VMRegisters ®, const VMFrame *f, int a, int b, int c ASSERTF(a); ASSERTD(b); reg.f[a] = reg.d[b]; break; + case CAST_U2F: + ASSERTF(a); ASSERTD(b); + reg.f[a] = unsigned(reg.d[b]); + break; case CAST_I2S: ASSERTS(a); ASSERTD(b); reg.s[a].Format("%d", reg.d[b]); break; + case CAST_U2S: + ASSERTS(a); ASSERTD(b); + reg.s[a].Format("%u", reg.d[b]); + break; case CAST_F2I: ASSERTD(a); ASSERTF(b); reg.d[a] = (int)reg.f[b]; break; + case CAST_F2U: + ASSERTD(a); ASSERTF(b); + reg.d[a] = (int)(unsigned)reg.f[b]; + break; case CAST_F2S: ASSERTS(a); ASSERTD(b); reg.s[a].Format("%.14g", reg.f[b]); @@ -1674,7 +1686,7 @@ static void DoCast(const VMRegisters ®, const VMFrame *f, int a, int b, int c case CAST_P2S: ASSERTS(a); ASSERTA(b); - reg.s[a].Format("%s<%p>", reg.atag[b] == ATAG_OBJECT ? "Object" : "Pointer", reg.a[b]); + reg.s[a].Format("%s<%p>", reg.atag[b] == ATAG_OBJECT ? (reg.a[b] == nullptr? "Object" : ((DObject*)reg.a[b])->GetClass()->TypeName.GetChars() ) : "Pointer", reg.a[b]); break; case CAST_S2I: From 34c949f84b32615f19f14816eb145677de8a9918 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 18 Nov 2016 17:44:25 +0100 Subject: [PATCH 028/185] - implemented the string concatenation operator '..'. This is capable of stringifying all of the common types for output. - gave OP_CONCAT some sane semantics. The way this was defined, by specifying the source operands as a range of registers instead of a pair like everything else made it completely useless for the task at hand. - changed formatting for floats to %.5f which for normal output in a game makes more sense. For special cases there should be a special formatting function for ints and floats that can do more specialized conversions. --- src/scripting/codegeneration/codegen.cpp | 153 +++++++++++++++++++++-- src/scripting/codegeneration/codegen.h | 15 +++ src/scripting/vm/vm.h | 2 + src/scripting/vm/vmdisasm.cpp | 2 + src/scripting/vm/vmexec.h | 23 ++-- src/scripting/vm/vmops.h | 2 +- src/scripting/zscript/zcc_compile.cpp | 2 +- 7 files changed, 175 insertions(+), 24 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index c8cf6b740..a5f6a3bc7 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -2442,7 +2442,7 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx) if (!left || !right) { delete this; - return false; + return nullptr; } if (left->IsVector() && right->IsVector()) @@ -2607,7 +2607,7 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx) if (!left || !right) { delete this; - return false; + return nullptr; } if (left->IsVector() || right->IsVector()) @@ -2628,7 +2628,7 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx) if (right == nullptr) { delete this; - return false; + return nullptr; } } ValueType = left->ValueType; @@ -2642,7 +2642,7 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx) if (left == nullptr) { delete this; - return false; + return nullptr; } } ValueType = right->ValueType; @@ -2843,7 +2843,7 @@ FxExpression *FxPow::Resolve(FCompileContext& ctx) if (!left || !right) { delete this; - return false; + return nullptr; } if (!left->IsNumeric() || !right->IsNumeric()) { @@ -3380,7 +3380,7 @@ FxExpression *FxBitOp::Resolve(FCompileContext& ctx) if (!left || !right) { delete this; - return false; + return nullptr; } if (left->ValueType == TypeBool && right->ValueType == TypeBool) @@ -3474,7 +3474,7 @@ FxExpression *FxShift::Resolve(FCompileContext& ctx) if (!left || !right) { delete this; - return false; + return nullptr; } if (left->IsNumeric() && right->IsNumeric()) @@ -3587,7 +3587,7 @@ FxExpression *FxLtGtEq::Resolve(FCompileContext& ctx) if (!left || !right) { delete this; - return false; + return nullptr; } if (left->IsNumeric() && right->IsNumeric()) @@ -3656,6 +3656,137 @@ ExpEmit FxLtGtEq::Emit(VMFunctionBuilder *build) // //========================================================================== +FxConcat::FxConcat(FxExpression *l, FxExpression *r) + : FxBinary(TK_DotDot, l, r) +{ + ValueType = TypeString; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxConcat::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + + RESOLVE(left, ctx); + RESOLVE(right, ctx); + if (!left || !right) + { + delete this; + return nullptr; + } + + // To concatenate two operands the only requirement is that they are integral types, i.e. can occupy a register + if (left->ValueType->GetRegType() == REGT_NIL || right->ValueType->GetRegType() == REGT_NIL) + { + ScriptPosition.Message(MSG_ERROR, "Invalid operand for string concatenation"); + delete this; + return nullptr; + } + + if (left->isConstant() && right->isConstant() && (left->ValueType == TypeString || left->ValueType == TypeName) && (right->ValueType == TypeString || right->ValueType == TypeName)) + { + // for now this is only types which have a constant string representation. + auto v1 = static_cast(left)->GetValue().GetString(); + auto v2 = static_cast(right)->GetValue().GetString(); + auto e = new FxConstant(v1 + v2, ScriptPosition); + delete this; + return e; + } + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxConcat::Emit(VMFunctionBuilder *build) +{ + ExpEmit op1 = left->Emit(build); + ExpEmit op2 = right->Emit(build); + ExpEmit strng, strng2; + + if (op1.RegType == REGT_STRING && op1.Konst) + { + strng = ExpEmit(build, REGT_STRING); + build->Emit(OP_LKS, strng.RegNum, op1.RegNum); + } + else if (op1.RegType == REGT_STRING) + { + strng = op1; + } + else + { + int cast; + strng = ExpEmit(build, REGT_STRING); + if (op1.Konst) + { + ExpEmit nonconst(build, op1.RegType); + build->Emit(op1.RegType == REGT_INT ? OP_LK : op1.RegType == REGT_FLOAT ? OP_LKF : OP_LKP, nonconst.RegNum, op1.RegNum); + op1 = nonconst; + } + if (op1.RegType == REGT_FLOAT) cast = op1.RegCount == 1 ? CAST_F2S : op1.RegCount == 2 ? CAST_V22S : CAST_V32S; + else if (left->ValueType == TypeUInt32) cast = CAST_U2S; + else if (left->ValueType == TypeName) cast = CAST_N2S; + else if (left->ValueType == TypeSound) cast = CAST_So2S; + else if (left->ValueType == TypeColor) cast = CAST_Co2S; + else if (op1.RegType == REGT_POINTER) cast = CAST_P2S; + else if (op1.RegType == REGT_INT) cast = CAST_I2S; + else assert(false && "Bad type for string concatenation"); + build->Emit(OP_CAST, strng.RegNum, op1.RegNum, cast); + op1.Free(build); + } + + if (op2.RegType == REGT_STRING && op2.Konst) + { + strng2 = ExpEmit(build, REGT_STRING); + build->Emit(OP_LKS, strng2.RegNum, op2.RegNum); + } + else if (op2.RegType == REGT_STRING) + { + strng2 = op2; + } + else + { + int cast; + strng2 = ExpEmit(build, REGT_STRING); + if (op2.Konst) + { + ExpEmit nonconst(build, op2.RegType); + build->Emit(op2.RegType == REGT_INT ? OP_LK : op2.RegType == REGT_FLOAT ? OP_LKF : OP_LKP, nonconst.RegNum, op2.RegNum); + op2 = nonconst; + } + if (op2.RegType == REGT_FLOAT) cast = op2.RegCount == 1 ? CAST_F2S : op2.RegCount == 2 ? CAST_V22S : CAST_V32S; + else if (right->ValueType == TypeUInt32) cast = CAST_U2S; + else if (right->ValueType == TypeName) cast = CAST_N2S; + else if (right->ValueType == TypeSound) cast = CAST_So2S; + else if (right->ValueType == TypeColor) cast = CAST_Co2S; + else if (op2.RegType == REGT_POINTER) cast = CAST_P2S; + else if (op2.RegType == REGT_INT) cast = CAST_I2S; + else assert(false && "Bad type for string concatenation"); + build->Emit(OP_CAST, strng2.RegNum, op2.RegNum, cast); + op2.Free(build); + } + strng.Free(build); + strng2.Free(build); + ExpEmit dest(build, REGT_STRING); + assert(strng.RegType == strng2.RegType && strng.RegType == REGT_STRING); + build->Emit(OP_CONCAT, dest.RegNum, strng.RegNum, strng2.RegNum); + return dest; +} + +//========================================================================== +// +// +// +//========================================================================== + FxBinaryLogical::FxBinaryLogical(int o, FxExpression *l, FxExpression *r) : FxExpression(EFX_BinaryLogical, l->ScriptPosition) { @@ -8854,9 +8985,11 @@ ExpEmit FxLocalVariableDeclaration::Emit(VMFunctionBuilder *build) break; case REGT_POINTER: - build->Emit(OP_LKP, RegNum, build->GetConstantAddress(constval->GetValue().GetPointer(), ATAG_GENERIC)); + { + bool isobject = ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) || (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass))); + build->Emit(OP_LKP, RegNum, build->GetConstantAddress(constval->GetValue().GetPointer(), isobject ? ATAG_OBJECT : ATAG_GENERIC)); break; - + } case REGT_STRING: build->Emit(OP_LKS, RegNum, build->GetConstantString(constval->GetValue().GetString())); } diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index df0634b43..66a0137b1 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -937,6 +937,21 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// +// +//========================================================================== + +class FxConcat : public FxBinary +{ +public: + FxConcat(FxExpression*, FxExpression*); + FxExpression *Resolve(FCompileContext&); + + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxBinaryLogical diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 4e833cf0b..deca91a80 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -125,6 +125,8 @@ enum CAST_S2So, CAST_Co2S, CAST_So2S, + CAST_V22S, + CAST_V32S, }; // Register types for VMParam diff --git a/src/scripting/vm/vmdisasm.cpp b/src/scripting/vm/vmdisasm.cpp index d39723dea..07d6fb8e3 100644 --- a/src/scripting/vm/vmdisasm.cpp +++ b/src/scripting/vm/vmdisasm.cpp @@ -396,6 +396,8 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction mode = MODE_AI | MODE_BF | MODE_CUNUSED; break; case CAST_F2S: + case CAST_V22S: + case CAST_V32S: mode = MODE_AS | MODE_BF | MODE_CUNUSED; break; case CAST_P2S: diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 673582bda..918dc6949 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -704,16 +704,7 @@ begin: 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; - } + reg.s[a] = reg.s[B] + reg.s[C]; NEXTOP; OP(LENS): ASSERTD(a); ASSERTS(B); @@ -1680,8 +1671,16 @@ static void DoCast(const VMRegisters ®, const VMFrame *f, int a, int b, int c reg.d[a] = (int)(unsigned)reg.f[b]; break; case CAST_F2S: - ASSERTS(a); ASSERTD(b); - reg.s[a].Format("%.14g", reg.f[b]); + ASSERTS(a); ASSERTF(b); + reg.s[a].Format("%.5f", reg.f[b]); // keep this small. For more precise conversion there should be a conversion function. + break; + case CAST_V22S: + ASSERTS(a); ASSERTF(b+1); + reg.s[a].Format("(%.5f, %.5f)", reg.f[b], reg.f[b + 1]); + break; + case CAST_V32S: + ASSERTS(a); ASSERTF(b + 2); + reg.s[a].Format("(%.5f, %.5f, %.5f)", reg.f[b], reg.f[b + 1], reg.f[b + 2]); break; case CAST_P2S: diff --git a/src/scripting/vm/vmops.h b/src/scripting/vm/vmops.h index 368f143bd..210ff9c49 100644 --- a/src/scripting/vm/vmops.h +++ b/src/scripting/vm/vmops.h @@ -101,7 +101,7 @@ xx(CATCH, catch, CATCH), // A == 0: continue search on next try xx(BOUND, bound, RII16), // if rA >= BC, throw exception // String instructions. -xx(CONCAT, concat, RSRSRS), // sA = sB.. ... ..sC +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++ diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 206e2dd88..ebe70c340 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2959,8 +2959,8 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) case PEX_Is: return new FxTypeCheck(left, right); - // todo: These do not have representations in DECORATE and no implementation exists yet. case PEX_Concat: + return new FxConcat(left, right); default: I_Error("Binary operator %d not implemented yet", op); From aa32d8970b703904618eb7e267990e61c0ee9f26 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 18 Nov 2016 21:34:06 +0100 Subject: [PATCH 029/185] - scriptified a_hereticmisc.cpp. --- src/g_heretic/a_hereticmisc.cpp | 188 ------------------ src/p_map.cpp | 9 + src/p_mobj.cpp | 7 + wadsrc/static/zscript/actor.txt | 7 +- wadsrc/static/zscript/heretic/hereticmisc.txt | 152 +++++++++++++- 5 files changed, 163 insertions(+), 200 deletions(-) diff --git a/src/g_heretic/a_hereticmisc.cpp b/src/g_heretic/a_hereticmisc.cpp index 17cd4df09..64de3ef84 100644 --- a/src/g_heretic/a_hereticmisc.cpp +++ b/src/g_heretic/a_hereticmisc.cpp @@ -25,191 +25,3 @@ #include "a_hereticweaps.cpp" #include "a_ironlich.cpp" - -static FRandom pr_podpain ("PodPain"); -static FRandom pr_makepod ("MakePod"); -static FRandom pr_teleg ("TeleGlitter"); -static FRandom pr_teleg2 ("TeleGlitter2"); -static FRandom pr_volcano ("VolcanoSet"); -static FRandom pr_blast ("VolcanoBlast"); -static FRandom pr_volcimpact ("VolcBallImpact"); - -//---------------------------------------------------------------------------- -// -// PROC A_PodPain -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_PodPain) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_CLASS_DEF (gootype, AActor) - - int count; - int chance; - AActor *goo; - - chance = pr_podpain (); - if (chance < 128) - { - return 0; - } - for (count = chance > 240 ? 2 : 1; count; count--) - { - goo = Spawn(gootype, self->PosPlusZ(48.), ALLOW_REPLACE); - goo->target = self; - goo->Vel.X = pr_podpain.Random2() / 128.; - goo->Vel.Y = pr_podpain.Random2() / 128.; - goo->Vel.Z = 0.5 + pr_podpain() / 128.; - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_RemovePod -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_RemovePod) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo; - - if ( (mo = self->master) ) - { - if (mo->special1 > 0) - { - mo->special1--; - } - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_MakePod -// -//---------------------------------------------------------------------------- - -#define MAX_GEN_PODS 16 - -DEFINE_ACTION_FUNCTION(AActor, A_MakePod) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_CLASS_DEF(podtype, AActor) - - AActor *mo; - - if (self->special1 == MAX_GEN_PODS) - { // Too many generated pods - return 0; - } - mo = Spawn(podtype, self->PosAtZ(ONFLOORZ), ALLOW_REPLACE); - if (!P_CheckPosition (mo, mo->Pos())) - { // Didn't fit - mo->Destroy (); - return 0; - } - mo->SetState (mo->FindState("Grow")); - mo->Thrust(pr_makepod() * (360. / 256), 4.5); - 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 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_AccTeleGlitter -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_AccTeleGlitter) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (++self->health > 35) - { - self->Vel.Z *= 1.5; - } - return 0; -} - - -//---------------------------------------------------------------------------- -// -// PROC A_VolcanoSet -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_VolcanoSet) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->tics = 105 + (pr_volcano() & 127); - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_VolcanoBlast -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_VolcanoBlast) -{ - PARAM_SELF_PROLOGUE(AActor); - - int i; - int count; - AActor *blast; - - count = 1 + (pr_blast() % 3); - for (i = 0; i < count; i++) - { - blast = Spawn("VolcanoBlast", self->PosPlusZ(44.), ALLOW_REPLACE); - blast->target = self; - blast->Angles.Yaw = pr_blast() * (360 / 256.); - blast->VelFromAngle(1.); - blast->Vel.Z = 2.5 + pr_blast() / 64.; - S_Sound (blast, CHAN_BODY, "world/volcano/shoot", 1, ATTN_NORM); - P_CheckMissileSpawn (blast, self->radius); - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_VolcBallImpact -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_VolcBallImpact) -{ - PARAM_SELF_PROLOGUE(AActor); - - unsigned int i; - AActor *tiny; - - if (self->Z() <= self->floorz) - { - self->flags |= MF_NOGRAVITY; - self->Gravity = 1; - self->AddZ(28); - //self->Vel.Z = 3; - } - P_RadiusAttack (self, self->target, 25, 25, NAME_Fire, RADF_HURTSOURCE); - for (i = 0; i < 4; i++) - { - tiny = Spawn("VolcanoTBlast", self->Pos(), ALLOW_REPLACE); - tiny->target = self; - tiny->Angles.Yaw = 90.*i; - tiny->VelFromAngle(0.7); - tiny->Vel.Z = 1. + pr_volcimpact() / 128.; - P_CheckMissileSpawn (tiny, self->radius); - } - return 0; -} - diff --git a/src/p_map.cpp b/src/p_map.cpp index 3f0edc8d7..26dc3d473 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -1738,6 +1738,15 @@ bool P_CheckPosition(AActor *thing, const DVector2 &pos, bool actorsonly) return P_CheckPosition(thing, pos, tm, actorsonly); } +DEFINE_ACTION_FUNCTION(AActor, CheckPosition) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_BOOL_DEF(actorsonly); + ACTION_RETURN_BOOL(P_CheckPosition(self, DVector2(x, y), actorsonly)); +} + //---------------------------------------------------------------------------- // // FUNC P_TestMobjLocation diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 59b4c43e9..c998bcf91 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -6022,6 +6022,13 @@ bool P_CheckMissileSpawn (AActor* th, double maxdist) return true; } +DEFINE_ACTION_FUNCTION(AActor, CheckMissileSpawn) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(add); + ACTION_RETURN_BOOL(P_CheckMissileSpawn(self, add)); +} + //--------------------------------------------------------------------------- // diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 043ab3ed4..137fedbec 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -1,7 +1,10 @@ class Actor : Thinker native { const DEFAULT_HEALTH = 1000; - + const ONFLOORZ = -2147483648.0; + const ONCEILINGZ = 2147483647.0; + const FLOATRANDZ = ONCEILINGZ-1; + Default { Scale 1; @@ -76,6 +79,8 @@ class Actor : Thinker native native Actor GetPointer(int aaptr); native void FaceMovementDirection(); native Actor AimTarget(); + native bool CheckMissileSpawn(double maxdist); + native bool CheckPosition(Vector2 pos, bool actorsonly = false); native static Actor Spawn(class type, vector3 pos = (0,0,0), int replace = NO_REPLACE); native Actor SpawnMissile(Actor dest, class type, Actor owner = null); native Actor SpawnMissileZ (double z, Actor dest, class type); diff --git a/wadsrc/static/zscript/heretic/hereticmisc.txt b/wadsrc/static/zscript/heretic/hereticmisc.txt index f858a6fa2..4cb094d06 100644 --- a/wadsrc/static/zscript/heretic/hereticmisc.txt +++ b/wadsrc/static/zscript/heretic/hereticmisc.txt @@ -16,9 +16,7 @@ class Pod : Actor DeathSound "world/podexplode"; PushFactor 0.5; } - native void A_PodPain (class podtype = "PodGoo"); - native void A_RemovePod (); - + States { Spawn: @@ -37,6 +35,44 @@ class Pod : Actor PPOD IJKLMNOP 3; Goto Spawn; } + + //---------------------------------------------------------------------------- + // + // PROC A_PodPain + // + //---------------------------------------------------------------------------- + + void A_PodPain (class gootype = "PodGoo") + { + int chance = Random[PodPain](); + if (chance < 128) + { + return; + } + for (int count = chance > 240 ? 2 : 1; count; count--) + { + Actor goo = Spawn(gootype, pos + (0, 0, 48), ALLOW_REPLACE); + goo.target = self; + goo.Vel.X = Random2[PodPain]() / 128.; + goo.Vel.Y = Random2[PodPain]() / 128.; + goo.Vel.Z = 0.5 + random[PodPain]() / 128.; + } + } + + //---------------------------------------------------------------------------- + // + // PROC A_RemovePod + // + //---------------------------------------------------------------------------- + + void A_RemovePod () + { + if (master && master.special1 > 0) + { + master.special1--; + } + } + } @@ -75,7 +111,6 @@ class PodGenerator : Actor AttackSound "world/podgrow"; } - native void A_MakePod (class podtype = "Pod"); States { @@ -83,6 +118,34 @@ class PodGenerator : Actor TNT1 A 35 A_MakePod; Loop; } + + //---------------------------------------------------------------------------- + // + // PROC A_MakePod + // + //---------------------------------------------------------------------------- + + const MAX_GEN_PODS = 16; + + void A_MakePod (class podtype = "Pod") + { + if (special1 >= MAX_GEN_PODS) + { // Too many generated pods + return; + } + Actor mo = Spawn(podtype, (pos.xy, ONFLOORZ), ALLOW_REPLACE); + if (!mo) return; + if (!mo.CheckPosition (mo.Pos.xy)) + { // Didn't fit + mo.Destroy (); + return; + } + mo.SetStateLabel("Grow"); + mo.Thrust(4.5, random[MakePod]() * (360. / 256)); + A_PlaySound (AttackSound, CHAN_BODY); + special1++; // Increment generated pod count + mo.master = self; // Link the generator to the pod + } } @@ -136,7 +199,6 @@ class TeleGlitter1 : Actor Damage 0; } - native void A_AccTeleGlitter (); States { @@ -148,6 +210,20 @@ class TeleGlitter1 : Actor TGLT E 2 BRIGHT; Loop; } + + //---------------------------------------------------------------------------- + // + // PROC A_AccTeleGlitter + // + //---------------------------------------------------------------------------- + + void A_AccTeleGlitter () + { + if (++health > 35) + { + Vel.Z *= 1.5; + } + } } // Teleglitter 2 ------------------------------------------------------------ @@ -178,9 +254,6 @@ class Volcano : Actor +SOLID } - native void A_VolcanoSet (); - native void A_VolcanoBlast (); - States { Spawn: @@ -190,7 +263,38 @@ class Volcano : Actor VLCO E 10 A_VolcanoBlast; Goto Spawn+1; } + + //---------------------------------------------------------------------------- + // + // PROC A_VolcanoSet + // + //---------------------------------------------------------------------------- + void A_VolcanoSet () + { + tics = 105 + (random[VolcanoSet]() & 127); + } + + //---------------------------------------------------------------------------- + // + // PROC A_VolcanoBlast + // + //---------------------------------------------------------------------------- + + void A_VolcanoBlast () + { + int count = random[VolcanoBlast](1,3); + for (int i = 0; i < count; i++) + { + Actor blast = Spawn("VolcanoBlast", pos + (0, 0, 44), ALLOW_REPLACE); + blast.target = self; + blast.Angle = random[VolcanoBlast]() * (360 / 256.); + blast.VelFromAngle(1.); + blast.Vel.Z = 2.5 + random[VolcanoBlast]() / 64.; + blast.A_PlaySound ("world/volcano/shoot", CHAN_BODY); + blast.CheckMissileSpawn (radius); + } + } } // Volcano blast ------------------------------------------------------------ @@ -210,8 +314,6 @@ class VolcanoBlast : Actor DeathSound "world/volcano/blast"; } - native void A_VolcBallImpact (); - States { Spawn: @@ -224,6 +326,35 @@ class VolcanoBlast : Actor XPL1 BCDEF 4 BRIGHT; Stop; } + + //---------------------------------------------------------------------------- + // + // PROC A_VolcBallImpact + // + //---------------------------------------------------------------------------- + + void A_VolcBallImpact () + { + if (pos.Z <= floorz) + { + bNoGravity = true; + Gravity = 1; + AddZ(28); + } + A_Explode(25, 25, XF_NOSPLASH|XF_HURTSOURCE, false, 0, 0, 0, "BulletPuff", 'Fire'); + for (int i = 0; i < 4; i++) + { + Actor tiny = Spawn("VolcanoTBlast", Pos, ALLOW_REPLACE); + if (tiny) + { + tiny.target = self; + tiny.Angle = 90.*i; + tiny.VelFromAngle(0.7); + tiny.Vel.Z = 1. + random[VolcBallImpact]() / 128.; + tiny.CheckMissileSpawn (radius); + } + } + } } // Volcano T Blast ---------------------------------------------------------- @@ -252,4 +383,3 @@ class VolcanoTBlast : Actor } } - From 7ff506961761773026cbb4f683029f54c8d5494e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 18 Nov 2016 22:12:53 +0100 Subject: [PATCH 030/185] - added all missing things to enable the scriptified version of A_BrainSpit. This uses a global function, this has been placed into DObject for now because the scripting interface does not allow non-class-owned functions yet. --- src/CMakeLists.txt | 1 - src/g_doom/a_bossbrain.cpp | 80 ------------------------ src/g_doom/a_doommisc.cpp | 1 - src/g_shared/a_specialspot.cpp | 15 ++++- src/g_skill.cpp | 14 +++++ wadsrc/static/zscript/base.txt | 9 +++ wadsrc/static/zscript/constants.txt | 28 +++++++++ wadsrc/static/zscript/doom/bossbrain.txt | 9 +-- 8 files changed, 68 insertions(+), 89 deletions(-) delete mode 100644 src/g_doom/a_bossbrain.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c5f307d56..b7f2eb3b2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -866,7 +866,6 @@ set( NOT_COMPILED_SOURCE_FILES ${OTHER_SYSTEM_SOURCES} sc_man_scanner.h sc_man_scanner.re - g_doom/a_bossbrain.cpp g_doom/a_doomweaps.cpp g_doom/a_painelemental.cpp g_doom/a_scriptedmarine.cpp diff --git a/src/g_doom/a_bossbrain.cpp b/src/g_doom/a_bossbrain.cpp deleted file mode 100644 index 8adb5c1df..000000000 --- a/src/g_doom/a_bossbrain.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* -#include "actor.h" -#include "info.h" -#include "m_random.h" -#include "p_local.h" -#include "p_enemy.h" -#include "s_sound.h" -#include "statnums.h" -#include "a_specialspot.h" -#include "vm.h" -#include "doomstat.h" -#include "g_level.h" -*/ - -static FRandom pr_spawnfly ("SpawnFly"); - -DEFINE_ACTION_FUNCTION(AActor, A_BrainSpit) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_CLASS_DEF(spawntype, AActor); - - DSpotState *state = DSpotState::GetSpotState(); - AActor *targ; - AActor *spit; - bool isdefault = false; - - // shoot a cube at current target - targ = state->GetNextInList(PClass::FindActor("BossTarget"), G_SkillProperty(SKILLP_EasyBossBrain)); - - if (targ != NULL) - { - if (spawntype == NULL) - { - spawntype = PClass::FindActor("SpawnShot"); - isdefault = true; - } - - // spawn brain missile - spit = P_SpawnMissile (self, targ, spawntype); - - if (spit != NULL) - { - // Boss cubes should move freely to their destination so it's - // probably best to disable all collision detection for them. - if (spit->flags & MF_NOCLIP) spit->flags5 |= MF5_NOINTERACTION; - - spit->target = targ; - spit->master = self; - // [RH] Do this correctly for any trajectory. Doom would divide by 0 - // if the target had the same y coordinate as the spitter. - if (spit->Vel.X == 0 && spit->Vel.Y == 0) - { - spit->special2 = 0; - } - else if (fabs(spit->Vel.Y) > fabs(spit->Vel.X)) - { - spit->special2 = int((targ->Y() - self->Y()) / spit->Vel.Y); - } - else - { - spit->special2 = int((targ->X() - self->X()) / spit->Vel.X); - } - // [GZ] Calculates when the projectile will have reached destination - spit->special2 += level.maptime; - spit->flags6 |= MF6_BOSSCUBE; - } - - if (!isdefault) - { - S_Sound(self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NONE); - } - else - { - // compatibility fallback - S_Sound (self, CHAN_WEAPON, "brain/spit", 1, ATTN_NONE); - } - } - return 0; -} - diff --git a/src/g_doom/a_doommisc.cpp b/src/g_doom/a_doommisc.cpp index 30fd6c671..467297761 100644 --- a/src/g_doom/a_doommisc.cpp +++ b/src/g_doom/a_doommisc.cpp @@ -20,7 +20,6 @@ #include "g_shared/a_pickups.h" // Include all the other Doom stuff here to reduce compile time -#include "a_bossbrain.cpp" #include "a_doomweaps.cpp" #include "a_painelemental.cpp" #include "a_scriptedmarine.cpp" diff --git a/src/g_shared/a_specialspot.cpp b/src/g_shared/a_specialspot.cpp index c094ee8ba..e96f5a903 100644 --- a/src/g_shared/a_specialspot.cpp +++ b/src/g_shared/a_specialspot.cpp @@ -251,6 +251,12 @@ DSpotState *DSpotState::GetSpotState(bool create) return SpotState; } +DEFINE_ACTION_FUNCTION(DSpotState, GetSpotState) +{ + PARAM_PROLOGUE; + ACTION_RETURN_OBJECT(DSpotState::GetSpotState()); +} + //---------------------------------------------------------------------------- // // @@ -317,6 +323,14 @@ ASpecialSpot *DSpotState::GetNextInList(PClassActor *type, int skipcounter) return NULL; } +DEFINE_ACTION_FUNCTION(DSpotState, GetNextInList) +{ + PARAM_SELF_PROLOGUE(DSpotState); + PARAM_CLASS(type, AActor); + PARAM_INT(skipcounter); + ACTION_RETURN_OBJECT(self->GetNextInList(type, skipcounter)); +} + //---------------------------------------------------------------------------- // // @@ -371,7 +385,6 @@ void ASpecialSpot::Destroy() // Mace spawn spot ---------------------------------------------------------- - // Every mace spawn spot will execute this action. The first one // will build a list of all mace spots in the level and spawn a // mace. The rest of the spots will do nothing. diff --git a/src/g_skill.cpp b/src/g_skill.cpp index 44c2cef8c..70daadc23 100644 --- a/src/g_skill.cpp +++ b/src/g_skill.cpp @@ -388,6 +388,13 @@ int G_SkillProperty(ESkillProperty prop) return 0; } +DEFINE_ACTION_FUNCTION(DObject, G_SkillPropertyInt) +{ + PARAM_PROLOGUE; + PARAM_INT(which); + ACTION_RETURN_INT(G_SkillProperty((ESkillProperty)which)); +} + //========================================================================== // // @@ -433,6 +440,13 @@ double G_SkillProperty(EFSkillProperty prop) return 0; } +DEFINE_ACTION_FUNCTION(DObject, G_SkillPropertyFloat) +{ + PARAM_PROLOGUE; + PARAM_INT(which); + ACTION_RETURN_FLOAT(G_SkillProperty((EFSkillProperty)which)); +} + //========================================================================== diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 6cf2835e8..1089476a1 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -1,5 +1,9 @@ class Object native { + // These really should be global functions... + native static int G_SkillPropertyInt(int p); + native static double G_SkillPropertyFloat(int p); + virtual native void Destroy(); native class GetClass(); } @@ -37,3 +41,8 @@ class DropItem : Object native */ } +class SpotState : Object native +{ + native static SpotState GetSpotState(); + native SpecialSpot GetNextInList(class type, int skipcounter); +} \ No newline at end of file diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index 3f7a26461..08eee789e 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -917,3 +917,31 @@ enum EMapThingFlags MTF_SECRET = 0x080000, // Secret pickup MTF_NOINFIGHTING = 0x100000, }; + +enum ESkillProperty +{ + SKILLP_FastMonsters, + SKILLP_Respawn, + SKILLP_RespawnLimit, + SKILLP_DisableCheats, + SKILLP_AutoUseHealth, + SKILLP_SpawnFilter, + SKILLP_EasyBossBrain, + SKILLP_ACSReturn, + SKILLP_NoPain, + SKILLP_EasyKey, + SKILLP_SlowMonsters, + SKILLP_Infight, +}; +enum EFSkillProperty // floating point properties +{ + SKILLP_AmmoFactor, + SKILLP_DropAmmoFactor, + SKILLP_ArmorFactor, + SKILLP_HealthFactor, + SKILLP_DamageFactor, + SKILLP_Aggressiveness, + SKILLP_MonsterHealth, + SKILLP_FriendlyHealth, +}; + diff --git a/wadsrc/static/zscript/doom/bossbrain.txt b/wadsrc/static/zscript/doom/bossbrain.txt index 6a72de2bf..9a2ad759c 100644 --- a/wadsrc/static/zscript/doom/bossbrain.txt +++ b/wadsrc/static/zscript/doom/bossbrain.txt @@ -212,9 +212,7 @@ extend class Actor Exit_Normal(0); } - native - void A_BrainSpit(class spawntype = null) // needs special treatment for default - ;/* + void A_BrainSpit(class spawntype = null) { SpotState spstate = SpotState.GetSpotState(); Actor targ; @@ -222,7 +220,7 @@ extend class Actor bool isdefault = false; // shoot a cube at current target - targ = spstate.GetNextInList("BossTarget", G_SkillProperty(SKILLP_EasyBossBrain)); + targ = spstate.GetNextInList("BossTarget", G_SkillPropertyInt(SKILLP_EasyBossBrain)); if (targ) { @@ -249,7 +247,7 @@ extend class Actor { spit.special2 = 0; } - else if (abs(spit.Vel.y) > fabs(spit.Vel.x)) + else if (abs(spit.Vel.y) > abs(spit.Vel.x)) { spit.special2 = int((targ.pos.y - pos.y) / spit.Vel.y); } @@ -273,7 +271,6 @@ extend class Actor } } } - */ private void SpawnFly(class spawntype, sound snd) { From 3ce699bf9b465dc222a81e1dcdd8d80bca7368e4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 19 Nov 2016 01:23:56 +0100 Subject: [PATCH 031/185] - implemented pass-by-reference arguments - so far only for memory based variables. - changed Dehacked weapon function lookup to check the symbol table instead of directly referencing the VM functions. Once scriptified these pointers will no longer be available. - removed all special ATAGs from the VM. While well intentioned any pointer tagged with them is basically unusable because it'd trigger asserts all over the place. - scriptified A_Punch for testing pass-by-reference parameters and stack variables. --- src/d_dehacked.cpp | 44 ++++++------ src/d_player.h | 9 ++- src/dobjtype.h | 1 + src/g_doom/a_doomweaps.cpp | 42 ------------ src/g_shared/a_pickups.h | 1 + src/g_shared/a_weapons.cpp | 34 ++++++++- src/namedef.h | 12 ++++ src/p_mobj.cpp | 8 +++ src/scripting/codegeneration/codegen.cpp | 30 ++++++-- src/scripting/thingdef.cpp | 2 +- src/scripting/thingdef_data.cpp | 8 ++- src/scripting/vm/vm.h | 4 +- src/scripting/vm/vmexec.h | 10 +-- src/scripting/zscript/zcc_compile.cpp | 1 + wadsrc/static/zscript.txt | 1 + wadsrc/static/zscript/actor.txt | 2 +- wadsrc/static/zscript/constants.txt | 2 +- wadsrc/static/zscript/doom/doomweapons.txt | 38 ---------- wadsrc/static/zscript/doom/weaponfist.txt | 80 ++++++++++++++++++++++ wadsrc/static/zscript/shared/inventory.txt | 2 + 20 files changed, 205 insertions(+), 126 deletions(-) create mode 100644 wadsrc/static/zscript/doom/weaponfist.txt diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 8d3a13580..7f546b1ee 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -166,36 +166,27 @@ static TArray MBFCodePointers; struct AmmoPerAttack { - VMNativeFunction **func; + ENamedName func; int ammocount; + VMFunction *ptr; }; DECLARE_ACTION(A_Punch) -DECLARE_ACTION(A_FirePistol) -DECLARE_ACTION(A_FireShotgun) -DECLARE_ACTION(A_FireShotgun2) -DECLARE_ACTION(A_FireCGun) -DECLARE_ACTION(A_FireMissile) -DECLARE_ACTION(A_Saw) -DECLARE_ACTION(A_FirePlasma) -DECLARE_ACTION(A_FireBFG) -DECLARE_ACTION(A_FireOldBFG) -DECLARE_ACTION(A_FireRailgun) // Default ammo use of the various weapon attacks static AmmoPerAttack AmmoPerAttacks[] = { - { &AActor_A_Punch_VMPtr, 0}, - { &AActor_A_FirePistol_VMPtr, 1}, - { &AActor_A_FireShotgun_VMPtr, 1}, - { &AActor_A_FireShotgun2_VMPtr, 2}, - { &AActor_A_FireCGun_VMPtr, 1}, - { &AActor_A_FireMissile_VMPtr, 1}, - { &AActor_A_Saw_VMPtr, 0}, - { &AActor_A_FirePlasma_VMPtr, 1}, - { &AActor_A_FireBFG_VMPtr, -1}, // uses deh.BFGCells - { &AActor_A_FireOldBFG_VMPtr, 1}, - { &AActor_A_FireRailgun_VMPtr, 1}, - { NULL, 0} + { NAME_A_Punch, 0}, + { NAME_A_FirePistol, 1}, + { NAME_A_FireShotgun, 1}, + { NAME_A_FireShotgun2, 2}, + { NAME_A_FireCGun, 1}, + { NAME_A_FireMissile, 1}, + { NAME_A_Saw, 0}, + { NAME_A_FirePlasma, 1}, + { NAME_A_FireBFG, -1}, // uses deh.BFGCells + { NAME_A_FireOldBFG, 1}, + { NAME_A_FireRailgun, 1}, + { NAME_None, 0} }; @@ -3095,7 +3086,12 @@ void FinishDehPatch () StateVisited[state] = true; for(unsigned j = 0; AmmoPerAttacks[j].func != NULL; j++) { - if (state->ActionFunc == *AmmoPerAttacks[j].func) + if (AmmoPerAttacks[i].ptr == nullptr) + { + auto p = dyn_cast(RUNTIME_CLASS(AStateProvider)->Symbols.FindSymbol(AmmoPerAttacks[i].func, true)); + if (p != nullptr) AmmoPerAttacks[i].ptr = p->Variants[0].Implementation; + } + if (state->ActionFunc == AmmoPerAttacks[j].ptr) { found = true; int use = AmmoPerAttacks[j].ammocount; diff --git a/src/d_player.h b/src/d_player.h index 7f57837c7..20a78c932 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -253,11 +253,10 @@ enum WF_USER4OK = 1 << 11, }; -#define WPIECE1 1 -#define WPIECE2 2 -#define WPIECE3 4 - -#define WP_NOCHANGE ((AWeapon*)~0) +// The VM cannot deal with this as an invalid pointer because it performs a read barrier on every object pointer read. +// This doesn't have to point to a valid weapon, though, because WP_NOCHANGE is never dereferenced, but it must point to a valid object +// and the class descriptor just works fine for that. +#define WP_NOCHANGE ((AWeapon*)RUNTIME_CLASS_CASTLESS(AWeapon)) #define MAXPLAYERNAME 15 diff --git a/src/dobjtype.h b/src/dobjtype.h index bf4608c7b..bd6483258 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -32,6 +32,7 @@ enum VARF_Static = (1<<13), // static class data (by necessity read only.) VARF_InternalAccess = (1<<14), // overrides VARF_ReadOnly for internal script code. VARF_Override = (1<<15), // overrides a virtual function from the parent class. + VARF_Ref = (1<<16), // argument is passed by reference. }; // Symbol information ------------------------------------------------------- diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp index 108a730c4..95ae4dfb6 100644 --- a/src/g_doom/a_doomweaps.cpp +++ b/src/g_doom/a_doomweaps.cpp @@ -15,7 +15,6 @@ #include "doomstat.h" */ -static FRandom pr_punch ("Punch"); static FRandom pr_saw ("Saw"); static FRandom pr_fireshotgun2 ("FireSG2"); static FRandom pr_fireplasma ("FirePlasma"); @@ -23,47 +22,6 @@ static FRandom pr_firerail ("FireRail"); static FRandom pr_bfgspray ("BFGSpray"); static FRandom pr_oldbfg ("OldBFG"); -// -// A_Punch -// -DEFINE_ACTION_FUNCTION(AActor, A_Punch) -{ - PARAM_ACTION_PROLOGUE(AActor); - - DAngle angle; - int damage; - DAngle pitch; - FTranslatedLineTarget t; - - if (self->player != NULL) - { - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL && !(weapon->WeaponFlags & WIF_DEHAMMO) && ACTION_CALL_FROM_PSPRITE()) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - } - - damage = (pr_punch()%10+1)<<1; - - if (self->FindInventory()) - damage *= 10; - - angle = self->Angles.Yaw + pr_punch.Random2() * (5.625 / 256); - pitch = P_AimLineAttack (self, angle, MELEERANGE); - - P_LineAttack (self, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff, LAF_ISMELEEATTACK, &t); - - // turn to face target - if (t.linetarget) - { - S_Sound (self, CHAN_WEAPON, "*fist", 1, ATTN_NORM); - self->Angles.Yaw = t.angleFromSource; - } - return 0; -} - // // A_FirePistol // diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index 6dc2d0bc5..e50c7f3d8 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -289,6 +289,7 @@ public: class AWeapon : public AStateProvider { DECLARE_CLASS_WITH_META(AWeapon, AStateProvider, PClassWeapon) + HAS_FIELDS HAS_OBJECT_POINTERS public: DWORD WeaponFlags; diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index 4a947cbee..9af5c6de2 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -17,10 +17,13 @@ #include "g_level.h" #include "d_net.h" #include "serializer.h" +#include "thingdef.h" #define BONUSADD 6 -IMPLEMENT_CLASS(AWeapon, false, true, false, false) +extern FFlagDef WeaponFlagDefs[]; + +IMPLEMENT_CLASS(AWeapon, false, true, true, false) IMPLEMENT_POINTERS_START(AWeapon) IMPLEMENT_POINTER(Ammo1) @@ -28,6 +31,26 @@ IMPLEMENT_POINTERS_START(AWeapon) IMPLEMENT_POINTER(SisterWeapon) IMPLEMENT_POINTERS_END +void AWeapon::InitNativeFields() +{ + auto meta = RUNTIME_CLASS(AWeapon); + + meta->AddNativeField("bAltFire", TypeBool, myoffsetof(AWeapon, bAltFire)); + + + // synthesize a symbol for each flag from the flag name tables to avoid redundant declaration of them. + for (size_t i = 0; WeaponFlagDefs[i].flagbit != 0xffffffff; i++) + { + if (WeaponFlagDefs[i].structoffset > 0) + { + meta->AddNativeField(FStringf("b%s", WeaponFlagDefs[i].name), (WeaponFlagDefs[i].fieldsize == 4 ? TypeSInt32 : TypeSInt16), WeaponFlagDefs[i].structoffset, WeaponFlagDefs[i].varflags, WeaponFlagDefs[i].flagbit); + } + } + // This flag is not accessible through actor definitions. + meta->AddNativeField("bDehAmmo", TypeSInt32, myoffsetof(AWeapon, WeaponFlags), VARF_ReadOnly, WIF_DEHAMMO); + +} + FString WeaponSection; TArray KeyConfWeapons; FWeaponSlots *PlayingKeyConf; @@ -651,6 +674,15 @@ bool AWeapon::DepleteAmmo (bool altFire, bool checkEnough, int ammouse) return true; } +DEFINE_ACTION_FUNCTION(AWeapon, DepleteAmmo) +{ + PARAM_SELF_PROLOGUE(AWeapon); + PARAM_BOOL(altfire); + PARAM_BOOL_DEF(checkenough); + PARAM_INT_DEF(ammouse); + ACTION_RETURN_BOOL(self->DepleteAmmo(altfire, checkenough, ammouse)); +} + //=========================================================================== // diff --git a/src/namedef.h b/src/namedef.h index 01859d01a..d4206e2bb 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -738,3 +738,15 @@ xx(Length) xx(Unit) xx(StateLabel) xx(Overlay) + +xx(A_Punch) +xx(A_FirePistol) +xx(A_FireShotgun) +xx(A_FireShotgun2) +xx(A_FireCGun) +xx(A_FireMissile) +xx(A_Saw) +xx(A_FirePlasma) +xx(A_FireBFG) +xx(A_FireOldBFG) +xx(A_FireRailgun) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index c998bcf91..09d850af5 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1035,6 +1035,14 @@ AInventory *AActor::FindInventory (FName type) return FindInventory(PClass::FindActor(type)); } +DEFINE_ACTION_FUNCTION(AActor, FindInventory) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_CLASS(type, AInventory); + PARAM_BOOL_DEF(subclass); + ACTION_RETURN_OBJECT(self->FindInventory(type, subclass)); +} + //============================================================================ // // AActor :: GiveInventoryType diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index a5f6a3bc7..c58167bab 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -3547,7 +3547,7 @@ ExpEmit FxShift::Emit(VMFunctionBuilder *build) if (!op1.Konst) { op1.Free(build); - instr = InstrMap[index][op2.Konst? 0:2]; + instr = InstrMap[index][op2.Konst? 2:0]; } else { @@ -7067,7 +7067,8 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) SAFE_RESOLVE_OPT(Self, ctx); bool failed = false; auto proto = Function->Variants[0].Proto; - auto argtypes = proto->ArgumentTypes; + auto &argtypes = proto->ArgumentTypes; + auto &argflags = Function->Variants[0].ArgFlags; int implicit = Function->GetImplicitArgs(); @@ -7100,8 +7101,29 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) } assert(type != nullptr); - FxExpression *x = new FxTypeCast(ArgList[i], type, false); - x = x->Resolve(ctx); + FxExpression *x; + if (!(argflags[i + implicit] & VARF_Ref)) + { + x = new FxTypeCast(ArgList[i], type, false); + x = x->Resolve(ctx); + } + else + { + bool writable; + ArgList[i] = ArgList[i]->Resolve(ctx); // nust be resolved before the address is requested. + ArgList[i]->RequestAddress(ctx, &writable); + ArgList[i]->ValueType = NewPointer(ArgList[i]->ValueType); + // For a reference argument the types must match 100%. + if (type != ArgList[i]->ValueType) + { + ScriptPosition.Message(MSG_ERROR, "Type mismatch in reference argument", Function->SymbolName.GetChars()); + x = nullptr; + } + else + { + x = ArgList[i]; + } + } failed |= (x == nullptr); ArgList[i] = x; } diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index 3abce216d..7f0d98846 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -131,7 +131,7 @@ void SetImplicitArgs(TArray *args, TArray *argflags, TArrayPush(NewPointer(cls)); } - args->Push(TypeState/*Info*/); // fixme: TypeState is not the correct type here!!! + args->Push(NewPointer(NewStruct("FStateParamInfo", nullptr))); } if (argflags != nullptr) { diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 95dc0bdce..8c4220b0e 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -388,7 +388,7 @@ static FFlagDef InventoryFlagDefs[] = DEFINE_DEPRECATED_FLAG(INTERHUBSTRIP), }; -static FFlagDef WeaponFlagDefs[] = +FFlagDef WeaponFlagDefs[] = { // Weapon flags DEFINE_FLAG(WIF, NOAUTOFIRE, AWeapon, WeaponFlags), @@ -411,12 +411,14 @@ static FFlagDef WeaponFlagDefs[] = DEFINE_FLAG(WIF, NOAUTOAIM, AWeapon, WeaponFlags), DEFINE_FLAG(WIF, NODEATHDESELECT, AWeapon, WeaponFlags), DEFINE_FLAG(WIF, NODEATHINPUT, AWeapon, WeaponFlags), - - DEFINE_DUMMY_FLAG(NOLMS, false), DEFINE_FLAG(WIF, ALT_USES_BOTH, AWeapon, WeaponFlags), + + DEFINE_DUMMY_FLAG(NOLMS, false), DEFINE_DUMMY_FLAG(ALLOW_WITH_RESPAWN_INVUL, false), }; + + static FFlagDef PlayerPawnFlagDefs[] = { // PlayerPawn flags diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index deca91a80..407080f2c 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -157,13 +157,15 @@ enum 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. + // functionally no different than ATAG_GENERIC (meaning they are useless because they trigger asserts all over the place.) + /* 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_RNG, // pointer to FRandom ATAG_STATE = ATAG_GENERIC, // pointer to FState (cannot have its own type because there's no means to track inside the VM.) diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 918dc6949..e4ab95946 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -87,7 +87,7 @@ begin: OP(LFP): ASSERTA(a); assert(sfunc != NULL); assert(sfunc->ExtraSpace > 0); reg.a[a] = f->GetExtra(); - reg.atag[a] = ATAG_FRAMEPOINTER; + reg.atag[a] = ATAG_GENERIC; // using ATAG_FRAMEPOINTER will cause endless asserts. NEXTOP; OP(LB): @@ -461,7 +461,7 @@ begin: break; case REGT_INT | REGT_ADDROF: assert(C < f->NumRegD); - ::new(param) VMValue(®.d[C], ATAG_DREGISTER); + ::new(param) VMValue(®.d[C], ATAG_GENERIC); break; case REGT_INT | REGT_KONST: assert(C < sfunc->NumKonstD); @@ -473,7 +473,7 @@ begin: break; case REGT_STRING | REGT_ADDROF: assert(C < f->NumRegS); - ::new(param) VMValue(®.s[C], ATAG_SREGISTER); + ::new(param) VMValue(®.s[C], ATAG_GENERIC); break; case REGT_STRING | REGT_KONST: assert(C < sfunc->NumKonstS); @@ -485,7 +485,7 @@ begin: break; case REGT_POINTER | REGT_ADDROF: assert(C < f->NumRegA); - ::new(param) VMValue(®.a[C], ATAG_AREGISTER); + ::new(param) VMValue(®.a[C], ATAG_GENERIC); break; case REGT_POINTER | REGT_KONST: assert(C < sfunc->NumKonstA); @@ -512,7 +512,7 @@ begin: break; case REGT_FLOAT | REGT_ADDROF: assert(C < f->NumRegF); - ::new(param) VMValue(®.f[C], ATAG_FREGISTER); + ::new(param) VMValue(®.f[C], ATAG_GENERIC); break; case REGT_FLOAT | REGT_KONST: assert(C < sfunc->NumKonstF); diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index ebe70c340..5dd430f9a 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2160,6 +2160,7 @@ void ZCCCompiler::InitFunctions() if ((flags & VARF_Out) || (type != TypeVector2 && type != TypeVector3)) { type = NewPointer(type); + flags |= VARF_Ref; } else if (type == TypeVector2) { diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 42f32a447..14493875a 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -48,6 +48,7 @@ zscript/doom/cyberdemon.txt zscript/doom/spidermaster.txt zscript/doom/keen.txt zscript/doom/bossbrain.txt +zscript/doom/weaponfist.txt zscript/doom/deadthings.txt zscript/doom/doomammo.txt diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 137fedbec..744128cdd 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -133,6 +133,7 @@ class Actor : Thinker native // DECORATE compatible functions native bool CheckClass(class checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false); + native Inventory FindInventory(class itemtype, bool subclass = false); native int CountInv(class itemtype, int ptr_select = AAPTR_DEFAULT); native float GetDistance(bool checkz, int ptr = AAPTR_TARGET); native float GetAngle(int flags, int ptr = AAPTR_DEFAULT); @@ -471,7 +472,6 @@ class Actor : Thinker native native void A_DeQueueCorpse(); native void A_ClearLastHeard(); native bool A_SelectWeapon(class whichweapon, int flags = 0); - action native void A_Punch(); native void A_Feathers(); native void A_ClassBossHealth(); native void A_ShootGun(); diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index 08eee789e..cf0cbdc5c 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -829,7 +829,7 @@ enum EStateType struct FStateParamInfo { state mCallingState; - EStateType mStateType; + /*EStateType*/int mStateType; int mPSPIndex; } diff --git a/wadsrc/static/zscript/doom/doomweapons.txt b/wadsrc/static/zscript/doom/doomweapons.txt index a6eecd189..b75cfa967 100644 --- a/wadsrc/static/zscript/doom/doomweapons.txt +++ b/wadsrc/static/zscript/doom/doomweapons.txt @@ -12,44 +12,6 @@ class DoomWeapon : Weapon } } -// -------------------------------------------------------------------------- -// -// Fist -// -// -------------------------------------------------------------------------- - -class Fist : Weapon -{ - Default - { - Weapon.SelectionOrder 3700; - Weapon.Kickback 100; - Obituary "$OB_MPFIST"; - Tag "$TAG_FIST"; - +WEAPON.WIMPY_WEAPON - +WEAPON.MELEEWEAPON - } - States - { - Ready: - PUNG A 1 A_WeaponReady; - Loop; - Deselect: - PUNG A 1 A_Lower; - Loop; - Select: - PUNG A 1 A_Raise; - Loop; - Fire: - PUNG B 4; - PUNG C 4 A_Punch; - PUNG D 5; - PUNG C 4; - PUNG B 5 A_ReFire; - Goto Ready; - } -} - // -------------------------------------------------------------------------- // diff --git a/wadsrc/static/zscript/doom/weaponfist.txt b/wadsrc/static/zscript/doom/weaponfist.txt new file mode 100644 index 000000000..3c1cc992f --- /dev/null +++ b/wadsrc/static/zscript/doom/weaponfist.txt @@ -0,0 +1,80 @@ +// -------------------------------------------------------------------------- +// +// Fist +// +// -------------------------------------------------------------------------- + +class Fist : Weapon +{ + Default + { + Weapon.SelectionOrder 3700; + Weapon.Kickback 100; + Obituary "$OB_MPFIST"; + Tag "$TAG_FIST"; + +WEAPON.WIMPY_WEAPON + +WEAPON.MELEEWEAPON + } + States + { + Ready: + PUNG A 1 A_WeaponReady; + Loop; + Deselect: + PUNG A 1 A_Lower; + Loop; + Select: + PUNG A 1 A_Raise; + Loop; + Fire: + PUNG B 4; + PUNG C 4 A_Punch; + PUNG D 5; + PUNG C 4; + PUNG B 5 A_ReFire; + Goto Ready; + } +} + + +//=========================================================================== +// +// Code (must be attached to Actor) +// +//=========================================================================== + +extend class Actor +{ + action void A_Punch() + { + FTranslatedLineTarget t; + + if (player != null) + { + Weapon weap = player.ReadyWeapon; + if (weap != null && !weap.bDehAmmo && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + if (!weap.DepleteAmmo (weap.bAltFire)) + return; + } + } + + int damage = random[Punch](1, 10) << 1; + + if (FindInventory("PowerStrength")) + damage *= 10; + + double ang = angle + Random2[Punch]() * (5.625 / 256); + double pitch = AimLineAttack (ang, MELEERANGE); + + LineAttack (ang, MELEERANGE, pitch, damage, 'Melee', "BulletPuff", LAF_ISMELEEATTACK, t); + + // turn to face target + if (t.linetarget) + { + A_PlaySound ("*fist", CHAN_WEAPON); + angle = t.angleFromSource; + } + } + +} \ No newline at end of file diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index 12f30c484..8337c5399 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -473,6 +473,8 @@ class Weapon : StateProvider native Stop; } + native bool DepleteAmmo(bool altFire, bool checkEnough = true, int ammouse = -1); + native action void A_ZoomFactor(float scale = 1, int flags = 0); native action void A_SetCrosshair(int xhair); const ZOOM_INSTANT = 1; From 10bc01c000016be55c1e7bb9d6dc32eab4ab75b4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 19 Nov 2016 09:10:31 +0100 Subject: [PATCH 032/185] - fixed yet another place where VS did not warn about improper use of NULL. --- src/d_dehacked.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 7f546b1ee..3ad1b2cd9 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -3084,7 +3084,7 @@ void FinishDehPatch () break; // State has already been checked so we reached a loop } StateVisited[state] = true; - for(unsigned j = 0; AmmoPerAttacks[j].func != NULL; j++) + for(unsigned j = 0; AmmoPerAttacks[j].func != NAME_None; j++) { if (AmmoPerAttacks[i].ptr == nullptr) { From df4e9324c9f3d48b15d39f7b95ff04285c856385 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 19 Nov 2016 09:24:54 +0100 Subject: [PATCH 033/185] - added terminators to all flag lists. --- src/scripting/thingdef_data.cpp | 47 ++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 8c4220b0e..f2fec2972 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -386,6 +386,7 @@ static FFlagDef InventoryFlagDefs[] = DEFINE_DEPRECATED_FLAG(PICKUPFLASH), DEFINE_DEPRECATED_FLAG(INTERHUBSTRIP), + { 0xffffffff } }; FFlagDef WeaponFlagDefs[] = @@ -415,6 +416,7 @@ FFlagDef WeaponFlagDefs[] = DEFINE_DUMMY_FLAG(NOLMS, false), DEFINE_DUMMY_FLAG(ALLOW_WITH_RESPAWN_INVUL, false), + { 0xffffffff } }; @@ -425,22 +427,24 @@ static FFlagDef PlayerPawnFlagDefs[] = DEFINE_FLAG(PPF, NOTHRUSTWHENINVUL, APlayerPawn, PlayerFlags), DEFINE_FLAG(PPF, CANSUPERMORPH, APlayerPawn, PlayerFlags), DEFINE_FLAG(PPF, CROUCHABLEMORPH, APlayerPawn, PlayerFlags), + { 0xffffffff } }; static FFlagDef PowerSpeedFlagDefs[] = { // PowerSpeed flags DEFINE_FLAG(PSF, NOTRAIL, APowerSpeed, SpeedFlags), + { 0xffffffff } }; static const struct FFlagList { const PClass * const *Type; FFlagDef *Defs; int NumDefs; } FlagLists[] = { { &RUNTIME_CLASS_CASTLESS(AActor), ActorFlagDefs, countof(ActorFlagDefs)-1 }, // -1 to account for the terminator { &RUNTIME_CLASS_CASTLESS(AActor), MoreFlagDefs, countof(MoreFlagDefs) }, - { &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) }, + { &RUNTIME_CLASS_CASTLESS(AInventory), InventoryFlagDefs, countof(InventoryFlagDefs)-1 }, + { &RUNTIME_CLASS_CASTLESS(AWeapon), WeaponFlagDefs, countof(WeaponFlagDefs)-1 }, + { &RUNTIME_CLASS_CASTLESS(APlayerPawn), PlayerPawnFlagDefs, countof(PlayerPawnFlagDefs)-1 }, + { &RUNTIME_CLASS_CASTLESS(APowerSpeed), PowerSpeedFlagDefs, countof(PowerSpeedFlagDefs)-1 }, }; #define NUM_FLAG_LISTS (countof(FlagLists)) @@ -647,6 +651,23 @@ void P_InitPlayerForScript(); void InitThingdef() { + PType *TypeActor = NewPointer(RUNTIME_CLASS(AActor)); + + PStruct *sstruct = NewStruct("Sector", nullptr); + auto sptr = NewPointer(sstruct); + sstruct->AddNativeField("soundtarget", TypeActor, myoffsetof(sector_t, SoundTarget)); + + G_InitLevelLocalsForScript(); + P_InitPlayerForScript(); + + FAutoSegIterator probe(CRegHead, CRegTail); + + while (*++probe != NULL) + { + if (((ClassReg *)*probe)->InitNatives) + ((ClassReg *)*probe)->InitNatives(); + } + // Sort the flag lists for (size_t i = 0; i < NUM_FLAG_LISTS; ++i) { @@ -682,22 +703,4 @@ void InitThingdef() AFTable.ShrinkToFit(); qsort(&AFTable[0], AFTable.Size(), sizeof(AFTable[0]), funccmp); } - - PType *TypeActor = NewPointer(RUNTIME_CLASS(AActor)); - - PStruct *sstruct = NewStruct("Sector", nullptr); - auto sptr = NewPointer(sstruct); - sstruct->AddNativeField("soundtarget", TypeActor, myoffsetof(sector_t, SoundTarget)); - - G_InitLevelLocalsForScript(); - P_InitPlayerForScript(); - - FAutoSegIterator probe(CRegHead, CRegTail); - - while (*++probe != NULL) - { - if (((ClassReg *)*probe)->InitNatives) - ((ClassReg *)*probe)->InitNatives(); - } - } From f11f020b6cb361ee7a8e88d38f9feb6e95583676 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 19 Nov 2016 12:12:29 +0100 Subject: [PATCH 034/185] - allow functions in structs. This is needed for several internal data types like players, sectors, lines, etc. - added a new type 'NativeStruct'. This will be used for types that cannot be instantiated, and is also needed to cleanly handle many internal types that only can exist as reference. --- src/dobjtype.cpp | 18 + src/dobjtype.h | 19 +- src/scripting/codegeneration/codegen.cpp | 49 +- src/scripting/codegeneration/codegen.h | 6 +- src/scripting/thingdef.cpp | 4 +- src/scripting/thingdef.h | 6 +- src/scripting/thingdef_data.cpp | 7 +- src/scripting/zscript/zcc-parse.lemon | 17 +- src/scripting/zscript/zcc_compile.cpp | 650 ++++++++++++----------- src/scripting/zscript/zcc_compile.h | 29 +- src/scripting/zscript/zcc_parser.h | 18 +- 11 files changed, 453 insertions(+), 370 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 32fd30c67..682cc0fd5 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2334,6 +2334,24 @@ PStruct *NewStruct(FName name, PTypeBase *outer) return static_cast(stype); } +/* PNativeStruct ****************************************************************/ + +IMPLEMENT_CLASS(PNativeStruct, false, false, false, false) + +//========================================================================== +// +// PNativeStruct - Parameterized Constructor +// +//========================================================================== + +PNativeStruct::PNativeStruct(FName name) + : PStruct(name, nullptr) +{ + mDescriptiveName.Format("NativeStruct<%s>", name.GetChars()); + Size = 0; + HasNativeFields = true; +} + /* PField *****************************************************************/ IMPLEMENT_CLASS(PField, false, false, false, false) diff --git a/src/dobjtype.h b/src/dobjtype.h index bd6483258..aeb042ebb 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -694,6 +694,15 @@ protected: PStruct(); }; +// a native struct will always be abstract and cannot be instantiated. All variables are references. +// In addition, native structs can have methods (but no virtual ones.) +class PNativeStruct : public PStruct +{ + DECLARE_CLASS(PNativeStruct, PStruct); +public: + PNativeStruct(FName name = NAME_None); +}; + class PPrototype : public PCompoundType { DECLARE_CLASS(PPrototype, PCompoundType); @@ -723,10 +732,10 @@ public: TArray ArgNames; // we need the names to access them later when the function gets compiled. uint32_t Flags; int UseFlags; - PClass *SelfClass; + PStruct *SelfClass; }; TArray Variants; - PClass *OwningClass = nullptr; + PStruct *OwningClass = nullptr; unsigned AddVariant(PPrototype *proto, TArray &argflags, TArray &argnames, VMFunction *impl, int flags, int useflags); int GetImplicitArgs() @@ -738,7 +747,7 @@ public: size_t PropagateMark(); - PFunction(PClass *owner = nullptr, FName name = NAME_None) : PSymbol(name), OwningClass(owner) {} + PFunction(PStruct *owner = nullptr, FName name = NAME_None) : PSymbol(name), OwningClass(owner) {} }; // Meta-info for every class derived from DObject --------------------------- @@ -749,9 +758,9 @@ enum }; class PClassClass; -class PClass : public PStruct +class PClass : public PNativeStruct { - DECLARE_CLASS(PClass, PStruct); + DECLARE_CLASS(PClass, PNativeStruct); HAS_OBJECT_POINTERS; protected: // We unravel _WITH_META here just as we did for PType. diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index c58167bab..a7be26f29 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -101,7 +101,7 @@ FCompileContext::FCompileContext(PFunction *fnc, PPrototype *ret, bool fromdecor if (fnc != nullptr) Class = fnc->OwningClass; } -FCompileContext::FCompileContext(PClass *cls, bool fromdecorate) +FCompileContext::FCompileContext(PStruct *cls, bool fromdecorate) : ReturnProto(nullptr), Function(nullptr), Class(cls), FromDecorate(fromdecorate), StateIndex(-1), StateCount(0), Lump(-1) { } @@ -5335,7 +5335,7 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) delete this; return nullptr; } - if (!ctx.Function->Variants[0].SelfClass->IsDescendantOf(RUNTIME_CLASS(AActor))) + if (!ctx.Function->Variants[0].SelfClass->IsKindOf(RUNTIME_CLASS(PClassActor))) { ScriptPosition.Message(MSG_ERROR, "'Default' requires an actor type."); delete this; @@ -5441,7 +5441,7 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) // //========================================================================== -FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PClass *classctx, FxExpression *&object, PStruct *objtype) +FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PStruct *classctx, FxExpression *&object, PStruct *objtype) { PSymbol *sym; PSymbolTable *symtbl; @@ -6379,7 +6379,15 @@ static bool CheckFunctionCompatiblity(FScriptPosition &ScriptPosition, PFunction { auto callingself = caller->Variants[0].SelfClass; auto calledself = callee->Variants[0].SelfClass; - if (!callingself->IsDescendantOf(calledself)) + bool match = (callingself == calledself); + if (!match) + { + auto callingselfcls = dyn_cast(caller->Variants[0].SelfClass); + auto calledselfcls = dyn_cast(callee->Variants[0].SelfClass); + match = callingselfcls != nullptr && calledselfcls != nullptr && callingselfcls->IsDescendantOf(calledselfcls); + } + + if (!match) { ScriptPosition.Message(MSG_ERROR, "Call to member function %s with incompatible self pointer.", callee->SymbolName.GetChars()); return false; @@ -6717,11 +6725,19 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) if (Self->ExprType == EFX_Super) { - // give the node the proper value type now that we know it's properly used. - cls = ctx.Function->Variants[0].SelfClass->ParentClass; - Self->ValueType = NewPointer(cls); - Self->ExprType = EFX_Self; - novirtual = true; // super calls are always non-virtual + auto clstype = dyn_cast(ctx.Function->Variants[0].SelfClass); + if (clstype != nullptr) + { + // give the node the proper value type now that we know it's properly used. + cls = clstype->ParentClass; + Self->ValueType = NewPointer(cls); + Self->ExprType = EFX_Self; + novirtual = true; // super calls are always non-virtual + } + else + { + ScriptPosition.Message(MSG_ERROR, "Super requires a class type"); + } } if (Self->IsVector()) @@ -6775,7 +6791,8 @@ isresolved: if (staticonly && (afd->Variants[0].Flags & VARF_Method)) { - if (!ctx.Class->IsDescendantOf(cls)) + auto clstype = dyn_cast(ctx.Class); + if (clstype == nullptr || !clstype->IsDescendantOf(cls)) { ScriptPosition.Message(MSG_ERROR, "Cannot call non-static function %s::%s from here\n", cls->TypeName.GetChars(), MethodName.GetChars()); delete this; @@ -8876,14 +8893,22 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) CHECKRESOLVED(); ABORT(ctx.Class); int symlabel; + auto clstype = dyn_cast(ctx.Class); if (names[0] == NAME_None) { scope = nullptr; } + else if (clstype == nullptr) + { + // not in an actor, so any further checks are pointless. + ScriptPosition.Message(MSG_ERROR, "'%s' is not an ancestor of '%s'", names[0].GetChars(), ctx.Class->TypeName.GetChars()); + delete this; + return nullptr; + } else if (names[0] == NAME_Super) { - scope = dyn_cast(ctx.Class->ParentClass); + scope = dyn_cast(clstype->ParentClass); } else { @@ -8894,7 +8919,7 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) delete this; return nullptr; } - else if (!scope->IsAncestorOf(ctx.Class)) + else if (!scope->IsAncestorOf(clstype)) { ScriptPosition.Message(MSG_ERROR, "'%s' is not an ancestor of '%s'", names[0].GetChars(), ctx.Class->TypeName.GetChars()); delete this; diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index 66a0137b1..5ad351d6b 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -75,7 +75,7 @@ struct FCompileContext FxCompoundStatement *Block = nullptr; PPrototype *ReturnProto; PFunction *Function; // The function that is currently being compiled (or nullptr for constant evaluation.) - PClass *Class; // The type of the owning class. + PStruct *Class; // The type of the owning class. bool FromDecorate; // DECORATE must silence some warnings and demote some errors. int StateIndex; // index in actor's state table for anonymous functions, otherwise -1 (not used by DECORATE which pre-resolves state indices) int StateCount; // amount of states an anoymous function is being used on (must be 1 for state indices to be allowed.) @@ -84,7 +84,7 @@ struct FCompileContext TDeletingArray FunctionArgs; FCompileContext(PFunction *func, PPrototype *ret, bool fromdecorate, int stateindex, int statecount, int lump); - FCompileContext(PClass *cls, bool fromdecorate); // only to be used to resolve constants! + FCompileContext(PStruct *cls, bool fromdecorate); // only to be used to resolve constants! PSymbol *FindInClass(FName identifier, PSymbolTable *&symt); PSymbol *FindInSelfClass(FName identifier, PSymbolTable *&symt); @@ -346,7 +346,7 @@ public: FxIdentifier(FName i, const FScriptPosition &p); FxExpression *Resolve(FCompileContext&); - FxExpression *ResolveMember(FCompileContext&, PClass*, FxExpression*&, PStruct*); + FxExpression *ResolveMember(FCompileContext&, PStruct*, FxExpression*&, PStruct*); }; diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index 7f0d98846..9dcf3a16f 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -104,7 +104,7 @@ FScriptPosition & GetStateSource(FState *state) // //========================================================================== -void SetImplicitArgs(TArray *args, TArray *argflags, TArray *argnames, PClass *cls, DWORD funcflags, int useflags) +void SetImplicitArgs(TArray *args, TArray *argflags, TArray *argnames, PStruct *cls, DWORD funcflags, int useflags) { // Must be called before adding any other arguments. assert(args == nullptr || args->Size() == 0); @@ -182,7 +182,7 @@ PFunction *CreateAnonymousFunction(PClass *containingclass, PType *returntype, i // //========================================================================== -PFunction *FindClassMemberFunction(PClass *selfcls, PClass *funccls, FName name, FScriptPosition &sc, bool *error) +PFunction *FindClassMemberFunction(PStruct *selfcls, PStruct *funccls, FName name, FScriptPosition &sc, bool *error) { // Skip ACS_NamedExecuteWithResult. Anything calling this should use the builtin instead. if (name == NAME_ACS_NamedExecuteWithResult) return nullptr; diff --git a/src/scripting/thingdef.h b/src/scripting/thingdef.h index a2c224558..5bad10c36 100644 --- a/src/scripting/thingdef.h +++ b/src/scripting/thingdef.h @@ -146,7 +146,7 @@ inline void ResetBaggage (Baggage *bag, PClassActor *stateclass) // //========================================================================== -AFuncDesc *FindFunction(PClass *cls, const char * string); +AFuncDesc *FindFunction(PStruct *cls, const char * string); FxExpression *ParseExpression(FScanner &sc, PClassActor *cls, bool mustresolve = false); @@ -156,9 +156,9 @@ void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray *args, TArray *argflags, TArray *argnames, PClass *cls, DWORD funcflags, int useflags); +void SetImplicitArgs(TArray *args, TArray *argflags, TArray *argnames, PStruct *cls, DWORD funcflags, int useflags); PFunction *CreateAnonymousFunction(PClass *containingclass, PType *returntype, int flags); -PFunction *FindClassMemberFunction(PClass *cls, PClass *funccls, FName name, FScriptPosition &sc, bool *error); +PFunction *FindClassMemberFunction(PStruct *cls, PStruct *funccls, FName name, FScriptPosition &sc, bool *error); void CreateDamageFunction(PClassActor *info, AActor *defaults, FxExpression *id, bool fromDecorate); //========================================================================== diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index f2fec2972..76770272d 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -577,11 +577,14 @@ FPropertyInfo *FindProperty(const char * string) // //========================================================================== -AFuncDesc *FindFunction(PClass *cls, const char * string) +AFuncDesc *FindFunction(PStruct *cls, const char * string) { for (int i = 0; i < 2; i++) { - if (i == 1 && !cls->IsDescendantOf(RUNTIME_CLASS(AActor))) break; + // Since many functions have been declared with Actor as owning class, despited being members of something else, let's hack around this until they have been fixed or exported. + // Since most of these are expected to be scriptified anyway, there's no point fixing them all before they get exported. + if (i == 1 && !cls->IsKindOf(RUNTIME_CLASS(PClassActor))) break; + FStringf fullname("%s_%s", i == 0 ? cls->TypeName.GetChars() : "Actor", string); int min = 0, max = AFTable.Size() - 1; diff --git a/src/scripting/zscript/zcc-parse.lemon b/src/scripting/zscript/zcc-parse.lemon index c88cab481..2d3605532 100644 --- a/src/scripting/zscript/zcc-parse.lemon +++ b/src/scripting/zscript/zcc-parse.lemon @@ -278,16 +278,21 @@ class_member(X) ::= const_def(A). { X = A; /*X-overwrites-A*/ } %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. +struct_def(X) ::= STRUCT(T) IDENTIFIER(A) struct_flags(S) LBRACE opt_struct_body(B) RBRACE opt_semicolon. { NEW_AST_NODE(Struct,def,T); def->NodeName = A.Name(); def->Body = B; def->Type = nullptr; def->Symbol = nullptr; + def->Flags = S.Flags; X = def; } +%type struct_flags{ClassFlagsBlock} +struct_flags(X) ::= . { X.Flags = 0; } +struct_flags(X) ::= NATIVE. { X.Flags = ZCC_Native; } + opt_struct_body(X) ::= . { X = NULL; } opt_struct_body(X) ::= struct_body(X). @@ -295,7 +300,7 @@ struct_body(X) ::= error. { X = NULL; } struct_body(X) ::= struct_member(X). struct_body(X) ::= struct_member(A) struct_body(B). { X = A; /*X-overwrites-A*/ X->AppendSibling(B); } -struct_member(X) ::= declarator_no_fun(A). { X = A; /*X-overwrites-A*/ } +struct_member(X) ::= declarator(A). { X = A; /*X-overwrites-A*/ } struct_member(X) ::= enum_def(A). { X = A; /*X-overwrites-A*/ } struct_member(X) ::= const_def(A). { X = A; /*X-overwrites-A*/ } @@ -844,14 +849,6 @@ declarator(X) ::= decl_flags(A) type_list_or_void(B) variables_or_function(C). X = NULL; } } -declarator_no_fun(X) ::= decl_flags(A) type(B) variable_list(C) SEMICOLON. -{ - NEW_AST_NODE(VarDeclarator, decl, A != nullptr? A->SourceLoc : B->SourceLoc); - decl->Type = B; - decl->Names = C; - decl->Flags = A == nullptr? 0 : A->Flags; - 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 */ diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 5dd430f9a..e50e8b822 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -196,6 +196,10 @@ void ZCCCompiler::ProcessStruct(ZCC_Struct *cnode, PSymbolTreeNode *treenode, ZC cls->Fields.Push(static_cast(node)); break; + case AST_FuncDeclarator: + cls->Functions.Push(static_cast(node)); + break; + case AST_EnumTerminator: enumType = nullptr; break; @@ -411,7 +415,7 @@ void ZCCCompiler::CreateStructTypes() { for(auto s : Structs) { - s->Outer = s->OuterDef == nullptr? nullptr : s->OuterDef->Type; + s->Outer = s->OuterDef == nullptr? nullptr : s->OuterDef->CType(); s->strct->Type = NewStruct(s->NodeName(), s->Outer); s->strct->Symbol = new PSymbolType(s->NodeName(), s->Type()); GlobalSymbols.AddSymbol(s->strct->Symbol); @@ -1989,6 +1993,331 @@ void ZCCCompiler::InitDefaults() } } + +void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool forclass) +{ + TArray rets(1); + TArray args; + TArray argflags; + TArray argdefaults; + TArray argnames; + + rets.Clear(); + args.Clear(); + argflags.Clear(); + bool hasdefault = false; + // For the time being, let's not allow overloading. This may be reconsidered later but really just adds an unnecessary amount of complexity here. + if (AddTreeNode(f->Name, f, &c->TreeNodes, false)) + { + auto t = f->Type; + if (t != nullptr) + { + do + { + auto type = DetermineType(c->Type(), f, f->Name, t, false, false); + if (type->IsKindOf(RUNTIME_CLASS(PStruct)) && type != TypeVector2 && type != TypeVector3) + { + // structs and classes only get passed by pointer. + type = NewPointer(type); + } + // TBD: disallow certain types? For now, let everything pass that isn't an array. + rets.Push(type); + t = static_cast(t->SiblingNext); + } while (t != f->Type); + } + + int notallowed = ZCC_Latent | ZCC_Meta | ZCC_ReadOnly | ZCC_FuncConst | ZCC_Abstract; + + if (f->Flags & notallowed) + { + Error(f, "Invalid qualifiers for %s (%s not allowed)", FName(f->Name).GetChars(), FlagsToString(f->Flags & notallowed).GetChars()); + f->Flags &= notallowed; + } + uint32_t varflags = VARF_Method; + int implicitargs = 1; + AFuncDesc *afd = nullptr; + int useflags = SUF_ACTOR | SUF_OVERLAY | SUF_WEAPON | SUF_ITEM; + if (f->UseFlags != nullptr) + { + useflags = 0; + auto p = f->UseFlags; + do + { + switch (p->Id) + { + case NAME_Actor: + useflags |= SUF_ACTOR; + break; + case NAME_Overlay: + useflags |= SUF_OVERLAY; + break; + case NAME_Weapon: + useflags |= SUF_WEAPON; + break; + case NAME_Item: + useflags |= SUF_ITEM; + break; + default: + Error(p, "Unknown Action qualifier %s", FName(p->Id).GetChars()); + break; + } + + p = static_cast(p->SiblingNext); + } while (p != f->UseFlags); + } + + // map to implementation flags. + if (f->Flags & ZCC_Private) varflags |= VARF_Private; + if (f->Flags & ZCC_Protected) varflags |= VARF_Protected; + if (f->Flags & ZCC_Deprecated) varflags |= VARF_Deprecated; + if (f->Flags & ZCC_Virtual) varflags |= VARF_Virtual; + if (f->Flags & ZCC_Override) varflags |= VARF_Override; + if (f->Flags & ZCC_Action) + { + // Non-Actors cannot have action functions. + if (!c->Type()->IsKindOf(RUNTIME_CLASS(PClassActor))) + { + Error(f, "'Action' can only be used in child classes of Actor"); + } + + varflags |= VARF_Final; // Action implies Final. + if (useflags & (SUF_OVERLAY | SUF_WEAPON | SUF_ITEM)) + { + varflags |= VARF_Action; + implicitargs = 3; + } + else + { + implicitargs = 1; + } + } + if (f->Flags & ZCC_Static) varflags = (varflags & ~VARF_Method) | VARF_Final, implicitargs = 0; // Static implies Final. + + + if (varflags & VARF_Override) varflags &= ~VARF_Virtual; // allow 'virtual override'. + // Only one of these flags may be used. + static int exclude[] = { ZCC_Virtual, ZCC_Override, ZCC_Action, ZCC_Static }; + static const char * print[] = { "virtual", "override", "action", "static" }; + int fc = 0; + FString build; + for (int i = 0; i < 4; i++) + { + if (f->Flags & exclude[i]) + { + fc++; + if (build.Len() > 0) build += ", "; + build += print[i]; + } + } + if (fc > 1) + { + Error(f, "Invalid combination of qualifiers %s on function %s.", FName(f->Name).GetChars(), build.GetChars()); + varflags |= VARF_Method; + } + if (varflags & VARF_Override) varflags |= VARF_Virtual; // Now that the flags are checked, make all override functions virtual as well. + + if (f->Flags & ZCC_Native) + { + varflags |= VARF_Native; + afd = FindFunction(c->Type(), FName(f->Name).GetChars()); + if (afd == nullptr) + { + Error(f, "The function '%s' has not been exported from the executable.", FName(f->Name).GetChars()); + } + else + { + (*afd->VMPointer)->ImplicitArgs = BYTE(implicitargs); + } + } + SetImplicitArgs(&args, &argflags, &argnames, c->Type(), varflags, useflags); + argdefaults.Resize(argnames.Size()); + auto p = f->Params; + bool hasoptionals = false; + if (p != nullptr) + { + do + { + int elementcount = 1; + VMValue vmval[3]; // default is REGT_NIL which means 'no default value' here. + if (p->Type != nullptr) + { + auto type = DetermineType(c->Type(), p, f->Name, p->Type, false, false); + int flags = 0; + if (p->Flags & ZCC_In) flags |= VARF_In; + if (p->Flags & ZCC_Out) flags |= VARF_Out; + if ((type->IsA(RUNTIME_CLASS(PStruct))) || (flags & VARF_Out)) + { + // 'out' parameters and all structs except vectors are passed by reference + if ((flags & VARF_Out) || (type != TypeVector2 && type != TypeVector3)) + { + type = NewPointer(type); + flags |= VARF_Ref; + } + else if (type == TypeVector2) + { + elementcount = 2; + } + else if (type == TypeVector3) + { + elementcount = 3; + } + } + if (type->GetRegType() == REGT_NIL && type != TypeVector2 && type != TypeVector3) + { + Error(p, "Invalid type %s for function parameter", type->DescriptiveName()); + } + else if (p->Default != nullptr) + { + flags |= VARF_Optional; + hasoptionals = true; + // The simplifier is not suited to convert the constant into something usable. + // All it does is reduce the expression to a constant but we still got to do proper type checking and conversion. + // It will also lose important type info about enums, once these get implemented + // The code generator can do this properly for us. + FxExpression *x = new FxTypeCast(ConvertNode(p->Default), type, false); + FCompileContext ctx(c->Type(), false); + x = x->Resolve(ctx); + + if (x != nullptr) + { + // Vectors need special treatment because they use more than one entry in the Defaults and do not report as actual constants + if (type == TypeVector2 && x->ExprType == EFX_VectorValue && static_cast(x)->isConstVector(2)) + { + auto vx = static_cast(x); + vmval[0] = static_cast(vx->xyz[0])->GetValue().GetFloat(); + vmval[1] = static_cast(vx->xyz[1])->GetValue().GetFloat(); + } + else if (type == TypeVector3 && x->ExprType == EFX_VectorValue && static_cast(x)->isConstVector(3)) + { + auto vx = static_cast(x); + vmval[0] = static_cast(vx->xyz[0])->GetValue().GetFloat(); + vmval[1] = static_cast(vx->xyz[1])->GetValue().GetFloat(); + vmval[2] = static_cast(vx->xyz[2])->GetValue().GetFloat(); + } + else if (!x->isConstant()) + { + Error(p, "Default parameter %s is not constant in %s", FName(p->Name).GetChars(), FName(f->Name).GetChars()); + } + else if (x->ValueType != type) + { + Error(p, "Default parameter %s could not be converted to target type %s", FName(p->Name).GetChars(), c->Type()->TypeName.GetChars()); + } + else + { + auto cnst = static_cast(x); + hasdefault = true; + switch (type->GetRegType()) + { + case REGT_INT: + vmval[0] = cnst->GetValue().GetInt(); + break; + + case REGT_FLOAT: + vmval[0] = cnst->GetValue().GetFloat(); + break; + + case REGT_POINTER: + if (type->IsKindOf(RUNTIME_CLASS(PClassPointer))) + vmval[0] = (DObject*)cnst->GetValue().GetPointer(); + else + vmval[0] = cnst->GetValue().GetPointer(); + break; + + case REGT_STRING: + vmval[0] = cnst->GetValue().GetString(); + break; + + default: + assert(0 && "no valid type for constant"); + break; + } + } + } + if (x != nullptr) delete x; + } + else if (hasoptionals) + { + Error(p, "All arguments after the first optional one need also be optional."); + } + // TBD: disallow certain types? For now, let everything pass that isn't an array. + args.Push(type); + argflags.Push(flags); + argnames.Push(p->Name); + + } + else + { + args.Push(nullptr); + argflags.Push(0); + argnames.Push(NAME_None); + } + for (int i = 0; i(p->SiblingNext); + } while (p != f->Params); + } + + PFunction *sym = new PFunction(c->Type(), f->Name); + sym->AddVariant(NewPrototype(rets, args), argflags, argnames, afd == nullptr ? nullptr : *(afd->VMPointer), varflags, useflags); + c->Type()->Symbols.ReplaceSymbol(sym); + + if (!(f->Flags & ZCC_Native)) + { + auto code = ConvertAST(c->Type(), f->Body); + if (code != nullptr) + { + sym->Variants[0].Implementation = FunctionBuildList.AddFunction(sym, code, FStringf("%s.%s", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()), false, -1, 0, Lump); + } + } + if (sym->Variants[0].Implementation != nullptr && hasdefault) // do not copy empty default lists, they only waste space and processing time. + { + sym->Variants[0].Implementation->DefaultArgs = std::move(argdefaults); + } + + if (varflags & VARF_Virtual) + { + if (varflags & VARF_Final) + { + sym->Variants[0].Implementation->Final = true; + } + if (forclass) + { + PClass *clstype = static_cast(c->Type()); + int vindex = clstype->FindVirtualIndex(sym->SymbolName, sym->Variants[0].Proto); + // specifying 'override' is necessary to prevent one of the biggest problem spots with virtual inheritance: Mismatching argument types. + if (varflags & VARF_Override) + { + if (vindex == -1) + { + Error(p, "Attempt to override non-existent virtual function %s", FName(f->Name).GetChars()); + } + else + { + auto oldfunc = clstype->Virtuals[vindex]; + if (oldfunc->Final) + { + Error(p, "Attempt to override final function %s", FName(f->Name).GetChars()); + } + clstype->Virtuals[vindex] = sym->Variants[0].Implementation; + sym->Variants[0].Implementation->VirtualIndex = vindex; + } + } + else + { + if (vindex != -1) + { + Error(p, "Function %s attempts to override parent function without 'override' qualifier", FName(f->Name).GetChars()); + } + sym->Variants[0].Implementation->VirtualIndex = clstype->Virtuals.Push(sym->Variants[0].Implementation); + } + } + else + { + Error(p, "Virtual functions can only be defined for classes"); + } + } + } +} + //========================================================================== // // Parses the functions list @@ -1997,11 +2326,13 @@ void ZCCCompiler::InitDefaults() void ZCCCompiler::InitFunctions() { - TArray rets(1); - TArray args; - TArray argflags; - TArray argdefaults; - TArray argnames; + for (auto s : Structs) + { + for (auto f : s->Functions) + { + CompileFunction(s, f, false); + } + } for (auto c : Classes) { @@ -2017,306 +2348,7 @@ void ZCCCompiler::InitFunctions() } for (auto f : c->Functions) { - rets.Clear(); - args.Clear(); - argflags.Clear(); - bool hasdefault = false; - // For the time being, let's not allow overloading. This may be reconsidered later but really just adds an unnecessary amount of complexity here. - if (AddTreeNode(f->Name, f, &c->TreeNodes, false)) - { - auto t = f->Type; - if (t != nullptr) - { - do - { - auto type = DetermineType(c->Type(), f, f->Name, t, false, false); - if (type->IsKindOf(RUNTIME_CLASS(PStruct)) && type != TypeVector2 && type != TypeVector3) - { - // structs and classes only get passed by pointer. - type = NewPointer(type); - } - // TBD: disallow certain types? For now, let everything pass that isn't an array. - rets.Push(type); - t = static_cast(t->SiblingNext); - } while (t != f->Type); - } - - int notallowed = ZCC_Latent | ZCC_Meta | ZCC_ReadOnly | ZCC_FuncConst | ZCC_Abstract; - - if (f->Flags & notallowed) - { - Error(f, "Invalid qualifiers for %s (%s not allowed)", FName(f->Name).GetChars(), FlagsToString(f->Flags & notallowed).GetChars()); - f->Flags &= notallowed; - } - uint32_t varflags = VARF_Method; - int implicitargs = 1; - AFuncDesc *afd = nullptr; - int useflags = SUF_ACTOR | SUF_OVERLAY | SUF_WEAPON | SUF_ITEM; - if (f->UseFlags != nullptr) - { - useflags = 0; - auto p = f->UseFlags; - do - { - switch (p->Id) - { - case NAME_Actor: - useflags |= SUF_ACTOR; - break; - case NAME_Overlay: - useflags |= SUF_OVERLAY; - break; - case NAME_Weapon: - useflags |= SUF_WEAPON; - break; - case NAME_Item: - useflags |= SUF_ITEM; - break; - default: - Error(p, "Unknown Action qualifier %s", FName(p->Id).GetChars()); - break; - } - - p = static_cast(p->SiblingNext); - } while (p != f->UseFlags); - } - - // map to implementation flags. - if (f->Flags & ZCC_Private) varflags |= VARF_Private; - if (f->Flags & ZCC_Protected) varflags |= VARF_Protected; - if (f->Flags & ZCC_Deprecated) varflags |= VARF_Deprecated; - if (f->Flags & ZCC_Virtual) varflags |= VARF_Virtual; - if (f->Flags & ZCC_Override) varflags |= VARF_Override; - if (f->Flags & ZCC_Action) - { - varflags |= VARF_Final; // Action implies Final. - if (useflags & (SUF_OVERLAY | SUF_WEAPON | SUF_ITEM)) - { - varflags |= VARF_Action; - implicitargs = 3; - } - else - { - implicitargs = 1; - } - } - if (f->Flags & ZCC_Static) varflags = (varflags & ~VARF_Method) | VARF_Final, implicitargs = 0; // Static implies Final. - - - if (varflags & VARF_Override) varflags &= ~VARF_Virtual; // allow 'virtual override'. - // Only one of these flags may be used. - static int exclude[] = { ZCC_Virtual, ZCC_Override, ZCC_Action, ZCC_Static }; - static const char * print[] = { "virtual", "override", "action", "static" }; - int fc = 0; - FString build; - for (int i = 0; i < 4; i++) - { - if (f->Flags & exclude[i]) - { - fc++; - if (build.Len() > 0) build += ", "; - build += print[i]; - } - } - if (fc > 1) - { - Error(f, "Invalid combination of qualifiers %s on function %s.", FName(f->Name).GetChars(), build.GetChars() ); - varflags |= VARF_Method; - } - if (varflags & VARF_Override) varflags |= VARF_Virtual; // Now that the flags are checked, make all override functions virtual as well. - - if (f->Flags & ZCC_Native) - { - varflags |= VARF_Native; - afd = FindFunction(c->Type(), FName(f->Name).GetChars()); - if (afd == nullptr) - { - Error(f, "The function '%s' has not been exported from the executable.", FName(f->Name).GetChars()); - } - else - { - (*afd->VMPointer)->ImplicitArgs = BYTE(implicitargs); - } - } - SetImplicitArgs(&args, &argflags, &argnames, c->Type(), varflags, useflags); - argdefaults.Resize(argnames.Size()); - auto p = f->Params; - bool hasoptionals = false; - if (p != nullptr) - { - do - { - int elementcount = 1; - VMValue vmval[3]; // default is REGT_NIL which means 'no default value' here. - if (p->Type != nullptr) - { - auto type = DetermineType(c->Type(), p, f->Name, p->Type, false, false); - int flags = 0; - if (p->Flags & ZCC_In) flags |= VARF_In; - if (p->Flags & ZCC_Out) flags |= VARF_Out; - if ((type->IsA(RUNTIME_CLASS(PStruct))) || (flags & VARF_Out)) - { - // 'out' parameters and all structs except vectors are passed by reference - if ((flags & VARF_Out) || (type != TypeVector2 && type != TypeVector3)) - { - type = NewPointer(type); - flags |= VARF_Ref; - } - else if (type == TypeVector2) - { - elementcount = 2; - } - else if (type == TypeVector3) - { - elementcount = 3; - } - } - if (type->GetRegType() == REGT_NIL && type != TypeVector2 && type != TypeVector3) - { - Error(p, "Invalid type %s for function parameter", type->DescriptiveName()); - } - else if (p->Default != nullptr) - { - flags |= VARF_Optional; - hasoptionals = true; - // The simplifier is not suited to convert the constant into something usable. - // All it does is reduce the expression to a constant but we still got to do proper type checking and conversion. - // It will also lose important type info about enums, once these get implemented - // The code generator can do this properly for us. - FxExpression *x = new FxTypeCast(ConvertNode(p->Default), type, false); - FCompileContext ctx(c->Type(), false); - x = x->Resolve(ctx); - - if (x != nullptr) - { - // Vectors need special treatment because they use more than one entry in the Defaults and do not report as actual constants - if (type == TypeVector2 && x->ExprType == EFX_VectorValue && static_cast(x)->isConstVector(2)) - { - auto vx = static_cast(x); - vmval[0] = static_cast(vx->xyz[0])->GetValue().GetFloat(); - vmval[1] = static_cast(vx->xyz[1])->GetValue().GetFloat(); - } - else if (type == TypeVector3 && x->ExprType == EFX_VectorValue && static_cast(x)->isConstVector(3)) - { - auto vx = static_cast(x); - vmval[0] = static_cast(vx->xyz[0])->GetValue().GetFloat(); - vmval[1] = static_cast(vx->xyz[1])->GetValue().GetFloat(); - vmval[2] = static_cast(vx->xyz[2])->GetValue().GetFloat(); - } - else if (!x->isConstant()) - { - Error(p, "Default parameter %s is not constant in %s", FName(p->Name).GetChars(), FName(f->Name).GetChars()); - } - else if (x->ValueType != type) - { - Error(p, "Default parameter %s could not be converted to target type %s", FName(p->Name).GetChars(), c->Type()->TypeName.GetChars()); - } - else - { - auto cnst = static_cast(x); - hasdefault = true; - switch (type->GetRegType()) - { - case REGT_INT: - vmval[0] = cnst->GetValue().GetInt(); - break; - - case REGT_FLOAT: - vmval[0] = cnst->GetValue().GetFloat(); - break; - - case REGT_POINTER: - if (type->IsKindOf(RUNTIME_CLASS(PClassPointer))) - vmval[0] = (DObject*)cnst->GetValue().GetPointer(); - else - vmval[0] = cnst->GetValue().GetPointer(); - break; - - case REGT_STRING: - vmval[0] = cnst->GetValue().GetString(); - break; - - default: - assert(0 && "no valid type for constant"); - break; - } - } - } - if (x != nullptr) delete x; - } - else if (hasoptionals) - { - Error(p, "All arguments after the first optional one need also be optional."); - } - // TBD: disallow certain types? For now, let everything pass that isn't an array. - args.Push(type); - argflags.Push(flags); - argnames.Push(p->Name); - - } - else - { - args.Push(nullptr); - argflags.Push(0); - argnames.Push(NAME_None); - } - for(int i=0;i(p->SiblingNext); - } while (p != f->Params); - } - - PFunction *sym = new PFunction(c->Type(), f->Name); - sym->AddVariant(NewPrototype(rets, args), argflags, argnames, afd == nullptr? nullptr : *(afd->VMPointer), varflags, useflags); - c->Type()->Symbols.ReplaceSymbol(sym); - - if (!(f->Flags & ZCC_Native)) - { - auto code = ConvertAST(c->Type(), f->Body); - if (code != nullptr) - { - sym->Variants[0].Implementation = FunctionBuildList.AddFunction(sym, code, FStringf("%s.%s", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()), false, -1, 0, Lump); - } - } - if (sym->Variants[0].Implementation != nullptr && hasdefault) // do not copy empty default lists, they only waste space and processing time. - { - sym->Variants[0].Implementation->DefaultArgs = std::move(argdefaults); - } - - if (varflags & VARF_Virtual) - { - if (varflags & VARF_Final) - { - sym->Variants[0].Implementation->Final = true; - } - int vindex = c->Type()->FindVirtualIndex(sym->SymbolName, sym->Variants[0].Proto); - // specifying 'override' is necessary to prevent one of the biggest problem spots with virtual inheritance: Mismatching argument types. - if (varflags & VARF_Override) - { - if (vindex == -1) - { - Error(p, "Attempt to override non-existent virtual function %s", FName(f->Name).GetChars()); - } - else - { - auto oldfunc = c->Type()->Virtuals[vindex]; - if (oldfunc->Final) - { - Error(p, "Attempt to override final function %s", FName(f->Name).GetChars()); - } - c->Type()->Virtuals[vindex] = sym->Variants[0].Implementation; - sym->Variants[0].Implementation->VirtualIndex = vindex; - } - } - else - { - if (vindex != -1) - { - Error(p, "Function %s attempts to override parent function without 'override' qualifier", FName(f->Name).GetChars()); - } - sym->Variants[0].Implementation->VirtualIndex = c->Type()->Virtuals.Push(sym->Variants[0].Implementation); - } - } - } + CompileFunction(c, f, true); } } } @@ -2368,7 +2400,9 @@ FxExpression *ZCCCompiler::SetupActionFunction(PClass *cls, ZCC_TreeNode *af) { FArgumentList argumentlist; // We can use this function directly without wrapping it in a caller. - if ((afd->Variants[0].Flags & VARF_Action) || !cls->IsDescendantOf(RUNTIME_CLASS(AStateProvider)) || !afd->Variants[0].SelfClass->IsDescendantOf(RUNTIME_CLASS(AStateProvider))) + auto selfclass = dyn_cast(afd->Variants[0].SelfClass); + assert(selfclass != nullptr); // non classes are not supposed to get here. + if ((afd->Variants[0].Flags & VARF_Action) || !cls->IsDescendantOf(RUNTIME_CLASS(AStateProvider)) || !selfclass->IsDescendantOf(RUNTIME_CLASS(AStateProvider))) { return new FxVMFunctionCall(new FxSelf(*af), afd, argumentlist, *af, false); } @@ -2663,7 +2697,7 @@ void ZCCCompiler::CompileStates() // //========================================================================== -FxExpression *ZCCCompiler::ConvertAST(PClass *cls, ZCC_TreeNode *ast) +FxExpression *ZCCCompiler::ConvertAST(PStruct *cls, ZCC_TreeNode *ast) { ConvertClass = cls; // there are two possibilities here: either a single function call or a compound statement. For a compound statement we also need to check if the last thing added was a return. diff --git a/src/scripting/zscript/zcc_compile.h b/src/scripting/zscript/zcc_compile.h index 2e8840a46..84e314353 100644 --- a/src/scripting/zscript/zcc_compile.h +++ b/src/scripting/zscript/zcc_compile.h @@ -20,6 +20,11 @@ struct ZCC_StructWork TArray Enums; TArray Constants; TArray Fields; + TArray Functions; + + ZCC_StructWork() + { + } ZCC_StructWork(ZCC_Struct * s, PSymbolTreeNode *n, ZCC_Class *outer) { @@ -41,34 +46,25 @@ struct ZCC_StructWork }; -struct ZCC_ClassWork +struct ZCC_ClassWork : public ZCC_StructWork { ZCC_Class *cls; - PSymbolTable TreeNodes; - PSymbolTreeNode *node; - TArray Enums; - TArray Constants; - TArray Fields; TArray Defaults; - TArray Functions; TArray States; ZCC_ClassWork(ZCC_Class * s, PSymbolTreeNode *n) { + strct = s; cls = s; node = n; - } - - FName NodeName() const - { - return cls->NodeName; + OuterDef = nullptr; + Outer = nullptr; } PClass *Type() { - return cls->Type; + return static_cast(strct->Type); } - }; struct ZCC_ConstantWork @@ -108,6 +104,7 @@ private: int GetInt(ZCC_Expression *expr); double GetDouble(ZCC_Expression *expr); const char *GetString(ZCC_Expression *expr, bool silent = false); + void CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool forclass); void InitFunctions(); void CompileStates(); @@ -142,12 +139,12 @@ private: void Error(ZCC_TreeNode *node, const char *msg, ...); void MessageV(ZCC_TreeNode *node, const char *txtcolor, const char *msg, va_list argptr); - FxExpression *ConvertAST(PClass *cclass, ZCC_TreeNode *ast); + FxExpression *ConvertAST(PStruct *cclass, ZCC_TreeNode *ast); FxExpression *ConvertNode(ZCC_TreeNode *node); FArgumentList &ConvertNodeList(FArgumentList &, ZCC_TreeNode *head); DObject *Outer; - PClass *ConvertClass; // class type to be used when resoving symbold while converting an AST + PStruct *ConvertClass; // class type to be used when resoving symbols while converting an AST PSymbolTable *GlobalTreeNodes; PSymbolTable *OutputSymbols; ZCC_AST &AST; diff --git a/src/scripting/zscript/zcc_parser.h b/src/scripting/zscript/zcc_parser.h index 070bef449..dd777eb6c 100644 --- a/src/scripting/zscript/zcc_parser.h +++ b/src/scripting/zscript/zcc_parser.h @@ -202,19 +202,19 @@ struct ZCC_NamedNode : ZCC_TreeNode PSymbolType *Symbol; }; -struct ZCC_Class : ZCC_NamedNode +struct ZCC_Struct : ZCC_NamedNode +{ + VM_UWORD Flags; + ZCC_TreeNode *Body; + PStruct *Type; +}; + +struct ZCC_Class : ZCC_Struct { ZCC_Identifier *ParentName; ZCC_Identifier *Replaces; - VM_UWORD Flags; - ZCC_TreeNode *Body; - PClass *Type; -}; -struct ZCC_Struct : ZCC_NamedNode -{ - ZCC_TreeNode *Body; - PStruct *Type; + PClass *CType() { return static_cast(Type); } }; struct ZCC_Enum : ZCC_NamedNode From 9fab8380ffeb6a59a4dfa4afa8ed2fca178370fd Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 19 Nov 2016 12:22:58 +0100 Subject: [PATCH 035/185] - fixed: FxVMFunctionCall::GetDirectFunction did not check if the function could be called with no arguments. --- src/scripting/codegeneration/codegen.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index a7be26f29..fe571ee41 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -7066,6 +7066,8 @@ VMFunction *FxVMFunctionCall::GetDirectFunction() // it inside VM code. if (ArgList.Size() == 0 && !(Function->Variants[0].Flags & VARF_Virtual)) { + unsigned imp = Function->GetImplicitArgs(); + if (Function->Variants[0].ArgFlags.Size() <= imp || !(Function->Variants[0].ArgFlags[imp] & VARF_Optional)) return nullptr; return Function->Variants[0].Implementation; } From 25e285b65d2e6f2ebef361267c89c83e828f5b1b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 19 Nov 2016 12:25:53 +0100 Subject: [PATCH 036/185] - fixed bad conversion from FString to const char * in state label type cast. --- src/scripting/codegeneration/codegen.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index fe571ee41..8fa8f4554 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -1440,8 +1440,8 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx) // Right now this only supports string constants. There should be an option to pass a string variable, too. if (basex->isConstant() && (basex->ValueType == TypeString || basex->ValueType == TypeName)) { - const char *s = static_cast(basex)->GetValue().GetString(); - if (*s == 0 && !ctx.FromDecorate) // DECORATE should never get here at all, but let's better be safe. + FString s= static_cast(basex)->GetValue().GetString(); + if (s.Len() == 0 && !ctx.FromDecorate) // DECORATE should never get here at all, but let's better be safe. { ScriptPosition.Message(MSG_ERROR, "State jump to empty label."); delete this; From de8cacc4653ceebe19e33b6555834afd5a53dd55 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 19 Nov 2016 12:41:00 +0100 Subject: [PATCH 037/185] - for struct member calls an address request is needed. --- src/scripting/codegeneration/codegen.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 8fa8f4554..4a8f4b55b 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -7185,6 +7185,12 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) { ValueType = TypeVoid; } + // If self is a struct, it will be a value type, not a reference, so we need to make an addresss request. + if (Self != nullptr && Self->ValueType->IsKindOf(RUNTIME_CLASS(PStruct)) && !Self->ValueType->IsKindOf(RUNTIME_CLASS(PClass))) + { + bool writable; + Self->RequestAddress(ctx, &writable); + } return this; } From d50da34664d40b4789d53d7146e422c13b1390e0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 19 Nov 2016 13:56:29 +0100 Subject: [PATCH 038/185] - scriptified the pistol to test if struct member functions work. - made APlayerPawn::PlayAttacking(2) virtual script functions so that mods have better control over player animations. Note that these have no native base so they skip the templated interface for managing virtual functions. --- src/dobjtype.cpp | 2 +- src/g_doom/a_doomweaps.cpp | 57 +++++------ src/p_pspr.cpp | 39 ++++---- src/p_pspr.h | 2 - src/p_user.cpp | 14 ++- src/scripting/codegeneration/codegen.cpp | 29 ++++-- src/scripting/vm/vm.h | 6 +- src/virtual.h | 20 ++-- wadsrc/static/zscript.txt | 1 + wadsrc/static/zscript/actor.txt | 1 + wadsrc/static/zscript/constants.txt | 1 + wadsrc/static/zscript/doom/doomweapons.txt | 47 --------- wadsrc/static/zscript/doom/weaponpistol.txt | 100 ++++++++++++++++++++ wadsrc/static/zscript/shared/inventory.txt | 1 - wadsrc/static/zscript/shared/player.txt | 20 ++++ 15 files changed, 214 insertions(+), 126 deletions(-) create mode 100644 wadsrc/static/zscript/doom/weaponpistol.txt diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 682cc0fd5..5154d1689 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2535,7 +2535,7 @@ unsigned PFunction::AddVariant(PPrototype *proto, TArray &argflags, TArra assert(proto->ArgumentTypes.Size() > 0); auto selftypeptr = dyn_cast(proto->ArgumentTypes[0]); assert(selftypeptr != nullptr); - variant.SelfClass = dyn_cast(selftypeptr->PointedType); + variant.SelfClass = dyn_cast(selftypeptr->PointedType); assert(variant.SelfClass != nullptr); } else diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp index 95ae4dfb6..77085f5b5 100644 --- a/src/g_doom/a_doomweaps.cpp +++ b/src/g_doom/a_doomweaps.cpp @@ -22,40 +22,6 @@ static FRandom pr_firerail ("FireRail"); static FRandom pr_bfgspray ("BFGSpray"); static FRandom pr_oldbfg ("OldBFG"); -// -// A_FirePistol -// -DEFINE_ACTION_FUNCTION(AActor, A_FirePistol) -{ - PARAM_ACTION_PROLOGUE(AActor); - - bool accurate; - - if (self->player != nullptr) - { - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != nullptr && ACTION_CALL_FROM_PSPRITE()) - { - if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1)) - return 0; - - P_SetPsprite(self->player, PSP_FLASH, weapon->FindState(NAME_Flash), true); - } - self->player->mo->PlayAttacking2 (); - - accurate = !self->player->refire; - } - else - { - accurate = true; - } - - S_Sound (self, CHAN_WEAPON, "weapons/pistol", 1, ATTN_NORM); - - P_GunShot (self, accurate, PClass::FindActor(NAME_BulletPuff), P_BulletSlope (self)); - return 0; -} - // // A_Saw // @@ -71,6 +37,29 @@ enum SAW_Flags SF_STEALARMOR = 128, }; + +static FRandom pr_gunshot("GunShot"); +// +// P_GunShot +// +void P_GunShot(AActor *mo, bool accurate, PClassActor *pufftype, DAngle pitch) +{ + DAngle angle; + int damage; + + damage = 5 * (pr_gunshot() % 3 + 1); + angle = mo->Angles.Yaw; + + if (!accurate) + { + angle += pr_gunshot.Random2() * (5.625 / 256); + } + + P_LineAttack(mo, angle, PLAYERMISSILERANGE, pitch, damage, NAME_Hitscan, pufftype); +} + + + DEFINE_ACTION_FUNCTION(AActor, A_Saw) { PARAM_ACTION_PROLOGUE(AActor); diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 1ba452b2b..d47156d16 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -79,7 +79,6 @@ CVAR(Int, sv_fastweapons, false, CVAR_SERVERINFO); // PRIVATE DATA DEFINITIONS ------------------------------------------------ static FRandom pr_wpnreadysnd ("WpnReadySnd"); -static FRandom pr_gunshot ("GunShot"); static const FGenericButtons ButtonChecks[] = { @@ -184,6 +183,16 @@ void P_SetPsprite(player_t *player, PSPLayers id, FState *state, bool pending) player->GetPSprite(id)->SetState(state, pending); } +DEFINE_ACTION_FUNCTION(_Player, SetPSprite) // the underscore is needed to get past the name mangler which removes the first clas name character to match the class representation (needs to be fixed in a later commit) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + PARAM_INT(id); + PARAM_POINTER(state, FState); + PARAM_BOOL_DEF(pending); + P_SetPsprite(self, (PSPLayers)id, state, pending); + return 0; +} + DPSprite *player_t::GetPSprite(PSPLayers layer) { AActor *oldcaller = nullptr; @@ -1381,6 +1390,15 @@ DAngle P_BulletSlope (AActor *mo, FTranslatedLineTarget *pLineTarget, int aimfla return pitch; } +DEFINE_ACTION_FUNCTION(AActor, BulletSlope) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_POINTER_DEF(t, FTranslatedLineTarget); + PARAM_INT_DEF(aimflags); + ACTION_RETURN_FLOAT(P_BulletSlope(self, t, aimflags).Degrees); +} + + AActor *P_AimTarget(AActor *mo) { FTranslatedLineTarget t; @@ -1395,25 +1413,6 @@ DEFINE_ACTION_FUNCTION(AActor, AimTarget) } -// -// P_GunShot -// -void P_GunShot (AActor *mo, bool accurate, PClassActor *pufftype, DAngle pitch) -{ - DAngle angle; - int damage; - - damage = 5*(pr_gunshot()%3+1); - angle = mo->Angles.Yaw; - - if (!accurate) - { - angle += pr_gunshot.Random2 () * (5.625 / 256); - } - - P_LineAttack (mo, angle, PLAYERMISSILERANGE, pitch, damage, NAME_Hitscan, pufftype); -} - DEFINE_ACTION_FUNCTION(AActor, A_Light) { PARAM_SELF_PROLOGUE(AActor); diff --git a/src/p_pspr.h b/src/p_pspr.h index d75f08b06..3c8f0097e 100644 --- a/src/p_pspr.h +++ b/src/p_pspr.h @@ -111,8 +111,6 @@ void P_BobWeapon (player_t *player, float *x, float *y, double ticfrac); DAngle P_BulletSlope (AActor *mo, FTranslatedLineTarget *pLineTarget = NULL, int aimflags = 0); AActor *P_AimTarget(AActor *mo); -void P_GunShot (AActor *mo, bool accurate, PClassActor *pufftype, DAngle pitch); - void DoReadyWeapon(AActor *self); void DoReadyWeaponToBob(AActor *self); void DoReadyWeaponToFire(AActor *self, bool primary = true, bool secondary = true); diff --git a/src/p_user.cpp b/src/p_user.cpp index 00e58e5ef..6f58f3cc8 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -1280,12 +1280,22 @@ void APlayerPawn::PlayRunning () void APlayerPawn::PlayAttacking () { - if (MissileState != NULL) SetState (MissileState); + static int VIndex = -1; + if (VIndex < 0) VIndex = GetVirtualIndex(RUNTIME_CLASS(APlayerPawn), "PlayAttacking"); + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { (DObject*)this }; + VMFrameStack stack; + stack.Call(this->GetClass()->Virtuals[VIndex], params, 1, nullptr, 0, nullptr); } void APlayerPawn::PlayAttacking2 () { - if (MeleeState != NULL) SetState (MeleeState); + static int VIndex = -1; + if (VIndex < 0) VIndex = GetVirtualIndex(RUNTIME_CLASS(APlayerPawn), "PlayAttacking2"); + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { (DObject*)this }; + VMFrameStack stack; + stack.Call(this->GetClass()->Virtuals[VIndex], params, 1, nullptr, 0, nullptr); } void APlayerPawn::ThrowPoisonBag () diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 4a8f4b55b..3577ac1ec 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -6706,7 +6706,7 @@ FxMemberFunctionCall::~FxMemberFunctionCall() FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) { ABORT(ctx.Class); - PClass *cls; + PStruct *cls; bool staticonly = false; bool novirtual = false; @@ -6714,11 +6714,19 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) { // If the left side is a class name for a static member function call it needs to be resolved manually // because the resulting value type would cause problems in nearly every other place where identifiers are being used. - cls = PClass::FindClass(static_cast(Self)->Identifier); - if (cls != nullptr && cls->bExported) + PClass *ccls = PClass::FindClass(static_cast(Self)->Identifier); + if (ccls != nullptr) { - staticonly = true; - goto isresolved; + if (ccls->bExported) + { + cls = ccls; + staticonly = true; + goto isresolved; + } + } + else + { + // Todo: static struct members need to work as well. } } SAFE_RESOLVE(Self, ctx); @@ -6755,9 +6763,9 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) { auto ptype = static_cast(Self->ValueType)->PointedType; - if (ptype->IsKindOf(RUNTIME_CLASS(PClass))) + if (ptype->IsKindOf(RUNTIME_CLASS(PStruct))) { - cls = static_cast(ptype); + cls = static_cast(ptype); } else { @@ -6773,6 +6781,8 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) return nullptr; } + // Todo: handle member calls from instantiated structs. + isresolved: bool error = false; PFunction *afd = FindClassMemberFunction(cls, ctx.Class, MethodName, ScriptPosition, &error); @@ -6792,7 +6802,8 @@ isresolved: if (staticonly && (afd->Variants[0].Flags & VARF_Method)) { auto clstype = dyn_cast(ctx.Class); - if (clstype == nullptr || !clstype->IsDescendantOf(cls)) + auto ccls = dyn_cast(cls); + if (clstype == nullptr || ccls == nullptr || !clstype->IsDescendantOf(ccls)) { ScriptPosition.Message(MSG_ERROR, "Cannot call non-static function %s::%s from here\n", cls->TypeName.GetChars(), MethodName.GetChars()); delete this; @@ -7067,7 +7078,7 @@ VMFunction *FxVMFunctionCall::GetDirectFunction() if (ArgList.Size() == 0 && !(Function->Variants[0].Flags & VARF_Virtual)) { unsigned imp = Function->GetImplicitArgs(); - if (Function->Variants[0].ArgFlags.Size() <= imp || !(Function->Variants[0].ArgFlags[imp] & VARF_Optional)) return nullptr; + if (Function->Variants[0].ArgFlags.Size() > imp && !(Function->Variants[0].ArgFlags[imp] & VARF_Optional)) return nullptr; return Function->Variants[0].Implementation; } diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 407080f2c..670c5a982 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -1032,8 +1032,6 @@ struct AFuncDesc // change every single use in case the parameters change. #define DECLARE_ACTION(name) extern VMNativeFunction *AActor_##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) \ static int AF_##cls##_##name(VM_ARGS); \ VMNativeFunction *cls##_##name##_VMPtr; \ @@ -1077,6 +1075,10 @@ void CallAction(VMFrameStack *stack, VMFunction *vmfunc, AActor *self); PARAM_PROLOGUE; \ PARAM_OBJECT(self, type); +// for structs we need to check for ATAG_GENERIC instead of ATAG_OBJECT +#define PARAM_SELF_STRUCT_PROLOGUE(type) \ + PARAM_PROLOGUE; \ + PARAM_POINTER(self, type); class PFunction; diff --git a/src/virtual.h b/src/virtual.h index d3a2bfa3a..e0679df74 100644 --- a/src/virtual.h +++ b/src/virtual.h @@ -37,6 +37,17 @@ VMEXPORTED_NATIVES_START VMEXPORTED_NATIVES_FUNC(PostBeginPlay) VMEXPORTED_NATIVES_END + +inline int GetVirtualIndex(PClass *cls, const char *funcname) +{ + // Look up the virtual function index in the defining class because this may have gotten overloaded in subclasses with something different than a virtual override. + auto sym = dyn_cast(cls->Symbols.FindSymbol(funcname, false)); + assert(sym != nullptr); + auto VIndex = sym->Variants[0].Implementation->VirtualIndex; + assert(VIndex >= 0); + return VIndex; +} + template class DVMObject : public T { @@ -79,14 +90,7 @@ public: else { static int VIndex = -1; - if (VIndex < 0) - { - // Look up the virtual function index in the defining class because this may have gotten overloaded in subclasses with something different than a virtual override. - auto sym = dyn_cast(RUNTIME_CLASS(DObject)->Symbols.FindSymbol("Destroy", false)); - assert(sym != nullptr); - VIndex = sym->Variants[0].Implementation->VirtualIndex; - assert(VIndex >= 0); - } + if (VIndex < 0) VIndex = GetVirtualIndex(RUNTIME_CLASS(DObject), "Destroy"); // Without the type cast this picks the 'void *' assignment... VMValue params[1] = { (DObject*)this }; VMFrameStack stack; diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 14493875a..2f5a420a3 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -49,6 +49,7 @@ zscript/doom/spidermaster.txt zscript/doom/keen.txt zscript/doom/bossbrain.txt zscript/doom/weaponfist.txt +zscript/doom/weaponpistol.txt zscript/doom/deadthings.txt zscript/doom/doomammo.txt diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 744128cdd..0fd6d2282 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -78,6 +78,7 @@ class Actor : Thinker native native void SetXYZ(vector3 newpos); native Actor GetPointer(int aaptr); native void FaceMovementDirection(); + native double BulletSlope(out FTranslatedLineTarget pLineTarget = null, int aimflags = 0); native Actor AimTarget(); native bool CheckMissileSpawn(double maxdist); native bool CheckPosition(Vector2 pos, bool actorsonly = false); diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index cf0cbdc5c..cfdc98425 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -711,6 +711,7 @@ enum EPSpriteFlags // Default psprite layers enum EPSPLayers { + PSP_STRIFEHANDS = -1, PSP_WEAPON = 1, PSP_FLASH = 1000, }; diff --git a/wadsrc/static/zscript/doom/doomweapons.txt b/wadsrc/static/zscript/doom/doomweapons.txt index b75cfa967..60b5ba157 100644 --- a/wadsrc/static/zscript/doom/doomweapons.txt +++ b/wadsrc/static/zscript/doom/doomweapons.txt @@ -13,53 +13,6 @@ class DoomWeapon : Weapon } -// -------------------------------------------------------------------------- -// -// Pistol -// -// -------------------------------------------------------------------------- - -class Pistol : DoomWeapon -{ - Default - { - Weapon.SelectionOrder 1900; - Weapon.AmmoUse 1; - Weapon.AmmoGive 20; - Weapon.AmmoType "Clip"; - Obituary "$OB_MPPISTOL"; - +WEAPON.WIMPY_WEAPON - Inventory.Pickupmessage "$PICKUP_PISTOL_DROPPED"; - Tag "$TAG_PISTOL"; - } - States - { - Ready: - PISG A 1 A_WeaponReady; - Loop; - Deselect: - PISG A 1 A_Lower; - Loop; - Select: - PISG A 1 A_Raise; - Loop; - Fire: - PISG A 4; - PISG B 6 A_FirePistol; - PISG C 4; - PISG B 5 A_ReFire; - Goto Ready; - Flash: - PISF A 7 Bright A_Light1; - Goto LightDone; - PISF A 7 Bright A_Light1; - Goto LightDone; - Spawn: - PIST A -1; - Stop; - } -} - // -------------------------------------------------------------------------- // // Chainsaw diff --git a/wadsrc/static/zscript/doom/weaponpistol.txt b/wadsrc/static/zscript/doom/weaponpistol.txt new file mode 100644 index 000000000..45a1ebecd --- /dev/null +++ b/wadsrc/static/zscript/doom/weaponpistol.txt @@ -0,0 +1,100 @@ +// -------------------------------------------------------------------------- +// +// Pistol +// +// -------------------------------------------------------------------------- + +class Pistol : DoomWeapon +{ + Default + { + Weapon.SelectionOrder 1900; + Weapon.AmmoUse 1; + Weapon.AmmoGive 20; + Weapon.AmmoType "Clip"; + Obituary "$OB_MPPISTOL"; + +WEAPON.WIMPY_WEAPON + Inventory.Pickupmessage "$PICKUP_PISTOL_DROPPED"; + Tag "$TAG_PISTOL"; + } + States + { + Ready: + PISG A 1 A_WeaponReady; + Loop; + Deselect: + PISG A 1 A_Lower; + Loop; + Select: + PISG A 1 A_Raise; + Loop; + Fire: + PISG A 4; + PISG B 6 A_FirePistol; + PISG C 4; + PISG B 5 A_ReFire; + Goto Ready; + Flash: + PISF A 7 Bright A_Light1; + Goto LightDone; + PISF A 7 Bright A_Light1; + Goto LightDone; + Spawn: + PIST A -1; + Stop; + } +} + +//=========================================================================== +// +// Code (must be attached to StateProvider) +// +//=========================================================================== + +extend class StateProvider +{ + //=========================================================================== + // This is also used by the shotgun and chaingun + //=========================================================================== + + protected action void GunShot(bool accurate, Class pufftype, double pitch) + { + int damage = 5 * random[GunShot](1, 3); + double ang = angle; + + if (!accurate) + { + ang += Random2[GunShot]() * (5.625 / 256); + } + + LineAttack(ang, PLAYERMISSILERANGE, pitch, damage, 'Hitscan', pufftype); + } + + //=========================================================================== + action void A_FirePistol() + { + bool accurate; + + if (player != null) + { + Weapon weap = player.ReadyWeapon; + if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + return; + + player.SetPsprite(PSP_FLASH, weap.FindState('Flash'), true); + } + player.mo.PlayAttacking2 (); + + accurate = !player.refire; + } + else + { + accurate = true; + } + + A_PlaySound ("weapons/pistol", CHAN_WEAPON); + GunShot (accurate, "BulletPuff", BulletSlope ()); + } +} \ No newline at end of file diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index 8337c5399..d66843593 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -49,7 +49,6 @@ class StateProvider : Inventory native action native void A_WeaponReady(int flags = 0); action native void A_Lower(); action native void A_Raise(); - action native void A_FirePistol(); action native void A_FireShotgun(); action native void A_FireShotgun2(); diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 224011acd..e2bbefbea 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -38,6 +38,17 @@ class PlayerPawn : Actor native Player.ViewBob 1; Obituary "$OB_MPDEFAULT"; } + + virtual void PlayAttacking () + { + if (MissileState != null) SetState (MissileState); + } + + virtual void PlayAttacking2 () + { + if (MeleeState != null) SetState (MeleeState); + } + } class PlayerChunk : PlayerPawn native @@ -57,3 +68,12 @@ class PlayerChunk : PlayerPawn native -TELESTOMP } } + +class PSprite : Object native +{ +} + +struct Player native +{ + native void SetPsprite(int id, State stat, bool pending = false); +} \ No newline at end of file From 0b70df88d8c92039184bf8bfd37f3dda458f7f88 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 19 Nov 2016 16:39:45 +0100 Subject: [PATCH 039/185] - scriptified A_FireShotgun and A_FireChaingun. --- src/g_doom/a_doomweaps.cpp | 149 +----------------- src/p_pspr.cpp | 75 ++++++++- src/p_pspr.h | 1 + wadsrc/static/zscript.txt | 2 + wadsrc/static/zscript/doom/doomweapons.txt | 92 ----------- wadsrc/static/zscript/doom/weaponchaingun.txt | 82 ++++++++++ wadsrc/static/zscript/doom/weaponshotgun.txt | 85 ++++++++++ wadsrc/static/zscript/shared/inventory.txt | 2 - wadsrc/static/zscript/shared/player.txt | 2 + 9 files changed, 247 insertions(+), 243 deletions(-) create mode 100644 wadsrc/static/zscript/doom/weaponchaingun.txt create mode 100644 wadsrc/static/zscript/doom/weaponshotgun.txt diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp index 77085f5b5..f7a73a4ce 100644 --- a/src/g_doom/a_doomweaps.cpp +++ b/src/g_doom/a_doomweaps.cpp @@ -15,6 +15,7 @@ #include "doomstat.h" */ +void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int index); static FRandom pr_saw ("Saw"); static FRandom pr_fireshotgun2 ("FireSG2"); static FRandom pr_fireplasma ("FirePlasma"); @@ -38,28 +39,6 @@ enum SAW_Flags }; -static FRandom pr_gunshot("GunShot"); -// -// P_GunShot -// -void P_GunShot(AActor *mo, bool accurate, PClassActor *pufftype, DAngle pitch) -{ - DAngle angle; - int damage; - - damage = 5 * (pr_gunshot() % 3 + 1); - angle = mo->Angles.Yaw; - - if (!accurate) - { - angle += pr_gunshot.Random2() * (5.625 / 256); - } - - P_LineAttack(mo, angle, PLAYERMISSILERANGE, pitch, damage, NAME_Hitscan, pufftype); -} - - - DEFINE_ACTION_FUNCTION(AActor, A_Saw) { PARAM_ACTION_PROLOGUE(AActor); @@ -199,40 +178,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_Saw) return 0; } -// -// A_FireShotgun -// -DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun) -{ - PARAM_ACTION_PROLOGUE(AActor); - - int i; - player_t *player; - - if (nullptr == (player = self->player)) - { - return 0; - } - - S_Sound (self, CHAN_WEAPON, "weapons/shotgf", 1, ATTN_NORM); - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != nullptr && ACTION_CALL_FROM_PSPRITE()) - { - if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1)) - return 0; - P_SetPsprite(player, PSP_FLASH, weapon->FindState(NAME_Flash), true); - } - player->mo->PlayAttacking2 (); - - DAngle pitch = P_BulletSlope (self); - - for (i = 0; i < 7; i++) - { - P_GunShot (self, false, PClass::FindActor(NAME_BulletPuff), pitch); - } - return 0; -} - // // A_FireShotgun2 // @@ -283,98 +228,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun2) return 0; } -//------------------------------------------------------------------------------------ -// -// Setting a random flash like some of Doom's weapons can easily crash when the -// definition is overridden incorrectly so let's check that the state actually exists. -// Be aware though that this will not catch all DEHACKED related problems. But it will -// find all DECORATE related ones. -// -//------------------------------------------------------------------------------------ - -void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int index) -{ - - PClassActor *cls = weapon->GetClass(); - while (cls != RUNTIME_CLASS(AWeapon)) - { - 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 < cls->OwnedStates + cls->NumOwnedStates) - { - // we're ok so set the state - P_SetPsprite(player, PSP_FLASH, flashstate + index, true); - return; - } - else - { - // oh, no! The state is beyond the end of the state table so use the original flash state. - P_SetPsprite(player, PSP_FLASH, flashstate, true); - return; - } - } - // try again with parent class - 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. - // The only way to check this would be to go through all Dehacked modifiable actors, convert - // their states into a single flat array and find the correct one. - // Rather than that, just check to make sure it belongs to something. - if (FState::StaticFindStateOwner(flashstate + index) == NULL) - { // Invalid state. With no index offset, it should at least be valid. - index = 0; - } - P_SetPsprite(player, PSP_FLASH, flashstate + index, true); -} - -// -// A_FireCGun -// -DEFINE_ACTION_FUNCTION(AActor, A_FireCGun) -{ - PARAM_ACTION_PROLOGUE(AActor); - - player_t *player; - - if (self == nullptr || nullptr == (player = self->player)) - { - return 0; - } - - AWeapon *weapon = player->ReadyWeapon; - if (weapon != nullptr && ACTION_CALL_FROM_PSPRITE()) - { - if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1)) - return 0; - - S_Sound (self, CHAN_WEAPON, "weapons/chngun", 1, ATTN_NORM); - - FState *flash = weapon->FindState(NAME_Flash); - if (flash != nullptr) - { - // [RH] Fix for Sparky's messed-up Dehacked patch! Blargh! - FState * atk = weapon->FindState(NAME_Fire); - - int theflash = clamp (int(player->GetPSprite(PSP_WEAPON)->GetState() - atk), 0, 1); - - if (flash[theflash].sprite != flash->sprite) - { - theflash = 0; - } - - P_SetSafeFlash (weapon, player, flash, theflash); - } - - } - player->mo->PlayAttacking2 (); - - P_GunShot (self, !player->refire, PClass::FindActor(NAME_BulletPuff), P_BulletSlope (self)); - return 0; -} - // // A_FireMissile // diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index d47156d16..3bc2dfbe1 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -29,6 +29,7 @@ #include "d_player.h" #include "serializer.h" #include "v_text.h" +#include "cmdlib.h" // MACROS ------------------------------------------------------------------ @@ -98,13 +99,20 @@ static const FGenericButtons ButtonChecks[] = // //------------------------------------------------------------------------ -IMPLEMENT_CLASS(DPSprite, false, true, false, false) +IMPLEMENT_CLASS(DPSprite, false, true, true, false) IMPLEMENT_POINTERS_START(DPSprite) IMPLEMENT_POINTER(Caller) IMPLEMENT_POINTER(Next) IMPLEMENT_POINTERS_END +void DPSprite::InitNativeFields() +{ + auto meta = RUNTIME_CLASS(DPSprite); + + meta->AddNativeField("State", TypeState, myoffsetof(DPSprite, State), VARF_ReadOnly); +} + //------------------------------------------------------------------------ // // @@ -254,6 +262,14 @@ DPSprite *player_t::GetPSprite(PSPLayers layer) return pspr; } +DEFINE_ACTION_FUNCTION(_Player, GetPSprite) // the underscore is needed to get past the name mangler which removes the first clas name character to match the class representation (needs to be fixed in a later commit) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + PARAM_INT(id); + ACTION_RETURN_OBJECT(self->GetPSprite((PSPLayers)id)); +} + + //--------------------------------------------------------------------------- // // PROC P_NewPspriteTick @@ -1561,6 +1577,63 @@ void player_t::DestroyPSprites() } } +//------------------------------------------------------------------------------------ +// +// Setting a random flash like some of Doom's weapons can easily crash when the +// definition is overridden incorrectly so let's check that the state actually exists. +// Be aware though that this will not catch all DEHACKED related problems. But it will +// find all DECORATE related ones. +// +//------------------------------------------------------------------------------------ + +void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int index) +{ + + PClassActor *cls = weapon->GetClass(); + while (cls != RUNTIME_CLASS(AWeapon)) + { + 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 < cls->OwnedStates + cls->NumOwnedStates) + { + // we're ok so set the state + P_SetPsprite(player, PSP_FLASH, flashstate + index, true); + return; + } + else + { + // oh, no! The state is beyond the end of the state table so use the original flash state. + P_SetPsprite(player, PSP_FLASH, flashstate, true); + return; + } + } + // try again with parent class + 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. + // The only way to check this would be to go through all Dehacked modifiable actors, convert + // their states into a single flat array and find the correct one. + // Rather than that, just check to make sure it belongs to something. + if (FState::StaticFindStateOwner(flashstate + index) == NULL) + { // Invalid state. With no index offset, it should at least be valid. + index = 0; + } + P_SetPsprite(player, PSP_FLASH, flashstate + index, true); +} + +DEFINE_ACTION_FUNCTION(_Player, SetSafeFlash) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + PARAM_OBJECT(weapon, AWeapon); + PARAM_POINTER(state, FState); + PARAM_INT(index); + P_SetSafeFlash(weapon, self, state, index); + return 0; +} + //------------------------------------------------------------------------ // // diff --git a/src/p_pspr.h b/src/p_pspr.h index 3c8f0097e..4c019c7d4 100644 --- a/src/p_pspr.h +++ b/src/p_pspr.h @@ -59,6 +59,7 @@ enum PSPFlags class DPSprite : public DObject { DECLARE_CLASS (DPSprite, DObject) + HAS_FIELDS HAS_OBJECT_POINTERS public: DPSprite(player_t *owner, AActor *caller, int id); diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 2f5a420a3..9244b9bdb 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -50,6 +50,8 @@ zscript/doom/keen.txt zscript/doom/bossbrain.txt zscript/doom/weaponfist.txt zscript/doom/weaponpistol.txt +zscript/doom/weaponshotgun.txt +zscript/doom/weaponchaingun.txt zscript/doom/deadthings.txt zscript/doom/doomammo.txt diff --git a/wadsrc/static/zscript/doom/doomweapons.txt b/wadsrc/static/zscript/doom/doomweapons.txt index 60b5ba157..ee7a821ea 100644 --- a/wadsrc/static/zscript/doom/doomweapons.txt +++ b/wadsrc/static/zscript/doom/doomweapons.txt @@ -54,54 +54,6 @@ class Chainsaw : Weapon } -// -------------------------------------------------------------------------- -// -// Shotgun -// -// -------------------------------------------------------------------------- - -class Shotgun : DoomWeapon -{ - Default - { - Weapon.SelectionOrder 1300; - Weapon.AmmoUse 1; - Weapon.AmmoGive 8; - Weapon.AmmoType "Shell"; - Inventory.PickupMessage "$GOTSHOTGUN"; - Obituary "$OB_MPSHOTGUN"; - Tag "$TAG_SHOTGUN"; - } - States - { - Ready: - SHTG A 1 A_WeaponReady; - Loop; - Deselect: - SHTG A 1 A_Lower; - Loop; - Select: - SHTG A 1 A_Raise; - Loop; - Fire: - SHTG A 3; - SHTG A 7 A_FireShotgun; - SHTG BC 5; - SHTG D 4; - SHTG CB 5; - SHTG A 3; - SHTG A 7 A_ReFire; - Goto Ready; - Flash: - SHTF A 4 Bright A_Light1; - SHTF B 3 Bright A_Light2; - Goto LightDone; - Spawn: - SHOT A -1; - Stop; - } -} - // -------------------------------------------------------------------------- // // Shotgun @@ -157,50 +109,6 @@ class SuperShotgun : DoomWeapon } } -// -------------------------------------------------------------------------- -// -// Chaingun -// -// -------------------------------------------------------------------------- - -class Chaingun : DoomWeapon -{ - Default - { - Weapon.SelectionOrder 700; - Weapon.AmmoUse 1; - Weapon.AmmoGive 20; - Weapon.AmmoType "Clip"; - Inventory.PickupMessage "$GOTCHAINGUN"; - Obituary "$OB_MPCHAINGUN"; - Tag "$TAG_CHAINGUN"; - } - States - { - Ready: - CHGG A 1 A_WeaponReady; - Loop; - Deselect: - CHGG A 1 A_Lower; - Loop; - Select: - CHGG A 1 A_Raise; - Loop; - Fire: - CHGG AB 4 A_FireCGun; - CHGG B 0 A_ReFire; - Goto Ready; - Flash: - CHGF A 5 Bright A_Light1; - Goto LightDone; - CHGF B 5 Bright A_Light2; - Goto LightDone; - Spawn: - MGUN A -1; - Stop; - } -} - // -------------------------------------------------------------------------- // // Rocket launcher diff --git a/wadsrc/static/zscript/doom/weaponchaingun.txt b/wadsrc/static/zscript/doom/weaponchaingun.txt new file mode 100644 index 000000000..92b3aec46 --- /dev/null +++ b/wadsrc/static/zscript/doom/weaponchaingun.txt @@ -0,0 +1,82 @@ +// -------------------------------------------------------------------------- +// +// Chaingun +// +// -------------------------------------------------------------------------- + +class Chaingun : DoomWeapon +{ + Default + { + Weapon.SelectionOrder 700; + Weapon.AmmoUse 1; + Weapon.AmmoGive 20; + Weapon.AmmoType "Clip"; + Inventory.PickupMessage "$GOTCHAINGUN"; + Obituary "$OB_MPCHAINGUN"; + Tag "$TAG_CHAINGUN"; + } + States + { + Ready: + CHGG A 1 A_WeaponReady; + Loop; + Deselect: + CHGG A 1 A_Lower; + Loop; + Select: + CHGG A 1 A_Raise; + Loop; + Fire: + CHGG AB 4 A_FireCGun; + CHGG B 0 A_ReFire; + Goto Ready; + Flash: + CHGF A 5 Bright A_Light1; + Goto LightDone; + CHGF B 5 Bright A_Light2; + Goto LightDone; + Spawn: + MGUN A -1; + Stop; + } +} + +//=========================================================================== +// +// Code (must be attached to StateProvider) +// +//=========================================================================== + +extend class StateProvider +{ + action void A_FireCGun() + { + if (player == null) + { + return; + } + + Weapon weap = player.ReadyWeapon; + if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + return; + + A_PlaySound ("weapons/chngun", CHAN_WEAPON); + + State flash = weap.FindState('Flash'); + if (flash != null) + { + // Removed most of the mess that was here in the C++ code because SetSafeFlash already does some thorough validation. + State atk = weap.FindState('Fire'); + State cur = player.GetPSprite(PSP_WEAPON).State; + int theflash = atk == cur? 0:1; + player.SetSafeFlash(weap, flash, theflash); + } + } + player.mo.PlayAttacking2 (); + + GunShot (!player.refire, "BulletPuff", BulletSlope ()); + } +} diff --git a/wadsrc/static/zscript/doom/weaponshotgun.txt b/wadsrc/static/zscript/doom/weaponshotgun.txt new file mode 100644 index 000000000..6a08afc11 --- /dev/null +++ b/wadsrc/static/zscript/doom/weaponshotgun.txt @@ -0,0 +1,85 @@ +// -------------------------------------------------------------------------- +// +// Shotgun +// +// -------------------------------------------------------------------------- + +class Shotgun : DoomWeapon +{ + Default + { + Weapon.SelectionOrder 1300; + Weapon.AmmoUse 1; + Weapon.AmmoGive 8; + Weapon.AmmoType "Shell"; + Inventory.PickupMessage "$GOTSHOTGUN"; + Obituary "$OB_MPSHOTGUN"; + Tag "$TAG_SHOTGUN"; + } + States + { + Ready: + SHTG A 1 A_WeaponReady; + Loop; + Deselect: + SHTG A 1 A_Lower; + Loop; + Select: + SHTG A 1 A_Raise; + Loop; + Fire: + SHTG A 3; + SHTG A 7 A_FireShotgun; + SHTG BC 5; + SHTG D 4; + SHTG CB 5; + SHTG A 3; + SHTG A 7 A_ReFire; + Goto Ready; + Flash: + SHTF A 4 Bright A_Light1; + SHTF B 3 Bright A_Light2; + Goto LightDone; + Spawn: + SHOT A -1; + Stop; + } +} + +//=========================================================================== +// +// Code (must be attached to StateProvider) +// +//=========================================================================== + +extend class StateProvider +{ + + action void A_FireShotgun() + { + if (player == null) + { + return; + } + + A_PlaySound ("weapons/shotgf", CHAN_WEAPON); + Weapon weap = player.ReadyWeapon; + if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + return; + + player.SetPsprite(PSP_FLASH, weap.FindState('Flash'), true); + } + player.mo.PlayAttacking2 (); + + double pitch = BulletSlope (); + + for (int i = 0; i < 7; i++) + { + GunShot (false, "BulletPuff", pitch); + } + } + +} + diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index d66843593..64c649ad6 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -49,14 +49,12 @@ class StateProvider : Inventory native action native void A_WeaponReady(int flags = 0); action native void A_Lower(); action native void A_Raise(); - action native void A_FireShotgun(); action native void A_FireShotgun2(); action void A_OpenShotgun2() { A_PlaySound("weapons/sshoto", CHAN_WEAPON); } action void A_LoadShotgun2() { A_PlaySound("weapons/sshotl", CHAN_WEAPON); } action void A_CloseShotgun2() { A_PlaySound("weapons/sshotc", CHAN_WEAPON); } - action native void A_FireCGun(); action native void A_FireSTGrenade(class grenadetype = "Grenade"); action native void A_FireMissile(); action native void A_FirePlasma(); diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index e2bbefbea..c8485cebd 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -76,4 +76,6 @@ class PSprite : Object native struct Player native { native void SetPsprite(int id, State stat, bool pending = false); + native void SetSafeFlash(Weapon weap, State flashstate, int index); + native PSprite GetPSprite(int id); } \ No newline at end of file From 3b240b73e9585b963a76f77c00ec617fe1a4bd1b Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sat, 19 Nov 2016 12:40:08 +0200 Subject: [PATCH 040/185] Fixed endianness issue with saved games See http://forum.zdoom.org/viewtopic.php?t=54272 --- src/resourcefiles/file_zip.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resourcefiles/file_zip.cpp b/src/resourcefiles/file_zip.cpp index 8713fe554..8011d56cf 100644 --- a/src/resourcefiles/file_zip.cpp +++ b/src/resourcefiles/file_zip.cpp @@ -577,7 +577,7 @@ bool WriteZip(const char *filename, TArray &filenames, TArray Date: Sat, 19 Nov 2016 12:41:01 +0200 Subject: [PATCH 041/185] Fixed compilation warnings in Cocoa backend --- src/posix/cocoa/i_input.mm | 2 +- src/posix/cocoa/i_joystick.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/posix/cocoa/i_input.mm b/src/posix/cocoa/i_input.mm index 3bbf42a9a..703280615 100644 --- a/src/posix/cocoa/i_input.mm +++ b/src/posix/cocoa/i_input.mm @@ -526,7 +526,7 @@ void ProcessMouseMoveInGame(NSEvent* theEvent) lastX = x; lastY = y; - if (0 != event.x | 0 != event.y) + if (0 != event.x || 0 != event.y) { event.type = EV_Mouse; diff --git a/src/posix/cocoa/i_joystick.cpp b/src/posix/cocoa/i_joystick.cpp index c4bcc85c3..747cc1422 100644 --- a/src/posix/cocoa/i_joystick.cpp +++ b/src/posix/cocoa/i_joystick.cpp @@ -1018,7 +1018,7 @@ IOKitJoystickManager::~IOKitJoystickManager() if (0 != notification) { IOObjectRelease(notification); - notification = NULL; + notification = 0; } } } From c28bcca3f3504b97fa791be56b83e1f679cfbb5b Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sat, 19 Nov 2016 12:44:35 +0200 Subject: [PATCH 042/185] Print unknown if release information is unavailable on macOS At least 10.4 Tiger doesn't support required sysctl name --- src/posix/cocoa/i_main.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/posix/cocoa/i_main.mm b/src/posix/cocoa/i_main.mm index d8f0e74cf..851e72e48 100644 --- a/src/posix/cocoa/i_main.mm +++ b/src/posix/cocoa/i_main.mm @@ -156,7 +156,7 @@ static void I_DetectOS() case 12: name = "macOS Sierra"; break; } - char release[16] = {}; + char release[16] = "unknown"; size_t size = sizeof release - 1; sysctlbyname("kern.osversion", release, &size, nullptr, 0); From 7595343aaac23ed4e374a900723f020d8ab89fa5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 19 Nov 2016 18:02:07 +0100 Subject: [PATCH 043/185] - fixed: Completely empty if statements left the code generator in a broken state. --- src/scripting/codegeneration/codegen.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 3577ac1ec..e38b6bd6b 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -7946,7 +7946,8 @@ FxExpression *FxIfStatement::Resolve(FCompileContext &ctx) if (WhenTrue == nullptr && WhenFalse == nullptr) { // We don't do anything either way, so disappear delete this; - return nullptr; + ScriptPosition.Message(MSG_WARNING, "empty if statement"); + return new FxNop(ScriptPosition); } SAFE_RESOLVE(Condition, ctx); From 74c5659fc586e59d495e2295f1833a44ed26479b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 19 Nov 2016 18:09:34 +0100 Subject: [PATCH 044/185] - explicitly call Destroy in PClass::StaticShutdown because some class type objects were no longer automatically collected. --- src/dobjtype.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 5154d1689..965a0d8fd 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2765,6 +2765,7 @@ void PClass::StaticShutdown () uniqueFPs.Push(const_cast(type->FlatPointers)); } } + type->Destroy(); } for (i = 0; i < uniqueFPs.Size(); ++i) { From af34d82888ba4a362902d5e03635c5d1a6ae436f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 20 Nov 2016 00:25:38 +0100 Subject: [PATCH 045/185] - scriptified A_Saw. - implemented multiple-return-value assignment. Due to some grammar conflicts the originally intended Lua-inspired syntax of 'a, b = Function()' could not be done, so it's '[a, b] = Function()' --- src/g_doom/a_doomweaps.cpp | 155 ---------------- src/g_shared/a_armor.cpp | 16 +- src/g_shared/a_pickups.cpp | 35 +++- src/g_shared/a_pickups.h | 1 + src/p_mobj.cpp | 6 + src/scripting/codegeneration/codegen.cpp | 150 ++++++++++++++-- src/scripting/codegeneration/codegen.h | 38 +++- src/scripting/zscript/zcc-parse.lemon | 9 +- src/scripting/zscript/zcc_compile.cpp | 31 +++- wadsrc/static/zscript.txt | 1 + wadsrc/static/zscript/actor.txt | 4 + wadsrc/static/zscript/doom/doomweapons.txt | 41 ----- wadsrc/static/zscript/doom/weaponchainsaw.txt | 166 ++++++++++++++++++ wadsrc/static/zscript/shared/inventory.txt | 4 +- 14 files changed, 426 insertions(+), 231 deletions(-) create mode 100644 wadsrc/static/zscript/doom/weaponchainsaw.txt diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp index f7a73a4ce..e802a6103 100644 --- a/src/g_doom/a_doomweaps.cpp +++ b/src/g_doom/a_doomweaps.cpp @@ -16,167 +16,12 @@ */ void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int index); -static FRandom pr_saw ("Saw"); static FRandom pr_fireshotgun2 ("FireSG2"); static FRandom pr_fireplasma ("FirePlasma"); static FRandom pr_firerail ("FireRail"); static FRandom pr_bfgspray ("BFGSpray"); static FRandom pr_oldbfg ("OldBFG"); -// -// A_Saw -// -enum SAW_Flags -{ - SF_NORANDOM = 1, - SF_RANDOMLIGHTMISS = 2, - SF_RANDOMLIGHTHIT = 4, - SF_NOUSEAMMOMISS = 8, - SF_NOUSEAMMO = 16, - SF_NOPULLIN = 32, - SF_NOTURN = 64, - SF_STEALARMOR = 128, -}; - - -DEFINE_ACTION_FUNCTION(AActor, A_Saw) -{ - PARAM_ACTION_PROLOGUE(AActor); - PARAM_SOUND_DEF (fullsound) - PARAM_SOUND_DEF (hitsound) - PARAM_INT_DEF (damage) - PARAM_CLASS_DEF (pufftype, AActor) - PARAM_INT_DEF (flags) - PARAM_FLOAT_DEF (range) - PARAM_ANGLE_DEF (spread_xy) - PARAM_ANGLE_DEF (spread_z) - PARAM_FLOAT_DEF (lifesteal) - PARAM_INT_DEF (lifestealmax) - PARAM_CLASS_DEF (armorbonustype, ABasicArmorBonus) - - DAngle angle; - DAngle slope; - player_t *player; - FTranslatedLineTarget t; - int actualdamage; - - if (NULL == (player = self->player)) - { - return 0; - } - - if (pufftype == NULL) - { - pufftype = PClass::FindActor(NAME_BulletPuff); - } - if (damage == 0) - { - damage = 2; - } - if (!(flags & SF_NORANDOM)) - { - damage *= (pr_saw()%10+1); - } - if (range == 0) - { - range = SAWRANGE; - } - - angle = self->Angles.Yaw + spread_xy * (pr_saw.Random2() / 255.); - slope = P_AimLineAttack (self, angle, range, &t) + spread_z * (pr_saw.Random2() / 255.); - - AWeapon *weapon = self->player->ReadyWeapon; - if ((weapon != NULL) && !(flags & SF_NOUSEAMMO) && !(!t.linetarget && (flags & SF_NOUSEAMMOMISS)) && !(weapon->WeaponFlags & WIF_DEHAMMO) && ACTION_CALL_FROM_PSPRITE()) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - - P_LineAttack (self, angle, range, slope, damage, NAME_Melee, pufftype, false, &t, &actualdamage); - - if (!t.linetarget) - { - if ((flags & SF_RANDOMLIGHTMISS) && (pr_saw() > 64)) - { - player->extralight = !player->extralight; - } - S_Sound (self, CHAN_WEAPON, fullsound, 1, ATTN_NORM); - return 0; - } - - if (flags & SF_RANDOMLIGHTHIT) - { - int randVal = pr_saw(); - if (randVal < 64) - { - player->extralight = 0; - } - else if (randVal < 160) - { - player->extralight = 1; - } - else - { - player->extralight = 2; - } - } - - if (lifesteal && !(t.linetarget->flags5 & MF5_DONTDRAIN)) - { - if (flags & SF_STEALARMOR) - { - if (armorbonustype == NULL) - { - armorbonustype = dyn_cast(PClass::FindClass("ArmorBonus")); - } - if (armorbonustype != NULL) - { - assert(armorbonustype->IsDescendantOf (RUNTIME_CLASS(ABasicArmorBonus))); - ABasicArmorBonus *armorbonus = static_cast(Spawn(armorbonustype)); - armorbonus->SaveAmount = int(armorbonus->SaveAmount * actualdamage * lifesteal); - armorbonus->MaxSaveAmount = lifestealmax <= 0 ? armorbonus->MaxSaveAmount : lifestealmax; - armorbonus->flags |= MF_DROPPED; - armorbonus->ClearCounters(); - - if (!armorbonus->CallTryPickup (self)) - { - armorbonus->Destroy (); - } - } - } - - else - { - P_GiveBody (self, int(actualdamage * lifesteal), lifestealmax); - } - } - - S_Sound (self, CHAN_WEAPON, hitsound, 1, ATTN_NORM); - - // turn to face target - if (!(flags & SF_NOTURN)) - { - DAngle anglediff = deltaangle(self->Angles.Yaw, t.angleFromSource); - - if (anglediff < 0.0) - { - if (anglediff < -4.5) - self->Angles.Yaw = angle + 90.0 / 21; - else - self->Angles.Yaw -= 4.5; - } - else - { - if (anglediff > 4.5) - self->Angles.Yaw = angle - 90.0 / 21; - else - self->Angles.Yaw += 4.5; - } - } - if (!(flags & SF_NOPULLIN)) - self->flags |= MF_JUSTATTACKED; - return 0; -} // // A_FireShotgun2 diff --git a/src/g_shared/a_armor.cpp b/src/g_shared/a_armor.cpp index 636441a9d..c05cc2c6a 100644 --- a/src/g_shared/a_armor.cpp +++ b/src/g_shared/a_armor.cpp @@ -7,11 +7,12 @@ #include "g_level.h" #include "d_player.h" #include "serializer.h" +#include "cmdlib.h" IMPLEMENT_CLASS(AArmor, false, false, false, false) IMPLEMENT_CLASS(ABasicArmor, false, false, false, false) IMPLEMENT_CLASS(ABasicArmorPickup, false, false, false, false) -IMPLEMENT_CLASS(ABasicArmorBonus, false, false, false, false) +IMPLEMENT_CLASS(ABasicArmorBonus, false, false, true, false) IMPLEMENT_CLASS(AHexenArmor, false, false, false, false) //=========================================================================== @@ -278,6 +279,19 @@ bool ABasicArmorPickup::Use (bool pickup) return true; } +//=========================================================================== +// +// ABasicArmorBonus :: InitNativeFields +// +//=========================================================================== + +void ABasicArmorBonus::InitNativeFields() +{ + auto meta = RUNTIME_CLASS(ABasicArmorBonus); + meta->AddNativeField("SaveAmount", TypeSInt32, myoffsetof(ABasicArmorBonus, SaveAmount)); + meta->AddNativeField("MaxSaveAmount", TypeSInt32, myoffsetof(ABasicArmorBonus, MaxSaveAmount)); +} + //=========================================================================== // // ABasicArmorBonus :: Serialize diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index fbc5ea509..a3abe7cf4 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -344,6 +344,14 @@ bool P_GiveBody (AActor *actor, int num, int max) return false; } +DEFINE_ACTION_FUNCTION(AActor, GiveBody) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(num); + PARAM_INT_DEF(max); + ACTION_RETURN_BOOL(P_GiveBody(self, num, max)); +} + //--------------------------------------------------------------------------- // // PROC A_RestoreSpecialThing1 @@ -352,12 +360,12 @@ bool P_GiveBody (AActor *actor, int num, int max) // //--------------------------------------------------------------------------- -DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialThing1) +DEFINE_ACTION_FUNCTION(AInventory, A_RestoreSpecialThing1) { - PARAM_SELF_PROLOGUE(AActor); + PARAM_SELF_PROLOGUE(AInventory); self->renderflags &= ~RF_INVISIBLE; - if (static_cast(self)->DoRespawn ()) + if (self->DoRespawn ()) { S_Sound (self, CHAN_VOICE, "misc/spawn", 1, ATTN_IDLE); } @@ -370,9 +378,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialThing1) // //--------------------------------------------------------------------------- -DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialThing2) +DEFINE_ACTION_FUNCTION(AInventory, A_RestoreSpecialThing2) { - PARAM_SELF_PROLOGUE(AActor); + PARAM_SELF_PROLOGUE(AInventory); self->flags |= MF_SPECIAL; if (!(self->GetDefault()->flags & MF_NOGRAVITY)) @@ -390,9 +398,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialThing2) // //--------------------------------------------------------------------------- -DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialDoomThing) +DEFINE_ACTION_FUNCTION(AInventory, A_RestoreSpecialDoomThing) { - PARAM_SELF_PROLOGUE(AActor); + PARAM_SELF_PROLOGUE(AInventory); self->renderflags &= ~RF_INVISIBLE; self->flags |= MF_SPECIAL; @@ -400,7 +408,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialDoomThing) { self->flags &= ~MF_NOGRAVITY; } - if (static_cast(self)->DoRespawn ()) + if (self->DoRespawn ()) { self->SetState (self->SpawnState); S_Sound (self, CHAN_VOICE, "misc/spawn", 1, ATTN_IDLE); @@ -1547,6 +1555,17 @@ bool AInventory::CallTryPickup (AActor *toucher, AActor **toucher_return) return res; } +DEFINE_ACTION_FUNCTION(AInventory, CallTryPickup) +{ + PARAM_SELF_PROLOGUE(AInventory); + PARAM_OBJECT(toucher, AActor); + AActor *t_ret; + bool res = self->CallTryPickup(toucher, &t_ret); + if (numret > 0) ret[0].SetInt(res); + if (numret > 1) ret[1].SetPointer(t_ret, ATAG_OBJECT), numret = 2; + return numret; +} + //=========================================================================== // diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index e50c7f3d8..9e1caaf5b 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -500,6 +500,7 @@ public: class ABasicArmorBonus : public AArmor { DECLARE_CLASS (ABasicArmorBonus, AArmor) + HAS_FIELDS public: virtual void Serialize(FSerializer &arc); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 09d850af5..f28ea4b5f 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -6884,6 +6884,12 @@ void AActor::ClearCounters() } } +DEFINE_ACTION_FUNCTION(AActor, ClearCounters) +{ + PARAM_SELF_PROLOGUE(AActor); + self->ClearCounters(); + return 0; +} int AActor::ApplyDamageFactor(FName damagetype, int damage) const { diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index e38b6bd6b..12acc438b 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -2331,6 +2331,95 @@ ExpEmit FxAssignSelf::Emit(VMFunctionBuilder *build) } } + +//========================================================================== +// +// +// +//========================================================================== + +FxMultiAssign::FxMultiAssign(FArgumentList &base, FxExpression *right, const FScriptPosition &pos) + :FxExpression(EFX_MultiAssign, pos) +{ + Base = std::move(base); + Right = right; + LocalVarContainer = new FxCompoundStatement(ScriptPosition); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxMultiAssign::~FxMultiAssign() +{ + SAFE_DELETE(Right); + SAFE_DELETE(LocalVarContainer); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxMultiAssign::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Right, ctx); + if (Right->ExprType != EFX_VMFunctionCall) + { + Right->ScriptPosition.Message(MSG_ERROR, "Function call expected on right side of multi-assigment"); + delete this; + return nullptr; + } + auto VMRight = static_cast(Right); + auto rets = VMRight->GetReturnTypes(); + if (rets.Size() < Base.Size()) + { + Right->ScriptPosition.Message(MSG_ERROR, "Insufficient returns in function %s", VMRight->Function->SymbolName.GetChars()); + delete this; + return nullptr; + } + // Pack the generated data (temp local variables for the results and necessary type casts and single assignments) into a compound statement for easier management. + for (unsigned i = 0; i < Base.Size(); i++) + { + auto singlevar = new FxLocalVariableDeclaration(rets[i], NAME_None, nullptr, 0, ScriptPosition); + LocalVarContainer->Add(singlevar); + Base[i] = Base[i]->Resolve(ctx); + ABORT(Base[i]); + auto varaccess = new FxLocalVariable(singlevar, ScriptPosition); + auto assignee = new FxTypeCast(varaccess, Base[i]->ValueType, false); + LocalVarContainer->Add(new FxAssign(Base[i], assignee, false)); + } + auto x = LocalVarContainer->Resolve(ctx); + LocalVarContainer = nullptr; + ABORT(x); + LocalVarContainer = static_cast(x); + static_cast(Right)->AssignCount = Base.Size(); + ValueType = TypeVoid; + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxMultiAssign::Emit(VMFunctionBuilder *build) +{ + Right->Emit(build); + for (unsigned i = 0; i < Base.Size(); i++) + { + LocalVarContainer->LocalVars[i]->SetReg(static_cast(Right)->ReturnRegs[i]); + } + static_cast(Right)->ReturnRegs.Clear(); + static_cast(Right)->ReturnRegs.ShrinkToFit(); + return LocalVarContainer->Emit(build); +} + //========================================================================== // // @@ -5398,6 +5487,13 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) } } + if (noglobal) + { + // This is needed to properly resolve class names on the left side of the member access operator + ValueType = TypeError; + return this; + } + // now check the global identifiers. if (newex == nullptr && (sym = ctx.FindGlobal(Identifier)) != nullptr) { @@ -6710,11 +6806,20 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) bool staticonly = false; bool novirtual = false; + PClass *ccls = nullptr; + if (Self->ExprType == EFX_Identifier) { + ccls = PClass::FindClass(static_cast(Self)->Identifier); // If the left side is a class name for a static member function call it needs to be resolved manually // because the resulting value type would cause problems in nearly every other place where identifiers are being used. - PClass *ccls = PClass::FindClass(static_cast(Self)->Identifier); + if (ccls != nullptr)static_cast(Self)->noglobal = true; + } + + SAFE_RESOLVE(Self, ctx); + + if (Self->ValueType == TypeError) + { if (ccls != nullptr) { if (ccls->bExported) @@ -6729,7 +6834,6 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) // Todo: static struct members need to work as well. } } - SAFE_RESOLVE(Self, ctx); if (Self->ExprType == EFX_Super) { @@ -7282,10 +7386,8 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) } else if (vmfunc->Proto->ReturnTypes.Size() > 0) { // Call, expecting one result - ExpEmit reg(build, vmfunc->Proto->ReturnTypes[0]->GetRegType(), vmfunc->Proto->ReturnTypes[0]->GetRegCount()); - build->Emit(OP_CALL_K, funcaddr, count, 1); - build->Emit(OP_RESULT, 0, EncodeRegType(reg), reg.RegNum); - return reg; + build->Emit(OP_CALL_K, funcaddr, count, MAX(1, AssignCount)); + goto handlereturns; } else { // Call, expecting no results @@ -7307,18 +7409,34 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) } else if (vmfunc->Proto->ReturnTypes.Size() > 0) { // Call, expecting one result - ExpEmit reg(build, vmfunc->Proto->ReturnTypes[0]->GetRegType(), vmfunc->Proto->ReturnTypes[0]->GetRegCount()); - build->Emit(OP_CALL, funcreg.RegNum, count, 1); - build->Emit(OP_RESULT, 0, EncodeRegType(reg), reg.RegNum); - return reg; + build->Emit(OP_CALL, funcreg.RegNum, count, MAX(1, AssignCount)); + goto handlereturns; } else { // Call, expecting no results build->Emit(OP_CALL, funcreg.RegNum, count, 0); return ExpEmit(); } - - + } +handlereturns: + if (AssignCount == 0) + { + // Regular call, will not write to ReturnRegs + ExpEmit reg(build, vmfunc->Proto->ReturnTypes[0]->GetRegType(), vmfunc->Proto->ReturnTypes[0]->GetRegCount()); + build->Emit(OP_RESULT, 0, EncodeRegType(reg), reg.RegNum); + return reg; + } + else + { + // Multi-Assignment call, this must fill in the ReturnRegs array so that the multi-assignment operator can dispatch the return values. + assert((unsigned)AssignCount <= vmfunc->Proto->ReturnTypes.Size()); + for (int i = 0; i < AssignCount; i++) + { + ExpEmit reg(build, vmfunc->Proto->ReturnTypes[i]->GetRegType(), vmfunc->Proto->ReturnTypes[i]->GetRegCount()); + build->Emit(OP_RESULT, 0, EncodeRegType(reg), reg.RegNum); + ReturnRegs.Push(reg); + } + return ExpEmit(); } } @@ -9018,13 +9136,19 @@ FxExpression *FxLocalVariableDeclaration::Resolve(FCompileContext &ctx) return this; } +void FxLocalVariableDeclaration::SetReg(ExpEmit emit) +{ + assert(ValueType->GetRegType() == emit.RegType && ValueType->GetRegCount() == emit.RegCount); + RegNum = emit.RegNum; +} + ExpEmit FxLocalVariableDeclaration::Emit(VMFunctionBuilder *build) { if (ValueType->RegType != REGT_NIL) { if (Init == nullptr) { - RegNum = build->Registers[ValueType->GetRegType()].Get(RegCount); + if (RegNum == -1) RegNum = build->Registers[ValueType->GetRegType()].Get(RegCount); } else { diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index 5ad351d6b..03b256970 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -68,6 +68,7 @@ struct FScriptPosition; class FxLoopStatement; class FxCompoundStatement; class FxLocalVariableDeclaration; +typedef TDeletingArray FArgumentList; struct FCompileContext { @@ -280,6 +281,7 @@ enum EFxType EFX_GlobalVariable, EFX_Super, EFX_StackVariable, + EFX_MultiAssign, EFX_COUNT }; @@ -343,6 +345,7 @@ class FxIdentifier : public FxExpression { public: FName Identifier; + bool noglobal = false; FxIdentifier(FName i, const FScriptPosition &p); FxExpression *Resolve(FCompileContext&); @@ -782,6 +785,28 @@ public: ExpEmit Address; }; +//========================================================================== +// +// FxAssign +// +//========================================================================== +class FxCompoundStatement; + +class FxMultiAssign : public FxExpression +{ + FxCompoundStatement *LocalVarContainer; // for handling the temporary variables of the results, which may need type casts. + FArgumentList Base; + FxExpression *Right; + bool AddressRequested = false; + bool AddressWritable = false; + +public: + FxMultiAssign(FArgumentList &base, FxExpression *right, const FScriptPosition &pos); + ~FxMultiAssign(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxAssignSelf @@ -1344,8 +1369,6 @@ public: // //========================================================================== -typedef TDeletingArray FArgumentList; - class FxFunctionCall : public FxExpression { FName MethodName; @@ -1448,11 +1471,16 @@ public: class FxVMFunctionCall : public FxExpression { + friend class FxMultiAssign; + bool EmitTail; bool NoVirtual; FxExpression *Self; PFunction *Function; FArgumentList ArgList; + // for multi assignment + int AssignCount = 0; + TArray ReturnRegs; public: FxVMFunctionCall(FxExpression *self, PFunction *func, FArgumentList &args, const FScriptPosition &pos, bool novirtual); @@ -1462,6 +1490,10 @@ public: VMFunction *GetDirectFunction(); ExpEmit Emit(VMFunctionBuilder *build); bool CheckEmitCast(VMFunctionBuilder *build, bool returnit, ExpEmit ®); + TArray &GetReturnTypes() const + { + return Function->Variants[0].Proto->ReturnTypes; + } }; //========================================================================== @@ -1497,6 +1529,7 @@ class FxCompoundStatement : public FxSequence FxCompoundStatement *Outer = nullptr; friend class FxLocalVariableDeclaration; + friend class FxMultiAssign; public: FxCompoundStatement(const FScriptPosition &pos) : FxSequence(pos) {} @@ -1822,6 +1855,7 @@ public: FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); void Release(VMFunctionBuilder *build); + void SetReg(ExpEmit reginfo); }; diff --git a/src/scripting/zscript/zcc-parse.lemon b/src/scripting/zscript/zcc-parse.lemon index 2d3605532..8bd9686e3 100644 --- a/src/scripting/zscript/zcc-parse.lemon +++ b/src/scripting/zscript/zcc-parse.lemon @@ -1556,7 +1556,7 @@ statement(X) ::= expression_statement(A) SEMICOLON. { X = A; /*X-overwrites-A*/ statement(X) ::= selection_statement(X). statement(X) ::= iteration_statement(X). statement(X) ::= jump_statement(X). -//statement(X) ::= assign_statement(A) SEMICOLON. { X = A; /*X-overwrites-A*/ } +statement(X) ::= assign_statement(A) SEMICOLON. { X = A; /*X-overwrites-A*/ } statement(X) ::= local_var(A) SEMICOLON. { X = A; /*X-overwrites-A*/ } statement(X) ::= error SEMICOLON. { X = NULL; } @@ -1767,11 +1767,11 @@ labeled_statement(X) ::= DEFAULT(T) COLON. /*----- Assignment Statements -----*/ -/* This is no longer being used, in favor of handling assignments as expressions, just like C and C++ do. - Keep this here in case some other parts require assignment syntax or Lua-style multi-assignments become a thing. %type assign_statement{ZCC_AssignStmt *} -assign_statement(X) ::= expr_list(A) EQ expr_list(B). [EQ] +// The grammar won't let this pass without some syntactic help. +// Parentheses and braces aren't accepted either so brackets are the only way to get this through the parser without a conflict. +assign_statement(X) ::= LBRACKET expr_list(A) RBRACKET EQ expr(B). [EQ] { NEW_AST_NODE(AssignStmt,stmt,A); stmt->AssignOp = ZCC_EQ; @@ -1779,7 +1779,6 @@ assign_statement(X) ::= expr_list(A) EQ expr_list(B). [EQ] stmt->Sources = B; X = stmt; } -*/ /*----- Local Variable Definition "Statements" -----*/ diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index e50e8b822..7c78b3c1e 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2262,10 +2262,18 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool if (!(f->Flags & ZCC_Native)) { - auto code = ConvertAST(c->Type(), f->Body); - if (code != nullptr) + if (f->Body == nullptr) { - sym->Variants[0].Implementation = FunctionBuildList.AddFunction(sym, code, FStringf("%s.%s", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()), false, -1, 0, Lump); + Error(f, "Empty function %s", FName(f->Name).GetChars()); + return; + } + else + { + auto code = ConvertAST(c->Type(), f->Body); + if (code != nullptr) + { + sym->Variants[0].Implementation = FunctionBuildList.AddFunction(sym, code, FStringf("%s.%s", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()), false, -1, 0, Lump); + } } } if (sym->Variants[0].Implementation != nullptr && hasdefault) // do not copy empty default lists, they only waste space and processing time. @@ -3149,7 +3157,7 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) case AST_CaseStmt: { auto cases = static_cast(ast); - return new FxCaseStatement(ConvertNode(cases->Condition), *ast); + return new FxCaseStatement(ConvertNode(cases->Condition), *ast); } case AST_CompoundStmt: @@ -3164,6 +3172,21 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) } while (node != compound->Content); return x; } + + case AST_AssignStmt: + { + auto ass = static_cast(ast); + FArgumentList args; + ConvertNodeList(args, ass->Dests); + assert(ass->Sources->SiblingNext == ass->Sources); // right side should be a single function call - nothing else + if (ass->Sources->NodeType != AST_ExprFuncCall) + { + // don't let this through to the code generator. This node is only used to assign multiple returns of a function to more than one variable. + Error(ass, "Right side of multi-assignment must be a function call"); + return new FxNop(*ast); // allow compiler to continue looking for errors. + } + return new FxMultiAssign(args, ConvertNode(ass->Sources), *ast); + } } // only for development. I_Error is more convenient here than a normal error. I_Error("ConvertNode encountered unsupported node of type %d", ast->NodeType); diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 9244b9bdb..6832c70f0 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -52,6 +52,7 @@ zscript/doom/weaponfist.txt zscript/doom/weaponpistol.txt zscript/doom/weaponshotgun.txt zscript/doom/weaponchaingun.txt +zscript/doom/weaponchainsaw.txt zscript/doom/deadthings.txt zscript/doom/doomammo.txt diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 0fd6d2282..7f845472a 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -71,6 +71,9 @@ class Actor : Thinker native native void RemoveFromHash(); native string GetTag(string defstr = ""); native float GetBobOffset(float frac = 0); + native void ClearCounters(); + native bool GiveBody (int num, int max=0); + native void SetDamage(int dmg); native static bool isDehState(state st); native double Distance2D(Actor other); @@ -469,6 +472,7 @@ class Actor : Thinker native native int A_Explode(int damage = -1, int distance = -1, int flags = XF_HURTSOURCE, bool alert = false, int fulldamagedistance = 0, int nails = 0, int naildamage = 10, class pufftype = "BulletPuff", name damagetype = "none"); native void A_Stop(); native void A_Respawn(int flags = 1); + native void A_RestoreSpecialPosition(); native void A_QueueCorpse(); native void A_DeQueueCorpse(); native void A_ClearLastHeard(); diff --git a/wadsrc/static/zscript/doom/doomweapons.txt b/wadsrc/static/zscript/doom/doomweapons.txt index ee7a821ea..d7eb835ce 100644 --- a/wadsrc/static/zscript/doom/doomweapons.txt +++ b/wadsrc/static/zscript/doom/doomweapons.txt @@ -13,47 +13,6 @@ class DoomWeapon : Weapon } -// -------------------------------------------------------------------------- -// -// Chainsaw -// -// -------------------------------------------------------------------------- - -class Chainsaw : Weapon -{ - Default - { - Weapon.Kickback 0; - Weapon.SelectionOrder 2200; - Weapon.UpSound "weapons/sawup"; - Weapon.ReadySound "weapons/sawidle"; - Inventory.PickupMessage "$GOTCHAINSAW"; - Obituary "$OB_MPCHAINSAW"; - Tag "$TAG_CHAINSAW"; - +WEAPON.MELEEWEAPON - } - States - { - Ready: - SAWG CD 4 A_WeaponReady; - Loop; - Deselect: - SAWG C 1 A_Lower; - Loop; - Select: - SAWG C 1 A_Raise; - Loop; - Fire: - SAWG AB 4 A_Saw; - SAWG B 0 A_ReFire; - Goto Ready; - Spawn: - CSAW A -1; - Stop; - } -} - - // -------------------------------------------------------------------------- // // Shotgun diff --git a/wadsrc/static/zscript/doom/weaponchainsaw.txt b/wadsrc/static/zscript/doom/weaponchainsaw.txt new file mode 100644 index 000000000..b2583efa5 --- /dev/null +++ b/wadsrc/static/zscript/doom/weaponchainsaw.txt @@ -0,0 +1,166 @@ +// -------------------------------------------------------------------------- +// +// Chainsaw +// +// -------------------------------------------------------------------------- + +class Chainsaw : Weapon +{ + Default + { + Weapon.Kickback 0; + Weapon.SelectionOrder 2200; + Weapon.UpSound "weapons/sawup"; + Weapon.ReadySound "weapons/sawidle"; + Inventory.PickupMessage "$GOTCHAINSAW"; + Obituary "$OB_MPCHAINSAW"; + Tag "$TAG_CHAINSAW"; + +WEAPON.MELEEWEAPON + } + States + { + Ready: + SAWG CD 4 A_WeaponReady; + Loop; + Deselect: + SAWG C 1 A_Lower; + Loop; + Select: + SAWG C 1 A_Raise; + Loop; + Fire: + SAWG AB 4 A_Saw; + SAWG B 0 A_ReFire; + Goto Ready; + Spawn: + CSAW A -1; + Stop; + } +} + + +extend class StateProvider +{ + action void 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") + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + + if (pufftype == null) + { + pufftype = 'BulletPuff'; + } + if (damage == 0) + { + damage = 2; + } + if (!(flags & SF_NORANDOM)) + { + damage *= random[Saw](1, 10); + } + if (range == 0) + { + range = SAWRANGE; + } + + double ang = angle + spread_xy * (Random2[Saw]() / 255.); + double slope = AimLineAttack (ang, range, t) + spread_z * (Random2[Saw]() / 255.); + + Weapon weap = player.ReadyWeapon; + if (weap != null && !(flags & SF_NOUSEAMMO) && !(!t.linetarget && (flags & SF_NOUSEAMMOMISS)) && !weap.bDehAmmo && + invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + if (!weap.DepleteAmmo (weap.bAltFire)) + return; + } + + Actor puff; + int actualdamage; + [puff, actualdamage] = LineAttack (ang, range, slope, damage, 'Melee', pufftype, false, t); + + if (!t.linetarget) + { + if ((flags & SF_RANDOMLIGHTMISS) && (Random[Saw]() > 64)) + { + player.extralight = !player.extralight; + } + A_PlaySound (fullsound, CHAN_WEAPON); + return; + } + + if (flags & SF_RANDOMLIGHTHIT) + { + int randVal = Random[Saw](); + if (randVal < 64) + { + player.extralight = 0; + } + else if (randVal < 160) + { + player.extralight = 1; + } + else + { + player.extralight = 2; + } + } + + if (lifesteal && !t.linetarget.bDontDrain) + { + if (flags & SF_STEALARMOR) + { + if (armorbonustype == null) + { + armorbonustype = "ArmorBonus"; + } + if (armorbonustype != null) + { + BasicArmorBonus armorbonus = BasicArmorBonus(Spawn(armorbonustype)); + armorbonus.SaveAmount = int(armorbonus.SaveAmount * actualdamage * lifesteal); + armorbonus.MaxSaveAmount = lifestealmax <= 0 ? armorbonus.MaxSaveAmount : lifestealmax; + armorbonus.bDropped = true; + armorbonus.ClearCounters(); + + if (!armorbonus.CallTryPickup (self)) + { + armorbonus.Destroy (); + } + } + } + + else + { + GiveBody (int(actualdamage * lifesteal), lifestealmax); + } + } + + A_PlaySound (hitsound, CHAN_WEAPON); + + // turn to face target + if (!(flags & SF_NOTURN)) + { + double anglediff = deltaangle(angle, t.angleFromSource); + + if (anglediff < 0.0) + { + if (anglediff < -4.5) + angle = ang + 90.0 / 21; + else + angle -= 4.5; + } + else + { + if (anglediff > 4.5) + angle = ang - 90.0 / 21; + else + angle += 4.5; + } + } + if (!(flags & SF_NOPULLIN)) + bJustAttacked = true; + } +} diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index 64c649ad6..67bb840dd 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -11,10 +11,11 @@ class Inventory : Actor native } // These are regular functions for the item itself. - private native void A_RestoreSpecialPosition(); private native void A_RestoreSpecialDoomThing(); private native void A_RestoreSpecialThing1(); private native void A_RestoreSpecialThing2(); + + native bool, Actor CallTryPickup(Actor toucher); States(Actor, Overlay, Weapon, Item) { @@ -70,7 +71,6 @@ class StateProvider : Inventory native action native void A_CheckReload(); action native void A_GunFlash(statelabel flash = null, int flags = 0); action native void A_FireAssaultGun(); - action native void 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 state A_CheckForReload(int counter, statelabel label, bool dontincrement = false); action native void A_ResetReloadCounter(); } From 814493b68d07813d4c3e332cb0514966554297c2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 20 Nov 2016 00:45:06 +0100 Subject: [PATCH 046/185] - scriptified the Super Shotgun. --- src/g_doom/a_doomweaps.cpp | 51 --------- wadsrc/static/zscript.txt | 1 + wadsrc/static/zscript/doom/doomweapons.txt | 55 ---------- wadsrc/static/zscript/doom/weaponssg.txt | 116 +++++++++++++++++++++ wadsrc/static/zscript/shared/inventory.txt | 5 - 5 files changed, 117 insertions(+), 111 deletions(-) create mode 100644 wadsrc/static/zscript/doom/weaponssg.txt diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp index e802a6103..c23bd7f1f 100644 --- a/src/g_doom/a_doomweaps.cpp +++ b/src/g_doom/a_doomweaps.cpp @@ -16,63 +16,12 @@ */ void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int index); -static FRandom pr_fireshotgun2 ("FireSG2"); static FRandom pr_fireplasma ("FirePlasma"); static FRandom pr_firerail ("FireRail"); static FRandom pr_bfgspray ("BFGSpray"); static FRandom pr_oldbfg ("OldBFG"); -// -// A_FireShotgun2 -// -DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun2) -{ - PARAM_ACTION_PROLOGUE(AActor); - - int i; - DAngle angle; - int damage; - player_t *player; - - if (nullptr == (player = self->player)) - { - return 0; - } - - S_Sound (self, CHAN_WEAPON, "weapons/sshotf", 1, ATTN_NORM); - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != nullptr && ACTION_CALL_FROM_PSPRITE()) - { - if (!weapon->DepleteAmmo (weapon->bAltFire, true, 2)) - return 0; - P_SetPsprite(player, PSP_FLASH, weapon->FindState(NAME_Flash), true); - } - player->mo->PlayAttacking2 (); - - - DAngle pitch = P_BulletSlope (self); - - for (i=0 ; i<20 ; i++) - { - damage = 5*(pr_fireshotgun2()%3+1); - angle = self->Angles.Yaw + pr_fireshotgun2.Random2() * (11.25 / 256); - - // Doom adjusts the bullet slope by shifting a random number [-255,255] - // left 5 places. At 2048 units away, this means the vertical position - // of the shot can deviate as much as 255 units from nominal. So using - // some simple trigonometry, that means the vertical angle of the shot - // can deviate by as many as ~7.097 degrees or ~84676099 BAMs. - - P_LineAttack (self, - angle, - PLAYERMISSILERANGE, - pitch + pr_fireshotgun2.Random2() * (7.097 / 256), damage, - NAME_Hitscan, NAME_BulletPuff); - } - return 0; -} - // // A_FireMissile // diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 6832c70f0..e91176433 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -51,6 +51,7 @@ zscript/doom/bossbrain.txt zscript/doom/weaponfist.txt zscript/doom/weaponpistol.txt zscript/doom/weaponshotgun.txt +zscript/doom/weaponssg.txt zscript/doom/weaponchaingun.txt zscript/doom/weaponchainsaw.txt diff --git a/wadsrc/static/zscript/doom/doomweapons.txt b/wadsrc/static/zscript/doom/doomweapons.txt index d7eb835ce..55f3f3bcf 100644 --- a/wadsrc/static/zscript/doom/doomweapons.txt +++ b/wadsrc/static/zscript/doom/doomweapons.txt @@ -13,61 +13,6 @@ class DoomWeapon : Weapon } -// -------------------------------------------------------------------------- -// -// Shotgun -// -// -------------------------------------------------------------------------- - -class SuperShotgun : DoomWeapon -{ - Default - { - Weapon.SelectionOrder 400; - Weapon.AmmoUse 2; - Weapon.AmmoGive 8; - Weapon.AmmoType "Shell"; - Inventory.PickupMessage "$GOTSHOTGUN2"; - Obituary "$OB_MPSSHOTGUN"; - Tag "$TAG_SUPERSHOTGUN"; - } - States - { - Ready: - SHT2 A 1 A_WeaponReady; - Loop; - Deselect: - SHT2 A 1 A_Lower; - Loop; - Select: - SHT2 A 1 A_Raise; - Loop; - Fire: - SHT2 A 3; - SHT2 A 7 A_FireShotgun2; - SHT2 B 7; - SHT2 C 7 A_CheckReload; - SHT2 D 7 A_OpenShotgun2; - SHT2 E 7; - SHT2 F 7 A_LoadShotgun2; - SHT2 G 6; - SHT2 H 6 A_CloseShotgun2; - SHT2 A 5 A_ReFire; - Goto Ready; - // unused states - SHT2 B 7; - SHT2 A 3; - Goto Deselect; - Flash: - SHT2 I 4 Bright A_Light1; - SHT2 J 3 Bright A_Light2; - Goto LightDone; - Spawn: - SGN2 A -1; - Stop; - } -} - // -------------------------------------------------------------------------- // // Rocket launcher diff --git a/wadsrc/static/zscript/doom/weaponssg.txt b/wadsrc/static/zscript/doom/weaponssg.txt new file mode 100644 index 000000000..75ac9f09e --- /dev/null +++ b/wadsrc/static/zscript/doom/weaponssg.txt @@ -0,0 +1,116 @@ +// -------------------------------------------------------------------------- +// +// Super Shotgun +// +// -------------------------------------------------------------------------- + +class SuperShotgun : DoomWeapon +{ + Default + { + Weapon.SelectionOrder 400; + Weapon.AmmoUse 2; + Weapon.AmmoGive 8; + Weapon.AmmoType "Shell"; + Inventory.PickupMessage "$GOTSHOTGUN2"; + Obituary "$OB_MPSSHOTGUN"; + Tag "$TAG_SUPERSHOTGUN"; + } + States + { + Ready: + SHT2 A 1 A_WeaponReady; + Loop; + Deselect: + SHT2 A 1 A_Lower; + Loop; + Select: + SHT2 A 1 A_Raise; + Loop; + Fire: + SHT2 A 3; + SHT2 A 7 A_FireShotgun2; + SHT2 B 7; + SHT2 C 7 A_CheckReload; + SHT2 D 7 A_OpenShotgun2; + SHT2 E 7; + SHT2 F 7 A_LoadShotgun2; + SHT2 G 6; + SHT2 H 6 A_CloseShotgun2; + SHT2 A 5 A_ReFire; + Goto Ready; + // unused states + SHT2 B 7; + SHT2 A 3; + Goto Deselect; + Flash: + SHT2 I 4 Bright A_Light1; + SHT2 J 3 Bright A_Light2; + Goto LightDone; + Spawn: + SGN2 A -1; + Stop; + } +} + + + +//=========================================================================== +// +// Code (must be attached to StateProvider) +// +//=========================================================================== + +extend class StateProvider +{ + action void A_FireShotgun2() + { + if (player == null) + { + return; + } + + A_PlaySound ("weapons/sshotf", CHAN_WEAPON); + Weapon weap = player.ReadyWeapon; + if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + if (!weap.DepleteAmmo (weap.bAltFire, true, 2)) + return; + + player.SetPsprite(PSP_FLASH, weap.FindState('Flash'), true); + } + player.mo.PlayAttacking2 (); + + double pitch = BulletSlope (); + + for (int i = 0 ; i < 20 ; i++) + { + int damage = 5 * random[FireSG2](1, 3); + double ang = angle + Random2[FireSG2]() * (11.25 / 256); + + // Doom adjusts the bullet slope by shifting a random number [-255,255] + // left 5 places. At 2048 units away, this means the vertical position + // of the shot can deviate as much as 255 units from nominal. So using + // some simple trigonometry, that means the vertical angle of the shot + // can deviate by as many as ~7.097 degrees. + + LineAttack (ang, PLAYERMISSILERANGE, pitch + Random2[FireSG2]() * (7.097 / 256), damage, 'Hitscan', "BulletPuff"); + } + } + + + action void A_OpenShotgun2() + { + A_PlaySound("weapons/sshoto", CHAN_WEAPON); + } + + action void A_LoadShotgun2() + { + A_PlaySound("weapons/sshotl", CHAN_WEAPON); + } + + action void A_CloseShotgun2() + { + A_PlaySound("weapons/sshotc", CHAN_WEAPON); + } +} diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index 67bb840dd..8509001a9 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -50,11 +50,6 @@ class StateProvider : Inventory native action native void A_WeaponReady(int flags = 0); action native void A_Lower(); action native void A_Raise(); - action native void A_FireShotgun2(); - - action void A_OpenShotgun2() { A_PlaySound("weapons/sshoto", CHAN_WEAPON); } - action void A_LoadShotgun2() { A_PlaySound("weapons/sshotl", CHAN_WEAPON); } - action void A_CloseShotgun2() { A_PlaySound("weapons/sshotc", CHAN_WEAPON); } action native void A_FireSTGrenade(class grenadetype = "Grenade"); action native void A_FireMissile(); From fdab994fcbc9834d09a41f010c13d1cbc6593acf Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 20 Nov 2016 01:11:01 +0100 Subject: [PATCH 047/185] - scriptified the Rocket launcher. --- src/g_doom/a_doomweaps.cpp | 55 ------ src/p_mobj.cpp | 21 +++ wadsrc/static/zscript.txt | 1 + wadsrc/static/zscript/actor.txt | 1 + wadsrc/static/zscript/doom/doomweapons.txt | 129 ------------- wadsrc/static/zscript/doom/weaponrlaunch.txt | 189 +++++++++++++++++++ wadsrc/static/zscript/shared/inventory.txt | 2 - 7 files changed, 212 insertions(+), 186 deletions(-) create mode 100644 wadsrc/static/zscript/doom/weaponrlaunch.txt diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp index c23bd7f1f..cce1161cf 100644 --- a/src/g_doom/a_doomweaps.cpp +++ b/src/g_doom/a_doomweaps.cpp @@ -22,61 +22,6 @@ static FRandom pr_bfgspray ("BFGSpray"); static FRandom pr_oldbfg ("OldBFG"); -// -// A_FireMissile -// -DEFINE_ACTION_FUNCTION(AActor, A_FireMissile) -{ - PARAM_ACTION_PROLOGUE(AActor); - - player_t *player; - - if (NULL == (player = self->player)) - { - return 0; - } - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL && ACTION_CALL_FROM_PSPRITE()) - { - if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1)) - return 0; - } - P_SpawnPlayerMissile (self, PClass::FindActor("Rocket")); - return 0; -} - -// -// A_FireSTGrenade: not exactly backported from ST, but should work the same -// -DEFINE_ACTION_FUNCTION(AActor, A_FireSTGrenade) -{ - PARAM_ACTION_PROLOGUE(AActor); - PARAM_CLASS_DEF(grenade, AActor); - - player_t *player; - - if (grenade == NULL) - return 0; - - if (NULL == (player = self->player)) - { - return 0; - } - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL && ACTION_CALL_FROM_PSPRITE()) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - - // Temporarily raise the pitch to send the grenade slightly upwards - DAngle SavedPlayerPitch = self->Angles.Pitch; - self->Angles.Pitch -= 6.328125; //(1152 << F RACBITS); - P_SpawnPlayerMissile(self, grenade); - self->Angles.Pitch = SavedPlayerPitch; - return 0; -} - // // A_FirePlasma // diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index f28ea4b5f..964736fed 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -6463,6 +6463,27 @@ AActor *P_SpawnPlayerMissile (AActor *source, double x, double y, double z, return NULL; } +DEFINE_ACTION_FUNCTION(AActor, SpawnPlayerMissile) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_CLASS(type, AActor); + PARAM_ANGLE_DEF(angle); + PARAM_FLOAT_DEF(x); + PARAM_FLOAT_DEF(y); + PARAM_FLOAT_DEF(z); + PARAM_POINTER_DEF(lt, FTranslatedLineTarget); + PARAM_BOOL_DEF(nofreeaim); + PARAM_BOOL_DEF(noautoaim); + PARAM_INT_DEF(aimflags); + AActor *missileactor; + if (numparam == 2) angle = self->Angles.Yaw; + AActor *misl = P_SpawnPlayerMissile(self, x, y, z, type, angle, lt, &missileactor, nofreeaim, noautoaim, aimflags); + if (numret > 0) ret[0].SetPointer(misl, ATAG_OBJECT); + if (numret > 1) ret[1].SetPointer(missileactor, ATAG_OBJECT), numret = 2; + return numret; +} + + int AActor::GetTeam() { if (player) diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index e91176433..aec7e8089 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -54,6 +54,7 @@ zscript/doom/weaponshotgun.txt zscript/doom/weaponssg.txt zscript/doom/weaponchaingun.txt zscript/doom/weaponchainsaw.txt +zscript/doom/weaponrlaunch.txt zscript/doom/deadthings.txt zscript/doom/doomammo.txt diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 7f845472a..2288b6c1b 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -89,6 +89,7 @@ class Actor : Thinker native native Actor SpawnMissile(Actor dest, class type, Actor owner = null); native Actor SpawnMissileZ (double z, Actor dest, class type); native Actor SpawnMissileAngleZSpeed (double z, class type, float angle, double vz, double speed, Actor owner = null, bool checkspawn = true); + native Actor, Actor SpawnPlayerMissile(class type, double angle = 0, double x = 0, double y = 0, double z = 0, out FTranslatedLineTarget pLineTarget = null, bool nofreeaim = false, bool noautoaim = false, int aimflags = 0); native void A_Light(int extralight); void A_Light0() { A_Light(0); } diff --git a/wadsrc/static/zscript/doom/doomweapons.txt b/wadsrc/static/zscript/doom/doomweapons.txt index 55f3f3bcf..ade261d33 100644 --- a/wadsrc/static/zscript/doom/doomweapons.txt +++ b/wadsrc/static/zscript/doom/doomweapons.txt @@ -13,135 +13,6 @@ class DoomWeapon : Weapon } -// -------------------------------------------------------------------------- -// -// Rocket launcher -// -// -------------------------------------------------------------------------- - -class RocketLauncher : DoomWeapon -{ - Default - { - Weapon.SelectionOrder 2500; - Weapon.AmmoUse 1; - Weapon.AmmoGive 2; - Weapon.AmmoType "RocketAmmo"; - +WEAPON.NOAUTOFIRE - Inventory.PickupMessage "$GOTLAUNCHER"; - Tag "$TAG_ROCKETLAUNCHER"; - } - States - { - Ready: - MISG A 1 A_WeaponReady; - Loop; - Deselect: - MISG A 1 A_Lower; - Loop; - Select: - MISG A 1 A_Raise; - Loop; - Fire: - MISG B 8 A_GunFlash; - MISG B 12 A_FireMissile; - MISG B 0 A_ReFire; - Goto Ready; - Flash: - MISF A 3 Bright A_Light1; - MISF B 4 Bright; - MISF CD 4 Bright A_Light2; - Goto LightDone; - Spawn: - LAUN A -1; - Stop; - } -} - -class Rocket : Actor -{ - Default - { - Radius 11; - Height 8; - Speed 20; - Damage 20; - Projectile; - +RANDOMIZE - +DEHEXPLOSION - +ROCKETTRAIL - SeeSound "weapons/rocklf"; - DeathSound "weapons/rocklx"; - Obituary "$OB_MPROCKET"; - } - States - { - Spawn: - MISL A 1 Bright; - Loop; - Death: - MISL B 8 Bright A_Explode; - MISL C 6 Bright; - MISL D 4 Bright; - Stop; - BrainExplode: - MISL BC 10 Bright; - MISL D 10 A_BrainExplode; - Stop; - } -} - -// -------------------------------------------------------------------------- -// -// Grenade -- Taken and adapted from Skulltag, with MBF stuff added to it -// -// -------------------------------------------------------------------------- - -class Grenade : Actor -{ - Default - { - Radius 8; - Height 8; - Speed 25; - Damage 20; - Projectile; - -NOGRAVITY - +RANDOMIZE - +DEHEXPLOSION - +GRENADETRAIL - BounceType "Doom"; - Gravity 0.25; - SeeSound "weapons/grenlf"; - DeathSound "weapons/grenlx"; - BounceSound "weapons/grbnce"; - Obituary "$OB_GRENADE"; - DamageType "Grenade"; - } - States - { - Spawn: - SGRN A 1 Bright; - Loop; - Death: - MISL B 8 Bright A_Explode; - MISL C 6 Bright; - MISL D 4 Bright; - Stop; - Grenade: - MISL A 1000 A_Die; - Wait; - Detonate: - MISL B 4 A_Scream; - MISL C 6 A_Detonate; - MISL D 10; - Stop; - Mushroom: - MISL B 8 A_Mushroom; - Goto Death+1; - } -} - // -------------------------------------------------------------------------- // // Plasma rifle diff --git a/wadsrc/static/zscript/doom/weaponrlaunch.txt b/wadsrc/static/zscript/doom/weaponrlaunch.txt new file mode 100644 index 000000000..906db3823 --- /dev/null +++ b/wadsrc/static/zscript/doom/weaponrlaunch.txt @@ -0,0 +1,189 @@ +// -------------------------------------------------------------------------- +// +// Rocket launcher +// +// -------------------------------------------------------------------------- + +class RocketLauncher : DoomWeapon +{ + Default + { + Weapon.SelectionOrder 2500; + Weapon.AmmoUse 1; + Weapon.AmmoGive 2; + Weapon.AmmoType "RocketAmmo"; + +WEAPON.NOAUTOFIRE + Inventory.PickupMessage "$GOTLAUNCHER"; + Tag "$TAG_ROCKETLAUNCHER"; + } + States + { + Ready: + MISG A 1 A_WeaponReady; + Loop; + Deselect: + MISG A 1 A_Lower; + Loop; + Select: + MISG A 1 A_Raise; + Loop; + Fire: + MISG B 8 A_GunFlash; + MISG B 12 A_FireMissile; + MISG B 0 A_ReFire; + Goto Ready; + Flash: + MISF A 3 Bright A_Light1; + MISF B 4 Bright; + MISF CD 4 Bright A_Light2; + Goto LightDone; + Spawn: + LAUN A -1; + Stop; + } +} + +class Rocket : Actor +{ + Default + { + Radius 11; + Height 8; + Speed 20; + Damage 20; + Projectile; + +RANDOMIZE + +DEHEXPLOSION + +ROCKETTRAIL + SeeSound "weapons/rocklf"; + DeathSound "weapons/rocklx"; + Obituary "$OB_MPROCKET"; + } + States + { + Spawn: + MISL A 1 Bright; + Loop; + Death: + MISL B 8 Bright A_Explode; + MISL C 6 Bright; + MISL D 4 Bright; + Stop; + BrainExplode: + MISL BC 10 Bright; + MISL D 10 A_BrainExplode; + Stop; + } +} + +// -------------------------------------------------------------------------- +// +// Grenade -- Taken and adapted from Skulltag, with MBF stuff added to it +// +// -------------------------------------------------------------------------- + +class Grenade : Actor +{ + Default + { + Radius 8; + Height 8; + Speed 25; + Damage 20; + Projectile; + -NOGRAVITY + +RANDOMIZE + +DEHEXPLOSION + +GRENADETRAIL + BounceType "Doom"; + Gravity 0.25; + SeeSound "weapons/grenlf"; + DeathSound "weapons/grenlx"; + BounceSound "weapons/grbnce"; + Obituary "$OB_GRENADE"; + DamageType "Grenade"; + } + States + { + Spawn: + SGRN A 1 Bright; + Loop; + Death: + MISL B 8 Bright A_Explode; + MISL C 6 Bright; + MISL D 4 Bright; + Stop; + Grenade: + MISL A 1000 A_Die; + Wait; + Detonate: + MISL B 4 A_Scream; + MISL C 6 A_Detonate; + MISL D 10; + Stop; + Mushroom: + MISL B 8 A_Mushroom; + Goto Death+1; + } +} + +//=========================================================================== +// +// Code (must be attached to StateProvider) +// +//=========================================================================== + +extend class StateProvider +{ + + //=========================================================================== + // + // A_FireMissile + // + //=========================================================================== + + action void A_FireMissile() + { + if (player == null) + { + return; + } + Weapon weap = player.ReadyWeapon; + if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + return; + } + + SpawnPlayerMissile ("Rocket"); + } + + //=========================================================================== + // + // A_FireSTGrenade: not exactly backported from ST, but should work the same + // + //=========================================================================== + + action void A_FireSTGrenade(class grenadetype = "Grenade") + { + if (grenadetype == null) + return; + + if (player == null) + { + return; + } + Weapon weap = player.ReadyWeapon; + if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + return; + } + + // Temporarily raise the pitch to send the grenadetype slightly upwards + double savedpitch = pitch; + pitch -= 6.328125; + SpawnPlayerMissile(grenadetype); + pitch = SavedPitch; + } +} \ No newline at end of file diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index 8509001a9..c1f40fd1f 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -51,8 +51,6 @@ class StateProvider : Inventory native action native void A_Lower(); action native void A_Raise(); - action native void A_FireSTGrenade(class grenadetype = "Grenade"); - action native void A_FireMissile(); action native void A_FirePlasma(); action native void A_FireRailgun(); action native void A_FireRailgunLeft(); From 3c726aa57073f02f74e13faea92b5114b8bf9614 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 20 Nov 2016 01:18:21 +0100 Subject: [PATCH 048/185] - scriptified A_FirePlasma. --- src/g_doom/a_doomweaps.cpp | 31 ---- wadsrc/static/zscript.txt | 1 + wadsrc/static/zscript/doom/doomweapons.txt | 109 -------------- wadsrc/static/zscript/doom/weaponplasma.txt | 148 ++++++++++++++++++++ wadsrc/static/zscript/shared/inventory.txt | 1 - 5 files changed, 149 insertions(+), 141 deletions(-) create mode 100644 wadsrc/static/zscript/doom/weaponplasma.txt diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp index cce1161cf..067a106be 100644 --- a/src/g_doom/a_doomweaps.cpp +++ b/src/g_doom/a_doomweaps.cpp @@ -16,42 +16,11 @@ */ void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int index); -static FRandom pr_fireplasma ("FirePlasma"); static FRandom pr_firerail ("FireRail"); static FRandom pr_bfgspray ("BFGSpray"); static FRandom pr_oldbfg ("OldBFG"); -// -// A_FirePlasma -// -DEFINE_ACTION_FUNCTION(AActor, A_FirePlasma) -{ - PARAM_ACTION_PROLOGUE(AActor); - - player_t *player; - - if (NULL == (player = self->player)) - { - return 0; - } - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL && ACTION_CALL_FROM_PSPRITE()) - { - if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1)) - return 0; - - FState *flash = weapon->FindState(NAME_Flash); - if (flash != NULL) - { - P_SetSafeFlash(weapon, player, flash, (pr_fireplasma()&1)); - } - } - - P_SpawnPlayerMissile (self, PClass::FindActor("PlasmaBall")); - return 0; -} - // // [RH] A_FireRailgun // diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index aec7e8089..192089d85 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -55,6 +55,7 @@ zscript/doom/weaponssg.txt zscript/doom/weaponchaingun.txt zscript/doom/weaponchainsaw.txt zscript/doom/weaponrlaunch.txt +zscript/doom/weaponplasma.txt zscript/doom/deadthings.txt zscript/doom/doomammo.txt diff --git a/wadsrc/static/zscript/doom/doomweapons.txt b/wadsrc/static/zscript/doom/doomweapons.txt index ade261d33..7f8d7478f 100644 --- a/wadsrc/static/zscript/doom/doomweapons.txt +++ b/wadsrc/static/zscript/doom/doomweapons.txt @@ -13,115 +13,6 @@ class DoomWeapon : Weapon } -// -------------------------------------------------------------------------- -// -// Plasma rifle -// -// -------------------------------------------------------------------------- - -class PlasmaRifle : DoomWeapon -{ - Default - { - Weapon.SelectionOrder 100; - Weapon.AmmoUse 1; - Weapon.AmmoGive 40; - Weapon.AmmoType "Cell"; - Inventory.PickupMessage "$GOTPLASMA"; - Tag "$TAG_PLASMARIFLE"; - } - States - { - Ready: - PLSG A 1 A_WeaponReady; - Loop; - Deselect: - PLSG A 1 A_Lower; - Loop; - Select: - PLSG A 1 A_Raise; - Loop; - Fire: - PLSG A 3 A_FirePlasma; - PLSG B 20 A_ReFire; - Goto Ready; - Flash: - PLSF A 4 Bright A_Light1; - Goto LightDone; - PLSF B 4 Bright A_Light1; - Goto LightDone; - Spawn: - PLAS A -1; - Stop; - } -} - -class PlasmaBall : Actor -{ - Default - { - Radius 13; - Height 8; - Speed 25; - Damage 5; - Projectile; - +RANDOMIZE - RenderStyle "Add"; - Alpha 0.75; - SeeSound "weapons/plasmaf"; - DeathSound "weapons/plasmax"; - Obituary "$OB_MPPLASMARIFLE"; - } - States - { - Spawn: - PLSS AB 6 Bright; - Loop; - Death: - PLSE ABCDE 4 Bright; - Stop; - } -} - -// -------------------------------------------------------------------------- -// -// BFG 2704 -// -// -------------------------------------------------------------------------- - -class PlasmaBall1 : PlasmaBall -{ - Default - { - Damage 4; - BounceType "Classic"; - BounceFactor 1.0; - Obituary "$OB_MPBFG_MBF"; - } - States - { - Spawn: - PLS1 AB 6 Bright; - Loop; - Death: - PLS1 CDEFG 4 Bright; - Stop; - } -} - -class PlasmaBall2 : PlasmaBall1 -{ - States - { - Spawn: - PLS2 AB 6 Bright; - Loop; - Death: - PLS2 CDE 4 Bright; - Stop; - } -} - // -------------------------------------------------------------------------- // // BFG 9000 diff --git a/wadsrc/static/zscript/doom/weaponplasma.txt b/wadsrc/static/zscript/doom/weaponplasma.txt new file mode 100644 index 000000000..945339a35 --- /dev/null +++ b/wadsrc/static/zscript/doom/weaponplasma.txt @@ -0,0 +1,148 @@ +// -------------------------------------------------------------------------- +// +// Plasma rifle +// +// -------------------------------------------------------------------------- + +class PlasmaRifle : DoomWeapon +{ + Default + { + Weapon.SelectionOrder 100; + Weapon.AmmoUse 1; + Weapon.AmmoGive 40; + Weapon.AmmoType "Cell"; + Inventory.PickupMessage "$GOTPLASMA"; + Tag "$TAG_PLASMARIFLE"; + } + States + { + Ready: + PLSG A 1 A_WeaponReady; + Loop; + Deselect: + PLSG A 1 A_Lower; + Loop; + Select: + PLSG A 1 A_Raise; + Loop; + Fire: + PLSG A 3 A_FirePlasma; + PLSG B 20 A_ReFire; + Goto Ready; + Flash: + PLSF A 4 Bright A_Light1; + Goto LightDone; + PLSF B 4 Bright A_Light1; + Goto LightDone; + Spawn: + PLAS A -1; + Stop; + } +} + +class PlasmaBall : Actor +{ + Default + { + Radius 13; + Height 8; + Speed 25; + Damage 5; + Projectile; + +RANDOMIZE + RenderStyle "Add"; + Alpha 0.75; + SeeSound "weapons/plasmaf"; + DeathSound "weapons/plasmax"; + Obituary "$OB_MPPLASMARIFLE"; + } + States + { + Spawn: + PLSS AB 6 Bright; + Loop; + Death: + PLSE ABCDE 4 Bright; + Stop; + } +} + +// -------------------------------------------------------------------------- +// +// BFG 2704 +// +// -------------------------------------------------------------------------- + +class PlasmaBall1 : PlasmaBall +{ + Default + { + Damage 4; + BounceType "Classic"; + BounceFactor 1.0; + Obituary "$OB_MPBFG_MBF"; + } + States + { + Spawn: + PLS1 AB 6 Bright; + Loop; + Death: + PLS1 CDEFG 4 Bright; + Stop; + } +} + +class PlasmaBall2 : PlasmaBall1 +{ + States + { + Spawn: + PLS2 AB 6 Bright; + Loop; + Death: + PLS2 CDE 4 Bright; + Stop; + } +} + + +//=========================================================================== +// +// Code (must be attached to StateProvider) +// +//=========================================================================== + +extend class StateProvider +{ + + //=========================================================================== + // + // A_FirePlasma + // + //=========================================================================== + + action void A_FirePlasma() + { + if (player == null) + { + return; + } + Weapon weap = player.ReadyWeapon; + if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + return; + + State flash = weap.FindState('Flash'); + if (flash != null) + { + player.SetSafeFlash(weap, flash, random[FirePlasma]()&1); + } + + } + + SpawnPlayerMissile ("PlasmaBall"); + } +} diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index c1f40fd1f..270d5e6d7 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -51,7 +51,6 @@ class StateProvider : Inventory native action native void A_Lower(); action native void A_Raise(); - action native void A_FirePlasma(); action native void A_FireRailgun(); action native void A_FireRailgunLeft(); action native void A_FireRailgunRight(); From ab6b2f369ead21a8741381eae911a72291f0f890 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 20 Nov 2016 09:47:46 +0100 Subject: [PATCH 049/185] - fixed: For varargs, not only the type but also the flag of the last specified argument need to be stored for later parameters. --- src/scripting/codegeneration/codegen.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 12acc438b..56ee12eaf 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -7218,6 +7218,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) { bool foundvarargs = false; PType * type = nullptr; + int flag = 0; if (argtypes.Last() != nullptr && ArgList.Size() + implicit > argtypes.Size()) { ScriptPosition.Message(MSG_ERROR, "Too many arguments in call to %s", Function->SymbolName.GetChars()); @@ -7231,12 +7232,16 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) if (!foundvarargs) { if (argtypes[i + implicit] == nullptr) foundvarargs = true; - else type = argtypes[i + implicit]; + else + { + type = argtypes[i + implicit]; + flag = argflags[i + implicit]; + } } assert(type != nullptr); FxExpression *x; - if (!(argflags[i + implicit] & VARF_Ref)) + if (!(flag & VARF_Ref)) { x = new FxTypeCast(ArgList[i], type, false); x = x->Resolve(ctx); From bb25c5faaaccdfa029d56b08127e0bae3732ab85 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 20 Nov 2016 12:27:26 +0100 Subject: [PATCH 050/185] - scriptified the remaining Doom weapon code. - implemented method calls from struct instances. - optimized disassembly of VM call instructions to print the function's name at the end where it is more visible and does not need to be truncated. Also use the printable name for script functions here. --- src/g_doom/a_doommisc.cpp | 1 - src/g_doom/a_doomweaps.cpp | 251 -------------------- src/p_map.cpp | 11 + src/scripting/codegeneration/codegen.cpp | 54 +++-- src/scripting/vm/vmdisasm.cpp | 9 +- wadsrc/static/zscript.txt | 1 + wadsrc/static/zscript/actor.txt | 1 - wadsrc/static/zscript/constants.txt | 2 + wadsrc/static/zscript/doom/doomweapons.txt | 139 ++++------- wadsrc/static/zscript/doom/weaponbfg.txt | 259 +++++++++++++++++++++ wadsrc/static/zscript/shared/inventory.txt | 7 - 11 files changed, 359 insertions(+), 376 deletions(-) delete mode 100644 src/g_doom/a_doomweaps.cpp create mode 100644 wadsrc/static/zscript/doom/weaponbfg.txt diff --git a/src/g_doom/a_doommisc.cpp b/src/g_doom/a_doommisc.cpp index 467297761..ca13ac7ee 100644 --- a/src/g_doom/a_doommisc.cpp +++ b/src/g_doom/a_doommisc.cpp @@ -20,7 +20,6 @@ #include "g_shared/a_pickups.h" // Include all the other Doom stuff here to reduce compile time -#include "a_doomweaps.cpp" #include "a_painelemental.cpp" #include "a_scriptedmarine.cpp" diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp deleted file mode 100644 index 067a106be..000000000 --- a/src/g_doom/a_doomweaps.cpp +++ /dev/null @@ -1,251 +0,0 @@ -/* -#include "actor.h" -#include "info.h" -#include "s_sound.h" -#include "m_random.h" -#include "a_pickups.h" -#include "d_player.h" -#include "p_pspr.h" -#include "p_local.h" -#include "gstrings.h" -#include "p_effect.h" -#include "gi.h" -#include "templates.h" -#include "vm.h" -#include "doomstat.h" -*/ - -void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int index); -static FRandom pr_firerail ("FireRail"); -static FRandom pr_bfgspray ("BFGSpray"); -static FRandom pr_oldbfg ("OldBFG"); - - -// -// [RH] A_FireRailgun -// -static void FireRailgun(AActor *self, int offset_xy, bool fromweapon) -{ - int damage; - player_t *player; - - if (NULL == (player = self->player)) - { - return; - } - - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL && fromweapon) - { - if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1)) - return; - - FState *flash = weapon->FindState(NAME_Flash); - if (flash != NULL) - { - P_SetSafeFlash(weapon, player, flash, (pr_firerail()&1)); - } - } - - damage = deathmatch ? 100 : 150; - - FRailParams p; - p.source = self; - p.damage = damage; - p.offset_xy = offset_xy; - P_RailAttack (&p); -} - - -DEFINE_ACTION_FUNCTION(AActor, A_FireRailgun) -{ - PARAM_ACTION_PROLOGUE(AActor); - FireRailgun(self, 0, ACTION_CALL_FROM_PSPRITE()); - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_FireRailgunRight) -{ - PARAM_ACTION_PROLOGUE(AActor); - FireRailgun(self, 10, ACTION_CALL_FROM_PSPRITE()); - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_FireRailgunLeft) -{ - PARAM_ACTION_PROLOGUE(AActor); - FireRailgun(self, -10, ACTION_CALL_FROM_PSPRITE()); - return 0; -} - -// -// A_FireBFG -// - -DEFINE_ACTION_FUNCTION(AActor, A_FireBFG) -{ - PARAM_ACTION_PROLOGUE(AActor); - - player_t *player; - - if (NULL == (player = self->player)) - { - return 0; - } - - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL && ACTION_CALL_FROM_PSPRITE()) - { - if (!weapon->DepleteAmmo (weapon->bAltFire, true, deh.BFGCells)) - return 0; - } - - P_SpawnPlayerMissile (self, 0, 0, 0, PClass::FindActor("BFGBall"), self->Angles.Yaw, NULL, NULL, !!(dmflags2 & DF2_NO_FREEAIMBFG)); - return 0; -} - - -// -// A_BFGSpray -// Spawn a BFG explosion on every monster in view -// -enum BFG_Flags -{ - BFGF_HURTSOURCE = 1, - BFGF_MISSILEORIGIN = 2, -}; - -DEFINE_ACTION_FUNCTION(AActor, A_BFGSpray) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_CLASS_DEF (spraytype, AActor) - PARAM_INT_DEF (numrays) - PARAM_INT_DEF (damagecnt) - PARAM_ANGLE_DEF (angle) - PARAM_FLOAT_DEF (distance) - PARAM_ANGLE_DEF (vrange) - PARAM_INT_DEF (defdamage) - PARAM_INT_DEF (flags) - - int i; - int j; - int damage; - DAngle an; - FTranslatedLineTarget t; - AActor *originator; - - if (spraytype == NULL) spraytype = PClass::FindActor("BFGExtra"); - if (numrays <= 0) numrays = 40; - if (damagecnt <= 0) damagecnt = 15; - if (angle == 0) angle = 90.; - if (distance <= 0) distance = 16 * 64; - if (vrange == 0) vrange = 32.; - - // [RH] Don't crash if no target - if (!self->target) - return 0; - - // [XA] Set the originator of the rays to the projectile (self) if - // the new flag is set, else set it to the player (self->target) - originator = (flags & BFGF_MISSILEORIGIN) ? self : (AActor *)(self->target); - - // offset angles from its attack angle - for (i = 0; i < numrays; i++) - { - an = self->Angles.Yaw - angle / 2 + angle / numrays*i; - - P_AimLineAttack(originator, an, distance, &t, vrange); - - if (t.linetarget != NULL) - { - AActor *spray = Spawn(spraytype, t.linetarget->PosPlusZ(t.linetarget->Height / 4), ALLOW_REPLACE); - - int dmgFlags = 0; - FName dmgType = NAME_BFGSplash; - - if (spray != NULL) - { - if ((spray->flags6 & MF6_MTHRUSPECIES && self->target->GetSpecies() == t.linetarget->GetSpecies()) || - (!(flags & BFGF_HURTSOURCE) && self->target == t.linetarget)) // [XA] Don't hit oneself unless we say so. - { - spray->Destroy(); // [MC] Remove it because technically, the spray isn't trying to "hit" them. - continue; - } - if (spray->flags5 & MF5_PUFFGETSOWNER) spray->target = self->target; - if (spray->flags3 & MF3_FOILINVUL) dmgFlags |= DMG_FOILINVUL; - if (spray->flags7 & MF7_FOILBUDDHA) dmgFlags |= DMG_FOILBUDDHA; - dmgType = spray->DamageType; - } - - if (defdamage == 0) - { - damage = 0; - for (j = 0; j < damagecnt; ++j) - damage += (pr_bfgspray() & 7) + 1; - } - else - { - // if this is used, damagecnt will be ignored - damage = defdamage; - } - - int newdam = P_DamageMobj(t.linetarget, originator, self->target, damage, dmgType, dmgFlags|DMG_USEANGLE, t.angleFromSource.Degrees); - P_TraceBleed(newdam > 0 ? newdam : damage, &t, self); - } - } - return 0; -} - -// -// A_FireOldBFG -// -// This function emulates Doom's Pre-Beta BFG -// By Lee Killough 6/6/98, 7/11/98, 7/19/98, 8/20/98 -// -// This code may not be used in other mods without appropriate credit given. -// Code leeches will be telefragged. - -DEFINE_ACTION_FUNCTION(AActor, A_FireOldBFG) -{ - PARAM_ACTION_PROLOGUE(AActor); - PClassActor *plasma[] = { PClass::FindActor("PlasmaBall1"), PClass::FindActor("PlasmaBall2") }; - AActor * mo = NULL; - - player_t *player; - bool doesautoaim = false; - - if (NULL == (player = self->player)) - { - return 0; - } - - AWeapon *weapon = self->player->ReadyWeapon; - if (!ACTION_CALL_FROM_PSPRITE()) weapon = NULL; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1)) - return 0; - - doesautoaim = !(weapon->WeaponFlags & WIF_NOAUTOAIM); - weapon->WeaponFlags |= WIF_NOAUTOAIM; // No autoaiming that gun - } - self->player->extralight = 2; - - // Save values temporarily - DAngle SavedPlayerAngle = self->Angles.Yaw; - DAngle SavedPlayerPitch = self->Angles.Pitch; - for (int i = 0; i < 2; i++) // Spawn two plasma balls in sequence - { - self->Angles.Yaw += ((pr_oldbfg()&127) - 64) * (90./768); - self->Angles.Pitch += ((pr_oldbfg()&127) - 64) * (90./640); - mo = P_SpawnPlayerMissile (self, plasma[i]); - // Restore saved values - self->Angles.Yaw = SavedPlayerAngle; - self->Angles.Pitch = SavedPlayerPitch; - } - if (doesautoaim && weapon != NULL) - { // Restore autoaim setting - weapon->WeaponFlags &= ~WIF_NOAUTOAIM; - } - return 0; -} diff --git a/src/p_map.cpp b/src/p_map.cpp index 26dc3d473..eedd503d8 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -4660,6 +4660,17 @@ void P_TraceBleed(int damage, FTranslatedLineTarget *t, AActor *puff) P_TraceBleed(damage, t->linetarget->PosPlusZ(t->linetarget->Height/2), t->linetarget, t->angleFromSource, pitch); } +DEFINE_ACTION_FUNCTION(_FTranslatedLineTarget, TraceBleed) +{ + PARAM_SELF_STRUCT_PROLOGUE(FTranslatedLineTarget); + PARAM_INT(damage); + PARAM_OBJECT(missile, AActor); + + P_TraceBleed(damage, self, missile); + return 0; +} + + //========================================================================== // // diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 56ee12eaf..6dac05d7b 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -6878,6 +6878,22 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) return nullptr; } } + else if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PStruct))) + { + bool writable; + if (Self->RequestAddress(ctx, &writable) && writable) + { + cls = static_cast(Self->ValueType); + Self->ValueType = NewPointer(Self->ValueType); + } + else + { + // Cannot be made writable so we cannot use its methods. + ScriptPosition.Message(MSG_ERROR, "Invalid expression on left hand side of %s\n", MethodName.GetChars()); + delete this; + return nullptr; + } + } else { ScriptPosition.Message(MSG_ERROR, "Invalid expression on left hand side of %s\n", MethodName.GetChars()); @@ -7250,18 +7266,22 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) { bool writable; ArgList[i] = ArgList[i]->Resolve(ctx); // nust be resolved before the address is requested. - ArgList[i]->RequestAddress(ctx, &writable); - ArgList[i]->ValueType = NewPointer(ArgList[i]->ValueType); - // For a reference argument the types must match 100%. - if (type != ArgList[i]->ValueType) + if (ArgList[i]->ValueType != TypeNullPtr) { - ScriptPosition.Message(MSG_ERROR, "Type mismatch in reference argument", Function->SymbolName.GetChars()); - x = nullptr; - } - else - { - x = ArgList[i]; + ArgList[i]->RequestAddress(ctx, &writable); + ArgList[i]->ValueType = NewPointer(ArgList[i]->ValueType); + // For a reference argument the types must match 100%. + if (type != ArgList[i]->ValueType) + { + ScriptPosition.Message(MSG_ERROR, "Type mismatch in reference argument", Function->SymbolName.GetChars()); + x = nullptr; + } + else + { + x = ArgList[i]; + } } + else x = ArgList[i]; } failed |= (x == nullptr); ArgList[i] = x; @@ -7305,13 +7325,6 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) { ValueType = TypeVoid; } - // If self is a struct, it will be a value type, not a reference, so we need to make an addresss request. - if (Self != nullptr && Self->ValueType->IsKindOf(RUNTIME_CLASS(PStruct)) && !Self->ValueType->IsKindOf(RUNTIME_CLASS(PClass))) - { - bool writable; - Self->RequestAddress(ctx, &writable); - } - return this; } @@ -8852,6 +8865,13 @@ FxExpression *FxClassPtrCast::Resolve(FCompileContext &ctx) return this; } } + else if (basex->ValueType == TypeString || basex->ValueType == TypeName) + { + FxExpression *x = new FxClassTypeCast(to, basex); + basex = nullptr; + delete this; + return x->Resolve(ctx); + } // Everything else is an error. ScriptPosition.Message(MSG_ERROR, "Cannot cast %s to %s. The types are incompatible.", basex->ValueType->DescriptiveName(), to->DescriptiveName()); delete this; diff --git a/src/scripting/vm/vmdisasm.cpp b/src/scripting/vm/vmdisasm.cpp index 07d6fb8e3..031f3328b 100644 --- a/src/scripting/vm/vmdisasm.cpp +++ b/src/scripting/vm/vmdisasm.cpp @@ -323,15 +323,15 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction 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); + col = printf_wrapper(out, "[%p],%d", callfunc, 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) { @@ -494,7 +494,8 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction } else if (code[i].op == OP_CALL_K || code[i].op == OP_TAIL_K) { - printf_wrapper(out, " [%p]\n", callfunc); + callname = callfunc->IsKindOf(RUNTIME_CLASS(VMScriptFunction)) ? static_cast(callfunc)->PrintableName : callfunc->Name != NAME_None ? callfunc->Name : "[anonfunc]"; + printf_wrapper(out, " [%s]\n", callname); } else { diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 192089d85..fdf057b58 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -56,6 +56,7 @@ zscript/doom/weaponchaingun.txt zscript/doom/weaponchainsaw.txt zscript/doom/weaponrlaunch.txt zscript/doom/weaponplasma.txt +zscript/doom/weaponbfg.txt zscript/doom/deadthings.txt zscript/doom/doomammo.txt diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 2288b6c1b..7f088154f 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -364,7 +364,6 @@ class Actor : Thinker native // End of MBF redundant functions. native void A_MonsterRail(); - native void A_BFGSpray(class spraytype = "BFGExtra", int numrays = 40, int damagecount = 15, float angle = 90, float distance = 16*64, float vrange = 32, int damage = 0, int flags = 0); native void A_Pain(); native void A_NoBlocking(bool drop = true); void A_Fall() { A_NoBlocking(); } diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index cfdc98425..29c60450c 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -840,6 +840,8 @@ struct FTranslatedLineTarget Actor linetarget; double angleFromSource; bool unlinked; // found by a trace that went through an unlinked portal. + + native void TraceBleed(int damage, Actor missile); } enum EAimFlags diff --git a/wadsrc/static/zscript/doom/doomweapons.txt b/wadsrc/static/zscript/doom/doomweapons.txt index 7f8d7478f..75f856218 100644 --- a/wadsrc/static/zscript/doom/doomweapons.txt +++ b/wadsrc/static/zscript/doom/doomweapons.txt @@ -1,6 +1,6 @@ // -------------------------------------------------------------------------- // -// Doom weapon base class +// Doom weap base class // // -------------------------------------------------------------------------- @@ -13,102 +13,51 @@ class DoomWeapon : Weapon } -// -------------------------------------------------------------------------- -// -// BFG 9000 -// -// -------------------------------------------------------------------------- -class BFG9000 : DoomWeapon +extend class StateProvider { - Default - { - Height 20; - Weapon.SelectionOrder 2800; - Weapon.AmmoUse 40; - Weapon.AmmoGive 40; - Weapon.AmmoType "Cell"; - +WEAPON.NOAUTOFIRE; - Inventory.PickupMessage "$GOTBFG9000"; - Tag "$TAG_BFG9000"; - } - States - { - Ready: - BFGG A 1 A_WeaponReady; - Loop; - Deselect: - BFGG A 1 A_Lower; - Loop; - Select: - BFGG A 1 A_Raise; - Loop; - Fire: - BFGG A 20 A_BFGsound; - BFGG B 10 A_GunFlash; - BFGG B 10 A_FireBFG; - BFGG B 20 A_ReFire; - Goto Ready; - Flash: - BFGF A 11 Bright A_Light1; - BFGF B 6 Bright A_Light2; - Goto LightDone; - Spawn: - BFUG A -1; - Stop; - OldFire: - BFGG A 10 A_BFGsound; - BFGG BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB 1 A_FireOldBFG; - BFGG B 0 A_Light0; - BFGG B 20 A_ReFire; - Goto Ready; - } -} + // + // [RH] A_FireRailgun + // + action void A_FireRailgun(int offset_xy = 0) + { + if (player == null) + { + return; + } -class BFGBall : Actor -{ - Default - { - Radius 13; - Height 8; - Speed 25; - Damage 100; - Projectile; - +RANDOMIZE - RenderStyle "Add"; - Alpha 0.75; - DeathSound "weapons/bfgx"; - Obituary "$OB_MPBFG_BOOM"; - } - States - { - Spawn: - BFS1 AB 4 Bright; - Loop; - Death: - BFE1 AB 8 Bright; - BFE1 C 8 Bright A_BFGSpray; - BFE1 DEF 8 Bright; - Stop; - } -} - -class BFGExtra : Actor -{ - Default - { - +NOBLOCKMAP - +NOGRAVITY - RenderStyle "Add"; - Alpha 0.75; - DamageType "BFGSplash"; - } - States - { - Spawn: - BFE2 ABCD 8 Bright; - Stop; - } -} + Weapon weap = player.ReadyWeapon; + if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + return; + + State flash = weap.FindState('Flash'); + if (flash != null) + { + player.SetSafeFlash(weap, flash, random[FireRail]()&1); + } + + } + int damage = GetCVar("deathmatch") ? 100 : 150; + A_RailAttack(damage, offset_xy, false); // note that this function handles ammo depletion itself for Dehacked compatibility purposes. + } + + action void A_FireRailgunLeft() + { + A_FireRailgun(-10); + } + + action void A_FireRailgunRight() + { + A_FireRailgun(10); + } + + action void A_RailWait() + { + // only here to satisfy old Dehacked patches. + } + +} \ No newline at end of file diff --git a/wadsrc/static/zscript/doom/weaponbfg.txt b/wadsrc/static/zscript/doom/weaponbfg.txt new file mode 100644 index 000000000..27f318daf --- /dev/null +++ b/wadsrc/static/zscript/doom/weaponbfg.txt @@ -0,0 +1,259 @@ +// -------------------------------------------------------------------------- +// +// BFG 9000 +// +// -------------------------------------------------------------------------- + +class BFG9000 : DoomWeapon +{ + Default + { + Height 20; + Weapon.SelectionOrder 2800; + Weapon.AmmoUse 40; + Weapon.AmmoGive 40; + Weapon.AmmoType "Cell"; + +WEAPON.NOAUTOFIRE; + Inventory.PickupMessage "$GOTBFG9000"; + Tag "$TAG_BFG9000"; + } + States + { + Ready: + BFGG A 1 A_WeaponReady; + Loop; + Deselect: + BFGG A 1 A_Lower; + Loop; + Select: + BFGG A 1 A_Raise; + Loop; + Fire: + BFGG A 20 A_BFGsound; + BFGG B 10 A_GunFlash; + BFGG B 10 A_FireBFG; + BFGG B 20 A_ReFire; + Goto Ready; + Flash: + BFGF A 11 Bright A_Light1; + BFGF B 6 Bright A_Light2; + Goto LightDone; + Spawn: + BFUG A -1; + Stop; + OldFire: + BFGG A 10 A_BFGsound; + BFGG BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB 1 A_FireOldBFG; + BFGG B 0 A_Light0; + BFGG B 20 A_ReFire; + Goto Ready; + } +} + +//=========================================================================== +// +// Weapon code (must be attached to StateProvider) +// +//=========================================================================== + +extend class StateProvider +{ + action void A_BFGsound() + { + A_PlaySound("weapons/bfgf", CHAN_WEAPON); + } + + + // + // A_FireBFG + // + + action void A_FireBFG() + { + if (player == null) + { + return; + } + Weapon weap = player.ReadyWeapon; + if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + return; + } + + SpawnPlayerMissile("BFGBall", angle, 0, 0, 0, null, false, GetCVar("sv_nobfgaim")); + } + + + // + // A_FireOldBFG + // + // This function emulates Doom's Pre-Beta BFG + // By Lee Killough 6/6/98, 7/11/98, 7/19/98, 8/20/98 + // + // This code may not be used in other mods without appropriate credit given. + // Code leeches will be telefragged. + + action void A_FireOldBFG() + { + bool doesautoaim = false; + + if (player == null) + { + return; + } + Weapon weap = player.ReadyWeapon; + + if (invoker != weap || stateinfo == null || stateinfo.mStateType != STATE_Psprite) weap = null; + if (weap != null) + { + if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + return; + + doesautoaim = weap.bNoAutoaim; + weap.bNoAutoaim = true; + } + player.extralight = 2; + + // Save values temporarily + double SavedPlayerAngle = angle; + double SavedPlayerPitch = pitch; + for (int i = 0; i < 2; i++) // Spawn two plasma balls in sequence + { + angle += ((random[OldBFG]() & 127) - 64) * (90./768); + pitch += ((random[OldBFG]() & 127) - 64) * (90./640); + SpawnPlayerMissile (i == 0? (class)("PlasmaBall1") : (class)("PlasmaBall2")); + // Restore saved values + angle = SavedPlayerAngle; + pitch = SavedPlayerPitch; + } + // Restore autoaim setting + if (weap != null) weap.bNoAutoaim = doesautoaim; + } +} + +class BFGBall : Actor +{ + Default + { + Radius 13; + Height 8; + Speed 25; + Damage 100; + Projectile; + +RANDOMIZE + RenderStyle "Add"; + Alpha 0.75; + DeathSound "weapons/bfgx"; + Obituary "$OB_MPBFG_BOOM"; + } + States + { + Spawn: + BFS1 AB 4 Bright; + Loop; + Death: + BFE1 AB 8 Bright; + BFE1 C 8 Bright A_BFGSpray; + BFE1 DEF 8 Bright; + Stop; + } +} + +class BFGExtra : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + RenderStyle "Add"; + Alpha 0.75; + DamageType "BFGSplash"; + } + States + { + Spawn: + BFE2 ABCD 8 Bright; + Stop; + } +} + + +//=========================================================================== +// +// Code (must be attached to Actor) +// +//=========================================================================== + +extend class Actor +{ + // + // A_BFGSpray + // Spawn a BFG explosion on every monster in view + // + void A_BFGSpray(class spraytype = "BFGExtra", int numrays = 40, int damagecnt = 15, double ang = 90, double distance = 16*64, double vrange = 32, int defdamage = 0, int flags = 0) + { + int damage; + FTranslatedLineTarget t; + + // validate parameters + if (spraytype == null) spraytype = "BFGExtra"; + if (numrays <= 0) numrays = 40; + if (damagecnt <= 0) damagecnt = 15; + if (ang == 0) ang = 90.; + if (distance <= 0) distance = 16 * 64; + if (vrange == 0) vrange = 32.; + + // [RH] Don't crash if no target + if (!target) return; + + // [XA] Set the originator of the rays to the projectile (self) if + // the new flag is set, else set it to the player (target) + Actor originator = (flags & BFGF_MISSILEORIGIN) ? self : target; + + // offset angles from its attack ang + for (int i = 0; i < numrays; i++) + { + double an = angle - ang / 2 + ang / numrays*i; + + originator.AimLineAttack(an, distance, t, vrange); + + if (t.linetarget != null) + { + Actor spray = Spawn(spraytype, t.linetarget.pos + (0, 0, t.linetarget.Height / 4), ALLOW_REPLACE); + + int dmgFlags = 0; + Name dmgType = 'BFGSplash'; + + if (spray != null) + { + if ((spray.bMThruSpecies && target.GetSpecies() == t.linetarget.GetSpecies()) || + (!(flags & BFGF_HURTSOURCE) && target == t.linetarget)) // [XA] Don't hit oneself unless we say so. + { + spray.Destroy(); // [MC] Remove it because technically, the spray isn't trying to "hit" them. + continue; + } + if (spray.bPuffGetsOwner) spray.target = target; + if (spray.bFoilInvul) dmgFlags |= DMG_FOILINVUL; + if (spray.bFoilBuddha) dmgFlags |= DMG_FOILBUDDHA; + dmgType = spray.DamageType; + } + + if (defdamage == 0) + { + damage = 0; + for (int j = 0; j < damagecnt; ++j) + damage += Random[BFGSpray](1, 8); + } + else + { + // if this is used, damagecnt will be ignored + damage = defdamage; + } + + int newdam = t.linetarget.DamageMobj(originator, target, damage, dmgType, dmgFlags|DMG_USEANGLE, t.angleFromSource); + t.TraceBleed(newdam > 0 ? newdam : damage, self); + } + } + } +} diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index 270d5e6d7..d5734e149 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -51,13 +51,6 @@ class StateProvider : Inventory native action native void A_Lower(); action native void A_Raise(); - action native void A_FireRailgun(); - action native void A_FireRailgunLeft(); - action native void A_FireRailgunRight(); - action void A_RailWait() {} - action void A_BFGsound() { A_PlaySound("weapons/bfgf", CHAN_WEAPON); } - action native void A_FireBFG(); - action native void A_FireOldBFG(); action native void A_ReFire(statelabel flash = null); action native void A_ClearReFire(); action native void A_CheckReload(); From 5951a9449c37115778ea56ac5c514a62343a8d33 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 20 Nov 2016 18:00:37 +0100 Subject: [PATCH 051/185] - added static constant arrays. At the moment they can only be defined inside functions due to lack of dedicated storage inside classes for static data. - added new VM instructions to access the constant tables with a variable index. - refactored VMFunctionBuilder's constant tables so that they are not limited to one entry per value. While this works fine for single values, it makes it impossible to store constant arrays in here. --- src/scripting/codegeneration/codegen.cpp | 216 +++++++++++++++++++---- src/scripting/codegeneration/codegen.h | 44 +++++ src/scripting/vm/vmbuilder.cpp | 147 +++++++++------ src/scripting/vm/vmbuilder.h | 35 ++-- src/scripting/vm/vmdisasm.cpp | 3 + src/scripting/vm/vmexec.h | 20 +++ src/scripting/vm/vmops.h | 4 + src/scripting/zscript/ast.cpp | 10 ++ src/scripting/zscript/zcc-parse.lemon | 23 +++ src/scripting/zscript/zcc_compile.cpp | 9 + src/scripting/zscript/zcc_parser.h | 8 + 11 files changed, 413 insertions(+), 106 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 6dac05d7b..7be1b9cf2 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -5402,7 +5402,13 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) FxLocalVariableDeclaration *local = ctx.FindLocalVariable(Identifier); if (local != nullptr) { - if (local->ValueType->GetRegType() != REGT_NIL) + if (local->ExprType == EFX_StaticArray) + { + auto x = new FxStaticArrayVariable(local, ScriptPosition); + delete this; + return x->Resolve(ctx); + } + else if (local->ValueType->GetRegType() != REGT_NIL) { auto x = new FxLocalVariable(local, ScriptPosition); delete this; @@ -5693,6 +5699,38 @@ ExpEmit FxLocalVariable::Emit(VMFunctionBuilder *build) } +//========================================================================== +// +// +// +//========================================================================== + +FxStaticArrayVariable::FxStaticArrayVariable(FxLocalVariableDeclaration *var, const FScriptPosition &sc) + : FxExpression(EFX_StaticArrayVariable, sc) +{ + Variable = static_cast(var); + ValueType = Variable->ValueType; +} + +FxExpression *FxStaticArrayVariable::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + return this; +} + +bool FxStaticArrayVariable::RequestAddress(FCompileContext &ctx, bool *writable) +{ + AddressRequested = true; + if (writable != nullptr) *writable = false; + return true; +} + +ExpEmit FxStaticArrayVariable::Emit(VMFunctionBuilder *build) +{ + // returns the first const register for this array + return ExpEmit(Variable->StackOffset, Variable->ElementType->GetRegType(), true, false); +} + //========================================================================== // @@ -6357,6 +6395,7 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) ExpEmit start = Array->Emit(build); PArray *const arraytype = static_cast(Array->ValueType); + /* what was this for? if (start.Konst) { ExpEmit tmpstart(build, REGT_POINTER); @@ -6364,16 +6403,17 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) start.Free(build); start = tmpstart; } + */ if (index->isConstant()) { unsigned indexval = static_cast(index)->GetValue().GetInt(); assert(indexval < arraytype->ElementCount && "Array index out of bounds"); - indexval *= arraytype->ElementSize; if (AddressRequested) { if (indexval != 0) { + indexval *= arraytype->ElementSize; if (!start.Fixed) { build->Emit(OP_ADDA_RK, start.RegNum, start.RegNum, build->GetConstantInt(indexval)); @@ -6389,61 +6429,90 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) } return start; } - else + else if (!start.Konst) { start.Free(build); ExpEmit dest(build, ValueType->GetRegType()); - build->Emit(arraytype->ElementType->GetLoadOp(), dest.RegNum, start.RegNum, build->GetConstantInt(indexval)); + build->Emit(arraytype->ElementType->GetLoadOp(), dest.RegNum, start.RegNum, build->GetConstantInt(indexval* arraytype->ElementSize)); + return dest; + } + else + { + static int LK_Ops[] = { OP_LK, OP_LKF, OP_LKS, OP_LKP }; + assert(start.RegType == ValueType->GetRegType()); + ExpEmit dest(build, start.RegType); + build->Emit(LK_Ops[start.RegType], dest.RegNum, start.RegNum + indexval); return dest; } } else { ExpEmit indexv(index->Emit(build)); - ExpEmit indexwork = indexv.Fixed ? ExpEmit(build, indexv.RegType) : indexv; build->Emit(OP_BOUND, indexv.RegNum, arraytype->ElementCount); - int shiftbits = 0; - while (1u << shiftbits < arraytype->ElementSize) - { - shiftbits++; - } - if (1u << shiftbits == arraytype->ElementSize) + if (!start.Konst) { - if (shiftbits > 0) + ExpEmit indexwork = indexv.Fixed ? ExpEmit(build, indexv.RegType) : indexv; + int shiftbits = 0; + while (1u << shiftbits < arraytype->ElementSize) { - build->Emit(OP_SLL_RI, indexwork.RegNum, indexv.RegNum, shiftbits); + shiftbits++; } - } - else - { - // A shift won't do, so use a multiplication - build->Emit(OP_MUL_RK, indexwork.RegNum, indexv.RegNum, build->GetConstantInt(arraytype->ElementSize)); - } - - indexwork.Free(build); - if (AddressRequested) - { - if (!start.Fixed) + if (1u << shiftbits == arraytype->ElementSize) { - build->Emit(OP_ADDA_RR, start.RegNum, start.RegNum, indexwork.RegNum); + if (shiftbits > 0) + { + build->Emit(OP_SLL_RI, indexwork.RegNum, indexv.RegNum, shiftbits); + } + } + else + { + // A shift won't do, so use a multiplication + build->Emit(OP_MUL_RK, indexwork.RegNum, indexv.RegNum, build->GetConstantInt(arraytype->ElementSize)); + } + indexwork.Free(build); + + if (AddressRequested) + { + if (!start.Fixed) + { + build->Emit(OP_ADDA_RR, start.RegNum, start.RegNum, indexwork.RegNum); + } + else + { + start.Free(build); + // do not clobber local variables. + ExpEmit temp(build, start.RegType); + build->Emit(OP_ADDA_RR, temp.RegNum, start.RegNum, indexwork.RegNum); + start = temp; + } + return start; } else { start.Free(build); - // do not clobber local variables. - ExpEmit temp(build, start.RegType); - build->Emit(OP_ADDA_RR, temp.RegNum, start.RegNum, indexwork.RegNum); - start = temp; + ExpEmit dest(build, ValueType->GetRegType()); + // added 1 to use the *_R version that takes the offset from a register + build->Emit(arraytype->ElementType->GetLoadOp() + 1, dest.RegNum, start.RegNum, indexwork.RegNum); + return dest; } - return start; } else { - start.Free(build); - ExpEmit dest(build, ValueType->GetRegType()); - // added 1 to use the *_R version that takes the offset from a register - build->Emit(arraytype->ElementType->GetLoadOp() + 1, dest.RegNum, start.RegNum, indexwork.RegNum); + static int LKR_Ops[] = { OP_LK_R, OP_LKF_R, OP_LKS_R, OP_LKP_R }; + assert(start.RegType == ValueType->GetRegType()); + ExpEmit dest(build, start.RegType); + if (start.RegNum <= 255) + { + // Since large constant tables are the exception, the constant component in C is an immediate value here. + build->Emit(LKR_Ops[start.RegType], dest.RegNum, indexv.RegNum, start.RegNum); + } + else + { + build->Emit(OP_ADD_RK, indexv.RegNum, indexv.RegNum, build->GetConstantInt(start.RegNum)); + build->Emit(LKR_Ops[start.RegType], dest.RegNum, indexv.RegNum, 0); + } + indexv.Free(build); return dest; } } @@ -9241,3 +9310,82 @@ void FxLocalVariableDeclaration::Release(VMFunctionBuilder *build) // Stack space will not be released because that would make controlled destruction impossible. // For that all local stack variables need to live for the entire execution of a function. } + + +FxStaticArray::FxStaticArray(PType *type, FName name, FArgumentList &args, const FScriptPosition &pos) + : FxLocalVariableDeclaration(NewArray(type, args.Size()), name, nullptr, VARF_Static|VARF_ReadOnly, pos) +{ + ElementType = type; + ExprType = EFX_StaticArray; + values = std::move(args); +} + +FxExpression *FxStaticArray::Resolve(FCompileContext &ctx) +{ + bool fail = false; + for (unsigned i = 0; i < values.Size(); i++) + { + values[i] = new FxTypeCast(values[i], ElementType, false); + values[i] = values[i]->Resolve(ctx); + if (values[i] == nullptr) fail = true; + else if (!values[i]->isConstant()) + { + ScriptPosition.Message(MSG_ERROR, "Initializer must be constant"); + fail = true; + } + } + if (fail) + { + delete this; + return nullptr; + } + if (ElementType->GetRegType() == REGT_NIL) + { + ScriptPosition.Message(MSG_ERROR, "Invalid type for constant array"); + delete this; + return nullptr; + } + + ctx.Block->LocalVars.Push(this); + return this; +} + +ExpEmit FxStaticArray::Emit(VMFunctionBuilder *build) +{ + switch (ElementType->GetRegType()) + { + default: + assert(false && "Invalid register type"); + break; + + case REGT_INT: + { + TArray cvalues; + for (auto v : values) cvalues.Push(static_cast(v)->GetValue().GetInt()); + StackOffset = build->AllocConstantsInt(cvalues.Size(), &cvalues[0]); + break; + } + case REGT_FLOAT: + { + TArray cvalues; + for (auto v : values) cvalues.Push(static_cast(v)->GetValue().GetFloat()); + StackOffset = build->AllocConstantsFloat(cvalues.Size(), &cvalues[0]); + break; + } + case REGT_STRING: + { + TArray cvalues; + for (auto v : values) cvalues.Push(static_cast(v)->GetValue().GetString()); + StackOffset = build->AllocConstantsString(cvalues.Size(), &cvalues[0]); + break; + } + case REGT_POINTER: + { + TArray cvalues; + for (auto v : values) cvalues.Push(static_cast(v)->GetValue().GetPointer()); + StackOffset = build->AllocConstantsAddress(cvalues.Size(), &cvalues[0], ElementType->GetLoadOp() == OP_LO ? ATAG_OBJECT : ATAG_GENERIC); + break; + } + } + return ExpEmit(); +} diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index 03b256970..7f588a0eb 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -282,6 +282,8 @@ enum EFxType EFX_Super, EFX_StackVariable, EFX_MultiAssign, + EFX_StaticArray, + EFX_StaticArrayVariable, EFX_COUNT }; @@ -1308,6 +1310,25 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// FxLocalVariable +// +//========================================================================== +class FxStaticArray; + +class FxStaticArrayVariable : public FxExpression +{ +public: + FxStaticArray *Variable; + bool AddressRequested; + + FxStaticArrayVariable(FxLocalVariableDeclaration*, const FScriptPosition&); + FxExpression *Resolve(FCompileContext&); + bool RequestAddress(FCompileContext &ctx, bool *writable); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxSelf @@ -1529,6 +1550,7 @@ class FxCompoundStatement : public FxSequence FxCompoundStatement *Outer = nullptr; friend class FxLocalVariableDeclaration; + friend class FxStaticArray; friend class FxMultiAssign; public: @@ -1841,6 +1863,7 @@ class FxLocalVariableDeclaration : public FxExpression { friend class FxCompoundStatement; friend class FxLocalVariable; + friend class FxStaticArrayVariable; FName Name; FxExpression *Init; @@ -1859,4 +1882,25 @@ public: }; +//========================================================================== +// +// +// +//========================================================================== + +class FxStaticArray : public FxLocalVariableDeclaration +{ + friend class FxStaticArrayVariable; + + PType *ElementType; + FArgumentList values; + +public: + + FxStaticArray(PType *type, FName name, FArgumentList &args, const FScriptPosition &pos); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + + #endif diff --git a/src/scripting/vm/vmbuilder.cpp b/src/scripting/vm/vmbuilder.cpp index 721ff5fab..042753d32 100644 --- a/src/scripting/vm/vmbuilder.cpp +++ b/src/scripting/vm/vmbuilder.cpp @@ -45,10 +45,6 @@ VMFunctionBuilder::VMFunctionBuilder(int numimplicits) { - NumIntConstants = 0; - NumFloatConstants = 0; - NumAddressConstants = 0; - NumStringConstants = 0; MaxParam = 0; ActiveParam = 0; NumImplicits = numimplicits; @@ -74,25 +70,25 @@ VMFunctionBuilder::~VMFunctionBuilder() void VMFunctionBuilder::MakeFunction(VMScriptFunction *func) { - func->Alloc(Code.Size(), NumIntConstants, NumFloatConstants, NumStringConstants, NumAddressConstants); + func->Alloc(Code.Size(), IntConstantList.Size(), FloatConstantList.Size(), StringConstantList.Size(), AddressConstantList.Size()); // Copy code block. memcpy(func->Code, &Code[0], Code.Size() * sizeof(VMOP)); // Create constant tables. - if (NumIntConstants > 0) + if (IntConstantList.Size() > 0) { FillIntConstants(func->KonstD); } - if (NumFloatConstants > 0) + if (FloatConstantList.Size() > 0) { FillFloatConstants(func->KonstF); } - if (NumAddressConstants > 0) + if (AddressConstantList.Size() > 0) { FillAddressConstants(func->KonstA, func->KonstATags()); } - if (NumStringConstants > 0) + if (StringConstantList.Size() > 0) { FillStringConstants(func->KonstS); } @@ -118,13 +114,7 @@ void VMFunctionBuilder::MakeFunction(VMScriptFunction *func) void VMFunctionBuilder::FillIntConstants(int *konst) { - TMapIterator it(IntConstants); - TMap::Pair *pair; - - while (it.NextPair(pair)) - { - konst[pair->Value] = pair->Key; - } + memcpy(konst, &IntConstantList[0], sizeof(int) * IntConstantList.Size()); } //========================================================================== @@ -135,13 +125,7 @@ void VMFunctionBuilder::FillIntConstants(int *konst) void VMFunctionBuilder::FillFloatConstants(double *konst) { - TMapIterator it(FloatConstants); - TMap::Pair *pair; - - while (it.NextPair(pair)) - { - konst[pair->Value] = pair->Key; - } + memcpy(konst, &FloatConstantList[0], sizeof(double) * FloatConstantList.Size()); } //========================================================================== @@ -152,14 +136,8 @@ void VMFunctionBuilder::FillFloatConstants(double *konst) 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; - } + memcpy(konst, &AddressConstantList[0], sizeof(void*) * AddressConstantList.Size()); + memcpy(tags, &AtagConstantList[0], sizeof(VM_ATAG) * AtagConstantList.Size()); } //========================================================================== @@ -170,12 +148,9 @@ void VMFunctionBuilder::FillAddressConstants(FVoidObj *konst, VM_ATAG *tags) void VMFunctionBuilder::FillStringConstants(FString *konst) { - TMapIterator it(StringConstants); - TMap::Pair *pair; - - while (it.NextPair(pair)) + for (auto &s : StringConstantList) { - konst[pair->Value] = pair->Key; + *konst++ = s; } } @@ -183,22 +158,21 @@ void VMFunctionBuilder::FillStringConstants(FString *konst) // // VMFunctionBuilder :: GetConstantInt // -// Returns a constant register initialized with the given value, or -1 if -// there were no more constants free. +// Returns a constant register initialized with the given value. // //========================================================================== -int VMFunctionBuilder::GetConstantInt(int val) +unsigned VMFunctionBuilder::GetConstantInt(int val) { - int *locp = IntConstants.CheckKey(val); + unsigned int *locp = IntConstantMap.CheckKey(val); if (locp != NULL) { return *locp; } else { - int loc = NumIntConstants++; - IntConstants.Insert(val, loc); + unsigned loc = IntConstantList.Push(val); + IntConstantMap.Insert(val, loc); return loc; } } @@ -207,22 +181,21 @@ int VMFunctionBuilder::GetConstantInt(int val) // // VMFunctionBuilder :: GetConstantFloat // -// Returns a constant register initialized with the given value, or -1 if -// there were no more constants free. +// Returns a constant register initialized with the given value. // //========================================================================== -int VMFunctionBuilder::GetConstantFloat(double val) +unsigned VMFunctionBuilder::GetConstantFloat(double val) { - int *locp = FloatConstants.CheckKey(val); + unsigned *locp = FloatConstantMap.CheckKey(val); if (locp != NULL) { return *locp; } else { - int loc = NumFloatConstants++; - FloatConstants.Insert(val, loc); + unsigned loc = FloatConstantList.Push(val); + FloatConstantMap.Insert(val, loc); return loc; } } @@ -231,22 +204,21 @@ int VMFunctionBuilder::GetConstantFloat(double val) // // VMFunctionBuilder :: GetConstantString // -// Returns a constant register initialized with the given value, or -1 if -// there were no more constants free. +// Returns a constant register initialized with the given value. // //========================================================================== -int VMFunctionBuilder::GetConstantString(FString val) +unsigned VMFunctionBuilder::GetConstantString(FString val) { - int *locp = StringConstants.CheckKey(val); + unsigned *locp = StringConstantMap.CheckKey(val); if (locp != NULL) { return *locp; } else { - int loc = NumStringConstants++; - StringConstants.Insert(val, loc); + int loc = StringConstantList.Push(val); + StringConstantMap.Insert(val, loc); return loc; } } @@ -260,13 +232,13 @@ int VMFunctionBuilder::GetConstantString(FString val) // //========================================================================== -int VMFunctionBuilder::GetConstantAddress(void *ptr, VM_ATAG tag) +unsigned 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); + AddrKonst *locp = AddressConstantMap.CheckKey(ptr); if (locp != NULL) { // There should only be one tag associated with a memory location. @@ -275,12 +247,71 @@ int VMFunctionBuilder::GetConstantAddress(void *ptr, VM_ATAG tag) } else { - AddrKonst loc = { NumAddressConstants++, tag }; - AddressConstants.Insert(ptr, loc); + unsigned locc = AddressConstantList.Push(ptr); + AtagConstantList.Push(tag); + + AddrKonst loc = { locc, tag }; + AddressConstantMap.Insert(ptr, loc); return loc.KonstNum; } } +//========================================================================== +// +// VMFunctionBuilder :: AllocConstants* +// +// Returns a range of constant register initialized with the given values. +// +//========================================================================== + +unsigned VMFunctionBuilder::AllocConstantsInt(unsigned count, int *values) +{ + unsigned addr = IntConstantList.Reserve(count); + memcpy(&IntConstantList[addr], values, count * sizeof(int)); + for (unsigned i = 0; i < count; i++) + { + IntConstantMap.Insert(values[i], addr + i); + } + return addr; +} + +unsigned VMFunctionBuilder::AllocConstantsFloat(unsigned count, double *values) +{ + unsigned addr = FloatConstantList.Reserve(count); + memcpy(&FloatConstantList[addr], values, count * sizeof(double)); + for (unsigned i = 0; i < count; i++) + { + FloatConstantMap.Insert(values[i], addr + i); + } + return addr; +} + +unsigned VMFunctionBuilder::AllocConstantsAddress(unsigned count, void **ptrs, VM_ATAG tag) +{ + unsigned addr = AddressConstantList.Reserve(count); + AtagConstantList.Reserve(count); + memcpy(&AddressConstantList[addr], ptrs, count * sizeof(void *)); + for (unsigned i = 0; i < count; i++) + { + AtagConstantList[addr + i] = tag; + AddrKonst loc = { addr+i, tag }; + AddressConstantMap.Insert(ptrs[i], loc); + } + return addr; +} + +unsigned VMFunctionBuilder::AllocConstantsString(unsigned count, FString *ptrs) +{ + unsigned addr = StringConstantList.Reserve(count); + for (unsigned i = 0; i < count; i++) + { + StringConstantList[addr + i] = ptrs[i]; + StringConstantMap.Insert(ptrs[i], addr + i); + } + return addr; +} + + //========================================================================== // // VMFunctionBuilder :: ParamChange diff --git a/src/scripting/vm/vmbuilder.h b/src/scripting/vm/vmbuilder.h index d69c97707..5991d0711 100644 --- a/src/scripting/vm/vmbuilder.h +++ b/src/scripting/vm/vmbuilder.h @@ -42,10 +42,16 @@ public: void MakeFunction(VMScriptFunction *func); // 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); + unsigned GetConstantInt(int val); + unsigned GetConstantFloat(double val); + unsigned GetConstantAddress(void *ptr, VM_ATAG tag); + unsigned GetConstantString(FString str); + + unsigned AllocConstantsInt(unsigned int count, int *values); + unsigned AllocConstantsFloat(unsigned int count, double *values); + unsigned AllocConstantsAddress(unsigned int count, void **ptrs, VM_ATAG tag); + unsigned AllocConstantsString(unsigned int count, FString *ptrs); + // Returns the address of the next instruction to be emitted. size_t GetAddress(); @@ -82,19 +88,20 @@ public: private: struct AddrKonst { - int KonstNum; + unsigned 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; + TArray IntConstantList; + TArray FloatConstantList; + TArray AddressConstantList; + TArray AtagConstantList; + TArray StringConstantList; + // These map from the constant value to its position in the constant table. + TMap IntConstantMap; + TMap FloatConstantMap; + TMap AddressConstantMap; + TMap StringConstantMap; int MaxParam; int ActiveParam; diff --git a/src/scripting/vm/vmdisasm.cpp b/src/scripting/vm/vmdisasm.cpp index 031f3328b..c95699613 100644 --- a/src/scripting/vm/vmdisasm.cpp +++ b/src/scripting/vm/vmdisasm.cpp @@ -97,6 +97,9 @@ #define RIRIRI MODE_AI | MODE_BI | MODE_CI #define RIRII8 MODE_AI | MODE_BI | MODE_CIMMZ +#define RFRII8 MODE_AF | MODE_BI | MODE_CIMMZ +#define RPRII8 MODE_AP | MODE_BI | MODE_CIMMZ +#define RSRII8 MODE_AS | 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 diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index e4ab95946..6202de3bb 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -84,6 +84,26 @@ begin: reg.a[a] = konsta[BC].v; reg.atag[a] = konstatag[BC]; NEXTOP; + + OP(LK_R) : + ASSERTD(a); ASSERTD(B); + reg.d[a] = konstd[reg.d[B] + C]; + NEXTOP; + OP(LKF_R) : + ASSERTF(a); ASSERTD(B); + reg.f[a] = konstf[reg.d[B] + C]; + NEXTOP; + OP(LKS_R) : + ASSERTS(a); ASSERTD(B); + reg.s[a] = konsts[reg.d[B] + C]; + NEXTOP; + OP(LKP_R) : + ASSERTA(a); ASSERTD(B); + b = reg.d[B] + C; + reg.a[a] = konsta[b].v; + reg.atag[a] = konstatag[b]; + NEXTOP; + OP(LFP): ASSERTA(a); assert(sfunc != NULL); assert(sfunc->ExtraSpace > 0); reg.a[a] = f->GetExtra(); diff --git a/src/scripting/vm/vmops.h b/src/scripting/vm/vmops.h index 210ff9c49..6f78e9e4e 100644 --- a/src/scripting/vm/vmops.h +++ b/src/scripting/vm/vmops.h @@ -10,6 +10,10 @@ 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(LK_R, lk, RIRII8), // load integer constant indexed +xx(LKF_R, lk, RFRII8), // load float constant indexed +xx(LKS_R, lk, RSRII8), // load string constant indexed +xx(LKP_R, lk, RPRII8), // load pointer constant indexed xx(LFP, lf, LFP), // load frame pointer // Load from memory. rA = *(rB + rkC) diff --git a/src/scripting/zscript/ast.cpp b/src/scripting/zscript/ast.cpp index d8945ca3b..3bdc2e244 100644 --- a/src/scripting/zscript/ast.cpp +++ b/src/scripting/zscript/ast.cpp @@ -595,6 +595,16 @@ static void PrintExprClassCast(FLispString &out, ZCC_TreeNode *node) out.Close(); } +static void PrintStaticArray(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_StaticArrayStatement *enode = (ZCC_StaticArrayStatement *)node; + out.Open("static-array-stmt"); + PrintNodes(out, enode->Type, false); + out.AddName(enode->Id); + PrintNodes(out, enode->Values, false); + out.Close(); +} + static void PrintExprMemberAccess(FLispString &out, ZCC_TreeNode *node) { ZCC_ExprMemberAccess *enode = (ZCC_ExprMemberAccess *)node; diff --git a/src/scripting/zscript/zcc-parse.lemon b/src/scripting/zscript/zcc-parse.lemon index 8bd9686e3..3380959ec 100644 --- a/src/scripting/zscript/zcc-parse.lemon +++ b/src/scripting/zscript/zcc-parse.lemon @@ -1559,6 +1559,29 @@ statement(X) ::= jump_statement(X). statement(X) ::= assign_statement(A) SEMICOLON. { X = A; /*X-overwrites-A*/ } statement(X) ::= local_var(A) SEMICOLON. { X = A; /*X-overwrites-A*/ } statement(X) ::= error SEMICOLON. { X = NULL; } +statement(X) ::= staticarray_statement(A). { X = A; /*X-overwrites-A*/ } + +/*----- Static array Statements -----*/ + +%type staticarray_statement{ZCC_StaticArrayStatement *} + +staticarray_statement(X) ::= STATIC CONST type(A) IDENTIFIER(B) LBRACKET RBRACKET EQ LBRACE expr_list(C) RBRACE. +{ + NEW_AST_NODE(StaticArrayStatement, stmt, A); + stmt->Type = A; + stmt->Id = ENamedName(B.Int); + stmt->Values = C; + X = stmt; +} + +staticarray_statement(X) ::= STATIC CONST type(A) LBRACKET RBRACKET IDENTIFIER(B) EQ LBRACE expr_list(C) RBRACE. +{ + NEW_AST_NODE(StaticArrayStatement, stmt, A); + stmt->Type = A; + stmt->Id = ENamedName(B.Int); + stmt->Values = C; + X = stmt; +} /*----- Jump Statements -----*/ diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 7c78b3c1e..291387617 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2826,6 +2826,15 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) return new FxClassPtrCast(cls, ConvertNode(cc->Parameters)); } + case AST_StaticArrayStatement: + { + auto sas = static_cast(ast); + PType *ztype = DetermineType(ConvertClass, sas, sas->Id, sas->Type, false, false); + FArgumentList args; + ConvertNodeList(args, sas->Values); + // This has to let the code generator resolve the constants, not the Simplifier, which lacks all the necessary type info. + return new FxStaticArray(ztype, sas->Id, args, *ast); + } case AST_ExprMemberAccess: { diff --git a/src/scripting/zscript/zcc_parser.h b/src/scripting/zscript/zcc_parser.h index dd777eb6c..a19249208 100644 --- a/src/scripting/zscript/zcc_parser.h +++ b/src/scripting/zscript/zcc_parser.h @@ -103,6 +103,7 @@ enum EZCCTreeNodeType AST_VectorValue, AST_DeclFlags, AST_ClassCast, + AST_StaticArrayStatement, NUM_AST_NODE_TYPES }; @@ -406,6 +407,13 @@ struct ZCC_Statement : ZCC_TreeNode { }; +struct ZCC_StaticArrayStatement : ZCC_Statement +{ + ZCC_Type *Type; + ENamedName Id; + ZCC_Expression *Values; +}; + struct ZCC_CompoundStmt : ZCC_Statement { ZCC_Statement *Content; From 159f09105e1d96b5eabc3c5aa1a6fefa2ac6ea01 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 20 Nov 2016 18:34:27 +0100 Subject: [PATCH 052/185] - used static constant arrays to shorten some code. --- wadsrc/static/zscript/actor.txt | 14 ++------------ wadsrc/static/zscript/hexen/demons.txt | 16 ++++++---------- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 7f088154f..5c824d7bb 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -282,21 +282,11 @@ class Actor : Thinker native void SpawnDirt (double radius) { - class dtype; - switch (random[Dirt](0, 5)) - { - case 0: dtype = "Dirt1"; break; - case 1: dtype = "Dirt2"; break; - case 2: dtype = "Dirt3"; break; - case 3: dtype = "Dirt4"; break; - case 4: dtype = "Dirt5"; break; - default: dtype = "Dirt6"; break; - } - + static const class chunks[] = { "Dirt1", "Dirt2", "Dirt3", "Dirt4", "Dirt5", "Dirt6" }; double zo = random[Dirt]() / 128. + 1; Vector3 pos = Vec3Angle(radius, random[Dirt]() * (360./256), zo); - Actor mo = Spawn (dtype, pos, ALLOW_REPLACE); + Actor mo = Spawn (chunks[random[Dirt](0, 5)], pos, ALLOW_REPLACE); if (mo) { mo.Vel.Z = random[Dirt]() / 64.; diff --git a/wadsrc/static/zscript/hexen/demons.txt b/wadsrc/static/zscript/hexen/demons.txt index 8aa65629d..25e078509 100644 --- a/wadsrc/static/zscript/hexen/demons.txt +++ b/wadsrc/static/zscript/hexen/demons.txt @@ -58,11 +58,9 @@ class Demon1 : Actor DEMN H 6; DEMN I 6 { - A_SpawnItemEx("Demon1Chunk1", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle+90), frandom[DemonChunks](1,4.984375)*sin(Angle+90), 8, 90, ChunkFlags); - A_SpawnItemEx("Demon1Chunk2", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 270, ChunkFlags); - A_SpawnItemEx("Demon1Chunk3", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 270, ChunkFlags); - A_SpawnItemEx("Demon1Chunk4", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 270, ChunkFlags); - A_SpawnItemEx("Demon1Chunk5", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 270, ChunkFlags); + static const class chunks[] = { "Demon1Chunk1", "Demon1Chunk2", "Demon1Chunk3", "Demon1Chunk4", "Demon1Chunk5" }; + for(int i = 0; i < 5; i++) + A_SpawnItemEx(chunks[i], 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle+90), frandom[DemonChunks](1,4.984375)*sin(Angle+90), 8, 90, ChunkFlags); } Goto Death+2; Ice: @@ -266,11 +264,9 @@ class Demon2 : Demon1 DEM2 H 6; DEM2 I 6 { - A_SpawnItemEx("Demon2Chunk1", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle+90), frandom[DemonChunks](1,4.984375)*sin(Angle+90), 8, 90, ChunkFlags); - A_SpawnItemEx("Demon2Chunk2", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 270, ChunkFlags); - A_SpawnItemEx("Demon2Chunk3", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 270, ChunkFlags); - A_SpawnItemEx("Demon2Chunk4", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 270, ChunkFlags); - A_SpawnItemEx("Demon2Chunk5", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 270, ChunkFlags); + static const class chunks[] = { "Demon2Chunk1", "Demon2Chunk2", "Demon2Chunk3", "Demon2Chunk4", "Demon2Chunk5" }; + for(int i = 0; i < 5; i++) + A_SpawnItemEx(chunks[i], 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle+90), frandom[DemonChunks](1,4.984375)*sin(Angle+90), 8, 90, ChunkFlags); } Goto Death+2; } From 1c2c26eb0860981adfd3494d3919ea9e318c97ce Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 20 Nov 2016 20:24:39 +0100 Subject: [PATCH 053/185] - implemented direct CVar access. --- src/c_cvars.cpp | 4 +- src/c_cvars.h | 13 ++- src/scripting/codegeneration/codegen.cpp | 128 ++++++++++++++++++++++- src/scripting/codegeneration/codegen.h | 10 ++ 4 files changed, 148 insertions(+), 7 deletions(-) diff --git a/src/c_cvars.cpp b/src/c_cvars.cpp index c8f1ee4c6..fe859cb49 100644 --- a/src/c_cvars.cpp +++ b/src/c_cvars.cpp @@ -1093,7 +1093,7 @@ BitVal (bitval) ECVarType FFlagCVar::GetRealType () const { - return CVAR_Dummy; + return CVAR_DummyBool; } UCVarValue FFlagCVar::GetGenericRep (ECVarType type) const @@ -1197,7 +1197,7 @@ BitVal (bitval) ECVarType FMaskCVar::GetRealType () const { - return CVAR_Dummy; + return CVAR_DummyInt; } UCVarValue FMaskCVar::GetGenericRep (ECVarType type) const diff --git a/src/c_cvars.h b/src/c_cvars.h index be7676e89..cf6975b86 100644 --- a/src/c_cvars.h +++ b/src/c_cvars.h @@ -81,13 +81,17 @@ enum ECVarType CVAR_Float, CVAR_String, CVAR_Color, // stored as CVAR_Int - CVAR_Dummy, // just redirects to another cvar + CVAR_DummyBool, // just redirects to another cvar + CVAR_DummyInt, // just redirects to another cvar + CVAR_Dummy, // Unknown CVAR_GUID }; class FConfigFile; class AActor; +class FxCVar; + class FBaseCVar { public: @@ -211,6 +215,7 @@ void C_DeinitConsole(); class FBoolCVar : public FBaseCVar { + friend class FxCVar; public: FBoolCVar (const char *name, bool def, uint32 flags, void (*callback)(FBoolCVar &)=NULL); @@ -236,6 +241,7 @@ protected: class FIntCVar : public FBaseCVar { + friend class FxCVar; public: FIntCVar (const char *name, int def, uint32 flags, void (*callback)(FIntCVar &)=NULL); @@ -263,6 +269,7 @@ protected: class FFloatCVar : public FBaseCVar { + friend class FxCVar; public: FFloatCVar (const char *name, float def, uint32 flags, void (*callback)(FFloatCVar &)=NULL); @@ -289,6 +296,7 @@ protected: class FStringCVar : public FBaseCVar { + friend class FxCVar; public: FStringCVar (const char *name, const char *def, uint32 flags, void (*callback)(FStringCVar &)=NULL); ~FStringCVar (); @@ -315,6 +323,7 @@ protected: class FColorCVar : public FIntCVar { + friend class FxCVar; public: FColorCVar (const char *name, int def, uint32 flags, void (*callback)(FColorCVar &)=NULL); @@ -339,6 +348,7 @@ protected: class FFlagCVar : public FBaseCVar { + friend class FxCVar; public: FFlagCVar (const char *name, FIntCVar &realvar, uint32 bitval); @@ -367,6 +377,7 @@ protected: class FMaskCVar : public FBaseCVar { + friend class FxCVar; public: FMaskCVar (const char *name, FIntCVar &realvar, uint32 bitval); diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 7be1b9cf2..9ca96de05 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -1993,7 +1993,7 @@ ExpEmit FxPreIncrDecr::Emit(VMFunctionBuilder *build) if (regtype == REGT_INT) { - build->Emit((Token == TK_Incr) ? OP_ADD_RK : OP_SUB_RK, value.RegNum, value.RegNum, build->GetConstantInt(1)); + build->Emit(OP_ADDI, value.RegNum, value.RegNum, (Token == TK_Incr) ? 1 : -1); } else { @@ -2077,7 +2077,7 @@ ExpEmit FxPostIncrDecr::Emit(VMFunctionBuilder *build) ExpEmit assign(build, regtype); if (regtype == REGT_INT) { - build->Emit((Token == TK_Incr) ? OP_ADD_RK : OP_SUB_RK, assign.RegNum, out.RegNum, build->GetConstantInt(1)); + build->Emit(OP_ADDI, assign.RegNum, out.RegNum, (Token == TK_Incr) ? 1 : -1); } else { @@ -2094,7 +2094,7 @@ ExpEmit FxPostIncrDecr::Emit(VMFunctionBuilder *build) if (regtype == REGT_INT) { build->Emit(OP_MOVE, out.RegNum, pointer.RegNum); - build->Emit((Token == TK_Incr) ? OP_ADD_RK : OP_SUB_RK, pointer.RegNum, pointer.RegNum, build->GetConstantInt(1)); + build->Emit(OP_ADDI, pointer.RegNum, pointer.RegNum, (Token == TK_Incr) ? 1 : -1); } else { @@ -2108,7 +2108,7 @@ ExpEmit FxPostIncrDecr::Emit(VMFunctionBuilder *build) { if (regtype == REGT_INT) { - build->Emit((Token == TK_Incr) ? OP_ADD_RK : OP_SUB_RK, pointer.RegNum, pointer.RegNum, build->GetConstantInt(1)); + build->Emit(OP_ADDI, pointer.RegNum, pointer.RegNum, (Token == TK_Incr) ? 1 : -1); } else { @@ -5526,6 +5526,18 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as line special %d\n", Identifier.GetChars(), num); newex = new FxConstant(num, ScriptPosition); } + + auto cvar = FindCVar(Identifier.GetChars(), nullptr); + if (cvar != nullptr) + { + if (cvar->GetFlags() & CVAR_USERINFO) + { + ScriptPosition.Message(MSG_ERROR, "Cannot access userinfo CVARs directly. Use GetCVar() instead."); + delete this; + return nullptr; + } + newex = new FxCVar(cvar, ScriptPosition); + } if (newex == nullptr) { @@ -5956,6 +5968,114 @@ ExpEmit FxGlobalVariable::Emit(VMFunctionBuilder *build) } +//========================================================================== +// +// +// +//========================================================================== + +FxCVar::FxCVar(FBaseCVar *cvar, const FScriptPosition &pos) + : FxExpression(EFX_CVar, pos) +{ + CVar = cvar; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxCVar::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + switch (CVar->GetRealType()) + { + case CVAR_Bool: + case CVAR_DummyBool: + ValueType = TypeBool; + break; + + case CVAR_Int: + case CVAR_DummyInt: + ValueType = TypeSInt32; + break; + + case CVAR_Color: + ValueType = TypeColor; + break; + + case CVAR_Float: + ValueType = TypeFloat64; + break; + + case CVAR_String: + ValueType = TypeString; + break; + + default: + ScriptPosition.Message(MSG_ERROR, "Unknown CVar type for %s", CVar->GetName()); + delete this; + return nullptr; + } + return this; +} + +ExpEmit FxCVar::Emit(VMFunctionBuilder *build) +{ + ExpEmit dest(build, ValueType->GetRegType()); + ExpEmit addr(build, REGT_POINTER); + int nul = build->GetConstantInt(0); + switch (CVar->GetRealType()) + { + case CVAR_Int: + build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast(CVar)->Value, ATAG_GENERIC)); + build->Emit(OP_LW, dest.RegNum, addr.RegNum, nul); + break; + + case CVAR_Color: + build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast(CVar)->Value, ATAG_GENERIC)); + build->Emit(OP_LW, dest.RegNum, addr.RegNum, nul); + break; + + case CVAR_Float: + build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast(CVar)->Value, ATAG_GENERIC)); + build->Emit(OP_LSP, dest.RegNum, addr.RegNum, nul); + break; + + case CVAR_Bool: + build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast(CVar)->Value, ATAG_GENERIC)); + build->Emit(OP_LBU, dest.RegNum, addr.RegNum, nul); + break; + + case CVAR_String: + build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast(CVar)->Value, ATAG_GENERIC)); + build->Emit(OP_LS, dest.RegNum, addr.RegNum, nul); + break; + + case CVAR_DummyBool: + build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast(CVar)->ValueVar.Value, ATAG_GENERIC)); + build->Emit(OP_LBIT, dest.RegNum, addr.RegNum, static_cast(CVar)->BitNum); + break; + + case CVAR_DummyInt: + { + auto cv = static_cast(CVar); + build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&cv->ValueVar.Value, ATAG_GENERIC)); + build->Emit(OP_LW, dest.RegNum, addr.RegNum, nul); + build->Emit(OP_AND_RK, dest.RegNum, dest.RegNum, build->GetConstantInt(cv->BitVal)); + build->Emit(OP_SRL_RI, dest.RegNum, dest.RegNum, cv->BitNum); + break; + } + + default: + assert(false && "Unsupported CVar type"); + break; + } + return dest; +} + + //========================================================================== // // diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index 7f588a0eb..a3b645176 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -284,6 +284,7 @@ enum EFxType EFX_MultiAssign, EFX_StaticArray, EFX_StaticArrayVariable, + EFX_CVar, EFX_COUNT }; @@ -1236,6 +1237,15 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +class FxCVar : public FxExpression +{ + FBaseCVar *CVar; +public: + FxCVar(FBaseCVar*, const FScriptPosition&); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxClassMember From e93961da96b40c375e690060af92a28d15829d0b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 20 Nov 2016 23:00:05 +0100 Subject: [PATCH 054/185] - removed all constant versions of vector instructions. The vector code does not use compound constants so there's no need to have instructions for them. - fixed: The code generator had no good safeguards for exceeding the maximum amount of registers. All there was was a handful of pitiful asserts which in production code do nothing at all but generate broken output. Even worse, the VM was hardwired to at most 255 constants per type per function by storing the constant count in a byte! This has been extended to 65535, but since many instructions only have a byte available for the constant index, a workaround had to be added to do a two-instruction setup if larger indices are needed. --- src/scripting/codegeneration/codegen.cpp | 8 +- src/scripting/vm/vm.h | 8 +- src/scripting/vm/vmbuilder.cpp | 120 ++++++- src/scripting/vm/vmdisasm.cpp | 2 +- src/scripting/vm/vmexec.h | 71 +--- src/scripting/vm/vmframe.cpp | 8 +- src/scripting/vm/vmops.h | 440 +++++++++++------------ 7 files changed, 336 insertions(+), 321 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 9ca96de05..593737065 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -1993,7 +1993,7 @@ ExpEmit FxPreIncrDecr::Emit(VMFunctionBuilder *build) if (regtype == REGT_INT) { - build->Emit(OP_ADDI, value.RegNum, value.RegNum, (Token == TK_Incr) ? 1 : -1); + build->Emit(OP_ADDI, value.RegNum, value.RegNum, uint8_t((Token == TK_Incr) ? 1 : -1)); } else { @@ -2077,7 +2077,7 @@ ExpEmit FxPostIncrDecr::Emit(VMFunctionBuilder *build) ExpEmit assign(build, regtype); if (regtype == REGT_INT) { - build->Emit(OP_ADDI, assign.RegNum, out.RegNum, (Token == TK_Incr) ? 1 : -1); + build->Emit(OP_ADDI, assign.RegNum, out.RegNum, uint8_t((Token == TK_Incr) ? 1 : -1)); } else { @@ -2094,7 +2094,7 @@ ExpEmit FxPostIncrDecr::Emit(VMFunctionBuilder *build) if (regtype == REGT_INT) { build->Emit(OP_MOVE, out.RegNum, pointer.RegNum); - build->Emit(OP_ADDI, pointer.RegNum, pointer.RegNum, (Token == TK_Incr) ? 1 : -1); + build->Emit(OP_ADDI, pointer.RegNum, pointer.RegNum, uint8_t((Token == TK_Incr) ? 1 : -1)); } else { @@ -2108,7 +2108,7 @@ ExpEmit FxPostIncrDecr::Emit(VMFunctionBuilder *build) { if (regtype == REGT_INT) { - build->Emit(OP_ADDI, pointer.RegNum, pointer.RegNum, (Token == TK_Incr) ? 1 : -1); + build->Emit(OP_ADDI, pointer.RegNum, pointer.RegNum, uint8_t((Token == TK_Incr) ? 1 : -1)); } else { diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 670c5a982..ab1708e08 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -814,10 +814,10 @@ public: VM_UBYTE NumRegF; VM_UBYTE NumRegS; VM_UBYTE NumRegA; - VM_UBYTE NumKonstD; - VM_UBYTE NumKonstF; - VM_UBYTE NumKonstS; - VM_UBYTE NumKonstA; + VM_UHALF NumKonstD; + VM_UHALF NumKonstF; + VM_UHALF NumKonstS; + VM_UHALF 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 FString PrintableName; // so that the VM can print meaningful info if something in this function goes wrong. diff --git a/src/scripting/vm/vmbuilder.cpp b/src/scripting/vm/vmbuilder.cpp index 042753d32..3ccf67f95 100644 --- a/src/scripting/vm/vmbuilder.cpp +++ b/src/scripting/vm/vmbuilder.cpp @@ -36,6 +36,19 @@ #include "info.h" #include "m_argv.h" #include "thingdef.h" +#include "doomerrors.h" + +struct VMRemap +{ + BYTE altOp, kReg, kType; +}; + + +#define xx(op, name, mode, alt, kreg, ktype) {OP_##alt, kreg, ktype } +VMRemap opRemap[NUM_OPS] = { +#include "vmops.h" +}; +#undef xx //========================================================================== // @@ -523,10 +536,75 @@ size_t VMFunctionBuilder::GetAddress() size_t VMFunctionBuilder::Emit(int opcode, int opa, int opb, int opc) { + static BYTE opcodes[] = { OP_LK, OP_LKF, OP_LKS, OP_LKP }; + assert(opcode >= 0 && opcode < NUM_OPS); - assert(opa >= 0 && opa <= 255); - assert(opb >= 0 && opb <= 255); - assert(opc >= 0 && opc <= 255); + assert(opa >= 0); + assert(opb >= 0); + assert(opc >= 0); + + + // The following were just asserts, meaning this would silently create broken code if there was an overflow + // if this happened in a release build. Not good. + // These are critical errors that need to be reported to the user. + // In addition, the limit of 256 constants can easily be exceeded with arrays so this had to be extended to + // 65535 by adding some checks here that map byte-limited instructions to alternatives that can handle larger indices. + // (See vmops.h for the remapping info.) + + // Note: OP_CMPS also needs treatment, but I do not expect constant overflow to become an issue with strings, so for now there is no handling. + + if (opa > 255) + { + if (opRemap[opcode].kReg != 1 || opa > 32767) + { + I_Error("Register limit exceeded"); + } + int regtype = opRemap[opcode].kType; + ExpEmit emit(this, regtype); + Emit(opcodes[regtype], emit.RegNum, opa); + opcode = opRemap[opcode].altOp; + opa = emit.RegNum; + emit.Free(this); + } + if (opb > 255) + { + if (opRemap[opcode].kReg != 2 || opb > 32767) + { + I_Error("Register limit exceeded"); + } + int regtype = opRemap[opcode].kType; + ExpEmit emit(this, regtype); + Emit(opcodes[regtype], emit.RegNum, opb); + opcode = opRemap[opcode].altOp; + opb = emit.RegNum; + emit.Free(this); + } + if (opc > 255) + { + if (opcode == OP_PARAM && (opb & REGT_KONST) && opc <= 32767) + { + int regtype = opb & REGT_TYPE; + opb = regtype; + ExpEmit emit(this, regtype); + Emit(opcodes[regtype], emit.RegNum, opc); + opc = emit.RegNum; + emit.Free(this); + } + else + { + if (opRemap[opcode].kReg != 4 || opc > 32767) + { + I_Error("Register limit exceeded"); + } + int regtype = opRemap[opcode].kType; + ExpEmit emit(this, regtype); + Emit(opcodes[regtype], emit.RegNum, opc); + opcode = opRemap[opcode].altOp; + opc = emit.RegNum; + emit.Free(this); + } + } + if (opcode == OP_PARAM) { int chg; @@ -784,23 +862,31 @@ void FFunctionBuildList::Build() } // Emit code - item.Code->Emit(&buildit); - buildit.MakeFunction(sfunc); - sfunc->NumArgs = 0; - // NumArgs for the VMFunction must be the amount of stack elements, which can differ from the amount of logical function arguments if vectors are in the list. - // For the VM a vector is 2 or 3 args, depending on size. - for (auto s : item.Func->Variants[0].Proto->ArgumentTypes) + try { - sfunc->NumArgs += s->GetRegCount(); - } + item.Code->Emit(&buildit); + buildit.MakeFunction(sfunc); + sfunc->NumArgs = 0; + // NumArgs for the VMFunction must be the amount of stack elements, which can differ from the amount of logical function arguments if vectors are in the list. + // For the VM a vector is 2 or 3 args, depending on size. + for (auto s : item.Func->Variants[0].Proto->ArgumentTypes) + { + sfunc->NumArgs += s->GetRegCount(); + } - if (dump != nullptr) - { - DumpFunction(dump, sfunc, item.PrintableName.GetChars(), (int)item.PrintableName.Len()); - codesize += sfunc->CodeSize; + if (dump != nullptr) + { + DumpFunction(dump, sfunc, item.PrintableName.GetChars(), (int)item.PrintableName.Len()); + codesize += sfunc->CodeSize; + } + sfunc->PrintableName = item.PrintableName; + sfunc->Unsafe = ctx.Unsafe; + } + catch (CRecoverableError &err) + { + // catch errors from the code generator and pring something meaningful. + item.Code->ScriptPosition.Message(MSG_ERROR, "%s in %s", err.GetMessage(), item.PrintableName); } - sfunc->PrintableName = item.PrintableName; - sfunc->Unsafe = ctx.Unsafe; } delete item.Code; if (dump != nullptr) diff --git a/src/scripting/vm/vmdisasm.cpp b/src/scripting/vm/vmdisasm.cpp index c95699613..d8fc16433 100644 --- a/src/scripting/vm/vmdisasm.cpp +++ b/src/scripting/vm/vmdisasm.cpp @@ -147,7 +147,7 @@ const VMOpInfo OpInfo[NUM_OPS] = { -#define xx(op, name, mode) { #name, mode } +#define xx(op, name, mode, alt, kreg, ktype) { #name, mode } #include "vmops.h" }; diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 6202de3bb..477c5ac97 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -8,7 +8,7 @@ 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 +#define xx(op,sym,mode,alt,kreg,ktype) &&op #include "vmops.h" }; #endif @@ -425,12 +425,6 @@ begin: DoCast(reg, f, a, B, C); } NEXTOP; - OP(DYNCAST_R): - // UNDONE - NEXTOP; - OP(DYNCAST_K): - // UNDONE - NEXTOP; OP(TEST): ASSERTD(a); @@ -1315,42 +1309,23 @@ begin: OP(ADDV2_RR): ASSERTF(a+1); ASSERTF(B+1); ASSERTF(C+1); fcp = ®.f[C]; - Do_ADDV2: fbp = ®.f[B]; reg.f[a] = fbp[0] + fcp[0]; reg.f[a+1] = fbp[1] + fcp[1]; NEXTOP; - OP(ADDV2_RK): - fcp = &konstf[C]; - goto Do_ADDV2; OP(SUBV2_RR): ASSERTF(a+1); ASSERTF(B+1); ASSERTF(C+1); fbp = ®.f[B]; fcp = ®.f[C]; - Do_SUBV2: reg.f[a] = fbp[0] - fcp[0]; reg.f[a+1] = fbp[1] - fcp[1]; NEXTOP; - OP(SUBV2_RK): - ASSERTF(a+1); ASSERTF(B+1); ASSERTKF(C+1); - fbp = ®.f[B]; - fcp = &konstf[C]; - goto Do_SUBV2; - OP(SUBV2_KR): - ASSERTF(A+1); ASSERTKF(B+1); ASSERTF(C+1); - fbp = &konstf[B]; - fcp = ®.f[C]; - goto Do_SUBV2; OP(DOTV2_RR): ASSERTF(a); ASSERTF(B+1); ASSERTF(C+1); reg.f[a] = reg.f[B] * reg.f[C] + reg.f[B+1] * reg.f[C+1]; NEXTOP; - OP(DOTV2_RK): - ASSERTF(a); ASSERTF(B+1); ASSERTKF(C+1); - reg.f[a] = reg.f[B] * konstf[C] + reg.f[B+1] * konstf[C+1]; - NEXTOP; OP(MULVF2_RR): ASSERTF(a+1); ASSERTF(B+1); ASSERTF(C); @@ -1414,50 +1389,30 @@ begin: OP(ADDV3_RR): ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C+2); fcp = ®.f[C]; - Do_ADDV3: 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(ADDV3_RK): - fcp = &konstf[C]; - goto Do_ADDV3; OP(SUBV3_RR): ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C+2); fbp = ®.f[B]; fcp = ®.f[C]; - Do_SUBV3: 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(SUBV3_RK): - ASSERTF(a+2); ASSERTF(B+2); ASSERTKF(C+2); - fbp = ®.f[B]; - fcp = &konstf[C]; - goto Do_SUBV3; - OP(SUBV3_KR): - ASSERTF(A+2); ASSERTKF(B+2); ASSERTF(C+2); - fbp = &konstf[B]; - fcp = ®.f[C]; - goto Do_SUBV3; OP(DOTV3_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(DOTV3_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]; @@ -1466,46 +1421,24 @@ begin: 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(MULVF3_RR): ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C); fc = reg.f[C]; fbp = ®.f[B]; - Do_MULV3: reg.f[a] = fbp[0] * fc; reg.f[a+1] = fbp[1] * fc; reg.f[a+2] = fbp[2] * fc; NEXTOP; - OP(MULVF3_RK): - ASSERTF(a+2); ASSERTF(B+2); ASSERTKF(C); - fc = konstf[C]; - fbp = ®.f[B]; - goto Do_MULV3; - OP(DIVVF3_RR): + OP(DIVVF3_RR): ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C); fc = reg.f[C]; fbp = ®.f[B]; - Do_DIVV3: reg.f[a] = fbp[0] / fc; reg.f[a+1] = fbp[1] / fc; reg.f[a+2] = fbp[2] / fc; NEXTOP; - OP(DIVVF3_RK): - ASSERTF(a+2); ASSERTF(B+2); ASSERTKF(C); - fc = konstf[C]; - fbp = ®.f[B]; - goto Do_DIVV3; OP(LENV3): ASSERTF(a); ASSERTF(B+2); diff --git a/src/scripting/vm/vmframe.cpp b/src/scripting/vm/vmframe.cpp index b20c8ac89..f35c3718d 100644 --- a/src/scripting/vm/vmframe.cpp +++ b/src/scripting/vm/vmframe.cpp @@ -86,10 +86,10 @@ void VMScriptFunction::Alloc(int numops, int numkonstd, int numkonstf, int numko { 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); + assert(numkonstd >= 0 && numkonstd <= 65535); + assert(numkonstf >= 0 && numkonstf <= 65535); + assert(numkonsts >= 0 && numkonsts <= 65535); + assert(numkonsta >= 0 && numkonsta <= 65535); void *mem = M_Malloc(numops * sizeof(VMOP) + numkonstd * sizeof(int) + numkonstf * sizeof(double) + diff --git a/src/scripting/vm/vmops.h b/src/scripting/vm/vmops.h index 6f78e9e4e..cf2a75746 100644 --- a/src/scripting/vm/vmops.h +++ b/src/scripting/vm/vmops.h @@ -1,251 +1,247 @@ #ifndef xx -#define xx(op, name, mode) OP_##op +#define xx(op, name, mode, alt, kreg, ktype) OP_##op #endif -xx(NOP, nop, NOP), // no operation +// first row is the opcode +// second row is the disassembly name +// third row is the disassembly flags +// fourth row is the alternative opcode if all 256 constant registers are exhausted. +// fifth row is the constant register index in the opcode +// sixth row is the constant register type. +// OP_PARAM and OP_CMPS need special treatment because they encode this information in the instruction. + +xx(NOP, nop, NOP, NOP, 0, 0), // 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(LK_R, lk, RIRII8), // load integer constant indexed -xx(LKF_R, lk, RFRII8), // load float constant indexed -xx(LKS_R, lk, RSRII8), // load string constant indexed -xx(LKP_R, lk, RPRII8), // load pointer constant indexed -xx(LFP, lf, LFP), // load frame pointer +xx(LI, li, LI, NOP, 0, 0), // load immediate signed 16-bit constant +xx(LK, lk, LKI, NOP, 0, 0), // load integer constant +xx(LKF, lk, LKF, NOP, 0, 0), // load float constant +xx(LKS, lk, LKS, NOP, 0, 0), // load string constant +xx(LKP, lk, LKP, NOP, 0, 0), // load pointer constant +xx(LK_R, lk, RIRII8, NOP, 0, 0), // load integer constant indexed +xx(LKF_R, lk, RFRII8, NOP, 0, 0), // load float constant indexed +xx(LKS_R, lk, RSRII8, NOP, 0, 0), // load string constant indexed +xx(LKP_R, lk, RPRII8, NOP, 0, 0), // load pointer constant indexed +xx(LFP, lf, LFP, NOP, 0, 0), // 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(LV2, lv2, RVRPKI), // load vector2 -xx(LV2_R, lv2, RVRPRI), -xx(LV3, lv3, RVRPKI), // load vector3 -xx(LV3_R, lv3, RVRPRI), +xx(LB, lb, RIRPKI, LB_R, 4, REGT_INT), // load byte +xx(LB_R, lb, RIRPRI, NOP, 0, 0), +xx(LH, lh, RIRPKI, LH_R, 4, REGT_INT), // load halfword +xx(LH_R, lh, RIRPRI, NOP, 0, 0), +xx(LW, lw, RIRPKI, LW_R, 4, REGT_INT), // load word +xx(LW_R, lw, RIRPRI, NOP, 0, 0), +xx(LBU, lbu, RIRPKI, LBU_R, 4, REGT_INT), // load byte unsigned +xx(LBU_R, lbu, RIRPRI, NOP, 0, 0), +xx(LHU, lhu, RIRPKI, LHU_R, 4, REGT_INT), // load halfword unsigned +xx(LHU_R, lhu, RIRPRI, NOP, 0, 0), +xx(LSP, lsp, RFRPKI, LSP_R, 4, REGT_INT), // load single-precision fp +xx(LSP_R, lsp, RFRPRI, NOP, 0, 0), +xx(LDP, ldp, RFRPKI, LDP_R, 4, REGT_INT), // load double-precision fp +xx(LDP_R, ldp, RFRPRI, NOP, 0, 0), +xx(LS, ls, RSRPKI, LS_R, 4, REGT_INT), // load string +xx(LS_R, ls, RSRPRI, NOP, 0, 0), +xx(LO, lo, RPRPKI, LO_R, 4, REGT_INT), // load object +xx(LO_R, lo, RPRPRI, NOP, 0, 0), +xx(LP, lp, RPRPKI, LP_R, 4, REGT_INT), // load pointer +xx(LP_R, lp, RPRPRI, NOP, 0, 0), +xx(LV2, lv2, RVRPKI, LV2_R, 4, REGT_INT), // load vector2 +xx(LV2_R, lv2, RVRPRI, NOP, 0, 0), +xx(LV3, lv3, RVRPKI, LV3_R, 4, REGT_INT), // load vector3 +xx(LV3_R, lv3, RVRPRI, NOP, 0, 0), -xx(LBIT, lbit, RIRPI8), // rA = !!(*rB & C) -- *rB is a byte +xx(LBIT, lbit, RIRPI8, NOP, 0, 0), // 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(SV2, sv2, RPRVKI), // store vector2 -xx(SV2_R, sv2, RPRVRI), -xx(SV3, sv3, RPRVKI), // store vector3 -xx(SV3_R, sv3, RPRVRI), +xx(SB, sb, RPRIKI, SB_R, 4, REGT_INT), // store byte +xx(SB_R, sb, RPRIRI, NOP, 0, 0), +xx(SH, sh, RPRIKI, SH_R, 4, REGT_INT), // store halfword +xx(SH_R, sh, RPRIRI, NOP, 0, 0), +xx(SW, sw, RPRIKI, SW_R, 4, REGT_INT), // store word +xx(SW_R, sw, RPRIRI, NOP, 0, 0), +xx(SSP, ssp, RPRFKI, SSP_R, 4, REGT_INT), // store single-precision fp +xx(SSP_R, ssp, RPRFRI, NOP, 0, 0), +xx(SDP, sdp, RPRFKI, SDP_R, 4, REGT_INT), // store double-precision fp +xx(SDP_R, sdp, RPRFRI, NOP, 0, 0), +xx(SS, ss, RPRSKI, SS_R, 4, REGT_INT), // store string +xx(SS_R, ss, RPRSRI, NOP, 0, 0), +xx(SP, sp, RPRPKI, SP_R, 4, REGT_INT), // store pointer +xx(SP_R, sp, RPRPRI, NOP, 0, 0), +xx(SV2, sv2, RPRVKI, SV2_R, 4, REGT_INT), // store vector2 +xx(SV2_R, sv2, RPRVRI, NOP, 0, 0), +xx(SV3, sv3, RPRVKI, SV3_R, 4, REGT_INT), // store vector3 +xx(SV3_R, sv3, RPRVRI, NOP, 0, 0), -xx(SBIT, sbit, RPRII8), // *rA |= C if rB is true, *rA &= ~C otherwise +xx(SBIT, sbit, RPRII8, NOP, 0, 0), // *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(MOVEV2, mov2, RFRF), // fA = fB (2 elements) -xx(MOVEV3, mov3, RFRF), // fA = fB (3 elements) -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), +xx(MOVE, mov, RIRI, NOP, 0, 0), // dA = dB +xx(MOVEF, mov, RFRF, NOP, 0, 0), // fA = fB +xx(MOVES, mov, RSRS, NOP, 0, 0), // sA = sB +xx(MOVEA, mov, RPRP, NOP, 0, 0), // aA = aB +xx(MOVEV2, mov2, RFRF, NOP, 0, 0), // fA = fB (2 elements) +xx(MOVEV3, mov3, RFRF, NOP, 0, 0), // fA = fB (3 elements) +xx(CAST, cast, CAST, NOP, 0, 0), // xA = xB, conversion specified by C // Control flow. -xx(TEST, test, RII16), // if (dA != BC) then pc++ -xx(TESTN, testn, 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(VTBL, vtbl, RPRPI8), // dereferences a virtual method table. -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 == 1: Throw exception object pkB - // A >= 2: Throw VM exception of type BC -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 +xx(TEST, test, RII16, NOP, 0, 0), // if (dA != BC) then pc++ +xx(TESTN, testn, RII16, NOP, 0, 0), // if (dA != -BC) then pc++ +xx(JMP, jmp, I24, NOP, 0, 0), // pc += ABC -- The ABC fields contain a signed 24-bit offset. +xx(IJMP, ijmp, RII16, NOP, 0, 0), // pc += dA + BC -- BC is a signed offset. The target instruction must be a JMP. +xx(PARAM, param, __BCP, NOP, 0, 0), // push parameter encoded in BC for function call (B=regtype, C=regnum) +xx(PARAMI, parami, I24, NOP, 0, 0), // push immediate, signed integer for function call +xx(CALL, call, RPI8I8, NOP, 0, 0), // Call function pkA with parameter count B and expected result count C +xx(CALL_K, call, KPI8I8, CALL, 1, REGT_POINTER), +xx(VTBL, vtbl, RPRPI8, NOP, 0, 0), // dereferences a virtual method table. +xx(TAIL, tail, RPI8, NOP, 0, 0), // Call+Ret in a single instruction +xx(TAIL_K, tail, KPI8, TAIL, 1, REGT_POINTER), +xx(RESULT, result, __BCP, NOP, 0, 0), // Result should go in register encoded in BC (in caller, after CALL) +xx(RET, ret, I8BCP, NOP, 0, 0), // Copy value from register encoded in BC to return value A, possibly returning +xx(RETI, reti, I8I16, NOP, 0, 0), // Copy immediate from BC to return value A, possibly returning +xx(TRY, try, I24, NOP, 0, 0), // When an exception is thrown, start searching for a handler at pc + ABC +xx(UNTRY, untry, I8, NOP, 0, 0), // Pop A entries off the exception stack +xx(THROW, throw, THROW, NOP, 0, 0), // A == 0: Throw exception object pB + // A == 1: Throw exception object pkB + // A >= 2: Throw VM exception of type BC +xx(CATCH, catch, CATCH, NOP, 0, 0), // 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, NOP, 0, 0), // 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++ +xx(CONCAT, concat, RSRSRS, NOP, 0, 0), // sA = sB..sC +xx(LENS, lens, RIRS, NOP, 0, 0), // dA = sB.Length +xx(CMPS, cmps, I8RXRX, NOP, 0, 0), // 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 (signed) -xx(DIV_RK, div, RIRIKI), -xx(DIV_KR, div, RIKIRI), -xx(DIVU_RR, divu, RIRIRI), // dA = dkB / dkC (unsigned) -xx(DIVU_RK, divu, RIRIKI), -xx(DIVU_KR, divu, RIKIRI), -xx(MOD_RR, mod, RIRIRI), // dA = dkB % dkC (signed) -xx(MOD_RK, mod, RIRIKI), -xx(MOD_KR, mod, RIKIRI), -xx(MODU_RR, modu, RIRIRI), // dA = dkB % dkC (unsigned) -xx(MODU_RK, modu, RIRIKI), -xx(MODU_KR, modu, 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), +xx(SLL_RR, sll, RIRIRI, NOP, 0, 0), // dA = dkB << diC +xx(SLL_RI, sll, RIRII8, NOP, 0, 0), +xx(SLL_KR, sll, RIKIRI, SLL_RR, 2, REGT_INT), +xx(SRL_RR, srl, RIRIRI, NOP, 0, 0), // dA = dkB >> diC -- unsigned +xx(SRL_RI, srl, RIRII8, NOP, 0, 0), +xx(SRL_KR, srl, RIKIRI, SRL_RR, 2, REGT_INT), +xx(SRA_RR, sra, RIRIRI, NOP, 0, 0), // dA = dkB >> diC -- signed +xx(SRA_RI, sra, RIRII8, NOP, 0, 0), +xx(SRA_KR, sra, RIKIRI, SRA_RR, 2, REGT_INT), +xx(ADD_RR, add, RIRIRI, NOP, 0, 0), // dA = dB + dkC +xx(ADD_RK, add, RIRIKI, ADD_RR, 4, REGT_INT), +xx(ADDI, addi, RIRIIs, NOP, 0, 0), // dA = dB + C -- C is a signed 8-bit constant +xx(SUB_RR, sub, RIRIRI, NOP, 0, 0), // dA = dkB - dkC +xx(SUB_RK, sub, RIRIKI, SUB_RR, 4, REGT_INT), +xx(SUB_KR, sub, RIKIRI, SUB_RR, 2, REGT_INT), +xx(MUL_RR, mul, RIRIRI, NOP, 0, 0), // dA = dB * dkC +xx(MUL_RK, mul, RIRIKI, MUL_RR, 4, REGT_INT), +xx(DIV_RR, div, RIRIRI, NOP, 0, 0), // dA = dkB / dkC (signed) +xx(DIV_RK, div, RIRIKI, DIV_RR, 4, REGT_INT), +xx(DIV_KR, div, RIKIRI, DIV_RR, 2, REGT_INT), +xx(DIVU_RR, divu, RIRIRI, NOP, 0, 0), // dA = dkB / dkC (unsigned) +xx(DIVU_RK, divu, RIRIKI, DIVU_RR,4, REGT_INT), +xx(DIVU_KR, divu, RIKIRI, DIVU_RR,2, REGT_INT), +xx(MOD_RR, mod, RIRIRI, NOP, 0, 0), // dA = dkB % dkC (signed) +xx(MOD_RK, mod, RIRIKI, MOD_RR, 4, REGT_INT), +xx(MOD_KR, mod, RIKIRI, MOD_RR, 2, REGT_INT), +xx(MODU_RR, modu, RIRIRI, NOP, 0, 0), // dA = dkB % dkC (unsigned) +xx(MODU_RK, modu, RIRIKI, MODU_RR,4, REGT_INT), +xx(MODU_KR, modu, RIKIRI, MODU_RR,2, REGT_INT), +xx(AND_RR, and, RIRIRI, NOP, 0, 0), // dA = dB & dkC +xx(AND_RK, and, RIRIKI, AND_RR, 4, REGT_INT), +xx(OR_RR, or, RIRIRI, NOP, 0, 0), // dA = dB | dkC +xx(OR_RK, or, RIRIKI, OR_RR, 4, REGT_INT), +xx(XOR_RR, xor, RIRIRI, NOP, 0, 0), // dA = dB ^ dkC +xx(XOR_RK, xor, RIRIKI, XOR_RR, 4, REGT_INT), +xx(MIN_RR, min, RIRIRI, NOP, 0, 0), // dA = min(dB,dkC) +xx(MIN_RK, min, RIRIKI, MIN_RR, 4, REGT_INT), +xx(MAX_RR, max, RIRIRI, NOP, 0, 0), // dA = max(dB,dkC) +xx(MAX_RK, max, RIRIKI, MAX_RR, 4, REGT_INT), +xx(ABS, abs, RIRI, NOP, 0, 0), // dA = abs(dB) +xx(NEG, neg, RIRI, NOP, 0, 0), // dA = -dB +xx(NOT, not, RIRI, NOP, 0, 0), // dA = ~dB +xx(SEXT, sext, RIRII8, NOP, 0, 0), // dA = dB, sign extended by shifting left then right by C +xx(ZAP_R, zap, RIRIRI, NOP, 0, 0), // dA = dB, with bytes zeroed where bits in C/dC are one +xx(ZAP_I, zap, RIRII8, NOP, 0, 0), +xx(ZAPNOT_R, zapnot, RIRIRI, NOP, 0, 0), // dA = dB, with bytes zeroed where bits in C/dC are zero +xx(ZAPNOT_I, zapnot, RIRII8, NOP, 0, 0), +xx(EQ_R, beq, CIRR, NOP, 0, 0), // if ((dB == dkC) != A) then pc++ +xx(EQ_K, beq, CIRK, EQ_R, 4, REGT_INT), +xx(LT_RR, blt, CIRR, NOP, 0, 0), // if ((dkB < dkC) != A) then pc++ +xx(LT_RK, blt, CIRK, LT_RR, 4, REGT_INT), +xx(LT_KR, blt, CIKR, LT_RR, 2, REGT_INT), +xx(LE_RR, ble, CIRR, NOP, 0, 0), // if ((dkB <= dkC) != A) then pc++ +xx(LE_RK, ble, CIRK, LE_RR, 4, REGT_INT), +xx(LE_KR, ble, CIKR, LE_RR, 2, REGT_INT), +xx(LTU_RR, bltu, CIRR, NOP, 0, 0), // if ((dkB < dkC) != A) then pc++ -- unsigned +xx(LTU_RK, bltu, CIRK, LTU_RR, 4, REGT_INT), +xx(LTU_KR, bltu, CIKR, LTU_RR, 2, REGT_INT), +xx(LEU_RR, bleu, CIRR, NOP, 0, 0), // if ((dkB <= dkC) != A) then pc++ -- unsigned +xx(LEU_RK, bleu, CIRK, LEU_RR, 4, REGT_INT), +xx(LEU_KR, bleu, CIKR, LEU_RR, 2, REGT_INT), // 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(ATAN2, atan2, RFRFRF), // fA = atan2(fB,fC), result is in degrees -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), +xx(ADDF_RR, add, RFRFRF, NOP, 0, 0), // fA = fB + fkC +xx(ADDF_RK, add, RFRFKF, ADDF_RR,4, REGT_FLOAT), +xx(SUBF_RR, sub, RFRFRF, NOP, 0, 0), // fA = fkB - fkC +xx(SUBF_RK, sub, RFRFKF, SUBF_RR,4, REGT_FLOAT), +xx(SUBF_KR, sub, RFKFRF, SUBF_RR,2, REGT_FLOAT), +xx(MULF_RR, mul, RFRFRF, NOP, 0, 0), // fA = fB * fkC +xx(MULF_RK, mul, RFRFKF, MULF_RR,4, REGT_FLOAT), +xx(DIVF_RR, div, RFRFRF, NOP, 0, 0), // fA = fkB / fkC +xx(DIVF_RK, div, RFRFKF, DIVF_RR,4, REGT_FLOAT), +xx(DIVF_KR, div, RFKFRF, DIVF_RR,2, REGT_FLOAT), +xx(MODF_RR, mod, RFRFRF, NOP, 0, 0), // fA = fkB % fkC +xx(MODF_RK, mod, RFRFKF, MODF_RR,4, REGT_FLOAT), +xx(MODF_KR, mod, RFKFRF, MODF_RR,4, REGT_FLOAT), +xx(POWF_RR, pow, RFRFRF, NOP, 0, 0), // fA = fkB ** fkC +xx(POWF_RK, pow, RFRFKF, POWF_RR,4, REGT_FLOAT), +xx(POWF_KR, pow, RFKFRF, POWF_RR,2, REGT_FLOAT), +xx(MINF_RR, min, RFRFRF, NOP, 0, 0), // fA = min(fB),fkC) +xx(MINF_RK, min, RFRFKF, MINF_RR,4, REGT_FLOAT), +xx(MAXF_RR, max, RFRFRF, NOP, 0, 0), // fA = max(fB),fkC) +xx(MAXF_RK, max, RFRFKF, MAXF_RR,4, REGT_FLOAT), +xx(ATAN2, atan2, RFRFRF, NOP, 0, 0), // fA = atan2(fB,fC), result is in degrees +xx(FLOP, flop, RFRFI8, NOP, 0, 0), // fA = f(fB), where function is selected by C +xx(EQF_R, beq, CFRR, NOP, 0, 0), // if ((fB == fkC) != (A & 1)) then pc++ +xx(EQF_K, beq, CFRK, EQF_R, 4, REGT_FLOAT), +xx(LTF_RR, blt, CFRR, NOP, 0, 0), // if ((fkB < fkC) != (A & 1)) then pc++ +xx(LTF_RK, blt, CFRK, LTF_RR, 4, REGT_FLOAT), +xx(LTF_KR, blt, CFKR, LTF_RR, 2, REGT_FLOAT), +xx(LEF_RR, ble, CFRR, NOP, 0, 0), // if ((fkb <= fkC) != (A & 1)) then pc++ +xx(LEF_RK, ble, CFRK, LEF_RR, 4, REGT_FLOAT), +xx(LEF_KR, ble, CFKR, LEF_RR, 2, REGT_FLOAT), // Vector math. (2D) -xx(NEGV2, negv2, RVRV), // vA = -vB -xx(ADDV2_RR, addv2, RVRVRV), // vA = vB + vkC -xx(ADDV2_RK, addv2, RVRVKV), -xx(SUBV2_RR, subv2, RVRVRV), // vA = vkB - vkC -xx(SUBV2_RK, subv2, RVRVKV), -xx(SUBV2_KR, subv2, RVKVRV), -xx(DOTV2_RR, dotv2, RVRVRV), // va = vB dot vkC -xx(DOTV2_RK, dotv2, RVRVKV), -xx(MULVF2_RR, mulv2, RVRVRF), // vA = vkB * fkC -xx(MULVF2_RK, mulv2, RVRVKF), -xx(DIVVF2_RR, divv2, RVRVRF), // vA = vkB / fkC -xx(DIVVF2_RK, divv2, RVRVKF), -xx(LENV2, lenv2, RFRV), // fA = vB.Length -xx(EQV2_R, beqv2, CVRR), // if ((vB == vkC) != A) then pc++ (inexact if A & 32) -xx(EQV2_K, beqv2, CVRK), +xx(NEGV2, negv2, RVRV, NOP, 0, 0), // vA = -vB +xx(ADDV2_RR, addv2, RVRVRV, NOP, 0, 0), // vA = vB + vkC +xx(SUBV2_RR, subv2, RVRVRV, NOP, 0, 0), // vA = vkB - vkC +xx(DOTV2_RR, dotv2, RVRVRV, NOP, 0, 0), // va = vB dot vkC +xx(MULVF2_RR, mulv2, RVRVRF, NOP, 0, 0), // vA = vkB * fkC +xx(MULVF2_RK, mulv2, RVRVKF, MULVF2_RR,4, REGT_FLOAT), +xx(DIVVF2_RR, divv2, RVRVRF, NOP, 0, 0), // vA = vkB / fkC +xx(DIVVF2_RK, divv2, RVRVKF, DIVVF2_RR,4, REGT_FLOAT), +xx(LENV2, lenv2, RFRV, NOP, 0, 0), // fA = vB.Length +xx(EQV2_R, beqv2, CVRR, NOP, 0, 0), // if ((vB == vkC) != A) then pc++ (inexact if A & 32) +xx(EQV2_K, beqv2, CVRK, NOP, 0, 0), // this will never be used. // Vector math (3D) -xx(NEGV3, negv3, RVRV), // vA = -vB -xx(ADDV3_RR, addv3, RVRVRV), // vA = vB + vkC -xx(ADDV3_RK, addv3, RVRVKV), -xx(SUBV3_RR, subv3, RVRVRV), // vA = vkB - vkC -xx(SUBV3_RK, subv3, RVRVKV), -xx(SUBV3_KR, subv3, RVKVRV), -xx(DOTV3_RR, dotv3, RVRVRV), // va = vB dot vkC -xx(DOTV3_RK, dotv3, RVRVKV), -xx(CROSSV_RR, crossv, RVRVRV), // vA = vkB cross vkC -xx(CROSSV_RK, crossv, RVRVKV), -xx(CROSSV_KR, crossv, RVKVRV), -xx(MULVF3_RR, mulv3, RVRVRF), // vA = vkB * fkC -xx(MULVF3_RK, mulv3, RVRVKF), -xx(DIVVF3_RR, divv3, RVRVRF), // vA = vkB / fkC -xx(DIVVF3_RK, divv3, RVRVKF), -xx(LENV3, lenv3, RFRV), // fA = vB.Length -xx(EQV3_R, beqv3, CVRR), // if ((vB == vkC) != A) then pc++ (inexact if A & 33) -xx(EQV3_K, beqv3, CVRK), +xx(NEGV3, negv3, RVRV, NOP, 0, 0), // vA = -vB +xx(ADDV3_RR, addv3, RVRVRV, NOP, 0, 0), // vA = vB + vkC +xx(SUBV3_RR, subv3, RVRVRV, NOP, 0, 0), // vA = vkB - vkC +xx(DOTV3_RR, dotv3, RVRVRV, NOP, 0, 0), // va = vB dot vkC +xx(CROSSV_RR, crossv, RVRVRV, NOP, 0, 0), // vA = vkB cross vkC +xx(MULVF3_RR, mulv3, RVRVRF, NOP, 0, 0), // vA = vkB * fkC +xx(MULVF3_RK, mulv3, RVRVKF, MULVF3_RR,4, REGT_FLOAT), +xx(DIVVF3_RR, divv3, RVRVRF, NOP, 0, 0), // vA = vkB / fkC +xx(DIVVF3_RK, divv3, RVRVKF, DIVVF3_RR,4, REGT_FLOAT), +xx(LENV3, lenv3, RFRV, NOP, 0, 0), // fA = vB.Length +xx(EQV3_R, beqv3, CVRR, NOP, 0, 0), // if ((vB == vkC) != A) then pc++ (inexact if A & 33) +xx(EQV3_K, beqv3, CVRK, NOP, 0, 0), // this will never be used. // 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), +xx(ADDA_RR, add, RPRPRI, NOP, 0, 0), // pA = pB + dkC +xx(ADDA_RK, add, RPRPKI, ADDA_RR,4, REGT_POINTER), +xx(SUBA, sub, RIRPRP, NOP, 0, 0), // dA = pB - pC +xx(EQA_R, beq, CPRR, NOP, 0, 0), // if ((pB == pkC) != A) then pc++ +xx(EQA_K, beq, CPRK, EQA_R, 4, REGT_POINTER), #undef xx From 8f722a3633cda80c8749e465b97bf9c36ddc7ebe Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 20 Nov 2016 23:26:32 +0100 Subject: [PATCH 055/185] - fixed: FxCVar must free its address register. --- src/scripting/codegeneration/codegen.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 593737065..1b70a1e0c 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -6072,6 +6072,7 @@ ExpEmit FxCVar::Emit(VMFunctionBuilder *build) assert(false && "Unsupported CVar type"); break; } + addr.Free(build); return dest; } From 0cbd260f965139ac410304a4ea11383d5aa31bc8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 20 Nov 2016 23:39:37 +0100 Subject: [PATCH 056/185] - replaced all calls to GetCVar with direct CVar accesses. --- wadsrc/static/zscript/doom/bossbrain.txt | 4 ++-- wadsrc/static/zscript/doom/doommisc.txt | 2 +- wadsrc/static/zscript/doom/doomweapons.txt | 2 +- wadsrc/static/zscript/doom/fatso.txt | 2 +- wadsrc/static/zscript/doom/weaponbfg.txt | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/wadsrc/static/zscript/doom/bossbrain.txt b/wadsrc/static/zscript/doom/bossbrain.txt index 9a2ad759c..cde600701 100644 --- a/wadsrc/static/zscript/doom/bossbrain.txt +++ b/wadsrc/static/zscript/doom/bossbrain.txt @@ -186,11 +186,11 @@ extend class Actor void A_BrainDie() { // [RH] If noexit, then don't end the level. - if ((GetCVar("deathmatch") || GetCVar("alwaysapplydmflags")) && GetCVar("sv_noexit")) + if ((deathmatch || alwaysapplydmflags) && sv_noexit) return; // New dmflag: Kill all boss spawned monsters before ending the level. - if (GetCVar("sv_killbossmonst")) + if (sv_killbossmonst) { int count; // Repeat until we have no more boss-spawned monsters. ThinkerIterator it = ThinkerIterator.Create(); diff --git a/wadsrc/static/zscript/doom/doommisc.txt b/wadsrc/static/zscript/doom/doommisc.txt index a11c411f8..7d4c9dec4 100644 --- a/wadsrc/static/zscript/doom/doommisc.txt +++ b/wadsrc/static/zscript/doom/doommisc.txt @@ -38,7 +38,7 @@ extend class Actor { void A_BarrelDestroy() { - if (GetCVar("sv_barrelrespawn")) + if (sv_barrelrespawn) { Height = Default.Height; bInvisible = true; diff --git a/wadsrc/static/zscript/doom/doomweapons.txt b/wadsrc/static/zscript/doom/doomweapons.txt index 75f856218..731740ac6 100644 --- a/wadsrc/static/zscript/doom/doomweapons.txt +++ b/wadsrc/static/zscript/doom/doomweapons.txt @@ -41,7 +41,7 @@ extend class StateProvider } - int damage = GetCVar("deathmatch") ? 100 : 150; + int damage = deathmatch ? 100 : 150; A_RailAttack(damage, offset_xy, false); // note that this function handles ammo depletion itself for Dehacked compatibility purposes. } diff --git a/wadsrc/static/zscript/doom/fatso.txt b/wadsrc/static/zscript/doom/fatso.txt index d1a456d16..59e0d4c63 100644 --- a/wadsrc/static/zscript/doom/fatso.txt +++ b/wadsrc/static/zscript/doom/fatso.txt @@ -192,7 +192,7 @@ extend class Actor aimtarget.Height = Height; bool shootmode = ((flags & MSF_Classic) || // Flag explicitely set, or no flags and compat options - (flags == 0 && isDehState(CurState) && GetCVar("compat_mushroom"))); + (flags == 0 && isDehState(CurState) && compat_mushroom)); for (i = -numspawns; i <= numspawns; i += 8) { diff --git a/wadsrc/static/zscript/doom/weaponbfg.txt b/wadsrc/static/zscript/doom/weaponbfg.txt index 27f318daf..3543b9cdb 100644 --- a/wadsrc/static/zscript/doom/weaponbfg.txt +++ b/wadsrc/static/zscript/doom/weaponbfg.txt @@ -81,7 +81,7 @@ extend class StateProvider return; } - SpawnPlayerMissile("BFGBall", angle, 0, 0, 0, null, false, GetCVar("sv_nobfgaim")); + SpawnPlayerMissile("BFGBall", angle, 0, 0, 0, null, false, sv_nobfgaim); } From 7d8143224ee8f425a27c4378ae0ed21f2f60ef58 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 21 Nov 2016 00:33:55 +0100 Subject: [PATCH 057/185] - restored two accidentally deleted VM instructions. --- src/scripting/vm/vmexec.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 477c5ac97..e460ef29c 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -1426,19 +1426,31 @@ begin: ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C); fc = reg.f[C]; fbp = ®.f[B]; + Do_MULV3: reg.f[a] = fbp[0] * fc; reg.f[a+1] = fbp[1] * fc; reg.f[a+2] = fbp[2] * fc; NEXTOP; + OP(MULVF3_RK): + ASSERTF(a+2); ASSERTF(B+2); ASSERTKF(C); + fc = konstf[C]; + fbp = ®.f[B]; + goto Do_MULV3; - OP(DIVVF3_RR): + OP(DIVVF3_RR): ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C); fc = reg.f[C]; fbp = ®.f[B]; + Do_DIVV3: reg.f[a] = fbp[0] / fc; reg.f[a+1] = fbp[1] / fc; reg.f[a+2] = fbp[2] / fc; NEXTOP; + OP(DIVVF3_RK): + ASSERTF(a+2); ASSERTF(B+2); ASSERTKF(C); + fc = konstf[C]; + fbp = ®.f[B]; + goto Do_DIVV3; OP(LENV3): ASSERTF(a); ASSERTF(B+2); From e7f6bae83e23725b260f5ff7e562ac51356bf532 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 21 Nov 2016 01:32:01 +0100 Subject: [PATCH 058/185] - implemented named arguments. - fixed flag CVAR access. As it turned out, OP_LBIT is a bit messy to set up properly when accessing integers that may or may not be big endian, so it now uses a shift and bit masking to do its work. - used the SpawnPlayerMissile call in A_FireBFG to test named arguments. --- src/scripting/codegeneration/codegen.cpp | 72 +++++++++++++++++++++++- src/scripting/codegeneration/codegen.h | 45 +++++++++++++++ src/scripting/zscript/zcc_compile.cpp | 5 +- wadsrc/static/zscript/doom/weaponbfg.txt | 2 +- 4 files changed, 119 insertions(+), 5 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 1b70a1e0c..43d5f8174 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -6054,9 +6054,14 @@ ExpEmit FxCVar::Emit(VMFunctionBuilder *build) break; case CVAR_DummyBool: - build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast(CVar)->ValueVar.Value, ATAG_GENERIC)); - build->Emit(OP_LBIT, dest.RegNum, addr.RegNum, static_cast(CVar)->BitNum); + { + auto cv = static_cast(CVar); + build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&cv->ValueVar.Value, ATAG_GENERIC)); + build->Emit(OP_LW, dest.RegNum, addr.RegNum, nul); + build->Emit(OP_SRL_RI, dest.RegNum, dest.RegNum, cv->BitNum); + build->Emit(OP_AND_RK, dest.RegNum, dest.RegNum, build->GetConstantInt(1)); break; + } case CVAR_DummyInt: { @@ -7408,7 +7413,9 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) bool failed = false; auto proto = Function->Variants[0].Proto; auto &argtypes = proto->ArgumentTypes; + auto &argnames = Function->Variants[0].ArgNames; auto &argflags = Function->Variants[0].ArgFlags; + auto &defaults = Function->Variants[0].Implementation->DefaultArgs; int implicit = Function->GetImplicitArgs(); @@ -7446,6 +7453,67 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) } assert(type != nullptr); + if (ArgList[i]->ExprType == EFX_NamedNode) + { + if (!(flag & VARF_Optional)) + { + ScriptPosition.Message(MSG_ERROR, "Cannot use a named argument here - not all required arguments have been passed."); + delete this; + return nullptr; + } + if (foundvarargs) + { + ScriptPosition.Message(MSG_ERROR, "Cannot use a named argument in the varargs part of the parameter list."); + delete this; + return nullptr; + } + unsigned j; + bool done = false; + FName name = static_cast(ArgList[i])->name; + for (j = 0; j < argnames.Size() - implicit; j++) + { + if (argnames[j + implicit] == name) + { + if (j < i) + { + ScriptPosition.Message(MSG_ERROR, "Named argument %s comes before current position in argument list.", name.GetChars()); + delete this; + return nullptr; + } + // copy the original argument into the list + auto old = static_cast(ArgList[i]); + ArgList[i] = old->value; + old->value = nullptr; + delete old; + // now fill the gap with constants created from the default list so that we got a full list of arguments. + int insert = j - i; + for (int k = 0; k < insert; k++) + { + auto ntype = argtypes[i + k + implicit]; + // If this is a reference argument, the pointer type must be undone because the code below expects the pointed type as value type. + if (argflags[i + k + implicit] & VARF_Ref) + { + assert(ntype->IsKindOf(RUNTIME_CLASS(PPointer))); + ntype = TypeNullPtr; // the default of a reference type can only be a null pointer + } + auto x = new FxConstant(ntype, defaults[i + k + implicit], ScriptPosition); + ArgList.Insert(i + k, x); + } + done = true; + break; + } + } + if (!done) + { + ScriptPosition.Message(MSG_ERROR, "Named argument %s not found.", name.GetChars()); + delete this; + return nullptr; + } + // re-get the proper info for the inserted node. + type = argtypes[i + implicit]; + flag = argflags[i + implicit]; + } + FxExpression *x; if (!(flag & VARF_Ref)) { diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index a3b645176..f004e469a 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -285,6 +285,7 @@ enum EFxType EFX_StaticArray, EFX_StaticArrayVariable, EFX_CVar, + EFX_NamedNode, EFX_COUNT }; @@ -472,6 +473,31 @@ public: ValueType = value.Type = TypeNullPtr; isresolved = true; } + + FxConstant(PType *type, VMValue &vmval, const FScriptPosition &pos) : FxExpression(EFX_Constant, pos) + { + ValueType = value.Type = type; + isresolved = true; + switch (vmval.Type) + { + default: + case REGT_INT: + value.Int = vmval.i; + break; + + case REGT_FLOAT: + value.Float = vmval.f; + break; + + case REGT_STRING: + value = ExpVal(vmval.s()); + break; + + case REGT_POINTER: + value.pointer = vmval.a; + break; + } + } static FxExpression *MakeConstant(PSymbol *sym, const FScriptPosition &pos); @@ -1912,5 +1938,24 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +class FxNamedNode : public FxExpression +{ +public: + FName name; + FxExpression *value; + FxNamedNode(FName n, FxExpression *x, const FScriptPosition &pos) + : FxExpression(EFX_NamedNode, pos), name(n), value(x) + { + } + + FxExpression *Resolve(FCompileContext&) + { + // This should never reach the backend in a supported context, + // it's just needed to extend argument lists with the skipped parameters and needs to be resolved by the parent node. + ScriptPosition.Message(MSG_ERROR, "Named arguments not supported here"); + delete this; + return nullptr; + } +}; #endif diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 291387617..f2d847325 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2845,8 +2845,9 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) case AST_FuncParm: { auto fparm = static_cast(ast); - // ignore the label for now, that's stuff for far later, when a bit more here is working. - return ConvertNode(fparm->Value); + auto node = ConvertNode(fparm->Value); + if (fparm->Label != NAME_None) node = new FxNamedNode(fparm->Label, node, *ast); + return node; } case AST_ExprID: diff --git a/wadsrc/static/zscript/doom/weaponbfg.txt b/wadsrc/static/zscript/doom/weaponbfg.txt index 3543b9cdb..1b96bfc29 100644 --- a/wadsrc/static/zscript/doom/weaponbfg.txt +++ b/wadsrc/static/zscript/doom/weaponbfg.txt @@ -81,7 +81,7 @@ extend class StateProvider return; } - SpawnPlayerMissile("BFGBall", angle, 0, 0, 0, null, false, sv_nobfgaim); + SpawnPlayerMissile("BFGBall", angle, nofreeaim:sv_nobfgaim); } From 3270b200454613871613b9ac977992521cc9201a Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Sun, 20 Nov 2016 21:33:23 -0600 Subject: [PATCH 059/185] Remove non-existant source file --- src/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b7f2eb3b2..87c875d16 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -866,7 +866,6 @@ set( NOT_COMPILED_SOURCE_FILES ${OTHER_SYSTEM_SOURCES} sc_man_scanner.h sc_man_scanner.re - g_doom/a_doomweaps.cpp g_doom/a_painelemental.cpp g_doom/a_scriptedmarine.cpp g_heretic/a_chicken.cpp From 188c0ee932302706b71b7f1b6b248349448f631e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 21 Nov 2016 10:28:06 +0100 Subject: [PATCH 060/185] - removed the REGT_NIL check from the PARAM_EXISTS macro, because with the implemented handling of named arguments it isn't possible that REGT_NIL can end up in the parameters without a programming error.. --- src/scripting/vm/vm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index ab1708e08..b8885e0a1 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -956,7 +956,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction #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))); -#define PARAM_EXISTS(p) ((p) < numparam && param[p].Type != REGT_NIL) +#define PARAM_EXISTS(p) ((p) < numparam) #define ASSERTINT(p) assert((p).Type == REGT_INT) #define ASSERTFLOAT(p) assert((p).Type == REGT_FLOAT) #define ASSERTSTRING(p) assert((p).Type == REGT_STRING) From 393bcf9e91c3fe4a67e7d365be9f43923051446c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 21 Nov 2016 10:50:09 +0100 Subject: [PATCH 061/185] - extended ExpEmit::RegNum to 16 bits so that it can hold larger values for constant registers. --- src/scripting/vm/vmbuilder.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/scripting/vm/vmbuilder.h b/src/scripting/vm/vmbuilder.h index 5991d0711..d53393518 100644 --- a/src/scripting/vm/vmbuilder.h +++ b/src/scripting/vm/vmbuilder.h @@ -13,7 +13,10 @@ struct ExpEmit void Free(VMFunctionBuilder *build); void Reuse(VMFunctionBuilder *build); - BYTE RegNum, RegType, RegCount, Konst:1, Fixed : 1, Final : 1, Target : 1; + uint16_t RegNum; + uint8_t RegType, RegCount; + // We are at 8 bytes for this struct, no matter what, so it's rather pointless to squeeze these flags into bitfields. + bool Konst, Fixed, Final, Target; }; class VMFunctionBuilder From de2eb1872714badda166445df005c7b4d8f34931 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 21 Nov 2016 12:38:39 +0100 Subject: [PATCH 062/185] - added per-channel access for color variables. However, since they are locally stored in registers, it required a minor bit of fudging for this case. - make sure that a PFunction's implementation is always initialized before starting the code generator. --- src/dobjtype.cpp | 14 ++++++++++++++ src/dobjtype.h | 1 + src/namedef.h | 6 ++++++ src/scripting/codegeneration/codegen.cpp | 24 ++++++++++++++++++++++++ src/scripting/vm/vmbuilder.cpp | 2 ++ src/scripting/zscript/zcc_compile.cpp | 2 +- 6 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 965a0d8fd..e84504015 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -85,6 +85,7 @@ PStatePointer *TypeState; PStateLabel *TypeStateLabel; PStruct *TypeVector2; PStruct *TypeVector3; +PStruct *TypeColorStruct; PPointer *TypeNullPtr; // PRIVATE DATA DEFINITIONS ------------------------------------------------ @@ -578,6 +579,19 @@ void PType::StaticInit() TypeTable.AddType(TypeStateLabel = new PStateLabel); TypeTable.AddType(TypeNullPtr = new PPointer); + TypeColorStruct = new PStruct("@ColorStruct", nullptr); //This name is intentionally obfuscated so that it cannot be used explicitly. The point of this type is to gain access to the single channels of a color value. +#ifdef __BIG_ENDIAN__ + TypeColorStruct->AddField(NAME_a, TypeUInt8); + TypeColorStruct->AddField(NAME_r, TypeUInt8); + TypeColorStruct->AddField(NAME_g, TypeUInt8); + TypeColorStruct->AddField(NAME_b, TypeUInt8); +#else + TypeColorStruct->AddField(NAME_b, TypeUInt8); + TypeColorStruct->AddField(NAME_g, TypeUInt8); + TypeColorStruct->AddField(NAME_r, TypeUInt8); + TypeColorStruct->AddField(NAME_a, TypeUInt8); +#endif + TypeVector2 = new PStruct(NAME_Vector2, nullptr); TypeVector2->AddField(NAME_X, TypeFloat64); TypeVector2->AddField(NAME_Y, TypeFloat64); diff --git a/src/dobjtype.h b/src/dobjtype.h index aeb042ebb..b8fc1cbf6 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -919,6 +919,7 @@ extern PSound *TypeSound; extern PColor *TypeColor; extern PStruct *TypeVector2; extern PStruct *TypeVector3; +extern PStruct *TypeColorStruct; extern PStatePointer *TypeState; extern PStateLabel *TypeStateLabel; extern PPointer *TypeNullPtr; diff --git a/src/namedef.h b/src/namedef.h index d4206e2bb..0418e0f87 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -750,3 +750,9 @@ xx(A_FirePlasma) xx(A_FireBFG) xx(A_FireOldBFG) xx(A_FireRailgun) + +// color channels +xx(a) +xx(r) +xx(g) +xx(b) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 43d5f8174..c040403d8 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -5652,6 +5652,10 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) SAFE_RESOLVE(Object, ctx); + // allow accessing the color chanels by mapping the type to a matching struct which defines them. + if (Object->ValueType == TypeColor) + Object->ValueType = TypeColorStruct; + if (Object->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) { auto ptype = static_cast(Object->ValueType)->PointedType; @@ -6305,6 +6309,26 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) delete this; return locvar; } + else if (classx->ExprType == EFX_LocalVariable && classx->ValueType == TypeColorStruct) + { + // This needs special treatment because it'd require accessing the register via address. + // Fortunately this is the only place where this kind of access is ever needed so an explicit handling is acceptable. + int bits; + switch (membervar->SymbolName.GetIndex()) + { + case NAME_a: bits = 24; break; + case NAME_r: bits = 16; break; + case NAME_g: bits = 8; break; + case NAME_b: default: bits = 0; break; + } + classx->ValueType = TypeColor; // need to set it back. + FxExpression *x = classx; + if (bits > 0) x = new FxShift(TK_URShift, x, new FxConstant(bits, ScriptPosition)); + x = new FxBitOp('&', x, new FxConstant(255, ScriptPosition)); + classx = nullptr; + delete this; + return x->Resolve(ctx); + } else { if (!(classx->RequestAddress(ctx, &AddressWritable))) diff --git a/src/scripting/vm/vmbuilder.cpp b/src/scripting/vm/vmbuilder.cpp index 3ccf67f95..04339f6eb 100644 --- a/src/scripting/vm/vmbuilder.cpp +++ b/src/scripting/vm/vmbuilder.cpp @@ -785,6 +785,8 @@ VMFunction *FFunctionBuildList::AddFunction(PFunction *functype, FxExpression *c it.StateIndex = stateindex; it.StateCount = statecount; it.Lump = lumpnum; + assert(it.Func->Variants.Size() == 1); + it.Func->Variants[0].Implementation = it.Function; // set prototype for named functions. if (it.Func->SymbolName != NAME_None) diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index f2d847325..3d8cc18b5 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2272,7 +2272,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool auto code = ConvertAST(c->Type(), f->Body); if (code != nullptr) { - sym->Variants[0].Implementation = FunctionBuildList.AddFunction(sym, code, FStringf("%s.%s", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()), false, -1, 0, Lump); + FunctionBuildList.AddFunction(sym, code, FStringf("%s.%s", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()), false, -1, 0, Lump); } } } From 7c122d03e9d17eeb79ec02fb4e2e2d8a703c58d3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 21 Nov 2016 13:04:27 +0100 Subject: [PATCH 063/185] - renamed all instances of 'float' parameters to 'double', so that the Float32 type can be made usable for structs. --- wadsrc/static/zscript/actor.txt | 158 +++++++++--------- wadsrc/static/zscript/actor_checks.txt | 38 ++--- wadsrc/static/zscript/doom/archvile.txt | 4 +- wadsrc/static/zscript/doom/fatso.txt | 2 +- wadsrc/static/zscript/doom/lostsoul.txt | 2 +- wadsrc/static/zscript/doom/painelemental.txt | 4 +- wadsrc/static/zscript/doom/weaponchainsaw.txt | 2 +- wadsrc/static/zscript/shared/inventory.txt | 10 +- .../static/zscript/strife/strifeweapons.txt | 2 +- 9 files changed, 111 insertions(+), 111 deletions(-) diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 5c824d7bb..99ca89c8e 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -65,12 +65,12 @@ class Actor : Thinker native native static readonly GetDefaultByType(class cls); - native static float deltaangle(float ang1, float ang2); - native static float absangle(float ang1, float ang2); - native static float GetDefaultSpeed(class type); + native static double deltaangle(double ang1, double ang2); + native static double absangle(double ang1, double ang2); + native static double GetDefaultSpeed(class type); native void RemoveFromHash(); native string GetTag(string defstr = ""); - native float GetBobOffset(float frac = 0); + native double GetBobOffset(double frac = 0); native void ClearCounters(); native bool GiveBody (int num, int max=0); @@ -88,7 +88,7 @@ class Actor : Thinker native native static Actor Spawn(class type, vector3 pos = (0,0,0), int replace = NO_REPLACE); native Actor SpawnMissile(Actor dest, class type, Actor owner = null); native Actor SpawnMissileZ (double z, Actor dest, class type); - native Actor SpawnMissileAngleZSpeed (double z, class type, float angle, double vz, double speed, Actor owner = null, bool checkspawn = true); + native Actor SpawnMissileAngleZSpeed (double z, class type, double angle, double vz, double speed, Actor owner = null, bool checkspawn = true); native Actor, Actor SpawnPlayerMissile(class type, double angle = 0, double x = 0, double y = 0, double z = 0, out FTranslatedLineTarget pLineTarget = null, bool nofreeaim = false, bool noautoaim = false, int aimflags = 0); native void A_Light(int extralight); @@ -98,7 +98,7 @@ class Actor : Thinker native void A_LightInverse() { A_Light(0x80000000); } native Actor OldSpawnMissile(Actor dest, class type, Actor owner = null); - native Actor SpawnPuff(class pufftype, vector3 pos, float hitdir, float particledir, int updown, int flags = 0, Actor vict = null); + native Actor SpawnPuff(class pufftype, vector3 pos, double hitdir, double particledir, int updown, int flags = 0, Actor vict = null); native void TraceBleed(int damage, Actor missile); native bool CheckMeleeRange(); @@ -119,13 +119,13 @@ class Actor : Thinker native native void UnlinkFromWorld(); native bool CanSeek(Actor target); native double AngleTo(Actor target, bool absolute = false); - native void AddZ(float zadd, bool moving = true); - native void SetZ(float z); - native vector3 Vec3Offset(float x, float y, float z, bool absolute = false); - native vector3 Vec3Angle(float length, float angle, float z = 0, bool absolute = false); - native vector3 Vec2OffsetZ(float x, float y, float atz, bool absolute = false); - native void VelFromAngle(float speed = 0, float angle = 0); - native void Thrust(float speed = 0, float angle = 0); + native void AddZ(double zadd, bool moving = true); + native void SetZ(double z); + native vector3 Vec3Offset(double x, double y, double z, bool absolute = false); + native vector3 Vec3Angle(double length, double angle, double z = 0, bool absolute = false); + native vector3 Vec2OffsetZ(double x, double y, double atz, bool absolute = false); + native void VelFromAngle(double speed = 0, double angle = 0); + native void Thrust(double speed = 0, double angle = 0); native bool isFriend(Actor other); native void AdjustFloorClip(); native DropItem GetDropItems(); @@ -140,21 +140,21 @@ class Actor : Thinker native native bool CheckClass(class checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false); native Inventory FindInventory(class itemtype, bool subclass = false); native int CountInv(class itemtype, int ptr_select = AAPTR_DEFAULT); - native float GetDistance(bool checkz, int ptr = AAPTR_TARGET); - native float GetAngle(int flags, int ptr = AAPTR_DEFAULT); - native float GetZAt(float px = 0, float py = 0, float angle = 0, int flags = 0, int pick_pointer = AAPTR_DEFAULT); + native double GetDistance(bool checkz, int ptr = AAPTR_TARGET); + native double GetAngle(int flags, int ptr = AAPTR_DEFAULT); + native double GetZAt(double px = 0, double py = 0, double angle = 0, int flags = 0, int pick_pointer = AAPTR_DEFAULT); native int GetSpawnHealth(); native int GetGibHealth(); - native float GetCrouchFactor(int ptr = AAPTR_PLAYER1); - native float GetCVar(string cvar); + native double GetCrouchFactor(int ptr = AAPTR_PLAYER1); + native double GetCVar(string cvar); native int GetPlayerInput(int inputnum, int ptr = AAPTR_DEFAULT); - native int CountProximity(class classname, float distance, int flags = 0, int ptr = AAPTR_DEFAULT); - native float GetSpriteAngle(int ptr = AAPTR_DEFAULT); - native float GetSpriteRotation(int ptr = AAPTR_DEFAULT); + native int CountProximity(class classname, double distance, int flags = 0, int ptr = AAPTR_DEFAULT); + native double GetSpriteAngle(int ptr = AAPTR_DEFAULT); + native double GetSpriteRotation(int ptr = AAPTR_DEFAULT); native int GetMissileDamage(int mask, int add, int ptr = AAPTR_DEFAULT); action native int OverlayID(); - action native float OverlayX(int layer = 0); - action native float OverlayY(int layer = 0); + action native double OverlayX(int layer = 0); + action native double OverlayY(int layer = 0); // DECORATE setters - it probably makes more sense to set these values directly now... void A_SetMass(int newmass) { mass = newmass; } @@ -169,13 +169,13 @@ class Actor : Thinker native void A_NoGravity() { bNoGravity = true; } void A_Gravity() { bNoGravity = false; Gravity = 1; } void A_LowGravity() { bNoGravity = false; Gravity = 0.125; } - void A_SetGravity(float newgravity) { gravity = clamp(newgravity, 0., 10.); } + void A_SetGravity(double newgravity) { gravity = clamp(newgravity, 0., 10.); } void A_SetFloorClip() { bFloorClip = true; AdjustFloorClip(); } void A_UnSetFloorClip() { bFloorClip = false; FloorClip = 0; } void A_HideThing() { bInvisible = true; } void A_UnHideThing() { bInvisible = false; } void A_SetArg(int arg, int val) { if (arg >= 0 && arg < 5) args[arg] = val; } - void A_Turn(float turn = 0) { angle += turn; } + void A_Turn(double turn = 0) { angle += turn; } void A_SetDamageType(name newdamagetype) { damagetype = newdamagetype; } void A_SetSolid() { bSolid = true; } void A_UnsetSolid() { bSolid = false; } @@ -197,7 +197,7 @@ class Actor : Thinker native // //--------------------------------------------------------------------------- - Actor SpawnMissileAngle (class type, float angle, double vz) + Actor SpawnMissileAngle (class type, double angle, double vz) { return SpawnMissileAngleZSpeed (pos.z + 32 + GetBobOffset(), type, angle, vz, GetDefaultSpeed (type)); } @@ -208,7 +208,7 @@ class Actor : Thinker native } - void A_SetScale(float scalex, float scaley = 0, int ptr = AAPTR_DEFAULT, bool usezero = false) + void A_SetScale(double scalex, double scaley = 0, int ptr = AAPTR_DEFAULT, bool usezero = false) { Actor aptr = GetPointer(ptr); if (aptr) @@ -217,12 +217,12 @@ class Actor : Thinker native aptr.Scale.Y = scaley != 0 || usezero? scaley : scalex; // use scalex here, too, if only one parameter. } } - void A_SetSpeed(float speed, int ptr = AAPTR_DEFAULT) + void A_SetSpeed(double speed, int ptr = AAPTR_DEFAULT) { Actor aptr = GetPointer(ptr); if (aptr) aptr.Speed = speed; } - void A_SetFloatSpeed(float speed, int ptr = AAPTR_DEFAULT) + void A_SetFloatSpeed(double speed, int ptr = AAPTR_DEFAULT) { Actor aptr = GetPointer(ptr); if (aptr) aptr.FloatSpeed = speed; @@ -232,14 +232,14 @@ class Actor : Thinker native Actor aptr = GetPointer(ptr); if (aptr) aptr.PainThreshold = threshold; } - bool A_SetSpriteAngle(float angle = 0, int ptr = AAPTR_DEFAULT) + bool A_SetSpriteAngle(double angle = 0, int ptr = AAPTR_DEFAULT) { Actor aptr = GetPointer(ptr); if (!aptr) return false; aptr.SpriteAngle = angle; return true; } - bool A_SetSpriteRotation(float angle = 0, int ptr = AAPTR_DEFAULT) + bool A_SetSpriteRotation(double angle = 0, int ptr = AAPTR_DEFAULT) { Actor aptr = GetPointer(ptr); if (!aptr) return false; @@ -247,7 +247,7 @@ class Actor : Thinker native return true; } - deprecated void A_FaceConsolePlayer(float MaxTurnAngle = 0) {} + deprecated void A_FaceConsolePlayer(double MaxTurnAngle = 0) {} void A_SetSpecial(int spec, int arg0 = 0, int arg1 = 0, int arg2 = 0, int arg3 = 0, int arg4 = 0) { @@ -333,17 +333,17 @@ class Actor : Thinker native } - native void A_Face(Actor faceto, float max_turn = 0, float max_pitch = 270, float ang_offset = 0, float pitch_offset = 0, int flags = 0, float z_ofs = 0); + native void A_Face(Actor faceto, double max_turn = 0, double max_pitch = 270, double ang_offset = 0, double pitch_offset = 0, int flags = 0, double z_ofs = 0); - void A_FaceTarget(float max_turn = 0, float max_pitch = 270, float ang_offset = 0, float pitch_offset = 0, int flags = 0, float z_ofs = 0) + void A_FaceTarget(double max_turn = 0, double max_pitch = 270, double ang_offset = 0, double pitch_offset = 0, int flags = 0, double z_ofs = 0) { A_Face(target, max_turn, max_pitch, ang_offset, pitch_offset, flags, z_ofs); } - void A_FaceTracer(float max_turn = 0, float max_pitch = 270, float ang_offset = 0, float pitch_offset = 0, int flags = 0, float z_ofs = 0) + void A_FaceTracer(double max_turn = 0, double max_pitch = 270, double ang_offset = 0, double pitch_offset = 0, int flags = 0, double z_ofs = 0) { A_Face(tracer, max_turn, max_pitch, ang_offset, pitch_offset, flags, z_ofs); } - void A_FaceMaster(float max_turn = 0, float max_pitch = 270, float ang_offset = 0, float pitch_offset = 0, int flags = 0, float z_ofs = 0) + void A_FaceMaster(double max_turn = 0, double max_pitch = 270, double ang_offset = 0, double pitch_offset = 0, int flags = 0, double z_ofs = 0) { A_Face(master, max_turn, max_pitch, ang_offset, pitch_offset, flags, z_ofs); } @@ -392,7 +392,7 @@ class Actor : Thinker native native void A_TurretLook(); native void A_KlaxonBlare(); native void A_Countdown(); - native void A_AlertMonsters(float maxdist = 0, int flags = 0); + native void A_AlertMonsters(double maxdist = 0, int flags = 0); native void A_ClearSoundTarget(); native void A_CheckTerrain(); @@ -400,8 +400,8 @@ class Actor : Thinker native deprecated native void A_MeleeAttack(); deprecated native void A_ComboAttack(); deprecated native void A_BulletAttack(); - native void A_WolfAttack(int flags = 0, sound whattoplay = "weapons/pistol", float snipe = 1.0, int maxdamage = 64, int blocksize = 128, int pointblank = 2, int longrange = 4, float runspeed = 160.0, class pufftype = "BulletPuff"); - native void A_PlaySound(sound whattoplay = "weapons/pistol", int slot = CHAN_BODY, float volume = 1.0, bool looping = false, float attenuation = ATTN_NORM, bool local = false); + native void A_WolfAttack(int flags = 0, sound whattoplay = "weapons/pistol", double snipe = 1.0, int maxdamage = 64, int blocksize = 128, int pointblank = 2, int longrange = 4, double runspeed = 160.0, class pufftype = "BulletPuff"); + native void A_PlaySound(sound whattoplay = "weapons/pistol", int slot = CHAN_BODY, double volume = 1.0, bool looping = false, double attenuation = ATTN_NORM, bool local = false); deprecated void A_PlayWeaponSound(sound whattoplay) { A_PlaySound(whattoplay, CHAN_WEAPON); } native void A_FLoopActiveSound(); native void A_LoopActiveSound(); @@ -410,55 +410,55 @@ class Actor : Thinker native deprecated native void A_StopSoundEx(name slot); native void A_SeekerMissile(int threshold, int turnmax, int flags = 0, int chance = 50, int distance = 10); native action state A_Jump(int chance, statelabel label, ...); - native void A_CustomMissile(class missiletype, float spawnheight = 32, float spawnofs_xy = 0, float angle = 0, int flags = 0, float pitch = 0, int ptr = AAPTR_TARGET); - native void 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, class missile = null, float Spawnheight = 32, float Spawnofs_xy = 0); - native void A_CustomRailgun(int damage, int spawnofs_xy = 0, color color1 = 0, color color2 = 0, int flags = 0, int aim = 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 = null, float spawnofs_z = 0, int spiraloffset = 270, int limit = 0); + native void A_CustomMissile(class missiletype, double spawnheight = 32, double spawnofs_xy = 0, double angle = 0, int flags = 0, double pitch = 0, int ptr = AAPTR_TARGET); + native void A_CustomBulletAttack(double spread_xy, double spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", double range = 0, int flags = 0, int ptr = AAPTR_TARGET, class missile = null, double Spawnheight = 32, double Spawnofs_xy = 0); + native void A_CustomRailgun(int damage, int spawnofs_xy = 0, color color1 = 0, color color2 = 0, int flags = 0, int aim = 0, double maxdiff = 0, class pufftype = "BulletPuff", double spread_xy = 0, double spread_z = 0, double range = 0, int duration = 0, double sparsity = 1.0, double driftspeed = 1.0, class spawnclass = null, double spawnofs_z = 0, int spiraloffset = 270, int limit = 0); native bool A_SetInventory(class itemtype, int amount, int ptr = AAPTR_DEFAULT, bool beyondMax = false); native bool A_GiveInventory(class itemtype, int amount = 0, int giveto = AAPTR_DEFAULT); native bool A_TakeInventory(class itemtype, int amount = 0, int flags = 0, int giveto = AAPTR_DEFAULT); - action native bool A_SpawnItem(class itemtype = "Unknown", float distance = 0, float zheight = 0, bool useammo = true, bool transfer_translation = false); - native bool 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); - native void A_Print(string whattoprint, float time = 0, name fontname = "none"); - native void A_PrintBold(string whattoprint, float time = 0, name fontname = "none"); + action native bool A_SpawnItem(class itemtype = "Unknown", double distance = 0, double zheight = 0, bool useammo = true, bool transfer_translation = false); + native bool A_SpawnItemEx(class itemtype, double xofs = 0, double yofs = 0, double zofs = 0, double xvel = 0, double yvel = 0, double zvel = 0, double angle = 0, int flags = 0, int failchance = 0, int tid=0); + native void A_Print(string whattoprint, double time = 0, name fontname = "none"); + native void A_PrintBold(string whattoprint, double time = 0, name fontname = "none"); native void A_Log(string whattoprint); native void A_LogInt(int whattoprint); - native void A_LogFloat(float whattoprint); - native void A_SetTranslucent(float alpha, int style = 0); - native void A_SetRenderStyle(float alpha, int style); - native void A_FadeIn(float reduce = 0.1, int flags = 0); - native void A_FadeOut(float reduce = 0.1, int flags = 1); //bool remove == true - native void A_FadeTo(float target, float amount = 0.1, int flags = 0); - native void A_SpawnDebris(class spawntype, bool transfer_translation = false, float mult_h = 1, float mult_v = 1); - native void A_SpawnParticle(color color1, int flags = 0, int lifetime = 35, float size = 1, float angle = 0, float xoff = 0, float yoff = 0, float zoff = 0, float velx = 0, float vely = 0, float velz = 0, float accelx = 0, float accely = 0, float accelz = 0, float startalphaf = 1, float fadestepf = -1, float sizestep = 0); + native void A_LogFloat(double whattoprint); + native void A_SetTranslucent(double alpha, int style = 0); + native void A_SetRenderStyle(double alpha, int style); + native void A_FadeIn(double reduce = 0.1, int flags = 0); + native void A_FadeOut(double reduce = 0.1, int flags = 1); //bool remove == true + native void A_FadeTo(double target, double amount = 0.1, int flags = 0); + native void A_SpawnDebris(class spawntype, bool transfer_translation = false, double mult_h = 1, double mult_v = 1); + native void A_SpawnParticle(color color1, int flags = 0, int lifetime = 35, double size = 1, double angle = 0, double xoff = 0, double yoff = 0, double zoff = 0, double velx = 0, double vely = 0, double velz = 0, double accelx = 0, double accely = 0, double accelz = 0, double startalphaf = 1, double fadestepf = -1, double sizestep = 0); native void A_ExtChase(bool usemelee, bool usemissile, bool playactive = true, bool nightmarefast = false); native void A_DropInventory(class itemtype); - native void A_SetBlend(color color1, float alpha, int tics, color color2 = 0); + native void A_SetBlend(color color1, double alpha, int tics, color color2 = 0); deprecated native void A_ChangeFlag(string flagname, bool value); native void A_ChangeCountFlags(int kill = FLAG_NO_CHANGE, int item = FLAG_NO_CHANGE, int secret = FLAG_NO_CHANGE); native void A_RaiseMaster(bool copy = 0); native void A_RaiseChildren(bool copy = 0); native void A_RaiseSiblings(bool copy = 0); - deprecated native void A_BasicAttack(int meleedamage, sound meleesound, class missiletype, float missileheight); - action native bool A_ThrowGrenade(class itemtype, float zheight = 0, float xyvel = 0, float zvel = 0, bool useammo = true); - native void A_Weave(int xspeed, int yspeed, float xdist, float ydist); + deprecated native void A_BasicAttack(int meleedamage, sound meleesound, class missiletype, double missileheight); + action native bool A_ThrowGrenade(class itemtype, double zheight = 0, double xyvel = 0, double zvel = 0, bool useammo = true); + native void A_Weave(int xspeed, int yspeed, double xdist, double ydist); - action native state, bool A_Teleport(statelabel teleportstate = null, class targettype = "BossSpot", class fogtype = "TeleportFog", int flags = 0, float mindist = 0, float maxdist = 128, int ptr = AAPTR_DEFAULT); - action native state, bool A_Warp(int ptr_destination, float xofs = 0, float yofs = 0, float zofs = 0, float angle = 0, int flags = 0, statelabel success_state = null, float heightoffset = 0, float radiusoffset = 0, float pitch = 0); + action native state, bool A_Teleport(statelabel teleportstate = null, class targettype = "BossSpot", class fogtype = "TeleportFog", int flags = 0, double mindist = 0, double maxdist = 128, int ptr = AAPTR_DEFAULT); + action native state, bool A_Warp(int ptr_destination, double xofs = 0, double yofs = 0, double zofs = 0, double angle = 0, int flags = 0, statelabel success_state = null, double heightoffset = 0, double radiusoffset = 0, double pitch = 0); native void A_CountdownArg(int argnum, statelabel targstate = null); native state A_MonsterRefire(int chance, statelabel label); - native void A_LookEx(int flags = 0, float minseedist = 0, float maxseedist = 0, float maxheardist = 0, float fov = 0, statelabel label = null); + native void A_LookEx(int flags = 0, double minseedist = 0, double maxseedist = 0, double maxheardist = 0, double fov = 0, statelabel label = null); - native void A_Recoil(float xyvel); + native void A_Recoil(double xyvel); native bool A_GiveToTarget(class itemtype, int amount = 0, int forward_ptr = AAPTR_DEFAULT); native bool A_TakeFromTarget(class itemtype, int amount = 0, int flags = 0, int forward_ptr = AAPTR_DEFAULT); - native int A_RadiusGive(class itemtype, float distance, int flags, int amount = 0, class filter = null, name species = "None", float mindist = 0, int limit = 0); + native int A_RadiusGive(class itemtype, double distance, int flags, int amount = 0, class filter = null, name species = "None", double mindist = 0, int limit = 0); native void A_CustomMeleeAttack(int damage = 0, sound meleesound = "", sound misssound = "", name damagetype = "none", bool bleed = true); - native void A_CustomComboAttack(class missiletype, float spawnheight, int damage, sound meleesound = "", name damagetype = "none", bool bleed = true); + native void A_CustomComboAttack(class missiletype, double spawnheight, int damage, sound meleesound = "", name damagetype = "none", bool bleed = true); native void A_Burst(class chunktype); - action native void A_Blast(int flags = 0, float strength = 255, float radius = 255, float speed = 20, class blasteffect = "BlastEffect", sound blastsound = "BlastRadius"); + action native void A_Blast(int flags = 0, double strength = 255, double radius = 255, double speed = 20, class blasteffect = "BlastEffect", sound blastsound = "BlastRadius"); native void A_RadiusThrust(int force = 128, int distance = -1, int flags = RTF_AFFECTSOURCE, int fullthrustdistance = 0); - native void A_RadiusDamageSelf(int damage = 128, float distance = 128, int flags = 0, class flashtype = null); + native void A_RadiusDamageSelf(int damage = 128, double distance = 128, int flags = 0, class flashtype = null); native int A_Explode(int damage = -1, int distance = -1, int flags = XF_HURTSOURCE, bool alert = false, int fulldamagedistance = 0, int nails = 0, int naildamage = 10, class pufftype = "BulletPuff", name damagetype = "none"); native void A_Stop(); native void A_Respawn(int flags = 1); @@ -477,17 +477,17 @@ class Actor : Thinker native native void A_RemoveForcefield(); native void A_DropWeaponPieces(class p1, class p2, class p3); native void A_PigPain (); - native void A_SetAngle(float angle = 0, int flags = 0, int ptr = AAPTR_DEFAULT); - native void A_SetPitch(float pitch, int flags = 0, int ptr = AAPTR_DEFAULT); - native void A_SetRoll(float roll, int flags = 0, int ptr = AAPTR_DEFAULT); - native void A_ScaleVelocity(float scale, int ptr = AAPTR_DEFAULT); - native void A_ChangeVelocity(float x = 0, float y = 0, float z = 0, int flags = 0, int ptr = AAPTR_DEFAULT); + native void A_SetAngle(double angle = 0, int flags = 0, int ptr = AAPTR_DEFAULT); + native void A_SetPitch(double pitch, int flags = 0, int ptr = AAPTR_DEFAULT); + native void A_SetRoll(double roll, int flags = 0, int ptr = AAPTR_DEFAULT); + native void A_ScaleVelocity(double scale, int ptr = AAPTR_DEFAULT); + native void A_ChangeVelocity(double x = 0, double y = 0, double z = 0, int flags = 0, int ptr = AAPTR_DEFAULT); deprecated native void A_SetUserVar(name varname, int value); deprecated native void A_SetUserArray(name varname, int index, int value); - deprecated native void A_SetUserVarFloat(name varname, float value); - deprecated native void A_SetUserArrayFloat(name varname, int index, float value); + deprecated native void A_SetUserVarFloat(name varname, double value); + deprecated native void A_SetUserArrayFloat(name varname, int index, double value); native void A_Quake(int intensity, int duration, int damrad, int tremrad, sound sfx = "world/quake"); - native void A_QuakeEx(int intensityX, int intensityY, int intensityZ, int duration, int damrad, int tremrad, sound sfx = "world/quake", int flags = 0, float mulWaveX = 1, float mulWaveY = 1, float mulWaveZ = 1, int falloff = 0, int highpoint = 0, float rollIntensity = 0, float rollWave = 0); + native void A_QuakeEx(int intensityX, int intensityY, int intensityZ, int duration, int damrad, int tremrad, sound sfx = "world/quake", int flags = 0, double mulWaveX = 1, double mulWaveY = 1, double mulWaveZ = 1, int falloff = 0, int highpoint = 0, double rollIntensity = 0, double rollWave = 0); action native void A_SetTics(int tics); native void A_DropItem(class item, int dropamount = -1, int chance = 256); native void A_DamageSelf(int amount, name damagetype = "none", int flags = 0, class filter = null, name species = "None", int src = AAPTR_DEFAULT, int inflict = AAPTR_DEFAULT); @@ -517,10 +517,10 @@ class Actor : Thinker native native void A_ResetHealth(int ptr = AAPTR_DEFAULT); native void A_SetSpecies(name species, int ptr = AAPTR_DEFAULT); native void A_SetChaseThreshold(int threshold, bool def = false, int ptr = AAPTR_DEFAULT); - native bool A_FaceMovementDirection(float offset = 0, float anglelimit = 0, float pitchlimit = 0, int flags = 0, int ptr = AAPTR_DEFAULT); + native bool A_FaceMovementDirection(double offset = 0, double anglelimit = 0, double pitchlimit = 0, int flags = 0, int ptr = AAPTR_DEFAULT); native int A_ClearOverlays(int sstart = 0, int sstop = 0, bool safety = true); native bool A_CopySpriteFrame(int from, int to, int flags = 0); - native bool A_SetVisibleRotation(float anglestart = 0, float angleend = 0, float pitchstart = 0, float pitchend = 0, int flags = 0, int ptr = AAPTR_DEFAULT); + native bool A_SetVisibleRotation(double anglestart = 0, double angleend = 0, double pitchstart = 0, double pitchend = 0, int flags = 0, int ptr = AAPTR_DEFAULT); native void A_SetTranslation(string transname); native void A_RearrangePointers(int newtarget, int newmaster = AAPTR_DEFAULT, int newtracer = AAPTR_DEFAULT, int flags=0); @@ -528,8 +528,8 @@ class Actor : Thinker native native void A_CopyFriendliness(int ptr_source = AAPTR_MASTER); action native bool A_Overlay(int layer, statelabel start = null, bool nooverride = false); - native void A_WeaponOffset(float wx = 0, float wy = 32, int flags = 0); - action native void A_OverlayOffset(int layer = PSP_WEAPON, float wx = 0, float wy = 32, int flags = 0); + native void A_WeaponOffset(double wx = 0, double wy = 32, int flags = 0); + action native void A_OverlayOffset(int layer = PSP_WEAPON, double wx = 0, double wy = 32, int flags = 0); action native void A_OverlayFlags(int layer, int flags, bool set); int ACS_NamedExecute(name script, int mapnum=0, int arg1=0, int arg2=0, int arg3=0) @@ -582,5 +582,5 @@ class Actor : Thinker native // Internal functions deprecated private native int __decorate_internal_int__(int i); deprecated private native bool __decorate_internal_bool__(bool b); - deprecated private native float __decorate_internal_float__(float f); + deprecated private native double __decorate_internal_float__(double f); } diff --git a/wadsrc/static/zscript/actor_checks.txt b/wadsrc/static/zscript/actor_checks.txt index 3ad4255d7..a4f7da1d8 100644 --- a/wadsrc/static/zscript/actor_checks.txt +++ b/wadsrc/static/zscript/actor_checks.txt @@ -31,7 +31,7 @@ extend class Actor // //========================================================================== - bool CheckIfCloser(Actor targ, float dist, bool noz = false) + bool CheckIfCloser(Actor targ, double dist, bool noz = false) { if (!targ) return false; return @@ -42,7 +42,7 @@ extend class Actor )); } - action state A_JumpIfCloser(float distance, statelabel label, bool noz = false) + action state A_JumpIfCloser(double distance, statelabel label, bool noz = false) { Actor targ; @@ -59,12 +59,12 @@ extend class Actor return CheckIfCloser(targ, distance, noz)? ResolveState(label) : null; } - action state A_JumpIfTracerCloser(float distance, statelabel label, bool noz = false) + action state A_JumpIfTracerCloser(double distance, statelabel label, bool noz = false) { return CheckIfCloser(tracer, distance, noz)? ResolveState(label) : null; } - action state A_JumpIfMasterCloser(float distance, statelabel label, bool noz = false) + action state A_JumpIfMasterCloser(double distance, statelabel label, bool noz = false) { return CheckIfCloser(master, distance, noz)? ResolveState(label) : null; } @@ -124,20 +124,20 @@ extend class Actor //========================================================================== native bool CheckIfSeen(); - native bool CheckSightOrRange(float distance, bool two_dimension = false); - native bool CheckRange(float distance, bool two_dimension = false); + native bool CheckSightOrRange(double distance, bool two_dimension = false); + native bool CheckRange(double distance, bool two_dimension = false); action state A_CheckSight(statelabel label) { return CheckIfSeen()? ResolveState(label) : null; } - action state A_CheckSightOrRange(float distance, statelabel label, bool two_dimension = false) + action state A_CheckSightOrRange(double distance, statelabel label, bool two_dimension = false) { return CheckSightOrRange(distance, two_dimension)? ResolveState(label) : null; } - action state A_CheckRange(float distance, statelabel label, bool two_dimension = false) + action state A_CheckRange(double distance, statelabel label, bool two_dimension = false) { return CheckRange(distance, two_dimension)? ResolveState(label) : null; } @@ -202,28 +202,28 @@ extend class Actor // //========================================================================== - native bool CheckLOF(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, float offsetforward = 0); - native bool CheckIfTargetInLOS (float fov = 0, int flags = 0, float dist_max = 0, float dist_close = 0); - native bool CheckIfInTargetLOS (float fov = 0, int flags = 0, float dist_max = 0, float dist_close = 0); - native bool CheckProximity(class classname, float distance, int count = 1, int flags = 0, int ptr = AAPTR_DEFAULT); - native bool CheckBlock(int flags = 0, int ptr = AAPTR_DEFAULT, float xofs = 0, float yofs = 0, float zofs = 0, float angle = 0); + native bool CheckLOF(int flags = 0, double range = 0, double minrange = 0, double angle = 0, double pitch = 0, double offsetheight = 0, double offsetwidth = 0, int ptr_target = AAPTR_DEFAULT, double offsetforward = 0); + native bool CheckIfTargetInLOS (double fov = 0, int flags = 0, double dist_max = 0, double dist_close = 0); + native bool CheckIfInTargetLOS (double fov = 0, int flags = 0, double dist_max = 0, double dist_close = 0); + native bool CheckProximity(class classname, double distance, int count = 1, int flags = 0, int ptr = AAPTR_DEFAULT); + native bool CheckBlock(int flags = 0, int ptr = AAPTR_DEFAULT, double xofs = 0, double yofs = 0, double zofs = 0, double angle = 0); - action state A_CheckLOF(statelabel label, 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, float offsetforward = 0) + action state A_CheckLOF(statelabel label, int flags = 0, double range = 0, double minrange = 0, double angle = 0, double pitch = 0, double offsetheight = 0, double offsetwidth = 0, int ptr_target = AAPTR_DEFAULT, double offsetforward = 0) { return CheckLOF(flags, range, minrange, angle, pitch, offsetheight, offsetwidth, ptr_target, offsetforward)? ResolveState(label) : null; } - action state A_JumpIfTargetInLOS (statelabel label, float fov = 0, int flags = 0, float dist_max = 0, float dist_close = 0) + action state A_JumpIfTargetInLOS (statelabel label, double fov = 0, int flags = 0, double dist_max = 0, double dist_close = 0) { return CheckIfTargetInLOS(fov, flags, dist_max, dist_close)? ResolveState(label) : null; } - action state A_JumpIfInTargetLOS (statelabel label, float fov = 0, int flags = 0, float dist_max = 0, float dist_close = 0) + action state A_JumpIfInTargetLOS (statelabel label, double fov = 0, int flags = 0, double dist_max = 0, double dist_close = 0) { return CheckIfInTargetLOS(fov, flags, dist_max, dist_close)? ResolveState(label) : null; } - action state A_CheckProximity(statelabel label, class classname, float distance, int count = 1, int flags = 0, int ptr = AAPTR_DEFAULT) + action state A_CheckProximity(statelabel label, class classname, double distance, int count = 1, int flags = 0, int ptr = AAPTR_DEFAULT) { // This one was doing some weird stuff that needs to be preserved. state jumpto = ResolveState(label); @@ -237,7 +237,7 @@ extend class Actor return CheckProximity(classname, distance, count, flags, ptr)? jumpto : null; } - action state A_CheckBlock(statelabel label, int flags = 0, int ptr = AAPTR_DEFAULT, float xofs = 0, float yofs = 0, float zofs = 0, float angle = 0) + action state A_CheckBlock(statelabel label, int flags = 0, int ptr = AAPTR_DEFAULT, double xofs = 0, double yofs = 0, double zofs = 0, double angle = 0) { return CheckBlock(flags, ptr, xofs, yofs, zofs, angle)? ResolveState(label) : null; } @@ -253,7 +253,7 @@ extend class Actor // if its lower. //=========================================================================== - action state A_JumpIfHigherOrLower(statelabel high, statelabel low, float offsethigh = 0, float offsetlow = 0, bool includeHeight = true, int ptr = AAPTR_TARGET) + action state A_JumpIfHigherOrLower(statelabel high, statelabel low, double offsethigh = 0, double offsetlow = 0, bool includeHeight = true, int ptr = AAPTR_TARGET) { Actor mobj = GetPointer(ptr); diff --git a/wadsrc/static/zscript/doom/archvile.txt b/wadsrc/static/zscript/doom/archvile.txt index 0e9008570..9faa80495 100644 --- a/wadsrc/static/zscript/doom/archvile.txt +++ b/wadsrc/static/zscript/doom/archvile.txt @@ -123,7 +123,7 @@ extend class Actor } } - void A_VileAttack(sound snd = "vile/stop", int initialdmg = 20, int blastdmg = 70, int blastradius = 70, float thrust = 1.0, name damagetype = "Fire", int flags = 0) + void A_VileAttack(sound snd = "vile/stop", int initialdmg = 20, int blastdmg = 70, int blastradius = 70, double thrust = 1.0, name damagetype = "Fire", int flags = 0) { if (target) { @@ -158,7 +158,7 @@ extend class Actor // A_Fire // Keep fire in front of player unless out of sight // - void A_Fire(float spawnheight = 0) + void A_Fire(double spawnheight = 0) { Actor dest = tracer; if (!dest || !target) return; diff --git a/wadsrc/static/zscript/doom/fatso.txt b/wadsrc/static/zscript/doom/fatso.txt index 59e0d4c63..98bcc3fc9 100644 --- a/wadsrc/static/zscript/doom/fatso.txt +++ b/wadsrc/static/zscript/doom/fatso.txt @@ -175,7 +175,7 @@ extend class Actor // Original idea: Linguica // - void A_Mushroom(class spawntype = "FatShot", int numspawns = 0, int flags = 0, float vrange = 4.0, float hrange = 0.5) + void A_Mushroom(class spawntype = "FatShot", int numspawns = 0, int flags = 0, double vrange = 4.0, double hrange = 0.5) { int i, j; diff --git a/wadsrc/static/zscript/doom/lostsoul.txt b/wadsrc/static/zscript/doom/lostsoul.txt index 7ef8b4cf0..89cefc42a 100644 --- a/wadsrc/static/zscript/doom/lostsoul.txt +++ b/wadsrc/static/zscript/doom/lostsoul.txt @@ -92,7 +92,7 @@ extend class Actor { const SKULLSPEED = 20; - void A_SkullAttack(float skullspeed = SKULLSPEED) + void A_SkullAttack(double skullspeed = SKULLSPEED) { if (target == null) return; diff --git a/wadsrc/static/zscript/doom/painelemental.txt b/wadsrc/static/zscript/doom/painelemental.txt index fde690b39..03a4d82c4 100644 --- a/wadsrc/static/zscript/doom/painelemental.txt +++ b/wadsrc/static/zscript/doom/painelemental.txt @@ -61,9 +61,9 @@ class PainElemental : Actor extend class Actor { - native void A_PainShootSkull(Class spawntype, float angle, int flags = 0, int limit = -1); + native void A_PainShootSkull(Class spawntype, double angle, int flags = 0, int limit = -1); - void A_PainAttack(class spawntype = "LostSoul", float addangle = 0, int flags = 0, int limit = -1) + void A_PainAttack(class spawntype = "LostSoul", double addangle = 0, int flags = 0, int limit = -1) { if (target) { diff --git a/wadsrc/static/zscript/doom/weaponchainsaw.txt b/wadsrc/static/zscript/doom/weaponchainsaw.txt index b2583efa5..0653bc16d 100644 --- a/wadsrc/static/zscript/doom/weaponchainsaw.txt +++ b/wadsrc/static/zscript/doom/weaponchainsaw.txt @@ -41,7 +41,7 @@ class Chainsaw : Weapon extend class StateProvider { - action void 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 void A_Saw(sound fullsound = "weapons/sawfull", sound hitsound = "weapons/sawhit", int damage = 2, class pufftype = "BulletPuff", int flags = 0, double range = 0, double spread_xy = 2.8125, double spread_z = 0, double lifesteal = 0, int lifestealmax = 0, class armorbonustype = "ArmorBonus") { FTranslatedLineTarget t; diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index d5734e149..f906ca01c 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -43,10 +43,10 @@ class Inventory : Actor native class StateProvider : Inventory native { action native state A_JumpIfNoAmmo(statelabel label); - action native void 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 = 0, sound MissSound = ""); - action native void A_FireBullets(float spread_xy, float spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", int flags = 1, float range = 0, class missile = null, float Spawnheight = 32, float Spawnofs_xy = 0); - action native void A_FireCustomMissile(class missiletype, float angle = 0, bool useammo = true, float spawnofs_xy = 0, float spawnheight = 0, int flags = 0, float pitch = 0); - action native void A_RailAttack(int damage, int spawnofs_xy = 0, bool useammo = true, color color1 = 0, color color2 = 0, 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, int limit = 0); + action native void A_CustomPunch(int damage, bool norandom = false, int flags = CPF_USEAMMO, class pufftype = "BulletPuff", double range = 0, double lifesteal = 0, int lifestealmax = 0, class armorbonustype = "ArmorBonus", sound MeleeSound = 0, sound MissSound = ""); + action native void A_FireBullets(double spread_xy, double spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", int flags = 1, double range = 0, class missile = null, double Spawnheight = 32, double Spawnofs_xy = 0); + action native void A_FireCustomMissile(class missiletype, double angle = 0, bool useammo = true, double spawnofs_xy = 0, double spawnheight = 0, int flags = 0, double pitch = 0); + action native void A_RailAttack(int damage, int spawnofs_xy = 0, bool useammo = true, color color1 = 0, color color2 = 0, int flags = 0, double maxdiff = 0, class pufftype = "BulletPuff", double spread_xy = 0, double spread_z = 0, double range = 0, int duration = 0, double sparsity = 1.0, double driftspeed = 1.0, class spawnclass = "none", double spawnofs_z = 0, int spiraloffset = 270, int limit = 0); action native void A_WeaponReady(int flags = 0); action native void A_Lower(); action native void A_Raise(); @@ -457,7 +457,7 @@ class Weapon : StateProvider native native bool DepleteAmmo(bool altFire, bool checkEnough = true, int ammouse = -1); - native action void A_ZoomFactor(float scale = 1, int flags = 0); + native action void A_ZoomFactor(double scale = 1, int flags = 0); native action void A_SetCrosshair(int xhair); const ZOOM_INSTANT = 1; const ZOOM_NOSCALETURNING = 2; diff --git a/wadsrc/static/zscript/strife/strifeweapons.txt b/wadsrc/static/zscript/strife/strifeweapons.txt index 9e4463893..968e4c4c5 100644 --- a/wadsrc/static/zscript/strife/strifeweapons.txt +++ b/wadsrc/static/zscript/strife/strifeweapons.txt @@ -816,7 +816,7 @@ class StrifeGrenadeLauncher : StrifeWeapon Inventory.PickupMessage "$TXT_GLAUNCHER"; } - action native void A_FireGrenade (class grenadetype, float angleofs, statelabel flash); + action native void A_FireGrenade (class grenadetype, double angleofs, statelabel flash); States { From 7d9955290380995af858d6f0ebd47b1aded99b4c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 21 Nov 2016 13:45:33 +0100 Subject: [PATCH 064/185] - added two new integral types SpriteID and TextureID, both are needed to allow proper serialization as they require something different to be written out than a regular integer. --- src/dobjtype.cpp | 91 ++++++++++++++++++++++++ src/dobjtype.h | 22 ++++++ src/namedef.h | 2 + src/p_mobj.cpp | 4 +- src/scripting/codegeneration/codegen.cpp | 8 +++ src/scripting/vm/vm.h | 2 + src/scripting/vm/vmexec.cpp | 2 + src/scripting/vm/vmexec.h | 13 ++++ src/scripting/zscript/zcc_compile.cpp | 34 +++++---- src/scripting/zscript/zcc_parser.h | 3 +- 10 files changed, 164 insertions(+), 17 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index e84504015..4354e0885 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -81,6 +81,8 @@ PString *TypeString; PName *TypeName; PSound *TypeSound; PColor *TypeColor; +PTextureID *TypeTextureID; +PSpriteID *TypeSpriteID; PStatePointer *TypeState; PStateLabel *TypeStateLabel; PStruct *TypeVector2; @@ -546,6 +548,8 @@ void PType::StaticInit() RUNTIME_CLASS(PString)->TypeTableType = RUNTIME_CLASS(PString); RUNTIME_CLASS(PName)->TypeTableType = RUNTIME_CLASS(PName); RUNTIME_CLASS(PSound)->TypeTableType = RUNTIME_CLASS(PSound); + RUNTIME_CLASS(PSpriteID)->TypeTableType = RUNTIME_CLASS(PSpriteID); + RUNTIME_CLASS(PTextureID)->TypeTableType = RUNTIME_CLASS(PTextureID); RUNTIME_CLASS(PColor)->TypeTableType = RUNTIME_CLASS(PColor); RUNTIME_CLASS(PPointer)->TypeTableType = RUNTIME_CLASS(PPointer); RUNTIME_CLASS(PClassPointer)->TypeTableType = RUNTIME_CLASS(PClassPointer); @@ -578,6 +582,8 @@ void PType::StaticInit() TypeTable.AddType(TypeState = new PStatePointer); TypeTable.AddType(TypeStateLabel = new PStateLabel); TypeTable.AddType(TypeNullPtr = new PPointer); + TypeTable.AddType(TypeSpriteID = new PSpriteID); + TypeTable.AddType(TypeTextureID = new PTextureID); TypeColorStruct = new PStruct("@ColorStruct", nullptr); //This name is intentionally obfuscated so that it cannot be used explicitly. The point of this type is to gain access to the single channels of a color value. #ifdef __BIG_ENDIAN__ @@ -1373,6 +1379,91 @@ bool PName::ReadValue(FSerializer &ar, const char *key, void *addr) const } } +/* PSpriteID ******************************************************************/ + +IMPLEMENT_CLASS(PSpriteID, false, false, false, false) + +//========================================================================== +// +// PName Default Constructor +// +//========================================================================== + +PSpriteID::PSpriteID() + : PInt(sizeof(int), true, true) +{ + mDescriptiveName = "SpriteID"; +} + +//========================================================================== +// +// PName :: WriteValue +// +//========================================================================== + +void PSpriteID::WriteValue(FSerializer &ar, const char *key, const void *addr) const +{ + int32_t val = *(int*)addr; + ar.Sprite(key, val, nullptr); +} + +//========================================================================== +// +// PName :: ReadValue +// +//========================================================================== + +bool PSpriteID::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + int32_t val; + ar.Sprite(key, val, nullptr); + *(int*)addr = val; + return true; +} + +/* PTextureID ******************************************************************/ + +IMPLEMENT_CLASS(PTextureID, false, false, false, false) + +//========================================================================== +// +// PTextureID Default Constructor +// +//========================================================================== + +PTextureID::PTextureID() + : PInt(sizeof(FTextureID), true, false) +{ + mDescriptiveName = "TextureID"; + assert(sizeof(FTextureID) == alignof(FTextureID)); +} + +//========================================================================== +// +// PTextureID :: WriteValue +// +//========================================================================== + +void PTextureID::WriteValue(FSerializer &ar, const char *key, const void *addr) const +{ + FTextureID val = *(FTextureID*)addr; + ar(key, val); +} + +//========================================================================== +// +// PTextureID :: ReadValue +// +//========================================================================== + +bool PTextureID::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + FTextureID val; + ar(key, val); + *(FTextureID*)addr = val; + return true; +} + /* PSound *****************************************************************/ IMPLEMENT_CLASS(PSound, false, false, false, false) diff --git a/src/dobjtype.h b/src/dobjtype.h index b8fc1cbf6..be192225b 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -515,6 +515,26 @@ public: bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; }; +class PSpriteID : public PInt +{ + DECLARE_CLASS(PSpriteID, PInt); +public: + PSpriteID(); + + void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; +}; + +class PTextureID : public PInt +{ + DECLARE_CLASS(PTextureID, PInt); +public: + PTextureID(); + + void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; +}; + class PColor : public PInt { DECLARE_CLASS(PColor, PInt); @@ -917,6 +937,8 @@ extern PString *TypeString; extern PName *TypeName; extern PSound *TypeSound; extern PColor *TypeColor; +extern PTextureID *TypeTextureID; +extern PSpriteID *TypeSpriteID; extern PStruct *TypeVector2; extern PStruct *TypeVector3; extern PStruct *TypeColorStruct; diff --git a/src/namedef.h b/src/namedef.h index 0418e0f87..5ee98119a 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -737,6 +737,8 @@ xx(DamageFunction) xx(Length) xx(Unit) xx(StateLabel) +xx(SpriteID) +xx(TextureID) xx(Overlay) xx(A_Punch) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 964736fed..313052c6b 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -191,7 +191,7 @@ void AActor::InitNativeFields() meta->AddNativeField(NAME_MomZ, TypeFloat64, myoffsetof(AActor, Vel.Z), VARF_ReadOnly | VARF_Deprecated); meta->AddNativeField(NAME_Speed, TypeFloat64, myoffsetof(AActor, Speed)); meta->AddNativeField("FloatSpeed", TypeFloat64, myoffsetof(AActor, FloatSpeed)); - meta->AddNativeField("sprite", TypeSInt32, myoffsetof(AActor, sprite)); // this is an index, not a name! + meta->AddNativeField("sprite", TypeSpriteID, myoffsetof(AActor, sprite)); meta->AddNativeField("frame", TypeUInt8, myoffsetof(AActor, frame)); meta->AddNativeField("Scale", TypeVector2, myoffsetof(AActor, Scale)); meta->AddNativeField(NAME_ScaleX, TypeFloat64, myoffsetof(AActor, Scale.X), VARF_Deprecated); @@ -206,7 +206,7 @@ void AActor::InitNativeFields() meta->AddNativeField(NAME_FloorZ, TypeFloat64, myoffsetof(AActor, floorz)); meta->AddNativeField("DropoffZ", TypeFloat64, myoffsetof(AActor, dropoffz), VARF_ReadOnly); meta->AddNativeField("floorsector", TypeSector, myoffsetof(AActor, floorsector)); - meta->AddNativeField("floorpic", TypeSInt32, myoffsetof(AActor, floorpic)); // Do we need a variable type 'texture' to do this? + meta->AddNativeField("floorpic", TypeTextureID, myoffsetof(AActor, floorpic)); meta->AddNativeField("floorterrain", TypeSInt32, myoffsetof(AActor, floorterrain)); meta->AddNativeField("ceilingsector", TypeSector, myoffsetof(AActor, ceilingsector)); meta->AddNativeField("ceilingpic", TypeSInt32, myoffsetof(AActor, ceilingpic)); // Do we need a variable type 'texture' to do this? diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index c040403d8..cae95da34 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -3825,6 +3825,8 @@ ExpEmit FxConcat::Emit(VMFunctionBuilder *build) else if (left->ValueType == TypeName) cast = CAST_N2S; else if (left->ValueType == TypeSound) cast = CAST_So2S; else if (left->ValueType == TypeColor) cast = CAST_Co2S; + else if (left->ValueType == TypeSpriteID) cast = CAST_SID2S; + else if (left->ValueType == TypeTextureID) cast = CAST_TID2S; else if (op1.RegType == REGT_POINTER) cast = CAST_P2S; else if (op1.RegType == REGT_INT) cast = CAST_I2S; else assert(false && "Bad type for string concatenation"); @@ -3856,6 +3858,8 @@ ExpEmit FxConcat::Emit(VMFunctionBuilder *build) else if (right->ValueType == TypeName) cast = CAST_N2S; else if (right->ValueType == TypeSound) cast = CAST_So2S; else if (right->ValueType == TypeColor) cast = CAST_Co2S; + else if (right->ValueType == TypeSpriteID) cast = CAST_SID2S; + else if (right->ValueType == TypeTextureID) cast = CAST_TID2S; else if (op2.RegType == REGT_POINTER) cast = CAST_P2S; else if (op2.RegType == REGT_INT) cast = CAST_I2S; else assert(false && "Bad type for string concatenation"); @@ -6880,6 +6884,8 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) case NAME_Color: case NAME_Sound: case NAME_State: + case NAME_SpriteID: + case NAME_TextureID: if (CheckArgSize(MethodName, ArgList, 1, 1, ScriptPosition)) { PType *type = @@ -6889,6 +6895,8 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) MethodName == NAME_Float ? TypeFloat64 : MethodName == NAME_Double ? TypeFloat64 : MethodName == NAME_Name ? TypeName : + MethodName == NAME_SpriteID ? TypeSpriteID : + MethodName == NAME_TextureID ? TypeTextureID : MethodName == NAME_State ? TypeState : MethodName == NAME_Color ? TypeColor : (PType*)TypeSound; diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index b8885e0a1..ad42ee1dd 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -127,6 +127,8 @@ enum CAST_So2S, CAST_V22S, CAST_V32S, + CAST_SID2S, + CAST_TID2S, }; // Register types for VMParam diff --git a/src/scripting/vm/vmexec.cpp b/src/scripting/vm/vmexec.cpp index 8f8559d93..24beb7f9c 100644 --- a/src/scripting/vm/vmexec.cpp +++ b/src/scripting/vm/vmexec.cpp @@ -36,6 +36,8 @@ #include #include "dobject.h" #include "xs_Float.h" +#include "r_state.h" +#include "textures/textures.h" #include "math/cmath.h" #define IMPLEMENT_VMEXEC diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index e460ef29c..2e7771680 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -1695,6 +1695,19 @@ static void DoCast(const VMRegisters ®, const VMFrame *f, int a, int b, int c reg.s[a] = S_sfx[reg.d[b]].name; break; + case CAST_SID2S: + ASSERTS(a); ASSERTD(b); + reg.s[a] = unsigned(reg.d[b]) >= sprites.Size() ? "TNT1" : sprites[reg.d[b]].name; + break; + + case CAST_TID2S: + { + ASSERTS(a); ASSERTD(b); + auto tex = TexMan[*(FTextureID*)&(reg.d[b])]; + reg.s[a] = tex == nullptr ? "(null)" : tex->Name.GetChars(); + break; + } + default: assert(0); } diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 3d8cc18b5..27a02a919 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1367,19 +1367,19 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n switch (btype->Type) { case ZCC_SInt8: - retval = TypeSInt8; + retval = formember? TypeSInt8 : (PType*)TypeError; break; case ZCC_UInt8: - retval = TypeUInt8; + retval = formember ? TypeUInt8 : (PType*)TypeError; break; case ZCC_SInt16: - retval = TypeSInt16; + retval = formember ? TypeSInt16 : (PType*)TypeError; break; case ZCC_UInt16: - retval = TypeUInt16; + retval = formember ? TypeUInt16 : (PType*)TypeError; break; case ZCC_SInt32: @@ -1395,11 +1395,9 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n retval = TypeBool; break; - // Do we really want to allow single precision floats, despite all the problems they cause? - // These are nearly guaranteed to desync between MSVC and GCC on x87, because GCC does not implement an IEEE compliant mode - case ZCC_Float32: case ZCC_FloatAuto: - //return TypeFloat32; + retval = formember ? TypeFloat32 : TypeFloat64; + case ZCC_Float64: retval = TypeFloat64; break; @@ -1433,14 +1431,24 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n break; case ZCC_UserType: - // statelabel is not a token - there really is no need to, it works just as well as an identifier. Maybe the same should be done for some other types, too? - if (btype->UserType->Id == NAME_StateLabel) + // statelabel et.al. are not tokens - there really is no need to, it works just as well as an identifier. Maybe the same should be done for some other types, too? + switch (btype->UserType->Id) { + case NAME_StateLabel: retval = TypeStateLabel; - } - else - { + break; + + case NAME_SpriteID: + retval = TypeSpriteID; + break; + + case NAME_TextureID: + retval = TypeTextureID; + break; + + default: retval = ResolveUserType(btype, &outertype->Symbols); + break; } break; } diff --git a/src/scripting/zscript/zcc_parser.h b/src/scripting/zscript/zcc_parser.h index a19249208..e000da06c 100644 --- a/src/scripting/zscript/zcc_parser.h +++ b/src/scripting/zscript/zcc_parser.h @@ -113,13 +113,12 @@ enum EZCCBuiltinType ZCC_SInt8, ZCC_UInt8, ZCC_SInt16, - ZCC_UInt16, + ZCC_UInt16, // smaller than 32 bit types are only valid in structs, classes and arrays. 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, From 97763b5a2b12fb053a479da51b1813c74259fda8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 21 Nov 2016 14:59:17 +0100 Subject: [PATCH 065/185] - added scriptable virtual overrides for PostBeginPlay, Tick, BeginPlay, Activate and Deactivate. --- src/dthinker.cpp | 16 +++++ src/p_mobj.cpp | 36 +++++++++++ src/p_user.cpp | 12 ++-- src/virtual.h | 107 +++++++++++++++++++++++++++++--- wadsrc/static/zscript/actor.txt | 5 +- wadsrc/static/zscript/base.txt | 2 + 6 files changed, 162 insertions(+), 16 deletions(-) diff --git a/src/dthinker.cpp b/src/dthinker.cpp index 06cd5dbfa..9478393c0 100644 --- a/src/dthinker.cpp +++ b/src/dthinker.cpp @@ -258,6 +258,14 @@ void DThinker::PostBeginPlay () { } +DEFINE_ACTION_FUNCTION(DThinker, PostBeginPlay) +{ + PARAM_SELF_PROLOGUE(DThinker); + self->VMSuperCall(); + self->PostBeginPlay(); + return 0; +} + void DThinker::PostSerialize() { } @@ -421,6 +429,14 @@ void DThinker::Tick () { } +DEFINE_ACTION_FUNCTION(DThinker, Tick) +{ + PARAM_SELF_PROLOGUE(DThinker); + self->VMSuperCall(); + self->Tick(); + return 0; +} + size_t DThinker::PropagateMark() { // Do not choke on partially initialized objects (as happens when loading a savegame fails) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 313052c6b..d1a273ef2 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4112,6 +4112,15 @@ void AActor::Tick () } } +DEFINE_ACTION_FUNCTION(AActor, Tick) +{ + PARAM_SELF_PROLOGUE(AActor); + self->VMSuperCall(); + self->Tick(); + return 0; +} + + //========================================================================== // // AActor :: CheckNoDelay @@ -4580,6 +4589,15 @@ void AActor::BeginPlay () } } +DEFINE_ACTION_FUNCTION(AActor, BeginPlay) +{ + PARAM_SELF_PROLOGUE(AActor); + self->VMSuperCall(); + self->BeginPlay(); + return 0; +} + + void AActor::PostBeginPlay () { if (Renderer != NULL) @@ -4635,6 +4653,15 @@ void AActor::Activate (AActor *activator) } } +DEFINE_ACTION_FUNCTION(AActor, Activate) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(activator, AActor); + self->VMSuperCall(); + self->Activate(activator); + return 0; +} + void AActor::Deactivate (AActor *activator) { if ((flags3 & MF3_ISMONSTER) && (health > 0 || (flags & MF_ICECORPSE))) @@ -4655,6 +4682,15 @@ void AActor::Deactivate (AActor *activator) } } +DEFINE_ACTION_FUNCTION(AActor, Deactivate) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(activator, AActor); + self->VMSuperCall(); + self->Deactivate(activator); + return 0; +} + // // P_RemoveMobj diff --git a/src/p_user.cpp b/src/p_user.cpp index 6f58f3cc8..ad0bb6ba4 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -1280,22 +1280,18 @@ void APlayerPawn::PlayRunning () void APlayerPawn::PlayAttacking () { - static int VIndex = -1; - if (VIndex < 0) VIndex = GetVirtualIndex(RUNTIME_CLASS(APlayerPawn), "PlayAttacking"); - // Without the type cast this picks the 'void *' assignment... + VINDEX(APlayerPawn, PlayAttacking); VMValue params[1] = { (DObject*)this }; VMFrameStack stack; - stack.Call(this->GetClass()->Virtuals[VIndex], params, 1, nullptr, 0, nullptr); + stack.Call(VFUNC, params, 1, nullptr, 0, nullptr); } void APlayerPawn::PlayAttacking2 () { - static int VIndex = -1; - if (VIndex < 0) VIndex = GetVirtualIndex(RUNTIME_CLASS(APlayerPawn), "PlayAttacking2"); - // Without the type cast this picks the 'void *' assignment... + VINDEX(APlayerPawn, PlayAttacking2); VMValue params[1] = { (DObject*)this }; VMFrameStack stack; - stack.Call(this->GetClass()->Virtuals[VIndex], params, 1, nullptr, 0, nullptr); + stack.Call(VFUNC, params, 1, nullptr, 0, nullptr); } void APlayerPawn::ThrowPoisonBag () diff --git a/src/virtual.h b/src/virtual.h index e0679df74..01541ceba 100644 --- a/src/virtual.h +++ b/src/virtual.h @@ -35,6 +35,9 @@ VMEXPORTED_NATIVES_START VMEXPORTED_NATIVES_FUNC(Destroy) VMEXPORTED_NATIVES_FUNC(Tick) VMEXPORTED_NATIVES_FUNC(PostBeginPlay) + VMEXPORTED_NATIVES_FUNC(BeginPlay) + VMEXPORTED_NATIVES_FUNC(Activate) + VMEXPORTED_NATIVES_FUNC(Deactivate) VMEXPORTED_NATIVES_END @@ -48,6 +51,15 @@ inline int GetVirtualIndex(PClass *cls, const char *funcname) return VIndex; } +#define VINDEX(cls, funcname) \ + static int VIndex = -1; \ + if (VIndex < 0) { \ + VIndex = GetVirtualIndex(RUNTIME_CLASS(cls), #funcname); \ + if (VIndex < 0) I_Error("Unable to find virtual function in " #cls, #funcname); \ + } + +#define VFUNC this->GetClass()->Virtuals[VIndex] + template class DVMObject : public T { @@ -84,28 +96,103 @@ public: { if (this->ObjectFlags & OF_SuperCall) { - this->ObjectFlags &= OF_SuperCall; + this->ObjectFlags &= ~OF_SuperCall; ExportedNatives::Get()->template Destroy(this); } else { - static int VIndex = -1; - if (VIndex < 0) VIndex = GetVirtualIndex(RUNTIME_CLASS(DObject), "Destroy"); + VINDEX(DObject, Destroy); // Without the type cast this picks the 'void *' assignment... VMValue params[1] = { (DObject*)this }; VMFrameStack stack; - stack.Call(this->GetClass()->Virtuals[VIndex], params, 1, nullptr, 0, nullptr); + stack.Call(VFUNC, params, 1, nullptr, 0, nullptr); } } void Tick() { - ExportedNatives::Get()->template Tick(this); + if (this->ObjectFlags & OF_SuperCall) + { + this->ObjectFlags &= ~OF_SuperCall; + ExportedNatives::Get()->template Tick(this); + } + else + { + VINDEX(DThinker, Tick); + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { (DObject*)this }; + VMFrameStack stack; + stack.Call(VFUNC, params, 1, nullptr, 0, nullptr); + } } void PostBeginPlay() { - ExportedNatives::Get()->template PostBeginPlay(this); + if (this->ObjectFlags & OF_SuperCall) + { + this->ObjectFlags &= ~OF_SuperCall; + ExportedNatives::Get()->template PostBeginPlay(this); + } + else + { + VINDEX(DThinker, PostBeginPlay); + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { (DObject*)this }; + VMFrameStack stack; + stack.Call(VFUNC, params, 1, nullptr, 0, nullptr); + } } + + void BeginPlay() + { + if (this->ObjectFlags & OF_SuperCall) + { + this->ObjectFlags &= ~OF_SuperCall; + ExportedNatives::Get()->template BeginPlay(this); + } + else + { + VINDEX(AActor, BeginPlay); + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { (DObject*)this }; + VMFrameStack stack; + stack.Call(VFUNC, params, 1, nullptr, 0, nullptr); + } + } + + void Activate(AActor *activator) + { + if (this->ObjectFlags & OF_SuperCall) + { + this->ObjectFlags &= ~OF_SuperCall; + ExportedNatives::Get()->template Activate(this, activator); + } + else + { + VINDEX(AActor, Activate); + // Without the type cast this picks the 'void *' assignment... + VMValue params[2] = { (DObject*)this, (DObject*)activator }; + VMFrameStack stack; + stack.Call(VFUNC, params, 2, nullptr, 0, nullptr); + } + } + + void Deactivate(AActor *activator) + { + if (this->ObjectFlags & OF_SuperCall) + { + this->ObjectFlags &= ~OF_SuperCall; + ExportedNatives::Get()->template Deactivate(this, activator); + } + else + { + VINDEX(AActor, Deactivate); + // Without the type cast this picks the 'void *' assignment... + VMValue params[2] = { (DObject*)this, (DObject*)activator }; + VMFrameStack stack; + stack.Call(VFUNC, params, 2, nullptr, 0, nullptr); + } + } + }; template @@ -130,7 +217,13 @@ VMEXPORT_NATIVES_END(DObject) VMEXPORT_NATIVES_START(DThinker, DObject) VMEXPORT_NATIVES_FUNC(Tick) VMEXPORT_NATIVES_FUNC(PostBeginPlay) - VMEXPORT_NATIVES_END(DThinker) +VMEXPORT_NATIVES_END(DThinker) + +VMEXPORT_NATIVES_START(AActor, DThinker) + VMEXPORT_NATIVES_FUNC(BeginPlay) + VMEXPORT_NATIVES_FUNC(Activate) + VMEXPORT_NATIVES_FUNC(Deactivate) +VMEXPORT_NATIVES_END(AActor) /* VMEXPORT_NATIVES_START(AActor, DThinker) diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 99ca89c8e..53f047513 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -62,7 +62,10 @@ class Actor : Thinker native { return sin(fb * (180./32)) * 8; } - + + virtual native void BeginPlay(); + virtual native void Activate(Actor activator); + virtual native void Deactivate(Actor activator); native static readonly GetDefaultByType(class cls); native static double deltaangle(double ang1, double ang2); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 1089476a1..7a2790726 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -10,6 +10,8 @@ class Object native class Thinker : Object native { + virtual native void Tick(); + virtual native void PostBeginPlay(); } class ThinkerIterator : Object native From 360436c2013bb2b9a291219f9a1b28546589d665 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 21 Nov 2016 19:09:58 +0100 Subject: [PATCH 066/185] - scriptified the scripted marines. - fixed symbol name generation for native functions. - moved PrintableName to VMFunction so that native functions also have this information. --- src/CMakeLists.txt | 1 - src/g_doom/a_doomglobal.h | 15 - src/g_doom/a_doommisc.cpp | 3 - src/g_doom/a_scriptedmarine.cpp | 654 ------------------ src/info.h | 2 +- src/p_acs.cpp | 50 +- src/p_actionfunctions.cpp | 2 +- src/p_mobj.cpp | 5 +- src/p_pspr.cpp | 2 +- src/p_states.cpp | 9 +- src/scripting/codegeneration/codegen.cpp | 9 + src/scripting/thingdef_data.cpp | 20 +- src/scripting/vm/vm.h | 7 +- src/scripting/vm/vmbuilder.cpp | 2 +- src/scripting/vm/vmdisasm.cpp | 4 +- src/scripting/zscript/zcc-parse.lemon | 4 +- src/scripting/zscript/zcc_compile.cpp | 4 +- src/virtual.h | 2 +- wadsrc/static/zscript/actor.txt | 4 +- wadsrc/static/zscript/doom/scriptedmarine.txt | 615 ++++++++++++++-- 20 files changed, 658 insertions(+), 756 deletions(-) delete mode 100644 src/g_doom/a_scriptedmarine.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 87c875d16..19179a0c4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -867,7 +867,6 @@ set( NOT_COMPILED_SOURCE_FILES sc_man_scanner.h sc_man_scanner.re g_doom/a_painelemental.cpp - g_doom/a_scriptedmarine.cpp g_heretic/a_chicken.cpp g_heretic/a_dsparil.cpp g_heretic/a_hereticartifacts.cpp diff --git a/src/g_doom/a_doomglobal.h b/src/g_doom/a_doomglobal.h index 31d41f6c0..73e3d3239 100644 --- a/src/g_doom/a_doomglobal.h +++ b/src/g_doom/a_doomglobal.h @@ -7,21 +7,6 @@ class AScriptedMarine : public AActor { DECLARE_CLASS (AScriptedMarine, AActor) public: - enum EMarineWeapon - { - WEAPON_Dummy, - WEAPON_Fist, - WEAPON_BerserkFist, - WEAPON_Chainsaw, - WEAPON_Pistol, - WEAPON_Shotgun, - WEAPON_SuperShotgun, - WEAPON_Chaingun, - WEAPON_RocketLauncher, - WEAPON_PlasmaRifle, - WEAPON_Railgun, - WEAPON_BFG - }; void Activate (AActor *activator); void Deactivate (AActor *activator); diff --git a/src/g_doom/a_doommisc.cpp b/src/g_doom/a_doommisc.cpp index ca13ac7ee..40c8e2f8d 100644 --- a/src/g_doom/a_doommisc.cpp +++ b/src/g_doom/a_doommisc.cpp @@ -9,7 +9,6 @@ #include "gstrings.h" #include "g_level.h" #include "p_enemy.h" -#include "a_doomglobal.h" #include "a_specialspot.h" #include "templates.h" #include "m_bbox.h" @@ -21,5 +20,3 @@ // Include all the other Doom stuff here to reduce compile time #include "a_painelemental.cpp" -#include "a_scriptedmarine.cpp" - diff --git a/src/g_doom/a_scriptedmarine.cpp b/src/g_doom/a_scriptedmarine.cpp deleted file mode 100644 index e270af6b5..000000000 --- a/src/g_doom/a_scriptedmarine.cpp +++ /dev/null @@ -1,654 +0,0 @@ -/* -#include "actor.h" -#include "p_enemy.h" -#include "a_action.h" -#include "m_random.h" -#include "p_local.h" -#include "a_doomglobal.h" -#include "s_sound.h" -#include "r_data/r_translate.h" -#include "vm.h" -#include "g_level.h" -*/ - -#define MARINE_PAIN_CHANCE 160 - -static FRandom pr_m_refire ("SMarineRefire"); -static FRandom pr_m_punch ("SMarinePunch"); -static FRandom pr_m_gunshot ("SMarineGunshot"); -static FRandom pr_m_saw ("SMarineSaw"); -static FRandom pr_m_fireshotgun2 ("SMarineFireSSG"); - -IMPLEMENT_CLASS(AScriptedMarine, false, false, false, false) - -void AScriptedMarine::Serialize(FSerializer &arc) -{ - Super::Serialize (arc); - - auto def = (AScriptedMarine*)GetDefault(); - - arc.Sprite("spriteoverride", SpriteOverride, &def->SpriteOverride) - ("currentweapon", CurrentWeapon, def->CurrentWeapon); -} - -void AScriptedMarine::Activate (AActor *activator) -{ - if (flags2 & MF2_DORMANT) - { - flags2 &= ~MF2_DORMANT; - tics = 1; - } -} - -void AScriptedMarine::Deactivate (AActor *activator) -{ - if (!(flags2 & MF2_DORMANT)) - { - flags2 |= MF2_DORMANT; - tics = -1; - } -} - -bool AScriptedMarine::GetWeaponStates(int weap, FState *&melee, FState *&missile) -{ - static ENamedName WeaponNames[] = - { - NAME_None, - NAME_Fist, - NAME_Berserk, - NAME_Chainsaw, - NAME_Pistol, - NAME_Shotgun, - NAME_SSG, - NAME_Chaingun, - NAME_Rocket, - NAME_Plasma, - NAME_Railgun, - NAME_BFG - }; - - if (weap < WEAPON_Dummy || weap > WEAPON_BFG) weap = WEAPON_Dummy; - - melee = FindState(NAME_Melee, WeaponNames[weap], true); - missile = FindState(NAME_Missile, WeaponNames[weap], true); - - return melee != NULL || missile != NULL; -} - -void AScriptedMarine::BeginPlay () -{ - Super::BeginPlay (); - - // Set the current weapon - for(int i=WEAPON_Dummy; i<=WEAPON_BFG; i++) - { - FState *melee, *missile; - if (GetWeaponStates(i, melee, missile)) - { - if (melee == MeleeState && missile == MissileState) - { - CurrentWeapon = i; - } - } - } -} - -void AScriptedMarine::Tick () -{ - Super::Tick (); - - // Override the standard sprite, if desired - if (SpriteOverride != 0 && sprite == SpawnState->sprite) - { - sprite = SpriteOverride; - } - - if (special1 != 0) - { - if (CurrentWeapon == WEAPON_SuperShotgun) - { // Play SSG reload sounds - int ticks = level.maptime - special1; - if (ticks < 47) - { - switch (ticks) - { - case 14: - S_Sound (this, CHAN_WEAPON, "weapons/sshoto", 1, ATTN_NORM); - break; - case 28: - S_Sound (this, CHAN_WEAPON, "weapons/sshotl", 1, ATTN_NORM); - break; - case 41: - S_Sound (this, CHAN_WEAPON, "weapons/sshotc", 1, ATTN_NORM); - break; - } - } - else - { - special1 = 0; - } - } - else - { // Wait for a long refire time - if (level.maptime >= special1) - { - special1 = 0; - } - else - { - flags |= MF_JUSTATTACKED; - } - } - } -} - -//============================================================================ -// -// A_M_Refire -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_M_Refire) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_BOOL_DEF(ignoremissile); - - if (self->target == NULL || self->target->health <= 0) - { - if (self->MissileState && pr_m_refire() < 160) - { // 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 0; - } - } - self->SetState (self->state + 1); - return 0; - } - if (((ignoremissile || self->MissileState == NULL) && !self->CheckMeleeRange ()) || - !P_CheckSight (self, self->target) || - pr_m_refire() < 4) // Small chance of stopping even when target not dead - { - self->SetState (self->state + 1); - } - return 0; -} - -//============================================================================ -// -// A_M_SawRefire -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_M_SawRefire) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (self->target == NULL || self->target->health <= 0) - { - self->SetState (self->state + 1); - return 0; - } - if (!self->CheckMeleeRange ()) - { - self->SetState (self->state + 1); - } - return 0; -} - -//============================================================================ -// -// A_MarineNoise -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_MarineNoise) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (static_cast(self)->CurrentWeapon == AScriptedMarine::WEAPON_Chainsaw) - { - S_Sound (self, CHAN_WEAPON, "weapons/sawidle", 1, ATTN_NORM); - } - return 0; -} - -//============================================================================ -// -// A_MarineChase -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_MarineChase) -{ - PARAM_SELF_PROLOGUE(AActor); - CALL_ACTION(A_MarineNoise, self); - A_Chase (stack, self); - return 0; -} - -//============================================================================ -// -// A_MarineLook -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_MarineLook) -{ - PARAM_SELF_PROLOGUE(AActor); - CALL_ACTION(A_MarineNoise, self); - CALL_ACTION(A_Look, self); - return 0; -} - -//============================================================================ -// -// A_M_Saw -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_M_Saw) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_SOUND_DEF (fullsound) - PARAM_SOUND_DEF (hitsound) - PARAM_INT_DEF (damage) - PARAM_CLASS_DEF (pufftype, AActor) - - if (self->target == NULL) - return 0; - - if (pufftype == NULL) - { - pufftype = PClass::FindActor(NAME_BulletPuff); - } - if (damage == 0) - { - damage = 2; - } - - A_FaceTarget (self); - if (self->CheckMeleeRange ()) - { - DAngle angle; - FTranslatedLineTarget t; - - damage *= (pr_m_saw()%10+1); - angle = self->Angles.Yaw + pr_m_saw.Random2() * (5.625 / 256); - - P_LineAttack (self, angle, SAWRANGE, - P_AimLineAttack (self, angle, SAWRANGE), damage, - NAME_Melee, pufftype, false, &t); - - if (!t.linetarget) - { - S_Sound (self, CHAN_WEAPON, fullsound, 1, ATTN_NORM); - return 0; - } - S_Sound (self, CHAN_WEAPON, hitsound, 1, ATTN_NORM); - - // turn to face target - angle = t.angleFromSource; - DAngle anglediff = deltaangle(self->Angles.Yaw, angle); - - if (anglediff < 0.0) - { - if (anglediff < -4.5) - self->Angles.Yaw = angle + 90.0 / 21; - else - self->Angles.Yaw -= 4.5; - } - else - { - if (anglediff > 4.5) - self->Angles.Yaw = angle - 90.0 / 21; - else - self->Angles.Yaw += 4.5; - } - } - else - { - S_Sound (self, CHAN_WEAPON, fullsound, 1, ATTN_NORM); - } - //A_Chase (self); - return 0; -} - -//============================================================================ -// -// A_M_Punch -// -//============================================================================ - -static void MarinePunch(AActor *self, int damagemul) -{ - DAngle angle; - int damage; - DAngle pitch; - FTranslatedLineTarget t; - - if (self->target == NULL) - return; - - damage = ((pr_m_punch()%10+1) << 1) * damagemul; - - A_FaceTarget (self); - angle = self->Angles.Yaw + pr_m_punch.Random2() * (5.625 / 256); - pitch = P_AimLineAttack (self, angle, MELEERANGE); - P_LineAttack (self, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff, true, &t); - - // turn to face target - if (t.linetarget) - { - S_Sound (self, CHAN_WEAPON, "*fist", 1, ATTN_NORM); - self->Angles.Yaw = t.angleFromSource; - } -} - -DEFINE_ACTION_FUNCTION(AActor, A_M_Punch) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_INT(mult); - - MarinePunch(self, mult); - return 0; -} - -//============================================================================ -// -// P_GunShot2 -// -//============================================================================ - -void P_GunShot2 (AActor *mo, bool accurate, DAngle pitch, PClassActor *pufftype) -{ - DAngle angle; - int damage; - - damage = 5*(pr_m_gunshot()%3+1); - angle = mo->Angles.Yaw; - - if (!accurate) - { - angle += pr_m_gunshot.Random2() * (5.625 / 256); - } - - P_LineAttack (mo, angle, MISSILERANGE, pitch, damage, NAME_Hitscan, pufftype); -} - -//============================================================================ -// -// A_M_FirePistol -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_M_FirePistol) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_BOOL(accurate); - - 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->Angles.Yaw, MISSILERANGE), - PClass::FindActor(NAME_BulletPuff)); - return 0; -} - -//============================================================================ -// -// A_M_FireShotgun -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_M_FireShotgun) -{ - PARAM_SELF_PROLOGUE(AActor); - - DAngle pitch; - - if (self->target == NULL) - return 0; - - S_Sound (self, CHAN_WEAPON, "weapons/shotgf", 1, ATTN_NORM); - A_FaceTarget (self); - pitch = P_AimLineAttack (self, self->Angles.Yaw, MISSILERANGE); - for (int i = 0; i < 7; ++i) - { - P_GunShot2 (self, false, pitch, PClass::FindActor(NAME_BulletPuff)); - } - self->special1 = level.maptime + 27; - return 0; -} - -//============================================================================ -// -// A_M_CheckAttack -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_M_CheckAttack) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (self->special1 != 0 || self->target == NULL) - { - self->SetState (self->FindState("SkipAttack")); - } - else - { - A_FaceTarget (self); - } - return 0; -} - -//============================================================================ -// -// A_M_FireShotgun2 -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_M_FireShotgun2) -{ - PARAM_SELF_PROLOGUE(AActor); - - DAngle pitch; - - if (self->target == NULL) - return 0; - - S_Sound (self, CHAN_WEAPON, "weapons/sshotf", 1, ATTN_NORM); - A_FaceTarget (self); - pitch = P_AimLineAttack (self, self->Angles.Yaw, MISSILERANGE); - for (int i = 0; i < 20; ++i) - { - int damage = 5*(pr_m_fireshotgun2()%3+1); - DAngle angle = self->Angles.Yaw + pr_m_fireshotgun2.Random2() * (11.25 / 256); - - P_LineAttack (self, angle, MISSILERANGE, - pitch + pr_m_fireshotgun2.Random2() * (7.097 / 256), damage, - NAME_Hitscan, NAME_BulletPuff); - } - self->special1 = level.maptime; - return 0; -} - -//============================================================================ -// -// A_M_FireCGun -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_M_FireCGun) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_BOOL(accurate); - - 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->Angles.Yaw, MISSILERANGE), - PClass::FindActor(NAME_BulletPuff)); - return 0; -} - -//============================================================================ -// -// A_M_FireMissile -// -// Giving a marine a rocket launcher is probably a bad idea unless you pump -// up his health, because he's just as likely to kill himself as he is to -// kill anything else with it. -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_M_FireMissile) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (self->target == NULL) - return 0; - - if (self->CheckMeleeRange ()) - { // If too close, punch it - MarinePunch(self, 1); - } - else - { - A_FaceTarget (self); - P_SpawnMissile (self, self->target, PClass::FindActor("Rocket")); - } - return 0; -} - -//============================================================================ -// -// A_M_FireRailgun -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_M_FireRailgun) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (self->target == NULL) - return 0; - - CALL_ACTION(A_MonsterRail, self); - self->special1 = level.maptime + 50; - return 0; -} - -//============================================================================ -// -// A_M_FirePlasma -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_M_FirePlasma) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (self->target == NULL) - return 0; - - A_FaceTarget (self); - P_SpawnMissile (self, self->target, PClass::FindActor("PlasmaBall")); - self->special1 = level.maptime + 20; - return 0; -} - -//============================================================================ -// -// A_M_BFGsound -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_M_BFGsound) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (self->target == NULL) - return 0; - - if (self->special1 != 0) - { - self->SetState (self->SeeState); - } - else - { - A_FaceTarget (self); - S_Sound (self, CHAN_WEAPON, "weapons/bfgf", 1, ATTN_NORM); - // Don't interrupt the firing sequence - self->PainChance = 0; - } - return 0; -} - -//============================================================================ -// -// A_M_FireBFG -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_M_FireBFG) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (self->target == NULL) - return 0; - - A_FaceTarget (self); - P_SpawnMissile (self, self->target, PClass::FindActor("BFGBall")); - self->special1 = level.maptime + 30; - self->PainChance = MARINE_PAIN_CHANCE; - return 0; -} - -//--------------------------------------------------------------------------- - -void AScriptedMarine::SetWeapon (EMarineWeapon type) -{ - if (GetWeaponStates(type, MeleeState, MissileState)) - { - static const char *classes[] = { - "ScriptedMarine", - "MarineFist", - "MarineBerserk", - "MarineChainsaw", - "MarinePistol", - "MarineShotgun", - "MarineSSG", - "MarineChaingun", - "MarineRocket", - "MarinePlasma", - "MarineRailgun", - "MarineBFG" - }; - - const PClass *cls = PClass::FindClass(classes[type]); - if (cls != NULL) - DecalGenerator = GetDefaultByType(cls)->DecalGenerator; - else - DecalGenerator = NULL; - } -} - -void AScriptedMarine::SetSprite (PClassActor *source) -{ - if (source == NULL) - { // A valid actor class wasn't passed, so use the standard sprite - SpriteOverride = sprite = GetClass()->OwnedStates[0].sprite; - // Copy the standard scaling - Scale = GetDefault()->Scale; - } - else - { // Use the same sprite and scaling the passed class spawns with - SpriteOverride = sprite = GetDefaultByType (source)->SpawnState->sprite; - Scale = GetDefaultByType(source)->Scale; - } -} diff --git a/src/info.h b/src/info.h index 5af51f34b..4f2b4b293 100644 --- a/src/info.h +++ b/src/info.h @@ -359,7 +359,7 @@ struct FStateLabelStorage } } - FState *GetState(int pos, PClassActor *cls); + FState *GetState(int pos, PClassActor *cls, bool exact = false); }; extern FStateLabelStorage StateLabels; diff --git a/src/p_acs.cpp b/src/p_acs.cpp index da8f76d7f..96e20d022 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -58,7 +58,6 @@ #include "sbar.h" #include "m_swap.h" #include "a_sharedglobal.h" -#include "a_doomglobal.h" #include "a_strifeglobal.h" #include "v_video.h" #include "w_wad.h" @@ -6110,6 +6109,34 @@ static bool CharArrayParms(int &capacity, int &offset, int &a, int *Stack, int & return true; } +static void SetMarineWeapon(AActor *marine, int weapon) +{ + static VMFunction *smw = nullptr; + if (smw == nullptr) + { + auto cls = PClass::FindActor("ScriptedMarine"); + auto func = dyn_cast(cls->Symbols.FindSymbol("SetWeapon", true)); + smw = func->Variants[0].Implementation; + } + VMValue params[2] = { marine, weapon }; + VMFrameStack stack; + stack.Call(smw, params, 2, nullptr, 0, nullptr); +} + +static void SetMarineSprite(AActor *marine, PClassActor *source) +{ + static VMFunction *sms = nullptr; + if (sms == nullptr) + { + auto cls = PClass::FindActor("ScriptedMarine"); + auto func = dyn_cast(cls->Symbols.FindSymbol("SetSprite", true)); + sms = func->Variants[0].Implementation; + } + VMValue params[2] = { marine, source }; + VMFrameStack stack; + stack.Call(sms, params, 2, nullptr, 0, nullptr); +} + int DLevelScript::RunScript () { DACSThinker *controller = DACSThinker::ActiveThinker; @@ -8946,20 +8973,19 @@ scriptwait: case PCD_SETMARINEWEAPON: if (STACK(2) != 0) { - AScriptedMarine *marine; - TActorIterator iterator (STACK(2)); + AActor *marine; + NActorIterator iterator("ScriptedMarine", STACK(2)); while ((marine = iterator.Next()) != NULL) { - marine->SetWeapon ((AScriptedMarine::EMarineWeapon)STACK(1)); + SetMarineWeapon(marine, STACK(1)); } } else { - if (activator != NULL && activator->IsKindOf (RUNTIME_CLASS(AScriptedMarine))) + if (activator != nullptr && activator->IsKindOf (PClass::FindClass("ScriptedMarine"))) { - barrier_cast(activator)->SetWeapon ( - (AScriptedMarine::EMarineWeapon)STACK(1)); + SetMarineWeapon(activator, STACK(1)); } } sp -= 2; @@ -8973,19 +8999,19 @@ scriptwait: { if (STACK(2) != 0) { - AScriptedMarine *marine; - TActorIterator iterator (STACK(2)); + AActor *marine; + NActorIterator iterator("ScriptedMarine", STACK(2)); while ((marine = iterator.Next()) != NULL) { - marine->SetSprite (type); + SetMarineSprite(marine, type); } } else { - if (activator != NULL && activator->IsKindOf (RUNTIME_CLASS(AScriptedMarine))) + if (activator != nullptr && activator->IsKindOf(PClass::FindClass("ScriptedMarine"))) { - barrier_cast(activator)->SetSprite (type); + SetMarineSprite(activator, type); } } } diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 37a2d533e..54485d653 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -143,7 +143,7 @@ bool ACustomInventory::CallStateChain (AActor *actor, FState *state) // If an unsafe function (i.e. one that accesses user variables) is being detected, print a warning once and remove the bogus function. We may not call it because that would inevitably crash. auto owner = FState::StaticFindStateOwner(state); Printf(TEXTCOLOR_RED "Unsafe state call in state %s.%d to %s which accesses user variables. The action function has been removed from this state\n", - owner->TypeName.GetChars(), state - owner->OwnedStates, static_cast(state->ActionFunc)->PrintableName.GetChars()); + owner->TypeName.GetChars(), state - owner->OwnedStates, state->ActionFunc->PrintableName.GetChars()); state->ActionFunc = nullptr; } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index d1a273ef2..1066d985a 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -315,10 +315,11 @@ void AActor::InitNativeFields() meta->AddNativeField("TelefogDestType", TypeActorClass, myoffsetof(AActor, TeleFogDestType)); meta->AddNativeField("SpawnState", TypeState, myoffsetof(AActor, SpawnState), VARF_ReadOnly); meta->AddNativeField("SeeState", TypeState, myoffsetof(AActor, SeeState), VARF_ReadOnly); - meta->AddNativeField("MeleeState", TypeState, myoffsetof(AActor, MeleeState), VARF_ReadOnly); - meta->AddNativeField("MissileState", TypeState, myoffsetof(AActor, MissileState), VARF_ReadOnly); + meta->AddNativeField("MeleeState", TypeState, myoffsetof(AActor, MeleeState)); + meta->AddNativeField("MissileState", TypeState, myoffsetof(AActor, MissileState)); //int ConversationRoot; // THe root of the current dialogue //FStrifeDialogueNode *Conversation; // [RH] The dialogue to show when this actor is "used." + meta->AddNativeField("DecalGenerator", NewPointer(TypeVoid), myoffsetof(AActor, DecalGenerator)); //FDecalBase *DecalGenerator; // synthesize a symbol for each flag from the flag name tables to avoid redundant declaration of them. diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 3bc2dfbe1..157badd87 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -388,7 +388,7 @@ void DPSprite::SetState(FState *newstate, bool pending) // If an unsafe function (i.e. one that accesses user variables) is being detected, print a warning once and remove the bogus function. We may not call it because that would inevitably crash. auto owner = FState::StaticFindStateOwner(newstate); Printf(TEXTCOLOR_RED "Unsafe state call in state %s.%d to %s which accesses user variables. The action function has been removed from this state\n", - owner->TypeName.GetChars(), newstate - owner->OwnedStates, static_cast(newstate->ActionFunc)->PrintableName.GetChars()); + owner->TypeName.GetChars(), newstate - owner->OwnedStates, newstate->ActionFunc->PrintableName.GetChars()); newstate->ActionFunc = nullptr; } if (newstate->CallAction(Owner->mo, Caller, &stp, &nextstate)) diff --git a/src/p_states.cpp b/src/p_states.cpp index a49d30af2..fde7a0276 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -289,7 +289,7 @@ static bool VerifyJumpTarget(PClassActor *cls, FState *CallingState, int index) // //========================================================================== -FState *FStateLabelStorage::GetState(int pos, PClassActor *cls) +FState *FStateLabelStorage::GetState(int pos, PClassActor *cls, bool exact) { if (pos > 0x10000000) { @@ -322,7 +322,7 @@ FState *FStateLabelStorage::GetState(int pos, PClassActor *cls) else if (cls != nullptr) { FName *labels = (FName*)&Storage[pos + sizeof(int)]; - return cls->FindState(val, labels, false); + return cls->FindState(val, labels, exact); } } return nullptr; @@ -337,8 +337,9 @@ FState *FStateLabelStorage::GetState(int pos, PClassActor *cls) DEFINE_ACTION_FUNCTION(AActor, FindState) { PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE(newstate); - ACTION_RETURN_STATE(newstate); + PARAM_INT(newstate); + PARAM_BOOL_DEF(exact) + ACTION_RETURN_STATE(StateLabels.GetState(newstate, self->GetClass(), exact)); } // same as above but context aware. diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index cae95da34..8d44e5c18 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -230,6 +230,7 @@ static PSymbol *FindBuiltinFunction(FName funcname, VMNativeFunction::NativeCall { PSymbolVMFunction *symfunc = new PSymbolVMFunction(funcname); VMNativeFunction *calldec = new VMNativeFunction(func, funcname); + calldec->PrintableName = funcname.GetChars(); symfunc->Function = calldec; sym = symfunc; GlobalSymbols.AddSymbol(sym); @@ -1428,6 +1429,14 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx) delete this; return x; } + else if (ValueType == TypeSpriteID && basex->IsInteger()) + { + basex->ValueType = TypeSpriteID; + auto x = basex; + basex = nullptr; + delete this; + return x; + } else if (ValueType == TypeStateLabel) { if (basex->ValueType == TypeNullPtr) diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 76770272d..cdb896902 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -581,17 +581,21 @@ AFuncDesc *FindFunction(PStruct *cls, const char * string) { for (int i = 0; i < 2; i++) { - // Since many functions have been declared with Actor as owning class, despited being members of something else, let's hack around this until they have been fixed or exported. + // Since many functions have been declared with Actor as owning class, despite being members of something else, let's hack around this until they have been fixed or exported. // Since most of these are expected to be scriptified anyway, there's no point fixing them all before they get exported. - if (i == 1 && !cls->IsKindOf(RUNTIME_CLASS(PClassActor))) break; + if (i == 1) + { + if (!cls->IsKindOf(RUNTIME_CLASS(PClassActor))) break; + cls = RUNTIME_CLASS(AActor); + } - FStringf fullname("%s_%s", i == 0 ? cls->TypeName.GetChars() : "Actor", string); int min = 0, max = AFTable.Size() - 1; while (min <= max) { int mid = (min + max) / 2; - int lexval = stricmp(fullname, AFTable[mid].Name + 1); + int lexval = stricmp(cls->TypeName.GetChars(), AFTable[mid].ClassName + 1); + if (lexval == 0) lexval = stricmp(string, AFTable[mid].FuncName); if (lexval == 0) { return &AFTable[mid]; @@ -641,7 +645,10 @@ static int propcmp(const void * a, const void * b) static int funccmp(const void * a, const void * b) { - return stricmp(((AFuncDesc*)a)->Name + 1, ((AFuncDesc*)b)->Name + 1); // +1 to get past the prefix letter of the native class name, which gets omitted by the FName for the class. + // +1 to get past the prefix letter of the native class name, which gets omitted by the FName for the class. + int res = stricmp(((AFuncDesc*)a)->ClassName + 1, ((AFuncDesc*)b)->ClassName + 1); + if (res == 0) res = stricmp(((AFuncDesc*)a)->FuncName, ((AFuncDesc*)b)->FuncName); + return res; } //========================================================================== @@ -700,7 +707,8 @@ void InitThingdef() { AFuncDesc *afunc = (AFuncDesc *)*probe; assert(afunc->VMPointer != NULL); - *(afunc->VMPointer) = new VMNativeFunction(afunc->Function, afunc->Name); + *(afunc->VMPointer) = new VMNativeFunction(afunc->Function, afunc->FuncName); + (*(afunc->VMPointer))->PrintableName.Format("%s.%s [Native]", afunc->ClassName+1, afunc->FuncName); AFTable.Push(*afunc); } AFTable.ShrinkToFit(); diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index ad42ee1dd..7d56b32db 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -669,6 +669,7 @@ public: int VirtualIndex = -1; FName Name; TArray DefaultArgs; + FString PrintableName; // so that the VM can print meaningful info if something in this function goes wrong. class PPrototype *Proto; @@ -822,7 +823,6 @@ public: VM_UHALF 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 - FString PrintableName; // so that the VM can print meaningful info if something in this function goes wrong. TArray SpecialInits; // list of all contents on the extra stack which require construction and destruction void InitExtra(void *addr); @@ -1015,7 +1015,8 @@ typedef int(*actionf_p)(VMFrameStack *stack, VMValue *param, TArray &de struct AFuncDesc { - const char *Name; + const char *ClassName; + const char *FuncName; actionf_p Function; VMNativeFunction **VMPointer; }; @@ -1037,7 +1038,7 @@ struct AFuncDesc #define DEFINE_ACTION_FUNCTION(cls, name) \ static int AF_##cls##_##name(VM_ARGS); \ VMNativeFunction *cls##_##name##_VMPtr; \ - static const AFuncDesc cls##_##name##_Hook = { #cls "_" #name, AF_##cls##_##name, &cls##_##name##_VMPtr }; \ + static const AFuncDesc cls##_##name##_Hook = { #cls, #name, AF_##cls##_##name, &cls##_##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_##cls##_##name(VM_ARGS) diff --git a/src/scripting/vm/vmbuilder.cpp b/src/scripting/vm/vmbuilder.cpp index 04339f6eb..74b7a3400 100644 --- a/src/scripting/vm/vmbuilder.cpp +++ b/src/scripting/vm/vmbuilder.cpp @@ -887,7 +887,7 @@ void FFunctionBuildList::Build() catch (CRecoverableError &err) { // catch errors from the code generator and pring something meaningful. - item.Code->ScriptPosition.Message(MSG_ERROR, "%s in %s", err.GetMessage(), item.PrintableName); + item.Code->ScriptPosition.Message(MSG_ERROR, "%s in %s", err.GetMessage(), item.PrintableName.GetChars()); } } delete item.Code; diff --git a/src/scripting/vm/vmdisasm.cpp b/src/scripting/vm/vmdisasm.cpp index d8fc16433..cba67cbdc 100644 --- a/src/scripting/vm/vmdisasm.cpp +++ b/src/scripting/vm/vmdisasm.cpp @@ -261,7 +261,6 @@ void VMDumpConstants(FILE *out, const VMScriptFunction *func) void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction *func) { VMFunction *callfunc; - const char *callname; const char *name; int col; int mode; @@ -497,8 +496,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction } else if (code[i].op == OP_CALL_K || code[i].op == OP_TAIL_K) { - callname = callfunc->IsKindOf(RUNTIME_CLASS(VMScriptFunction)) ? static_cast(callfunc)->PrintableName : callfunc->Name != NAME_None ? callfunc->Name : "[anonfunc]"; - printf_wrapper(out, " [%s]\n", callname); + printf_wrapper(out, " [%s]\n", callfunc->PrintableName.GetChars()); } else { diff --git a/src/scripting/zscript/zcc-parse.lemon b/src/scripting/zscript/zcc-parse.lemon index 3380959ec..80057724c 100644 --- a/src/scripting/zscript/zcc-parse.lemon +++ b/src/scripting/zscript/zcc-parse.lemon @@ -787,11 +787,11 @@ type_list(X) ::= type_list(A) COMMA type_or_array(B). { X = A; /*X-overwrites-A* type_list_or_void(X) ::= VOID. { X = NULL; } type_list_or_void(X) ::= type_list(X). -array_size_expr(X) ::= LBRACKET opt_expr(A) RBRACKET. +array_size_expr(X) ::= LBRACKET(L) opt_expr(A) RBRACKET. { if (A == NULL) { - NEW_AST_NODE(Expression,nil,A); + NEW_AST_NODE(Expression,nil,L.SourceLoc); nil->Operation = PEX_Nil; nil->Type = NULL; X = nil; diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 27a02a919..9682066b9 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2304,14 +2304,14 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool { if (vindex == -1) { - Error(p, "Attempt to override non-existent virtual function %s", FName(f->Name).GetChars()); + Error(f, "Attempt to override non-existent virtual function %s", FName(f->Name).GetChars()); } else { auto oldfunc = clstype->Virtuals[vindex]; if (oldfunc->Final) { - Error(p, "Attempt to override final function %s", FName(f->Name).GetChars()); + Error(f, "Attempt to override final function %s", FName(f->Name).GetChars()); } clstype->Virtuals[vindex] = sym->Variants[0].Implementation; sym->Variants[0].Implementation->VirtualIndex = vindex; diff --git a/src/virtual.h b/src/virtual.h index 01541ceba..8842eb891 100644 --- a/src/virtual.h +++ b/src/virtual.h @@ -55,7 +55,7 @@ inline int GetVirtualIndex(PClass *cls, const char *funcname) static int VIndex = -1; \ if (VIndex < 0) { \ VIndex = GetVirtualIndex(RUNTIME_CLASS(cls), #funcname); \ - if (VIndex < 0) I_Error("Unable to find virtual function in " #cls, #funcname); \ + if (VIndex < 0) I_Error("Unable to find virtual function %s in " #cls, #funcname); \ } #define VFUNC this->GetClass()->Virtuals[VIndex] diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 53f047513..87d2f8759 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -115,7 +115,7 @@ class Actor : Thinker native native void NewChaseDir(); native bool CheckMissileRange(); native bool SetState(state st, bool nofunction = false); - native state FindState(statelabel st); // do we need exact later? + native state FindState(statelabel st, bool exact = false); // do we need exact later? bool SetStateLabel(statelabel st, bool nofunction = false) { return SetState(FindState(st), nofunction); } native action state ResolveState(statelabel st); // this one, unlike FindState, is context aware. native void LinkToWorld(); @@ -369,8 +369,6 @@ class Actor : Thinker native native void A_Detonate(); native bool A_CallSpecial(int special, int arg1=0, int arg2=0, int arg3=0, int arg4=0, int arg5=0); - native void A_M_Saw(sound fullsound = "weapons/sawfull", sound hitsound = "weapons/sawhit", int damage = 2, class pufftype = "BulletPuff"); - native void A_ActiveSound(); native void A_FastChase(); diff --git a/wadsrc/static/zscript/doom/scriptedmarine.txt b/wadsrc/static/zscript/doom/scriptedmarine.txt index 7a82513cb..1096f24b5 100644 --- a/wadsrc/static/zscript/doom/scriptedmarine.txt +++ b/wadsrc/static/zscript/doom/scriptedmarine.txt @@ -1,8 +1,35 @@ // Scriptable marine ------------------------------------------------------- -class ScriptedMarine : Actor native +class ScriptedMarine : Actor { + const MARINE_PAIN_CHANCE = 160; + + enum EMarineWeapon + { + WEAPON_Dummy, + WEAPON_Fist, + WEAPON_BerserkFist, + WEAPON_Chainsaw, + WEAPON_Pistol, + WEAPON_Shotgun, + WEAPON_SuperShotgun, + WEAPON_Chaingun, + WEAPON_RocketLauncher, + WEAPON_PlasmaRifle, + WEAPON_Railgun, + WEAPON_BFG + }; + + struct WeaponStates + { + state melee; + state missile; + } + + int CurrentWeapon; + SpriteID SpriteOverride; + Default { Health 100; @@ -10,7 +37,7 @@ class ScriptedMarine : Actor native Height 56; Mass 100; Speed 8; - Painchance 160; + Painchance MARINE_PAIN_CHANCE; MONSTER; -COUNTKILL Translation 0; @@ -19,23 +46,6 @@ class ScriptedMarine : Actor native PainSound "*pain50"; } - native void A_M_Refire (bool ignoremissile=false); - native void A_M_CheckAttack (); - native void A_MarineChase (); - native void A_MarineLook (); - native void A_MarineNoise (); - native void A_M_Punch (int force); - native void A_M_SawRefire (); - native void A_M_FirePistol (bool accurate); - native void A_M_FireShotgun (); - native void A_M_FireShotgun2 (); - native void A_M_FireCGun(bool accurate); - native void A_M_FireMissile (); - native void A_M_FirePlasma (); - native void A_M_FireRailgun (); - native void A_M_BFGsound (); - native void A_M_FireBFG (); - States { Spawn: @@ -58,25 +68,22 @@ class ScriptedMarine : Actor native PLAY E 4 A_FaceTarget; PLAY E 4 A_M_Punch(1); PLAY A 9; - PLAY A 0 A_M_Refire(1); + PLAY A 0 A_M_Refire(1, "FistEnd"); Loop; + FistEnd: PLAY A 5 A_FaceTarget; Goto See; Melee.Berserk: PLAY E 4 A_FaceTarget; PLAY E 4 A_M_Punch(10); PLAY A 9; - PLAY A 0 A_M_Refire(1); + PLAY A 0 A_M_Refire(1, "FistEnd"); Loop; - PLAY A 5 A_FaceTarget; - Goto See; Melee.Chainsaw: PLAY E 4 A_MarineNoise; PLAY E 4 A_M_Saw; PLAY E 0 A_M_SawRefire; goto Melee.Chainsaw+1; - PLAY A 0; - Goto See; Missile: Missile.None: @@ -88,16 +95,15 @@ class ScriptedMarine : Actor native PLAY E 4 A_FaceTarget; PLAY F 6 BRIGHT A_M_FirePistol(1); PLAY A 4 A_FaceTarget; - PLAY A 0 A_M_Refire; + PLAY A 0 A_M_Refire(0, "ShootEnd"); + ShootEnd: PLAY A 5; Goto See; Fireloop.Pistol: PLAY F 6 BRIGHT A_M_FirePistol(0); PLAY A 4 A_FaceTarget; - PLAY A 0 A_M_Refire; + PLAY A 0 A_M_Refire(0, "ShootEnd"); Goto Fireloop.Pistol; - PLAY A 5; - Goto See; Missile.Shotgun: PLAY E 3 A_M_CheckAttack; PLAY F 7 BRIGHT A_M_FireShotgun; @@ -110,26 +116,20 @@ class ScriptedMarine : Actor native PLAY E 4 A_FaceTarget; PLAY FF 4 BRIGHT A_M_FireCGun(1); PLAY FF 4 BRIGHT A_M_FireCGun(0); - PLAY A 0 A_M_Refire; + PLAY A 0 A_M_Refire(0, "See"); Goto Missile.Chaingun+3; - PLAY A 0; - Goto See; Missile.Rocket: PLAY E 8; PLAY F 6 BRIGHT A_M_FireMissile; PLAY E 6; - PLAY A 0 A_M_Refire; + PLAY A 0 A_M_Refire(0, "See"); Loop; - PLAY A 0; - Goto See; Missile.Plasma: PLAY E 2 A_FaceTarget; PLAY E 0 A_FaceTarget; PLAY F 3 BRIGHT A_M_FirePlasma; - PLAY A 0 A_M_Refire; + PLAY A 0 A_M_Refire(0, "See"); Goto Missile.Plasma+1; - PLAY A 0; - Goto See; Missile.Railgun: PLAY E 4 A_M_CheckAttack; PLAY F 6 BRIGHT A_M_FireRailgun; @@ -139,10 +139,8 @@ class ScriptedMarine : Actor native PLAY EEEEE 5 A_FaceTarget; PLAY F 6 BRIGHT A_M_FireBFG; PLAY A 4 A_FaceTarget; - PLAY A 0 A_M_Refire; + PLAY A 0 A_M_Refire(0, "See"); Loop; - PLAY A 0; - Goto See; SkipAttack: PLAY A 1; @@ -169,6 +167,541 @@ class ScriptedMarine : Actor native PLAY MLKJIH 5; Goto See; } + + //============================================================================ + // + // + // + //============================================================================ + + private bool GetWeaponStates(int weap, WeaponStates wstates) + { + static const statelabel MeleeNames[] = + { + "Melee.None", "Melee.Fist", "Melee.Berserk", "Melee.Chainsaw", "Melee.Pistol", "Melee.Shotgun", + "Melee.SSG", "Melee.Chaingun", "Melee.Rocket", "Melee.Plasma", "Melee.Railgun", "Melee.BFG" + }; + + static const statelabel MissileNames[] = + { + "Missile.None", "Missile.Fist", "Missile.Berserk", "Missile.Chainsaw", "Missile.Pistol", "Missile.Shotgun", + "Missile.SSG", "Missile.Chaingun", "Missile.Rocket", "Missile.Plasma", "Missile.Railgun", "Missile.BFG" + }; + + if (weap < WEAPON_Dummy || weap > WEAPON_BFG) weap = WEAPON_Dummy; + + wstates.melee = FindState(MeleeNames[weap], true); + wstates.missile = FindState(MissileNames[weap], true); + + return wstates.melee != null || wstates.missile != null; + } + + //============================================================================ + // + // + // + //============================================================================ + + override void BeginPlay () + { + Super.BeginPlay (); + + // Set the current weapon + for(int i = WEAPON_Dummy; i <= WEAPON_BFG; i++) + { + WeaponStates wstates; + if (GetWeaponStates(i, wstates)) + { + if (wstates.melee == MeleeState && wstates.missile == MissileState) + { + CurrentWeapon = i; + } + } + } + } + + //============================================================================ + // + // + // + //============================================================================ + + // placeholder to make it compile for the time being. + SpriteID GetSprite(State st) + { + return SpriteID(0); + } + + override void Tick () + { + Super.Tick (); + + // Override the standard sprite, if desired + if (SpriteOverride != 0 && sprite == GetSprite(SpawnState)) + { + sprite = SpriteOverride; + } + + if (special1 != 0) + { + if (CurrentWeapon == WEAPON_SuperShotgun) + { // Play SSG reload sounds + int ticks = level.maptime - special1; + if (ticks < 47) + { + switch (ticks) + { + case 14: + A_PlaySound ("weapons/sshoto", CHAN_WEAPON); + break; + case 28: + A_PlaySound ("weapons/sshotl", CHAN_WEAPON); + break; + case 41: + A_PlaySound ("weapons/sshotc", CHAN_WEAPON); + break; + } + } + else + { + special1 = 0; + } + } + else + { // Wait for a long refire time + if (level.maptime >= special1) + { + special1 = 0; + } + else + { + bJustAttacked = true; + } + } + } + } + + //============================================================================ + // + // A_M_Refire + // + //============================================================================ + + void A_M_Refire (bool ignoremissile, statelabel jumpto) + { + if (target == null || target.health <= 0) + { + if (MissileState && random[SMarineRefire]() < 160) + { // Look for a new target most of the time + if (LookForPlayers (true) && CheckMissileRange ()) + { // Found somebody new and in range, so don't stop shooting + return; + } + } + SetStateLabel (jumpto); + return; + } + if (((ignoremissile || MissileState == null) && !CheckMeleeRange ()) || + !CheckSight (target) || random[SMarineRefire]() < 4) // Small chance of stopping even when target not dead + { + SetStateLabel (jumpto); + } + } + + //============================================================================ + // + // A_M_SawRefire + // + //============================================================================ + + void A_M_SawRefire () + { + if (target == null || target.health <= 0 || !CheckMeleeRange ()) + { + SetStateLabel ("See"); + } + } + + //============================================================================ + // + // A_MarineNoise + // + //============================================================================ + + void A_MarineNoise () + { + if (CurrentWeapon == WEAPON_Chainsaw) + { + A_PlaySound ("weapons/sawidle", CHAN_WEAPON); + } + } + + //============================================================================ + // + // A_MarineChase + // + //============================================================================ + + void A_MarineChase () + { + A_MarineNoise(); + A_Chase (); + } + + //============================================================================ + // + // A_MarineLook + // + //============================================================================ + + void A_MarineLook () + { + A_MarineNoise(); + A_Look(); + } + + //============================================================================ + // + // A_M_Punch (also used in the rocket attack.) + // + //============================================================================ + + void A_M_Punch(int damagemul) + { + FTranslatedLineTarget t; + + if (target == null) + return; + + int damage = (random[SMarinePunch](1, 10) << 1) * damagemul; + + A_FaceTarget (); + double ang = angle + random2[SMarinePunch]() * (5.625 / 256); + double pitch = AimLineAttack (ang, MELEERANGE); + LineAttack (ang, MELEERANGE, pitch, damage, 'Melee', "BulletPuff", true, t); + + // turn to face target + if (t.linetarget) + { + A_PlaySound ("*fist", CHAN_WEAPON); + angle = t.angleFromSource; + } + } + + //============================================================================ + // + // P_GunShot2 + // + //============================================================================ + + private void GunShot2 (bool accurate, double pitch, class pufftype) + { + int damage = 5 * random[SMarineGunshot](1,3); + double ang = angle; + + if (!accurate) + { + ang += Random2[SMarineGunshot]() * (5.625 / 256); + } + + LineAttack (ang, MISSILERANGE, pitch, damage, 'Hitscan', pufftype); + } + + //============================================================================ + // + // A_M_FirePistol + // + //============================================================================ + + void A_M_FirePistol (bool accurate) + { + if (target == null) + return; + + A_PlaySound ("weapons/pistol", CHAN_WEAPON); + A_FaceTarget (); + GunShot2 (accurate, AimLineAttack (angle, MISSILERANGE), "BulletPuff"); + } + + //============================================================================ + // + // A_M_FireShotgun + // + //============================================================================ + + void A_M_FireShotgun () + { + if (target == null) + return; + + A_PlaySound ("weapons/shotgf", CHAN_WEAPON); + A_FaceTarget (); + double pitch = AimLineAttack (angle, MISSILERANGE); + for (int i = 0; i < 7; ++i) + { + GunShot2 (false, pitch, "BulletPuff"); + } + special1 = level.maptime + 27; + } + + //============================================================================ + // + // A_M_CheckAttack + // + //============================================================================ + + void A_M_CheckAttack () + { + if (special1 != 0 || target == null) + { + SetStateLabel ("SkipAttack"); + } + else + { + A_FaceTarget (); + } + } + + //============================================================================ + // + // A_M_FireShotgun2 + // + //============================================================================ + + void A_M_FireShotgun2 () + { + if (target == null) + return; + + A_PlaySound ("weapons/sshotf", CHAN_WEAPON); + A_FaceTarget (); + double pitch = AimLineAttack (angle, MISSILERANGE); + for (int i = 0; i < 20; ++i) + { + int damage = 5*(random[SMarineFireSSG]()%3+1); + double ang = angle + Random2[SMarineFireSSG]() * (11.25 / 256); + + LineAttack (ang, MISSILERANGE, pitch + Random2[SMarineFireSSG]() * (7.097 / 256), damage, 'Hitscan', "BulletPuff"); + } + special1 = level.maptime; + } + + //============================================================================ + // + // A_M_FireCGun + // + //============================================================================ + + void A_M_FireCGun(bool accurate) + { + if (target == null) + return; + + A_PlaySound ("weapons/chngun", CHAN_WEAPON); + A_FaceTarget (); + GunShot2 (accurate, AimLineAttack (angle, MISSILERANGE), "BulletPuff"); + } + + //============================================================================ + // + // A_M_FireMissile + // + // Giving a marine a rocket launcher is probably a bad idea unless you pump + // up his health, because he's just as likely to kill himself as he is to + // kill anything else with it. + // + //============================================================================ + + void A_M_FireMissile () + { + if (target == null) + return; + + if (CheckMeleeRange ()) + { // If too close, punch it + A_M_Punch(1); + } + else + { + A_FaceTarget (); + SpawnMissile (target, "Rocket"); + } + } + + //============================================================================ + // + // A_M_FireRailgun + // + //============================================================================ + + void A_M_FireRailgun () + { + if (target == null) + return; + + A_MonsterRail(); + special1 = level.maptime + 50; + } + + //============================================================================ + // + // A_M_FirePlasma + // + //============================================================================ + + void A_M_FirePlasma () + { + if (target == null) + return; + + A_FaceTarget (); + SpawnMissile (target, "PlasmaBall"); + special1 = level.maptime + 20; + } + + //============================================================================ + // + // A_M_BFGsound + // + //============================================================================ + + void A_M_BFGsound () + { + if (target == null) + return; + + if (special1 != 0) + { + SetState (SeeState); + } + else + { + A_FaceTarget (); + A_PlaySound ("weapons/bfgf", CHAN_WEAPON); + // Don't interrupt the firing sequence + PainChance = 0; + } + } + + //============================================================================ + // + // A_M_FireBFG + // + //============================================================================ + + void A_M_FireBFG () + { + if (target == null) + return; + + A_FaceTarget (); + SpawnMissile (target, "BFGBall"); + special1 = level.maptime + 30; + PainChance = MARINE_PAIN_CHANCE; + } + + //--------------------------------------------------------------------------- + + final void SetWeapon (int type) + { + WeaponStates wstates; + if (GetWeaponStates(type, wstates)) + { + static const class classes[] = { + "ScriptedMarine", + "MarineFist", + "MarineBerserk", + "MarineChainsaw", + "MarinePistol", + "MarineShotgun", + "MarineSSG", + "MarineChaingun", + "MarineRocket", + "MarinePlasma", + "MarineRailgun", + "MarineBFG" + }; + + MeleeState = wstates.melee; + MissileState = wstates.missile; + DecalGenerator = GetDefaultByType(classes[type]).DecalGenerator; + } + } + + final void SetSprite (class source) + { + if (source == null) + { // A valid actor class wasn't passed, so use the standard sprite + SpriteOverride = sprite = GetSprite(SpawnState); + // Copy the standard scaling + Scale = Default.Scale; + } + else + { // Use the same sprite and scaling the passed class spawns with + readonly def = GetDefaultByType (source); + SpriteOverride = sprite = GetSprite(def.SpawnState); + Scale = def.Scale; + } + } +} + +extend class Actor +{ + //============================================================================ + // + // A_M_Saw (this is globally exported) + // + //============================================================================ + + void A_M_Saw(sound fullsound = "weapons/sawfull", sound hitsound = "weapons/sawhit", int damage = 2, class pufftype = "BulletPuff") + { + if (target == null) + return; + + if (pufftype == null) pufftype = "BulletPuff"; + if (damage == 0) damage = 2; + + A_FaceTarget (); + if (CheckMeleeRange ()) + { + FTranslatedLineTarget t; + + damage *= random[SMarineSaw](1, 10); + double ang = angle + Random2[SMarineSaw]() * (5.625 / 256); + + LineAttack (angle, SAWRANGE, AimLineAttack (angle, SAWRANGE), damage, 'Melee', pufftype, false, t); + + if (!t.linetarget) + { + A_PlaySound (fullsound, 1, CHAN_WEAPON); + return; + } + A_PlaySound (hitsound, CHAN_WEAPON); + + // turn to face target + ang = t.angleFromSource; + double anglediff = deltaangle(angle, ang); + + if (anglediff < 0.0) + { + if (anglediff < -4.5) + angle = ang + 90.0 / 21; + else + angle -= 4.5; + } + else + { + if (anglediff > 4.5) + angle = ang - 90.0 / 21; + else + angle += 4.5; + } + } + else + { + A_PlaySound (fullsound, 1, CHAN_WEAPON); + } + } } //--------------------------------------------------------------------------- From 6cc00e79a6dacc444cd0b6401d02b9d98abe1dd4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 21 Nov 2016 19:20:27 +0100 Subject: [PATCH 067/185] - made all internal struct types NativeStructs so that all variables of their types are made references. --- src/dobjtype.cpp | 20 ++++++++++++++++++++ src/dobjtype.h | 1 + src/g_level.cpp | 2 +- src/p_mobj.cpp | 4 ++-- src/p_user.cpp | 2 +- src/scripting/thingdef_data.cpp | 2 +- src/scripting/zscript/zcc_compile.cpp | 2 +- 7 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 4354e0885..09a3b1c94 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2457,6 +2457,26 @@ PNativeStruct::PNativeStruct(FName name) HasNativeFields = true; } +//========================================================================== +// +// NewNativeStruct +// Returns a PNativeStruct for the given name and container, making sure not to +// create duplicates. +// +//========================================================================== + +PNativeStruct *NewNativeStruct(FName name, PTypeBase *outer) +{ + size_t bucket; + PType *stype = TypeTable.FindType(RUNTIME_CLASS(PNativeStruct), (intptr_t)outer, (intptr_t)name, &bucket); + if (stype == NULL) + { + stype = new PStruct(name, outer); + TypeTable.AddType(stype, RUNTIME_CLASS(PNativeStruct), (intptr_t)outer, (intptr_t)name, bucket); + } + return static_cast(stype); +} + /* PField *****************************************************************/ IMPLEMENT_CLASS(PField, false, false, false, false) diff --git a/src/dobjtype.h b/src/dobjtype.h index be192225b..6134bbf90 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -922,6 +922,7 @@ PPointer *NewPointer(PType *type, bool isconst = false); PClassPointer *NewClassPointer(PClass *restrict); PEnum *NewEnum(FName name, PTypeBase *outer); PStruct *NewStruct(FName name, PTypeBase *outer); +PNativeStruct *NewNativeStruct(FName name, PTypeBase *outer); PPrototype *NewPrototype(const TArray &rettypes, const TArray &argtypes); // Built-in types ----------------------------------------------------------- diff --git a/src/g_level.cpp b/src/g_level.cpp index 9a955a03e..8987aed6c 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1858,7 +1858,7 @@ void FLevelLocals::AddScroller (int secnum) void G_InitLevelLocalsForScript() { - PStruct *lstruct = NewStruct("LevelLocals", nullptr); + PStruct *lstruct = NewNativeStruct("LevelLocals", nullptr); PField *levelf = new PField("level", lstruct, VARF_Native | VARF_Static, (intptr_t)&level); GlobalSymbols.AddSymbol(levelf); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 1066d985a..a97ed61c5 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -161,8 +161,8 @@ void AActor::InitNativeFields() PType *TypeActor = NewPointer(RUNTIME_CLASS(AActor)); PType *TypeActorClass = NewClassPointer(RUNTIME_CLASS(AActor)); PType *TypeInventory = NewPointer(RUNTIME_CLASS(AInventory)); - PType *TypePlayer = NewPointer(NewStruct("Player", nullptr)); - auto TypeSector = NewPointer(NewStruct("Sector", nullptr)); + PType *TypePlayer = NewPointer(NewNativeStruct("Player", nullptr)); + auto TypeSector = NewPointer(NewNativeStruct("Sector", nullptr)); PType *array5 = NewArray(TypeSInt32, 5); auto meta = RUNTIME_CLASS(AActor); diff --git a/src/p_user.cpp b/src/p_user.cpp index ad0bb6ba4..6d34037f1 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -3137,7 +3137,7 @@ bool P_IsPlayerTotallyFrozen(const player_t *player) void P_InitPlayerForScript() { - PStruct *pstruct = NewStruct("Player", nullptr); + PStruct *pstruct = NewNativeStruct("Player", nullptr); pstruct->Size = sizeof(player_t); pstruct->Align = alignof(player_t); PArray *parray = NewArray(pstruct, MAXPLAYERS); diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index cdb896902..5e8338a27 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -663,7 +663,7 @@ void InitThingdef() { PType *TypeActor = NewPointer(RUNTIME_CLASS(AActor)); - PStruct *sstruct = NewStruct("Sector", nullptr); + PStruct *sstruct = NewNativeStruct("Sector", nullptr); auto sptr = NewPointer(sstruct); sstruct->AddNativeField("soundtarget", TypeActor, myoffsetof(sector_t, SoundTarget)); diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 9682066b9..81b1c5ef6 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1533,7 +1533,7 @@ PType *ZCCCompiler::ResolveUserType(ZCC_BasicType *type, PSymbolTable *symt) { return TypeSInt32; // hack this to an integer until we can resolve the enum mess. } - if (ptype->IsKindOf(RUNTIME_CLASS(PClass))) + if (ptype->IsKindOf(RUNTIME_CLASS(PNativeStruct))) // native structs and classes cannot be instantiated, they always get used as reference. { return NewPointer(ptype, type->isconst); } From ff3baac8a78dd8545c2c21877c33a4da2b3ba802 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 21 Nov 2016 19:36:14 +0100 Subject: [PATCH 068/185] - made PStatePointer a real pointer pointing to a native struct named 'state', because that's what it really is and what it needs to be if we want to use a state as more than an opaque identifier in the VM --- src/dobjtype.cpp | 86 +++++++++++++++++++++++------------------------- src/dobjtype.h | 21 ++++++------ 2 files changed, 53 insertions(+), 54 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 09a3b1c94..2f536c300 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -1547,50 +1547,6 @@ PStateLabel::PStateLabel() mDescriptiveName = "StateLabel"; } -/* PStatePointer **********************************************************/ - -IMPLEMENT_CLASS(PStatePointer, false, false, false, false) - -//========================================================================== -// -// PStatePointer Default Constructor -// -//========================================================================== - -PStatePointer::PStatePointer() -: PBasicType(sizeof(FState *), alignof(FState *)) -{ - mDescriptiveName = "State"; - storeOp = OP_SP; - loadOp = OP_LP; - moveOp = OP_MOVEA; - RegType = REGT_POINTER; -} - -//========================================================================== -// -// PStatePointer :: WriteValue -// -//========================================================================== - -void PStatePointer::WriteValue(FSerializer &ar, const char *key,const void *addr) const -{ - ar(key, *(FState **)addr); -} - -//========================================================================== -// -// PStatePointer :: ReadValue -// -//========================================================================== - -bool PStatePointer::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - bool res = false; - ::Serialize(ar, key, *(FState **)addr, nullptr, &res); - return res; -} - /* PPointer ***************************************************************/ IMPLEMENT_CLASS(PPointer, false, true, false, false) @@ -1736,6 +1692,48 @@ PPointer *NewPointer(PType *type, bool isconst) return static_cast(ptype); } +/* PStatePointer **********************************************************/ + +IMPLEMENT_CLASS(PStatePointer, false, false, false, false) + +//========================================================================== +// +// PStatePointer Default Constructor +// +//========================================================================== + +PStatePointer::PStatePointer() +{ + mDescriptiveName = "Pointer"; + PointedType = NewNativeStruct(NAME_State, nullptr); + IsConst = true; +} + +//========================================================================== +// +// PStatePointer :: WriteValue +// +//========================================================================== + +void PStatePointer::WriteValue(FSerializer &ar, const char *key, const void *addr) const +{ + ar(key, *(FState **)addr); +} + +//========================================================================== +// +// PStatePointer :: ReadValue +// +//========================================================================== + +bool PStatePointer::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + bool res = false; + ::Serialize(ar, key, *(FState **)addr, nullptr, &res); + return res; +} + + /* PClassPointer **********************************************************/ diff --git a/src/dobjtype.h b/src/dobjtype.h index 6134bbf90..f464e36f8 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -551,16 +551,6 @@ public: // Pointers ----------------------------------------------------------------- -class PStatePointer : public PBasicType -{ - DECLARE_CLASS(PStatePointer, PBasicType); -public: - PStatePointer(); - - void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; - bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; -}; - class PPointer : public PBasicType { DECLARE_CLASS(PPointer, PBasicType); @@ -583,6 +573,17 @@ protected: void SetOps(); }; +class PStatePointer : public PPointer +{ + DECLARE_CLASS(PStatePointer, PPointer); +public: + PStatePointer(); + + void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; +}; + + class PClassPointer : public PPointer { DECLARE_CLASS(PClassPointer, PPointer); From 135cfcf0163a582b89a00f22ae7c65b19146be21 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 21 Nov 2016 21:34:34 +0100 Subject: [PATCH 069/185] - implemented State as an actual native struct, so that its fields can be accessed from scripts. - refactored state bitfield members into a flag word because the address of a bitfield cannot be taken, making such variables inaccessible to scripts. - actually use PNativeStruct for representing native structs defined in a script. --- src/d_dehacked.cpp | 15 ++--- src/dobjtype.cpp | 3 +- src/info.h | 71 ++++++++++++---------- src/p_mobj.cpp | 4 +- src/p_states.cpp | 37 +++++++++-- src/scripting/codegeneration/codegen.cpp | 4 +- src/scripting/decorate/olddecorations.cpp | 2 +- src/scripting/decorate/thingdef_states.cpp | 10 +-- src/scripting/thingdef_data.cpp | 2 + src/scripting/zscript/zcc_compile.cpp | 16 +++-- wadsrc/static/zscript/actor.txt | 1 - wadsrc/static/zscript/doom/fatso.txt | 2 +- 12 files changed, 102 insertions(+), 65 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 3ad1b2cd9..508821fd8 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -1466,28 +1466,21 @@ static int PatchFrame (int frameNum) if (info != &dummy) { - info->DefineFlags |= SDF_DEHACKED; // Signals the state has been modified by dehacked + info->StateFlags |= STF_DEHACKED; // Signals the state has been modified by dehacked if ((unsigned)(frame & 0x7fff) > 63) { - Printf ("Frame %d: Subnumber must be in range [0,63]\n", frameNum); + Printf("Frame %d: Subnumber must be in range [0,63]\n", frameNum); } info->Tics = tics; info->Misc1 = misc1; info->Frame = frame & 0x3f; - info->Fullbright = frame & 0x8000 ? true : false; + if (frame & 0x8000) info->StateFlags |= STF_FULLBRIGHT; + else info->StateFlags &= STF_FULLBRIGHT; } return result; } -// there is exactly one place where this is needed and we do not want to expose the state internals to ZSCRIPT. -DEFINE_ACTION_FUNCTION(AActor, isDEHState) -{ - PARAM_PROLOGUE; - PARAM_POINTER(state, FState); - ACTION_RETURN_BOOL(state != nullptr && (state->DefineFlags & SDF_DEHACKED)); -} - static int PatchSprite (int sprNum) { int result; diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 2f536c300..420dbc515 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -558,6 +558,7 @@ void PType::StaticInit() RUNTIME_CLASS(PDynArray)->TypeTableType = RUNTIME_CLASS(PDynArray); RUNTIME_CLASS(PMap)->TypeTableType = RUNTIME_CLASS(PMap); RUNTIME_CLASS(PStruct)->TypeTableType = RUNTIME_CLASS(PStruct); + RUNTIME_CLASS(PNativeStruct)->TypeTableType = RUNTIME_CLASS(PNativeStruct); RUNTIME_CLASS(PPrototype)->TypeTableType = RUNTIME_CLASS(PPrototype); RUNTIME_CLASS(PClass)->TypeTableType = RUNTIME_CLASS(PClass); RUNTIME_CLASS(PStatePointer)->TypeTableType = RUNTIME_CLASS(PStatePointer); @@ -2469,7 +2470,7 @@ PNativeStruct *NewNativeStruct(FName name, PTypeBase *outer) PType *stype = TypeTable.FindType(RUNTIME_CLASS(PNativeStruct), (intptr_t)outer, (intptr_t)name, &bucket); if (stype == NULL) { - stype = new PStruct(name, outer); + stype = new PNativeStruct(name); TypeTable.AddType(stype, RUNTIME_CLASS(PNativeStruct), (intptr_t)outer, (intptr_t)name, bucket); } return static_cast(stype); diff --git a/src/info.h b/src/info.h index 4f2b4b293..a41a6def8 100644 --- a/src/info.h +++ b/src/info.h @@ -63,7 +63,17 @@ enum EStateDefineFlags SDF_LABEL = 4, SDF_INDEX = 5, SDF_MASK = 7, - SDF_DEHACKED = 8, // Identify a state as having been modified by a dehacked lump +}; + +enum EStateFlags +{ + STF_SLOW = 1, // State duration is extended when slow monsters is on. + STF_FAST = 2, // State duration is shortened when fast monsters is on. + STF_FULLBRIGHT = 4, // State is fullbright + STF_NODELAY = 8, // Spawn states executes its action normally + STF_SAMEFRAME = 16, // Ignore Frame (except when spawning actor) + STF_CANRAISE = 32, // Allows a monster to be resurrected without waiting for an infinate frame + STF_DEHACKED = 64, // Modified by Dehacked }; enum EStateUseFlags @@ -101,33 +111,44 @@ struct FState { FState *NextState; VMFunction *ActionFunc; - WORD sprite; - SWORD Tics; - WORD TicRange; - short Light; - BYTE Frame; - BYTE UseFlags; - BYTE DefineFlags; // Unused byte so let's use it during state creation. - int Misc1; // Was changed to SBYTE, reverted to long for MBF compat - int Misc2; // Was changed to BYTE, reverted to long for MBF compat - BYTE Fullbright:1; // State is fullbright - BYTE SameFrame:1; // Ignore Frame (except when spawning actor) - BYTE Fast:1; - 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 - + int32_t sprite; + int16_t Tics; + uint16_t TicRange; + int16_t Light; + uint16_t StateFlags; + uint8_t Frame; + uint8_t UseFlags; + uint8_t DefineFlags; // Unused byte so let's use it during state creation. + int32_t Misc1; // Was changed to SBYTE, reverted to long for MBF compat + int32_t Misc2; // Was changed to BYTE, reverted to long for MBF compat +public: inline int GetFrame() const { return Frame; } inline bool GetSameFrame() const { - return SameFrame; + return !!(StateFlags & STF_SAMEFRAME); } inline int GetFullbright() const { - return Fullbright ? 0x10 /*RF_FULLBRIGHT*/ : 0; + return (StateFlags & STF_FULLBRIGHT)? 0x10 /*RF_FULLBRIGHT*/ : 0; + } + inline bool GetFast() const + { + return !!(StateFlags & STF_FAST); + } + inline bool GetSlow() const + { + return !!(StateFlags & STF_SLOW); + } + inline bool GetNoDelay() const + { + return !!(StateFlags & STF_NODELAY); + } + inline bool GetCanRaise() const + { + return !!(StateFlags & STF_CANRAISE); } inline int GetTics() const { @@ -149,22 +170,10 @@ struct FState { return NextState; } - inline bool GetNoDelay() const - { - return NoDelay; - } - inline bool GetCanRaise() const - { - return CanRaise; - } inline void SetFrame(BYTE frame) { Frame = frame - 'A'; } - inline bool CheckUse(int usetype) - { - return !!(UseFlags & usetype); - } void SetAction(VMFunction *func) { ActionFunc = func; } void ClearAction() { ActionFunc = NULL; } void SetAction(const char *name); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index a97ed61c5..b7da3e2c5 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -584,11 +584,11 @@ bool AActor::InStateSequence(FState * newstate, FState * basestate) int AActor::GetTics(FState * newstate) { int tics = newstate->GetTics(); - if (isFast() && newstate->Fast) + if (isFast() && newstate->GetFast()) { return tics - (tics>>1); } - else if (isSlow() && newstate->Slow) + else if (isSlow() && newstate->GetSlow()) { return tics<<1; } diff --git a/src/p_states.cpp b/src/p_states.cpp index fde7a0276..5444bcc3a 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -924,9 +924,9 @@ int FStateDefinitions::AddStates(FState *state, const char *framechars, const FS if (*framechars == '#') noframe = true; - else if (*framechars == '^') + else if (*framechars == '^') frame = '\\' - 'A'; - else + else frame = (*framechars & 223) - 'A'; framechars++; @@ -937,13 +937,14 @@ int FStateDefinitions::AddStates(FState *state, const char *framechars, const FS } state->Frame = frame; - state->SameFrame = noframe; + if (noframe) state->StateFlags |= STF_SAMEFRAME; + else state->StateFlags &= STF_SAMEFRAME; StateArray.Push(*state); SourceLines.Push(sc); ++count; // NODELAY flag is not carried past the first state - state->NoDelay = false; + state->StateFlags &= STF_NODELAY; } laststate = &StateArray[StateArray.Size() - 1]; laststatebeforelabel = laststate; @@ -1055,3 +1056,31 @@ CCMD(dumpstates) Printf(PRINT_LOG, "----------------------------\n"); } } + +//========================================================================== +// +// sets up the script-side version of states +// +//========================================================================== + +void P_InitStateForScript() +{ + PNativeStruct *pstruct = dyn_cast(TypeState->PointedType); + assert(pstruct != nullptr); + + pstruct->AddNativeField("NextState", TypeState, myoffsetof(FState, NextState), VARF_ReadOnly); + pstruct->AddNativeField("sprite", TypeSInt32, myoffsetof(FState, sprite), VARF_ReadOnly); + pstruct->AddNativeField("Tics", TypeSInt16, myoffsetof(FState, Tics), VARF_ReadOnly); + pstruct->AddNativeField("TicRange", TypeUInt16, myoffsetof(FState, TicRange), VARF_ReadOnly); + pstruct->AddNativeField("Frame", TypeUInt8, myoffsetof(FState, Frame), VARF_ReadOnly); + pstruct->AddNativeField("UseFlags", TypeUInt8, myoffsetof(FState, UseFlags), VARF_ReadOnly); + pstruct->AddNativeField("Misc1", TypeSInt32, myoffsetof(FState, Misc1), VARF_ReadOnly); + pstruct->AddNativeField("Misc2", TypeSInt32, myoffsetof(FState, Misc2), VARF_ReadOnly); + pstruct->AddNativeField("bSlow", TypeUInt16, myoffsetof(FState, StateFlags), VARF_ReadOnly, STF_SLOW); + pstruct->AddNativeField("bFast", TypeUInt16, myoffsetof(FState, StateFlags), VARF_ReadOnly, STF_FAST); + pstruct->AddNativeField("bFullbright", TypeUInt16, myoffsetof(FState, StateFlags), VARF_ReadOnly, STF_FULLBRIGHT); + pstruct->AddNativeField("bNoDelay", TypeUInt16, myoffsetof(FState, StateFlags), VARF_ReadOnly, STF_NODELAY); + pstruct->AddNativeField("bSameFrame", TypeUInt16, myoffsetof(FState, StateFlags), VARF_ReadOnly, STF_SAMEFRAME); + pstruct->AddNativeField("bCanRaise", TypeUInt16, myoffsetof(FState, StateFlags), VARF_ReadOnly, STF_CANRAISE); + pstruct->AddNativeField("bDehacked", TypeUInt16, myoffsetof(FState, StateFlags), VARF_ReadOnly, STF_DEHACKED); +} \ No newline at end of file diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 8d44e5c18..75d49801f 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -5679,7 +5679,7 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) return ret; } } - else if (Object->ValueType->IsA(RUNTIME_CLASS(PStruct))) + else if (Object->ValueType->IsKindOf(RUNTIME_CLASS(PStruct))) { auto ret = ResolveMember(ctx, ctx.Class, Object, static_cast(Object->ValueType)); delete this; @@ -6278,7 +6278,7 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) return nullptr; } } - else if (classx->ValueType->IsA(RUNTIME_CLASS(PStruct))) // Classes can never be used as value types so we do not have to consider that case. + else if (classx->ValueType->IsKindOf(RUNTIME_CLASS(PStruct))) { // if this is a struct within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset. if (classx->ExprType == EFX_ClassMember || classx->ExprType == EFX_StructMember) diff --git a/src/scripting/decorate/olddecorations.cpp b/src/scripting/decorate/olddecorations.cpp index a4cf20de4..a2cbc636b 100644 --- a/src/scripting/decorate/olddecorations.cpp +++ b/src/scripting/decorate/olddecorations.cpp @@ -699,7 +699,7 @@ static void ParseSpriteFrames (PClassActor *info, TArray &states, TArray { sc.ScriptError ("* must come after a frame"); } - state.Fullbright = true; + state.StateFlags |= STF_FULLBRIGHT; } else if (*token < 'A' || *token > ']') { diff --git a/src/scripting/decorate/thingdef_states.cpp b/src/scripting/decorate/thingdef_states.cpp index cad542d1b..4f60b8585 100644 --- a/src/scripting/decorate/thingdef_states.cpp +++ b/src/scripting/decorate/thingdef_states.cpp @@ -274,24 +274,24 @@ do_stop: { if (sc.Compare("BRIGHT")) { - state.Fullbright = true; + state.StateFlags |= STF_FULLBRIGHT; continue; } if (sc.Compare("FAST")) { - state.Fast = true; + state.StateFlags |= STF_FAST; continue; } if (sc.Compare("SLOW")) { - state.Slow = true; + state.StateFlags |= STF_SLOW; continue; } if (sc.Compare("NODELAY")) { if (bag.statedef.GetStateLabelIndex(NAME_Spawn) == bag.statedef.GetStateCount()) { - state.NoDelay = true; + state.StateFlags |= STF_NODELAY; } else { @@ -327,7 +327,7 @@ do_stop: } if (sc.Compare("CANRAISE")) { - state.CanRaise = true; + state.StateFlags |= STF_CANRAISE; continue; } diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 5e8338a27..23aba902f 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -658,6 +658,7 @@ static int funccmp(const void * a, const void * b) //========================================================================== void G_InitLevelLocalsForScript(); void P_InitPlayerForScript(); +void P_InitStateForScript(); void InitThingdef() { @@ -669,6 +670,7 @@ void InitThingdef() G_InitLevelLocalsForScript(); P_InitPlayerForScript(); + P_InitStateForScript(); FAutoSegIterator probe(CRegHead, CRegTail); diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 81b1c5ef6..c76df32e3 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -416,7 +416,10 @@ void ZCCCompiler::CreateStructTypes() for(auto s : Structs) { s->Outer = s->OuterDef == nullptr? nullptr : s->OuterDef->CType(); - s->strct->Type = NewStruct(s->NodeName(), s->Outer); + if (s->strct->Flags & ZCC_Native) + s->strct->Type = NewNativeStruct(s->NodeName(), nullptr); + else + s->strct->Type = NewStruct(s->NodeName(), s->Outer); s->strct->Symbol = new PSymbolType(s->NodeName(), s->Type()); GlobalSymbols.AddSymbol(s->strct->Symbol); @@ -2568,11 +2571,12 @@ void ZCCCompiler::CompileStates() Error(sl, "Duration is not a constant"); } } - state.Fullbright = sl->bBright; - state.Fast = sl->bFast; - state.Slow = sl->bSlow; - state.CanRaise = sl->bCanRaise; - if ((state.NoDelay = sl->bNoDelay)) + if (sl->bBright) state.StateFlags |= STF_FULLBRIGHT; + if (sl->bFast) state.StateFlags |= STF_FAST; + if (sl->bSlow) state.StateFlags |= STF_SLOW; + if (sl->bCanRaise) state.StateFlags |= STF_CANRAISE; + if (sl->bNoDelay) state.StateFlags |= STF_NODELAY; + if (sl->bNoDelay) { if (statedef.GetStateLabelIndex(NAME_Spawn) != statedef.GetStateCount()) { diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 87d2f8759..61bdf49c8 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -78,7 +78,6 @@ class Actor : Thinker native native bool GiveBody (int num, int max=0); native void SetDamage(int dmg); - native static bool isDehState(state st); native double Distance2D(Actor other); native void SetOrigin(vector3 newpos, bool moving); native void SetXYZ(vector3 newpos); diff --git a/wadsrc/static/zscript/doom/fatso.txt b/wadsrc/static/zscript/doom/fatso.txt index 98bcc3fc9..3831110c0 100644 --- a/wadsrc/static/zscript/doom/fatso.txt +++ b/wadsrc/static/zscript/doom/fatso.txt @@ -192,7 +192,7 @@ extend class Actor aimtarget.Height = Height; bool shootmode = ((flags & MSF_Classic) || // Flag explicitely set, or no flags and compat options - (flags == 0 && isDehState(CurState) && compat_mushroom)); + (flags == 0 && CurState.bDehacked && compat_mushroom)); for (i = -numspawns; i <= numspawns; i += 8) { From 3db712cd730fe0e0f23aa56eec44cd79cb2605e7 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 21 Nov 2016 22:20:25 +0100 Subject: [PATCH 070/185] - fixed: Switch statement without a default jumped to the first first case label instead. - removed placeholder code from scripted Marine. --- src/scripting/codegeneration/codegen.cpp | 3 +++ wadsrc/static/zscript/doom/scriptedmarine.txt | 13 ++++--------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 75d49801f..701b998ca 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -8250,6 +8250,7 @@ ExpEmit FxSwitchStatement::Emit(VMFunctionBuilder *build) } size_t DefaultAddress = build->Emit(OP_JMP, 0); TArray BreakAddresses; + bool defaultset = false; for (auto line : Content) { @@ -8270,6 +8271,7 @@ ExpEmit FxSwitchStatement::Emit(VMFunctionBuilder *build) else { build->BackpatchToHere(DefaultAddress); + defaultset = true; } break; @@ -8290,6 +8292,7 @@ ExpEmit FxSwitchStatement::Emit(VMFunctionBuilder *build) { build->BackpatchToHere(addr); } + if (!defaultset) build->BackpatchToHere(DefaultAddress); Content.Clear(); Content.ShrinkToFit(); return ExpEmit(); diff --git a/wadsrc/static/zscript/doom/scriptedmarine.txt b/wadsrc/static/zscript/doom/scriptedmarine.txt index 1096f24b5..3987bc795 100644 --- a/wadsrc/static/zscript/doom/scriptedmarine.txt +++ b/wadsrc/static/zscript/doom/scriptedmarine.txt @@ -96,6 +96,7 @@ class ScriptedMarine : Actor PLAY F 6 BRIGHT A_M_FirePistol(1); PLAY A 4 A_FaceTarget; PLAY A 0 A_M_Refire(0, "ShootEnd"); + Goto Fireloop.Pistol; ShootEnd: PLAY A 5; Goto See; @@ -226,18 +227,12 @@ class ScriptedMarine : Actor // //============================================================================ - // placeholder to make it compile for the time being. - SpriteID GetSprite(State st) - { - return SpriteID(0); - } - override void Tick () { Super.Tick (); // Override the standard sprite, if desired - if (SpriteOverride != 0 && sprite == GetSprite(SpawnState)) + if (SpriteOverride != 0 && sprite == SpawnState.sprite) { sprite = SpriteOverride; } @@ -632,14 +627,14 @@ class ScriptedMarine : Actor { if (source == null) { // A valid actor class wasn't passed, so use the standard sprite - SpriteOverride = sprite = GetSprite(SpawnState); + SpriteOverride = sprite = SpawnState.sprite; // Copy the standard scaling Scale = Default.Scale; } else { // Use the same sprite and scaling the passed class spawns with readonly def = GetDefaultByType (source); - SpriteOverride = sprite = GetSprite(def.SpawnState); + SpriteOverride = sprite = def.SpawnState.sprite; Scale = def.Scale; } } From bbb0778fd45423a9f893dce2d4b89dcab3b1fc63 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 22 Nov 2016 12:21:55 +0100 Subject: [PATCH 071/185] - scriptified Chicken and Pig - not tested yet, because other things have priority. --- src/CMakeLists.txt | 2 - src/d_player.h | 3 +- src/g_heretic/a_chicken.cpp | 233 --------------------- src/g_heretic/a_hereticmisc.cpp | 1 - src/g_hexen/a_fighterplayer.cpp | 7 + src/g_hexen/a_hexenmisc.cpp | 1 - src/g_hexen/a_pig.cpp | 107 ---------- src/p_pspr.cpp | 29 +++ src/p_user.cpp | 12 +- src/scripting/codegeneration/codegen.cpp | 20 +- wadsrc/static/zscript/actor.txt | 3 +- wadsrc/static/zscript/constants.txt | 5 + wadsrc/static/zscript/heretic/chicken.txt | 153 +++++++++++++- wadsrc/static/zscript/hexen/pig.txt | 77 ++++++- wadsrc/static/zscript/shared/inventory.txt | 6 + wadsrc/static/zscript/shared/player.txt | 7 +- 16 files changed, 309 insertions(+), 357 deletions(-) delete mode 100644 src/g_heretic/a_chicken.cpp delete mode 100644 src/g_hexen/a_pig.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 19179a0c4..c1a14d703 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -867,7 +867,6 @@ set( NOT_COMPILED_SOURCE_FILES sc_man_scanner.h sc_man_scanner.re g_doom/a_painelemental.cpp - g_heretic/a_chicken.cpp g_heretic/a_dsparil.cpp g_heretic/a_hereticartifacts.cpp g_heretic/a_hereticweaps.cpp @@ -892,7 +891,6 @@ set( NOT_COMPILED_SOURCE_FILES g_hexen/a_magecone.cpp g_hexen/a_magelightning.cpp g_hexen/a_magestaff.cpp - g_hexen/a_pig.cpp g_hexen/a_serpent.cpp g_hexen/a_spike.cpp g_hexen/a_summon.cpp diff --git a/src/d_player.h b/src/d_player.h index 20a78c932..d3f684137 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -100,6 +100,7 @@ FString GetPrintableDisplayName(PClassPlayerPawn *cls); class APlayerPawn : public AActor { DECLARE_CLASS_WITH_META(APlayerPawn, AActor, PClassPlayerPawn) + HAS_FIELDS HAS_OBJECT_POINTERS public: @@ -116,7 +117,7 @@ public: virtual void PlayRunning (); virtual void ThrowPoisonBag (); virtual void TweakSpeeds (double &forwardmove, double &sidemove); - virtual void MorphPlayerThink (); + void MorphPlayerThink (); virtual void ActivateMorphWeapon (); AWeapon *PickNewWeapon (PClassAmmo *ammotype); AWeapon *BestWeapon (PClassAmmo *ammotype); diff --git a/src/g_heretic/a_chicken.cpp b/src/g_heretic/a_chicken.cpp deleted file mode 100644 index 8a109d46d..000000000 --- a/src/g_heretic/a_chicken.cpp +++ /dev/null @@ -1,233 +0,0 @@ -/* -#include "actor.h" -#include "gi.h" -#include "m_random.h" -#include "s_sound.h" -#include "d_player.h" -#include "a_action.h" -#include "a_pickups.h" -#include "p_local.h" -#include "a_sharedglobal.h" -#include "p_enemy.h" -#include "d_event.h" -#include "gstrings.h" -#include "vm.h" -*/ - -void P_UpdateBeak (AActor *actor); - -static FRandom pr_chickenplayerthink ("ChickenPlayerThink"); -static FRandom pr_chicattack ("ChicAttack"); -static FRandom pr_feathers ("Feathers"); -static FRandom pr_beakatkpl1 ("BeakAtkPL1"); -static FRandom pr_beakatkpl2 ("BeakAtkPL2"); - -class AChickenPlayer : public APlayerPawn -{ - DECLARE_CLASS (AChickenPlayer, APlayerPawn) -public: - void MorphPlayerThink (); -}; - -IMPLEMENT_CLASS(AChickenPlayer, false, false, false, false) - -void AChickenPlayer::MorphPlayerThink () -{ - if (health > 0) - { // Handle beak movement - P_UpdateBeak (this); - } - if (player->morphTics & 15) - { - return; - } - if (Vel.X == 0 && Vel.Y == 0 && pr_chickenplayerthink () < 160) - { // Twitch view angle - Angles.Yaw += pr_chickenplayerthink.Random2() * (360. / 256. / 32.); - } - if ((Z() <= floorz) && (pr_chickenplayerthink() < 32)) - { // Jump and noise - Vel.Z += JumpZ; - - FState * painstate = FindState(NAME_Pain); - if (painstate != NULL) SetState (painstate); - } - if (pr_chickenplayerthink () < 48) - { // Just noise - S_Sound (this, CHAN_VOICE, "chicken/active", 1, ATTN_NORM); - } -} - -//---------------------------------------------------------------------------- -// -// PROC A_ChicAttack -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_ChicAttack) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (!self->target) - { - return 0; - } - if (self->CheckMeleeRange()) - { - int damage = 1 + (pr_chicattack() & 1); - int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_Feathers -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_Feathers) -{ - PARAM_SELF_PROLOGUE(AActor); - - int i; - int count; - AActor *mo; - - if (self->health > 0) - { // Pain - count = pr_feathers() < 32 ? 2 : 1; - } - else - { // Death - count = 5 + (pr_feathers()&3); - } - for (i = 0; i < count; i++) - { - mo = Spawn("Feather", self->PosPlusZ(20.), NO_REPLACE); - mo->target = self; - mo->Vel.X = pr_feathers.Random2() / 256.; - mo->Vel.Y = pr_feathers.Random2() / 256.; - mo->Vel.Z = 1. + pr_feathers() / 128.; - mo->SetState (mo->SpawnState + (pr_feathers()&7)); - } - return 0; -} - -//--------------------------------------------------------------------------- -// -// PROC P_UpdateBeak -// -//--------------------------------------------------------------------------- - -void P_UpdateBeak (AActor *self) -{ - DPSprite *pspr; - if (self->player != nullptr && (pspr = self->player->FindPSprite(PSP_WEAPON)) != nullptr) - { - pspr->y = WEAPONTOP + self->player->chickenPeck / 2; - } -} - -//--------------------------------------------------------------------------- -// -// PROC A_BeakRaise -// -//--------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_BeakRaise) -{ - PARAM_ACTION_PROLOGUE(AActor); - - player_t *player; - - if (nullptr == (player = self->player)) - { - return 0; - } - player->GetPSprite(PSP_WEAPON)->y = WEAPONTOP; - P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->GetReadyState()); - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC P_PlayPeck -// -//---------------------------------------------------------------------------- - -void P_PlayPeck (AActor *chicken) -{ - S_Sound (chicken, CHAN_VOICE, "chicken/peck", 1, ATTN_NORM); -} - -//---------------------------------------------------------------------------- -// -// PROC A_BeakAttackPL1 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL1) -{ - PARAM_ACTION_PROLOGUE(AActor); - - DAngle angle; - int damage; - DAngle slope; - player_t *player; - FTranslatedLineTarget t; - - if (NULL == (player = self->player)) - { - return 0; - } - - damage = 1 + (pr_beakatkpl1()&3); - angle = player->mo->Angles.Yaw; - slope = P_AimLineAttack (player->mo, angle, MELEERANGE); - P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "BeakPuff", true, &t); - if (t.linetarget) - { - player->mo->Angles.Yaw = t.angleFromSource; - } - P_PlayPeck (player->mo); - player->chickenPeck = 12; - player->GetPSprite(PSP_WEAPON)->Tics -= pr_beakatkpl1() & 7; - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_BeakAttackPL2 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL2) -{ - PARAM_ACTION_PROLOGUE(AActor); - - DAngle angle; - int damage; - DAngle slope; - player_t *player; - FTranslatedLineTarget t; - - if (NULL == (player = self->player)) - { - return 0; - } - - damage = pr_beakatkpl2.HitDice (4); - angle = player->mo->Angles.Yaw; - slope = P_AimLineAttack (player->mo, angle, MELEERANGE); - P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "BeakPuff", true, &t); - if (t.linetarget) - { - player->mo->Angles.Yaw = t.angleFromSource; - } - P_PlayPeck (player->mo); - player->chickenPeck = 12; - player->GetPSprite(PSP_WEAPON)->Tics -= pr_beakatkpl2()&3; - return 0; -} diff --git a/src/g_heretic/a_hereticmisc.cpp b/src/g_heretic/a_hereticmisc.cpp index 64de3ef84..5aa048977 100644 --- a/src/g_heretic/a_hereticmisc.cpp +++ b/src/g_heretic/a_hereticmisc.cpp @@ -19,7 +19,6 @@ #include "serializer.h" // Include all the other Heretic stuff here to reduce compile time -#include "a_chicken.cpp" #include "a_dsparil.cpp" #include "a_hereticartifacts.cpp" #include "a_hereticweaps.cpp" diff --git a/src/g_hexen/a_fighterplayer.cpp b/src/g_hexen/a_fighterplayer.cpp index 7e1502a1c..afdbe8a90 100644 --- a/src/g_hexen/a_fighterplayer.cpp +++ b/src/g_hexen/a_fighterplayer.cpp @@ -49,6 +49,13 @@ void AdjustPlayerAngle (AActor *pmo, FTranslatedLineTarget *t) } } +DEFINE_ACTION_FUNCTION(AActor, AdjustPlayerAngle) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_POINTER(t, FTranslatedLineTarget); + AdjustPlayerAngle(self, t); + return 0; +} //============================================================================ // // TryPunch diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp index c87c9e46d..f98305cba 100644 --- a/src/g_hexen/a_hexenmisc.cpp +++ b/src/g_hexen/a_hexenmisc.cpp @@ -45,7 +45,6 @@ #include "a_magecone.cpp" #include "a_magelightning.cpp" #include "a_magestaff.cpp" -#include "a_pig.cpp" #include "a_serpent.cpp" #include "a_spike.cpp" #include "a_summon.cpp" diff --git a/src/g_hexen/a_pig.cpp b/src/g_hexen/a_pig.cpp deleted file mode 100644 index 41054da00..000000000 --- a/src/g_hexen/a_pig.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* -#include "actor.h" -#include "gi.h" -#include "m_random.h" -#include "s_sound.h" -#include "d_player.h" -#include "a_action.h" -#include "a_pickups.h" -#include "p_local.h" -#include "a_sharedglobal.h" -#include "p_enemy.h" -#include "d_event.h" -#include "gstrings.h" -#include "vm.h" -*/ - -static FRandom pr_snoutattack ("SnoutAttack"); -static FRandom pr_pigattack ("PigAttack"); -static FRandom pr_pigplayerthink ("PigPlayerThink"); - -// Pig player --------------------------------------------------------------- - -class APigPlayer : public APlayerPawn -{ - DECLARE_CLASS (APigPlayer, APlayerPawn) -public: - void MorphPlayerThink (); -}; - -IMPLEMENT_CLASS(APigPlayer, false, false, false, false) - -void APigPlayer::MorphPlayerThink () -{ - if (player->morphTics & 15) - { - return; - } - if(Vel.X == 0 && Vel.Y == 0 && pr_pigplayerthink() < 64) - { // Snout sniff - if (player->ReadyWeapon != nullptr) - { - P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->FindState("Grunt")); - } - S_Sound (this, CHAN_VOICE, "PigActive1", 1, ATTN_NORM); // snort - return; - } - if (pr_pigplayerthink() < 48) - { - S_Sound (this, CHAN_VOICE, "PigActive", 1, ATTN_NORM); - } -} - -//============================================================================ -// -// A_SnoutAttack -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SnoutAttack) -{ - PARAM_ACTION_PROLOGUE(AActor); - - DAngle angle; - int damage; - DAngle slope; - player_t *player; - AActor *puff; - FTranslatedLineTarget t; - - if (NULL == (player = self->player)) - { - return 0; - } - - damage = 3+(pr_snoutattack()&3); - angle = player->mo->Angles.Yaw; - slope = P_AimLineAttack(player->mo, angle, MELEERANGE); - puff = P_LineAttack(player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "SnoutPuff", true, &t); - S_Sound(player->mo, CHAN_VOICE, "PigActive", 1, ATTN_NORM); - if(t.linetarget) - { - AdjustPlayerAngle(player->mo, &t); - if(puff != NULL) - { // Bit something - S_Sound(player->mo, CHAN_VOICE, "PigAttack", 1, ATTN_NORM); - } - } - return 0; -} - -//============================================================================ -// -// A_PigPain -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_PigPain) -{ - PARAM_SELF_PROLOGUE(AActor); - - CALL_ACTION(A_Pain, self); - if (self->Z() <= self->floorz) - { - self->Vel.Z = 3.5; - } - return 0; -} diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 157badd87..b5f569108 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -109,8 +109,29 @@ IMPLEMENT_POINTERS_END void DPSprite::InitNativeFields() { auto meta = RUNTIME_CLASS(DPSprite); + PType *TypeActor = NewPointer(RUNTIME_CLASS(AActor)); + PType *TypePSP = NewPointer(RUNTIME_CLASS(DPSprite)); + PType *TypePlayer = NewPointer(NewNativeStruct("Player", nullptr)); meta->AddNativeField("State", TypeState, myoffsetof(DPSprite, State), VARF_ReadOnly); + meta->AddNativeField("Caller", TypeActor, myoffsetof(DPSprite, Caller), VARF_ReadOnly); + meta->AddNativeField("Next", TypePSP, myoffsetof(DPSprite, Next), VARF_ReadOnly); + meta->AddNativeField("Owner", TypePlayer, myoffsetof(DPSprite, Owner), VARF_ReadOnly); + meta->AddNativeField("Sprite", TypeSpriteID, myoffsetof(DPSprite, Sprite)); + meta->AddNativeField("Frame", TypeSInt32, myoffsetof(DPSprite, Frame)); + meta->AddNativeField("ID", TypePlayer, myoffsetof(DPSprite, ID), VARF_ReadOnly); + meta->AddNativeField("processPending", TypeBool, myoffsetof(DPSprite, processPending)); + meta->AddNativeField("x", TypeFloat64, myoffsetof(DPSprite, x)); + meta->AddNativeField("y", TypeFloat64, myoffsetof(DPSprite, y)); + meta->AddNativeField("oldx", TypeFloat64, myoffsetof(DPSprite, oldx)); + meta->AddNativeField("oldy", TypeFloat64, myoffsetof(DPSprite, oldy)); + meta->AddNativeField("firstTic", TypeBool, myoffsetof(DPSprite, firstTic)); + meta->AddNativeField("Tics", TypeSInt32, myoffsetof(DPSprite, Tics)); + meta->AddNativeField("bAddWeapon", TypeSInt32, myoffsetof(DPSprite, Flags), 0, PSPF_ADDWEAPON); + meta->AddNativeField("bAddBob", TypeSInt32, myoffsetof(DPSprite, Flags), 0, PSPF_ADDBOB); + meta->AddNativeField("bPowDouble", TypeSInt32, myoffsetof(DPSprite, Flags), 0, PSPF_POWDOUBLE); + meta->AddNativeField("bCVarFast", TypeSInt32, myoffsetof(DPSprite, Flags), 0, PSPF_CVARFAST); + meta->AddNativeField("bFlip", TypeSInt32, myoffsetof(DPSprite, Flags), 0, PSPF_FLIP); } //------------------------------------------------------------------------ @@ -179,6 +200,14 @@ DPSprite *player_t::FindPSprite(int layer) return pspr; } +DEFINE_ACTION_FUNCTION(_Player, FindPSprite) // the underscore is needed to get past the name mangler which removes the first clas name character to match the class representation (needs to be fixed in a later commit) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + PARAM_INT(id); + ACTION_RETURN_OBJECT(self->FindPSprite((PSPLayers)id)); +} + + //------------------------------------------------------------------------ // // diff --git a/src/p_user.cpp b/src/p_user.cpp index 6d34037f1..84fcbd313 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -161,6 +161,12 @@ bool ValidatePlayerClass(PClassActor *ti, const char *name) return true; } +void APlayerPawn::InitNativeFields() +{ + auto meta = RUNTIME_CLASS(APlayerPawn); + meta->AddNativeField("JumpZ", TypeFloat64, myoffsetof(APlayerPawn, JumpZ)); +} + void SetupPlayerClasses () { FPlayerClass newclass; @@ -622,7 +628,7 @@ void player_t::SendPitchLimits() const // //=========================================================================== -IMPLEMENT_CLASS(APlayerPawn, false, true, false, true) +IMPLEMENT_CLASS(APlayerPawn, false, true, true, true) IMPLEMENT_POINTERS_START(APlayerPawn) IMPLEMENT_POINTER(InvFirst) @@ -1381,6 +1387,10 @@ void APlayerPawn::GiveDefaultInventory () void APlayerPawn::MorphPlayerThink () { + VINDEX(APlayerPawn, MorphPlayerThink); + VMValue params[1] = { (DObject*)this }; + VMFrameStack stack; + stack.Call(VFUNC, params, 1, nullptr, 0, nullptr); } void APlayerPawn::ActivateMorphWeapon () diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 701b998ca..3f8f09eb7 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -2543,7 +2543,15 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx) return nullptr; } - if (left->IsVector() && right->IsVector()) + if (left->ValueType == TypeState && right->IsInteger() && Operator == '+' && !left->isConstant()) + { + // This is the only special case of pointer addition that will be accepted - because it is used quite often in the existing game code. + ValueType = TypeState; + right = new FxMulDiv('*', right, new FxConstant((int)sizeof(FState), ScriptPosition)); // multiply by size here, so that constants can be better optimized. + right = right->Resolve(ctx); + ABORT(right); + } + else if (left->IsVector() && right->IsVector()) { // a vector2 can be added to or subtracted from a vector 3 but it needs to be the right operand. if (left->ValueType == right->ValueType || (left->ValueType == TypeVector3 && right->ValueType == TypeVector2)) @@ -2616,6 +2624,16 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build) ExpEmit op2 = right->Emit(build); if (Operator == '+') { + if (op1.RegType == REGT_POINTER) + { + assert(!op1.Konst); + assert(op2.RegType == REGT_INT); + op1.Free(build); + op2.Free(build); + ExpEmit opout(build, REGT_POINTER); + build->Emit(op2.Konst? OP_ADDA_RK : OP_ADDA_RR, opout.RegNum, op1.RegNum, op2.RegNum); + return opout; + } // Since addition is commutative, only the second operand may be a constant. if (op1.Konst) { diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 61bdf49c8..db86647c3 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -67,6 +67,7 @@ class Actor : Thinker native virtual native void Activate(Actor activator); virtual native void Deactivate(Actor activator); + native void AdjustPlayerAngle(FTranslatedLineTarget t); native static readonly GetDefaultByType(class cls); native static double deltaangle(double ang1, double ang2); native static double absangle(double ang1, double ang2); @@ -467,7 +468,6 @@ class Actor : Thinker native native void A_DeQueueCorpse(); native void A_ClearLastHeard(); native bool A_SelectWeapon(class whichweapon, int flags = 0); - native void A_Feathers(); native void A_ClassBossHealth(); native void A_ShootGun(); native void A_RocketInFlight(); @@ -476,7 +476,6 @@ class Actor : Thinker native native void A_GiveQuestItem(int itemno); native void A_RemoveForcefield(); native void A_DropWeaponPieces(class p1, class p2, class p3); - native void A_PigPain (); native void A_SetAngle(double angle = 0, int flags = 0, int ptr = AAPTR_DEFAULT); native void A_SetPitch(double pitch, int flags = 0, int ptr = AAPTR_DEFAULT); native void A_SetRoll(double roll, int flags = 0, int ptr = AAPTR_DEFAULT); diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index 29c60450c..b5b60481a 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -948,3 +948,8 @@ enum EFSkillProperty // floating point properties SKILLP_FriendlyHealth, }; +enum EWeaponPos +{ + WEAPONBOTTOM = 128, + WEAPONTOP = 32 +} \ No newline at end of file diff --git a/wadsrc/static/zscript/heretic/chicken.txt b/wadsrc/static/zscript/heretic/chicken.txt index 2e5ada81c..5d6065f66 100644 --- a/wadsrc/static/zscript/heretic/chicken.txt +++ b/wadsrc/static/zscript/heretic/chicken.txt @@ -26,8 +26,6 @@ class Beak : Weapon Weapon.SisterWeapon "BeakPowered"; } - action native void A_BeakRaise (); - action native void A_BeakAttackPL1(); States { @@ -44,9 +42,56 @@ class Beak : Weapon BEAK A 18 A_BeakAttackPL1; Goto Ready; } + + //--------------------------------------------------------------------------- + // + // PROC A_BeakRaise + // + //--------------------------------------------------------------------------- + + action void A_BeakRaise () + { + + if (player == null) + { + return; + } + player.GetPSprite(PSP_WEAPON).y = WEAPONTOP; + player.SetPsprite(PSP_WEAPON, player.ReadyWeapon.GetReadyState()); + } + + //---------------------------------------------------------------------------- + // + // PROC A_BeakAttackPL1 + // + //---------------------------------------------------------------------------- + + action void A_BeakAttackPL1() + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + + int damage = random[BeakAtk](1,3); + double ang = angle; + double slope = AimLineAttack (ang, MELEERANGE); + LineAttack (ang, MELEERANGE, slope, damage, 'Melee', "BeakPuff", true, t); + if (t.linetarget) + { + angle = t.angleFromSource; + } + A_PlaySound ("chicken/peck", CHAN_VOICE); + player.chickenPeck = 12; + player.GetPSprite(PSP_WEAPON).Tics -= random[BeakAtk](0,7); + } } +// BeakPowered --------------------------------------------------------------------- + class BeakPowered : Beak { Default @@ -55,7 +100,6 @@ class BeakPowered : Beak Weapon.SisterWeapon "Beak"; } - action native void A_BeakAttackPL2(); States { @@ -63,11 +107,40 @@ class BeakPowered : Beak BEAK A 12 A_BeakAttackPL2; Goto Ready; } + + //---------------------------------------------------------------------------- + // + // PROC A_BeakAttackPL2 + // + //---------------------------------------------------------------------------- + + action void A_BeakAttackPL2() + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + + int damage = random[BeakAtk](1,8) * 4; + double ang = angle; + double slope = AimLineAttack (ang, MELEERANGE); + LineAttack (ang, MELEERANGE, slope, damage, 'Melee', "BeakPuff", true, t); + if (t.linetarget) + { + angle = t.angleFromSource; + } + A_PlaySound ("chicken/peck", CHAN_VOICE); + player.chickenPeck = 12; + player.GetPSprite(PSP_WEAPON).Tics -= random[BeakAtk](0,3); + } + } // Chicken player ----------------------------------------------------------- -class ChickenPlayer : PlayerPawn native +class ChickenPlayer : PlayerPawn { Default { @@ -118,6 +191,44 @@ class ChickenPlayer : PlayerPawn native CHKN L -1; Stop; } + + //--------------------------------------------------------------------------- + // + // PROC P_UpdateBeak + // + //--------------------------------------------------------------------------- + + override void MorphPlayerThink () + { + if (health > 0) + { // Handle beak movement + PSprite pspr; + if (player != null && (pspr = player.FindPSprite(PSP_WEAPON)) != null) + { + pspr.y = WEAPONTOP + player.chickenPeck / 2; + } + } + if (player.morphTics & 15) + { + return; + } + if (Vel.X == 0 && Vel.Y == 0 && random[ChickenPlayerThink]() < 160) + { // Twitch view ang + angle += Random2[ChickenPlayerThink]() * (360. / 256. / 32.); + } + if ((pos.z <= floorz) && (random[ChickenPlayerThink]() < 32)) + { // Jump and noise + Vel.Z += JumpZ; + + State painstate = FindState('Pain'); + if (painstate != null) SetState (painstate); + } + if (random[ChickenPlayerThink]() < 48) + { // Just noise + A_PlaySound ("chicken/active", CHAN_VOICE); + } + } + } @@ -199,3 +310,37 @@ class Feather : Actor } } +extend class Actor +{ + //---------------------------------------------------------------------------- + // + // PROC A_Feathers + // This is used by both the chicken player and monster and must be in the + // common base class to be accessible by both + // + //---------------------------------------------------------------------------- + + void A_Feathers() + { + int count; + + if (health > 0) + { // Pain + count = random[Feathers]() < 32 ? 2 : 1; + } + else + { // Death + count = 5 + (random[Feathers]()&3); + } + for (int i = 0; i < count; i++) + { + Actor mo = Spawn("Feather", pos + (0, 0, 20), NO_REPLACE); + mo.target = self; + mo.Vel.X = Random2[Feathers]() / 256.; + mo.Vel.Y = Random2[Feathers]() / 256.; + mo.Vel.Z = 1. + random[Feathers]() / 128.; + mo.SetState (mo.SpawnState + (random[Feathers]()&7)); + } + } + +} \ No newline at end of file diff --git a/wadsrc/static/zscript/hexen/pig.txt b/wadsrc/static/zscript/hexen/pig.txt index 8fa446882..9f62e661e 100644 --- a/wadsrc/static/zscript/hexen/pig.txt +++ b/wadsrc/static/zscript/hexen/pig.txt @@ -34,8 +34,6 @@ class Snout : Weapon Weapon.YAdjust 10; } - action native void A_SnoutAttack (); - States { Ready: @@ -54,12 +52,43 @@ class Snout : Weapon WPIG B 8; Goto Ready; } + + //============================================================================ + // + // A_SnoutAttack + // + //============================================================================ + + action void A_SnoutAttack () + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + + int damage = random[SnoutAttack](3, 6); + double ang = angle; + double slope = AimLineAttack(ang, MELEERANGE); + Actor puff = LineAttack(ang, MELEERANGE, slope, damage, 'Melee', "SnoutPuff", true, t); + A_PlaySound("PigActive", CHAN_VOICE); + if(t.linetarget) + { + AdjustPlayerAngle(t); + if(puff != null) + { // Bit something + A_PlaySound("PigAttack", CHAN_VOICE); + } + } + } + } // Pig player --------------------------------------------------------------- -class PigPlayer : PlayerPawn native +class PigPlayer : PlayerPawn { Default { @@ -112,6 +141,30 @@ class PigPlayer : PlayerPawn native PIGY M 1 A_FreezeDeathChunks; Wait; } + + + override void MorphPlayerThink () + { + if (player.morphTics & 15) + { + return; + } + if(Vel.X == 0 && Vel.Y == 0 && random[PigPlayerThink]() < 64) + { // Snout sniff + if (player.ReadyWeapon != null) + { + player.SetPsprite(PSP_WEAPON, player.ReadyWeapon.FindState('Grunt')); + } + A_PlaySound ("PigActive1", CHAN_VOICE); // snort + return; + } + if (random[PigPlayerThink]() < 48) + { + A_PlaySound ("PigActive", CHAN_VOICE); // snort + } + } + + } @@ -168,3 +221,21 @@ class Pig : MorphedMonster } } + +extend class Actor +{ + //============================================================================ + // + // A_PigPain + // + //============================================================================ + + void A_PigPain () + { + A_Pain(); + if (pos.z <= floorz) + { + Vel.Z = 3.5; + } + } +} \ No newline at end of file diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index f906ca01c..2a9aabe27 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -457,6 +457,12 @@ class Weapon : StateProvider native native bool DepleteAmmo(bool altFire, bool checkEnough = true, int ammouse = -1); + virtual State GetReadyState () + { + return FindState('Ready'); + } + + native action void A_ZoomFactor(double scale = 1, int flags = 0); native action void A_SetCrosshair(int xhair); const ZOOM_INSTANT = 1; diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index c8485cebd..4f9e84333 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -49,6 +49,10 @@ class PlayerPawn : Actor native if (MeleeState != null) SetState (MeleeState); } + virtual void MorphPlayerThink() + { + } + } class PlayerChunk : PlayerPawn native @@ -78,4 +82,5 @@ struct Player native native void SetPsprite(int id, State stat, bool pending = false); native void SetSafeFlash(Weapon weap, State flashstate, int index); native PSprite GetPSprite(int id); -} \ No newline at end of file + native PSprite FindPSprite(int id); +} From 03a02a2036203d766f8d97f38b4bda477d955691 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 22 Nov 2016 12:28:11 +0100 Subject: [PATCH 072/185] - updated copyrights in a few files. --- src/scripting/decorate/thingdef_exp.cpp | 1 + src/scripting/decorate/thingdef_parse.cpp | 4 ++-- src/scripting/decorate/thingdef_states.cpp | 6 +++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/scripting/decorate/thingdef_exp.cpp b/src/scripting/decorate/thingdef_exp.cpp index e7d217609..a0ab09510 100644 --- a/src/scripting/decorate/thingdef_exp.cpp +++ b/src/scripting/decorate/thingdef_exp.cpp @@ -5,6 +5,7 @@ ** **--------------------------------------------------------------------------- ** Copyright 2005 Jan Cholasta +** Copyright 2005-2016 Christoph Oelckers ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index 490d9cf79..442e52884 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -4,8 +4,8 @@ ** Actor definitions - all parser related code ** **--------------------------------------------------------------------------- -** Copyright 2002-2007 Christoph Oelckers -** Copyright 2004-2007 Randy Heit +** Copyright 2002-2016 Christoph Oelckers +** Copyright 2004-2016 Randy Heit ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without diff --git a/src/scripting/decorate/thingdef_states.cpp b/src/scripting/decorate/thingdef_states.cpp index 4f60b8585..3b4abe002 100644 --- a/src/scripting/decorate/thingdef_states.cpp +++ b/src/scripting/decorate/thingdef_states.cpp @@ -4,8 +4,8 @@ ** Actor definitions - the state parser ** **--------------------------------------------------------------------------- -** Copyright 2002-2007 Christoph Oelckers -** Copyright 2004-2007 Randy Heit +** Copyright 2002-2016 Christoph Oelckers +** Copyright 2004-2016 Randy Heit ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -132,7 +132,7 @@ static FString ParseStateString(FScanner &sc) } //========================================================================== -//*** +// // ParseStates // parses a state block // From ab5c11064afd46536345b9dde6243a13e706d0ea Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 22 Nov 2016 13:03:46 +0100 Subject: [PATCH 073/185] - added a few missing tildes. --- src/d_dehacked.cpp | 2 +- src/p_states.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 508821fd8..2e8c56f05 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -1475,7 +1475,7 @@ static int PatchFrame (int frameNum) info->Misc1 = misc1; info->Frame = frame & 0x3f; if (frame & 0x8000) info->StateFlags |= STF_FULLBRIGHT; - else info->StateFlags &= STF_FULLBRIGHT; + else info->StateFlags &= ~STF_FULLBRIGHT; } return result; diff --git a/src/p_states.cpp b/src/p_states.cpp index 5444bcc3a..6e45db6b0 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -938,13 +938,13 @@ int FStateDefinitions::AddStates(FState *state, const char *framechars, const FS state->Frame = frame; if (noframe) state->StateFlags |= STF_SAMEFRAME; - else state->StateFlags &= STF_SAMEFRAME; + else state->StateFlags &= ~STF_SAMEFRAME; StateArray.Push(*state); SourceLines.Push(sc); ++count; // NODELAY flag is not carried past the first state - state->StateFlags &= STF_NODELAY; + state->StateFlags &= ~STF_NODELAY; } laststate = &StateArray[StateArray.Size() - 1]; laststatebeforelabel = laststate; From 980c9863058c8ab1d0894f9525676440073c2572 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 22 Nov 2016 19:20:31 +0100 Subject: [PATCH 074/185] - allow defining native fields through scripts. Internally this only requires exporting the address, but not the entire field. - added new VARF_Transient flag so that the decision whether to serialize a field does not depend solely on its native status. It may actually make a lot of sense to use the auto-serializer for native fields, too, as this would eliminate a lot of maintenance code. - defined (u)int8/16 as aliases to the byte and short types (Can't we not just get rid of this naming convention already...?) - exporting the fields of Actor revealed a few name clashes between them and some global types, so Actor.Sector was renamed to CurSector and Actor.Inventory was renamed to Actor.Inv. --- src/__autostart.cpp | 6 +- src/autosegs.h | 4 + src/dobjtype.cpp | 22 +- src/dobjtype.h | 7 +- src/namedef.h | 4 + src/p_mobj.cpp | 317 +++++++++++------------ src/p_pspr.cpp | 8 +- src/p_user.cpp | 2 +- src/sc_man_scanner.re | 4 + src/sc_man_tokens.h | 4 + src/scripting/codegeneration/codegen.cpp | 23 +- src/scripting/thingdef.h | 1 + src/scripting/thingdef_data.cpp | 55 ++++ src/scripting/vm/vm.h | 40 +++ src/scripting/zscript/zcc_compile.cpp | 43 ++- src/scripting/zscript/zcc_compile.h | 2 +- src/scripting/zscript/zcc_parser.cpp | 4 + src/zzautozend.cpp | 4 + wadsrc/static/zscript/actor.txt | 162 ++++++++++++ wadsrc/static/zscript/base.txt | 6 +- wadsrc/static/zscript/doom/bossbrain.txt | 2 +- wadsrc/static/zscript/shared/player.txt | 2 +- 22 files changed, 520 insertions(+), 202 deletions(-) diff --git a/src/__autostart.cpp b/src/__autostart.cpp index 280c3b13d..3daabbeae 100644 --- a/src/__autostart.cpp +++ b/src/__autostart.cpp @@ -53,7 +53,7 @@ // for initialized read-only data.) #pragma comment(linker, "/merge:.areg=.rdata /merge:.creg=.rdata /merge:.greg=.rdata") -#pragma comment(linker, "/merge:.yreg=.rdata") +#pragma comment(linker, "/merge:.yreg=.rdata /merge:.freg=.rdata") #pragma section(".areg$a",read) __declspec(allocate(".areg$a")) void *const ARegHead = 0; @@ -64,6 +64,9 @@ __declspec(allocate(".creg$a")) void *const CRegHead = 0; #pragma section(".greg$a",read) __declspec(allocate(".greg$a")) void *const GRegHead = 0; +#pragma section(".freg$a",read) +__declspec(allocate(".freg$a")) void *const FRegHead = 0; + #pragma section(".yreg$a",read) __declspec(allocate(".yreg$a")) void *const YRegHead = 0; @@ -97,6 +100,7 @@ __declspec(allocate(".yreg$a")) void *const YRegHead = 0; void *const ARegHead __attribute__((section(SECTION_AREG))) = 0; void *const CRegHead __attribute__((section(SECTION_CREG))) = 0; +void *const FRegHead __attribute__((section(SECTION_FREG))) = 0; void *const GRegHead __attribute__((section(SECTION_GREG))) = 0; void *const YRegHead __attribute__((section(SECTION_YREG))) = 0; diff --git a/src/autosegs.h b/src/autosegs.h index 08abe7cd3..f38e3628e 100644 --- a/src/autosegs.h +++ b/src/autosegs.h @@ -49,6 +49,10 @@ extern REGINFO ARegTail; extern REGINFO CRegHead; extern REGINFO CRegTail; +// List of class fields +extern REGINFO FRegHead; +extern REGINFO FRegTail; + // List of properties extern REGINFO GRegHead; extern REGINFO GRegTail; diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 420dbc515..5afb8a578 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -613,8 +613,8 @@ void PType::StaticInit() TypeVector3->AddField(NAME_X, TypeFloat64); TypeVector3->AddField(NAME_Y, TypeFloat64); TypeVector3->AddField(NAME_Z, TypeFloat64); - // allow accessing xy as a vector2. This is marked native because it's not supposed to be serialized. - TypeVector3->Symbols.AddSymbol(new PField(NAME_XY, TypeVector2, VARF_Native, 0)); + // allow accessing xy as a vector2. This is not supposed to be serialized so it's marked transient + TypeVector3->Symbols.AddSymbol(new PField(NAME_XY, TypeVector2, VARF_Transient, 0)); TypeTable.AddType(TypeVector3); TypeVector3->loadOp = OP_LV3; TypeVector3->storeOp = OP_SV3; @@ -2240,7 +2240,7 @@ void PStruct::SetDefaultValue(void *base, unsigned offset, TArrayFlags & VARF_Native)) + if (!(field->Flags & VARF_Transient)) { field->Type->SetDefaultValue(base, unsigned(offset + field->Offset), special); } @@ -2257,7 +2257,7 @@ void PStruct::SetPointer(void *base, unsigned offset, TArray *special) c { for (const PField *field : Fields) { - if (!(field->Flags & VARF_Native)) + if (!(field->Flags & VARF_Transient)) { field->Type->SetPointer(base, unsigned(offset + field->Offset), special); } @@ -2307,8 +2307,8 @@ void PStruct::WriteFields(FSerializer &ar, const void *addr, const TArrayFlags & VARF_Native)) + // Skip fields without or with native serialization + if (!(field->Flags & VARF_Transient)) { field->Type->WriteValue(ar, field->SymbolName.GetChars(), (const BYTE *)addr + field->Offset); } @@ -2394,7 +2394,7 @@ PField *PStruct::AddField(FName name, PType *type, DWORD flags) PField *PStruct::AddNativeField(FName name, PType *type, size_t address, DWORD flags, int bitvalue) { - PField *field = new PField(name, type, flags|VARF_Native, address, bitvalue); + PField *field = new PField(name, type, flags|VARF_Native|VARF_Transient, address, bitvalue); if (Symbols.AddSymbol(field) == nullptr) { // name is already in use @@ -2495,8 +2495,7 @@ PField::PField() PField::PField(FName name, PType *type, DWORD flags, size_t offset, int bitvalue) : PSymbol(name), Offset(offset), Type(type), Flags(flags) { - BitValue = bitvalue; - if (bitvalue != -1) + if (bitvalue != 0) { BitValue = 0; unsigned val = bitvalue; @@ -2519,6 +2518,7 @@ PField::PField(FName name, PType *type, DWORD flags, size_t offset, int bitvalue I_FatalError("Trying to create an invalid bit field element: %s", name.GetChars()); } } + else BitValue = -1; } /* PPrototype *************************************************************/ @@ -2692,10 +2692,10 @@ static void RecurseWriteFields(const PClass *type, FSerializer &ar, const void * if (type != NULL) { RecurseWriteFields(type->ParentClass, ar, addr); - // Don't write this part if it has no non-native variables + // Don't write this part if it has no non-transient variables for (unsigned i = 0; i < type->Fields.Size(); ++i) { - if (!(type->Fields[i]->Flags & VARF_Native)) + if (!(type->Fields[i]->Flags & VARF_Transient)) { // Tag this section with the class it came from in case // a more-derived class has variables that shadow a less- diff --git a/src/dobjtype.h b/src/dobjtype.h index f464e36f8..76d6e7585 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -19,7 +19,7 @@ enum VARF_Optional = (1<<0), // func param is optional VARF_Method = (1<<1), // func has an implied self parameter VARF_Action = (1<<2), // func has implied owner and state parameters - VARF_Native = (1<<3), // func is native code/don't auto serialize field + VARF_Native = (1<<3), // func is native code, field is natively defined VARF_ReadOnly = (1<<4), // field is read only, do not write to it VARF_Private = (1<<5), // field is private to containing class VARF_Protected = (1<<6), // field is only accessible by containing class and children. @@ -33,6 +33,7 @@ enum VARF_InternalAccess = (1<<14), // overrides VARF_ReadOnly for internal script code. VARF_Override = (1<<15), // overrides a virtual function from the parent class. VARF_Ref = (1<<16), // argument is passed by reference. + VARF_Transient = (1<<17) // don't auto serialize field. }; // Symbol information ------------------------------------------------------- @@ -610,7 +611,7 @@ class PField : public PSymbol DECLARE_CLASS(PField, PSymbol); HAS_OBJECT_POINTERS public: - PField(FName name, PType *type, DWORD flags = 0, size_t offset = 0, int bitvalue = -1); + PField(FName name, PType *type, DWORD flags = 0, size_t offset = 0, int bitvalue = 0); size_t Offset; PType *Type; @@ -700,7 +701,7 @@ public: bool HasNativeFields; virtual PField *AddField(FName name, PType *type, DWORD flags=0); - virtual PField *AddNativeField(FName name, PType *type, size_t address, DWORD flags = 0, int bitvalue = -1); + virtual PField *AddNativeField(FName name, PType *type, size_t address, DWORD flags = 0, int bitvalue = 0); size_t PropagateMark(); diff --git a/src/namedef.h b/src/namedef.h index 5ee98119a..545bf0260 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -695,6 +695,10 @@ xx(uShort) xx(Int) xx(uInt) xx(Bool) +xx(uint8) +xx(int8) +xx(uint16) +xx(int16) xx(Float) xx(Float32) xx(Float64) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index b7da3e2c5..181399655 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -156,171 +156,166 @@ AActor::~AActor () extern FFlagDef InternalActorFlagDefs[]; extern FFlagDef ActorFlagDefs[]; +DEFINE_FIELD(AActor, player) +DEFINE_FIELD_NAMED(AActor, __Pos, pos) +DEFINE_FIELD_NAMED(AActor, __Pos.X, x) +DEFINE_FIELD_NAMED(AActor, __Pos.Y, y) +DEFINE_FIELD_NAMED(AActor, __Pos.Z, z) +DEFINE_FIELD(AActor, Prev) +DEFINE_FIELD(AActor, SpriteAngle) +DEFINE_FIELD(AActor, SpriteRotation) +DEFINE_FIELD(AActor, VisibleStartAngle) +DEFINE_FIELD(AActor, VisibleStartPitch) +DEFINE_FIELD(AActor, VisibleEndAngle) +DEFINE_FIELD(AActor, VisibleEndPitch) +DEFINE_FIELD_NAMED(AActor, Angles.Yaw, angle) +DEFINE_FIELD_NAMED(AActor, Angles.Pitch, pitch) +DEFINE_FIELD_NAMED(AActor, Angles.Roll, roll) +DEFINE_FIELD(AActor, Vel) +DEFINE_FIELD_NAMED(AActor, Vel.X, velx) +DEFINE_FIELD_NAMED(AActor, Vel.Y, vely) +DEFINE_FIELD_NAMED(AActor, Vel.Z, velz) +DEFINE_FIELD_NAMED(AActor, Vel.X, momx) +DEFINE_FIELD_NAMED(AActor, Vel.Y, momy) +DEFINE_FIELD_NAMED(AActor, Vel.Z, momz) +DEFINE_FIELD(AActor, Speed) +DEFINE_FIELD(AActor, FloatSpeed) +DEFINE_FIELD(AActor, sprite) +DEFINE_FIELD(AActor, frame) +DEFINE_FIELD(AActor, Scale) +DEFINE_FIELD_NAMED(AActor, Scale.X, scalex) +DEFINE_FIELD_NAMED(AActor, Scale.Y, scaley) +DEFINE_FIELD(AActor, RenderStyle) +DEFINE_FIELD(AActor, picnum) +DEFINE_FIELD(AActor, Alpha) +DEFINE_FIELD(AActor, fillcolor) +DEFINE_FIELD_NAMED(AActor, Sector, CurSector) // clashes with type 'sector'. +DEFINE_FIELD(AActor, subsector) +DEFINE_FIELD(AActor, ceilingz) +DEFINE_FIELD(AActor, floorz) +DEFINE_FIELD(AActor, dropoffz) +DEFINE_FIELD(AActor, floorsector) +DEFINE_FIELD(AActor, floorpic) +DEFINE_FIELD(AActor, floorterrain) +DEFINE_FIELD(AActor, ceilingsector) +DEFINE_FIELD(AActor, ceilingpic) +DEFINE_FIELD(AActor, Height) +DEFINE_FIELD(AActor, radius) +DEFINE_FIELD(AActor, projectilepassheight) +DEFINE_FIELD(AActor, tics) +DEFINE_FIELD_NAMED(AActor, state, curstate) // clashes with type 'state'. +DEFINE_FIELD_NAMED(AActor, DamageVal, Damage) // name differs for historic reasons +DEFINE_FIELD(AActor, projectileKickback) +DEFINE_FIELD(AActor, VisibleToTeam) +DEFINE_FIELD(AActor, special1) +DEFINE_FIELD(AActor, special2) +DEFINE_FIELD(AActor, specialf1) +DEFINE_FIELD(AActor, specialf2) +DEFINE_FIELD(AActor, weaponspecial) +DEFINE_FIELD(AActor, health) +DEFINE_FIELD(AActor, movedir) +DEFINE_FIELD(AActor, visdir) +DEFINE_FIELD(AActor, movecount) +DEFINE_FIELD(AActor, strafecount) +DEFINE_FIELD(AActor, target) +DEFINE_FIELD(AActor, master) +DEFINE_FIELD(AActor, tracer) +DEFINE_FIELD(AActor, LastHeard) +DEFINE_FIELD(AActor, lastenemy) +DEFINE_FIELD(AActor, LastLookActor) +DEFINE_FIELD(AActor, reactiontime) +DEFINE_FIELD(AActor, threshold) +DEFINE_FIELD(AActor, DefThreshold) +DEFINE_FIELD(AActor, SpawnPoint) +DEFINE_FIELD(AActor, SpawnAngle) +DEFINE_FIELD(AActor, StartHealth) +DEFINE_FIELD(AActor, WeaveIndexXY) +DEFINE_FIELD(AActor, WeaveIndexZ) +DEFINE_FIELD(AActor, skillrespawncount) +DEFINE_FIELD(AActor, args) +DEFINE_FIELD(AActor, Mass) +DEFINE_FIELD(AActor, special) +DEFINE_FIELD(AActor, tid) +DEFINE_FIELD(AActor, TIDtoHate) +DEFINE_FIELD(AActor, waterlevel) +DEFINE_FIELD(AActor, Score) +DEFINE_FIELD(AActor, accuracy) +DEFINE_FIELD(AActor, stamina) +DEFINE_FIELD(AActor, meleerange) +DEFINE_FIELD(AActor, PainThreshold) +DEFINE_FIELD(AActor, Gravity) +DEFINE_FIELD(AActor, Floorclip) +DEFINE_FIELD(AActor, DamageType) +DEFINE_FIELD(AActor, DamageTypeReceived) +DEFINE_FIELD(AActor, FloatBobPhase) +DEFINE_FIELD(AActor, RipperLevel) +DEFINE_FIELD(AActor, RipLevelMin) +DEFINE_FIELD(AActor, RipLevelMax) +DEFINE_FIELD(AActor, Species) +DEFINE_FIELD(AActor, alternative) +DEFINE_FIELD(AActor, goal) +DEFINE_FIELD(AActor, MinMissileChance) +DEFINE_FIELD(AActor, LastLookPlayerNumber) +DEFINE_FIELD(AActor, SpawnFlags) +DEFINE_FIELD(AActor, meleethreshold) +DEFINE_FIELD(AActor, maxtargetrange) +DEFINE_FIELD(AActor, bouncefactor) +DEFINE_FIELD(AActor, wallbouncefactor) +DEFINE_FIELD(AActor, bouncecount) +DEFINE_FIELD(AActor, Friction) +DEFINE_FIELD(AActor, FastChaseStrafeCount) +DEFINE_FIELD(AActor, pushfactor) +DEFINE_FIELD(AActor, lastpush) +DEFINE_FIELD(AActor, activationtype) +DEFINE_FIELD(AActor, lastbump) +DEFINE_FIELD(AActor, DesignatedTeam) +DEFINE_FIELD(AActor, BlockingMobj) +DEFINE_FIELD(AActor, BlockingLine) +DEFINE_FIELD(AActor, PoisonDamage) +DEFINE_FIELD(AActor, PoisonDamageType) +DEFINE_FIELD(AActor, PoisonDuration) +DEFINE_FIELD(AActor, PoisonPeriod) +DEFINE_FIELD(AActor, PoisonDamageReceived) +DEFINE_FIELD(AActor, PoisonDamageTypeReceived) +DEFINE_FIELD(AActor, PoisonDurationReceived) +DEFINE_FIELD(AActor, PoisonPeriodReceived) +DEFINE_FIELD(AActor, Poisoner) +DEFINE_FIELD_NAMED(AActor, Inventory, Inv) // clashes with type 'Inventory'. +DEFINE_FIELD(AActor, smokecounter) +DEFINE_FIELD(AActor, FriendPlayer) +DEFINE_FIELD(AActor, Translation) +DEFINE_FIELD(AActor, AttackSound) +DEFINE_FIELD(AActor, DeathSound) +DEFINE_FIELD(AActor, SeeSound) +DEFINE_FIELD(AActor, PainSound) +DEFINE_FIELD(AActor, ActiveSound) +DEFINE_FIELD(AActor, UseSound) +DEFINE_FIELD(AActor, BounceSound) +DEFINE_FIELD(AActor, WallBounceSound) +DEFINE_FIELD(AActor, CrushPainSound) +DEFINE_FIELD(AActor, MaxDropOffHeight) +DEFINE_FIELD(AActor, MaxStepHeight) +DEFINE_FIELD(AActor, PainChance) +DEFINE_FIELD(AActor, PainType) +DEFINE_FIELD(AActor, DeathType) +DEFINE_FIELD(AActor, DamageFactor) +DEFINE_FIELD(AActor, DamageMultiply) +DEFINE_FIELD(AActor, TeleFogSourceType) +DEFINE_FIELD(AActor, TeleFogDestType) +DEFINE_FIELD(AActor, SpawnState) +DEFINE_FIELD(AActor, SeeState) +DEFINE_FIELD(AActor, MeleeState) +DEFINE_FIELD(AActor, MissileState) +DEFINE_FIELD(AActor, ConversationRoot) +DEFINE_FIELD(AActor, Conversation) +DEFINE_FIELD(AActor, DecalGenerator) + + void AActor::InitNativeFields() { - PType *TypeActor = NewPointer(RUNTIME_CLASS(AActor)); - PType *TypeActorClass = NewClassPointer(RUNTIME_CLASS(AActor)); - PType *TypeInventory = NewPointer(RUNTIME_CLASS(AInventory)); - PType *TypePlayer = NewPointer(NewNativeStruct("Player", nullptr)); - auto TypeSector = NewPointer(NewNativeStruct("Sector", nullptr)); - PType *array5 = NewArray(TypeSInt32, 5); - auto meta = RUNTIME_CLASS(AActor); - - meta->AddNativeField("Player", TypePlayer, myoffsetof(AActor, player)); - meta->AddNativeField("Pos", TypeVector3, myoffsetof(AActor, __Pos), VARF_ReadOnly); - meta->AddNativeField(NAME_X, TypeFloat64, myoffsetof(AActor, __Pos.X), VARF_ReadOnly | VARF_Deprecated); // must remain read-only! - meta->AddNativeField(NAME_Y, TypeFloat64, myoffsetof(AActor, __Pos.Y), VARF_ReadOnly | VARF_Deprecated); // must remain read-only! - meta->AddNativeField(NAME_Z, TypeFloat64, myoffsetof(AActor, __Pos.Z), VARF_ReadOnly | VARF_Deprecated); // must remain read-only! - meta->AddNativeField("Prev", TypeVector3, myoffsetof(AActor, Prev)); - meta->AddNativeField("spriteAngle", TypeFloat64, myoffsetof(AActor, SpriteAngle)); - meta->AddNativeField("spriteRotation", TypeFloat64, myoffsetof(AActor, SpriteRotation)); - meta->AddNativeField(NAME_VisibleStartAngle, TypeFloat64, myoffsetof(AActor, VisibleStartAngle)); - meta->AddNativeField(NAME_VisibleStartPitch, TypeFloat64, myoffsetof(AActor, VisibleStartPitch)); - meta->AddNativeField(NAME_VisibleEndAngle, TypeFloat64, myoffsetof(AActor, VisibleEndAngle)); - meta->AddNativeField(NAME_VisibleEndPitch, TypeFloat64, myoffsetof(AActor, VisibleEndPitch)); - meta->AddNativeField(NAME_Angle, TypeFloat64, myoffsetof(AActor, Angles.Yaw)); - meta->AddNativeField(NAME_Pitch, TypeFloat64, myoffsetof(AActor, Angles.Pitch)); - meta->AddNativeField(NAME_Roll, TypeFloat64, myoffsetof(AActor, Angles.Roll)); - meta->AddNativeField("Vel", TypeVector3, myoffsetof(AActor, Vel)); - meta->AddNativeField(NAME_VelX, TypeFloat64, myoffsetof(AActor, Vel.X), VARF_ReadOnly | VARF_Deprecated); - meta->AddNativeField(NAME_VelY, TypeFloat64, myoffsetof(AActor, Vel.Y), VARF_ReadOnly | VARF_Deprecated); - meta->AddNativeField(NAME_VelZ, TypeFloat64, myoffsetof(AActor, Vel.Z), VARF_ReadOnly | VARF_Deprecated); - meta->AddNativeField(NAME_MomX, TypeFloat64, myoffsetof(AActor, Vel.X), VARF_ReadOnly | VARF_Deprecated); - meta->AddNativeField(NAME_MomY, TypeFloat64, myoffsetof(AActor, Vel.Y), VARF_ReadOnly | VARF_Deprecated); - meta->AddNativeField(NAME_MomZ, TypeFloat64, myoffsetof(AActor, Vel.Z), VARF_ReadOnly | VARF_Deprecated); - meta->AddNativeField(NAME_Speed, TypeFloat64, myoffsetof(AActor, Speed)); - meta->AddNativeField("FloatSpeed", TypeFloat64, myoffsetof(AActor, FloatSpeed)); - meta->AddNativeField("sprite", TypeSpriteID, myoffsetof(AActor, sprite)); - meta->AddNativeField("frame", TypeUInt8, myoffsetof(AActor, frame)); - meta->AddNativeField("Scale", TypeVector2, myoffsetof(AActor, Scale)); - meta->AddNativeField(NAME_ScaleX, TypeFloat64, myoffsetof(AActor, Scale.X), VARF_Deprecated); - meta->AddNativeField(NAME_ScaleY, TypeFloat64, myoffsetof(AActor, Scale.Y), VARF_Deprecated); - //FRenderStyle RenderStyle; // how do we expose this? - meta->AddNativeField("picnum", TypeSInt32, myoffsetof(AActor, picnum)); // Do we need a variable type 'texture' to do this? - meta->AddNativeField(NAME_Alpha, TypeFloat64, myoffsetof(AActor, Alpha)); - meta->AddNativeField("fillcolor", TypeColor, myoffsetof(AActor, fillcolor)); - meta->AddNativeField("Sector", TypeSector, myoffsetof(AActor, Sector)); - //meta->AddNativeField("Subsector", TypeSubsector, myoffsetof(AActor, subsector)); - meta->AddNativeField(NAME_CeilingZ, TypeFloat64, myoffsetof(AActor, ceilingz)); - meta->AddNativeField(NAME_FloorZ, TypeFloat64, myoffsetof(AActor, floorz)); - meta->AddNativeField("DropoffZ", TypeFloat64, myoffsetof(AActor, dropoffz), VARF_ReadOnly); - meta->AddNativeField("floorsector", TypeSector, myoffsetof(AActor, floorsector)); - meta->AddNativeField("floorpic", TypeTextureID, myoffsetof(AActor, floorpic)); - meta->AddNativeField("floorterrain", TypeSInt32, myoffsetof(AActor, floorterrain)); - meta->AddNativeField("ceilingsector", TypeSector, myoffsetof(AActor, ceilingsector)); - meta->AddNativeField("ceilingpic", TypeSInt32, myoffsetof(AActor, ceilingpic)); // Do we need a variable type 'texture' to do this? - meta->AddNativeField(NAME_Height, TypeFloat64, myoffsetof(AActor, Height)); - meta->AddNativeField(NAME_Radius, TypeFloat64, myoffsetof(AActor, radius), VARF_ReadOnly); - meta->AddNativeField("projectilepassheight",TypeFloat64, myoffsetof(AActor, projectilepassheight)); - meta->AddNativeField("tics", TypeSInt32, myoffsetof(AActor, tics)); - meta->AddNativeField("CurState", TypeState, myoffsetof(AActor, state), VARF_ReadOnly); // has to be renamed on the script side because it clashes with the same named type. - meta->AddNativeField(NAME_Damage, TypeSInt32, myoffsetof(AActor, DamageVal), VARF_ReadOnly); - meta->AddNativeField("projectilekickback", TypeSInt32, myoffsetof(AActor, projectileKickback)); - //DWORD VisibleToTeam; - meta->AddNativeField("special1", TypeSInt32, myoffsetof(AActor, special1)); - meta->AddNativeField("special2", TypeSInt32, myoffsetof(AActor, special2)); - meta->AddNativeField("specialf1", TypeFloat64, myoffsetof(AActor, specialf1)); - meta->AddNativeField("specialf2", TypeFloat64, myoffsetof(AActor, specialf2)); - meta->AddNativeField("weaponspecial", TypeSInt32, myoffsetof(AActor, weaponspecial)); - meta->AddNativeField(NAME_Health, TypeSInt32, myoffsetof(AActor, health)); - meta->AddNativeField("movedir", TypeUInt8, myoffsetof(AActor, movedir)); - meta->AddNativeField("visdir", TypeSInt8, myoffsetof(AActor, visdir)); - meta->AddNativeField("movecount", TypeSInt16, myoffsetof(AActor, movecount)); - meta->AddNativeField("strafecount", TypeSInt16, myoffsetof(AActor, strafecount)); - meta->AddNativeField(NAME_Target, TypeActor, myoffsetof(AActor, target)); - meta->AddNativeField(NAME_Master, TypeActor, myoffsetof(AActor, master)); - meta->AddNativeField(NAME_Tracer, TypeActor, myoffsetof(AActor, tracer)); - meta->AddNativeField("LastHeard", TypeActor, myoffsetof(AActor, LastHeard)); - meta->AddNativeField("LastEnemy", TypeActor, myoffsetof(AActor, lastenemy)); - meta->AddNativeField("LastLookActor", TypeActor, myoffsetof(AActor, LastLookActor)); - meta->AddNativeField(NAME_ReactionTime, TypeSInt32, myoffsetof(AActor, reactiontime)); - meta->AddNativeField(NAME_Threshold, TypeSInt32, myoffsetof(AActor, threshold)); - meta->AddNativeField(NAME_DefThreshold, TypeSInt32, myoffsetof(AActor, DefThreshold), VARF_ReadOnly); - meta->AddNativeField("SpawnPoint", TypeVector3, myoffsetof(AActor, SpawnPoint), VARF_ReadOnly); - meta->AddNativeField("SpawnAngle", TypeUInt16, myoffsetof(AActor, SpawnAngle), VARF_ReadOnly); - meta->AddNativeField("StartHealth", TypeSInt32, myoffsetof(AActor, StartHealth)); - meta->AddNativeField("WeaveIndexXY", TypeUInt16, myoffsetof(AActor, WeaveIndexXY)); - meta->AddNativeField("WeaveIndexZ", TypeUInt16, myoffsetof(AActor, WeaveIndexZ)); - meta->AddNativeField("skillrespawncount", TypeSInt32, myoffsetof(AActor, skillrespawncount)); - meta->AddNativeField(NAME_Args, array5, myoffsetof(AActor, args)); - meta->AddNativeField(NAME_Mass, TypeSInt32, myoffsetof(AActor, Mass)); - meta->AddNativeField(NAME_Special, TypeSInt32, myoffsetof(AActor, special)); - meta->AddNativeField(NAME_TID, TypeSInt32, myoffsetof(AActor, tid), VARF_ReadOnly); - meta->AddNativeField(NAME_TIDtoHate, TypeSInt32, myoffsetof(AActor, TIDtoHate), VARF_ReadOnly); - meta->AddNativeField(NAME_WaterLevel, TypeSInt32, myoffsetof(AActor, waterlevel), VARF_ReadOnly); - meta->AddNativeField(NAME_Score, TypeSInt32, myoffsetof(AActor, Score)); - meta->AddNativeField(NAME_Accuracy, TypeSInt32, myoffsetof(AActor, accuracy)); - meta->AddNativeField(NAME_Stamina, TypeSInt32, myoffsetof(AActor, stamina)); - meta->AddNativeField(NAME_MeleeRange, TypeFloat64, myoffsetof(AActor, meleerange)); - meta->AddNativeField("PainThreshold", TypeSInt32, myoffsetof(AActor, PainThreshold)); - meta->AddNativeField("Gravity", TypeFloat64, myoffsetof(AActor, Gravity)); - meta->AddNativeField("FloorClip", TypeFloat64, myoffsetof(AActor, Floorclip)); - meta->AddNativeField("DamageType", TypeName, myoffsetof(AActor, DamageType)); - meta->AddNativeField("DamageTypeReceived", TypeName, myoffsetof(AActor, DamageTypeReceived)); - meta->AddNativeField("FloatBobPhase", TypeUInt8, myoffsetof(AActor, FloatBobPhase)); - meta->AddNativeField("RipperLevel", TypeSInt32, myoffsetof(AActor, RipperLevel)); - meta->AddNativeField("RipLevelMin", TypeSInt32, myoffsetof(AActor, RipLevelMin)); - meta->AddNativeField("RipLevelMax", TypeSInt32, myoffsetof(AActor, RipLevelMax)); - meta->AddNativeField("Species", TypeName, myoffsetof(AActor, Species)); - meta->AddNativeField("Alternative", TypeActor, myoffsetof(AActor, alternative)); - meta->AddNativeField("goal", TypeActor, myoffsetof(AActor, goal)); - meta->AddNativeField("MinMissileChance", TypeUInt8, myoffsetof(AActor, MinMissileChance)); - meta->AddNativeField("LastLookPlayerNumber",TypeSInt8, myoffsetof(AActor, LastLookPlayerNumber)); - meta->AddNativeField("SpawnFlags", TypeUInt32, myoffsetof(AActor, SpawnFlags)); - meta->AddNativeField("meleethreshold", TypeFloat64, myoffsetof(AActor, meleethreshold)); - meta->AddNativeField("maxtargetrange", TypeFloat64, myoffsetof(AActor, maxtargetrange)); - meta->AddNativeField("bouncefactor", TypeFloat64, myoffsetof(AActor, bouncefactor)); - meta->AddNativeField("wallbouncefactor", TypeFloat64, myoffsetof(AActor, wallbouncefactor)); - meta->AddNativeField("bouncecount", TypeSInt32, myoffsetof(AActor, bouncecount)); - meta->AddNativeField("friction", TypeFloat64, myoffsetof(AActor, Friction)); - meta->AddNativeField("FastChaseStrafeCount",TypeSInt32, myoffsetof(AActor, FastChaseStrafeCount)); - meta->AddNativeField("pushfactor", TypeFloat64, myoffsetof(AActor, pushfactor)); - meta->AddNativeField("lastpush", TypeSInt32, myoffsetof(AActor, lastpush)); - meta->AddNativeField("activationtype", TypeSInt32, myoffsetof(AActor, activationtype)); - meta->AddNativeField("lastbump", TypeSInt32, myoffsetof(AActor, lastbump)); - meta->AddNativeField("DesignatedTeam", TypeSInt32, myoffsetof(AActor, DesignatedTeam)); - meta->AddNativeField("BlockingMobj", TypeActor, myoffsetof(AActor, BlockingMobj)); - //line_t *BlockingLine; // Line that blocked the last move - meta->AddNativeField("PoisonDamage", TypeSInt32, myoffsetof(AActor, PoisonDamage)); - meta->AddNativeField("PoisonDamageType", TypeName, myoffsetof(AActor, PoisonDamageType)); - meta->AddNativeField("PoisonDuration", TypeSInt32, myoffsetof(AActor, PoisonDuration)); - meta->AddNativeField("PoisonPeriod", TypeSInt32, myoffsetof(AActor, PoisonPeriod)); - meta->AddNativeField("PoisonDamageReceived",TypeSInt32, myoffsetof(AActor, PoisonDamageReceived)); - meta->AddNativeField("PoisonDamageTypeReceived", TypeName, myoffsetof(AActor, PoisonDamageTypeReceived)); - meta->AddNativeField("PoisonDurationReceived", TypeSInt32, myoffsetof(AActor, PoisonDurationReceived)); - meta->AddNativeField("PoisonPeriodReceived", TypeSInt32, myoffsetof(AActor, PoisonPeriodReceived)); - meta->AddNativeField("Poisoner", TypeActor, myoffsetof(AActor, Poisoner)); - meta->AddNativeField("Inv", TypeInventory, myoffsetof(AActor, Inventory)); // Needs to be renamed because it hides the actual type. - meta->AddNativeField("smokecounter", TypeUInt8, myoffsetof(AActor, smokecounter)); - meta->AddNativeField("FriendPlayer", TypeUInt8, myoffsetof(AActor, FriendPlayer)); - meta->AddNativeField("Translation", TypeUInt32, myoffsetof(AActor, Translation)); - meta->AddNativeField("AttackSound", TypeSound, myoffsetof(AActor, AttackSound)); - meta->AddNativeField("DeathSound", TypeSound, myoffsetof(AActor, DeathSound)); - meta->AddNativeField("SeeSound", TypeSound, myoffsetof(AActor, SeeSound)); - meta->AddNativeField("PainSound", TypeSound, myoffsetof(AActor, PainSound)); - meta->AddNativeField("ActiveSound", TypeSound, myoffsetof(AActor, ActiveSound)); - meta->AddNativeField("UseSound", TypeSound, myoffsetof(AActor, UseSound)); - meta->AddNativeField("BounceSound", TypeSound, myoffsetof(AActor, BounceSound)); - meta->AddNativeField("WallBounceSound", TypeSound, myoffsetof(AActor, WallBounceSound)); - meta->AddNativeField("CrushPainSound", TypeSound, myoffsetof(AActor, CrushPainSound)); - meta->AddNativeField("MaxDropoffHeight", TypeFloat64, myoffsetof(AActor, MaxDropOffHeight)); - meta->AddNativeField("MaxStepHeight", TypeFloat64, myoffsetof(AActor, MaxStepHeight)); - meta->AddNativeField("PainChance", TypeSInt16, myoffsetof(AActor, PainChance)); - meta->AddNativeField("PainType", TypeName, myoffsetof(AActor, PainType)); - meta->AddNativeField("DeathType", TypeName, myoffsetof(AActor, DeathType)); - meta->AddNativeField("DamageFactor", TypeFloat64, myoffsetof(AActor, DamageFactor)); - meta->AddNativeField("DamageMultiply", TypeFloat64, myoffsetof(AActor, DamageMultiply)); - meta->AddNativeField("TelefogSourceType", TypeActorClass, myoffsetof(AActor, TeleFogSourceType)); - meta->AddNativeField("TelefogDestType", TypeActorClass, myoffsetof(AActor, TeleFogDestType)); - meta->AddNativeField("SpawnState", TypeState, myoffsetof(AActor, SpawnState), VARF_ReadOnly); - meta->AddNativeField("SeeState", TypeState, myoffsetof(AActor, SeeState), VARF_ReadOnly); - meta->AddNativeField("MeleeState", TypeState, myoffsetof(AActor, MeleeState)); - meta->AddNativeField("MissileState", TypeState, myoffsetof(AActor, MissileState)); - //int ConversationRoot; // THe root of the current dialogue - //FStrifeDialogueNode *Conversation; // [RH] The dialogue to show when this actor is "used." + // needs to be done manually until it can be given a proper type. meta->AddNativeField("DecalGenerator", NewPointer(TypeVoid), myoffsetof(AActor, DecalGenerator)); - //FDecalBase *DecalGenerator; // synthesize a symbol for each flag from the flag name tables to avoid redundant declaration of them. for (size_t i = 0; ActorFlagDefs[i].flagbit != 0xffffffff; i++) diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index b5f569108..f1cc8e792 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -200,7 +200,7 @@ DPSprite *player_t::FindPSprite(int layer) return pspr; } -DEFINE_ACTION_FUNCTION(_Player, FindPSprite) // the underscore is needed to get past the name mangler which removes the first clas name character to match the class representation (needs to be fixed in a later commit) +DEFINE_ACTION_FUNCTION(_PlayerInfo, FindPSprite) // the underscore is needed to get past the name mangler which removes the first clas name character to match the class representation (needs to be fixed in a later commit) { PARAM_SELF_STRUCT_PROLOGUE(player_t); PARAM_INT(id); @@ -220,7 +220,7 @@ void P_SetPsprite(player_t *player, PSPLayers id, FState *state, bool pending) player->GetPSprite(id)->SetState(state, pending); } -DEFINE_ACTION_FUNCTION(_Player, SetPSprite) // the underscore is needed to get past the name mangler which removes the first clas name character to match the class representation (needs to be fixed in a later commit) +DEFINE_ACTION_FUNCTION(_PlayerInfo, SetPSprite) // the underscore is needed to get past the name mangler which removes the first clas name character to match the class representation (needs to be fixed in a later commit) { PARAM_SELF_STRUCT_PROLOGUE(player_t); PARAM_INT(id); @@ -291,7 +291,7 @@ DPSprite *player_t::GetPSprite(PSPLayers layer) return pspr; } -DEFINE_ACTION_FUNCTION(_Player, GetPSprite) // the underscore is needed to get past the name mangler which removes the first clas name character to match the class representation (needs to be fixed in a later commit) +DEFINE_ACTION_FUNCTION(_PlayerInfo, GetPSprite) // the underscore is needed to get past the name mangler which removes the first clas name character to match the class representation (needs to be fixed in a later commit) { PARAM_SELF_STRUCT_PROLOGUE(player_t); PARAM_INT(id); @@ -1653,7 +1653,7 @@ void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int i P_SetPsprite(player, PSP_FLASH, flashstate + index, true); } -DEFINE_ACTION_FUNCTION(_Player, SetSafeFlash) +DEFINE_ACTION_FUNCTION(_PlayerInfo, SetSafeFlash) { PARAM_SELF_STRUCT_PROLOGUE(player_t); PARAM_OBJECT(weapon, AWeapon); diff --git a/src/p_user.cpp b/src/p_user.cpp index 84fcbd313..5b25fd713 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -3147,7 +3147,7 @@ bool P_IsPlayerTotallyFrozen(const player_t *player) void P_InitPlayerForScript() { - PStruct *pstruct = NewNativeStruct("Player", nullptr); + PStruct *pstruct = NewNativeStruct("PlayerInfo", nullptr); pstruct->Size = sizeof(player_t); pstruct->Align = alignof(player_t); PArray *parray = NewArray(pstruct, MAXPLAYERS); diff --git a/src/sc_man_scanner.re b/src/sc_man_scanner.re index 194582d73..59113e4a7 100644 --- a/src/sc_man_scanner.re +++ b/src/sc_man_scanner.re @@ -111,6 +111,10 @@ std2: 'sbyte' { RET(TK_SByte); } 'short' { RET(TK_Short); } 'ushort' { RET(TK_UShort); } + 'int8' { RET(TK_Int8); } + 'uint8' { RET(TK_UInt8); } + 'int16' { RET(TK_Int16); } + 'uint16' { RET(TK_UInt16); } 'int' { RET(TK_Int); } 'uint' { RET(TK_UInt); } 'long' { RET(TK_Long); } diff --git a/src/sc_man_tokens.h b/src/sc_man_tokens.h index 801d02be3..8ea05d7e4 100644 --- a/src/sc_man_tokens.h +++ b/src/sc_man_tokens.h @@ -55,6 +55,10 @@ xx(TK_Byte, "'byte'") xx(TK_SByte, "'sbyte'") xx(TK_Short, "'short'") xx(TK_UShort, "'ushort'") +xx(TK_Int8, "'int8'") +xx(TK_UInt8, "'uint8'") +xx(TK_Int16, "'int16'") +xx(TK_UInt16, "'uint16'") xx(TK_Int, "'int'") xx(TK_UInt, "'uint'") xx(TK_Long, "'long'") diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 3f8f09eb7..1cc16214c 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -4082,7 +4082,7 @@ ExpEmit FxBinaryLogical::Emit(VMFunctionBuilder *build) build->Emit(OP_JMP, 1); auto ctarget = build->Emit(OP_LI, to.RegNum, (Operator == TK_AndAnd) ? 0 : 1); for (auto addr : patchspots) build->Backpatch(addr, ctarget); - list.Clear(); + list.DeleteAndClear(); list.ShrinkToFit(); return to; } @@ -5232,6 +5232,8 @@ ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build) // 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); + choices.DeleteAndClear(); + choices.ShrinkToFit(); return resultreg; } @@ -6303,7 +6305,8 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) { auto parentfield = static_cast(classx)->membervar; // PFields are garbage collected so this will be automatically taken care of later. - auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset, membervar->BitValue); + auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset); + newfield->BitValue = membervar->BitValue; static_cast(classx)->membervar = newfield; classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. auto x = classx->Resolve(ctx); @@ -6313,7 +6316,8 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) else if (classx->ExprType == EFX_GlobalVariable) { auto parentfield = static_cast(classx)->membervar; - auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset, membervar->BitValue); + auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset); + newfield->BitValue = membervar->BitValue; static_cast(classx)->membervar = newfield; classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. auto x = classx->Resolve(ctx); @@ -6323,7 +6327,8 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) else if (classx->ExprType == EFX_StackVariable) { auto parentfield = static_cast(classx)->membervar; - auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset, membervar->BitValue); + auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset); + newfield->BitValue = membervar->BitValue; static_cast(classx)->ReplaceField(newfield); classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. auto x = classx->Resolve(ctx); @@ -7382,7 +7387,7 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; - ArgList.Clear(); + ArgList.DeleteAndClear(); ArgList.ShrinkToFit(); if (EmitTail) @@ -7661,7 +7666,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) ExpEmit reg; if (CheckEmitCast(build, EmitTail, reg)) { - ArgList.Clear(); + ArgList.DeleteAndClear(); ArgList.ShrinkToFit(); return reg; } @@ -7704,7 +7709,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) { count += EmitParameter(build, ArgList[i], ScriptPosition); } - ArgList.Clear(); + ArgList.DeleteAndClear(); ArgList.ShrinkToFit(); // Get a constant register for this function @@ -7905,7 +7910,7 @@ ExpEmit FxFlopFunctionCall::Emit(VMFunctionBuilder *build) } build->Emit(OP_FLOP, to.RegNum, from.RegNum, FxFlops[Index].Flop); - ArgList.Clear(); + ArgList.DeleteAndClear(); ArgList.ShrinkToFit(); return to; } @@ -8311,7 +8316,7 @@ ExpEmit FxSwitchStatement::Emit(VMFunctionBuilder *build) build->BackpatchToHere(addr); } if (!defaultset) build->BackpatchToHere(DefaultAddress); - Content.Clear(); + Content.DeleteAndClear(); Content.ShrinkToFit(); return ExpEmit(); } diff --git a/src/scripting/thingdef.h b/src/scripting/thingdef.h index 5bad10c36..dd8529252 100644 --- a/src/scripting/thingdef.h +++ b/src/scripting/thingdef.h @@ -147,6 +147,7 @@ inline void ResetBaggage (Baggage *bag, PClassActor *stateclass) //========================================================================== AFuncDesc *FindFunction(PStruct *cls, const char * string); +FieldDesc *FindField(PStruct *cls, const char * string); FxExpression *ParseExpression(FScanner &sc, PClassActor *cls, bool mustresolve = false); diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 23aba902f..d50f73bd3 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -46,6 +46,7 @@ static TArray properties; static TArray AFTable; +static TArray FieldTable; //========================================================================== // @@ -613,6 +614,37 @@ AFuncDesc *FindFunction(PStruct *cls, const char * string) return nullptr; } +//========================================================================== +// +// Find a function by name using a binary search +// +//========================================================================== + +FieldDesc *FindField(PStruct *cls, const char * string) +{ + int min = 0, max = FieldTable.Size() - 1; + + while (min <= max) + { + int mid = (min + max) / 2; + int lexval = stricmp(cls->TypeName.GetChars(), FieldTable[mid].ClassName + 1); + if (lexval == 0) lexval = stricmp(string, FieldTable[mid].FieldName); + if (lexval == 0) + { + return &FieldTable[mid]; + } + else if (lexval > 0) + { + min = mid + 1; + } + else + { + max = mid - 1; + } + } + return nullptr; +} + //========================================================================== // @@ -651,6 +683,14 @@ static int funccmp(const void * a, const void * b) return res; } +static int fieldcmp(const void * a, const void * b) +{ + // +1 to get past the prefix letter of the native class name, which gets omitted by the FName for the class. + int res = stricmp(((FieldDesc*)a)->ClassName + 1, ((FieldDesc*)b)->ClassName + 1); + if (res == 0) res = stricmp(((FieldDesc*)a)->FieldName, ((FieldDesc*)b)->FieldName); + return res; +} + //========================================================================== // // Initialization @@ -716,4 +756,19 @@ void InitThingdef() AFTable.ShrinkToFit(); qsort(&AFTable[0], AFTable.Size(), sizeof(AFTable[0]), funccmp); } + + FieldTable.Clear(); + if (FieldTable.Size() == 0) + { + FAutoSegIterator probe(FRegHead, FRegTail); + + while (*++probe != NULL) + { + FieldDesc *afield = (FieldDesc *)*probe; + FieldTable.Push(*afield); + } + FieldTable.ShrinkToFit(); + qsort(&FieldTable[0], FieldTable.Size(), sizeof(FieldTable[0]), fieldcmp); + } + } diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 7d56b32db..f2edca9b9 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -1013,6 +1013,15 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction typedef int(*actionf_p)(VMFrameStack *stack, VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret);/*(VM_ARGS)*/ +struct FieldDesc +{ + const char *ClassName; + const char *FieldName; + unsigned FieldOffset; + unsigned FieldSize; + int BitValue; +}; + struct AFuncDesc { const char *ClassName; @@ -1023,12 +1032,17 @@ struct AFuncDesc #if defined(_MSC_VER) #pragma section(".areg$u",read) +#pragma section(".freg$u",read) #define MSVC_ASEG __declspec(allocate(".areg$u")) +#define MSVC_FSEG __declspec(allocate(".freg$u")) #define GCC_ASEG +#define GCC_FSEG #else #define MSVC_ASEG +#define MSVC_FSEG #define GCC_ASEG __attribute__((section(SECTION_AREG))) __attribute__((used)) +#define GCC_FSEG __attribute__((section(SECTION_FREG))) __attribute__((used)) #endif // Macros to handle action functions. These are here so that I don't have to @@ -1043,6 +1057,32 @@ struct AFuncDesc MSVC_ASEG AFuncDesc const *const cls##_##name##_HookPtr GCC_ASEG = &cls##_##name##_Hook; \ static int AF_##cls##_##name(VM_ARGS) +// cls is the scripted class name, icls the internal one (e.g. player_t vs. Player) +#define DEFINE_FIELD_X(cls, icls, name) \ + static const FieldDesc VMField_##icls##_##name = { "A" #cls, #name, (unsigned)myoffsetof(icls, name), (unsigned)sizeof(icls::name), 0 }; \ + extern FieldDesc const *const VMField_##icls##_##name##_HookPtr; \ + MSVC_FSEG FieldDesc const *const VMField_##icls##_##name##_HookPtr GCC_FSEG = &VMField_##cls##_##name; + +#define DEFINE_FIELD_X_BIT(cls, icls, name, bitval) \ + static const FieldDesc VMField_##icls##_##name = { "A" #cls, #name, (unsigned)myoffsetof(icls, name), (unsigned)sizeof(icls::name), bitval }; \ + extern FieldDesc const *const VMField_##icls##_##name##_HookPtr; \ + MSVC_FSEG FieldDesc const *const VMField_##icls##_##name##_HookPtr GCC_FSEG = &VMField_##cls##_##name; + +#define DEFINE_FIELD(cls, name) \ + static const FieldDesc VMField_##cls##_##name = { #cls, #name, (unsigned)myoffsetof(cls, name), (unsigned)sizeof(cls::name), 0 }; \ + extern FieldDesc const *const VMField_##cls##_##name##_HookPtr; \ + MSVC_FSEG FieldDesc const *const VMField_##cls##_##name##_HookPtr GCC_FSEG = &VMField_##cls##_##name; + +#define DEFINE_FIELD_NAMED(cls, name, scriptname) \ + static const FieldDesc VMField_##cls##_##scriptname = { #cls, #scriptname, (unsigned)myoffsetof(cls, name), (unsigned)sizeof(cls::name), 0 }; \ + extern FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr; \ + MSVC_FSEG FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr GCC_FSEG = &VMField_##cls##_##scriptname; + +#define DEFINE_FIELD_BIT(cls, name, scriptname, bitval) \ + static const FieldDesc VMField_##cls##_##scriptname = { #cls, #scriptname, (unsigned)myoffsetof(cls, name), (unsigned)sizeof(cls::name), bitval }; \ + extern FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr; \ + MSVC_FSEG FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr GCC_FSEG = &VMField_##cls##_##scriptname; + class AActor; void CallAction(VMFrameStack *stack, VMFunction *vmfunc, AActor *self); #define CALL_ACTION(name, self) CallAction(stack, AActor_##name##_VMPtr, self); diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index c76df32e3..72bfcf735 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1186,6 +1186,7 @@ void ZCCCompiler::CompileAllFields() // Create copies of the arrays which can be altered auto Classes = this->Classes; auto Structs = this->Structs; + TMap HasNativeChildren; // first step: Look for native classes with native children. // These may not have any variables added to them because it'd clash with the native definitions. @@ -1200,8 +1201,8 @@ void ZCCCompiler::CompileAllFields() { if (ac->ParentClass == c->Type() && ac->Size != TentativeClass) { - Error(c->cls, "Trying to add fields to class '%s' with native children", c->Type()->TypeName.GetChars()); - Classes.Delete(i--); + // Only set a marker here, so that we can print a better message when the actual fields get added. + HasNativeChildren.Insert(ac, true); break; } } @@ -1236,7 +1237,7 @@ void ZCCCompiler::CompileAllFields() type->Size = Classes[i]->Type()->ParentClass->Size; } } - if (CompileFields(type, Classes[i]->Fields, nullptr, &Classes[i]->TreeNodes, false)) + if (CompileFields(type, Classes[i]->Fields, nullptr, &Classes[i]->TreeNodes, false, !!HasNativeChildren.CheckKey(type))) { // Remove from the list if all fields got compiled. Classes.Delete(i--); @@ -1263,11 +1264,12 @@ void ZCCCompiler::CompileAllFields() // //========================================================================== -bool ZCCCompiler::CompileFields(PStruct *type, TArray &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct) +bool ZCCCompiler::CompileFields(PStruct *type, TArray &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct, bool hasnativechildren) { while (Fields.Size() > 0) { auto field = Fields[0]; + FieldDesc *fd = nullptr; PType *fieldtype = DetermineType(type, field, field->Names->Name, field->Type, true, true); @@ -1289,8 +1291,9 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray &Fiel if (field->Flags & ZCC_Native) { - // todo: get the native address of this field. + varflags |= VARF_Native | VARF_Transient; } + if (field->Flags & ZCC_Meta) { varflags |= VARF_ReadOnly; // metadata implies readonly @@ -1312,8 +1315,32 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray &Fiel { thisfieldtype = ResolveArraySize(thisfieldtype, name->ArraySize, &type->Symbols); } - - type->AddField(name->Name, thisfieldtype, varflags); + + if (varflags & VARF_Native) + { + fd = FindField(type, FName(name->Name).GetChars()); + if (fd == nullptr) + { + Error(field, "The member variable '%s.%s' has not been exported from the executable.", type->TypeName.GetChars(), FName(name->Name).GetChars()); + } + else if (thisfieldtype->Size != fd->FieldSize) + { + Error(field, "The member variable '%s.%s' has mismatching sizes in internal and external declaration. (Internal = %d, External = %d)", type->TypeName.GetChars(), FName(name->Name).GetChars(), fd->FieldSize, thisfieldtype->Size); + } + // Q: Should we check alignment, too? A mismatch may be an indicator for bad assumptions. + else + { + type->AddNativeField(name->Name, thisfieldtype, fd->FieldOffset, varflags, fd->BitValue); + } + } + else if (hasnativechildren) + { + Error(field, "Cannot add field %s to %s. %s has native children which means it size may not change.", type->TypeName.GetChars(), fd->FieldSize, FName(name->Name).GetChars()); + } + else + { + type->AddField(name->Name, thisfieldtype, varflags); + } } name = static_cast(name->SiblingNext); } while (name != field->Names); @@ -2133,7 +2160,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool afd = FindFunction(c->Type(), FName(f->Name).GetChars()); if (afd == nullptr) { - Error(f, "The function '%s' has not been exported from the executable.", FName(f->Name).GetChars()); + Error(f, "The function '%s.%s' has not been exported from the executable.", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()); } else { diff --git a/src/scripting/zscript/zcc_compile.h b/src/scripting/zscript/zcc_compile.h index 84e314353..9599b4b96 100644 --- a/src/scripting/zscript/zcc_compile.h +++ b/src/scripting/zscript/zcc_compile.h @@ -91,7 +91,7 @@ private: bool CompileConstant(ZCC_ConstantDef *def, PSymbolTable *Symbols); void CompileAllFields(); - bool CompileFields(PStruct *type, TArray &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct); + bool CompileFields(PStruct *type, TArray &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct, bool hasnativechildren = false); FString FlagsToString(uint32_t flags); PType *DetermineType(PType *outertype, ZCC_TreeNode *field, FName name, ZCC_Type *ztype, bool allowarraytypes, bool formember); PType *ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PSymbolTable *sym); diff --git a/src/scripting/zscript/zcc_parser.cpp b/src/scripting/zscript/zcc_parser.cpp index de3d2c7e1..37fd8ff0c 100644 --- a/src/scripting/zscript/zcc_parser.cpp +++ b/src/scripting/zscript/zcc_parser.cpp @@ -137,6 +137,10 @@ static void InitTokenMap() TOKENDEF2(TK_Byte, ZCC_BYTE, NAME_Byte); TOKENDEF2(TK_Short, ZCC_SHORT, NAME_Short); TOKENDEF2(TK_UShort, ZCC_USHORT, NAME_uShort); + TOKENDEF2(TK_Int8, ZCC_SBYTE, NAME_int8); + TOKENDEF2(TK_UInt8, ZCC_BYTE, NAME_uint8); + TOKENDEF2(TK_Int16, ZCC_SHORT, NAME_int16); + TOKENDEF2(TK_UInt16, ZCC_USHORT, NAME_uint16); TOKENDEF2(TK_Int, ZCC_INT, NAME_Int); TOKENDEF2(TK_UInt, ZCC_UINT, NAME_uInt); TOKENDEF2(TK_Bool, ZCC_BOOL, NAME_Bool); diff --git a/src/zzautozend.cpp b/src/zzautozend.cpp index 5567b1ddd..18c020310 100644 --- a/src/zzautozend.cpp +++ b/src/zzautozend.cpp @@ -43,6 +43,9 @@ __declspec(allocate(".areg$z")) void *const ARegTail = 0; #pragma section(".creg$z",read) __declspec(allocate(".creg$z")) void *const CRegTail = 0; +#pragma section(".freg$z",read) +__declspec(allocate(".freg$z")) void *const FRegTail = 0; + #pragma section(".greg$z",read) __declspec(allocate(".greg$z")) void *const GRegTail = 0; @@ -56,6 +59,7 @@ __declspec(allocate(".yreg$z")) void *const YRegTail = 0; void *const ARegTail __attribute__((section(SECTION_AREG))) = 0; void *const CRegTail __attribute__((section(SECTION_CREG))) = 0; +void *const FRegTail __attribute__((section(SECTION_FREG))) = 0; void *const GRegTail __attribute__((section(SECTION_GREG))) = 0; void *const YRegTail __attribute__((section(SECTION_YREG))) = 0; diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index db86647c3..da9db687c 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -5,6 +5,168 @@ class Actor : Thinker native const ONCEILINGZ = 2147483647.0; const FLOATRANDZ = ONCEILINGZ-1; + // flags are not defined here, the native fields for those get synthesized from the internal tables. + + // for some comments on these fields, see their native representations in actor.h. + native PlayerInfo Player; + native readonly vector3 Pos; + native vector3 Prev; + native double spriteAngle; + native double spriteRotation; + native double VisibleStartAngle; + native double VisibleStartPitch; + native double VisibleEndAngle; + native double VisibleEndPitch; + native double Angle; + native double Pitch; + native double Roll; + native vector3 Vel; + native double Speed; + native double FloatSpeed; + native SpriteID sprite; + native uint8 frame; + native vector2 Scale; + native TextureID picnum; + native double Alpha; + native color fillcolor; + native Sector CurSector; + native double CeilingZ; + native double FloorZ; + native double DropoffZ; + native Sector floorsector; + native TextureID floorpic; + native int floorterrain; + native Sector ceilingsector; + native TextureID ceilingpic; + native double Height; + native readonly double Radius; + native double projectilepassheight; + native int tics; + native readonly State CurState; + native readonly int Damage; + native int projectilekickback; + native int special1; + native int special2; + native double specialf1; + native double specialf2; + native int weaponspecial; + native int Health; + native uint8 movedir; + native int8 visdir; + native int16 movecount; + native int16 strafecount; + native Actor Target; + native Actor Master; + native Actor Tracer; + native Actor LastHeard; + native Actor LastEnemy; + native Actor LastLookActor; + native int ReactionTime; + native int Threshold; + native readonly int DefThreshold; + native readonly vector3 SpawnPoint; + native readonly uint16 SpawnAngle; + native int StartHealth; + native uint8 WeaveIndexXY; + native uint8 WeaveIndexZ; + native int skillrespawncount; + native int Args[5]; + native int Mass; + native int Special; + native readonly int TID; + native readonly int TIDtoHate; + native readonly int WaterLevel; + native int Score; + native int Accuracy; + native int Stamina; + native double MeleeRange; + native int PainThreshold; + native double Gravity; + native double FloorClip; + native name DamageType; + native name DamageTypeReceived; + native uint8 FloatBobPhase; + native int RipperLevel; + native int RipLevelMin; + native int RipLevelMax; + native name Species; + native Actor Alternative; + native Actor goal; + native uint8 MinMissileChance; + native int8 LastLookPlayerNumber; + native uint SpawnFlags; + native double meleethreshold; + native double maxtargetrange; + native double bouncefactor; + native double wallbouncefactor; + native int bouncecount; + native double friction; + native int FastChaseStrafeCount; + native double pushfactor; + native int lastpush; + native int activationtype; + native int lastbump; + native int DesignatedTeam; + native Actor BlockingMobj; + native int PoisonDamage; + native name PoisonDamageType; + native int PoisonDuration; + native int PoisonPeriod; + native int PoisonDamageReceived; + native name PoisonDamageTypeReceived; + native int PoisonDurationReceived; + native int PoisonPeriodReceived; + native Actor Poisoner; + native Inventory Inv; + native uint8 smokecounter; + native uint8 FriendPlayer; + native uint Translation; + native sound AttackSound; + native sound DeathSound; + native sound SeeSound; + native sound PainSound; + native sound ActiveSound; + native sound UseSound; + native sound BounceSound; + native sound WallBounceSound; + native sound CrushPainSound; + native double MaxDropoffHeight; + native double MaxStepHeight; + native int16 PainChance; + native name PainType; + native name DeathType; + native double DamageFactor; + native double DamageMultiply; + native Class TelefogSourceType; + native Class TelefogDestType; + native readonly State SpawnState; + native readonly State SeeState; + native State MeleeState; + native State MissileState; + + // need some definition work first + //FRenderStyle RenderStyle; + //line_t *BlockingLine; // Line that blocked the last move + //int ConversationRoot; // THe root of the current dialogue + //DecalBase DecalGenerator; + + // deprecated things. + native readonly deprecated double X; + native readonly deprecated double Y; + native readonly deprecated double Z; + native readonly deprecated double VelX; + native readonly deprecated double VelY; + native readonly deprecated double VelZ; + native readonly deprecated double MomX; + native readonly deprecated double MomY; + native readonly deprecated double MomZ; + native deprecated double ScaleX; + native deprecated double ScaleY; + + //int ConversationRoot; // THe root of the current dialogue; + //FStrifeDialogueNode *Conversation; // [RH] The dialogue to show when this actor is used.; + + Default { Scale 1; diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 7a2790726..b3f48acae 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -47,4 +47,8 @@ class SpotState : Object native { native static SpotState GetSpotState(); native SpecialSpot GetNextInList(class type, int skipcounter); -} \ No newline at end of file +} + +struct Sector native +{ +} diff --git a/wadsrc/static/zscript/doom/bossbrain.txt b/wadsrc/static/zscript/doom/bossbrain.txt index cde600701..e6a13317f 100644 --- a/wadsrc/static/zscript/doom/bossbrain.txt +++ b/wadsrc/static/zscript/doom/bossbrain.txt @@ -374,7 +374,7 @@ extend class Actor } // Make it act as if it was around when the player first made noise // (if the player has made noise). - newmobj.LastHeard = newmobj.Sector.SoundTarget; + newmobj.LastHeard = newmobj.CurSector.SoundTarget; if (newmobj.SeeState != null && newmobj.LookForPlayers (true)) { diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 4f9e84333..71cdb8479 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -77,7 +77,7 @@ class PSprite : Object native { } -struct Player native +struct PlayerInfo native // this is what internally is player_t { native void SetPsprite(int id, State stat, bool pending = false); native void SetSafeFlash(Weapon weap, State flashstate, int index); From e2167c661c3a036537c536eac3b122b075bdf890 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Tue, 22 Nov 2016 21:16:13 +0100 Subject: [PATCH 075/185] - Fixed GCC/Clang compile errors. --- src/doomtype.h | 2 ++ src/virtual.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/doomtype.h b/src/doomtype.h index 129c5f122..a9818df78 100644 --- a/src/doomtype.h +++ b/src/doomtype.h @@ -264,12 +264,14 @@ char ( &_ArraySizeHelper( T (&array)[N] ))[N]; #ifdef __MACH__ #define SECTION_AREG "__DATA,areg" #define SECTION_CREG "__DATA,creg" +#define SECTION_FREG "__DATA,freg" #define SECTION_GREG "__DATA,greg" #define SECTION_MREG "__DATA,mreg" #define SECTION_YREG "__DATA,yreg" #else #define SECTION_AREG "areg" #define SECTION_CREG "creg" +#define SECTION_FREG "freg" #define SECTION_GREG "greg" #define SECTION_MREG "mreg" #define SECTION_YREG "yreg" diff --git a/src/virtual.h b/src/virtual.h index 8842eb891..f3167407d 100644 --- a/src/virtual.h +++ b/src/virtual.h @@ -228,4 +228,4 @@ VMEXPORT_NATIVES_END(AActor) /* VMEXPORT_NATIVES_START(AActor, DThinker) VMEXPORT_NATIVES_END(AActor) -*/ \ No newline at end of file +*/ From e1c4e4939a31b8a875d9206ae2a5597c62b1ceb2 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Tue, 22 Nov 2016 21:20:42 +0100 Subject: [PATCH 076/185] - Fixed the order of the MS sections. --- src/__autostart.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/__autostart.cpp b/src/__autostart.cpp index 3daabbeae..13e104d75 100644 --- a/src/__autostart.cpp +++ b/src/__autostart.cpp @@ -52,8 +52,8 @@ // a single section during the final link. (.rdata is the standard section // for initialized read-only data.) -#pragma comment(linker, "/merge:.areg=.rdata /merge:.creg=.rdata /merge:.greg=.rdata") -#pragma comment(linker, "/merge:.yreg=.rdata /merge:.freg=.rdata") +#pragma comment(linker, "/merge:.areg=.rdata /merge:.creg=.rdata /merge:.freg=.rdata") +#pragma comment(linker, "/merge:.greg=.rdata /merge:.yreg=.rdata") #pragma section(".areg$a",read) __declspec(allocate(".areg$a")) void *const ARegHead = 0; @@ -61,12 +61,12 @@ __declspec(allocate(".areg$a")) void *const ARegHead = 0; #pragma section(".creg$a",read) __declspec(allocate(".creg$a")) void *const CRegHead = 0; -#pragma section(".greg$a",read) -__declspec(allocate(".greg$a")) void *const GRegHead = 0; - #pragma section(".freg$a",read) __declspec(allocate(".freg$a")) void *const FRegHead = 0; +#pragma section(".greg$a",read) +__declspec(allocate(".greg$a")) void *const GRegHead = 0; + #pragma section(".yreg$a",read) __declspec(allocate(".yreg$a")) void *const YRegHead = 0; From 099b9970efbc00b511a4520e435ccfa29543e751 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 22 Nov 2016 23:42:32 +0100 Subject: [PATCH 077/185] - added proper definitions for all exported native fields. - synthesize native fields for all declared flags, not just for AActor. --- src/actor.h | 2 - src/d_player.h | 1 - src/dobject.cpp | 17 +- src/dobject.h | 6 +- src/dobjtype.cpp | 2 +- src/g_shared/a_armor.cpp | 15 +- src/g_shared/a_pickups.h | 2 - src/g_shared/a_weapons.cpp | 80 +++++-- src/p_mobj.cpp | 35 +-- src/p_pspr.cpp | 48 ++-- src/p_pspr.h | 2 +- src/p_user.cpp | 224 +++++++++--------- src/scripting/thingdef_data.cpp | 57 +++-- src/scripting/vm/vm.h | 7 +- src/scripting/zscript/zcc-parse.lemon | 3 +- src/scripting/zscript/zcc_compile.cpp | 9 +- src/scripting/zscript/zcc_parser.h | 5 + wadsrc/static/zscript/base.txt | 6 +- wadsrc/static/zscript/constants.txt | 1 + wadsrc/static/zscript/doom/weaponchaingun.txt | 2 +- wadsrc/static/zscript/shared/botstuff.txt | 4 + wadsrc/static/zscript/shared/inventory.txt | 34 +++ wadsrc/static/zscript/shared/player.txt | 136 ++++++++++- 23 files changed, 452 insertions(+), 246 deletions(-) diff --git a/src/actor.h b/src/actor.h index d8bb1a897..83873adc5 100644 --- a/src/actor.h +++ b/src/actor.h @@ -565,7 +565,6 @@ class DDropItem : public DObject { DECLARE_CLASS(DDropItem, DObject) HAS_OBJECT_POINTERS - HAS_FIELDS public: DDropItem *Next; FName Name; @@ -579,7 +578,6 @@ const double MinVel = EQUAL_EPSILON; class AActor : public DThinker { DECLARE_CLASS_WITH_META (AActor, DThinker, PClassActor) - HAS_FIELDS HAS_OBJECT_POINTERS public: AActor () throw(); diff --git a/src/d_player.h b/src/d_player.h index d3f684137..d1678b619 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -100,7 +100,6 @@ FString GetPrintableDisplayName(PClassPlayerPawn *cls); class APlayerPawn : public AActor { DECLARE_CLASS_WITH_META(APlayerPawn, AActor, PClassPlayerPawn) - HAS_FIELDS HAS_OBJECT_POINTERS public: diff --git a/src/dobject.cpp b/src/dobject.cpp index ad575bebc..e3e37432b 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -64,12 +64,15 @@ ClassReg DObject::RegistrationInfo = &DVMObject::RegistrationInfo, // VMExport nullptr, // Pointers &DObject::InPlaceConstructor, // ConstructNative - &DObject::InitNativeFields, // InitNatives + nullptr, sizeof(DObject), // SizeOf CLASSREG_PClass, // MetaClassNum }; _DECLARE_TI(DObject) +// This bit is needed in the playsim - but give it a less crappy name. +DEFINE_FIELD_BIT(DObject,ObjectFlags, bDestroyed, OF_EuthanizeMe) + //========================================================================== // // @@ -347,18 +350,6 @@ DObject::~DObject () // //========================================================================== -void DObject::InitNativeFields() -{ - auto meta = RUNTIME_CLASS(DObject); - meta->AddNativeField("bDestroyed", TypeSInt32, myoffsetof(DObject, ObjectFlags), VARF_ReadOnly, OF_EuthanizeMe); -} - -//========================================================================== -// -// -// -//========================================================================== - void DObject::Destroy () { ObjectFlags = (ObjectFlags & ~OF_Fixed) | OF_EuthanizeMe; diff --git a/src/dobject.h b/src/dobject.h index d858e577f..f728713e0 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -150,9 +150,6 @@ protected: \ #define HAS_OBJECT_POINTERS \ static const size_t PointerOffsets[]; -#define HAS_FIELDS \ - static void InitNativeFields(); - #if defined(_MSC_VER) # pragma section(".creg$u",read) # define _DECLARE_TI(cls) __declspec(allocate(".creg$u")) ClassReg * const cls::RegistrationInfoPtr = &cls::RegistrationInfo; @@ -187,7 +184,7 @@ protected: \ // Possible arguments for the IMPLEMENT_CLASS macro #define _X_POINTERS_true(cls) cls::PointerOffsets #define _X_POINTERS_false(cls) nullptr -#define _X_FIELDS_true(cls) cls::InitNativeFields +#define _X_FIELDS_true(cls) nullptr #define _X_FIELDS_false(cls) nullptr #define _X_CONSTRUCTOR_true(cls) #define _X_CONSTRUCTOR_false(cls) void cls::InPlaceConstructor(void *mem) { new((EInPlace *)mem) cls; } @@ -445,7 +442,6 @@ public: virtual PClass *StaticType() const { return RegistrationInfo.MyClass; } static ClassReg RegistrationInfo, * const RegistrationInfoPtr; static void InPlaceConstructor (void *mem); - static void InitNativeFields(); typedef PClass MetaClass; private: typedef DObject ThisClass; diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 5afb8a578..11640ec94 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2515,7 +2515,7 @@ PField::PField(FName name, PType *type, DWORD flags, size_t offset, int bitvalue else { // Just abort. Bit fields should only be defined internally. - I_FatalError("Trying to create an invalid bit field element: %s", name.GetChars()); + I_Error("Trying to create an invalid bit field element: %s", name.GetChars()); } } else BitValue = -1; diff --git a/src/g_shared/a_armor.cpp b/src/g_shared/a_armor.cpp index c05cc2c6a..8f1116a9e 100644 --- a/src/g_shared/a_armor.cpp +++ b/src/g_shared/a_armor.cpp @@ -281,16 +281,17 @@ bool ABasicArmorPickup::Use (bool pickup) //=========================================================================== // -// ABasicArmorBonus :: InitNativeFields +// ABasicArmorBonus // //=========================================================================== -void ABasicArmorBonus::InitNativeFields() -{ - auto meta = RUNTIME_CLASS(ABasicArmorBonus); - meta->AddNativeField("SaveAmount", TypeSInt32, myoffsetof(ABasicArmorBonus, SaveAmount)); - meta->AddNativeField("MaxSaveAmount", TypeSInt32, myoffsetof(ABasicArmorBonus, MaxSaveAmount)); -} +DEFINE_FIELD(ABasicArmorBonus, SavePercent) +DEFINE_FIELD(ABasicArmorBonus, MaxSaveAmount) +DEFINE_FIELD(ABasicArmorBonus, MaxAbsorb) +DEFINE_FIELD(ABasicArmorBonus, MaxFullAbsorb) +DEFINE_FIELD(ABasicArmorBonus, SaveAmount) +DEFINE_FIELD(ABasicArmorBonus, BonusCount) +DEFINE_FIELD(ABasicArmorBonus, BonusMax) //=========================================================================== // diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index 9e1caaf5b..6dc2d0bc5 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -289,7 +289,6 @@ public: class AWeapon : public AStateProvider { DECLARE_CLASS_WITH_META(AWeapon, AStateProvider, PClassWeapon) - HAS_FIELDS HAS_OBJECT_POINTERS public: DWORD WeaponFlags; @@ -500,7 +499,6 @@ public: class ABasicArmorBonus : public AArmor { DECLARE_CLASS (ABasicArmorBonus, AArmor) - HAS_FIELDS public: virtual void Serialize(FSerializer &arc); diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index 9af5c6de2..5f221c5bc 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -31,25 +31,45 @@ IMPLEMENT_POINTERS_START(AWeapon) IMPLEMENT_POINTER(SisterWeapon) IMPLEMENT_POINTERS_END -void AWeapon::InitNativeFields() -{ - auto meta = RUNTIME_CLASS(AWeapon); +DEFINE_FIELD(AWeapon, WeaponFlags) +DEFINE_FIELD(AWeapon, AmmoType1) +DEFINE_FIELD(AWeapon, AmmoType2) +DEFINE_FIELD(AWeapon, AmmoGive1) +DEFINE_FIELD(AWeapon, AmmoGive2) +DEFINE_FIELD(AWeapon, MinAmmo1) +DEFINE_FIELD(AWeapon, MinAmmo2) +DEFINE_FIELD(AWeapon, AmmoUse1) +DEFINE_FIELD(AWeapon, AmmoUse2) +DEFINE_FIELD(AWeapon, Kickback) +DEFINE_FIELD(AWeapon, YAdjust) +DEFINE_FIELD(AWeapon, UpSound) +DEFINE_FIELD(AWeapon, ReadySound) +DEFINE_FIELD(AWeapon, SisterWeaponType) +DEFINE_FIELD(AWeapon, ProjectileType) +DEFINE_FIELD(AWeapon, AltProjectileType) +DEFINE_FIELD(AWeapon, SelectionOrder) +DEFINE_FIELD(AWeapon, MinSelAmmo1) +DEFINE_FIELD(AWeapon, MinSelAmmo2) +DEFINE_FIELD(AWeapon, MoveCombatDist) +DEFINE_FIELD(AWeapon, ReloadCounter) +DEFINE_FIELD(AWeapon, BobStyle) +DEFINE_FIELD(AWeapon, BobSpeed) +DEFINE_FIELD(AWeapon, BobRangeX) +DEFINE_FIELD(AWeapon, BobRangeY) +DEFINE_FIELD(AWeapon, Ammo1) +DEFINE_FIELD(AWeapon, Ammo2) +DEFINE_FIELD(AWeapon, SisterWeapon) +DEFINE_FIELD(AWeapon, FOVScale) +DEFINE_FIELD(AWeapon, Crosshair) +DEFINE_FIELD(AWeapon, GivenAsMorphWeapon) +DEFINE_FIELD(AWeapon, bAltFire) +DEFINE_FIELD_BIT(AWeapon, WeaponFlags, bDehAmmo, WIF_DEHAMMO) - meta->AddNativeField("bAltFire", TypeBool, myoffsetof(AWeapon, bAltFire)); - - - // synthesize a symbol for each flag from the flag name tables to avoid redundant declaration of them. - for (size_t i = 0; WeaponFlagDefs[i].flagbit != 0xffffffff; i++) - { - if (WeaponFlagDefs[i].structoffset > 0) - { - meta->AddNativeField(FStringf("b%s", WeaponFlagDefs[i].name), (WeaponFlagDefs[i].fieldsize == 4 ? TypeSInt32 : TypeSInt16), WeaponFlagDefs[i].structoffset, WeaponFlagDefs[i].varflags, WeaponFlagDefs[i].flagbit); - } - } - // This flag is not accessible through actor definitions. - meta->AddNativeField("bDehAmmo", TypeSInt32, myoffsetof(AWeapon, WeaponFlags), VARF_ReadOnly, WIF_DEHAMMO); - -} +//=========================================================================== +// +// +// +//=========================================================================== FString WeaponSection; TArray KeyConfWeapons; @@ -62,12 +82,24 @@ static int ntoh_cmp(const void *a, const void *b); IMPLEMENT_CLASS(PClassWeapon, false, false, false, false) +//=========================================================================== +// +// +// +//=========================================================================== + PClassWeapon::PClassWeapon() { SlotNumber = -1; SlotPriority = INT_MAX; } +//=========================================================================== +// +// +// +//=========================================================================== + void PClassWeapon::DeriveData(PClass *newclass) { assert(newclass->IsKindOf(RUNTIME_CLASS(PClassWeapon))); @@ -79,6 +111,12 @@ void PClassWeapon::DeriveData(PClass *newclass) } +//=========================================================================== +// +// +// +//=========================================================================== + void PClassWeapon::ReplaceClassRef(PClass *oldclass, PClass *newclass) { Super::ReplaceClassRef(oldclass, newclass); @@ -91,6 +129,12 @@ void PClassWeapon::ReplaceClassRef(PClass *oldclass, PClass *newclass) } } +//=========================================================================== +// +// +// +//=========================================================================== + void PClassWeapon::Finalize(FStateDefinitions &statedef) { Super::Finalize(statedef); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 181399655..29123590a 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -131,7 +131,7 @@ CVAR (Int, cl_bloodtype, 0, CVAR_ARCHIVE); // CODE -------------------------------------------------------------------- -IMPLEMENT_CLASS(AActor, false, true, true, true) +IMPLEMENT_CLASS(AActor, false, true, false, true) IMPLEMENT_POINTERS_START(AActor) IMPLEMENT_POINTER(target) @@ -310,24 +310,6 @@ DEFINE_FIELD(AActor, ConversationRoot) DEFINE_FIELD(AActor, Conversation) DEFINE_FIELD(AActor, DecalGenerator) - -void AActor::InitNativeFields() -{ - auto meta = RUNTIME_CLASS(AActor); - // needs to be done manually until it can be given a proper type. - meta->AddNativeField("DecalGenerator", NewPointer(TypeVoid), myoffsetof(AActor, DecalGenerator)); - - // synthesize a symbol for each flag from the flag name tables to avoid redundant declaration of them. - for (size_t i = 0; ActorFlagDefs[i].flagbit != 0xffffffff; i++) - { - meta->AddNativeField(FStringf("b%s", ActorFlagDefs[i].name), (ActorFlagDefs[i].fieldsize == 4? TypeSInt32 : TypeSInt16), ActorFlagDefs[i].structoffset, ActorFlagDefs[i].varflags, ActorFlagDefs[i].flagbit); - } - for (size_t i = 0; InternalActorFlagDefs[i].flagbit != 0xffffffff; i++) - { - meta->AddNativeField(FStringf("b%s", InternalActorFlagDefs[i].name), (InternalActorFlagDefs[i].fieldsize == 4 ? TypeSInt32 : TypeSInt16), InternalActorFlagDefs[i].structoffset, InternalActorFlagDefs[i].varflags, InternalActorFlagDefs[i].flagbit); - } -} - //========================================================================== // // AActor :: Serialize @@ -7183,18 +7165,13 @@ DEFINE_ACTION_FUNCTION(AActor, Vec3Offset) IMPLEMENT_CLASS(DDropItem, false, true, true, false) IMPLEMENT_POINTERS_START(DDropItem) - IMPLEMENT_POINTER(Next) +IMPLEMENT_POINTER(Next) IMPLEMENT_POINTERS_END -void DDropItem::InitNativeFields() -{ - auto meta = RUNTIME_CLASS(DDropItem); - PType *TypeDropItem = NewPointer(RUNTIME_CLASS(DDropItem)); - meta->AddNativeField("Next", TypeDropItem, myoffsetof(DDropItem, Next), VARF_ReadOnly); - meta->AddNativeField("Name", TypeName, myoffsetof(DDropItem, Name), VARF_ReadOnly); - meta->AddNativeField("Probability", TypeSInt32, myoffsetof(DDropItem, Probability), VARF_ReadOnly); - meta->AddNativeField("Amount", TypeSInt32, myoffsetof(DDropItem, Amount)); -} +DEFINE_FIELD(DDropItem, Next) +DEFINE_FIELD(DDropItem, Name) +DEFINE_FIELD(DDropItem, Probability) +DEFINE_FIELD(DDropItem, Amount) void PrintMiscActorInfo(AActor *query) { diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index f1cc8e792..0e39e259e 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -99,40 +99,32 @@ static const FGenericButtons ButtonChecks[] = // //------------------------------------------------------------------------ -IMPLEMENT_CLASS(DPSprite, false, true, true, false) +IMPLEMENT_CLASS(DPSprite, false, true, false, false) IMPLEMENT_POINTERS_START(DPSprite) IMPLEMENT_POINTER(Caller) IMPLEMENT_POINTER(Next) IMPLEMENT_POINTERS_END -void DPSprite::InitNativeFields() -{ - auto meta = RUNTIME_CLASS(DPSprite); - PType *TypeActor = NewPointer(RUNTIME_CLASS(AActor)); - PType *TypePSP = NewPointer(RUNTIME_CLASS(DPSprite)); - PType *TypePlayer = NewPointer(NewNativeStruct("Player", nullptr)); - - meta->AddNativeField("State", TypeState, myoffsetof(DPSprite, State), VARF_ReadOnly); - meta->AddNativeField("Caller", TypeActor, myoffsetof(DPSprite, Caller), VARF_ReadOnly); - meta->AddNativeField("Next", TypePSP, myoffsetof(DPSprite, Next), VARF_ReadOnly); - meta->AddNativeField("Owner", TypePlayer, myoffsetof(DPSprite, Owner), VARF_ReadOnly); - meta->AddNativeField("Sprite", TypeSpriteID, myoffsetof(DPSprite, Sprite)); - meta->AddNativeField("Frame", TypeSInt32, myoffsetof(DPSprite, Frame)); - meta->AddNativeField("ID", TypePlayer, myoffsetof(DPSprite, ID), VARF_ReadOnly); - meta->AddNativeField("processPending", TypeBool, myoffsetof(DPSprite, processPending)); - meta->AddNativeField("x", TypeFloat64, myoffsetof(DPSprite, x)); - meta->AddNativeField("y", TypeFloat64, myoffsetof(DPSprite, y)); - meta->AddNativeField("oldx", TypeFloat64, myoffsetof(DPSprite, oldx)); - meta->AddNativeField("oldy", TypeFloat64, myoffsetof(DPSprite, oldy)); - meta->AddNativeField("firstTic", TypeBool, myoffsetof(DPSprite, firstTic)); - meta->AddNativeField("Tics", TypeSInt32, myoffsetof(DPSprite, Tics)); - meta->AddNativeField("bAddWeapon", TypeSInt32, myoffsetof(DPSprite, Flags), 0, PSPF_ADDWEAPON); - meta->AddNativeField("bAddBob", TypeSInt32, myoffsetof(DPSprite, Flags), 0, PSPF_ADDBOB); - meta->AddNativeField("bPowDouble", TypeSInt32, myoffsetof(DPSprite, Flags), 0, PSPF_POWDOUBLE); - meta->AddNativeField("bCVarFast", TypeSInt32, myoffsetof(DPSprite, Flags), 0, PSPF_CVARFAST); - meta->AddNativeField("bFlip", TypeSInt32, myoffsetof(DPSprite, Flags), 0, PSPF_FLIP); -} +DEFINE_FIELD_NAMED(DPSprite, State, CurState) // deconflict with same named type +DEFINE_FIELD(DPSprite, Caller) +DEFINE_FIELD(DPSprite, Next) +DEFINE_FIELD(DPSprite, Owner) +DEFINE_FIELD(DPSprite, Sprite) +DEFINE_FIELD(DPSprite, Frame) +DEFINE_FIELD(DPSprite, ID) +DEFINE_FIELD(DPSprite, processPending) +DEFINE_FIELD(DPSprite, x) +DEFINE_FIELD(DPSprite, y) +DEFINE_FIELD(DPSprite, oldx) +DEFINE_FIELD(DPSprite, oldy) +DEFINE_FIELD(DPSprite, firstTic) +DEFINE_FIELD(DPSprite, Tics) +DEFINE_FIELD_BIT(DPSprite, Flags, bAddWeapon, PSPF_ADDWEAPON) +DEFINE_FIELD_BIT(DPSprite, Flags, bAddBob, PSPF_ADDBOB) +DEFINE_FIELD_BIT(DPSprite, Flags, bPowDouble, PSPF_POWDOUBLE) +DEFINE_FIELD_BIT(DPSprite, Flags, bCVarFast, PSPF_CVARFAST) +DEFINE_FIELD_BIT(DPSprite, Flags, bFlip, PSPF_FLIP) //------------------------------------------------------------------------ // diff --git a/src/p_pspr.h b/src/p_pspr.h index 4c019c7d4..7039b2cc8 100644 --- a/src/p_pspr.h +++ b/src/p_pspr.h @@ -59,7 +59,6 @@ enum PSPFlags class DPSprite : public DObject { DECLARE_CLASS (DPSprite, DObject) - HAS_FIELDS HAS_OBJECT_POINTERS public: DPSprite(player_t *owner, AActor *caller, int id); @@ -89,6 +88,7 @@ private: void Tick(); void Destroy(); +public: // must be public to be able to generate the field export tables. Grrr... TObjPtr Caller; TObjPtr Next; player_t *Owner; diff --git a/src/p_user.cpp b/src/p_user.cpp index 5b25fd713..2917db668 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -161,12 +161,6 @@ bool ValidatePlayerClass(PClassActor *ti, const char *name) return true; } -void APlayerPawn::InitNativeFields() -{ - auto meta = RUNTIME_CLASS(APlayerPawn); - meta->AddNativeField("JumpZ", TypeFloat64, myoffsetof(APlayerPawn, JumpZ)); -} - void SetupPlayerClasses () { FPlayerClass newclass; @@ -628,7 +622,7 @@ void player_t::SendPitchLimits() const // //=========================================================================== -IMPLEMENT_CLASS(APlayerPawn, false, true, true, true) +IMPLEMENT_CLASS(APlayerPawn, false, true, false, true) IMPLEMENT_POINTERS_START(APlayerPawn) IMPLEMENT_POINTER(InvFirst) @@ -3139,112 +3133,118 @@ bool P_IsPlayerTotallyFrozen(const player_t *player) //========================================================================== // -// sets up the script-side version of players -// Since this is a global variable and the script compiler does -// not allow defining them, it will be fully set up here. +// native members // //========================================================================== -void P_InitPlayerForScript() -{ - PStruct *pstruct = NewNativeStruct("PlayerInfo", nullptr); - pstruct->Size = sizeof(player_t); - pstruct->Align = alignof(player_t); - PArray *parray = NewArray(pstruct, MAXPLAYERS); - pstruct->Size = 0; // make sure it cannot be instantiated in the script. - PField *playerf = new PField("players", pstruct, VARF_Native | VARF_Static, (intptr_t)&players); - GlobalSymbols.AddSymbol(playerf); +DEFINE_FIELD(APlayerPawn, crouchsprite) +DEFINE_FIELD(APlayerPawn, MaxHealth) +DEFINE_FIELD(APlayerPawn, MugShotMaxHealth) +DEFINE_FIELD(APlayerPawn, RunHealth) +DEFINE_FIELD(APlayerPawn, PlayerFlags) +DEFINE_FIELD(APlayerPawn, InvFirst) +DEFINE_FIELD(APlayerPawn, InvSel) +DEFINE_FIELD(APlayerPawn, JumpZ) +DEFINE_FIELD(APlayerPawn, GruntSpeed) +DEFINE_FIELD(APlayerPawn, FallingScreamMinSpeed) +DEFINE_FIELD(APlayerPawn, FallingScreamMaxSpeed) +DEFINE_FIELD(APlayerPawn, ViewHeight) +DEFINE_FIELD(APlayerPawn, ForwardMove1) +DEFINE_FIELD(APlayerPawn, ForwardMove2) +DEFINE_FIELD(APlayerPawn, SideMove1) +DEFINE_FIELD(APlayerPawn, SideMove2) +DEFINE_FIELD(APlayerPawn, ScoreIcon) +DEFINE_FIELD(APlayerPawn, SpawnMask) +DEFINE_FIELD(APlayerPawn, MorphWeapon) +DEFINE_FIELD(APlayerPawn, AttackZOffset) +DEFINE_FIELD(APlayerPawn, UseRange) +DEFINE_FIELD(APlayerPawn, AirCapacity) +DEFINE_FIELD(APlayerPawn, FlechetteType) +DEFINE_FIELD(APlayerPawn, DamageFade) +DEFINE_FIELD(APlayerPawn, ViewBob) - PType *TypeActor = NewPointer(RUNTIME_CLASS(AActor)); - PType *TypePlayerPawn = NewPointer(RUNTIME_CLASS(APlayerPawn)); - PType *TypeWeapon = NewPointer(RUNTIME_CLASS(AWeapon)); - PType *TypeClassActor = NewClassPointer(RUNTIME_CLASS(AActor)); - PType *TypeClassPlayerPawn = NewClassPointer(RUNTIME_CLASS(APlayerPawn)); - PType *TypeClassWeapon = NewClassPointer(RUNTIME_CLASS(AWeapon)); - - //ticcmd_t cmd; - //usercmd_t original_cmd; - //userinfo_t userinfo; // [RH] who is this? - //FWeaponSlots weapons; - pstruct->AddNativeField("mo", TypePlayerPawn, myoffsetof(player_t, mo), VARF_ReadOnly); - pstruct->AddNativeField("playerstate", TypeUInt8, myoffsetof(player_t, playerstate)); - pstruct->AddNativeField("original_oldbuttons", TypeUInt32, myoffsetof(player_t, original_oldbuttons)); - pstruct->AddNativeField("cls", TypeClassPlayerPawn, myoffsetof(player_t, cls), VARF_ReadOnly); - pstruct->AddNativeField("DesiredFOV", TypeFloat32, myoffsetof(player_t, DesiredFOV)); - pstruct->AddNativeField("FOV", TypeFloat32, myoffsetof(player_t, FOV), VARF_ReadOnly); - pstruct->AddNativeField("viewz", TypeFloat64, myoffsetof(player_t, viewz)); - pstruct->AddNativeField("viewheight", TypeFloat64, myoffsetof(player_t, viewheight)); - pstruct->AddNativeField("deltaviewheight", TypeFloat64, myoffsetof(player_t, deltaviewheight)); - pstruct->AddNativeField("bob", TypeFloat64, myoffsetof(player_t, bob)); - pstruct->AddNativeField("vel", TypeVector2, myoffsetof(player_t, Vel)); - pstruct->AddNativeField("centering", TypeBool, myoffsetof(player_t, centering)); - pstruct->AddNativeField("turnticks", TypeUInt8, myoffsetof(player_t, turnticks)); - pstruct->AddNativeField("attackdown", TypeBool, myoffsetof(player_t, attackdown)); - pstruct->AddNativeField("usedown", TypeBool, myoffsetof(player_t, usedown)); - pstruct->AddNativeField("oldbuttons", TypeUInt32, myoffsetof(player_t, oldbuttons)); - pstruct->AddNativeField("health", TypeSInt32, myoffsetof(player_t, health)); - pstruct->AddNativeField("inventorytics", TypeSInt32, myoffsetof(player_t, inventorytics)); - pstruct->AddNativeField("CurrentPlayerClass", TypeUInt8, myoffsetof(player_t, CurrentPlayerClass)); - pstruct->AddNativeField("frags", NewArray(TypeSInt32, MAXPLAYERS), myoffsetof(player_t, frags)); - pstruct->AddNativeField("fragcount", TypeSInt32, myoffsetof(player_t, fragcount)); - pstruct->AddNativeField("lastkilltime", TypeSInt32, myoffsetof(player_t, lastkilltime)); - pstruct->AddNativeField("multicount", TypeUInt8, myoffsetof(player_t, multicount)); - pstruct->AddNativeField("spreecount", TypeUInt8, myoffsetof(player_t, spreecount)); - pstruct->AddNativeField("WeaponState", TypeUInt16, myoffsetof(player_t, WeaponState)); - pstruct->AddNativeField("ReadyWeapon", TypeWeapon, myoffsetof(player_t, ReadyWeapon)); - pstruct->AddNativeField("PendingWeapon", TypeWeapon, myoffsetof(player_t, PendingWeapon)); - pstruct->AddNativeField("psprites", NewPointer(RUNTIME_CLASS(DPSprite)), myoffsetof(player_t, psprites)); - pstruct->AddNativeField("cheats", TypeSInt32, myoffsetof(player_t, cheats)); - pstruct->AddNativeField("timefreezer", TypeSInt32, myoffsetof(player_t, timefreezer)); - pstruct->AddNativeField("refire", TypeSInt16, myoffsetof(player_t, refire)); - pstruct->AddNativeField("inconsistent", TypeSInt16, myoffsetof(player_t, inconsistant)); - pstruct->AddNativeField("waiting", TypeSInt32, myoffsetof(player_t, waiting)); - pstruct->AddNativeField("killcount", TypeSInt32, myoffsetof(player_t, killcount)); - pstruct->AddNativeField("itemcount", TypeSInt32, myoffsetof(player_t, itemcount)); - pstruct->AddNativeField("secretcount", TypeSInt32, myoffsetof(player_t, secretcount)); - pstruct->AddNativeField("damagecount", TypeSInt32, myoffsetof(player_t, damagecount)); - pstruct->AddNativeField("bonuscount", TypeSInt32, myoffsetof(player_t, bonuscount)); - pstruct->AddNativeField("hazardcount", TypeSInt32, myoffsetof(player_t, hazardcount)); - pstruct->AddNativeField("hazardinterval", TypeSInt32, myoffsetof(player_t, hazardinterval)); - pstruct->AddNativeField("hazardtype", TypeName, myoffsetof(player_t, hazardtype)); - pstruct->AddNativeField("poisoncount", TypeSInt32, myoffsetof(player_t, poisoncount)); - pstruct->AddNativeField("poisontype", TypeName, myoffsetof(player_t, poisontype)); - pstruct->AddNativeField("poisonpaintype", TypeName, myoffsetof(player_t, poisonpaintype)); - pstruct->AddNativeField("poisoner", TypeActor, myoffsetof(player_t, poisoner)); - pstruct->AddNativeField("attacker", TypeActor, myoffsetof(player_t, attacker)); - pstruct->AddNativeField("extralight", TypeSInt32, myoffsetof(player_t, extralight)); - pstruct->AddNativeField("fixedcolormap", TypeSInt16, myoffsetof(player_t, fixedcolormap)); - pstruct->AddNativeField("fixedlightlevel", TypeSInt16, myoffsetof(player_t, fixedlightlevel)); - pstruct->AddNativeField("morphtics", TypeSInt32, myoffsetof(player_t, morphTics)); - pstruct->AddNativeField("MorphedPlayerClass", TypeClassPlayerPawn, myoffsetof(player_t, MorphedPlayerClass)); - pstruct->AddNativeField("MorphStyle", TypeSInt32, myoffsetof(player_t, MorphStyle)); - pstruct->AddNativeField("MorphExitFlash", TypeClassActor, myoffsetof(player_t, MorphExitFlash)); - pstruct->AddNativeField("PremorphWeapon", TypeClassWeapon, myoffsetof(player_t, PremorphWeapon)); - pstruct->AddNativeField("chickenPeck", TypeSInt32, myoffsetof(player_t, chickenPeck)); - pstruct->AddNativeField("jumpTics", TypeSInt32, myoffsetof(player_t, jumpTics)); - pstruct->AddNativeField("onground", TypeBool, myoffsetof(player_t, onground)); - pstruct->AddNativeField("respawn_time", TypeSInt32, myoffsetof(player_t, respawn_time)); - pstruct->AddNativeField("camera", TypeActor, myoffsetof(player_t, camera)); - pstruct->AddNativeField("air_finished", TypeSInt32, myoffsetof(player_t, air_finished)); - pstruct->AddNativeField("LastDamageType", TypeName, myoffsetof(player_t, LastDamageType)); - pstruct->AddNativeField("MUSINFOactor", TypeActor, myoffsetof(player_t, MUSINFOactor)); - pstruct->AddNativeField("MUSINFOtics", TypeSInt8, myoffsetof(player_t, MUSINFOtics)); - pstruct->AddNativeField("settings_controller", TypeBool, myoffsetof(player_t, settings_controller)); - pstruct->AddNativeField("crouching", TypeSInt8, myoffsetof(player_t, crouching)); - pstruct->AddNativeField("crouchdir", TypeSInt8, myoffsetof(player_t, crouchdir)); - pstruct->AddNativeField("bot", NewPointer(RUNTIME_CLASS(DBot)), myoffsetof(player_t, Bot)); - pstruct->AddNativeField("BlendR", TypeFloat32, myoffsetof(player_t, BlendR)); - pstruct->AddNativeField("BlendG", TypeFloat32, myoffsetof(player_t, BlendG)); - pstruct->AddNativeField("BlendB", TypeFloat32, myoffsetof(player_t, BlendB)); - pstruct->AddNativeField("BlendA", TypeFloat32, myoffsetof(player_t, BlendA)); - pstruct->AddNativeField("LogText", TypeString, myoffsetof(player_t, LogText)); - pstruct->AddNativeField("MinPitch", TypeFloat64, myoffsetof(player_t, MinPitch)); - pstruct->AddNativeField("MaxPitch", TypeFloat64, myoffsetof(player_t, MaxPitch)); - pstruct->AddNativeField("crouchfactor", TypeFloat64, myoffsetof(player_t, crouchfactor)); - pstruct->AddNativeField("crouchoffset", TypeFloat64, myoffsetof(player_t, crouchoffset)); - pstruct->AddNativeField("crouchviewdelta", TypeFloat64, myoffsetof(player_t, crouchviewdelta)); - pstruct->AddNativeField("ConversationNPC", TypeActor, myoffsetof(player_t, ConversationNPC)); - pstruct->AddNativeField("ConversationPC", TypeActor, myoffsetof(player_t, ConversationPC)); - pstruct->AddNativeField("ConversationNPCAngle", TypeFloat64, myoffsetof(player_t, ConversationNPCAngle)); - pstruct->AddNativeField("ConversationFaceTalker", TypeBool, myoffsetof(player_t, ConversationFaceTalker)); -} \ No newline at end of file +DEFINE_FIELD_X(PlayerInfo, player_t, mo) +DEFINE_FIELD_X(PlayerInfo, player_t, playerstate) +DEFINE_FIELD_X(PlayerInfo, player_t, original_oldbuttons) +DEFINE_FIELD_X(PlayerInfo, player_t, cls) +DEFINE_FIELD_X(PlayerInfo, player_t, DesiredFOV) +DEFINE_FIELD_X(PlayerInfo, player_t, FOV) +DEFINE_FIELD_X(PlayerInfo, player_t, viewz) +DEFINE_FIELD_X(PlayerInfo, player_t, viewheight) +DEFINE_FIELD_X(PlayerInfo, player_t, deltaviewheight) +DEFINE_FIELD_X(PlayerInfo, player_t, bob) +DEFINE_FIELD_X(PlayerInfo, player_t, Vel) +DEFINE_FIELD_X(PlayerInfo, player_t, centering) +DEFINE_FIELD_X(PlayerInfo, player_t, turnticks) +DEFINE_FIELD_X(PlayerInfo, player_t, attackdown) +DEFINE_FIELD_X(PlayerInfo, player_t, usedown) +DEFINE_FIELD_X(PlayerInfo, player_t, oldbuttons) +DEFINE_FIELD_X(PlayerInfo, player_t, health) +DEFINE_FIELD_X(PlayerInfo, player_t, inventorytics) +DEFINE_FIELD_X(PlayerInfo, player_t, CurrentPlayerClass) +DEFINE_FIELD_X(PlayerInfo, player_t, frags) +DEFINE_FIELD_X(PlayerInfo, player_t, fragcount) +DEFINE_FIELD_X(PlayerInfo, player_t, lastkilltime) +DEFINE_FIELD_X(PlayerInfo, player_t, multicount) +DEFINE_FIELD_X(PlayerInfo, player_t, spreecount) +DEFINE_FIELD_X(PlayerInfo, player_t, WeaponState) +DEFINE_FIELD_X(PlayerInfo, player_t, ReadyWeapon) +DEFINE_FIELD_X(PlayerInfo, player_t, PendingWeapon) +DEFINE_FIELD_X(PlayerInfo, player_t, psprites) +DEFINE_FIELD_X(PlayerInfo, player_t, cheats) +DEFINE_FIELD_X(PlayerInfo, player_t, timefreezer) +DEFINE_FIELD_X(PlayerInfo, player_t, refire) +DEFINE_FIELD_NAMED_X(PlayerInfo, player_t, inconsistant, inconsistent) +DEFINE_FIELD_X(PlayerInfo, player_t, waiting) +DEFINE_FIELD_X(PlayerInfo, player_t, killcount) +DEFINE_FIELD_X(PlayerInfo, player_t, itemcount) +DEFINE_FIELD_X(PlayerInfo, player_t, secretcount) +DEFINE_FIELD_X(PlayerInfo, player_t, damagecount) +DEFINE_FIELD_X(PlayerInfo, player_t, bonuscount) +DEFINE_FIELD_X(PlayerInfo, player_t, hazardcount) +DEFINE_FIELD_X(PlayerInfo, player_t, hazardinterval) +DEFINE_FIELD_X(PlayerInfo, player_t, hazardtype) +DEFINE_FIELD_X(PlayerInfo, player_t, poisoncount) +DEFINE_FIELD_X(PlayerInfo, player_t, poisontype) +DEFINE_FIELD_X(PlayerInfo, player_t, poisonpaintype) +DEFINE_FIELD_X(PlayerInfo, player_t, poisoner) +DEFINE_FIELD_X(PlayerInfo, player_t, attacker) +DEFINE_FIELD_X(PlayerInfo, player_t, extralight) +DEFINE_FIELD_X(PlayerInfo, player_t, fixedcolormap) +DEFINE_FIELD_X(PlayerInfo, player_t, fixedlightlevel) +DEFINE_FIELD_X(PlayerInfo, player_t, morphTics) +DEFINE_FIELD_X(PlayerInfo, player_t, MorphedPlayerClass) +DEFINE_FIELD_X(PlayerInfo, player_t, MorphStyle) +DEFINE_FIELD_X(PlayerInfo, player_t, MorphExitFlash) +DEFINE_FIELD_X(PlayerInfo, player_t, PremorphWeapon) +DEFINE_FIELD_X(PlayerInfo, player_t, chickenPeck) +DEFINE_FIELD_X(PlayerInfo, player_t, jumpTics) +DEFINE_FIELD_X(PlayerInfo, player_t, onground) +DEFINE_FIELD_X(PlayerInfo, player_t, respawn_time) +DEFINE_FIELD_X(PlayerInfo, player_t, camera) +DEFINE_FIELD_X(PlayerInfo, player_t, air_finished) +DEFINE_FIELD_X(PlayerInfo, player_t, LastDamageType) +DEFINE_FIELD_X(PlayerInfo, player_t, MUSINFOactor) +DEFINE_FIELD_X(PlayerInfo, player_t, MUSINFOtics) +DEFINE_FIELD_X(PlayerInfo, player_t, settings_controller) +DEFINE_FIELD_X(PlayerInfo, player_t, crouching) +DEFINE_FIELD_X(PlayerInfo, player_t, crouchdir) +DEFINE_FIELD_X(PlayerInfo, player_t, Bot) +DEFINE_FIELD_X(PlayerInfo, player_t, BlendR) +DEFINE_FIELD_X(PlayerInfo, player_t, BlendG) +DEFINE_FIELD_X(PlayerInfo, player_t, BlendB) +DEFINE_FIELD_X(PlayerInfo, player_t, BlendA) +DEFINE_FIELD_X(PlayerInfo, player_t, LogText) +DEFINE_FIELD_X(PlayerInfo, player_t, MinPitch) +DEFINE_FIELD_X(PlayerInfo, player_t, MaxPitch) +DEFINE_FIELD_X(PlayerInfo, player_t, crouchfactor) +DEFINE_FIELD_X(PlayerInfo, player_t, crouchoffset) +DEFINE_FIELD_X(PlayerInfo, player_t, crouchviewdelta) +DEFINE_FIELD_X(PlayerInfo, player_t, ConversationNPC) +DEFINE_FIELD_X(PlayerInfo, player_t, ConversationPC) +DEFINE_FIELD_X(PlayerInfo, player_t, ConversationNPCAngle) +DEFINE_FIELD_X(PlayerInfo, player_t, ConversationFaceTalker) +DEFINE_FIELD_X(PlayerInfo, player_t, cmd) +DEFINE_FIELD_X(PlayerInfo, player_t, original_cmd) +DEFINE_FIELD_X(PlayerInfo, player_t, userinfo) +DEFINE_FIELD_X(PlayerInfo, player_t, weapons) diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index d50f73bd3..7488c9716 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -63,7 +63,7 @@ static TArray FieldTable; #define DEFINE_DUMMY_FLAG(name, deprec) { DEPF_UNUSED, #name, -1, 0, deprec? VARF_Deprecated:0 } // internal flags. These do not get exposed to actor definitions but scripts need to be able to access them as variables. -FFlagDef InternalActorFlagDefs[]= +static FFlagDef InternalActorFlagDefs[]= { DEFINE_FLAG(MF, INCHASE, AActor, flags), DEFINE_FLAG(MF, UNMORPHED, AActor, flags), @@ -90,11 +90,10 @@ FFlagDef InternalActorFlagDefs[]= DEFINE_FLAG(MF6, INTRYMOVE, AActor, flags6), DEFINE_FLAG(MF7, HANDLENODELAY, AActor, flags7), DEFINE_FLAG(MF7, FLYCHEAT, AActor, flags7), - { 0xffffffff } }; -FFlagDef ActorFlagDefs[]= +static FFlagDef ActorFlagDefs[]= { DEFINE_FLAG(MF, PICKUP, APlayerPawn, flags), DEFINE_FLAG(MF, SPECIAL, APlayerPawn, flags), @@ -328,7 +327,6 @@ FFlagDef ActorFlagDefs[]= DEFINE_FLAG2(BOUNCE_MBF, MBFBOUNCER, AActor, BounceFlags), DEFINE_FLAG2(BOUNCE_AutoOffFloorOnly, BOUNCEAUTOOFFFLOORONLY, AActor, BounceFlags), DEFINE_FLAG2(BOUNCE_UseBounceState, USEBOUNCESTATE, AActor, BounceFlags), - { 0xffffffff } }; // These won't be accessible through bitfield variables @@ -387,10 +385,9 @@ static FFlagDef InventoryFlagDefs[] = DEFINE_DEPRECATED_FLAG(PICKUPFLASH), DEFINE_DEPRECATED_FLAG(INTERHUBSTRIP), - { 0xffffffff } }; -FFlagDef WeaponFlagDefs[] = +static FFlagDef WeaponFlagDefs[] = { // Weapon flags DEFINE_FLAG(WIF, NOAUTOFIRE, AWeapon, WeaponFlags), @@ -417,7 +414,6 @@ FFlagDef WeaponFlagDefs[] = DEFINE_DUMMY_FLAG(NOLMS, false), DEFINE_DUMMY_FLAG(ALLOW_WITH_RESPAWN_INVUL, false), - { 0xffffffff } }; @@ -428,24 +424,23 @@ static FFlagDef PlayerPawnFlagDefs[] = DEFINE_FLAG(PPF, NOTHRUSTWHENINVUL, APlayerPawn, PlayerFlags), DEFINE_FLAG(PPF, CANSUPERMORPH, APlayerPawn, PlayerFlags), DEFINE_FLAG(PPF, CROUCHABLEMORPH, APlayerPawn, PlayerFlags), - { 0xffffffff } }; static FFlagDef PowerSpeedFlagDefs[] = { // PowerSpeed flags DEFINE_FLAG(PSF, NOTRAIL, APowerSpeed, SpeedFlags), - { 0xffffffff } }; -static const struct FFlagList { const PClass * const *Type; FFlagDef *Defs; int NumDefs; } FlagLists[] = +static const struct FFlagList { const PClass * const *Type; FFlagDef *Defs; int NumDefs; int Use; } FlagLists[] = { - { &RUNTIME_CLASS_CASTLESS(AActor), ActorFlagDefs, countof(ActorFlagDefs)-1 }, // -1 to account for the terminator - { &RUNTIME_CLASS_CASTLESS(AActor), MoreFlagDefs, countof(MoreFlagDefs) }, - { &RUNTIME_CLASS_CASTLESS(AInventory), InventoryFlagDefs, countof(InventoryFlagDefs)-1 }, - { &RUNTIME_CLASS_CASTLESS(AWeapon), WeaponFlagDefs, countof(WeaponFlagDefs)-1 }, - { &RUNTIME_CLASS_CASTLESS(APlayerPawn), PlayerPawnFlagDefs, countof(PlayerPawnFlagDefs)-1 }, - { &RUNTIME_CLASS_CASTLESS(APowerSpeed), PowerSpeedFlagDefs, countof(PowerSpeedFlagDefs)-1 }, + { &RUNTIME_CLASS_CASTLESS(AActor), ActorFlagDefs, countof(ActorFlagDefs), 3 }, // -1 to account for the terminator + { &RUNTIME_CLASS_CASTLESS(AActor), MoreFlagDefs, countof(MoreFlagDefs), 1 }, + { &RUNTIME_CLASS_CASTLESS(AActor), InternalActorFlagDefs, countof(InternalActorFlagDefs), 2 }, + { &RUNTIME_CLASS_CASTLESS(AInventory), InventoryFlagDefs, countof(InventoryFlagDefs), 3 }, + { &RUNTIME_CLASS_CASTLESS(AWeapon), WeaponFlagDefs, countof(WeaponFlagDefs), 3 }, + { &RUNTIME_CLASS_CASTLESS(APlayerPawn), PlayerPawnFlagDefs, countof(PlayerPawnFlagDefs), 3 }, + { &RUNTIME_CLASS_CASTLESS(APowerSpeed), PowerSpeedFlagDefs, countof(PowerSpeedFlagDefs), 3 }, }; #define NUM_FLAG_LISTS (countof(FlagLists)) @@ -493,7 +488,7 @@ FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2, bo int max = strict ? 2 : NUM_FLAG_LISTS; for (int i = 0; i < max; ++i) { - if (type->IsDescendantOf (*FlagLists[i].Type)) + if ((FlagLists[i].Use & 1) && type->IsDescendantOf (*FlagLists[i].Type)) { def = FindFlag (FlagLists[i].Defs, FlagLists[i].NumDefs, part1); if (def != NULL) @@ -709,9 +704,35 @@ void InitThingdef() sstruct->AddNativeField("soundtarget", TypeActor, myoffsetof(sector_t, SoundTarget)); G_InitLevelLocalsForScript(); - P_InitPlayerForScript(); P_InitStateForScript(); + // set up a variable for the global players array. + PStruct *pstruct = NewNativeStruct("PlayerInfo", nullptr); + pstruct->Size = sizeof(player_t); + pstruct->Align = alignof(player_t); + PArray *parray = NewArray(pstruct, MAXPLAYERS); + PField *playerf = new PField("players", pstruct, VARF_Native | VARF_Static, (intptr_t)&players); + GlobalSymbols.AddSymbol(playerf); + + + // this needs to be done manually until it can be given a proper type. + RUNTIME_CLASS(AActor)->AddNativeField("DecalGenerator", NewPointer(TypeVoid), myoffsetof(AActor, DecalGenerator)); + + // synthesize a symbol for each flag from the flag name tables to avoid redundant declaration of them. + for (auto &fl : FlagLists) + { + if (fl.Use & 2) + { + for(int i=0;i 0) // skip the deprecated entries in this list + { + const_cast(*fl.Type)->AddNativeField(FStringf("b%s", fl.Defs[i].name), (fl.Defs[i].fieldsize == 4 ? TypeSInt32 : TypeSInt16), fl.Defs[i].structoffset, fl.Defs[i].varflags, fl.Defs[i].flagbit); + } + } + } + } + FAutoSegIterator probe(CRegHead, CRegTail); while (*++probe != NULL) diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index f2edca9b9..10ac4bb7b 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -1061,7 +1061,12 @@ struct AFuncDesc #define DEFINE_FIELD_X(cls, icls, name) \ static const FieldDesc VMField_##icls##_##name = { "A" #cls, #name, (unsigned)myoffsetof(icls, name), (unsigned)sizeof(icls::name), 0 }; \ extern FieldDesc const *const VMField_##icls##_##name##_HookPtr; \ - MSVC_FSEG FieldDesc const *const VMField_##icls##_##name##_HookPtr GCC_FSEG = &VMField_##cls##_##name; + MSVC_FSEG FieldDesc const *const VMField_##icls##_##name##_HookPtr GCC_FSEG = &VMField_##icls##_##name; + +#define DEFINE_FIELD_NAMED_X(cls, icls, name, scriptname) \ + static const FieldDesc VMField_##icls##_##scriptname = { "A" #cls, #scriptname, (unsigned)myoffsetof(icls, name), (unsigned)sizeof(icls::name), 0 }; \ + extern FieldDesc const *const VMField_##icls##_##scriptname##_HookPtr; \ + MSVC_FSEG FieldDesc const *const VMField_##icls##_##scriptname##_HookPtr GCC_FSEG = &VMField_##icls##_##scriptname; #define DEFINE_FIELD_X_BIT(cls, icls, name, bitval) \ static const FieldDesc VMField_##icls##_##name = { "A" #cls, #name, (unsigned)myoffsetof(icls, name), (unsigned)sizeof(icls::name), bitval }; \ diff --git a/src/scripting/zscript/zcc-parse.lemon b/src/scripting/zscript/zcc-parse.lemon index 80057724c..fc1803f1d 100644 --- a/src/scripting/zscript/zcc-parse.lemon +++ b/src/scripting/zscript/zcc-parse.lemon @@ -295,8 +295,9 @@ struct_flags(X) ::= NATIVE. { X.Flags = ZCC_Native; } opt_struct_body(X) ::= . { X = NULL; } opt_struct_body(X) ::= struct_body(X). +opt_struct_body(X) ::= error. { X = NULL; } + -struct_body(X) ::= error. { X = NULL; } struct_body(X) ::= struct_member(X). struct_body(X) ::= struct_member(A) struct_body(B). { X = A; /*X-overwrites-A*/ X->AppendSibling(B); } diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 72bfcf735..ac9a8825c 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1274,7 +1274,9 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray &Fiel PType *fieldtype = DetermineType(type, field, field->Names->Name, field->Type, true, true); // For structs only allow 'deprecated', for classes exclude function qualifiers. - int notallowed = forstruct? ~ZCC_Deprecated : ZCC_Latent | ZCC_Final | ZCC_Action | ZCC_Static | ZCC_FuncConst | ZCC_Abstract | ZCC_Virtual | ZCC_Override; + int notallowed = forstruct? + ZCC_Latent | ZCC_Final | ZCC_Action | ZCC_Static | ZCC_FuncConst | ZCC_Abstract | ZCC_Virtual | ZCC_Override | ZCC_Meta | ZCC_Extension : + ZCC_Latent | ZCC_Final | ZCC_Action | ZCC_Static | ZCC_FuncConst | ZCC_Abstract | ZCC_Virtual | ZCC_Override | ZCC_Extension; if (field->Flags & notallowed) { @@ -1323,13 +1325,15 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray &Fiel { Error(field, "The member variable '%s.%s' has not been exported from the executable.", type->TypeName.GetChars(), FName(name->Name).GetChars()); } - else if (thisfieldtype->Size != fd->FieldSize) + else if (thisfieldtype->Size != fd->FieldSize && fd->BitValue == 0) { Error(field, "The member variable '%s.%s' has mismatching sizes in internal and external declaration. (Internal = %d, External = %d)", type->TypeName.GetChars(), FName(name->Name).GetChars(), fd->FieldSize, thisfieldtype->Size); } // Q: Should we check alignment, too? A mismatch may be an indicator for bad assumptions. else { + // for bit fields the type must point to the source variable. + if (fd->BitValue != 0) thisfieldtype = fd->FieldSize == 1 ? TypeUInt8 : fd->FieldSize == 2 ? TypeUInt16 : TypeUInt32; type->AddNativeField(name->Name, thisfieldtype, fd->FieldOffset, varflags, fd->BitValue); } } @@ -1427,6 +1431,7 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n case ZCC_FloatAuto: retval = formember ? TypeFloat32 : TypeFloat64; + break; case ZCC_Float64: retval = TypeFloat64; diff --git a/src/scripting/zscript/zcc_parser.h b/src/scripting/zscript/zcc_parser.h index e000da06c..a2fc3fb56 100644 --- a/src/scripting/zscript/zcc_parser.h +++ b/src/scripting/zscript/zcc_parser.h @@ -164,6 +164,11 @@ struct ZCC_TreeNode // Appends a sibling to this node's sibling list. void AppendSibling(ZCC_TreeNode *sibling) { + if (this == nullptr) + { + // Some bad syntax can actually get here, so better abort so that the user can see the error which caused this. + I_FatalError("Internal script compiler error. Execution aborted."); + } if (sibling == NULL) { return; diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index b3f48acae..0f28de335 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -1,5 +1,7 @@ class Object native { + native bool bDestroyed; + // These really should be global functions... native static int G_SkillPropertyInt(int p); native static double G_SkillPropertyFloat(int p); @@ -35,12 +37,10 @@ class ActorIterator : Object native class DropItem : Object native { - /* native fields listed for reference only for now native readonly DropItem Next; native readonly name Name; native readonly int Probability; - native readonly int Amount; - */ + native int Amount; } class SpotState : Object native diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index b5b60481a..68b81dc2b 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -1,5 +1,6 @@ // for flag changer functions. const FLAG_NO_CHANGE = -1; +const MAXPLAYERS = 8; enum EStateUseFlags { diff --git a/wadsrc/static/zscript/doom/weaponchaingun.txt b/wadsrc/static/zscript/doom/weaponchaingun.txt index 92b3aec46..3766b9b6e 100644 --- a/wadsrc/static/zscript/doom/weaponchaingun.txt +++ b/wadsrc/static/zscript/doom/weaponchaingun.txt @@ -70,7 +70,7 @@ extend class StateProvider { // Removed most of the mess that was here in the C++ code because SetSafeFlash already does some thorough validation. State atk = weap.FindState('Fire'); - State cur = player.GetPSprite(PSP_WEAPON).State; + State cur = player.GetPSprite(PSP_WEAPON).CurState; int theflash = atk == cur? 0:1; player.SetSafeFlash(weap, flash, theflash); } diff --git a/wadsrc/static/zscript/shared/botstuff.txt b/wadsrc/static/zscript/shared/botstuff.txt index cf671ea8b..3ae2d1889 100644 --- a/wadsrc/static/zscript/shared/botstuff.txt +++ b/wadsrc/static/zscript/shared/botstuff.txt @@ -23,3 +23,7 @@ class CajunTrace : Actor +NOTELEPORT } } + +struct Bot native +{ +} diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index 2a9aabe27..929f826da 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -102,6 +102,14 @@ class BasicArmor : Armor native class BasicArmorBonus : Armor native { + native double SavePercent; // The default, for when you don't already have armor + native int MaxSaveAmount; + native int MaxAbsorb; + native int MaxFullAbsorb; + native int SaveAmount; + native int BonusCount; + native int BonusMax; + Default { +Inventory.AUTOACTIVATE @@ -438,6 +446,32 @@ class PuzzleItem : Inventory native class Weapon : StateProvider native { + native uint WeaponFlags; + native class AmmoType1, AmmoType2; // Types of ammo used by this weapon + native int AmmoGive1, AmmoGive2; // Amount of each ammo to get when picking up weapon + native int MinAmmo1, MinAmmo2; // Minimum ammo needed to switch to this weapon + native int AmmoUse1, AmmoUse2; // How much ammo to use with each shot + native int Kickback; + native float YAdjust; // For viewing the weapon fullscreen (visual only so no need to be a double) + native sound UpSound, ReadySound; // Sounds when coming up and idle + native class SisterWeaponType; // Another weapon to pick up with this one + native class ProjectileType; // Projectile used by primary attack + native class AltProjectileType; // Projectile used by alternate attack + native int SelectionOrder; // Lower-numbered weapons get picked first + native int MinSelAmmo1, MinSelAmmo2; // Ignore in BestWeapon() if inadequate ammo + native double MoveCombatDist; // Used by bots, but do they *really* need it? + native int ReloadCounter; // For A_CheckForReload + native int BobStyle; // [XA] Bobbing style. Defines type of bobbing (e.g. Normal, Alpha) (visual only so no need to be a double) + native float BobSpeed; // [XA] Bobbing speed. Defines how quickly a weapon bobs. + native float BobRangeX, BobRangeY; // [XA] Bobbing range. Defines how far a weapon bobs in either direction. + native Ammo Ammo1, Ammo2; // In-inventory instance variables + native Weapon SisterWeapon; + native float FOVScale; + native int Crosshair; // 0 to use player's crosshair + native bool GivenAsMorphWeapon; + native bool bAltFire; // Set when this weapon's alternate fire is used. + native readonly bool bDehAmmo; + Default { Inventory.PickupSound "misc/w_pkup"; diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 71cdb8479..ed95354f8 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -1,5 +1,31 @@ class PlayerPawn : Actor native { + + native int crouchsprite; + native int MaxHealth; + native int MugShotMaxHealth; + native int RunHealth; + native int PlayerFlags; + native Inventory InvFirst; // first inventory item displayed on inventory bar + native Inventory InvSel; // selected inventory item + + // [GRB] Player class properties + native double JumpZ; + native double GruntSpeed; + native double FallingScreamMinSpeed, FallingScreamMaxSpeed; + native double ViewHeight; + native double ForwardMove1, ForwardMove2; + native double SideMove1, SideMove2; + native TextureID ScoreIcon; + native int SpawnMask; + native Name MorphWeapon; + native double AttackZOffset; // attack height, relative to player center + native double UseRange; // [NS] Distance at which player can +use + native double AirCapacity; // Multiplier for air supply underwater. + native Class FlechetteType; + native color DamageFade; // [CW] Fades for when you are being damaged. + native double ViewBob; // [SP] ViewBob Multiplier + Default { Health 100; @@ -75,10 +101,118 @@ class PlayerChunk : PlayerPawn native class PSprite : Object native { + native readonly State CurState; + native readonly Actor Caller; + native readonly PSprite Next; + native readonly PlayerInfo Owner; + native SpriteID Sprite; + native int Frame; + native readonly int ID; + native Bool processPending; + native double x; + native double y; + native double oldx; + native double oldy; + native Bool firstTic; + native int Tics; + native bool bAddWeapon; + native bool bAddBob; + native bool bPowDouble; + native bool bCVarFast; + native bool bFlip; } -struct PlayerInfo native // this is what internally is player_t +struct PlayerInfo native // this is what internally is known as player_t { + native readonly PlayerPawn mo; + native uint8 playerstate; + native uint original_oldbuttons; + native readonly Class cls; + native float DesiredFOV; + native readonly float FOV; + native double viewz; + native double viewheight; + native double deltaviewheight; + native double bob; + native vector2 vel; + native bool centering; + native uint8 turnticks; + native bool attackdown; + native bool usedown; + native uint oldbuttons; + native int health; + native int inventorytics; + native uint8 CurrentPlayerClass; + native int frags[MAXPLAYERS]; + native int fragcount; + native int lastkilltime; + native uint8 multicount; + native uint8 spreecount; + native uint16 WeaponState; + native Weapon ReadyWeapon; + native Weapon PendingWeapon; + native PSprite psprites; + native int cheats; + native int timefreezer; + native int16 refire; + native int16 inconsistent; + native bool waiting; + native int killcount; + native int itemcount; + native int secretcount; + native int damagecount; + native int bonuscount; + native int hazardcount; + native int hazardinterval; + native Name hazardtype; + native int poisoncount; + native Name poisontype; + native Name poisonpaintype; + native Actor poisoner; + native Actor attacker; + native int extralight; + native int16 fixedcolormap; + native int16 fixedlightlevel; + native int morphtics; + native ClassMorphedPlayerClass; + native int MorphStyle; + native Class MorphExitFlash; + native Class PremorphWeapon; + native int chickenPeck; + native int jumpTics; + native bool onground; + native int respawn_time; + native Actor camera; + native int air_finished; + native Name LastDamageType; + native Actor MUSINFOactor; + native int8 MUSINFOtics; + native bool settings_controller; + native int8 crouching; + native int8 crouchdir; + native Bot bot; + native float BlendR; + native float BlendG; + native float BlendB; + native float BlendA; + native String LogText; + native double MinPitch; + native double MaxPitch; + native double crouchfactor; + native double crouchoffset; + native double crouchviewdelta; + native Actor ConversationNPC; + native Actor ConversationPC; + native double ConversationNPCAngle; + native bool ConversationFaceTalker; +/* these are not doable yet +ticcmd_t cmd; +usercmd_t original_cmd; +userinfo_t userinfo; // [RH] who is this? +FWeaponSlots weapons; +*/ + + native void SetPsprite(int id, State stat, bool pending = false); native void SetSafeFlash(Weapon weap, State flashstate, int index); native PSprite GetPSprite(int id); From 46757ff8bfbe3716bdc7c8903c7d953c88aeba63 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 23 Nov 2016 00:35:06 +0100 Subject: [PATCH 078/185] - exported the native fields of FState and FLevelLocals as well. --- src/g_level.cpp | 82 +++++++++++++++------------------ src/p_states.cpp | 36 ++++++--------- src/scripting/thingdef_data.cpp | 9 ++-- wadsrc/static/zscript/base.txt | 59 ++++++++++++++++++++++++ 4 files changed, 114 insertions(+), 72 deletions(-) diff --git a/src/g_level.cpp b/src/g_level.cpp index 8987aed6c..a715b5d26 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1850,55 +1850,45 @@ void FLevelLocals::AddScroller (int secnum) //========================================================================== // -// sets up the script-side version of FLevelLocals -// Since this is a global variable and the script compiler does -// not allow defining them, it will be fully set up here. +// // //========================================================================== -void G_InitLevelLocalsForScript() -{ - PStruct *lstruct = NewNativeStruct("LevelLocals", nullptr); - PField *levelf = new PField("level", lstruct, VARF_Native | VARF_Static, (intptr_t)&level); - GlobalSymbols.AddSymbol(levelf); - - // This only exports a selection of fields. Not everything here is useful to the playsim. - lstruct->AddNativeField("time", TypeSInt32, myoffsetof(FLevelLocals, time), VARF_ReadOnly); - lstruct->AddNativeField("maptime", TypeSInt32, myoffsetof(FLevelLocals, maptime), VARF_ReadOnly); - lstruct->AddNativeField("totaltime", TypeSInt32, myoffsetof(FLevelLocals, totaltime), VARF_ReadOnly); - lstruct->AddNativeField("starttime", TypeSInt32, myoffsetof(FLevelLocals, starttime), VARF_ReadOnly); - lstruct->AddNativeField("partime", TypeSInt32, myoffsetof(FLevelLocals, partime), VARF_ReadOnly); - lstruct->AddNativeField("sucktime", TypeSInt32, myoffsetof(FLevelLocals, sucktime), VARF_ReadOnly); - lstruct->AddNativeField("cluster", TypeSInt32, myoffsetof(FLevelLocals, cluster), VARF_ReadOnly); - lstruct->AddNativeField("clusterflags", TypeSInt32, myoffsetof(FLevelLocals, clusterflags), VARF_ReadOnly); - lstruct->AddNativeField("levelnum", TypeSInt32, myoffsetof(FLevelLocals, levelnum), VARF_ReadOnly); - //lstruct->AddNativeField("levelname", TypeString, myoffsetof(FLevelLocals, LevelName), VARF_ReadOnly); // must use an access function to resolve string table references. - lstruct->AddNativeField("mapname", TypeString, myoffsetof(FLevelLocals, MapName), VARF_ReadOnly); - lstruct->AddNativeField("nextmap", TypeString, myoffsetof(FLevelLocals, NextMap)); - lstruct->AddNativeField("nextsecretmap", TypeString, myoffsetof(FLevelLocals, NextSecretMap)); - lstruct->AddNativeField("maptype", TypeSInt32, myoffsetof(FLevelLocals, maptype), VARF_ReadOnly); - lstruct->AddNativeField("monsterstelefrag", TypeSInt32, myoffsetof(FLevelLocals, flags), VARF_ReadOnly, LEVEL_MONSTERSTELEFRAG); - lstruct->AddNativeField("actownspecial", TypeSInt32, myoffsetof(FLevelLocals, flags), VARF_ReadOnly, LEVEL_ACTOWNSPECIAL); - lstruct->AddNativeField("sndseqtotalctrl", TypeSInt32, myoffsetof(FLevelLocals, flags), VARF_ReadOnly, LEVEL_SNDSEQTOTALCTRL); - lstruct->AddNativeField("allmap", TypeSInt32, myoffsetof(FLevelLocals, flags2), 0, (LEVEL2_ALLMAP)); - lstruct->AddNativeField("missilesactivateimpact", TypeSInt32, myoffsetof(FLevelLocals, flags2), 0, LEVEL2_MISSILESACTIVATEIMPACT); - lstruct->AddNativeField("monsterfallingdamage", TypeSInt32, myoffsetof(FLevelLocals, flags2), 0, LEVEL2_MONSTERFALLINGDAMAGE); - lstruct->AddNativeField("checkswitchrange", TypeSInt32, myoffsetof(FLevelLocals, flags2), 0, LEVEL2_CHECKSWITCHRANGE); - lstruct->AddNativeField("polygrind", TypeSInt32, myoffsetof(FLevelLocals, flags2), 0, LEVEL2_POLYGRIND); - lstruct->AddNativeField("music", TypeString, myoffsetof(FLevelLocals, Music), VARF_ReadOnly); - lstruct->AddNativeField("musicorder", TypeSInt32, myoffsetof(FLevelLocals, musicorder), VARF_ReadOnly); - lstruct->AddNativeField("total_secrets", TypeSInt32, myoffsetof(FLevelLocals, total_secrets), VARF_ReadOnly); - lstruct->AddNativeField("found_secrets", TypeSInt32, myoffsetof(FLevelLocals, found_secrets)); - lstruct->AddNativeField("total_items", TypeSInt32, myoffsetof(FLevelLocals, total_items), VARF_ReadOnly); - lstruct->AddNativeField("found_items", TypeSInt32, myoffsetof(FLevelLocals, found_items)); - lstruct->AddNativeField("total_monsters", TypeSInt32, myoffsetof(FLevelLocals, total_monsters), VARF_ReadOnly); - lstruct->AddNativeField("killed_monsters", TypeSInt32, myoffsetof(FLevelLocals, killed_monsters)); - lstruct->AddNativeField("gravity", TypeFloat64, myoffsetof(FLevelLocals, gravity)); - lstruct->AddNativeField("aircontrol", TypeFloat64, myoffsetof(FLevelLocals, aircontrol)); - lstruct->AddNativeField("airfriction", TypeFloat64, myoffsetof(FLevelLocals, airfriction)); - lstruct->AddNativeField("airsupply", TypeSInt32, myoffsetof(FLevelLocals, airsupply)); - lstruct->AddNativeField("teamdamage", TypeFloat64, myoffsetof(FLevelLocals, teamdamage)); -} +DEFINE_FIELD(FLevelLocals, time) +DEFINE_FIELD(FLevelLocals, maptime) +DEFINE_FIELD(FLevelLocals, totaltime) +DEFINE_FIELD(FLevelLocals, starttime) +DEFINE_FIELD(FLevelLocals, partime) +DEFINE_FIELD(FLevelLocals, sucktime) +DEFINE_FIELD(FLevelLocals, cluster) +DEFINE_FIELD(FLevelLocals, clusterflags) +DEFINE_FIELD(FLevelLocals, levelnum) +DEFINE_FIELD(FLevelLocals, LevelName) +DEFINE_FIELD(FLevelLocals, MapName) +DEFINE_FIELD(FLevelLocals, NextMap) +DEFINE_FIELD(FLevelLocals, NextSecretMap) +DEFINE_FIELD(FLevelLocals, maptype) +DEFINE_FIELD(FLevelLocals, Music) +DEFINE_FIELD(FLevelLocals, musicorder) +DEFINE_FIELD(FLevelLocals, total_secrets) +DEFINE_FIELD(FLevelLocals, found_secrets) +DEFINE_FIELD(FLevelLocals, total_items) +DEFINE_FIELD(FLevelLocals, found_items) +DEFINE_FIELD(FLevelLocals, total_monsters) +DEFINE_FIELD(FLevelLocals, killed_monsters) +DEFINE_FIELD(FLevelLocals, gravity) +DEFINE_FIELD(FLevelLocals, aircontrol) +DEFINE_FIELD(FLevelLocals, airfriction) +DEFINE_FIELD(FLevelLocals, airsupply) +DEFINE_FIELD(FLevelLocals, teamdamage) +DEFINE_FIELD_BIT(FLevelLocals, flags, monsterstelefrag, LEVEL_MONSTERSTELEFRAG) +DEFINE_FIELD_BIT(FLevelLocals, flags, actownspecial, LEVEL_ACTOWNSPECIAL) +DEFINE_FIELD_BIT(FLevelLocals, flags, sndseqtotalctrl, LEVEL_SNDSEQTOTALCTRL) +DEFINE_FIELD_BIT(FLevelLocals, flags2, allmap, LEVEL2_ALLMAP) +DEFINE_FIELD_BIT(FLevelLocals, flags2, missilesactivateimpact, LEVEL2_MISSILESACTIVATEIMPACT) +DEFINE_FIELD_BIT(FLevelLocals, flags2, monsterfallingdamage, LEVEL2_MONSTERFALLINGDAMAGE) +DEFINE_FIELD_BIT(FLevelLocals, flags2, checkswitchrange, LEVEL2_CHECKSWITCHRANGE) +DEFINE_FIELD_BIT(FLevelLocals, flags2, polygrind, LEVEL2_POLYGRIND) //========================================================================== // diff --git a/src/p_states.cpp b/src/p_states.cpp index 6e45db6b0..b3e9593af 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -1063,24 +1063,18 @@ CCMD(dumpstates) // //========================================================================== -void P_InitStateForScript() -{ - PNativeStruct *pstruct = dyn_cast(TypeState->PointedType); - assert(pstruct != nullptr); - - pstruct->AddNativeField("NextState", TypeState, myoffsetof(FState, NextState), VARF_ReadOnly); - pstruct->AddNativeField("sprite", TypeSInt32, myoffsetof(FState, sprite), VARF_ReadOnly); - pstruct->AddNativeField("Tics", TypeSInt16, myoffsetof(FState, Tics), VARF_ReadOnly); - pstruct->AddNativeField("TicRange", TypeUInt16, myoffsetof(FState, TicRange), VARF_ReadOnly); - pstruct->AddNativeField("Frame", TypeUInt8, myoffsetof(FState, Frame), VARF_ReadOnly); - pstruct->AddNativeField("UseFlags", TypeUInt8, myoffsetof(FState, UseFlags), VARF_ReadOnly); - pstruct->AddNativeField("Misc1", TypeSInt32, myoffsetof(FState, Misc1), VARF_ReadOnly); - pstruct->AddNativeField("Misc2", TypeSInt32, myoffsetof(FState, Misc2), VARF_ReadOnly); - pstruct->AddNativeField("bSlow", TypeUInt16, myoffsetof(FState, StateFlags), VARF_ReadOnly, STF_SLOW); - pstruct->AddNativeField("bFast", TypeUInt16, myoffsetof(FState, StateFlags), VARF_ReadOnly, STF_FAST); - pstruct->AddNativeField("bFullbright", TypeUInt16, myoffsetof(FState, StateFlags), VARF_ReadOnly, STF_FULLBRIGHT); - pstruct->AddNativeField("bNoDelay", TypeUInt16, myoffsetof(FState, StateFlags), VARF_ReadOnly, STF_NODELAY); - pstruct->AddNativeField("bSameFrame", TypeUInt16, myoffsetof(FState, StateFlags), VARF_ReadOnly, STF_SAMEFRAME); - pstruct->AddNativeField("bCanRaise", TypeUInt16, myoffsetof(FState, StateFlags), VARF_ReadOnly, STF_CANRAISE); - pstruct->AddNativeField("bDehacked", TypeUInt16, myoffsetof(FState, StateFlags), VARF_ReadOnly, STF_DEHACKED); -} \ No newline at end of file +DEFINE_FIELD(FState, NextState) +DEFINE_FIELD(FState, sprite) +DEFINE_FIELD(FState, Tics) +DEFINE_FIELD(FState, TicRange) +DEFINE_FIELD(FState, Frame) +DEFINE_FIELD(FState, UseFlags) +DEFINE_FIELD(FState, Misc1) +DEFINE_FIELD(FState, Misc2) +DEFINE_FIELD_BIT(FState, StateFlags, bSlow) +DEFINE_FIELD_BIT(FState, StateFlags, bFast) +DEFINE_FIELD_BIT(FState, StateFlags, bFullbright) +DEFINE_FIELD_BIT(FState, StateFlags, bNoDelay) +DEFINE_FIELD_BIT(FState, StateFlags, bSameFrame) +DEFINE_FIELD_BIT(FState, StateFlags, bCanRaise) +DEFINE_FIELD_BIT(FState, StateFlags, bDehacked) diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 7488c9716..bc6e0ad43 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -691,9 +691,6 @@ static int fieldcmp(const void * a, const void * b) // Initialization // //========================================================================== -void G_InitLevelLocalsForScript(); -void P_InitPlayerForScript(); -void P_InitStateForScript(); void InitThingdef() { @@ -703,8 +700,10 @@ void InitThingdef() auto sptr = NewPointer(sstruct); sstruct->AddNativeField("soundtarget", TypeActor, myoffsetof(sector_t, SoundTarget)); - G_InitLevelLocalsForScript(); - P_InitStateForScript(); + // set up a variable for the global level data structure + PStruct *lstruct = NewNativeStruct("LevelLocals", nullptr); + PField *levelf = new PField("level", lstruct, VARF_Native | VARF_Static, (intptr_t)&level); + GlobalSymbols.AddSymbol(levelf); // set up a variable for the global players array. PStruct *pstruct = NewNativeStruct("PlayerInfo", nullptr); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 0f28de335..15a8c9a3b 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -49,6 +49,65 @@ class SpotState : Object native native SpecialSpot GetNextInList(class type, int skipcounter); } +struct LevelLocals native +{ + native readonly int time; + native readonly int maptime; + native readonly int totaltime; + native readonly int starttime; + native readonly int partime; + native readonly int sucktime; + native readonly int cluster; + native readonly int clusterflags; + native readonly int levelnum; + native readonly String LevelName; + native readonly String MapName; + native String NextMap; + native String NextSecretMap; + native readonly int maptype; + native readonly String Music; + native readonly int musicorder; + native readonly int total_secrets; + native int found_secrets; + native readonly int total_items; + native int found_items; + native readonly int total_monsters; + native int killed_monsters; + native double gravity; + native double aircontrol; + native double airfriction; + native int airsupply; + native double teamdamage; + native bool monsterstelefrag; + native bool actownspecial; + native bool sndseqtotalctrl; + native bool allmap; + native bool missilesactivateimpact; + native bool monsterfallingdamage; + native bool checkswitchrange; + native bool polygrind; +// level_info_t *info cannot be done yet. +} + +struct State native +{ + State NextState; + int sprite; + int16 Tics; + uint16 TicRange; + uint8 Frame; + uint8 UseFlags; + int Misc1; + int Misc2; + uint16 bSlow; + uint16 bFast; + bool bFullbright; + bool bNoDelay; + bool bSameFrame; + bool bCanRaise; + bool bDehacked; +} + struct Sector native { } From 0c95568d98fe6e23c99361f770a933d17f575b69 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 23 Nov 2016 01:31:48 +0100 Subject: [PATCH 079/185] - exported native fields of several more classes. --- src/g_shared/a_armor.cpp | 18 +++++++++ src/g_shared/a_pickups.cpp | 24 +++++++++++- src/g_shared/a_pickups.h | 2 +- src/scripting/decorate/olddecorations.cpp | 2 + src/scripting/vm/vm.h | 1 + wadsrc/static/zscript/shared/inventory.txt | 45 +++++++++++++++++++++- 6 files changed, 89 insertions(+), 3 deletions(-) diff --git a/src/g_shared/a_armor.cpp b/src/g_shared/a_armor.cpp index 8f1116a9e..e1dd0986e 100644 --- a/src/g_shared/a_armor.cpp +++ b/src/g_shared/a_armor.cpp @@ -15,6 +15,15 @@ IMPLEMENT_CLASS(ABasicArmorPickup, false, false, false, false) IMPLEMENT_CLASS(ABasicArmorBonus, false, false, true, false) IMPLEMENT_CLASS(AHexenArmor, false, false, false, false) + +DEFINE_FIELD(ABasicArmor, AbsorbCount) +DEFINE_FIELD(ABasicArmor, SavePercent) +DEFINE_FIELD(ABasicArmor, MaxAbsorb) +DEFINE_FIELD(ABasicArmor, MaxFullAbsorb) +DEFINE_FIELD(ABasicArmor, BonusCount) +DEFINE_FIELD(ABasicArmor, ArmorType) +DEFINE_FIELD(ABasicArmor, ActualSaveAmount) + //=========================================================================== // // ABasicArmor :: Serialize @@ -193,6 +202,11 @@ void ABasicArmor::AbsorbDamage (int damage, FName damageType, int &newdamage) } } +DEFINE_FIELD(ABasicArmorPickup, SavePercent) +DEFINE_FIELD(ABasicArmorPickup, MaxAbsorb) +DEFINE_FIELD(ABasicArmorPickup, MaxFullAbsorb) +DEFINE_FIELD(ABasicArmorPickup, SaveAmount) + //=========================================================================== // // ABasicArmorPickup :: Serialize @@ -396,6 +410,10 @@ bool ABasicArmorBonus::Use (bool pickup) return true; } + +DEFINE_FIELD(AHexenArmor, Slots) +DEFINE_FIELD(AHexenArmor, SlotsIncrement) + //=========================================================================== // // AHexenArmor :: Serialize diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index a3abe7cf4..ce8f53d61 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -88,6 +88,9 @@ void PClassAmmo::DeriveData(PClass *newclass) IMPLEMENT_CLASS(AAmmo, false, false, false, false) +DEFINE_FIELD(AAmmo, BackpackAmount) +DEFINE_FIELD(AAmmo, BackpackMaxAmount) + //=========================================================================== // // AAmmo :: Serialize @@ -483,6 +486,20 @@ IMPLEMENT_POINTERS_START(AInventory) IMPLEMENT_POINTER(Owner) IMPLEMENT_POINTERS_END +DEFINE_FIELD_BIT(AInventory, ItemFlags, bPickupGood, IF_PICKUPGOOD) +DEFINE_FIELD_BIT(AInventory, ItemFlags, bCreateCopyMoved, IF_CREATECOPYMOVED) +DEFINE_FIELD_BIT(AInventory, ItemFlags, bInitEffectFailed, IF_INITEFFECTFAILED) +DEFINE_FIELD(AInventory, Owner) +DEFINE_FIELD(AInventory, Amount) +DEFINE_FIELD(AInventory, MaxAmount) +DEFINE_FIELD(AInventory, InterHubAmount) +DEFINE_FIELD(AInventory, RespawnTics) +DEFINE_FIELD(AInventory, Icon) +DEFINE_FIELD(AInventory, DropTime) +DEFINE_FIELD(AInventory, SpawnPointClass) +DEFINE_FIELD(AInventory, PickupFlash) +DEFINE_FIELD(AInventory, PickupSound) + //=========================================================================== // // AInventory :: Tick @@ -1739,6 +1756,8 @@ void PClassHealth::DeriveData(PClass *newclass) IMPLEMENT_CLASS(AHealth, false, false, false, false) +DEFINE_FIELD(AHealth, PrevHealth) + //=========================================================================== // // AHealth :: PickupMessage @@ -1858,6 +1877,10 @@ void AHealthPickup::Serialize(FSerializer &arc) // Backpack ----------------------------------------------------------------- +IMPLEMENT_CLASS(ABackpackItem, false, false, false, false) + +DEFINE_FIELD(ABackpackItem, bDepleted) + //=========================================================================== // // ABackpackItem :: Serialize @@ -2033,7 +2056,6 @@ void ABackpackItem::DetachFromOwner () // //=========================================================================== -IMPLEMENT_CLASS(ABackpackItem, false, false, false, false) IMPLEMENT_CLASS(AMapRevealer, false, false, false, false) //=========================================================================== diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index 6dc2d0bc5..ec34404df 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -429,8 +429,8 @@ class AHealth : public AInventory { DECLARE_CLASS_WITH_META(AHealth, AInventory, PClassHealth) - int PrevHealth; public: + int PrevHealth; virtual bool TryPickup (AActor *&other); virtual const char *PickupMessage (); }; diff --git a/src/scripting/decorate/olddecorations.cpp b/src/scripting/decorate/olddecorations.cpp index a2cbc636b..7540d45f4 100644 --- a/src/scripting/decorate/olddecorations.cpp +++ b/src/scripting/decorate/olddecorations.cpp @@ -98,6 +98,8 @@ public: IMPLEMENT_CLASS(AFakeInventory, false, false, false, false) +DEFINE_FIELD(AFakeInventory, Respawnable) + // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 10ac4bb7b..7b05fae36 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -4,6 +4,7 @@ #include "zstring.h" #include "autosegs.h" #include "vectors.h" +#include "cmdlib.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 diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index 929f826da..47f753ca1 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -1,5 +1,20 @@ class Inventory : Actor native { + + native Actor Owner; // Who owns this item? NULL if it's still a pickup. + native int Amount; // Amount of item this instance has + native int MaxAmount; // Max amount of item this instance can have + native int InterHubAmount; // Amount of item that can be kept between hubs or levels + native int RespawnTics; // Tics from pickup time to respawn time + native TextureID Icon; // Icon to show on status bar or HUD + native int DropTime; // Countdown after dropping + native Class SpawnPointClass; // For respawning like Heretic's mace + native Class PickupFlash; // actor to spawn as pickup flash + native Sound PickupSound; + native bool bPickupGood; + native bool bCreateCopyMoved; + native bool bInitEffectFailed; + Default { Inventory.Amount 1; @@ -73,6 +88,9 @@ class ScoreItem : Inventory native class Ammo : Inventory native { + native int BackpackAmount; + native int BackpackMaxAmount; + Default { +INVENTORY.KEEPDEPLETED @@ -82,6 +100,7 @@ class Ammo : Inventory native class BackpackItem : Inventory native { + native bool bDepleted; } class Armor : Inventory native @@ -94,6 +113,15 @@ class Armor : Inventory native class BasicArmor : Armor native { + + native int AbsorbCount; + native double SavePercent; + native int MaxAbsorb; + native int MaxFullAbsorb; + native int BonusCount; + native Name ArmorType; + native int ActualSaveAmount; + Default { +Inventory.KEEPDEPLETED @@ -121,6 +149,12 @@ class BasicArmorBonus : Armor native class BasicArmorPickup : Armor native { + + native double SavePercent; + native int MaxAbsorb; + native int MaxFullAbsorb; + native int SaveAmount; + Default { +Inventory.AUTOACTIVATE; @@ -130,6 +164,10 @@ class BasicArmorPickup : Armor native class HexenArmor : Armor native { + + native double Slots[5]; + native double SlotsIncrement[4]; + Default { +Inventory.KEEPDEPLETED @@ -139,7 +177,10 @@ class HexenArmor : Armor native class DehackedPickup : Inventory native {} -class FakeInventory : Inventory native {} +class FakeInventory : Inventory native +{ + native bool Respawnable; +} class CustomInventory : StateProvider native { @@ -151,6 +192,8 @@ class CustomInventory : StateProvider native class Health : Inventory native { + native int PrevHealth; + Default { Inventory.Amount 1; From 789315bb4a7a2a5701b40c4ee004336395bd452f Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Tue, 22 Nov 2016 21:22:39 -0500 Subject: [PATCH 080/185] - Fixed build with MinGW-w64 (TDM-GCC 5.1). Note that the resulting binary will crash under -O3 until the alignment violation is taken care of in FRemapTable::Alloc. - It appears that CMake added native support for building rc files with MinGW at some point so removed manual rc compiling code. --- src/CMakeLists.txt | 10 +----- src/i_module.cpp | 2 +- src/v_video.cpp | 2 +- src/win32/i_crash.cpp | 48 ----------------------------- src/win32/i_keyboard.cpp | 5 +++ src/win32/i_rawps2.cpp | 2 +- src/win32/i_specialpaths.cpp | 1 + src/win32/i_xinput.cpp | 11 +++++++ tools/updaterevision/CMakeLists.txt | 17 +++------- 9 files changed, 26 insertions(+), 72 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 04e6087ea..7d532ca9c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -728,15 +728,7 @@ if( WIN32 ) set( SYSTEM_SOURCES ${PLAT_WIN32_SOURCES} ) set( OTHER_SYSTEM_SOURCES ${PLAT_POSIX_SOURCES} ${PLAT_SDL_SOURCES} ${PLAT_OSX_SOURCES} ${PLAT_COCOA_SOURCES} ${PLAT_UNIX_SOURCES} ) - if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) - # CMake is not set up to compile and link rc files with GCC. :( - add_custom_command( OUTPUT zdoom-rc.o - COMMAND windres -o zdoom-rc.o -i ${CMAKE_CURRENT_SOURCE_DIR}/win32/zdoom.rc - DEPENDS win32/zdoom.rc ) - set( SYSTEM_SOURCES ${SYSTEM_SOURCES} zdoom-rc.o ) - else() - set( SYSTEM_SOURCES ${SYSTEM_SOURCES} win32/zdoom.rc ) - endif() + set( SYSTEM_SOURCES ${SYSTEM_SOURCES} win32/zdoom.rc ) elseif( APPLE ) if( OSX_COCOA_BACKEND ) set( SYSTEM_SOURCES_DIR posix posix/cocoa ) diff --git a/src/i_module.cpp b/src/i_module.cpp index 1ed40310f..a82963ec5 100644 --- a/src/i_module.cpp +++ b/src/i_module.cpp @@ -97,5 +97,5 @@ bool FModule::Open(const char* lib) void *FModule::GetSym(const char* name) { - return GetProcAddress((HMODULE)handle, name); + return (void *)GetProcAddress((HMODULE)handle, name); } diff --git a/src/v_video.cpp b/src/v_video.cpp index 37cfdd480..32e1a54d3 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -72,7 +72,7 @@ FRenderer *Renderer; IMPLEMENT_ABSTRACT_CLASS (DCanvas) IMPLEMENT_ABSTRACT_CLASS (DFrameBuffer) -#if defined(_DEBUG) && defined(_M_IX86) +#if defined(_DEBUG) && defined(_M_IX86) && !defined(__MINGW32__) #define DBGBREAK { __asm int 3 } #else #define DBGBREAK diff --git a/src/win32/i_crash.cpp b/src/win32/i_crash.cpp index d4804ec0e..4a0a1b160 100644 --- a/src/win32/i_crash.cpp +++ b/src/win32/i_crash.cpp @@ -75,54 +75,6 @@ #include #include -#if defined(_WIN64) && defined(__GNUC__) -struct KNONVOLATILE_CONTEXT_POINTERS { - union { - PDWORD64 IntegerContext[16]; - struct { - PDWORD64 Rax; - PDWORD64 Rcx; - PDWORD64 Rdx; - PDWORD64 Rbx; - PDWORD64 Rsp; - PDWORD64 Rbp; - PDWORD64 Rsi; - PDWORD64 Rdi; - PDWORD64 R8; - PDWORD64 R9; - PDWORD64 R10; - PDWORD64 R11; - PDWORD64 R12; - PDWORD64 R13; - PDWORD64 R14; - PDWORD64 R15; - }; - }; -}; -typedef -EXCEPTION_DISPOSITION -NTAPI -EXCEPTION_ROUTINE ( - struct _EXCEPTION_RECORD *ExceptionRecord, - PVOID EstablisherFrame, - struct _CONTEXT *ContextRecord, - PVOID DispatcherContext - ); -NTSYSAPI -EXCEPTION_ROUTINE * -NTAPI -RtlVirtualUnwind ( - DWORD HandlerType, - DWORD64 ImageBase, - DWORD64 ControlPc, - PRUNTIME_FUNCTION FunctionEntry, - PCONTEXT ContextRecord, - PVOID *HandlerData, - PDWORD64 EstablisherFrame, - KNONVOLATILE_CONTEXT_POINTERS *ContextPointers - ); -#endif - // MACROS ------------------------------------------------------------------ #define REMOTE_HOST "localhost" diff --git a/src/win32/i_keyboard.cpp b/src/win32/i_keyboard.cpp index cdcf9d8d8..e62942e8d 100644 --- a/src/win32/i_keyboard.cpp +++ b/src/win32/i_keyboard.cpp @@ -21,6 +21,11 @@ #define DINPUT_BUFFERSIZE 32 +// MinGW-w64 (TDM5.1 - 2016/11/21) +#ifndef DIK_PREVTRACK +#define DIK_PREVTRACK DIK_CIRCUMFLEX +#endif + // TYPES ------------------------------------------------------------------- class FDInputKeyboard : public FKeyboard diff --git a/src/win32/i_rawps2.cpp b/src/win32/i_rawps2.cpp index 50de1d0f4..940ef4bb1 100644 --- a/src/win32/i_rawps2.cpp +++ b/src/win32/i_rawps2.cpp @@ -389,7 +389,7 @@ bool FRawPS2Controller::ProcessInput(RAWHID *raw, int code) { // w32api has an incompatible definition of bRawData. // (But the version that comes with MinGW64 is fine.) -#if defined(__GNUC__) && !defined(_WIN64) +#if defined(__GNUC__) && !defined(__MINGW64_VERSION_MAJOR) BYTE *rawdata = &raw->bRawData; #else BYTE *rawdata = raw->bRawData; diff --git a/src/win32/i_specialpaths.cpp b/src/win32/i_specialpaths.cpp index 6d4890ea9..745c12f12 100644 --- a/src/win32/i_specialpaths.cpp +++ b/src/win32/i_specialpaths.cpp @@ -33,6 +33,7 @@ ** */ +#define _WIN32_WINNT 0x0601 #include #include #include diff --git a/src/win32/i_xinput.cpp b/src/win32/i_xinput.cpp index 1180f9f32..22c2dd714 100644 --- a/src/win32/i_xinput.cpp +++ b/src/win32/i_xinput.cpp @@ -33,6 +33,17 @@ #define XUSER_MAX_COUNT 4 #endif +// MinGW +#ifndef XINPUT_DLL +#define XINPUT_DLL_A "xinput1_3.dll" +#define XINPUT_DLL_W L"xinput1_3.dll" +#ifdef UNICODE + #define XINPUT_DLL XINPUT_DLL_W +#else + #define XINPUT_DLL XINPUT_DLL_A +#endif +#endif + // TYPES ------------------------------------------------------------------- typedef DWORD (WINAPI *XInputGetStateType)(DWORD index, XINPUT_STATE *state); diff --git a/tools/updaterevision/CMakeLists.txt b/tools/updaterevision/CMakeLists.txt index 22890472a..db99ab812 100644 --- a/tools/updaterevision/CMakeLists.txt +++ b/tools/updaterevision/CMakeLists.txt @@ -1,19 +1,12 @@ cmake_minimum_required( VERSION 2.8.7 ) if( WIN32 ) - if( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE OR ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) - add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/trustinfo.o - COMMAND windres -o ${CMAKE_CURRENT_BINARY_DIR}/trustinfo.o -i ${CMAKE_CURRENT_SOURCE_DIR}/trustinfo.rc - DEPENDS trustinfo.rc ) - set( TRUSTINFO trustinfo.o ) + if( MSVC_VERSION GREATER 1399 ) + # VC 8+ adds a manifest automatically to the executable. We need to + # merge ours with it. + set( MT_MERGE ON ) else() - if( MSVC_VERSION GREATER 1399 ) - # VC 8+ adds a manifest automatically to the executable. We need to - # merge ours with it. - set( MT_MERGE ON ) - else( MSVC_VERSION GREATER 1399 ) - set( TRUSTINFO trustinfo.rc ) - endif( MSVC_VERSION GREATER 1399 ) + set( TRUSTINFO trustinfo.rc ) endif() else( WIN32 ) set( TRUSTINFO "" ) From 649c96261a8ad72996b19ff84c39d074ef46cd5b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 23 Nov 2016 10:13:17 +0100 Subject: [PATCH 081/185] - clarified error messages for bogus conversation scripts. --- src/p_conversation.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 0bc2b98a8..41c873375 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -252,7 +252,7 @@ static bool LoadScriptFile(int lumpnum, FileReader *lump, int numnodes, bool inc if ((type == 1 && !isbinary) || (type == 2 && isbinary)) { - DPrintf(DMSG_ERROR, "Incorrect data format for %s.", Wads.GetLumpFullName(lumpnum)); + DPrintf(DMSG_ERROR, "Incorrect data format for conversation script in %s.", Wads.GetLumpFullName(lumpnum)); return false; } @@ -272,7 +272,7 @@ static bool LoadScriptFile(int lumpnum, FileReader *lump, int numnodes, bool inc // is exactly 1516 bytes long. if (numnodes % 1516 != 0) { - DPrintf(DMSG_ERROR, "Incorrect data format for %s.", Wads.GetLumpFullName(lumpnum)); + DPrintf(DMSG_ERROR, "Incorrect data format for conversation script in %s.", Wads.GetLumpFullName(lumpnum)); return false; } numnodes /= 1516; @@ -282,7 +282,7 @@ static bool LoadScriptFile(int lumpnum, FileReader *lump, int numnodes, bool inc // And the teaser version has 1488-byte entries. if (numnodes % 1488 != 0) { - DPrintf(DMSG_ERROR, "Incorrect data format for %s.", Wads.GetLumpFullName(lumpnum)); + DPrintf(DMSG_ERROR, "Incorrect data format for conversation script in %s.", Wads.GetLumpFullName(lumpnum)); return false; } numnodes /= 1488; From 0489b6e7c5075bad5c83b9b2961c9f629ec11197 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Wed, 23 Nov 2016 10:19:52 +0100 Subject: [PATCH 082/185] - Fixed missing newlines to the conversation error message. --- src/p_conversation.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 41c873375..0208e6477 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -252,7 +252,7 @@ static bool LoadScriptFile(int lumpnum, FileReader *lump, int numnodes, bool inc if ((type == 1 && !isbinary) || (type == 2 && isbinary)) { - DPrintf(DMSG_ERROR, "Incorrect data format for conversation script in %s.", Wads.GetLumpFullName(lumpnum)); + DPrintf(DMSG_ERROR, "Incorrect data format for conversation script in %s.\n", Wads.GetLumpFullName(lumpnum)); return false; } @@ -272,7 +272,7 @@ static bool LoadScriptFile(int lumpnum, FileReader *lump, int numnodes, bool inc // is exactly 1516 bytes long. if (numnodes % 1516 != 0) { - DPrintf(DMSG_ERROR, "Incorrect data format for conversation script in %s.", Wads.GetLumpFullName(lumpnum)); + DPrintf(DMSG_ERROR, "Incorrect data format for conversation script in %s.\n", Wads.GetLumpFullName(lumpnum)); return false; } numnodes /= 1516; @@ -282,7 +282,7 @@ static bool LoadScriptFile(int lumpnum, FileReader *lump, int numnodes, bool inc // And the teaser version has 1488-byte entries. if (numnodes % 1488 != 0) { - DPrintf(DMSG_ERROR, "Incorrect data format for conversation script in %s.", Wads.GetLumpFullName(lumpnum)); + DPrintf(DMSG_ERROR, "Incorrect data format for conversation script in %s.\n", Wads.GetLumpFullName(lumpnum)); return false; } numnodes /= 1488; From 6ae266c76eb191f5a607b721cccc7a1b3567f1a0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 23 Nov 2016 14:27:08 +0100 Subject: [PATCH 083/185] - fixed: The check for identical floor planes on an opening should never allow it to be narrowed down. This can cause problems in rare situations where a sloped plane is checked outside its sector boundaries. --- src/p_map.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 5cc9bdf72..d102307bc 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -839,9 +839,11 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec // If the floor planes on both sides match we should recalculate open.bottom at the actual position we are checking // This is to avoid bumpy movement when crossing a linedef with the same slope on both sides. + // This should never narrow down the opening, though, only widen it. if (open.frontfloorplane == open.backfloorplane && open.bottom > LINEOPEN_MIN) { - open.bottom = open.frontfloorplane.ZatPoint(cres.Position); + auto newopen = open.frontfloorplane.ZatPoint(cres.Position); + if (newopen < open.bottom) open.bottom = newopen; } if (rail && From 5b059971f0eceb38f9883d19b37b0adcd4360e67 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 23 Nov 2016 14:32:18 +0100 Subject: [PATCH 084/185] - fixed: P_SpawnMapThing forced gravity instead of disabling it when being given Gravity = 0 from UDMF. --- src/p_mobj.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 2183f8cb9..62da26049 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -5063,7 +5063,11 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) if (mthing->FloatbobPhase >= 0 && mthing->FloatbobPhase < 64) mobj->FloatBobPhase = mthing->FloatbobPhase; if (mthing->Gravity < 0) mobj->Gravity = -mthing->Gravity; else if (mthing->Gravity > 0) mobj->Gravity *= mthing->Gravity; - else mobj->flags &= ~MF_NOGRAVITY; + else + { + mobj->flags |= MF_NOGRAVITY; + mobj->Gravity = 0; + } // For Hexen floatbob 'compatibility' we do not really want to alter the floorz. if (mobj->specialf1 == 0 || !(mobj->flags2 & MF2_FLOATBOB) || !(ib_compatflags & BCOMPATF_FLOATBOB)) From e138a3ffbc916ac2c9390c4f339e9154e07222a7 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Wed, 23 Nov 2016 12:15:58 +0200 Subject: [PATCH 085/185] Fixed infinite recursion with self-referencing multipatch textures See http://forum.zdoom.org/viewtopic.php?t=54355 --- src/textures/multipatchtexture.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/textures/multipatchtexture.cpp b/src/textures/multipatchtexture.cpp index 88d8815a6..de3dd2f13 100644 --- a/src/textures/multipatchtexture.cpp +++ b/src/textures/multipatchtexture.cpp @@ -1334,6 +1334,7 @@ void FMultiPatchTexture::ResolvePatches() { if (Inits[i].HasLine) Inits[i].sc.Message(MSG_WARNING, "Texture '%s' references itself as patch\n", Inits[i].TexName.GetChars()); else Printf(TEXTCOLOR_YELLOW "Texture '%s' references itself as patch\n", Inits[i].TexName.GetChars()); + continue; } else { From 9bd19c2d2e48556018458348fe07d2a4ea4f557e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 23 Nov 2016 14:38:45 +0100 Subject: [PATCH 086/185] - ensure that the MAPINFO parser never mixes HexenHack parsing with the new format. --- src/g_mapinfo.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index bc0470474..7bfb690e7 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -1508,10 +1508,18 @@ level_info_t *FMapInfoParser::ParseMapHeader(level_info_t &defaultinfo) if (sc.CheckNumber()) { // MAPNAME is a number; assume a Hexen wad - char maptemp[8]; - mysnprintf (maptemp, countof(maptemp), "MAP%02d", sc.Number); - mapname = maptemp; - HexenHack = true; + if (format_type == FMT_New) + { + mapname = sc.String; + } + else + { + char maptemp[8]; + mysnprintf(maptemp, countof(maptemp), "MAP%02d", sc.Number); + mapname = maptemp; + HexenHack = true; + format_type = FMT_Old; + } } else { From 7325e3f0f89a0d2431171fd9381d028f38a256e4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 23 Nov 2016 17:34:36 +0100 Subject: [PATCH 087/185] - exported all member fields that make sense. Entirely private ones or classes that are not supposed to be extended were left out. --- src/g_shared/a_artifacts.cpp | 46 +++++++--------------- src/g_shared/a_artifacts.h | 7 ++-- src/g_shared/a_keys.cpp | 2 + src/g_shared/a_pickups.cpp | 2 + src/g_shared/a_puzzleitems.cpp | 2 + src/g_shared/a_weaponpiece.cpp | 3 ++ src/g_shared/a_weapons.cpp | 2 + src/p_states.cpp | 14 +++---- wadsrc/static/zscript/shared/inventory.txt | 40 ++++++++++++++++++- 9 files changed, 75 insertions(+), 43 deletions(-) diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index 7cf05613a..66832c21c 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -56,6 +56,13 @@ void PClassPowerupGiver::ReplaceClassRef(PClass *oldclass, PClass *newclass) } } + +DEFINE_FIELD(APowerupGiver, PowerupType) +DEFINE_FIELD(APowerupGiver, EffectTics) +DEFINE_FIELD(APowerupGiver, BlendColor) +DEFINE_FIELD(APowerupGiver, Mode) +DEFINE_FIELD(APowerupGiver, Strength) + //=========================================================================== // // APowerupGiver :: Use @@ -114,6 +121,11 @@ void APowerupGiver::Serialize(FSerializer &arc) // Powerup ------------------------------------------------------------------- +DEFINE_FIELD(APowerup, EffectTics) +DEFINE_FIELD(APowerup, BlendColor) +DEFINE_FIELD(APowerup, Mode) +DEFINE_FIELD(APowerup, Strength) + //=========================================================================== // // APowerup :: Tick @@ -1184,40 +1196,12 @@ void APowerWeaponLevel2::EndEffect () } } -// Player Speed Trail (used by the Speed Powerup) ---------------------------- - -class APlayerSpeedTrail : public AActor -{ - DECLARE_CLASS (APlayerSpeedTrail, AActor) -public: - void Tick (); -}; - -IMPLEMENT_CLASS(APlayerSpeedTrail, false, false, false, false) - -//=========================================================================== -// -// APlayerSpeedTrail :: Tick -// -//=========================================================================== - -void APlayerSpeedTrail::Tick () -{ - const double fade = .6 / 8; - if (Alpha <= fade) - { - Destroy (); - } - else - { - Alpha -= fade; - } -} - // Speed Powerup ------------------------------------------------------------- IMPLEMENT_CLASS(APowerSpeed, false, false, false, false) +DEFINE_FIELD(APowerSpeed, SpeedFlags) + //=========================================================================== // // APowerSpeed :: Serialize @@ -1280,7 +1264,7 @@ void APowerSpeed::DoEffect () if (Owner->Vel.LengthSquared() <= 12*12) return; - AActor *speedMo = Spawn (Owner->Pos(), NO_REPLACE); + AActor *speedMo = Spawn("PlayerSpeedTrail", Owner->Pos(), NO_REPLACE); if (speedMo) { speedMo->Angles.Yaw = Owner->Angles.Yaw; diff --git a/src/g_shared/a_artifacts.h b/src/g_shared/a_artifacts.h index 85ebc2e81..163094d32 100644 --- a/src/g_shared/a_artifacts.h +++ b/src/g_shared/a_artifacts.h @@ -143,6 +143,7 @@ protected: void Tick (); void EndEffect (); +private: bool HitCenterFrame; }; @@ -281,15 +282,15 @@ public: virtual void Serialize(FSerializer &arc); void SetNoCallUndoMorph() { bNoCallUndoMorph = true; } + // Variables FNameNoInit PlayerClass, MorphFlash, UnMorphFlash; int MorphStyle; + player_t *Player; + bool bNoCallUndoMorph; // Because P_UndoPlayerMorph() can call EndEffect recursively protected: void InitEffect (); void EndEffect (); - // Variables - player_t *Player; - bool bNoCallUndoMorph; // Because P_UndoPlayerMorph() can call EndEffect recursively }; #endif //__A_ARTIFACTS_H__ diff --git a/src/g_shared/a_keys.cpp b/src/g_shared/a_keys.cpp index 69fbe48af..538e26090 100644 --- a/src/g_shared/a_keys.cpp +++ b/src/g_shared/a_keys.cpp @@ -472,6 +472,8 @@ bool P_CheckKeys (AActor *owner, int keynum, bool remote) IMPLEMENT_CLASS(AKey, false, false, false, false) +DEFINE_FIELD(AKey, KeyNumber) + bool AKey::HandlePickup (AInventory *item) { // In single player, you can pick up an infinite number of keys diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index ce8f53d61..c6475cc74 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -1801,6 +1801,8 @@ bool AHealth::TryPickup (AActor *&other) IMPLEMENT_CLASS(AHealthPickup, false, false, false, false) +DEFINE_FIELD(AHealthPickup, autousemode) + //=========================================================================== // // AHealthPickup :: CreateCopy diff --git a/src/g_shared/a_puzzleitems.cpp b/src/g_shared/a_puzzleitems.cpp index d243dc73c..640d5517d 100644 --- a/src/g_shared/a_puzzleitems.cpp +++ b/src/g_shared/a_puzzleitems.cpp @@ -19,6 +19,8 @@ void PClassPuzzleItem::DeriveData(PClass *newclass) IMPLEMENT_CLASS(APuzzleItem, false, false, false, false) +DEFINE_FIELD(APuzzleItem, PuzzleItemNumber) + bool APuzzleItem::HandlePickup (AInventory *item) { // Can't carry more than 1 of each puzzle item in coop netplay diff --git a/src/g_shared/a_weaponpiece.cpp b/src/g_shared/a_weaponpiece.cpp index 7aa9591e9..9edae6906 100644 --- a/src/g_shared/a_weaponpiece.cpp +++ b/src/g_shared/a_weaponpiece.cpp @@ -6,6 +6,9 @@ IMPLEMENT_CLASS(PClassWeaponPiece, false, false, false, false) IMPLEMENT_CLASS(AWeaponHolder, false, false, false, false) +DEFINE_FIELD(AWeaponHolder, PieceMask); +DEFINE_FIELD(AWeaponHolder, PieceWeapon); + void PClassWeaponPiece::ReplaceClassRef(PClass *oldclass, PClass *newclass) { Super::ReplaceClassRef(oldclass, newclass); diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index 5f221c5bc..530f8e364 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -868,6 +868,8 @@ FState *AWeapon::GetStateForButtonName (FName button) IMPLEMENT_CLASS(AWeaponGiver, false, false, false, false) +DEFINE_FIELD(AWeaponGiver, DropAmmoFactor); + void AWeaponGiver::Serialize(FSerializer &arc) { Super::Serialize(arc); diff --git a/src/p_states.cpp b/src/p_states.cpp index b3e9593af..f141cb550 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -1071,10 +1071,10 @@ DEFINE_FIELD(FState, Frame) DEFINE_FIELD(FState, UseFlags) DEFINE_FIELD(FState, Misc1) DEFINE_FIELD(FState, Misc2) -DEFINE_FIELD_BIT(FState, StateFlags, bSlow) -DEFINE_FIELD_BIT(FState, StateFlags, bFast) -DEFINE_FIELD_BIT(FState, StateFlags, bFullbright) -DEFINE_FIELD_BIT(FState, StateFlags, bNoDelay) -DEFINE_FIELD_BIT(FState, StateFlags, bSameFrame) -DEFINE_FIELD_BIT(FState, StateFlags, bCanRaise) -DEFINE_FIELD_BIT(FState, StateFlags, bDehacked) +DEFINE_FIELD_BIT(FState, StateFlags, bSlow, STF_SLOW) +DEFINE_FIELD_BIT(FState, StateFlags, bFast, STF_FAST) +DEFINE_FIELD_BIT(FState, StateFlags, bFullbright, STF_FULLBRIGHT) +DEFINE_FIELD_BIT(FState, StateFlags, bNoDelay, STF_NODELAY) +DEFINE_FIELD_BIT(FState, StateFlags, bSameFrame, STF_SAMEFRAME) +DEFINE_FIELD_BIT(FState, StateFlags, bCanRaise, STF_CANRAISE) +DEFINE_FIELD_BIT(FState, StateFlags, bDehacked, STF_DEHACKED) diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index 47f753ca1..048590b39 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -204,6 +204,8 @@ class Health : Inventory native class HealthPickup : Inventory native { + native int autousemode; + Default { Inventory.DefMaxAmount; @@ -213,6 +215,8 @@ class HealthPickup : Inventory native class Key : Inventory native { + native uint8 KeyNumber; + Default { +DONTGIB; // Don't disappear due to a crusher @@ -223,6 +227,13 @@ class Key : Inventory native class PowerupGiver : Inventory native { + + native Class PowerupType; + native int EffectTics; // Non-0 to override the powerup's default tics + native color BlendColor; // Non-0 to override the powerup's default blend + native Name Mode; // Meaning depends on powerup - used for Invulnerability and Invisibility + native double Strength; // Meaning depends on powerup - currently used only by Invisibility + Default { Inventory.DefMaxAmount; @@ -232,7 +243,13 @@ class PowerupGiver : Inventory native } } -class Powerup : Inventory native {} +class Powerup : Inventory native +{ + native int EffectTics; + native color BlendColor; + native Name Mode; // Meaning depends on powerup - used for Invulnerability and Invisibility + native double Strength; // Meaning depends on powerup - currently used only by Invisibility +} class PowerInvulnerable : Powerup native { @@ -337,6 +354,8 @@ class PowerWeaponLevel2 : Powerup native class PowerSpeed : Powerup native { + native int SpeedFlags; + Default { Powerup.Duration -45; @@ -348,7 +367,7 @@ class PowerSpeed : Powerup native // Player Speed Trail (used by the Speed Powerup) ---------------------------- -class PlayerSpeedTrail native +class PlayerSpeedTrail : Actor { Default { @@ -357,6 +376,15 @@ class PlayerSpeedTrail native Alpha 0.6; RenderStyle "Translucent"; } + + override void Tick() + { + Alpha -= .6 / 8; + if (Alpha <= 0) + { + Destroy (); + } + } } class PowerMinotaur : Powerup native @@ -477,6 +505,8 @@ class MapRevealer : Inventory native {} class PuzzleItem : Inventory native { + native int PuzzleItemNumber; + Default { +NOGRAVITY @@ -549,6 +579,9 @@ class Weapon : StateProvider native class WeaponGiver : Weapon native { + + native double DropAmmoFactor; + Default { Weapon.AmmoGive1 -1; @@ -558,6 +591,9 @@ class WeaponGiver : Weapon native class WeaponHolder : Inventory native { + native int PieceMask; + native Class PieceWeapon; + Default { +NOBLOCKMAP From f8c6adb7eb86e53ad537449b205987fe535fdb38 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 23 Nov 2016 18:54:16 +0100 Subject: [PATCH 088/185] - completely redid how A_PainShootSkull checks the legality of the LS spawn. It turned out that the Boom method does not work well with portals and fixing it while keeping it doesn't look feasible - the entire approach was bad from the start. Instead, let's use the same approach as P_XYMovement: Spawn the Lost Soul at the center of the PE, and then use multiple P_TryMoves to get it to its intended location. This will check all blocking lines, just like Boom did, but it will also properly handle z-positioning and portal transitions. --- src/g_doom/a_painelemental.cpp | 126 +++++++++++++++++---------------- 1 file changed, 64 insertions(+), 62 deletions(-) diff --git a/src/g_doom/a_painelemental.cpp b/src/g_doom/a_painelemental.cpp index f2db5a240..3fca0896c 100644 --- a/src/g_doom/a_painelemental.cpp +++ b/src/g_doom/a_painelemental.cpp @@ -62,84 +62,86 @@ void A_PainShootSkull (VMFrameStack *stack, AActor *self, DAngle Angle, PClassAc } // okay, there's room for another one - prestep = 4 + (self->radius + GetDefaultByType(spawntype)->radius) * 1.5; + double otherradius = GetDefaultByType(spawntype)->radius; + prestep = 4 + (self->radius + otherradius) * 1.5; - // NOTE: The following code contains some advance work for line-to-line portals which is currenty inactive. + DVector2 move = Angle.ToVector(prestep); + DVector3 spawnpos = self->PosPlusZ(8.0); + DVector3 destpos = spawnpos + move; - DVector2 dist = Angle.ToVector(prestep); - DVector3 pos = self->Vec3Offset(dist.X, dist.Y, 8., true); - DVector3 src = self->Pos(); + other = Spawn(spawntype, spawnpos, ALLOW_REPLACE); - for (int i = 0; i < 2; i++) + // Now check if the spawn is legal. Unlike Boom's hopeless attempt at fixing it, let's do it the same way + // P_XYMovement solves the line skipping: Spawn the Lost Soul near the PE's center and then use multiple + // smaller steps to get it to its intended position. This will also result in proper clipping, but + // it will avoid all the problems of the Boom method, which checked too many lines and despite some + // adjustments never worked with portals. + + if (other != nullptr) { - // Check whether the Lost Soul is being fired through a 1-sided // phares - // wall or an impassible line, or a "monsters can't cross" line.// | - // If it is, then we don't allow the spawn. // V + double maxmove = other->radius - 1; - FBoundingBox box(MIN(src.X, pos.X), MIN(src.Y, pos.Y), MAX(src.X, pos.X), MAX(src.Y, pos.Y)); - FBlockLinesIterator it(box); - line_t *ld; - bool inportal = false; + if (maxmove <= 0) maxmove = MAXMOVE; - while ((ld = it.Next())) + const double xspeed = fabs(move.X); + const double yspeed = fabs(move.Y); + + int steps = 1; + + if (xspeed > yspeed) { - if (ld->isLinePortal() && i == 0) + if (xspeed > maxmove) { - if (P_PointOnLineSidePrecise(src, ld) == 0 && - P_PointOnLineSidePrecise(pos, ld) == 1) - { - // crossed a portal line from front to back, we need to repeat the check on the other side as well. - inportal = true; - } - } - else if (!(ld->flags & ML_TWOSIDED) || - (ld->flags & (ML_BLOCKING | ML_BLOCKMONSTERS | ML_BLOCKEVERYTHING))) - { - if (box.inRange(ld)) - { - if (P_PointOnLineSidePrecise(src, ld) != P_PointOnLineSidePrecise(pos, ld)) - return; // line blocks trajectory // ^ - } + steps = int(1 + xspeed / maxmove); + } + } + else + { + if (yspeed > maxmove) + { + steps = int(1 + yspeed / maxmove); } } - if (!inportal) break; - // recalculate position and redo the check on the other side of the portal - pos = self->Vec3Offset(dist.X, dist.Y, 8.); - src.X = pos.X - dist.X; - src.Y = pos.Y - dist.Y; + DVector2 stepmove = move / steps; + self->flags &= ~MF_SOLID; // make it solid again + other->flags2 |= MF2_NOTELEPORT; // we do not want the LS to teleport + for (int i = 0; i < steps; i++) + { + DVector2 ptry = other->Pos().XY() + stepmove; + DAngle oldangle = other->Angles.Yaw; + if (!P_TryMove(other, ptry, 0, nullptr)) + { + // kill it immediately + other->ClearCounters(); + P_DamageMobj(other, self, self, TELEFRAG_DAMAGE, NAME_None); + return; + } - } + if (other->Pos().XY() != ptry) + { + // If the new position does not match the desired position, the player + // must have gone through a portal. + // For that we need to adjust the movement vector for the following steps. + DAngle anglediff = deltaangle(oldangle, other->Angles.Yaw); - other = Spawn (spawntype, pos, ALLOW_REPLACE); + if (anglediff != 0) + { + stepmove = stepmove.Rotated(anglediff); + } + } - // Check to see if the new Lost Soul's z value is above the - // ceiling of its new sector, or below the floor. If so, kill it. + } + self->flags |= MF_SOLID; // don't let the LS be stuck in the PE while checking the move - if (other->Top() > other->Sector->HighestCeilingAt(other) || - other->Z() < other->Sector->LowestFloorAt(other)) - { - // kill it immediately - P_DamageMobj (other, self, self, TELEFRAG_DAMAGE, NAME_None);// ^ - return; // | - } // phares + // [RH] Lost souls hate the same things as their pain elementals + other->CopyFriendliness (self, !(flags & PAF_NOTARGET)); - // Check for movements. - - if (!P_CheckPosition (other, other->Pos())) - { - // kill it immediately - P_DamageMobj (other, self, self, TELEFRAG_DAMAGE, NAME_None); - return; - } - - // [RH] Lost souls hate the same things as their pain elementals - other->CopyFriendliness (self, !(flags & PAF_NOTARGET)); - - if (!(flags & PAF_NOSKULLATTACK)) - { - DECLARE_VMFUNC(AActor, A_SkullAttack); - CallAction(stack, A_SkullAttack, other); + if (!(flags & PAF_NOSKULLATTACK)) + { + DECLARE_VMFUNC(AActor, A_SkullAttack); + CallAction(stack, A_SkullAttack, other); + } } } From 1a20a5b9999db0e3e09407624b3713a0ef57f574 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 23 Nov 2016 19:47:09 +0100 Subject: [PATCH 089/185] - scriptified A_PainShootSkull which was the last remaining bit in g_doom, so this directory is gone now. --- src/CMakeLists.txt | 5 - src/g_doom/a_doomglobal.h | 28 ---- src/g_doom/a_doommisc.cpp | 22 --- src/g_doom/a_painelemental.cpp | 160 ------------------- src/p_mobj.cpp | 17 ++ src/scripting/vm/vm.h | 1 + wadsrc/static/zscript/actor.txt | 11 +- wadsrc/static/zscript/doom/painelemental.txt | 134 +++++++++++++++- 8 files changed, 160 insertions(+), 218 deletions(-) delete mode 100644 src/g_doom/a_doomglobal.h delete mode 100644 src/g_doom/a_doommisc.cpp delete mode 100644 src/g_doom/a_painelemental.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 77e756b38..9499cb64f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -824,7 +824,6 @@ endif() file( GLOB HEADER_FILES ${EXTRA_HEADER_DIRS} fragglescript/*.h - g_doom/*.h g_heretic/*.h g_hexen/*.h g_raven/*.h @@ -858,7 +857,6 @@ set( NOT_COMPILED_SOURCE_FILES ${OTHER_SYSTEM_SOURCES} sc_man_scanner.h sc_man_scanner.re - g_doom/a_painelemental.cpp g_heretic/a_dsparil.cpp g_heretic/a_hereticartifacts.cpp g_heretic/a_hereticweaps.cpp @@ -1153,7 +1151,6 @@ set (PCH_SOURCES w_wad.cpp wi_stuff.cpp zstrformat.cpp - g_doom/a_doommisc.cpp g_heretic/a_hereticmisc.cpp g_hexen/a_hexenmisc.cpp g_raven/a_artitele.cpp @@ -1309,7 +1306,6 @@ endif() target_link_libraries( zdoom ${ZDOOM_LIBS} gdtoa dumb lzma ) include_directories( . - g_doom g_heretic g_hexen g_raven @@ -1443,7 +1439,6 @@ source_group("External\\Math" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/m source_group("External\\RapidJSON" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rapidjson/.+") source_group("Externak\\SFMT" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sfmt/.+") source_group("FraggleScript" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/fragglescript/.+") -source_group("Games\\Doom Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_doom/.+") source_group("Games\\Heretic Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_heretic/.+") source_group("Games\\Hexen Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_hexen/.+") source_group("Games\\Raven Shared" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_raven/.+") diff --git a/src/g_doom/a_doomglobal.h b/src/g_doom/a_doomglobal.h deleted file mode 100644 index 73e3d3239..000000000 --- a/src/g_doom/a_doomglobal.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef __A_DOOMGLOBAL_H__ -#define __A_DOOMGLOBAL_H__ - -#include "info.h" - -class AScriptedMarine : public AActor -{ - DECLARE_CLASS (AScriptedMarine, AActor) -public: - - void Activate (AActor *activator); - void Deactivate (AActor *activator); - void BeginPlay (); - void Tick (); - void SetWeapon (EMarineWeapon); - void SetSprite (PClassActor *source); - - void Serialize(FSerializer &arc); - - int CurrentWeapon; - -protected: - bool GetWeaponStates(int weap, FState *&melee, FState *&missile); - - int SpriteOverride; -}; - -#endif //__A_DOOMGLOBAL_H__ diff --git a/src/g_doom/a_doommisc.cpp b/src/g_doom/a_doommisc.cpp deleted file mode 100644 index 40c8e2f8d..000000000 --- a/src/g_doom/a_doommisc.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "actor.h" -#include "info.h" -#include "p_local.h" -#include "p_spec.h" -#include "a_sharedglobal.h" -#include "m_random.h" -#include "gi.h" -#include "doomstat.h" -#include "gstrings.h" -#include "g_level.h" -#include "p_enemy.h" -#include "a_specialspot.h" -#include "templates.h" -#include "m_bbox.h" -#include "portal.h" -#include "d_player.h" -#include "p_maputl.h" -#include "serializer.h" -#include "g_shared/a_pickups.h" - -// Include all the other Doom stuff here to reduce compile time -#include "a_painelemental.cpp" diff --git a/src/g_doom/a_painelemental.cpp b/src/g_doom/a_painelemental.cpp deleted file mode 100644 index 3fca0896c..000000000 --- a/src/g_doom/a_painelemental.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/* -#include "actor.h" -#include "info.h" -#include "p_enemy.h" -#include "p_local.h" -#include "a_action.h" -#include "templates.h" -#include "m_bbox.h" -#include "vm.h" -#include "doomstat.h" -*/ - -enum PA_Flags -{ - PAF_NOSKULLATTACK = 1, - PAF_AIMFACING = 2, - PAF_NOTARGET = 4, -}; - -// -// A_PainShootSkull -// Spawn a lost soul and launch it at the target -// -void A_PainShootSkull (VMFrameStack *stack, AActor *self, DAngle Angle, PClassActor *spawntype, int flags = 0, int limit = -1) -{ - AActor *other; - double prestep; - - if (spawntype == NULL) spawntype = PClass::FindActor("LostSoul"); - assert(spawntype != NULL); - if (self->DamageType == NAME_Massacre) return; - - // [RH] check to make sure it's not too close to the ceiling - if (self->Top() + 8 > self->ceilingz) - { - if (self->flags & MF_FLOAT) - { - self->Vel.Z -= 2; - self->flags |= MF_INFLOAT; - self->flags4 |= MF4_VFRICTION; - } - return; - } - - // [RH] make this optional - if (limit == -1 && (i_compatflags & COMPATF_LIMITPAIN)) - limit = 21; - - if (limit) - { - // count total number of skulls currently on the level - // if there are already 21 skulls on the level, don't spit another one - int count = limit; - FThinkerIterator iterator (spawntype); - DThinker *othink; - - while ( (othink = iterator.Next ()) ) - { - if (--count == 0) - return; - } - } - - // okay, there's room for another one - double otherradius = GetDefaultByType(spawntype)->radius; - prestep = 4 + (self->radius + otherradius) * 1.5; - - DVector2 move = Angle.ToVector(prestep); - DVector3 spawnpos = self->PosPlusZ(8.0); - DVector3 destpos = spawnpos + move; - - other = Spawn(spawntype, spawnpos, ALLOW_REPLACE); - - // Now check if the spawn is legal. Unlike Boom's hopeless attempt at fixing it, let's do it the same way - // P_XYMovement solves the line skipping: Spawn the Lost Soul near the PE's center and then use multiple - // smaller steps to get it to its intended position. This will also result in proper clipping, but - // it will avoid all the problems of the Boom method, which checked too many lines and despite some - // adjustments never worked with portals. - - if (other != nullptr) - { - double maxmove = other->radius - 1; - - if (maxmove <= 0) maxmove = MAXMOVE; - - const double xspeed = fabs(move.X); - const double yspeed = fabs(move.Y); - - int steps = 1; - - if (xspeed > yspeed) - { - if (xspeed > maxmove) - { - steps = int(1 + xspeed / maxmove); - } - } - else - { - if (yspeed > maxmove) - { - steps = int(1 + yspeed / maxmove); - } - } - - DVector2 stepmove = move / steps; - self->flags &= ~MF_SOLID; // make it solid again - other->flags2 |= MF2_NOTELEPORT; // we do not want the LS to teleport - for (int i = 0; i < steps; i++) - { - DVector2 ptry = other->Pos().XY() + stepmove; - DAngle oldangle = other->Angles.Yaw; - if (!P_TryMove(other, ptry, 0, nullptr)) - { - // kill it immediately - other->ClearCounters(); - P_DamageMobj(other, self, self, TELEFRAG_DAMAGE, NAME_None); - return; - } - - if (other->Pos().XY() != ptry) - { - // If the new position does not match the desired position, the player - // must have gone through a portal. - // For that we need to adjust the movement vector for the following steps. - DAngle anglediff = deltaangle(oldangle, other->Angles.Yaw); - - if (anglediff != 0) - { - stepmove = stepmove.Rotated(anglediff); - } - } - - } - self->flags |= MF_SOLID; // don't let the LS be stuck in the PE while checking the move - - // [RH] Lost souls hate the same things as their pain elementals - other->CopyFriendliness (self, !(flags & PAF_NOTARGET)); - - if (!(flags & PAF_NOSKULLATTACK)) - { - DECLARE_VMFUNC(AActor, A_SkullAttack); - CallAction(stack, A_SkullAttack, other); - } - } -} - - -DEFINE_ACTION_FUNCTION(AActor, A_PainShootSkull) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_CLASS(spawntype, AActor); - PARAM_FLOAT(angle); - PARAM_INT_DEF(flags); - PARAM_INT_DEF(limit); - A_PainShootSkull(stack, self, angle, spawntype, flags, limit); - - return 0; -} - diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index a4dc45df2..075d34c4e 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -7115,6 +7115,23 @@ DEFINE_ACTION_FUNCTION(AActor, AngleTo) ACTION_RETURN_FLOAT(self->AngleTo(targ, absolute).Degrees); } +DEFINE_ACTION_FUNCTION(AActor, AngleToVector) +{ + PARAM_PROLOGUE; + PARAM_ANGLE(angle); + PARAM_FLOAT_DEF(length); + ACTION_RETURN_VEC2(angle.ToVector(length)); +} + +DEFINE_ACTION_FUNCTION(AActor, RotateVector) +{ + PARAM_PROLOGUE; + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_ANGLE(angle); + ACTION_RETURN_VEC2(DVector2(x, y).Rotated(angle)); +} + DEFINE_ACTION_FUNCTION(AActor, DistanceBySpeed) { PARAM_SELF_PROLOGUE(AActor); diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 7b05fae36..05c43aa1f 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -1097,6 +1097,7 @@ void CallAction(VMFrameStack *stack, VMFunction *vmfunc, AActor *self); #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_VEC2(v) do { DVector2 u = v; if (numret > 0) { assert(ret != nullptr); ret[0].SetVector2(u); return 1; } return 0; } while(0) #define ACTION_RETURN_VEC3(v) do { DVector3 u = v; if (numret > 0) { assert(ret != nullptr); ret[0].SetVector(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/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index da9db687c..1aa02e5af 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -4,6 +4,8 @@ class Actor : Thinker native const ONFLOORZ = -2147483648.0; const ONCEILINGZ = 2147483647.0; const FLOATRANDZ = ONCEILINGZ-1; + const TELEFRAG_DAMAGE = 1000000; + // flags are not defined here, the native fields for those get synthesized from the internal tables. @@ -215,6 +217,13 @@ class Actor : Thinker native // Functions + // 'parked' global functions. + native static double deltaangle(double ang1, double ang2); + native static double absangle(double ang1, double ang2); + native static Vector2 AngleToVector(double angle, double length = 1); + native static Vector2 RotateVector(Vector2 vec, double angle); + + bool IsPointerEqual(int ptr_select1, int ptr_select2) { return GetPointer(ptr_select1) == GetPointer(ptr_select2); @@ -231,8 +240,6 @@ class Actor : Thinker native native void AdjustPlayerAngle(FTranslatedLineTarget t); native static readonly GetDefaultByType(class cls); - native static double deltaangle(double ang1, double ang2); - native static double absangle(double ang1, double ang2); native static double GetDefaultSpeed(class type); native void RemoveFromHash(); native string GetTag(string defstr = ""); diff --git a/wadsrc/static/zscript/doom/painelemental.txt b/wadsrc/static/zscript/doom/painelemental.txt index 03a4d82c4..fe9e0590a 100644 --- a/wadsrc/static/zscript/doom/painelemental.txt +++ b/wadsrc/static/zscript/doom/painelemental.txt @@ -61,8 +61,139 @@ class PainElemental : Actor extend class Actor { - native void A_PainShootSkull(Class spawntype, double angle, int flags = 0, int limit = -1); + // + // A_PainShootSkull + // Spawn a lost soul and launch it at the target + // + void A_PainShootSkull(Class spawntype, double angle, int flags = 0, int limit = -1) + { + // Don't spawn if we get massacred. + if (DamageType == 'Massacre') return; + if (spawntype == null) spawntype = "LostSoul"; + + // [RH] check to make sure it's not too close to the ceiling + if (pos.z + height + 8 > ceilingz) + { + if (bFloat) + { + Vel.Z -= 2; + bInFloat = true; + bVFriction = true; + } + return; + } + + // [RH] make this optional + if (limit < 0 && compat_limitpain) + limit = 21; + + if (limit > 0) + { + // count total number of skulls currently on the level + // if there are already 21 skulls on the level, don't spit another one + int count = limit; + ThinkerIterator it = ThinkerIterator.Create(spawntype); + Thinker othink; + + while ( (othink = it.Next ()) ) + { + if (--count == 0) + return; + } + } + + // okay, there's room for another one + double otherradius = GetDefaultByType(spawntype).radius; + double prestep = 4 + (radius + otherradius) * 1.5; + + Vector2 move = AngleToVector(angle, prestep); + Vector3 spawnpos = pos + (0,0,8); + Vector3 destpos = spawnpos + move; + + Actor other = Spawn(spawntype, spawnpos, ALLOW_REPLACE); + + // Now check if the spawn is legal. Unlike Boom's hopeless attempt at fixing it, let's do it the same way + // P_XYMovement solves the line skipping: Spawn the Lost Soul near the PE's center and then use multiple + // smaller steps to get it to its intended position. This will also result in proper clipping, but + // it will avoid all the problems of the Boom method, which checked too many lines that weren't even touched + // and despite some adjustments never worked with portals. + + if (other != null) + { + double maxmove = other.radius - 1; + + if (maxmove <= 0) maxmove = 16; + + double xspeed = abs(move.X); + double yspeed = abs(move.Y); + + int steps = 1; + + if (xspeed > yspeed) + { + if (xspeed > maxmove) + { + steps = int(1 + xspeed / maxmove); + } + } + else + { + if (yspeed > maxmove) + { + steps = int(1 + yspeed / maxmove); + } + } + + Vector2 stepmove = move / steps; + bool savedsolid = bSolid; + bool savednoteleport = other.bNoTeleport; + + // make the PE nonsolid for the check and the LS non-teleporting so that P_TryMove doesn't do unwanted things. + bSolid = false; + other.bNoTeleport = true; + for (int i = 0; i < steps; i++) + { + Vector2 ptry = other.pos.xy + stepmove; + double oldangle = other.angle; + if (!other.TryMove(ptry, 0)) + { + // kill it immediately + other.ClearCounters(); + other.DamageMobj(self, self, TELEFRAG_DAMAGE, 'None'); + bSolid = savedsolid; + other.bNoTeleport = savednoteleport; + return; + } + + if (other.pos.xy != ptry) + { + // If the new position does not match the desired position, the player + // must have gone through a portal. + // For that we need to adjust the movement vector for the following steps. + double anglediff = deltaangle(oldangle, other.angle); + + if (anglediff != 0) + { + stepmove = RotateVector(stepmove, anglediff); + } + } + + } + bSolid = savedsolid; + other.bNoTeleport = savednoteleport; + + // [RH] Lost souls hate the same things as their pain elementals + other.CopyFriendliness (self, !(flags & PAF_NOTARGET)); + + if (!(flags & PAF_NOSKULLATTACK)) + { + other.A_SkullAttack(); + } + } + } + + void A_PainAttack(class spawntype = "LostSoul", double addangle = 0, int flags = 0, int limit = -1) { if (target) @@ -71,6 +202,7 @@ extend class Actor A_PainShootSkull(spawntype, angle + addangle, flags, limit); } } + void A_DualPainAttack(class spawntype = "LostSoul") { if (target) From 5e67cf79d34ef753b3f5dc1320ae2e9523794e92 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 23 Nov 2016 21:26:59 +0100 Subject: [PATCH 090/185] - scriptified the Ironlich. --- src/CMakeLists.txt | 1 - src/g_heretic/a_hereticmisc.cpp | 2 - src/g_heretic/a_ironlich.cpp | 213 --------------------- src/p_mobj.cpp | 18 ++ src/scripting/zscript/zcc_compile.cpp | 5 + src/virtual.h | 22 +++ wadsrc/static/zscript/actor.txt | 2 + wadsrc/static/zscript/base.txt | 2 + wadsrc/static/zscript/heretic/ironlich.txt | 173 ++++++++++++++++- 9 files changed, 215 insertions(+), 223 deletions(-) delete mode 100644 src/g_heretic/a_ironlich.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9499cb64f..cd44a6761 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -860,7 +860,6 @@ set( NOT_COMPILED_SOURCE_FILES g_heretic/a_dsparil.cpp g_heretic/a_hereticartifacts.cpp g_heretic/a_hereticweaps.cpp - g_heretic/a_ironlich.cpp g_hexen/a_blastradius.cpp g_hexen/a_boostarmor.cpp g_hexen/a_clericflame.cpp diff --git a/src/g_heretic/a_hereticmisc.cpp b/src/g_heretic/a_hereticmisc.cpp index 5aa048977..18093b752 100644 --- a/src/g_heretic/a_hereticmisc.cpp +++ b/src/g_heretic/a_hereticmisc.cpp @@ -22,5 +22,3 @@ #include "a_dsparil.cpp" #include "a_hereticartifacts.cpp" #include "a_hereticweaps.cpp" -#include "a_ironlich.cpp" - diff --git a/src/g_heretic/a_ironlich.cpp b/src/g_heretic/a_ironlich.cpp deleted file mode 100644 index 8068c251b..000000000 --- a/src/g_heretic/a_ironlich.cpp +++ /dev/null @@ -1,213 +0,0 @@ -/* -#include "actor.h" -#include "info.h" -#include "m_random.h" -#include "s_sound.h" -#include "p_local.h" -#include "p_enemy.h" -#include "a_action.h" -#include "gstrings.h" -#include "vm.h" -#include "g_level.h" -*/ - -static FRandom pr_foo ("WhirlwindDamage"); -static FRandom pr_atk ("LichAttack"); -static FRandom pr_seek ("WhirlwindSeek"); - -class AWhirlwind : public AActor -{ - DECLARE_CLASS (AWhirlwind, AActor) -public: - int DoSpecialDamage (AActor *target, int damage, FName damagetype); -}; - -IMPLEMENT_CLASS(AWhirlwind, false, false, false, false) - -int AWhirlwind::DoSpecialDamage (AActor *target, int damage, FName damagetype) -{ - int randVal; - - if (!(target->flags7 & MF7_DONTTHRUST)) - { - target->Angles.Yaw += pr_foo.Random2() * (360 / 4096.); - target->Vel.X += pr_foo.Random2() / 64.; - target->Vel.Y += pr_foo.Random2() / 64.; - } - - if ((level.time & 16) && !(target->flags2 & MF2_BOSS) && !(target->flags7 & MF7_DONTTHRUST)) - { - randVal = pr_foo(); - if (randVal > 160) - { - randVal = 160; - } - target->Vel.Z += randVal / 32.; - if (target->Vel.Z > 12) - { - target->Vel.Z = 12; - } - } - if (!(level.time & 7)) - { - P_DamageMobj (target, NULL, this->target, 3, NAME_Melee); - } - return -1; -} - -//---------------------------------------------------------------------------- -// -// PROC A_LichAttack -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_LichAttack) -{ - PARAM_SELF_PROLOGUE(AActor); - - int i; - AActor *fire; - AActor *baseFire; - AActor *mo; - AActor *target; - int randAttack; - static const int atkResolve1[] = { 50, 150 }; - static const int atkResolve2[] = { 150, 200 }; - - // Ice ball (close 20% : far 60%) - // Fire column (close 40% : far 20%) - // Whirlwind (close 40% : far 20%) - // Distance threshold = 8 cells - - target = self->target; - if (target == NULL) - { - return 0; - } - A_FaceTarget (self); - if (self->CheckMeleeRange ()) - { - 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 0; - } - int dist = self->Distance2D(target) > 8 * 64; - randAttack = pr_atk (); - if (randAttack < atkResolve1[dist]) - { // Ice ball - 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::FindActor("HeadFX3")); - if (baseFire != NULL) - { - baseFire->SetState (baseFire->FindState("NoGrow")); - for (i = 0; i < 5; i++) - { - fire = Spawn("HeadFX3", baseFire->Pos(), ALLOW_REPLACE); - if (i == 0) - { - S_Sound (self, CHAN_BODY, "ironlich/attack1", 1, ATTN_NORM); - } - fire->target = baseFire->target; - fire->Angles.Yaw = baseFire->Angles.Yaw; - fire->Vel = baseFire->Vel; - fire->SetDamage(0); - fire->health = (i+1) * 2; - P_CheckMissileSpawn (fire, self->radius); - } - } - } - else - { // Whirlwind - mo = P_SpawnMissile (self, target, RUNTIME_CLASS(AWhirlwind)); - if (mo != NULL) - { - mo->AddZ(-32); - mo->tracer = target; - mo->health = 20*TICRATE; // Duration - S_Sound (self, CHAN_BODY, "ironlich/attack3", 1, ATTN_NORM); - } - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_WhirlwindSeek -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_WhirlwindSeek) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->health -= 3; - if (self->health < 0) - { - self->Vel.Zero(); - self->SetState(self->FindState(NAME_Death)); - self->flags &= ~MF_MISSILE; - return 0; - } - if ((self->threshold -= 3) < 0) - { - self->threshold = 58 + (pr_seek() & 31); - S_Sound(self, CHAN_BODY, "ironlich/attack3", 1, ATTN_NORM); - } - if (self->tracer && self->tracer->flags&MF_SHADOW) - { - return 0; - } - P_SeekerMissile(self, 10, 30); - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_LichIceImpact -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_LichIceImpact) -{ - PARAM_SELF_PROLOGUE(AActor); - - unsigned int i; - AActor *shard; - - for (i = 0; i < 8; i++) - { - shard = Spawn("HeadFX2", self->Pos(), ALLOW_REPLACE); - shard->target = self->target; - shard->Angles.Yaw = i*45.; - shard->VelFromAngle(); - shard->Vel.Z = -.6; - P_CheckMissileSpawn (shard, self->radius); - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_LichFireGrow -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_LichFireGrow) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->health--; - self->AddZ(9.); - if (self->health == 0) - { - self->RestoreDamage(); - self->SetState (self->FindState("NoGrow")); - } - return 0; -} - diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 075d34c4e..a79fc0f16 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -6668,6 +6668,17 @@ int AActor::DoSpecialDamage (AActor *target, int damage, FName damagetype) } } +DEFINE_ACTION_FUNCTION(AActor, DoSpecialDamage) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(target, AActor); + PARAM_INT(damage); + PARAM_NAME(damagetype); + self->VMSuperCall(); + ACTION_RETURN_INT(self->DoSpecialDamage(target, damage, damagetype)); +} + + int AActor::TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FName damagetype) { FState *death; @@ -7180,6 +7191,13 @@ DEFINE_ACTION_FUNCTION(AActor, Vec3Offset) ACTION_RETURN_VEC3(self->Vec3Offset(x, y, z, absolute)); } +DEFINE_ACTION_FUNCTION(AActor, RestoreDamage) +{ + PARAM_SELF_PROLOGUE(AActor); + self->RestoreDamage(); + return 0; +} + //---------------------------------------------------------------------------- // // DropItem handling diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index ac9a8825c..3437c848c 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2326,6 +2326,11 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool if (varflags & VARF_Virtual) { + if (sym->Variants[0].Implementation == nullptr) + { + Error(f, "Virtual function %s.%s not present.", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()); + return; + } if (varflags & VARF_Final) { sym->Variants[0].Implementation->Final = true; diff --git a/src/virtual.h b/src/virtual.h index f3167407d..4e0b3f01b 100644 --- a/src/virtual.h +++ b/src/virtual.h @@ -38,6 +38,7 @@ VMEXPORTED_NATIVES_START VMEXPORTED_NATIVES_FUNC(BeginPlay) VMEXPORTED_NATIVES_FUNC(Activate) VMEXPORTED_NATIVES_FUNC(Deactivate) + VMEXPORTED_NATIVES_FUNC(DoSpecialDamage) VMEXPORTED_NATIVES_END @@ -192,6 +193,26 @@ public: stack.Call(VFUNC, params, 2, nullptr, 0, nullptr); } } + int DoSpecialDamage(AActor *target, int damage, FName damagetype) + { + if (this->ObjectFlags & OF_SuperCall) + { + this->ObjectFlags &= ~OF_SuperCall; + return ExportedNatives::Get()->template DoSpecialDamage(this, target, damage, damagetype); + } + else + { + VINDEX(AActor, DoSpecialDamage); + // Without the type cast this picks the 'void *' assignment... + VMValue params[4] = { (DObject*)this, (DObject*)target, damage, damagetype.GetIndex() }; + VMReturn ret; + VMFrameStack stack; + int retval; + ret.IntAt(&retval); + stack.Call(VFUNC, params, 4, &ret, 1, nullptr); + return retval; + } + } }; @@ -223,6 +244,7 @@ VMEXPORT_NATIVES_START(AActor, DThinker) VMEXPORT_NATIVES_FUNC(BeginPlay) VMEXPORT_NATIVES_FUNC(Activate) VMEXPORT_NATIVES_FUNC(Deactivate) + VMEXPORT_NATIVES_FUNC(DoSpecialDamage) VMEXPORT_NATIVES_END(AActor) /* diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 1aa02e5af..e7179bd47 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -237,6 +237,7 @@ class Actor : Thinker native virtual native void BeginPlay(); virtual native void Activate(Actor activator); virtual native void Deactivate(Actor activator); + virtual native int DoSpecialDamage (Actor target, int damage, Name damagetype); native void AdjustPlayerAngle(FTranslatedLineTarget t); native static readonly GetDefaultByType(class cls); @@ -247,6 +248,7 @@ class Actor : Thinker native native void ClearCounters(); native bool GiveBody (int num, int max=0); + native void RestoreDamage(); native void SetDamage(int dmg); native double Distance2D(Actor other); native void SetOrigin(vector3 newpos, bool moving); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 15a8c9a3b..11d565ae9 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -12,6 +12,8 @@ class Object native class Thinker : Object native { + const TICRATE = 35; + virtual native void Tick(); virtual native void PostBeginPlay(); } diff --git a/wadsrc/static/zscript/heretic/ironlich.txt b/wadsrc/static/zscript/heretic/ironlich.txt index e6ba05e05..8a4dd4c05 100644 --- a/wadsrc/static/zscript/heretic/ironlich.txt +++ b/wadsrc/static/zscript/heretic/ironlich.txt @@ -27,7 +27,6 @@ class Ironlich : Actor DropItem "ArtiEgg", 51, 0; } - native void A_LichAttack (); States { @@ -54,6 +53,77 @@ class Ironlich : Actor LICH I -1 A_BossDeath; Stop; } + + //---------------------------------------------------------------------------- + // + // PROC A_LichAttack + // + //---------------------------------------------------------------------------- + + void A_LichAttack () + { + static const int atkResolve1[] = { 50, 150 }; + static const int atkResolve2[] = { 150, 200 }; + + // Ice ball (close 20% : far 60%) + // Fire column (close 40% : far 20%) + // Whirlwind (close 40% : far 20%) + // Distance threshold = 8 cells + + if (target == null) + { + return; + } + A_FaceTarget (); + if (CheckMeleeRange ()) + { + int damage = random[LichAttack](1, 8) * 6; + int newdam = target.DamageMobj (self, self, damage, 'Melee'); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + return; + } + int dist = Distance2D(target) > 8 * 64; + int randAttack = random[LichAttack](); + if (randAttack < atkResolve1[dist]) + { // Ice ball + SpawnMissile (target, "HeadFX1"); + A_PlaySound ("ironlich/attack2", CHAN_BODY); + } + else if (randAttack < atkResolve2[dist]) + { // Fire column + Actor baseFire = SpawnMissile (target, "HeadFX3"); + if (baseFire != null) + { + baseFire.SetStateLabel("NoGrow"); + for (int i = 0; i < 5; i++) + { + Actor fire = Spawn("HeadFX3", baseFire.Pos, ALLOW_REPLACE); + if (i == 0) + { + A_PlaySound ("ironlich/attack1", CHAN_BODY); + } + fire.target = baseFire.target; + fire.angle = baseFire.angle; + fire.Vel = baseFire.Vel; + fire.SetDamage(0); + fire.health = (i+1) * 2; + fire.CheckMissileSpawn (radius); + } + } + } + else + { // Whirlwind + Actor mo = SpawnMissile (target, "Whirlwind"); + if (mo != null) + { + mo.AddZ(-32); + mo.tracer = target; + mo.health = 20*TICRATE; // Duration + A_PlaySound ("ironlich/attack3", CHAN_BODY); + } + } + } + } // Head FX 1 ---------------------------------------------------------------- @@ -74,7 +144,6 @@ class HeadFX1 : Actor RenderStyle "Add"; } - native void A_LichIceImpact(); States { @@ -86,6 +155,25 @@ class HeadFX1 : Actor FX05 EFG 5 BRIGHT; Stop; } + + //---------------------------------------------------------------------------- + // + // PROC A_LichIceImpact + // + //---------------------------------------------------------------------------- + + void A_LichIceImpact() + { + for (int i = 0; i < 8; i++) + { + Actor shard = Spawn("HeadFX2", Pos, ALLOW_REPLACE); + shard.target = target; + shard.angle = i*45.; + shard.VelFromAngle(); + shard.Vel.Z = -.6; + shard.CheckMissileSpawn (radius); + } + } } // Head FX 2 ---------------------------------------------------------------- @@ -135,8 +223,6 @@ class HeadFX3 : Actor RenderStyle "Add"; } - native void A_LichFireGrow (); - States { Spawn: @@ -149,12 +235,29 @@ class HeadFX3 : Actor FX06 DEFG 5 BRIGHT; Stop; } + + //---------------------------------------------------------------------------- + // + // PROC A_LichFireGrow + // + //---------------------------------------------------------------------------- + + void A_LichFireGrow () + { + health--; + AddZ(9.); + if (health == 0) + { + RestoreDamage(); + SetStateLabel("NoGrow"); + } + } } // Whirlwind ---------------------------------------------------------------- -class Whirlwind : Actor native +class Whirlwind : Actor { Default { @@ -174,8 +277,6 @@ class Whirlwind : Actor native Alpha 0.4; } - native void A_WhirlwindSeek(); - States { Spawn: @@ -186,6 +287,64 @@ class Whirlwind : Actor native FX07 GFED 4; Stop; } + + override int DoSpecialDamage (Actor target, int damage, Name damagetype) + { + int randVal; + + if (!target.bDontThrust) + { + target.angle += Random2[WhirlwindDamage]() * (360 / 4096.); + target.Vel.X += Random2[WhirlwindDamage]() / 64.; + target.Vel.Y += Random2[WhirlwindDamage]() / 64.; + } + + if ((level.time & 16) && !target.bBoss && !target.bDontThrust) + { + randVal = min(160, random[WhirlwindSeek]()); + target.Vel.Z += randVal / 32.; + if (target.Vel.Z > 12) + { + target.Vel.Z = 12; + } + } + if (!(level.time & 7)) + { + target.DamageMobj (null, target, 3, 'Melee'); + } + return -1; + } + + //---------------------------------------------------------------------------- + // + // PROC A_WhirlwindSeek + // + //---------------------------------------------------------------------------- + + void A_WhirlwindSeek() + { + + health -= 3; + if (health < 0) + { + Vel = (0,0,0); + SetStateLabel("Death"); + bMissile = false; + return; + } + if ((threshold -= 3) < 0) + { + threshold = 58 + (random[WhirlwindSeek]() & 31); + A_PlaySound("ironlich/attack3", CHAN_BODY); + } + if (tracer && tracer.bShadow) + { + return; + } + A_SeekerMissile(10, 30); + } + } + From 7527141ad4aab0edc87cd41a970b01971e8fc5b5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 23 Nov 2016 22:34:17 +0100 Subject: [PATCH 091/185] - fixed: The morph actors stored their required classes as names, not as class pointers. This prevented any kind of error check on them. Unfortunately, due to backwards compatibility needs, on DECORATE the missing class may not be fatal so a workaround had to be added to clear those bogus pointers later if they are discovered to be broken. For ZScript, though, this will result in a compile error, which was the intention behind this change. --- src/dobjtype.cpp | 1 + src/g_shared/a_artifacts.cpp | 9 ++--- src/g_shared/a_artifacts.h | 7 ++-- src/g_shared/a_morph.cpp | 8 +--- src/g_shared/a_sharedglobal.h | 3 +- src/scripting/thingdef.cpp | 20 +++++++++- src/scripting/thingdef_properties.cpp | 56 ++++++++++++++++----------- 7 files changed, 64 insertions(+), 40 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 11640ec94..52a269873 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -3298,6 +3298,7 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) // see if we can reuse the existing class. This is only possible if the inheritance is identical. Otherwise it needs to be replaced. if (this == existclass->ParentClass) { + existclass->ObjectFlags &= OF_Transient; return existclass; } } diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index 66832c21c..5b03d4a60 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -1910,13 +1910,10 @@ void APowerMorph::InitEffect( ) { Super::InitEffect(); - if (Owner != NULL && Owner->player != NULL && PlayerClass != NAME_None) + if (Owner != nullptr && Owner->player != nullptr && PlayerClass != nullptr) { player_t *realplayer = Owner->player; // Remember the identity of the player - 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)) + if (P_MorphPlayer(realplayer, realplayer, PlayerClass, -1/*INDEFINITELY*/, MorphStyle, MorphFlash, UnMorphFlash)) { Owner = realplayer->mo; // Replace the new owner in our owner; safe because we are not attached to anything yet ItemFlags |= IF_CREATECOPYMOVED; // Let the caller know the "real" owner has changed (to the morphed actor) @@ -1960,7 +1957,7 @@ void APowerMorph::EndEffect( ) } // Unmorph if possible - if (!bNoCallUndoMorph) + if (!bInUndoMorph) { int savedMorphTics = Player->morphTics; P_UndoPlayerMorph (Player, Player, 0, !!(Player->MorphStyle & MORPH_UNDOALWAYS)); diff --git a/src/g_shared/a_artifacts.h b/src/g_shared/a_artifacts.h index 163094d32..bd7e86323 100644 --- a/src/g_shared/a_artifacts.h +++ b/src/g_shared/a_artifacts.h @@ -280,13 +280,14 @@ class APowerMorph : public APowerup public: virtual void Serialize(FSerializer &arc); - void SetNoCallUndoMorph() { bNoCallUndoMorph = true; } + void SetNoCallUndoMorph() { bInUndoMorph = true; } // Variables - FNameNoInit PlayerClass, MorphFlash, UnMorphFlash; + PClassPlayerPawn *PlayerClass; + PClassActor *MorphFlash, *UnMorphFlash; int MorphStyle; player_t *Player; - bool bNoCallUndoMorph; // Because P_UndoPlayerMorph() can call EndEffect recursively + bool bInUndoMorph; // Because P_UndoPlayerMorph() can call EndEffect recursively protected: void InitEffect (); diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 506f18b2f..49ea525bb 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -620,17 +620,13 @@ IMPLEMENT_CLASS(AMorphProjectile, false, false, false, false) int AMorphProjectile::DoSpecialDamage (AActor *target, int damage, FName damagetype) { - PClassActor *morph_flash = PClass::FindActor(MorphFlash); - PClassActor *unmorph_flash = PClass::FindActor(UnMorphFlash); if (target->player) { - PClassPlayerPawn *player_class = dyn_cast(PClass::FindClass(PlayerClass)); - P_MorphPlayer (NULL, target->player, player_class, Duration, MorphStyle, morph_flash, unmorph_flash); + P_MorphPlayer (NULL, target->player, PlayerClass, Duration, MorphStyle, MorphFlash, UnMorphFlash); } else { - PClassActor *monster_class = PClass::FindActor(MonsterClass); - P_MorphMonster (target, monster_class, Duration, MorphStyle, morph_flash, unmorph_flash); + P_MorphMonster (target, MonsterClass, Duration, MorphStyle, MorphFlash, UnMorphFlash); } return -1; } diff --git a/src/g_shared/a_sharedglobal.h b/src/g_shared/a_sharedglobal.h index 65f9d90b6..6911c6688 100644 --- a/src/g_shared/a_sharedglobal.h +++ b/src/g_shared/a_sharedglobal.h @@ -192,7 +192,8 @@ public: void Serialize(FSerializer &arc); - FNameNoInit PlayerClass, MonsterClass, MorphFlash, UnMorphFlash; + PClassPlayerPawn *PlayerClass; + PClassActor *MonsterClass, *MorphFlash, *UnMorphFlash; int Duration, MorphStyle; }; diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index 9dcf3a16f..d6c53dd8d 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -68,6 +68,7 @@ // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- void InitThingdef(); +TArray OptionalClassPtrs; // STATIC FUNCTION PROTOTYPES -------------------------------------------- PClassActor *QuestItemClasses[31]; @@ -390,8 +391,21 @@ void LoadActors () { if (ti->Size == TentativeClass) { - Printf(TEXTCOLOR_RED "Class %s referenced but not defined\n", ti->TypeName.GetChars()); - FScriptPosition::ErrorCounter++; + if (ti->ObjectFlags & OF_Transient) + { + Printf(TEXTCOLOR_ORANGE "Class %s referenced but not defined\n", ti->TypeName.GetChars()); + FScriptPosition::WarnCounter++; + DObject::StaticPointerSubstitution(ti, nullptr); + for (auto op : OptionalClassPtrs) + { + if (*op == ti) *op = nullptr; + } + } + else + { + Printf(TEXTCOLOR_RED "Class %s referenced but not defined\n", ti->TypeName.GetChars()); + FScriptPosition::ErrorCounter++; + } continue; } @@ -431,4 +445,6 @@ void LoadActors () QuestItemClasses[i] = PClass::FindActor(fmt); } StateSourceLines.Clear(); + OptionalClassPtrs.Clear(); + OptionalClassPtrs.ShrinkToFit(); } diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 7faab937b..8968dc1d6 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -71,13 +71,14 @@ #include "r_data/colormaps.h" #include "vmbuilder.h" +extern TArray OptionalClassPtrs; //========================================================================== // // Gets a class pointer and performs an error check for correct type // //========================================================================== -static PClassActor *FindClassTentative(const char *name, PClass *ancestor) +static PClassActor *FindClassTentative(const char *name, PClass *ancestor, bool optional = false) { // "" and "none" mean 'no class' if (name == NULL || *name == 0 || !stricmp(name, "none")) @@ -91,23 +92,27 @@ static PClassActor *FindClassTentative(const char *name, PClass *ancestor) { I_Error("%s does not inherit from %s\n", name, ancestor->TypeName.GetChars()); } + if (cls->Size == TentativeClass && optional) + { + cls->ObjectFlags |= OF_Transient; // since this flag has no meaning in class types, let's use it for marking the type optional. + } return static_cast(cls); } -static AAmmo::MetaClass *FindClassTentativeAmmo(const char *name) +static AAmmo::MetaClass *FindClassTentativeAmmo(const char *name, bool optional = false) { - return static_cast(FindClassTentative(name, RUNTIME_CLASS(AAmmo))); + return static_cast(FindClassTentative(name, RUNTIME_CLASS(AAmmo), optional)); } -static AWeapon::MetaClass *FindClassTentativeWeapon(const char *name) +static AWeapon::MetaClass *FindClassTentativeWeapon(const char *name, bool optional = false) { - return static_cast(FindClassTentative(name, RUNTIME_CLASS(AWeapon))); + return static_cast(FindClassTentative(name, RUNTIME_CLASS(AWeapon), optional)); } -static APowerup::MetaClass *FindClassTentativePowerup(const char *name) +static APowerup::MetaClass *FindClassTentativePowerup(const char *name, bool optional = false) { - return static_cast(FindClassTentative(name, RUNTIME_CLASS(APowerup))); + return static_cast(FindClassTentative(name, RUNTIME_CLASS(APowerup), optional)); } -static APlayerPawn::MetaClass *FindClassTentativePlayerPawn(const char *name) +static APlayerPawn::MetaClass *FindClassTentativePlayerPawn(const char *name, bool optional = false) { - return static_cast(FindClassTentative(name, RUNTIME_CLASS(APlayerPawn))); + return static_cast(FindClassTentative(name, RUNTIME_CLASS(APlayerPawn), optional)); } //========================================================================== @@ -2984,21 +2989,23 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, viewbob, F, PlayerPawn) } //========================================================================== -// +// (non-fatal with non-existent types only in DECORATE) //========================================================================== DEFINE_CLASS_PROPERTY(playerclass, S, MorphProjectile) { PROP_STRING_PARM(str, 0); - defaults->PlayerClass = FName(str); + defaults->PlayerClass = FindClassTentativePlayerPawn(str, bag.fromDecorate); + if (bag.fromDecorate) OptionalClassPtrs.Push((PClassActor**)&defaults->PlayerClass); } //========================================================================== -// +// (non-fatal with non-existent types only in DECORATE) //========================================================================== DEFINE_CLASS_PROPERTY(monsterclass, S, MorphProjectile) { PROP_STRING_PARM(str, 0); - defaults->MonsterClass = FName(str); + defaults->MonsterClass = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate); + if (bag.fromDecorate) OptionalClassPtrs.Push(&defaults->MonsterClass); } //========================================================================== @@ -3020,12 +3027,13 @@ DEFINE_CLASS_PROPERTY(morphstyle, M, MorphProjectile) } //========================================================================== -// +// (non-fatal with non-existent types only in DECORATE) //========================================================================== DEFINE_CLASS_PROPERTY(morphflash, S, MorphProjectile) { PROP_STRING_PARM(str, 0); - defaults->MorphFlash = FName(str); + defaults->MorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate); + if (bag.fromDecorate) OptionalClassPtrs.Push(&defaults->MorphFlash); } //========================================================================== @@ -3034,16 +3042,18 @@ DEFINE_CLASS_PROPERTY(morphflash, S, MorphProjectile) DEFINE_CLASS_PROPERTY(unmorphflash, S, MorphProjectile) { PROP_STRING_PARM(str, 0); - defaults->UnMorphFlash = FName(str); + defaults->UnMorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate); + if (bag.fromDecorate) OptionalClassPtrs.Push(&defaults->UnMorphFlash); } //========================================================================== -// +// (non-fatal with non-existent types only in DECORATE) //========================================================================== DEFINE_CLASS_PROPERTY(playerclass, S, PowerMorph) { PROP_STRING_PARM(str, 0); - defaults->PlayerClass = FName(str); + defaults->PlayerClass = FindClassTentativePlayerPawn(str, bag.fromDecorate); + if (bag.fromDecorate) OptionalClassPtrs.Push((PClassActor**)&defaults->PlayerClass); } //========================================================================== @@ -3056,21 +3066,23 @@ DEFINE_CLASS_PROPERTY(morphstyle, M, PowerMorph) } //========================================================================== -// +// (non-fatal with non-existent types only in DECORATE) //========================================================================== DEFINE_CLASS_PROPERTY(morphflash, S, PowerMorph) { PROP_STRING_PARM(str, 0); - defaults->MorphFlash = FName(str); + defaults->MorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate); + if (bag.fromDecorate) OptionalClassPtrs.Push(&defaults->MorphFlash); } //========================================================================== -// +// (non-fatal with non-existent types only in DECORATE) //========================================================================== DEFINE_CLASS_PROPERTY(unmorphflash, S, PowerMorph) { PROP_STRING_PARM(str, 0); - defaults->UnMorphFlash = FName(str); + defaults->UnMorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate); + if (bag.fromDecorate) OptionalClassPtrs.Push(&defaults->UnMorphFlash); } From 8a7671ad8b0e5cbd5b7fe93d7e4c240c1050bbc1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 23 Nov 2016 23:28:03 +0100 Subject: [PATCH 092/185] - exported all member fields from the morph items. - renamed APowerMorph::Player to avoid accidental confusion with AActor::player, which in scripting is the same due to case insensitvity. - renamed save key for above variable. --- src/g_shared/a_artifacts.cpp | 29 ++++++++++++++-------- src/g_shared/a_artifacts.h | 2 +- src/g_shared/a_morph.cpp | 12 +++++++++ wadsrc/static/zscript/shared/inventory.txt | 6 +++++ wadsrc/static/zscript/shared/morph.txt | 9 +++++++ 5 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index 5b03d4a60..bf24c8eb8 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -1884,6 +1884,13 @@ void APowerDoubleFiringSpeed::EndEffect( ) IMPLEMENT_CLASS(APowerMorph, false, false, false, false) +DEFINE_FIELD(APowerMorph, PlayerClass) +DEFINE_FIELD(APowerMorph, MorphFlash) +DEFINE_FIELD(APowerMorph, UnMorphFlash) +DEFINE_FIELD(APowerMorph, MorphStyle) +DEFINE_FIELD(APowerMorph, MorphedPlayer) +DEFINE_FIELD(APowerMorph, bInUndoMorph) + //=========================================================================== // // APowerMorph :: Serialize @@ -1897,7 +1904,7 @@ void APowerMorph::Serialize(FSerializer &arc) ("morphstyle", MorphStyle) ("morphflash", MorphFlash) ("unmorphflash", UnMorphFlash) - ("player", Player); + ("morphedplayer", MorphedPlayer); } //=========================================================================== @@ -1917,7 +1924,7 @@ void APowerMorph::InitEffect( ) { Owner = realplayer->mo; // Replace the new owner in our owner; safe because we are not attached to anything yet ItemFlags |= IF_CREATECOPYMOVED; // Let the caller know the "real" owner has changed (to the morphed actor) - Player = realplayer; // Store the player identity (morphing clears the unmorphed actor's "player" field) + MorphedPlayer = realplayer; // Store the player identity (morphing clears the unmorphed actor's "player" field) } else // morph failed - give the caller an opportunity to fail the pickup completely { @@ -1939,19 +1946,19 @@ void APowerMorph::EndEffect( ) // Abort if owner already destroyed if (Owner == NULL) { - assert(Player == NULL); + assert(MorphedPlayer == NULL); return; } // Abort if owner already unmorphed - if (Player == NULL) + if (MorphedPlayer == NULL) { return; } // Abort if owner is dead; their Die() method will // take care of any required unmorphing on death. - if (Player->health <= 0) + if (MorphedPlayer->health <= 0) { return; } @@ -1959,26 +1966,26 @@ void APowerMorph::EndEffect( ) // Unmorph if possible if (!bInUndoMorph) { - int savedMorphTics = Player->morphTics; - P_UndoPlayerMorph (Player, Player, 0, !!(Player->MorphStyle & MORPH_UNDOALWAYS)); + int savedMorphTics = MorphedPlayer->morphTics; + P_UndoPlayerMorph (MorphedPlayer, MorphedPlayer, 0, !!(MorphedPlayer->MorphStyle & MORPH_UNDOALWAYS)); // Abort if unmorph failed; in that case, // set the usual retry timer and return. - if (Player != NULL && Player->morphTics) + if (MorphedPlayer != NULL && MorphedPlayer->morphTics) { // Transfer retry timeout // to the powerup's timer. - EffectTics = Player->morphTics; + EffectTics = MorphedPlayer->morphTics; // Reload negative morph tics; // use actual value; it may // be in use for animation. - Player->morphTics = savedMorphTics; + MorphedPlayer->morphTics = savedMorphTics; // Try again some time later return; } } // Unmorph suceeded - Player = NULL; + MorphedPlayer = NULL; } // Infinite Ammo Powerup ----------------------------------------------------- diff --git a/src/g_shared/a_artifacts.h b/src/g_shared/a_artifacts.h index bd7e86323..d9629c165 100644 --- a/src/g_shared/a_artifacts.h +++ b/src/g_shared/a_artifacts.h @@ -286,7 +286,7 @@ public: PClassPlayerPawn *PlayerClass; PClassActor *MorphFlash, *UnMorphFlash; int MorphStyle; - player_t *Player; + player_t *MorphedPlayer; bool bInUndoMorph; // Because P_UndoPlayerMorph() can call EndEffect recursively protected: diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 49ea525bb..84de5a0d6 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -618,6 +618,13 @@ void InitAllPowerupEffects(AInventory *item) IMPLEMENT_CLASS(AMorphProjectile, false, false, false, false) +DEFINE_FIELD(AMorphProjectile, PlayerClass) +DEFINE_FIELD(AMorphProjectile, MonsterClass) +DEFINE_FIELD(AMorphProjectile, MorphFlash) +DEFINE_FIELD(AMorphProjectile, UnMorphFlash) +DEFINE_FIELD(AMorphProjectile, Duration) +DEFINE_FIELD(AMorphProjectile, MorphStyle) + int AMorphProjectile::DoSpecialDamage (AActor *target, int damage, FName damagetype) { if (target->player) @@ -652,6 +659,11 @@ IMPLEMENT_POINTERS_START(AMorphedMonster) IMPLEMENT_POINTER(UnmorphedMe) IMPLEMENT_POINTERS_END +DEFINE_FIELD(AMorphedMonster, UnmorphedMe) +DEFINE_FIELD(AMorphedMonster, UnmorphTime) +DEFINE_FIELD(AMorphedMonster, MorphStyle) +DEFINE_FIELD(AMorphedMonster, MorphExitFlash) + void AMorphedMonster::Serialize(FSerializer &arc) { Super::Serialize (arc); diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index 048590b39..12e521d53 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -487,6 +487,12 @@ class PowerDoubleFiringSpeed : Powerup native {} class PowerMorph : Powerup native { + native Class PlayerClass; + native Class MorphFlash, UnMorphFlash; + native int MorphStyle; + native PlayerInfo MorphedPlayer; + native bool bInUndoMorph; + Default { Powerup.Duration -40; diff --git a/wadsrc/static/zscript/shared/morph.txt b/wadsrc/static/zscript/shared/morph.txt index ff58d897b..c5c2cbe0a 100644 --- a/wadsrc/static/zscript/shared/morph.txt +++ b/wadsrc/static/zscript/shared/morph.txt @@ -1,5 +1,10 @@ class MorphProjectile : Actor native { + + native Class PlayerClass; + native Class MonsterClass, MorphFlash, UnMorphFlash; + native int Duration, MorphStyle; + Default { Damage 1; @@ -11,6 +16,10 @@ class MorphProjectile : Actor native class MorphedMonster : Actor native { + native Actor UnmorphedMe; + native int UnmorphTime, MorphStyle; + native Class MorphExitFlash; + Default { Monster; From cd919e72e16012dcbb35b1dd1decf50cc670d53e Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Wed, 23 Nov 2016 21:50:21 +0100 Subject: [PATCH 093/185] - Don't null-check the ZCC_TreeNode 'this' pointer. Compilers are allowed to simplify the 'this == nullptr' code block because it makes no sense in 'well-defined C++ code'. --- src/scripting/zscript/zcc-parse.lemon | 38 +++++++++++++-------------- src/scripting/zscript/zcc_parser.cpp | 31 ++++++++++++++++++++++ src/scripting/zscript/zcc_parser.h | 30 ++------------------- 3 files changed, 52 insertions(+), 47 deletions(-) diff --git a/src/scripting/zscript/zcc-parse.lemon b/src/scripting/zscript/zcc-parse.lemon index fc1803f1d..379d1516e 100644 --- a/src/scripting/zscript/zcc-parse.lemon +++ b/src/scripting/zscript/zcc-parse.lemon @@ -22,7 +22,7 @@ static void SetNodeLine(ZCC_TreeNode *name, int 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); + if (a == NULL) a = b; else AppendTreeNodeSibling(a, 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 @@ -221,14 +221,14 @@ dottable_id(X) ::= dottable_id(A) DOT IDENTIFIER(B). { NEW_AST_NODE(Identifier,id2,A); id2->Id = B.Name(); - A->AppendSibling(id2); + AppendTreeNodeSibling(A, id2); X = A; /*X-overwrites-A*/ } dottable_id(X) ::= dottable_id(A) DOT DEFAULT. { NEW_AST_NODE(Identifier,id2,A); id2->Id = NAME_Default; - A->AppendSibling(id2); + AppendTreeNodeSibling(A, id2); X = A; /*X-overwrites-A*/ } @@ -239,7 +239,7 @@ dottable_id(X) ::= dottable_id(A) DOT COLOR. { NEW_AST_NODE(Identifier,id2,A); id2->Id = NAME_Color; - A->AppendSibling(id2); + AppendTreeNodeSibling(A, id2); X = A; /*X-overwrites-A*/ } @@ -299,7 +299,7 @@ opt_struct_body(X) ::= error. { X = NULL; } struct_body(X) ::= struct_member(X). -struct_body(X) ::= struct_member(A) struct_body(B). { X = A; /*X-overwrites-A*/ X->AppendSibling(B); } +struct_body(X) ::= struct_member(A) struct_body(B). { X = A; /*X-overwrites-A*/ AppendTreeNodeSibling(X, B); } struct_member(X) ::= declarator(A). { X = A; /*X-overwrites-A*/ } struct_member(X) ::= enum_def(A). { X = A; /*X-overwrites-A*/ } @@ -375,11 +375,11 @@ enum_def(X) ::= ENUM(T) IDENTIFIER(A) enum_type(B) LBRACE opt_enum_list(C) RBRAC } // Add a new terminating node, to indicate that the ConstantDefs for this enum are done. NEW_AST_NODE(EnumTerminator,term,U); - C->AppendSibling(term); + AppendTreeNodeSibling(C, term); } if (C != NULL) { - def->AppendSibling(C); + AppendTreeNodeSibling(def, C); } X = def; } @@ -389,7 +389,7 @@ enum_type(X) ::= COLON int_type(A). { X = A; /*X-overwrites-A*/ } enum_list(X) ::= error. { X = NULL; } enum_list(X) ::= enumerator(X). -enum_list(X) ::= enum_list(A) COMMA enumerator(B). { X = A; /*X-overwrites-A*/ X->AppendSibling(B); } +enum_list(X) ::= enum_list(A) COMMA enumerator(B). { X = A; /*X-overwrites-A*/ AppendTreeNodeSibling(X, B); } opt_enum_list(X) ::= . { X = NULL; } opt_enum_list(X) ::= enum_list(X) opt_comma. @@ -450,7 +450,7 @@ states_opt(X) ::= states_opt(A) COMMA IDENTIFIER(B). NEW_AST_NODE(Identifier,id,B); id->Id = B.Name(); X = A; /*X-overwrites-A*/ - X->AppendSibling(id); + AppendTreeNodeSibling(X, id); } @@ -545,7 +545,7 @@ state_opts(X) ::= state_opts(A) FAST. { A.Fast = true; X = A; /*X-overwri state_opts(X) ::= state_opts(A) SLOW. { A.Slow = true; X = A; /*X-overwrites-A*/ } state_opts(X) ::= state_opts(A) NODELAY. { A.NoDelay = true; X = A; /*X-overwrites-A*/ } state_opts(X) ::= state_opts(A) CANRAISE. { A.CanRaise = true; X = A; /*X-overwrites-A*/ } -state_opts(X) ::= state_opts(A) OFFSET LPAREN expr(B) COMMA expr(C) RPAREN. { A.Offset = B; B->AppendSibling(C); X = A; /*X-overwrites-A*/ } +state_opts(X) ::= state_opts(A) OFFSET LPAREN expr(B) COMMA expr(C) RPAREN. { A.Offset = B; AppendTreeNodeSibling(B, C); X = A; /*X-overwrites-A*/ } state_opts(X) ::= state_opts(A) LIGHT LPAREN light_list(B) RPAREN. { X = A; /*X-overwrites-A*/ X.Lights = B; } %type light_list {ZCC_ExprConstant *} @@ -565,7 +565,7 @@ light_list(X) ::= light_list(A) COMMA STRCONST(B). strconst->Operation = PEX_ConstValue; strconst->Type = TypeString; strconst->StringVal = B.String; - A->AppendSibling(strconst); + AppendTreeNodeSibling(A, strconst); X = A; /*X-overwrites-A*/ } @@ -783,7 +783,7 @@ type_or_array(X) ::= type(X). type_or_array(X) ::= type(A) array_size(B). { X = A; /*X-overwrites-A*/ X->ArraySize = B; } type_list(X) ::= type_or_array(X). /* A comma-separated list of types */ -type_list(X) ::= type_list(A) COMMA type_or_array(B). { X = A; /*X-overwrites-A*/ X->AppendSibling(B); } +type_list(X) ::= type_list(A) COMMA type_or_array(B). { X = A; /*X-overwrites-A*/ AppendTreeNodeSibling(X, B); } type_list_or_void(X) ::= VOID. { X = NULL; } type_list_or_void(X) ::= type_list(X). @@ -805,7 +805,7 @@ array_size_expr(X) ::= LBRACKET(L) opt_expr(A) RBRACKET. array_size(X) ::= array_size_expr(X). array_size(X) ::= array_size(A) array_size_expr(B). { - A->AppendSibling(B); + AppendTreeNodeSibling(A, B); X = A; /*X-overwrites-A*/ } @@ -911,7 +911,7 @@ variable_name(X) ::= IDENTIFIER(A) array_size(B). variable_list(X) ::= variable_name(X). variable_list(X) ::= variable_list(A) COMMA variable_name(B). { - A->AppendSibling(B); + AppendTreeNodeSibling(A, B); X = A; /*X-overwrites-A*/ } @@ -984,11 +984,11 @@ func_params(X) ::= func_param_list(A) COMMA ELLIPSIS. parm->Flags = 0; parm->Default = nullptr; X = A; /*X-overwrites-A*/ - X->AppendSibling(parm); + AppendTreeNodeSibling(X, parm); } func_param_list(X) ::= func_param(X). -func_param_list(X) ::= func_param_list(A) COMMA func_param(B). { X = A; /*X-overwrites-A*/ X->AppendSibling(B); } +func_param_list(X) ::= func_param_list(A) COMMA func_param(B). { X = A; /*X-overwrites-A*/ AppendTreeNodeSibling(X, B); } func_param(X) ::= func_param_flags(A) type(B) IDENTIFIER(C). { @@ -1422,7 +1422,7 @@ expr_list(X) ::= expr(X). expr_list(X) ::= expr_list(A) COMMA expr(B). { X = A; /*X-overwrites-A*/ - X->AppendSibling(B); + AppendTreeNodeSibling(X, B); } /*----- Function argument lists -----*/ @@ -1453,7 +1453,7 @@ func_expr_list(X) ::= func_expr_list(A) COMMA(T) func_expr_item(B). B = nil_b; } X = A; /*X-overwrites-A*/ - X->AppendSibling(B); + AppendTreeNodeSibling(X, B); } func_expr_item(X) ::= . @@ -1877,6 +1877,6 @@ var_init(X) ::= IDENTIFIER EQ LBRACE error RBRACE. variable_list_with_init(X) ::= var_init(X). variable_list_with_init(X) ::= variable_list_with_init(A) COMMA var_init(B). { - A->AppendSibling(B); + AppendTreeNodeSibling(A, B); X = A; /*X-overwrites-A*/ } diff --git a/src/scripting/zscript/zcc_parser.cpp b/src/scripting/zscript/zcc_parser.cpp index 37fd8ff0c..401a15c25 100644 --- a/src/scripting/zscript/zcc_parser.cpp +++ b/src/scripting/zscript/zcc_parser.cpp @@ -466,3 +466,34 @@ ZCC_TreeNode *ZCCParseState::InitNode(size_t size, EZCCTreeNodeType type) node->SourceLump = sc->LumpNum; return node; } + +// Appends a sibling to this node's sibling list. +void AppendTreeNodeSibling(ZCC_TreeNode *thisnode, ZCC_TreeNode *sibling) +{ + if (thisnode == nullptr) + { + // Some bad syntax can actually get here, so better abort so that the user can see the error which caused this. + I_FatalError("Internal script compiler error. Execution aborted."); + } + if (sibling == nullptr) + { + return; + } + + ZCC_TreeNode *&SiblingPrev = thisnode->SiblingPrev; + ZCC_TreeNode *&SiblingNext = thisnode->SiblingNext; + + // Check integrity of our sibling list. + assert(SiblingPrev->SiblingNext == thisnode); + assert(SiblingNext->SiblingPrev == thisnode); + + // 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 = thisnode; +} diff --git a/src/scripting/zscript/zcc_parser.h b/src/scripting/zscript/zcc_parser.h index a2fc3fb56..7a763b2c1 100644 --- a/src/scripting/zscript/zcc_parser.h +++ b/src/scripting/zscript/zcc_parser.h @@ -161,34 +161,6 @@ struct ZCC_TreeNode // one of the structures below. EZCCTreeNodeType NodeType; - // Appends a sibling to this node's sibling list. - void AppendSibling(ZCC_TreeNode *sibling) - { - if (this == nullptr) - { - // Some bad syntax can actually get here, so better abort so that the user can see the error which caused this. - I_FatalError("Internal script compiler error. Execution aborted."); - } - 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; - } - operator FScriptPosition() { return FScriptPosition(*SourceName, SourceLoc); @@ -196,6 +168,8 @@ struct ZCC_TreeNode }; +void AppendTreeNodeSibling(ZCC_TreeNode *thisnode, ZCC_TreeNode *sibling); + struct ZCC_Identifier : ZCC_TreeNode { ENamedName Id; From 3e890d182b62a8ad42f83e745c58276312ad6a16 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 24 Nov 2016 01:23:35 +0100 Subject: [PATCH 094/185] - scriptified D'Sparil. - added retrieval of defaults from an actor pointer. --- src/CMakeLists.txt | 1 - src/g_heretic/a_dsparil.cpp | 327 ------------------ src/g_heretic/a_hereticmisc.cpp | 1 - src/g_heretic/a_hereticweaps.cpp | 45 +-- src/g_shared/a_specialspot.cpp | 12 + src/p_map.cpp | 5 + src/p_mobj.cpp | 6 + src/p_pspr.cpp | 13 - src/p_teleport.cpp | 12 + src/scripting/codegeneration/codegen.cpp | 16 + wadsrc/static/zscript/actor.txt | 13 +- wadsrc/static/zscript/base.txt | 2 + wadsrc/static/zscript/heretic/dsparil.txt | 272 ++++++++++++++- .../static/zscript/heretic/hereticweaps.txt | 30 +- 14 files changed, 349 insertions(+), 406 deletions(-) delete mode 100644 src/g_heretic/a_dsparil.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cd44a6761..d4edae81e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -857,7 +857,6 @@ set( NOT_COMPILED_SOURCE_FILES ${OTHER_SYSTEM_SOURCES} sc_man_scanner.h sc_man_scanner.re - g_heretic/a_dsparil.cpp g_heretic/a_hereticartifacts.cpp g_heretic/a_hereticweaps.cpp g_hexen/a_blastradius.cpp diff --git a/src/g_heretic/a_dsparil.cpp b/src/g_heretic/a_dsparil.cpp deleted file mode 100644 index 5ab4067d3..000000000 --- a/src/g_heretic/a_dsparil.cpp +++ /dev/null @@ -1,327 +0,0 @@ -/* -#include "actor.h" -#include "info.h" -#include "p_local.h" -#include "p_enemy.h" -#include "a_action.h" -#include "s_sound.h" -#include "m_random.h" -#include "a_sharedglobal.h" -#include "gstrings.h" -#include "a_specialspot.h" -#include "vm.h" -#include "g_level.h" -*/ - -static FRandom pr_s2fx1 ("S2FX1"); -static FRandom pr_scrc1atk ("Srcr1Attack"); -static FRandom pr_dst ("D'SparilTele"); -static FRandom pr_s2d ("Srcr2Decide"); -static FRandom pr_s2a ("Srcr2Attack"); -static FRandom pr_bluespark ("BlueSpark"); - -//---------------------------------------------------------------------------- -// -// PROC A_Sor1Pain -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_Sor1Pain) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->special1 = 20; // Number of steps to walk fast - CALL_ACTION(A_Pain, self); - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_Sor1Chase -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_Sor1Chase) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (self->special1) - { - self->special1--; - self->tics -= 3; - } - A_Chase(stack, self); - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_Srcr1Attack -// -// Sorcerer demon attack. -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_Srcr1Attack) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo; - DAngle angle; - - if (!self->target) - { - return 0; - } - S_Sound (self, CHAN_BODY, self->AttackSound, 1, ATTN_NORM); - if (self->CheckMeleeRange ()) - { - 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 0; - } - - PClassActor *fx = PClass::FindActor("SorcererFX1"); - if (self->health > (self->SpawnHealth()/3)*2) - { // Spit one fireball - P_SpawnMissileZ (self, self->Z() + 48, self->target, fx ); - } - else - { // Spit three fireballs - mo = P_SpawnMissileZ (self, self->Z() + 48, self->target, fx); - if (mo != NULL) - { - angle = mo->Angles.Yaw; - P_SpawnMissileAngleZ(self, self->Z() + 48, fx, angle - 3, mo->Vel.Z); - P_SpawnMissileAngleZ(self, self->Z() + 48, fx, angle + 3, mo->Vel.Z); - } - if (self->health < self->SpawnHealth()/3) - { // Maybe attack again - if (self->special1) - { // Just attacked, so don't attack again - self->special1 = 0; - } - else - { // Set state to attack again - self->special1 = 1; - self->SetState (self->FindState("Missile2")); - } - } - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_SorcererRise -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_SorcererRise) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo; - - self->flags &= ~MF_SOLID; - mo = Spawn("Sorcerer2", self->Pos(), ALLOW_REPLACE); - mo->Translation = self->Translation; - mo->SetState (mo->FindState("Rise")); - mo->Angles.Yaw = self->Angles.Yaw; - mo->CopyFriendliness (self, true); - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC P_DSparilTeleport -// -//---------------------------------------------------------------------------- - -void P_DSparilTeleport (AActor *actor) -{ - DVector3 prev; - AActor *mo; - AActor *spot; - - DSpotState *state = DSpotState::GetSpotState(); - if (state == NULL) return; - - spot = state->GetSpotWithMinMaxDistance(PClass::FindActor("BossSpot"), actor->X(), actor->Y(), 128, 0); - if (spot == NULL) return; - - prev = actor->Pos(); - if (P_TeleportMove (actor, spot->Pos(), false)) - { - mo = Spawn("Sorcerer2Telefade", prev, ALLOW_REPLACE); - if (mo) mo->Translation = actor->Translation; - S_Sound (mo, CHAN_BODY, "misc/teleport", 1, ATTN_NORM); - actor->SetState (actor->FindState("Teleport")); - S_Sound (actor, CHAN_BODY, "misc/teleport", 1, ATTN_NORM); - actor->SetZ(actor->floorz); - actor->Angles.Yaw = spot->Angles.Yaw; - actor->Vel.Zero(); - } -} - -//---------------------------------------------------------------------------- -// -// PROC A_Srcr2Decide -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_Srcr2Decide) -{ - PARAM_SELF_PROLOGUE(AActor); - - static const int chance[] = - { - 192, 120, 120, 120, 64, 64, 32, 16, 0 - }; - - unsigned int chanceindex = self->health / ((self->SpawnHealth()/8 == 0) ? 1 : self->SpawnHealth()/8); - if (chanceindex >= countof(chance)) - { - chanceindex = countof(chance) - 1; - } - - if (pr_s2d() < chance[chanceindex]) - { - P_DSparilTeleport (self); - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_Srcr2Attack -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_Srcr2Attack) -{ - PARAM_SELF_PROLOGUE(AActor); - - int chance; - - if (!self->target) - { - return 0; - } - S_Sound (self, CHAN_BODY, self->AttackSound, 1, ATTN_NONE); - if (self->CheckMeleeRange()) - { - 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 0; - } - chance = self->health < self->SpawnHealth()/2 ? 96 : 48; - if (pr_s2a() < chance) - { // Wizard spawners - - PClassActor *fx = PClass::FindActor("Sorcerer2FX2"); - if (fx) - { - P_SpawnMissileAngle(self, fx, self->Angles.Yaw - 45, 0.5); - P_SpawnMissileAngle(self, fx, self->Angles.Yaw + 45, 0.5); - } - } - else - { // Blue bolt - P_SpawnMissile (self, self->target, PClass::FindActor("Sorcerer2FX1")); - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_BlueSpark -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_BlueSpark) -{ - PARAM_SELF_PROLOGUE(AActor); - - int i; - AActor *mo; - - for (i = 0; i < 2; i++) - { - mo = Spawn("Sorcerer2FXSpark", self->Pos(), ALLOW_REPLACE); - mo->Vel.X = pr_bluespark.Random2() / 128.; - mo->Vel.Y = pr_bluespark.Random2() / 128.; - mo->Vel.Z = 1. + pr_bluespark() / 256.; - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_GenWizard -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_GenWizard) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo; - - mo = Spawn("Wizard", self->Pos(), ALLOW_REPLACE); - if (mo != NULL) - { - mo->AddZ(-mo->GetDefault()->Height / 2, false); - if (!P_TestMobjLocation (mo)) - { // Didn't fit - mo->ClearCounters(); - mo->Destroy (); - } - else - { // [RH] Make the new wizards inherit D'Sparil's target - mo->CopyFriendliness (self->target, true); - - self->Vel.Zero(); - self->SetState (self->FindState(NAME_Death)); - self->flags &= ~MF_MISSILE; - mo->master = self->target; - P_SpawnTeleportFog(self, self->Pos(), false, true); - } - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_Sor2DthInit -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_Sor2DthInit) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->special1 = 7; // Animation loop counter - P_Massacre (); // Kill monsters early - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_Sor2DthLoop -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_Sor2DthLoop) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (--self->special1) - { // Need to loop - self->SetState (self->FindState("DeathLoop")); - } - return 0; -} - diff --git a/src/g_heretic/a_hereticmisc.cpp b/src/g_heretic/a_hereticmisc.cpp index 18093b752..5929c1d86 100644 --- a/src/g_heretic/a_hereticmisc.cpp +++ b/src/g_heretic/a_hereticmisc.cpp @@ -19,6 +19,5 @@ #include "serializer.h" // Include all the other Heretic stuff here to reduce compile time -#include "a_dsparil.cpp" #include "a_hereticartifacts.cpp" #include "a_hereticweaps.cpp" diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp index 4d3a0b0e8..dc34fd206 100644 --- a/src/g_heretic/a_hereticweaps.cpp +++ b/src/g_heretic/a_hereticweaps.cpp @@ -27,7 +27,6 @@ static FRandom pr_bfx1 ("BlasterFX1"); static FRandom pr_ripd ("RipperD"); static FRandom pr_fb1 ("FireBlasterPL1"); static FRandom pr_bfx1t ("BlasterFX1Tick"); -static FRandom pr_hrfx2 ("HornRodFX2"); static FRandom pr_rp ("RainPillar"); static FRandom pr_fsr1 ("FireSkullRodPL1"); static FRandom pr_storm ("SkullRodStorm"); @@ -819,27 +818,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnRippers) // --- Skull rod ------------------------------------------------------------ -// Horn Rod FX 2 ------------------------------------------------------------ - -class AHornRodFX2 : public AActor -{ - DECLARE_CLASS (AHornRodFX2, AActor) -public: - int DoSpecialDamage (AActor *target, int damage, FName damagetype); -}; - -IMPLEMENT_CLASS(AHornRodFX2, false, false, false, false) - -int AHornRodFX2::DoSpecialDamage (AActor *target, int damage, FName damagetype) -{ - if (target->IsKindOf (PClass::FindClass("Sorcerer2")) && pr_hrfx2() < 96) - { // D'Sparil teleports away - P_DSparilTeleport (target); - return -1; - } - return damage; -} - // Rain pillar 1 ------------------------------------------------------------ class ARainPillar : public AActor @@ -940,7 +918,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSkullRodPL2) if (!weapon->DepleteAmmo (weapon->bAltFire)) return 0; } - P_SpawnPlayerMissile (self, 0,0,0, RUNTIME_CLASS(AHornRodFX2), self->Angles.Yaw, &t, &MissileActor); + P_SpawnPlayerMissile (self, 0,0,0, PClass::FindActor("HornRodFX2"), self->Angles.Yaw, &t, &MissileActor); // Use MissileActor instead of the return value from // P_SpawnPlayerMissile because we need to give info to the mobj // even if it exploded immediately. @@ -1170,25 +1148,6 @@ void APhoenixRodPowered::EndPowerup () P_SetPsprite(Owner->player, PSP_WEAPON, SisterWeapon->GetReadyState()); } -class APhoenixFX1 : public AActor -{ - DECLARE_CLASS (APhoenixFX1, AActor) -public: - int DoSpecialDamage (AActor *target, int damage, FName damagetype); -}; - -IMPLEMENT_CLASS(APhoenixFX1, false, false, false, false) - -int APhoenixFX1::DoSpecialDamage (AActor *target, int damage, FName damagetype) -{ - if (target->IsKindOf (PClass::FindClass("Sorcerer2")) && pr_hrfx2() < 96) - { // D'Sparil teleports away - P_DSparilTeleport (target); - return -1; - } - return damage; -} - // Phoenix FX 2 ------------------------------------------------------------- class APhoenixFX2 : public AActor @@ -1232,7 +1191,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePhoenixPL1) if (!weapon->DepleteAmmo (weapon->bAltFire)) return 0; } - P_SpawnPlayerMissile (self, RUNTIME_CLASS(APhoenixFX1)); + P_SpawnPlayerMissile (self, PClass::FindActor("PhoenixFX1")); self->Thrust(self->Angles.Yaw + 180, 4); return 0; } diff --git a/src/g_shared/a_specialspot.cpp b/src/g_shared/a_specialspot.cpp index e96f5a903..935333a5c 100644 --- a/src/g_shared/a_specialspot.cpp +++ b/src/g_shared/a_specialspot.cpp @@ -344,6 +344,18 @@ ASpecialSpot *DSpotState::GetSpotWithMinMaxDistance(PClassActor *type, double x, return NULL; } +DEFINE_ACTION_FUNCTION(DSpotState, GetSpotWithMinMaxDistance) +{ + PARAM_SELF_PROLOGUE(DSpotState); + PARAM_CLASS(type, AActor); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(mindist); + PARAM_FLOAT(maxdist); + ACTION_RETURN_OBJECT(self->GetSpotWithMinMaxDistance(type, x, y, mindist, maxdist)); +} + + //---------------------------------------------------------------------------- // // diff --git a/src/p_map.cpp b/src/p_map.cpp index db0a129c6..af5ab100a 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -1777,6 +1777,11 @@ bool P_TestMobjLocation(AActor *mobj) return false; } +DEFINE_ACTION_FUNCTION(AActor, TestMobjLocation) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_BOOL(P_TestMobjLocation(self)); +} //============================================================================= // diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index a79fc0f16..8784dc075 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -6781,6 +6781,12 @@ int AActor::SpawnHealth() const } } +DEFINE_ACTION_FUNCTION(AActor, SpawnHealth) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_INT(self->SpawnHealth()); +} + FState *AActor::GetRaiseState() { if (!(flags & MF_CORPSE)) diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 0e39e259e..ca305d677 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -1449,19 +1449,6 @@ DEFINE_ACTION_FUNCTION(AActor, AimTarget) ACTION_RETURN_OBJECT(P_AimTarget(self)); } - -DEFINE_ACTION_FUNCTION(AActor, A_Light) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_INT(light); - - if (self->player != NULL) - { - self->player->extralight = clamp(light, -20, 20); - } - return 0; -} - //------------------------------------------------------------------------ // // PROC P_SetupPsprites diff --git a/src/p_teleport.cpp b/src/p_teleport.cpp index 01595ff65..80bfd4f7f 100644 --- a/src/p_teleport.cpp +++ b/src/p_teleport.cpp @@ -96,6 +96,18 @@ void P_SpawnTeleportFog(AActor *mobj, const DVector3 &pos, bool beforeTele, bool mo->target = mobj; } +DEFINE_ACTION_FUNCTION(AActor, SpawnTeleportFog) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + PARAM_BOOL(before); + PARAM_BOOL(settarget); + P_SpawnTeleportFog(self, DVector3(x, y, z), before, settarget); + return 0; +} + // // TELEPORTATION // diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 1cc16214c..ba4eab9e3 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -5593,6 +5593,22 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PStruct *classct PSymbol *sym; PSymbolTable *symtbl; bool isclass = objtype->IsKindOf(RUNTIME_CLASS(PClass)); + + if (Identifier == NAME_Default) + { + if (!objtype->IsKindOf(RUNTIME_CLASS(PClassActor))) + { + ScriptPosition.Message(MSG_ERROR, "'Default' requires an actor type."); + delete this; + return nullptr; + } + + FxExpression * x = new FxClassDefaults(object, ScriptPosition); + object = nullptr; + delete this; + return x->Resolve(ctx); + } + if ((sym = objtype->Symbols.FindSymbolInTable(Identifier, symtbl)) != nullptr) { if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index e7179bd47..f4489f575 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -249,6 +249,7 @@ class Actor : Thinker native native bool GiveBody (int num, int max=0); native void RestoreDamage(); + native int SpawnHealth(); native void SetDamage(int dmg); native double Distance2D(Actor other); native void SetOrigin(vector3 newpos, bool moving); @@ -259,17 +260,19 @@ class Actor : Thinker native native Actor AimTarget(); native bool CheckMissileSpawn(double maxdist); native bool CheckPosition(Vector2 pos, bool actorsonly = false); + native bool TestMobjLocation(); native static Actor Spawn(class type, vector3 pos = (0,0,0), int replace = NO_REPLACE); native Actor SpawnMissile(Actor dest, class type, Actor owner = null); native Actor SpawnMissileZ (double z, Actor dest, class type); native Actor SpawnMissileAngleZSpeed (double z, class type, double angle, double vz, double speed, Actor owner = null, bool checkspawn = true); native Actor, Actor SpawnPlayerMissile(class type, double angle = 0, double x = 0, double y = 0, double z = 0, out FTranslatedLineTarget pLineTarget = null, bool nofreeaim = false, bool noautoaim = false, int aimflags = 0); + native void SpawnTeleportFog(Vector3 pos, bool beforeTele, bool setTarget); - native void A_Light(int extralight); - void A_Light0() { A_Light(0); } - void A_Light1() { A_Light(1); } - void A_Light2() { A_Light(2); } - void A_LightInverse() { A_Light(0x80000000); } + void A_Light(int extralight) { if (player) player.extralight = clamp(extralight, -20, 20); } + void A_Light0() { if (player) player.extralight = 0; } + void A_Light1() { if (player) player.extralight = 1; } + void A_Light2() { if (player) player.extralight = 2; } + void A_LightInverse() { if (player) player.extralight = 0x80000000; } native Actor OldSpawnMissile(Actor dest, class type, Actor owner = null); native Actor SpawnPuff(class pufftype, vector3 pos, double hitdir, double particledir, int updown, int flags = 0, Actor vict = null); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 11d565ae9..a63020bbf 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -49,6 +49,8 @@ class SpotState : Object native { native static SpotState GetSpotState(); native SpecialSpot GetNextInList(class type, int skipcounter); + native SpecialSpot GetSpotWithMinMaxDistance(Class type, double x, double y, double mindist, double maxdist); + } struct LevelLocals native diff --git a/wadsrc/static/zscript/heretic/dsparil.txt b/wadsrc/static/zscript/heretic/dsparil.txt index 8cd60c8bb..e2cfca558 100644 --- a/wadsrc/static/zscript/heretic/dsparil.txt +++ b/wadsrc/static/zscript/heretic/dsparil.txt @@ -38,10 +38,6 @@ class Sorcerer1 : Actor HitObituary "$OB_DSPARIL1HIT"; } - native void A_Sor1Pain (); - native void A_Sor1Chase (); - native void A_Srcr1Attack (); - native void A_SorcererRise (); States { @@ -79,6 +75,104 @@ class Sorcerer1 : Actor SRCR L 12; SRCR P -1 A_SorcererRise; } + + + //---------------------------------------------------------------------------- + // + // PROC A_Sor1Pain + // + //---------------------------------------------------------------------------- + + void A_Sor1Pain () + { + special1 = 20; // Number of steps to walk fast + A_Pain(); + } + + //---------------------------------------------------------------------------- + // + // PROC A_Sor1Chase + // + //---------------------------------------------------------------------------- + + void A_Sor1Chase () + { + if (special1) + { + special1--; + tics -= 3; + } + A_Chase(); + } + + //---------------------------------------------------------------------------- + // + // PROC A_Srcr1Attack + // + // Sorcerer demon attack. + // + //---------------------------------------------------------------------------- + + void A_Srcr1Attack () + { + if (!target) + { + return; + } + A_PlaySound (AttackSound, CHAN_BODY); + if (CheckMeleeRange ()) + { + int damage = random[Srcr1Attack](1,8) * 8; + int newdam = target.DamageMobj (self, self, damage, 'Melee'); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + return; + } + + if (health > (SpawnHealth()/3)*2) + { // Spit one fireball + SpawnMissileZ (pos.z + 48, target, "SorcererFX1"); + } + else + { // Spit three fireballs + Actor mo = SpawnMissileZ (pos.z + 48, target, "SorcererFX1"); + if (mo != null) + { + double ang = mo.angle; + SpawnMissileAngleZ(pos.z + 48, "SorcererFX1", ang - 3, mo.Vel.Z); + SpawnMissileAngleZ(pos.z + 48, "SorcererFX1", ang + 3, mo.Vel.Z); + } + if (health < SpawnHealth()/3) + { // Maybe attack again + if (special1) + { // Just attacked, so don't attack again + special1 = 0; + } + else + { // Set state to attack again + special1 = 1; + SetStateLabel("Missile2"); + } + } + } + } + + //---------------------------------------------------------------------------- + // + // PROC A_SorcererRise + // + //---------------------------------------------------------------------------- + + void A_SorcererRise () + { + bSolid = false; + Actor mo = Spawn("Sorcerer2", Pos, ALLOW_REPLACE); + mo.Translation = Translation; + mo.SetStateLabel("Rise"); + mo.angle = angle; + mo.CopyFriendliness (self, true); + } + + } @@ -142,10 +236,6 @@ class Sorcerer2 : Actor HitObituary "$OB_DSPARIL2HIT"; } - native void A_Srcr2Decide (); - native void A_Srcr2Attack (); - native void A_Sor2DthInit (); - native void A_Sor2DthLoop (); States { @@ -189,6 +279,118 @@ class Sorcerer2 : Actor SDTH O -1 A_BossDeath; Stop; } + + //---------------------------------------------------------------------------- + // + // PROC P_DSparilTeleport + // + //---------------------------------------------------------------------------- + + void DSparilTeleport () + { + SpotState state = SpotState.GetSpotState(); + if (state == null) return; + + Actor spot = state.GetSpotWithMinMaxDistance("BossSpot", pos.x, pos.y, 128, 0); + if (spot == null) return; + + Vector3 prev = Pos; + if (TeleportMove (spot.Pos, false)) + { + Actor mo = Spawn("Sorcerer2Telefade", prev, ALLOW_REPLACE); + if (mo) + { + mo.Translation = Translation; + mo.A_PlaySound("misc/teleport", CHAN_BODY); + } + SetStateLabel ("Teleport"); + A_PlaySound ("misc/teleport", CHAN_BODY); + SetZ(floorz); + angle = spot.angle; + vel = (0,0,0); + } + } + + //---------------------------------------------------------------------------- + // + // PROC A_Srcr2Decide + // + //---------------------------------------------------------------------------- + + void A_Srcr2Decide () + { + static const int chance[] = + { + 192, 120, 120, 120, 64, 64, 32, 16, 0 + }; + + int health8 = max(1, SpawnHealth() / 8); + int chanceindex = min(8, health / health8); + + if (random[Srcr2Decide]() < chance[chanceindex]) + { + DSparilTeleport (); + } + } + + //---------------------------------------------------------------------------- + // + // PROC A_Srcr2Attack + // + //---------------------------------------------------------------------------- + + void A_Srcr2Attack () + { + if (!target) + { + return; + } + A_PlaySound (AttackSound, CHAN_BODY); + if (CheckMeleeRange()) + { + int damage = random[Srcr2Atk](1, 8) * 20; + int newdam = target.DamageMobj (self, self, damage, 'Melee'); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + return; + } + int chance = health < SpawnHealth()/2 ? 96 : 48; + if (random[Srcr2Atk]() < chance) + { // Wizard spawners + + SpawnMissileAngle("Sorcerer2FX2", Angle - 45, 0.5); + SpawnMissileAngle("Sorcerer2FX2", Angle + 45, 0.5); + } + else + { // Blue bolt + SpawnMissile (target, "Sorcerer2FX1"); + } + } + + //---------------------------------------------------------------------------- + // + // PROC A_Sor2DthInit + // + //---------------------------------------------------------------------------- + + void A_Sor2DthInit () + { + special1 = 7; // Animation loop counter + Thing_Destroy(0); // Kill monsters early + } + + //---------------------------------------------------------------------------- + // + // PROC A_Sor2DthLoop + // + //---------------------------------------------------------------------------- + + void A_Sor2DthLoop () + { + if (--special1) + { // Need to loop + SetStateLabel("DeathLoop"); + } + } } @@ -210,8 +412,6 @@ class Sorcerer2FX1 : Actor RenderStyle "Add"; } - native void A_BlueSpark (); - States { Spawn: @@ -222,6 +422,23 @@ class Sorcerer2FX1 : Actor FX16 HIJKL 5 BRIGHT; Stop; } + + //---------------------------------------------------------------------------- + // + // PROC A_BlueSpark + // + //---------------------------------------------------------------------------- + + void A_BlueSpark () + { + for (int i = 0; i < 2; i++) + { + Actor mo = Spawn("Sorcerer2FXSpark", pos, ALLOW_REPLACE); + mo.Vel.X = Random2[BlueSpark]() / 128.; + mo.Vel.Y = Random2[BlueSpark]() / 128.; + mo.Vel.Z = 1. + Random[BlueSpark]() / 256.; + } + } } // Sorcerer 2 FX Spark ------------------------------------------------------ @@ -244,7 +461,7 @@ class Sorcerer2FXSpark : Actor Spawn: FX16 DEF 12 BRIGHT; Stop; - } + } } // Sorcerer 2 FX 2 ---------------------------------------------------------- @@ -263,8 +480,6 @@ class Sorcerer2FX2 : Actor RenderStyle "Add"; } - native void A_GenWizard (); - States { Spawn: @@ -277,7 +492,38 @@ class Sorcerer2FX2 : Actor Stop; } + +//---------------------------------------------------------------------------- +// +// PROC A_GenWizard +// +//---------------------------------------------------------------------------- + + void A_GenWizard () + { + Actor mo = Spawn("Wizard", pos, ALLOW_REPLACE); + if (mo != null) + { + mo.AddZ(-mo.Default.Height / 2, false); + if (!mo.TestMobjLocation ()) + { // Didn't fit + mo.ClearCounters(); + mo.Destroy (); + } + else + { // [RH] Make the new wizards inherit D'Sparil's target + mo.CopyFriendliness (self.target, true); + + Vel = (0,0,0); + SetStateLabel('Death'); + bMissile = false; + mo.master = target; + SpawnTeleportFog(pos, false, true); + } + } + } } + // Sorcerer 2 Telefade ------------------------------------------------------ class Sorcerer2Telefade : Actor diff --git a/wadsrc/static/zscript/heretic/hereticweaps.txt b/wadsrc/static/zscript/heretic/hereticweaps.txt index 4c254500b..e309ba095 100644 --- a/wadsrc/static/zscript/heretic/hereticweaps.txt +++ b/wadsrc/static/zscript/heretic/hereticweaps.txt @@ -1037,7 +1037,7 @@ class HornRodFX1 : Actor // Horn Rod FX 2 ------------------------------------------------------------ -class HornRodFX2 : Actor native +class HornRodFX2 : Actor { Default { @@ -1059,7 +1059,7 @@ class HornRodFX2 : Actor native States { - Spawn: + Spawn: FX00 C 3 BRIGHT; FX00 D 3 BRIGHT A_SeekerMissile(10, 30); FX00 E 3 BRIGHT; @@ -1074,6 +1074,18 @@ class HornRodFX2 : Actor native FX00 G 1 A_SkullRodStorm; Wait; } + + override int DoSpecialDamage (Actor target, int damage, Name damagetype) + { + Sorcerer2 s2 = Sorcerer2(target); + if (s2 != null && random[HornRodFX2]() < 96) + { // D'Sparil teleports away + s2.DSparilTeleport (); + return -1; + } + return damage; + } + } // Rain pillar 1 ------------------------------------------------------------ @@ -1195,7 +1207,7 @@ class PhoenixRodPowered : PhoenixRod native // Phoenix FX 1 ------------------------------------------------------------- -class PhoenixFX1 : Actor native +class PhoenixFX1 : Actor { Default { @@ -1225,6 +1237,18 @@ class PhoenixFX1 : Actor native FX08 DEFGH 4 BRIGHT; Stop; } + + override int DoSpecialDamage (Actor target, int damage, Name damagetype) + { + Sorcerer2 s2 = Sorcerer2(target); + if (s2 != null && random[HornRodFX2]() < 96) + { // D'Sparil teleports away + s2.DSparilTeleport (); + return -1; + } + return damage; + } + } // Phoenix puff ------------------------------------------------------------- From dc11b6315709fb9bdf124a05e2a90be261c9c9d9 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Thu, 24 Nov 2016 00:47:53 -0500 Subject: [PATCH 095/185] - Fixed building with vanilla MinGW, at least with whatever modified header files that my system has from my last experimentation. --- src/CMakeLists.txt | 8 ++++++-- src/win32/i_specialpaths.cpp | 9 +++++++++ src/win32/i_system.cpp | 4 ++-- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7d532ca9c..a2bde0de5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -178,8 +178,12 @@ if( WIN32 ) comdlg32 ws2_32 setupapi - oleaut32 - DelayImp ) + oleaut32 ) + + if( NOT ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) + set( ZDOOM_LIBS ${ZDOOM_LIBS} DelayImp ) + endif() + if( DX_dxguid_LIBRARY ) list( APPEND ZDOOM_LIBS "${DX_dxguid_LIBRARY}" ) endif() diff --git a/src/win32/i_specialpaths.cpp b/src/win32/i_specialpaths.cpp index 745c12f12..cddeacde6 100644 --- a/src/win32/i_specialpaths.cpp +++ b/src/win32/i_specialpaths.cpp @@ -46,6 +46,15 @@ #include "optwin32.h" +// Vanilla MinGW does not have folder ids +#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) +static const GUID FOLDERID_LocalAppData = { 0xf1b32785, 0x6fba, 0x4fcf, 0x9d, 0x55, 0x7b, 0x8e, 0x7f, 0x15, 0x70, 0x91 }; +static const GUID FOLDERID_RoamingAppData = { 0x3eb685db, 0x65f9, 0x4cf6, 0xa0, 0x3a, 0xe3, 0xef, 0x65, 0x72, 0x9f, 0x3d }; +static const GUID FOLDERID_SavedGames = { 0x4c5c32ff, 0xbb9d, 0x43b0, 0xb5, 0xb4, 0x2d, 0x72, 0xe5, 0x4e, 0xaa, 0xa4 }; +static const GUID FOLDERID_Documents = { 0xfdd39ad0, 0x238f, 0x46af, 0xad, 0xb4, 0x6c, 0x85, 0x48, 0x03, 0x69, 0xc7 }; +static const GUID FOLDERID_Pictures = { 0x33e28130, 0x4e1e, 0x4676, 0x83, 0x5a, 0x98, 0x39, 0x5c, 0x3b, 0xc3, 0xbb }; +#endif + //=========================================================================== // // IsProgramDirectoryWritable diff --git a/src/win32/i_system.cpp b/src/win32/i_system.cpp index d55d1e093..29ea3c4b7 100644 --- a/src/win32/i_system.cpp +++ b/src/win32/i_system.cpp @@ -1314,7 +1314,7 @@ static HCURSOR CreateCompatibleCursor(FTexture *cursorpic) HDC dc = GetDC(NULL); if (dc == NULL) { - return false; + return nullptr; } HDC and_mask_dc = CreateCompatibleDC(dc); HDC xor_mask_dc = CreateCompatibleDC(dc); @@ -1721,7 +1721,7 @@ FString I_GetLongPathName(FString shortpath) using OptWin32::GetLongPathNameA; // Doesn't exist on NT4 - if (!GetLongPathName) + if (!GetLongPathNameA) return shortpath; DWORD buffsize = GetLongPathNameA(shortpath.GetChars(), NULL, 0); From 68dc3c4f2daf80ef043ad6f7d1ff5b49b81a15e6 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Wed, 23 Nov 2016 16:24:56 +0100 Subject: [PATCH 096/185] - Preventive fix for future include conflicts. basicinlines.h is only included in m_fixed.h, while basictypes.h is included only in headers, so it's better to respect this convention. OSX compiles fine also without m_fixed.h, even better. --- src/posix/cocoa/i_timer.cpp | 2 -- src/posix/sdl/i_timer.cpp | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/posix/cocoa/i_timer.cpp b/src/posix/cocoa/i_timer.cpp index 901657eb9..5141f8750 100644 --- a/src/posix/cocoa/i_timer.cpp +++ b/src/posix/cocoa/i_timer.cpp @@ -37,8 +37,6 @@ #include #include -#include "basictypes.h" -#include "basicinlines.h" #include "doomdef.h" #include "i_system.h" #include "templates.h" diff --git a/src/posix/sdl/i_timer.cpp b/src/posix/sdl/i_timer.cpp index cad3000ba..84108f3b7 100644 --- a/src/posix/sdl/i_timer.cpp +++ b/src/posix/sdl/i_timer.cpp @@ -7,8 +7,7 @@ #include -#include "basictypes.h" -#include "basicinlines.h" +#include "m_fixed.h" #include "hardware.h" #include "i_system.h" #include "templates.h" From ae382f4005683da471e91c2f42afb5240ef5c486 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Mon, 21 Nov 2016 15:06:39 +0100 Subject: [PATCH 097/185] - Fixed the spline/cubic crashes for FMOD 4.24 64-bit, too. --- src/sound/fmodsound.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index c130b7e6a..cb4fac2cc 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -238,8 +238,8 @@ static const FEnumList ResamplerNames[] = { "No Interpolation", FMOD_DSP_RESAMPLER_NOINTERP }, { "NoInterp", FMOD_DSP_RESAMPLER_NOINTERP }, { "Linear", FMOD_DSP_RESAMPLER_LINEAR }, - // [BL] 64-bit version of FMOD Ex 4.26 crashes with these resamplers. -#if FMOD_STUDIO || !(defined(_M_X64) || defined(__amd64__)) || !(FMOD_VERSION >= 0x42600 && FMOD_VERSION <= 0x426FF) + // [BL] 64-bit versions of FMOD Ex between 4.24 and 4.26 crash with these resamplers. +#if FMOD_STUDIO || !(defined(_M_X64) || defined(__amd64__)) || !(FMOD_VERSION >= 0x42400 && FMOD_VERSION <= 0x426FF) { "Cubic", FMOD_DSP_RESAMPLER_CUBIC }, { "Spline", FMOD_DSP_RESAMPLER_SPLINE }, #endif From 2ece9b6172950b82371f2ac22139c7fc00160c81 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 24 Nov 2016 10:39:16 +0100 Subject: [PATCH 098/185] - scriptified Heretic's staff and wand. --- src/g_heretic/a_hereticweaps.cpp | 184 ++---------- src/sc_man_tokens.h | 1 + wadsrc/static/zscript.txt | 2 + .../static/zscript/heretic/hereticweaps.txt | 270 ------------------ wadsrc/static/zscript/heretic/weaponstaff.txt | 147 ++++++++++ wadsrc/static/zscript/heretic/weaponwand.txt | 217 ++++++++++++++ 6 files changed, 393 insertions(+), 428 deletions(-) create mode 100644 wadsrc/static/zscript/heretic/weaponstaff.txt create mode 100644 wadsrc/static/zscript/heretic/weaponwand.txt diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp index dc34fd206..196bd3240 100644 --- a/src/g_heretic/a_hereticweaps.cpp +++ b/src/g_heretic/a_hereticweaps.cpp @@ -15,10 +15,6 @@ #include "doomstat.h" */ -static FRandom pr_sap ("StaffAtkPL1"); -static FRandom pr_sap2 ("StaffAtkPL2"); -static FRandom pr_fgw ("FireWandPL1"); -static FRandom pr_fgw2 ("FireWandPL2"); static FRandom pr_boltspark ("BoltSpark"); static FRandom pr_macerespawn ("MaceRespawn"); static FRandom pr_maceatk ("FireMacePL1"); @@ -50,134 +46,6 @@ void P_DSparilTeleport (AActor *actor); extern bool P_AutoUseChaosDevice (player_t *player); -// --- Staff ---------------------------------------------------------------- - -//---------------------------------------------------------------------------- -// -// PROC A_StaffAttackPL1 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_StaffAttack) -{ - PARAM_ACTION_PROLOGUE(AActor); - - DAngle angle; - DAngle slope; - player_t *player; - FTranslatedLineTarget t; - - if (NULL == (player = self->player)) - { - return 0; - } - - PARAM_INT (damage); - PARAM_CLASS (puff, AActor); - - AWeapon *weapon = player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - if (puff == NULL) - { - puff = PClass::FindActor(NAME_BulletPuff); // just to be sure - } - angle = self->Angles.Yaw + pr_sap.Random2() * (5.625 / 256); - slope = P_AimLineAttack (self, angle, MELEERANGE); - P_LineAttack (self, angle, MELEERANGE, slope, damage, NAME_Melee, puff, true, &t); - if (t.linetarget) - { - //S_StartSound(player->mo, sfx_stfhit); - // turn to face target - self->Angles.Yaw = t.angleFromSource; - } - return 0; -} - - -//---------------------------------------------------------------------------- -// -// PROC A_FireGoldWandPL1 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_FireGoldWandPL1) -{ - PARAM_ACTION_PROLOGUE(AActor); - - DAngle angle; - int damage; - player_t *player; - - if (NULL == (player = self->player)) - { - return 0; - } - - AWeapon *weapon = player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo(weapon->bAltFire)) - return 0; - } - DAngle pitch = P_BulletSlope(self); - damage = 7 + (pr_fgw() & 7); - angle = self->Angles.Yaw; - if (player->refire) - { - angle += pr_fgw.Random2() * (5.625 / 256); - } - P_LineAttack(self, angle, PLAYERMISSILERANGE, pitch, damage, NAME_Hitscan, "GoldWandPuff1"); - S_Sound(self, CHAN_WEAPON, "weapons/wandhit", 1, ATTN_NORM); - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_FireGoldWandPL2 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_FireGoldWandPL2) -{ - PARAM_ACTION_PROLOGUE(AActor); - - int i; - DAngle angle; - int damage; - double vz; - player_t *player; - - if (NULL == (player = self->player)) - { - return 0; - } - - AWeapon *weapon = player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - DAngle pitch = P_BulletSlope(self); - - vz = -GetDefaultByName("GoldWandFX2")->Speed * pitch.TanClamped(); - P_SpawnMissileAngle(self, PClass::FindActor("GoldWandFX2"), self->Angles.Yaw - (45. / 8), vz); - P_SpawnMissileAngle(self, PClass::FindActor("GoldWandFX2"), self->Angles.Yaw + (45. / 8), vz); - angle = self->Angles.Yaw - (45. / 8); - for(i = 0; i < 5; i++) - { - damage = 1+(pr_fgw2()&7); - P_LineAttack (self, angle, PLAYERMISSILERANGE, pitch, damage, NAME_Hitscan, "GoldWandPuff2"); - angle += ((45. / 8) * 2) / 4; - } - S_Sound (self, CHAN_WEAPON, "weapons/wandhit", 1, ATTN_NORM); - return 0; -} - //---------------------------------------------------------------------------- // // PROC A_FireCrossbowPL1 @@ -323,20 +191,20 @@ DEFINE_ACTION_FUNCTION(AActor, A_GauntletAttack) S_Sound (self, CHAN_AUTO, "weapons/gauntletshit", 1, ATTN_NORM); } // turn to face target - DAngle angle = t.angleFromSource; - DAngle anglediff = deltaangle(self->Angles.Yaw, angle); + DAngle ang = t.angleFromSource; + DAngle anglediff = deltaangle(self->Angles.Yaw, ang); if (anglediff < 0.0) { if (anglediff < -4.5) - self->Angles.Yaw = angle + 90.0 / 21; + self->Angles.Yaw = ang + 90.0 / 21; else self->Angles.Yaw -= 4.5; } else { if (anglediff > 4.5) - self->Angles.Yaw = angle - 90.0 / 21; + self->Angles.Yaw = ang - 90.0 / 21; else self->Angles.Yaw += 4.5; } @@ -477,9 +345,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_MacePL1Check) // [RH] Avoid some precision loss by scaling the velocity directly #if 0 // This is the original code, for reference. - a.ngle_t angle = self->angle>>ANGLETOF.INESHIFT; - self->velx = F.ixedMul(7*F.RACUNIT, f.inecosine[angle]); - self->vely = F.ixedMul(7*F.RACUNIT, f.inesine[angle]); + a.ngle_t ang = self->ang>>ANGLETOF.INESHIFT; + self->velx = F.ixedMul(7*F.RACUNIT, f.inecosine[ang]); + self->vely = F.ixedMul(7*F.RACUNIT, f.inesine[ang]); #else double velscale = 7 / self->Vel.XY().Length(); self->Vel.X *= velscale; @@ -621,7 +489,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DeathBallImpact) int i; AActor *target; - DAngle angle = 0.; + DAngle ang = 0.; bool newAngle; FTranslatedLineTarget t; @@ -648,29 +516,29 @@ DEFINE_ACTION_FUNCTION(AActor, A_DeathBallImpact) } else { // Seek - angle = self->AngleTo(target); + ang = self->AngleTo(target); newAngle = true; } } else { // Find new target - angle = 0.; + ang = 0.; for (i = 0; i < 16; i++) { - P_AimLineAttack (self, angle, 640., &t, 0., ALF_NOFRIENDS|ALF_PORTALRESTRICT, NULL, self->target); + P_AimLineAttack (self, ang, 640., &t, 0., ALF_NOFRIENDS|ALF_PORTALRESTRICT, NULL, self->target); if (t.linetarget && self->target != t.linetarget) { self->tracer = t.linetarget; - angle = t.angleFromSource; + ang = t.angleFromSource; newAngle = true; break; } - angle += 22.5; + ang += 22.5; } } if (newAngle) { - self->Angles.Yaw = angle; + self->Angles.Yaw = ang; self->VelFromAngle(); } self->SetState (self->SpawnState); @@ -762,7 +630,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireBlasterPL1) { PARAM_ACTION_PROLOGUE(AActor); - DAngle angle; + DAngle ang; int damage; player_t *player; @@ -779,12 +647,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireBlasterPL1) } DAngle pitch = P_BulletSlope(self); damage = pr_fb1.HitDice (4); - angle = self->Angles.Yaw; + ang = self->Angles.Yaw; if (player->refire) { - angle += pr_fb1.Random2() * (5.625 / 256); + ang += pr_fb1.Random2() * (5.625 / 256); } - P_LineAttack (self, angle, PLAYERMISSILERANGE, pitch, damage, NAME_Hitscan, "BlasterPuff"); + P_LineAttack (self, ang, PLAYERMISSILERANGE, pitch, damage, NAME_Hitscan, "BlasterPuff"); S_Sound (self, CHAN_WEAPON, "weapons/blastershoot", 1, ATTN_NORM); return 0; } @@ -800,15 +668,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnRippers) PARAM_SELF_PROLOGUE(AActor); unsigned int i; - DAngle angle; + DAngle ang; AActor *ripper; for(i = 0; i < 8; i++) { ripper = Spawn (self->Pos(), ALLOW_REPLACE); - angle = i*45.; + ang = i*45.; ripper->target = self->target; - ripper->Angles.Yaw = angle; + ripper->Angles.Yaw = ang; ripper->VelFromAngle(); P_CheckMissileSpawn (ripper, self->radius); } @@ -1207,17 +1075,17 @@ DEFINE_ACTION_FUNCTION(AActor, A_PhoenixPuff) PARAM_SELF_PROLOGUE(AActor); AActor *puff; - DAngle angle; + DAngle ang; //[RH] Heretic never sets the target for seeking //P_SeekerMissile (self, 5, 10); puff = Spawn("PhoenixPuff", self->Pos(), ALLOW_REPLACE); - angle = self->Angles.Yaw + 90; - puff->Vel = DVector3(angle.ToVector(1.3), 0); + ang = self->Angles.Yaw + 90; + puff->Vel = DVector3(ang.ToVector(1.3), 0); puff = Spawn("PhoenixPuff", self->Pos(), ALLOW_REPLACE); - angle = self->Angles.Yaw - 90; - puff->Vel = DVector3(angle.ToVector(1.3), 0); + ang = self->Angles.Yaw - 90; + puff->Vel = DVector3(ang.ToVector(1.3), 0); return 0; } diff --git a/src/sc_man_tokens.h b/src/sc_man_tokens.h index 8ea05d7e4..dfa6c044c 100644 --- a/src/sc_man_tokens.h +++ b/src/sc_man_tokens.h @@ -49,6 +49,7 @@ xx(TK_Until, "'until'") xx(TK_While, "'while'") xx(TK_Bool, "'bool'") xx(TK_Float, "'float'") +xx(TK_Float32, "'float32'") xx(TK_Double, "'double'") xx(TK_Char, "'char'") xx(TK_Byte, "'byte'") diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index fdf057b58..1e73cc0dd 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -95,6 +95,8 @@ zscript/heretic/wizard.txt zscript/heretic/ironlich.txt zscript/heretic/dsparil.txt zscript/heretic/chicken.txt +zscript/heretic/weaponstaff.txt +zscript/heretic/weaponwand.txt zscript/hexen/baseweapons.txt zscript/hexen/korax.txt diff --git a/wadsrc/static/zscript/heretic/hereticweaps.txt b/wadsrc/static/zscript/heretic/hereticweaps.txt index e309ba095..00985b2ba 100644 --- a/wadsrc/static/zscript/heretic/hereticweaps.txt +++ b/wadsrc/static/zscript/heretic/hereticweaps.txt @@ -8,276 +8,6 @@ class HereticWeapon : Weapon } -// Staff -------------------------------------------------------------------- - -class Staff : HereticWeapon -{ - Default - { - Weapon.SelectionOrder 3800; - +THRUGHOST - +WEAPON.WIMPY_WEAPON - +WEAPON.MELEEWEAPON - Weapon.sisterweapon "StaffPowered"; - Obituary "$OB_MPSTAFF"; - Tag "$TAG_STAFF"; - } - - action native void A_StaffAttack (int damage, class puff); - - States - { - Ready: - STFF A 1 A_WeaponReady; - Loop; - Deselect: - STFF A 1 A_Lower; - Loop; - Select: - STFF A 1 A_Raise; - Loop; - Fire: - STFF B 6; - STFF C 8 A_StaffAttack(random[StaffAttack](5, 20), "StaffPuff"); - STFF B 8 A_ReFire; - Goto Ready; - } -} - -class StaffPowered : Staff -{ - Default - { - Weapon.sisterweapon "Staff"; - Weapon.ReadySound "weapons/staffcrackle"; - +WEAPON.POWERED_UP - +WEAPON.READYSNDHALF - +WEAPON.STAFF2_KICKBACK - Obituary "$OB_MPPSTAFF"; - Tag "$TAG_STAFFP"; - } - - States - { - Ready: - STFF DEF 4 A_WeaponReady; - Loop; - Deselect: - STFF D 1 A_Lower; - Loop; - Select: - STFF D 1 A_Raise; - Loop; - Fire: - STFF G 6; - STFF H 8 A_StaffAttack(random[StaffAttack](18, 81), "StaffPuff2"); - STFF G 8 A_ReFire; - Goto Ready; - } -} - - -// Staff puff --------------------------------------------------------------- - -class StaffPuff : Actor -{ - Default - { - RenderStyle "Translucent"; - Alpha 0.4; - VSpeed 1; - +NOBLOCKMAP - +NOGRAVITY - +PUFFONACTORS - AttackSound "weapons/staffhit"; - } - - States - { - Spawn: - PUF3 A 4 BRIGHT; - PUF3 BCD 4; - Stop; - } -} - -// Staff puff 2 ------------------------------------------------------------- - -class StaffPuff2 : Actor -{ - Default - { - RenderStyle "Add"; - +NOBLOCKMAP - +NOGRAVITY - +PUFFONACTORS - AttackSound "weapons/staffpowerhit"; - } - - States - { - Spawn: - PUF4 ABCDEF 4 BRIGHT; - Stop; - } -} - - - -// Gold wand ---------------------------------------------------------------- - -class GoldWand : HereticWeapon -{ - Default - { - +BLOODSPLATTER - Weapon.SelectionOrder 2000; - Weapon.AmmoGive 25; - Weapon.AmmoUse 1; - Weapon.AmmoType "GoldWandAmmo"; - Weapon.SisterWeapon "GoldWandPowered"; - Weapon.YAdjust 5; - Inventory.PickupMessage "$TXT_WPNGOLDWAND"; - Obituary "$OB_MPGOLDWAND"; - Tag "$TAG_GOLDWAND"; - } - - action native void A_FireGoldWandPL1 (); - - States - { - Spawn: - GWAN A -1; - Stop; - Ready: - GWND A 1 A_WeaponReady; - Loop; - Deselect: - GWND A 1 A_Lower; - Loop; - Select: - GWND A 1 A_Raise; - Loop; - Fire: - GWND B 3; - GWND C 5 A_FireGoldWandPL1; - GWND D 3; - GWND D 0 A_ReFire; - Goto Ready; - } -} - -class GoldWandPowered : GoldWand -{ - Default - { - +WEAPON.POWERED_UP - Weapon.AmmoGive 0; - Weapon.SisterWeapon "GoldWand"; - Obituary "$OB_MPPGOLDWAND"; - Tag "$TAG_GOLDWANDP"; - } - - action native void A_FireGoldWandPL2 (); - - States - { - Fire: - GWND B 3; - GWND C 4 A_FireGoldWandPL2; - GWND D 3; - GWND D 0 A_ReFire; - Goto Ready; - } -} - - -// Gold wand FX1 ------------------------------------------------------------ - -class GoldWandFX1 : Actor -{ - Default - { - Radius 10; - Height 6; - Speed 22; - Damage 2; - Projectile; - RenderStyle "Add"; - DeathSound "weapons/wandhit"; - Obituary "$OB_MPPGOLDWAND"; - } - - States - { - Spawn: - FX01 AB 6 BRIGHT; - Loop; - Death: - FX01 EFGH 3 BRIGHT; - Stop; - } -} - -// Gold wand FX2 ------------------------------------------------------------ - -class GoldWandFX2 : GoldWandFX1 -{ - Default - { - Speed 18; - Damage 1; - DeathSound ""; - } - - States - { - Spawn: - FX01 CD 6 BRIGHT; - Loop; - } -} - -// Gold wand puff 1 --------------------------------------------------------- - -class GoldWandPuff1 : Actor -{ - Default - { - +NOBLOCKMAP - +NOGRAVITY - +PUFFONACTORS - RenderStyle "Add"; - } - - States - { - Spawn: - PUF2 ABCDE 3 BRIGHT; - Stop; - } -} - -// Gold wand puff 2 --------------------------------------------------------- - -class GoldWandPuff2 : GoldWandFX1 -{ - Default - { - Skip_Super; - +NOBLOCKMAP - +NOGRAVITY - +PUFFONACTORS - } - - States - { - Spawn: - Goto Super::Death; - } -} - - // Crossbow ----------------------------------------------------------------- class Crossbow : HereticWeapon diff --git a/wadsrc/static/zscript/heretic/weaponstaff.txt b/wadsrc/static/zscript/heretic/weaponstaff.txt new file mode 100644 index 000000000..6349bd61b --- /dev/null +++ b/wadsrc/static/zscript/heretic/weaponstaff.txt @@ -0,0 +1,147 @@ +// Staff -------------------------------------------------------------------- + +class Staff : HereticWeapon +{ + Default + { + Weapon.SelectionOrder 3800; + +THRUGHOST + +WEAPON.WIMPY_WEAPON + +WEAPON.MELEEWEAPON + Weapon.sisterweapon "StaffPowered"; + Obituary "$OB_MPSTAFF"; + Tag "$TAG_STAFF"; + } + + + States + { + Ready: + STFF A 1 A_WeaponReady; + Loop; + Deselect: + STFF A 1 A_Lower; + Loop; + Select: + STFF A 1 A_Raise; + Loop; + Fire: + STFF B 6; + STFF C 8 A_StaffAttack(random[StaffAttack](5, 20), "StaffPuff"); + STFF B 8 A_ReFire; + Goto Ready; + } + + //---------------------------------------------------------------------------- + // + // PROC A_StaffAttackPL1 + // + //---------------------------------------------------------------------------- + + action void A_StaffAttack (int damage, class puff) + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + double ang = angle + Random2[StaffAtk]() * (5.625 / 256); + double slope = AimLineAttack (ang, MELEERANGE); + LineAttack (ang, MELEERANGE, slope, damage, 'Melee', puff, true, t); + if (t.linetarget) + { + //S_StartSound(player.mo, sfx_stfhit); + // turn to face target + angle = t.angleFromSource; + } + } +} + +class StaffPowered : Staff +{ + Default + { + Weapon.sisterweapon "Staff"; + Weapon.ReadySound "weapons/staffcrackle"; + +WEAPON.POWERED_UP + +WEAPON.READYSNDHALF + +WEAPON.STAFF2_KICKBACK + Obituary "$OB_MPPSTAFF"; + Tag "$TAG_STAFFP"; + } + + States + { + Ready: + STFF DEF 4 A_WeaponReady; + Loop; + Deselect: + STFF D 1 A_Lower; + Loop; + Select: + STFF D 1 A_Raise; + Loop; + Fire: + STFF G 6; + STFF H 8 A_StaffAttack(random[StaffAttack](18, 81), "StaffPuff2"); + STFF G 8 A_ReFire; + Goto Ready; + } +} + + +// Staff puff --------------------------------------------------------------- + +class StaffPuff : Actor +{ + Default + { + RenderStyle "Translucent"; + Alpha 0.4; + VSpeed 1; + +NOBLOCKMAP + +NOGRAVITY + +PUFFONACTORS + AttackSound "weapons/staffhit"; + } + + States + { + Spawn: + PUF3 A 4 BRIGHT; + PUF3 BCD 4; + Stop; + } +} + +// Staff puff 2 ------------------------------------------------------------- + +class StaffPuff2 : Actor +{ + Default + { + RenderStyle "Add"; + +NOBLOCKMAP + +NOGRAVITY + +PUFFONACTORS + AttackSound "weapons/staffpowerhit"; + } + + States + { + Spawn: + PUF4 ABCDEF 4 BRIGHT; + Stop; + } +} + + + diff --git a/wadsrc/static/zscript/heretic/weaponwand.txt b/wadsrc/static/zscript/heretic/weaponwand.txt new file mode 100644 index 000000000..bd1475adb --- /dev/null +++ b/wadsrc/static/zscript/heretic/weaponwand.txt @@ -0,0 +1,217 @@ +// Gold wand ---------------------------------------------------------------- + +class GoldWand : HereticWeapon +{ + Default + { + +BLOODSPLATTER + Weapon.SelectionOrder 2000; + Weapon.AmmoGive 25; + Weapon.AmmoUse 1; + Weapon.AmmoType "GoldWandAmmo"; + Weapon.SisterWeapon "GoldWandPowered"; + Weapon.YAdjust 5; + Inventory.PickupMessage "$TXT_WPNGOLDWAND"; + Obituary "$OB_MPGOLDWAND"; + Tag "$TAG_GOLDWAND"; + } + + States + { + Spawn: + GWAN A -1; + Stop; + Ready: + GWND A 1 A_WeaponReady; + Loop; + Deselect: + GWND A 1 A_Lower; + Loop; + Select: + GWND A 1 A_Raise; + Loop; + Fire: + GWND B 3; + GWND C 5 A_FireGoldWandPL1; + GWND D 3; + GWND D 0 A_ReFire; + Goto Ready; + } + + + //---------------------------------------------------------------------------- + // + // PROC A_FireGoldWandPL1 + // + //---------------------------------------------------------------------------- + + action void A_FireGoldWandPL1 () + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + double pitch = BulletSlope(); + int damage = 7 + random[FireGoldWand]() & 7; + double ang = angle; + if (player.refire) + { + ang += Random2[FireGoldWand]() * (5.625 / 256); + } + LineAttack(ang, PLAYERMISSILERANGE, pitch, damage, 'Hitscan', "GoldWandPuff1"); + A_PlaySound("weapons/wandhit", CHAN_WEAPON); + } + +} + +class GoldWandPowered : GoldWand +{ + Default + { + +WEAPON.POWERED_UP + Weapon.AmmoGive 0; + Weapon.SisterWeapon "GoldWand"; + Obituary "$OB_MPPGOLDWAND"; + Tag "$TAG_GOLDWANDP"; + } + + States + { + Fire: + GWND B 3; + GWND C 4 A_FireGoldWandPL2; + GWND D 3; + GWND D 0 A_ReFire; + Goto Ready; + } + + //---------------------------------------------------------------------------- + // + // PROC A_FireGoldWandPL2 + // + //---------------------------------------------------------------------------- + + action void A_FireGoldWandPL2 () + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + double pitch = BulletSlope(); + + double vz = -GetDefaultByType("GoldWandFX2").Speed * clamp(tan(pitch), -5, 5); + SpawnMissileAngle("GoldWandFX2", angle - (45. / 8), vz); + SpawnMissileAngle("GoldWandFX2", angle + (45. / 8), vz); + double ang = angle - (45. / 8); + for(int i = 0; i < 5; i++) + { + int damage = random[FireGoldWand](1, 8); + LineAttack (ang, PLAYERMISSILERANGE, pitch, damage, 'Hitscan', "GoldWandPuff2"); + ang += ((45. / 8) * 2) / 4; + } + A_PlaySound("weapons/wandhit", CHAN_WEAPON); + } + + +} + + +// Gold wand FX1 ------------------------------------------------------------ + +class GoldWandFX1 : Actor +{ + Default + { + Radius 10; + Height 6; + Speed 22; + Damage 2; + Projectile; + RenderStyle "Add"; + DeathSound "weapons/wandhit"; + Obituary "$OB_MPPGOLDWAND"; + } + + States + { + Spawn: + FX01 AB 6 BRIGHT; + Loop; + Death: + FX01 EFGH 3 BRIGHT; + Stop; + } +} + +// Gold wand FX2 ------------------------------------------------------------ + +class GoldWandFX2 : GoldWandFX1 +{ + Default + { + Speed 18; + Damage 1; + DeathSound ""; + } + + States + { + Spawn: + FX01 CD 6 BRIGHT; + Loop; + } +} + +// Gold wand puff 1 --------------------------------------------------------- + +class GoldWandPuff1 : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + +PUFFONACTORS + RenderStyle "Add"; + } + + States + { + Spawn: + PUF2 ABCDE 3 BRIGHT; + Stop; + } +} + +// Gold wand puff 2 --------------------------------------------------------- + +class GoldWandPuff2 : GoldWandFX1 +{ + Default + { + Skip_Super; + +NOBLOCKMAP + +NOGRAVITY + +PUFFONACTORS + } + + States + { + Spawn: + Goto Super::Death; + } +} + From 677d7579d41991d48ed2c2774c5278aeb1a5db71 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 24 Nov 2016 11:29:51 +0100 Subject: [PATCH 099/185] - scriptified Heretic's crossbow and gauntlets. --- src/g_heretic/a_hereticweaps.cpp | 167 ----------- wadsrc/static/zscript.txt | 2 + .../static/zscript/heretic/hereticweaps.txt | 279 ------------------ .../static/zscript/heretic/weaponcrossbow.txt | 208 +++++++++++++ .../zscript/heretic/weapongauntlets.txt | 210 +++++++++++++ 5 files changed, 420 insertions(+), 446 deletions(-) create mode 100644 wadsrc/static/zscript/heretic/weaponcrossbow.txt create mode 100644 wadsrc/static/zscript/heretic/weapongauntlets.txt diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp index 196bd3240..b584be0ea 100644 --- a/src/g_heretic/a_hereticweaps.cpp +++ b/src/g_heretic/a_hereticweaps.cpp @@ -18,7 +18,6 @@ static FRandom pr_boltspark ("BoltSpark"); static FRandom pr_macerespawn ("MaceRespawn"); static FRandom pr_maceatk ("FireMacePL1"); -static FRandom pr_gatk ("GauntletAttack"); static FRandom pr_bfx1 ("BlasterFX1"); static FRandom pr_ripd ("RipperD"); static FRandom pr_fb1 ("FireBlasterPL1"); @@ -46,172 +45,6 @@ void P_DSparilTeleport (AActor *actor); extern bool P_AutoUseChaosDevice (player_t *player); -//---------------------------------------------------------------------------- -// -// PROC A_FireCrossbowPL1 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_FireCrossbowPL1) -{ - PARAM_ACTION_PROLOGUE(AActor); - - player_t *player; - - if (NULL == (player = self->player)) - { - return 0; - } - - AWeapon *weapon = player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX1")); - P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX3"), self->Angles.Yaw - 4.5); - P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX3"), self->Angles.Yaw + 4.5); - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_FireCrossbowPL2 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_FireCrossbowPL2) -{ - PARAM_ACTION_PROLOGUE(AActor); - - player_t *player; - - if (NULL == (player = self->player)) - { - return 0; - } - - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX2")); - P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX2"), self->Angles.Yaw - 4.5); - P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX2"), self->Angles.Yaw + 4.5); - P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX3"), self->Angles.Yaw - 9.); - P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX3"), self->Angles.Yaw + 9.); - return 0; -} - -//--------------------------------------------------------------------------- -// -// PROC A_GauntletAttack -// -//--------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_GauntletAttack) -{ - PARAM_ACTION_PROLOGUE(AActor); - - DAngle Angle; - int damage; - DAngle slope; - int randVal; - double dist; - player_t *player; - PClassActor *pufftype; - FTranslatedLineTarget t; - int actualdamage = 0; - - if (nullptr == (player = self->player)) - { - return 0; - } - - PARAM_INT(power); - - AWeapon *weapon = player->ReadyWeapon; - if (weapon != nullptr) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - - player->GetPSprite(PSP_WEAPON)->x = ((pr_gatk() & 3) - 2); - player->GetPSprite(PSP_WEAPON)->y = WEAPONTOP + (pr_gatk() & 3); - } - Angle = self->Angles.Yaw; - if (power) - { - damage = pr_gatk.HitDice (2); - dist = 4*MELEERANGE; - Angle += pr_gatk.Random2() * (2.8125 / 256); - pufftype = PClass::FindActor("GauntletPuff2"); - } - else - { - damage = pr_gatk.HitDice (2); - dist = SAWRANGE; - Angle += pr_gatk.Random2() * (5.625 / 256); - pufftype = PClass::FindActor("GauntletPuff1"); - } - slope = P_AimLineAttack (self, Angle, dist); - P_LineAttack (self, Angle, dist, slope, damage, NAME_Melee, pufftype, false, &t, &actualdamage); - if (!t.linetarget) - { - if (pr_gatk() > 64) - { - player->extralight = !player->extralight; - } - S_Sound (self, CHAN_AUTO, "weapons/gauntletson", 1, ATTN_NORM); - return 0; - } - randVal = pr_gatk(); - if (randVal < 64) - { - player->extralight = 0; - } - else if (randVal < 160) - { - player->extralight = 1; - } - else - { - player->extralight = 2; - } - if (power) - { - if (!(t.linetarget->flags5 & MF5_DONTDRAIN)) P_GiveBody (self, actualdamage>>1); - S_Sound (self, CHAN_AUTO, "weapons/gauntletspowhit", 1, ATTN_NORM); - } - else - { - S_Sound (self, CHAN_AUTO, "weapons/gauntletshit", 1, ATTN_NORM); - } - // turn to face target - DAngle ang = t.angleFromSource; - DAngle anglediff = deltaangle(self->Angles.Yaw, ang); - - if (anglediff < 0.0) - { - if (anglediff < -4.5) - self->Angles.Yaw = ang + 90.0 / 21; - else - self->Angles.Yaw -= 4.5; - } - else - { - if (anglediff > 4.5) - self->Angles.Yaw = ang - 90.0 / 21; - else - self->Angles.Yaw += 4.5; - } - self->flags |= MF_JUSTATTACKED; - return 0; -} - // --- Mace ----------------------------------------------------------------- #define MAGIC_JUNK 1234 diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 1e73cc0dd..d2853ddb9 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -97,6 +97,8 @@ zscript/heretic/dsparil.txt zscript/heretic/chicken.txt zscript/heretic/weaponstaff.txt zscript/heretic/weaponwand.txt +zscript/heretic/weaponcrossbow.txt +zscript/heretic/weapongauntlets.txt zscript/hexen/baseweapons.txt zscript/hexen/korax.txt diff --git a/wadsrc/static/zscript/heretic/hereticweaps.txt b/wadsrc/static/zscript/heretic/hereticweaps.txt index 00985b2ba..a6faf958f 100644 --- a/wadsrc/static/zscript/heretic/hereticweaps.txt +++ b/wadsrc/static/zscript/heretic/hereticweaps.txt @@ -8,285 +8,6 @@ class HereticWeapon : Weapon } -// Crossbow ----------------------------------------------------------------- - -class Crossbow : HereticWeapon -{ - Default - { - Weapon.SelectionOrder 800; - Weapon.AmmoUse 1; - Weapon.AmmoGive 10; - Weapon.AmmoType "CrossbowAmmo"; - Weapon.SisterWeapon "CrossbowPowered"; - Weapon.YAdjust 15; - Inventory.PickupMessage "$TXT_WPNCROSSBOW"; - Tag "$TAG_CROSSBOW"; - } - - action native void A_FireCrossbowPL1 (); - - States - { - Spawn: - WBOW A -1; - Stop; - Ready: - CRBW AAAAAABBBBBBCCCCCC 1 A_WeaponReady; - Loop; - Deselect: - CRBW A 1 A_Lower; - Loop; - Select: - CRBW A 1 A_Raise; - Loop; - Fire: - CRBW D 6 A_FireCrossbowPL1; - CRBW EFGH 3; - CRBW AB 4; - CRBW C 5 A_ReFire; - Goto Ready; - } -} - - -class CrossbowPowered : Crossbow -{ - Default - { - +WEAPON.POWERED_UP - Weapon.AmmoGive 0; - Weapon.SisterWeapon "Crossbow"; - Tag "$TAG_CROSSBOWP"; - } - - action native void A_FireCrossbowPL2(); - - States - { - Fire: - CRBW D 5 A_FireCrossbowPL2; - CRBW E 3; - CRBW F 2; - CRBW G 3; - CRBW H 2; - CRBW A 3; - CRBW B 3; - CRBW C 4 A_ReFire; - Goto Ready; - } -} - - -// Crossbow FX1 ------------------------------------------------------------- - -class CrossbowFX1 : Actor -{ - Default - { - Radius 11; - Height 8; - Speed 30; - Damage 10; - Projectile; - RenderStyle "Add"; - SeeSound "weapons/bowshoot"; - DeathSound "weapons/bowhit"; - Obituary "$OB_MPCROSSBOW"; - } - - States - { - Spawn: - FX03 B 1 BRIGHT; - Loop; - Death: - FX03 HIJ 8 BRIGHT; - Stop; - } -} - - -// Crossbow FX2 ------------------------------------------------------------- - -class CrossbowFX2 : CrossbowFX1 -{ - Default - { - Speed 32; - Damage 6; - Obituary "$OB_MPPCROSSBOW"; - } - - States - { - Spawn: - FX03 B 1 BRIGHT A_SpawnItemEx("CrossbowFX4", random2[BoltSpark]()*0.015625, random2[BoltSpark]()*0.015625, 0, 0,0,0,0,SXF_ABSOLUTEPOSITION, 50); - Loop; - } -} - -// Crossbow FX3 ------------------------------------------------------------- - -class CrossbowFX3 : CrossbowFX1 -{ - Default - { - Speed 20; - Damage 2; - SeeSound ""; - -NOBLOCKMAP - +WINDTHRUST - +THRUGHOST - } - - States - { - Spawn: - FX03 A 1 BRIGHT; - Loop; - Death: - FX03 CDE 8 BRIGHT; - Stop; - } -} - -// Crossbow FX4 ------------------------------------------------------------- - -class CrossbowFX4 : Actor -{ - Default - { - +NOBLOCKMAP - Gravity 0.125; - RenderStyle "Add"; - } - - States - { - Spawn: - FX03 FG 8 BRIGHT; - Stop; - } -} - - - - -// Gauntlets ---------------------------------------------------------------- - -class Gauntlets : Weapon -{ - Default - { - +BLOODSPLATTER - Weapon.SelectionOrder 2300; - +WEAPON.WIMPY_WEAPON - +WEAPON.MELEEWEAPON - Weapon.Kickback 0; - Weapon.YAdjust 15; - Weapon.UpSound "weapons/gauntletsactivate"; - Weapon.SisterWeapon "GauntletsPowered"; - Inventory.PickupMessage "$TXT_WPNGAUNTLETS"; - Tag "$TAG_GAUNTLETS"; - Obituary "$OB_MPGAUNTLETS"; - } - - action native void A_GauntletAttack (int power); - - States - { - Spawn: - WGNT A -1; - Stop; - Ready: - GAUN A 1 A_WeaponReady; - Loop; - Deselect: - GAUN A 1 A_Lower; - Loop; - Select: - GAUN A 1 A_Raise; - Loop; - Fire: - GAUN B 4 A_PlaySound("weapons/gauntletsuse", CHAN_WEAPON); - GAUN C 4; - Hold: - GAUN DEF 4 BRIGHT A_GauntletAttack(0); - GAUN C 4 A_ReFire; - GAUN B 4 A_Light0; - Goto Ready; - } -} - - -class GauntletsPowered : Gauntlets -{ - Default - { - +WEAPON.POWERED_UP - Tag "$TAG_GAUNTLETSP"; - Obituary "$OB_MPPGAUNTLETS"; - Weapon.SisterWeapon "Gauntlets"; - } - - States - { - Ready: - GAUN GHI 4 A_WeaponReady; - Loop; - Deselect: - GAUN G 1 A_Lower; - Loop; - Select: - GAUN G 1 A_Raise; - Loop; - Fire: - GAUN J 4 A_PlaySound("weapons/gauntletsuse", CHAN_WEAPON); - GAUN K 4; - Hold: - GAUN LMN 4 BRIGHT A_GauntletAttack(1); - GAUN K 4 A_ReFire; - GAUN J 4 A_Light0; - Goto Ready; - } -} - - -// Gauntlet puff 1 ---------------------------------------------------------- - -class GauntletPuff1 : Actor -{ - Default - { - +NOBLOCKMAP - +NOGRAVITY - +PUFFONACTORS - RenderStyle "Translucent"; - Alpha 0.4; - VSpeed 0.8; - } - - States - { - Spawn: - PUF1 ABCD 4 BRIGHT; - Stop; - } -} - -// Gauntlet puff 2 --------------------------------------------------------- - -class GauntletPuff2 : GauntletPuff1 -{ - States - { - Spawn: - PUF1 EFGH 4 BRIGHT; - Stop; - } -} - // The mace itself ---------------------------------------------------------- diff --git a/wadsrc/static/zscript/heretic/weaponcrossbow.txt b/wadsrc/static/zscript/heretic/weaponcrossbow.txt new file mode 100644 index 000000000..bd5e9517a --- /dev/null +++ b/wadsrc/static/zscript/heretic/weaponcrossbow.txt @@ -0,0 +1,208 @@ +// Crossbow ----------------------------------------------------------------- + +class Crossbow : HereticWeapon +{ + Default + { + Weapon.SelectionOrder 800; + Weapon.AmmoUse 1; + Weapon.AmmoGive 10; + Weapon.AmmoType "CrossbowAmmo"; + Weapon.SisterWeapon "CrossbowPowered"; + Weapon.YAdjust 15; + Inventory.PickupMessage "$TXT_WPNCROSSBOW"; + Tag "$TAG_CROSSBOW"; + } + + States + { + Spawn: + WBOW A -1; + Stop; + Ready: + CRBW AAAAAABBBBBBCCCCCC 1 A_WeaponReady; + Loop; + Deselect: + CRBW A 1 A_Lower; + Loop; + Select: + CRBW A 1 A_Raise; + Loop; + Fire: + CRBW D 6 A_FireCrossbowPL1; + CRBW EFGH 3; + CRBW AB 4; + CRBW C 5 A_ReFire; + Goto Ready; + } + + //---------------------------------------------------------------------------- + // + // PROC A_FireCrossbowPL1 + // + //---------------------------------------------------------------------------- + + action void A_FireCrossbowPL1 () + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + SpawnPlayerMissile ("CrossbowFX1"); + SpawnPlayerMissile ("CrossbowFX3", angle - 4.5); + SpawnPlayerMissile ("CrossbowFX3", angle + 4.5); + } +} + + +class CrossbowPowered : Crossbow +{ + Default + { + +WEAPON.POWERED_UP + Weapon.AmmoGive 0; + Weapon.SisterWeapon "Crossbow"; + Tag "$TAG_CROSSBOWP"; + } + + States + { + Fire: + CRBW D 5 A_FireCrossbowPL2; + CRBW E 3; + CRBW F 2; + CRBW G 3; + CRBW H 2; + CRBW A 3; + CRBW B 3; + CRBW C 4 A_ReFire; + Goto Ready; + } + + //---------------------------------------------------------------------------- + // + // PROC A_FireCrossbowPL2 + // + //---------------------------------------------------------------------------- + + action void A_FireCrossbowPL2() + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + SpawnPlayerMissile ("CrossbowFX2"); + SpawnPlayerMissile ("CrossbowFX2", angle - 4.5); + SpawnPlayerMissile ("CrossbowFX2", angle + 4.5); + SpawnPlayerMissile ("CrossbowFX3", angle - 9.); + SpawnPlayerMissile ("CrossbowFX3", angle + 9.); + } +} + + +// Crossbow FX1 ------------------------------------------------------------- + +class CrossbowFX1 : Actor +{ + Default + { + Radius 11; + Height 8; + Speed 30; + Damage 10; + Projectile; + RenderStyle "Add"; + SeeSound "weapons/bowshoot"; + DeathSound "weapons/bowhit"; + Obituary "$OB_MPCROSSBOW"; + } + + States + { + Spawn: + FX03 B 1 BRIGHT; + Loop; + Death: + FX03 HIJ 8 BRIGHT; + Stop; + } +} + + +// Crossbow FX2 ------------------------------------------------------------- + +class CrossbowFX2 : CrossbowFX1 +{ + Default + { + Speed 32; + Damage 6; + Obituary "$OB_MPPCROSSBOW"; + } + + States + { + Spawn: + FX03 B 1 BRIGHT A_SpawnItemEx("CrossbowFX4", random2[BoltSpark]()*0.015625, random2[BoltSpark]()*0.015625, 0, 0,0,0,0,SXF_ABSOLUTEPOSITION, 50); + Loop; + } +} + +// Crossbow FX3 ------------------------------------------------------------- + +class CrossbowFX3 : CrossbowFX1 +{ + Default + { + Speed 20; + Damage 2; + SeeSound ""; + -NOBLOCKMAP + +WINDTHRUST + +THRUGHOST + } + + States + { + Spawn: + FX03 A 1 BRIGHT; + Loop; + Death: + FX03 CDE 8 BRIGHT; + Stop; + } +} + +// Crossbow FX4 ------------------------------------------------------------- + +class CrossbowFX4 : Actor +{ + Default + { + +NOBLOCKMAP + Gravity 0.125; + RenderStyle "Add"; + } + + States + { + Spawn: + FX03 FG 8 BRIGHT; + Stop; + } +} + diff --git a/wadsrc/static/zscript/heretic/weapongauntlets.txt b/wadsrc/static/zscript/heretic/weapongauntlets.txt new file mode 100644 index 000000000..d06efe465 --- /dev/null +++ b/wadsrc/static/zscript/heretic/weapongauntlets.txt @@ -0,0 +1,210 @@ +// Gauntlets ---------------------------------------------------------------- + +class Gauntlets : Weapon +{ + Default + { + +BLOODSPLATTER + Weapon.SelectionOrder 2300; + +WEAPON.WIMPY_WEAPON + +WEAPON.MELEEWEAPON + Weapon.Kickback 0; + Weapon.YAdjust 15; + Weapon.UpSound "weapons/gauntletsactivate"; + Weapon.SisterWeapon "GauntletsPowered"; + Inventory.PickupMessage "$TXT_WPNGAUNTLETS"; + Tag "$TAG_GAUNTLETS"; + Obituary "$OB_MPGAUNTLETS"; + } + + States + { + Spawn: + WGNT A -1; + Stop; + Ready: + GAUN A 1 A_WeaponReady; + Loop; + Deselect: + GAUN A 1 A_Lower; + Loop; + Select: + GAUN A 1 A_Raise; + Loop; + Fire: + GAUN B 4 A_PlaySound("weapons/gauntletsuse", CHAN_WEAPON); + GAUN C 4; + Hold: + GAUN DEF 4 BRIGHT A_GauntletAttack(0); + GAUN C 4 A_ReFire; + GAUN B 4 A_Light0; + Goto Ready; + } + + //--------------------------------------------------------------------------- + // + // PROC A_GauntletAttack + // + //--------------------------------------------------------------------------- + + action void A_GauntletAttack (int power) + { + int damage; + double dist; + Class pufftype; + FTranslatedLineTarget t; + int actualdamage = 0; + Actor puff; + + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + + player.GetPSprite(PSP_WEAPON).x = ((random[GauntletAtk]() & 3) - 2); + player.GetPSprite(PSP_WEAPON).y = WEAPONTOP + (random[GauntletAtk]() & 3); + } + double ang = angle; + if (power) + { + damage = random[GauntletAtk](1, 8) * 2; + dist = 4*MELEERANGE; + ang += random2[GauntletAtk]() * (2.8125 / 256); + pufftype = "GauntletPuff2"; + } + else + { + damage = random[GauntletAtk](1, 8) * 2; + dist = SAWRANGE; + ang += random2[GauntletAtk]() * (5.625 / 256); + pufftype = "GauntletPuff1"; + } + double slope = AimLineAttack (ang, dist); + [puff, actualdamage] = LineAttack (ang, dist, slope, damage, 'Melee', pufftype, false, t); + if (!t.linetarget) + { + if (random[GauntletAtk]() > 64) + { + player.extralight = !player.extralight; + } + A_PlaySound ("weapons/gauntletson", CHAN_AUTO); + return; + } + int randVal = random[GauntletAtk](); + if (randVal < 64) + { + player.extralight = 0; + } + else if (randVal < 160) + { + player.extralight = 1; + } + else + { + player.extralight = 2; + } + if (power) + { + if (!t.linetarget.bDontDrain) GiveBody (actualdamage >> 1); + A_PlaySound ("weapons/gauntletspowhit", CHAN_AUTO); + } + else + { + A_PlaySound ("weapons/gauntletshit", CHAN_AUTO); + } + // turn to face target + ang = t.angleFromSource; + double anglediff = deltaangle(angle, ang); + + if (anglediff < 0.0) + { + if (anglediff < -4.5) + angle = ang + 90.0 / 21; + else + angle -= 4.5; + } + else + { + if (anglediff > 4.5) + angle = ang - 90.0 / 21; + else + angle += 4.5; + } + bJustAttacked = true; + } +} + + +class GauntletsPowered : Gauntlets +{ + Default + { + +WEAPON.POWERED_UP + Tag "$TAG_GAUNTLETSP"; + Obituary "$OB_MPPGAUNTLETS"; + Weapon.SisterWeapon "Gauntlets"; + } + + States + { + Ready: + GAUN GHI 4 A_WeaponReady; + Loop; + Deselect: + GAUN G 1 A_Lower; + Loop; + Select: + GAUN G 1 A_Raise; + Loop; + Fire: + GAUN J 4 A_PlaySound("weapons/gauntletsuse", CHAN_WEAPON); + GAUN K 4; + Hold: + GAUN LMN 4 BRIGHT A_GauntletAttack(1); + GAUN K 4 A_ReFire; + GAUN J 4 A_Light0; + Goto Ready; + } +} + + +// Gauntlet puff 1 ---------------------------------------------------------- + +class GauntletPuff1 : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + +PUFFONACTORS + RenderStyle "Translucent"; + Alpha 0.4; + VSpeed 0.8; + } + + States + { + Spawn: + PUF1 ABCD 4 BRIGHT; + Stop; + } +} + +// Gauntlet puff 2 --------------------------------------------------------- + +class GauntletPuff2 : GauntletPuff1 +{ + States + { + Spawn: + PUF1 EFGH 4 BRIGHT; + Stop; + } +} + From 3a059cbfd6ca0884b778506b50a2728bf39a039c Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Thu, 24 Nov 2016 10:47:45 +0100 Subject: [PATCH 100/185] - Backported A_FireRailgun 'puffType' param from Zandronum. Zandronum added this so that it could restore the original Skulltag piercing armor capability with a specific puff, like it's done with the other zdoom railgun action functions. --- wadsrc/static/zscript/doom/doomweapons.txt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/wadsrc/static/zscript/doom/doomweapons.txt b/wadsrc/static/zscript/doom/doomweapons.txt index 731740ac6..f3a40c22a 100644 --- a/wadsrc/static/zscript/doom/doomweapons.txt +++ b/wadsrc/static/zscript/doom/doomweapons.txt @@ -19,8 +19,9 @@ extend class StateProvider // // [RH] A_FireRailgun + // [TP] This now takes a puff type to retain Skulltag's railgun's ability to pierce armor. // - action void A_FireRailgun(int offset_xy = 0) + action void A_FireRailgun(class puffType = "BulletPuff", int offset_xy = 0) { if (player == null) { @@ -42,17 +43,17 @@ extend class StateProvider } int damage = deathmatch ? 100 : 150; - A_RailAttack(damage, offset_xy, false); // note that this function handles ammo depletion itself for Dehacked compatibility purposes. + A_RailAttack(damage, offset_xy, false, pufftype: puffType); // note that this function handles ammo depletion itself for Dehacked compatibility purposes. } action void A_FireRailgunLeft() { - A_FireRailgun(-10); + A_FireRailgun(offset_xy: -10); } action void A_FireRailgunRight() { - A_FireRailgun(10); + A_FireRailgun(offset_xy: 10); } action void A_RailWait() @@ -60,4 +61,4 @@ extend class StateProvider // only here to satisfy old Dehacked patches. } -} \ No newline at end of file +} From 3f5bf88d69ff85eeea5b719c0ace3feaa0836776 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 24 Nov 2016 13:45:43 +0100 Subject: [PATCH 101/185] - scriptified Heretic's mace. - fixed: FxAssignSelf did not the correct number of registers for vector operations. - fixed a few asserts in vector2 instructions. - turned the virtual AActor::HitFloor method into a flag MF7_SMASHABLE. The only use of this function was to kill Hexen's pottery when they hit the floor, and this looks like something that can be exposed to modders less clumsily. --- src/actor.h | 4 +- src/g_heretic/a_hereticweaps.cpp | 343 ------------- src/g_hexen/a_hexenspecialdecs.cpp | 15 - src/g_raven/a_artitele.cpp | 18 - src/namedef.h | 1 + src/p_mobj.cpp | 30 +- src/scripting/codegeneration/codegen.cpp | 2 +- src/scripting/thingdef_data.cpp | 1 + src/scripting/vm/vmexec.h | 8 +- src/virtual.h | 22 + wadsrc/static/zscript.txt | 1 + wadsrc/static/zscript/actor.txt | 3 + .../static/zscript/heretic/hereticweaps.txt | 204 -------- wadsrc/static/zscript/heretic/weaponmace.txt | 468 ++++++++++++++++++ .../static/zscript/hexen/hexenspecialdecs.txt | 4 +- 15 files changed, 529 insertions(+), 595 deletions(-) create mode 100644 wadsrc/static/zscript/heretic/weaponmace.txt diff --git a/src/actor.h b/src/actor.h index 83873adc5..bbe7381a2 100644 --- a/src/actor.h +++ b/src/actor.h @@ -385,6 +385,7 @@ enum ActorFlag7 MF7_USEKILLSCRIPTS = 0x00800000, // [JM] Use "KILL" Script on death if not forced by GameInfo. MF7_NOKILLSCRIPTS = 0x01000000, // [JM] No "KILL" Script on death whatsoever, even if forced by GameInfo. MF7_SPRITEANGLE = 0x02000000, // [MC] Utilize the SpriteAngle property and lock the rotation to the degrees specified. + MF7_SMASHABLE = 0x04000000, // dies if hitting the floor. }; // --- mobj.renderflags --- @@ -636,9 +637,6 @@ public: // Made a metadata property so no longer virtual void Howl (); - // Actor just hit the floor - virtual void HitFloor (); - // plays bouncing sound void PlayBounceSound(bool onfloor); diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp index b584be0ea..cc964ecc0 100644 --- a/src/g_heretic/a_hereticweaps.cpp +++ b/src/g_heretic/a_hereticweaps.cpp @@ -45,349 +45,6 @@ void P_DSparilTeleport (AActor *actor); extern bool P_AutoUseChaosDevice (player_t *player); -// --- Mace ----------------------------------------------------------------- - -#define MAGIC_JUNK 1234 - -// Mace FX4 ----------------------------------------------------------------- - -class AMaceFX4 : public AActor -{ - DECLARE_CLASS (AMaceFX4, AActor) -public: - int DoSpecialDamage (AActor *target, int damage, FName damagetype); -}; - -IMPLEMENT_CLASS(AMaceFX4, false, false, false, false) - -int AMaceFX4::DoSpecialDamage (AActor *target, int damage, FName damagetype) -{ - if ((target->flags2 & MF2_BOSS) || (target->flags3 & MF3_DONTSQUASH) || target->IsTeammate (this->target)) - { // Don't allow cheap boss kills and don't instagib teammates - return damage; - } - else if (target->player) - { // Player specific checks - if (target->player->mo->flags2 & MF2_INVULNERABLE) - { // Can't hurt invulnerable players - return -1; - } - if (P_AutoUseChaosDevice (target->player)) - { // Player was saved using chaos device - return -1; - } - } - return TELEFRAG_DAMAGE; // Something's gonna die -} - -//---------------------------------------------------------------------------- -// -// PROC A_FireMacePL1B -// -//---------------------------------------------------------------------------- - -void FireMacePL1B (AActor *actor) -{ - AActor *ball; - player_t *player; - - if (NULL == (player = actor->player)) - { - return; - } - - AWeapon *weapon = player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; - } - ball = Spawn("MaceFX2", actor->PosPlusZ(28 - actor->Floorclip), ALLOW_REPLACE); - ball->Vel.Z = 2 - player->mo->Angles.Pitch.TanClamped(); - ball->target = actor; - ball->Angles.Yaw = actor->Angles.Yaw; - ball->AddZ(ball->Vel.Z); - ball->VelFromAngle(); - ball->Vel += actor->Vel.XY()/2; - S_Sound (ball, CHAN_BODY, "weapons/maceshoot", 1, ATTN_NORM); - P_CheckMissileSpawn (ball, actor->radius); -} - -//---------------------------------------------------------------------------- -// -// PROC A_FireMacePL1 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_FireMacePL1) -{ - PARAM_ACTION_PROLOGUE(AActor); - - AActor *ball; - player_t *player; - - if (nullptr == (player = self->player)) - { - return 0; - } - - if (pr_maceatk() < 28) - { - FireMacePL1B(self); - return 0; - } - AWeapon *weapon = player->ReadyWeapon; - if (weapon != nullptr) - { - if (!weapon->DepleteAmmo(weapon->bAltFire)) - return 0; - - player->GetPSprite(PSP_WEAPON)->x = ((pr_maceatk() & 3) - 2); - player->GetPSprite(PSP_WEAPON)->y = WEAPONTOP + (pr_maceatk() & 3); - } - ball = P_SpawnPlayerMissile(self, PClass::FindActor("MaceFX1"), self->Angles.Yaw + (((pr_maceatk() & 7) - 4) * (360. / 256))); - if (ball) - { - ball->special1 = 16; // tics till dropoff - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_MacePL1Check -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_MacePL1Check) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (self->special1 == 0) - { - return 0; - } - self->special1 -= 4; - if (self->special1 > 0) - { - return 0; - } - self->special1 = 0; - self->flags &= ~MF_NOGRAVITY; - self->Gravity = 1. / 8;; - // [RH] Avoid some precision loss by scaling the velocity directly -#if 0 - // This is the original code, for reference. - a.ngle_t ang = self->ang>>ANGLETOF.INESHIFT; - self->velx = F.ixedMul(7*F.RACUNIT, f.inecosine[ang]); - self->vely = F.ixedMul(7*F.RACUNIT, f.inesine[ang]); -#else - double velscale = 7 / self->Vel.XY().Length(); - self->Vel.X *= velscale; - self->Vel.Y *= velscale; -#endif - self->Vel.Z *= 0.5; - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_MaceBallImpact -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_MaceBallImpact) -{ - PARAM_SELF_PROLOGUE(AActor); - - if ((self->health != MAGIC_JUNK) && (self->flags & MF_INBOUNCE)) - { // Bounce - self->health = MAGIC_JUNK; - self->Vel.Z *= 0.75; - self->BounceFlags = BOUNCE_None; - self->SetState (self->SpawnState); - S_Sound (self, CHAN_BODY, "weapons/macebounce", 1, ATTN_NORM); - } - else - { // Explode - self->Vel.Zero(); - self->flags |= MF_NOGRAVITY; - self->Gravity = 1; - S_Sound (self, CHAN_BODY, "weapons/macehit", 1, ATTN_NORM); - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_MaceBallImpact2 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_MaceBallImpact2) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *tiny; - - if ((self->Z() <= self->floorz) && P_HitFloor (self)) - { // Landed in some sort of liquid - self->Destroy (); - return 0; - } - if (self->flags & MF_INBOUNCE) - { - if (self->Vel.Z < 2) - { - goto boom; - } - - // Bounce - self->Vel.Z *= 0.75; - self->SetState (self->SpawnState); - - tiny = Spawn("MaceFX3", self->Pos(), ALLOW_REPLACE); - tiny->target = self->target; - tiny->Angles.Yaw = self->Angles.Yaw + 90.; - tiny->VelFromAngle(self->Vel.Z - 1.); - tiny->Vel += { self->Vel.X * .5, self->Vel.Y * .5, self->Vel.Z }; - P_CheckMissileSpawn (tiny, self->radius); - - tiny = Spawn("MaceFX3", self->Pos(), ALLOW_REPLACE); - tiny->target = self->target; - tiny->Angles.Yaw = self->Angles.Yaw - 90.; - tiny->VelFromAngle(self->Vel.Z - 1.); - tiny->Vel += { self->Vel.X * .5, self->Vel.Y * .5, self->Vel.Z }; - P_CheckMissileSpawn (tiny, self->radius); - } - else - { // Explode -boom: - self->Vel.Zero(); - self->flags |= MF_NOGRAVITY; - self->BounceFlags = BOUNCE_None; - self->Gravity = 1; - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_FireMacePL2 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_FireMacePL2) -{ - PARAM_ACTION_PROLOGUE(AActor); - - AActor *mo; - player_t *player; - FTranslatedLineTarget t; - - if (NULL == (player = self->player)) - { - return 0; - } - - AWeapon *weapon = player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - mo = P_SpawnPlayerMissile (self, 0,0,0, RUNTIME_CLASS(AMaceFX4), self->Angles.Yaw, &t); - if (mo) - { - mo->Vel += self->Vel.XY(); - mo->Vel.Z = 2 - player->mo->Angles.Pitch.TanClamped(); - if (t.linetarget && !t.unlinked) - { - mo->tracer = t.linetarget; - } - } - S_Sound (self, CHAN_WEAPON, "weapons/maceshoot", 1, ATTN_NORM); - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_DeathBallImpact -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_DeathBallImpact) -{ - PARAM_SELF_PROLOGUE(AActor); - - int i; - AActor *target; - DAngle ang = 0.; - bool newAngle; - FTranslatedLineTarget t; - - if ((self->Z() <= self->floorz) && P_HitFloor (self)) - { // Landed in some sort of liquid - self->Destroy (); - return 0; - } - if (self->flags & MF_INBOUNCE) - { - if (self->Vel.Z < 2) - { - goto boom; - } - - // Bounce - newAngle = false; - target = self->tracer; - if (target) - { - if (!(target->flags&MF_SHOOTABLE)) - { // Target died - self->tracer = NULL; - } - else - { // Seek - ang = self->AngleTo(target); - newAngle = true; - } - } - else - { // Find new target - ang = 0.; - for (i = 0; i < 16; i++) - { - P_AimLineAttack (self, ang, 640., &t, 0., ALF_NOFRIENDS|ALF_PORTALRESTRICT, NULL, self->target); - if (t.linetarget && self->target != t.linetarget) - { - self->tracer = t.linetarget; - ang = t.angleFromSource; - newAngle = true; - break; - } - ang += 22.5; - } - } - if (newAngle) - { - self->Angles.Yaw = ang; - self->VelFromAngle(); - } - self->SetState (self->SpawnState); - S_Sound (self, CHAN_BODY, "weapons/macestop", 1, ATTN_NORM); - } - else - { // Explode -boom: - self->Vel.Zero(); - self->flags |= MF_NOGRAVITY; - self->Gravity = 1; - S_Sound (self, CHAN_BODY, "weapons/maceexplode", 1, ATTN_NORM); - } - return 0; -} - // Blaster FX 1 ------------------------------------------------------------- diff --git a/src/g_hexen/a_hexenspecialdecs.cpp b/src/g_hexen/a_hexenspecialdecs.cpp index 6d441ba57..0dcdc2c5f 100644 --- a/src/g_hexen/a_hexenspecialdecs.cpp +++ b/src/g_hexen/a_hexenspecialdecs.cpp @@ -32,21 +32,6 @@ void A_PotteryExplode (AActor *); void A_PotteryChooseBit (AActor *); void A_PotteryCheck (AActor *); -class APottery1 : public AActor -{ - DECLARE_CLASS (APottery1, AActor) -public: - void HitFloor (); -}; - -IMPLEMENT_CLASS(APottery1, false, false, false, false) - -void APottery1::HitFloor () -{ - Super::HitFloor (); - P_DamageMobj (this, NULL, NULL, 25, NAME_None); -} - //============================================================================ // // A_PotteryExplode diff --git a/src/g_raven/a_artitele.cpp b/src/g_raven/a_artitele.cpp index 35387df45..b333c9a13 100644 --- a/src/g_raven/a_artitele.cpp +++ b/src/g_raven/a_artitele.cpp @@ -61,21 +61,3 @@ bool AArtiTeleport::Use (bool pickup) return true; } -//--------------------------------------------------------------------------- -// -// FUNC P_AutoUseChaosDevice -// -//--------------------------------------------------------------------------- - -bool P_AutoUseChaosDevice (player_t *player) -{ - AInventory *arti = player->mo->FindInventory(PClass::FindActor("ArtiTeleport")); - - if (arti != NULL) - { - player->mo->UseInventory (arti); - player->health = player->mo->health = (player->health+1)/2; - return true; - } - return false; -} diff --git a/src/namedef.h b/src/namedef.h index 545bf0260..639c762eb 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -209,6 +209,7 @@ xx(XDeath) xx(Burn) //xx(Ice) // already defined above xx(Disintegrate) +xx(Smash) // Weapon animator names. xx(Select) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 8784dc075..46ecbd3fa 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -948,6 +948,14 @@ bool AActor::UseInventory (AInventory *item) return true; } +DEFINE_ACTION_FUNCTION(AActor, UseInventory) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(item, AInventory); + self->VMSuperCall(); + ACTION_RETURN_BOOL(self->UseInventory(item)); +} + //=========================================================================== // // AActor :: DropInventory @@ -2741,7 +2749,10 @@ void P_ZMovement (AActor *mo, double oldfloorz) return; } // Let the actor do something special for hitting the floor - mo->HitFloor (); + if (mo->flags7 & MF7_SMASHABLE) + { + P_DamageMobj(mo, nullptr, nullptr, mo->health, NAME_Smash); + } if (mo->player) { if (mo->player->jumpTics < 0 || mo->Vel.Z < minvel) @@ -3230,10 +3241,6 @@ void AActor::Howl () } } -void AActor::HitFloor () -{ -} - bool AActor::Slam (AActor *thing) { flags &= ~MF_SKULLFLY; @@ -5945,6 +5952,12 @@ bool P_HitFloor (AActor *thing) return P_HitWater (thing, m->m_sector, pos); } +DEFINE_ACTION_FUNCTION(AActor, HitFloor) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_BOOL(P_HitFloor(self)); +} + //--------------------------------------------------------------------------- // // P_CheckSplash @@ -6543,6 +6556,13 @@ bool AActor::IsTeammate (AActor *other) return false; } +DEFINE_ACTION_FUNCTION(AActor, isTeammate) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(other, AActor); + ACTION_RETURN_BOOL(self->IsTeammate(other)); +} + //========================================================================== // // AActor :: GetSpecies diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index ba4eab9e3..4bf6f076e 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -2323,7 +2323,7 @@ ExpEmit FxAssignSelf::Emit(VMFunctionBuilder *build) ExpEmit pointer = Assignment->Address; // FxAssign should have already emitted it if (!pointer.Target) { - ExpEmit out(build, ValueType->GetRegType()); + ExpEmit out(build, ValueType->GetRegType(), ValueType->GetRegCount()); if (Assignment->IsBitWrite != -1) { build->Emit(OP_LBIT, out.RegNum, pointer.RegNum, 1 << Assignment->IsBitWrite); diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index bc6e0ad43..3d7a9d3e1 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -294,6 +294,7 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(MF7, USEKILLSCRIPTS, AActor, flags7), DEFINE_FLAG(MF7, NOKILLSCRIPTS, AActor, flags7), DEFINE_FLAG(MF7, SPRITEANGLE, AActor, flags7), + DEFINE_FLAG(MF7, SMASHABLE, AActor, flags7), // Effect flags DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 2e7771680..6f25318d6 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -217,7 +217,7 @@ begin: reg.atag[a] = ATAG_GENERIC; NEXTOP; OP(LV2): - ASSERTF(a+2); ASSERTA(B); ASSERTKD(C); + ASSERTF(a+1); ASSERTA(B); ASSERTKD(C); GETADDR(PB,KC,X_READ_NIL); { auto v = (double *)ptr; @@ -226,7 +226,7 @@ begin: } NEXTOP; OP(LV2_R): - ASSERTF(a+2); ASSERTA(B); ASSERTD(C); + ASSERTF(a+1); ASSERTA(B); ASSERTD(C); GETADDR(PB,RC,X_READ_NIL); { auto v = (double *)ptr; @@ -331,7 +331,7 @@ begin: *(void **)ptr = reg.a[B]; NEXTOP; OP(SV2): - ASSERTA(a); ASSERTF(B+2); ASSERTKD(C); + ASSERTA(a); ASSERTF(B+1); ASSERTKD(C); GETADDR(PA,KC,X_WRITE_NIL); { auto v = (double *)ptr; @@ -340,7 +340,7 @@ begin: } NEXTOP; OP(SV2_R): - ASSERTA(a); ASSERTF(B+2); ASSERTD(C); + ASSERTA(a); ASSERTF(B+1); ASSERTD(C); GETADDR(PA,RC,X_WRITE_NIL); { auto v = (double *)ptr; diff --git a/src/virtual.h b/src/virtual.h index 4e0b3f01b..26fc694ea 100644 --- a/src/virtual.h +++ b/src/virtual.h @@ -39,6 +39,7 @@ VMEXPORTED_NATIVES_START VMEXPORTED_NATIVES_FUNC(Activate) VMEXPORTED_NATIVES_FUNC(Deactivate) VMEXPORTED_NATIVES_FUNC(DoSpecialDamage) + VMEXPORTED_NATIVES_FUNC(UseInventory) VMEXPORTED_NATIVES_END @@ -213,6 +214,26 @@ public: return retval; } } + bool UseInventory(AInventory *item) + { + if (this->ObjectFlags & OF_SuperCall) + { + this->ObjectFlags &= ~OF_SuperCall; + return ExportedNatives::Get()->template UseInventory(this, item); + } + else + { + VINDEX(AActor, UseInventory); + // Without the type cast this picks the 'void *' assignment... + VMValue params[2] = { (DObject*)this, (DObject*)item }; + VMReturn ret; + VMFrameStack stack; + int retval; + ret.IntAt(&retval); + stack.Call(VFUNC, params, 2, &ret, 1, nullptr); + return !!retval; + } + } }; @@ -245,6 +266,7 @@ VMEXPORT_NATIVES_START(AActor, DThinker) VMEXPORT_NATIVES_FUNC(Activate) VMEXPORT_NATIVES_FUNC(Deactivate) VMEXPORT_NATIVES_FUNC(DoSpecialDamage) + VMEXPORT_NATIVES_FUNC(UseInventory) VMEXPORT_NATIVES_END(AActor) /* diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index d2853ddb9..074bb8968 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -99,6 +99,7 @@ zscript/heretic/weaponstaff.txt zscript/heretic/weaponwand.txt zscript/heretic/weaponcrossbow.txt zscript/heretic/weapongauntlets.txt +zscript/heretic/weaponmace.txt zscript/hexen/baseweapons.txt zscript/hexen/korax.txt diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index f4489f575..0f0acc307 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -238,6 +238,7 @@ class Actor : Thinker native virtual native void Activate(Actor activator); virtual native void Deactivate(Actor activator); virtual native int DoSpecialDamage (Actor target, int damage, Name damagetype); + virtual native bool UseInventory(Inventory item); native void AdjustPlayerAngle(FTranslatedLineTarget t); native static readonly GetDefaultByType(class cls); @@ -247,6 +248,8 @@ class Actor : Thinker native native double GetBobOffset(double frac = 0); native void ClearCounters(); native bool GiveBody (int num, int max=0); + native bool HitFloor(); + native bool isTeammate(Actor other); native void RestoreDamage(); native int SpawnHealth(); diff --git a/wadsrc/static/zscript/heretic/hereticweaps.txt b/wadsrc/static/zscript/heretic/hereticweaps.txt index a6faf958f..07f993efe 100644 --- a/wadsrc/static/zscript/heretic/hereticweaps.txt +++ b/wadsrc/static/zscript/heretic/hereticweaps.txt @@ -7,210 +7,6 @@ class HereticWeapon : Weapon } } - - -// The mace itself ---------------------------------------------------------- - -class Mace : HereticWeapon -{ - Default - { - Weapon.SelectionOrder 1400; - Weapon.AmmoUse 1; - Weapon.AmmoGive1 50; - Weapon.YAdjust 15; - Weapon.AmmoType "MaceAmmo"; - Weapon.SisterWeapon "MacePowered"; - Inventory.PickupMessage "$TXT_WPNMACE"; - Tag "$TAG_MACE"; - } - - action native void A_FireMacePL1(); - - States - { - Spawn: - WMCE A -1; - Stop; - Ready: - MACE A 1 A_WeaponReady; - Loop; - Deselect: - MACE A 1 A_Lower; - Loop; - Select: - MACE A 1 A_Raise; - Loop; - Fire: - MACE B 4; - Hold: - MACE CDEF 3 A_FireMacePL1; - MACE C 4 A_ReFire; - MACE DEFB 4; - Goto Ready; - } -} - -class MacePowered : Mace -{ - Default - { - +WEAPON.POWERED_UP - Weapon.AmmoUse 5; - Weapon.AmmoGive 0; - Weapon.SisterWeapon "Mace"; - Tag "$TAG_MACEP"; - } - - action native void A_FireMacePL2(); - - States - { - Fire: - Hold: - MACE B 4; - MACE D 4 A_FireMacePL2; - MACE B 4; - MACE A 8 A_ReFire; - Goto Ready; - } -} - -// Mace FX1 ----------------------------------------------------------------- - -class MaceFX1 : Actor -{ - Default - { - Radius 8; - Height 6; - Speed 20; - Damage 2; - Projectile; - +THRUGHOST - BounceType "HereticCompat"; - SeeSound "weapons/maceshoot"; - Obituary "$OB_MPMACE"; - } - - native void A_MacePL1Check(); - native void A_MaceBallImpact(); - - States - { - Spawn: - FX02 AB 4 A_MacePL1Check; - Loop; - Death: - FX02 F 4 BRIGHT A_MaceBallImpact; - FX02 GHIJ 4 BRIGHT; - Stop; - } -} - -// Mace FX2 ----------------------------------------------------------------- - -class MaceFX2 : MaceFX1 -{ - Default - { - Speed 10; - Damage 6; - Gravity 0.125; - -NOGRAVITY - SeeSound ""; - } - - native void A_MaceBallImpact2(); - - States - { - Spawn: - FX02 CD 4; - Loop; - Death: - FX02 F 4 A_MaceBallImpact2; - goto Super::Death+1; - } -} - -// Mace FX3 ----------------------------------------------------------------- - -class MaceFX3 : MaceFX1 -{ - Default - { - Speed 7; - Damage 4; - -NOGRAVITY; - Gravity 0.125; - } - - States - { - Spawn: - FX02 AB 4; - Loop; - } -} - - -// Mace FX4 ----------------------------------------------------------------- - -class MaceFX4 : Actor native -{ - Default - { - Radius 8; - Height 6; - Speed 7; - Damage 18; - Gravity 0.125; - Projectile; - -NOGRAVITY - +TELESTOMP - +THRUGHOST - -NOTELEPORT - BounceType "HereticCompat"; - SeeSound ""; - Obituary "$OB_MPPMACE"; - } - - native void A_DeathBallImpact(); - - States - { - Spawn: - FX02 E 99; - Loop; - Death: - FX02 C 4 A_DeathBallImpact; - FX02 GHIJ 4 BRIGHT; - Stop; - } -} - - -// Mace spawn spot ---------------------------------------------------------- - -class MaceSpawner : SpecialSpot -{ - Default - { - +NOSECTOR - +NOBLOCKMAP - } - - States - { - Spawn: - TNT1 A 1; - TNT1 A -1 A_SpawnSingleItem("Mace", 64, 64, 0); - Stop; - } -} - - // Blaster ------------------------------------------------------------------ class Blaster : HereticWeapon diff --git a/wadsrc/static/zscript/heretic/weaponmace.txt b/wadsrc/static/zscript/heretic/weaponmace.txt new file mode 100644 index 000000000..fd11e685f --- /dev/null +++ b/wadsrc/static/zscript/heretic/weaponmace.txt @@ -0,0 +1,468 @@ +// The mace itself ---------------------------------------------------------- + +class Mace : HereticWeapon +{ + Default + { + Weapon.SelectionOrder 1400; + Weapon.AmmoUse 1; + Weapon.AmmoGive1 50; + Weapon.YAdjust 15; + Weapon.AmmoType "MaceAmmo"; + Weapon.SisterWeapon "MacePowered"; + Inventory.PickupMessage "$TXT_WPNMACE"; + Tag "$TAG_MACE"; + } + + States + { + Spawn: + WMCE A -1; + Stop; + Ready: + MACE A 1 A_WeaponReady; + Loop; + Deselect: + MACE A 1 A_Lower; + Loop; + Select: + MACE A 1 A_Raise; + Loop; + Fire: + MACE B 4; + Hold: + MACE CDEF 3 A_FireMacePL1; + MACE C 4 A_ReFire; + MACE DEFB 4; + Goto Ready; + } + + //---------------------------------------------------------------------------- + // + // PROC A_FireMacePL1 + // + //---------------------------------------------------------------------------- + + action void A_FireMacePL1() + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + + if (random[MaceAtk]() < 28) + { + Actor ball = Spawn("MaceFX2", Pos + (0, 0, 28 - Floorclip), ALLOW_REPLACE); + ball.Vel.Z = 2 - clamp(tan(pitch), -5, 5); + ball.target = self; + ball.angle = self.angle; + ball.AddZ(ball.Vel.Z); + ball.VelFromAngle(); + ball.Vel += Vel.xy / 2; + ball.A_PlaySound ("weapons/maceshoot", CHAN_BODY); + ball.CheckMissileSpawn (radius); + } + else + { + player.GetPSprite(PSP_WEAPON).x = ((random[MaceAtk]() & 3) - 2); + player.GetPSprite(PSP_WEAPON).y = WEAPONTOP + (random[MaceAtk]() & 3); + Actor ball = SpawnPlayerMissile("MaceFX1", angle + (((random[MaceAtk]() & 7) - 4) * (360. / 256))); + if (ball) + { + ball.special1 = 16; // tics till dropoff + } + } + } +} + +class MacePowered : Mace +{ + Default + { + +WEAPON.POWERED_UP + Weapon.AmmoUse 5; + Weapon.AmmoGive 0; + Weapon.SisterWeapon "Mace"; + Tag "$TAG_MACEP"; + } + + States + { + Fire: + Hold: + MACE B 4; + MACE D 4 A_FireMacePL2; + MACE B 4; + MACE A 8 A_ReFire; + Goto Ready; + } + + //---------------------------------------------------------------------------- + // + // PROC A_FireMacePL2 + // + //---------------------------------------------------------------------------- + + action void A_FireMacePL2() + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + Actor mo = SpawnPlayerMissile ("MaceFX4", angle, pLineTarget:t); + if (mo) + { + mo.Vel.xy += Vel.xy; + mo.Vel.Z = 2 - clamp(tan(pitch), -5, 5); + if (t.linetarget && !t.unlinked) + { + mo.tracer = t.linetarget; + } + } + A_PlaySound ("weapons/maceshoot", CHAN_WEAPON); + } +} + +// Mace FX1 ----------------------------------------------------------------- + +class MaceFX1 : Actor +{ + const MAGIC_JUNK = 1234; + + Default + { + Radius 8; + Height 6; + Speed 20; + Damage 2; + Projectile; + +THRUGHOST + BounceType "HereticCompat"; + SeeSound "weapons/maceshoot"; + Obituary "$OB_MPMACE"; + } + + States + { + Spawn: + FX02 AB 4 A_MacePL1Check; + Loop; + Death: + FX02 F 4 BRIGHT A_MaceBallImpact; + FX02 GHIJ 4 BRIGHT; + Stop; + } + + //---------------------------------------------------------------------------- + // + // PROC A_MacePL1Check + // + //---------------------------------------------------------------------------- + + void A_MacePL1Check() + { + if (special1 == 0) return; + special1 -= 4; + if (special1 > 0) return; + special1 = 0; + bNoGravity = false; + Gravity = 1. / 8; + // [RH] Avoid some precision loss by scaling the velocity directly + double velscale = 7 / Vel.XY.Length(); + Vel.XY *= velscale; + Vel.Z *= 0.5; + } + + //---------------------------------------------------------------------------- + // + // PROC A_MaceBallImpact + // + //---------------------------------------------------------------------------- + + void A_MaceBallImpact() + { + if ((health != MAGIC_JUNK) && bInFloat) + { // Bounce + health = MAGIC_JUNK; + Vel.Z *= 0.75; + bBounceOnFloors = bBounceOnCeilings = false; + SetState (SpawnState); + A_PlaySound ("weapons/macebounce", CHAN_BODY); + } + else + { // Explode + Vel = (0,0,0); + bNoGravity = true; + Gravity = 1; + A_PlaySound ("weapons/macehit", CHAN_BODY); + } + } +} + +// Mace FX2 ----------------------------------------------------------------- + +class MaceFX2 : MaceFX1 +{ + Default + { + Speed 10; + Damage 6; + Gravity 0.125; + -NOGRAVITY + SeeSound ""; + } + + States + { + Spawn: + FX02 CD 4; + Loop; + Death: + FX02 F 4 A_MaceBallImpact2; + goto Super::Death+1; + } + + //---------------------------------------------------------------------------- + // + // PROC A_MaceBallImpact2 + // + //---------------------------------------------------------------------------- + + void A_MaceBallImpact2() + { + if ((pos.Z <= floorz) && HitFloor ()) + { // Landed in some sort of liquid + Destroy (); + return; + } + if (bInFloat) + { + if (Vel.Z >= 2) + { + // Bounce + Vel.Z *= 0.75; + SetState (SpawnState); + + Actor tiny = Spawn("MaceFX3", Pos, ALLOW_REPLACE); + tiny.target = target; + tiny.angle = angle + 90.; + tiny.VelFromAngle(Vel.Z - 1.); + tiny.Vel += (Vel.XY * .5, Vel.Z); + tiny.CheckMissileSpawn (radius); + + tiny = Spawn("MaceFX3", Pos, ALLOW_REPLACE); + tiny.target = target; + tiny.angle = angle - 90.; + tiny.VelFromAngle(Vel.Z - 1.); + tiny.Vel += (Vel.XY * .5, Vel.Z); + tiny.CheckMissileSpawn (radius); + return; + } + } + Vel = (0,0,0); + bNoGravity = true; + bBounceOnFloors = bBounceOnCeilings = false; + Gravity = 1; + } +} + +// Mace FX3 ----------------------------------------------------------------- + +class MaceFX3 : MaceFX1 +{ + Default + { + Speed 7; + Damage 4; + -NOGRAVITY; + Gravity 0.125; + } + + States + { + Spawn: + FX02 AB 4; + Loop; + } +} + + +// Mace FX4 ----------------------------------------------------------------- + +class MaceFX4 : Actor +{ + Default + { + Radius 8; + Height 6; + Speed 7; + Damage 18; + Gravity 0.125; + Projectile; + -NOGRAVITY + +TELESTOMP + +THRUGHOST + -NOTELEPORT + BounceType "HereticCompat"; + SeeSound ""; + Obituary "$OB_MPPMACE"; + } + + States + { + Spawn: + FX02 E 99; + Loop; + Death: + FX02 C 4 A_DeathBallImpact; + FX02 GHIJ 4 BRIGHT; + Stop; + } + + //--------------------------------------------------------------------------- + // + // FUNC P_AutoUseChaosDevice + // + //--------------------------------------------------------------------------- + + private bool AutoUseChaosDevice (PlayerInfo player) + { + Inventory arti = player.mo.FindInventory("ArtiTeleport"); + + if (arti != null) + { + player.mo.UseInventory (arti); + player.health = player.mo.health = (player.health+1)/2; + return true; + } + return false; + } + + //---------------------------------------------------------------------------- + // + // PROC DoSpecialDamage + // + //---------------------------------------------------------------------------- + + override int DoSpecialDamage (Actor target, int damage, Name damagetype) + { + if (target.bBoss || target.bDontSquash || target.IsTeammate (self.target)) + { // Don't allow cheap boss kills and don't instagib teammates + return damage; + } + else if (target.player) + { // Player specific checks + if (target.player.mo.bInvulnerable) + { // Can't hurt invulnerable players + return -1; + } + if (AutoUseChaosDevice (target.player)) + { // Player was saved using chaos device + return -1; + } + } + return TELEFRAG_DAMAGE; // Something's gonna die + } + + //---------------------------------------------------------------------------- + // + // PROC A_DeathBallImpact + // + //---------------------------------------------------------------------------- + + void A_DeathBallImpact() + { + FTranslatedLineTarget t; + + if ((pos.Z <= floorz) && HitFloor ()) + { // Landed in some sort of liquid + Destroy (); + return; + } + if (bInFloat) + { + if (Vel.Z >= 2) + { + // Bounce + bool newAngle = false; + double ang = 0; + if (tracer) + { + if (!tracer.bShootable) + { // Target died + tracer = null; + } + else + { // Seek + ang = AngleTo(tracer); + newAngle = true; + } + } + else + { // Find new target + ang = 0.; + for (int i = 0; i < 16; i++) + { + AimLineAttack (ang, 640., t, 0., ALF_NOFRIENDS|ALF_PORTALRESTRICT, null, target); + if (t.linetarget && target != t.linetarget) + { + tracer = t.linetarget; + ang = t.angleFromSource; + newAngle = true; + break; + } + ang += 22.5; + } + } + if (newAngle) + { + angle = ang; + VelFromAngle(); + } + SetState (SpawnState); + A_PlaySound ("weapons/macestop", CHAN_BODY); + return; + } + } + Vel = (0,0,0); + bNoGravity = true; + Gravity = 1; + A_PlaySound ("weapons/maceexplode", CHAN_BODY); + } +} + + +// Mace spawn spot ---------------------------------------------------------- + +class MaceSpawner : SpecialSpot +{ + Default + { + +NOSECTOR + +NOBLOCKMAP + } + + States + { + Spawn: + TNT1 A 1; + TNT1 A -1 A_SpawnSingleItem("Mace", 64, 64, 0); + Stop; + } +} diff --git a/wadsrc/static/zscript/hexen/hexenspecialdecs.txt b/wadsrc/static/zscript/hexen/hexenspecialdecs.txt index 30ae0fff1..558ef8395 100644 --- a/wadsrc/static/zscript/hexen/hexenspecialdecs.txt +++ b/wadsrc/static/zscript/hexen/hexenspecialdecs.txt @@ -83,14 +83,14 @@ class TreeDestructible : Actor // Pottery1 ------------------------------------------------------------------ -class Pottery1 : Actor native +class Pottery1 : Actor { Default { Health 15; Speed 10; Height 32; - +SOLID +SHOOTABLE +NOBLOOD +DROPOFF + +SOLID +SHOOTABLE +NOBLOOD +DROPOFF +SMASHABLE +SLIDESONWALLS +PUSHABLE +TELESTOMP +CANPASS +NOICEDEATH } From 9ae272d753009808265fc66a15ebce3ed92de737 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 24 Nov 2016 20:02:44 +0100 Subject: [PATCH 102/185] - scriptified Heretic's blaster. - scriptified all Effect functions of Fastprojectile's children - implemented access to class meta data. - added a VM instruction to retrieve the class metadata, to eliminate the overhead of the function call that would otherwise be needed. - made GetClass() a builtin so that it can use the new instruction Important note about this commit: Scriptifying CFlameMissile::Effect revealed a problem with the virtual function interface: In order to work, this needs to be explicitly enabled for each single native class that may be used as a base for a scripted class. Needless to say, this will end up way too much work, as there are over 100 native classes, excluding those which will be scriptified. But in order to fix the problem this partially broken state needs to be committed first. --- src/dobject.cpp | 6 - src/g_heretic/a_hereticweaps.cpp | 127 --------- src/g_hexen/a_clericflame.cpp | 34 +-- src/g_shared/a_fastprojectile.cpp | 41 +-- src/g_shared/a_sharedglobal.h | 1 - src/info.cpp | 2 - src/info.h | 1 - src/namedef.h | 1 + src/p_mobj.cpp | 22 ++ src/scripting/codegeneration/codegen.cpp | 119 +++++--- src/scripting/codegeneration/codegen.h | 20 ++ src/scripting/vm/vmexec.cpp | 1 + src/scripting/vm/vmexec.h | 6 + src/scripting/vm/vmops.h | 1 + src/scripting/zscript/zcc_compile.cpp | 11 +- wadsrc/static/zscript.txt | 2 + wadsrc/static/zscript/actor.txt | 23 ++ wadsrc/static/zscript/base.txt | 1 - .../static/zscript/heretic/hereticweaps.txt | 173 ------------ .../static/zscript/heretic/weaponblaster.txt | 259 ++++++++++++++++++ wadsrc/static/zscript/hexen/clericflame.txt | 26 +- .../static/zscript/shared/fastprojectile.txt | 41 +++ wadsrc/static/zscript/shared/sharedmisc.txt | 11 - 23 files changed, 499 insertions(+), 430 deletions(-) create mode 100644 wadsrc/static/zscript/heretic/weaponblaster.txt create mode 100644 wadsrc/static/zscript/shared/fastprojectile.txt diff --git a/src/dobject.cpp b/src/dobject.cpp index e3e37432b..849f6a477 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -363,12 +363,6 @@ DEFINE_ACTION_FUNCTION(DObject, Destroy) return 0; } -DEFINE_ACTION_FUNCTION(DObject, GetClass) -{ - PARAM_SELF_PROLOGUE(DObject); - ACTION_RETURN_OBJECT(self->GetClass()); -} - //========================================================================== // // diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp index cc964ecc0..3b2711e24 100644 --- a/src/g_heretic/a_hereticweaps.cpp +++ b/src/g_heretic/a_hereticweaps.cpp @@ -46,133 +46,6 @@ void P_DSparilTeleport (AActor *actor); extern bool P_AutoUseChaosDevice (player_t *player); -// Blaster FX 1 ------------------------------------------------------------- - -//---------------------------------------------------------------------------- -// -// Thinker for the ultra-fast blaster PL2 ripper-spawning missile. -// -//---------------------------------------------------------------------------- - -class ABlasterFX1 : public AFastProjectile -{ - DECLARE_CLASS(ABlasterFX1, AFastProjectile) -public: - void Effect (); - int DoSpecialDamage (AActor *target, int damage, FName damagetype); -}; - -int ABlasterFX1::DoSpecialDamage (AActor *target, int damage, FName damagetype) -{ - if (target->IsKindOf (PClass::FindClass ("Ironlich"))) - { // Less damage to Ironlich bosses - damage = pr_bfx1() & 1; - if (!damage) - { - return -1; - } - } - return damage; -} - -void ABlasterFX1::Effect () -{ - if (pr_bfx1t() < 64) - { - Spawn("BlasterSmoke", PosAtZ(MAX(Z() - 8., floorz)), ALLOW_REPLACE); - } -} - -IMPLEMENT_CLASS(ABlasterFX1, false, false, false, false) - -// Ripper ------------------------------------------------------------------- - - -class ARipper : public AActor -{ - DECLARE_CLASS (ARipper, AActor) -public: - int DoSpecialDamage (AActor *target, int damage, FName damagetype); -}; - -IMPLEMENT_CLASS(ARipper, false, false, false, false) - -int ARipper::DoSpecialDamage (AActor *target, int damage, FName damagetype) -{ - if (target->IsKindOf (PClass::FindClass ("Ironlich"))) - { // Less damage to Ironlich bosses - damage = pr_ripd() & 1; - if (!damage) - { - return -1; - } - } - return damage; -} - -//---------------------------------------------------------------------------- -// -// PROC A_FireBlasterPL1 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_FireBlasterPL1) -{ - PARAM_ACTION_PROLOGUE(AActor); - - DAngle ang; - int damage; - player_t *player; - - if (NULL == (player = self->player)) - { - return 0; - } - - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - DAngle pitch = P_BulletSlope(self); - damage = pr_fb1.HitDice (4); - ang = self->Angles.Yaw; - if (player->refire) - { - ang += pr_fb1.Random2() * (5.625 / 256); - } - P_LineAttack (self, ang, PLAYERMISSILERANGE, pitch, damage, NAME_Hitscan, "BlasterPuff"); - S_Sound (self, CHAN_WEAPON, "weapons/blastershoot", 1, ATTN_NORM); - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_SpawnRippers -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_SpawnRippers) -{ - PARAM_SELF_PROLOGUE(AActor); - - unsigned int i; - DAngle ang; - AActor *ripper; - - for(i = 0; i < 8; i++) - { - ripper = Spawn (self->Pos(), ALLOW_REPLACE); - ang = i*45.; - ripper->target = self->target; - ripper->Angles.Yaw = ang; - ripper->VelFromAngle(); - P_CheckMissileSpawn (ripper, self->radius); - } - return 0; -} - // --- Skull rod ------------------------------------------------------------ diff --git a/src/g_hexen/a_clericflame.cpp b/src/g_hexen/a_clericflame.cpp index 2c66cb42d..d4f86ecd5 100644 --- a/src/g_hexen/a_clericflame.cpp +++ b/src/g_hexen/a_clericflame.cpp @@ -25,38 +25,6 @@ void A_CFlameMissile (AActor *); // Flame Missile ------------------------------------------------------------ -class ACFlameMissile : public AFastProjectile -{ - DECLARE_CLASS (ACFlameMissile, AFastProjectile) -public: - void BeginPlay (); - void Effect (); -}; - -IMPLEMENT_CLASS(ACFlameMissile, false, false, false, false) - -void ACFlameMissile::BeginPlay () -{ - special1 = 2; -} - -void ACFlameMissile::Effect () -{ - if (!--special1) - { - special1 = 4; - double newz = Z() - 12; - if (newz < floorz) - { - newz = floorz; - } - AActor *mo = Spawn ("CFlameFloor", PosAtZ(newz), ALLOW_REPLACE); - if (mo) - { - mo->Angles.Yaw = Angles.Yaw; - } - } -} //============================================================================ // @@ -80,7 +48,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CFlameAttack) if (!weapon->DepleteAmmo (weapon->bAltFire)) return 0; } - P_SpawnPlayerMissile (self, RUNTIME_CLASS(ACFlameMissile)); + P_SpawnPlayerMissile (self, PClass::FindActor("CFlameMissile")); S_Sound (self, CHAN_WEAPON, "ClericFlameFire", 1, ATTN_NORM); return 0; } diff --git a/src/g_shared/a_fastprojectile.cpp b/src/g_shared/a_fastprojectile.cpp index ffca8a8fa..1ded466a9 100644 --- a/src/g_shared/a_fastprojectile.cpp +++ b/src/g_shared/a_fastprojectile.cpp @@ -6,6 +6,7 @@ #include "p_lnspec.h" #include "b_bot.h" #include "p_checkposition.h" +#include "virtual.h" IMPLEMENT_CLASS(AFastProjectile, false, false, false, false) @@ -132,7 +133,13 @@ void AFastProjectile::Tick () if (!frac.isZero() && ripcount <= 0) { ripcount = count >> 3; - Effect(); + + // call the scripted 'Effect' method. + VINDEX(AFastProjectile, Effect); + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { (DObject*)this }; + VMFrameStack stack; + stack.Call(VFUNC, params, 1, nullptr, 0, nullptr); } } } @@ -153,35 +160,3 @@ void AFastProjectile::Tick () } -void AFastProjectile::Effect() -{ - FName name = GetClass()->MissileName; - if (name != NAME_None) - { - double hitz = Z()-8; - - if (hitz < floorz) - { - hitz = floorz; - } - // Do not clip this offset to the floor. - hitz += GetClass()->MissileHeight; - - PClassActor *trail = PClass::FindActor(name); - if (trail != NULL) - { - AActor *act = Spawn (trail, PosAtZ(hitz), ALLOW_REPLACE); - if (act != nullptr) - { - if ((flags5 & MF5_GETOWNER) && (target != nullptr)) - act->target = target; - else - act->target = this; - - act->Angles.Pitch = Angles.Pitch; - act->Angles.Yaw = Angles.Yaw; - } - } - } -} - diff --git a/src/g_shared/a_sharedglobal.h b/src/g_shared/a_sharedglobal.h index 6911c6688..bb85a023c 100644 --- a/src/g_shared/a_sharedglobal.h +++ b/src/g_shared/a_sharedglobal.h @@ -228,7 +228,6 @@ class AFastProjectile : public AActor DECLARE_CLASS(AFastProjectile, AActor) public: void Tick (); - virtual void Effect(); }; diff --git a/src/info.cpp b/src/info.cpp index 8ef594d1b..fec5af63e 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -230,7 +230,6 @@ PClassActor::PClassActor() BurnHeight = -1; GibHealth = INT_MIN; WoundHealth = 6; - PoisonDamage = 0; FastSpeed = -1.; RDFactor = 1.; CameraHeight = INT_MIN; @@ -291,7 +290,6 @@ void PClassActor::DeriveData(PClass *newclass) newa->BloodColor = BloodColor; newa->GibHealth = GibHealth; newa->WoundHealth = WoundHealth; - newa->PoisonDamage = PoisonDamage; newa->FastSpeed = FastSpeed; newa->RDFactor = RDFactor; newa->CameraHeight = CameraHeight; diff --git a/src/info.h b/src/info.h index a41a6def8..bb21524a5 100644 --- a/src/info.h +++ b/src/info.h @@ -296,7 +296,6 @@ public: 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 double FastSpeed; // speed in fast mode double RDFactor; // Radius damage factor double CameraHeight; // Height of camera when used as such diff --git a/src/namedef.h b/src/namedef.h index 639c762eb..b7365b2b2 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -285,6 +285,7 @@ xx(FRandom) xx(Random2) xx(RandomPick) xx(FRandomPick) +xx(GetClass) xx(Exp) xx(Log10) xx(Ceil) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 46ecbd3fa..3c8d1173b 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -310,6 +310,28 @@ DEFINE_FIELD(AActor, ConversationRoot) DEFINE_FIELD(AActor, Conversation) DEFINE_FIELD(AActor, DecalGenerator) +DEFINE_FIELD(PClassActor, Obituary) +DEFINE_FIELD(PClassActor, HitObituary) +DEFINE_FIELD(PClassActor, DeathHeight) +DEFINE_FIELD(PClassActor, BurnHeight) +DEFINE_FIELD(PClassActor, BloodColor) +DEFINE_FIELD(PClassActor, GibHealth) +DEFINE_FIELD(PClassActor, WoundHealth) +DEFINE_FIELD(PClassActor, FastSpeed) +DEFINE_FIELD(PClassActor, RDFactor) +DEFINE_FIELD(PClassActor, CameraHeight) +DEFINE_FIELD(PClassActor, HowlSound) +DEFINE_FIELD(PClassActor, BloodType) +DEFINE_FIELD(PClassActor, BloodType2) +DEFINE_FIELD(PClassActor, BloodType3) +DEFINE_FIELD(PClassActor, DontHurtShooter) +DEFINE_FIELD(PClassActor, ExplosionRadius) +DEFINE_FIELD(PClassActor, ExplosionDamage) +DEFINE_FIELD(PClassActor, MeleeDamage) +DEFINE_FIELD(PClassActor, MeleeSound) +DEFINE_FIELD(PClassActor, MissileName) +DEFINE_FIELD(PClassActor, MissileHeight) + //========================================================================== // // AActor :: Serialize diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 4bf6f076e..b7e20f7fc 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -5637,12 +5637,6 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PStruct *classct return nullptr; } - if (vsym->Flags & VARF_Static) - { - // todo. For now these cannot be defined so let's just exit. - ScriptPosition.Message(MSG_ERROR, "Static members not implemented yet."); - return nullptr; - } auto x = isclass ? new FxClassMember(object, vsym, ScriptPosition) : new FxStructMember(object, vsym, ScriptPosition); object = nullptr; return x->Resolve(ctx); @@ -5918,40 +5912,14 @@ FxExpression *FxClassDefaults::Resolve(FCompileContext& ctx) // //========================================================================== -int BuiltinGetDefault(VMFrameStack *stack, VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret) -{ - assert(numparam == 1); - PARAM_POINTER_AT(0, obj, DObject); - ACTION_RETURN_OBJECT(obj->GetClass()->Defaults); -} - -//========================================================================== -// -// -// -//========================================================================== - ExpEmit FxClassDefaults::Emit(VMFunctionBuilder *build) { - EmitParameter(build, obj, ScriptPosition); - PSymbol *sym = FindBuiltinFunction(NAME_BuiltinGetDefault, BuiltinGetDefault); - - assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); - assert(((PSymbolVMFunction *)sym)->Function != nullptr); - auto callfunc = ((PSymbolVMFunction *)sym)->Function; - int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); - build->Emit(opcode, build->GetConstantAddress(callfunc, ATAG_OBJECT), 1, 1); - - if (EmitTail) - { - ExpEmit call; - call.Final = true; - return call; - } - - ExpEmit out(build, REGT_POINTER); - build->Emit(OP_RESULT, 0, REGT_POINTER, out.RegNum); - return out; + ExpEmit ob = obj->Emit(build); + ob.Free(build); + ExpEmit meta(build, REGT_POINTER); + build->Emit(OP_META, meta.RegNum, ob.RegNum); + build->Emit(OP_LO, meta.RegNum, meta.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults))); + return meta; } @@ -6272,6 +6240,11 @@ FxStructMember::~FxStructMember() bool FxStructMember::RequestAddress(FCompileContext &ctx, bool *writable) { + // Cannot take the address of metadata variables. + if (membervar->Flags & VARF_Static) + { + return false; + } AddressRequested = true; if (writable != nullptr) *writable = (AddressWritable && !ctx.CheckReadOnly(membervar->Flags) && (!classx->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) || !static_cast(classx->ValueType)->IsConst)); @@ -6411,6 +6384,14 @@ ExpEmit FxStructMember::Emit(VMFunctionBuilder *build) obj = newobj; } + if (membervar->Flags & VARF_Static) + { + obj.Free(build); + ExpEmit meta(build, REGT_POINTER); + build->Emit(OP_META, meta.RegNum, obj.RegNum); + obj = meta; + } + if (AddressRequested) { if (membervar->Offset == 0) @@ -6953,6 +6934,13 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) } break; + case NAME_GetClass: + if (CheckArgSize(NAME_GetClass, ArgList, 0, 0, ScriptPosition)) + { + func = new FxGetClass(new FxSelf(ScriptPosition)); + } + break; + case NAME_Random: // allow calling Random without arguments to default to (0, 255) if (ArgList.Size() == 0) @@ -7132,6 +7120,12 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) // handle builtins: Vectors got 2: Length and Unit. if (MethodName == NAME_Length || MethodName == NAME_Unit) { + if (ArgList.Size() > 0) + { + ScriptPosition.Message(MSG_ERROR, "too many parameters in call to %s", MethodName.GetChars()); + delete this; + return nullptr; + } auto x = new FxVectorBuiltin(Self, MethodName); Self = nullptr; delete this; @@ -7144,6 +7138,17 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) auto ptype = static_cast(Self->ValueType)->PointedType; if (ptype->IsKindOf(RUNTIME_CLASS(PStruct))) { + if (ptype->IsKindOf(RUNTIME_CLASS(PClass)) && MethodName == NAME_GetClass) + { + if (ArgList.Size() > 0) + { + ScriptPosition.Message(MSG_ERROR, "too many parameters in call to %s", MethodName.GetChars()); + delete this; + return nullptr; + } + auto x = new FxGetClass(Self); + return x->Resolve(ctx); + } cls = static_cast(ptype); } else @@ -7976,6 +7981,44 @@ ExpEmit FxVectorBuiltin::Emit(VMFunctionBuilder *build) return to; } +//========================================================================== +// +// +//========================================================================== + +FxGetClass::FxGetClass(FxExpression *self) + :FxExpression(EFX_GetClass, self->ScriptPosition) +{ + Self = self; +} + +FxGetClass::~FxGetClass() +{ + SAFE_DELETE(Self); +} + +FxExpression *FxGetClass::Resolve(FCompileContext &ctx) +{ + SAFE_RESOLVE(Self, ctx); + if (!Self->IsObject()) + { + ScriptPosition.Message(MSG_ERROR, "GetClass() requires an object"); + delete this; + return nullptr; + } + ValueType = NewClassPointer(static_cast(static_cast(Self->ValueType)->PointedType)); + return this; +} + +ExpEmit FxGetClass::Emit(VMFunctionBuilder *build) +{ + ExpEmit op = Self->Emit(build); + op.Free(build); + ExpEmit to(build, REGT_POINTER); + build->Emit(OP_META, to.RegNum, op.RegNum); + return to; +} + //========================================================================== // // FxSequence :: Resolve diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index f004e469a..d7547a198 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -286,6 +286,7 @@ enum EFxType EFX_StaticArrayVariable, EFX_CVar, EFX_NamedNode, + EFX_GetClass, EFX_COUNT }; @@ -320,6 +321,7 @@ public: bool IsPointer() const { return ValueType->GetRegType() == REGT_POINTER; } bool IsVector() const { return ValueType == TypeVector2 || ValueType == TypeVector3; }; bool IsBoolCompat() const { return ValueType->GetRegCount() == 1 && (ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT || ValueType->GetRegType() == REGT_POINTER); } + bool IsObject() const { return ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && !ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) && ValueType != TypeNullPtr && static_cast(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass)); } virtual ExpEmit Emit(VMFunctionBuilder *build); @@ -1520,6 +1522,24 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// FxFlopFunctionCall +// +//========================================================================== + +class FxGetClass : public FxExpression +{ + FxExpression *Self; + +public: + + FxGetClass(FxExpression *self); + ~FxGetClass(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxVMFunctionCall diff --git a/src/scripting/vm/vmexec.cpp b/src/scripting/vm/vmexec.cpp index 24beb7f9c..750c384e0 100644 --- a/src/scripting/vm/vmexec.cpp +++ b/src/scripting/vm/vmexec.cpp @@ -75,6 +75,7 @@ #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 ASSERTO(x) assert((unsigned)(x) < f->NumRegA && reg.atag[x] == ATAG_OBJECT) #define ASSERTKD(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstD) #define ASSERTKF(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstF) diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 6f25318d6..4df76a73e 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -110,6 +110,12 @@ begin: reg.atag[a] = ATAG_GENERIC; // using ATAG_FRAMEPOINTER will cause endless asserts. NEXTOP; + OP(META): + ASSERTA(a); ASSERTO(B); + reg.a[a] = ((DObject*)reg.a[B])->GetClass(); // I wish this could be done without a special opcode but there's really no good way to guarantee initialization of the Class pointer... + reg.atag[a] = ATAG_OBJECT; + NEXTOP; + OP(LB): ASSERTD(a); ASSERTA(B); ASSERTKD(C); GETADDR(PB,KC,X_READ_NIL); diff --git a/src/scripting/vm/vmops.h b/src/scripting/vm/vmops.h index cf2a75746..b36f93881 100644 --- a/src/scripting/vm/vmops.h +++ b/src/scripting/vm/vmops.h @@ -23,6 +23,7 @@ xx(LKF_R, lk, RFRII8, NOP, 0, 0), // load float constant indexed xx(LKS_R, lk, RSRII8, NOP, 0, 0), // load string constant indexed xx(LKP_R, lk, RPRII8, NOP, 0, 0), // load pointer constant indexed xx(LFP, lf, LFP, NOP, 0, 0), // load frame pointer +xx(META, meta, RPRP, NOP, 0, 0), // load a class's meta class address // Load from memory. rA = *(rB + rkC) xx(LB, lb, RIRPKI, LB_R, 4, REGT_INT), // load byte diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 3437c848c..a4a2cc453 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1298,8 +1298,12 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray &Fiel if (field->Flags & ZCC_Meta) { - varflags |= VARF_ReadOnly; // metadata implies readonly - // todo: this needs to go into the metaclass and needs some handling + varflags |= VARF_Static|VARF_ReadOnly; // metadata implies readonly + if (!(field->Flags & ZCC_Native)) + { + // Non-native meta data is not implemented yet and requires some groundwork in the class copy code. + Error(field, "Metadata member %s must be native", FName(field->Names->Name).GetChars()); + } } if (field->Type->ArraySize != nullptr) @@ -1320,7 +1324,8 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray &Fiel if (varflags & VARF_Native) { - fd = FindField(type, FName(name->Name).GetChars()); + auto querytype = (varflags & VARF_Static) ? type->GetClass() : type; + fd = FindField(querytype, FName(name->Name).GetChars()); if (fd == nullptr) { Error(field, "The member variable '%s.%s' has not been exported from the executable.", type->TypeName.GetChars(), FName(name->Name).GetChars()); diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 074bb8968..3507e45a8 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -31,6 +31,7 @@ zscript/shared/setcolor.txt zscript/shared/sectoraction.txt zscript/shared/ice.txt zscript/shared/dog.txt +zscript/shared/fastprojectile.txt zscript/doom/doomplayer.txt zscript/doom/possessed.txt @@ -100,6 +101,7 @@ zscript/heretic/weaponwand.txt zscript/heretic/weaponcrossbow.txt zscript/heretic/weapongauntlets.txt zscript/heretic/weaponmace.txt +zscript/heretic/weaponblaster.txt zscript/hexen/baseweapons.txt zscript/hexen/korax.txt diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 0f0acc307..3eb855007 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -145,6 +145,29 @@ class Actor : Thinker native native readonly State SeeState; native State MeleeState; native State MissileState; + + native meta String Obituary; // Player was killed by this actor + native meta String HitObituary; // Player was killed by this actor in melee + native meta double DeathHeight; // Height on normal death + native meta double BurnHeight; // Height on burning death + native meta color BloodColor; // Colorized blood + native meta int GibHealth; // Negative health below which this monster dies an extreme death + native meta int WoundHealth; // Health needed to enter wound state + native meta double FastSpeed; // speed in fast mode + native meta double RDFactor; // Radius damage factor + native meta double CameraHeight; // Height of camera when used as such + native meta Sound HowlSound; // Sound being played when electrocuted or poisoned + native meta Name BloodType; // Blood replacement type + native meta Name BloodType2; // Bloopsplatter replacement type + native meta Name BloodType3; // AxeBlood replacement type + native meta bool DontHurtShooter; + native meta int ExplosionRadius; + native meta int ExplosionDamage; + native meta int MeleeDamage; + native meta Sound MeleeSound; + native meta Name MissileName; + native meta double MissileHeight; + // need some definition work first //FRenderStyle RenderStyle; diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index a63020bbf..c899bbd37 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -7,7 +7,6 @@ class Object native native static double G_SkillPropertyFloat(int p); virtual native void Destroy(); - native class GetClass(); } class Thinker : Object native diff --git a/wadsrc/static/zscript/heretic/hereticweaps.txt b/wadsrc/static/zscript/heretic/hereticweaps.txt index 07f993efe..c3c641b4e 100644 --- a/wadsrc/static/zscript/heretic/hereticweaps.txt +++ b/wadsrc/static/zscript/heretic/hereticweaps.txt @@ -7,179 +7,6 @@ class HereticWeapon : Weapon } } -// Blaster ------------------------------------------------------------------ - -class Blaster : HereticWeapon -{ - Default - { - +BLOODSPLATTER - Weapon.SelectionOrder 500; - Weapon.AmmoUse 1; - Weapon.AmmoGive 30; - Weapon.YAdjust 15; - Weapon.AmmoType "BlasterAmmo"; - Weapon.SisterWeapon "BlasterPowered"; - Inventory.PickupMessage "$TXT_WPNBLASTER"; - Tag "$TAG_BLASTER"; - Obituary "$OB_MPBLASTER"; - } - - action native void A_FireBlasterPL1(); - - States - { - Spawn: - WBLS A -1; - Stop; - Ready: - BLSR A 1 A_WeaponReady; - Loop; - Deselect: - BLSR A 1 A_Lower; - Loop; - Select: - BLSR A 1 A_Raise; - Loop; - Fire: - BLSR BC 3; - Hold: - BLSR D 2 A_FireBlasterPL1; - BLSR CB 2; - BLSR A 0 A_ReFire; - Goto Ready; - } -} - -class BlasterPowered : Blaster -{ - Default - { - +WEAPON.POWERED_UP - Weapon.AmmoUse 5; - Weapon.AmmoGive 0; - Weapon.SisterWeapon "Blaster"; - Tag "$TAG_BLASTERP"; - } - - States - { - Fire: - BLSR BC 0; - Hold: - BLSR D 3 A_FireCustomMissile("BlasterFX1"); - BLSR CB 4; - BLSR A 0 A_ReFire; - Goto Ready; - } -} - -// Blaster FX 1 ------------------------------------------------------------- - -class BlasterFX1 : FastProjectile native -{ - Default - { - Radius 12; - Height 8; - Speed 184; - Damage 2; - SeeSound "weapons/blastershoot"; - DeathSound "weapons/blasterhit"; - +SPAWNSOUNDSOURCE - Obituary "$OB_MPPBLASTER"; - } - - native void A_SpawnRippers(); - - States - { - Spawn: - ACLO E 200; - Loop; - Death: - FX18 A 3 BRIGHT A_SpawnRippers; - FX18 B 3 BRIGHT; - FX18 CDEFG 4 BRIGHT; - Stop; - } -} - -// Blaster smoke ------------------------------------------------------------ - -class BlasterSmoke : Actor -{ - Default - { - +NOBLOCKMAP - +NOGRAVITY - +NOTELEPORT - +CANNOTPUSH - RenderStyle "Translucent"; - Alpha 0.4; - } - - States - { - Spawn: - FX18 HIJKL 4; - Stop; - } -} - -// Ripper ------------------------------------------------------------------- - -class Ripper : Actor native -{ - Default - { - Radius 8; - Height 6; - Speed 14; - Damage 1; - Projectile; - +RIPPER - DeathSound "weapons/blasterpowhit"; - Obituary "$OB_MPPBLASTER"; - } - - States - { - Spawn: - FX18 M 4; - FX18 N 5; - Loop; - Death: - FX18 OPQRS 4 BRIGHT; - Stop; - } -} - -// Blaster Puff ------------------------------------------------------------- - -class BlasterPuff : Actor -{ - Default - { - +NOBLOCKMAP - +NOGRAVITY - +PUFFONACTORS - RenderStyle "Add"; - SeeSound "weapons/blasterhit"; - } - - States - { - Crash: - FX17 ABCDE 4 BRIGHT; - Stop; - Spawn: - FX17 FG 3 BRIGHT; - FX17 HIJKL 4 BRIGHT; - Stop; - } -} - // Skull (Horn) Rod --------------------------------------------------------- diff --git a/wadsrc/static/zscript/heretic/weaponblaster.txt b/wadsrc/static/zscript/heretic/weaponblaster.txt new file mode 100644 index 000000000..8f4756b5b --- /dev/null +++ b/wadsrc/static/zscript/heretic/weaponblaster.txt @@ -0,0 +1,259 @@ +// Blaster ------------------------------------------------------------------ + +class Blaster : HereticWeapon +{ + Default + { + +BLOODSPLATTER + Weapon.SelectionOrder 500; + Weapon.AmmoUse 1; + Weapon.AmmoGive 30; + Weapon.YAdjust 15; + Weapon.AmmoType "BlasterAmmo"; + Weapon.SisterWeapon "BlasterPowered"; + Inventory.PickupMessage "$TXT_WPNBLASTER"; + Tag "$TAG_BLASTER"; + Obituary "$OB_MPBLASTER"; + } + + States + { + Spawn: + WBLS A -1; + Stop; + Ready: + BLSR A 1 A_WeaponReady; + Loop; + Deselect: + BLSR A 1 A_Lower; + Loop; + Select: + BLSR A 1 A_Raise; + Loop; + Fire: + BLSR BC 3; + Hold: + BLSR D 2 A_FireBlasterPL1; + BLSR CB 2; + BLSR A 0 A_ReFire; + Goto Ready; + } + + //---------------------------------------------------------------------------- + // + // PROC A_FireBlasterPL1 + // + //---------------------------------------------------------------------------- + + action void A_FireBlasterPL1() + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + + double pitch = BulletSlope(); + int damage = random[FireBlaster](1, 8) * 4; + double ang = angle; + if (player.refire) + { + ang += Random2[FireBlaster]() * (5.625 / 256); + } + LineAttack (ang, PLAYERMISSILERANGE, pitch, damage, 'Hitscan', "BlasterPuff"); + A_PlaySound ("weapons/blastershoot", CHAN_WEAPON); + } +} + +class BlasterPowered : Blaster +{ + Default + { + +WEAPON.POWERED_UP + Weapon.AmmoUse 5; + Weapon.AmmoGive 0; + Weapon.SisterWeapon "Blaster"; + Tag "$TAG_BLASTERP"; + } + + States + { + Fire: + BLSR BC 0; + Hold: + BLSR D 3 A_FireCustomMissile("BlasterFX1"); + BLSR CB 4; + BLSR A 0 A_ReFire; + Goto Ready; + } +} + +// Blaster FX 1 ------------------------------------------------------------- + +class BlasterFX1 : FastProjectile +{ + Default + { + Radius 12; + Height 8; + Speed 184; + Damage 2; + SeeSound "weapons/blastershoot"; + DeathSound "weapons/blasterhit"; + +SPAWNSOUNDSOURCE + Obituary "$OB_MPPBLASTER"; + } + + States + { + Spawn: + ACLO E 200; + Loop; + Death: + FX18 A 3 BRIGHT A_SpawnRippers; + FX18 B 3 BRIGHT; + FX18 CDEFG 4 BRIGHT; + Stop; + } + + //---------------------------------------------------------------------------- + // + // + // + //---------------------------------------------------------------------------- + + override int DoSpecialDamage (Actor target, int damage, Name damagetype) + { + if (target is "Ironlich") + { // Less damage to Ironlich bosses + damage = random[BlasterFX]() & 1; + if (!damage) + { + return -1; + } + } + return damage; + } + + override void Effect () + { + if (random[BlasterFX]() < 64) + { + Spawn("BlasterSmoke", (pos.xy, max(pos.z - 8, floorz)), ALLOW_REPLACE); + } + } + + //---------------------------------------------------------------------------- + // + // PROC A_SpawnRippers + // + //---------------------------------------------------------------------------- + + void A_SpawnRippers() + { + for(int i = 0; i < 8; i++) + { + Actor ripper = Spawn("Ripper", pos, ALLOW_REPLACE); + ripper.target = target; + ripper.angle = i*45; + ripper.VelFromAngle(); + ripper.CheckMissileSpawn (radius); + } + } +} + +// Blaster smoke ------------------------------------------------------------ + +class BlasterSmoke : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + +NOTELEPORT + +CANNOTPUSH + RenderStyle "Translucent"; + Alpha 0.4; + } + + States + { + Spawn: + FX18 HIJKL 4; + Stop; + } +} + +// Ripper ------------------------------------------------------------------- + +class Ripper : Actor +{ + Default + { + Radius 8; + Height 6; + Speed 14; + Damage 1; + Projectile; + +RIPPER + DeathSound "weapons/blasterpowhit"; + Obituary "$OB_MPPBLASTER"; + } + + States + { + Spawn: + FX18 M 4; + FX18 N 5; + Loop; + Death: + FX18 OPQRS 4 BRIGHT; + Stop; + } + + int DoSpecialDamage (Actor target, int damage, Name damagetype) + { + if (target is "Ironlich") + { // Less damage to Ironlich bosses + damage = random[Ripper]() & 1; + if (!damage) + { + return -1; + } + } + return damage; + } + +} + +// Blaster Puff ------------------------------------------------------------- + +class BlasterPuff : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + +PUFFONACTORS + RenderStyle "Add"; + SeeSound "weapons/blasterhit"; + } + + States + { + Crash: + FX17 ABCDE 4 BRIGHT; + Stop; + Spawn: + FX17 FG 3 BRIGHT; + FX17 HIJKL 4 BRIGHT; + Stop; + } +} + diff --git a/wadsrc/static/zscript/hexen/clericflame.txt b/wadsrc/static/zscript/hexen/clericflame.txt index 13fca8ad1..37e4149f9 100644 --- a/wadsrc/static/zscript/hexen/clericflame.txt +++ b/wadsrc/static/zscript/hexen/clericflame.txt @@ -170,7 +170,7 @@ class CircleFlame : Actor // Flame Missile ------------------------------------------------------------ -class CFlameMissile : FastProjectile native +class CFlameMissile : FastProjectile { Default { @@ -208,4 +208,28 @@ class CFlameMissile : FastProjectile native CFFX M 3 Bright; Stop; } + + override void BeginPlay () + { + special1 = 2; + } + + override void Effect () + { + if (!--special1) + { + special1 = 4; + double newz = pos.z - 12; + if (newz < floorz) + { + newz = floorz; + } + Actor mo = Spawn ("CFlameFloor", (pos.xy, newz), ALLOW_REPLACE); + if (mo) + { + mo.angle = angle; + } + } + } + } diff --git a/wadsrc/static/zscript/shared/fastprojectile.txt b/wadsrc/static/zscript/shared/fastprojectile.txt new file mode 100644 index 000000000..b1d509073 --- /dev/null +++ b/wadsrc/static/zscript/shared/fastprojectile.txt @@ -0,0 +1,41 @@ +// Fast projectiles -------------------------------------------------------- + +class FastProjectile : Actor native +{ + Default + { + Projectile; + MissileHeight 0; + } + + + virtual void Effect() + { + class trail = MissileName; + if (trail != null) + { + double hitz = pos.z - 8; + + if (hitz < floorz) + { + hitz = floorz; + } + // Do not clip this offset to the floor. + hitz += MissileHeight; + + Actor act = Spawn (trail, (pos.xy, hitz), ALLOW_REPLACE); + if (act != null) + { + if (bGetOwner && target != null) + act.target = target; + else + act.target = self; + + act.angle = angle; + act.pitch = pitch; + } + } + } + +} + diff --git a/wadsrc/static/zscript/shared/sharedmisc.txt b/wadsrc/static/zscript/shared/sharedmisc.txt index bebf28549..5989702fd 100644 --- a/wadsrc/static/zscript/shared/sharedmisc.txt +++ b/wadsrc/static/zscript/shared/sharedmisc.txt @@ -179,17 +179,6 @@ class RandomSpawner : Actor native } } -// Fast projectiles -------------------------------------------------------- - -class FastProjectile : Actor native -{ - Default - { - Projectile; - MissileHeight 0; - } -} - // Sector flag setter ------------------------------------------------------ class SectorFlagSetter : Actor native From 66d28a24b88471162be0a7201fe2693fe9ab771b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 24 Nov 2016 21:36:02 +0100 Subject: [PATCH 103/185] - disabled the scripted virtual function module after finding out that it only works if each single class that may serve as a parent for scripting is explicitly declared. Needless to say, this is simply too volatile and would require constant active maintenance, not to mention a huge amount of work up front to get going. It also hid a nasty problem with the Destroy method. Due to the way the garbage collector works, Destroy cannot be exposed to scripts as-is. It may be called from scripts but it may not be overridden from scripts because the garbage collector can call this function after all data needed for calling a scripted override has already been destroyed because if that data is also being collected there is no guarantee that proper order of destruction is observed. So for now Destroy is just a normal native method to scripted classes --- src/actor.h | 9 +- src/b_bot.cpp | 2 +- src/c_dispatch.cpp | 4 +- src/d_dehacked.cpp | 2 +- src/d_dehacked.h | 2 +- src/d_player.h | 2 +- src/decallib.cpp | 10 +- src/dobject.cpp | 3 +- src/dobject.h | 16 +- src/dobjgc.cpp | 2 +- src/dobjtype.cpp | 83 ++++--- src/dobjtype.h | 1 - src/dsectoreffect.cpp | 8 +- src/dsectoreffect.h | 4 +- src/dthinker.cpp | 173 +++++++++++++- src/dthinker.h | 4 +- src/fragglescript/t_func.cpp | 4 +- src/fragglescript/t_prepro.cpp | 2 +- src/fragglescript/t_script.cpp | 6 +- src/fragglescript/t_script.h | 6 +- src/fragglescript/t_variable.cpp | 2 +- src/g_heretic/a_hereticartifacts.cpp | 4 +- src/g_heretic/a_hereticweaps.cpp | 10 +- src/g_hexen/a_boostarmor.cpp | 2 +- src/g_hexen/a_clericholy.cpp | 4 +- src/g_hexen/a_clericstaff.cpp | 2 +- src/g_hexen/a_fighteraxe.cpp | 2 +- src/g_hexen/a_fighterplayer.cpp | 6 +- src/g_hexen/a_fighterquietus.cpp | 2 +- src/g_hexen/a_flechette.cpp | 14 +- src/g_hexen/a_healingradius.cpp | 2 +- src/g_hexen/a_heresiarch.cpp | 10 +- src/g_hexen/a_hexenspecialdecs.cpp | 4 +- src/g_hexen/a_magecone.cpp | 2 +- src/g_hexen/a_magelightning.cpp | 4 +- src/g_hexen/a_magestaff.cpp | 4 +- src/g_hexen/a_spike.cpp | 2 +- src/g_hexen/a_summon.cpp | 2 +- src/g_hexen/a_teleportother.cpp | 4 +- src/g_level.cpp | 2 +- src/g_raven/a_artitele.cpp | 2 +- src/g_raven/a_minotaur.cpp | 4 +- src/g_shared/a_action.cpp | 8 +- src/g_shared/a_armor.cpp | 10 +- src/g_shared/a_artifacts.cpp | 52 ++--- src/g_shared/a_artifacts.h | 2 +- src/g_shared/a_bridge.cpp | 6 +- src/g_shared/a_camera.cpp | 4 +- src/g_shared/a_debris.cpp | 2 +- src/g_shared/a_decals.cpp | 6 +- src/g_shared/a_fastprojectile.cpp | 14 +- src/g_shared/a_flashfader.cpp | 2 +- src/g_shared/a_fountain.cpp | 4 +- src/g_shared/a_hatetarget.cpp | 2 +- src/g_shared/a_keys.cpp | 2 +- src/g_shared/a_lightning.cpp | 2 +- src/g_shared/a_mapmarker.cpp | 2 +- src/g_shared/a_morph.cpp | 4 +- src/g_shared/a_movingcamera.cpp | 14 +- src/g_shared/a_pickups.cpp | 26 +-- src/g_shared/a_pickups.h | 4 +- src/g_shared/a_puzzleitems.cpp | 4 +- src/g_shared/a_quake.cpp | 2 +- src/g_shared/a_randomspawner.cpp | 2 +- src/g_shared/a_secrettrigger.cpp | 2 +- src/g_shared/a_sectoraction.cpp | 24 +- src/g_shared/a_setcolor.cpp | 4 +- src/g_shared/a_sharedglobal.h | 10 +- src/g_shared/a_skies.cpp | 14 +- src/g_shared/a_soundenvironment.cpp | 4 +- src/g_shared/a_soundsequence.cpp | 6 +- src/g_shared/a_spark.cpp | 2 +- src/g_shared/a_specialspot.cpp | 4 +- src/g_shared/a_specialspot.h | 4 +- src/g_shared/a_waterzone.cpp | 2 +- src/g_shared/a_weaponpiece.cpp | 6 +- src/g_shared/a_weapons.cpp | 6 +- src/g_shared/hudmessages.cpp | 8 +- src/g_shared/sbar.h | 2 +- src/g_shared/sbarinfo.cpp | 2 +- src/g_shared/shared_sbar.cpp | 2 +- src/g_strife/a_coin.cpp | 2 +- src/g_strife/a_loremaster.cpp | 2 +- src/g_strife/a_programmer.cpp | 2 +- src/g_strife/a_rebels.cpp | 2 +- src/g_strife/a_spectral.cpp | 2 +- src/g_strife/a_strifeitems.cpp | 28 +-- src/g_strife/a_strifestuff.cpp | 6 +- src/g_strife/a_strifeweapons.cpp | 6 +- src/g_strife/strife_sbar.cpp | 2 +- src/info.cpp | 2 +- src/intermission/intermission.cpp | 12 +- src/intermission/intermission.h | 4 +- src/m_argv.cpp | 2 +- src/m_cheat.cpp | 2 +- src/menu/colorpickermenu.cpp | 4 +- src/menu/joystickmenu.cpp | 2 +- src/menu/listmenu.cpp | 2 +- src/menu/loadsavemenu.cpp | 12 +- src/menu/menu.cpp | 2 +- src/menu/menuinput.cpp | 2 +- src/menu/messagebox.cpp | 13 +- src/menu/optionmenu.cpp | 6 +- src/menu/optionmenuitems.h | 2 +- src/menu/playermenu.cpp | 2 +- src/menu/readthis.cpp | 2 +- src/menu/videomenu.cpp | 2 +- src/p_acs.cpp | 6 +- src/p_buildmap.cpp | 2 +- src/p_ceiling.cpp | 2 +- src/p_conversation.cpp | 3 +- src/p_doors.cpp | 4 +- src/p_floor.cpp | 15 +- src/p_interaction.cpp | 2 +- src/p_lights.cpp | 16 +- src/p_lnspec.cpp | 4 +- src/p_map.cpp | 4 +- src/p_mobj.cpp | 117 +++++++++- src/p_pillar.cpp | 2 +- src/p_plats.cpp | 2 +- src/p_pspr.cpp | 2 +- src/p_pspr.h | 2 +- src/p_pusher.cpp | 2 +- src/p_scroll.cpp | 4 +- src/p_spec.cpp | 4 +- src/p_spec.h | 5 +- src/p_switch.cpp | 2 +- src/p_teleport.cpp | 2 +- src/p_user.cpp | 40 ++-- src/po_man.cpp | 10 +- src/po_man.h | 2 +- src/posix/sdl/sdlvideo.cpp | 2 +- src/r_data/r_interpolate.cpp | 18 +- src/r_data/r_interpolate.h | 2 +- src/r_defs.h | 2 +- src/s_advsound.cpp | 6 +- src/s_sndseq.cpp | 14 +- src/s_sndseq.h | 2 +- src/scripting/decorate/olddecorations.cpp | 2 +- src/scripting/vm/vm.h | 2 +- src/scripting/vm/vmframe.cpp | 8 +- src/scripting/zscript/zcc_compile.cpp | 36 --- src/v_video.cpp | 8 +- src/virtual.h | 272 +--------------------- src/win32/fb_d3d9.cpp | 2 +- src/win32/fb_ddraw.cpp | 2 +- src/win32/win32video.cpp | 2 +- wadsrc/static/zscript/base.txt | 2 +- wadsrc/static/zscript/hexen/firedemon.txt | 16 +- 149 files changed, 727 insertions(+), 759 deletions(-) diff --git a/src/actor.h b/src/actor.h index bbe7381a2..36fcc5de4 100644 --- a/src/actor.h +++ b/src/actor.h @@ -584,7 +584,7 @@ public: AActor () throw(); AActor (const AActor &other) throw(); AActor &operator= (const AActor &other); - void Destroy (); + void Destroy () override; ~AActor (); void Serialize(FSerializer &arc); @@ -612,6 +612,7 @@ public: bool CheckNoDelay(); virtual void BeginPlay(); // Called immediately after the actor is created + void CallBeginPlay(); virtual void PostBeginPlay(); // Called immediately before the actor's first tick void LevelSpawned(); // Called after BeginPlay if this actor was spawned by the world virtual void HandleSpawnFlags(); // Translates SpawnFlags into in-game flags. @@ -620,6 +621,8 @@ public: virtual void Activate (AActor *activator); virtual void Deactivate (AActor *activator); + void CallActivate(AActor *activator); + void CallDeactivate(AActor *activator); virtual void Tick (); @@ -629,6 +632,7 @@ public: // Perform some special damage action. Returns the amount of damage to do. // Returning -1 signals the damage routine to exit immediately virtual int DoSpecialDamage (AActor *target, int damage, FName damagetype); + int CallDoSpecialDamage(AActor *target, int damage, FName damagetype); // Like DoSpecialDamage, but called on the actor receiving the damage. virtual int TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FName damagetype); @@ -684,7 +688,8 @@ public: 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); + virtual bool DoUseInventory (AInventory *item); + bool UseInventory(AInventory *item); // Tosses an item out of the inventory. virtual AInventory *DropInventory (AInventory *item); diff --git a/src/b_bot.cpp b/src/b_bot.cpp index 93d71092d..3f4d0c592 100644 --- a/src/b_bot.cpp +++ b/src/b_bot.cpp @@ -15,7 +15,7 @@ #include "serializer.h" #include "d_player.h" -IMPLEMENT_CLASS(DBot, false, true, false, false) +IMPLEMENT_CLASS(DBot, false, true) IMPLEMENT_POINTERS_START(DBot) IMPLEMENT_POINTER(dest) diff --git a/src/c_dispatch.cpp b/src/c_dispatch.cpp index 71aeea0fa..d112634d6 100644 --- a/src/c_dispatch.cpp +++ b/src/c_dispatch.cpp @@ -187,7 +187,7 @@ static const char *KeyConfCommands[] = // CODE -------------------------------------------------------------------- -IMPLEMENT_CLASS(DWaitingCommand, false, false, false, false) +IMPLEMENT_CLASS(DWaitingCommand, false, false) void DWaitingCommand::Serialize(FSerializer &arc) { @@ -225,7 +225,7 @@ void DWaitingCommand::Tick () } } -IMPLEMENT_CLASS(DStoredCommand, false, false, false, false) +IMPLEMENT_CLASS(DStoredCommand, false, false) DStoredCommand::DStoredCommand () { diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 2e8c56f05..40e8e5702 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -221,7 +221,7 @@ DehInfo deh = // from the original actor's defaults. The original actor is then changed to // spawn the new class. -IMPLEMENT_CLASS(ADehackedPickup, false, true, false, false) +IMPLEMENT_CLASS(ADehackedPickup, false, true) IMPLEMENT_POINTERS_START(ADehackedPickup) IMPLEMENT_POINTER(RealPickup) diff --git a/src/d_dehacked.h b/src/d_dehacked.h index 564a6d499..a622707a3 100644 --- a/src/d_dehacked.h +++ b/src/d_dehacked.h @@ -41,7 +41,7 @@ class ADehackedPickup : public AInventory DECLARE_CLASS (ADehackedPickup, AInventory) HAS_OBJECT_POINTERS public: - void Destroy (); + void Destroy() override; const char *PickupMessage (); bool ShouldRespawn (); bool ShouldStay (); diff --git a/src/d_player.h b/src/d_player.h index d1678b619..af06e9730 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -109,7 +109,7 @@ public: virtual void Tick(); virtual void AddInventory (AInventory *item); virtual void RemoveInventory (AInventory *item); - virtual bool UseInventory (AInventory *item); + virtual bool DoUseInventory (AInventory *item); virtual void MarkPrecacheSounds () const; virtual void PlayIdle (); diff --git a/src/decallib.cpp b/src/decallib.cpp index 970bd7458..9fe2966eb 100644 --- a/src/decallib.cpp +++ b/src/decallib.cpp @@ -119,7 +119,7 @@ protected: DDecalThinker () : DThinker (STAT_DECALTHINKER) {} }; -IMPLEMENT_CLASS(DDecalThinker, false, true, false, false) +IMPLEMENT_CLASS(DDecalThinker, false, true) IMPLEMENT_POINTERS_START(DDecalThinker) IMPLEMENT_POINTER(TheDecal) @@ -1153,7 +1153,7 @@ FDecalAnimator::~FDecalAnimator () { } -IMPLEMENT_CLASS(DDecalFader, false, false, false, false) +IMPLEMENT_CLASS(DDecalFader, false, false) void DDecalFader::Serialize(FSerializer &arc) { @@ -1202,7 +1202,7 @@ DThinker *FDecalFaderAnim::CreateThinker (DBaseDecal *actor, side_t *wall) const return fader; } -IMPLEMENT_CLASS(DDecalStretcher, false, false, false, false) +IMPLEMENT_CLASS(DDecalStretcher, false, false) void DDecalStretcher::Serialize(FSerializer &arc) { @@ -1290,7 +1290,7 @@ void DDecalStretcher::Tick () } } -IMPLEMENT_CLASS(DDecalSlider, false, false, false, false) +IMPLEMENT_CLASS(DDecalSlider, false, false) void DDecalSlider::Serialize(FSerializer &arc) { @@ -1370,7 +1370,7 @@ FDecalAnimator *FDecalLib::FindAnimator (const char *name) return NULL; } -IMPLEMENT_CLASS(DDecalColorer, false, false, false, false) +IMPLEMENT_CLASS(DDecalColorer, false, false) void DDecalColorer::Serialize(FSerializer &arc) { diff --git a/src/dobject.cpp b/src/dobject.cpp index 849f6a477..b05ae69ac 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -61,7 +61,7 @@ ClassReg DObject::RegistrationInfo = nullptr, // MyClass "DObject", // Name nullptr, // ParentType - &DVMObject::RegistrationInfo, // VMExport + nullptr, nullptr, // Pointers &DObject::InPlaceConstructor, // ConstructNative nullptr, @@ -358,7 +358,6 @@ void DObject::Destroy () DEFINE_ACTION_FUNCTION(DObject, Destroy) { PARAM_SELF_PROLOGUE(DObject); - self->VMSuperCall(); self->Destroy(); return 0; } diff --git a/src/dobject.h b/src/dobject.h index f728713e0..cb1074c0c 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -110,7 +110,7 @@ struct ClassReg PClass *MyClass; const char *Name; ClassReg *ParentType; - ClassReg *VMExport; + ClassReg *_VMExport; const size_t *Pointers; void (*ConstructNative)(void *); void(*InitNatives)(); @@ -157,23 +157,23 @@ protected: \ # define _DECLARE_TI(cls) ClassReg * const cls::RegistrationInfoPtr __attribute__((section(SECTION_CREG))) = &cls::RegistrationInfo; #endif -#define _IMP_PCLASS(cls, ptrs, create, initn, vmexport) \ +#define _IMP_PCLASS(cls, ptrs, create) \ ClassReg cls::RegistrationInfo = {\ nullptr, \ #cls, \ &cls::Super::RegistrationInfo, \ - vmexport, \ + nullptr, \ ptrs, \ create, \ - initn, \ + nullptr, \ sizeof(cls), \ cls::MetaClassNum }; \ _DECLARE_TI(cls) \ PClass *cls::StaticType() const { return RegistrationInfo.MyClass; } -#define IMPLEMENT_CLASS(cls, isabstract, ptrs, fields, vmexport) \ +#define IMPLEMENT_CLASS(cls, isabstract, ptrs) \ _X_CONSTRUCTOR_##isabstract(cls) \ - _IMP_PCLASS(cls, _X_POINTERS_##ptrs(cls), _X_ABSTRACT_##isabstract(cls), _X_FIELDS_##fields(cls), _X_VMEXPORT_##vmexport(cls)) + _IMP_PCLASS(cls, _X_POINTERS_##ptrs(cls), _X_ABSTRACT_##isabstract(cls)) // Taking the address of a field in an object at address 1 instead of // address 0 keeps GCC from complaining about possible misuse of offsetof. @@ -190,7 +190,7 @@ protected: \ #define _X_CONSTRUCTOR_false(cls) void cls::InPlaceConstructor(void *mem) { new((EInPlace *)mem) cls; } #define _X_ABSTRACT_true(cls) nullptr #define _X_ABSTRACT_false(cls) cls::InPlaceConstructor -#define _X_VMEXPORT_true(cls) &DVMObject::RegistrationInfo +#define _X_VMEXPORT_true(cls) nullptr #define _X_VMEXPORT_false(cls) nullptr enum EObjectFlags @@ -481,7 +481,7 @@ public: // that don't call their base class. void CheckIfSerialized () const; - virtual void Destroy (); + virtual void Destroy(); // If you need to replace one object with another and want to // change any pointers from the old object to the new object, diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index 40ef7b784..827516172 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -125,7 +125,7 @@ public: int SideNum; }; -IMPLEMENT_CLASS(DSectorMarker, false, false, false, false) +IMPLEMENT_CLASS(DSectorMarker, false, false) // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 52a269873..079890f86 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -97,8 +97,8 @@ static const size_t TheEnd = ~(size_t)0; // CODE -------------------------------------------------------------------- -IMPLEMENT_CLASS(PErrorType, false, false, false, false) -IMPLEMENT_CLASS(PVoidType, false, false, false, false) +IMPLEMENT_CLASS(PErrorType, false, false) +IMPLEMENT_CLASS(PVoidType, false, false) void DumpTypeTable() { @@ -145,7 +145,7 @@ void DumpTypeTable() /* PClassType *************************************************************/ -IMPLEMENT_CLASS(PClassType, false, false, false, false) +IMPLEMENT_CLASS(PClassType, false, false) //========================================================================== // @@ -173,7 +173,7 @@ void PClassType::DeriveData(PClass *newclass) /* PClassClass ************************************************************/ -IMPLEMENT_CLASS(PClassClass, false, false, false, false) +IMPLEMENT_CLASS(PClassClass, false, false) //========================================================================== // @@ -191,7 +191,7 @@ PClassClass::PClassClass() /* PType ******************************************************************/ -IMPLEMENT_CLASS(PType, true, true, false, false) +IMPLEMENT_CLASS(PType, true, true) IMPLEMENT_POINTERS_START(PType) IMPLEMENT_POINTER(HashNext) @@ -647,7 +647,7 @@ void PType::StaticInit() /* PBasicType *************************************************************/ -IMPLEMENT_CLASS(PBasicType, true, false, false, false) +IMPLEMENT_CLASS(PBasicType, true, false) //========================================================================== // @@ -673,11 +673,11 @@ PBasicType::PBasicType(unsigned int size, unsigned int align) /* PCompoundType **********************************************************/ -IMPLEMENT_CLASS(PCompoundType, true, false, false, false) +IMPLEMENT_CLASS(PCompoundType, true, false) /* PNamedType *************************************************************/ -IMPLEMENT_CLASS(PNamedType, true, true, false, false) +IMPLEMENT_CLASS(PNamedType, true, true) IMPLEMENT_POINTERS_START(PNamedType) IMPLEMENT_POINTER(Outer) @@ -725,7 +725,7 @@ FString PNamedType::QualifiedName() const /* PInt *******************************************************************/ -IMPLEMENT_CLASS(PInt, false, false, false, false) +IMPLEMENT_CLASS(PInt, false, false) //========================================================================== // @@ -964,7 +964,7 @@ double PInt::GetValueFloat(void *addr) const /* PBool ******************************************************************/ -IMPLEMENT_CLASS(PBool, false, false, false, false) +IMPLEMENT_CLASS(PBool, false, false) //========================================================================== // @@ -985,7 +985,7 @@ PBool::PBool() /* PFloat *****************************************************************/ -IMPLEMENT_CLASS(PFloat, false, false, false, false) +IMPLEMENT_CLASS(PFloat, false, false) //========================================================================== // @@ -1235,7 +1235,7 @@ void PFloat::SetOps() /* PString ****************************************************************/ -IMPLEMENT_CLASS(PString, false, false, false, false) +IMPLEMENT_CLASS(PString, false, false) //========================================================================== // @@ -1332,7 +1332,7 @@ void PString::DestroyValue(void *addr) const /* PName ******************************************************************/ -IMPLEMENT_CLASS(PName, false, false, false, false) +IMPLEMENT_CLASS(PName, false, false) //========================================================================== // @@ -1382,7 +1382,7 @@ bool PName::ReadValue(FSerializer &ar, const char *key, void *addr) const /* PSpriteID ******************************************************************/ -IMPLEMENT_CLASS(PSpriteID, false, false, false, false) +IMPLEMENT_CLASS(PSpriteID, false, false) //========================================================================== // @@ -1424,7 +1424,7 @@ bool PSpriteID::ReadValue(FSerializer &ar, const char *key, void *addr) const /* PTextureID ******************************************************************/ -IMPLEMENT_CLASS(PTextureID, false, false, false, false) +IMPLEMENT_CLASS(PTextureID, false, false) //========================================================================== // @@ -1467,7 +1467,7 @@ bool PTextureID::ReadValue(FSerializer &ar, const char *key, void *addr) const /* PSound *****************************************************************/ -IMPLEMENT_CLASS(PSound, false, false, false, false) +IMPLEMENT_CLASS(PSound, false, false) //========================================================================== // @@ -1517,7 +1517,7 @@ bool PSound::ReadValue(FSerializer &ar, const char *key, void *addr) const /* PColor *****************************************************************/ -IMPLEMENT_CLASS(PColor, false, false, false, false) +IMPLEMENT_CLASS(PColor, false, false) //========================================================================== // @@ -1534,7 +1534,7 @@ PColor::PColor() /* PStateLabel *****************************************************************/ -IMPLEMENT_CLASS(PStateLabel, false, false, false, false) +IMPLEMENT_CLASS(PStateLabel, false, false) //========================================================================== // @@ -1550,7 +1550,7 @@ PStateLabel::PStateLabel() /* PPointer ***************************************************************/ -IMPLEMENT_CLASS(PPointer, false, true, false, false) +IMPLEMENT_CLASS(PPointer, false, true) IMPLEMENT_POINTERS_START(PPointer) IMPLEMENT_POINTER(PointedType) @@ -1695,7 +1695,7 @@ PPointer *NewPointer(PType *type, bool isconst) /* PStatePointer **********************************************************/ -IMPLEMENT_CLASS(PStatePointer, false, false, false, false) +IMPLEMENT_CLASS(PStatePointer, false, false) //========================================================================== // @@ -1738,7 +1738,7 @@ bool PStatePointer::ReadValue(FSerializer &ar, const char *key, void *addr) cons /* PClassPointer **********************************************************/ -IMPLEMENT_CLASS(PClassPointer, false, true, false, false) +IMPLEMENT_CLASS(PClassPointer,false, true) IMPLEMENT_POINTERS_START(PClassPointer) IMPLEMENT_POINTER(ClassRestriction) @@ -1819,7 +1819,7 @@ PClassPointer *NewClassPointer(PClass *restrict) /* PEnum ******************************************************************/ -IMPLEMENT_CLASS(PEnum, false, true, false, false) +IMPLEMENT_CLASS(PEnum, false, true) IMPLEMENT_POINTERS_START(PEnum) IMPLEMENT_POINTER(ValueType) @@ -1872,7 +1872,7 @@ PEnum *NewEnum(FName name, PTypeBase *outer) /* PArray *****************************************************************/ -IMPLEMENT_CLASS(PArray, false, true, false, false) +IMPLEMENT_CLASS(PArray, false, true) IMPLEMENT_POINTERS_START(PArray) IMPLEMENT_POINTER(ElementType) @@ -2035,7 +2035,7 @@ PArray *NewArray(PType *type, unsigned int count) /* PDynArray **************************************************************/ -IMPLEMENT_CLASS(PDynArray, false, true, false, false) +IMPLEMENT_CLASS(PDynArray, false, true) IMPLEMENT_POINTERS_START(PDynArray) IMPLEMENT_POINTER(ElementType) @@ -2118,7 +2118,7 @@ PDynArray *NewDynArray(PType *type) /* PMap *******************************************************************/ -IMPLEMENT_CLASS(PMap, false, true, false, false) +IMPLEMENT_CLASS(PMap, false, true) IMPLEMENT_POINTERS_START(PMap) IMPLEMENT_POINTER(KeyType) @@ -2202,7 +2202,7 @@ PMap *NewMap(PType *keytype, PType *valuetype) /* PStruct ****************************************************************/ -IMPLEMENT_CLASS(PStruct, false, false, false, false) +IMPLEMENT_CLASS(PStruct, false, false) //========================================================================== // @@ -2440,7 +2440,7 @@ PStruct *NewStruct(FName name, PTypeBase *outer) /* PNativeStruct ****************************************************************/ -IMPLEMENT_CLASS(PNativeStruct, false, false, false, false) +IMPLEMENT_CLASS(PNativeStruct, false, false) //========================================================================== // @@ -2478,7 +2478,7 @@ PNativeStruct *NewNativeStruct(FName name, PTypeBase *outer) /* PField *****************************************************************/ -IMPLEMENT_CLASS(PField, false, false, false, false) +IMPLEMENT_CLASS(PField, false, false) //========================================================================== // @@ -2523,7 +2523,7 @@ PField::PField(FName name, PType *type, DWORD flags, size_t offset, int bitvalue /* PPrototype *************************************************************/ -IMPLEMENT_CLASS(PPrototype, false, false, false, false) +IMPLEMENT_CLASS(PPrototype, false, false) //========================================================================== // @@ -2609,7 +2609,7 @@ PPrototype *NewPrototype(const TArray &rettypes, const TArray /* PFunction **************************************************************/ -IMPLEMENT_CLASS(PFunction, false, false, false, false) +IMPLEMENT_CLASS(PFunction, false, false) //========================================================================== // @@ -2672,7 +2672,7 @@ unsigned PFunction::AddVariant(PPrototype *proto, TArray &argflags, TArra /* PClass *****************************************************************/ -IMPLEMENT_CLASS(PClass, false, true, false, false) +IMPLEMENT_CLASS(PClass, false, true) IMPLEMENT_POINTERS_START(PClass) IMPLEMENT_POINTER(ParentClass) @@ -2907,7 +2907,6 @@ void PClass::StaticShutdown () { auto cr = ((ClassReg *)*probe); cr->MyClass = nullptr; - if (cr->VMExport != nullptr) cr->VMExport->MyClass = nullptr; } } @@ -3034,10 +3033,6 @@ PClass *ClassReg::RegisterClass() { cls->ParentClass = ParentType->RegisterClass(); } - if (VMExport != nullptr) - { - cls->VMExported = VMExport->RegisterClass(); - } return cls; } @@ -3717,19 +3712,19 @@ CCMD(typetable) // Symbol tables ------------------------------------------------------------ -IMPLEMENT_CLASS(PTypeBase, true, false, false, false); -IMPLEMENT_CLASS(PSymbol, true, false, false, false); -IMPLEMENT_CLASS(PSymbolConst, false, false, false, false); -IMPLEMENT_CLASS(PSymbolConstNumeric, false, false, false, false); -IMPLEMENT_CLASS(PSymbolConstString, false, false, false, false); -IMPLEMENT_CLASS(PSymbolTreeNode, false, false, false, false) -IMPLEMENT_CLASS(PSymbolType, false, true, false, false) +IMPLEMENT_CLASS(PTypeBase, true, false); +IMPLEMENT_CLASS(PSymbol, true, false); +IMPLEMENT_CLASS(PSymbolConst, false, false); +IMPLEMENT_CLASS(PSymbolConstNumeric, false, false); +IMPLEMENT_CLASS(PSymbolConstString, false, false); +IMPLEMENT_CLASS(PSymbolTreeNode, false, false) +IMPLEMENT_CLASS(PSymbolType, false, true) IMPLEMENT_POINTERS_START(PSymbolType) IMPLEMENT_POINTER(Type) IMPLEMENT_POINTERS_END -IMPLEMENT_CLASS(PSymbolVMFunction, false, true, false, false) +IMPLEMENT_CLASS(PSymbolVMFunction, false, true) IMPLEMENT_POINTERS_START(PSymbolVMFunction) IMPLEMENT_POINTER(Function) diff --git a/src/dobjtype.h b/src/dobjtype.h index 76d6e7585..b952a3c23 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -809,7 +809,6 @@ public: // Per-class information ------------------------------------- PClass *ParentClass; // the class this class derives from - PClass *VMExported; // this is here to allow script classes to override native virtual functions 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 BYTE *Defaults; diff --git a/src/dsectoreffect.cpp b/src/dsectoreffect.cpp index 700a407fd..3c33d1634 100644 --- a/src/dsectoreffect.cpp +++ b/src/dsectoreffect.cpp @@ -31,7 +31,7 @@ #include "serializer.h" #include "doomstat.h" -IMPLEMENT_CLASS(DSectorEffect, false, false, false, false) +IMPLEMENT_CLASS(DSectorEffect, false, false) DSectorEffect::DSectorEffect () : DThinker(STAT_SECTOREFFECT) @@ -71,7 +71,7 @@ void DSectorEffect::Serialize(FSerializer &arc) arc("sector", m_Sector); } -IMPLEMENT_CLASS(DMover, false, true, false, false) +IMPLEMENT_CLASS(DMover, false, true) IMPLEMENT_POINTERS_START(DMover) IMPLEMENT_POINTER(interpolation) @@ -108,7 +108,7 @@ void DMover::StopInterpolation(bool force) } } -IMPLEMENT_CLASS(DMovingFloor, false, false, false, false) +IMPLEMENT_CLASS(DMovingFloor, false, false) DMovingFloor::DMovingFloor () { @@ -121,7 +121,7 @@ DMovingFloor::DMovingFloor (sector_t *sector) interpolation = sector->SetInterpolation(sector_t::FloorMove, true); } -IMPLEMENT_CLASS(DMovingCeiling, false, false, false, false) +IMPLEMENT_CLASS(DMovingCeiling, false, false) DMovingCeiling::DMovingCeiling () { diff --git a/src/dsectoreffect.h b/src/dsectoreffect.h index 0a5e9bd56..e9327ce70 100644 --- a/src/dsectoreffect.h +++ b/src/dsectoreffect.h @@ -12,7 +12,7 @@ public: void Serialize(FSerializer &arc); - void Destroy(); + void Destroy() override; sector_t *GetSector() const { return m_Sector; } @@ -35,7 +35,7 @@ protected: DMover (); void Serialize(FSerializer &arc); - void Destroy(); + void Destroy() override; }; class DMovingFloor : public DMover diff --git a/src/dthinker.cpp b/src/dthinker.cpp index 9478393c0..d214b28e9 100644 --- a/src/dthinker.cpp +++ b/src/dthinker.cpp @@ -48,7 +48,7 @@ extern cycle_t BotSupportCycles; extern cycle_t ActionCycles; extern int BotWTG; -IMPLEMENT_CLASS(DThinker, false, false, false, true) +IMPLEMENT_CLASS(DThinker, false, false) DThinker *NextToThink; @@ -56,6 +56,12 @@ FThinkerList DThinker::Thinkers[MAX_STATNUM+2]; FThinkerList DThinker::FreshThinkers[MAX_STATNUM+1]; bool DThinker::bSerialOverride = false; +//========================================================================== +// +// +// +//========================================================================== + void FThinkerList::AddTail(DThinker *thinker) { assert(thinker->PrevThinker == NULL && thinker->NextThinker == NULL); @@ -80,6 +86,12 @@ void FThinkerList::AddTail(DThinker *thinker) GC::WriteBarrier(Sentinel, thinker); } +//========================================================================== +// +// +// +//========================================================================== + DThinker *FThinkerList::GetHead() const { if (Sentinel == NULL || Sentinel->NextThinker == Sentinel) @@ -90,6 +102,12 @@ DThinker *FThinkerList::GetHead() const return Sentinel->NextThinker; } +//========================================================================== +// +// +// +//========================================================================== + DThinker *FThinkerList::GetTail() const { if (Sentinel == NULL || Sentinel->PrevThinker == Sentinel) @@ -99,11 +117,23 @@ DThinker *FThinkerList::GetTail() const return Sentinel->PrevThinker; } +//========================================================================== +// +// +// +//========================================================================== + bool FThinkerList::IsEmpty() const { return Sentinel == NULL || Sentinel->NextThinker == NULL; } +//========================================================================== +// +// +// +//========================================================================== + void DThinker::SaveList(FSerializer &arc, DThinker *node) { if (node != NULL) @@ -234,6 +264,12 @@ void DThinker::Destroy () Super::Destroy(); } +//========================================================================== +// +// +// +//========================================================================== + void DThinker::Remove() { if (this == NextToThink) @@ -254,6 +290,12 @@ void DThinker::Remove() PrevThinker = NULL; } +//========================================================================== +// +// +// +//========================================================================== + void DThinker::PostBeginPlay () { } @@ -261,15 +303,41 @@ void DThinker::PostBeginPlay () DEFINE_ACTION_FUNCTION(DThinker, PostBeginPlay) { PARAM_SELF_PROLOGUE(DThinker); - self->VMSuperCall(); self->PostBeginPlay(); return 0; } +void DThinker::CallPostBeginPlay() +{ + IFVIRTUAL(DThinker, PostBeginPlay) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { (DObject*)this }; + VMFrameStack stack; + stack.Call(func, params, 1, nullptr, 0, nullptr); + } + else + { + PostBeginPlay(); + } +} + +//========================================================================== +// +// +// +//========================================================================== + void DThinker::PostSerialize() { } +//========================================================================== +// +// +// +//========================================================================== + DThinker *DThinker::FirstThinker (int statnum) { DThinker *node; @@ -290,6 +358,12 @@ DThinker *DThinker::FirstThinker (int statnum) return node; } +//========================================================================== +// +// +// +//========================================================================== + void DThinker::ChangeStatNum (int statnum) { FThinkerList *list; @@ -313,7 +387,12 @@ void DThinker::ChangeStatNum (int statnum) list->AddTail(this); } +//========================================================================== +// // Mark the first thinker of each list +// +//========================================================================== + void DThinker::MarkRoots() { for (int i = 0; i <= MAX_STATNUM; ++i) @@ -324,7 +403,12 @@ void DThinker::MarkRoots() GC::Mark(Thinkers[MAX_STATNUM+1].Sentinel); } +//========================================================================== +// // Destroy every thinker +// +//========================================================================== + void DThinker::DestroyAllThinkers () { int i; @@ -341,6 +425,12 @@ void DThinker::DestroyAllThinkers () GC::FullGC(); } +//========================================================================== +// +// +// +//========================================================================== + void DThinker::DestroyThinkersInList (FThinkerList &list) { if (list.Sentinel != NULL) @@ -355,6 +445,12 @@ void DThinker::DestroyThinkersInList (FThinkerList &list) } } +//========================================================================== +// +// +// +//========================================================================== + void DThinker::RunThinkers () { int i, count; @@ -385,6 +481,12 @@ void DThinker::RunThinkers () ThinkCycles.Unclock(); } +//========================================================================== +// +// +// +//========================================================================== + int DThinker::TickThinkers (FThinkerList *list, FThinkerList *dest) { int count = 0; @@ -407,7 +509,7 @@ int DThinker::TickThinkers (FThinkerList *list, FThinkerList *dest) node->Remove(); dest->AddTail(node); } - node->PostBeginPlay(); + node->CallPostBeginPlay(); } else if (dest != NULL) { @@ -416,7 +518,7 @@ int DThinker::TickThinkers (FThinkerList *list, FThinkerList *dest) if (!(node->ObjectFlags & OF_EuthanizeMe)) { // Only tick thinkers not scheduled for destruction - node->Tick(); + node->CallTick(); node->ObjectFlags &= ~OF_JustSpawned; GC::CheckGC(); } @@ -425,6 +527,12 @@ int DThinker::TickThinkers (FThinkerList *list, FThinkerList *dest) return count; } +//========================================================================== +// +// +// +//========================================================================== + void DThinker::Tick () { } @@ -432,11 +540,28 @@ void DThinker::Tick () DEFINE_ACTION_FUNCTION(DThinker, Tick) { PARAM_SELF_PROLOGUE(DThinker); - self->VMSuperCall(); self->Tick(); return 0; } +void DThinker::CallTick() +{ + IFVIRTUAL(DThinker, Tick) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { (DObject*)this }; + VMFrameStack stack; + stack.Call(func, params, 1, nullptr, 0, nullptr); + } + else Tick(); +} + +//========================================================================== +// +// +// +//========================================================================== + size_t DThinker::PropagateMark() { // Do not choke on partially initialized objects (as happens when loading a savegame fails) @@ -450,6 +575,12 @@ size_t DThinker::PropagateMark() return Super::PropagateMark(); } +//========================================================================== +// +// +// +//========================================================================== + FThinkerIterator::FThinkerIterator (const PClass *type, int statnum) { if ((unsigned)statnum > MAX_STATNUM) @@ -467,6 +598,12 @@ FThinkerIterator::FThinkerIterator (const PClass *type, int statnum) m_SearchingFresh = false; } +//========================================================================== +// +// +// +//========================================================================== + FThinkerIterator::FThinkerIterator (const PClass *type, int statnum, DThinker *prev) { if ((unsigned)statnum > MAX_STATNUM) @@ -491,12 +628,24 @@ FThinkerIterator::FThinkerIterator (const PClass *type, int statnum, DThinker *p } } +//========================================================================== +// +// +// +//========================================================================== + void FThinkerIterator::Reinit () { m_CurrThinker = DThinker::Thinkers[m_Stat].GetHead(); m_SearchingFresh = false; } +//========================================================================== +// +// +// +//========================================================================== + DThinker *FThinkerIterator::Next (bool exact) { if (m_ParentType == NULL) @@ -542,8 +691,13 @@ DThinker *FThinkerIterator::Next (bool exact) return NULL; } +//========================================================================== +// // This is for scripting, which needs the iterator wrapped into an object with the needed functions exported. // Unfortunately we cannot have templated type conversions in scripts. +// +//========================================================================== + class DThinkerIterator : public DObject, public FThinkerIterator { DECLARE_CLASS(DThinkerIterator, DObject) @@ -555,7 +709,7 @@ public: } }; -IMPLEMENT_CLASS(DThinkerIterator, false, false, false, false); +IMPLEMENT_CLASS(DThinkerIterator, false, false); DEFINE_ACTION_FUNCTION(DThinkerIterator, Create) { PARAM_PROLOGUE; @@ -577,8 +731,11 @@ DEFINE_ACTION_FUNCTION(DThinkerIterator, Reinit) return 0; } - - +//========================================================================== +// +// +// +//========================================================================== ADD_STAT (think) { diff --git a/src/dthinker.h b/src/dthinker.h index 95985c2fb..3d580c3c2 100644 --- a/src/dthinker.h +++ b/src/dthinker.h @@ -66,10 +66,12 @@ class DThinker : public DObject DECLARE_CLASS (DThinker, DObject) public: DThinker (int statnum = STAT_DEFAULT) throw(); - void Destroy (); + void Destroy () override; virtual ~DThinker (); virtual void Tick (); + void CallTick(); virtual void PostBeginPlay (); // Called just before the first tick + void CallPostBeginPlay(); virtual void PostSerialize(); size_t PropagateMark(); diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index ddc1a4bd4..7266daf40 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -1785,7 +1785,7 @@ public: void Destroy() { Super::Destroy(); m_Sector->lightingdata=NULL; } }; -IMPLEMENT_CLASS(DLightLevel, false, false, false, false) +IMPLEMENT_CLASS(DLightLevel, false, false) void DLightLevel::Serialize(FSerializer &arc) { @@ -2975,7 +2975,7 @@ void FParser::SF_ObjAwaken(void) if(mo) { - mo->Activate(Script->trigger); + mo->CallActivate(Script->trigger); } } diff --git a/src/fragglescript/t_prepro.cpp b/src/fragglescript/t_prepro.cpp index 2129df54f..4128e6661 100644 --- a/src/fragglescript/t_prepro.cpp +++ b/src/fragglescript/t_prepro.cpp @@ -71,7 +71,7 @@ // //========================================================================== -IMPLEMENT_CLASS(DFsSection, false, true, false, false) +IMPLEMENT_CLASS(DFsSection, false, true) IMPLEMENT_POINTERS_START(DFsSection) IMPLEMENT_POINTER(next) diff --git a/src/fragglescript/t_script.cpp b/src/fragglescript/t_script.cpp index a40122623..b852607b3 100644 --- a/src/fragglescript/t_script.cpp +++ b/src/fragglescript/t_script.cpp @@ -99,7 +99,7 @@ AActor *trigger_obj; // //========================================================================== -IMPLEMENT_CLASS(DFsScript, false, true, false, false) +IMPLEMENT_CLASS(DFsScript, false, true) IMPLEMENT_POINTERS_START(DFsScript) IMPLEMENT_POINTER(parent) @@ -269,7 +269,7 @@ void DFsScript::ParseScript(char *position) // //========================================================================== -IMPLEMENT_CLASS(DRunningScript, false, true, false, false) +IMPLEMENT_CLASS(DRunningScript, false, true) IMPLEMENT_POINTERS_START(DRunningScript) IMPLEMENT_POINTER(prev) @@ -380,7 +380,7 @@ void DRunningScript::Serialize(FSerializer &arc) // //========================================================================== -IMPLEMENT_CLASS(DFraggleThinker, false, true, false, false) +IMPLEMENT_CLASS(DFraggleThinker, false, true) IMPLEMENT_POINTERS_START(DFraggleThinker) IMPLEMENT_POINTER(RunningScripts) diff --git a/src/fragglescript/t_script.h b/src/fragglescript/t_script.h index 3734e16b8..50829e000 100644 --- a/src/fragglescript/t_script.h +++ b/src/fragglescript/t_script.h @@ -337,7 +337,7 @@ public: DFsScript(); ~DFsScript(); - void Destroy(); + void Destroy() override; void Serialize(FSerializer &ar); DFsVariable *NewVariable(const char *name, int vtype); @@ -652,7 +652,7 @@ class DRunningScript : public DObject public: DRunningScript(AActor *trigger=NULL, DFsScript *owner = NULL, int index = 0) ; - void Destroy(); + void Destroy() override; void Serialize(FSerializer &arc); TObjPtr script; @@ -687,7 +687,7 @@ public: bool nocheckposition; DFraggleThinker(); - void Destroy(); + void Destroy() override; void Serialize(FSerializer & arc); diff --git a/src/fragglescript/t_variable.cpp b/src/fragglescript/t_variable.cpp index 23d24b78a..9bdddda34 100644 --- a/src/fragglescript/t_variable.cpp +++ b/src/fragglescript/t_variable.cpp @@ -179,7 +179,7 @@ AActor* actorvalue(const svalue_t &svalue) // //========================================================================== -IMPLEMENT_CLASS(DFsVariable, false, true, false, false) +IMPLEMENT_CLASS(DFsVariable, false, true) IMPLEMENT_POINTERS_START(DFsVariable) IMPLEMENT_POINTER(next) diff --git a/src/g_heretic/a_hereticartifacts.cpp b/src/g_heretic/a_hereticartifacts.cpp index f2ad18b2f..2fb45c124 100644 --- a/src/g_heretic/a_hereticartifacts.cpp +++ b/src/g_heretic/a_hereticartifacts.cpp @@ -17,7 +17,7 @@ public: bool Use (bool pickup); }; -IMPLEMENT_CLASS(AArtiTomeOfPower, false, false, false, false) +IMPLEMENT_CLASS(AArtiTomeOfPower, false, false) bool AArtiTomeOfPower::Use (bool pickup) { @@ -51,7 +51,7 @@ public: bool Use (bool pickup); }; -IMPLEMENT_CLASS(AArtiTimeBomb, false, false, false, false) +IMPLEMENT_CLASS(AArtiTimeBomb, false, false) bool AArtiTimeBomb::Use (bool pickup) { diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp index 3b2711e24..4e2d62f1d 100644 --- a/src/g_heretic/a_hereticweaps.cpp +++ b/src/g_heretic/a_hereticweaps.cpp @@ -58,7 +58,7 @@ public: int DoSpecialDamage (AActor *target, int damage, FName damagetype); }; -IMPLEMENT_CLASS(ARainPillar, false, false, false, false) +IMPLEMENT_CLASS(ARainPillar, false, false) int ARainPillar::DoSpecialDamage (AActor *target, int damage, FName damagetype) { @@ -80,7 +80,7 @@ public: TObjPtr Rain1, Rain2; }; -IMPLEMENT_CLASS(ARainTracker, false, false, false, false) +IMPLEMENT_CLASS(ARainTracker, false, false) void ARainTracker::Serialize(FSerializer &arc) { @@ -367,8 +367,8 @@ public: void EndPowerup (); }; -IMPLEMENT_CLASS(APhoenixRod, false, false, false, false) -IMPLEMENT_CLASS(APhoenixRodPowered, false, false, false, false) +IMPLEMENT_CLASS(APhoenixRod, false, false) +IMPLEMENT_CLASS(APhoenixRodPowered, false, false) void APhoenixRodPowered::EndPowerup () { @@ -388,7 +388,7 @@ public: int DoSpecialDamage (AActor *target, int damage, FName damagetype); }; -IMPLEMENT_CLASS(APhoenixFX2, false, false, false, false) +IMPLEMENT_CLASS(APhoenixFX2, false, false) int APhoenixFX2::DoSpecialDamage (AActor *target, int damage, FName damagetype) { diff --git a/src/g_hexen/a_boostarmor.cpp b/src/g_hexen/a_boostarmor.cpp index 1323af8a5..b910f63e7 100644 --- a/src/g_hexen/a_boostarmor.cpp +++ b/src/g_hexen/a_boostarmor.cpp @@ -17,7 +17,7 @@ public: bool Use (bool pickup); }; -IMPLEMENT_CLASS(AArtiBoostArmor, false, false, false, false) +IMPLEMENT_CLASS(AArtiBoostArmor, false, false) bool AArtiBoostArmor::Use (bool pickup) { diff --git a/src/g_hexen/a_clericholy.cpp b/src/g_hexen/a_clericholy.cpp index 362434b02..52ff4179d 100644 --- a/src/g_hexen/a_clericholy.cpp +++ b/src/g_hexen/a_clericholy.cpp @@ -58,11 +58,11 @@ public: BYTE CHolyCount; }; -IMPLEMENT_CLASS(ACWeapWraithverge, false, false, false, false) +IMPLEMENT_CLASS(ACWeapWraithverge, false, false) // Holy Spirit -------------------------------------------------------------- -IMPLEMENT_CLASS(AHolySpirit, false, false, false, false) +IMPLEMENT_CLASS(AHolySpirit, false, false) bool AHolySpirit::Slam(AActor *thing) { diff --git a/src/g_hexen/a_clericstaff.cpp b/src/g_hexen/a_clericstaff.cpp index a838357d6..ef7beaffa 100644 --- a/src/g_hexen/a_clericstaff.cpp +++ b/src/g_hexen/a_clericstaff.cpp @@ -25,7 +25,7 @@ public: int DoSpecialDamage (AActor *target, int damage, FName damagetype); }; -IMPLEMENT_CLASS(ACStaffMissile, false, false, false, false) +IMPLEMENT_CLASS(ACStaffMissile, false, false) int ACStaffMissile::DoSpecialDamage (AActor *target, int damage, FName damagetype) { diff --git a/src/g_hexen/a_fighteraxe.cpp b/src/g_hexen/a_fighteraxe.cpp index 1dc02d599..fde3a9c18 100644 --- a/src/g_hexen/a_fighteraxe.cpp +++ b/src/g_hexen/a_fighteraxe.cpp @@ -31,7 +31,7 @@ public: FState *GetAtkState (bool hold); }; -IMPLEMENT_CLASS(AFWeapAxe, false, false, false, false) +IMPLEMENT_CLASS(AFWeapAxe, false, false) FState *AFWeapAxe::GetUpState () { diff --git a/src/g_hexen/a_fighterplayer.cpp b/src/g_hexen/a_fighterplayer.cpp index afdbe8a90..4f1d1fd3b 100644 --- a/src/g_hexen/a_fighterplayer.cpp +++ b/src/g_hexen/a_fighterplayer.cpp @@ -11,9 +11,9 @@ #include "vm.h" */ -IMPLEMENT_CLASS(AFighterWeapon, false, false, false, false) -IMPLEMENT_CLASS(AClericWeapon, false, false, false, false) -IMPLEMENT_CLASS(AMageWeapon, false, false, false, false) +IMPLEMENT_CLASS(AFighterWeapon, false, false) +IMPLEMENT_CLASS(AClericWeapon, false, false) +IMPLEMENT_CLASS(AMageWeapon, false, false) static FRandom pr_fpatk ("FPunchAttack"); diff --git a/src/g_hexen/a_fighterquietus.cpp b/src/g_hexen/a_fighterquietus.cpp index adba8d235..458d1415b 100644 --- a/src/g_hexen/a_fighterquietus.cpp +++ b/src/g_hexen/a_fighterquietus.cpp @@ -59,7 +59,7 @@ public: int DoSpecialDamage(AActor *victim, int damage, FName damagetype); }; -IMPLEMENT_CLASS(AFSwordMissile, false, false, false, false) +IMPLEMENT_CLASS(AFSwordMissile, false, false) int AFSwordMissile::DoSpecialDamage(AActor *victim, int damage, FName damagetype) { diff --git a/src/g_hexen/a_flechette.cpp b/src/g_hexen/a_flechette.cpp index 335842887..77917c402 100644 --- a/src/g_hexen/a_flechette.cpp +++ b/src/g_hexen/a_flechette.cpp @@ -24,7 +24,7 @@ DECLARE_ACTION(A_CheckThrowBomb) // Poison Bag Artifact (Flechette) ------------------------------------------ -IMPLEMENT_CLASS(AArtiPoisonBag, false, false, false, false) +IMPLEMENT_CLASS(AArtiPoisonBag, false, false) // Poison Bag 1 (The Cleric's) ---------------------------------------------- @@ -35,7 +35,7 @@ public: bool Use (bool pickup); }; -IMPLEMENT_CLASS(AArtiPoisonBag1, false, false, false, false) +IMPLEMENT_CLASS(AArtiPoisonBag1, false, false) bool AArtiPoisonBag1::Use (bool pickup) { @@ -60,7 +60,7 @@ public: bool Use (bool pickup); }; -IMPLEMENT_CLASS(AArtiPoisonBag2, false, false, false, false) +IMPLEMENT_CLASS(AArtiPoisonBag2, false, false) bool AArtiPoisonBag2::Use (bool pickup) { @@ -85,7 +85,7 @@ public: bool Use (bool pickup); }; -IMPLEMENT_CLASS(AArtiPoisonBag3, false, false, false, false) +IMPLEMENT_CLASS(AArtiPoisonBag3, false, false) bool AArtiPoisonBag3::Use (bool pickup) { @@ -136,7 +136,7 @@ public: bool Use (bool pickup); }; -IMPLEMENT_CLASS(AArtiPoisonBagGiver, false, false, false, false) +IMPLEMENT_CLASS(AArtiPoisonBagGiver, false, false) bool AArtiPoisonBagGiver::Use (bool pickup) { @@ -167,7 +167,7 @@ public: bool Use (bool pickup); }; -IMPLEMENT_CLASS(AArtiPoisonBagShooter, false, false, false, false) +IMPLEMENT_CLASS(AArtiPoisonBagShooter, false, false) bool AArtiPoisonBagShooter::Use (bool pickup) { @@ -296,7 +296,7 @@ public: void BeginPlay (); }; -IMPLEMENT_CLASS(APoisonCloud, false, false, false, false) +IMPLEMENT_CLASS(APoisonCloud, false, false) void APoisonCloud::BeginPlay () { diff --git a/src/g_hexen/a_healingradius.cpp b/src/g_hexen/a_healingradius.cpp index 25efbc3ca..bf18a7e0e 100644 --- a/src/g_hexen/a_healingradius.cpp +++ b/src/g_hexen/a_healingradius.cpp @@ -25,7 +25,7 @@ public: bool Use (bool pickup); }; -IMPLEMENT_CLASS(AArtiHealingRadius, false, false, false, false) +IMPLEMENT_CLASS(AArtiHealingRadius, false, false) bool AArtiHealingRadius::Use (bool pickup) { diff --git a/src/g_hexen/a_heresiarch.cpp b/src/g_hexen/a_heresiarch.cpp index 32ad9ab69..a53d9926d 100644 --- a/src/g_hexen/a_heresiarch.cpp +++ b/src/g_hexen/a_heresiarch.cpp @@ -72,7 +72,7 @@ public: void Die (AActor *source, AActor *inflictor, int dmgflags); }; -IMPLEMENT_CLASS(AHeresiarch, false, false, false, false) +IMPLEMENT_CLASS(AHeresiarch, false, false) void AHeresiarch::Serialize(FSerializer &arc) { @@ -122,7 +122,7 @@ public: } }; -IMPLEMENT_CLASS(ASorcBall, false, false, false, false) +IMPLEMENT_CLASS(ASorcBall, false, false) // First ball (purple) - fires projectiles ---------------------------------- @@ -140,7 +140,7 @@ public: virtual void CastSorcererSpell (); }; -IMPLEMENT_CLASS(ASorcBall1, false, false, false, false) +IMPLEMENT_CLASS(ASorcBall1, false, false) // Second ball (blue) - generates the shield -------------------------------- @@ -156,7 +156,7 @@ public: virtual void CastSorcererSpell (); }; -IMPLEMENT_CLASS(ASorcBall2, false, false, false, false) +IMPLEMENT_CLASS(ASorcBall2, false, false) // Third ball (green) - summons Bishops ------------------------------------- @@ -172,7 +172,7 @@ public: virtual void CastSorcererSpell (); }; -IMPLEMENT_CLASS(ASorcBall3, false, false, false, false) +IMPLEMENT_CLASS(ASorcBall3, false, false) // Sorcerer spell 1 (The burning, bouncing head thing) ---------------------- diff --git a/src/g_hexen/a_hexenspecialdecs.cpp b/src/g_hexen/a_hexenspecialdecs.cpp index 0dcdc2c5f..1745e6efc 100644 --- a/src/g_hexen/a_hexenspecialdecs.cpp +++ b/src/g_hexen/a_hexenspecialdecs.cpp @@ -121,7 +121,7 @@ public: void PostBeginPlay (); }; -IMPLEMENT_CLASS(AZCorpseLynchedNoHeart, false, false, false, false) +IMPLEMENT_CLASS(AZCorpseLynchedNoHeart, false, false) void AZCorpseLynchedNoHeart::PostBeginPlay () { @@ -329,7 +329,7 @@ public: void Activate (AActor *activator); }; -IMPLEMENT_CLASS(AZBell, false, false, false, false) +IMPLEMENT_CLASS(AZBell, false, false) void AZBell::Activate (AActor *activator) { diff --git a/src/g_hexen/a_magecone.cpp b/src/g_hexen/a_magecone.cpp index da53a829c..102f68155 100644 --- a/src/g_hexen/a_magecone.cpp +++ b/src/g_hexen/a_magecone.cpp @@ -32,7 +32,7 @@ public: int DoSpecialDamage (AActor *victim, int damage, FName damagetype); }; -IMPLEMENT_CLASS(AFrostMissile, false, false, false, false) +IMPLEMENT_CLASS(AFrostMissile, false, false) int AFrostMissile::DoSpecialDamage (AActor *victim, int damage, FName damagetype) { diff --git a/src/g_hexen/a_magelightning.cpp b/src/g_hexen/a_magelightning.cpp index 2a744db75..d5fcef880 100644 --- a/src/g_hexen/a_magelightning.cpp +++ b/src/g_hexen/a_magelightning.cpp @@ -34,7 +34,7 @@ public: int SpecialMissileHit (AActor *victim); }; -IMPLEMENT_CLASS(ALightning, false, false, false, false) +IMPLEMENT_CLASS(ALightning, false, false) int ALightning::SpecialMissileHit (AActor *thing) { @@ -87,7 +87,7 @@ public: int SpecialMissileHit (AActor *thing); }; -IMPLEMENT_CLASS(ALightningZap, false, false, false, false) +IMPLEMENT_CLASS(ALightningZap, false, false) int ALightningZap::SpecialMissileHit (AActor *thing) { diff --git a/src/g_hexen/a_magestaff.cpp b/src/g_hexen/a_magestaff.cpp index 0b78bd279..78d9edec0 100644 --- a/src/g_hexen/a_magestaff.cpp +++ b/src/g_hexen/a_magestaff.cpp @@ -56,7 +56,7 @@ public: BYTE MStaffCount; }; -IMPLEMENT_CLASS(AMWeapBloodscourge, false, false, false, false) +IMPLEMENT_CLASS(AMWeapBloodscourge, false, false) // Mage Staff FX2 (Bloodscourge) -------------------------------------------- @@ -68,7 +68,7 @@ public: bool SpecialBlastHandling (AActor *source, double strength); }; -IMPLEMENT_CLASS(AMageStaffFX2, false, false, false, false) +IMPLEMENT_CLASS(AMageStaffFX2, false, false) int AMageStaffFX2::SpecialMissileHit (AActor *victim) { diff --git a/src/g_hexen/a_spike.cpp b/src/g_hexen/a_spike.cpp index be28e38df..cd0d2e891 100644 --- a/src/g_hexen/a_spike.cpp +++ b/src/g_hexen/a_spike.cpp @@ -26,7 +26,7 @@ public: void Deactivate (AActor *activator); }; -IMPLEMENT_CLASS(AThrustFloor, false, false, false, false) +IMPLEMENT_CLASS(AThrustFloor, false, false) void AThrustFloor::Activate (AActor *activator) { diff --git a/src/g_hexen/a_summon.cpp b/src/g_hexen/a_summon.cpp index 7c0746c91..58e50eeaf 100644 --- a/src/g_hexen/a_summon.cpp +++ b/src/g_hexen/a_summon.cpp @@ -21,7 +21,7 @@ public: bool Use (bool pickup); }; -IMPLEMENT_CLASS(AArtiDarkServant, false, false, false, false) +IMPLEMENT_CLASS(AArtiDarkServant, false, false) //============================================================================ // diff --git a/src/g_hexen/a_teleportother.cpp b/src/g_hexen/a_teleportother.cpp index 4eeba53f9..0e7dd018d 100644 --- a/src/g_hexen/a_teleportother.cpp +++ b/src/g_hexen/a_teleportother.cpp @@ -34,7 +34,7 @@ public: bool Use (bool pickup); }; -IMPLEMENT_CLASS(AArtiTeleportOther, false, false, false, false) +IMPLEMENT_CLASS(AArtiTeleportOther, false, false) // Teleport Other FX -------------------------------------------------------- @@ -45,7 +45,7 @@ public: int DoSpecialDamage (AActor *target, int damage, FName damagetype); }; -IMPLEMENT_CLASS(ATelOtherFX1, false, false, false, false) +IMPLEMENT_CLASS(ATelOtherFX1, false, false) static void TeloSpawn (AActor *source, const char *type) { diff --git a/src/g_level.cpp b/src/g_level.cpp index a715b5d26..904b38b8a 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -903,7 +903,7 @@ public: void Tick (); }; -IMPLEMENT_CLASS(DAutosaver, false, false, false, false) +IMPLEMENT_CLASS(DAutosaver, false, false) void DAutosaver::Tick () { diff --git a/src/g_raven/a_artitele.cpp b/src/g_raven/a_artitele.cpp index b333c9a13..76c0bc402 100644 --- a/src/g_raven/a_artitele.cpp +++ b/src/g_raven/a_artitele.cpp @@ -23,7 +23,7 @@ public: bool Use (bool pickup); }; -IMPLEMENT_CLASS(AArtiTeleport, false, false, false, false) +IMPLEMENT_CLASS(AArtiTeleport, false, false) bool AArtiTeleport::Use (bool pickup) { diff --git a/src/g_raven/a_minotaur.cpp b/src/g_raven/a_minotaur.cpp index dd4e4a8b8..cd0ab2669 100644 --- a/src/g_raven/a_minotaur.cpp +++ b/src/g_raven/a_minotaur.cpp @@ -31,7 +31,7 @@ void P_MinotaurSlam (AActor *source, AActor *target); DECLARE_ACTION(A_MinotaurLook) -IMPLEMENT_CLASS(AMinotaur, false, false, false, false) +IMPLEMENT_CLASS(AMinotaur, false, false) void AMinotaur::Tick () { @@ -72,7 +72,7 @@ int AMinotaur::DoSpecialDamage (AActor *target, int damage, FName damagetype) // Minotaur Friend ---------------------------------------------------------- -IMPLEMENT_CLASS(AMinotaurFriend, false, false, false, false) +IMPLEMENT_CLASS(AMinotaurFriend, false, false) void AMinotaurFriend::BeginPlay () { diff --git a/src/g_shared/a_action.cpp b/src/g_shared/a_action.cpp index a371e4ad5..3938a9743 100644 --- a/src/g_shared/a_action.cpp +++ b/src/g_shared/a_action.cpp @@ -28,7 +28,7 @@ public: void Deactivate (AActor *activator); }; -IMPLEMENT_CLASS(ASwitchableDecoration, false, false, false, false) +IMPLEMENT_CLASS(ASwitchableDecoration, false, false) void ASwitchableDecoration::Activate (AActor *activator) { @@ -49,7 +49,7 @@ public: void Deactivate (AActor *activator) {} }; -IMPLEMENT_CLASS(ASwitchingDecoration, false, false, false, false) +IMPLEMENT_CLASS(ASwitchingDecoration, false, false) //---------------------------------------------------------------------------- // @@ -295,7 +295,7 @@ class DCorpsePointer : public DThinker HAS_OBJECT_POINTERS public: DCorpsePointer (AActor *ptr); - void Destroy (); + void Destroy() override; void Serialize(FSerializer &arc); TObjPtr Corpse; DWORD Count; // Only the first corpse pointer's count is valid. @@ -303,7 +303,7 @@ private: DCorpsePointer () {} }; -IMPLEMENT_CLASS(DCorpsePointer, false, true, false, false) +IMPLEMENT_CLASS(DCorpsePointer, false, true) IMPLEMENT_POINTERS_START(DCorpsePointer) IMPLEMENT_POINTER(Corpse) diff --git a/src/g_shared/a_armor.cpp b/src/g_shared/a_armor.cpp index e1dd0986e..6be1472bf 100644 --- a/src/g_shared/a_armor.cpp +++ b/src/g_shared/a_armor.cpp @@ -9,11 +9,11 @@ #include "serializer.h" #include "cmdlib.h" -IMPLEMENT_CLASS(AArmor, false, false, false, false) -IMPLEMENT_CLASS(ABasicArmor, false, false, false, false) -IMPLEMENT_CLASS(ABasicArmorPickup, false, false, false, false) -IMPLEMENT_CLASS(ABasicArmorBonus, false, false, true, false) -IMPLEMENT_CLASS(AHexenArmor, false, false, false, false) +IMPLEMENT_CLASS(AArmor, false, false) +IMPLEMENT_CLASS(ABasicArmor, false, false) +IMPLEMENT_CLASS(ABasicArmorPickup, false, false) +IMPLEMENT_CLASS(ABasicArmorBonus, false, false) +IMPLEMENT_CLASS(AHexenArmor, false, false) DEFINE_FIELD(ABasicArmor, AbsorbCount) diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index bf24c8eb8..73b71e2ff 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -40,11 +40,11 @@ static FRandom pr_torch ("Torch"); #define TIMEFREEZE_TICS ( 12 * TICRATE ) */ -IMPLEMENT_CLASS(APowerup, false, false, false, false) +IMPLEMENT_CLASS(APowerup, false, false) // Powerup-Giver ------------------------------------------------------------- -IMPLEMENT_CLASS(PClassPowerupGiver, false, false, false, false) +IMPLEMENT_CLASS(PClassPowerupGiver, false, false) void PClassPowerupGiver::ReplaceClassRef(PClass *oldclass, PClass *newclass) { @@ -388,7 +388,7 @@ bool APowerup::GetNoTeleportFreeze () // Invulnerability Powerup --------------------------------------------------- -IMPLEMENT_CLASS(APowerInvulnerable, false, false, false, false) +IMPLEMENT_CLASS(APowerInvulnerable, false, false) //=========================================================================== // @@ -525,7 +525,7 @@ int APowerInvulnerable::AlterWeaponSprite (visstyle_t *vis) // Strength (aka Berserk) Powerup -------------------------------------------- -IMPLEMENT_CLASS(APowerStrength, false, false, false, false) +IMPLEMENT_CLASS(APowerStrength, false, false) //=========================================================================== // @@ -590,7 +590,7 @@ PalEntry APowerStrength::GetBlend () // Invisibility Powerup ------------------------------------------------------ -IMPLEMENT_CLASS(APowerInvisibility, false, false, false, false) +IMPLEMENT_CLASS(APowerInvisibility, false, false) // Invisibility flag combos #define INVISIBILITY_FLAGS1 (MF_SHADOW) @@ -795,7 +795,7 @@ bool APowerInvisibility::HandlePickup (AInventory *item) // Ironfeet Powerup ---------------------------------------------------------- -IMPLEMENT_CLASS(APowerIronFeet, false, false, false, false) +IMPLEMENT_CLASS(APowerIronFeet, false, false) //=========================================================================== // @@ -832,7 +832,7 @@ void APowerIronFeet::DoEffect () // Strife Environment Suit Powerup ------------------------------------------- -IMPLEMENT_CLASS(APowerMask, false, false, false, false) +IMPLEMENT_CLASS(APowerMask, false, false) //=========================================================================== // @@ -869,7 +869,7 @@ void APowerMask::DoEffect () // Light-Amp Powerup --------------------------------------------------------- -IMPLEMENT_CLASS(APowerLightAmp, false, false, false, false) +IMPLEMENT_CLASS(APowerLightAmp, false, false) //=========================================================================== // @@ -911,7 +911,7 @@ void APowerLightAmp::EndEffect () // Torch Powerup ------------------------------------------------------------- -IMPLEMENT_CLASS(APowerTorch, false, false, false, false) +IMPLEMENT_CLASS(APowerTorch, false, false) //=========================================================================== // @@ -974,7 +974,7 @@ void APowerTorch::DoEffect () // Flight (aka Wings of Wrath) powerup --------------------------------------- -IMPLEMENT_CLASS(APowerFlight, false, false, false, false) +IMPLEMENT_CLASS(APowerFlight, false, false) //=========================================================================== // @@ -1114,7 +1114,7 @@ bool APowerFlight::DrawPowerup (int x, int y) // Weapon Level 2 (aka Tome of Power) Powerup -------------------------------- -IMPLEMENT_CLASS(APowerWeaponLevel2, false, false, false, false) +IMPLEMENT_CLASS(APowerWeaponLevel2, false, false) //=========================================================================== // @@ -1198,7 +1198,7 @@ void APowerWeaponLevel2::EndEffect () // Speed Powerup ------------------------------------------------------------- -IMPLEMENT_CLASS(APowerSpeed, false, false, false, false) +IMPLEMENT_CLASS(APowerSpeed, false, false) DEFINE_FIELD(APowerSpeed, SpeedFlags) @@ -1287,11 +1287,11 @@ void APowerSpeed::DoEffect () // Minotaur (aka Dark Servant) powerup --------------------------------------- -IMPLEMENT_CLASS(APowerMinotaur, false, false, false, false) +IMPLEMENT_CLASS(APowerMinotaur, false, false) // Targeter powerup --------------------------------------------------------- -IMPLEMENT_CLASS(APowerTargeter, false, false, false, false) +IMPLEMENT_CLASS(APowerTargeter, false, false) void APowerTargeter::Travelled () { @@ -1406,7 +1406,7 @@ void APowerTargeter::PositionAccuracy () // Frightener Powerup -------------------------------- -IMPLEMENT_CLASS(APowerFrightener, false, false, false, false) +IMPLEMENT_CLASS(APowerFrightener, false, false) //=========================================================================== // @@ -1442,7 +1442,7 @@ void APowerFrightener::EndEffect () // Buddha Powerup -------------------------------- -IMPLEMENT_CLASS(APowerBuddha, false, false, false, false) +IMPLEMENT_CLASS(APowerBuddha, false, false) //=========================================================================== // @@ -1478,11 +1478,11 @@ void APowerBuddha::EndEffect () // Scanner powerup ---------------------------------------------------------- -IMPLEMENT_CLASS(APowerScanner, false, false, false, false) +IMPLEMENT_CLASS(APowerScanner, false, false) // Time freezer powerup ----------------------------------------------------- -IMPLEMENT_CLASS( APowerTimeFreezer, false, false, false, false) +IMPLEMENT_CLASS( APowerTimeFreezer, false, false) //=========================================================================== // @@ -1609,7 +1609,7 @@ void APowerTimeFreezer::EndEffect() // Damage powerup ------------------------------------------------------ -IMPLEMENT_CLASS(APowerDamage, false, false, false, false) +IMPLEMENT_CLASS(APowerDamage, false, false) //=========================================================================== // @@ -1666,7 +1666,7 @@ void APowerDamage::ModifyDamage(int damage, FName damageType, int &newdamage, bo // Quarter damage powerup ------------------------------------------------------ -IMPLEMENT_CLASS(APowerProtection, false, false, false, false) +IMPLEMENT_CLASS(APowerProtection, false, false) #define PROTECTION_FLAGS3 (MF3_NORADIUSDMG | MF3_DONTMORPH | MF3_DONTSQUASH | MF3_DONTBLAST | MF3_NOTELEOTHER) #define PROTECTION_FLAGS5 (MF5_NOPAIN | MF5_DONTRIP) @@ -1744,7 +1744,7 @@ void APowerProtection::ModifyDamage(int damage, FName damageType, int &newdamage // Drain rune ------------------------------------------------------- -IMPLEMENT_CLASS(APowerDrain, false, false, false, false) +IMPLEMENT_CLASS(APowerDrain, false, false) //=========================================================================== // @@ -1784,7 +1784,7 @@ void APowerDrain::EndEffect( ) // Regeneration rune ------------------------------------------------------- -IMPLEMENT_CLASS(APowerRegeneration, false, false, false, false) +IMPLEMENT_CLASS(APowerRegeneration, false, false) //=========================================================================== // @@ -1806,7 +1806,7 @@ void APowerRegeneration::DoEffect() // High jump rune ------------------------------------------------------- -IMPLEMENT_CLASS(APowerHighJump, false, false, false, false) +IMPLEMENT_CLASS(APowerHighJump, false, false) //=========================================================================== // @@ -1844,7 +1844,7 @@ void APowerHighJump::EndEffect( ) // Double firing speed rune --------------------------------------------- -IMPLEMENT_CLASS(APowerDoubleFiringSpeed, false, false, false, false) +IMPLEMENT_CLASS(APowerDoubleFiringSpeed, false, false) //=========================================================================== // @@ -1882,7 +1882,7 @@ void APowerDoubleFiringSpeed::EndEffect( ) // Morph powerup ------------------------------------------------------ -IMPLEMENT_CLASS(APowerMorph, false, false, false, false) +IMPLEMENT_CLASS(APowerMorph, false, false) DEFINE_FIELD(APowerMorph, PlayerClass) DEFINE_FIELD(APowerMorph, MorphFlash) @@ -1990,7 +1990,7 @@ void APowerMorph::EndEffect( ) // Infinite Ammo Powerup ----------------------------------------------------- -IMPLEMENT_CLASS(APowerInfiniteAmmo, false, false, false, false) +IMPLEMENT_CLASS(APowerInfiniteAmmo, false, false) //=========================================================================== // diff --git a/src/g_shared/a_artifacts.h b/src/g_shared/a_artifacts.h index d9629c165..95de95086 100644 --- a/src/g_shared/a_artifacts.h +++ b/src/g_shared/a_artifacts.h @@ -12,7 +12,7 @@ class APowerup : public AInventory DECLARE_CLASS (APowerup, AInventory) public: virtual void Tick (); - virtual void Destroy (); + virtual void Destroy () override; virtual bool HandlePickup (AInventory *item); virtual AInventory *CreateCopy (AActor *other); virtual AInventory *CreateTossable (); diff --git a/src/g_shared/a_bridge.cpp b/src/g_shared/a_bridge.cpp index c4b452f77..556767f37 100644 --- a/src/g_shared/a_bridge.cpp +++ b/src/g_shared/a_bridge.cpp @@ -37,10 +37,10 @@ class ACustomBridge : public AActor DECLARE_CLASS (ACustomBridge, AActor) public: void BeginPlay (); - void Destroy(); + void Destroy() override; }; -IMPLEMENT_CLASS(ACustomBridge, false, false, false, false) +IMPLEMENT_CLASS(ACustomBridge, false, false) void ACustomBridge::BeginPlay () { @@ -155,7 +155,7 @@ public: void BeginPlay (); }; -IMPLEMENT_CLASS(AInvisibleBridge, false, false, false, false) +IMPLEMENT_CLASS(AInvisibleBridge, false, false) void AInvisibleBridge::BeginPlay () { diff --git a/src/g_shared/a_camera.cpp b/src/g_shared/a_camera.cpp index ae34c3cbc..a0bc40ce3 100644 --- a/src/g_shared/a_camera.cpp +++ b/src/g_shared/a_camera.cpp @@ -64,7 +64,7 @@ protected: DAngle Range; }; -IMPLEMENT_CLASS(ASecurityCamera, false, false, false, false) +IMPLEMENT_CLASS(ASecurityCamera, false, false) void ASecurityCamera::Serialize(FSerializer &arc) { @@ -124,7 +124,7 @@ protected: DAngle MaxPitchChange; }; -IMPLEMENT_CLASS(AAimingCamera, false, false, false, false) +IMPLEMENT_CLASS(AAimingCamera, false, false) void AAimingCamera::Serialize(FSerializer &arc) { diff --git a/src/g_shared/a_debris.cpp b/src/g_shared/a_debris.cpp index d3d69d7f6..0932088c2 100644 --- a/src/g_shared/a_debris.cpp +++ b/src/g_shared/a_debris.cpp @@ -23,5 +23,5 @@ public: } }; -IMPLEMENT_CLASS(AGlassShard, false, false, false, false) +IMPLEMENT_CLASS(AGlassShard, false, false) diff --git a/src/g_shared/a_decals.cpp b/src/g_shared/a_decals.cpp index 06563f995..bfbe6d13d 100644 --- a/src/g_shared/a_decals.cpp +++ b/src/g_shared/a_decals.cpp @@ -58,14 +58,14 @@ static int ImpactCount; CVAR (Bool, cl_spreaddecals, true, CVAR_ARCHIVE) -IMPLEMENT_CLASS(DBaseDecal, false, true, false, false) +IMPLEMENT_CLASS(DBaseDecal, false, true) IMPLEMENT_POINTERS_START(DBaseDecal) IMPLEMENT_POINTER(WallPrev) IMPLEMENT_POINTER(WallNext) IMPLEMENT_POINTERS_END -IMPLEMENT_CLASS(DImpactDecal, false, false, false, false) +IMPLEMENT_CLASS(DImpactDecal, false, false) DBaseDecal::DBaseDecal () : DThinker(STAT_DECAL), @@ -746,7 +746,7 @@ public: void BeginPlay (); }; -IMPLEMENT_CLASS(ADecal, false, false, false, false) +IMPLEMENT_CLASS(ADecal, false, false) void ADecal::BeginPlay () { diff --git a/src/g_shared/a_fastprojectile.cpp b/src/g_shared/a_fastprojectile.cpp index 1ded466a9..c68fa800c 100644 --- a/src/g_shared/a_fastprojectile.cpp +++ b/src/g_shared/a_fastprojectile.cpp @@ -8,7 +8,7 @@ #include "p_checkposition.h" #include "virtual.h" -IMPLEMENT_CLASS(AFastProjectile, false, false, false, false) +IMPLEMENT_CLASS(AFastProjectile, false, false) //---------------------------------------------------------------------------- @@ -135,11 +135,13 @@ void AFastProjectile::Tick () ripcount = count >> 3; // call the scripted 'Effect' method. - VINDEX(AFastProjectile, Effect); - // Without the type cast this picks the 'void *' assignment... - VMValue params[1] = { (DObject*)this }; - VMFrameStack stack; - stack.Call(VFUNC, params, 1, nullptr, 0, nullptr); + IFVIRTUAL(AFastProjectile, Effect) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { (DObject*)this }; + VMFrameStack stack; + stack.Call(func, params, 1, nullptr, 0, nullptr); + } } } } diff --git a/src/g_shared/a_flashfader.cpp b/src/g_shared/a_flashfader.cpp index 8602f7a86..3e0b939e0 100644 --- a/src/g_shared/a_flashfader.cpp +++ b/src/g_shared/a_flashfader.cpp @@ -3,7 +3,7 @@ #include "d_player.h" #include "serializer.h" -IMPLEMENT_CLASS(DFlashFader, false, true, false, false) +IMPLEMENT_CLASS(DFlashFader, false, true) IMPLEMENT_POINTERS_START(DFlashFader) IMPLEMENT_POINTER(ForWho) diff --git a/src/g_shared/a_fountain.cpp b/src/g_shared/a_fountain.cpp index e89745fc7..7d7e2e412 100644 --- a/src/g_shared/a_fountain.cpp +++ b/src/g_shared/a_fountain.cpp @@ -46,13 +46,13 @@ public: void Deactivate (AActor *activator); }; -IMPLEMENT_CLASS(AParticleFountain, false, false, false, false) +IMPLEMENT_CLASS(AParticleFountain, false, false) void AParticleFountain::PostBeginPlay () { Super::PostBeginPlay (); if (!(SpawnFlags & MTF_DORMANT)) - Activate (NULL); + CallActivate (NULL); } void AParticleFountain::Activate (AActor *activator) diff --git a/src/g_shared/a_hatetarget.cpp b/src/g_shared/a_hatetarget.cpp index 7d25bdb31..8d5b0fa72 100644 --- a/src/g_shared/a_hatetarget.cpp +++ b/src/g_shared/a_hatetarget.cpp @@ -46,7 +46,7 @@ public: int TakeSpecialDamage(AActor *inflictor, AActor *source, int damage, FName damagetype); }; -IMPLEMENT_CLASS(AHateTarget, false, false, false, false) +IMPLEMENT_CLASS(AHateTarget, false, false) void AHateTarget::BeginPlay() { diff --git a/src/g_shared/a_keys.cpp b/src/g_shared/a_keys.cpp index 538e26090..51962c1b0 100644 --- a/src/g_shared/a_keys.cpp +++ b/src/g_shared/a_keys.cpp @@ -470,7 +470,7 @@ bool P_CheckKeys (AActor *owner, int keynum, bool remote) // //========================================================================== -IMPLEMENT_CLASS(AKey, false, false, false, false) +IMPLEMENT_CLASS(AKey, false, false) DEFINE_FIELD(AKey, KeyNumber) diff --git a/src/g_shared/a_lightning.cpp b/src/g_shared/a_lightning.cpp index f00560fc8..3f44f2fdd 100644 --- a/src/g_shared/a_lightning.cpp +++ b/src/g_shared/a_lightning.cpp @@ -13,7 +13,7 @@ static FRandom pr_lightning ("Lightning"); -IMPLEMENT_CLASS(DLightningThinker, false, false, false, false) +IMPLEMENT_CLASS(DLightningThinker, false, false) DLightningThinker::DLightningThinker () : DThinker (STAT_LIGHTNING) diff --git a/src/g_shared/a_mapmarker.cpp b/src/g_shared/a_mapmarker.cpp index d874042c5..524bfca44 100644 --- a/src/g_shared/a_mapmarker.cpp +++ b/src/g_shared/a_mapmarker.cpp @@ -51,7 +51,7 @@ // //-------------------------------------------------------------------------- -IMPLEMENT_CLASS(AMapMarker, false, false, false, false) +IMPLEMENT_CLASS(AMapMarker, false, false) void AMapMarker::BeginPlay () { diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 84de5a0d6..5514ae413 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -616,7 +616,7 @@ void InitAllPowerupEffects(AInventory *item) // Base class for morphing projectiles -------------------------------------- -IMPLEMENT_CLASS(AMorphProjectile, false, false, false, false) +IMPLEMENT_CLASS(AMorphProjectile, false, false) DEFINE_FIELD(AMorphProjectile, PlayerClass) DEFINE_FIELD(AMorphProjectile, MonsterClass) @@ -653,7 +653,7 @@ void AMorphProjectile::Serialize(FSerializer &arc) // Morphed Monster (you must subclass this to do something useful) --------- -IMPLEMENT_CLASS(AMorphedMonster, false, true, false, false) +IMPLEMENT_CLASS(AMorphedMonster, false, true) IMPLEMENT_POINTERS_START(AMorphedMonster) IMPLEMENT_POINTER(UnmorphedMe) diff --git a/src/g_shared/a_movingcamera.cpp b/src/g_shared/a_movingcamera.cpp index 030f5d368..a1ffe5dc6 100644 --- a/src/g_shared/a_movingcamera.cpp +++ b/src/g_shared/a_movingcamera.cpp @@ -66,7 +66,7 @@ public: TObjPtr Next; }; -IMPLEMENT_CLASS(AInterpolationPoint, false, true, false, false) +IMPLEMENT_CLASS(AInterpolationPoint, false, true) IMPLEMENT_POINTERS_START(AInterpolationPoint) IMPLEMENT_POINTER(Next) @@ -135,7 +135,7 @@ public: void Tick () {} // Does absolutely nothing itself }; -IMPLEMENT_CLASS(AInterpolationSpecial, false, false, false, false) +IMPLEMENT_CLASS(AInterpolationSpecial, false, false) /* == PathFollower: something that follows a camera path @@ -178,7 +178,7 @@ protected: int HoldTime; }; -IMPLEMENT_CLASS(APathFollower, false, true, false, false) +IMPLEMENT_CLASS(APathFollower, false, true) IMPLEMENT_POINTERS_START(APathFollower) IMPLEMENT_POINTER(PrevNode) @@ -342,9 +342,9 @@ void APathFollower::Tick () if (CurrNode != NULL) NewNode (); if (CurrNode == NULL || CurrNode->Next == NULL) - Deactivate (this); + CallDeactivate (this); if ((args[2] & 1) == 0 && CurrNode->Next->Next == NULL) - Deactivate (this); + CallDeactivate (this); } } } @@ -480,7 +480,7 @@ protected: bool Interpolate (); }; -IMPLEMENT_CLASS(AActorMover, false, false, false, false) +IMPLEMENT_CLASS(AActorMover, false, false) void AActorMover::BeginPlay() { @@ -596,7 +596,7 @@ protected: TObjPtr Activator; }; -IMPLEMENT_CLASS(AMovingCamera, false, true, false, false) +IMPLEMENT_CLASS(AMovingCamera, false, true) IMPLEMENT_POINTERS_START(AMovingCamera) IMPLEMENT_POINTER(Activator) diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index c6475cc74..16a63a2ff 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -23,7 +23,7 @@ static FRandom pr_restore ("RestorePos"); -IMPLEMENT_CLASS(PClassInventory, false, false, false, false) +IMPLEMENT_CLASS(PClassInventory, false, false) PClassInventory::PClassInventory() { @@ -70,7 +70,7 @@ void PClassInventory::Finalize(FStateDefinitions &statedef) ((AActor*)Defaults)->flags |= MF_SPECIAL; } -IMPLEMENT_CLASS(PClassAmmo, false, false, false, false) +IMPLEMENT_CLASS(PClassAmmo, false, false) PClassAmmo::PClassAmmo() { @@ -86,7 +86,7 @@ void PClassAmmo::DeriveData(PClass *newclass) newc->DropAmount = DropAmount; } -IMPLEMENT_CLASS(AAmmo, false, false, false, false) +IMPLEMENT_CLASS(AAmmo, false, false) DEFINE_FIELD(AAmmo, BackpackAmount) DEFINE_FIELD(AAmmo, BackpackMaxAmount) @@ -480,7 +480,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialPosition) int AInventory::StaticLastMessageTic; const char *AInventory::StaticLastMessage; -IMPLEMENT_CLASS(AInventory, false, true, false, false) +IMPLEMENT_CLASS(AInventory, false, true) IMPLEMENT_POINTERS_START(AInventory) IMPLEMENT_POINTER(Owner) @@ -1378,7 +1378,7 @@ bool AInventory::DrawPowerup (int x, int y) /* AArtifact implementation */ /***************************************************************************/ -IMPLEMENT_CLASS(APowerupGiver, false, false, false, false) +IMPLEMENT_CLASS(APowerupGiver, false, false) //=========================================================================== // @@ -1679,8 +1679,8 @@ void AInventory::DetachFromOwner () { } -IMPLEMENT_CLASS(AStateProvider, false, false, false, false) -IMPLEMENT_CLASS(ACustomInventory, false, false, false, false) +IMPLEMENT_CLASS(AStateProvider, false, false) +IMPLEMENT_CLASS(ACustomInventory, false, false) //=========================================================================== // @@ -1725,7 +1725,7 @@ bool ACustomInventory::TryPickup (AActor *&toucher) return useok; } -IMPLEMENT_CLASS(PClassHealth, false, false, false, false) +IMPLEMENT_CLASS(PClassHealth, false, false) //=========================================================================== // @@ -1754,7 +1754,7 @@ void PClassHealth::DeriveData(PClass *newclass) newc->LowHealthMessage = LowHealthMessage; } -IMPLEMENT_CLASS(AHealth, false, false, false, false) +IMPLEMENT_CLASS(AHealth, false, false) DEFINE_FIELD(AHealth, PrevHealth) @@ -1799,7 +1799,7 @@ bool AHealth::TryPickup (AActor *&other) return false; } -IMPLEMENT_CLASS(AHealthPickup, false, false, false, false) +IMPLEMENT_CLASS(AHealthPickup, false, false) DEFINE_FIELD(AHealthPickup, autousemode) @@ -1879,7 +1879,7 @@ void AHealthPickup::Serialize(FSerializer &arc) // Backpack ----------------------------------------------------------------- -IMPLEMENT_CLASS(ABackpackItem, false, false, false, false) +IMPLEMENT_CLASS(ABackpackItem, false, false) DEFINE_FIELD(ABackpackItem, bDepleted) @@ -2058,7 +2058,7 @@ void ABackpackItem::DetachFromOwner () // //=========================================================================== -IMPLEMENT_CLASS(AMapRevealer, false, false, false, false) +IMPLEMENT_CLASS(AMapRevealer, false, false) //=========================================================================== // @@ -2083,7 +2083,7 @@ bool AMapRevealer::TryPickup (AActor *&toucher) // //=========================================================================== -IMPLEMENT_CLASS(AScoreItem, false, false, false, false) +IMPLEMENT_CLASS(AScoreItem, false, false) //=========================================================================== // diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index ec34404df..bf4af5a63 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -159,7 +159,7 @@ public: virtual void MarkPrecacheSounds() const; virtual void BeginPlay (); - virtual void Destroy (); + virtual void Destroy () override; virtual void DepleteOrDestroy (); virtual void Tick (); virtual bool ShouldRespawn (); @@ -331,7 +331,7 @@ public: virtual bool TryPickupRestricted (AActor *&toucher); virtual bool PickupForAmmo (AWeapon *ownedWeapon); virtual bool Use (bool pickup); - virtual void Destroy(); + virtual void Destroy() override; virtual FState *GetUpState (); virtual FState *GetDownState (); diff --git a/src/g_shared/a_puzzleitems.cpp b/src/g_shared/a_puzzleitems.cpp index 640d5517d..0d63bb00c 100644 --- a/src/g_shared/a_puzzleitems.cpp +++ b/src/g_shared/a_puzzleitems.cpp @@ -8,7 +8,7 @@ #include "doomstat.h" #include "v_font.h" -IMPLEMENT_CLASS(PClassPuzzleItem, false, false, false, false) +IMPLEMENT_CLASS(PClassPuzzleItem, false, false) void PClassPuzzleItem::DeriveData(PClass *newclass) { @@ -17,7 +17,7 @@ void PClassPuzzleItem::DeriveData(PClass *newclass) static_cast(newclass)->PuzzFailMessage = PuzzFailMessage; } -IMPLEMENT_CLASS(APuzzleItem, false, false, false, false) +IMPLEMENT_CLASS(APuzzleItem, false, false) DEFINE_FIELD(APuzzleItem, PuzzleItemNumber) diff --git a/src/g_shared/a_quake.cpp b/src/g_shared/a_quake.cpp index 80a53ee08..96a932d4f 100644 --- a/src/g_shared/a_quake.cpp +++ b/src/g_shared/a_quake.cpp @@ -14,7 +14,7 @@ static FRandom pr_quake ("Quake"); -IMPLEMENT_CLASS(DEarthquake, false, true, false, false) +IMPLEMENT_CLASS(DEarthquake, false, true) IMPLEMENT_POINTERS_START(DEarthquake) IMPLEMENT_POINTER(m_Spot) diff --git a/src/g_shared/a_randomspawner.cpp b/src/g_shared/a_randomspawner.cpp index 40fdd0745..0cecfd115 100644 --- a/src/g_shared/a_randomspawner.cpp +++ b/src/g_shared/a_randomspawner.cpp @@ -230,4 +230,4 @@ class ARandomSpawner : public AActor }; -IMPLEMENT_CLASS(ARandomSpawner, false, false, false, false) +IMPLEMENT_CLASS(ARandomSpawner, false, false) diff --git a/src/g_shared/a_secrettrigger.cpp b/src/g_shared/a_secrettrigger.cpp index 372cef07d..509ec47e9 100644 --- a/src/g_shared/a_secrettrigger.cpp +++ b/src/g_shared/a_secrettrigger.cpp @@ -50,7 +50,7 @@ public: void Activate (AActor *activator); }; -IMPLEMENT_CLASS(ASecretTrigger, false, false, false, false) +IMPLEMENT_CLASS(ASecretTrigger, false, false) void ASecretTrigger::PostBeginPlay () { diff --git a/src/g_shared/a_sectoraction.cpp b/src/g_shared/a_sectoraction.cpp index 61a69b1b3..2d7037551 100644 --- a/src/g_shared/a_sectoraction.cpp +++ b/src/g_shared/a_sectoraction.cpp @@ -37,7 +37,7 @@ // The base class for sector actions ---------------------------------------- -IMPLEMENT_CLASS(ASectorAction, false, false, false, false) +IMPLEMENT_CLASS(ASectorAction, false, false) ASectorAction::ASectorAction (bool activatedByUse) : ActivatedByUse (activatedByUse) {} @@ -142,7 +142,7 @@ public: bool DoTriggerAction (AActor *triggerer, int activationType); }; -IMPLEMENT_CLASS(ASecActEnter, false, false, false, false) +IMPLEMENT_CLASS(ASecActEnter, false, false) bool ASecActEnter::DoTriggerAction (AActor *triggerer, int activationType) @@ -160,7 +160,7 @@ public: bool DoTriggerAction (AActor *triggerer, int activationType); }; -IMPLEMENT_CLASS(ASecActExit, false, false, false, false) +IMPLEMENT_CLASS(ASecActExit, false, false) bool ASecActExit::DoTriggerAction (AActor *triggerer, int activationType) @@ -181,7 +181,7 @@ public: // Skull Tag uses 9999 for a special that is triggered whenever // the player is on the sector's floor. I think this is more useful. -IMPLEMENT_CLASS(ASecActHitFloor, false, false, false, false) +IMPLEMENT_CLASS(ASecActHitFloor, false, false) bool ASecActHitFloor::DoTriggerAction (AActor *triggerer, int activationType) @@ -199,7 +199,7 @@ public: bool DoTriggerAction (AActor *triggerer, int activationType); }; -IMPLEMENT_CLASS(ASecActHitCeil, false, false, false, false) +IMPLEMENT_CLASS(ASecActHitCeil, false, false) bool ASecActHitCeil::DoTriggerAction (AActor *triggerer, int activationType) @@ -218,7 +218,7 @@ public: bool DoTriggerAction (AActor *triggerer, int activationType); }; -IMPLEMENT_CLASS(ASecActUse, false, false, false, false) +IMPLEMENT_CLASS(ASecActUse, false, false) bool ASecActUse::DoTriggerAction (AActor *triggerer, int activationType) @@ -237,7 +237,7 @@ public: bool DoTriggerAction (AActor *triggerer, int activationType); }; -IMPLEMENT_CLASS(ASecActUseWall, false, false, false, false) +IMPLEMENT_CLASS(ASecActUseWall, false, false) bool ASecActUseWall::DoTriggerAction (AActor *triggerer, int activationType) @@ -255,7 +255,7 @@ public: bool DoTriggerAction (AActor *triggerer, int activationType); }; -IMPLEMENT_CLASS(ASecActEyesDive, false, false, false, false) +IMPLEMENT_CLASS(ASecActEyesDive, false, false) bool ASecActEyesDive::DoTriggerAction (AActor *triggerer, int activationType) @@ -273,7 +273,7 @@ public: bool DoTriggerAction (AActor *triggerer, int activationType); }; -IMPLEMENT_CLASS(ASecActEyesSurface, false, false, false, false) +IMPLEMENT_CLASS(ASecActEyesSurface, false, false) bool ASecActEyesSurface::DoTriggerAction (AActor *triggerer, int activationType) @@ -291,7 +291,7 @@ public: bool DoTriggerAction (AActor *triggerer, int activationType); }; -IMPLEMENT_CLASS(ASecActEyesBelowC, false, false, false, false) +IMPLEMENT_CLASS(ASecActEyesBelowC, false, false) bool ASecActEyesBelowC::DoTriggerAction (AActor *triggerer, int activationType) @@ -309,7 +309,7 @@ public: bool DoTriggerAction (AActor *triggerer, int activationType); }; -IMPLEMENT_CLASS(ASecActEyesAboveC, false, false, false, false) +IMPLEMENT_CLASS(ASecActEyesAboveC, false, false) bool ASecActEyesAboveC::DoTriggerAction (AActor *triggerer, int activationType) @@ -327,7 +327,7 @@ public: bool DoTriggerAction (AActor *triggerer, int activationType); }; -IMPLEMENT_CLASS(ASecActHitFakeFloor, false, false, false, false) +IMPLEMENT_CLASS(ASecActHitFakeFloor, false, false) bool ASecActHitFakeFloor::DoTriggerAction (AActor *triggerer, int activationType) diff --git a/src/g_shared/a_setcolor.cpp b/src/g_shared/a_setcolor.cpp index 585b9fcf6..e8a11b850 100644 --- a/src/g_shared/a_setcolor.cpp +++ b/src/g_shared/a_setcolor.cpp @@ -15,7 +15,7 @@ class AColorSetter : public AActor }; -IMPLEMENT_CLASS(AColorSetter, false, false, false, false) +IMPLEMENT_CLASS(AColorSetter, false, false) class AFadeSetter : public AActor { @@ -30,4 +30,4 @@ class AFadeSetter : public AActor }; -IMPLEMENT_CLASS(AFadeSetter, false, false, false, false) +IMPLEMENT_CLASS(AFadeSetter, false, false) diff --git a/src/g_shared/a_sharedglobal.h b/src/g_shared/a_sharedglobal.h index bb85a023c..a690107c9 100644 --- a/src/g_shared/a_sharedglobal.h +++ b/src/g_shared/a_sharedglobal.h @@ -24,7 +24,7 @@ public: DBaseDecal (const DBaseDecal *basis); void Serialize(FSerializer &arc); - void Destroy (); + void Destroy() override; FTextureID StickToWall(side_t *wall, double x, double y, F3DFloor * ffloor); double GetRealZ (const side_t *wall) const; void SetShade (DWORD rgb); @@ -66,7 +66,7 @@ public: static DImpactDecal *StaticCreate(const FDecalTemplate *tpl, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color = 0); void BeginPlay (); - void Destroy (); + void Destroy() override; protected: DBaseDecal *CloneSelf(const FDecalTemplate *tpl, double x, double y, double z, side_t *wall, F3DFloor * ffloor) const; @@ -88,7 +88,7 @@ class ASkyViewpoint : public AActor DECLARE_CLASS (ASkyViewpoint, AActor) public: void BeginPlay (); - void Destroy (); + void Destroy() override; }; // For an EE compatible linedef based definition. @@ -116,7 +116,7 @@ public: DFlashFader (float r1, float g1, float b1, float a1, float r2, float g2, float b2, float a2, float time, AActor *who); - void Destroy (); + void Destroy() override; void Serialize(FSerializer &arc); void Tick (); AActor *WhoFor() { return ForWho; } @@ -206,7 +206,7 @@ public: void Serialize(FSerializer &arc); void Die (AActor *source, AActor *inflictor, int dmgflags); - void Destroy (); + void Destroy() override; TObjPtr UnmorphedMe; int UnmorphTime, MorphStyle; diff --git a/src/g_shared/a_skies.cpp b/src/g_shared/a_skies.cpp index 148a452e0..d42324936 100644 --- a/src/g_shared/a_skies.cpp +++ b/src/g_shared/a_skies.cpp @@ -42,7 +42,7 @@ // arg0 = Visibility*4 for this skybox -IMPLEMENT_CLASS(ASkyViewpoint, false, false, false, false) +IMPLEMENT_CLASS(ASkyViewpoint, false, false) // If this actor has no TID, make it the default sky box void ASkyViewpoint::BeginPlay () @@ -73,7 +73,7 @@ void ASkyViewpoint::Destroy () Super::Destroy(); } -IMPLEMENT_CLASS(ASkyCamCompat, false, false, false, false) +IMPLEMENT_CLASS(ASkyCamCompat, false, false) void ASkyCamCompat::BeginPlay() { @@ -98,7 +98,7 @@ public: void PostBeginPlay (); }; -IMPLEMENT_CLASS(ASkyPicker, false, false, false, false) +IMPLEMENT_CLASS(ASkyPicker, false, false) void ASkyPicker::PostBeginPlay () { @@ -142,7 +142,7 @@ void ASkyPicker::PostBeginPlay () // arg0 = opacity of plane; 0 = invisible, 255 = fully opaque -IMPLEMENT_CLASS(AStackPoint, false, false, false, false) +IMPLEMENT_CLASS(AStackPoint, false, false) void AStackPoint::BeginPlay () { @@ -157,10 +157,10 @@ class ASectorSilencer : public AActor DECLARE_CLASS (ASectorSilencer, AActor) public: void BeginPlay (); - void Destroy (); + void Destroy() override; }; -IMPLEMENT_CLASS(ASectorSilencer, false, false, false, false) +IMPLEMENT_CLASS(ASectorSilencer, false, false) void ASectorSilencer::BeginPlay () { @@ -184,7 +184,7 @@ public: void BeginPlay (); }; -IMPLEMENT_CLASS(ASectorFlagSetter, false, false, false, false) +IMPLEMENT_CLASS(ASectorFlagSetter, false, false) void ASectorFlagSetter::BeginPlay () { diff --git a/src/g_shared/a_soundenvironment.cpp b/src/g_shared/a_soundenvironment.cpp index 8e5cb133b..25088ae44 100644 --- a/src/g_shared/a_soundenvironment.cpp +++ b/src/g_shared/a_soundenvironment.cpp @@ -46,14 +46,14 @@ public: void Activate (AActor *deactivator); }; -IMPLEMENT_CLASS(ASoundEnvironment, false, false, false, false) +IMPLEMENT_CLASS(ASoundEnvironment, false, false) void ASoundEnvironment::PostBeginPlay () { Super::PostBeginPlay (); if (!(flags2 & MF2_DORMANT)) { - Activate (this); + CallActivate (this); } } diff --git a/src/g_shared/a_soundsequence.cpp b/src/g_shared/a_soundsequence.cpp index 25380a4c7..304017fba 100644 --- a/src/g_shared/a_soundsequence.cpp +++ b/src/g_shared/a_soundsequence.cpp @@ -80,7 +80,7 @@ public: TObjPtr Sequence; }; -IMPLEMENT_CLASS(ASoundSequenceSlot, false, true, false, false) +IMPLEMENT_CLASS(ASoundSequenceSlot, false, true) IMPLEMENT_POINTERS_START(ASoundSequenceSlot) IMPLEMENT_POINTER(Sequence) @@ -104,14 +104,14 @@ class ASoundSequence : public AActor { DECLARE_CLASS (ASoundSequence, AActor) public: - void Destroy (); + void Destroy() override; void PostBeginPlay (); void Activate (AActor *activator); void Deactivate (AActor *activator); void MarkPrecacheSounds () const; }; -IMPLEMENT_CLASS(ASoundSequence, false, false, false, false) +IMPLEMENT_CLASS(ASoundSequence, false, false) //========================================================================== // diff --git a/src/g_shared/a_spark.cpp b/src/g_shared/a_spark.cpp index 654ad710b..f13c7178f 100644 --- a/src/g_shared/a_spark.cpp +++ b/src/g_shared/a_spark.cpp @@ -45,7 +45,7 @@ public: void Activate (AActor *activator); }; -IMPLEMENT_CLASS(ASpark, false, false, false, false) +IMPLEMENT_CLASS(ASpark, false, false) void ASpark::Activate (AActor *activator) { diff --git a/src/g_shared/a_specialspot.cpp b/src/g_shared/a_specialspot.cpp index 935333a5c..026185d07 100644 --- a/src/g_shared/a_specialspot.cpp +++ b/src/g_shared/a_specialspot.cpp @@ -44,8 +44,8 @@ static FRandom pr_spot ("SpecialSpot"); static FRandom pr_spawnmace ("SpawnMace"); -IMPLEMENT_CLASS(DSpotState, false, false, false, false) -IMPLEMENT_CLASS(ASpecialSpot, false, false, false, false) +IMPLEMENT_CLASS(DSpotState, false, false) +IMPLEMENT_CLASS(ASpecialSpot, false, false) TObjPtr DSpotState::SpotState; //---------------------------------------------------------------------------- diff --git a/src/g_shared/a_specialspot.h b/src/g_shared/a_specialspot.h index 8fe38608a..57a643bdd 100644 --- a/src/g_shared/a_specialspot.h +++ b/src/g_shared/a_specialspot.h @@ -11,7 +11,7 @@ class ASpecialSpot : public AActor public: void BeginPlay(); - void Destroy(); + void Destroy() override; }; @@ -28,7 +28,7 @@ public: DSpotState (); - void Destroy (); + void Destroy() override; void Tick (); static DSpotState *GetSpotState(bool create = true); FSpotList *FindSpotList(PClassActor *type); diff --git a/src/g_shared/a_waterzone.cpp b/src/g_shared/a_waterzone.cpp index 556d08d7a..2245b22bd 100644 --- a/src/g_shared/a_waterzone.cpp +++ b/src/g_shared/a_waterzone.cpp @@ -42,7 +42,7 @@ public: void PostBeginPlay (); }; -IMPLEMENT_CLASS(AWaterZone, false, false, false, false) +IMPLEMENT_CLASS(AWaterZone, false, false) void AWaterZone::PostBeginPlay () { diff --git a/src/g_shared/a_weaponpiece.cpp b/src/g_shared/a_weaponpiece.cpp index 9edae6906..52c9a9e38 100644 --- a/src/g_shared/a_weaponpiece.cpp +++ b/src/g_shared/a_weaponpiece.cpp @@ -3,8 +3,8 @@ #include "doomstat.h" #include "serializer.h" -IMPLEMENT_CLASS(PClassWeaponPiece, false, false, false, false) -IMPLEMENT_CLASS(AWeaponHolder, false, false, false, false) +IMPLEMENT_CLASS(PClassWeaponPiece, false, false) +IMPLEMENT_CLASS(AWeaponHolder, false, false) DEFINE_FIELD(AWeaponHolder, PieceMask); DEFINE_FIELD(AWeaponHolder, PieceWeapon); @@ -27,7 +27,7 @@ void AWeaponHolder::Serialize(FSerializer &arc) ("pieceweapon", PieceWeapon); } -IMPLEMENT_CLASS(AWeaponPiece, false, true, false, false) +IMPLEMENT_CLASS(AWeaponPiece, false, true) IMPLEMENT_POINTERS_START(AWeaponPiece) IMPLEMENT_POINTER(FullWeapon) diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index 530f8e364..b94a4770c 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -23,7 +23,7 @@ extern FFlagDef WeaponFlagDefs[]; -IMPLEMENT_CLASS(AWeapon, false, true, true, false) +IMPLEMENT_CLASS(AWeapon, false, true) IMPLEMENT_POINTERS_START(AWeapon) IMPLEMENT_POINTER(Ammo1) @@ -80,7 +80,7 @@ TMap Weapons_hton; static int ntoh_cmp(const void *a, const void *b); -IMPLEMENT_CLASS(PClassWeapon, false, false, false, false) +IMPLEMENT_CLASS(PClassWeapon, false, false) //=========================================================================== // @@ -866,7 +866,7 @@ FState *AWeapon::GetStateForButtonName (FName button) /* Weapon giver ***********************************************************/ -IMPLEMENT_CLASS(AWeaponGiver, false, false, false, false) +IMPLEMENT_CLASS(AWeaponGiver, false, false) DEFINE_FIELD(AWeaponGiver, DropAmmoFactor); diff --git a/src/g_shared/hudmessages.cpp b/src/g_shared/hudmessages.cpp index e9370ae79..0db6d4743 100644 --- a/src/g_shared/hudmessages.cpp +++ b/src/g_shared/hudmessages.cpp @@ -44,15 +44,15 @@ EXTERN_CVAR(Int, con_scaletext) int active_con_scaletext(); -IMPLEMENT_CLASS(DHUDMessage, false, true, false, false) +IMPLEMENT_CLASS(DHUDMessage, false, true) IMPLEMENT_POINTERS_START(DHUDMessage) IMPLEMENT_POINTER(Next) IMPLEMENT_POINTERS_END -IMPLEMENT_CLASS(DHUDMessageFadeOut, false, false, false, false) -IMPLEMENT_CLASS(DHUDMessageFadeInOut, false, false, false, false) -IMPLEMENT_CLASS(DHUDMessageTypeOnFadeOut, false, false, false, false) +IMPLEMENT_CLASS(DHUDMessageFadeOut, false, false) +IMPLEMENT_CLASS(DHUDMessageFadeInOut, false, false) +IMPLEMENT_CLASS(DHUDMessageTypeOnFadeOut, false, false) /************************************************************************* * Basic HUD message. Appears and disappears without any special effects * diff --git a/src/g_shared/sbar.h b/src/g_shared/sbar.h index 6d5b10739..7b7a2849a 100644 --- a/src/g_shared/sbar.h +++ b/src/g_shared/sbar.h @@ -341,7 +341,7 @@ public: }; DBaseStatusBar (int reltop, int hres=320, int vres=200); - void Destroy (); + void Destroy() override; void SetScaled (bool scale, bool force=false); diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index 304101311..a005c1ada 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -1531,7 +1531,7 @@ private: SBarInfoMainBlock *lastPopup; }; -IMPLEMENT_CLASS(DSBarInfo, false, true, false, false) +IMPLEMENT_CLASS(DSBarInfo, false, true) IMPLEMENT_POINTERS_START(DSBarInfo) IMPLEMENT_POINTER(ammo1) diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index 80d221cfc..c288a05c8 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -62,7 +62,7 @@ #define XHAIRPICKUPSIZE (2+XHAIRSHRINKSIZE) #define POWERUPICONSIZE 32 -IMPLEMENT_CLASS(DBaseStatusBar, false, true, false, false) +IMPLEMENT_CLASS(DBaseStatusBar, false, true) IMPLEMENT_POINTERS_START(DBaseStatusBar) IMPLEMENT_POINTER(Messages[0]) diff --git a/src/g_strife/a_coin.cpp b/src/g_strife/a_coin.cpp index 87c4619d3..53cc59f50 100644 --- a/src/g_strife/a_coin.cpp +++ b/src/g_strife/a_coin.cpp @@ -6,7 +6,7 @@ // Coin --------------------------------------------------------------------- -IMPLEMENT_CLASS(ACoin, false, false, false, false) +IMPLEMENT_CLASS(ACoin, false, false) const char *ACoin::PickupMessage () { diff --git a/src/g_strife/a_loremaster.cpp b/src/g_strife/a_loremaster.cpp index 0f1bef7cc..747ba326a 100644 --- a/src/g_strife/a_loremaster.cpp +++ b/src/g_strife/a_loremaster.cpp @@ -17,7 +17,7 @@ public: int DoSpecialDamage (AActor *victim, int damage, FName damagetype); }; -IMPLEMENT_CLASS(ALoreShot, false, false, false, false) +IMPLEMENT_CLASS(ALoreShot, false, false) int ALoreShot::DoSpecialDamage (AActor *victim, int damage, FName damagetype) { diff --git a/src/g_strife/a_programmer.cpp b/src/g_strife/a_programmer.cpp index c00e7fb01..07f6a6c4c 100644 --- a/src/g_strife/a_programmer.cpp +++ b/src/g_strife/a_programmer.cpp @@ -23,7 +23,7 @@ public: PalEntry GetBlend (); }; -IMPLEMENT_CLASS(AProgLevelEnder, false, false, false, false) +IMPLEMENT_CLASS(AProgLevelEnder, false, false) //============================================================================ // diff --git a/src/g_strife/a_rebels.cpp b/src/g_strife/a_rebels.cpp index 7f21886bf..d3d68153f 100644 --- a/src/g_strife/a_rebels.cpp +++ b/src/g_strife/a_rebels.cpp @@ -47,7 +47,7 @@ public: bool Use (bool pickup); }; -IMPLEMENT_CLASS(ATeleporterBeacon, false, false, false, false) +IMPLEMENT_CLASS(ATeleporterBeacon, false, false) bool ATeleporterBeacon::Use (bool pickup) { diff --git a/src/g_strife/a_spectral.cpp b/src/g_strife/a_spectral.cpp index c7012accf..4bd24bac7 100644 --- a/src/g_strife/a_spectral.cpp +++ b/src/g_strife/a_spectral.cpp @@ -16,7 +16,7 @@ public: void Touch (AActor *toucher); }; -IMPLEMENT_CLASS(ASpectralMonster, false, false, false, false) +IMPLEMENT_CLASS(ASpectralMonster, false, false) void ASpectralMonster::Touch (AActor *toucher) { diff --git a/src/g_strife/a_strifeitems.cpp b/src/g_strife/a_strifeitems.cpp index c1b9d75d6..0586583ff 100644 --- a/src/g_strife/a_strifeitems.cpp +++ b/src/g_strife/a_strifeitems.cpp @@ -19,7 +19,7 @@ */ // Degnin Ore --------------------------------------------------------------- -IMPLEMENT_CLASS(ADegninOre, false, false, false, false) +IMPLEMENT_CLASS(ADegninOre, false, false) DEFINE_ACTION_FUNCTION(AActor, A_RemoveForceField) { @@ -75,7 +75,7 @@ public: bool TryPickup (AActor *&toucher); }; -IMPLEMENT_CLASS(AHealthTraining, false, false, false, false) +IMPLEMENT_CLASS(AHealthTraining, false, false) bool AHealthTraining::TryPickup (AActor *&toucher) { @@ -105,7 +105,7 @@ public: bool Use (bool pickup); }; -IMPLEMENT_CLASS(AScanner, false, false, false, false) +IMPLEMENT_CLASS(AScanner, false, false) bool AScanner::Use (bool pickup) { @@ -130,7 +130,7 @@ public: bool SpecialDropAction (AActor *dropper); }; -IMPLEMENT_CLASS(APrisonPass, false, false, false, false) +IMPLEMENT_CLASS(APrisonPass, false, false) bool APrisonPass::TryPickup (AActor *&toucher) { @@ -163,7 +163,7 @@ bool APrisonPass::SpecialDropAction (AActor *dropper) // actions and cannot be held. ---------------------------------------------- //--------------------------------------------------------------------------- -IMPLEMENT_CLASS(ADummyStrifeItem, false, false, false, false) +IMPLEMENT_CLASS(ADummyStrifeItem, false, false) // Sound the alarm! --------------------------------------------------------- @@ -175,7 +175,7 @@ public: bool SpecialDropAction (AActor *dropper); }; -IMPLEMENT_CLASS(ARaiseAlarm, false, false, false, false) +IMPLEMENT_CLASS(ARaiseAlarm, false, false) bool ARaiseAlarm::TryPickup (AActor *&toucher) { @@ -209,7 +209,7 @@ public: bool TryPickup (AActor *&toucher); }; -IMPLEMENT_CLASS(AOpenDoor222, false, false, false, false) +IMPLEMENT_CLASS(AOpenDoor222, false, false) bool AOpenDoor222::TryPickup (AActor *&toucher) { @@ -228,7 +228,7 @@ public: bool SpecialDropAction (AActor *dropper); }; -IMPLEMENT_CLASS(ACloseDoor222, false, false, false, false) +IMPLEMENT_CLASS(ACloseDoor222, false, false) bool ACloseDoor222::TryPickup (AActor *&toucher) { @@ -262,7 +262,7 @@ public: bool SpecialDropAction (AActor *dropper); }; -IMPLEMENT_CLASS(AOpenDoor224, false, false, false, false) +IMPLEMENT_CLASS(AOpenDoor224, false, false) bool AOpenDoor224::TryPickup (AActor *&toucher) { @@ -287,7 +287,7 @@ public: bool TryPickup (AActor *&toucher); }; -IMPLEMENT_CLASS(AAmmoFillup, false, false, false, false) +IMPLEMENT_CLASS(AAmmoFillup, false, false) bool AAmmoFillup::TryPickup (AActor *&toucher) { @@ -325,7 +325,7 @@ public: bool TryPickup (AActor *&toucher); }; -IMPLEMENT_CLASS(AHealthFillup, false, false, false, false) +IMPLEMENT_CLASS(AHealthFillup, false, false) bool AHealthFillup::TryPickup (AActor *&toucher) { @@ -342,7 +342,7 @@ bool AHealthFillup::TryPickup (AActor *&toucher) // Upgrade Stamina ---------------------------------------------------------- -IMPLEMENT_CLASS(AUpgradeStamina, false, false, false, false) +IMPLEMENT_CLASS(AUpgradeStamina, false, false) bool AUpgradeStamina::TryPickup (AActor *&toucher) { @@ -360,7 +360,7 @@ bool AUpgradeStamina::TryPickup (AActor *&toucher) // Upgrade Accuracy --------------------------------------------------------- -IMPLEMENT_CLASS(AUpgradeAccuracy, false, false, false, false) +IMPLEMENT_CLASS(AUpgradeAccuracy, false, false) bool AUpgradeAccuracy::TryPickup (AActor *&toucher) { @@ -373,7 +373,7 @@ bool AUpgradeAccuracy::TryPickup (AActor *&toucher) // Start a slideshow -------------------------------------------------------- -IMPLEMENT_CLASS(ASlideshowStarter, false, false, false, false) +IMPLEMENT_CLASS(ASlideshowStarter, false, false) bool ASlideshowStarter::TryPickup (AActor *&toucher) { diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp index 1580f127f..7cccdd3f3 100644 --- a/src/g_strife/a_strifestuff.cpp +++ b/src/g_strife/a_strifestuff.cpp @@ -72,7 +72,7 @@ public: int TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FName damagetype); }; -IMPLEMENT_CLASS(AForceFieldGuard, false, false, false, false) +IMPLEMENT_CLASS(AForceFieldGuard, false, false) int AForceFieldGuard::TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FName damagetype) { @@ -197,7 +197,7 @@ public: void Die (AActor *source, AActor *inflictor, int dmgflags); }; -IMPLEMENT_CLASS(APowerCoupling, false, false, false, false) +IMPLEMENT_CLASS(APowerCoupling, false, false) void APowerCoupling::Die (AActor *source, AActor *inflictor, int dmgflags) { @@ -239,7 +239,7 @@ public: } }; -IMPLEMENT_CLASS(AMeat, false, false, false, false) +IMPLEMENT_CLASS(AMeat, false, false) //========================================================================== // diff --git a/src/g_strife/a_strifeweapons.cpp b/src/g_strife/a_strifeweapons.cpp index 56eb06597..0268682f3 100644 --- a/src/g_strife/a_strifeweapons.cpp +++ b/src/g_strife/a_strifeweapons.cpp @@ -184,7 +184,7 @@ public: int DoSpecialDamage (AActor *target, int damage, FName damagetype); }; -IMPLEMENT_CLASS(APoisonBolt, false, false, false, false) +IMPLEMENT_CLASS(APoisonBolt, false, false) int APoisonBolt::DoSpecialDamage (AActor *target, int damage, FName damagetype) { @@ -607,7 +607,7 @@ public: int DoSpecialDamage (AActor *target, int damage, FName damagetype); }; -IMPLEMENT_CLASS(APhosphorousFire, false, false, false, false) +IMPLEMENT_CLASS(APhosphorousFire, false, false) int APhosphorousFire::DoSpecialDamage (AActor *target, int damage, FName damagetype) { @@ -734,7 +734,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireGrenade) // The Almighty Sigil! ------------------------------------------------------ -IMPLEMENT_CLASS(ASigil, false, false, false, false) +IMPLEMENT_CLASS(ASigil, false, false) //============================================================================ // diff --git a/src/g_strife/strife_sbar.cpp b/src/g_strife/strife_sbar.cpp index 73e31e676..39f92d076 100644 --- a/src/g_strife/strife_sbar.cpp +++ b/src/g_strife/strife_sbar.cpp @@ -851,7 +851,7 @@ private: double ItemFlash; }; -IMPLEMENT_CLASS(DStrifeStatusBar, false, false, false, false); +IMPLEMENT_CLASS(DStrifeStatusBar, false, false); DBaseStatusBar *CreateStrifeStatusBar () { diff --git a/src/info.cpp b/src/info.cpp index fec5af63e..8a2842ff4 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -151,7 +151,7 @@ int GetSpriteIndex(const char * spritename, bool add) return (lastindex = (int)sprites.Push (temp)); } -IMPLEMENT_CLASS(PClassActor, false, true, false, false) +IMPLEMENT_CLASS(PClassActor, false, true) IMPLEMENT_POINTERS_START(PClassActor) IMPLEMENT_POINTER(DropItems) diff --git a/src/intermission/intermission.cpp b/src/intermission/intermission.cpp index be8f58e19..2aacd215b 100644 --- a/src/intermission/intermission.cpp +++ b/src/intermission/intermission.cpp @@ -54,12 +54,12 @@ FIntermissionDescriptorList IntermissionDescriptors; -IMPLEMENT_CLASS(DIntermissionScreen, false, false, false, false) -IMPLEMENT_CLASS(DIntermissionScreenFader, false, false, false, false) -IMPLEMENT_CLASS(DIntermissionScreenText, false, false, false, false) -IMPLEMENT_CLASS(DIntermissionScreenCast, false, false, false, false) -IMPLEMENT_CLASS(DIntermissionScreenScroller, false, false, false, false) -IMPLEMENT_CLASS(DIntermissionController, false, true, false, false) +IMPLEMENT_CLASS(DIntermissionScreen, false, false) +IMPLEMENT_CLASS(DIntermissionScreenFader, false, false) +IMPLEMENT_CLASS(DIntermissionScreenText, false, false) +IMPLEMENT_CLASS(DIntermissionScreenCast, false, false) +IMPLEMENT_CLASS(DIntermissionScreenScroller, false, false) +IMPLEMENT_CLASS(DIntermissionController, false, true) IMPLEMENT_POINTERS_START(DIntermissionController) IMPLEMENT_POINTER(mScreen) diff --git a/src/intermission/intermission.h b/src/intermission/intermission.h index 45779f895..25b369a3a 100644 --- a/src/intermission/intermission.h +++ b/src/intermission/intermission.h @@ -176,7 +176,7 @@ public: virtual int Responder (event_t *ev); virtual int Ticker (); virtual void Drawer (); - void Destroy(); + void Destroy() override; FTextureID GetBackground(bool *fill) { *fill = mFlatfill; @@ -301,7 +301,7 @@ public: bool Responder (event_t *ev); void Ticker (); void Drawer (); - void Destroy(); + void Destroy() override; friend void F_AdvanceIntermission(); }; diff --git a/src/m_argv.cpp b/src/m_argv.cpp index 7d82ed834..395885986 100644 --- a/src/m_argv.cpp +++ b/src/m_argv.cpp @@ -37,7 +37,7 @@ #include "cmdlib.h" #include "i_system.h" -IMPLEMENT_CLASS(DArgs, false, false, false, false) +IMPLEMENT_CLASS(DArgs, false, false) //=========================================================================== // diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index c53192ee7..7ba40f957 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -1033,7 +1033,7 @@ public: } }; -IMPLEMENT_CLASS(DSuicider, false, true, false, false) +IMPLEMENT_CLASS(DSuicider, false, true) IMPLEMENT_POINTERS_START(DSuicider) IMPLEMENT_POINTER(Pawn) diff --git a/src/menu/colorpickermenu.cpp b/src/menu/colorpickermenu.cpp index 639c6bbef..e1ee3566d 100644 --- a/src/menu/colorpickermenu.cpp +++ b/src/menu/colorpickermenu.cpp @@ -95,7 +95,7 @@ public: desc->CalcIndent(); } - void Destroy() + void Destroy() override { if (mStartItem >= 0) { @@ -331,7 +331,7 @@ public: } }; -IMPLEMENT_CLASS(DColorPickerMenu, true, false, false, false) +IMPLEMENT_CLASS(DColorPickerMenu, true, false) CCMD(undocolorpic) { diff --git a/src/menu/joystickmenu.cpp b/src/menu/joystickmenu.cpp index cca13ad44..f715dce4a 100644 --- a/src/menu/joystickmenu.cpp +++ b/src/menu/joystickmenu.cpp @@ -236,7 +236,7 @@ class DJoystickConfigMenu : public DOptionMenu DECLARE_CLASS(DJoystickConfigMenu, DOptionMenu) }; -IMPLEMENT_CLASS(DJoystickConfigMenu, false, false, false, false) +IMPLEMENT_CLASS(DJoystickConfigMenu, false, false) //============================================================================= // diff --git a/src/menu/listmenu.cpp b/src/menu/listmenu.cpp index 7fdd0c5bc..455ea6c4b 100644 --- a/src/menu/listmenu.cpp +++ b/src/menu/listmenu.cpp @@ -42,7 +42,7 @@ #include "d_event.h" #include "menu/menu.h" -IMPLEMENT_CLASS(DListMenu, false, false, false, false) +IMPLEMENT_CLASS(DListMenu, false, false) //============================================================================= // diff --git a/src/menu/loadsavemenu.cpp b/src/menu/loadsavemenu.cpp index 6d543228c..73183ca22 100644 --- a/src/menu/loadsavemenu.cpp +++ b/src/menu/loadsavemenu.cpp @@ -103,7 +103,7 @@ protected: char savegamestring[SAVESTRINGSIZE]; DLoadSaveMenu(DMenu *parent = NULL, FListMenuDescriptor *desc = NULL); - void Destroy(); + void Destroy() override; int RemoveSaveSlot (int index); void UnloadSaveData (); @@ -119,7 +119,7 @@ public: }; -IMPLEMENT_CLASS(DLoadSaveMenu, false, false, false, false) +IMPLEMENT_CLASS(DLoadSaveMenu, false, false) TArray DLoadSaveMenu::SaveGames; int DLoadSaveMenu::LastSaved = -1; @@ -466,6 +466,7 @@ void DLoadSaveMenu::Destroy() if (currentSavePic != nullptr) delete currentSavePic; currentSavePic = nullptr; ClearSaveStuff (); + Super::Destroy(); } //============================================================================= @@ -927,14 +928,14 @@ class DSaveMenu : public DLoadSaveMenu public: DSaveMenu(DMenu *parent = NULL, FListMenuDescriptor *desc = NULL); - void Destroy(); + void Destroy() override; void DoSave (FSaveGameNode *node); bool Responder (event_t *ev); bool MenuEvent (int mkey, bool fromcontroller); }; -IMPLEMENT_CLASS(DSaveMenu, false, false, false, false) +IMPLEMENT_CLASS(DSaveMenu, false, false) //============================================================================= @@ -975,6 +976,7 @@ void DSaveMenu::Destroy() if (Selected == 0) Selected = -1; else Selected--; } + Super::Destroy(); } //============================================================================= @@ -1102,7 +1104,7 @@ public: bool MenuEvent (int mkey, bool fromcontroller); }; -IMPLEMENT_CLASS(DLoadMenu, false, false, false, false) +IMPLEMENT_CLASS(DLoadMenu, false, false) //============================================================================= diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index 6648c32b4..0c6019a5f 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -91,7 +91,7 @@ static bool MenuEnabled = true; // //============================================================================ -IMPLEMENT_CLASS(DMenu, false, true, false, false) +IMPLEMENT_CLASS(DMenu, false, true) IMPLEMENT_POINTERS_START(DMenu) IMPLEMENT_POINTER(mParentMenu) diff --git a/src/menu/menuinput.cpp b/src/menu/menuinput.cpp index c33e9fed2..cca4756f5 100644 --- a/src/menu/menuinput.cpp +++ b/src/menu/menuinput.cpp @@ -44,7 +44,7 @@ // [TP] New #includes #include "v_text.h" -IMPLEMENT_CLASS(DTextEnterMenu, true, false, false, false) +IMPLEMENT_CLASS(DTextEnterMenu, true, false) #define INPUTGRID_WIDTH 13 #define INPUTGRID_HEIGHT 5 diff --git a/src/menu/messagebox.cpp b/src/menu/messagebox.cpp index de8fa1027..c406fc701 100644 --- a/src/menu/messagebox.cpp +++ b/src/menu/messagebox.cpp @@ -63,7 +63,7 @@ class DMessageBoxMenu : public DMenu public: DMessageBoxMenu(DMenu *parent = NULL, const char *message = NULL, int messagemode = 0, bool playsound = false, FName action = NAME_None); - void Destroy(); + void Destroy() override; void Init(DMenu *parent, const char *message, int messagemode, bool playsound = false); void Drawer(); bool Responder(event_t *ev); @@ -73,7 +73,7 @@ public: virtual void HandleResult(bool res); }; -IMPLEMENT_CLASS(DMessageBoxMenu, false, false, false, false) +IMPLEMENT_CLASS(DMessageBoxMenu, false, false) //============================================================================= // @@ -128,6 +128,7 @@ void DMessageBoxMenu::Destroy() { if (mMessage != NULL) V_FreeBrokenLines(mMessage); mMessage = NULL; + Super::Destroy(); } //============================================================================= @@ -365,7 +366,7 @@ public: virtual void HandleResult(bool res); }; -IMPLEMENT_CLASS(DQuitMenu, false, false, false, false) +IMPLEMENT_CLASS(DQuitMenu, false, false) //============================================================================= // @@ -458,7 +459,7 @@ public: virtual void HandleResult(bool res); }; -IMPLEMENT_CLASS(DEndGameMenu, false, false, false, false) +IMPLEMENT_CLASS(DEndGameMenu, false, false) //============================================================================= // @@ -536,7 +537,7 @@ public: virtual void HandleResult(bool res); }; -IMPLEMENT_CLASS(DQuickSaveMenu, false, false, false, false) +IMPLEMENT_CLASS(DQuickSaveMenu, false, false) //============================================================================= // @@ -632,7 +633,7 @@ public: virtual void HandleResult(bool res); }; -IMPLEMENT_CLASS(DQuickLoadMenu, false, false, false, false) +IMPLEMENT_CLASS(DQuickLoadMenu, false, false) //============================================================================= // diff --git a/src/menu/optionmenu.cpp b/src/menu/optionmenu.cpp index 1631c3d4b..f9a29b6f5 100644 --- a/src/menu/optionmenu.cpp +++ b/src/menu/optionmenu.cpp @@ -64,7 +64,7 @@ void M_DrawConText (int color, int x, int y, const char *str) TAG_DONE); } -IMPLEMENT_CLASS(DOptionMenu, false, false, false, false) +IMPLEMENT_CLASS(DOptionMenu, false, false) //============================================================================= // @@ -578,7 +578,7 @@ public: } }; -IMPLEMENT_CLASS(DGameplayMenu, false, false, false, false) +IMPLEMENT_CLASS(DGameplayMenu, false, false) class DCompatibilityMenu : public DOptionMenu { @@ -600,4 +600,4 @@ public: } }; -IMPLEMENT_CLASS(DCompatibilityMenu, false, false, false, false) +IMPLEMENT_CLASS(DCompatibilityMenu, false, false) diff --git a/src/menu/optionmenuitems.h b/src/menu/optionmenuitems.h index e83f4ada4..c3cb7297a 100644 --- a/src/menu/optionmenuitems.h +++ b/src/menu/optionmenuitems.h @@ -399,7 +399,7 @@ public: }; #ifndef NO_IMP -IMPLEMENT_CLASS(DEnterKey, true, false, false, false) +IMPLEMENT_CLASS(DEnterKey, true, false) #endif //============================================================================= diff --git a/src/menu/playermenu.cpp b/src/menu/playermenu.cpp index e32c7dd61..9f5196367 100644 --- a/src/menu/playermenu.cpp +++ b/src/menu/playermenu.cpp @@ -526,7 +526,7 @@ public: void Drawer (); }; -IMPLEMENT_CLASS(DPlayerMenu, false, false, false, false) +IMPLEMENT_CLASS(DPlayerMenu, false, false) //============================================================================= // diff --git a/src/menu/readthis.cpp b/src/menu/readthis.cpp index 0dfc47e73..b8a3837ee 100644 --- a/src/menu/readthis.cpp +++ b/src/menu/readthis.cpp @@ -54,7 +54,7 @@ public: bool MouseEvent(int type, int x, int y); }; -IMPLEMENT_CLASS(DReadThisMenu, false, false, false, false) +IMPLEMENT_CLASS(DReadThisMenu, false, false) //============================================================================= // diff --git a/src/menu/videomenu.cpp b/src/menu/videomenu.cpp index 37f59149e..d8edee8f1 100644 --- a/src/menu/videomenu.cpp +++ b/src/menu/videomenu.cpp @@ -183,7 +183,7 @@ public: } }; -IMPLEMENT_CLASS(DVideoModeMenu, false, false, false, false) +IMPLEMENT_CLASS(DVideoModeMenu, false, false) //============================================================================= diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 96e20d022..a5b8b977d 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -1368,7 +1368,7 @@ private: DPlaneWatcher() {} }; -IMPLEMENT_CLASS(DPlaneWatcher, false, true, false, false) +IMPLEMENT_CLASS(DPlaneWatcher, false, true) IMPLEMENT_POINTERS_START(DPlaneWatcher) IMPLEMENT_POINTER(Activator) @@ -2859,7 +2859,7 @@ void FBehavior::StaticStopMyScripts (AActor *actor) //---- The ACS Interpreter ----// -IMPLEMENT_CLASS(DACSThinker, false, true, false, false) +IMPLEMENT_CLASS(DACSThinker, false, true) IMPLEMENT_POINTERS_START(DACSThinker) IMPLEMENT_POINTER(LastScript) @@ -2990,7 +2990,7 @@ void DACSThinker::StopScriptsFor (AActor *actor) } } -IMPLEMENT_CLASS(DLevelScript, false, true, false, false) +IMPLEMENT_CLASS(DLevelScript, false, true) IMPLEMENT_POINTERS_START(DLevelScript) IMPLEMENT_POINTER(next) diff --git a/src/p_buildmap.cpp b/src/p_buildmap.cpp index b3526c60d..4d1909da5 100644 --- a/src/p_buildmap.cpp +++ b/src/p_buildmap.cpp @@ -865,7 +865,7 @@ public: void BeginPlay (); }; -IMPLEMENT_CLASS(ACustomSprite, false, false, false, false) +IMPLEMENT_CLASS(ACustomSprite, false, false) void ACustomSprite::BeginPlay () { diff --git a/src/p_ceiling.cpp b/src/p_ceiling.cpp index d22dd6371..a38a17f9c 100644 --- a/src/p_ceiling.cpp +++ b/src/p_ceiling.cpp @@ -38,7 +38,7 @@ // //============================================================================ -IMPLEMENT_CLASS(DCeiling, false, false, false, false) +IMPLEMENT_CLASS(DCeiling, false, false) DCeiling::DCeiling () { diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 15e3e42c4..404b2f2bc 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -834,6 +834,7 @@ public: V_FreeBrokenLines(mDialogueLines); mDialogueLines = NULL; I_SetMusicVolume (1.f); + Super::Destroy(); } bool DimAllowed() @@ -1103,7 +1104,7 @@ public: }; -IMPLEMENT_CLASS(DConversationMenu, true, false, false, false) +IMPLEMENT_CLASS(DConversationMenu, true, false) int DConversationMenu::mSelection; // needs to be preserved if the same dialogue is restarted diff --git a/src/p_doors.cpp b/src/p_doors.cpp index 542308fa6..aa59e5463 100644 --- a/src/p_doors.cpp +++ b/src/p_doors.cpp @@ -45,7 +45,7 @@ // //============================================================================ -IMPLEMENT_CLASS(DDoor, false, false, false, false) +IMPLEMENT_CLASS(DDoor, false, false) DDoor::DDoor () { @@ -513,7 +513,7 @@ bool EV_DoDoor (DDoor::EVlDoor type, line_t *line, AActor *thing, // //============================================================================ -IMPLEMENT_CLASS(DAnimatedDoor, false, false, false, false) +IMPLEMENT_CLASS(DAnimatedDoor, false, false) DAnimatedDoor::DAnimatedDoor () { diff --git a/src/p_floor.cpp b/src/p_floor.cpp index 7b5ff5cc9..0431fa808 100644 --- a/src/p_floor.cpp +++ b/src/p_floor.cpp @@ -64,7 +64,7 @@ static void StartFloorSound (sector_t *sec) // //========================================================================== -IMPLEMENT_CLASS(DFloor, false, false, false, false) +IMPLEMENT_CLASS(DFloor, false, false) DFloor::DFloor () { @@ -815,7 +815,7 @@ bool EV_DoDonut (int tag, line_t *line, double pillarspeed, double slimespeed) // //========================================================================== -IMPLEMENT_CLASS(DElevator, false, true, false, false) +IMPLEMENT_CLASS(DElevator, false, true) IMPLEMENT_POINTERS_START(DElevator) IMPLEMENT_POINTER(m_Interp_Floor) @@ -1105,9 +1105,9 @@ bool EV_DoChange (line_t *line, EChange changetype, int tag) // //========================================================================== -IMPLEMENT_CLASS(DWaggleBase, false, false, false, false) -IMPLEMENT_CLASS(DFloorWaggle, false, false, false, false) -IMPLEMENT_CLASS(DCeilingWaggle, false, false, false, false) +IMPLEMENT_CLASS(DWaggleBase, false, false) +IMPLEMENT_CLASS(DFloorWaggle, false, false) +IMPLEMENT_CLASS(DCeilingWaggle, false, false) DWaggleBase::DWaggleBase () { @@ -1141,11 +1141,6 @@ DWaggleBase::DWaggleBase (sector_t *sec) { } -void DWaggleBase::Destroy() -{ - Super::Destroy(); -} - //========================================================================== // // diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 48d13bebf..aece79edc 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1071,7 +1071,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, } } - damage = inflictor->DoSpecialDamage(target, damage, mod); + damage = inflictor->CallDoSpecialDamage(target, damage, mod); if (damage < 0) { return -1; diff --git a/src/p_lights.cpp b/src/p_lights.cpp index c44a22d4b..910c52a64 100644 --- a/src/p_lights.cpp +++ b/src/p_lights.cpp @@ -173,7 +173,7 @@ private: // //----------------------------------------------------------------------------- -IMPLEMENT_CLASS(DLighting, false, false, false, false) +IMPLEMENT_CLASS(DLighting, false, false) DLighting::DLighting () { @@ -191,7 +191,7 @@ DLighting::DLighting (sector_t *sector) // //----------------------------------------------------------------------------- -IMPLEMENT_CLASS(DFireFlicker, false, false, false, false) +IMPLEMENT_CLASS(DFireFlicker, false, false) DFireFlicker::DFireFlicker () { @@ -258,7 +258,7 @@ DFireFlicker::DFireFlicker (sector_t *sector, int upper, int lower) // //----------------------------------------------------------------------------- -IMPLEMENT_CLASS(DFlicker, false, false, false, false) +IMPLEMENT_CLASS(DFlicker, false, false) DFlicker::DFlicker () { @@ -334,7 +334,7 @@ void EV_StartLightFlickering (int tag, int upper, int lower) // //----------------------------------------------------------------------------- -IMPLEMENT_CLASS(DLightFlash, false, false, false, false) +IMPLEMENT_CLASS(DLightFlash, false, false) DLightFlash::DLightFlash () { @@ -409,7 +409,7 @@ DLightFlash::DLightFlash (sector_t *sector, int min, int max) // //----------------------------------------------------------------------------- -IMPLEMENT_CLASS(DStrobe, false, false, false, false) +IMPLEMENT_CLASS(DStrobe, false, false) DStrobe::DStrobe () { @@ -667,7 +667,7 @@ void EV_LightChange (int tag, int value) // //----------------------------------------------------------------------------- -IMPLEMENT_CLASS(DGlow, false, false, false, false) +IMPLEMENT_CLASS(DGlow, false, false) DGlow::DGlow () { @@ -736,7 +736,7 @@ DGlow::DGlow (sector_t *sector) // //----------------------------------------------------------------------------- -IMPLEMENT_CLASS(DGlow2, false, false, false, false) +IMPLEMENT_CLASS(DGlow2, false, false) DGlow2::DGlow2 () { @@ -869,7 +869,7 @@ void EV_StartLightFading (int tag, int value, int tics) // //----------------------------------------------------------------------------- -IMPLEMENT_CLASS(DPhased, false, false, false, false) +IMPLEMENT_CLASS(DPhased, false, false) DPhased::DPhased () { diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index c8c7db74d..e41912e23 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -1368,7 +1368,7 @@ void DoActivateThing(AActor * thing, AActor * activator) if (thing->activationtype & THINGSPEC_Switch) // Set other flag if switching thing->activationtype |= THINGSPEC_Deactivate; } - thing->Activate (activator); + thing->CallActivate (activator); } void DoDeactivateThing(AActor * thing, AActor * activator) @@ -1379,7 +1379,7 @@ void DoDeactivateThing(AActor * thing, AActor * activator) if (thing->activationtype & THINGSPEC_Switch) // Set other flag if switching thing->activationtype |= THINGSPEC_Activate; } - thing->Deactivate (activator); + thing->CallDeactivate (activator); } FUNC(LS_Thing_Activate) diff --git a/src/p_map.cpp b/src/p_map.cpp index af5ab100a..f1fa55cf9 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -6758,7 +6758,7 @@ bool P_ActivateThingSpecial(AActor * thing, AActor * trigger, bool death) thing->activationtype &= ~THINGSPEC_Activate; // Clear flag if (thing->activationtype & THINGSPEC_Switch) // Set other flag if switching thing->activationtype |= THINGSPEC_Deactivate; - thing->Activate(trigger); + thing->CallActivate(trigger); res = true; } // If not, can it be deactivated? @@ -6767,7 +6767,7 @@ bool P_ActivateThingSpecial(AActor * thing, AActor * trigger, bool death) thing->activationtype &= ~THINGSPEC_Deactivate; // Clear flag if (thing->activationtype & THINGSPEC_Switch) // Set other flag if switching thing->activationtype |= THINGSPEC_Activate; - thing->Deactivate(trigger); + thing->CallDeactivate(trigger); res = true; } } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 3c8d1173b..cde2eb0b4 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -131,7 +131,7 @@ CVAR (Int, cl_bloodtype, 0, CVAR_ARCHIVE); // CODE -------------------------------------------------------------------- -IMPLEMENT_CLASS(AActor, false, true, false, true) +IMPLEMENT_CLASS(AActor, false, true) IMPLEMENT_POINTERS_START(AActor) IMPLEMENT_POINTER(target) @@ -943,7 +943,7 @@ AInventory *AActor::FirstInv () // //============================================================================ -bool AActor::UseInventory (AInventory *item) +bool AActor::DoUseInventory (AInventory *item) { // No using items if you're dead. if (health <= 0) @@ -975,7 +975,23 @@ DEFINE_ACTION_FUNCTION(AActor, UseInventory) PARAM_SELF_PROLOGUE(AActor); PARAM_OBJECT(item, AInventory); self->VMSuperCall(); - ACTION_RETURN_BOOL(self->UseInventory(item)); + ACTION_RETURN_BOOL(self->DoUseInventory(item)); +} + +bool AActor::UseInventory(AInventory *item) +{ + IFVIRTUAL(AActor, UseInventory) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[2] = { (DObject*)this, (DObject*)item }; + VMReturn ret; + VMFrameStack stack; + int retval; + ret.IntAt(&retval); + stack.Call(func, params, 2, &ret, 1, nullptr); + return !!retval; + } + else return DoUseInventory(item); } //=========================================================================== @@ -4475,7 +4491,7 @@ AActor *AActor::StaticSpawn (PClassActor *type, const DVector3 &pos, replace_t a actor->UpdateWaterLevel (false); if (!SpawningMapThing) { - actor->BeginPlay (); + actor->CallBeginPlay (); if (actor->ObjectFlags & OF_EuthanizeMe) { return NULL; @@ -4551,7 +4567,7 @@ void AActor::HandleSpawnFlags () } if (SpawnFlags & MTF_DORMANT) { - Deactivate (NULL); + CallDeactivate (NULL); } if (SpawnFlags & MTF_STANDSTILL) { @@ -4595,18 +4611,29 @@ void AActor::BeginPlay () if (flags2 & MF2_DORMANT) { flags2 &= ~MF2_DORMANT; - Deactivate (NULL); + CallDeactivate (NULL); } } DEFINE_ACTION_FUNCTION(AActor, BeginPlay) { PARAM_SELF_PROLOGUE(AActor); - self->VMSuperCall(); self->BeginPlay(); return 0; } +void AActor::CallBeginPlay() +{ + IFVIRTUAL(AActor, BeginPlay) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { (DObject*)this }; + VMFrameStack stack; + stack.Call(func, params, 1, nullptr, 0, nullptr); + } + else BeginPlay(); +} + void AActor::PostBeginPlay () { @@ -4643,6 +4670,12 @@ bool AActor::isSlow() return !!G_SkillProperty(SKILLP_SlowMonsters); } +//=========================================================================== +// +// Activate +// +//=========================================================================== + void AActor::Activate (AActor *activator) { if ((flags3 & MF3_ISMONSTER) && (health > 0 || (flags & MF_ICECORPSE))) @@ -4672,6 +4705,25 @@ DEFINE_ACTION_FUNCTION(AActor, Activate) return 0; } +void AActor::CallActivate(AActor *activator) +{ + IFVIRTUAL(AActor, Activate) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[2] = { (DObject*)this, (DObject*)activator }; + VMFrameStack stack; + stack.Call(func, params, 2, nullptr, 0, nullptr); + } + else Activate(activator); +} + + +//=========================================================================== +// +// Deactivate +// +//=========================================================================== + void AActor::Deactivate (AActor *activator) { if ((flags3 & MF3_ISMONSTER) && (health > 0 || (flags & MF_ICECORPSE))) @@ -4701,10 +4753,23 @@ DEFINE_ACTION_FUNCTION(AActor, Deactivate) return 0; } +void AActor::CallDeactivate(AActor *activator) +{ + IFVIRTUAL(AActor, Deactivate) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[2] = { (DObject*)this, (DObject*)activator }; + VMFrameStack stack; + stack.Call(func, params, 2, nullptr, 0, nullptr); + } + else Deactivate(activator); +} +//=========================================================================== // -// P_RemoveMobj +// Destroy // +//=========================================================================== void AActor::Destroy () { @@ -5415,7 +5480,7 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) if (mthing->fillcolor) mobj->fillcolor = mthing->fillcolor; - mobj->BeginPlay (); + mobj->CallBeginPlay (); if (!(mobj->ObjectFlags & OF_EuthanizeMe)) { mobj->LevelSpawned (); @@ -6687,6 +6752,14 @@ bool AActor::IsHostile (AActor *other) return true; } +//========================================================================== +// +// AActor :: DoSpecialDamage +// +// override this for special damage effects. +// +//========================================================================== + int AActor::DoSpecialDamage (AActor *target, int damage, FName damagetype) { if (target->player && target->player->mo == target && damage < 1000 && @@ -6720,6 +6793,28 @@ DEFINE_ACTION_FUNCTION(AActor, DoSpecialDamage) ACTION_RETURN_INT(self->DoSpecialDamage(target, damage, damagetype)); } +int AActor::CallDoSpecialDamage(AActor *target, int damage, FName damagetype) +{ + IFVIRTUAL(AActor, DoSpecialDamage) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[4] = { (DObject*)this, (DObject*)target, damage, damagetype.GetIndex() }; + VMReturn ret; + VMFrameStack stack; + int retval; + ret.IntAt(&retval); + stack.Call(func, params, 4, &ret, 1, nullptr); + return retval; + } + else return DoSpecialDamage(target, damage, damagetype); + +} + +//========================================================================== +// +// AActor :: TakeSpecialDamage +// +//========================================================================== int AActor::TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FName damagetype) { @@ -7032,7 +7127,7 @@ public: } }; -IMPLEMENT_CLASS(DActorIterator, false, false, false, false); +IMPLEMENT_CLASS(DActorIterator, false, false); DEFINE_ACTION_FUNCTION(DActorIterator, Create) { PARAM_PROLOGUE; @@ -7252,7 +7347,7 @@ DEFINE_ACTION_FUNCTION(AActor, RestoreDamage) // //---------------------------------------------------------------------------- -IMPLEMENT_CLASS(DDropItem, false, true, true, false) +IMPLEMENT_CLASS(DDropItem, false, true) IMPLEMENT_POINTERS_START(DDropItem) IMPLEMENT_POINTER(Next) diff --git a/src/p_pillar.cpp b/src/p_pillar.cpp index 27eb13ec5..b0ea0e4a3 100644 --- a/src/p_pillar.cpp +++ b/src/p_pillar.cpp @@ -40,7 +40,7 @@ #include "serializer.h" #include "r_data/r_interpolate.h" -IMPLEMENT_CLASS(DPillar, false, true, false, false) +IMPLEMENT_CLASS(DPillar, false, true) IMPLEMENT_POINTERS_START(DPillar) IMPLEMENT_POINTER(m_Interp_Floor) diff --git a/src/p_plats.cpp b/src/p_plats.cpp index 9924a0f9c..43e8eefb4 100644 --- a/src/p_plats.cpp +++ b/src/p_plats.cpp @@ -35,7 +35,7 @@ static FRandom pr_doplat ("DoPlat"); -IMPLEMENT_CLASS(DPlat, false, false, false, false) +IMPLEMENT_CLASS(DPlat, false, false) DPlat::DPlat () { diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index ca305d677..eddeb3430 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -99,7 +99,7 @@ static const FGenericButtons ButtonChecks[] = // //------------------------------------------------------------------------ -IMPLEMENT_CLASS(DPSprite, false, true, false, false) +IMPLEMENT_CLASS(DPSprite, false, true) IMPLEMENT_POINTERS_START(DPSprite) IMPLEMENT_POINTER(Caller) diff --git a/src/p_pspr.h b/src/p_pspr.h index 7039b2cc8..d6eb2a82d 100644 --- a/src/p_pspr.h +++ b/src/p_pspr.h @@ -86,7 +86,7 @@ private: void Serialize(FSerializer &arc); void Tick(); - void Destroy(); + void Destroy() override; public: // must be public to be able to generate the field export tables. Grrr... TObjPtr Caller; diff --git a/src/p_pusher.cpp b/src/p_pusher.cpp index f2f982a7f..1cf004120 100644 --- a/src/p_pusher.cpp +++ b/src/p_pusher.cpp @@ -74,7 +74,7 @@ protected: friend bool PIT_PushThing (AActor *thing); }; -IMPLEMENT_CLASS(DPusher, false, true, false, false) +IMPLEMENT_CLASS(DPusher, false, true) IMPLEMENT_POINTERS_START(DPusher) IMPLEMENT_POINTER(m_Source) diff --git a/src/p_scroll.cpp b/src/p_scroll.cpp index f44eac25a..25789d944 100644 --- a/src/p_scroll.cpp +++ b/src/p_scroll.cpp @@ -44,7 +44,7 @@ public: DScroller (EScroll type, double dx, double dy, int control, int affectee, int accel, EScrollPos scrollpos = EScrollPos::scw_all); DScroller (double dx, double dy, const line_t *l, int control, int accel, EScrollPos scrollpos = EScrollPos::scw_all); - void Destroy(); + void Destroy() override; void Serialize(FSerializer &arc); void Tick (); @@ -73,7 +73,7 @@ private: } }; -IMPLEMENT_CLASS(DScroller, false, true, false, false) +IMPLEMENT_CLASS(DScroller, false, true) IMPLEMENT_POINTERS_START(DScroller) IMPLEMENT_POINTER(m_Interpolations[0]) diff --git a/src/p_spec.cpp b/src/p_spec.cpp index e687d5724..c9a8294b5 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -660,7 +660,7 @@ protected: short LastLight; }; -IMPLEMENT_CLASS(DLightTransfer, false, false, false, false) +IMPLEMENT_CLASS(DLightTransfer, false, false) void DLightTransfer::Serialize(FSerializer &arc) { @@ -750,7 +750,7 @@ protected: BYTE Flags; }; -IMPLEMENT_CLASS(DWallLightTransfer, false, false, false, false) +IMPLEMENT_CLASS(DWallLightTransfer, false, false) void DWallLightTransfer::Serialize(FSerializer &arc) { diff --git a/src/p_spec.h b/src/p_spec.h index 41d47c721..8a0729d6a 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -243,7 +243,7 @@ public: void Serialize(FSerializer &arc); void Tick (); - void Destroy(); + void Destroy() override; protected: EPillar m_Type; @@ -572,7 +572,7 @@ public: DElevator (sector_t *sec); - void Destroy(); + void Destroy() override; void Serialize(FSerializer &arc); void Tick (); @@ -617,7 +617,6 @@ protected: int offset, int timer, bool ceiling); void DoWaggle (bool ceiling); - void Destroy(); DWaggleBase (); }; diff --git a/src/p_switch.cpp b/src/p_switch.cpp index 2d5423f08..ae7cf2143 100644 --- a/src/p_switch.cpp +++ b/src/p_switch.cpp @@ -320,7 +320,7 @@ bool P_ChangeSwitchTexture (side_t *side, int useAgain, BYTE special, bool *ques // //========================================================================== -IMPLEMENT_CLASS(DActiveButton, false, false, false, false) +IMPLEMENT_CLASS(DActiveButton, false, false) DActiveButton::DActiveButton () { diff --git a/src/p_teleport.cpp b/src/p_teleport.cpp index 80bfd4f7f..14055202a 100644 --- a/src/p_teleport.cpp +++ b/src/p_teleport.cpp @@ -47,7 +47,7 @@ extern void P_CalcHeight (player_t *player); CVAR (Bool, telezoom, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); -IMPLEMENT_CLASS(ATeleportFog, false, false, false, false) +IMPLEMENT_CLASS(ATeleportFog, false, false) void ATeleportFog::PostBeginPlay () { diff --git a/src/p_user.cpp b/src/p_user.cpp index 2917db668..03df6a0ca 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -508,7 +508,7 @@ int player_t::GetSpawnClass() // //=========================================================================== -IMPLEMENT_CLASS(PClassPlayerPawn, false, false, false, false) +IMPLEMENT_CLASS(PClassPlayerPawn, false, false) PClassPlayerPawn::PClassPlayerPawn() { @@ -622,14 +622,14 @@ void player_t::SendPitchLimits() const // //=========================================================================== -IMPLEMENT_CLASS(APlayerPawn, false, true, false, true) +IMPLEMENT_CLASS(APlayerPawn, false, true) IMPLEMENT_POINTERS_START(APlayerPawn) IMPLEMENT_POINTER(InvFirst) IMPLEMENT_POINTER(InvSel) IMPLEMENT_POINTERS_END -IMPLEMENT_CLASS(APlayerChunk, false, false, false, false) +IMPLEMENT_CLASS(APlayerChunk, false, false) void APlayerPawn::Serialize(FSerializer &arc) { @@ -882,7 +882,7 @@ void APlayerPawn::RemoveInventory (AInventory *item) // //=========================================================================== -bool APlayerPawn::UseInventory (AInventory *item) +bool APlayerPawn::DoUseInventory (AInventory *item) { const PClass *itemtype = item->GetClass(); @@ -896,7 +896,7 @@ bool APlayerPawn::UseInventory (AInventory *item) return false; } - if (!Super::UseInventory (item)) + if (!Super::DoUseInventory (item)) { // Heretic and Hexen advance the inventory cursor if the use failed. // Should this behavior be retained? @@ -1280,18 +1280,22 @@ void APlayerPawn::PlayRunning () void APlayerPawn::PlayAttacking () { - VINDEX(APlayerPawn, PlayAttacking); - VMValue params[1] = { (DObject*)this }; - VMFrameStack stack; - stack.Call(VFUNC, params, 1, nullptr, 0, nullptr); + IFVIRTUAL(APlayerPawn, PlayAttacking) + { + VMValue params[1] = { (DObject*)this }; + VMFrameStack stack; + stack.Call(func, params, 1, nullptr, 0, nullptr); + } } void APlayerPawn::PlayAttacking2 () { - VINDEX(APlayerPawn, PlayAttacking2); - VMValue params[1] = { (DObject*)this }; - VMFrameStack stack; - stack.Call(VFUNC, params, 1, nullptr, 0, nullptr); + IFVIRTUAL(APlayerPawn, PlayAttacking2) + { + VMValue params[1] = { (DObject*)this }; + VMFrameStack stack; + stack.Call(func, params, 1, nullptr, 0, nullptr); + } } void APlayerPawn::ThrowPoisonBag () @@ -1381,10 +1385,12 @@ void APlayerPawn::GiveDefaultInventory () void APlayerPawn::MorphPlayerThink () { - VINDEX(APlayerPawn, MorphPlayerThink); - VMValue params[1] = { (DObject*)this }; - VMFrameStack stack; - stack.Call(VFUNC, params, 1, nullptr, 0, nullptr); + IFVIRTUAL(APlayerPawn, MorphPlayerThink) + { + VMValue params[1] = { (DObject*)this }; + VMFrameStack stack; + stack.Call(func, params, 1, nullptr, 0, nullptr); + } } void APlayerPawn::ActivateMorphWeapon () diff --git a/src/po_man.cpp b/src/po_man.cpp index 4e304daa8..fafa227ee 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -172,7 +172,7 @@ static FPolyNode *FreePolyNodes; // //========================================================================== -IMPLEMENT_CLASS(DPolyAction, false, true, false, false) +IMPLEMENT_CLASS(DPolyAction, false, true) IMPLEMENT_POINTERS_START(DPolyAction) IMPLEMENT_POINTER(m_Interpolation) @@ -240,7 +240,7 @@ void DPolyAction::StopInterpolation () // //========================================================================== -IMPLEMENT_CLASS(DRotatePoly, false, false, false, false) +IMPLEMENT_CLASS(DRotatePoly, false, false) DRotatePoly::DRotatePoly () { @@ -257,7 +257,7 @@ DRotatePoly::DRotatePoly (int polyNum) // //========================================================================== -IMPLEMENT_CLASS(DMovePoly, false, false, false, false) +IMPLEMENT_CLASS(DMovePoly, false, false) DMovePoly::DMovePoly () { @@ -284,7 +284,7 @@ DMovePoly::DMovePoly (int polyNum) // //========================================================================== -IMPLEMENT_CLASS(DMovePolyTo, false, false, false, false) +IMPLEMENT_CLASS(DMovePolyTo, false, false) DMovePolyTo::DMovePolyTo() { @@ -309,7 +309,7 @@ DMovePolyTo::DMovePolyTo(int polyNum) // //========================================================================== -IMPLEMENT_CLASS(DPolyDoor, false, false, false, false) +IMPLEMENT_CLASS(DPolyDoor, false, false) DPolyDoor::DPolyDoor () { diff --git a/src/po_man.h b/src/po_man.h index ec6a3901b..4d78fa179 100644 --- a/src/po_man.h +++ b/src/po_man.h @@ -12,7 +12,7 @@ class DPolyAction : public DThinker public: DPolyAction(int polyNum); void Serialize(FSerializer &arc); - void Destroy(); + void Destroy() override; void Stop(); double GetSpeed() const { return m_Speed; } diff --git a/src/posix/sdl/sdlvideo.cpp b/src/posix/sdl/sdlvideo.cpp index a1e6056ca..4a6833026 100644 --- a/src/posix/sdl/sdlvideo.cpp +++ b/src/posix/sdl/sdlvideo.cpp @@ -79,7 +79,7 @@ private: SDLFB () {} }; -IMPLEMENT_CLASS(SDLFB, false, false, false, false) +IMPLEMENT_CLASS(SDLFB, false, false) struct MiniModeInfo { diff --git a/src/r_data/r_interpolate.cpp b/src/r_data/r_interpolate.cpp index c98adb47b..a202345a3 100644 --- a/src/r_data/r_interpolate.cpp +++ b/src/r_data/r_interpolate.cpp @@ -62,7 +62,7 @@ public: DSectorPlaneInterpolation() {} DSectorPlaneInterpolation(sector_t *sector, bool plane, bool attach); - void Destroy(); + void Destroy() override; void UpdateInterpolation(); void Restore(); void Interpolate(double smoothratio); @@ -91,7 +91,7 @@ public: DSectorScrollInterpolation() {} DSectorScrollInterpolation(sector_t *sector, bool plane); - void Destroy(); + void Destroy() override; void UpdateInterpolation(); void Restore(); void Interpolate(double smoothratio); @@ -119,7 +119,7 @@ public: DWallScrollInterpolation() {} DWallScrollInterpolation(side_t *side, int part); - void Destroy(); + void Destroy() override; void UpdateInterpolation(); void Restore(); void Interpolate(double smoothratio); @@ -146,7 +146,7 @@ public: DPolyobjInterpolation() {} DPolyobjInterpolation(FPolyObj *poly); - void Destroy(); + void Destroy() override; void UpdateInterpolation(); void Restore(); void Interpolate(double smoothratio); @@ -161,17 +161,17 @@ public: // //========================================================================== -IMPLEMENT_CLASS(DInterpolation, true, true, false, false) +IMPLEMENT_CLASS(DInterpolation, true, true) IMPLEMENT_POINTERS_START(DInterpolation) IMPLEMENT_POINTER(Next) IMPLEMENT_POINTER(Prev) IMPLEMENT_POINTERS_END -IMPLEMENT_CLASS(DSectorPlaneInterpolation, false, false, false, false) -IMPLEMENT_CLASS(DSectorScrollInterpolation, false, false, false, false) -IMPLEMENT_CLASS(DWallScrollInterpolation, false, false, false, false) -IMPLEMENT_CLASS(DPolyobjInterpolation, false, false, false, false) +IMPLEMENT_CLASS(DSectorPlaneInterpolation, false, false) +IMPLEMENT_CLASS(DSectorScrollInterpolation, false, false) +IMPLEMENT_CLASS(DWallScrollInterpolation, false, false) +IMPLEMENT_CLASS(DPolyobjInterpolation, false, false) //========================================================================== // diff --git a/src/r_data/r_interpolate.h b/src/r_data/r_interpolate.h index 092cbe5ee..44ff9bed0 100644 --- a/src/r_data/r_interpolate.h +++ b/src/r_data/r_interpolate.h @@ -27,7 +27,7 @@ public: int AddRef(); int DelRef(bool force = false); - virtual void Destroy(); + void Destroy() override; virtual void UpdateInterpolation() = 0; virtual void Restore() = 0; virtual void Interpolate(double smoothratio) = 0; diff --git a/src/r_defs.h b/src/r_defs.h index a21d23616..2d16d28f9 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -253,7 +253,7 @@ class ASectorAction : public AActor DECLARE_CLASS (ASectorAction, AActor) public: ASectorAction (bool activatedByUse = false); - void Destroy (); + void Destroy () override; void BeginPlay (); void Activate (AActor *source); void Deactivate (AActor *source); diff --git a/src/s_advsound.cpp b/src/s_advsound.cpp index c68df5f3c..083e0eeef 100644 --- a/src/s_advsound.cpp +++ b/src/s_advsound.cpp @@ -2213,7 +2213,7 @@ private: int NextCheck; }; -IMPLEMENT_CLASS(AAmbientSound, false, false, false, false) +IMPLEMENT_CLASS(AAmbientSound, false, false) //========================================================================== // @@ -2346,7 +2346,7 @@ void AAmbientSound::SetTicker (struct FAmbientSound *ambient) void AAmbientSound::BeginPlay () { Super::BeginPlay (); - Activate (NULL); + CallActivate (NULL); } //========================================================================== @@ -2470,7 +2470,7 @@ public: virtual void PostBeginPlay(); }; -IMPLEMENT_CLASS(AMusicChanger, false, false, false, false) +IMPLEMENT_CLASS(AMusicChanger, false, false) bool AMusicChanger::DoTriggerAction (AActor *triggerer, int activationType) { diff --git a/src/s_sndseq.cpp b/src/s_sndseq.cpp index 1bed35ed5..28786ef8f 100644 --- a/src/s_sndseq.cpp +++ b/src/s_sndseq.cpp @@ -105,7 +105,7 @@ class DSeqActorNode : public DSeqNode HAS_OBJECT_POINTERS public: DSeqActorNode(AActor *actor, int sequence, int modenum); - void Destroy(); + void Destroy() override; void Serialize(FSerializer &arc); void MakeSound(int loop, FSoundID id) { @@ -133,7 +133,7 @@ class DSeqPolyNode : public DSeqNode DECLARE_CLASS(DSeqPolyNode, DSeqNode) public: DSeqPolyNode(FPolyObj *poly, int sequence, int modenum); - void Destroy(); + void Destroy() override; void Serialize(FSerializer &arc); void MakeSound(int loop, FSoundID id) { @@ -161,7 +161,7 @@ class DSeqSectorNode : public DSeqNode DECLARE_CLASS(DSeqSectorNode, DSeqNode) public: DSeqSectorNode(sector_t *sec, int chan, int sequence, int modenum); - void Destroy(); + void Destroy() override; void Serialize(FSerializer &arc); void MakeSound(int loop, FSoundID id) { @@ -285,7 +285,7 @@ void DSeqNode::SerializeSequences (FSerializer &arc) arc("sndseqlisthead", SequenceListHead); } -IMPLEMENT_CLASS(DSeqNode, false, true, false, false) +IMPLEMENT_CLASS(DSeqNode, false, true) IMPLEMENT_POINTERS_START(DSeqNode) IMPLEMENT_POINTER(m_ChildSeqNode) @@ -429,7 +429,7 @@ FName DSeqNode::GetSequenceName () const return Sequences[m_Sequence]->SeqName; } -IMPLEMENT_CLASS(DSeqActorNode, false, true, false, false) +IMPLEMENT_CLASS(DSeqActorNode, false, true) IMPLEMENT_POINTERS_START(DSeqActorNode) IMPLEMENT_POINTER(m_Actor) @@ -441,7 +441,7 @@ void DSeqActorNode::Serialize(FSerializer &arc) arc("actor", m_Actor); } -IMPLEMENT_CLASS(DSeqPolyNode, false, false, false, false) +IMPLEMENT_CLASS(DSeqPolyNode, false, false) void DSeqPolyNode::Serialize(FSerializer &arc) { @@ -449,7 +449,7 @@ void DSeqPolyNode::Serialize(FSerializer &arc) arc("poly", m_Poly); } -IMPLEMENT_CLASS(DSeqSectorNode, false, false, false, false) +IMPLEMENT_CLASS(DSeqSectorNode, false, false) void DSeqSectorNode::Serialize(FSerializer &arc) { diff --git a/src/s_sndseq.h b/src/s_sndseq.h index 74ded5af4..13444f862 100644 --- a/src/s_sndseq.h +++ b/src/s_sndseq.h @@ -22,7 +22,7 @@ class DSeqNode : public DObject public: void Serialize(FSerializer &arc); void StopAndDestroy (); - void Destroy (); + void Destroy() override; void Tick (); void ChangeData (int seqOffset, int delayTics, float volume, FSoundID currentSoundID); void AddChoice (int seqnum, seqtype_t type); diff --git a/src/scripting/decorate/olddecorations.cpp b/src/scripting/decorate/olddecorations.cpp index 7540d45f4..8321a8f89 100644 --- a/src/scripting/decorate/olddecorations.cpp +++ b/src/scripting/decorate/olddecorations.cpp @@ -96,7 +96,7 @@ public: } }; -IMPLEMENT_CLASS(AFakeInventory, false, false, false, false) +IMPLEMENT_CLASS(AFakeInventory, false, false) DEFINE_FIELD(AFakeInventory, Respawnable) diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 05c43aa1f..c7082ff76 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -667,7 +667,7 @@ public: bool Final = false; // cannot be overridden bool Unsafe = false; // Contains references to class fields that are unsafe for psp and item state calls. BYTE ImplicitArgs = 0; // either 0 for static, 1 for method or 3 for action - int VirtualIndex = -1; + unsigned VirtualIndex = ~0u; FName Name; TArray DefaultArgs; FString PrintableName; // so that the VM can print meaningful info if something in this function goes wrong. diff --git a/src/scripting/vm/vmframe.cpp b/src/scripting/vm/vmframe.cpp index f35c3718d..0ec6ec15b 100644 --- a/src/scripting/vm/vmframe.cpp +++ b/src/scripting/vm/vmframe.cpp @@ -34,15 +34,15 @@ #include #include "dobject.h" -IMPLEMENT_CLASS(VMException, false, false, false, false) -IMPLEMENT_CLASS(VMFunction, true, true, false, false) +IMPLEMENT_CLASS(VMException, false, false) +IMPLEMENT_CLASS(VMFunction, true, true) IMPLEMENT_POINTERS_START(VMFunction) IMPLEMENT_POINTER(Proto) IMPLEMENT_POINTERS_END -IMPLEMENT_CLASS(VMScriptFunction, false, false, false, false) -IMPLEMENT_CLASS(VMNativeFunction, false, false, false, false) +IMPLEMENT_CLASS(VMScriptFunction, false, false) +IMPLEMENT_CLASS(VMNativeFunction, false, false) VMScriptFunction::VMScriptFunction(FName name) { diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index a4a2cc453..98ebc17d9 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -51,8 +51,6 @@ #include "codegeneration/codegen.h" #include "vmbuilder.h" -#define DEFAULTS_VMEXPORT ((BYTE *)(void *)1) - //========================================================================== // // ZCCCompiler :: ProcessClass @@ -505,26 +503,6 @@ void ZCCCompiler::CreateClassTypes() } else { - // The parent was the last native class in the inheritance tree. - // There is probably a better place for this somewhere else - // TODO: Do this somewhere else or find a less hackish way to do it - if (!parent->bRuntimeClass) - { - //assert(parent->VMExported != nullptr); // Ideally the macro would be used on all inheritable-native classes - /**/ if (parent->VMExported != nullptr) { /**/ // remove the if condition when all done - - parent = parent->VMExported; - assert(parent->bRuntimeClass == false); - - if (parent->Defaults == nullptr) - { - // We have to manually do that since zscript knows nothing about these - parent->Defaults = DEFAULTS_VMEXPORT; - } - - /**/ } /**/ - } - // We will never get here if the name is a duplicate, so we can just do the assignment. try { @@ -1980,15 +1958,6 @@ void ZCCCompiler::InitDefaults() // Copy the parent's defaults and meta data. auto ti = static_cast(c->Type()); - // Hack for the DVMObjects as they weren't in the list originally - // TODO: process them in a non hackish way obviously - if (ti->ParentClass->Defaults == DEFAULTS_VMEXPORT) - { - ti->ParentClass->Defaults = nullptr; - ti->ParentClass->InitializeDefaults(); - ti->ParentClass->ParentClass->DeriveData(ti->ParentClass); - } - ti->InitializeDefaults(); ti->ParentClass->DeriveData(ti); @@ -2400,11 +2369,6 @@ void ZCCCompiler::InitFunctions() // cannot be done earlier because it requires the parent class to be processed by this code, too. if (c->Type()->ParentClass != nullptr) { - if (c->Type()->ParentClass->Virtuals.Size() == 0) - { - // This a VMClass which didn't get processed here. - c->Type()->ParentClass->Virtuals = c->Type()->ParentClass->ParentClass->Virtuals; - } c->Type()->Virtuals = c->Type()->ParentClass->Virtuals; } for (auto f : c->Functions) diff --git a/src/v_video.cpp b/src/v_video.cpp index b18a6e727..7192c5d03 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -69,8 +69,8 @@ int active_con_scale(); FRenderer *Renderer; -IMPLEMENT_CLASS(DCanvas, true, false, false, false) -IMPLEMENT_CLASS(DFrameBuffer, true, false, false, false) +IMPLEMENT_CLASS(DCanvas, true, false) +IMPLEMENT_CLASS(DFrameBuffer, true, false) #if defined(_DEBUG) && defined(_M_IX86) && !defined(__MINGW32__) #define DBGBREAK { __asm int 3 } @@ -106,11 +106,11 @@ public: float Gamma; }; -IMPLEMENT_CLASS(DDummyFrameBuffer, true, false, false, false) +IMPLEMENT_CLASS(DDummyFrameBuffer, true, false) // SimpleCanvas is not really abstract, but this macro does not // try to generate a CreateNew() function. -IMPLEMENT_CLASS(DSimpleCanvas, true, false, false, false) +IMPLEMENT_CLASS(DSimpleCanvas, true, false) class FPaletteTester : public FTexture { diff --git a/src/virtual.h b/src/virtual.h index 26fc694ea..8485dec07 100644 --- a/src/virtual.h +++ b/src/virtual.h @@ -1,275 +1,21 @@ - - - -// Templates really are powerful -#define VMEXPORTED_NATIVES_START \ - template class ExportedNatives : public ExportedNatives {}; \ - template<> class ExportedNatives { \ - protected: ExportedNatives() {} \ - public: \ - static ExportedNatives *Get() { static ExportedNatives *Instance = nullptr; if (Instance == nullptr) Instance = new ExportedNatives; return Instance; } \ - ExportedNatives(const ExportedNatives&) = delete; \ - ExportedNatives(ExportedNatives&&) = delete; - -#define VMEXPORTED_NATIVES_FUNC(func) \ - template ret func(void *ptr, args ... arglist) { return ret(); } - -#define VMEXPORTED_NATIVES_END }; - -#define VMEXPORT_NATIVES_START(cls, parent) \ - template<> class ExportedNatives : public ExportedNatives { \ - protected: ExportedNatives() {} \ - public: \ - static ExportedNatives *Get() { static ExportedNatives *Instance = nullptr; if (Instance == nullptr) Instance = new ExportedNatives; return Instance; } \ - ExportedNatives(const ExportedNatives&) = delete; \ - ExportedNatives(ExportedNatives&&) = delete; - -#define VMEXPORT_NATIVES_FUNC(func) \ - template ret func(void *ptr, args ... arglist) { return static_cast(ptr)->object::func(arglist...); } - -#define VMEXPORT_NATIVES_END(cls) }; - - -//Initial list -VMEXPORTED_NATIVES_START - VMEXPORTED_NATIVES_FUNC(Destroy) - VMEXPORTED_NATIVES_FUNC(Tick) - VMEXPORTED_NATIVES_FUNC(PostBeginPlay) - VMEXPORTED_NATIVES_FUNC(BeginPlay) - VMEXPORTED_NATIVES_FUNC(Activate) - VMEXPORTED_NATIVES_FUNC(Deactivate) - VMEXPORTED_NATIVES_FUNC(DoSpecialDamage) - VMEXPORTED_NATIVES_FUNC(UseInventory) -VMEXPORTED_NATIVES_END - - -inline int GetVirtualIndex(PClass *cls, const char *funcname) +inline unsigned GetVirtualIndex(PClass *cls, const char *funcname) { // Look up the virtual function index in the defining class because this may have gotten overloaded in subclasses with something different than a virtual override. auto sym = dyn_cast(cls->Symbols.FindSymbol(funcname, false)); assert(sym != nullptr); auto VIndex = sym->Variants[0].Implementation->VirtualIndex; - assert(VIndex >= 0); return VIndex; } -#define VINDEX(cls, funcname) \ - static int VIndex = -1; \ - if (VIndex < 0) { \ +#define IFVIRTUAL(cls, funcname) \ + static unsigned VIndex = ~0u; \ + if (VIndex == ~0u) { \ VIndex = GetVirtualIndex(RUNTIME_CLASS(cls), #funcname); \ - if (VIndex < 0) I_Error("Unable to find virtual function %s in " #cls, #funcname); \ - } + assert(VIndex != ~0u); \ + } \ + auto clss = GetClass(); \ + VMFunction *func = clss->Virtuals.Size() > VIndex? clss->Virtuals[VIndex] : nullptr; \ + if (func != nullptr) -#define VFUNC this->GetClass()->Virtuals[VIndex] -template -class DVMObject : public T -{ -public: - static char *FormatClassName() - { - static char *name = nullptr; - if (name == nullptr) - { - name = new char[64]; - mysnprintf(name, 64, "DVMObject<%s>", Super::RegistrationInfo.Name); - atterm([]{ delete[] DVMObject::RegistrationInfo.Name; }); - } - return name; - } - virtual PClass *StaticType() const - { - return RegistrationInfo.MyClass; - } - static ClassReg RegistrationInfo; - static ClassReg * const RegistrationInfoPtr; - typedef T Super; - -private: - typedef DVMObject ThisClass; - static void InPlaceConstructor(void *mem) - { - new((EInPlace *)mem) DVMObject; - } - -public: - void Destroy() - { - if (this->ObjectFlags & OF_SuperCall) - { - this->ObjectFlags &= ~OF_SuperCall; - ExportedNatives::Get()->template Destroy(this); - } - else - { - VINDEX(DObject, Destroy); - // Without the type cast this picks the 'void *' assignment... - VMValue params[1] = { (DObject*)this }; - VMFrameStack stack; - stack.Call(VFUNC, params, 1, nullptr, 0, nullptr); - } - } - void Tick() - { - if (this->ObjectFlags & OF_SuperCall) - { - this->ObjectFlags &= ~OF_SuperCall; - ExportedNatives::Get()->template Tick(this); - } - else - { - VINDEX(DThinker, Tick); - // Without the type cast this picks the 'void *' assignment... - VMValue params[1] = { (DObject*)this }; - VMFrameStack stack; - stack.Call(VFUNC, params, 1, nullptr, 0, nullptr); - } - } - - void PostBeginPlay() - { - if (this->ObjectFlags & OF_SuperCall) - { - this->ObjectFlags &= ~OF_SuperCall; - ExportedNatives::Get()->template PostBeginPlay(this); - } - else - { - VINDEX(DThinker, PostBeginPlay); - // Without the type cast this picks the 'void *' assignment... - VMValue params[1] = { (DObject*)this }; - VMFrameStack stack; - stack.Call(VFUNC, params, 1, nullptr, 0, nullptr); - } - } - - void BeginPlay() - { - if (this->ObjectFlags & OF_SuperCall) - { - this->ObjectFlags &= ~OF_SuperCall; - ExportedNatives::Get()->template BeginPlay(this); - } - else - { - VINDEX(AActor, BeginPlay); - // Without the type cast this picks the 'void *' assignment... - VMValue params[1] = { (DObject*)this }; - VMFrameStack stack; - stack.Call(VFUNC, params, 1, nullptr, 0, nullptr); - } - } - - void Activate(AActor *activator) - { - if (this->ObjectFlags & OF_SuperCall) - { - this->ObjectFlags &= ~OF_SuperCall; - ExportedNatives::Get()->template Activate(this, activator); - } - else - { - VINDEX(AActor, Activate); - // Without the type cast this picks the 'void *' assignment... - VMValue params[2] = { (DObject*)this, (DObject*)activator }; - VMFrameStack stack; - stack.Call(VFUNC, params, 2, nullptr, 0, nullptr); - } - } - - void Deactivate(AActor *activator) - { - if (this->ObjectFlags & OF_SuperCall) - { - this->ObjectFlags &= ~OF_SuperCall; - ExportedNatives::Get()->template Deactivate(this, activator); - } - else - { - VINDEX(AActor, Deactivate); - // Without the type cast this picks the 'void *' assignment... - VMValue params[2] = { (DObject*)this, (DObject*)activator }; - VMFrameStack stack; - stack.Call(VFUNC, params, 2, nullptr, 0, nullptr); - } - } - int DoSpecialDamage(AActor *target, int damage, FName damagetype) - { - if (this->ObjectFlags & OF_SuperCall) - { - this->ObjectFlags &= ~OF_SuperCall; - return ExportedNatives::Get()->template DoSpecialDamage(this, target, damage, damagetype); - } - else - { - VINDEX(AActor, DoSpecialDamage); - // Without the type cast this picks the 'void *' assignment... - VMValue params[4] = { (DObject*)this, (DObject*)target, damage, damagetype.GetIndex() }; - VMReturn ret; - VMFrameStack stack; - int retval; - ret.IntAt(&retval); - stack.Call(VFUNC, params, 4, &ret, 1, nullptr); - return retval; - } - } - bool UseInventory(AInventory *item) - { - if (this->ObjectFlags & OF_SuperCall) - { - this->ObjectFlags &= ~OF_SuperCall; - return ExportedNatives::Get()->template UseInventory(this, item); - } - else - { - VINDEX(AActor, UseInventory); - // Without the type cast this picks the 'void *' assignment... - VMValue params[2] = { (DObject*)this, (DObject*)item }; - VMReturn ret; - VMFrameStack stack; - int retval; - ret.IntAt(&retval); - stack.Call(VFUNC, params, 2, &ret, 1, nullptr); - return !!retval; - } - } - -}; - -template -ClassReg DVMObject::RegistrationInfo = -{ - nullptr, - DVMObject::FormatClassName(), - &DVMObject::Super::RegistrationInfo, - nullptr, - nullptr, - DVMObject::InPlaceConstructor, - nullptr, - sizeof(DVMObject), - DVMObject::MetaClassNum -}; -template _DECLARE_TI(DVMObject) - -VMEXPORT_NATIVES_START(DObject, void) - VMEXPORT_NATIVES_FUNC(Destroy) -VMEXPORT_NATIVES_END(DObject) - -VMEXPORT_NATIVES_START(DThinker, DObject) - VMEXPORT_NATIVES_FUNC(Tick) - VMEXPORT_NATIVES_FUNC(PostBeginPlay) -VMEXPORT_NATIVES_END(DThinker) - -VMEXPORT_NATIVES_START(AActor, DThinker) - VMEXPORT_NATIVES_FUNC(BeginPlay) - VMEXPORT_NATIVES_FUNC(Activate) - VMEXPORT_NATIVES_FUNC(Deactivate) - VMEXPORT_NATIVES_FUNC(DoSpecialDamage) - VMEXPORT_NATIVES_FUNC(UseInventory) -VMEXPORT_NATIVES_END(AActor) - -/* -VMEXPORT_NATIVES_START(AActor, DThinker) -VMEXPORT_NATIVES_END(AActor) -*/ diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index 6d162bbec..0e8dd3dec 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -91,7 +91,7 @@ // TYPES ------------------------------------------------------------------- -IMPLEMENT_CLASS(D3DFB, false, false, false, false) +IMPLEMENT_CLASS(D3DFB, false, false) struct D3DFB::PackedTexture { diff --git a/src/win32/fb_ddraw.cpp b/src/win32/fb_ddraw.cpp index bd5a4db23..85f0c4768 100644 --- a/src/win32/fb_ddraw.cpp +++ b/src/win32/fb_ddraw.cpp @@ -61,7 +61,7 @@ // TYPES ------------------------------------------------------------------- -IMPLEMENT_CLASS(DDrawFB, false, false, false, false) +IMPLEMENT_CLASS(DDrawFB, false, false) // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- diff --git a/src/win32/win32video.cpp b/src/win32/win32video.cpp index df96f7f41..0d91ed1d0 100644 --- a/src/win32/win32video.cpp +++ b/src/win32/win32video.cpp @@ -80,7 +80,7 @@ // TYPES ------------------------------------------------------------------- -IMPLEMENT_CLASS(BaseWinFB, true, false, false, false) +IMPLEMENT_CLASS(BaseWinFB, true, false) typedef IDirect3D9 *(WINAPI *DIRECT3DCREATE9FUNC)(UINT SDKVersion); typedef HRESULT (WINAPI *DIRECTDRAWCREATEFUNC)(GUID FAR *lpGUID, LPDIRECTDRAW FAR *lplpDD, IUnknown FAR *pUnkOuter); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index c899bbd37..3eebceeb5 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -6,7 +6,7 @@ class Object native native static int G_SkillPropertyInt(int p); native static double G_SkillPropertyFloat(int p); - virtual native void Destroy(); + /*virtual*/ native void Destroy(); } class Thinker : Object native diff --git a/wadsrc/static/zscript/hexen/firedemon.txt b/wadsrc/static/zscript/hexen/firedemon.txt index b425ecb11..9ca12529f 100644 --- a/wadsrc/static/zscript/hexen/firedemon.txt +++ b/wadsrc/static/zscript/hexen/firedemon.txt @@ -4,7 +4,7 @@ class FireDemon : Actor { const FIREDEMON_ATTACK_RANGE = 64*8.; - int strafecount; + int fdstrafecount; Default { @@ -77,7 +77,7 @@ class FireDemon : Actor // Fire Demon AI // // special1 index into floatbob - // strafecount whether strafing or not + // fdstrafecount whether strafing or not //============================================================================ //============================================================================ @@ -125,7 +125,7 @@ class FireDemon : Actor } // Initialize fire demon - strafecount = 0; + fdstrafecount = 0; bJustAttacked = false; } @@ -188,13 +188,13 @@ class FireDemon : Actor } // Strafe - if (strafecount > 0) + if (fdstrafecount > 0) { - strafecount--; + fdstrafecount--; } else { - strafecount = 0; + fdstrafecount = 0; Vel.X = Vel.Y = 0; dist = Distance2D(target); if (dist < FIREDEMON_ATTACK_RANGE) @@ -207,7 +207,7 @@ class FireDemon : Actor else ang -= 90; Thrust(8, ang); - strafecount = 3; // strafe time + fdstrafecount = 3; // strafe time } } } @@ -215,7 +215,7 @@ class FireDemon : Actor FaceMovementDirection (); // Normal movement - if (!strafecount) + if (!fdstrafecount) { if (--movecount<0 || !MonsterMove ()) { From c25774e311e7d73e10710d501de901a74c5a9960 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Thu, 24 Nov 2016 20:43:37 +0100 Subject: [PATCH 104/185] - Fixed the Super Shotgun refire mismatch. --- wadsrc/static/zscript/doom/weaponssg.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wadsrc/static/zscript/doom/weaponssg.txt b/wadsrc/static/zscript/doom/weaponssg.txt index 75ac9f09e..6c06fe6ec 100644 --- a/wadsrc/static/zscript/doom/weaponssg.txt +++ b/wadsrc/static/zscript/doom/weaponssg.txt @@ -111,6 +111,7 @@ extend class StateProvider action void A_CloseShotgun2() { - A_PlaySound("weapons/sshotc", CHAN_WEAPON); + A_PlaySound("weapons/sshotc", CHAN_WEAPON); + A_Refire(); } } From 11ac0c622b15f4a6c97c8a59dcba0611702d57da Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 25 Nov 2016 01:33:04 +0100 Subject: [PATCH 105/185] - fixed: The BFG needs to get its default ammo usage from the DehInfo struct. - fixed: State's fields need to be declared native. --- src/d_dehacked.cpp | 6 ++++ src/scripting/thingdef_data.cpp | 5 +++ wadsrc/static/zscript/base.txt | 41 +++++++++++++++--------- wadsrc/static/zscript/doom/weaponbfg.txt | 2 +- 4 files changed, 38 insertions(+), 16 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 40e8e5702..679c8c1ad 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -214,6 +214,12 @@ DehInfo deh = 40, // BFG cells per shot }; +DEFINE_FIELD_X(DehInfo, DehInfo, MaxSoulsphere) +DEFINE_FIELD_X(DehInfo, DehInfo, ExplosionStyle) +DEFINE_FIELD_X(DehInfo, DehInfo, ExplosionAlpha) +DEFINE_FIELD_X(DehInfo, DehInfo, NoAutofreeze) +DEFINE_FIELD_X(DehInfo, DehInfo, BFGCells) + // Doom identified pickup items by their sprites. ZDoom prefers to use their // class type to identify them instead. To support the traditional Doom // behavior, for every thing touched by dehacked that has the MF_PICKUP flag, diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 3d7a9d3e1..3f7f27e43 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -706,6 +706,11 @@ void InitThingdef() PField *levelf = new PField("level", lstruct, VARF_Native | VARF_Static, (intptr_t)&level); GlobalSymbols.AddSymbol(levelf); + // set up a variable for the DEH data + PStruct *dstruct = NewNativeStruct("DehInfo", nullptr); + PField *dehi = new PField("deh", dstruct, VARF_Native | VARF_Static, (intptr_t)&deh); + GlobalSymbols.AddSymbol(dehi); + // set up a variable for the global players array. PStruct *pstruct = NewNativeStruct("PlayerInfo", nullptr); pstruct->Size = sizeof(player_t); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 3eebceeb5..160c1c514 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -92,23 +92,34 @@ struct LevelLocals native // level_info_t *info cannot be done yet. } +// a few values of this need to be readable by the play code. +// Most are handled at load time and are omitted here. +struct DehInfo native +{ + native int MaxSoulsphere; + native uint8 ExplosionStyle; + native double ExplosionAlpha; + native int NoAutofreeze; + native int BFGCells; +} + struct State native { - State NextState; - int sprite; - int16 Tics; - uint16 TicRange; - uint8 Frame; - uint8 UseFlags; - int Misc1; - int Misc2; - uint16 bSlow; - uint16 bFast; - bool bFullbright; - bool bNoDelay; - bool bSameFrame; - bool bCanRaise; - bool bDehacked; + native State NextState; + native int sprite; + native int16 Tics; + native uint16 TicRange; + native uint8 Frame; + native uint8 UseFlags; + native int Misc1; + native int Misc2; + native uint16 bSlow; + native uint16 bFast; + native bool bFullbright; + native bool bNoDelay; + native bool bSameFrame; + native bool bCanRaise; + native bool bDehacked; } struct Sector native diff --git a/wadsrc/static/zscript/doom/weaponbfg.txt b/wadsrc/static/zscript/doom/weaponbfg.txt index 1b96bfc29..e83c5d8f6 100644 --- a/wadsrc/static/zscript/doom/weaponbfg.txt +++ b/wadsrc/static/zscript/doom/weaponbfg.txt @@ -77,7 +77,7 @@ extend class StateProvider Weapon weap = player.ReadyWeapon; if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) { - if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + if (!weap.DepleteAmmo (weap.bAltFire, true, deh.MaxSoulsphere/*BFGCells*/)) return; } From b5f55cacba49348ff1850a7794942846cc0d5053 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 25 Nov 2016 09:56:06 +0100 Subject: [PATCH 106/185] - removed test code. --- wadsrc/static/zscript/doom/weaponbfg.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/zscript/doom/weaponbfg.txt b/wadsrc/static/zscript/doom/weaponbfg.txt index e83c5d8f6..9bf0084b3 100644 --- a/wadsrc/static/zscript/doom/weaponbfg.txt +++ b/wadsrc/static/zscript/doom/weaponbfg.txt @@ -77,7 +77,7 @@ extend class StateProvider Weapon weap = player.ReadyWeapon; if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) { - if (!weap.DepleteAmmo (weap.bAltFire, true, deh.MaxSoulsphere/*BFGCells*/)) + if (!weap.DepleteAmmo (weap.bAltFire, true, deh.BFGCells)) return; } From 82e5e2daa949c66f46e577c9ffa7c1e1bf99aa62 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 25 Nov 2016 12:31:13 +0100 Subject: [PATCH 107/185] - fixed a variable mixup in Dehacked weapon initialization. This ultimately failed to set the weapon's AmmoUse field and made the weapon fail to detect it's out of ammo. --- src/d_dehacked.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 679c8c1ad..624116e06 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -3085,10 +3085,10 @@ void FinishDehPatch () StateVisited[state] = true; for(unsigned j = 0; AmmoPerAttacks[j].func != NAME_None; j++) { - if (AmmoPerAttacks[i].ptr == nullptr) + if (AmmoPerAttacks[j].ptr == nullptr) { - auto p = dyn_cast(RUNTIME_CLASS(AStateProvider)->Symbols.FindSymbol(AmmoPerAttacks[i].func, true)); - if (p != nullptr) AmmoPerAttacks[i].ptr = p->Variants[0].Implementation; + auto p = dyn_cast(RUNTIME_CLASS(AStateProvider)->Symbols.FindSymbol(AmmoPerAttacks[j].func, true)); + if (p != nullptr) AmmoPerAttacks[j].ptr = p->Variants[0].Implementation; } if (state->ActionFunc == AmmoPerAttacks[j].ptr) { From c2f7ed7f1c2266b72d35f8ef0684096225f35dbc Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 25 Nov 2016 12:45:17 +0100 Subject: [PATCH 108/185] - fixed: BuiltinNameToClass should treat NAME_None as 'nothing'. It's names that get here, after all, so the name for 'nothing' should actually mean 'nothing' here. --- src/scripting/codegeneration/codegen.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index b7e20f7fc..a34e12f7d 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -9150,15 +9150,19 @@ int BuiltinNameToClass(VMFrameStack *stack, VMValue *param, TArray &def assert(ret->RegType == REGT_POINTER); FName clsname = ENamedName(param[0].i); - const PClass *cls = PClass::FindClass(clsname); - const PClass *desttype = reinterpret_cast(param[1].a); - - if (!cls->IsDescendantOf(desttype)) + if (clsname != NAME_None) { - Printf("class '%s' is not compatible with '%s'", clsname.GetChars(), desttype->TypeName.GetChars()); - cls = nullptr; + const PClass *cls = PClass::FindClass(clsname); + const PClass *desttype = reinterpret_cast(param[1].a); + + if (!cls->IsDescendantOf(desttype)) + { + Printf("class '%s' is not compatible with '%s'\n", clsname.GetChars(), desttype->TypeName.GetChars()); + cls = nullptr; + } + ret->SetPointer(const_cast(cls), ATAG_OBJECT); } - ret->SetPointer(const_cast(cls), ATAG_OBJECT); + else ret->SetPointer(nullptr, ATAG_OBJECT); return 1; } From 8dba322775eeedf2a8a22eda5437a002f96fae0b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 25 Nov 2016 16:05:03 +0100 Subject: [PATCH 109/185] - scriptified Heretic's Skull Rod. - Took the opportunity and fixed the logic for the Skull Rod's rain spawner. The old code which was part of the 3D floor submission was unable to work with portals at all. The new approach no longer tries to hide the dead projectile in the ceiling, it leaves it where it is and changes a few flags, so that its z-position can be used as reference to get the actual ceiling. This works for line portals, but for sector portals still requires some changes to sector_t::NextHighestCeilingAt to work, but at least this can be made to work unlike the old code. - added names for the player-related translations to A_SetTranslation. - fixed: Failure to resolve a function argument was checked for, too late. - made the parameter for A_SetTranslation a name instead of a string, because it is more efficient. We do not need full strings here. --- src/actor.h | 2 +- src/g_heretic/a_hereticweaps.cpp | 299 ------------ src/namedef.h | 19 + src/p_actionfunctions.cpp | 2 +- src/p_mobj.cpp | 19 +- src/p_sectors.cpp | 30 +- src/r_data/r_translate.cpp | 37 +- src/r_data/r_translate.h | 2 +- src/scripting/codegeneration/codegen.cpp | 2 +- src/scripting/thingdef_data.cpp | 9 +- wadsrc/static/zscript.txt | 1 + wadsrc/static/zscript/actor.txt | 6 +- wadsrc/static/zscript/base.txt | 8 +- wadsrc/static/zscript/constants.txt | 30 +- .../static/zscript/heretic/hereticweaps.txt | 200 --------- .../static/zscript/heretic/weaponskullrod.txt | 425 ++++++++++++++++++ 16 files changed, 570 insertions(+), 521 deletions(-) create mode 100644 wadsrc/static/zscript/heretic/weaponskullrod.txt diff --git a/src/actor.h b/src/actor.h index 36fcc5de4..bdb5241d1 100644 --- a/src/actor.h +++ b/src/actor.h @@ -759,7 +759,7 @@ public: virtual FName GetSpecies(); // set translation - void SetTranslation(const char *trname); + void SetTranslation(FName trname); double GetBobOffset(double ticfrac = 0) const { diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp index 4e2d62f1d..7ec036413 100644 --- a/src/g_heretic/a_hereticweaps.cpp +++ b/src/g_heretic/a_hereticweaps.cpp @@ -46,305 +46,6 @@ void P_DSparilTeleport (AActor *actor); extern bool P_AutoUseChaosDevice (player_t *player); -// --- Skull rod ------------------------------------------------------------ - - -// Rain pillar 1 ------------------------------------------------------------ - -class ARainPillar : public AActor -{ - DECLARE_CLASS (ARainPillar, AActor) -public: - int DoSpecialDamage (AActor *target, int damage, FName damagetype); -}; - -IMPLEMENT_CLASS(ARainPillar, false, false) - -int ARainPillar::DoSpecialDamage (AActor *target, int damage, FName damagetype) -{ - if (target->flags2 & MF2_BOSS) - { // Decrease damage for bosses - damage = (pr_rp() & 7) + 1; - } - return damage; -} - -// Rain tracker "inventory" item -------------------------------------------- - -class ARainTracker : public AInventory -{ - DECLARE_CLASS (ARainTracker, AInventory) -public: - - void Serialize(FSerializer &arc); - TObjPtr Rain1, Rain2; -}; - -IMPLEMENT_CLASS(ARainTracker, false, false) - -void ARainTracker::Serialize(FSerializer &arc) -{ - Super::Serialize (arc); - arc("rain1", Rain1) - ("rain2", Rain2); -} - -//---------------------------------------------------------------------------- -// -// PROC A_FireSkullRodPL1 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_FireSkullRodPL1) -{ - PARAM_ACTION_PROLOGUE(AActor); - - AActor *mo; - player_t *player; - - if (NULL == (player = self->player)) - { - return 0; - } - - AWeapon *weapon = player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - mo = P_SpawnPlayerMissile (self, PClass::FindActor("HornRodFX1")); - // Randomize the first frame - if (mo && pr_fsr1() > 128) - { - mo->SetState (mo->state->GetNextState()); - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_FireSkullRodPL2 -// -// The special2 field holds the player number that shot the rain missile. -// The special1 field holds the id of the rain sound. -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_FireSkullRodPL2) -{ - PARAM_ACTION_PROLOGUE(AActor); - - player_t *player; - AActor *MissileActor; - FTranslatedLineTarget t; - - if (NULL == (player = self->player)) - { - return 0; - } - AWeapon *weapon = player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - P_SpawnPlayerMissile (self, 0,0,0, PClass::FindActor("HornRodFX2"), self->Angles.Yaw, &t, &MissileActor); - // Use MissileActor instead of the return value from - // P_SpawnPlayerMissile because we need to give info to the mobj - // even if it exploded immediately. - if (MissileActor != NULL) - { - MissileActor->special2 = (int)(player - players); - if (t.linetarget && !t.unlinked) - { - MissileActor->tracer = t.linetarget; - } - S_Sound (MissileActor, CHAN_WEAPON, "weapons/hornrodpowshoot", 1, ATTN_NORM); - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_AddPlayerRain -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_AddPlayerRain) -{ - PARAM_SELF_PROLOGUE(AActor); - - ARainTracker *tracker; - - if (self->target == NULL || self->target->health <= 0) - { // Shooter is dead or nonexistant - return 0; - } - - tracker = self->target->FindInventory (); - - // They player is only allowed two rainstorms at a time. Shooting more - // than that will cause the oldest one to terminate. - if (tracker != NULL) - { - if (tracker->Rain1 && tracker->Rain2) - { // Terminate an active rain - if (tracker->Rain1->health < tracker->Rain2->health) - { - if (tracker->Rain1->health > 16) - { - tracker->Rain1->health = 16; - } - tracker->Rain1 = NULL; - } - else - { - if (tracker->Rain2->health > 16) - { - tracker->Rain2->health = 16; - } - tracker->Rain2 = NULL; - } - } - } - else - { - tracker = static_cast (self->target->GiveInventoryType (RUNTIME_CLASS(ARainTracker))); - } - // Add rain mobj to list - if (tracker->Rain1) - { - tracker->Rain2 = self; - } - else - { - tracker->Rain1 = self; - } - self->special1 = S_FindSound ("misc/rain"); - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_SkullRodStorm -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_SkullRodStorm) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo; - ARainTracker *tracker; - - if (self->health-- == 0) - { - S_StopSound (self, CHAN_BODY); - if (self->target == NULL) - { // Player left the game - self->Destroy (); - return 0; - } - tracker = self->target->FindInventory (); - if (tracker != NULL) - { - if (tracker->Rain1 == self) - { - tracker->Rain1 = NULL; - } - else if (tracker->Rain2 == self) - { - tracker->Rain2 = NULL; - } - } - self->Destroy (); - return 0; - } - if (pr_storm() < 25) - { // Fudge rain frequency - return 0; - } - double xo = ((pr_storm() & 127) - 64); - double yo = ((pr_storm() & 127) - 64); - DVector3 pos = self->Vec2OffsetZ(xo, yo, ONCEILINGZ); - mo = Spawn (pos, ALLOW_REPLACE); - // We used bouncecount to store the 3D floor index in A_HideInCeiling - if (!mo) return 0; - if (mo->Sector->PortalGroup != self->Sector->PortalGroup) - { - // spawning this through a portal will never work right so abort right away. - mo->Destroy(); - return 0; - } - if (self->bouncecount >= 0 && (unsigned)self->bouncecount < self->Sector->e->XFloor.ffloors.Size()) - pos.Z = self->Sector->e->XFloor.ffloors[self->bouncecount]->bottom.plane->ZatPoint(mo); - else - pos.Z = self->Sector->ceilingplane.ZatPoint(mo); - int moceiling = P_Find3DFloor(NULL, pos, false, false, pos.Z); - if (moceiling >= 0) mo->SetZ(pos.Z - mo->Height); - mo->Translation = multiplayer ? TRANSLATION(TRANSLATION_RainPillar,self->special2) : 0; - mo->target = self->target; - mo->Vel.X = MinVel; // Force collision detection - mo->Vel.Z = -mo->Speed; - mo->special2 = self->special2; // Transfer player number - P_CheckMissileSpawn (mo, self->radius); - if (self->special1 != -1 && !S_IsActorPlayingSomething (self, CHAN_BODY, -1)) - { - S_Sound (self, CHAN_BODY|CHAN_LOOP, self->special1, 1, ATTN_NORM); - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_RainImpact -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_RainImpact) -{ - PARAM_SELF_PROLOGUE(AActor); - if (self->Z() > self->floorz) - { - self->SetState (self->FindState("NotFloor")); - } - else if (pr_impact() < 40) - { - P_HitFloor (self); - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_HideInCeiling -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_HideInCeiling) -{ - PARAM_SELF_PROLOGUE(AActor); - - // We use bouncecount to store the 3D floor index - double foo; - for (int i = self->Sector->e->XFloor.ffloors.Size() - 1; i >= 0; i--) - { - F3DFloor * rover = self->Sector->e->XFloor.ffloors[i]; - if (!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue; - - if ((foo = rover->bottom.plane->ZatPoint(self)) >= self->Top()) - { - self->SetZ(foo + 4, false); - self->bouncecount = i; - return 0; - } - } - self->bouncecount = -1; - self->SetZ(self->ceilingz + 4, false); - return 0; -} - // --- Phoenix Rod ---------------------------------------------------------- class APhoenixRod : public AWeapon diff --git a/src/namedef.h b/src/namedef.h index b7365b2b2..779c2e132 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -764,3 +764,22 @@ xx(a) xx(r) xx(g) xx(b) + +// Special translation names +xx(RainPillar1) +xx(RainPillar2) +xx(RainPillar3) +xx(RainPillar4) +xx(RainPillar5) +xx(RainPillar6) +xx(RainPillar7) +xx(RainPillar8) + +xx(Player1) +xx(Player2) +xx(Player3) +xx(Player4) +xx(Player5) +xx(Player6) +xx(Player7) +xx(Player8) diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 24c98f86c..95bcb3e25 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -6802,7 +6802,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SetVisibleRotation) DEFINE_ACTION_FUNCTION(AActor, A_SetTranslation) { PARAM_SELF_PROLOGUE(AActor); - PARAM_STRING(trname); + PARAM_NAME(trname); self->SetTranslation(trname); return 0; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index cde2eb0b4..f956d8911 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1089,6 +1089,14 @@ AInventory *AActor::GiveInventoryType (PClassActor *type) return item; } +DEFINE_ACTION_FUNCTION(AActor, GiveInventoryType) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_CLASS(type, AInventory); + ACTION_RETURN_OBJECT(self->GiveInventoryType(type)); +} + + //============================================================================ // // AActor :: GiveAmmo @@ -7098,9 +7106,10 @@ int AActor::ApplyDamageFactor(FName damagetype, int damage) const } -void AActor::SetTranslation(const char *trname) +void AActor::SetTranslation(FName trname) { - if (*trname == 0) + // There is no constant for the empty name... + if (trname.GetChars()[0] == 0) { // an empty string resets to the default Translation = GetDefault()->Translation; @@ -7341,6 +7350,12 @@ DEFINE_ACTION_FUNCTION(AActor, RestoreDamage) return 0; } +DEFINE_ACTION_FUNCTION(AActor, PlayerNumber) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_INT(self->player ? int(self->player - players) : 0); +} + //---------------------------------------------------------------------------- // // DropItem handling diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index 5ed4cd144..e93d718cd 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -960,7 +960,7 @@ double sector_t::NextHighestCeilingAt(double x, double y, double bottomz, double } } if ((flags & FFCF_NOPORTALS) || sec->PortalBlocksMovement(ceiling) || planeheight >= sec->GetPortalPlaneZ(ceiling)) - { // Use sector's floor + { // Use sector's ceiling if (resultffloor) *resultffloor = NULL; if (resultsec) *resultsec = sec; return realceil; @@ -976,6 +976,34 @@ double sector_t::NextHighestCeilingAt(double x, double y, double bottomz, double } } +DEFINE_ACTION_FUNCTION(_Sector, NextHighestCeilingAt) +{ + PARAM_SELF_STRUCT_PROLOGUE(sector_t); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(bottomz); + PARAM_FLOAT(topz); + PARAM_INT_DEF(flags); + sector_t *resultsec; + F3DFloor *resultff; + double resultheight = self->NextHighestCeilingAt(x, y, bottomz, topz, flags, &resultsec, &resultff); + + if (numret > 2) + { + ret[2].SetPointer(resultff, ATAG_GENERIC); + numret = 3; + } + if (numret > 1) + { + ret[1].SetPointer(resultsec, ATAG_GENERIC); + } + if (numret > 0) + { + ret[0].SetFloat(resultheight); + } + return numret; +} + double sector_t::NextLowestFloorAt(double x, double y, double z, int flags, double steph, sector_t **resultsec, F3DFloor **resultffloor) { sector_t *sec = this; diff --git a/src/r_data/r_translate.cpp b/src/r_data/r_translate.cpp index 983baea58..3689d1c0f 100644 --- a/src/r_data/r_translate.cpp +++ b/src/r_data/r_translate.cpp @@ -1196,20 +1196,37 @@ void R_GetPlayerTranslation (int color, const FPlayerColorSet *colorset, FPlayer //---------------------------------------------------------------------------- static TMap customTranslationMap; -int R_FindCustomTranslation(const char *name) +int R_FindCustomTranslation(FName name) { - if (name == nullptr) - { - return -1; - } - // Ice is a special case which will remain in its original slot. - if (!stricmp(name, "Ice")) + switch (name) { + case NAME_Ice: + // Ice is a special case which will remain in its original slot. return TRANSLATION(TRANSLATION_Standard, 7); - } - else if (!stricmp(name, "None")) - { + + case NAME_None: return 0; + + case NAME_RainPillar1: + case NAME_RainPillar2: + case NAME_RainPillar3: + case NAME_RainPillar4: + case NAME_RainPillar5: + case NAME_RainPillar6: + case NAME_RainPillar7: + case NAME_RainPillar8: + return TRANSLATION(TRANSLATION_RainPillar, name.GetIndex() - NAME_RainPillar1); + + case NAME_Player1: + case NAME_Player2: + case NAME_Player3: + case NAME_Player4: + case NAME_Player5: + case NAME_Player6: + case NAME_Player7: + case NAME_Player8: + return TRANSLATION(TRANSLATION_Players, name.GetIndex() - NAME_Player1); + } int *t = customTranslationMap.CheckKey(FName(name, true)); return (t != nullptr)? *t : -1; diff --git a/src/r_data/r_translate.h b/src/r_data/r_translate.h index 4ca2f203f..1680f4df0 100644 --- a/src/r_data/r_translate.h +++ b/src/r_data/r_translate.h @@ -110,7 +110,7 @@ extern TArray BloodTranslationColors; int CreateBloodTranslation(PalEntry color); -int R_FindCustomTranslation(const char *name); +int R_FindCustomTranslation(FName name); void R_ParseTrnslate(); diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index a34e12f7d..908850e3e 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -7609,7 +7609,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) { bool writable; ArgList[i] = ArgList[i]->Resolve(ctx); // nust be resolved before the address is requested. - if (ArgList[i]->ValueType != TypeNullPtr) + if (ArgList[i] != nullptr && ArgList[i]->ValueType != TypeNullPtr) { ArgList[i]->RequestAddress(ctx, &writable); ArgList[i]->ValueType = NewPointer(ArgList[i]->ValueType); diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 3f7f27e43..1b93e22a5 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -700,6 +700,10 @@ void InitThingdef() PStruct *sstruct = NewNativeStruct("Sector", nullptr); auto sptr = NewPointer(sstruct); sstruct->AddNativeField("soundtarget", TypeActor, myoffsetof(sector_t, SoundTarget)); + + // expose the glibal Multiplayer variable. + PField *multif = new PField("multiplayer", TypeBool, VARF_Native | VARF_ReadOnly | VARF_Static, (intptr_t)&multiplayer); + GlobalSymbols.AddSymbol(multif); // set up a variable for the global level data structure PStruct *lstruct = NewNativeStruct("LevelLocals", nullptr); @@ -708,8 +712,9 @@ void InitThingdef() // set up a variable for the DEH data PStruct *dstruct = NewNativeStruct("DehInfo", nullptr); - PField *dehi = new PField("deh", dstruct, VARF_Native | VARF_Static, (intptr_t)&deh); - GlobalSymbols.AddSymbol(dehi); + PField *dehf = new PField("deh", dstruct, VARF_Native | VARF_Static, (intptr_t)&deh); + + GlobalSymbols.AddSymbol(dehf); // set up a variable for the global players array. PStruct *pstruct = NewNativeStruct("PlayerInfo", nullptr); diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 3507e45a8..7144c64e5 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -102,6 +102,7 @@ zscript/heretic/weaponcrossbow.txt zscript/heretic/weapongauntlets.txt zscript/heretic/weaponmace.txt zscript/heretic/weaponblaster.txt +zscript/heretic/weaponskullrod.txt zscript/hexen/baseweapons.txt zscript/hexen/korax.txt diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 3eb855007..1b13d05ff 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -5,6 +5,7 @@ class Actor : Thinker native const ONCEILINGZ = 2147483647.0; const FLOATRANDZ = ONCEILINGZ-1; const TELEFRAG_DAMAGE = 1000000; + const MinVel = 1./65536; // flags are not defined here, the native fields for those get synthesized from the internal tables. @@ -263,6 +264,7 @@ class Actor : Thinker native virtual native int DoSpecialDamage (Actor target, int damage, Name damagetype); virtual native bool UseInventory(Inventory item); + native void AdjustPlayerAngle(FTranslatedLineTarget t); native static readonly GetDefaultByType(class cls); native static double GetDefaultSpeed(class type); @@ -273,6 +275,7 @@ class Actor : Thinker native native bool GiveBody (int num, int max=0); native bool HitFloor(); native bool isTeammate(Actor other); + native int PlayerNumber(); native void RestoreDamage(); native int SpawnHealth(); @@ -342,6 +345,7 @@ class Actor : Thinker native // DECORATE compatible functions native bool CheckClass(class checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false); native Inventory FindInventory(class itemtype, bool subclass = false); + native Inventory GiveInventoryType(class itemtype); native int CountInv(class itemtype, int ptr_select = AAPTR_DEFAULT); native double GetDistance(bool checkz, int ptr = AAPTR_TARGET); native double GetAngle(int flags, int ptr = AAPTR_DEFAULT); @@ -720,7 +724,7 @@ class Actor : Thinker native native int A_ClearOverlays(int sstart = 0, int sstop = 0, bool safety = true); native bool A_CopySpriteFrame(int from, int to, int flags = 0); native bool A_SetVisibleRotation(double anglestart = 0, double angleend = 0, double pitchstart = 0, double pitchend = 0, int flags = 0, int ptr = AAPTR_DEFAULT); - native void A_SetTranslation(string transname); + native void A_SetTranslation(name transname); native void A_RearrangePointers(int newtarget, int newmaster = AAPTR_DEFAULT, int newtracer = AAPTR_DEFAULT, int flags=0); native void A_TransferPointer(int ptr_source, int ptr_recepient, int sourcefield, int recepientfield=AAPTR_DEFAULT, int flags=0); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 160c1c514..13aa480a9 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -122,6 +122,12 @@ struct State native native bool bDehacked; } -struct Sector native +struct F3DFloor native { } + +struct Sector native +{ + native double, Sector, F3DFloor NextHighestCeilingAt(double x, double y, double bottomz, double topz, int flags = 0); +} + diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index 68b81dc2b..70f8abed0 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -953,4 +953,32 @@ enum EWeaponPos { WEAPONBOTTOM = 128, WEAPONTOP = 32 -} \ No newline at end of file +} + +enum ETranslationTable +{ + TRANSLATION_Invalid, + TRANSLATION_Players, + TRANSLATION_PlayersExtra, + TRANSLATION_Standard, + TRANSLATION_LevelScripted, + TRANSLATION_Decals, + TRANSLATION_PlayerCorpses, + TRANSLATION_Decorate, + TRANSLATION_Blood, + TRANSLATION_RainPillar, + TRANSLATION_Custom, +}; + +enum EFindFloorCeiling +{ + FFCF_ONLYSPAWNPOS = 1, + FFCF_SAMESECTOR = 2, + FFCF_ONLY3DFLOORS = 4, // includes 3D midtexes + FFCF_3DRESTRICT = 8, // ignore 3D midtexes and floors whose floorz are above thing's z + FFCF_NOPORTALS = 16, // ignore portals (considers them impassable.) + FFCF_NOFLOOR = 32, + FFCF_NOCEILING = 64, + FFCF_RESTRICTEDPORTAL = 128, // current values in the iterator's return are through a restricted portal type (i.e. some features are blocked.) + FFCF_NODROPOFF = 256, // Caller does not need a dropoff (saves some time when checking portals) +}; diff --git a/wadsrc/static/zscript/heretic/hereticweaps.txt b/wadsrc/static/zscript/heretic/hereticweaps.txt index c3c641b4e..1b84d13fe 100644 --- a/wadsrc/static/zscript/heretic/hereticweaps.txt +++ b/wadsrc/static/zscript/heretic/hereticweaps.txt @@ -8,206 +8,6 @@ class HereticWeapon : Weapon } -// Skull (Horn) Rod --------------------------------------------------------- - -class SkullRod : HereticWeapon -{ - Default - { - Weapon.SelectionOrder 200; - Weapon.AmmoUse1 1; - Weapon.AmmoGive1 50; - Weapon.YAdjust 15; - Weapon.AmmoType1 "SkullRodAmmo"; - Weapon.SisterWeapon "SkullRodPowered"; - Inventory.PickupMessage "$TXT_WPNSKULLROD"; - Tag "$TAG_SKULLROD"; - } - - action native void A_FireSkullRodPL1(); - - States - { - Spawn: - WSKL A -1; - Stop; - Ready: - HROD A 1 A_WeaponReady; - Loop; - Deselect: - HROD A 1 A_Lower; - Loop; - Select: - HROD A 1 A_Raise; - Loop; - Fire: - HROD AB 4 A_FireSkullRodPL1; - HROD B 0 A_ReFire; - Goto Ready; - } -} - -class SkullRodPowered : SkullRod -{ - Default - { - +WEAPON.POWERED_UP - Weapon.AmmoUse1 5; - Weapon.AmmoGive1 0; - Weapon.SisterWeapon "SkullRod"; - Tag "$TAG_SKULLRODP"; - } - - action native void A_FireSkullRodPL2(); - - States - { - Fire: - HROD C 2; - HROD D 3; - HROD E 2; - HROD F 3; - HROD G 4 A_FireSkullRodPL2; - HROD F 2; - HROD E 3; - HROD D 2; - HROD C 2 A_ReFire; - Goto Ready; - } -} - -// Horn Rod FX 1 ------------------------------------------------------------ - -class HornRodFX1 : Actor -{ - Default - { - Radius 12; - Height 8; - Speed 22; - Damage 3; - Projectile; - +WINDTHRUST - -NOBLOCKMAP - RenderStyle "Add"; - SeeSound "weapons/hornrodshoot"; - DeathSound "weapons/hornrodhit"; - Obituary "$OB_MPSKULLROD"; - } - - States - { - Spawn: - FX00 AB 6 BRIGHT; - Loop; - Death: - FX00 HI 5 BRIGHT; - FX00 JK 4 BRIGHT; - FX00 LM 3 BRIGHT; - Stop; - } -} - - -// Horn Rod FX 2 ------------------------------------------------------------ - -class HornRodFX2 : Actor -{ - Default - { - Radius 12; - Height 8; - Speed 22; - Damage 10; - Health 140; - Projectile; - RenderStyle "Add"; - SeeSound "weapons/hornrodpowshoot"; - DeathSound "weapons/hornrodpowhit"; - Obituary "$OB_MPPSKULLROD"; - } - - native void A_AddPlayerRain(); - native void A_HideInCeiling(); - native void A_SkullRodStorm(); - - States - { - Spawn: - FX00 C 3 BRIGHT; - FX00 D 3 BRIGHT A_SeekerMissile(10, 30); - FX00 E 3 BRIGHT; - FX00 F 3 BRIGHT A_SeekerMissile(10, 30); - Loop; - Death: - FX00 H 5 BRIGHT A_AddPlayerRain; - FX00 I 5 BRIGHT; - FX00 J 4 BRIGHT; - FX00 KLM 3 BRIGHT; - FX00 G 1 A_HideInCeiling; - FX00 G 1 A_SkullRodStorm; - Wait; - } - - override int DoSpecialDamage (Actor target, int damage, Name damagetype) - { - Sorcerer2 s2 = Sorcerer2(target); - if (s2 != null && random[HornRodFX2]() < 96) - { // D'Sparil teleports away - s2.DSparilTeleport (); - return -1; - } - return damage; - } - -} - -// Rain pillar 1 ------------------------------------------------------------ - -class RainPillar : Actor native -{ - Default - { - Radius 5; - Height 12; - Speed 12; - Damage 5; - Mass 5; - Projectile; - -ACTIVATEPCROSS - -ACTIVATEIMPACT - RenderStyle "Add"; - Obituary "$OB_MPPSKULLROD"; - } - - native void A_RainImpact(); - - States - { - Spawn: - FX22 A -1 BRIGHT; - Stop; - Death: - FX22 B 4 BRIGHT A_RainImpact; - FX22 CDEF 4 BRIGHT; - Stop; - NotFloor: - FX22 GHI 4 BRIGHT; - Stop; - } -} - -// Rain tracker "inventory" item -------------------------------------------- - -class RainTracker : Inventory native -{ - Default - { - +INVENTORY.UNDROPPABLE - } -} - - // Phoenix Rod -------------------------------------------------------------- class PhoenixRod : Weapon native diff --git a/wadsrc/static/zscript/heretic/weaponskullrod.txt b/wadsrc/static/zscript/heretic/weaponskullrod.txt new file mode 100644 index 000000000..a8d77e1d8 --- /dev/null +++ b/wadsrc/static/zscript/heretic/weaponskullrod.txt @@ -0,0 +1,425 @@ +// Skull (Horn) Rod --------------------------------------------------------- + +class SkullRod : HereticWeapon +{ + Default + { + Weapon.SelectionOrder 200; + Weapon.AmmoUse1 1; + Weapon.AmmoGive1 50; + Weapon.YAdjust 15; + Weapon.AmmoType1 "SkullRodAmmo"; + Weapon.SisterWeapon "SkullRodPowered"; + Inventory.PickupMessage "$TXT_WPNSKULLROD"; + Tag "$TAG_SKULLROD"; + } + + States + { + Spawn: + WSKL A -1; + Stop; + Ready: + HROD A 1 A_WeaponReady; + Loop; + Deselect: + HROD A 1 A_Lower; + Loop; + Select: + HROD A 1 A_Raise; + Loop; + Fire: + HROD AB 4 A_FireSkullRodPL1; + HROD B 0 A_ReFire; + Goto Ready; + } + + //---------------------------------------------------------------------------- + // + // PROC A_FireSkullRodPL1 + // + //---------------------------------------------------------------------------- + + action void A_FireSkullRodPL1() + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + Actor mo = SpawnPlayerMissile ("HornRodFX1"); + // Randomize the first frame + if (mo && random[FireSkullRod]() > 128) + { + mo.SetState (mo.CurState.NextState); + } + } + + +} + +class SkullRodPowered : SkullRod +{ + Default + { + +WEAPON.POWERED_UP + Weapon.AmmoUse1 5; + Weapon.AmmoGive1 0; + Weapon.SisterWeapon "SkullRod"; + Tag "$TAG_SKULLRODP"; + } + + States + { + Fire: + HROD C 2; + HROD D 3; + HROD E 2; + HROD F 3; + HROD G 4 A_FireSkullRodPL2; + HROD F 2; + HROD E 3; + HROD D 2; + HROD C 2 A_ReFire; + Goto Ready; + } + + //---------------------------------------------------------------------------- + // + // PROC A_FireSkullRodPL2 + // + // The special2 field holds the player number that shot the rain missile. + // The special1 field holds the id of the rain sound. + // + //---------------------------------------------------------------------------- + + action void A_FireSkullRodPL2() + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + // Use MissileActor instead of the first return value from P_SpawnPlayerMissile + // because we need to give info to it, even if it exploded immediately. + Actor mo, MissileActor; + [mo, MissileActor] = SpawnPlayerMissile ("HornRodFX2", angle, pLineTarget: t); + if (MissileActor != null) + { + if (t.linetarget && !t.unlinked) + { + MissileActor.tracer = t.linetarget; + } + MissileActor.A_PlaySound ("weapons/hornrodpowshoot", CHAN_WEAPON); + } + } + + +} + +// Horn Rod FX 1 ------------------------------------------------------------ + +class HornRodFX1 : Actor +{ + Default + { + Radius 12; + Height 8; + Speed 22; + Damage 3; + Projectile; + +WINDTHRUST + -NOBLOCKMAP + RenderStyle "Add"; + SeeSound "weapons/hornrodshoot"; + DeathSound "weapons/hornrodhit"; + Obituary "$OB_MPSKULLROD"; + } + + States + { + Spawn: + FX00 AB 6 BRIGHT; + Loop; + Death: + FX00 HI 5 BRIGHT; + FX00 JK 4 BRIGHT; + FX00 LM 3 BRIGHT; + Stop; + } +} + + +// Horn Rod FX 2 ------------------------------------------------------------ + +class HornRodFX2 : Actor +{ + Default + { + Radius 12; + Height 8; + Speed 22; + Damage 10; + Health 140; + Projectile; + RenderStyle "Add"; + SeeSound "weapons/hornrodpowshoot"; + DeathSound "weapons/hornrodpowhit"; + Obituary "$OB_MPPSKULLROD"; + } + + States + { + Spawn: + FX00 C 3 BRIGHT; + FX00 D 3 BRIGHT A_SeekerMissile(10, 30); + FX00 E 3 BRIGHT; + FX00 F 3 BRIGHT A_SeekerMissile(10, 30); + Loop; + Death: + FX00 H 5 BRIGHT A_AddPlayerRain; + FX00 I 5 BRIGHT; + FX00 J 4 BRIGHT; + FX00 KLM 3 BRIGHT; + FX00 G 1 A_HideInCeiling; + FX00 G 1 A_SkullRodStorm; + Wait; + } + + override int DoSpecialDamage (Actor target, int damage, Name damagetype) + { + Sorcerer2 s2 = Sorcerer2(target); + if (s2 != null && random[HornRodFX2]() < 96) + { // D'Sparil teleports away + s2.DSparilTeleport (); + return -1; + } + return damage; + } + + //---------------------------------------------------------------------------- + // + // PROC A_AddPlayerRain + // + //---------------------------------------------------------------------------- + + void A_AddPlayerRain() + { + RainTracker tracker; + + if (target == null || target.health <= 0) + { // Shooter is dead or nonexistant + return; + } + + tracker = RainTracker(target.FindInventory("RainTracker")); + + // They player is only allowed two rainstorms at a time. Shooting more + // than that will cause the oldest one to terminate. + if (tracker != null) + { + if (tracker.Rain1 && tracker.Rain2) + { // Terminate an active rain + if (tracker.Rain1.health < tracker.Rain2.health) + { + if (tracker.Rain1.health > 16) + { + tracker.Rain1.health = 16; + } + tracker.Rain1 = null; + } + else + { + if (tracker.Rain2.health > 16) + { + tracker.Rain2.health = 16; + } + tracker.Rain2 = null; + } + } + } + else + { + tracker = RainTracker(target.GiveInventoryType("RainTracker")); + } + // Add rain mobj to list + if (tracker.Rain1) + { + tracker.Rain2 = self; + } + else + { + tracker.Rain1 = self; + } + ActiveSound = "misc/rain"; + } + + //---------------------------------------------------------------------------- + // + // PROC A_HideInCeiling + // + //---------------------------------------------------------------------------- + + void A_HideInCeiling() + { + // This no longer hides in the ceiling. It just makes the actor invisible and keeps it in place. + // We need its actual position to determine the correct ceiling height in A_SkullRodStorm. + bInvisible = true; + bSolid = false; + bMissile = false; + Vel = (0,0,0); + } + + //---------------------------------------------------------------------------- + // + // PROC A_SkullRodStorm + // + //---------------------------------------------------------------------------- + + void A_SkullRodStorm() + { + static const Name translations[] = + { + "RainPillar1", "RainPillar2", "RainPillar3", "RainPillar4", + "RainPillar5", "RainPillar6", "RainPillar7", "RainPillar8" + }; + + if (health-- == 0) + { + A_StopSound (CHAN_BODY); + if (target == null) + { // Player left the game + Destroy (); + return; + } + RainTracker tracker = RainTracker(target.FindInventory("RainTracker")); + if (tracker != null) + { + if (tracker.Rain1 == self) + { + tracker.Rain1 = null; + } + else if (tracker.Rain2 == self) + { + tracker.Rain2 = null; + } + } + Destroy (); + return; + } + if (Random[SkullRodStorm]() < 25) + { // Fudge rain frequency + return; + } + double xo = ((Random[SkullRodStorm]() & 127) - 64); + double yo = ((Random[SkullRodStorm]() & 127) - 64); + Vector3 spawnpos = Vec2OffsetZ(xo, yo, pos.z); + Actor mo = Spawn("RainPillar", spawnpos, ALLOW_REPLACE); + if (!mo) return; + + // Find the ceiling above the spawn location. This may come from 3D floors but will not reach through portals. + // (should probably be fixed for portals, too.) + double newz = mo.CurSector.NextHighestCeilingAt(mo.pos.x, mo.pos.y, mo.pos.z, mo.pos.z, FFCF_NOPORTALS) - mo.height; + mo.SetZ(newz); + + if (multiplayer && target.player) + { + mo.A_SetTranslation(translations[target.PlayerNumber()]); + } + mo.target = target; + mo.Vel.X = MinVel; // Force collision detection + mo.Vel.Z = -mo.Speed; + mo.CheckMissileSpawn (radius); + if (ActiveSound > 0) A_PlaySound(ActiveSound, CHAN_BODY, 1, true); + } + + +} + +// Rain pillar 1 ------------------------------------------------------------ + +class RainPillar : Actor +{ + Default + { + Radius 5; + Height 12; + Speed 12; + Damage 5; + Mass 5; + Projectile; + -ACTIVATEPCROSS + -ACTIVATEIMPACT + RenderStyle "Add"; + Obituary "$OB_MPPSKULLROD"; + } + + States + { + Spawn: + FX22 A -1 BRIGHT; + Stop; + Death: + FX22 B 4 BRIGHT A_RainImpact; + FX22 CDEF 4 BRIGHT; + Stop; + NotFloor: + FX22 GHI 4 BRIGHT; + Stop; + } + + //---------------------------------------------------------------------------- + // + // PROC A_RainImpact + // + //---------------------------------------------------------------------------- + + void A_RainImpact() + { + if (pos.z > floorz) + { + SetStateLabel("NotFloor"); + } + else if (random[RainImpact]() < 40) + { + HitFloor (); + } + } + + // Rain pillar 1 ------------------------------------------------------------ + + int DoSpecialDamage (Actor target, int damage, Name damagetype) + { + if (target.bBoss) + { // Decrease damage for bosses + damage = random[RainDamage](1, 8); + } + return damage; + } +} + +// Rain tracker "inventory" item -------------------------------------------- + +class RainTracker : Inventory +{ + Actor Rain1, Rain2; + + Default + { + +INVENTORY.UNDROPPABLE + } +} From 53ff7f0c73ea46193d029c58897ed3a1a8191999 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 25 Nov 2016 16:35:07 +0100 Subject: [PATCH 110/185] - fixed: Do not allow empty function arguments pass. For unknown reasons the grammar accepts them as valid, so this needs to be checked when resolving them. --- src/scripting/codegeneration/codegen.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 908850e3e..ab0bb96e1 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -6820,6 +6820,16 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) ABORT(ctx.Class); bool error = false; + for (auto a : ArgList) + { + if (a == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Empty function argument."); + delete this; + return nullptr; + } + } + PFunction *afd = FindClassMemberFunction(ctx.Class, ctx.Class, MethodName, ScriptPosition, &error); if (afd != nullptr) @@ -7071,6 +7081,16 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) PClass *ccls = nullptr; + for (auto a : ArgList) + { + if (a == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Empty function argument."); + delete this; + return nullptr; + } + } + if (Self->ExprType == EFX_Identifier) { ccls = PClass::FindClass(static_cast(Self)->Identifier); From 4f370ba18106340af31ef29df076dbcd78336f40 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 25 Nov 2016 18:13:08 +0100 Subject: [PATCH 111/185] - scriptified the Phoenix Rod, completing the Heretic weapons. --- src/CMakeLists.txt | 1 - src/g_heretic/a_hereticmisc.cpp | 1 - src/g_heretic/a_hereticweaps.cpp | 285 -------------- src/g_shared/a_artifacts.cpp | 2 +- src/g_shared/a_pickups.h | 1 + src/g_shared/a_weapons.cpp | 21 ++ wadsrc/static/zscript.txt | 2 +- .../static/zscript/heretic/hereticweaps.txt | 184 ---------- .../static/zscript/heretic/weaponphoenix.txt | 347 ++++++++++++++++++ wadsrc/static/zscript/shared/inventory.txt | 1 + 10 files changed, 372 insertions(+), 473 deletions(-) delete mode 100644 src/g_heretic/a_hereticweaps.cpp delete mode 100644 wadsrc/static/zscript/heretic/hereticweaps.txt create mode 100644 wadsrc/static/zscript/heretic/weaponphoenix.txt diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d4edae81e..434d0c520 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -858,7 +858,6 @@ set( NOT_COMPILED_SOURCE_FILES sc_man_scanner.h sc_man_scanner.re g_heretic/a_hereticartifacts.cpp - g_heretic/a_hereticweaps.cpp g_hexen/a_blastradius.cpp g_hexen/a_boostarmor.cpp g_hexen/a_clericflame.cpp diff --git a/src/g_heretic/a_hereticmisc.cpp b/src/g_heretic/a_hereticmisc.cpp index 5929c1d86..af9d10ba5 100644 --- a/src/g_heretic/a_hereticmisc.cpp +++ b/src/g_heretic/a_hereticmisc.cpp @@ -20,4 +20,3 @@ // Include all the other Heretic stuff here to reduce compile time #include "a_hereticartifacts.cpp" -#include "a_hereticweaps.cpp" diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp deleted file mode 100644 index 7ec036413..000000000 --- a/src/g_heretic/a_hereticweaps.cpp +++ /dev/null @@ -1,285 +0,0 @@ -/* -#include "templates.h" -#include "actor.h" -#include "info.h" -#include "s_sound.h" -#include "m_random.h" -#include "a_pickups.h" -#include "d_player.h" -#include "p_pspr.h" -#include "p_local.h" -#include "gstrings.h" -#include "gi.h" -#include "r_data/r_translate.h" -#include "vm.h" -#include "doomstat.h" -*/ - -static FRandom pr_boltspark ("BoltSpark"); -static FRandom pr_macerespawn ("MaceRespawn"); -static FRandom pr_maceatk ("FireMacePL1"); -static FRandom pr_bfx1 ("BlasterFX1"); -static FRandom pr_ripd ("RipperD"); -static FRandom pr_fb1 ("FireBlasterPL1"); -static FRandom pr_bfx1t ("BlasterFX1Tick"); -static FRandom pr_rp ("RainPillar"); -static FRandom pr_fsr1 ("FireSkullRodPL1"); -static FRandom pr_storm ("SkullRodStorm"); -static FRandom pr_impact ("RainImpact"); -static FRandom pr_pfx1 ("PhoenixFX1"); -static FRandom pr_pfx2 ("PhoenixFX2"); -static FRandom pr_fp2 ("FirePhoenixPL2"); - -#define FLAME_THROWER_TICS (10*TICRATE) - -void P_DSparilTeleport (AActor *actor); - -#define USE_BLSR_AMMO_1 1 -#define USE_BLSR_AMMO_2 5 -#define USE_SKRD_AMMO_1 1 -#define USE_SKRD_AMMO_2 5 -#define USE_PHRD_AMMO_1 1 -#define USE_PHRD_AMMO_2 1 -#define USE_MACE_AMMO_1 1 -#define USE_MACE_AMMO_2 5 - -extern bool P_AutoUseChaosDevice (player_t *player); - - -// --- Phoenix Rod ---------------------------------------------------------- - -class APhoenixRod : public AWeapon -{ - DECLARE_CLASS (APhoenixRod, AWeapon) -public: - - void Serialize(FSerializer &arc) - { - Super::Serialize (arc); - arc("flamecount", FlameCount); - } - int FlameCount; // for flamethrower duration -}; - -class APhoenixRodPowered : public APhoenixRod -{ - DECLARE_CLASS (APhoenixRodPowered, APhoenixRod) -public: - void EndPowerup (); -}; - -IMPLEMENT_CLASS(APhoenixRod, false, false) -IMPLEMENT_CLASS(APhoenixRodPowered, false, false) - -void APhoenixRodPowered::EndPowerup () -{ - DepleteAmmo (bAltFire); - Owner->player->refire = 0; - S_StopSound (Owner, CHAN_WEAPON); - Owner->player->ReadyWeapon = SisterWeapon; - P_SetPsprite(Owner->player, PSP_WEAPON, SisterWeapon->GetReadyState()); -} - -// Phoenix FX 2 ------------------------------------------------------------- - -class APhoenixFX2 : public AActor -{ - DECLARE_CLASS (APhoenixFX2, AActor) -public: - int DoSpecialDamage (AActor *target, int damage, FName damagetype); -}; - -IMPLEMENT_CLASS(APhoenixFX2, false, false) - -int APhoenixFX2::DoSpecialDamage (AActor *target, int damage, FName damagetype) -{ - if (target->player && pr_pfx2 () < 128) - { // Freeze player for a bit - target->reactiontime += 4; - } - return damage; -} - -//---------------------------------------------------------------------------- -// -// PROC A_FirePhoenixPL1 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_FirePhoenixPL1) -{ - PARAM_ACTION_PROLOGUE(AActor); - - player_t *player; - - if (NULL == (player = self->player)) - { - return 0; - } - - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - P_SpawnPlayerMissile (self, PClass::FindActor("PhoenixFX1")); - self->Thrust(self->Angles.Yaw + 180, 4); - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_PhoenixPuff -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_PhoenixPuff) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *puff; - DAngle ang; - - //[RH] Heretic never sets the target for seeking - //P_SeekerMissile (self, 5, 10); - puff = Spawn("PhoenixPuff", self->Pos(), ALLOW_REPLACE); - ang = self->Angles.Yaw + 90; - puff->Vel = DVector3(ang.ToVector(1.3), 0); - - puff = Spawn("PhoenixPuff", self->Pos(), ALLOW_REPLACE); - ang = self->Angles.Yaw - 90; - puff->Vel = DVector3(ang.ToVector(1.3), 0); - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_InitPhoenixPL2 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_InitPhoenixPL2) -{ - PARAM_ACTION_PROLOGUE(AActor); - - if (self->player != NULL) - { - APhoenixRod *flamethrower = static_cast (self->player->ReadyWeapon); - if (flamethrower != NULL) - { - flamethrower->FlameCount = FLAME_THROWER_TICS; - } - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_FirePhoenixPL2 -// -// Flame thrower effect. -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_FirePhoenixPL2) -{ - PARAM_ACTION_PROLOGUE(AActor); - - AActor *mo; - - double slope; - FSoundID soundid; - player_t *player; - APhoenixRod *flamethrower; - - if (nullptr == (player = self->player)) - { - return 0; - } - - soundid = "weapons/phoenixpowshoot"; - - flamethrower = static_cast (player->ReadyWeapon); - if (flamethrower == nullptr || --flamethrower->FlameCount == 0) - { // Out of flame - P_SetPsprite(player, PSP_WEAPON, flamethrower->FindState("Powerdown")); - player->refire = 0; - S_StopSound (self, CHAN_WEAPON); - return 0; - } - - slope = -self->Angles.Pitch.TanClamped(); - double xo = pr_fp2.Random2() / 128.; - double yo = pr_fp2.Random2() / 128.; - DVector3 pos = self->Vec3Offset(xo, yo, 26 + slope - self->Floorclip); - - slope += 0.1; - mo = Spawn("PhoenixFX2", pos, ALLOW_REPLACE); - mo->target = self; - mo->Angles.Yaw = self->Angles.Yaw; - mo->VelFromAngle(); - mo->Vel += self->Vel.XY(); - mo->Vel.Z = mo->Speed * slope; - if (!player->refire || !S_IsActorPlayingSomething (self, CHAN_WEAPON, -1)) - { - S_Sound (self, CHAN_WEAPON|CHAN_LOOP, soundid, 1, ATTN_NORM); - } - P_CheckMissileSpawn (mo, self->radius); - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_ShutdownPhoenixPL2 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_ShutdownPhoenixPL2) -{ - PARAM_ACTION_PROLOGUE(AActor); - - player_t *player; - - if (NULL == (player = self->player)) - { - return 0; - } - S_StopSound (self, CHAN_WEAPON); - AWeapon *weapon = player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_FlameEnd -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_FlameEnd) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->Vel.Z += 1.5; - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_FloatPuff -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_FloatPuff) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->Vel.Z += 1.8; - return 0; -} - diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index 73b71e2ff..854881647 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -1185,7 +1185,7 @@ void APowerWeaponLevel2::EndEffect () if (player->ReadyWeapon != NULL && player->ReadyWeapon->WeaponFlags & WIF_POWERED_UP) { - player->ReadyWeapon->EndPowerup (); + player->ReadyWeapon->CallEndPowerup (); } if (player->PendingWeapon != NULL && player->PendingWeapon != WP_NOCHANGE && player->PendingWeapon->WeaponFlags & WIF_POWERED_UP && diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index bf4af5a63..0cfd04147 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -342,6 +342,7 @@ public: virtual void PostMorphWeapon (); virtual void EndPowerup (); + void CallEndPowerup(); enum { diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index b94a4770c..02cd19fa6 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -18,6 +18,7 @@ #include "d_net.h" #include "serializer.h" #include "thingdef.h" +#include "virtual.h" #define BONUSADD 6 @@ -789,6 +790,26 @@ void AWeapon::EndPowerup () } } +DEFINE_ACTION_FUNCTION(AWeapon, EndPowerup) +{ + PARAM_SELF_PROLOGUE(AWeapon); + self->EndPowerup(); + return 0; +} + +void AWeapon::CallEndPowerup() +{ + IFVIRTUAL(AWeapon, EndPowerup) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { (DObject*)this }; + VMFrameStack stack; + stack.Call(func, params, 1, nullptr, 0, nullptr); + } + else EndPowerup(); +} + + //=========================================================================== // // AWeapon :: GetUpState diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 7144c64e5..fa0cebd96 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -85,7 +85,6 @@ zscript/heretic/hereticartifacts.txt zscript/heretic/heretickeys.txt zscript/heretic/hereticdecorations.txt zscript/heretic/hereticmisc.txt -zscript/heretic/hereticweaps.txt zscript/heretic/mummy.txt zscript/heretic/clink.txt zscript/heretic/beast.txt @@ -103,6 +102,7 @@ zscript/heretic/weapongauntlets.txt zscript/heretic/weaponmace.txt zscript/heretic/weaponblaster.txt zscript/heretic/weaponskullrod.txt +zscript/heretic/weaponphoenix.txt zscript/hexen/baseweapons.txt zscript/hexen/korax.txt diff --git a/wadsrc/static/zscript/heretic/hereticweaps.txt b/wadsrc/static/zscript/heretic/hereticweaps.txt deleted file mode 100644 index 1b84d13fe..000000000 --- a/wadsrc/static/zscript/heretic/hereticweaps.txt +++ /dev/null @@ -1,184 +0,0 @@ - -class HereticWeapon : Weapon -{ - Default - { - Weapon.Kickback 150; - } -} - - -// Phoenix Rod -------------------------------------------------------------- - -class PhoenixRod : Weapon native -{ - Default - { - +WEAPON.NOAUTOFIRE - Weapon.SelectionOrder 2600; - Weapon.Kickback 150; - Weapon.YAdjust 15; - Weapon.AmmoUse 1; - Weapon.AmmoGive 2; - Weapon.AmmoType "PhoenixRodAmmo"; - Weapon.Sisterweapon "PhoenixRodPowered"; - Inventory.PickupMessage "$TXT_WPNPHOENIXROD"; - Tag "$TAG_PHOENIXROD"; - } - - action native void A_FirePhoenixPL1(); - - States - { - Spawn: - WPHX A -1; - Stop; - Ready: - PHNX A 1 A_WeaponReady; - Loop; - Deselect: - PHNX A 1 A_Lower; - Loop; - Select: - PHNX A 1 A_Raise; - Loop; - Fire: - PHNX B 5; - PHNX C 7 A_FirePhoenixPL1; - PHNX DB 4; - PHNX B 0 A_ReFire; - Goto Ready; - } -} - -class PhoenixRodPowered : PhoenixRod native -{ - Default - { - +WEAPON.POWERED_UP - +WEAPON.MELEEWEAPON - Weapon.SisterWeapon "PhoenixRod"; - Weapon.AmmoGive 0; - Tag "$TAG_PHOENIXRODP"; - } - - action native void A_InitPhoenixPL2(); - action native void A_FirePhoenixPL2(); - action native void A_ShutdownPhoenixPL2(); - - States - { - Fire: - PHNX B 3 A_InitPhoenixPL2; - Hold: - PHNX C 1 A_FirePhoenixPL2; - PHNX B 4 A_ReFire; - Powerdown: - PHNX B 4 A_ShutdownPhoenixPL2; - Goto Ready; - } -} - -// Phoenix FX 1 ------------------------------------------------------------- - -class PhoenixFX1 : Actor -{ - Default - { - Radius 11; - Height 8; - Speed 20; - Damage 20; - DamageType "Fire"; - Projectile; - +THRUGHOST - +SPECIALFIREDAMAGE - SeeSound "weapons/phoenixshoot"; - DeathSound "weapons/phoenixhit"; - Obituary "$OB_MPPHOENIXROD"; - } - - native void A_PhoenixPuff(); - - States - { - Spawn: - FX04 A 4 BRIGHT A_PhoenixPuff; - Loop; - Death: - FX08 A 6 BRIGHT A_Explode; - FX08 BC 5 BRIGHT; - FX08 DEFGH 4 BRIGHT; - Stop; - } - - override int DoSpecialDamage (Actor target, int damage, Name damagetype) - { - Sorcerer2 s2 = Sorcerer2(target); - if (s2 != null && random[HornRodFX2]() < 96) - { // D'Sparil teleports away - s2.DSparilTeleport (); - return -1; - } - return damage; - } - -} - -// Phoenix puff ------------------------------------------------------------- - -class PhoenixPuff : Actor -{ - Default - { - +NOBLOCKMAP - +NOGRAVITY - +NOTELEPORT - +CANNOTPUSH - RenderStyle "Translucent"; - Alpha 0.4; - } - - States - { - Spawn: - FX04 BCDEF 4; - Stop; - } -} - -// Phoenix FX 2 ------------------------------------------------------------- - -class PhoenixFX2 : Actor native -{ - Default - { - Radius 6; - Height 8; - Speed 10; - Damage 2; - DamageType "Fire"; - Projectile; - RenderStyle "Add"; - Obituary "$OB_MPPPHOENIXROD"; - } - - native void A_FlameEnd(); - native void A_FloatPuff(); - - States - { - Spawn: - FX09 ABABA 2 BRIGHT; - FX09 B 2 BRIGHT A_FlameEnd; - FX09 CDEF 2 BRIGHT; - Stop; - Death: - FX09 G 3 BRIGHT; - FX09 H 3 BRIGHT A_FloatPuff; - FX09 I 4 BRIGHT; - FX09 JK 5 BRIGHT; - Stop; - } -} - diff --git a/wadsrc/static/zscript/heretic/weaponphoenix.txt b/wadsrc/static/zscript/heretic/weaponphoenix.txt new file mode 100644 index 000000000..554d52d21 --- /dev/null +++ b/wadsrc/static/zscript/heretic/weaponphoenix.txt @@ -0,0 +1,347 @@ + +class HereticWeapon : Weapon +{ + Default + { + Weapon.Kickback 150; + } +} + + +// Phoenix Rod -------------------------------------------------------------- + +class PhoenixRod : Weapon +{ + Default + { + +WEAPON.NOAUTOFIRE + Weapon.SelectionOrder 2600; + Weapon.Kickback 150; + Weapon.YAdjust 15; + Weapon.AmmoUse 1; + Weapon.AmmoGive 2; + Weapon.AmmoType "PhoenixRodAmmo"; + Weapon.Sisterweapon "PhoenixRodPowered"; + Inventory.PickupMessage "$TXT_WPNPHOENIXROD"; + Tag "$TAG_PHOENIXROD"; + } + + States + { + Spawn: + WPHX A -1; + Stop; + Ready: + PHNX A 1 A_WeaponReady; + Loop; + Deselect: + PHNX A 1 A_Lower; + Loop; + Select: + PHNX A 1 A_Raise; + Loop; + Fire: + PHNX B 5; + PHNX C 7 A_FirePhoenixPL1; + PHNX DB 4; + PHNX B 0 A_ReFire; + Goto Ready; + } + + //---------------------------------------------------------------------------- + // + // PROC A_FirePhoenixPL1 + // + //---------------------------------------------------------------------------- + + action void A_FirePhoenixPL1() + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + SpawnPlayerMissile ("PhoenixFX1"); + Thrust(4, angle + 180); + } + + +} + +class PhoenixRodPowered : PhoenixRod +{ + const FLAME_THROWER_TICS = (10*TICRATE); + + private int FlameCount; // for flamethrower duration + + Default + { + +WEAPON.POWERED_UP + +WEAPON.MELEEWEAPON + Weapon.SisterWeapon "PhoenixRod"; + Weapon.AmmoGive 0; + Tag "$TAG_PHOENIXRODP"; + } + + States + { + Fire: + PHNX B 3 A_InitPhoenixPL2; + Hold: + PHNX C 1 A_FirePhoenixPL2; + PHNX B 4 A_ReFire; + Powerdown: + PHNX B 4 A_ShutdownPhoenixPL2; + Goto Ready; + } + + + override void EndPowerup () + { + DepleteAmmo (bAltFire); + Owner.player.refire = 0; + Owner.A_StopSound (CHAN_WEAPON); + Owner.player.ReadyWeapon = SisterWeapon; + Owner.player.SetPsprite(PSP_WEAPON, SisterWeapon.GetReadyState()); + } + + //---------------------------------------------------------------------------- + // + // PROC A_InitPhoenixPL2 + // + //---------------------------------------------------------------------------- + + action void A_InitPhoenixPL2() + { + if (player != null) + { + PhoenixRodPowered flamethrower = PhoenixRodPowered(player.ReadyWeapon); + if (flamethrower != null) + { + flamethrower.FlameCount = FLAME_THROWER_TICS; + } + } + } + + //---------------------------------------------------------------------------- + // + // PROC A_FirePhoenixPL2 + // + // Flame thrower effect. + // + //---------------------------------------------------------------------------- + + action void A_FirePhoenixPL2() + { + if (player == null) + { + return; + } + + PhoenixRodPowered flamethrower = PhoenixRodPowered(player.ReadyWeapon); + + if (flamethrower == null || --flamethrower.FlameCount == 0) + { // Out of flame + player.SetPsprite(PSP_WEAPON, flamethrower.FindState("Powerdown")); + player.refire = 0; + A_StopSound (CHAN_WEAPON); + return; + } + + double slope = -clamp(tan(pitch), -5, 5); + double xo = Random2[FirePhoenixPL2]() / 128.; + double yo = Random2[FirePhoenixPL2]() / 128.; + Vector3 spawnpos = Vec3Offset(xo, yo, 26 + slope - Floorclip); + + slope += 0.1; + Actor mo = Spawn("PhoenixFX2", spawnpos, ALLOW_REPLACE); + mo.target = self; + mo.Angle = Angle; + mo.VelFromAngle(); + mo.Vel.XY += Vel.XY; + mo.Vel.Z = mo.Speed * slope; + if (!player.refire) + { + A_PlaySound("weapons/phoenixpowshoot", CHAN_WEAPON, 1, true); + } + mo.CheckMissileSpawn (radius); + } + + //---------------------------------------------------------------------------- + // + // PROC A_ShutdownPhoenixPL2 + // + //---------------------------------------------------------------------------- + + action void A_ShutdownPhoenixPL2() + { + if (player == null) + { + return; + } + A_StopSound (CHAN_WEAPON); + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + weapon.DepleteAmmo (weapon.bAltFire); + } + } + + +} + +// Phoenix FX 1 ------------------------------------------------------------- + +class PhoenixFX1 : Actor +{ + Default + { + Radius 11; + Height 8; + Speed 20; + Damage 20; + DamageType "Fire"; + Projectile; + +THRUGHOST + +SPECIALFIREDAMAGE + SeeSound "weapons/phoenixshoot"; + DeathSound "weapons/phoenixhit"; + Obituary "$OB_MPPHOENIXROD"; + } + + States + { + Spawn: + FX04 A 4 BRIGHT A_PhoenixPuff; + Loop; + Death: + FX08 A 6 BRIGHT A_Explode; + FX08 BC 5 BRIGHT; + FX08 DEFGH 4 BRIGHT; + Stop; + } + + override int DoSpecialDamage (Actor target, int damage, Name damagetype) + { + Sorcerer2 s2 = Sorcerer2(target); + if (s2 != null && random[HornRodFX2]() < 96) + { // D'Sparil teleports away + s2.DSparilTeleport (); + return -1; + } + return damage; + } + + //---------------------------------------------------------------------------- + // + // PROC A_PhoenixPuff + // + //---------------------------------------------------------------------------- + + void A_PhoenixPuff() + { + //[RH] Heretic never sets the target for seeking + //P_SeekerMissile (self, 5, 10); + Actor puff = Spawn("PhoenixPuff", Pos, ALLOW_REPLACE); + puff.Vel.XY = AngleToVector(Angle + 90, 1.3); + + puff = Spawn("PhoenixPuff", Pos, ALLOW_REPLACE); + puff.Vel.XY = AngleToVector(Angle - 90, 1.3); + } + + +} + +// Phoenix puff ------------------------------------------------------------- + +class PhoenixPuff : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + +NOTELEPORT + +CANNOTPUSH + RenderStyle "Translucent"; + Alpha 0.4; + } + + States + { + Spawn: + FX04 BCDEF 4; + Stop; + } +} + +// Phoenix FX 2 ------------------------------------------------------------- + +class PhoenixFX2 : Actor +{ + Default + { + Radius 6; + Height 8; + Speed 10; + Damage 2; + DamageType "Fire"; + Projectile; + RenderStyle "Add"; + Obituary "$OB_MPPPHOENIXROD"; + } + + States + { + Spawn: + FX09 ABABA 2 BRIGHT; + FX09 B 2 BRIGHT A_FlameEnd; + FX09 CDEF 2 BRIGHT; + Stop; + Death: + FX09 G 3 BRIGHT; + FX09 H 3 BRIGHT A_FloatPuff; + FX09 I 4 BRIGHT; + FX09 JK 5 BRIGHT; + Stop; + } + + + int DoSpecialDamage (Actor target, int damage, Name damagetype) + { + if (target.player && Random[PhoenixFX2]() < 128) + { // Freeze player for a bit + target.reactiontime += 4; + } + return damage; + } + + //---------------------------------------------------------------------------- + // + // PROC A_FlameEnd + // + //---------------------------------------------------------------------------- + + void A_FlameEnd() + { + Vel.Z += 1.5; + } + + //---------------------------------------------------------------------------- + // + // PROC A_FloatPuff + // + //---------------------------------------------------------------------------- + + void A_FloatPuff() + { + Vel.Z += 1.8; + } + + +} diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index 12e521d53..52a346ce1 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -569,6 +569,7 @@ class Weapon : StateProvider native } native bool DepleteAmmo(bool altFire, bool checkEnough = true, int ammouse = -1); + native virtual void EndPowerup(); virtual State GetReadyState () { From 0d6f37835fbeba30b24b5ffe3f19fbd7ff100867 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 25 Nov 2016 18:41:00 +0100 Subject: [PATCH 112/185] - completed Heretic scriptification with the two remaining artifacts. --- src/CMakeLists.txt | 5 -- src/dobject.h | 5 -- src/g_heretic/a_hereticartifacts.cpp | 63 ------------------- src/g_heretic/a_hereticmisc.cpp | 22 ------- src/g_shared/a_morph.cpp | 9 +++ src/g_shared/a_pickups.cpp | 27 +++++++- src/g_shared/a_pickups.h | 1 + src/p_mobj.cpp | 7 +-- .../zscript/heretic/hereticartifacts.txt | 37 ++++++++++- wadsrc/static/zscript/shared/inventory.txt | 3 + wadsrc/static/zscript/shared/player.txt | 2 + 11 files changed, 77 insertions(+), 104 deletions(-) delete mode 100644 src/g_heretic/a_hereticartifacts.cpp delete mode 100644 src/g_heretic/a_hereticmisc.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 434d0c520..215e88b52 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -824,7 +824,6 @@ endif() file( GLOB HEADER_FILES ${EXTRA_HEADER_DIRS} fragglescript/*.h - g_heretic/*.h g_hexen/*.h g_raven/*.h g_shared/*.h @@ -857,7 +856,6 @@ set( NOT_COMPILED_SOURCE_FILES ${OTHER_SYSTEM_SOURCES} sc_man_scanner.h sc_man_scanner.re - g_heretic/a_hereticartifacts.cpp g_hexen/a_blastradius.cpp g_hexen/a_boostarmor.cpp g_hexen/a_clericflame.cpp @@ -1148,7 +1146,6 @@ set (PCH_SOURCES w_wad.cpp wi_stuff.cpp zstrformat.cpp - g_heretic/a_hereticmisc.cpp g_hexen/a_hexenmisc.cpp g_raven/a_artitele.cpp g_raven/a_minotaur.cpp @@ -1303,7 +1300,6 @@ endif() target_link_libraries( zdoom ${ZDOOM_LIBS} gdtoa dumb lzma ) include_directories( . - g_heretic g_hexen g_raven g_strife @@ -1436,7 +1432,6 @@ source_group("External\\Math" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/m source_group("External\\RapidJSON" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rapidjson/.+") source_group("Externak\\SFMT" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sfmt/.+") source_group("FraggleScript" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/fragglescript/.+") -source_group("Games\\Heretic Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_heretic/.+") source_group("Games\\Hexen Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_hexen/.+") source_group("Games\\Raven Shared" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_raven/.+") source_group("Games\\Strife Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_strife/.+") diff --git a/src/dobject.h b/src/dobject.h index cb1074c0c..7d27133dc 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -467,11 +467,6 @@ public: void SerializeUserVars(FSerializer &arc); virtual void Serialize(FSerializer &arc); - void VMSuperCall() - { - ObjectFlags |= OF_SuperCall; - } - void ClearClass() { Class = NULL; diff --git a/src/g_heretic/a_hereticartifacts.cpp b/src/g_heretic/a_hereticartifacts.cpp deleted file mode 100644 index 2fb45c124..000000000 --- a/src/g_heretic/a_hereticartifacts.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* -#include "info.h" -#include "a_pickups.h" -#include "a_artifacts.h" -#include "gstrings.h" -#include "p_local.h" -#include "s_sound.h" -#include "vm.h" -*/ - -// Tome of power ------------------------------------------------------------ - -class AArtiTomeOfPower : public APowerupGiver -{ - DECLARE_CLASS (AArtiTomeOfPower, APowerupGiver) -public: - bool Use (bool pickup); -}; - -IMPLEMENT_CLASS(AArtiTomeOfPower, false, false) - -bool AArtiTomeOfPower::Use (bool pickup) -{ - if (Owner->player->morphTics && (Owner->player->MorphStyle & MORPH_UNDOBYTOMEOFPOWER)) - { // Attempt to undo chicken - if (!P_UndoPlayerMorph (Owner->player, Owner->player, MORPH_UNDOBYTOMEOFPOWER)) - { // Failed - if (!(Owner->player->MorphStyle & MORPH_FAILNOTELEFRAG)) - { - P_DamageMobj (Owner, NULL, NULL, TELEFRAG_DAMAGE, NAME_Telefrag); - } - } - else - { // Succeeded - S_Sound (Owner, CHAN_VOICE, "*evillaugh", 1, ATTN_IDLE); - } - return true; - } - else - { - return Super::Use (pickup); - } -} - -// Time bomb ---------------------------------------------------------------- - -class AArtiTimeBomb : public AInventory -{ - DECLARE_CLASS (AArtiTimeBomb, AInventory) -public: - bool Use (bool pickup); -}; - -IMPLEMENT_CLASS(AArtiTimeBomb, false, false) - -bool AArtiTimeBomb::Use (bool pickup) -{ - AActor *mo = Spawn("ActivatedTimeBomb", - Owner->Vec3Angle(24., Owner->Angles.Yaw, - Owner->Floorclip), ALLOW_REPLACE); - mo->target = Owner; - return true; -} - diff --git a/src/g_heretic/a_hereticmisc.cpp b/src/g_heretic/a_hereticmisc.cpp deleted file mode 100644 index af9d10ba5..000000000 --- a/src/g_heretic/a_hereticmisc.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "actor.h" -#include "info.h" -#include "a_pickups.h" -#include "a_action.h" -#include "m_random.h" -#include "p_local.h" -#include "s_sound.h" -#include "gstrings.h" -#include "p_enemy.h" -#include "a_specialspot.h" -#include "g_level.h" -#include "a_sharedglobal.h" -#include "templates.h" -#include "r_data/r_translate.h" -#include "doomstat.h" -#include "d_player.h" -#include "a_morph.h" -#include "p_spec.h" -#include "serializer.h" - -// Include all the other Heretic stuff here to reduce compile time -#include "a_hereticartifacts.cpp" diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 5514ae413..5ab1e3eb9 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -372,6 +372,15 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, return true; } +DEFINE_ACTION_FUNCTION(_PlayerInfo, UndoPlayerMorph) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + PARAM_POINTER(player, player_t); + PARAM_INT_DEF(unmorphflag); + PARAM_BOOL_DEF(force); + ACTION_RETURN_BOOL(P_UndoPlayerMorph(self, player, unmorphflag, force)); +} + //--------------------------------------------------------------------------- // // FUNC P_MorphMonster diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index 16a63a2ff..ee68a16db 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -20,6 +20,7 @@ #include "d_player.h" #include "p_spec.h" #include "serializer.h" +#include "virtual.h" static FRandom pr_restore ("RestorePos"); @@ -1005,6 +1006,30 @@ bool AInventory::Use (bool pickup) return false; } +DEFINE_ACTION_FUNCTION(AInventory, Use) +{ + PARAM_SELF_PROLOGUE(AInventory); + PARAM_BOOL(pickup); + ACTION_RETURN_BOOL(self->Use(pickup)); +} + +bool AInventory::CallUse(bool pickup) +{ + IFVIRTUAL(AInventory, Use) + { + VMValue params[2] = { (DObject*)this, pickup }; + VMReturn ret; + VMFrameStack stack; + int retval; + ret.IntAt(&retval); + stack.Call(func, params, 2, &ret, 1, nullptr); + return !!retval; + + } + else return Use(pickup); +} + + //=========================================================================== // // AInventory :: Hide @@ -1494,7 +1519,7 @@ bool AInventory::TryPickup (AActor *&toucher) copy->AttachToOwner (newtoucher); if (ItemFlags & IF_AUTOACTIVATE) { - if (copy->Use (true)) + if (copy->CallUse (true)) { if (--copy->Amount <= 0) { diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index 0cfd04147..f035efeea 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -204,6 +204,7 @@ public: virtual void GoAwayAndDie (); virtual bool HandlePickup (AInventory *item); virtual bool Use (bool pickup); + bool CallUse(bool pickup); virtual void Travelled (); virtual void OwnerDied (); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index f956d8911..d845846db 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -955,7 +955,7 @@ bool AActor::DoUseInventory (AInventory *item) { return false; } - if (!item->Use (false)) + if (!item->CallUse (false)) { return false; } @@ -974,7 +974,6 @@ DEFINE_ACTION_FUNCTION(AActor, UseInventory) { PARAM_SELF_PROLOGUE(AActor); PARAM_OBJECT(item, AInventory); - self->VMSuperCall(); ACTION_RETURN_BOOL(self->DoUseInventory(item)); } @@ -4149,7 +4148,6 @@ void AActor::Tick () DEFINE_ACTION_FUNCTION(AActor, Tick) { PARAM_SELF_PROLOGUE(AActor); - self->VMSuperCall(); self->Tick(); return 0; } @@ -4708,7 +4706,6 @@ DEFINE_ACTION_FUNCTION(AActor, Activate) { PARAM_SELF_PROLOGUE(AActor); PARAM_OBJECT(activator, AActor); - self->VMSuperCall(); self->Activate(activator); return 0; } @@ -4756,7 +4753,6 @@ DEFINE_ACTION_FUNCTION(AActor, Deactivate) { PARAM_SELF_PROLOGUE(AActor); PARAM_OBJECT(activator, AActor); - self->VMSuperCall(); self->Deactivate(activator); return 0; } @@ -6797,7 +6793,6 @@ DEFINE_ACTION_FUNCTION(AActor, DoSpecialDamage) PARAM_OBJECT(target, AActor); PARAM_INT(damage); PARAM_NAME(damagetype); - self->VMSuperCall(); ACTION_RETURN_INT(self->DoSpecialDamage(target, damage, damagetype)); } diff --git a/wadsrc/static/zscript/heretic/hereticartifacts.txt b/wadsrc/static/zscript/heretic/hereticartifacts.txt index 50a25008a..3ef265735 100644 --- a/wadsrc/static/zscript/heretic/hereticartifacts.txt +++ b/wadsrc/static/zscript/heretic/hereticartifacts.txt @@ -47,7 +47,7 @@ Class ArtiInvisibility : PowerupGiver // Tome of power ------------------------------------------------------------ -Class ArtiTomeOfPower : PowerupGiver native +Class ArtiTomeOfPower : PowerupGiver { Default { @@ -65,6 +65,31 @@ Class ArtiTomeOfPower : PowerupGiver native PWBK A 350; Loop; } + + bool Use (bool pickup) + { + Playerinfo p = Owner.player; + if (p && p.morphTics && (p.MorphStyle & MRF_UNDOBYTOMEOFPOWER)) + { // Attempt to undo chicken + if (!p.UndoPlayerMorph (p, MRF_UNDOBYTOMEOFPOWER)) + { // Failed + if (!(p.MorphStyle & MRF_FAILNOTELEFRAG)) + { + Owner.DamageMobj (null, null, TELEFRAG_DAMAGE, 'Telefrag'); + } + } + else + { // Succeeded + Owner.A_PlaySound ("*evillaugh", CHAN_VOICE); + } + return true; + } + else + { + return Super.Use (pickup); + } + } + } @@ -99,7 +124,7 @@ Class ActivatedTimeBomb : Actor } -Class ArtiTimeBomb : Inventory native +Class ArtiTimeBomb : Inventory { Default { @@ -120,4 +145,12 @@ Class ArtiTimeBomb : Inventory native FBMB E 350; Loop; } + + override bool Use (bool pickup) + { + Actor mo = Spawn("ActivatedTimeBomb", Owner.Vec3Angle(24., Owner.angle, - Owner.Floorclip), ALLOW_REPLACE); + mo.target = Owner; + return true; + } + } diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index 52a346ce1..c2c99453f 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -25,6 +25,9 @@ class Inventory : Actor native Inventory.PickupMessage "$TXT_DEFAULTPICKUPMSG"; } + virtual native bool Use (bool pickup); + + // These are regular functions for the item itself. private native void A_RestoreSpecialDoomThing(); private native void A_RestoreSpecialThing1(); diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index ed95354f8..e76e637fe 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -213,8 +213,10 @@ FWeaponSlots weapons; */ + native bool UndoPlayerMorph(playerinfo player, int unmorphflag = 0, bool force = false); native void SetPsprite(int id, State stat, bool pending = false); native void SetSafeFlash(Weapon weap, State flashstate, int index); native PSprite GetPSprite(int id); native PSprite FindPSprite(int id); + } From 6e1c6c4b33ac0360cb58b72a129423ba006f7293 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 25 Nov 2016 19:52:35 +0100 Subject: [PATCH 113/185] - scriptified ArtiTeleport. - shortened ArtiEgg and ArtiPork's use state to a single function. --- src/CMakeLists.txt | 1 - src/g_game.cpp | 36 +++++++++++++ src/g_raven/a_artitele.cpp | 63 ----------------------- src/p_teleport.cpp | 11 ++++ wadsrc/static/zscript/actor.txt | 3 +- wadsrc/static/zscript/base.txt | 2 + wadsrc/static/zscript/constants.txt | 11 ++++ wadsrc/static/zscript/heretic/dsparil.txt | 2 +- wadsrc/static/zscript/raven/artiegg.txt | 18 +++---- wadsrc/static/zscript/raven/artitele.txt | 34 +++++++++++- 10 files changed, 104 insertions(+), 77 deletions(-) delete mode 100644 src/g_raven/a_artitele.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 215e88b52..bca0e9371 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1147,7 +1147,6 @@ set (PCH_SOURCES wi_stuff.cpp zstrformat.cpp g_hexen/a_hexenmisc.cpp - g_raven/a_artitele.cpp g_raven/a_minotaur.cpp g_strife/a_strifestuff.cpp g_strife/strife_sbar.cpp diff --git a/src/g_game.cpp b/src/g_game.cpp index 810a29da1..9af9b4532 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1536,6 +1536,23 @@ static FPlayerStart *SelectRandomDeathmatchSpot (int playernum, unsigned int sel return &deathmatchstarts[i]; } +DEFINE_ACTION_FUNCTION(DObject, G_PickDeathmatchStart) +{ + PARAM_PROLOGUE; + unsigned int selections = deathmatchstarts.Size(); + unsigned int i = pr_dmspawn() % selections; + if (numret > 1) + { + ret[1].SetInt(deathmatchstarts[i].angle); + numret = 2; + } + if (numret > 0) + { + ret[0].SetVector(deathmatchstarts[i].pos); + } + return numret; +} + void G_DeathMatchSpawnPlayer (int playernum) { unsigned int selections; @@ -1577,6 +1594,7 @@ void G_DeathMatchSpawnPlayer (int playernum) if (mo != NULL) P_PlayerStartStomp(mo); } + // // G_PickPlayerStart // @@ -1614,6 +1632,24 @@ FPlayerStart *G_PickPlayerStart(int playernum, int flags) return &playerstarts[playernum]; } +DEFINE_ACTION_FUNCTION(DObject, G_PickPlayerStart) +{ + PARAM_PROLOGUE; + PARAM_INT(playernum); + PARAM_INT_DEF(flags); + auto ps = G_PickPlayerStart(playernum, flags); + if (numret > 1) + { + ret[1].SetInt(ps? ps->angle : 0); + numret = 2; + } + if (numret > 0) + { + ret[0].SetVector(ps ? ps->pos : DVector3(0, 0, 0)); + } + return numret; +} + // // G_QueueBody // diff --git a/src/g_raven/a_artitele.cpp b/src/g_raven/a_artitele.cpp deleted file mode 100644 index 76c0bc402..000000000 --- a/src/g_raven/a_artitele.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "info.h" -#include "a_pickups.h" -#include "a_artifacts.h" -#include "gstrings.h" -#include "p_local.h" -#include "p_spec.h" -#include "gi.h" -#include "s_sound.h" -#include "m_random.h" -#include "doomstat.h" -#include "g_game.h" -#include "d_player.h" -#include "a_morph.h" - -static FRandom pr_tele ("TeleportSelf"); - -// Teleport (self) ---------------------------------------------------------- - -class AArtiTeleport : public AInventory -{ - DECLARE_CLASS (AArtiTeleport, AInventory) -public: - bool Use (bool pickup); -}; - -IMPLEMENT_CLASS(AArtiTeleport, false, false) - -bool AArtiTeleport::Use (bool pickup) -{ - DVector3 dest; - int destAngle; - - if (deathmatch) - { - unsigned int selections = deathmatchstarts.Size (); - unsigned int i = pr_tele() % selections; - dest = deathmatchstarts[i].pos; - destAngle = deathmatchstarts[i].angle; - } - else - { - FPlayerStart *start = G_PickPlayerStart(int(Owner->player - players)); - dest = start->pos; - destAngle = start->angle; - } - dest.Z = ONFLOORZ; - P_Teleport (Owner, dest, (double)destAngle, TELF_SOURCEFOG | TELF_DESTFOG); - bool canlaugh = true; - if (Owner->player->morphTics && (Owner->player->MorphStyle & MORPH_UNDOBYCHAOSDEVICE)) - { // Teleporting away will undo any morph effects (pig) - if (!P_UndoPlayerMorph (Owner->player, Owner->player, MORPH_UNDOBYCHAOSDEVICE) - && (Owner->player->MorphStyle & MORPH_FAILNOLAUGH)) - { - canlaugh = false; - } - } - if (canlaugh) - { // Full volume laugh - S_Sound (Owner, CHAN_VOICE, "*evillaugh", 1, ATTN_NONE); - } - return true; -} - diff --git a/src/p_teleport.cpp b/src/p_teleport.cpp index 14055202a..e9752ee53 100644 --- a/src/p_teleport.cpp +++ b/src/p_teleport.cpp @@ -238,6 +238,17 @@ bool P_Teleport (AActor *thing, DVector3 pos, DAngle angle, int flags) return true; } +DEFINE_ACTION_FUNCTION(AActor, Teleport) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + PARAM_ANGLE(an); + PARAM_INT(flags); + ACTION_RETURN_BOOL(P_Teleport(self, DVector3(x, y, z), an, flags)); +} + static AActor *SelectTeleDest (int tid, int tag, bool norandom) { AActor *searcher; diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 1b13d05ff..45b44f767 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -306,6 +306,7 @@ class Actor : Thinker native native Actor OldSpawnMissile(Actor dest, class type, Actor owner = null); native Actor SpawnPuff(class pufftype, vector3 pos, double hitdir, double particledir, int updown, int flags = 0, Actor vict = null); + native bool Teleport(Vector3 pos, double angle, int flags); native void TraceBleed(int damage, Actor missile); native bool CheckMeleeRange(); native int DamageMobj(Actor inflictor, Actor source, int damage, Name mod, int flags = 0, double angle = 0); @@ -318,7 +319,7 @@ class Actor : Thinker native native void NewChaseDir(); native bool CheckMissileRange(); native bool SetState(state st, bool nofunction = false); - native state FindState(statelabel st, bool exact = false); // do we need exact later? + native state FindState(statelabel st, bool exact = false); bool SetStateLabel(statelabel st, bool nofunction = false) { return SetState(FindState(st), nofunction); } native action state ResolveState(statelabel st); // this one, unlike FindState, is context aware. native void LinkToWorld(); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 13aa480a9..6d0e77795 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -5,6 +5,8 @@ class Object native // These really should be global functions... native static int G_SkillPropertyInt(int p); native static double G_SkillPropertyFloat(int p); + native static vector3, int G_PickDeathmatchStart(); + native static vector3, int G_PickPlayerStart(int pnum, int flags = 0); /*virtual*/ native void Destroy(); } diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index 70f8abed0..d87ad338a 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -982,3 +982,14 @@ enum EFindFloorCeiling FFCF_RESTRICTEDPORTAL = 128, // current values in the iterator's return are through a restricted portal type (i.e. some features are blocked.) FFCF_NODROPOFF = 256, // Caller does not need a dropoff (saves some time when checking portals) }; + +enum ETeleport +{ + TELF_DESTFOG = 1, + TELF_SOURCEFOG = 2, + TELF_KEEPORIENTATION = 4, + TELF_KEEPVELOCITY = 8, + TELF_KEEPHEIGHT = 16, + TELF_ROTATEBOOM = 32, + TELF_ROTATEBOOMINVERSE = 64, +}; diff --git a/wadsrc/static/zscript/heretic/dsparil.txt b/wadsrc/static/zscript/heretic/dsparil.txt index e2cfca558..54931b65e 100644 --- a/wadsrc/static/zscript/heretic/dsparil.txt +++ b/wadsrc/static/zscript/heretic/dsparil.txt @@ -345,7 +345,7 @@ class Sorcerer2 : Actor { return; } - A_PlaySound (AttackSound, CHAN_BODY); + A_PlaySound (AttackSound, CHAN_BODY, 1, false, ATTN_NONE); if (CheckMeleeRange()) { int damage = random[Srcr2Atk](1, 8) * 20; diff --git a/wadsrc/static/zscript/raven/artiegg.txt b/wadsrc/static/zscript/raven/artiegg.txt index ef3c6e2be..f0287048e 100644 --- a/wadsrc/static/zscript/raven/artiegg.txt +++ b/wadsrc/static/zscript/raven/artiegg.txt @@ -47,11 +47,10 @@ class ArtiEgg : CustomInventory EGGC ABCB 6; Loop; Use: - TNT1 A 0 A_FireCustomMissile("EggFX", -15, 0, 0, 0, 1); - TNT1 A 0 A_FireCustomMissile("EggFX", -7.5, 0, 0, 0, 1); - TNT1 A 0 A_FireCustomMissile("EggFX", 0, 0, 0, 0, 1); - TNT1 A 0 A_FireCustomMissile("EggFX", 7.5, 0, 0, 0, 1); - TNT1 A 0 A_FireCustomMissile("EggFX", 15, 0, 0, 0, 1); + TNT1 A 0 + { + for (double i = -15; i <= 15; i += 7.5) A_FireCustomMissile("EggFX", i, 0, 0, 0, 1); + } Stop; } } @@ -103,11 +102,10 @@ class ArtiPork : CustomInventory PORK ABCDEFGH 5; Loop; Use: - TNT1 A 0 A_FireCustomMissile("PorkFX", -15, 0, 0, 0, 1); - TNT1 A 0 A_FireCustomMissile("PorkFX", -7.5, 0, 0, 0, 1); - TNT1 A 0 A_FireCustomMissile("PorkFX", 0, 0, 0, 0, 1); - TNT1 A 0 A_FireCustomMissile("PorkFX", 7.5, 0, 0, 0, 1); - TNT1 A 0 A_FireCustomMissile("PorkFX", 15, 0, 0, 0, 1); + TNT1 A 0 + { + for (double i = -15; i <= 15; i += 7.5) A_FireCustomMissile("PorkFX", i, 0, 0, 0, 1); + } Stop; } } diff --git a/wadsrc/static/zscript/raven/artitele.txt b/wadsrc/static/zscript/raven/artitele.txt index 9f21bd733..3242db92e 100644 --- a/wadsrc/static/zscript/raven/artitele.txt +++ b/wadsrc/static/zscript/raven/artitele.txt @@ -1,7 +1,7 @@ // Teleport (self) ---------------------------------------------------------- -class ArtiTeleport : Inventory native +class ArtiTeleport : Inventory { Default { @@ -22,6 +22,38 @@ class ArtiTeleport : Inventory native ATLP ABCB 4; Loop; } + + override bool Use (bool pickup) + { + Vector3 dest; + int destAngle; + + if (deathmatch) + { + [dest, destAngle] = G_PickDeathmatchStart(); + } + else + { + [dest, destAngle] = G_PickPlayerStart(Owner.PlayerNumber()); + } + dest.Z = ONFLOORZ; + Owner.Teleport (dest, destAngle, TELF_SOURCEFOG | TELF_DESTFOG); + bool canlaugh = true; + Playerinfo p = Owner.player; + if (p && p.morphTics && (p.MorphStyle & MRF_UNDOBYCHAOSDEVICE)) + { // Teleporting away will undo any morph effects (pig) + if (!p.UndoPlayerMorph (p, MRF_UNDOBYCHAOSDEVICE) && (p.MorphStyle & MRF_FAILNOLAUGH)) + { + canlaugh = false; + } + } + if (canlaugh) + { // Full volume laugh + A_PlaySound ("*evillaugh", CHAN_VOICE, 1, false, ATTN_NONE); + } + return true; + } + } From 7385cd70c04f471c6a3e5c2a4daba6463359d4c2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 26 Nov 2016 01:14:47 +0100 Subject: [PATCH 114/185] - scriptified the Minotaur. Interesting tidbit: The damage calculation in P_MinotaurSlam had been incorrect for the Heretic version since the friendly Hexen Dark Servant was added, but nobody ever noticed in 14 years... --- src/CMakeLists.txt | 5 - src/actor.h | 2 + src/g_hexen/a_hexenmisc.cpp | 2 - src/g_hexen/a_summon.cpp | 85 ---- src/g_raven/a_minotaur.cpp | 623 ----------------------- src/g_raven/ravenshared.h | 29 -- src/g_shared/a_morph.cpp | 2 +- src/g_strife/a_alienspectres.cpp | 2 +- src/g_strife/a_strifestuff.cpp | 2 +- src/p_interaction.cpp | 26 +- src/p_map.cpp | 16 +- src/p_maputl.cpp | 8 + src/p_mobj.cpp | 47 +- src/p_user.cpp | 2 +- src/scripting/codegeneration/codegen.cpp | 79 ++- src/scripting/thingdef_data.cpp | 13 +- src/w_wad.cpp | 9 + wadsrc/static/zscript/actor.txt | 7 + wadsrc/static/zscript/base.txt | 31 ++ wadsrc/static/zscript/constants.txt | 14 + wadsrc/static/zscript/hexen/summon.txt | 68 ++- wadsrc/static/zscript/raven/minotaur.txt | 551 +++++++++++++++++++- 22 files changed, 834 insertions(+), 789 deletions(-) delete mode 100644 src/g_hexen/a_summon.cpp delete mode 100644 src/g_raven/a_minotaur.cpp delete mode 100644 src/g_raven/ravenshared.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bca0e9371..95db06b2f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -825,7 +825,6 @@ file( GLOB HEADER_FILES ${EXTRA_HEADER_DIRS} fragglescript/*.h g_hexen/*.h - g_raven/*.h g_shared/*.h g_strife/*.h intermission/*.h @@ -878,7 +877,6 @@ set( NOT_COMPILED_SOURCE_FILES g_hexen/a_magestaff.cpp g_hexen/a_serpent.cpp g_hexen/a_spike.cpp - g_hexen/a_summon.cpp g_hexen/a_teleportother.cpp g_strife/a_acolyte.cpp g_strife/a_alienspectres.cpp @@ -1147,7 +1145,6 @@ set (PCH_SOURCES wi_stuff.cpp zstrformat.cpp g_hexen/a_hexenmisc.cpp - g_raven/a_minotaur.cpp g_strife/a_strifestuff.cpp g_strife/strife_sbar.cpp g_shared/a_action.cpp @@ -1300,7 +1297,6 @@ endif() target_link_libraries( zdoom ${ZDOOM_LIBS} gdtoa dumb lzma ) include_directories( . g_hexen - g_raven g_strife g_shared oplsynth @@ -1432,7 +1428,6 @@ source_group("External\\RapidJSON" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_D source_group("Externak\\SFMT" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sfmt/.+") source_group("FraggleScript" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/fragglescript/.+") source_group("Games\\Hexen Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_hexen/.+") -source_group("Games\\Raven Shared" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_raven/.+") source_group("Games\\Strife Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_strife/.+") source_group("Intermission" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/intermission/.+") source_group("Menu" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/menu/.+") diff --git a/src/actor.h b/src/actor.h index bdb5241d1..f6020d292 100644 --- a/src/actor.h +++ b/src/actor.h @@ -628,6 +628,7 @@ public: // Called when actor dies virtual void Die (AActor *source, AActor *inflictor, int dmgflags = 0); + void CallDie(AActor *source, AActor *inflictor, int dmgflags = 0); // Perform some special damage action. Returns the amount of damage to do. // Returning -1 signals the damage routine to exit immediately @@ -660,6 +661,7 @@ public: // Actor had MF_SKULLFLY set and rammed into something // Returns false to stop moving and true to keep moving virtual bool Slam (AActor *victim); + bool CallSlam(AActor *victim); // Called by PIT_CheckThing() and needed for some Hexen things. // Returns -1 for normal behavior, 0 to return false, and 1 to return true. diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp index f98305cba..f442df65e 100644 --- a/src/g_hexen/a_hexenmisc.cpp +++ b/src/g_hexen/a_hexenmisc.cpp @@ -15,7 +15,6 @@ #include "p_lnspec.h" #include "p_terrain.h" #include "m_bbox.h" -#include "ravenshared.h" #include "v_palette.h" #include "g_game.h" #include "p_blockmap.h" @@ -47,5 +46,4 @@ #include "a_magestaff.cpp" #include "a_serpent.cpp" #include "a_spike.cpp" -#include "a_summon.cpp" #include "a_teleportother.cpp" diff --git a/src/g_hexen/a_summon.cpp b/src/g_hexen/a_summon.cpp deleted file mode 100644 index 58e50eeaf..000000000 --- a/src/g_hexen/a_summon.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* -#include "info.h" -#include "a_pickups.h" -#include "a_artifacts.h" -#include "gstrings.h" -#include "p_local.h" -#include "s_sound.h" -#include "ravenshared.h" -#include "vm.h" -#include "g_level.h" -*/ - -void A_Summon (AActor *); - -// Dark Servant Artifact ---------------------------------------------------- - -class AArtiDarkServant : public AInventory -{ - DECLARE_CLASS (AArtiDarkServant, AInventory) -public: - bool Use (bool pickup); -}; - -IMPLEMENT_CLASS(AArtiDarkServant, false, false) - -//============================================================================ -// -// Activate the summoning artifact -// -//============================================================================ - -bool AArtiDarkServant::Use (bool pickup) -{ - AActor *mo = P_SpawnPlayerMissile (Owner, PClass::FindActor("SummoningDoll")); - if (mo) - { - mo->target = Owner; - mo->tracer = Owner; - mo->Vel.Z = 5; - } - return true; -} - -//============================================================================ -// -// A_Summon -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_Summon) -{ - PARAM_SELF_PROLOGUE(AActor); - - AMinotaurFriend *mo; - - mo = Spawn(self->Pos(), ALLOW_REPLACE); - if (mo) - { - if (P_TestMobjLocation(mo) == false || !self->tracer) - { // Didn't fit - change back to artifact - mo->Destroy(); - AActor *arti = Spawn(self->Pos(), ALLOW_REPLACE); - if (arti) arti->flags |= MF_DROPPED; - return 0; - } - - mo->StartTime = level.maptime; - if (self->tracer->flags & MF_CORPSE) - { // Master dead - mo->tracer = NULL; // No master - } - else - { - mo->tracer = self->tracer; // Pointer to master - AInventory *power = Spawn(); - power->CallTryPickup(self->tracer); - mo->SetFriendPlayer(self->tracer->player); - } - - // Make smoke puff - Spawn("MinotaurSmoke", self->Pos(), ALLOW_REPLACE); - S_Sound(self, CHAN_VOICE, mo->ActiveSound, 1, ATTN_NORM); - } - return 0; -} diff --git a/src/g_raven/a_minotaur.cpp b/src/g_raven/a_minotaur.cpp deleted file mode 100644 index cd0ab2669..000000000 --- a/src/g_raven/a_minotaur.cpp +++ /dev/null @@ -1,623 +0,0 @@ -#include "actor.h" -#include "info.h" -#include "m_random.h" -#include "s_sound.h" -#include "p_local.h" -#include "p_enemy.h" -#include "ravenshared.h" -#include "a_action.h" -#include "gi.h" -#include "w_wad.h" -#include "vm.h" -#include "g_level.h" -#include "doomstat.h" -#include "a_pickups.h" -#include "d_player.h" -#include "serializer.h" -#include "vm.h" - -#define MAULATORTICS (25*35) - -static FRandom pr_minotauratk1 ("MinotaurAtk1"); -static FRandom pr_minotaurdecide ("MinotaurDecide"); -static FRandom pr_atk ("MinotaurAtk2"); -static FRandom pr_minotauratk3 ("MinotaurAtk3"); -static FRandom pr_fire ("MntrFloorFire"); -static FRandom pr_minotaurslam ("MinotaurSlam"); -static FRandom pr_minotaurroam ("MinotaurRoam"); -static FRandom pr_minotaurchase ("MinotaurChase"); - -void P_MinotaurSlam (AActor *source, AActor *target); - -DECLARE_ACTION(A_MinotaurLook) - -IMPLEMENT_CLASS(AMinotaur, false, false) - -void AMinotaur::Tick () -{ - Super::Tick (); - - // The unfriendly Minotaur (Heretic's) is invulnerable while charging - if (!(flags5 & MF5_SUMMONEDMONSTER)) - { - // Get MF_SKULLFLY bit and shift it so it matches MF2_INVULNERABLE - DWORD flying = (flags & MF_SKULLFLY) << 3; - if ((flags2 & MF2_INVULNERABLE) != flying) - { - flags2 ^= MF2_INVULNERABLE; - } - } -} - -bool AMinotaur::Slam (AActor *thing) -{ - // Slamming minotaurs shouldn't move non-creatures - if (!(thing->flags3&MF3_ISMONSTER) && !thing->player) - { - return false; - } - return Super::Slam (thing); -} - -int AMinotaur::DoSpecialDamage (AActor *target, int damage, FName damagetype) -{ - damage = Super::DoSpecialDamage (target, damage, damagetype); - if ((damage != -1) && (flags & MF_SKULLFLY)) - { // Slam only when in charge mode - P_MinotaurSlam (this, target); - return -1; - } - return damage; -} - -// Minotaur Friend ---------------------------------------------------------- - -IMPLEMENT_CLASS(AMinotaurFriend, false, false) - -void AMinotaurFriend::BeginPlay () -{ - Super::BeginPlay (); - StartTime = -1; -} - -void AMinotaurFriend::Serialize(FSerializer &arc) -{ - Super::Serialize (arc); - arc("starttime", StartTime); -} - -void AMinotaurFriend::Die (AActor *source, AActor *inflictor, int dmgflags) -{ - Super::Die (source, inflictor, dmgflags); - - if (tracer && tracer->health > 0 && tracer->player) - { - // Search thinker list for minotaur - TThinkerIterator iterator; - AMinotaurFriend *mo; - - while ((mo = iterator.Next()) != NULL) - { - if (mo->health <= 0) continue; - // [RH] Minotaurs can't be morphed, so this isn't needed - //if (!(mo->flags&MF_COUNTKILL)) continue; // for morphed minotaurs - if (mo->flags&MF_CORPSE) continue; - if (mo->StartTime >= 0 && (level.maptime - StartTime) >= MAULATORTICS) continue; - if (mo->tracer != NULL && mo->tracer->player == tracer->player) break; - } - - if (mo == NULL) - { - AInventory *power = tracer->FindInventory(PClass::FindActor("PowerMinotaur")); - if (power != NULL) - { - power->Destroy (); - } - } - } -} - -// Action functions for the minotaur ---------------------------------------- - -//---------------------------------------------------------------------------- -// -// PROC A_MinotaurAtk1 -// -// Melee attack. -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_MinotaurDeath) -{ - PARAM_SELF_PROLOGUE(AActor); - - 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_SELF_PROLOGUE(AActor); - - player_t *player; - - if (!self->target) - { - return 0; - } - S_Sound (self, CHAN_WEAPON, "minotaur/melee", 1, ATTN_NORM); - if (self->CheckMeleeRange()) - { - int damage = pr_minotauratk1.HitDice (4); - int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); - if ((player = self->target->player) != NULL && - player->mo == self->target) - { // Squish the player - player->deltaviewheight = -16; - } - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_MinotaurDecide -// -// Choose a missile attack. -// -//---------------------------------------------------------------------------- - -#define MNTR_CHARGE_SPEED (13.) - -DEFINE_ACTION_FUNCTION(AActor, A_MinotaurDecide) -{ - PARAM_SELF_PROLOGUE(AActor); - - bool friendly = !!(self->flags5 & MF5_SUMMONEDMONSTER); - AActor *target; - double dist; - - target = self->target; - if (!target) - { - return 0; - } - if (!friendly) - { - S_Sound (self, CHAN_WEAPON, "minotaur/sight", 1, ATTN_NORM); - } - dist = self->Distance2D(target); - if (target->Top() > self->Z() - && target->Top() < self->Top() - && dist < (friendly ? 16*64. : 8*64.) - && dist > 1*64. - && pr_minotaurdecide() < 150) - { // Charge attack - // Don't call the state function right away - self->SetState (self->FindState ("Charge"), true); - self->flags |= MF_SKULLFLY; - if (!friendly) - { // Heretic's Minotaur is invulnerable during charge attack - self->flags2 |= MF2_INVULNERABLE; - } - A_FaceTarget (self); - self->VelFromAngle(MNTR_CHARGE_SPEED); - self->special1 = TICRATE/2; // Charge duration - } - else if (target->Z() == target->floorz - && dist < 9*64. - && pr_minotaurdecide() < (friendly ? 100 : 220)) - { // Floor fire attack - self->SetState (self->FindState ("Hammer")); - self->special2 = 0; - } - else - { // Swing attack - A_FaceTarget (self); - // Don't need to call P_SetMobjState because the current state - // falls through to the swing attack - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_MinotaurCharge -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_MinotaurCharge) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *puff; - - if (self->target == NULL) - { - return 0; - } - if (self->special1 > 0) - { - PClassActor *type; - - if (gameinfo.gametype == GAME_Heretic) - { - type = PClass::FindActor("PhoenixPuff"); - } - else - { - type = PClass::FindActor("PunchPuff"); - } - puff = Spawn (type, self->Pos(), ALLOW_REPLACE); - puff->Vel.Z = 2; - self->special1--; - } - else - { - self->flags &= ~MF_SKULLFLY; - self->flags2 &= ~MF2_INVULNERABLE; - self->SetState (self->SeeState); - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_MinotaurAtk2 -// -// Swing attack. -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk2) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo; - DAngle angle; - double vz; - double z; - bool friendly = !!(self->flags5 & MF5_SUMMONEDMONSTER); - - if (self->target == NULL) - { - return 0; - } - S_Sound (self, CHAN_WEAPON, "minotaur/attack2", 1, ATTN_NORM); - if (self->CheckMeleeRange()) - { - int damage; - 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 0; - } - z = self->Z() + 40; - PClassActor *fx = PClass::FindActor("MinotaurFX1"); - if (fx) - { - mo = P_SpawnMissileZ (self, z, self->target, fx); - if (mo != NULL) - { -// S_Sound (mo, CHAN_WEAPON, "minotaur/attack2", 1, ATTN_NORM); - vz = mo->Vel.Z; - angle = mo->Angles.Yaw; - P_SpawnMissileAngleZ (self, z, fx, angle-(45./8), vz); - P_SpawnMissileAngleZ (self, z, fx, angle+(45./8), vz); - P_SpawnMissileAngleZ (self, z, fx, angle-(45./16), vz); - P_SpawnMissileAngleZ (self, z, fx, angle+(45./16), vz); - } - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_MinotaurAtk3 -// -// Floor fire attack. -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk3) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo; - player_t *player; - bool friendly = !!(self->flags5 & MF5_SUMMONEDMONSTER); - - if (!self->target) - { - return 0; - } - S_Sound (self, CHAN_VOICE, "minotaur/attack3", 1, ATTN_NORM); - if (self->CheckMeleeRange()) - { - int damage; - - damage = pr_minotauratk3.HitDice (friendly ? 3 : 5); - int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); - if ((player = self->target->player) != NULL && - player->mo == self->target) - { // Squish the player - player->deltaviewheight = -16; - } - } - else - { - if (self->Floorclip > 0 && (i_compatflags & COMPATF_MINOTAUR)) - { - // only play the sound. - S_Sound (self, CHAN_WEAPON, "minotaur/fx2hit", 1, ATTN_NORM); - } - else - { - mo = P_SpawnMissile (self, self->target, PClass::FindActor("MinotaurFX2")); - if (mo != NULL) - { - S_Sound (mo, CHAN_WEAPON, "minotaur/attack1", 1, ATTN_NORM); - } - } - } - if (pr_minotauratk3() < 192 && self->special2 == 0) - { - self->SetState (self->FindState ("HammerLoop")); - self->special2 = 1; - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_MntrFloorFire -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_MntrFloorFire) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo; - - self->SetZ(self->floorz); - double x = pr_fire.Random2() / 64.; - double y = pr_fire.Random2() / 64.; - - mo = Spawn("MinotaurFX3", self->Vec2OffsetZ(x, y, self->floorz), ALLOW_REPLACE); - mo->target = self->target; - mo->Vel.X = MinVel; // Force block checking - P_CheckMissileSpawn (mo, self->radius); - return 0; -} - -//--------------------------------------------------------------------------- -// -// FUNC P_MinotaurSlam -// -//--------------------------------------------------------------------------- - -void P_MinotaurSlam (AActor *source, AActor *target) -{ - DAngle angle; - double thrust; - int damage; - - angle = source->AngleTo(target); - thrust = 16 + pr_minotaurslam() / 64.; - target->VelFromAngle(thrust, angle); - damage = pr_minotaurslam.HitDice (static_cast(source) ? 4 : 6); - int newdam = P_DamageMobj (target, NULL, NULL, damage, NAME_Melee); - P_TraceBleed (newdam > 0 ? newdam : damage, target, angle, 0.); - if (target->player) - { - target->reactiontime = 14+(pr_minotaurslam()&7); - } -} - -//---------------------------------------------------------------------------- -// -// Minotaur variables -// -// special1 charge duration countdown -// special2 internal to minotaur AI -// StartTime minotaur start time -// tracer pointer to player that spawned it -//---------------------------------------------------------------------------- - -//---------------------------------------------------------------------------- -// -// A_MinotaurRoam -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_MinotaurRoam) -{ - PARAM_SELF_PROLOGUE(AActor); - - // In case pain caused him to skip his fade in. - self->RenderStyle = STYLE_Normal; - - if (self->IsKindOf(RUNTIME_CLASS(AMinotaurFriend))) - { - AMinotaurFriend *self1 = static_cast (self); - - if (self1->StartTime >= 0 && (level.maptime - self1->StartTime) >= MAULATORTICS) - { - P_DamageMobj (self1, NULL, NULL, TELEFRAG_DAMAGE, NAME_None); - return 0; - } - } - - if (pr_minotaurroam() < 30) - CALL_ACTION(A_MinotaurLook, self); // adjust to closest target - - if (pr_minotaurroam() < 6) - { - //Choose new direction - self->movedir = pr_minotaurroam() % 8; - FaceMovementDirection (self); - } - if (!P_Move(self)) - { - // Turn - if (pr_minotaurroam() & 1) - self->movedir = (self->movedir + 1) % 8; - else - self->movedir = (self->movedir + 7) % 8; - FaceMovementDirection (self); - } - return 0; -} - - -//---------------------------------------------------------------------------- -// -// PROC A_MinotaurLook -// -// Look for enemy of player -//---------------------------------------------------------------------------- -#define MINOTAUR_LOOK_DIST (16*54.) - -DEFINE_ACTION_FUNCTION(AActor, A_MinotaurLook) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (!self->IsKindOf(RUNTIME_CLASS(AMinotaurFriend))) - { - CALL_ACTION(A_Look, self); - return 0; - } - - AActor *mo = NULL; - player_t *player; - double dist; - int i; - AActor *master = self->tracer; - - self->target = NULL; - if (deathmatch) // Quick search for players - { - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) continue; - player = &players[i]; - mo = player->mo; - if (mo == master) continue; - if (mo->health <= 0) continue; - dist = self->Distance2D(mo); - if (dist > MINOTAUR_LOOK_DIST) continue; - self->target = mo; - break; - } - } - - if (!self->target) // Near player monster search - { - if (master && (master->health>0) && (master->player)) - mo = P_RoughMonsterSearch(master, 20); - else - mo = P_RoughMonsterSearch(self, 20); - self->target = mo; - } - - if (!self->target) // Normal monster search - { - FActorIterator iterator (0); - - while ((mo = iterator.Next()) != NULL) - { - if (!(mo->flags3 & MF3_ISMONSTER)) continue; - if (mo->health <= 0) continue; - if (!(mo->flags & MF_SHOOTABLE)) continue; - dist = self->Distance2D(mo); - if (dist > MINOTAUR_LOOK_DIST) continue; - if ((mo == master) || (mo == self)) continue; - if ((mo->flags5 & MF5_SUMMONEDMONSTER) && (mo->tracer == master)) continue; - self->target = mo; - break; // Found actor to attack - } - } - - if (self->target) - { - self->SetState (self->SeeState, true); - } - else - { - self->SetState (self->FindState ("Roam"), true); - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_MinotaurChase) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (!self->IsKindOf(RUNTIME_CLASS(AMinotaurFriend))) - { - A_Chase (stack, self); - return 0; - } - - AMinotaurFriend *self1 = static_cast (self); - - // In case pain caused him to skip his fade in. - self1->RenderStyle = STYLE_Normal; - - if (self1->StartTime >= 0 && (level.maptime - self1->StartTime) >= MAULATORTICS) - { - P_DamageMobj (self1, NULL, NULL, TELEFRAG_DAMAGE, NAME_None); - return 0; - } - - if (pr_minotaurchase() < 30) - CALL_ACTION(A_MinotaurLook, self1); // adjust to closest target - - if (!self1->target || (self1->target->health <= 0) || - !(self1->target->flags&MF_SHOOTABLE)) - { // look for a new target - self1->SetIdle(); - return 0; - } - - FaceMovementDirection (self1); - self1->reactiontime = 0; - - // Melee attack - if (self1->MeleeState && self1->CheckMeleeRange ()) - { - if (self1->AttackSound) - { - S_Sound (self1, CHAN_WEAPON, self1->AttackSound, 1, ATTN_NORM); - } - self1->SetState (self1->MeleeState); - return 0; - } - - // Missile attack - if (self1->MissileState && P_CheckMissileRange(self1)) - { - self1->SetState (self1->MissileState); - return 0; - } - - // chase towards target - if (!P_Move (self1)) - { - P_NewChaseDir (self1); - FaceMovementDirection (self1); - } - - // Active sound - if (pr_minotaurchase() < 6) - { - self1->PlayActiveSound (); - } - return 0; -} - diff --git a/src/g_raven/ravenshared.h b/src/g_raven/ravenshared.h deleted file mode 100644 index 3c6019ae7..000000000 --- a/src/g_raven/ravenshared.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef __RAVENSHARED_H__ -#define __RAVENSHARED_H__ - -class AActor; - -class AMinotaur : public AActor -{ - DECLARE_CLASS (AMinotaur, AActor) -public: - int DoSpecialDamage (AActor *target, int damage, FName damagetype); - -public: - bool Slam (AActor *); - void Tick (); -}; - -class AMinotaurFriend : public AMinotaur -{ - DECLARE_CLASS (AMinotaurFriend, AMinotaur) -public: - int StartTime; - - void Die (AActor *source, AActor *inflictor, int dmgflags); - void BeginPlay (); - - void Serialize(FSerializer &arc); -}; - -#endif //__RAVENSHARED_H__ diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 5ab1e3eb9..2f986c201 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -704,7 +704,7 @@ void AMorphedMonster::Die (AActor *source, AActor *inflictor, int dmgflags) if (UnmorphedMe != NULL && (UnmorphedMe->flags & MF_UNMORPHED)) { UnmorphedMe->health = health; - UnmorphedMe->Die (source, inflictor, dmgflags); + UnmorphedMe->CallDie (source, inflictor, dmgflags); } } diff --git a/src/g_strife/a_alienspectres.cpp b/src/g_strife/a_alienspectres.cpp index a1c20355f..194bfd9e0 100644 --- a/src/g_strife/a_alienspectres.cpp +++ b/src/g_strife/a_alienspectres.cpp @@ -136,7 +136,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_AlienSpectreDeath) if (oracle->health > 0) { oracle->health = 0; - oracle->Die (self, self); + oracle->CallDie (self, self); } } player->GiveInventoryType (QuestItemClasses[22]); diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp index 7cccdd3f3..6815b1d49 100644 --- a/src/g_strife/a_strifestuff.cpp +++ b/src/g_strife/a_strifestuff.cpp @@ -119,7 +119,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_GetHurt) } if (self->health <= 0) { - self->Die (self->target, self->target); + self->CallDie (self->target, self->target); } return 0; } diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index aece79edc..8c28c46b3 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -58,6 +58,7 @@ #include "d_net.h" #include "d_netinf.h" #include "a_morph.h" +#include "virtual.h" static FRandom pr_obituary ("Obituary"); static FRandom pr_botrespawn ("BotRespawn"); @@ -342,7 +343,7 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags) realthis->health = realgibhealth -1; // if morphed was gibbed, so must original be (where allowed)l } } - realthis->Die(source, inflictor, dmgflags); + realthis->CallDie(source, inflictor, dmgflags); } return; } @@ -761,7 +762,26 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags) } } +DEFINE_ACTION_FUNCTION(AActor, Die) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(source, AActor); + PARAM_OBJECT(inflictor, AActor); + PARAM_INT(dmgflags); + self->Die(source, inflictor, dmgflags); + return 0; +} +void AActor::CallDie(AActor *source, AActor *inflictor, int dmgflags) +{ + IFVIRTUAL(AActor, Die) + { + VMValue params[4] = { (DObject*)this, source, inflictor, dmgflags }; + VMFrameStack stack; + stack.Call(func, params, 4, nullptr, 0, nullptr); + } + else return Die(source, inflictor, dmgflags); +} //--------------------------------------------------------------------------- @@ -1443,7 +1463,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, source = source->tracer; } } - target->Die (source, inflictor, flags); + target->CallDie (source, inflictor, flags); return damage; } } @@ -1794,7 +1814,7 @@ void P_PoisonDamage (player_t *player, AActor *source, int damage, target->DamageType = player->poisontype; } } - target->Die(source, source); + target->CallDie(source, source); return; } } diff --git a/src/p_map.cpp b/src/p_map.cpp index f1fa55cf9..e6265be8c 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -1245,7 +1245,7 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch // Check for skulls slamming into things if (tm.thing->flags & MF_SKULLFLY) { - bool res = tm.thing->Slam(tm.thing->BlockingMobj); + bool res = tm.thing->CallSlam(tm.thing->BlockingMobj); tm.thing->BlockingMobj = NULL; return res; } @@ -3278,7 +3278,7 @@ bool FSlide::BounceWall(AActor *mo) if (mo->flags & MF_MISSILE) P_ExplodeMissile(mo, line, NULL); else - mo->Die(NULL, NULL); + mo->CallDie(NULL, NULL); return true; } @@ -4611,6 +4611,18 @@ void P_TraceBleed(int damage, AActor *target, DAngle angle, DAngle pitch) P_TraceBleed(damage, target->PosPlusZ(target->Height/2), target, angle, pitch); } +DEFINE_ACTION_FUNCTION(AActor, TraceBleedAngle) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(damage); + PARAM_FLOAT(angle); + PARAM_FLOAT(pitch); + + P_TraceBleed(damage, self, angle, pitch); + return 0; +} + + //========================================================================== // // diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 0a1d831d8..5bb3bea0f 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -1690,6 +1690,14 @@ AActor *P_RoughMonsterSearch (AActor *mo, int distance, bool onlyseekable) return P_BlockmapSearch (mo, distance, RoughBlockCheck, (void *)onlyseekable); } +DEFINE_ACTION_FUNCTION(AActor, RoughMonsterSearch) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(distance); + PARAM_BOOL_DEF(onlyseekable); + ACTION_RETURN_OBJECT(P_RoughMonsterSearch(self, distance, onlyseekable)); +} + AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, int, void *), void *params) { int blockX; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index d845846db..559efda82 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -49,7 +49,6 @@ #include "p_acs.h" #include "cmdlib.h" #include "decallib.h" -#include "ravenshared.h" #include "a_action.h" #include "a_keys.h" #include "p_conversation.h" @@ -1787,7 +1786,7 @@ bool AActor::FloorBounceMissile (secplane_t &plane) if (flags & MF_MISSILE) P_ExplodeMissile(this, NULL, NULL); else - Die(NULL, NULL); + CallDie(NULL, NULL); return true; } if (!(BounceFlags & BOUNCE_CanBounceWater)) @@ -1814,7 +1813,7 @@ bool AActor::FloorBounceMissile (secplane_t &plane) if (flags & MF_MISSILE) P_ExplodeMissile(this, NULL, NULL); else - Die(NULL, NULL); + CallDie(NULL, NULL); return true; } @@ -3313,6 +3312,31 @@ bool AActor::Slam (AActor *thing) return false; // stop moving } +DEFINE_ACTION_FUNCTION(AActor, Slam) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(thing, AActor); + ACTION_RETURN_BOOL(self->Slam(thing)); +} + +bool AActor::CallSlam(AActor *thing) +{ + IFVIRTUAL(AActor, Slam) + { + VMValue params[2] = { (DObject*)this, thing }; + VMReturn ret; + VMFrameStack stack; + int retval; + ret.IntAt(&retval); + stack.Call(func, params, 2, &ret, 1, nullptr); + return !!retval; + + } + else return Slam(thing); +} + + + bool AActor::SpecialBlastHandling (AActor *source, double strength) { return true; @@ -5495,7 +5519,7 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) else mobj->health = -mthing->health; if (mthing->health == 0) - mobj->Die(NULL, NULL); + mobj->CallDie(NULL, NULL); else if (mthing->health != 1) mobj->StartHealth = mobj->health; @@ -6902,6 +6926,14 @@ void AActor::SetIdle(bool nofunction) SetState(idle, nofunction); } +DEFINE_ACTION_FUNCTION(AActor, SetIdle) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_BOOL_DEF(nofunction); + self->SetIdle(nofunction); + return 0; +} + int AActor::SpawnHealth() const { int defhealth = StartHealth ? StartHealth : GetDefault()->health; @@ -7351,6 +7383,13 @@ DEFINE_ACTION_FUNCTION(AActor, PlayerNumber) ACTION_RETURN_INT(self->player ? int(self->player - players) : 0); } +DEFINE_ACTION_FUNCTION(AActor, SetFriendPlayer) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_POINTER(player, player_t); + self->SetFriendPlayer(player); + return 0; +} //---------------------------------------------------------------------------- // // DropItem handling diff --git a/src/p_user.cpp b/src/p_user.cpp index 03df6a0ca..f28bf9f42 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -1446,7 +1446,7 @@ void APlayerPawn::Die (AActor *source, AActor *inflictor, int dmgflags) if (player != NULL && player->mo != this) { // Make the real player die, too - player->mo->Die (source, inflictor, dmgflags); + player->mo->CallDie (source, inflictor, dmgflags); } else { diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index ab0bb96e1..8a5eddd2d 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -185,6 +185,16 @@ FxLocalVariableDeclaration *FCompileContext::FindLocalVariable(FName name) } } +static PStruct *FindStructType(FName name) +{ + PStruct *ccls = PClass::FindClass(name); + if (ccls == nullptr) + { + ccls = dyn_cast(TypeTable.FindType(RUNTIME_CLASS(PStruct), 0, (intptr_t)name, nullptr)); + if (ccls == nullptr) ccls = dyn_cast(TypeTable.FindType(RUNTIME_CLASS(PNativeStruct), 0, (intptr_t)name, nullptr)); + } + return ccls; +} //========================================================================== // // ExpEmit @@ -244,7 +254,7 @@ static PSymbol *FindBuiltinFunction(FName funcname, VMNativeFunction::NativeCall // //========================================================================== -static bool AreCompatiblePointerTypes(PType *dest, PType *source) +static bool AreCompatiblePointerTypes(PType *dest, PType *source, bool forcompare = false) { if (dest->IsKindOf(RUNTIME_CLASS(PPointer)) && source->IsKindOf(RUNTIME_CLASS(PPointer))) { @@ -252,12 +262,13 @@ static bool AreCompatiblePointerTypes(PType *dest, PType *source) auto fromtype = static_cast(source); auto totype = static_cast(dest); if (fromtype == nullptr) return true; - if (totype->IsConst && !fromtype->IsConst) return false; + if (!forcompare && totype->IsConst && !fromtype->IsConst) return false; if (fromtype == totype) return true; if (fromtype->PointedType->IsKindOf(RUNTIME_CLASS(PClass)) && totype->PointedType->IsKindOf(RUNTIME_CLASS(PClass))) { auto fromcls = static_cast(fromtype->PointedType); auto tocls = static_cast(totype->PointedType); + if (forcompare && tocls->IsDescendantOf(fromcls)) return true; return (fromcls->IsDescendantOf(tocls)); } } @@ -2211,6 +2222,14 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx) } // Both types are the same so this is ok. } + else if (Right->ValueType->IsA(RUNTIME_CLASS(PNativeStruct)) && Base->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(Base->ValueType)->PointedType == Right->ValueType) + { + // allow conversion of native structs to pointers of the same type. This is necessary to assign elements from global arrays like players, sectors, etc. to local pointers. + // For all other types this is not needed. Structs are not assignable and classes can only exist as references. + bool writable; + Right->RequestAddress(ctx, &writable); + Right->ValueType = Base->ValueType; + } else { // pass it to FxTypeCast for complete handling. @@ -3267,7 +3286,7 @@ FxExpression *FxCompareEq::Resolve(FCompileContext& ctx) else if (left->ValueType->GetRegType() == REGT_POINTER && right->ValueType->GetRegType() == REGT_POINTER) { if (left->ValueType != right->ValueType && right->ValueType != TypeNullPtr && left->ValueType != TypeNullPtr && - !AreCompatiblePointerTypes(left->ValueType, right->ValueType)) + !AreCompatiblePointerTypes(left->ValueType, right->ValueType, true)) { goto error; } @@ -5691,12 +5710,48 @@ FxMemberIdentifier::~FxMemberIdentifier() FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) { + PStruct *ccls = nullptr; CHECKRESOLVED(); + if (Object->ExprType == EFX_Identifier) + { + // If the left side is a class name for a static member function call it needs to be resolved manually + // because the resulting value type would cause problems in nearly every other place where identifiers are being used. + ccls = FindStructType(static_cast(Object)->Identifier); + if (ccls != nullptr) static_cast(Object)->noglobal = true; + } + SAFE_RESOLVE(Object, ctx); - // allow accessing the color chanels by mapping the type to a matching struct which defines them. - if (Object->ValueType == TypeColor) + // check for class or struct constants if the left side is a type name. + if (Object->ValueType == TypeError) + { + if (ccls != nullptr) + { + if (!ccls->IsKindOf(RUNTIME_CLASS(PClass)) || static_cast(ccls)->bExported) + { + PSymbol *sym; + if ((sym = ccls->Symbols.FindSymbol(Identifier, true)) != nullptr) + { + if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) + { + ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s.%s' as constant\n", ccls->TypeName.GetChars(), Identifier.GetChars()); + delete this; + return FxConstant::MakeConstant(sym, ScriptPosition); + } + else + { + ScriptPosition.Message(MSG_ERROR, "Unable to access '%s.%s' in a static context\n", ccls->TypeName.GetChars(), Identifier.GetChars()); + delete this; + return nullptr; + } + } + } + } + } + + // allow accessing the color channels by mapping the type to a matching struct which defines them. + if (Object->ValueType == TypeColor) Object->ValueType = TypeColorStruct; if (Object->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) @@ -6635,12 +6690,12 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) if (!start.Konst) { - ExpEmit indexwork = indexv.Fixed ? ExpEmit(build, indexv.RegType) : indexv; int shiftbits = 0; while (1u << shiftbits < arraytype->ElementSize) { shiftbits++; } + ExpEmit indexwork = indexv.Fixed && arraytype->ElementSize > 1 ? ExpEmit(build, indexv.RegType) : indexv; if (1u << shiftbits == arraytype->ElementSize) { if (shiftbits > 0) @@ -7079,7 +7134,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) bool staticonly = false; bool novirtual = false; - PClass *ccls = nullptr; + PStruct *ccls = nullptr; for (auto a : ArgList) { @@ -7093,10 +7148,10 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) if (Self->ExprType == EFX_Identifier) { - ccls = PClass::FindClass(static_cast(Self)->Identifier); // If the left side is a class name for a static member function call it needs to be resolved manually // because the resulting value type would cause problems in nearly every other place where identifiers are being used. - if (ccls != nullptr)static_cast(Self)->noglobal = true; + ccls = FindStructType(static_cast(Self)->Identifier); + if (ccls != nullptr) static_cast(Self)->noglobal = true; } SAFE_RESOLVE(Self, ctx); @@ -7105,17 +7160,13 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) { if (ccls != nullptr) { - if (ccls->bExported) + if (!ccls->IsKindOf(RUNTIME_CLASS(PClass)) || static_cast(ccls)->bExported) { cls = ccls; staticonly = true; goto isresolved; } } - else - { - // Todo: static struct members need to work as well. - } } if (Self->ExprType == EFX_Super) diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 1b93e22a5..a6c9ff9f1 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -43,6 +43,7 @@ #include "d_player.h" #include "p_effect.h" #include "autosegs.h" +#include "gi.h" static TArray properties; static TArray AFTable; @@ -721,7 +722,11 @@ void InitThingdef() pstruct->Size = sizeof(player_t); pstruct->Align = alignof(player_t); PArray *parray = NewArray(pstruct, MAXPLAYERS); - PField *playerf = new PField("players", pstruct, VARF_Native | VARF_Static, (intptr_t)&players); + PField *playerf = new PField("players", parray, VARF_Native | VARF_Static, (intptr_t)&players); + GlobalSymbols.AddSymbol(playerf); + + parray = NewArray(TypeBool, MAXPLAYERS); + playerf = new PField("playeringame", parray, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&playeringame); GlobalSymbols.AddSymbol(playerf); @@ -803,3 +808,9 @@ void InitThingdef() } } + +DEFINE_ACTION_FUNCTION(DObject, GameType) +{ + PARAM_PROLOGUE; + ACTION_RETURN_INT(gameinfo.gametype); +} diff --git a/src/w_wad.cpp b/src/w_wad.cpp index da369144a..41833fc24 100644 --- a/src/w_wad.cpp +++ b/src/w_wad.cpp @@ -501,6 +501,15 @@ int FWadCollection::CheckNumForName (const char *name, int space, int wadnum, bo return i != NULL_INDEX ? i : -1; } +DEFINE_ACTION_FUNCTION(_Wads, CheckNumForName) +{ + PARAM_PROLOGUE; + PARAM_STRING(name); + PARAM_INT(ns); + PARAM_INT_DEF(wadnum); + PARAM_BOOL_DEF(exact); + ACTION_RETURN_INT(Wads.CheckNumForName(name, ns, wadnum, exact)); +} //========================================================================== // // W_GetNumForName diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 45b44f767..a006c79ed 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -262,6 +262,8 @@ class Actor : Thinker native virtual native void Activate(Actor activator); virtual native void Deactivate(Actor activator); virtual native int DoSpecialDamage (Actor target, int damage, Name damagetype); + virtual native void Die(Actor source, Actor inflictor, int dmgflags); + virtual native bool Slam(Actor victim); virtual native bool UseInventory(Inventory item); @@ -276,6 +278,7 @@ class Actor : Thinker native native bool HitFloor(); native bool isTeammate(Actor other); native int PlayerNumber(); + native void SetFriendPlayer(PlayerInfo player); native void RestoreDamage(); native int SpawnHealth(); @@ -296,6 +299,7 @@ class Actor : Thinker native native Actor SpawnMissileAngleZSpeed (double z, class type, double angle, double vz, double speed, Actor owner = null, bool checkspawn = true); native Actor, Actor SpawnPlayerMissile(class type, double angle = 0, double x = 0, double y = 0, double z = 0, out FTranslatedLineTarget pLineTarget = null, bool nofreeaim = false, bool noautoaim = false, int aimflags = 0); native void SpawnTeleportFog(Vector3 pos, bool beforeTele, bool setTarget); + native Actor RoughMonsterSearch(int distance, bool onlyseekable = false); void A_Light(int extralight) { if (player) player.extralight = clamp(extralight, -20, 20); } void A_Light0() { if (player) player.extralight = 0; } @@ -308,6 +312,9 @@ class Actor : Thinker native native bool Teleport(Vector3 pos, double angle, int flags); native void TraceBleed(int damage, Actor missile); + native void TraceBleedAngle(int damage, double angle, double pitch); + + native void SetIdle(bool nofunction = false); native bool CheckMeleeRange(); native int DamageMobj(Actor inflictor, Actor source, int damage, Name mod, int flags = 0, double angle = 0); native double AimLineAttack(double angle, double distance, out FTranslatedLineTarget pLineTarget = null, double vrange = 0., int flags = 0, Actor target = null, Actor friender = null); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 6d0e77795..c91b7aaa4 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -7,6 +7,7 @@ class Object native native static double G_SkillPropertyFloat(int p); native static vector3, int G_PickDeathmatchStart(); native static vector3, int G_PickPlayerStart(int pnum, int flags = 0); + native static int GameType(); /*virtual*/ native void Destroy(); } @@ -133,3 +134,33 @@ struct Sector native native double, Sector, F3DFloor NextHighestCeilingAt(double x, double y, double bottomz, double topz, int flags = 0); } +struct Wads +{ + enum WadNamespace + { + ns_hidden = -1, + + ns_global = 0, + ns_sprites, + ns_flats, + ns_colormaps, + ns_acslibrary, + ns_newtextures, + ns_bloodraw, + ns_bloodsfx, + ns_bloodmisc, + ns_strifevoices, + ns_hires, + ns_voxels, + + ns_specialzipdirectory, + ns_sounds, + ns_patches, + ns_graphics, + ns_music, + + ns_firstskin, + } + + native static int CheckNumForName(string name, int ns, int wadnum = -1, bool exact = false); +} \ No newline at end of file diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index d87ad338a..eadf30bc7 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -993,3 +993,17 @@ enum ETeleport TELF_ROTATEBOOM = 32, TELF_ROTATEBOOMINVERSE = 64, }; + +enum EGameType +{ + GAME_Any = 0, + GAME_Doom = 1, + GAME_Heretic = 2, + GAME_Hexen = 4, + GAME_Strife = 8, + GAME_Chex = 16, //Chex is basically Doom, but we need to have a different set of actors. + + GAME_Raven = GAME_Heretic|GAME_Hexen, + GAME_DoomChex = GAME_Doom|GAME_Chex, + GAME_DoomStrifeChex = GAME_Doom|GAME_Strife|GAME_Chex +} diff --git a/wadsrc/static/zscript/hexen/summon.txt b/wadsrc/static/zscript/hexen/summon.txt index 06ceb7e17..c9e9b9295 100644 --- a/wadsrc/static/zscript/hexen/summon.txt +++ b/wadsrc/static/zscript/hexen/summon.txt @@ -1,7 +1,7 @@ // Dark Servant Artifact ---------------------------------------------------- -class ArtiDarkServant : Inventory native +class ArtiDarkServant : Inventory { Default { @@ -23,6 +23,26 @@ class ArtiDarkServant : Inventory native SUMN A 350; Loop; } + + //============================================================================ + // + // Activate the summoning artifact + // + //============================================================================ + + override bool Use (bool pickup) + { + Actor mo = Owner.SpawnPlayerMissile ("SummoningDoll"); + if (mo) + { + mo.target = Owner; + mo.tracer = Owner; + mo.Vel.Z = 5; + } + return true; + } + + } // Summoning Doll ----------------------------------------------------------- @@ -36,8 +56,6 @@ class SummoningDoll : Actor +NOTELEPORT } - native void A_Summon(); - States { Spawn: @@ -48,6 +66,49 @@ class SummoningDoll : Actor SUMN A 4 A_Summon; Stop; } + + //============================================================================ + // + // A_Summon + // + //============================================================================ + + void A_Summon() + { + Actor mo = Spawn("MinotaurFriend", pos, ALLOW_REPLACE); + if (mo) + { + if (mo.TestMobjLocation() == false || !tracer) + { // Didn't fit - change back to artifact + mo.Destroy(); + Actor arti = Spawn("ArtiDarkServant", Pos, ALLOW_REPLACE); + if (arti) arti.bDropped = true; + return; + } + + // Careful! The Minotaur might have been replaced + // so only set the time if we got a genuine one. + MinotaurFriend m = MinotaurFriend(mo); + if (m) m.StartTime = level.maptime; + + if (tracer.bCorpse) + { // Master dead + mo.tracer = null; // No master + } + else + { + mo.tracer = tracer; // Pointer to master + Inventory power = Inventory(Spawn("PowerMinotaur")); + power.CallTryPickup(tracer); + mo.SetFriendPlayer(tracer.player); + } + + // Make smoke puff + Spawn("MinotaurSmoke", Pos, ALLOW_REPLACE); + A_PlaySound(mo.ActiveSound, CHAN_VOICE); + } + } + } // Minotaur Smoke ----------------------------------------------------------- @@ -69,3 +130,4 @@ class MinotaurSmoke : Actor Stop; } } + diff --git a/wadsrc/static/zscript/raven/minotaur.txt b/wadsrc/static/zscript/raven/minotaur.txt index 9bbbe81a0..fa40cbec1 100644 --- a/wadsrc/static/zscript/raven/minotaur.txt +++ b/wadsrc/static/zscript/raven/minotaur.txt @@ -1,5 +1,9 @@ -class Minotaur : Actor native +class Minotaur : Actor { + const MAULATORTICS = 25 * TICRATE; + const MNTR_CHARGE_SPEED =13.; + const MINOTAUR_LOOK_DIST = 16*54.; + Default { Health 3000; @@ -26,16 +30,6 @@ class Minotaur : Actor native DropItem "PhoenixRodAmmo", 84, 10; } - native void A_MinotaurDecide(); - native void A_MinotaurAtk1(); - native void A_MinotaurAtk2(); - native void A_MinotaurAtk3(); - native void A_MinotaurCharge(); - native void A_MinotaurLook(); - native void A_MinotaurRoam(); - native void A_MinotaurChase(); - native void A_MinotaurDeath(); - States { Spawn: @@ -101,10 +95,478 @@ class Minotaur : Actor native MNTR E 10 A_BossDeath; Stop; } + + //--------------------------------------------------------------------------- + // + // FUNC P_MinotaurSlam + // + //--------------------------------------------------------------------------- + + void MinotaurSlam (Actor target) + { + double ang = AngleTo(target); + double thrust = 16 + random[MinotaurSlam]() / 64.; + target.VelFromAngle(ang, thrust); + int damage = random[MinotaurSlam](1, 8) * (bSummonedMonster? 4 : 6); + int newdam = target.DamageMobj (null, null, damage, 'Melee'); + target.TraceBleedAngle (newdam > 0 ? newdam : damage, ang, 0.); + if (target.player) + { + target.reactiontime = random[MinotaurSlam](14, 21); + } + } + + + //---------------------------------------------------------------------------- + // + // + // + //---------------------------------------------------------------------------- + + override void Tick () + { + Super.Tick (); + + // The unfriendly Minotaur (Heretic's) is invulnerable while charging + if (!bSummonedMonster) + { + bInvulnerable = bSkullFly; + } + } + + override bool Slam (Actor thing) + { + // Slamming minotaurs shouldn't move non-creatures + if (!thing.bIsMonster && !thing.player) + { + return false; + } + return Super.Slam (thing); + } + + override int DoSpecialDamage (Actor target, int damage, Name damagetype) + { + damage = Super.DoSpecialDamage (target, damage, damagetype); + if (damage != -1 && bSkullFly) + { // Slam only when in charge mode + MinotaurSlam (target); + return -1; + } + return damage; + } + + //---------------------------------------------------------------------------- + // + // PROC A_MinotaurAtk1 + // + // Melee attack. + // + //---------------------------------------------------------------------------- + + void A_MinotaurAtk1() + { + if (!target) + { + return; + } + A_PlaySound ("minotaur/melee", CHAN_WEAPON); + if (CheckMeleeRange()) + { + int damage = random[MinotaurAtk1](1, 8) * 4; + int newdam = target.DamageMobj (self, self, damage, 'Melee'); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + PlayerInfo player = target.player; + if (player != null && player.mo == target) + { // Squish the player + player.deltaviewheight = -16; + } + } + } + + //---------------------------------------------------------------------------- + // + // PROC A_MinotaurDecide + // + // Choose a missile attack. + // + //---------------------------------------------------------------------------- + + void A_MinotaurDecide() + { + bool friendly = bSummonedMonster; + + if (!target) + { + return; + } + if (!friendly) + { + A_PlaySound ("minotaur/sight", CHAN_WEAPON); + } + double dist = Distance2D(target); + if (target.pos.z + target.height > pos.z + && target.pos.z + target.height < pos.z + height + && dist < (friendly ? 16*64. : 8*64.) + && dist > 1*64. + && random[MinotaurDecide]() < 150) + { // Charge attack + // Don't call the state function right away + SetStateLabel("Charge", true); + bSkullFly = true; + if (!friendly) + { // Heretic's Minotaur is invulnerable during charge attack + bInvulnerable = true; + } + A_FaceTarget (); + VelFromAngle(MNTR_CHARGE_SPEED); + special1 = TICRATE/2; // Charge duration + } + else if (target.pos.z == target.floorz + && dist < 9*64. + && random[MinotaurDecide]() < (friendly ? 100 : 220)) + { // Floor fire attack + SetStateLabel("Hammer"); + special2 = 0; + } + else + { // Swing attack + A_FaceTarget (); + // Don't need to call P_SetMobjState because the current state + // falls through to the swing attack + } + } + + //---------------------------------------------------------------------------- + // + // PROC A_MinotaurCharge + // + //---------------------------------------------------------------------------- + + void A_MinotaurCharge() + { + if (target == null) + { + return; + } + if (special1 > 0) + { + Class type; + + //if (gameinfo.gametype == GAME_Heretic) + if (gametype() == GAME_Heretic) + { + type = "PhoenixPuff"; + } + else + { + type = "PunchPuff"; + } + Actor puff = Spawn (type, Pos, ALLOW_REPLACE); + puff.Vel.Z = 2; + special1--; + } + else + { + bSkullFly = false; + bInvulnerable = false; + SetState (SeeState); + } + } + + //---------------------------------------------------------------------------- + // + // PROC A_MinotaurAtk2 + // + // Swing attack. + // + //---------------------------------------------------------------------------- + + void A_MinotaurAtk2() + { + bool friendly = bSummonedMonster; + + if (target == null) + { + return; + } + A_PlaySound ("minotaur/attack2", CHAN_WEAPON); + if (CheckMeleeRange()) + { + int damage = random[MinotaurAtk2](1, 8) * (friendly ? 3 : 5); + int newdam = target.DamageMobj (self, self, damage, 'Melee'); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + return; + } + double z = pos.z + 40; + Class fx = "MinotaurFX1"; + Actor mo = SpawnMissileZ (z, target, fx); + if (mo != null) + { +// S_Sound (mo, CHAN_WEAPON, "minotaur/attack2", 1, ATTN_NORM); + double vz = mo.Vel.Z; + double ang = mo.angle; + SpawnMissileAngleZ (z, fx, ang-(45./8), vz); + SpawnMissileAngleZ (z, fx, ang+(45./8), vz); + SpawnMissileAngleZ (z, fx, ang-(45./16), vz); + SpawnMissileAngleZ (z, fx, ang+(45./16), vz); + } + } + + //---------------------------------------------------------------------------- + // + // PROC A_MinotaurAtk3 + // + // Floor fire attack. + // + //---------------------------------------------------------------------------- + + void A_MinotaurAtk3() + { + bool friendly = bSummonedMonster; + + if (!target) + { + return; + } + A_PlaySound ("minotaur/attack3", CHAN_VOICE); + if (CheckMeleeRange()) + { + int damage = random[MinotaurAtk3](1, 8) * (friendly ? 3 : 5); + int newdam = target.DamageMobj (self, self, damage, 'Melee'); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + PlayerInfo player = target.player; + if (player != null && player.mo == target) + { // Squish the player + player.deltaviewheight = -16; + } + } + else + { + if (Floorclip > 0 && compat_minotaur) + { + // only play the sound. + A_PlaySound ("minotaur/fx2hit", CHAN_WEAPON); + } + else + { + Actor mo = SpawnMissile (target, "MinotaurFX2"); + if (mo != null) + { + mo.A_PlaySound ("minotaur/attack1", CHAN_WEAPON); + } + } + } + if (random[MinotaurAtk3]() < 192 && special2 == 0) + { + SetStateLabel ("HammerLoop"); + special2 = 1; + } + } + + //---------------------------------------------------------------------------- + // + // PROC A_MinotaurDeath + // + //---------------------------------------------------------------------------- + + void A_MinotaurDeath() + { + if (Wads.CheckNumForName ("MNTRF1", Wads.ns_sprites) < 0 && + Wads.CheckNumForName ("MNTRF0", Wads.ns_sprites) < 0) + SetStateLabel("FadeOut"); + } + + + //---------------------------------------------------------------------------- + // + // A_MinotaurRoam + // + //---------------------------------------------------------------------------- + + void A_MinotaurRoam() + { + // In case pain caused him to skip his fade in. + A_SetRenderStyle(1, STYLE_Normal); + + MinotaurFriend mf = MinotaurFriend(self); + if (mf) + { + if (mf.StartTime >= 0 && (level.maptime - mf.StartTime) >= MAULATORTICS) + { + DamageMobj (null, null, TELEFRAG_DAMAGE, 'None'); + return; + } + } + + if (random[MinotaurRoam]() < 30) + A_MinotaurLook(); // adjust to closest target + + if (random[MinotaurRoam]() < 6) + { + //Choose new direction + movedir = random[MinotaurRoam]() % 8; + FaceMovementDirection (); + } + if (!MonsterMove()) + { + // Turn + if (random[MinotaurRoam]() & 1) + movedir = (movedir + 1) % 8; + else + movedir = (movedir + 7) % 8; + FaceMovementDirection (); + } + } + + + //---------------------------------------------------------------------------- + // + // PROC A_MinotaurLook + // + // Look for enemy of player + //---------------------------------------------------------------------------- + + void A_MinotaurLook() + { + if (!(self is "MinotaurFriend")) + { + A_Look(); + return; + } + + Actor mo = null; + PlayerInfo player; + double dist; + Actor master = tracer; + + target = null; + if (deathmatch) // Quick search for players + { + for (int i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) continue; + player = players[i]; + mo = player.mo; + if (mo == master) continue; + if (mo.health <= 0) continue; + dist = Distance2D(mo); + if (dist > MINOTAUR_LOOK_DIST) continue; + target = mo; + break; + } + } + + if (!target) // Near player monster search + { + if (master && (master.health > 0) && (master.player)) + mo = master.RoughMonsterSearch(20); + else + mo = RoughMonsterSearch(20); + target = mo; + } + + if (!target) // Normal monster search + { + ThinkerIterator it = ThinkerIterator.Create("Actor"); + + while ((mo = Actor(it.Next())) != null) + { + if (!mo.bIsMonster) continue; + if (mo.health <= 0) continue; + if (!mo.bShootable) continue; + dist = Distance2D(mo); + if (dist > MINOTAUR_LOOK_DIST) continue; + if (mo == master || mo == self) continue; + if (mo.bSummonedMonster && mo.tracer == master) continue; + target = mo; + break; // Found actor to attack + } + } + + if (target) + { + SetState (SeeState, true); + } + else + { + SetStateLabel ("Roam", true); + } + } + + //---------------------------------------------------------------------------- + // + // PROC A_MinotaurChase + // + //---------------------------------------------------------------------------- + + void A_MinotaurChase() + { + MinotaurFriend mf = MinotaurFriend(self); + if (!mf) + { + A_Chase(); + return; + } + + + // In case pain caused him to skip his fade in. + A_SetRenderStyle(1, STYLE_Normal); + + if (mf.StartTime >= 0 && (level.maptime - mf.StartTime) >= MAULATORTICS) + { + DamageMobj (null, null, TELEFRAG_DAMAGE, 'None'); + return; + } + + if (random[MinotaurChase]() < 30) + A_MinotaurLook(); // adjust to closest target + + if (!target || (target.health <= 0) || !target.bShootable) + { // look for a new target + SetIdle(); + return; + } + + FaceMovementDirection (); + reactiontime = 0; + + // Melee attack + if (MeleeState && CheckMeleeRange ()) + { + if (AttackSound) + { + A_PlaySound (AttackSound, CHAN_WEAPON); + } + SetState (MeleeState); + return; + } + + // Missile attack + if (MissileState && CheckMissileRange()) + { + SetState (MissileState); + return; + } + + // chase towards target + if (!MonsterMove ()) + { + NewChaseDir (); + FaceMovementDirection (); + } + + // Active sound + if (random[MinotaurChase]() < 6) + { + PlayActiveSound (); + } + } } -class MinotaurFriend : Minotaur native +class MinotaurFriend : Minotaur { + int StartTime; + Default { Health 2500; @@ -132,6 +594,51 @@ class MinotaurFriend : Minotaur native Death: Goto FadeOut; } + + //---------------------------------------------------------------------------- + // + // + // + //---------------------------------------------------------------------------- + + override void BeginPlay () + { + Super.BeginPlay (); + StartTime = -1; + } + + override void Die (Actor source, Actor inflictor, int dmgflags) + { + Super.Die (source, inflictor, dmgflags); + + if (tracer && tracer.health > 0 && tracer.player) + { + // Search thinker list for minotaur + ThinkerIterator it = ThinkerIterator.Create("MinotaurFriend"); + MinotaurFriend mo; + + while ((mo = MinotaurFriend(it.Next())) != null) + { + if (mo.health <= 0) continue; + // [RH] Minotaurs can't be morphed, so this isn't needed + //if (!(mo.flags&MF_COUNTKILL)) continue; // for morphed minotaurs + if (mo.bCorpse) continue; + if (mo.StartTime >= 0 && (level.maptime - StartTime) >= MAULATORTICS) continue; + if (mo.tracer != null && mo.tracer.player == tracer.player) break; + } + + if (mo == null) + { + Inventory power = tracer.FindInventory("PowerMinotaur"); + if (power != null) + { + power.Destroy (); + } + } + } + } + + } // Minotaur FX 1 ------------------------------------------------------------ @@ -179,8 +686,6 @@ class MinotaurFX2 : MinotaurFX1 DeathSound "minotaur/fx2hit"; } - native void A_MntrFloorFire(); - states { Spawn: @@ -191,6 +696,24 @@ class MinotaurFX2 : MinotaurFX1 FX13 JKLM 4 Bright; Stop; } + + //---------------------------------------------------------------------------- + // + // PROC A_MntrFloorFire + // + //---------------------------------------------------------------------------- + + void A_MntrFloorFire() + { + SetZ(floorz); + double x = Random2[MntrFloorFire]() / 64.; + double y = Random2[MntrFloorFire]() / 64.; + + Actor mo = Spawn("MinotaurFX3", Vec2OffsetZ(x, y, floorz), ALLOW_REPLACE); + mo.target = target; + mo.Vel.X = MinVel; // Force block checking + mo.CheckMissileSpawn (radius); + } } // Minotaur FX 3 ------------------------------------------------------------ From 4e802652c7871c945e167d995792623960f8c8b4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 26 Nov 2016 09:51:14 +0100 Subject: [PATCH 115/185] - scriptified ArtiBlastRadius. --- src/CMakeLists.txt | 1 - src/g_hexen/a_blastradius.cpp | 158 ------------------ src/g_hexen/a_hexenmisc.cpp | 1 - src/p_enemy.cpp | 10 +- src/p_mobj.cpp | 11 +- src/p_sectors.cpp | 45 +++++ src/r_defs.h | 4 +- wadsrc/static/zscript/actor.txt | 3 +- wadsrc/static/zscript/base.txt | 66 ++++++++ wadsrc/static/zscript/heretic/hereticmisc.txt | 8 + .../static/zscript/heretic/weaponphoenix.txt | 10 -- wadsrc/static/zscript/hexen/blastradius.txt | 131 +++++++++++++++ 12 files changed, 273 insertions(+), 175 deletions(-) delete mode 100644 src/g_hexen/a_blastradius.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 95db06b2f..d53429d05 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -855,7 +855,6 @@ set( NOT_COMPILED_SOURCE_FILES ${OTHER_SYSTEM_SOURCES} sc_man_scanner.h sc_man_scanner.re - g_hexen/a_blastradius.cpp g_hexen/a_boostarmor.cpp g_hexen/a_clericflame.cpp g_hexen/a_clericholy.cpp diff --git a/src/g_hexen/a_blastradius.cpp b/src/g_hexen/a_blastradius.cpp deleted file mode 100644 index 0776e107f..000000000 --- a/src/g_hexen/a_blastradius.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/* -#include "info.h" -#include "a_pickups.h" -#include "a_artifacts.h" -#include "gstrings.h" -#include "p_local.h" -#include "p_enemy.h" -#include "s_sound.h" -*/ - -/* For reference, the default values: -#define BLAST_RADIUS_DIST 255*F.RACUNIT -#define BLAST_SPEED 20*F.RACUNIT -#define BLAST_FULLSTRENGTH 255 -*/ - -// Disc of Repulsion -------------------------------------------------------- - -//========================================================================== -// -// AArtiBlastRadius :: BlastActor -// -//========================================================================== - -void BlastActor (AActor *victim, double strength, double speed, AActor *Owner, PClassActor *blasteffect, bool dontdamage) -{ - DAngle angle; - AActor *mo; - DVector3 pos; - - if (!victim->SpecialBlastHandling (Owner, strength)) - { - return; - } - - angle = Owner->AngleTo(victim); - DVector2 move = angle.ToVector(speed); - victim->Vel.X = move.X; - victim->Vel.Y = move.Y; - - // Spawn blast puff - angle -= 180.; - pos = victim->Vec3Offset( - (victim->radius + 1) * angle.Cos(), - (victim->radius + 1) * angle.Sin(), - (victim->Height / 2) - victim->Floorclip); - mo = Spawn (blasteffect, pos, ALLOW_REPLACE); - if (mo) - { - mo->Vel.X = victim->Vel.X; - mo->Vel.Y = victim->Vel.Y; - } - if (victim->flags & MF_MISSILE) - { - // [RH] Floor and ceiling huggers should not be blasted vertically. - if (!(victim->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER))) - { - mo->Vel.Z = victim->Vel.Z = 8; - } - } - else - { - victim->Vel.Z = 1000. / victim->Mass; - } - if (victim->player) - { - // Players handled automatically - } - else if (!dontdamage) - { - victim->flags2 |= MF2_BLASTED; - } - if (victim->flags6 & MF6_TOUCHY) - { // Touchy objects die when blasted - victim->flags6 &= ~MF6_ARMED; // Disarm - P_DamageMobj(victim, Owner, Owner, victim->health, NAME_Melee, DMG_FORCED); - } -} - -enum -{ - BF_USEAMMO = 1, - BF_DONTWARN = 2, - BF_AFFECTBOSSES = 4, - BF_NOIMPACTDAMAGE = 8, -}; - -//========================================================================== -// -// AArtiBlastRadius :: Activate -// -// Blast all actors away -// -//========================================================================== - -DEFINE_ACTION_FUNCTION (AActor, A_Blast) -{ - PARAM_ACTION_PROLOGUE(AActor); - PARAM_INT_DEF (blastflags) - PARAM_FLOAT_DEF (strength) - PARAM_FLOAT_DEF (radius) - PARAM_FLOAT_DEF (speed) - PARAM_CLASS_DEF (blasteffect, AActor) - PARAM_SOUND_DEF (blastsound) - - AActor *mo; - TThinkerIterator iterator; - - if (self->player && (blastflags & BF_USEAMMO) && ACTION_CALL_FROM_PSPRITE()) - { - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL && !weapon->DepleteAmmo(weapon->bAltFire)) - { - return 0; - } - } - - S_Sound (self, CHAN_AUTO, blastsound, 1, ATTN_NORM); - - if (!(blastflags & BF_DONTWARN)) - { - P_NoiseAlert (self, self); - } - while ( (mo = iterator.Next ()) ) - { - if ((mo == self) || ((mo->flags2 & MF2_BOSS) && !(blastflags & BF_AFFECTBOSSES)) - || (mo->flags2 & MF2_DORMANT) || (mo->flags3 & MF3_DONTBLAST)) - { // Not a valid monster: originator, boss, dormant, or otherwise protected - continue; - } - if ((mo->flags & MF_ICECORPSE) || (mo->flags3 & MF3_CANBLAST)) - { - // Let these special cases go - } - else if ((mo->flags3 & MF3_ISMONSTER) && (mo->health <= 0)) - { - continue; - } - else if (!(mo->player) && - !(mo->flags & MF_MISSILE) && - !(mo->flags3 & (MF3_ISMONSTER|MF3_CANBLAST)) && - !(mo->flags6 & (MF6_TOUCHY|MF6_VULNERABLE))) - { // Must be monster, player, missile, touchy or vulnerable - continue; - } - if (self->Distance2D(mo) > radius) - { // Out of range - continue; - } - if (mo->Sector->PortalGroup != self->Sector->PortalGroup && !P_CheckSight(self, mo)) - { - // in another region and cannot be seen. - continue; - } - BlastActor (mo, strength, speed, self, blasteffect, !!(blastflags & BF_NOIMPACTDAMAGE)); - } - return 0; -} diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp index f442df65e..2384a8518 100644 --- a/src/g_hexen/a_hexenmisc.cpp +++ b/src/g_hexen/a_hexenmisc.cpp @@ -24,7 +24,6 @@ #include "serializer.h" // Include all the Hexen stuff here to reduce compile time -#include "a_blastradius.cpp" #include "a_boostarmor.cpp" #include "a_clericflame.cpp" #include "a_clericholy.cpp" diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index db237e8bb..a4be4dd1b 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -262,7 +262,15 @@ void P_NoiseAlert (AActor *target, AActor *emitter, bool splash, double maxdist) } } - +DEFINE_ACTION_FUNCTION(AActor, NoiseAlert) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(emitter, AActor); + PARAM_BOOL_DEF(splash); + PARAM_FLOAT_DEF(maxdist); + P_NoiseAlert(self, emitter, splash, maxdist); + return 0; +} //---------------------------------------------------------------------------- diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 559efda82..e9c6a2980 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -22,7 +22,6 @@ //----------------------------------------------------------------------------- // HEADER FILES ------------------------------------------------------------ - #include #include "templates.h" #include "i_system.h" @@ -3342,6 +3341,16 @@ bool AActor::SpecialBlastHandling (AActor *source, double strength) return true; } +// This only gets called from the script side so we do not need a native wrapper like for the other virtual methods. +DEFINE_ACTION_FUNCTION(AActor, SpecialBlastHandling) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(source, AActor); + PARAM_FLOAT(strength); + ACTION_RETURN_BOOL(self->SpecialBlastHandling(source, strength)); +} + + int AActor::SpecialMissileHit (AActor *victim) { return -1; diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index e93d718cd..841401226 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -1265,3 +1265,48 @@ int side_t::GetLightLevel (bool foggy, int baselight, bool is3dlight, int *pfake } return baselight; } + + +DEFINE_FIELD_X(Sector, sector_t, floorplane) +DEFINE_FIELD_X(Sector, sector_t, ceilingplane) +DEFINE_FIELD_X(Sector, sector_t, ColorMap) +DEFINE_FIELD_X(Sector, sector_t, SoundTarget) +DEFINE_FIELD_X(Sector, sector_t, special) +DEFINE_FIELD_X(Sector, sector_t, lightlevel) +DEFINE_FIELD_X(Sector, sector_t, seqType) +DEFINE_FIELD_X(Sector, sector_t, sky) +DEFINE_FIELD_X(Sector, sector_t, SeqName) +DEFINE_FIELD_X(Sector, sector_t, centerspot) +DEFINE_FIELD_X(Sector, sector_t, validcount) +DEFINE_FIELD_X(Sector, sector_t, thinglist) +DEFINE_FIELD_X(Sector, sector_t, friction) +DEFINE_FIELD_X(Sector, sector_t, movefactor) +DEFINE_FIELD_X(Sector, sector_t, terrainnum) +DEFINE_FIELD_X(Sector, sector_t, floordata) +DEFINE_FIELD_X(Sector, sector_t, ceilingdata) +DEFINE_FIELD_X(Sector, sector_t, lightingdata) +DEFINE_FIELD_X(Sector, sector_t, interpolations) +DEFINE_FIELD_X(Sector, sector_t, soundtraversed) +DEFINE_FIELD_X(Sector, sector_t, stairlock) +DEFINE_FIELD_X(Sector, sector_t, prevsec) +DEFINE_FIELD_X(Sector, sector_t, nextsec) +DEFINE_FIELD_X(Sector, sector_t, linecount) +DEFINE_FIELD_X(Sector, sector_t, lines) +DEFINE_FIELD_X(Sector, sector_t, heightsec) +DEFINE_FIELD_X(Sector, sector_t, bottommap) +DEFINE_FIELD_X(Sector, sector_t, midmap) +DEFINE_FIELD_X(Sector, sector_t, topmap) +DEFINE_FIELD_X(Sector, sector_t, touching_thinglist) +DEFINE_FIELD_X(Sector, sector_t, render_thinglist) +DEFINE_FIELD_X(Sector, sector_t, gravity) +DEFINE_FIELD_X(Sector, sector_t, damagetype) +DEFINE_FIELD_X(Sector, sector_t, damageamount) +DEFINE_FIELD_X(Sector, sector_t, damageinterval) +DEFINE_FIELD_X(Sector, sector_t, leakydamage) +DEFINE_FIELD_X(Sector, sector_t, ZoneNumber) +DEFINE_FIELD_X(Sector, sector_t, MoreFlags) +DEFINE_FIELD_X(Sector, sector_t, Flags) +DEFINE_FIELD_X(Sector, sector_t, SecActTarget) +DEFINE_FIELD_X(Sector, sector_t, Portals) +DEFINE_FIELD_X(Sector, sector_t, PortalGroup) +DEFINE_FIELD_X(Sector, sector_t, sectornum) diff --git a/src/r_defs.h b/src/r_defs.h index 2d16d28f9..f33baeedc 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -983,8 +983,8 @@ public: BYTE soundtraversed; // 0 = untraversed, 1,2 = sndlines -1 // jff 2/26/98 lockout machinery for stairbuilding SBYTE stairlock; // -2 on first locked -1 after thinker done 0 normally - SWORD prevsec; // -1 or number of sector for previous step - SWORD nextsec; // -1 or number of next step sector + int prevsec; // -1 or number of sector for previous step + int nextsec; // -1 or number of next step sector short linecount; struct line_t **lines; // [linecount] size diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index a006c79ed..62d88237f 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -265,6 +265,7 @@ class Actor : Thinker native virtual native void Die(Actor source, Actor inflictor, int dmgflags); virtual native bool Slam(Actor victim); virtual native bool UseInventory(Inventory item); + virtual native bool SpecialBlastHandling (Actor source, double strength); native void AdjustPlayerAngle(FTranslatedLineTarget t); @@ -279,6 +280,7 @@ class Actor : Thinker native native bool isTeammate(Actor other); native int PlayerNumber(); native void SetFriendPlayer(PlayerInfo player); + native void NoiseAlert(Actor emitter, bool splash = false, double maxdist = 0); native void RestoreDamage(); native int SpawnHealth(); @@ -669,7 +671,6 @@ class Actor : Thinker native native void A_CustomMeleeAttack(int damage = 0, sound meleesound = "", sound misssound = "", name damagetype = "none", bool bleed = true); native void A_CustomComboAttack(class missiletype, double spawnheight, int damage, sound meleesound = "", name damagetype = "none", bool bleed = true); native void A_Burst(class chunktype); - action native void A_Blast(int flags = 0, double strength = 255, double radius = 255, double speed = 20, class blasteffect = "BlastEffect", sound blastsound = "BlastRadius"); native void A_RadiusThrust(int force = 128, int distance = -1, int flags = RTF_AFFECTSOURCE, int fullthrustdistance = 0); native void A_RadiusDamageSelf(int damage = 128, double distance = 128, int flags = 0, class flashtype = null); native int A_Explode(int damage = -1, int distance = -1, int flags = XF_HURTSOURCE, bool alert = false, int fulldamagedistance = 0, int nails = 0, int naildamage = 10, class pufftype = "BulletPuff", name damagetype = "none"); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index c91b7aaa4..3766bb6b2 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -131,6 +131,72 @@ struct F3DFloor native struct Sector native { + //secplane_t floorplane, ceilingplane; + //FDynamicColormap *ColorMap; // [RH] Per-sector colormap + + native Actor SoundTarget; + + native int16 special; + native int16 lightlevel; + native int16 seqType; + + native int sky; + native Name SeqName; + + native readonly Vector2 centerspot; + native int validcount; + //AActor* thinglist; + + native double friction, movefactor; + native int terrainnum[2]; + + // thinker_t for reversable actions + //SectorEffect floordata; + //SectorEffect ceilingdata; + //SectorEffect lightingdata; + + enum EInterpolationType + { + CeilingMove, + FloorMove, + CeilingScroll, + FloorScroll + }; + //Interpolation interpolations[4]; + + native uint8 soundtraversed; + native int8 stairlock; + native int prevsec; + native int nextsec; + + native readonly int16 linecount; + //line_t **lines; + + native readonly Sector heightsec; + + native uint bottommap, midmap, topmap; + + //struct msecnode_t *touching_thinglist; + //struct msecnode_t *render_thinglist; + + native double gravity; + native Name damagetype; + native int damageamount; + native int16 damageinterval; + native int16 leakydamage; + + native uint16 ZoneNumber; + native uint16 MoreFlags; + native uint Flags; + + native SectorAction SecActTarget; + + native readonly uint Portals[2]; + native readonly int PortalGroup; + + native readonly int sectornum; + + native double, Sector, F3DFloor NextHighestCeilingAt(double x, double y, double bottomz, double topz, int flags = 0); } diff --git a/wadsrc/static/zscript/heretic/hereticmisc.txt b/wadsrc/static/zscript/heretic/hereticmisc.txt index 4cb094d06..ea79f5f80 100644 --- a/wadsrc/static/zscript/heretic/hereticmisc.txt +++ b/wadsrc/static/zscript/heretic/hereticmisc.txt @@ -1,4 +1,12 @@ +class HereticWeapon : Weapon +{ + Default + { + Weapon.Kickback 150; + } +} + // Pod ---------------------------------------------------------------------- class Pod : Actor diff --git a/wadsrc/static/zscript/heretic/weaponphoenix.txt b/wadsrc/static/zscript/heretic/weaponphoenix.txt index 554d52d21..6b949b8f6 100644 --- a/wadsrc/static/zscript/heretic/weaponphoenix.txt +++ b/wadsrc/static/zscript/heretic/weaponphoenix.txt @@ -1,13 +1,3 @@ - -class HereticWeapon : Weapon -{ - Default - { - Weapon.Kickback 150; - } -} - - // Phoenix Rod -------------------------------------------------------------- class PhoenixRod : Weapon diff --git a/wadsrc/static/zscript/hexen/blastradius.txt b/wadsrc/static/zscript/hexen/blastradius.txt index 17ac75dc3..a9c631318 100644 --- a/wadsrc/static/zscript/hexen/blastradius.txt +++ b/wadsrc/static/zscript/hexen/blastradius.txt @@ -20,6 +20,137 @@ class ArtiBlastRadius : CustomInventory Use: TNT1 A 0 A_Blast; } + +} + +//========================================================================== +// +// A_Blast is public to Actor +// +//========================================================================== + +extend class Actor +{ + /* For reference, the default values: + #define BLAST_RADIUS_DIST 255.0 + #define BLAST_SPEED 20.0 + #define BLAST_FULLSTRENGTH 255 + */ + + //========================================================================== + // + // AArtiBlastRadius :: BlastActor + // + //========================================================================== + + private void BlastActor (Actor victim, double strength, double speed, Class blasteffect, bool dontdamage) + { + if (!victim.SpecialBlastHandling (self, strength)) + { + return; + } + + double ang = AngleTo(victim); + Vector2 move = AngleToVector(ang, speed); + victim.Vel.XY = move; + + // Spawn blast puff + ang -= 180.; + Vector3 spawnpos = victim.Vec3Offset( + (victim.radius + 1) * cos(ang), + (victim.radius + 1) * sin(ang), + (victim.Height / 2) - victim.Floorclip); + Actor mo = Spawn (blasteffect, spawnpos, ALLOW_REPLACE); + if (mo) + { + mo.Vel.XY = victim.Vel.XY; + } + if (victim.bMissile) + { + // [RH] Floor and ceiling huggers should not be blasted vertically. + if (!victim.bFloorHugger && !victim.bCeilingHugger) + { + mo.Vel.Z = victim.Vel.Z = 8; + } + } + else + { + victim.Vel.Z = 1000. / victim.Mass; + } + if (victim.player) + { + // Players handled automatically + } + else if (!dontdamage) + { + victim.bBlasted = true; + } + if (victim.bTouchy) + { // Touchy objects die when blasted + victim.bArmed = false; // Disarm + victim.DamageMobj(self, self, victim.health, 'Melee', DMG_FORCED); + } + } + + //========================================================================== + // + // AArtiBlastRadius :: Activate + // + // Blast all actors away + // + //========================================================================== + + action void A_Blast(int blastflags = 0, double strength = 255, double radius = 255, double speed = 20, class blasteffect = "BlastEffect", sound blastsound = "BlastRadius") + { + + Weapon weapon = player.ReadyWeapon; + if (player && (blastflags & BF_USEAMMO) && invoker == weapon && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + + { + if (weapon != null && !weapon.DepleteAmmo(weapon.bAltFire)) + { + return; + } + } + + A_PlaySound (blastsound, CHAN_AUTO); + + if (!(blastflags & BF_DONTWARN)) + { + NoiseAlert (self); + } + ThinkerIterator it = ThinkerIterator.Create("Actor"); + Actor mo; + while ( (mo = Actor(it.Next ())) ) + { + if (mo == self || (mo.bBoss && !(blastflags & BF_AFFECTBOSSES)) || mo.bDormant || mo.bDontBlast) + { // Not a valid monster: originator, boss, dormant, or otherwise protected + continue; + } + if (mo.bIceCorpse || mo.bCanBlast) + { + // Let these special cases go + } + else if (mo.bIsMonster && mo.health <= 0) + { + continue; + } + else if (!mo.player && !mo.bMissile && !mo.bIsMonster && !mo.bCanBlast && !mo.bTouchy && !mo.bVulnerable) + { // Must be monster, player, missile, touchy or vulnerable + continue; + } + if (Distance2D(mo) > radius) + { // Out of range + continue; + } + if (mo.CurSector.PortalGroup != CurSector.PortalGroup && !CheckSight(mo)) + { + // in another region and cannot be seen. + continue; + } + BlastActor (mo, strength, speed, blasteffect, !!(blastflags & BF_NOIMPACTDAMAGE)); + } + } } // Blast Effect ------------------------------------------------------------- From f508a57bb85d83c83d13d672094614030852b9eb Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 26 Nov 2016 10:08:25 +0100 Subject: [PATCH 116/185] - scriptified ArtiBoostArmor. --- src/CMakeLists.txt | 1 - src/g_hexen/a_boostarmor.cpp | 64 ---------------------- src/g_hexen/a_hexenmisc.cpp | 1 - wadsrc/static/zscript/hexen/boostarmor.txt | 47 +++++++++++++++- 4 files changed, 46 insertions(+), 67 deletions(-) delete mode 100644 src/g_hexen/a_boostarmor.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d53429d05..41419df79 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -855,7 +855,6 @@ set( NOT_COMPILED_SOURCE_FILES ${OTHER_SYSTEM_SOURCES} sc_man_scanner.h sc_man_scanner.re - g_hexen/a_boostarmor.cpp g_hexen/a_clericflame.cpp g_hexen/a_clericholy.cpp g_hexen/a_clericmace.cpp diff --git a/src/g_hexen/a_boostarmor.cpp b/src/g_hexen/a_boostarmor.cpp deleted file mode 100644 index b910f63e7..000000000 --- a/src/g_hexen/a_boostarmor.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* -#include "info.h" -#include "a_pickups.h" -#include "a_artifacts.h" -#include "gstrings.h" -#include "p_local.h" -#include "gi.h" -#include "s_sound.h" -*/ - -// Boost Armor Artifact (Dragonskin Bracers) -------------------------------- - -class AArtiBoostArmor : public AInventory -{ - DECLARE_CLASS (AArtiBoostArmor, AInventory) -public: - bool Use (bool pickup); -}; - -IMPLEMENT_CLASS(AArtiBoostArmor, false, false) - -bool AArtiBoostArmor::Use (bool pickup) -{ - int count = 0; - - if (gameinfo.gametype == GAME_Hexen) - { - AHexenArmor *armor; - - for (int i = 0; i < 4; ++i) - { - armor = Spawn(); - armor->flags |= MF_DROPPED; - armor->health = i; - armor->Amount = 1; - if (!armor->CallTryPickup (Owner)) - { - armor->Destroy (); - } - else - { - count++; - } - } - return count != 0; - } - else - { - ABasicArmorBonus *armor = Spawn(); - armor->flags |= MF_DROPPED; - armor->SaveAmount = 50; - armor->MaxSaveAmount = 300; - if (!armor->CallTryPickup (Owner)) - { - armor->Destroy (); - return false; - } - else - { - return true; - } - } -} - diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp index 2384a8518..fa8d151a7 100644 --- a/src/g_hexen/a_hexenmisc.cpp +++ b/src/g_hexen/a_hexenmisc.cpp @@ -24,7 +24,6 @@ #include "serializer.h" // Include all the Hexen stuff here to reduce compile time -#include "a_boostarmor.cpp" #include "a_clericflame.cpp" #include "a_clericholy.cpp" #include "a_clericmace.cpp" diff --git a/wadsrc/static/zscript/hexen/boostarmor.txt b/wadsrc/static/zscript/hexen/boostarmor.txt index 4c14b69bc..f8c797c99 100644 --- a/wadsrc/static/zscript/hexen/boostarmor.txt +++ b/wadsrc/static/zscript/hexen/boostarmor.txt @@ -1,7 +1,7 @@ // Boost Armor Artifact (Dragonskin Bracers) -------------------------------- -class ArtiBoostArmor : Inventory native +class ArtiBoostArmor : Inventory { Default { @@ -21,4 +21,49 @@ class ArtiBoostArmor : Inventory native BRAC ABCDEFGH 4 Bright; Loop; } + + override bool Use (bool pickup) + { + int count = 0; + + if (gametype() == GAME_Hexen) + { + HexenArmor armor; + + for (int i = 0; i < 4; ++i) + { + armor = HexenArmor(Spawn("HexenArmor")); + armor.bDropped = true; + armor.health = i; + armor.Amount = 1; + if (!armor.CallTryPickup (Owner)) + { + armor.Destroy (); + } + else + { + count++; + } + } + return count != 0; + } + else + { + BasicArmorBonus armor = BasicArmorBonus(Spawn("BasicArmorBonus")); + armor.bDropped = true; + armor.SaveAmount = 50; + armor.MaxSaveAmount = 300; + if (!armor.CallTryPickup (Owner)) + { + armor.Destroy (); + return false; + } + else + { + return true; + } + } + } + + } From bc1e4eff7208d9d29c3374531764c5d9b8d5d09b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 26 Nov 2016 10:30:41 +0100 Subject: [PATCH 117/185] - scriptified the Cleric's flame weapon. Also fixed the angle calculations for the circle flame. --- src/CMakeLists.txt | 1 - src/g_hexen/a_clericflame.cpp | 138 -------------------- src/g_hexen/a_hexenmisc.cpp | 1 - wadsrc/static/zscript/hexen/clericflame.txt | 101 +++++++++++++- 4 files changed, 94 insertions(+), 147 deletions(-) delete mode 100644 src/g_hexen/a_clericflame.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 41419df79..376d33887 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -855,7 +855,6 @@ set( NOT_COMPILED_SOURCE_FILES ${OTHER_SYSTEM_SOURCES} sc_man_scanner.h sc_man_scanner.re - g_hexen/a_clericflame.cpp g_hexen/a_clericholy.cpp g_hexen/a_clericmace.cpp g_hexen/a_clericstaff.cpp diff --git a/src/g_hexen/a_clericflame.cpp b/src/g_hexen/a_clericflame.cpp deleted file mode 100644 index d4f86ecd5..000000000 --- a/src/g_hexen/a_clericflame.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* -#include "actor.h" -#include "gi.h" -#include "m_random.h" -#include "s_sound.h" -#include "d_player.h" -#include "a_action.h" -#include "p_local.h" -#include "a_action.h" -#include "p_pspr.h" -#include "gstrings.h" -#include "a_hexenglobal.h" -#include "vm.h" -*/ - -const double FLAMESPEED = 0.45; -const double FLAMEROTSPEED = 2.; - -static FRandom pr_missile ("CFlameMissile"); - -void A_CFlameAttack (AActor *); -void A_CFlameRotate (AActor *); -void A_CFlamePuff (AActor *); -void A_CFlameMissile (AActor *); - -// Flame Missile ------------------------------------------------------------ - - -//============================================================================ -// -// A_CFlameAttack -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_CFlameAttack) -{ - PARAM_ACTION_PROLOGUE(AActor); - - player_t *player; - - if (NULL == (player = self->player)) - { - return 0; - } - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - P_SpawnPlayerMissile (self, PClass::FindActor("CFlameMissile")); - S_Sound (self, CHAN_WEAPON, "ClericFlameFire", 1, ATTN_NORM); - return 0; -} - -//============================================================================ -// -// A_CFlamePuff -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_CFlamePuff) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->renderflags &= ~RF_INVISIBLE; - self->Vel.Zero(); - S_Sound (self, CHAN_BODY, "ClericFlameExplode", 1, ATTN_NORM); - return 0; -} - -//============================================================================ -// -// A_CFlameMissile -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_CFlameMissile) -{ - PARAM_SELF_PROLOGUE(AActor); - - int i; - DAngle an; - double dist; - AActor *mo; - - self->renderflags &= ~RF_INVISIBLE; - S_Sound (self, CHAN_BODY, "ClericFlameExplode", 1, ATTN_NORM); - AActor *BlockingMobj = self->BlockingMobj; - if (BlockingMobj && BlockingMobj->flags&MF_SHOOTABLE) - { // Hit something, so spawn the flame circle around the thing - dist = BlockingMobj->radius + 18; - for (i = 0; i < 4; i++) - { - an = i*45.; - mo = Spawn ("CircleFlame", BlockingMobj->Vec3Angle(dist, an, 5), ALLOW_REPLACE); - if (mo) - { - mo->Angles.Yaw = an; - mo->target = self->target; - mo->VelFromAngle(FLAMESPEED); - mo->specialf1 = mo->Vel.X; - mo->specialf2 = mo->Vel.Y; - mo->tics -= pr_missile()&3; - } - mo = Spawn("CircleFlame", BlockingMobj->Vec3Angle(dist, an, 5), ALLOW_REPLACE); - if(mo) - { - mo->Angles.Yaw = an + 180.; - mo->target = self->target; - mo->VelFromAngle(-FLAMESPEED); - mo->specialf1 = mo->Vel.X; - mo->specialf2 = mo->Vel.Y; - mo->tics -= pr_missile()&3; - } - } - self->SetState (self->SpawnState); - } - return 0; -} - -//============================================================================ -// -// A_CFlameRotate -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_CFlameRotate) -{ - PARAM_SELF_PROLOGUE(AActor); - - DAngle an = self->Angles.Yaw + 90.; - self->VelFromAngle(FLAMEROTSPEED, an); - self->Vel += DVector2(self->specialf1, self->specialf2); - - self->Angles.Yaw += 6.; - return 0; -} diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp index fa8d151a7..cbe9d3c12 100644 --- a/src/g_hexen/a_hexenmisc.cpp +++ b/src/g_hexen/a_hexenmisc.cpp @@ -24,7 +24,6 @@ #include "serializer.h" // Include all the Hexen stuff here to reduce compile time -#include "a_clericflame.cpp" #include "a_clericholy.cpp" #include "a_clericmace.cpp" #include "a_clericstaff.cpp" diff --git a/wadsrc/static/zscript/hexen/clericflame.txt b/wadsrc/static/zscript/hexen/clericflame.txt index 37e4149f9..d222a07db 100644 --- a/wadsrc/static/zscript/hexen/clericflame.txt +++ b/wadsrc/static/zscript/hexen/clericflame.txt @@ -16,8 +16,6 @@ class CWeapFlame : ClericWeapon Tag "$TAG_CWEAPFLAME"; } - action native void A_CFlameAttack(); - States { Spawn: @@ -43,6 +41,29 @@ class CWeapFlame : ClericWeapon CFLM G 2; Goto Ready; } + + //============================================================================ + // + // A_CFlameAttack + // + //============================================================================ + + action void A_CFlameAttack() + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + SpawnPlayerMissile ("CFlameMissile"); + A_PlaySound ("ClericFlameFire", CHAN_WEAPON); + } } // Floor Flame -------------------------------------------------------------- @@ -127,6 +148,9 @@ class FlamePuff2 : FlamePuff class CircleFlame : Actor { + const FLAMESPEED = 0.45; + const FLAMEROTSPEED = 2.; + Default { Radius 6; @@ -140,8 +164,6 @@ class CircleFlame : Actor Obituary "$OB_MPCWEAPFLAME"; } - native void A_CFlameRotate(); - States { Spawn: @@ -166,6 +188,20 @@ class CircleFlame : Actor CFCF TUVWXYZ 3 Bright; Stop; } + + //============================================================================ + // + // A_CFlameRotate + // + //============================================================================ + + void A_CFlameRotate() + { + double an = Angle + 90.; + VelFromAngle(FLAMEROTSPEED, an); + Vel.XY += (specialf1, specialf2); + Angle += 6; + } } // Flame Missile ------------------------------------------------------------ @@ -184,9 +220,6 @@ class CFlameMissile : FastProjectile Obituary "$OB_MPCWEAPFLAME"; } - native void A_CFlamePuff(); - native void A_CFlameMissile(); - States { Spawn: @@ -232,4 +265,58 @@ class CFlameMissile : FastProjectile } } + //============================================================================ + // + // A_CFlamePuff + // + //============================================================================ + + void A_CFlamePuff() + { + bInvisible = false; + Vel = (0,0,0); + A_PlaySound ("ClericFlameExplode", CHAN_BODY); + } + + //============================================================================ + // + // A_CFlameMissile + // + //============================================================================ + + void A_CFlameMissile() + { + bInvisible = false; + A_PlaySound ("ClericFlameExplode", CHAN_BODY); + if (BlockingMobj && BlockingMobj.bShootable) + { // Hit something, so spawn the flame circle around the thing + double dist = BlockingMobj.radius + 18; + for (int i = 0; i < 4; i++) + { + double an = i*45.; + Actor mo = Spawn ("CircleFlame", BlockingMobj.Vec3Angle(dist, an, 5), ALLOW_REPLACE); + if (mo) + { + mo.angle = an; + mo.target = target; + mo.VelFromAngle(CircleFlame.FLAMESPEED); + mo.specialf1 = mo.Vel.X; + mo.specialf2 = mo.Vel.Y; + mo.tics -= random[FlameMissile]()&3; + } + an += 180; + mo = Spawn("CircleFlame", BlockingMobj.Vec3Angle(dist, an, 5), ALLOW_REPLACE); + if(mo) + { + mo.angle = an; + mo.target = target; + mo.VelFromAngle(-CircleFlame.FLAMESPEED); + mo.specialf1 = mo.Vel.X; + mo.specialf2 = mo.Vel.Y; + mo.tics -= random[FlameMissile]()&3; + } + } + SetState (SpawnState); + } + } } From 177aa6ec42ee787b4d91a974c762cf1b6dc2dfb8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 26 Nov 2016 13:18:48 +0100 Subject: [PATCH 118/185] - converted half of ClericHoly. (Making a commit before starting on the more complex stuff.) - added a 'constructor' for color values. --- src/actor.h | 1 + src/g_hexen/a_clericholy.cpp | 343 --------------------- src/g_hexen/a_hexenglobal.h | 8 - src/g_hexen/a_korax.cpp | 5 +- src/g_shared/a_pickups.cpp | 21 ++ src/g_shared/a_pickups.h | 1 + src/p_mobj.cpp | 20 +- src/scripting/codegeneration/codegen.cpp | 78 ++++- src/scripting/codegeneration/codegen.h | 19 ++ src/scripting/thingdef_data.cpp | 1 + src/scripting/zscript/zcc-parse.lemon | 2 +- src/v_blend.cpp | 2 +- wadsrc/static/zscript/actor.txt | 2 + wadsrc/static/zscript/constants.txt | 8 + wadsrc/static/zscript/hexen/clericboss.txt | 17 +- wadsrc/static/zscript/hexen/clericholy.txt | 294 +++++++++++++++++- wadsrc/static/zscript/shared/inventory.txt | 1 + 17 files changed, 455 insertions(+), 368 deletions(-) diff --git a/src/actor.h b/src/actor.h index f6020d292..92e277d48 100644 --- a/src/actor.h +++ b/src/actor.h @@ -386,6 +386,7 @@ enum ActorFlag7 MF7_NOKILLSCRIPTS = 0x01000000, // [JM] No "KILL" Script on death whatsoever, even if forced by GameInfo. MF7_SPRITEANGLE = 0x02000000, // [MC] Utilize the SpriteAngle property and lock the rotation to the degrees specified. MF7_SMASHABLE = 0x04000000, // dies if hitting the floor. + MF7_NOSHIELDREFLECT = 0x08000000, // will not be reflected by shields. }; // --- mobj.renderflags --- diff --git a/src/g_hexen/a_clericholy.cpp b/src/g_hexen/a_clericholy.cpp index 52ff4179d..8ffb5be27 100644 --- a/src/g_hexen/a_clericholy.cpp +++ b/src/g_hexen/a_clericholy.cpp @@ -24,332 +24,8 @@ static FRandom pr_wraithvergedrop ("WraithvergeDrop"); void SpawnSpiritTail (AActor *spirit); -//========================================================================== -// Cleric's Wraithverge (Holy Symbol?) -------------------------------------- - -class ACWeapWraithverge : public AClericWeapon -{ - DECLARE_CLASS (ACWeapWraithverge, AClericWeapon) -public: - - void Serialize(FSerializer &arc) - { - Super::Serialize (arc); - arc("cholycount", CHolyCount); - } - PalEntry GetBlend () - { - if (paletteflash & PF_HEXENWEAPONS) - { - if (CHolyCount == 3) - return PalEntry(128, 70, 70, 70); - else if (CHolyCount == 2) - return PalEntry(128, 100, 100, 100); - else if (CHolyCount == 1) - return PalEntry(128, 130, 130, 130); - else - return PalEntry(0, 0, 0, 0); - } - else - { - return PalEntry (CHolyCount * 128 / 3, 131, 131, 131); - } - } - BYTE CHolyCount; -}; - -IMPLEMENT_CLASS(ACWeapWraithverge, false, false) - // Holy Spirit -------------------------------------------------------------- -IMPLEMENT_CLASS(AHolySpirit, false, false) - -bool AHolySpirit::Slam(AActor *thing) -{ - if (thing->flags&MF_SHOOTABLE && thing != target) - { - if (multiplayer && !deathmatch && thing->player && target->player) - { // don't attack other co-op players - return true; - } - if (thing->flags2&MF2_REFLECTIVE - && (thing->player || thing->flags2&MF2_BOSS)) - { - tracer = target; - target = thing; - return true; - } - if (thing->flags3&MF3_ISMONSTER || thing->player) - { - tracer = thing; - } - if (pr_spiritslam() < 96) - { - int dam = 12; - if (thing->player || thing->flags2&MF2_BOSS) - { - dam = 3; - // ghost burns out faster when attacking players/bosses - health -= 6; - } - P_DamageMobj(thing, this, target, dam, NAME_Melee); - if (pr_spiritslam() < 128) - { - Spawn("HolyPuff", Pos(), ALLOW_REPLACE); - S_Sound(this, CHAN_WEAPON, "SpiritAttack", 1, ATTN_NORM); - if (thing->flags3&MF3_ISMONSTER && pr_spiritslam() < 128) - { - thing->Howl(); - } - } - } - if (thing->health <= 0) - { - tracer = NULL; - } - } - return true; -} - -bool AHolySpirit::SpecialBlastHandling (AActor *source, double strength) -{ - if (tracer == source) - { - tracer = target; - target = source; - GC::WriteBarrier(this, source); - } - return true; -} - -//============================================================================ -// -// A_CHolyAttack2 -// -// Spawns the spirits -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_CHolyAttack2) -{ - PARAM_SELF_PROLOGUE(AActor); - - int j; - AActor *mo; - - for (j = 0; j < 4; j++) - { - mo = Spawn (self->Pos(), ALLOW_REPLACE); - if (!mo) - { - continue; - } - switch (j) - { // float bob index - - case 0: - mo->WeaveIndexZ = pr_holyatk2() & 7; // upper-left - break; - case 1: - mo->WeaveIndexZ = 32 + (pr_holyatk2() & 7); // upper-right - break; - case 2: - mo->WeaveIndexXY = 32 + (pr_holyatk2() & 7); // lower-left - break; - case 3: - mo->WeaveIndexXY = 32 + (pr_holyatk2() & 7); - mo->WeaveIndexZ = 32 + (pr_holyatk2() & 7); - break; - } - mo->SetZ(self->Z()); - mo->Angles.Yaw = self->Angles.Yaw + 67.5 - 45.*j; - mo->Thrust(); - mo->target = self->target; - mo->args[0] = 10; // initial turn value - mo->args[1] = 0; // initial look angle - if (deathmatch) - { // Ghosts last slightly less longer in DeathMatch - mo->health = 85; - } - if (self->tracer) - { - mo->tracer = self->tracer; - mo->flags |= MF_NOCLIP|MF_SKULLFLY; - mo->flags &= ~MF_MISSILE; - } - SpawnSpiritTail (mo); - } - return 0; -} - -//============================================================================ -// -// SpawnSpiritTail -// -//============================================================================ - -void SpawnSpiritTail (AActor *spirit) -{ - AActor *tail, *next; - int i; - - tail = Spawn ("HolyTail", spirit->Pos(), ALLOW_REPLACE); - tail->target = spirit; // parent - for (i = 1; i < 3; i++) - { - next = Spawn ("HolyTailTrail", spirit->Pos(), ALLOW_REPLACE); - tail->tracer = next; - tail = next; - } - tail->tracer = NULL; // last tail bit -} - -//============================================================================ -// -// A_CHolyAttack -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_CHolyAttack) -{ - PARAM_ACTION_PROLOGUE(AActor); - - player_t *player; - FTranslatedLineTarget t; - - if (NULL == (player = self->player)) - { - return 0; - } - ACWeapWraithverge *weapon = static_cast (self->player->ReadyWeapon); - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - AActor *missile = P_SpawnPlayerMissile (self, 0,0,0, PClass::FindActor("HolyMissile"), self->Angles.Yaw, &t); - if (missile != NULL && !t.unlinked) - { - missile->tracer = t.linetarget; - } - - weapon->CHolyCount = 3; - S_Sound (self, CHAN_WEAPON, "HolySymbolFire", 1, ATTN_NORM); - return 0; -} - -//============================================================================ -// -// A_CHolyPalette -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_CHolyPalette) -{ - PARAM_ACTION_PROLOGUE(AActor); - - if (self->player != NULL) - { - ACWeapWraithverge *weapon = static_cast (self->player->ReadyWeapon); - if (weapon != NULL && weapon->CHolyCount != 0) - { - weapon->CHolyCount--; - } - } - return 0; -} - -//============================================================================ -// -// CHolyTailFollow -// -//============================================================================ - -static void CHolyTailFollow(AActor *actor, double dist) -{ - AActor *child; - DAngle an; - double oldDistance, newDistance; - - while (actor) - { - child = actor->tracer; - if (child) - { - an = actor->AngleTo(child); - oldDistance = child->Distance2D(actor); - if (P_TryMove(child, actor->Pos().XY() + an.ToVector(dist), true)) - { - newDistance = child->Distance2D(actor) - 1; - if (oldDistance < 1) - { - if (child->Z() < actor->Z()) - { - child->SetZ(actor->Z() - dist); - } - else - { - child->SetZ(actor->Z() + dist); - } - } - else - { - child->SetZ(actor->Z() + (newDistance * (child->Z() - actor->Z()) / oldDistance)); - } - } - } - actor = child; - dist -= 1; - } -} - -//============================================================================ -// -// CHolyTailRemove -// -//============================================================================ - -static void CHolyTailRemove (AActor *actor) -{ - AActor *next; - - while (actor) - { - next = actor->tracer; - actor->Destroy (); - actor = next; - } -} - -//============================================================================ -// -// A_CHolyTail -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_CHolyTail) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *parent; - - parent = self->target; - - 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 0; - } - else - { - if (P_TryMove(self, parent->Vec2Angle(14., parent->Angles.Yaw, true), true)) - { - self->SetZ(parent->Z() - 5.); - } - CHolyTailFollow(self, 10); - } - return 0; -} - //============================================================================ // // CHolyFindTarget @@ -495,22 +171,3 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolyCheckScream) return 0; } -//============================================================================ -// -// A_ClericAttack -// (for the ClericBoss) -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_ClericAttack) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (!self->target) return 0; - - AActor * missile = P_SpawnMissileZ (self, self->Z() + 40., 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_hexenglobal.h b/src/g_hexen/a_hexenglobal.h index 3455b684d..dc174b32a 100644 --- a/src/g_hexen/a_hexenglobal.h +++ b/src/g_hexen/a_hexenglobal.h @@ -5,14 +5,6 @@ void AdjustPlayerAngle(AActor *pmo, FTranslatedLineTarget *t); -class AHolySpirit : public AActor -{ - DECLARE_CLASS (AHolySpirit, AActor) -public: - bool Slam (AActor *thing); - bool SpecialBlastHandling (AActor *source, double strength); -}; - class AFighterWeapon : public AWeapon { DECLARE_CLASS (AFighterWeapon, AWeapon); diff --git a/src/g_hexen/a_korax.cpp b/src/g_hexen/a_korax.cpp index 2824d8c0a..8a459ffd4 100644 --- a/src/g_hexen/a_korax.cpp +++ b/src/g_hexen/a_korax.cpp @@ -189,8 +189,11 @@ void KSpiritInit (AActor *spirit, AActor *korax) spirit->args[0] = 10; // initial turn value spirit->args[1] = 0; // initial look angle +#if 0 // Temporarily deactivated. // Spawn a tail for spirit - SpawnSpiritTail (spirit); + HolyTail.SpawnSpiritTail (spirit); +#endif + } //============================================================================ diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index ee68a16db..b026a61d7 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -1324,6 +1324,27 @@ PalEntry AInventory::GetBlend () return 0; } +DEFINE_ACTION_FUNCTION(AInventory, GetBlend) +{ + PARAM_SELF_PROLOGUE(AInventory); + ACTION_RETURN_INT(self->GetBlend()); +} + +PalEntry AInventory::CallGetBlend() +{ + IFVIRTUAL(AInventory, GetBlend) + { + VMValue params[1] = { (DObject*)this }; + VMReturn ret; + VMFrameStack stack; + int retval; + ret.IntAt(&retval); + stack.Call(func, params, 1, &ret, 1, nullptr); + return retval; + } + else return GetBlend(); +} + //=========================================================================== // // AInventory :: PrevItem diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index f035efeea..bd252437d 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -215,6 +215,7 @@ public: virtual int AlterWeaponSprite (visstyle_t *vis); virtual PalEntry GetBlend (); + PalEntry CallGetBlend(); protected: virtual bool TryPickup (AActor *&toucher); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index e9c6a2980..7e9b8a96b 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3284,6 +3284,13 @@ void AActor::Howl () } } +DEFINE_ACTION_FUNCTION(AActor, Howl) +{ + PARAM_SELF_PROLOGUE(AActor); + self->Howl(); + return 0; +} + bool AActor::Slam (AActor *thing) { flags &= ~MF_SKULLFLY; @@ -3367,8 +3374,7 @@ bool AActor::AdjustReflectionAngle (AActor *thing, DAngle &angle) if (absangle(angle, thing->Angles.Yaw) > 45) return true; // Let missile explode - if (thing->IsKindOf (RUNTIME_CLASS(AHolySpirit))) // shouldn't this be handled by another flag??? - return true; + if (thing->flags7 & MF7_NOSHIELDREFLECT) return true; if (pr_reflect () < 128) angle += 45; @@ -7349,6 +7355,16 @@ DEFINE_ACTION_FUNCTION(AActor, SetXYZ) return 0; } +DEFINE_ACTION_FUNCTION(AActor, Vec2Angle) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(length); + PARAM_ANGLE(angle); + PARAM_BOOL_DEF(absolute); + ACTION_RETURN_VEC2(self->Vec2Angle(length, angle, absolute)); +} + + DEFINE_ACTION_FUNCTION(AActor, Vec3Angle) { PARAM_SELF_PROLOGUE(AActor); diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 8a5eddd2d..4562f3ef7 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -6969,13 +6969,19 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) switch (MethodName) { + case NAME_Color: + if (ArgList.Size() == 3 || ArgList.Size() == 4) + { + func = new FxColorLiteral(ArgList, ScriptPosition); + break; + } + // fall through case NAME_Bool: case NAME_Int: case NAME_uInt: case NAME_Float: case NAME_Double: case NAME_Name: - case NAME_Color: case NAME_Sound: case NAME_State: case NAME_SpriteID: @@ -8090,6 +8096,76 @@ ExpEmit FxGetClass::Emit(VMFunctionBuilder *build) return to; } +//========================================================================== +// +// +//========================================================================== + +FxColorLiteral::FxColorLiteral(FArgumentList &args, FScriptPosition &sc) + :FxExpression(EFX_ColorLiteral, sc) +{ + ArgList = std::move(args); +} + +FxExpression *FxColorLiteral::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + unsigned constelements = 0; + assert(ArgList.Size() == 3 || ArgList.Size() == 4); + if (ArgList.Size() == 3) ArgList.Insert(0, nullptr); + for (int i = 0; i < 4; i++) + { + if (ArgList[i] != nullptr) + { + SAFE_RESOLVE(ArgList[i], ctx); + if (!ArgList[i]->IsInteger()) + { + ScriptPosition.Message(MSG_ERROR, "Integer expected for color component"); + delete this; + return nullptr; + } + if (ArgList[i]->isConstant()) + { + constval += clamp(static_cast(ArgList[i])->GetValue().GetInt(), 0, 255) << (24 - i * 8); + delete ArgList[i]; + ArgList[i] = nullptr; + constelements++; + } + } + else constelements++; + } + if (constelements == 4) + { + auto x = new FxConstant(constval, ScriptPosition); + x->ValueType = TypeColor; + delete this; + return x; + } + ValueType = TypeColor; + return this; +} + +ExpEmit FxColorLiteral::Emit(VMFunctionBuilder *build) +{ + ExpEmit out(build, REGT_INT); + build->Emit(OP_LK, out.RegNum, build->GetConstantInt(constval)); + for (int i = 0; i < 4; i++) + { + if (ArgList[i] != nullptr) + { + assert(!ArgList[i]->isConstant()); + ExpEmit in = ArgList[i]->Emit(build); + in.Free(build); + ExpEmit work(build, REGT_INT); + build->Emit(OP_MAX_RK, work.RegNum, in.RegNum, build->GetConstantInt(0)); + build->Emit(OP_MIN_RK, work.RegNum, work.RegNum, build->GetConstantInt(255)); + if (i != 3) build->Emit(OP_SLL_RI, work.RegNum, work.RegNum, 24 - (i * 8)); + build->Emit(OP_OR_RR, out.RegNum, out.RegNum, work.RegNum); + } + } + return out; +} + //========================================================================== // // FxSequence :: Resolve diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index d7547a198..1110cd6b6 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -287,6 +287,7 @@ enum EFxType EFX_CVar, EFX_NamedNode, EFX_GetClass, + EFX_ColorLiteral, EFX_COUNT }; @@ -1540,6 +1541,24 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// FxColorLiteral +// +//========================================================================== + +class FxColorLiteral : public FxExpression +{ + FArgumentList ArgList; + int constval = 0; + +public: + + FxColorLiteral(FArgumentList &args, FScriptPosition &sc); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxVMFunctionCall diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index a6c9ff9f1..7a3d3a7c6 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -296,6 +296,7 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(MF7, NOKILLSCRIPTS, AActor, flags7), DEFINE_FLAG(MF7, SPRITEANGLE, AActor, flags7), DEFINE_FLAG(MF7, SMASHABLE, AActor, flags7), + DEFINE_FLAG(MF7, NOSHIELDREFLECT, AActor, flags7), // Effect flags DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), diff --git a/src/scripting/zscript/zcc-parse.lemon b/src/scripting/zscript/zcc-parse.lemon index 379d1516e..d22746cf8 100644 --- a/src/scripting/zscript/zcc-parse.lemon +++ b/src/scripting/zscript/zcc-parse.lemon @@ -740,7 +740,7 @@ type_name(X) ::= DOT dottable_id(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 VECTOR2 VECTOR3 NAME MAP ARRAY VOID STATE. + SBYTE BYTE SHORT USHORT INT UINT BOOL FLOAT DOUBLE STRING VECTOR2 VECTOR3 NAME MAP ARRAY VOID STATE COLOR UINT8 INT8 UINT16 INT16. /* Aggregate types */ %type aggregate_type {ZCC_Type *} diff --git a/src/v_blend.cpp b/src/v_blend.cpp index c13ed547c..ffc16cd5c 100644 --- a/src/v_blend.cpp +++ b/src/v_blend.cpp @@ -104,7 +104,7 @@ void V_AddPlayerBlend (player_t *CPlayer, float blend[4], float maxinvalpha, int // [RH] All powerups can affect the screen blending now for (AInventory *item = CPlayer->mo->Inventory; item != NULL; item = item->Inventory) { - PalEntry color = item->GetBlend (); + PalEntry color = item->CallGetBlend (); if (color.a != 0) { V_AddBlend (color.r/255.f, color.g/255.f, color.b/255.f, color.a/255.f, blend); diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 62d88237f..ccf3fb374 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -339,6 +339,7 @@ class Actor : Thinker native native void SetZ(double z); native vector3 Vec3Offset(double x, double y, double z, bool absolute = false); native vector3 Vec3Angle(double length, double angle, double z = 0, bool absolute = false); + native vector2 Vec2Angle(double length, double angle, bool absolute = false); native vector3 Vec2OffsetZ(double x, double y, double atz, bool absolute = false); native void VelFromAngle(double speed = 0, double angle = 0); native void Thrust(double speed = 0, double angle = 0); @@ -351,6 +352,7 @@ class Actor : Thinker native native double DistanceBySpeed(Actor other, double speed); native name GetSpecies(); native void PlayActiveSound(); + native void Howl(); // DECORATE compatible functions native bool CheckClass(class checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false); diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index eadf30bc7..5f86282a8 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -1007,3 +1007,11 @@ enum EGameType GAME_DoomChex = GAME_Doom|GAME_Chex, GAME_DoomStrifeChex = GAME_Doom|GAME_Strife|GAME_Chex } + +enum PaletteFlashFlags +{ + PF_HEXENWEAPONS = 1, + PF_POISON = 2, + PF_ICE = 4, + PF_HAZARD = 8, +}; diff --git a/wadsrc/static/zscript/hexen/clericboss.txt b/wadsrc/static/zscript/hexen/clericboss.txt index a2019bae5..4bf223517 100644 --- a/wadsrc/static/zscript/hexen/clericboss.txt +++ b/wadsrc/static/zscript/hexen/clericboss.txt @@ -18,8 +18,6 @@ class ClericBoss : Actor Obituary "$OBCBOSS"; } - native void A_ClericAttack(); - States { Spawn: @@ -79,4 +77,19 @@ class ClericBoss : Actor FDTH V 4 Bright ; Stop; } + + //============================================================================ + // + // A_ClericAttack + // + //============================================================================ + + void A_ClericAttack() + { + if (!target) return; + + Actor missile = SpawnMissileZ (pos.z + 40., target, "HolyMissile"); + if (missile != null) missile.tracer = null; // No initial target + A_PlaySound ("HolySymbolFire", CHAN_WEAPON); + } } diff --git a/wadsrc/static/zscript/hexen/clericholy.txt b/wadsrc/static/zscript/hexen/clericholy.txt index 1a4372f4d..593462d00 100644 --- a/wadsrc/static/zscript/hexen/clericholy.txt +++ b/wadsrc/static/zscript/hexen/clericholy.txt @@ -76,8 +76,10 @@ class WraithvergeDrop : Actor // Cleric's Wraithverge (Holy Symbol?) -------------------------------------- -class CWeapWraithverge : ClericWeapon native +class CWeapWraithverge : ClericWeapon { + int CHolyCount; + Default { Health 3; @@ -96,8 +98,6 @@ class CWeapWraithverge : ClericWeapon native Inventory.PickupSound "WeaponBuild"; } - action native void A_CHolyAttack(); - action native void A_CHolyPalette(); States { @@ -122,6 +122,66 @@ class CWeapWraithverge : ClericWeapon native CHLY G 2 Offset (0, 36) A_CHolyPalette; Goto Ready; } + + override color GetBlend () + { + if (paletteflash & PF_HEXENWEAPONS) + { + if (CHolyCount == 3) + return Color(128, 70, 70, 70); + else if (CHolyCount == 2) + return Color(128, 100, 100, 100); + else if (CHolyCount == 1) + return Color(128, 130, 130, 130); + else + return Color(0, 0, 0, 0); + } + else + { + return Color(CHolyCount * 128 / 3, 131, 131, 131); + } + } + + //============================================================================ + // + // A_CHolyAttack + // + //============================================================================ + + action void A_CHolyAttack() + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + Actor missile = SpawnPlayerMissile ("HolyMissile", angle, pLineTarget:t); + if (missile != null && !t.unlinked) + { + missile.tracer = t.linetarget; + } + + invoker.CHolyCount = 3; + A_PlaySound ("HolySymbolFire", CHAN_WEAPON); + } + + //============================================================================ + // + // A_CHolyPalette + // + //============================================================================ + + action void A_CHolyPalette() + { + if (invoker.CHolyCount > 0) invoker.CHolyCount--; + } } // Holy Missile ------------------------------------------------------------- @@ -139,8 +199,6 @@ class HolyMissile : Actor +EXTREMEDEATH } - native void A_CHolyAttack2(); - States { Spawn: @@ -149,6 +207,60 @@ class HolyMissile : Actor SPIR P 1 Bright A_CHolyAttack2; Stop; } + + //============================================================================ + // + // A_CHolyAttack2 + // + // Spawns the spirits + //============================================================================ + + void A_CHolyAttack2() + { + for (int j = 0; j < 4; j++) + { + Actor mo = Spawn("HolySpirit", Pos, ALLOW_REPLACE); + if (!mo) + { + continue; + } + switch (j) + { // float bob index + + case 0: + mo.WeaveIndexZ = random[HolyAtk2]() & 7; // upper-left + break; + case 1: + mo.WeaveIndexZ = 32 + (random[HolyAtk2]() & 7); // upper-right + break; + case 2: + mo.WeaveIndexXY = 32 + (random[HolyAtk2]() & 7); // lower-left + break; + case 3: + mo.WeaveIndexXY = 32 + (random[HolyAtk2]() & 7); + mo.WeaveIndexZ = 32 + (random[HolyAtk2]() & 7); + break; + } + mo.SetZ(pos.z); + mo.angle = angle + 67.5 - 45.*j; + mo.Thrust(); + mo.target = target; + mo.args[0] = 10; // initial turn value + mo.args[1] = 0; // initial look angle + if (deathmatch) + { // Ghosts last slightly less longer in DeathMatch + mo.health = 85; + } + if (tracer) + { + mo.tracer = tracer; + mo.bNoClip = true; + mo.bSkullFly = true; + mo.bMissile = false; + } + HolyTail.SpawnSpiritTail (mo); + } + } } // Holy Missile Puff -------------------------------------------------------- @@ -192,7 +304,7 @@ class HolyPuff : Actor // Holy Spirit -------------------------------------------------------------- -class HolySpirit : Actor native +class HolySpirit : Actor { Default { @@ -204,7 +316,7 @@ class HolySpirit : Actor native Projectile; +RIPPER +SEEKERMISSILE +FOILINVUL +SKYEXPLODE +NOEXPLODEFLOOR +CANBLAST - +EXTREMEDEATH + +EXTREMEDEATH +NOSHIELDREFLECT RenderStyle "Translucent"; Alpha 0.4; DeathSound "SpiritDie"; @@ -226,6 +338,70 @@ class HolySpirit : Actor native SPIR FGHI 4; Stop; } + + //============================================================================ + // + // + // + //============================================================================ + + override bool Slam(Actor thing) + { + if (thing.bShootable && thing != target) + { + if (multiplayer && !deathmatch && thing.player && target.player) + { // don't attack other co-op players + return true; + } + if (thing.bReflective && (thing.player || thing.bBoss)) + { + tracer = target; + target = thing; + return true; + } + if (thing.bIsMonster || thing.player) + { + tracer = thing; + } + if (random[SpiritSlam]() < 96) + { + int dam = 12; + if (thing.player || thing.bBoss) + { + dam = 3; + // ghost burns out faster when attacking players/bosses + health -= 6; + } + thing.DamageMobj(self, target, dam, 'Melee'); + if (random[SpiritSlam]() < 128) + { + Spawn("HolyPuff", Pos, ALLOW_REPLACE); + A_PlaySound("SpiritAttack", CHAN_WEAPON); + if (thing.bIsMonster && random[SpiritSlam]() < 128) + { + thing.Howl(); + } + } + } + if (thing.health <= 0) + { + tracer = null; + } + } + return true; + } + + override bool SpecialBlastHandling (Actor source, double strength) + { + if (tracer == source) + { + tracer = target; + target = source; + } + return true; + } + + } // Holy Tail ---------------------------------------------------------------- @@ -242,8 +418,6 @@ class HolyTail : Actor Alpha 0.6; } - native void A_CHolyTail(); - States { Spawn: @@ -253,6 +427,108 @@ class HolyTail : Actor SPIR D -1; Stop; } + + //============================================================================ + // + // SpawnSpiritTail + // + //============================================================================ + + static void SpawnSpiritTail (Actor spirit) + { + Actor tail = Spawn ("HolyTail", spirit.Pos, ALLOW_REPLACE); + tail.target = spirit; // parent + for (int i = 1; i < 3; i++) + { + Actor next = Spawn ("HolyTailTrail", spirit.Pos, ALLOW_REPLACE); + tail.tracer = next; + tail = next; + } + tail.tracer = null; // last tail bit + } + + //============================================================================ + // + // CHolyTailFollow + // + //============================================================================ + + private void CHolyTailFollow(double dist) + { + Actor mo = self; + while (mo) + { + Actor child = mo.tracer; + if (child) + { + double an = mo.AngleTo(child); + double oldDistance = child.Distance2D(mo); + if (child.TryMove(mo.Pos.XY + AngleToVector(an, dist), true)) + { + double newDistance = child.Distance2D(mo) - 1; + if (oldDistance < 1) + { + if (child.pos.z < mo.pos.z) + { + child.SetZ(mo.pos.z - dist); + } + else + { + child.SetZ(mo.pos.z + dist); + } + } + else + { + child.SetZ(mo.pos.z + (newDistance * (child.pos.z - mo.pos.z) / oldDistance)); + } + } + } + mo = child; + dist -= 1; + } + } + + //============================================================================ + // + // CHolyTailRemove + // + //============================================================================ + + private void CHolyTailRemove () + { + Actor mo = self; + while (mo) + { + Actor next = mo.tracer; + mo.Destroy (); + mo = next; + } + } + + //============================================================================ + // + // A_CHolyTail + // + //============================================================================ + + void A_CHolyTail() + { + Actor parent = self.target; + + if (parent == null || parent.health <= 0) // better check for health than current state - it's safer! + { // Ghost removed, so remove all tail parts + CHolyTailRemove (); + return; + } + else + { + if (TryMove(parent.Vec2Angle(14., parent.Angle, true), true)) + { + self.SetZ(parent.pos.z - 5.); + } + CHolyTailFollow(10); + } + } } // Holy Tail Trail --------------------------------------------------------- diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index c2c99453f..f87331470 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -26,6 +26,7 @@ class Inventory : Actor native } virtual native bool Use (bool pickup); + virtual native color GetBlend (); // These are regular functions for the item itself. From 4fcb397346b1ffd1a68eb8777a40d89086b20940 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 26 Nov 2016 14:06:41 +0100 Subject: [PATCH 119/185] - scriptified the remaining parts of the Wraithverge. --- src/CMakeLists.txt | 1 - src/g_hexen/a_clericholy.cpp | 173 --------------------- src/g_hexen/a_hexenmisc.cpp | 1 - wadsrc/static/zscript/hexen/clericholy.txt | 142 ++++++++++++++++- 4 files changed, 136 insertions(+), 181 deletions(-) delete mode 100644 src/g_hexen/a_clericholy.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 376d33887..c1242853d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -855,7 +855,6 @@ set( NOT_COMPILED_SOURCE_FILES ${OTHER_SYSTEM_SOURCES} sc_man_scanner.h sc_man_scanner.re - g_hexen/a_clericholy.cpp g_hexen/a_clericmace.cpp g_hexen/a_clericstaff.cpp g_hexen/a_fighteraxe.cpp diff --git a/src/g_hexen/a_clericholy.cpp b/src/g_hexen/a_clericholy.cpp deleted file mode 100644 index 8ffb5be27..000000000 --- a/src/g_hexen/a_clericholy.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/* -#include "actor.h" -#include "info.h" -#include "p_local.h" -#include "m_random.h" -#include "s_sound.h" -#include "a_hexenglobal.h" -#include "gstrings.h" -#include "a_weaponpiece.h" -#include "vm.h" -#include "g_level.h" -#include "doomstat.h" -*/ - -#define BLAST_FULLSTRENGTH 255 - -static FRandom pr_holyatk2 ("CHolyAtk2"); -static FRandom pr_holyseeker ("CHolySeeker"); -static FRandom pr_holyweave ("CHolyWeave"); -static FRandom pr_holyseek ("CHolySeek"); -static FRandom pr_checkscream ("CCheckScream"); -static FRandom pr_spiritslam ("CHolySlam"); -static FRandom pr_wraithvergedrop ("WraithvergeDrop"); - -void SpawnSpiritTail (AActor *spirit); - -// Holy Spirit -------------------------------------------------------------- - -//============================================================================ -// -// CHolyFindTarget -// -//============================================================================ - -static void CHolyFindTarget (AActor *actor) -{ - AActor *target; - - if ( (target = P_RoughMonsterSearch (actor, 6, true)) ) - { - actor->tracer = target; - actor->flags |= MF_NOCLIP|MF_SKULLFLY; - actor->flags &= ~MF_MISSILE; - } -} - -//============================================================================ -// -// CHolySeekerMissile -// -// Similar to P_SeekerMissile, but seeks to a random Z on the target -//============================================================================ - -static void CHolySeekerMissile (AActor *actor, DAngle thresh, DAngle turnMax) -{ - int dir; - DAngle delta; - AActor *target; - double newZ; - double deltaZ; - - target = actor->tracer; - if (target == NULL) - { - return; - } - if (!(target->flags&MF_SHOOTABLE) - || (!(target->flags3&MF3_ISMONSTER) && !target->player)) - { // Target died/target isn't a player or creature - actor->tracer = NULL; - actor->flags &= ~(MF_NOCLIP | MF_SKULLFLY); - actor->flags |= MF_MISSILE; - CHolyFindTarget(actor); - return; - } - dir = P_FaceMobj (actor, target, &delta); - if (delta > thresh) - { - delta /= 2; - if (delta > turnMax) - { - delta = turnMax; - } - } - if (dir) - { // Turn clockwise - actor->Angles.Yaw += delta; - } - else - { // Turn counter clockwise - actor->Angles.Yaw -= delta; - } - actor->VelFromAngle(); - - if (!(level.time&15) - || actor->Z() > target->Top() - || actor->Top() < target->Z()) - { - newZ = target->Z() + ((pr_holyseeker()*target->Height) / 256.); - deltaZ = newZ - actor->Z(); - if (fabs(deltaZ) > 15) - { - if (deltaZ > 0) - { - deltaZ = 15; - } - else - { - deltaZ = -15; - } - } - actor->Vel.Z = deltaZ / actor->DistanceBySpeed(target, actor->Speed); - } - return; -} - -//============================================================================ -// -// A_CHolySeek -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_CHolySeek) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->health--; - if (self->health <= 0) - { - self->Vel.X /= 4; - self->Vel.Y /= 4; - self->Vel.Z = 0; - self->SetState (self->FindState(NAME_Death)); - self->tics -= pr_holyseek()&3; - return 0; - } - if (self->tracer) - { - CHolySeekerMissile (self, (double)self->args[0], self->args[0]*2.); - if (!((level.time+7)&15)) - { - self->args[0] = 5+(pr_holyseek()/20); - } - } - - int xyspeed = (pr_holyweave() % 5); - int zspeed = (pr_holyweave() % 5); - A_Weave(self, xyspeed, zspeed, 4., 2.); - return 0; -} - -//============================================================================ -// -// A_CHolyCheckScream -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_CHolyCheckScream) -{ - PARAM_SELF_PROLOGUE(AActor); - - CALL_ACTION(A_CHolySeek, self); - if (pr_checkscream() < 20) - { - S_Sound (self, CHAN_VOICE, "SpiritActive", 1, ATTN_NORM); - } - if (!self->tracer) - { - CHolyFindTarget(self); - } - return 0; -} - diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp index cbe9d3c12..7bd38ceab 100644 --- a/src/g_hexen/a_hexenmisc.cpp +++ b/src/g_hexen/a_hexenmisc.cpp @@ -24,7 +24,6 @@ #include "serializer.h" // Include all the Hexen stuff here to reduce compile time -#include "a_clericholy.cpp" #include "a_clericmace.cpp" #include "a_clericstaff.cpp" #include "a_fighteraxe.cpp" diff --git a/wadsrc/static/zscript/hexen/clericholy.txt b/wadsrc/static/zscript/hexen/clericholy.txt index 593462d00..33b69bf25 100644 --- a/wadsrc/static/zscript/hexen/clericholy.txt +++ b/wadsrc/static/zscript/hexen/clericholy.txt @@ -323,9 +323,6 @@ class HolySpirit : Actor Obituary "$OB_MPCWEAPWRAITHVERGE"; } - native void A_CHolySeek(); - native void A_CHolyCheckScream(); - States { Spawn: @@ -401,7 +398,140 @@ class HolySpirit : Actor return true; } - + //============================================================================ + // + // CHolyFindTarget + // + //============================================================================ + + private void CHolyFindTarget () + { + Actor target; + + if ( (target = RoughMonsterSearch (6, true)) ) + { + tracer = target; + bNoClip = true; + bSkullFly = true; + bMissile = false; + } + } + + //============================================================================ + // + // CHolySeekerMissile + // + // Similar to P_SeekerMissile, but seeks to a random Z on the target + //============================================================================ + + private void CHolySeekerMissile (double thresh, double turnMax) + { + Actor target = tracer; + if (target == NULL) + { + return; + } + if (!target.bShootable || (!target.bIsMonster && !target.player)) + { // Target died/target isn't a player or creature + tracer = null; + bNoClip = false; + bSkullFly = false; + bMissile = true; + CHolyFindTarget(); + return; + } + double ang = deltaangle(angle, AngleTo(target)); + double delta = abs(ang); + + if (delta > thresh) + { + delta /= 2; + if (delta > turnMax) + { + delta = turnMax; + } + } + if (ang > 0) + { // Turn clockwise + angle += delta; + } + else + { // Turn counter clockwise + angle -= delta; + } + VelFromAngle(); + + if (!(level.time&15) + || pos.z > target.pos.z + target.height + || pos.z + height < target.pos.z) + { + double newZ = target.pos.z + ((random[HolySeeker]()*target.Height) / 256.); + double deltaZ = newZ - pos.z; + if (abs(deltaZ) > 15) + { + if (deltaZ > 0) + { + deltaZ = 15; + } + else + { + deltaZ = -15; + } + } + Vel.Z = deltaZ / DistanceBySpeed(target, Speed); + } + } + + //============================================================================ + // + // A_CHolySeek + // + //============================================================================ + + void A_CHolySeek() + { + health--; + if (health <= 0) + { + Vel.X /= 4; + Vel.Y /= 4; + Vel.Z = 0; + SetStateLabel ("Death"); + tics -= random[HolySeeker]()&3; + return; + } + if (tracer) + { + CHolySeekerMissile (args[0], args[0]*2.); + if (!((level.time+7)&15)) + { + args[0] = 5+(random[HolySeeker]()/20); + } + } + + int xyspeed = (random[HolySeeker]() % 5); + int zspeed = (random[HolySeeker]() % 5); + A_Weave(xyspeed, zspeed, 4., 2.); + } + + //============================================================================ + // + // A_CHolyCheckScream + // + //============================================================================ + + void A_CHolyCheckScream() + { + A_CHolySeek(); + if (random[HolyScream]() < 20) + { + A_PlaySound ("SpiritActive", CHAN_VOICE); + } + if (!tracer) + { + CHolyFindTarget(); + } + } } // Holy Tail ---------------------------------------------------------------- @@ -513,7 +643,7 @@ class HolyTail : Actor void A_CHolyTail() { - Actor parent = self.target; + Actor parent = target; if (parent == null || parent.health <= 0) // better check for health than current state - it's safer! { // Ghost removed, so remove all tail parts @@ -524,7 +654,7 @@ class HolyTail : Actor { if (TryMove(parent.Vec2Angle(14., parent.Angle, true), true)) { - self.SetZ(parent.pos.z - 5.); + SetZ(parent.pos.z - 5.); } CHolyTailFollow(10); } From 659a592f16829ac7ec643af7a13ac0ad885ccc02 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 26 Nov 2016 16:25:10 +0100 Subject: [PATCH 120/185] - scriptified Korax. --- src/CMakeLists.txt | 1 - src/g_hexen/a_hexenmisc.cpp | 1 - src/g_hexen/a_korax.cpp | 502 -------------------------- wadsrc/static/zscript/hexen/korax.txt | 428 +++++++++++++++++++++- 4 files changed, 413 insertions(+), 519 deletions(-) delete mode 100644 src/g_hexen/a_korax.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c1242853d..828c7fc34 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -867,7 +867,6 @@ set( NOT_COMPILED_SOURCE_FILES g_hexen/a_heresiarch.cpp g_hexen/a_hexenspecialdecs.cpp g_hexen/a_iceguy.cpp - g_hexen/a_korax.cpp g_hexen/a_magecone.cpp g_hexen/a_magelightning.cpp g_hexen/a_magestaff.cpp diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp index 7bd38ceab..3fb334cb1 100644 --- a/src/g_hexen/a_hexenmisc.cpp +++ b/src/g_hexen/a_hexenmisc.cpp @@ -36,7 +36,6 @@ #include "a_heresiarch.cpp" #include "a_hexenspecialdecs.cpp" #include "a_iceguy.cpp" -#include "a_korax.cpp" #include "a_magecone.cpp" #include "a_magelightning.cpp" #include "a_magestaff.cpp" diff --git a/src/g_hexen/a_korax.cpp b/src/g_hexen/a_korax.cpp deleted file mode 100644 index 8a459ffd4..000000000 --- a/src/g_hexen/a_korax.cpp +++ /dev/null @@ -1,502 +0,0 @@ -//=========================================================================== -// Korax Variables -// tracer last teleport destination -// special2 set if "below half" script not yet run -// -// Korax Scripts (reserved) -// 249 Tell scripts that we are below half health -// 250-254 Control scripts (254 is only used when less than half health) -// 255 Death script -// -// Korax TIDs (reserved) -// 245 Reserved for Korax himself -// 248 Initial teleport destination -// 249 Teleport destination -// 250-254 For use in respective control scripts -// 255 For use in death script (spawn spots) -//=========================================================================== - -/* -#include "actor.h" -#include "info.h" -#include "p_local.h" -#include "p_spec.h" -#include "s_sound.h" -#include "a_action.h" -#include "m_random.h" -#include "i_system.h" -#include "vm.h" -#include "g_level.h" -*/ - -const int KORAX_SPIRIT_LIFETIME = 5*TICRATE/5; // 5 seconds -const int KORAX_COMMAND_HEIGHT = 120; -const int KORAX_COMMAND_OFFSET = 27; - -const int KORAX_TID = 245; -const int KORAX_FIRST_TELEPORT_TID = 248; -const int KORAX_TELEPORT_TID = 249; - -const int KORAX_DELTAANGLE = 85; -const int KORAX_ARM_EXTENSION_SHORT = 40; -const int KORAX_ARM_EXTENSION_LONG = 55; - -const int KORAX_ARM1_HEIGHT = 108; -const int KORAX_ARM2_HEIGHT = 82; -const int KORAX_ARM3_HEIGHT = 54; -const int KORAX_ARM4_HEIGHT = 104; -const int KORAX_ARM5_HEIGHT = 86; -const int KORAX_ARM6_HEIGHT = 53; - -const double KORAX_BOLT_HEIGHT = 48.; -const int KORAX_BOLT_LIFETIME = 3; - - - -static FRandom pr_koraxchase ("KoraxChase"); -static FRandom pr_kspiritinit ("KSpiritInit"); -static FRandom pr_koraxdecide ("KoraxDecide"); -static FRandom pr_koraxmissile ("KoraxMissile"); -static FRandom pr_koraxcommand ("KoraxCommand"); -static FRandom pr_kspiritweave ("KSpiritWeave"); -static FRandom pr_kspiritseek ("KSpiritSeek"); -static FRandom pr_kspiritroam ("KSpiritRoam"); -static FRandom pr_kmissile ("SKoraxMissile"); - -void A_KoraxChase (AActor *); -void A_KoraxStep (AActor *); -void A_KoraxStep2 (AActor *); -void A_KoraxDecide (AActor *); -void A_KoraxBonePop (AActor *); -void A_KoraxMissile (AActor *); -void A_KoraxCommand (AActor *); -void A_KSpiritRoam (AActor *); -void A_KBolt (AActor *); -void A_KBoltRaise (AActor *); - -void KoraxFire (AActor *actor, PClassActor *type, int arm); -void KSpiritInit (AActor *spirit, AActor *korax); -AActor *P_SpawnKoraxMissile (const DVector3 &pos, AActor *source, AActor *dest, PClassActor *type); - -extern void SpawnSpiritTail (AActor *spirit); - -//============================================================================ -// -// A_KoraxChase -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_KoraxChase) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *spot; - - if ((!self->special2) && (self->health <= (self->SpawnHealth()/2))) - { - FActorIterator iterator (KORAX_FIRST_TELEPORT_TID); - spot = iterator.Next (); - if (spot != NULL) - { - P_Teleport (self, spot->PosAtZ(ONFLOORZ), spot->Angles.Yaw, TELF_SOURCEFOG | TELF_DESTFOG); - } - - P_StartScript (self, NULL, 249, NULL, NULL, 0, 0); - self->special2 = 1; // Don't run again - - return 0; - } - - if (self->target == NULL) - { - return 0; - } - if (pr_koraxchase()<30) - { - self->SetState (self->MissileState); - } - else if (pr_koraxchase()<30) - { - S_Sound (self, CHAN_VOICE, "KoraxActive", 1, ATTN_NONE); - } - - // Teleport away - if (self->health < (self->SpawnHealth()>>1)) - { - if (pr_koraxchase()<10) - { - FActorIterator iterator (KORAX_TELEPORT_TID); - - if (self->tracer != NULL) - { // Find the previous teleport destination - do - { - spot = iterator.Next (); - } while (spot != NULL && spot != self->tracer); - } - - // Go to the next teleport destination - spot = iterator.Next (); - self->tracer = spot; - if (spot) - { - P_Teleport (self, spot->PosAtZ(ONFLOORZ), spot->Angles.Yaw, TELF_SOURCEFOG | TELF_DESTFOG); - } - } - } - return 0; -} - -//============================================================================ -// -// A_KoraxBonePop -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_KoraxBonePop) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo; - int i; - - // Spawn 6 spirits equalangularly - for (i = 0; i < 6; ++i) - { - mo = P_SpawnMissileAngle (self, PClass::FindActor("KoraxSpirit"), DAngle(60.*i), 5.); - if (mo) - { - KSpiritInit (mo, self); - } - } - - P_StartScript (self, NULL, 255, NULL, NULL, 0, 0); // Death script - return 0; -} - -//============================================================================ -// -// KSpiritInit -// -//============================================================================ - -void KSpiritInit (AActor *spirit, AActor *korax) -{ - spirit->health = KORAX_SPIRIT_LIFETIME; - - spirit->tracer = korax; // Swarm around korax - spirit->WeaveIndexZ = 32 + (pr_kspiritinit() & 7); // Float bob index - spirit->args[0] = 10; // initial turn value - spirit->args[1] = 0; // initial look angle - -#if 0 // Temporarily deactivated. - // Spawn a tail for spirit - HolyTail.SpawnSpiritTail (spirit); -#endif - -} - -//============================================================================ -// -// A_KoraxDecide -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_KoraxDecide) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (pr_koraxdecide()<220) - { - self->SetState (self->FindState("Attack")); - } - else - { - self->SetState (self->FindState("Command")); - } - return 0; -} - -//============================================================================ -// -// A_KoraxMissile -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_KoraxMissile) -{ - PARAM_SELF_PROLOGUE(AActor); - - static const struct { const char *type, *sound; } choices[6] = - { - { "WraithFX1", "WraithMissileFire" }, - { "Demon1FX1", "DemonMissileFire" }, - { "Demon2FX1", "DemonMissileFire" }, - { "FireDemonMissile", "FireDemonAttack" }, - { "CentaurFX", "CentaurLeaderAttack" }, - { "SerpentFX", "CentaurLeaderAttack" } - }; - - int type = pr_koraxmissile() % 6; - int i; - PClassActor *info; - - S_Sound(self, CHAN_VOICE, "KoraxAttack", 1, ATTN_NORM); - - info = PClass::FindActor(choices[type].type); - if (info == NULL) - { - I_Error("Unknown Korax missile: %s\n", choices[type].type); - } - - // Fire all 6 missiles at once - S_Sound(self, CHAN_WEAPON, choices[type].sound, 1, ATTN_NONE); - for (i = 0; i < 6; ++i) - { - KoraxFire(self, info, i); - } - return 0; -} - -//============================================================================ -// -// A_KoraxCommand -// -// Call action code scripts (250-254) -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_KoraxCommand) -{ - PARAM_SELF_PROLOGUE(AActor); - DAngle ang; - int numcommands; - - S_Sound (self, CHAN_VOICE, "KoraxCommand", 1, ATTN_NORM); - - // Shoot stream of lightning to ceiling - ang = self->Angles.Yaw - 90; - DVector3 pos = self->Vec3Angle(KORAX_COMMAND_OFFSET, ang, KORAX_COMMAND_HEIGHT); - Spawn("KoraxBolt", pos, ALLOW_REPLACE); - - if (self->health <= (self->SpawnHealth() >> 1)) - { - numcommands = 5; - } - else - { - numcommands = 4; - } - - P_StartScript (self, NULL, 250+(pr_koraxcommand()%numcommands), NULL, NULL, 0, 0); - return 0; -} - -//============================================================================ -// -// KoraxFire -// -// Arm projectiles -// arm positions numbered: -// 1 top left -// 2 middle left -// 3 lower left -// 4 top right -// 5 middle right -// 6 lower right -// -//============================================================================ - -void KoraxFire (AActor *actor, PClassActor *type, int arm) -{ - static const int extension[6] = - { - KORAX_ARM_EXTENSION_SHORT, - KORAX_ARM_EXTENSION_LONG, - KORAX_ARM_EXTENSION_LONG, - KORAX_ARM_EXTENSION_SHORT, - KORAX_ARM_EXTENSION_LONG, - KORAX_ARM_EXTENSION_LONG - }; - static const int armheight[6] = - { - KORAX_ARM1_HEIGHT, - KORAX_ARM2_HEIGHT, - KORAX_ARM3_HEIGHT, - KORAX_ARM4_HEIGHT, - KORAX_ARM5_HEIGHT, - KORAX_ARM6_HEIGHT - }; - - DAngle ang = actor->Angles.Yaw + (arm < 3 ? -KORAX_DELTAANGLE : KORAX_DELTAANGLE); - DVector3 pos = actor->Vec3Angle(extension[arm], ang, armheight[arm] - actor->Floorclip); - P_SpawnKoraxMissile (pos, actor, actor->target, type); -} - -//============================================================================ -// -// A_KSpiritSeeker -// -//============================================================================ - -static void A_KSpiritSeeker (AActor *actor, DAngle thresh, DAngle turnMax) -{ - int dir; - DAngle delta; - AActor *target; - double newZ; - double deltaZ; - - target = actor->tracer; - if (target == NULL) - { - return; - } - dir = P_FaceMobj (actor, target, &delta); - if (delta > thresh) - { - delta /= 2; - if(delta > turnMax) - { - delta = turnMax; - } - } - if(dir) - { // Turn clockwise - actor->Angles.Yaw += delta; - } - else - { // Turn counter clockwise - actor->Angles.Yaw -= delta; - } - actor->VelFromAngle(); - - if (!(level.time&15) - || actor->Z() > target->Z() + target->GetDefault()->Height - || actor->Top() < target->Z()) - { - newZ = target->Z() + pr_kspiritseek() * target->GetDefault()->Height / 256; - deltaZ = newZ-actor->Z(); - - if (fabs(deltaZ) > 15) - { - if(deltaZ > 0) - { - deltaZ = 15; - } - else - { - deltaZ = -15; - } - } - actor->Vel.Z = deltaZ + actor->DistanceBySpeed(target, actor->Speed); - } - return; -} - -//============================================================================ -// -// A_KSpiritRoam -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_KSpiritRoam) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (self->health-- <= 0) - { - S_Sound (self, CHAN_VOICE, "SpiritDie", 1, ATTN_NORM); - self->SetState (self->FindState("Death")); - } - else - { - if (self->tracer) - { - A_KSpiritSeeker(self, (double)self->args[0], self->args[0] * 2.); - } - int xyspeed = (pr_kspiritweave() % 5); - int zspeed = (pr_kspiritweave() % 5); - A_Weave(self, xyspeed, zspeed, 4., 2.); - - if (pr_kspiritroam()<50) - { - S_Sound (self, CHAN_VOICE, "SpiritActive", 1, ATTN_NONE); - } - } - return 0; -} - -//============================================================================ -// -// A_KBolt -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_KBolt) -{ - PARAM_SELF_PROLOGUE(AActor); - - // Countdown lifetime - if (self->special1-- <= 0) - { - self->Destroy (); - } - return 0; -} - -//============================================================================ -// -// A_KBoltRaise -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_KBoltRaise) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo; - - // Spawn a child upward - double z = self->Z() + KORAX_BOLT_HEIGHT; - - if ((z + KORAX_BOLT_HEIGHT) < self->ceilingz) - { - mo = Spawn("KoraxBolt", self->PosAtZ(z), ALLOW_REPLACE); - if (mo) - { - mo->special1 = KORAX_BOLT_LIFETIME; - } - } - else - { - // Maybe cap it off here - } - return 0; -} - -//============================================================================ -// -// P_SpawnKoraxMissile -// -//============================================================================ - -AActor *P_SpawnKoraxMissile (const DVector3 &pos, AActor *source, AActor *dest, PClassActor *type) -{ - AActor *th; - DAngle an; - double dist; - - th = Spawn (type, pos, ALLOW_REPLACE); - th->target = source; // Originator - an = th->AngleTo(dest); - if (dest->flags & MF_SHADOW) - { // Invisible target - an += pr_kmissile.Random2() * (45/256.); - } - th->Angles.Yaw = an; - th->VelFromAngle(); - dist = dest->DistanceBySpeed(th, th->Speed); - th->Vel.Z = (dest->Z() - pos.Z + 30) / dist; - return (P_CheckMissileSpawn(th, source->radius) ? th : NULL); -} diff --git a/wadsrc/static/zscript/hexen/korax.txt b/wadsrc/static/zscript/hexen/korax.txt index 16bf172a4..1c1f31712 100644 --- a/wadsrc/static/zscript/hexen/korax.txt +++ b/wadsrc/static/zscript/hexen/korax.txt @@ -1,5 +1,43 @@ +//=========================================================================== +// Korax Variables +// tracer last teleport destination +// special2 set if "below half" script not yet run +// +// Korax Scripts (reserved) +// 249 Tell scripts that we are below half health +// 250-254 Control scripts (254 is only used when less than half health) +// 255 Death script +// +// Korax TIDs (reserved) +// 245 Reserved for Korax himself +// 248 Initial teleport destination +// 249 Teleport destination +// 250-254 For use in respective control scripts +// 255 For use in death script (spawn spots) +//=========================================================================== + class Korax : Actor { + const KORAX_ARM_EXTENSION_SHORT = 40; + const KORAX_ARM_EXTENSION_LONG = 55; + + const KORAX_ARM1_HEIGHT = 108; + const KORAX_ARM2_HEIGHT = 82; + const KORAX_ARM3_HEIGHT = 54; + const KORAX_ARM4_HEIGHT = 104; + const KORAX_ARM5_HEIGHT = 86; + const KORAX_ARM6_HEIGHT = 53; + + const KORAX_FIRST_TELEPORT_TID = 248; + const KORAX_TELEPORT_TID = 249; + + const KORAX_DELTAANGLE = 85; + + const KORAX_COMMAND_HEIGHT = 120; + const KORAX_COMMAND_OFFSET = 27; + + const KORAX_SPIRIT_LIFETIME = 5*TICRATE/5; // 5 seconds + Default { Health 5000; @@ -24,12 +62,6 @@ class Korax : Actor Obituary "$OB_KORAX"; } - native void A_KoraxChase(); - native void A_KoraxDecide(); - native void A_KoraxBonePop(); - native void A_KoraxMissile(); - native void A_KoraxCommand(); - States { Spawn: @@ -39,13 +71,11 @@ class Korax : Actor KORX AAA 3 A_KoraxChase; KORX B 3 A_Chase; KORX BBB 3 A_KoraxChase; - KORX C 0 A_PlaySound("KoraxStep"); - KORX C 3 A_Chase; + KORX C 3 A_KoraxStep; KORX CCC 3 A_KoraxChase; KORX D 3 A_Chase; KORX DDD 3 A_KoraxChase; - KORX A 0 A_PlaySound("KoraxStep"); - KORX A 3 A_Chase; + KORX A 3 A_KoraxStep; Loop; Pain: KORX H 5 A_Pain; @@ -79,6 +109,255 @@ class Korax : Actor KORX E 5 Bright; Goto See; } + + + void A_KoraxStep() + { + A_PlaySound("KoraxStep"); + A_Chase(); + } + + //============================================================================ + // + // A_KoraxChase + // + //============================================================================ + + + void A_KoraxChase() + { + if ((!special2) && (health <= (SpawnHealth()/2))) + { + ActorIterator it = ActorIterator.Create(KORAX_FIRST_TELEPORT_TID); + Actor spot = it.Next (); + if (spot != null) + { + Teleport ((spot.pos.xy, ONFLOORZ), spot.angle, TELF_SOURCEFOG | TELF_DESTFOG); + } + ACS_Execute(249, 0); + special2 = 1; // Don't run again + return; + } + + if (target == null) + { + return; + } + if (random[KoraxChase]() < 30) + { + SetState (MissileState); + } + else if (random[KoraxChase]() < 30) + { + A_PlaySound("KoraxActive", CHAN_VOICE, 1, false, ATTN_NONE); + } + + // Teleport away + if (health < (SpawnHealth() >> 1)) + { + if (random[KoraxChase]() < 10) + { + ActorIterator it = ActorIterator.Create(KORAX_TELEPORT_TID); + Actor spot; + + if (tracer != null) + { // Find the previous teleport destination + do + { + spot = it.Next (); + } while (spot != null && spot != tracer); + } + + // Go to the next teleport destination + spot = it.Next (); + tracer = spot; + if (spot) + { + Teleport ((spot.pos.xy, ONFLOORZ), spot.angle, TELF_SOURCEFOG | TELF_DESTFOG); + } + } + } + } + + //============================================================================ + // + // A_KoraxDecide + // + //============================================================================ + + void A_KoraxDecide() + { + if (random[KoraxDecide]() < 220) + { + SetStateLabel ("Attack"); + } + else + { + SetStateLabel ("Command"); + } + } + + //============================================================================ + // + // A_KoraxBonePop + // + //============================================================================ + + void A_KoraxBonePop() + { + // Spawn 6 spirits equalangularly + for (int i = 0; i < 6; ++i) + { + Actor mo = SpawnMissileAngle ("KoraxSpirit", 60.*i, 5.); + if (mo) + { + KSpiritInit (mo); + } + } + ACS_Execute(255, 0); + } + + //============================================================================ + // + // KSpiritInit + // + //============================================================================ + + private void KSpiritInit (Actor spirit) + { + spirit.health = KORAX_SPIRIT_LIFETIME; + + spirit.tracer = self; // Swarm around korax + spirit.WeaveIndexZ = 32 + (random[Kspiritnit]() & 7); // Float bob index + spirit.args[0] = 10; // initial turn value + spirit.args[1] = 0; // initial look angle + + // Spawn a tail for spirit + HolyTail.SpawnSpiritTail (spirit); + } + + //============================================================================ + // + // A_KoraxMissile + // + //============================================================================ + + void A_KoraxMissile() + { + static const class choices[] = + { + "WraithFX1", "Demon1FX1", "Demon2FX1", "FireDemonMissile", "CentaurFX", "SerpentFX" + }; + static const sound sounds[] = + { + "WraithMissileFire", "DemonMissileFire", "DemonMissileFire", "FireDemonAttack", "CentaurLeaderAttack", "SerpentLeaderAttack" + }; + int type = random[KoraxMissile]() % 6; + + A_PlaySound("KoraxAttack", CHAN_VOICE); + + // Fire all 6 missiles at once + A_PlaySound(sounds[type], CHAN_WEAPON, 1, false, ATTN_NONE); + class info = choices[type]; + for (int i = 0; i < 6; ++i) + { + KoraxFire(info, i); + } + } + + //============================================================================ + // + // KoraxFire + // + // Arm projectiles + // arm positions numbered: + // 1 top left + // 2 middle left + // 3 lower left + // 4 top right + // 5 middle right + // 6 lower right + // + //============================================================================ + + void KoraxFire (Class type, int arm) + { + static const int extension[] = + { + KORAX_ARM_EXTENSION_SHORT, + KORAX_ARM_EXTENSION_LONG, + KORAX_ARM_EXTENSION_LONG, + KORAX_ARM_EXTENSION_SHORT, + KORAX_ARM_EXTENSION_LONG, + KORAX_ARM_EXTENSION_LONG + }; + static const int armheight[] = + { + KORAX_ARM1_HEIGHT, + KORAX_ARM2_HEIGHT, + KORAX_ARM3_HEIGHT, + KORAX_ARM4_HEIGHT, + KORAX_ARM5_HEIGHT, + KORAX_ARM6_HEIGHT + }; + + double ang = angle + (arm < 3 ? -KORAX_DELTAANGLE : KORAX_DELTAANGLE); + Vector3 pos = Vec3Angle(extension[arm], ang, armheight[arm] - Floorclip); + SpawnKoraxMissile (pos, target, type); + } + + //============================================================================ + // + // P_SpawnKoraxMissile + // + //============================================================================ + + private void SpawnKoraxMissile (Vector3 pos, Actor dest, Class type) + { + Actor th = Spawn (type, pos, ALLOW_REPLACE); + th.target = self; // Originator + double an = th.AngleTo(dest); + if (dest.bShadow) + { // Invisible target + an += Random2[KoraxMissile]() * (45/256.); + } + th.angle = an; + th.VelFromAngle(); + double dist = dest.DistanceBySpeed(th, th.Speed); + th.Vel.Z = (dest.pos.z - pos.Z + 30) / dist; + th.CheckMissileSpawn(radius); + } + + //============================================================================ + // + // A_KoraxCommand + // + // Call action code scripts (250-254) + // + //============================================================================ + + void A_KoraxCommand() + { + int numcommands; + + A_PlaySound("KoraxCommand", CHAN_VOICE); + + // Shoot stream of lightning to ceiling + double ang = angle - 90; + Vector3 pos = Vec3Angle(KORAX_COMMAND_OFFSET, ang, KORAX_COMMAND_HEIGHT); + Spawn("KoraxBolt", pos, ALLOW_REPLACE); + + if (health <= (SpawnHealth() >> 1)) + { + numcommands = 5; + } + else + { + numcommands = 4; + } + + ACS_Execute(250 + (random[KoraxCommand]()%numcommands), 0); + } } class KoraxSpirit : Actor @@ -94,8 +373,6 @@ class KoraxSpirit : Actor Alpha 0.4; } - native void A_KSpiritRoam(); - States { Spawn: @@ -105,10 +382,98 @@ class KoraxSpirit : Actor SPIR DEFGHI 5; Stop; } + + //============================================================================ + // + // A_KSpiritSeeker + // + //============================================================================ + + private void KSpiritSeeker (double thresh, double turnMax) + { + Actor target = tracer; + if (target == null) + { + return; + } + double dir = deltaangle(angle, AngleTo(target)); + double delta = abs(dir); + if (delta > thresh) + { + delta /= 2; + if(delta > turnMax) + { + delta = turnMax; + } + } + if(dir > 0) + { // Turn clockwise + angle += delta; + } + else + { // Turn counter clockwise + angle -= delta; + } + VelFromAngle(); + + if (!(level.time&15) + || pos.z > target.pos.z + target.Default.Height + || pos.z + height < target.pos.z) + { + double newZ = target.pos.z + random[KoraxRoam]() * target.Default.Height / 256; + double deltaZ = newZ - pos.z; + + if (abs(deltaZ) > 15) + { + if(deltaZ > 0) + { + deltaZ = 15; + } + else + { + deltaZ = -15; + } + } + Vel.Z = deltaZ + DistanceBySpeed(target, Speed); + } + } + + //============================================================================ + // + // A_KSpiritRoam + // + //============================================================================ + + void A_KSpiritRoam() + { + if (health-- <= 0) + { + A_PlaySound("SpiritDie", CHAN_VOICE); + SetStateLabel ("Death"); + } + else + { + if (tracer) + { + KSpiritSeeker(args[0], args[0] * 2.); + } + int xyspeed = (random[KoraxRoam]() % 5); + int zspeed = (random[KoraxRoam]() % 5); + A_Weave(xyspeed, zspeed, 4., 2.); + + if (random[KoraxRoam]() < 50) + { + A_PlaySound("SpiritActive", CHAN_VOICE, 1, false, ATTN_NONE); + } + } + } } class KoraxBolt : Actor { + const KORAX_BOLT_HEIGHT = 48.; + const KORAX_BOLT_LIFETIME = 3; + Default { Radius 15; @@ -119,9 +484,6 @@ class KoraxBolt : Actor RenderStyle "Add"; } - native void A_KBolt(); - native void A_KBoltRaise(); - States { Spawn: @@ -130,4 +492,40 @@ class KoraxBolt : Actor MLFX IJKLM 2 Bright A_KBolt; Stop; } + + //============================================================================ + // + // A_KBolt + // + //============================================================================ + + void A_KBolt() + { + // Countdown lifetime + if (special1-- <= 0) + { + Destroy (); + } + } + + //============================================================================ + // + // A_KBoltRaise + // + //============================================================================ + + void A_KBoltRaise() + { + // Spawn a child upward + double z = pos.z + KORAX_BOLT_HEIGHT; + + if ((z + KORAX_BOLT_HEIGHT) < ceilingz) + { + Actor mo = Spawn("KoraxBolt", (pos.xy, z), ALLOW_REPLACE); + if (mo) + { + mo.special1 = KORAX_BOLT_LIFETIME; + } + } + } } From 997e4a2ac40a68bad6cb8cde02938f31335adc48 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 26 Nov 2016 19:23:22 +0100 Subject: [PATCH 121/185] - scriptified the remaining Cleric weapons. --- src/CMakeLists.txt | 2 - src/g_hexen/a_clericmace.cpp | 59 ------ src/g_hexen/a_clericstaff.cpp | 199 -------------------- src/g_hexen/a_hexenmisc.cpp | 2 - src/p_interaction.cpp | 9 + src/p_user.cpp | 6 + src/scripting/zscript/zcc_parser.cpp | 2 + wadsrc/static/zscript/actor.txt | 1 - wadsrc/static/zscript/hexen/clericmace.txt | 42 ++++- wadsrc/static/zscript/hexen/clericstaff.txt | 156 ++++++++++++++- wadsrc/static/zscript/shared/player.txt | 4 +- 11 files changed, 210 insertions(+), 272 deletions(-) delete mode 100644 src/g_hexen/a_clericmace.cpp delete mode 100644 src/g_hexen/a_clericstaff.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 828c7fc34..42dc50f98 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -855,8 +855,6 @@ set( NOT_COMPILED_SOURCE_FILES ${OTHER_SYSTEM_SOURCES} sc_man_scanner.h sc_man_scanner.re - g_hexen/a_clericmace.cpp - g_hexen/a_clericstaff.cpp g_hexen/a_fighteraxe.cpp g_hexen/a_fighterhammer.cpp g_hexen/a_fighterplayer.cpp diff --git a/src/g_hexen/a_clericmace.cpp b/src/g_hexen/a_clericmace.cpp deleted file mode 100644 index a15196cf8..000000000 --- a/src/g_hexen/a_clericmace.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* -#include "m_random.h" -#include "p_local.h" -#include "a_hexenglobal.h" -#include "vm.h" -*/ - -static FRandom pr_maceatk ("CMaceAttack"); - -//=========================================================================== -// -// A_CMaceAttack -// -//=========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_CMaceAttack) -{ - PARAM_ACTION_PROLOGUE(AActor); - - DAngle angle; - int damage; - DAngle slope; - int i; - player_t *player; - FTranslatedLineTarget t; - - if (NULL == (player = self->player)) - { - return 0; - } - - PClassActor *hammertime = PClass::FindActor("HammerPuff"); - - damage = 25+(pr_maceatk()&15); - for (i = 0; i < 16; i++) - { - for (int j = 1; j >= -1; j -= 2) - { - angle = player->mo->Angles.Yaw + j*i*(45. / 16); - slope = P_AimLineAttack(player->mo, angle, 2 * MELEERANGE, &t); - if (t.linetarget) - { - P_LineAttack(player->mo, angle, 2 * MELEERANGE, slope, damage, NAME_Melee, hammertime, true, &t); - if (t.linetarget != NULL) - { - AdjustPlayerAngle(player->mo, &t); - return 0; - } - } - } - } - // didn't find any creatures, so try to strike any walls - player->mo->weaponspecial = 0; - - angle = player->mo->Angles.Yaw; - slope = P_AimLineAttack (player->mo, angle, MELEERANGE); - P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, hammertime); - return 0; -} diff --git a/src/g_hexen/a_clericstaff.cpp b/src/g_hexen/a_clericstaff.cpp deleted file mode 100644 index ef7beaffa..000000000 --- a/src/g_hexen/a_clericstaff.cpp +++ /dev/null @@ -1,199 +0,0 @@ -/* -#include "actor.h" -#include "gi.h" -#include "m_random.h" -#include "s_sound.h" -#include "d_player.h" -#include "a_action.h" -#include "p_local.h" -#include "a_action.h" -#include "p_pspr.h" -#include "gstrings.h" -#include "a_hexenglobal.h" -#include "vm.h" -*/ - -static FRandom pr_staffcheck ("CStaffCheck"); -static FRandom pr_blink ("CStaffBlink"); - -// Serpent Staff Missile ---------------------------------------------------- - -class ACStaffMissile : public AActor -{ - DECLARE_CLASS (ACStaffMissile, AActor) -public: - int DoSpecialDamage (AActor *target, int damage, FName damagetype); -}; - -IMPLEMENT_CLASS(ACStaffMissile, false, false) - -int ACStaffMissile::DoSpecialDamage (AActor *target, int damage, FName damagetype) -{ - // Cleric Serpent Staff does poison damage - if (target->player) - { - P_PoisonPlayer (target->player, this, this->target, 20); - damage >>= 1; - } - return damage; -} - -//============================================================================ -// -// A_CStaffCheck -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck) -{ - PARAM_ACTION_PROLOGUE(AActor); - - APlayerPawn *pmo; - int damage; - int newLife, max; - DAngle angle; - DAngle slope; - int i; - player_t *player; - FTranslatedLineTarget t; - PClassActor *puff; - - if (nullptr == (player = self->player)) - { - 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++) - { - for (int j = 1; j >= -1; j -= 2) - { - angle = pmo->Angles.Yaw + j*i*(45. / 16); - slope = P_AimLineAttack(pmo, angle, 1.5 * MELEERANGE, &t, 0., ALF_CHECK3D); - if (t.linetarget) - { - P_LineAttack(pmo, angle, 1.5 * MELEERANGE, slope, damage, NAME_Melee, puff, false, &t); - if (t.linetarget != nullptr) - { - pmo->Angles.Yaw = t.angleFromSource; - if (((t.linetarget->player && (!t.linetarget->IsTeammate(pmo) || level.teamdamage != 0)) || t.linetarget->flags3&MF3_ISMONSTER) - && (!(t.linetarget->flags2&(MF2_DORMANT | MF2_INVULNERABLE)))) - { - newLife = player->health + (damage >> 3); - newLife = newLife > max ? max : newLife; - if (newLife > player->health) - { - pmo->health = player->health = newLife; - } - if (weapon != nullptr) - { - FState * newstate = weapon->FindState("Drain"); - if (newstate != nullptr) P_SetPsprite(player, PSP_WEAPON, newstate); - } - } - if (weapon != nullptr) - { - weapon->DepleteAmmo(weapon->bAltFire, false); - } - } - return 0; - } - } - } - return 0; -} - -//============================================================================ -// -// A_CStaffAttack -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_CStaffAttack) -{ - PARAM_ACTION_PROLOGUE(AActor); - - AActor *mo; - player_t *player; - - if (NULL == (player = self->player)) - { - return 0; - } - - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - mo = P_SpawnPlayerMissile (self, RUNTIME_CLASS(ACStaffMissile), self->Angles.Yaw - 3.0); - if (mo) - { - mo->WeaveIndexXY = 32; - } - mo = P_SpawnPlayerMissile (self, RUNTIME_CLASS(ACStaffMissile), self->Angles.Yaw + 3.0); - if (mo) - { - mo->WeaveIndexXY = 0; - } - S_Sound (self, CHAN_WEAPON, "ClericCStaffFire", 1, ATTN_NORM); - return 0; -} - -//============================================================================ -// -// A_CStaffMissileSlither -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_CStaffMissileSlither) -{ - PARAM_SELF_PROLOGUE(AActor); - - A_Weave(self, 3, 0, 1., 0.); - return 0; -} - -//============================================================================ -// -// A_CStaffInitBlink -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_CStaffInitBlink) -{ - PARAM_ACTION_PROLOGUE(AActor); - - self->weaponspecial = (pr_blink()>>1)+20; - return 0; -} - -//============================================================================ -// -// A_CStaffCheckBlink -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheckBlink) -{ - PARAM_ACTION_PROLOGUE(AActor); - - if (self->player && self->player->ReadyWeapon) - { - if (!--self->weaponspecial) - { - P_SetPsprite(self->player, PSP_WEAPON, self->player->ReadyWeapon->FindState ("Blink")); - self->weaponspecial = (pr_blink()+50)>>2; - } - else - { - DoReadyWeapon(self); - } - } - return 0; -} diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp index 3fb334cb1..101bcf145 100644 --- a/src/g_hexen/a_hexenmisc.cpp +++ b/src/g_hexen/a_hexenmisc.cpp @@ -24,8 +24,6 @@ #include "serializer.h" // Include all the Hexen stuff here to reduce compile time -#include "a_clericmace.cpp" -#include "a_clericstaff.cpp" #include "a_fighteraxe.cpp" #include "a_fighterhammer.cpp" #include "a_fighterplayer.cpp" diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 8c28c46b3..040e05ce0 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1734,6 +1734,15 @@ bool P_PoisonPlayer (player_t *player, AActor *poisoner, AActor *source, int poi return true; } +DEFINE_ACTION_FUNCTION(_PlayerInfo, PoisonPlayer) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + PARAM_OBJECT(poisoner, AActor); + PARAM_OBJECT(source, AActor); + PARAM_INT(poison); + ACTION_RETURN_BOOL(P_PoisonPlayer(self, poisoner, source, poison)); +} + //========================================================================== // // P_PoisonDamage - Similar to P_DamageMobj diff --git a/src/p_user.cpp b/src/p_user.cpp index f28bf9f42..eadbda10e 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -1207,6 +1207,12 @@ int APlayerPawn::GetMaxHealth() const return MaxHealth > 0? MaxHealth : ((i_compatflags&COMPATF_DEHHEALTH)? 100 : deh.MaxHealth); } +DEFINE_ACTION_FUNCTION(APlayerPawn, GetMaxHealth) +{ + PARAM_SELF_PROLOGUE(APlayerPawn); + ACTION_RETURN_INT(self->GetMaxHealth()); +} + //=========================================================================== // // APlayerPawn :: UpdateWaterLevel diff --git a/src/scripting/zscript/zcc_parser.cpp b/src/scripting/zscript/zcc_parser.cpp index 401a15c25..9d24d0cb1 100644 --- a/src/scripting/zscript/zcc_parser.cpp +++ b/src/scripting/zscript/zcc_parser.cpp @@ -406,10 +406,12 @@ void ParseScripts() int lump, lastlump = 0; FScriptPosition::ResetErrorCounter(); + while ((lump = Wads.FindLump("ZSCRIPT", &lastlump)) != -1) { DoParse(lump); } + } /* diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index ccf3fb374..2b1ba6a5a 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -592,7 +592,6 @@ class Actor : Thinker native native void A_FreezeDeathChunks(); native void A_GenericFreezeDeath(); native void A_IceGuyDie(); - native void A_CStaffMissileSlither(); native void A_PlayerScream(); native void A_SkullPop(class skulltype = "BloodySkull"); native void A_CheckPlayerDone(); diff --git a/wadsrc/static/zscript/hexen/clericmace.txt b/wadsrc/static/zscript/hexen/clericmace.txt index 5e00b9c3b..b6f42c7e4 100644 --- a/wadsrc/static/zscript/hexen/clericmace.txt +++ b/wadsrc/static/zscript/hexen/clericmace.txt @@ -13,8 +13,6 @@ class CWeapMace : ClericWeapon Tag "$TAG_CWEAPMACE"; } - action native void A_CMaceAttack(); - States { Select: @@ -46,4 +44,44 @@ class CWeapMace : ClericWeapon CMCE A 1 Offset (8, 45); Goto Ready; } + + //=========================================================================== + // + // A_CMaceAttack + // + //=========================================================================== + + action void A_CMaceAttack() + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + + int damage = 25+(random[MaceAtk]()&15); + for (int i = 0; i < 16; i++) + { + for (int j = 1; j >= -1; j -= 2) + { + double ang = angle + j*i*(45. / 16); + double slope = AimLineAttack(ang, 2 * MELEERANGE, t); + if (t.linetarget) + { + LineAttack(ang, 2 * MELEERANGE, slope, damage, 'Melee', "HammerPuff", true, t); + if (t.linetarget != null) + { + AdjustPlayerAngle(t); + return; + } + } + } + } + // didn't find any creatures, so try to strike any walls + weaponspecial = 0; + + double slope = AimLineAttack (angle, MELEERANGE); + LineAttack (angle, MELEERANGE, slope, damage, 'Melee', "HammerPuff"); + } } diff --git a/wadsrc/static/zscript/hexen/clericstaff.txt b/wadsrc/static/zscript/hexen/clericstaff.txt index 7ae0e9da3..0d7ca0a99 100644 --- a/wadsrc/static/zscript/hexen/clericstaff.txt +++ b/wadsrc/static/zscript/hexen/clericstaff.txt @@ -16,11 +16,6 @@ class CWeapStaff : ClericWeapon Tag "$TAG_CWEAPSTAFF"; } - action native void A_CStaffInitBlink(); - action native void A_CStaffCheckBlink(); - action native void A_CStaffCheck(); - action native void A_CStaffAttack(); - States { Spawn: @@ -55,11 +50,132 @@ class CWeapStaff : ClericWeapon CSSF K 10 Offset (0, 36); Goto Ready + 2; } + + //============================================================================ + // + // A_CStaffCheck + // + //============================================================================ + + action void A_CStaffCheck() + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + Weapon weapon = player.ReadyWeapon; + + int damage = 20 + (random[StaffCheck]() & 15); + int max = player.mo.GetMaxHealth(); + for (int i = 0; i < 3; i++) + { + for (int j = 1; j >= -1; j -= 2) + { + double ang = angle + j*i*(45. / 16); + double slope = AimLineAttack(ang, 1.5 * MELEERANGE, t, 0., ALF_CHECK3D); + if (t.linetarget) + { + LineAttack(ang, 1.5 * MELEERANGE, slope, damage, 'Melee', "CStaffPuff", false, t); + if (t.linetarget != null) + { + angle = t.angleFromSource; + if (((t.linetarget.player && (!t.linetarget.IsTeammate(self) || level.teamdamage != 0)) || t.linetarget.bIsMonster) + && (!t.linetarget.bDormant && !bInvulnerable)) + { + int newLife = player.health + (damage >> 3); + newLife = newLife > max ? max : newLife; + if (newLife > player.health) + { + health = player.health = newLife; + } + if (weapon != null) + { + State newstate = weapon.FindState("Drain"); + if (newstate != null) player.SetPsprite(PSP_WEAPON, newstate); + } + } + if (weapon != null) + { + weapon.DepleteAmmo(weapon.bAltFire, false); + } + } + return; + } + } + } + } + + //============================================================================ + // + // A_CStaffAttack + // + //============================================================================ + + action void A_CStaffAttack() + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + Actor mo = SpawnPlayerMissile ("CStaffMissile", angle - 3.0); + if (mo) + { + mo.WeaveIndexXY = 32; + } + mo = SpawnPlayerMissile ("CStaffMissile", angle + 3.0); + if (mo) + { + mo.WeaveIndexXY = 0; + } + A_PlaySound ("ClericCStaffFire", CHAN_WEAPON); + } + + //============================================================================ + // + // A_CStaffInitBlink + // + //============================================================================ + + action void A_CStaffInitBlink() + { + weaponspecial = (random[CStaffBlink]() >> 1) + 20; + } + + //============================================================================ + // + // A_CStaffCheckBlink + // + //============================================================================ + + action void A_CStaffCheckBlink() + { + if (player && player.ReadyWeapon) + { + if (!--weaponspecial) + { + player.SetPsprite(PSP_WEAPON, player.ReadyWeapon.FindState ("Blink")); + weaponspecial = (random[CStaffBlink]() + 50) >> 2; + } + else + { + A_WeaponReady(); + } + } + } } // Serpent Staff Missile ---------------------------------------------------- -class CStaffMissile : Actor native +class CStaffMissile : Actor { Default { @@ -82,6 +198,34 @@ class CStaffMissile : Actor native CSSF HI 3 Bright; Stop; } + + override int DoSpecialDamage (Actor target, int damage, Name damagetype) + { + // Cleric Serpent Staff does poison damage + if (target.player) + { + target.player.PoisonPlayer (self, self.target, 20); + damage >>= 1; + } + return damage; + } + +} + +extend class Actor +{ + + //============================================================================ + // + // A_CStaffMissileSlither + // + //============================================================================ + + void A_CStaffMissileSlither() + { + A_Weave(3, 0, 1., 0.); + } + } // Serpent Staff Puff ------------------------------------------------------- diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index e76e637fe..48d62688b 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -78,7 +78,8 @@ class PlayerPawn : Actor native virtual void MorphPlayerThink() { } - + + native int GetMaxHealth(); } class PlayerChunk : PlayerPawn native @@ -214,6 +215,7 @@ FWeaponSlots weapons; native bool UndoPlayerMorph(playerinfo player, int unmorphflag = 0, bool force = false); + native bool PoisonPlayer(Actor poisoner, Actor source, int poison); native void SetPsprite(int id, State stat, bool pending = false); native void SetSafeFlash(Weapon weap, State flashstate, int index); native PSprite GetPSprite(int id); From e541c27622de448cad9a3610b65a5b31405e62c9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 26 Nov 2016 19:48:30 +0100 Subject: [PATCH 122/185] - scriptified the weapon's state getter methods - as preparation for the fighter axe. --- src/g_hexen/a_fighteraxe.cpp | 32 ----------- src/g_shared/a_pickups.h | 12 ++--- src/g_shared/a_weapons.cpp | 63 +++++++++++++++++----- wadsrc/static/zscript/hexen/fighteraxe.txt | 24 ++++++++- wadsrc/static/zscript/shared/inventory.txt | 25 +++++++++ 5 files changed, 104 insertions(+), 52 deletions(-) diff --git a/src/g_hexen/a_fighteraxe.cpp b/src/g_hexen/a_fighteraxe.cpp index fde3a9c18..7036def95 100644 --- a/src/g_hexen/a_fighteraxe.cpp +++ b/src/g_hexen/a_fighteraxe.cpp @@ -21,38 +21,6 @@ static FRandom pr_axeatk ("FAxeAtk"); // The Fighter's Axe -------------------------------------------------------- -class AFWeapAxe : public AFighterWeapon -{ - DECLARE_CLASS (AFWeapAxe, AFighterWeapon) -public: - FState *GetUpState (); - FState *GetDownState (); - FState *GetReadyState (); - FState *GetAtkState (bool hold); -}; - -IMPLEMENT_CLASS(AFWeapAxe, false, false) - -FState *AFWeapAxe::GetUpState () -{ - return Ammo1->Amount ? FindState ("SelectGlow") : Super::GetUpState(); -} - -FState *AFWeapAxe::GetDownState () -{ - return Ammo1->Amount ? FindState ("DeselectGlow") : Super::GetDownState(); -} - -FState *AFWeapAxe::GetReadyState () -{ - return Ammo1->Amount ? FindState ("ReadyGlow") : Super::GetReadyState(); -} - -FState *AFWeapAxe::GetAtkState (bool hold) -{ - return Ammo1->Amount ? FindState ("FireGlow") : Super::GetAtkState(hold); -} - //============================================================================ // // A_FAxeCheckReady diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index bd252437d..bc8319931 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -335,12 +335,12 @@ public: virtual bool Use (bool pickup); virtual void Destroy() override; - virtual FState *GetUpState (); - virtual FState *GetDownState (); - virtual FState *GetReadyState (); - virtual FState *GetAtkState (bool hold); - virtual FState *GetAltAtkState (bool hold); - virtual FState *GetStateForButtonName (FName button); + FState *GetUpState (); + FState *GetDownState (); + FState *GetReadyState (); + FState *GetAtkState (bool hold); + FState *GetAltAtkState (bool hold); + FState *GetStateForButtonName (FName button); virtual void PostMorphWeapon (); virtual void EndPowerup (); diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index 02cd19fa6..e9d931520 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -818,7 +818,16 @@ void AWeapon::CallEndPowerup() FState *AWeapon::GetUpState () { - return FindState(NAME_Select); + IFVIRTUAL(AWeapon, GetUpState) + { + VMValue params[1] = { (DObject*)this }; + VMReturn ret; + VMFrameStack stack; + FState *retval; + ret.PointerAt((void**)&retval); + stack.Call(func, params, 1, &ret, 1, nullptr); + return retval; + } } //=========================================================================== @@ -829,7 +838,16 @@ FState *AWeapon::GetUpState () FState *AWeapon::GetDownState () { - return FindState(NAME_Deselect); + IFVIRTUAL(AWeapon, GetDownState) + { + VMValue params[1] = { (DObject*)this }; + VMReturn ret; + VMFrameStack stack; + FState *retval; + ret.PointerAt((void**)&retval); + stack.Call(func, params, 1, &ret, 1, nullptr); + return retval; + } } //=========================================================================== @@ -840,7 +858,16 @@ FState *AWeapon::GetDownState () FState *AWeapon::GetReadyState () { - return FindState(NAME_Ready); + IFVIRTUAL(AWeapon, GetReadyState) + { + VMValue params[1] = { (DObject*)this }; + VMReturn ret; + VMFrameStack stack; + FState *retval; + ret.PointerAt((void**)&retval); + stack.Call(func, params, 1, &ret, 1, nullptr); + return retval; + } } //=========================================================================== @@ -851,11 +878,16 @@ FState *AWeapon::GetReadyState () FState *AWeapon::GetAtkState (bool hold) { - FState * state=NULL; - - if (hold) state = FindState(NAME_Hold); - if (state == NULL) state = FindState(NAME_Fire); - return state; + IFVIRTUAL(AWeapon, GetAtkState) + { + VMValue params[2] = { (DObject*)this, hold }; + VMReturn ret; + VMFrameStack stack; + FState *retval; + ret.PointerAt((void**)&retval); + stack.Call(func, params, 2, &ret, 1, nullptr); + return retval; + } } //=========================================================================== @@ -866,11 +898,16 @@ FState *AWeapon::GetAtkState (bool hold) FState *AWeapon::GetAltAtkState (bool hold) { - FState * state=NULL; - - if (hold) state = FindState(NAME_AltHold); - if (state == NULL) state = FindState(NAME_AltFire); - return state; + IFVIRTUAL(AWeapon, GetAltAtkState) + { + VMValue params[2] = { (DObject*)this, hold }; + VMReturn ret; + VMFrameStack stack; + FState *retval; + ret.PointerAt((void**)&retval); + stack.Call(func, params, 2, &ret, 1, nullptr); + return retval; + } } //=========================================================================== diff --git a/wadsrc/static/zscript/hexen/fighteraxe.txt b/wadsrc/static/zscript/hexen/fighteraxe.txt index 30b235192..35049ab9a 100644 --- a/wadsrc/static/zscript/hexen/fighteraxe.txt +++ b/wadsrc/static/zscript/hexen/fighteraxe.txt @@ -1,7 +1,7 @@ // The Fighter's Axe -------------------------------------------------------- -class FWeapAxe : FighterWeapon native +class FWeapAxe : FighterWeapon { Default { @@ -79,6 +79,28 @@ class FWeapAxe : FighterWeapon native FAXE A 1; Goto ReadyGlow; } + + override State GetUpState () + { + return Ammo1.Amount ? FindState ("SelectGlow") : Super.GetUpState(); + } + + override State GetDownState () + { + return Ammo1.Amount ? FindState ("DeselectGlow") : Super.GetDownState(); + } + + override State GetReadyState () + { + return Ammo1.Amount ? FindState ("ReadyGlow") : Super.GetReadyState(); + } + + override State GetAtkState (bool hold) + { + return Ammo1.Amount ? FindState ("FireGlow") : Super.GetAtkState(hold); + } + + } // Axe Puff ----------------------------------------------------------------- diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index f87331470..f6c95f8bd 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -580,6 +580,31 @@ class Weapon : StateProvider native return FindState('Ready'); } + virtual State GetUpState () + { + return FindState('Select'); + } + + virtual State GetDownState () + { + return FindState('Deselect'); + } + + virtual State GetAtkState (bool hold) + { + State s = null; + if (hold) s = FindState('Hold'); + if (s == null) s = FindState('Fire'); + return s; + } + + virtual State GetAltAtkState (bool hold) + { + State s = null; + if (hold) s = FindState('AltHold'); + if (s == null) s = FindState('AltFire'); + return s; + } native action void A_ZoomFactor(double scale = 1, int flags = 0); native action void A_SetCrosshair(int xhair); From bdad526f62a51d8808b00c1f77d583d6e68f2db1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 26 Nov 2016 21:03:00 +0100 Subject: [PATCH 123/185] - scriptified the Fighter's axe. --- src/CMakeLists.txt | 1 - src/g_hexen/a_fighteraxe.cpp | 245 --------------------- src/g_hexen/a_hexenmisc.cpp | 1 - wadsrc/static/zscript/hexen/fighteraxe.txt | 189 +++++++++++++++- 4 files changed, 182 insertions(+), 254 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 42dc50f98..58a699477 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -855,7 +855,6 @@ set( NOT_COMPILED_SOURCE_FILES ${OTHER_SYSTEM_SOURCES} sc_man_scanner.h sc_man_scanner.re - g_hexen/a_fighteraxe.cpp g_hexen/a_fighterhammer.cpp g_hexen/a_fighterplayer.cpp g_hexen/a_fighterquietus.cpp diff --git a/src/g_hexen/a_fighteraxe.cpp b/src/g_hexen/a_fighteraxe.cpp index 7036def95..e69de29bb 100644 --- a/src/g_hexen/a_fighteraxe.cpp +++ b/src/g_hexen/a_fighteraxe.cpp @@ -1,245 +0,0 @@ -/* -#include "actor.h" -#include "gi.h" -#include "m_random.h" -#include "s_sound.h" -#include "d_player.h" -#include "a_action.h" -#include "p_local.h" -#include "a_action.h" -#include "p_pspr.h" -#include "gstrings.h" -#include "a_hexenglobal.h" -#include "vm.h" -*/ - -DECLARE_ACTION(A_Raise) - -#define AXERANGE (2.25 * MELEERANGE) - -static FRandom pr_axeatk ("FAxeAtk"); - -// The Fighter's Axe -------------------------------------------------------- - -//============================================================================ -// -// A_FAxeCheckReady -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckReady) -{ - PARAM_ACTION_PROLOGUE(AActor); - - player_t *player; - - if (nullptr == (player = self->player)) - { - return 0; - } - if (player->ReadyWeapon->Ammo1->Amount) - { - P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->FindState ("ReadyGlow")); - } - else - { - DoReadyWeapon(self); - } - return 0; -} - -//============================================================================ -// -// A_FAxeCheckReadyG -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckReadyG) -{ - PARAM_ACTION_PROLOGUE(AActor); - - player_t *player; - - if (nullptr == (player = self->player)) - { - return 0; - } - if (player->ReadyWeapon->Ammo1->Amount <= 0) - { - P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->FindState ("Ready")); - } - else - { - DoReadyWeapon(self); - } - return 0; -} - -//============================================================================ -// -// A_FAxeCheckUp -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckUp) -{ - PARAM_ACTION_PROLOGUE(AActor); - - player_t *player; - - if (nullptr == (player = self->player)) - { - return 0; - } - if (player->ReadyWeapon->Ammo1->Amount) - { - P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->FindState ("SelectGlow")); - } - else - { - CALL_ACTION(A_Raise, self); - } - return 0; -} - -//============================================================================ -// -// A_FAxeCheckUpG -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckUpG) -{ - PARAM_ACTION_PROLOGUE(AActor); - - player_t *player; - - if (nullptr == (player = self->player)) - { - return 0; - } - if (player->ReadyWeapon->Ammo1->Amount <= 0) - { - P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->FindState ("Select")); - } - else - { - CALL_ACTION(A_Raise, self); - } - return 0; -} - -//============================================================================ -// -// A_FAxeCheckAtk -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckAtk) -{ - PARAM_ACTION_PROLOGUE(AActor); - - player_t *player; - - if (nullptr == (player = self->player)) - { - return 0; - } - if (player->ReadyWeapon->Ammo1->Amount) - { - P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->FindState ("FireGlow")); - } - return 0; -} - -//============================================================================ -// -// A_FAxeAttack -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FAxeAttack) -{ - PARAM_ACTION_PROLOGUE(AActor); - - DAngle angle; - int power; - int damage; - DAngle slope; - int i; - int useMana; - player_t *player; - AWeapon *weapon; - PClassActor *pufftype; - FTranslatedLineTarget t; - - if (nullptr == (player = self->player)) - { - return 0; - } - AActor *pmo=player->mo; - - damage = 40+(pr_axeatk()&15); - damage += pr_axeatk()&7; - power = 0; - weapon = player->ReadyWeapon; - if (player->ReadyWeapon->Ammo1->Amount > 0) - { - damage <<= 1; - power = 6; - pufftype = PClass::FindActor ("AxePuffGlow"); - useMana = 1; - } - else - { - pufftype = PClass::FindActor ("AxePuff"); - useMana = 0; - } - for (i = 0; i < 16; i++) - { - for (int j = 1; j >= -1; j -= 2) - { - angle = pmo->Angles.Yaw + j*i*(45. / 16); - slope = P_AimLineAttack(pmo, angle, AXERANGE, &t); - if (t.linetarget) - { - P_LineAttack(pmo, angle, AXERANGE, slope, damage, NAME_Melee, pufftype, true, &t); - if (t.linetarget != nullptr) - { - if (t.linetarget->flags3&MF3_ISMONSTER || t.linetarget->player) - { - t.linetarget->Thrust(t.angleFromSource, power); - } - AdjustPlayerAngle(pmo, &t); - useMana++; - goto axedone; - } - } - } - } - // didn't find any creatures, so try to strike any walls - pmo->weaponspecial = 0; - - angle = pmo->Angles.Yaw; - slope = P_AimLineAttack (pmo, angle, MELEERANGE); - P_LineAttack (pmo, angle, MELEERANGE, slope, damage, NAME_Melee, pufftype, true); - -axedone: - if (useMana == 2) - { - AWeapon *weapon = player->ReadyWeapon; - if (weapon != nullptr) - { - weapon->DepleteAmmo (weapon->bAltFire, false); - - if ((weapon->Ammo1 == nullptr || weapon->Ammo1->Amount == 0) && - (!(weapon->WeaponFlags & WIF_PRIMARY_USES_BOTH) || - weapon->Ammo2 == nullptr || weapon->Ammo2->Amount == 0)) - { - P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->FindState ("Fire") + 5); - } - } - } - return 0; -} - diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp index 101bcf145..f2b8d8866 100644 --- a/src/g_hexen/a_hexenmisc.cpp +++ b/src/g_hexen/a_hexenmisc.cpp @@ -24,7 +24,6 @@ #include "serializer.h" // Include all the Hexen stuff here to reduce compile time -#include "a_fighteraxe.cpp" #include "a_fighterhammer.cpp" #include "a_fighterplayer.cpp" #include "a_fighterquietus.cpp" diff --git a/wadsrc/static/zscript/hexen/fighteraxe.txt b/wadsrc/static/zscript/hexen/fighteraxe.txt index 35049ab9a..a0d1deba1 100644 --- a/wadsrc/static/zscript/hexen/fighteraxe.txt +++ b/wadsrc/static/zscript/hexen/fighteraxe.txt @@ -3,6 +3,8 @@ class FWeapAxe : FighterWeapon { + const AXERANGE = (2.25 * MELEERANGE); + Default { Weapon.SelectionOrder 1500; @@ -17,13 +19,6 @@ class FWeapAxe : FighterWeapon Tag "$TAG_FWEAPAXE"; } - action native void A_FAxeCheckUp(); - action native void A_FAxeCheckReady(); - action native void A_FAxeCheckAtk(); - action native void A_FAxeAttack(); - action native void A_FAxeCheckUpG(); - action native void A_FAxeCheckReadyG(); - States { Spawn: @@ -45,6 +40,7 @@ class FWeapAxe : FighterWeapon FAXE D 1 Offset (-5, 70) A_FAxeAttack; FAXE D 2 Offset (-25, 90); FAXE E 1 Offset (15, 32); + EndAttack: FAXE E 2 Offset (10, 54); FAXE E 7 Offset (10, 150); FAXE A 1 Offset (0, 60) A_ReFire; @@ -101,6 +97,185 @@ class FWeapAxe : FighterWeapon } + + //============================================================================ + // + // A_FAxeCheckReady + // + //============================================================================ + + action void A_FAxeCheckReady() + { + if (player == null) + { + return; + } + Weapon w = player.ReadyWeapon; + if (w.Ammo1 && w.Ammo1.Amount > 0) + { + player.SetPsprite(PSP_WEAPON, w.FindState("ReadyGlow")); + } + else + { + A_WeaponReady(); + } + } + + //============================================================================ + // + // A_FAxeCheckReadyG + // + //============================================================================ + + action void A_FAxeCheckReadyG() + { + if (player == null) + { + return; + } + Weapon w = player.ReadyWeapon; + if (!w.Ammo1 || w.Ammo1.Amount <= 0) + { + player.SetPsprite(PSP_WEAPON, w.FindState("Ready")); + } + else + { + A_WeaponReady(); + } + } + + //============================================================================ + // + // A_FAxeCheckUp + // + //============================================================================ + + action void A_FAxeCheckUp() + { + if (player == null) + { + return; + } + Weapon w = player.ReadyWeapon; + if (w.Ammo1 && w.Ammo1.Amount > 0) + { + player.SetPsprite(PSP_WEAPON, w.FindState("SelectGlow")); + } + else + { + A_Raise(); + } + } + + //============================================================================ + // + // A_FAxeCheckUpG + // + //============================================================================ + + action void A_FAxeCheckUpG() + { + if (player == null) + { + return; + } + Weapon w = player.ReadyWeapon; + if (!w.Ammo1 || w.Ammo1.Amount <= 0) + { + player.SetPsprite(PSP_WEAPON, w.FindState("Select")); + } + else + { + A_Raise(); + } + } + + //============================================================================ + // + // A_FAxeCheckAtk + // + //============================================================================ + + action void A_FAxeCheckAtk() + { + if (player == null) + { + return; + } + Weapon w = player.ReadyWeapon; + if (w.Ammo1 && w.Ammo1.Amount > 0) + { + player.SetPsprite(PSP_WEAPON, w.FindState("FireGlow")); + } + } + + //============================================================================ + // + // A_FAxeAttack + // + //============================================================================ + + action void A_FAxeAttack() + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + + int damage = 40+(random[AxeAtk]() & 15); + damage += random[AxeAtk]() & 7; + int power = 0; + Weapon weapon = player.ReadyWeapon; + class pufftype; + int usemana; + if ((usemana = (weapon.Ammo1 && weapon.Ammo1.Amount > 0))) + { + damage <<= 1; + power = 6; + pufftype = "AxePuffGlow"; + } + else + { + pufftype = "AxePuff"; + } + for (int i = 0; i < 16; i++) + { + for (int j = 1; j >= -1; j -= 2) + { + double ang = angle + j*i*(45. / 16); + double slope = AimLineAttack(ang, AXERANGE, t); + if (t.linetarget) + { + LineAttack(ang, AXERANGE, slope, damage, 'Melee', pufftype, true, t); + if (t.linetarget != null) + { + if (t.linetarget.bIsMonster || t.linetarget.player) + { + t.linetarget.Thrust(power, t.angleFromSource); + } + AdjustPlayerAngle(t); + + weapon.DepleteAmmo (weapon.bAltFire, false); + + if ((weapon.Ammo1 == null || weapon.Ammo1.Amount == 0) && + (!(weapon.bPrimary_Uses_Both) || + weapon.Ammo2 == null || weapon.Ammo2.Amount == 0)) + { + player.SetPsprite(PSP_WEAPON, weapon.FindState("EndAttack")); + } + return; + } + } + } + } + // didn't find any creatures, so try to strike any walls + self.weaponspecial = 0; + + double slope = AimLineAttack (angle, MELEERANGE); + LineAttack (angle, MELEERANGE, slope, damage, 'Melee', pufftype, true); + } } // Axe Puff ----------------------------------------------------------------- From 178db4bb098ea3a45d1f492a945cc6ca451d218c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 26 Nov 2016 21:39:20 +0100 Subject: [PATCH 124/185] - scriptified the fighter's hammer. --- src/CMakeLists.txt | 1 - src/g_hexen/a_fighteraxe.cpp | 0 src/g_hexen/a_fighterhammer.cpp | 124 ------------------ src/g_hexen/a_hexenmisc.cpp | 1 - src/g_shared/a_weapons.cpp | 10 ++ wadsrc/static/zscript/hexen/fighterhammer.txt | 88 ++++++++++++- wadsrc/static/zscript/shared/inventory.txt | 8 ++ 7 files changed, 102 insertions(+), 130 deletions(-) delete mode 100644 src/g_hexen/a_fighteraxe.cpp delete mode 100644 src/g_hexen/a_fighterhammer.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 58a699477..c3e241900 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -855,7 +855,6 @@ set( NOT_COMPILED_SOURCE_FILES ${OTHER_SYSTEM_SOURCES} sc_man_scanner.h sc_man_scanner.re - g_hexen/a_fighterhammer.cpp g_hexen/a_fighterplayer.cpp g_hexen/a_fighterquietus.cpp g_hexen/a_flechette.cpp diff --git a/src/g_hexen/a_fighteraxe.cpp b/src/g_hexen/a_fighteraxe.cpp deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/g_hexen/a_fighterhammer.cpp b/src/g_hexen/a_fighterhammer.cpp deleted file mode 100644 index 84eca78b7..000000000 --- a/src/g_hexen/a_fighterhammer.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* -#include "actor.h" -#include "gi.h" -#include "m_random.h" -#include "s_sound.h" -#include "d_player.h" -#include "a_action.h" -#include "p_local.h" -#include "a_action.h" -#include "p_pspr.h" -#include "gstrings.h" -#include "a_hexenglobal.h" -#include "vm.h" -*/ - -const double HAMMER_RANGE = 1.5 * MELEERANGE; - -static FRandom pr_hammeratk ("FHammerAtk"); - -//============================================================================ -// -// A_FHammerAttack -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack) -{ - PARAM_ACTION_PROLOGUE(AActor); - - DAngle angle; - int damage; - DAngle slope; - int i; - player_t *player; - FTranslatedLineTarget t; - PClassActor *hammertime; - - if (NULL == (player = self->player)) - { - return 0; - } - AActor *pmo=player->mo; - - damage = 60+(pr_hammeratk()&63); - hammertime = PClass::FindActor("HammerPuff"); - for (i = 0; i < 16; i++) - { - for (int j = 1; j >= -1; j -= 2) - { - angle = pmo->Angles.Yaw + j*i*(45. / 32); - slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE, &t, 0., ALF_CHECK3D); - if (t.linetarget != NULL) - { - P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true, &t); - if (t.linetarget != NULL) - { - AdjustPlayerAngle(pmo, &t); - if (t.linetarget->flags3 & MF3_ISMONSTER || t.linetarget->player) - { - t.linetarget->Thrust(t.angleFromSource, 10); - } - pmo->weaponspecial = false; // Don't throw a hammer - goto hammerdone; - } - } - } - } - // didn't find any targets in meleerange, so set to throw out a hammer - angle = pmo->Angles.Yaw; - slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE, NULL, 0., ALF_CHECK3D); - if (P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true) != NULL) - { - pmo->weaponspecial = false; - } - else - { - pmo->weaponspecial = true; - } -hammerdone: - // Don't spawn a hammer if the player doesn't have enough mana - if (player->ReadyWeapon == NULL || - !player->ReadyWeapon->CheckAmmo (player->ReadyWeapon->bAltFire ? - AWeapon::AltFire : AWeapon::PrimaryFire, false, true)) - { - pmo->weaponspecial = false; - } - return 0; -} - -//============================================================================ -// -// A_FHammerThrow -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FHammerThrow) -{ - PARAM_ACTION_PROLOGUE(AActor); - - AActor *mo; - player_t *player; - - if (NULL == (player = self->player)) - { - return 0; - } - - if (!player->mo->weaponspecial) - { - return 0; - } - AWeapon *weapon = player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire, false)) - return 0; - } - mo = P_SpawnPlayerMissile (player->mo, PClass::FindActor("HammerMissile")); - if (mo) - { - mo->special1 = 0; - } - return 0; -} diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp index f2b8d8866..f098006c7 100644 --- a/src/g_hexen/a_hexenmisc.cpp +++ b/src/g_hexen/a_hexenmisc.cpp @@ -24,7 +24,6 @@ #include "serializer.h" // Include all the Hexen stuff here to reduce compile time -#include "a_fighterhammer.cpp" #include "a_fighterplayer.cpp" #include "a_fighterquietus.cpp" #include "a_flechette.cpp" diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index e9d931520..2d2c3eb01 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -664,6 +664,16 @@ bool AWeapon::CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo, int am return false; } +DEFINE_ACTION_FUNCTION(AWeapon, CheckAmmo) +{ + PARAM_SELF_PROLOGUE(AWeapon); + PARAM_INT(mode); + PARAM_BOOL(autoswitch); + PARAM_BOOL_DEF(require); + PARAM_INT_DEF(ammocnt); + ACTION_RETURN_BOOL(self->CheckAmmo(mode, autoswitch, require, ammocnt)); +} + //=========================================================================== // // AWeapon :: DepleteAmmo diff --git a/wadsrc/static/zscript/hexen/fighterhammer.txt b/wadsrc/static/zscript/hexen/fighterhammer.txt index f415cbb72..655e59379 100644 --- a/wadsrc/static/zscript/hexen/fighterhammer.txt +++ b/wadsrc/static/zscript/hexen/fighterhammer.txt @@ -3,6 +3,8 @@ class FWeapHammer : FighterWeapon { + const HAMMER_RANGE = 1.5 * MELEERANGE; + Default { +BLOODSPLATTER @@ -18,9 +20,6 @@ class FWeapHammer : FighterWeapon Tag "$TAG_FWEAPHAMMER"; } - action native void A_FHammerAttack(); - action native void A_FHammerThrow(); - States { Spawn: @@ -50,6 +49,87 @@ class FWeapHammer : FighterWeapon FHMR A 1; Goto Ready; } + + //============================================================================ + // + // A_FHammerAttack + // + //============================================================================ + + action void A_FHammerAttack() + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + + int damage = 60+(random[HammerAtk]() & 63); + for (int i = 0; i < 16; i++) + { + for (int j = 1; j >= -1; j -= 2) + { + double ang = angle + j*i*(45. / 32); + double slope = AimLineAttack(ang, HAMMER_RANGE, t, 0., ALF_CHECK3D); + if (t.linetarget != null) + { + LineAttack(ang, HAMMER_RANGE, slope, damage, 'Melee', "HammerPuff", true, t); + if (t.linetarget != null) + { + AdjustPlayerAngle(t); + if (t.linetarget.bIsMonster || t.linetarget.player) + { + t.linetarget.Thrust(10, t.angleFromSource); + } + weaponspecial = false; // Don't throw a hammer + return; + } + } + } + } + // didn't find any targets in meleerange, so set to throw out a hammer + double slope = AimLineAttack (angle, HAMMER_RANGE, null, 0., ALF_CHECK3D); + weaponspecial = (LineAttack (angle, HAMMER_RANGE, slope, damage, 'Melee', "HammerPuff", true) == null); + + // Don't spawn a hammer if the player doesn't have enough mana + if (player.ReadyWeapon == null || + !player.ReadyWeapon.CheckAmmo (player.ReadyWeapon.bAltFire ? + Weapon.AltFire : Weapon.PrimaryFire, false, true)) + { + weaponspecial = false; + } + } + + //============================================================================ + // + // A_FHammerThrow + // + //============================================================================ + + action void A_FHammerThrow() + { + if (player == null) + { + return; + } + + if (!weaponspecial) + { + return; + } + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire, false)) + return; + } + Actor mo = SpawnPlayerMissile ("HammerMissile"); + if (mo) + { + mo.special1 = 0; + } + } } // Hammer Missile ----------------------------------------------------------- @@ -76,7 +156,7 @@ class HammerMissile : Actor FHFX CDEFGH 2 Bright; Loop; Death: - FHFX I 3 Bright A_SetTranslucent(1,1); + FHFX I 3 Bright A_SetRenderStyle(1, STYLE_Add); FHFX J 3 Bright; FHFX K 3 Bright A_Explode (128, 128, 0); FHFX LM 3 Bright; diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index f6c95f8bd..54a2b0ba9 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -529,6 +529,13 @@ class PuzzleItem : Inventory native class Weapon : StateProvider native { + enum EFireMode + { + PrimaryFire, + AltFire, + EitherFire + }; + native uint WeaponFlags; native class AmmoType1, AmmoType2; // Types of ammo used by this weapon native int AmmoGive1, AmmoGive2; // Amount of each ammo to get when picking up weapon @@ -572,6 +579,7 @@ class Weapon : StateProvider native Stop; } + native bool CheckAmmo(int fireMode, bool autoSwitch, bool requireAmmo = false, int ammocount = -1); native bool DepleteAmmo(bool altFire, bool checkEnough = true, int ammouse = -1); native virtual void EndPowerup(); From 80f233cd0b77d0ca264329d524298e32175ef99b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 26 Nov 2016 22:25:49 +0100 Subject: [PATCH 125/185] - scriptified the fighter's fist. --- src/CMakeLists.txt | 1 - src/g_hexen/a_fighterplayer.cpp | 142 -------------------- src/g_hexen/a_hexenglobal.h | 20 --- src/g_hexen/a_hexenmisc.cpp | 1 - src/g_hexen/a_magestaff.cpp | 8 ++ src/g_shared/a_weapons.cpp | 5 + wadsrc/static/zscript/actor.txt | 1 - wadsrc/static/zscript/hexen/baseweapons.txt | 39 +++++- wadsrc/static/zscript/hexen/fighterfist.txt | 81 ++++++++++- 9 files changed, 129 insertions(+), 169 deletions(-) delete mode 100644 src/g_hexen/a_fighterplayer.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c3e241900..a57ae9c3a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -855,7 +855,6 @@ set( NOT_COMPILED_SOURCE_FILES ${OTHER_SYSTEM_SOURCES} sc_man_scanner.h sc_man_scanner.re - g_hexen/a_fighterplayer.cpp g_hexen/a_fighterquietus.cpp g_hexen/a_flechette.cpp g_hexen/a_flies.cpp diff --git a/src/g_hexen/a_fighterplayer.cpp b/src/g_hexen/a_fighterplayer.cpp deleted file mode 100644 index 4f1d1fd3b..000000000 --- a/src/g_hexen/a_fighterplayer.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/* -#include "actor.h" -#include "gi.h" -#include "m_random.h" -#include "s_sound.h" -#include "d_player.h" -#include "a_action.h" -#include "p_local.h" -#include "a_action.h" -#include "a_hexenglobal.h" -#include "vm.h" -*/ - -IMPLEMENT_CLASS(AFighterWeapon, false, false) -IMPLEMENT_CLASS(AClericWeapon, false, false) -IMPLEMENT_CLASS(AMageWeapon, false, false) - -static FRandom pr_fpatk ("FPunchAttack"); - -//============================================================================ -// -// AdjustPlayerAngle -// -//============================================================================ - -#define MAX_ANGLE_ADJUST (5.) - -void AdjustPlayerAngle (AActor *pmo, FTranslatedLineTarget *t) -{ - // normally this will adjust relative to the actual direction to the target, - // but with arbitrary portals that cannot be calculated so using the actual - // attack angle is the only option. - DAngle atkangle = t->unlinked ? t->angleFromSource : pmo->AngleTo(t->linetarget); - DAngle difference = deltaangle(pmo->Angles.Yaw, atkangle); - if (fabs(difference) > MAX_ANGLE_ADJUST) - { - if (difference > 0) - { - pmo->Angles.Yaw += MAX_ANGLE_ADJUST; - } - else - { - pmo->Angles.Yaw -= MAX_ANGLE_ADJUST; - } - } - else - { - pmo->Angles.Yaw = t->angleFromSource; - } -} - -DEFINE_ACTION_FUNCTION(AActor, AdjustPlayerAngle) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_POINTER(t, FTranslatedLineTarget); - AdjustPlayerAngle(self, t); - return 0; -} -//============================================================================ -// -// TryPunch -// -// Returns true if an actor was punched, false if not. -// -//============================================================================ - -static bool TryPunch(APlayerPawn *pmo, DAngle angle, int damage, int power) -{ - PClassActor *pufftype; - FTranslatedLineTarget t; - DAngle slope; - - slope = P_AimLineAttack (pmo, angle, 2*MELEERANGE, &t); - if (t.linetarget != NULL) - { - if (++pmo->weaponspecial >= 3) - { - damage <<= 1; - power *= 3; - pufftype = PClass::FindActor("HammerPuff"); - } - else - { - pufftype = PClass::FindActor("PunchPuff"); - } - P_LineAttack (pmo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, pufftype, true, &t); - if (t.linetarget != NULL) - { - if (t.linetarget->player != NULL || - (t.linetarget->Mass != INT_MAX && (t.linetarget->flags3 & MF3_ISMONSTER))) - { - t.linetarget->Thrust(t.angleFromSource, power); - } - AdjustPlayerAngle (pmo, &t); - return true; - } - } - return false; -} - -//============================================================================ -// -// A_FPunchAttack -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FPunchAttack) -{ - PARAM_ACTION_PROLOGUE(AActor); - - int damage; - int i; - player_t *player; - - if (nullptr == (player = self->player)) - { - return 0; - } - APlayerPawn *pmo = player->mo; - - damage = 40+(pr_fpatk()&15); - for (i = 0; i < 16; i++) - { - if (TryPunch(pmo, pmo->Angles.Yaw + i*(45./16), damage, 2) || - TryPunch(pmo, pmo->Angles.Yaw - i*(45./16), damage, 2)) - { // hit something - if (pmo->weaponspecial >= 3) - { - pmo->weaponspecial = 0; - P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->FindState("Fire2")); - S_Sound (pmo, CHAN_VOICE, "*fistgrunt", 1, ATTN_NORM); - } - return 0; - } - } - // didn't find any creatures, so try to strike any walls - pmo->weaponspecial = 0; - - DAngle slope = P_AimLineAttack (pmo, pmo->Angles.Yaw, MELEERANGE); - P_LineAttack (pmo, pmo->Angles.Yaw, MELEERANGE, slope, damage, NAME_Melee, PClass::FindActor("PunchPuff"), true); - return 0; -} diff --git a/src/g_hexen/a_hexenglobal.h b/src/g_hexen/a_hexenglobal.h index dc174b32a..277d1bff1 100644 --- a/src/g_hexen/a_hexenglobal.h +++ b/src/g_hexen/a_hexenglobal.h @@ -3,26 +3,6 @@ #include "d_player.h" -void AdjustPlayerAngle(AActor *pmo, FTranslatedLineTarget *t); - -class AFighterWeapon : public AWeapon -{ - DECLARE_CLASS (AFighterWeapon, AWeapon); -public: -}; - -class AClericWeapon : public AWeapon -{ - DECLARE_CLASS (AClericWeapon, AWeapon); -public: -}; - -class AMageWeapon : public AWeapon -{ - DECLARE_CLASS (AMageWeapon, AWeapon); -public: -}; - class AArtiPoisonBag : public AInventory { DECLARE_CLASS (AArtiPoisonBag, AInventory) diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp index f098006c7..49c1369b3 100644 --- a/src/g_hexen/a_hexenmisc.cpp +++ b/src/g_hexen/a_hexenmisc.cpp @@ -24,7 +24,6 @@ #include "serializer.h" // Include all the Hexen stuff here to reduce compile time -#include "a_fighterplayer.cpp" #include "a_fighterquietus.cpp" #include "a_flechette.cpp" #include "a_flies.cpp" diff --git a/src/g_hexen/a_magestaff.cpp b/src/g_hexen/a_magestaff.cpp index 78d9edec0..27e9f5732 100644 --- a/src/g_hexen/a_magestaff.cpp +++ b/src/g_hexen/a_magestaff.cpp @@ -11,6 +11,14 @@ #include "doomstat.h" */ +class AMageWeapon : public AWeapon +{ + DECLARE_CLASS (AMageWeapon, AWeapon); +public: +}; + +IMPLEMENT_CLASS(AMageWeapon, false, false) + static FRandom pr_mstafftrack ("MStaffTrack"); static FRandom pr_bloodscourgedrop ("BloodScourgeDrop"); diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index 2d2c3eb01..b19896e91 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -838,6 +838,7 @@ FState *AWeapon::GetUpState () stack.Call(func, params, 1, &ret, 1, nullptr); return retval; } + return nullptr; } //=========================================================================== @@ -858,6 +859,7 @@ FState *AWeapon::GetDownState () stack.Call(func, params, 1, &ret, 1, nullptr); return retval; } + return nullptr; } //=========================================================================== @@ -878,6 +880,7 @@ FState *AWeapon::GetReadyState () stack.Call(func, params, 1, &ret, 1, nullptr); return retval; } + return nullptr; } //=========================================================================== @@ -898,6 +901,7 @@ FState *AWeapon::GetAtkState (bool hold) stack.Call(func, params, 2, &ret, 1, nullptr); return retval; } + return nullptr; } //=========================================================================== @@ -918,6 +922,7 @@ FState *AWeapon::GetAltAtkState (bool hold) stack.Call(func, params, 2, &ret, 1, nullptr); return retval; } + return nullptr; } //=========================================================================== diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 2b1ba6a5a..34d74760c 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -268,7 +268,6 @@ class Actor : Thinker native virtual native bool SpecialBlastHandling (Actor source, double strength); - native void AdjustPlayerAngle(FTranslatedLineTarget t); native static readonly GetDefaultByType(class cls); native static double GetDefaultSpeed(class type); native void RemoveFromHash(); diff --git a/wadsrc/static/zscript/hexen/baseweapons.txt b/wadsrc/static/zscript/hexen/baseweapons.txt index eb685a873..4c84ed780 100644 --- a/wadsrc/static/zscript/hexen/baseweapons.txt +++ b/wadsrc/static/zscript/hexen/baseweapons.txt @@ -1,7 +1,7 @@ // The Doom and Heretic players are not excluded from pickup in case // somebody wants to use these weapons with either of those games. -class FighterWeapon : Weapon native +class FighterWeapon : Weapon { Default { @@ -10,7 +10,7 @@ class FighterWeapon : Weapon native } } -class ClericWeapon : Weapon native +class ClericWeapon : Weapon { Default { @@ -27,3 +27,38 @@ class MageWeapon : Weapon native Inventory.ForbiddenTo "FighterPlayer", "ClericPlayer"; } } + +extend class Actor +{ + //============================================================================ + // + // AdjustPlayerAngle + // + //============================================================================ + + const MAX_ANGLE_ADJUST = (5.); + + void AdjustPlayerAngle(FTranslatedLineTarget t) + { + // normally this will adjust relative to the actual direction to the target, + // but with arbitrary portals that cannot be calculated so using the actual + // attack angle is the only option. + double atkangle = t.unlinked ? t.angleFromSource : AngleTo(t.linetarget); + double difference = deltaangle(Angle, atkangle); + if (abs(difference) > MAX_ANGLE_ADJUST) + { + if (difference > 0) + { + angle += MAX_ANGLE_ADJUST; + } + else + { + angle -= MAX_ANGLE_ADJUST; + } + } + else + { + angle = t.angleFromSource; + } + } +} \ No newline at end of file diff --git a/wadsrc/static/zscript/hexen/fighterfist.txt b/wadsrc/static/zscript/hexen/fighterfist.txt index 8428ebe7d..712055e6e 100644 --- a/wadsrc/static/zscript/hexen/fighterfist.txt +++ b/wadsrc/static/zscript/hexen/fighterfist.txt @@ -13,8 +13,6 @@ class FWeapFist : FighterWeapon Tag "$TAG_FWEAPFIST"; } - action native void A_FPunchAttack(); - States { Select: @@ -44,6 +42,85 @@ class FWeapFist : FighterWeapon FPCH E 10 Offset (0, 150); Goto Ready; } + + //============================================================================ + // + // TryPunch + // + // Returns true if an actor was punched, false if not. + // + //============================================================================ + + private action bool TryPunch(double angle, int damage, int power) + { + Class pufftype; + FTranslatedLineTarget t; + + double slope = AimLineAttack (angle, 2*MELEERANGE, t); + if (t.linetarget != null) + { + if (++weaponspecial >= 3) + { + damage <<= 1; + power *= 3; + pufftype = "HammerPuff"; + } + else + { + pufftype = "PunchPuff"; + } + LineAttack (angle, 2*MELEERANGE, slope, damage, 'Melee', pufftype, true, t); + if (t.linetarget != null) + { + // The mass threshold has been changed to CommanderKeen's value which has been used most often for 'unmovable' stuff. + if (t.linetarget.player != null || + (t.linetarget.Mass < 10000000 && (t.linetarget.bIsMonster))) + { + if (!t.linetarget.bDontThrust) + t.linetarget.Thrust(power, t.angleFromSource); + } + AdjustPlayerAngle(t); + return true; + } + } + return false; + } + + //============================================================================ + // + // A_FPunchAttack + // + //============================================================================ + + action void A_FPunchAttack() + { + if (player == null) + { + return; + } + + int damage = 40 + (random[FighterAtk]() & 15); + for (int i = 0; i < 16; i++) + { + if (TryPunch(angle + i*(45./16), damage, 2) || + TryPunch(angle - i*(45./16), damage, 2)) + { // hit something + if (weaponspecial >= 3) + { + weaponspecial = 0; + player.SetPsprite(PSP_WEAPON, player.ReadyWeapon.FindState("Fire2")); + A_PlaySound ("*fistgrunt", CHAN_VOICE); + } + return; + } + } + // didn't find any creatures, so try to strike any walls + weaponspecial = 0; + + double slope = AimLineAttack (angle, MELEERANGE); + LineAttack (angle, MELEERANGE, slope, damage, 'Melee', "PunchPuff", true); + } + } // Punch puff --------------------------------------------------------------- From 796c262285c3cbafe669346acfe2ef8a5506b609 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 26 Nov 2016 23:05:16 +0100 Subject: [PATCH 126/185] - scriptified the Quietus. --- src/CMakeLists.txt | 1 - src/g_hexen/a_fighterquietus.cpp | 146 ------------------ src/g_hexen/a_hexenmisc.cpp | 1 - wadsrc/static/zscript/actor.txt | 1 - wadsrc/static/zscript/hexen/baseweapons.txt | 20 +++ wadsrc/static/zscript/hexen/fighterboss.txt | 20 ++- .../static/zscript/hexen/fighterquietus.txt | 61 +++++++- 7 files changed, 94 insertions(+), 156 deletions(-) delete mode 100644 src/g_hexen/a_fighterquietus.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a57ae9c3a..06028ecff 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -855,7 +855,6 @@ set( NOT_COMPILED_SOURCE_FILES ${OTHER_SYSTEM_SOURCES} sc_man_scanner.h sc_man_scanner.re - g_hexen/a_fighterquietus.cpp g_hexen/a_flechette.cpp g_hexen/a_flies.cpp g_hexen/a_healingradius.cpp diff --git a/src/g_hexen/a_fighterquietus.cpp b/src/g_hexen/a_fighterquietus.cpp deleted file mode 100644 index 458d1415b..000000000 --- a/src/g_hexen/a_fighterquietus.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/* -#include "actor.h" -#include "gi.h" -#include "m_random.h" -#include "s_sound.h" -#include "d_player.h" -#include "a_action.h" -#include "p_local.h" -#include "p_pspr.h" -#include "gstrings.h" -#include "a_hexenglobal.h" -#include "a_weaponpiece.h" -#include "vm.h" -*/ - -static FRandom pr_quietusdrop ("QuietusDrop"); -static FRandom pr_fswordflame ("FSwordFlame"); - -//========================================================================== - -//============================================================================ -// -// A_DropQuietusPieces -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_DropWeaponPieces) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_CLASS(p1, AActor); - PARAM_CLASS(p2, AActor); - PARAM_CLASS(p3, AActor); - - for (int i = 0, j = 0; i < 3; ++i) - { - PClassActor *cls = j == 0 ? p1 : j == 1 ? p2 : p3; - if (cls) - { - AActor *piece = Spawn (cls, self->Pos(), ALLOW_REPLACE); - if (piece != NULL) - { - piece->Vel = self->Vel + DAngle(i*120.).ToVector(1); - piece->flags |= MF_DROPPED; - j = (j == 0) ? (pr_quietusdrop() & 1) + 1 : 3-j; - } - } - } - return 0; -} - - - -// Fighter Sword Missile ---------------------------------------------------- - -class AFSwordMissile : public AActor -{ - DECLARE_CLASS (AFSwordMissile, AActor) -public: - int DoSpecialDamage(AActor *victim, int damage, FName damagetype); -}; - -IMPLEMENT_CLASS(AFSwordMissile, false, false) - -int AFSwordMissile::DoSpecialDamage(AActor *victim, int damage, FName damagetype) -{ - if (victim->player) - { - damage -= damage >> 2; - } - return damage; -} - -//============================================================================ -// -// A_FSwordAttack -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FSwordAttack) -{ - PARAM_ACTION_PROLOGUE(AActor); - - player_t *player; - - if (NULL == (player = self->player)) - { - return 0; - } - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - P_SpawnPlayerMissile (self, 0, 0, -10, RUNTIME_CLASS(AFSwordMissile), self->Angles.Yaw + (45./4)); - P_SpawnPlayerMissile (self, 0, 0, -5, RUNTIME_CLASS(AFSwordMissile), self->Angles.Yaw + (45./8)); - P_SpawnPlayerMissile (self, 0, 0, 0, RUNTIME_CLASS(AFSwordMissile), self->Angles.Yaw); - P_SpawnPlayerMissile (self, 0, 0, 5, RUNTIME_CLASS(AFSwordMissile), self->Angles.Yaw - (45./8)); - P_SpawnPlayerMissile (self, 0, 0, 10, RUNTIME_CLASS(AFSwordMissile), self->Angles.Yaw - (45./4)); - S_Sound (self, CHAN_WEAPON, "FighterSwordFire", 1, ATTN_NORM); - return 0; -} - -//============================================================================ -// -// A_FSwordFlames -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FSwordFlames) -{ - PARAM_SELF_PROLOGUE(AActor); - - int i; - - for (i = 1+(pr_fswordflame()&3); i; i--) - { - double xo = (pr_fswordflame() - 128) / 16.; - double yo = (pr_fswordflame() - 128) / 16.; - double zo = (pr_fswordflame() - 128) / 8.; - Spawn ("FSwordFlame", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE); - } - return 0; -} - -//============================================================================ -// -// A_FighterAttack -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FighterAttack) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (!self->target) return 0; - - P_SpawnMissileAngle(self, RUNTIME_CLASS(AFSwordMissile), self->Angles.Yaw + (45. / 4), 0); - P_SpawnMissileAngle(self, RUNTIME_CLASS(AFSwordMissile), self->Angles.Yaw + (45. / 8), 0); - P_SpawnMissileAngle(self, RUNTIME_CLASS(AFSwordMissile), self->Angles.Yaw, 0); - P_SpawnMissileAngle(self, RUNTIME_CLASS(AFSwordMissile), self->Angles.Yaw - (45. / 8), 0); - P_SpawnMissileAngle(self, RUNTIME_CLASS(AFSwordMissile), self->Angles.Yaw - (45. / 4), 0); - S_Sound (self, CHAN_WEAPON, "FighterSwordFire", 1, ATTN_NORM); - return 0; -} - diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp index 49c1369b3..e00b72583 100644 --- a/src/g_hexen/a_hexenmisc.cpp +++ b/src/g_hexen/a_hexenmisc.cpp @@ -24,7 +24,6 @@ #include "serializer.h" // Include all the Hexen stuff here to reduce compile time -#include "a_fighterquietus.cpp" #include "a_flechette.cpp" #include "a_flies.cpp" #include "a_healingradius.cpp" diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 34d74760c..0adc0f1eb 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -688,7 +688,6 @@ class Actor : Thinker native native void A_DropFire(); native void A_GiveQuestItem(int itemno); native void A_RemoveForcefield(); - native void A_DropWeaponPieces(class p1, class p2, class p3); native void A_SetAngle(double angle = 0, int flags = 0, int ptr = AAPTR_DEFAULT); native void A_SetPitch(double pitch, int flags = 0, int ptr = AAPTR_DEFAULT); native void A_SetRoll(double roll, int flags = 0, int ptr = AAPTR_DEFAULT); diff --git a/wadsrc/static/zscript/hexen/baseweapons.txt b/wadsrc/static/zscript/hexen/baseweapons.txt index 4c84ed780..b7e2bd398 100644 --- a/wadsrc/static/zscript/hexen/baseweapons.txt +++ b/wadsrc/static/zscript/hexen/baseweapons.txt @@ -61,4 +61,24 @@ extend class Actor angle = t.angleFromSource; } } + + //============================================================================ + // + // A_DropQuietusPieces + // + //============================================================================ + + void A_DropWeaponPieces(class p1, class p2, class p3) + { + for (int i = 0, j = 0; i < 3; ++i) + { + Actor piece = Spawn (j == 0 ? p1 : j == 1 ? p2 : p3, Pos, ALLOW_REPLACE); + if (piece != null) + { + piece.Vel = self.Vel + AngleToVector(i * 120., 1); + piece.bDropped = true; + j = (j == 0) ? (random[PieceDrop]() & 1) + 1 : 3-j; + } + } + } } \ No newline at end of file diff --git a/wadsrc/static/zscript/hexen/fighterboss.txt b/wadsrc/static/zscript/hexen/fighterboss.txt index 8e862de30..9871cf571 100644 --- a/wadsrc/static/zscript/hexen/fighterboss.txt +++ b/wadsrc/static/zscript/hexen/fighterboss.txt @@ -19,8 +19,6 @@ class FighterBoss : Actor Obituary "$OB_FBOSS"; } - native void A_FighterAttack(); - States { Spawn: @@ -80,4 +78,22 @@ class FighterBoss : Actor FDTH V 4 Bright; Stop; } + + //============================================================================ + // + // A_FighterAttack + // + //============================================================================ + + void A_FighterAttack() + { + if (!target) return; + + SpawnMissileAngle("FSwordMissile", Angle + (45. / 4), 0); + SpawnMissileAngle("FSwordMissile", Angle + (45. / 8), 0); + SpawnMissileAngle("FSwordMissile", Angle, 0); + SpawnMissileAngle("FSwordMissile", Angle - (45. / 8), 0); + SpawnMissileAngle("FSwordMissile", Angle - (45. / 4), 0); + A_PlaySound ("FighterSwordFire", CHAN_WEAPON); + } } diff --git a/wadsrc/static/zscript/hexen/fighterquietus.txt b/wadsrc/static/zscript/hexen/fighterquietus.txt index 7c94f7901..53388eece 100644 --- a/wadsrc/static/zscript/hexen/fighterquietus.txt +++ b/wadsrc/static/zscript/hexen/fighterquietus.txt @@ -97,8 +97,6 @@ class FWeapQuietus : FighterWeapon Tag "$TAG_FWEAPQUIETUS"; } - action native void A_FSwordAttack(); - States { Spawn: @@ -127,11 +125,40 @@ class FWeapQuietus : FighterWeapon FSRD B 1 Bright Offset (5, 40); Goto Ready; } + + //============================================================================ + // + // A_FSwordAttack + // + //============================================================================ + + action void A_FSwordAttack() + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + SpawnPlayerMissile ("FSwordMissile", Angle + (45./4),0, 0, -10); + SpawnPlayerMissile ("FSwordMissile", Angle + (45./8),0, 0, -5); + SpawnPlayerMissile ("FSwordMissile", Angle ,0, 0, 0); + SpawnPlayerMissile ("FSwordMissile", Angle - (45./8),0, 0, 5); + SpawnPlayerMissile ("FSwordMissile", Angle - (45./4),0, 0, 10); + A_PlaySound ("FighterSwordFire", CHAN_WEAPON); + } + + } // Fighter Sword Missile ---------------------------------------------------- -class FSwordMissile : Actor native +class FSwordMissile : Actor { Default { @@ -146,8 +173,6 @@ class FSwordMissile : Actor native Obituary "$OB_MPFWEAPQUIETUS"; } - native void A_FSwordFlames(); - States { Spawn: @@ -164,6 +189,32 @@ class FSwordMissile : Actor native FSFX KLM 3 Bright; Stop; } + + override int DoSpecialDamage(Actor victim, int damage, Name damagetype) + { + if (victim.player) + { + damage -= damage >> 2; + } + return damage; + } + + //============================================================================ + // + // A_FSwordFlames + // + //============================================================================ + + void A_FSwordFlames() + { + for (int i = 1+(random[FSwordFlame]()&3); i; i--) + { + double xo = (random[FSwordFlame]() - 128) / 16.; + double yo = (random[FSwordFlame]() - 128) / 16.; + double zo = (random[FSwordFlame]() - 128) / 8.; + Spawn ("FSwordFlame", Vec3Offset(xo, yo, zo), ALLOW_REPLACE); + } + } } // Fighter Sword Flame ------------------------------------------------------ From 547973c8bab2818125207a87ba987974a08d5b76 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 26 Nov 2016 23:28:21 +0100 Subject: [PATCH 127/185] Rewrite OWallMost and WallMost to contain no build code --- src/r_segs.cpp | 288 ++++++++++++++++--------------------------------- 1 file changed, 90 insertions(+), 198 deletions(-) diff --git a/src/r_segs.cpp b/src/r_segs.cpp index 369722242..1defd253b 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -2508,232 +2508,124 @@ void R_StoreWallRange (int start, int stop) ds_p++; } -int OWallMost (short *mostbuf, double z, const FWallCoords *wallc) +int WallMostAny(short *mostbuf, double z1, double z2, const FWallCoords *wallc) { - int bad, ix1, ix2; - double y, iy1, iy2; - double s1, s2, s3, s4; + float y1 = (float)(CenterY - z1 * InvZtoScale / wallc->sz1); + float y2 = (float)(CenterY - z2 * InvZtoScale / wallc->sz2); - z = -z; - s1 = globaluclip * wallc->sz1; s2 = globaluclip * wallc->sz2; - s3 = globaldclip * wallc->sz1; s4 = globaldclip * wallc->sz2; - bad = (zs3)<<2)+((z>s4)<<3); - - if ((bad&3) == 3) - { // entire line is above the screen - memset (&mostbuf[wallc->sx1], 0, (wallc->sx2 - wallc->sx1)*sizeof(mostbuf[0])); - return bad; - } - - if ((bad&12) == 12) - { // entire line is below the screen - clearbufshort (&mostbuf[wallc->sx1], wallc->sx2 - wallc->sx1, viewheight); - return bad; - } - ix1 = wallc->sx1; iy1 = wallc->sz1; - ix2 = wallc->sx2; iy2 = wallc->sz2; - if (bad & 3) - { // the line intersects the top of the screen - double t = (z-s1) / (s2-s1); - double inty = wallc->sz1 + t * (wallc->sz2 - wallc->sz1); - int xcross = xs_RoundToInt(wallc->sx1 + (t * wallc->sz2 * (wallc->sx2 - wallc->sx1)) / inty); - - if ((bad & 3) == 2) - { // the right side is above the screen - if (wallc->sx1 <= xcross) { iy2 = inty; ix2 = xcross; } - if (wallc->sx2 > xcross) memset (&mostbuf[xcross], 0, (wallc->sx2-xcross)*sizeof(mostbuf[0])); - } - else - { // the left side is above the screen - if (xcross <= wallc->sx2) { iy1 = inty; ix1 = xcross; } - if (xcross > wallc->sx1) memset (&mostbuf[wallc->sx1], 0, (xcross-wallc->sx1)*sizeof(mostbuf[0])); - } - } - - if (bad & 12) - { // the line intersects the bottom of the screen - double t = (z-s3) / (s4-s3); - double inty = wallc->sz1 + t * (wallc->sz2 - wallc->sz1); - int xcross = xs_RoundToInt(wallc->sx1 + (t * wallc->sz2 * (wallc->sx2 - wallc->sx1)) / inty); - - if ((bad & 12) == 8) - { // the right side is below the screen - if (wallc->sx1 <= xcross) { iy2 = inty; ix2 = xcross; } - if (wallc->sx2 > xcross) clearbufshort (&mostbuf[xcross], wallc->sx2 - xcross, viewheight); - } - else - { // the left side is below the screen - if (xcross <= wallc->sx2) { iy1 = inty; ix1 = xcross; } - if (xcross > wallc->sx1) clearbufshort (&mostbuf[wallc->sx1], xcross - wallc->sx1, viewheight); - } - } - - y = z * InvZtoScale / iy1; - if (ix2 == ix1) + if (y1 < 0 && y2 < 0) // entire line is above screen { - mostbuf[ix1] = (short)xs_RoundToInt(y + CenterY); + memset(&mostbuf[wallc->sx1], 0, (wallc->sx2 - wallc->sx1) * sizeof(mostbuf[0])); + return 3; + } + else if (y1 > viewheight && y2 > viewheight) // entire line is below screen + { + clearbufshort(&mostbuf[wallc->sx1], wallc->sx2 - wallc->sx1, viewheight); + return 12; + } + + if (wallc->sx2 <= wallc->sx1) + return 0; + + float rcp_delta = 1.0f / (wallc->sx2 - wallc->sx1); + if (y1 >= 0.0f && y2 >= 0.0f && xs_RoundToInt(y1) <= viewheight && xs_RoundToInt(y2) <= viewheight) + { + for (int x = wallc->sx1; x < wallc->sx2; x++) + { + float t = (x - wallc->sx1) * rcp_delta; + float y = y1 * (1.0f - t) + y2 * t; + mostbuf[x] = (short)xs_RoundToInt(y); + } } else { - fixed_t yinc = FLOAT2FIXED(((z * InvZtoScale / iy2) - y) / (ix2 - ix1)); - qinterpolatedown16short (&mostbuf[ix1], ix2-ix1, FLOAT2FIXED(y + CenterY) + FRACUNIT/2, yinc); + for (int x = wallc->sx1; x < wallc->sx2; x++) + { + float t = (x - wallc->sx1) * rcp_delta; + float y = y1 * (1.0f - t) + y2 * t; + mostbuf[x] = (short)clamp(xs_RoundToInt(y), 0, viewheight); + } } - return bad; + + return 0; } -int WallMost (short *mostbuf, const secplane_t &plane, const FWallCoords *wallc) +int OWallMost(short *mostbuf, double z, const FWallCoords *wallc) +{ + return WallMostAny(mostbuf, z, z, wallc); +} + +int WallMost(short *mostbuf, const secplane_t &plane, const FWallCoords *wallc) { if (!plane.isSlope()) { return OWallMost(mostbuf, plane.Zat0() - ViewPos.Z, wallc); } - - double x, y, den, z1, z2, oz1, oz2; - double s1, s2, s3, s4; - int bad, ix1, ix2; - double iy1, iy2; - - // Get Z coordinates at both ends of the line - if (MirrorFlags & RF_XFLIP) - { - x = curline->v2->fX(); - y = curline->v2->fY(); - if (wallc->sx1 == 0 && 0 != (den = wallc->tleft.X - wallc->tright.X + wallc->tleft.Y - wallc->tright.Y)) - { - double frac = (wallc->tleft.Y + wallc->tleft.X) / den; - x -= frac * (x - curline->v1->fX()); - y -= frac * (y - curline->v1->fY()); - } - z1 = ViewPos.Z - plane.ZatPoint(x, y); - - if (wallc->sx2 > wallc->sx1 + 1) - { - x = curline->v1->fX(); - y = curline->v1->fY(); - if (wallc->sx2 == viewwidth && 0 != (den = wallc->tleft.X - wallc->tright.X - wallc->tleft.Y + wallc->tright.Y)) - { - double frac = (wallc->tright.Y - wallc->tright.X) / den; - x += frac * (curline->v2->fX() - x); - y += frac * (curline->v2->fY() - y); - } - z2 = ViewPos.Z - plane.ZatPoint(x, y); - } - else - { - z2 = z1; - } - } else { - x = curline->v1->fX(); - y = curline->v1->fY(); - if (wallc->sx1 == 0 && 0 != (den = wallc->tleft.X - wallc->tright.X + wallc->tleft.Y - wallc->tright.Y)) - { - double frac = (wallc->tleft.Y + wallc->tleft.X) / den; - x += frac * (curline->v2->fX() - x); - y += frac * (curline->v2->fY() - y); - } - z1 = ViewPos.Z - plane.ZatPoint(x, y); - - if (wallc->sx2 > wallc->sx1 + 1) + // Get Z coordinates at both ends of the line + double x, y, den, z1, z2; + if (MirrorFlags & RF_XFLIP) { x = curline->v2->fX(); y = curline->v2->fY(); - if (wallc->sx2 == viewwidth && 0 != (den = wallc->tleft.X - wallc->tright.X - wallc->tleft.Y + wallc->tright.Y)) + if (wallc->sx1 == 0 && 0 != (den = wallc->tleft.X - wallc->tright.X + wallc->tleft.Y - wallc->tright.Y)) { - double frac = (wallc->tright.Y - wallc->tright.X) / den; + double frac = (wallc->tleft.Y + wallc->tleft.X) / den; x -= frac * (x - curline->v1->fX()); y -= frac * (y - curline->v1->fY()); } - z2 = ViewPos.Z - plane.ZatPoint(x, y); + z1 = plane.ZatPoint(x, y) - ViewPos.Z; + + if (wallc->sx2 > wallc->sx1 + 1) + { + x = curline->v1->fX(); + y = curline->v1->fY(); + if (wallc->sx2 == viewwidth && 0 != (den = wallc->tleft.X - wallc->tright.X - wallc->tleft.Y + wallc->tright.Y)) + { + double frac = (wallc->tright.Y - wallc->tright.X) / den; + x += frac * (curline->v2->fX() - x); + y += frac * (curline->v2->fY() - y); + } + z2 = plane.ZatPoint(x, y) - ViewPos.Z; + } + else + { + z2 = z1; + } } else { - z2 = z1; + x = curline->v1->fX(); + y = curline->v1->fY(); + if (wallc->sx1 == 0 && 0 != (den = wallc->tleft.X - wallc->tright.X + wallc->tleft.Y - wallc->tright.Y)) + { + double frac = (wallc->tleft.Y + wallc->tleft.X) / den; + x += frac * (curline->v2->fX() - x); + y += frac * (curline->v2->fY() - y); + } + z1 = plane.ZatPoint(x, y) - ViewPos.Z; + + if (wallc->sx2 > wallc->sx1 + 1) + { + x = curline->v2->fX(); + y = curline->v2->fY(); + if (wallc->sx2 == viewwidth && 0 != (den = wallc->tleft.X - wallc->tright.X - wallc->tleft.Y + wallc->tright.Y)) + { + double frac = (wallc->tright.Y - wallc->tright.X) / den; + x -= frac * (x - curline->v1->fX()); + y -= frac * (y - curline->v1->fY()); + } + z2 = plane.ZatPoint(x, y) - ViewPos.Z; + } + else + { + z2 = z1; + } } + + return WallMostAny(mostbuf, z1, z2, wallc); } - - s1 = globaluclip * wallc->sz1; s2 = globaluclip * wallc->sz2; - s3 = globaldclip * wallc->sz1; s4 = globaldclip * wallc->sz2; - bad = (z1s3)<<2)+((z2>s4)<<3); - - ix1 = wallc->sx1; ix2 = wallc->sx2; - iy1 = wallc->sz1; iy2 = wallc->sz2; - oz1 = z1; oz2 = z2; - - if ((bad&3) == 3) - { // The entire line is above the screen - memset (&mostbuf[ix1], 0, (ix2-ix1)*sizeof(mostbuf[0])); - return bad; - } - - if ((bad&12) == 12) - { // The entire line is below the screen - clearbufshort (&mostbuf[ix1], ix2-ix1, viewheight); - return bad; - - } - - if (bad&3) - { // The line intersects the top of the screen - //inty = intz / (globaluclip>>16) - double t = (oz1-s1) / (s2-s1+oz1-oz2); - double inty = wallc->sz1 + t * (wallc->sz2-wallc->sz1); - double intz = oz1 + t * (oz2-oz1); - int xcross = wallc->sx1 + xs_RoundToInt((t * wallc->sz2 * (wallc->sx2-wallc->sx1)) / inty); - - //t = divscale30((x1<<4)-xcross*yb1[w],xcross*(yb2[w]-yb1[w])-((x2-x1)<<4)); - //inty = yb1[w] + mulscale30(yb2[w]-yb1[w],t); - //intz = z1 + mulscale30(z2-z1,t); - - if ((bad&3) == 2) - { // The right side of the line is above the screen - if (wallc->sx1 <= xcross) { z2 = intz; iy2 = inty; ix2 = xcross; } - memset (&mostbuf[xcross], 0, (wallc->sx2-xcross)*sizeof(mostbuf[0])); - } - else - { // The left side of the line is above the screen - if (xcross <= wallc->sx2) { z1 = intz; iy1 = inty; ix1 = xcross; } - memset (&mostbuf[wallc->sx1], 0, (xcross-wallc->sx1)*sizeof(mostbuf[0])); - } - } - - if (bad&12) - { // The line intersects the bottom of the screen - //inty = intz / (globaldclip>>16) - double t = (oz1-s3) / (s4-s3+oz1-oz2); - double inty = wallc->sz1 + t * (wallc->sz2-wallc->sz1); - double intz = oz1 + t * (oz2-oz1); - int xcross = wallc->sx1 + xs_RoundToInt((t * wallc->sz2 * (wallc->sx2-wallc->sx1)) / inty); - - //t = divscale30((x1<<4)-xcross*yb1[w],xcross*(yb2[w]-yb1[w])-((x2-x1)<<4)); - //inty = yb1[w] + mulscale30(yb2[w]-yb1[w],t); - //intz = z1 + mulscale30(z2-z1,t); - - if ((bad&12) == 8) - { // The right side of the line is below the screen - if (wallc->sx1 <= xcross) { z2 = intz; iy2 = inty; ix2 = xcross; } - if (wallc->sx2 > xcross) clearbufshort (&mostbuf[xcross], wallc->sx2-xcross, viewheight); - } - else - { // The left side of the line is below the screen - if (xcross <= wallc->sx2) { z1 = intz; iy1 = inty; ix1 = xcross; } - if (xcross > wallc->sx1) clearbufshort (&mostbuf[wallc->sx1], xcross-wallc->sx1, viewheight); - } - } - - y = z1 * InvZtoScale / iy1; - if (ix2 == ix1) - { - mostbuf[ix1] = (short)xs_RoundToInt(y + CenterY); - } - else - { - fixed_t yinc = FLOAT2FIXED(((z2 * InvZtoScale / iy2) - y) / (ix2-ix1)); - qinterpolatedown16short (&mostbuf[ix1], ix2-ix1, FLOAT2FIXED(y + CenterY) + FRACUNIT/2, yinc); - } - - return bad; } static void PrepWallRoundFix(fixed_t *lwall, fixed_t walxrepeat, int x1, int x2) From 69d4d36429fbe96d91ca23222dfbfc8a37c81e04 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 27 Nov 2016 00:18:07 +0100 Subject: [PATCH 128/185] - scriptified ArtiHealingRadius. - allow switch/case with names. - fixed break jump target handling for switch/case. This only worked when the break was in the outermost compound statement, those in inner ones were missed. --- src/g_hexen/a_healingradius.cpp | 95 ------------------- src/g_hexen/a_hexenmisc.cpp | 1 - src/p_mobj.cpp | 9 +- src/p_user.cpp | 13 +++ src/scripting/codegeneration/codegen.cpp | 68 ++++++++----- src/scripting/codegeneration/codegen.h | 3 + wadsrc/static/zscript/actor.txt | 2 + wadsrc/static/zscript/hexen/healingradius.txt | 68 ++++++++++++- wadsrc/static/zscript/shared/player.txt | 12 +++ 9 files changed, 151 insertions(+), 120 deletions(-) delete mode 100644 src/g_hexen/a_healingradius.cpp diff --git a/src/g_hexen/a_healingradius.cpp b/src/g_hexen/a_healingradius.cpp deleted file mode 100644 index bf18a7e0e..000000000 --- a/src/g_hexen/a_healingradius.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* -#include "info.h" -#include "a_pickups.h" -#include "a_artifacts.h" -#include "gstrings.h" -#include "p_local.h" -#include "s_sound.h" -#include "m_random.h" -#include "a_action.h" -#include "a_hexenglobal.h" -#include "gi.h" -#include "doomstat.h" -*/ - -#define HEAL_RADIUS_DIST 255. - -static FRandom pr_healradius ("HealRadius"); - -// Healing Radius Artifact -------------------------------------------------- - -class AArtiHealingRadius : public AInventory -{ - DECLARE_CLASS (AArtiHealingRadius, AInventory) -public: - bool Use (bool pickup); -}; - -IMPLEMENT_CLASS(AArtiHealingRadius, false, false) - -bool AArtiHealingRadius::Use (bool pickup) -{ - bool effective = false; - FName mode; - - if (Owner->IsKindOf(RUNTIME_CLASS(APlayerPawn))) - { - mode = static_cast(Owner->GetClass())->HealingRadiusType; - } - - for (int i = 0; i < MAXPLAYERS; ++i) - { - if (playeringame[i] && - players[i].mo != NULL && - players[i].mo->health > 0 && - players[i].mo->Distance2D (Owner) <= HEAL_RADIUS_DIST) - { - // Q: Is it worth it to make this selectable as a player property? - // A: Probably not - but it sure doesn't hurt. - bool gotsome=false; - switch (mode) - { - case NAME_Armor: - for (int j = 0; j < 4; ++j) - { - AHexenArmor *armor = Spawn (); - armor->health = j; - armor->Amount = 1; - if (!armor->CallTryPickup (players[i].mo)) - { - armor->Destroy (); - } - else - { - gotsome = true; - } - } - break; - - case NAME_Mana: - { - int amount = 50 + (pr_healradius() % 50); - - 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; - } - break; - } - - default: - //case NAME_Health: - gotsome = P_GiveBody (players[i].mo, 50 + (pr_healradius()%50)); - break; - } - if (gotsome) - { - S_Sound (players[i].mo, CHAN_AUTO, "MysticIncant", 1, ATTN_NORM); - effective=true; - } - } - } - return effective; - -} diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp index e00b72583..4fc0d4590 100644 --- a/src/g_hexen/a_hexenmisc.cpp +++ b/src/g_hexen/a_hexenmisc.cpp @@ -26,7 +26,6 @@ // Include all the Hexen stuff here to reduce compile time #include "a_flechette.cpp" #include "a_flies.cpp" -#include "a_healingradius.cpp" #include "a_heresiarch.cpp" #include "a_hexenspecialdecs.cpp" #include "a_iceguy.cpp" diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 7e9b8a96b..5abc02e96 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1093,7 +1093,6 @@ DEFINE_ACTION_FUNCTION(AActor, GiveInventoryType) ACTION_RETURN_OBJECT(self->GiveInventoryType(type)); } - //============================================================================ // // AActor :: GiveAmmo @@ -1122,6 +1121,14 @@ bool AActor::GiveAmmo (PClassAmmo *type, int amount) return false; } +DEFINE_ACTION_FUNCTION(AActor, GiveAmmo) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_CLASS(type, AAmmo); + PARAM_INT(amount); + ACTION_RETURN_BOOL(self->GiveAmmo(type, amount)); +} + //============================================================================ // // AActor :: ClearInventory diff --git a/src/p_user.cpp b/src/p_user.cpp index eadbda10e..ce78d04a8 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -3175,6 +3175,19 @@ DEFINE_FIELD(APlayerPawn, FlechetteType) DEFINE_FIELD(APlayerPawn, DamageFade) DEFINE_FIELD(APlayerPawn, ViewBob) +DEFINE_FIELD(PClassPlayerPawn, HealingRadiusType) +DEFINE_FIELD(PClassPlayerPawn, DisplayName) +DEFINE_FIELD(PClassPlayerPawn, SoundClass) +DEFINE_FIELD(PClassPlayerPawn, Face) +DEFINE_FIELD(PClassPlayerPawn, Portrait) +DEFINE_FIELD(PClassPlayerPawn, Slot) +DEFINE_FIELD(PClassPlayerPawn, InvulMode) +DEFINE_FIELD(PClassPlayerPawn, HexenArmor) +DEFINE_FIELD(PClassPlayerPawn, ColorRangeStart) +DEFINE_FIELD(PClassPlayerPawn, ColorRangeEnd) +DEFINE_FIELD(PClassPlayerPawn, ColorSets) +DEFINE_FIELD(PClassPlayerPawn, PainFlashes) + DEFINE_FIELD_X(PlayerInfo, player_t, mo) DEFINE_FIELD_X(PlayerInfo, player_t, playerstate) DEFINE_FIELD_X(PlayerInfo, player_t, original_oldbuttons) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 4562f3ef7..0fb6b172f 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -8338,7 +8338,7 @@ bool FxCompoundStatement::CheckLocalVariable(FName name) FxSwitchStatement::FxSwitchStatement(FxExpression *cond, FArgumentList &content, const FScriptPosition &pos) : FxExpression(EFX_SwitchStatement, pos) { - Condition = new FxIntCast(cond, false); + Condition = cond; Content = std::move(content); } @@ -8352,6 +8352,12 @@ FxExpression *FxSwitchStatement::Resolve(FCompileContext &ctx) CHECKRESOLVED(); SAFE_RESOLVE(Condition, ctx); + if (Condition->ValueType != TypeName) + { + Condition = new FxIntCast(Condition, false); + SAFE_RESOLVE(Condition, ctx); + } + if (Content.Size() == 0) { ScriptPosition.Message(MSG_WARNING, "Empty switch statement"); @@ -8370,15 +8376,15 @@ FxExpression *FxSwitchStatement::Resolve(FCompileContext &ctx) } } + auto outerctrl = ctx.ControlStmt; + ctx.ControlStmt = this; + for (auto &line : Content) { - // Do not resolve breaks, they need special treatment inside switch blocks. - if (line->ExprType != EFX_JumpStatement || static_cast(line)->Token != TK_Break) - { - SAFE_RESOLVE(line, ctx); - line->NeedResult = false; - } + SAFE_RESOLVE(line, ctx); + line->NeedResult = false; } + ctx.ControlStmt = outerctrl; if (Condition->isConstant()) { @@ -8398,6 +8404,12 @@ FxExpression *FxSwitchStatement::Resolve(FCompileContext &ctx) auto casestmt = static_cast(content[i]); if (casestmt->Condition == nullptr) defaultindex = i; else if (casestmt->CaseValue == static_cast(Condition)->GetValue().GetInt()) caseindex = i; + if (casestmt->Condition && casestmt->Condition->ValueType != Condition->ValueType) + { + casestmt->Condition->ScriptPosition.Message(MSG_ERROR, "Type mismatch in case statement"); + delete this; + return nullptr; + } } if (content[i]->ExprType == EFX_JumpStatement && static_cast(content[i])->Token == TK_Break) { @@ -8478,7 +8490,6 @@ ExpEmit FxSwitchStatement::Emit(VMFunctionBuilder *build) ca.jumpaddress = build->Emit(OP_JMP, 0); } size_t DefaultAddress = build->Emit(OP_JMP, 0); - TArray BreakAddresses; bool defaultset = false; for (auto line : Content) @@ -8504,22 +8515,14 @@ ExpEmit FxSwitchStatement::Emit(VMFunctionBuilder *build) } break; - case EFX_JumpStatement: - if (static_cast(line)->Token == TK_Break) - { - BreakAddresses.Push(build->Emit(OP_JMP, 0)); - break; - } - // fall through for continue. - default: line->Emit(build); break; } } - for (auto addr : BreakAddresses) + for (auto addr : Breaks) { - build->BackpatchToHere(addr); + build->BackpatchToHere(addr->Address); } if (!defaultset) build->BackpatchToHere(DefaultAddress); Content.DeleteAndClear(); @@ -8555,7 +8558,7 @@ bool FxSwitchStatement::CheckReturn() FxCaseStatement::FxCaseStatement(FxExpression *cond, const FScriptPosition &pos) : FxExpression(EFX_CaseStatement, pos) { - Condition = cond? new FxIntCast(cond, false) : nullptr; + Condition = cond; } FxCaseStatement::~FxCaseStatement() @@ -8576,7 +8579,17 @@ FxExpression *FxCaseStatement::Resolve(FCompileContext &ctx) delete this; return nullptr; } - CaseValue = static_cast(Condition)->GetValue().GetInt(); + // Case labels can be ints or names. + if (Condition->ValueType != TypeName) + { + Condition = new FxIntCast(Condition, false); + SAFE_RESOLVE(Condition, ctx); + CaseValue = static_cast(Condition)->GetValue().GetInt(); + } + else + { + CaseValue = static_cast(Condition)->GetValue().GetName(); + } } return this; } @@ -8747,10 +8760,13 @@ bool FxIfStatement::CheckReturn() FxExpression *FxLoopStatement::Resolve(FCompileContext &ctx) { + auto outerctrl = ctx.ControlStmt; auto outer = ctx.Loop; + ctx.ControlStmt = this; ctx.Loop = this; auto x = DoResolve(ctx); ctx.Loop = outer; + ctx.ControlStmt = outerctrl; return x; } @@ -9074,9 +9090,17 @@ FxExpression *FxJumpStatement::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); - if (ctx.Loop != nullptr) + if (ctx.ControlStmt != nullptr) { - ctx.Loop->Jumps.Push(this); + if (ctx.ControlStmt == ctx.Loop || Token == TK_Continue) + { + ctx.Loop->Jumps.Push(this); + } + else + { + // break in switch. + static_cast(ctx.ControlStmt)->Breaks.Push(this); + } return this; } else diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index 1110cd6b6..ae0581e05 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -72,6 +72,7 @@ typedef TDeletingArray FArgumentList; struct FCompileContext { + FxExpression *ControlStmt = nullptr; FxLoopStatement *Loop = nullptr; FxCompoundStatement *Block = nullptr; PPrototype *ReturnProto; @@ -1656,6 +1657,8 @@ class FxSwitchStatement : public FxExpression TArray CaseAddresses; public: + TArray Breaks; + FxSwitchStatement(FxExpression *cond, FArgumentList &content, const FScriptPosition &pos); ~FxSwitchStatement(); FxExpression *Resolve(FCompileContext&); diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 0adc0f1eb..cefcd6511 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -357,6 +357,8 @@ class Actor : Thinker native native bool CheckClass(class checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false); native Inventory FindInventory(class itemtype, bool subclass = false); native Inventory GiveInventoryType(class itemtype); + native bool GiveAmmo (Class type, int amount); + native int CountInv(class itemtype, int ptr_select = AAPTR_DEFAULT); native double GetDistance(bool checkz, int ptr = AAPTR_TARGET); native double GetAngle(int flags, int ptr = AAPTR_DEFAULT); diff --git a/wadsrc/static/zscript/hexen/healingradius.txt b/wadsrc/static/zscript/hexen/healingradius.txt index 94d8e2dd5..52b87c15b 100644 --- a/wadsrc/static/zscript/hexen/healingradius.txt +++ b/wadsrc/static/zscript/hexen/healingradius.txt @@ -1,8 +1,10 @@ // Healing Radius Artifact -------------------------------------------------- -class ArtiHealingRadius : Inventory native +class ArtiHealingRadius : Inventory { + const HEAL_RADIUS_DIST = 255.; + Default { +COUNTITEM @@ -21,6 +23,70 @@ class ArtiHealingRadius : Inventory native Spawn: HRAD ABCDEFGHIJKLMNOP 4 Bright; Loop; + } + + override bool Use (bool pickup) + { + bool effective = false; + Name mode = 'Health'; + + PlayerPawn pp = PlayerPawn(Owner); + if (pp) mode = pp.HealingRadiusType; + + for (int i = 0; i < MAXPLAYERS; ++i) + { + PlayerPawn mo = players[i].mo; + if (playeringame[i] && mo != null && mo.health > 0 && mo.Distance2D (Owner) <= HEAL_RADIUS_DIST) + { + // Q: Is it worth it to make this selectable as a player property? + // A: Probably not - but it sure doesn't hurt. + bool gotsome=false; + switch (mode) + { + case 'Armor': + for (int j = 0; j < 4; ++j) + { + HexenArmor armor = HexenArmor(Spawn("HexenArmor")); + armor.health = j; + armor.Amount = 1; + if (!armor.CallTryPickup (mo)) + { + armor.Destroy (); + } + else + { + gotsome = true; + } + } + break; + + case 'Mana': + { + int amount = 50 + (random[HealRadius]() % 50); + + if (mo.GiveAmmo ("Mana1", amount) || + mo.GiveAmmo ("Mana2", amount)) + { + gotsome = true; + } + break; + } + + default: + //case NAME_Health: + gotsome = mo.GiveBody (50 + (random[HealRadius]() % 50)); + break; + } + if (gotsome) + { + mo.A_PlaySound ("MysticIncant", CHAN_AUTO); + effective=true; + } + } + } + return effective; + } + } diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 48d62688b..2d5be6278 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -8,6 +8,18 @@ class PlayerPawn : Actor native native int PlayerFlags; native Inventory InvFirst; // first inventory item displayed on inventory bar native Inventory InvSel; // selected inventory item + native meta String DisplayName; // Display name (used in menus, etc.) + native meta String SoundClass; // Sound class + native meta String Face; // Doom status bar face (when used) + native meta String Portrait; + native meta String Slot[10]; + native meta Name InvulMode; + native meta Name HealingRadiusType; + native meta double HexenArmor[5]; + native meta uint8 ColorRangeStart; // Skin color range + native meta uint8 ColorRangeEnd; + //FPlayerColorSetMap ColorSets; + //PainFlashList PainFlashes; // [GRB] Player class properties native double JumpZ; From ab03b016e9263d03b368a3b4298e5d95bb529558 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 27 Nov 2016 00:41:06 +0100 Subject: [PATCH 129/185] - scriptified the IceGuy. --- src/CMakeLists.txt | 2 - src/g_hexen/a_hexenmisc.cpp | 1 - src/g_hexen/a_iceguy.cpp | 132 ------------------------- src/p_mobj.cpp | 14 +++ wadsrc/static/zscript/actor.txt | 2 +- wadsrc/static/zscript/hexen/iceguy.txt | 103 ++++++++++++++++++- 6 files changed, 113 insertions(+), 141 deletions(-) delete mode 100644 src/g_hexen/a_iceguy.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 06028ecff..c5a54d1ba 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -857,10 +857,8 @@ set( NOT_COMPILED_SOURCE_FILES sc_man_scanner.re g_hexen/a_flechette.cpp g_hexen/a_flies.cpp - g_hexen/a_healingradius.cpp g_hexen/a_heresiarch.cpp g_hexen/a_hexenspecialdecs.cpp - g_hexen/a_iceguy.cpp g_hexen/a_magecone.cpp g_hexen/a_magelightning.cpp g_hexen/a_magestaff.cpp diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp index 4fc0d4590..3223575c8 100644 --- a/src/g_hexen/a_hexenmisc.cpp +++ b/src/g_hexen/a_hexenmisc.cpp @@ -28,7 +28,6 @@ #include "a_flies.cpp" #include "a_heresiarch.cpp" #include "a_hexenspecialdecs.cpp" -#include "a_iceguy.cpp" #include "a_magecone.cpp" #include "a_magelightning.cpp" #include "a_magestaff.cpp" diff --git a/src/g_hexen/a_iceguy.cpp b/src/g_hexen/a_iceguy.cpp deleted file mode 100644 index 1163a117a..000000000 --- a/src/g_hexen/a_iceguy.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/* -#include "actor.h" -#include "info.h" -#include "p_local.h" -#include "s_sound.h" -#include "p_enemy.h" -#include "a_action.h" -#include "m_random.h" -#include "vm.h" -*/ - -static FRandom pr_iceguylook ("IceGuyLook"); -static FRandom pr_iceguychase ("IceGuyChase"); - -static const char *WispTypes[2] = -{ - "IceGuyWisp1", - "IceGuyWisp2", -}; - -//============================================================================ -// -// A_IceGuyLook -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_IceGuyLook) -{ - PARAM_SELF_PROLOGUE(AActor); - - double dist; - DAngle an; - - CALL_ACTION(A_Look, self); - if (pr_iceguylook() < 64) - { - dist = (pr_iceguylook() - 128) * self->radius / 128.; - an = self->Angles.Yaw + 90; - Spawn(WispTypes[pr_iceguylook() & 1], self->Vec3Angle(dist, an, 60.), ALLOW_REPLACE); - } - return 0; -} - -//============================================================================ -// -// A_IceGuyChase -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_IceGuyChase) -{ - PARAM_SELF_PROLOGUE(AActor); - - double dist; - DAngle an; - AActor *mo; - - A_Chase(stack, self); - if (pr_iceguychase() < 128) - { - dist = (pr_iceguychase() - 128) * self->radius / 128.; - an = self->Angles.Yaw + 90; - mo = Spawn(WispTypes[pr_iceguylook() & 1], self->Vec3Angle(dist, an, 60.), ALLOW_REPLACE); - if (mo) - { - mo->Vel = self->Vel; - mo->target = self; - } - } - return 0; -} - -//============================================================================ -// -// A_IceGuyAttack -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_IceGuyAttack) -{ - PARAM_SELF_PROLOGUE(AActor); - - if(!self->target) - { - return 0; - } - P_SpawnMissileXYZ(self->Vec3Angle(self->radius / 2, self->Angles.Yaw + 90, 40.), self, self->target, PClass::FindActor("IceGuyFX")); - P_SpawnMissileXYZ(self->Vec3Angle(self->radius / 2, self->Angles.Yaw - 90, 40.), self, self->target, PClass::FindActor("IceGuyFX")); - S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM); - return 0; -} - -//============================================================================ -// -// A_IceGuyDie -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_IceGuyDie) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->Vel.Zero(); - self->Height = self->GetDefault()->Height; - CALL_ACTION(A_FreezeDeathChunks, self); - return 0; -} - -//============================================================================ -// -// A_IceGuyMissileExplode -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_IceGuyMissileExplode) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo; - unsigned int i; - - for (i = 0; i < 8; i++) - { - mo = P_SpawnMissileAngleZ (self, self->Z()+3, PClass::FindActor("IceGuyFX2"), DAngle(i*45.), -0.3); - if (mo) - { - mo->target = self->target; - } - } - return 0; -} - diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 5abc02e96..2e87729d0 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -6375,6 +6375,20 @@ AActor *P_SpawnMissileXYZ (DVector3 pos, AActor *source, AActor *dest, PClassAct return (!checkspawn || P_CheckMissileSpawn (th, source->radius)) ? th : NULL; } +DEFINE_ACTION_FUNCTION(AActor, SpawnMissileXYZ) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + PARAM_OBJECT(dest, AActor); + PARAM_CLASS(type, AActor); + PARAM_BOOL_DEF(check); + PARAM_OBJECT_DEF(owner, AActor); + ACTION_RETURN_OBJECT(P_SpawnMissileXYZ(DVector3(x,y,z), self, dest, type, check, owner)); +} + + AActor *P_OldSpawnMissile(AActor *source, AActor *owner, AActor *dest, PClassActor *type) { if (source == NULL) diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index cefcd6511..92f1073fd 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -296,6 +296,7 @@ class Actor : Thinker native native bool TestMobjLocation(); native static Actor Spawn(class type, vector3 pos = (0,0,0), int replace = NO_REPLACE); native Actor SpawnMissile(Actor dest, class type, Actor owner = null); + native Actor SpawnMissileXYZ(Vector3 pos, Actor dest, Class type, bool checkspawn = true, Actor owner = null); native Actor SpawnMissileZ (double z, Actor dest, class type); native Actor SpawnMissileAngleZSpeed (double z, class type, double angle, double vz, double speed, Actor owner = null, bool checkspawn = true); native Actor, Actor SpawnPlayerMissile(class type, double angle = 0, double x = 0, double y = 0, double z = 0, out FTranslatedLineTarget pLineTarget = null, bool nofreeaim = false, bool noautoaim = false, int aimflags = 0); @@ -592,7 +593,6 @@ class Actor : Thinker native native void A_FreezeDeath(); native void A_FreezeDeathChunks(); native void A_GenericFreezeDeath(); - native void A_IceGuyDie(); native void A_PlayerScream(); native void A_SkullPop(class skulltype = "BloodySkull"); native void A_CheckPlayerDone(); diff --git a/wadsrc/static/zscript/hexen/iceguy.txt b/wadsrc/static/zscript/hexen/iceguy.txt index 8081d5a61..41105b728 100644 --- a/wadsrc/static/zscript/hexen/iceguy.txt +++ b/wadsrc/static/zscript/hexen/iceguy.txt @@ -22,9 +22,6 @@ class IceGuy : Actor Obituary "$OB_ICEGUY"; } - native void A_IceGuyLook(); - native void A_IceGuyChase(); - native void A_IceGuyAttack(); States { @@ -51,6 +48,84 @@ class IceGuy : Actor ICEY A -1; Goto See; } + + //============================================================================ + // + // SpawnWisp + // + //============================================================================ + + private void SpawnWisp() + { + static const class WispTypes[] = { "IceGuyWisp1", "IceGuyWisp2" }; + + double dist = (random[IceGuyLook]() - 128) * radius / 128.; + double an = angle + 90; + Actor mo = Spawn(WispTypes[random[IceGuyLook]() & 1], Vec3Angle(dist, an, 60.), ALLOW_REPLACE); + if (mo) + { + mo.Vel = Vel; + mo.target = self; + } + } + + //============================================================================ + // + // A_IceGuyLook + // + //============================================================================ + + void A_IceGuyLook() + { + A_Look(); + if (random[IceGuyLook]() < 64) SpawnWisp(); + } + + //============================================================================ + // + // A_IceGuyChase + // + //============================================================================ + + void A_IceGuyChase() + { + A_Chase(); + if (random[IceGuyLook]() < 128) SpawnWisp(); + } + + //============================================================================ + // + // A_IceGuyAttack + // + //============================================================================ + + void A_IceGuyAttack() + { + if(!target) + { + return; + } + SpawnMissileXYZ(Vec3Angle(radius / 2, angle + 90, 40.), target, "IceGuyFX"); + SpawnMissileXYZ(Vec3Angle(radius / 2, angle - 90, 40.), target, "IceGuyFX"); + A_PlaySound (AttackSound, CHAN_WEAPON); + } +} + +extend class Actor +{ + //============================================================================ + // + // A_IceGuyDie (globally accessible) + // + //============================================================================ + + void A_IceGuyDie() + { + Vel = (0,0,0); + Height = Default.Height; + A_FreezeDeathChunks(); + } + } // Ice Guy Projectile ------------------------------------------------------- @@ -69,8 +144,6 @@ class IceGuyFX : Actor DeathSound "IceGuyMissileExplode"; } - native void A_IceGuyMissileExplode(); - States { Spawn: @@ -83,6 +156,25 @@ class IceGuyFX : Actor ICPR H 3 Bright; Stop; } + + + //============================================================================ + // + // A_IceGuyMissileExplode + // + //============================================================================ + + void A_IceGuyMissileExplode() + { + for (int i = 0; i < 8; i++) + { + Actor mo = SpawnMissileAngleZ (pos.z+3, "IceGuyFX2", i*45., -0.3); + if (mo) + { + mo.target = target; + } + } + } } // Ice Guy Projectile's Puff ------------------------------------------------ @@ -183,3 +275,4 @@ class IceGuyWisp2 : IceGuyWisp1 Stop; } } + From 6417c1a7a39b6b5ee40f678219ffdb6c59f5473b Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sun, 27 Nov 2016 00:43:32 +0100 Subject: [PATCH 130/185] Rewrite PrepWall and PrepLWall, plus make them aware of pixel centers --- src/r_segs.cpp | 120 ++++++++++++++++++++----------------------------- 1 file changed, 49 insertions(+), 71 deletions(-) diff --git a/src/r_segs.cpp b/src/r_segs.cpp index 1defd253b..ac5683b9b 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -2628,98 +2628,76 @@ int WallMost(short *mostbuf, const secplane_t &plane, const FWallCoords *wallc) } } -static void PrepWallRoundFix(fixed_t *lwall, fixed_t walxrepeat, int x1, int x2) +void PrepWall(float *vstep, fixed_t *upos, double walxrepeat, int x1, int x2) { - // fix for rounding errors - walxrepeat = abs(walxrepeat); - fixed_t fix = (MirrorFlags & RF_XFLIP) ? walxrepeat-1 : 0; - int x; + float uOverZ = WallT.UoverZorg + WallT.UoverZstep * (float)(x1 + 0.5 - CenterX); + float invZ = WallT.InvZorg + WallT.InvZstep * (float)(x1 + 0.5 - CenterX); + float uGradient = WallT.UoverZstep; + float zGradient = WallT.InvZstep; + float xrepeat = (float)walxrepeat; + float depthScale = (float)(WallT.InvZstep * WallTMapScale2); + float depthOrg = (float)(-WallT.UoverZstep * WallTMapScale2); - if (x1 > 0) + if (xrepeat < 0.0f) { - for (x = x1; x < x2; x++) + for (int x = x1; x < x2; x++) { - if ((unsigned)lwall[x] >= (unsigned)walxrepeat) - { - lwall[x] = fix; - } - else - { - break; - } + float u = uOverZ / invZ; + + upos[x] = (fixed_t)((xrepeat - u * xrepeat) * FRACUNIT); + vstep[x] = depthOrg + u * depthScale; + + uOverZ += uGradient; + invZ += zGradient; } } - fix = walxrepeat - 1 - fix; - for (x = x2-1; x >= x1; x--) + else { - if ((unsigned)lwall[x] >= (unsigned)walxrepeat) + for (int x = x1; x < x2; x++) { - lwall[x] = fix; - } - else - { - break; + float u = uOverZ / invZ; + + upos[x] = (fixed_t)(u * xrepeat * FRACUNIT); + vstep[x] = depthOrg + u * depthScale; + + uOverZ += uGradient; + invZ += zGradient; } } } -void PrepWall (float *swall, fixed_t *lwall, double walxrepeat, int x1, int x2) -{ // swall = scale, lwall = texturecolumn - double top, bot, i; - double xrepeat = fabs(walxrepeat * 65536); - double depth_scale = WallT.InvZstep * WallTMapScale2; - double depth_org = -WallT.UoverZstep * WallTMapScale2; +void PrepLWall(fixed_t *upos, double walxrepeat, int x1, int x2) +{ + float uOverZ = WallT.UoverZorg + WallT.UoverZstep * (float)(x1 + 0.5 - CenterX); + float invZ = WallT.InvZorg + WallT.InvZstep * (float)(x1 + 0.5 - CenterX); + float uGradient = WallT.UoverZstep; + float zGradient = WallT.InvZstep; + float xrepeat = (float)walxrepeat; - i = x1 - centerx; - top = WallT.UoverZorg + WallT.UoverZstep * i; - bot = WallT.InvZorg + WallT.InvZstep * i; - - for (int x = x1; x < x2; x++) + if (xrepeat < 0.0f) { - double frac = top / bot; - if (walxrepeat < 0) + for (int x = x1; x < x2; x++) { - lwall[x] = xs_RoundToInt(xrepeat - frac * xrepeat); + float u = uOverZ / invZ * xrepeat - xrepeat; + + upos[x] = (fixed_t)(u * FRACUNIT); + + uOverZ += uGradient; + invZ += zGradient; } - else - { - lwall[x] = xs_RoundToInt(frac * xrepeat); - } - swall[x] = float(frac * depth_scale + depth_org); - top += WallT.UoverZstep; - bot += WallT.InvZstep; } - PrepWallRoundFix(lwall, FLOAT2FIXED(walxrepeat), x1, x2); -} - -void PrepLWall (fixed_t *lwall, double walxrepeat, int x1, int x2) -{ // lwall = texturecolumn - double top, bot, i; - double xrepeat = fabs(walxrepeat * 65536); - double topstep, botstep; - - i = x1 - centerx; - top = WallT.UoverZorg + WallT.UoverZstep * i; - bot = WallT.InvZorg + WallT.InvZstep * i; - - top *= xrepeat; - topstep = WallT.UoverZstep * xrepeat; - botstep = WallT.InvZstep; - - for (int x = x1; x < x2; x++) + else { - if (walxrepeat < 0) + for (int x = x1; x < x2; x++) { - lwall[x] = xs_RoundToInt(xrepeat - top / bot); + float u = uOverZ / invZ * xrepeat; + + upos[x] = (fixed_t)(u * FRACUNIT); + + uOverZ += uGradient; + invZ += zGradient; } - else - { - lwall[x] = xs_RoundToInt(top / bot); - } - top += topstep; - bot += botstep; } - PrepWallRoundFix(lwall, FLOAT2FIXED(walxrepeat), x1, x2); } // pass = 0: when seg is first drawn From 6eff1cb8be81ebc5b33603a3437b53f4679fc92d Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Sat, 26 Nov 2016 12:45:17 +0100 Subject: [PATCH 131/185] - Fixed more GCC/Clang warnings. --- src/memarena.cpp | 4 ++-- src/memarena.h | 6 +++--- src/p_actionfunctions.cpp | 2 +- src/p_pspr.cpp | 2 +- src/scripting/codegeneration/codegen.cpp | 2 +- src/scripting/zscript/zcc_compile.cpp | 14 +++++++++++++- 6 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/memarena.cpp b/src/memarena.cpp index e6e9edd6e..8ea8b5806 100644 --- a/src/memarena.cpp +++ b/src/memarena.cpp @@ -72,11 +72,11 @@ static inline void *RoundPointer(void *ptr) // //========================================================================== -FMemArena::FMemArena(int bs) +FMemArena::FMemArena(size_t blocksize) { TopBlock = NULL; FreeBlocks = NULL; - BlockSize = bs; + BlockSize = blocksize; } //========================================================================== diff --git a/src/memarena.h b/src/memarena.h index cc0c8f148..3601469bf 100644 --- a/src/memarena.h +++ b/src/memarena.h @@ -40,7 +40,7 @@ class FMemArena { public: - FMemArena(int blocksize = 10*1024); + FMemArena(size_t blocksize = 10*1024); ~FMemArena(); void *Alloc(size_t size); @@ -55,7 +55,7 @@ protected: Block *TopBlock; Block *FreeBlocks; - int BlockSize; + size_t BlockSize; }; // An arena specializing in storage of FStrings. It knows how to free them, @@ -87,4 +87,4 @@ private: }; -#endif \ No newline at end of file +#endif diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 95bcb3e25..d33695a1b 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -143,7 +143,7 @@ bool ACustomInventory::CallStateChain (AActor *actor, FState *state) // If an unsafe function (i.e. one that accesses user variables) is being detected, print a warning once and remove the bogus function. We may not call it because that would inevitably crash. auto owner = FState::StaticFindStateOwner(state); Printf(TEXTCOLOR_RED "Unsafe state call in state %s.%d to %s which accesses user variables. The action function has been removed from this state\n", - owner->TypeName.GetChars(), state - owner->OwnedStates, state->ActionFunc->PrintableName.GetChars()); + owner->TypeName.GetChars(), int(state - owner->OwnedStates), state->ActionFunc->PrintableName.GetChars()); state->ActionFunc = nullptr; } diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index eddeb3430..e2ea3084d 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -409,7 +409,7 @@ void DPSprite::SetState(FState *newstate, bool pending) // If an unsafe function (i.e. one that accesses user variables) is being detected, print a warning once and remove the bogus function. We may not call it because that would inevitably crash. auto owner = FState::StaticFindStateOwner(newstate); Printf(TEXTCOLOR_RED "Unsafe state call in state %s.%d to %s which accesses user variables. The action function has been removed from this state\n", - owner->TypeName.GetChars(), newstate - owner->OwnedStates, newstate->ActionFunc->PrintableName.GetChars()); + owner->TypeName.GetChars(), int(newstate - owner->OwnedStates), newstate->ActionFunc->PrintableName.GetChars()); newstate->ActionFunc = nullptr; } if (newstate->CallAction(Owner->mo, Caller, &stp, &nextstate)) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 0fb6b172f..1e06f5751 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -7771,7 +7771,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) } VMFunction *vmfunc = Function->Variants[0].Implementation; - bool staticcall = (vmfunc->Final || vmfunc->VirtualIndex == -1 || NoVirtual); + bool staticcall = (vmfunc->Final || vmfunc->VirtualIndex == ~0u || NoVirtual); count = 0; // Emit code to pass implied parameters diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 98ebc17d9..56f991287 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1469,6 +1469,9 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n break; } break; + + default: + break; } break; } @@ -1520,6 +1523,9 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n } break; } + + default: + break; } if (retval != TypeError && retval->MemberOnly && !formember) { @@ -1997,6 +2003,9 @@ void ZCCCompiler::InitDefaults() case AST_FlagStmt: ProcessDefaultFlag(ti, static_cast(content)); break; + + default: + break; } content = static_cast(content->SiblingNext); } while (content != d->Content); @@ -3215,6 +3224,9 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) } return new FxMultiAssign(args, ConvertNode(ass->Sources), *ast); } + + default: + break; } // only for development. I_Error is more convenient here than a normal error. I_Error("ConvertNode encountered unsupported node of type %d", ast->NodeType); @@ -3234,4 +3246,4 @@ FArgumentList &ZCCCompiler::ConvertNodeList(FArgumentList &args, ZCC_TreeNode *h } while (node != head); } return args; -} \ No newline at end of file +} From 096c51d5464df360e1ba2dd5b75b07805f33dcce Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 27 Nov 2016 10:40:43 +0100 Subject: [PATCH 132/185] - changed AInventory::HandlePickup to work iteratively instead of recursively. Two reasons for this: 1. if this has to be routed through the VM each recursion will cost 1000 bytes of stack space which simply is not good. 2. having the virtual function only care about the item itself but not the entire inventory chain is a lot less error prone for scripting. Since the scripting interface needs a separate caller function anyway this seemed like a good time to change it. The same will be done for the other chained inventory handlers as well. --- src/CMakeLists.txt | 1 - src/dobjtype.cpp | 1 + src/g_game.cpp | 8 ++--- src/g_hexen/a_hexenglobal.h | 15 -------- src/g_shared/a_armor.cpp | 8 ----- src/g_shared/a_artifacts.cpp | 4 --- src/g_shared/a_keys.cpp | 4 --- src/g_shared/a_pickups.cpp | 49 ++++++++++++++++----------- src/g_shared/a_pickups.h | 1 + src/g_shared/a_weaponpiece.h | 2 ++ src/g_shared/a_weapons.cpp | 4 --- src/g_shared/sbarinfo.cpp | 1 + src/g_strife/a_coin.cpp | 4 --- src/g_strife/a_strifeweapons.cpp | 4 --- src/p_mobj.cpp | 11 +++++- src/scripting/thingdef.cpp | 1 + src/scripting/thingdef_properties.cpp | 8 ++--- wadsrc/static/zscript/actor.txt | 1 + 18 files changed, 55 insertions(+), 72 deletions(-) delete mode 100644 src/g_hexen/a_hexenglobal.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c5a54d1ba..368654698 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -855,7 +855,6 @@ set( NOT_COMPILED_SOURCE_FILES ${OTHER_SYSTEM_SOURCES} sc_man_scanner.h sc_man_scanner.re - g_hexen/a_flechette.cpp g_hexen/a_flies.cpp g_hexen/a_heresiarch.cpp g_hexen/a_hexenspecialdecs.cpp diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 079890f86..e9f574ea4 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -45,6 +45,7 @@ #include "autosegs.h" #include "v_text.h" #include "a_pickups.h" +#include "a_artifacts.h" #include "a_weaponpiece.h" #include "d_player.h" #include "doomerrors.h" diff --git a/src/g_game.cpp b/src/g_game.cpp index 9af9b4532..350669cfe 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -478,15 +478,15 @@ CCMD (useflechette) { // Select from one of arti_poisonbag1-3, whichever the player has static const ENamedName bagnames[3] = { + NAME_ArtiPoisonBag3, // use type 3 first because that's the default when the player has none specified. NAME_ArtiPoisonBag1, - NAME_ArtiPoisonBag2, - NAME_ArtiPoisonBag3 + NAME_ArtiPoisonBag2 }; if (who == NULL) return; - PClassActor *type = GetFlechetteType(who); + PClassActor *type = who->FlechetteType; if (type != NULL) { AInventory *item; @@ -497,7 +497,7 @@ CCMD (useflechette) } } - // The default flechette could not be found. Try all 3 types then. + // The default flechette could not be found, or the player had no default. Try all 3 types then. for (int j = 0; j < 3; ++j) { AInventory *item; diff --git a/src/g_hexen/a_hexenglobal.h b/src/g_hexen/a_hexenglobal.h deleted file mode 100644 index 277d1bff1..000000000 --- a/src/g_hexen/a_hexenglobal.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef __A_HEXENGLOBAL_H__ -#define __A_HEXENGLOBAL_H__ - -#include "d_player.h" - -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_shared/a_armor.cpp b/src/g_shared/a_armor.cpp index 6be1472bf..25d45d35d 100644 --- a/src/g_shared/a_armor.cpp +++ b/src/g_shared/a_armor.cpp @@ -115,10 +115,6 @@ bool ABasicArmor::HandlePickup (AInventory *item) armor->SaveAmount = int(armor->SaveAmount * G_SkillProperty(SKILLP_ArmorFactor)); } - if (Inventory != NULL) - { - return Inventory->HandlePickup (item); - } return false; } @@ -474,10 +470,6 @@ bool AHexenArmor::HandlePickup (AInventory *item) } return true; } - else if (Inventory != NULL) - { - return Inventory->HandlePickup (item); - } return false; } diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index 854881647..99a4f46d8 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -309,10 +309,6 @@ bool APowerup::HandlePickup (AInventory *item) power->ItemFlags |= IF_PICKUPGOOD; return true; } - if (Inventory != NULL) - { - return Inventory->HandlePickup (item); - } return false; } diff --git a/src/g_shared/a_keys.cpp b/src/g_shared/a_keys.cpp index 51962c1b0..fc9363be5 100644 --- a/src/g_shared/a_keys.cpp +++ b/src/g_shared/a_keys.cpp @@ -487,10 +487,6 @@ bool AKey::HandlePickup (AInventory *item) item->ItemFlags |= IF_PICKUPGOOD; return true; } - if (Inventory != NULL) - { - return Inventory->HandlePickup (item); - } return false; } diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index b026a61d7..3ce3dc776 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -183,10 +183,6 @@ bool AAmmo::HandlePickup (AInventory *item) } return true; } - if (Inventory != NULL) - { - return Inventory->HandlePickup (item); - } return false; } @@ -718,13 +714,39 @@ bool AInventory::HandlePickup (AInventory *item) } return true; } - if (Inventory != NULL) + return false; +} + +DEFINE_ACTION_FUNCTION(AInventory, HandlePickup) +{ + PARAM_SELF_PROLOGUE(AInventory); + PARAM_OBJECT(item, AInventory); + ACTION_RETURN_BOOL(self->HandlePickup(item)); +} + +bool AInventory::CallHandlePickup(AInventory *item) +{ + auto self = this; + while (self != nullptr) { - return Inventory->HandlePickup (item); + IFVIRTUAL(AActor, HandlePickup) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[2] = { (DObject*)self, (DObject*)item }; + VMReturn ret; + VMFrameStack stack; + int retval; + ret.IntAt(&retval); + stack.Call(func, params, 2, &ret, 1, nullptr); + if (retval) return true; + } + else if (self->HandlePickup(item)) return true; + self = self->Inventory; } return false; } + //=========================================================================== // // AInventory :: GoAway @@ -1480,7 +1502,7 @@ bool AInventory::TryPickup (AActor *&toucher) // picked up, then it leaves the flag cleared. ItemFlags &= ~IF_PICKUPGOOD; - if (toucher->Inventory != NULL && toucher->Inventory->HandlePickup (this)) + if (toucher->Inventory != NULL && toucher->Inventory->CallHandlePickup (this)) { // Let something else the player is holding intercept the pickup. if (!(ItemFlags & IF_PICKUPGOOD)) @@ -1892,10 +1914,6 @@ bool AHealthPickup::HandlePickup (AInventory *item) { return Super::HandlePickup (item); } - if (Inventory != NULL) - { - return Inventory->HandlePickup (item); - } return false; } @@ -2044,14 +2062,7 @@ bool ABackpackItem::HandlePickup (AInventory *item) item->ItemFlags |= IF_PICKUPGOOD; return true; } - else if (Inventory != NULL) - { - return Inventory->HandlePickup (item); - } - else - { - return false; - } + return false; } //=========================================================================== diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index bc8319931..2fe680231 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -203,6 +203,7 @@ public: virtual bool GoAway (); virtual void GoAwayAndDie (); virtual bool HandlePickup (AInventory *item); + bool CallHandlePickup(AInventory *item); virtual bool Use (bool pickup); bool CallUse(bool pickup); virtual void Travelled (); diff --git a/src/g_shared/a_weaponpiece.h b/src/g_shared/a_weaponpiece.h index 88f3da02c..3a6fbcbd7 100644 --- a/src/g_shared/a_weaponpiece.h +++ b/src/g_shared/a_weaponpiece.h @@ -1,3 +1,5 @@ +#pragma once +#include "a_pickups.h" // class PClassWeaponPiece : public PClassInventory diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index b19896e91..c2feebec6 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -346,10 +346,6 @@ bool AWeapon::HandlePickup (AInventory *item) } return true; } - if (Inventory != NULL) - { - return Inventory->HandlePickup (item); - } return false; } diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index a005c1ada..ed91be4c7 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -50,6 +50,7 @@ #include "sbarinfo.h" #include "gi.h" #include "r_data/r_translate.h" +#include "a_artifacts.h" #include "a_weaponpiece.h" #include "a_strifeglobal.h" #include "g_level.h" diff --git a/src/g_strife/a_coin.cpp b/src/g_strife/a_coin.cpp index 53cc59f50..f74d92e55 100644 --- a/src/g_strife/a_coin.cpp +++ b/src/g_strife/a_coin.cpp @@ -41,10 +41,6 @@ bool ACoin::HandlePickup (AInventory *item) } return true; } - if (Inventory != NULL) - { - return Inventory->HandlePickup (item); - } return false; } diff --git a/src/g_strife/a_strifeweapons.cpp b/src/g_strife/a_strifeweapons.cpp index 0268682f3..1909ec781 100644 --- a/src/g_strife/a_strifeweapons.cpp +++ b/src/g_strife/a_strifeweapons.cpp @@ -786,10 +786,6 @@ bool ASigil::HandlePickup (AInventory *item) } return true; } - if (Inventory != NULL) - { - return Inventory->HandlePickup (item); - } return false; } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 2e87729d0..c7cf50f5e 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -41,7 +41,6 @@ #include "c_dispatch.h" #include "b_bot.h" //Added by MC: #include "stats.h" -#include "a_hexenglobal.h" #include "a_sharedglobal.h" #include "gi.h" #include "sbar.h" @@ -69,6 +68,7 @@ #include "serializer.h" #include "r_utility.h" #include "thingdef.h" +#include "d_player.h" #include "virtual.h" // MACROS ------------------------------------------------------------------ @@ -7436,6 +7436,15 @@ DEFINE_ACTION_FUNCTION(AActor, SetFriendPlayer) self->SetFriendPlayer(player); return 0; } + +DEFINE_ACTION_FUNCTION(AActor, ClearBounce) +{ + PARAM_SELF_PROLOGUE(AActor); + self->BounceFlags = 0; + return 0; +} + + //---------------------------------------------------------------------------- // // DropItem handling diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index d6c53dd8d..5708f89d2 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -57,6 +57,7 @@ #include "m_argv.h" #include "p_local.h" #include "doomerrors.h" +#include "a_artifacts.h" #include "a_weaponpiece.h" #include "p_conversation.h" #include "v_text.h" diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 8968dc1d6..8586d32af 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -39,7 +39,7 @@ */ #include "gi.h" -#include "actor.h" +#include "d_player.h" #include "info.h" #include "tarray.h" #include "w_wad.h" @@ -57,8 +57,7 @@ #include "p_effect.h" #include "v_palette.h" #include "doomerrors.h" -#include "a_hexenglobal.h" -#include "a_weaponpiece.h" +#include "a_artifacts.h" #include "p_conversation.h" #include "v_text.h" #include "thingdef.h" @@ -69,6 +68,7 @@ #include "teaminfo.h" #include "v_video.h" #include "r_data/colormaps.h" +#include "a_weaponpiece.h" #include "vmbuilder.h" extern TArray OptionalClassPtrs; @@ -2800,7 +2800,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, RUNTIME_CLASS(AArtiPoisonBag)); + defaults->FlechetteType = FindClassTentative(str, PClass::FindActor("ArtiPoisonBag")); } //========================================================================== diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 92f1073fd..8acd261f3 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -280,6 +280,7 @@ class Actor : Thinker native native int PlayerNumber(); native void SetFriendPlayer(PlayerInfo player); native void NoiseAlert(Actor emitter, bool splash = false, double maxdist = 0); + native void ClearBounce(); native void RestoreDamage(); native int SpawnHealth(); From b10ffb5133837d8f64942366d92fd7e54fee05b1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 27 Nov 2016 11:59:47 +0100 Subject: [PATCH 133/185] - exported a few more functions. - refactored the ModifyDamage interface to be more scripting friendly. In general it should be avoided having to call directly into chained inventory functions because they are very problematic and prone to errors. So this got wrapped into a single handler (on AActor, not AInventory!) which will later make it easier to refactor the parameters of ModifyDamage to work better for scripting and avoid the chaining. --- src/actor.h | 1 + src/g_shared/a_pickups.cpp | 25 +++++++++++++++++++++- src/g_shared/a_pickups.h | 1 + src/p_interaction.cpp | 25 +++++++++++++--------- src/p_mobj.cpp | 25 ++++++++++++++++++++++ wadsrc/static/zscript/actor.txt | 2 ++ wadsrc/static/zscript/shared/inventory.txt | 2 ++ wadsrc/static/zscript/shared/player.txt | 1 + 8 files changed, 71 insertions(+), 11 deletions(-) diff --git a/src/actor.h b/src/actor.h index 92e277d48..4c0f33dde 100644 --- a/src/actor.h +++ b/src/actor.h @@ -1420,6 +1420,7 @@ public: } int ApplyDamageFactor(FName damagetype, int damage) const; + int GetModifiedDamage(FName damagetype, int damage, bool passive); }; diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index 3ce3dc776..a57d90bcd 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -822,6 +822,29 @@ AInventory *AInventory::CreateCopy (AActor *other) return copy; } +DEFINE_ACTION_FUNCTION(AInventory, CreateCopy) +{ + PARAM_SELF_PROLOGUE(AInventory); + PARAM_OBJECT(other, AActor); + ACTION_RETURN_OBJECT(self->CreateCopy(other)); +} + +AInventory *AInventory::CallCreateCopy(AActor *other) +{ + IFVIRTUAL(AActor, CreateCopy) + { + VMValue params[2] = { (DObject*)this, (DObject*)other }; + VMReturn ret; + VMFrameStack stack; + AInventory *retval; + ret.PointerAt((void**)&retval); + stack.Call(func, params, 2, &ret, 1, nullptr); + return retval; + } + else return CreateCopy(other); +} + + //=========================================================================== // // AInventory::CreateTossable @@ -1538,7 +1561,7 @@ bool AInventory::TryPickup (AActor *&toucher) { // Add the item to the inventory. It is not already there, or HandlePickup // would have already taken care of it. - AInventory *copy = CreateCopy (toucher); + AInventory *copy = CallCreateCopy (toucher); if (copy == NULL) { return false; diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index 2fe680231..429b2ab90 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -199,6 +199,7 @@ public: virtual void AttachToOwner (AActor *other); virtual void DetachFromOwner (); virtual AInventory *CreateCopy (AActor *other); + AInventory *CallCreateCopy(AActor *other); virtual AInventory *CreateTossable (); virtual bool GoAway (); virtual void GoAwayAndDie (); diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 040e05ce0..c2d958050 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1105,15 +1105,15 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, damage = int(damage * source->DamageMultiply); // Handle active damage modifiers (e.g. PowerDamage) - if (damage > 0 && source->Inventory != NULL) + if (damage > 0) { - source->Inventory->ModifyDamage(damage, mod, damage, false); + damage = source->GetModifiedDamage(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)) + if (damage > 0 && !(flags & DMG_NO_PROTECT)) { - target->Inventory->ModifyDamage(damage, mod, damage, true); + damage = target->GetModifiedDamage(mod, damage, true); } if (damage > 0 && !(flags & DMG_NO_FACTOR)) { @@ -1749,8 +1749,7 @@ DEFINE_ACTION_FUNCTION(_PlayerInfo, PoisonPlayer) // //========================================================================== -void P_PoisonDamage (player_t *player, AActor *source, int damage, - bool playPainSound) +void P_PoisonDamage (player_t *player, AActor *source, int damage, bool playPainSound) { AActor *target; @@ -1771,10 +1770,7 @@ void P_PoisonDamage (player_t *player, AActor *source, int damage, // Take half damage in trainer mode damage = int(damage * G_SkillProperty(SKILLP_DamageFactor)); // Handle passive damage modifiers (e.g. PowerProtection) - if (target->Inventory != NULL) - { - target->Inventory->ModifyDamage(damage, player->poisontype, damage, true); - } + damage = target->GetModifiedDamage(player->poisontype, damage, true); // Modify with damage factors damage = target->ApplyDamageFactor(player->poisontype, damage); @@ -1845,6 +1841,15 @@ void P_PoisonDamage (player_t *player, AActor *source, int damage, */ } +DEFINE_ACTION_FUNCTION(_PlayerInfo, PoisonDamage) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + PARAM_OBJECT(source, AActor); + PARAM_INT(damage); + PARAM_BOOL(playsound); + P_PoisonDamage(self, source, damage, playsound); + return 0; +} CCMD (kill) { diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index c7cf50f5e..ad1c317e8 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -7158,6 +7158,23 @@ DEFINE_ACTION_FUNCTION(AActor, ClearCounters) return 0; } +int AActor::GetModifiedDamage(FName damagetype, int damage, bool passive) +{ + if (Inventory != nullptr) + Inventory->ModifyDamage(damage, damagetype, damage, false); + + return damage; +} + +DEFINE_ACTION_FUNCTION(AActor, GetModifiedDamage) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_NAME(type); + PARAM_INT(damage); + PARAM_BOOL(passive); + ACTION_RETURN_INT(self->GetModifiedDamage(type, damage, passive)); +} + int AActor::ApplyDamageFactor(FName damagetype, int damage) const { damage = int(damage * DamageFactor); @@ -7168,6 +7185,14 @@ int AActor::ApplyDamageFactor(FName damagetype, int damage) const return damage; } +DEFINE_ACTION_FUNCTION(AActor, ApplyDamageFactor) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_NAME(type); + PARAM_INT(damage); + ACTION_RETURN_INT(self->ApplyDamageFactor(type, damage)); +} + void AActor::SetTranslation(FName trname) { diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 8acd261f3..64a62a822 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -303,6 +303,8 @@ class Actor : Thinker native native Actor, Actor SpawnPlayerMissile(class type, double angle = 0, double x = 0, double y = 0, double z = 0, out FTranslatedLineTarget pLineTarget = null, bool nofreeaim = false, bool noautoaim = false, int aimflags = 0); native void SpawnTeleportFog(Vector3 pos, bool beforeTele, bool setTarget); native Actor RoughMonsterSearch(int distance, bool onlyseekable = false); + native int ApplyDamageFactor(FName damagetype, int damage); + native int GetModifiedDamage(FName damagetype, int damage, bool passive); void A_Light(int extralight) { if (player) player.extralight = clamp(extralight, -20, 20); } void A_Light0() { if (player) player.extralight = 0; } diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index 54a2b0ba9..dab317ea6 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -27,6 +27,8 @@ class Inventory : Actor native virtual native bool Use (bool pickup); virtual native color GetBlend (); + virtual native bool HandlePickup(Inventory item); + virtual native Inventory CreateCopy(Actor other); // These are regular functions for the item itself. diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 2d5be6278..136feb32e 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -228,6 +228,7 @@ FWeaponSlots weapons; native bool UndoPlayerMorph(playerinfo player, int unmorphflag = 0, bool force = false); native bool PoisonPlayer(Actor poisoner, Actor source, int poison); + native PoisonDamage(Actor source, int damage, bool playPainSound) native void SetPsprite(int id, State stat, bool pending = false); native void SetSafeFlash(Weapon weap, State flashstate, int index); native PSprite GetPSprite(int id); From 36f559ecb726cdfe9bbdc11a15970ff3135f34c5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 27 Nov 2016 12:18:06 +0100 Subject: [PATCH 134/185] - fixed bad definition of struct grammar which tried to resolve from right to left, creating large amounts of recursion and strange problems with PlayerInfo. - added a command line option to generate a parser trace file. - fixed a syntax error in player.txt. --- src/scripting/zscript/zcc-parse.lemon | 2 +- src/scripting/zscript/zcc_parser.cpp | 20 +++++++++++--------- wadsrc/static/zscript/shared/player.txt | 2 +- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/scripting/zscript/zcc-parse.lemon b/src/scripting/zscript/zcc-parse.lemon index d22746cf8..ccd7e6e84 100644 --- a/src/scripting/zscript/zcc-parse.lemon +++ b/src/scripting/zscript/zcc-parse.lemon @@ -299,7 +299,7 @@ opt_struct_body(X) ::= error. { X = NULL; } struct_body(X) ::= struct_member(X). -struct_body(X) ::= struct_member(A) struct_body(B). { X = A; /*X-overwrites-A*/ AppendTreeNodeSibling(X, B); } +struct_body(X) ::= struct_body(A) struct_member(B). { X = A; /*X-overwrites-A*/ AppendTreeNodeSibling(X, B); } struct_member(X) ::= declarator(A). { X = A; /*X-overwrites-A*/ } struct_member(X) ::= enum_def(A). { X = A; /*X-overwrites-A*/ } diff --git a/src/scripting/zscript/zcc_parser.cpp b/src/scripting/zscript/zcc_parser.cpp index 9d24d0cb1..989ec10ae 100644 --- a/src/scripting/zscript/zcc_parser.cpp +++ b/src/scripting/zscript/zcc_parser.cpp @@ -302,12 +302,15 @@ static void DoParse(int lumpnum) parser = ZCCParseAlloc(malloc); ZCCParseState state; -//#define TRACE -#ifdef TRACE // this costs a lot of time and should only be activated when it's really needed. - FILE *f = fopen("trace.txt", "w"); - char prompt = '\0'; - ZCCParseTrace(f, &prompt); -#endif + + FILE *f = nullptr; + const char *tracefile = Args->CheckValue("-tracefile"); + if (tracefile != nullptr) + { + f = fopen(tracefile, "w"); + char prompt = '\0'; + ZCCParseTrace(f, &prompt); + } sc.OpenLumpNum(lumpnum); auto saved = sc.SavePos(); @@ -341,6 +344,7 @@ static void DoParse(int lumpnum) } } + if (f) fprintf(f, "Starting parsing %s\n", sc.String); ParseSingleFile(sc.String, 0, parser, state); } } @@ -356,12 +360,10 @@ static void DoParse(int lumpnum) I_Error("%d errors while parsing %s", FScriptPosition::ErrorCounter, Wads.GetLumpFullPath(lumpnum).GetChars()); } -#ifdef TRACE - if (f != NULL) + if (f != nullptr) { fclose(f); } -#endif // Make a dump of the AST before running the compiler for diagnostic purposes. if (Args->CheckParm("-dumpast")) diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 136feb32e..c7615e9c2 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -228,7 +228,7 @@ FWeaponSlots weapons; native bool UndoPlayerMorph(playerinfo player, int unmorphflag = 0, bool force = false); native bool PoisonPlayer(Actor poisoner, Actor source, int poison); - native PoisonDamage(Actor source, int damage, bool playPainSound) + native void PoisonDamage(Actor source, int damage, bool playPainSound); native void SetPsprite(int id, State stat, bool pending = false); native void SetSafeFlash(Weapon weap, State flashstate, int index); native PSprite GetPSprite(int id); From 3dd323ac0d34abf8d0cd0517e566c2df26453174 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 27 Nov 2016 12:52:54 +0100 Subject: [PATCH 135/185] - scriptified the Flechette. Not fully tested yet. - fixed issues with the refactoring of the recent commits. This one starts again. - added builtins for TextureID. Note about builtins: Currently they are just hacked into the compiler backend. They really should be made part of the respective types to keep matters clean and allow more widespread use of builtins to create more efficient code. --- src/g_hexen/a_flechette.cpp | 455 --------------------- src/g_hexen/a_hexenmisc.cpp | 5 +- src/g_hexen/a_hexenspecialdecs.cpp | 14 - src/g_shared/a_pickups.cpp | 12 +- src/namedef.h | 5 + src/scripting/codegeneration/codegen.cpp | 46 +++ wadsrc/static/zscript/actor.txt | 4 +- wadsrc/static/zscript/hexen/flechette.txt | 375 ++++++++++++++++- wadsrc/static/zscript/shared/inventory.txt | 1 + 9 files changed, 424 insertions(+), 493 deletions(-) delete mode 100644 src/g_hexen/a_flechette.cpp diff --git a/src/g_hexen/a_flechette.cpp b/src/g_hexen/a_flechette.cpp deleted file mode 100644 index 77917c402..000000000 --- a/src/g_hexen/a_flechette.cpp +++ /dev/null @@ -1,455 +0,0 @@ -/* -#include "actor.h" -#include "info.h" -#include "a_pickups.h" -#include "a_artifacts.h" -#include "gstrings.h" -#include "p_local.h" -#include "s_sound.h" -#include "m_random.h" -#include "a_action.h" -#include "a_hexenglobal.h" -#include "w_wad.h" -#include "vm.h" -#include "g_level.h" -*/ - -EXTERN_CVAR(Bool, sv_unlimited_pickup) - -static FRandom pr_poisonbag ("PoisonBag"); -static FRandom pr_poisoncloud ("PoisonCloud"); -static FRandom pr_poisoncloudd ("PoisonCloudDamage"); - -DECLARE_ACTION(A_CheckThrowBomb) - -// Poison Bag Artifact (Flechette) ------------------------------------------ - -IMPLEMENT_CLASS(AArtiPoisonBag, false, false) - -// Poison Bag 1 (The Cleric's) ---------------------------------------------- - -class AArtiPoisonBag1 : public AArtiPoisonBag -{ - DECLARE_CLASS (AArtiPoisonBag1, AArtiPoisonBag) -public: - bool Use (bool pickup); -}; - -IMPLEMENT_CLASS(AArtiPoisonBag1, false, false) - -bool AArtiPoisonBag1::Use (bool pickup) -{ - AActor *mo = Spawn("PoisonBag", Owner->Vec3Offset( - 16 * Owner->Angles.Yaw.Cos(), - 24 * Owner->Angles.Yaw.Sin(), - -Owner->Floorclip + 8), ALLOW_REPLACE); - if (mo) - { - mo->target = Owner; - return true; - } - return false; -} - -// Poison Bag 2 (The Mage's) ------------------------------------------------ - -class AArtiPoisonBag2 : public AArtiPoisonBag -{ - DECLARE_CLASS (AArtiPoisonBag2, AArtiPoisonBag) -public: - bool Use (bool pickup); -}; - -IMPLEMENT_CLASS(AArtiPoisonBag2, false, false) - -bool AArtiPoisonBag2::Use (bool pickup) -{ - AActor *mo = Spawn("FireBomb", Owner->Vec3Offset( - 16 * Owner->Angles.Yaw.Cos(), - 24 * Owner->Angles.Yaw.Sin(), - -Owner->Floorclip + 8), ALLOW_REPLACE); - if (mo) - { - mo->target = Owner; - return true; - } - return false; -} - -// Poison Bag 3 (The Fighter's) --------------------------------------------- - -class AArtiPoisonBag3 : public AArtiPoisonBag -{ - DECLARE_CLASS (AArtiPoisonBag3, AArtiPoisonBag) -public: - bool Use (bool pickup); -}; - -IMPLEMENT_CLASS(AArtiPoisonBag3, false, false) - -bool AArtiPoisonBag3::Use (bool pickup) -{ - AActor *mo; - - mo = Spawn("ThrowingBomb", Owner->PosPlusZ(35. - Owner->Floorclip + (Owner->player? Owner->player->crouchoffset : 0)), ALLOW_REPLACE); - if (mo) - { - mo->Angles.Yaw = Owner->Angles.Yaw + (((pr_poisonbag() & 7) - 4) * (360./256.)); - - /* Original flight code from Hexen - * mo->momz = 4*F.RACUNIT+((player->lookdir)<<(F.RACBITS-4)); - * mo->z += player->lookdir<<(F.RACBITS-4); - * P_ThrustMobj(mo, mo->angle, mo->info->speed); - * mo->momx += player->mo->momx>>1; - * mo->momy += player->mo->momy>>1; - */ - - // When looking straight ahead, it uses a z velocity of 4 while the xy velocity - // is as set by the projectile. To accommodate this with a proper trajectory, we - // aim the projectile ~20 degrees higher than we're looking at and increase the - // speed we fire at accordingly. - DAngle orgpitch = -Owner->Angles.Pitch; - DAngle modpitch = clamp(-Owner->Angles.Pitch + 20, -89., 89.); - DAngle angle = mo->Angles.Yaw; - double speed = DVector2(mo->Speed, 4.).Length(); - double xyscale = speed * modpitch.Cos(); - - mo->Vel.Z = speed * modpitch.Sin(); - mo->Vel.X = xyscale * angle.Cos() + Owner->Vel.X / 2; - mo->Vel.Y = xyscale * angle.Sin() + Owner->Vel.Y / 2; - mo->AddZ(mo->Speed * orgpitch.Sin()); - - mo->target = Owner; - mo->tics -= pr_poisonbag()&3; - P_CheckMissileSpawn(mo, Owner->radius); - return true; - } - return false; -} - -// Poison Bag 4 (Generic Giver) ---------------------------------------------- - -class AArtiPoisonBagGiver : public AArtiPoisonBag -{ - DECLARE_CLASS (AArtiPoisonBagGiver, AArtiPoisonBag) -public: - bool Use (bool pickup); -}; - -IMPLEMENT_CLASS(AArtiPoisonBagGiver, false, false) - -bool AArtiPoisonBagGiver::Use (bool pickup) -{ - PClassActor *missiletype = PClass::FindActor(this->GetClass()->MissileName); - if (missiletype != NULL) - { - AActor *mo = Spawn (missiletype, Owner->Pos(), ALLOW_REPLACE); - if (mo != NULL) - { - if (mo->IsKindOf(RUNTIME_CLASS(AInventory))) - { - AInventory *inv = static_cast(mo); - if (inv->CallTryPickup(Owner)) - return true; - } - mo->Destroy(); // Destroy if not inventory or couldn't be picked up - } - } - return false; -} - -// Poison Bag 5 (Generic Thrower) ---------------------------------------------- - -class AArtiPoisonBagShooter : public AArtiPoisonBag -{ - DECLARE_CLASS (AArtiPoisonBagShooter, AArtiPoisonBag) -public: - bool Use (bool pickup); -}; - -IMPLEMENT_CLASS(AArtiPoisonBagShooter, false, false) - -bool AArtiPoisonBagShooter::Use (bool pickup) -{ - PClassActor *missiletype = PClass::FindActor(this->GetClass()->MissileName); - if (missiletype != NULL) - { - AActor *mo = P_SpawnPlayerMissile(Owner, missiletype); - if (mo != NULL) - { - // automatic handling of seeker missiles - if (mo->flags2 & MF2_SEEKERMISSILE) - { - mo->tracer = Owner->target; - } - return true; - } - } - return false; -} - -//============================================================================ -// -// GetFlechetteType -// -//============================================================================ - -PClassActor *GetFlechetteType(AActor *other) -{ - PClassActor *spawntype = NULL; - if (other->IsKindOf(RUNTIME_CLASS(APlayerPawn))) - { - spawntype = static_cast(other)->FlechetteType; - } - if (spawntype == NULL) - { - // default fallback if nothing valid defined. - spawntype = RUNTIME_CLASS(AArtiPoisonBag3); - } - return spawntype; -} - -//============================================================================ -// -// AArtiPoisonBag :: HandlePickup -// -//============================================================================ - -bool AArtiPoisonBag::HandlePickup (AInventory *item) -{ - // Only do special handling when picking up the base class - if (item->GetClass() != RUNTIME_CLASS(AArtiPoisonBag)) - { - return Super::HandlePickup (item); - } - - if (GetClass() == GetFlechetteType(Owner)) - { - if (Amount < MaxAmount || sv_unlimited_pickup) - { - Amount += item->Amount; - if (Amount > MaxAmount && !sv_unlimited_pickup) - { - Amount = MaxAmount; - } - item->ItemFlags |= IF_PICKUPGOOD; - } - return true; - } - if (Inventory != NULL) - { - return Inventory->HandlePickup (item); - } - return false; -} - -//============================================================================ -// -// AArtiPoisonBag :: CreateCopy -// -//============================================================================ - -AInventory *AArtiPoisonBag::CreateCopy (AActor *other) -{ - // Only the base class gets special handling - if (GetClass() != RUNTIME_CLASS(AArtiPoisonBag)) - { - return Super::CreateCopy (other); - } - - AInventory *copy; - PClassActor *spawntype = GetFlechetteType(other); - copy = static_cast(Spawn (spawntype)); - copy->Amount = Amount; - copy->MaxAmount = MaxAmount; - GoAwayAndDie (); - return copy; -} - -//============================================================================ -// -// AArtiPoisonBag :: BeginPlay -// -//============================================================================ - -void AArtiPoisonBag::BeginPlay () -{ - Super::BeginPlay (); - // If a subclass's specific icon is not defined, let it use the base class's. - if (!Icon.isValid()) - { - AInventory *defbag; - // Why doesn't this work? - //defbag = GetDefault(); - defbag = (AInventory *)GetDefaultByType (RUNTIME_CLASS(AArtiPoisonBag)); - Icon = defbag->Icon; - } -} - -// Poison Cloud ------------------------------------------------------------- - -class APoisonCloud : public AActor -{ - DECLARE_CLASS (APoisonCloud, AActor) -public: - int DoSpecialDamage (AActor *target, int damage, FName damagetype); - void BeginPlay (); -}; - -IMPLEMENT_CLASS(APoisonCloud, false, false) - -void APoisonCloud::BeginPlay () -{ - Vel.X = MinVel; // missile objects must move to impact other objects - special1 = 24+(pr_poisoncloud()&7); - special2 = 0; -} - -int APoisonCloud::DoSpecialDamage (AActor *victim, int damage, FName damagetype) -{ - if (victim->player) - { - bool mate = (target != NULL && victim->player != target->player && victim->IsTeammate (target)); - bool dopoison; - - if (!mate) - { - dopoison = victim->player->poisoncount < 4; - } - else - { - dopoison = victim->player->poisoncount < (int)(4. * level.teamdamage); - } - - if (dopoison) - { - int damage = 15 + (pr_poisoncloudd()&15); - if (mate) - { - damage = (int)(damage * level.teamdamage); - } - // Handle passive damage modifiers (e.g. PowerProtection) - if (victim->Inventory != NULL) - { - victim->Inventory->ModifyDamage(damage, damagetype, damage, true); - } - // Modify with damage factors - damage = victim->ApplyDamageFactor(damagetype, damage); - if (damage > 0) - { - P_PoisonDamage (victim->player, this, - 15+(pr_poisoncloudd()&15), false); // Don't play painsound - - // If successful, play the poison sound. - if (P_PoisonPlayer (victim->player, this, this->target, 50)) - S_Sound (victim, CHAN_VOICE, "*poison", 1, ATTN_NORM); - } - } - return -1; - } - else if (!(victim->flags3 & MF3_ISMONSTER)) - { // only damage monsters/players with the poison cloud - return -1; - } - return damage; -} - -//=========================================================================== -// -// A_PoisonBagInit -// -//=========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_PoisonBagInit) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo; - - mo = Spawn (self->PosPlusZ(28.), ALLOW_REPLACE); - if (mo) - { - mo->target = self->target; - } - return 0; -} - -//=========================================================================== -// -// A_PoisonBagCheck -// -//=========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_PoisonBagCheck) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (--self->special1 <= 0) - { - self->SetState (self->FindState ("Death")); - } - else - { - return 0; - } - return 0; -} - -//=========================================================================== -// -// A_PoisonBagDamage -// -//=========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_PoisonBagDamage) -{ - PARAM_SELF_PROLOGUE(AActor); - - int bobIndex; - - P_RadiusAttack (self, self->target, 4, 40, self->DamageType, RADF_HURTSOURCE); - bobIndex = self->special2; - self->AddZ(BobSin(bobIndex) / 16); - self->special2 = (bobIndex + 1) & 63; - return 0; -} - -//=========================================================================== -// -// A_CheckThrowBomb -// -//=========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_CheckThrowBomb) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (--self->health <= 0) - { - self->SetState (self->FindState(NAME_Death)); - } - return 0; -} - -//=========================================================================== -// -// A_CheckThrowBomb2 -// -//=========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_CheckThrowBomb2) -{ - PARAM_SELF_PROLOGUE(AActor); - - // [RH] Check using actual velocity, although the vel.z < 2 check still stands - if (self->Vel.Z < 2 && self->Vel.LengthSquared() < (9./4.)) - { - self->SetState (self->SpawnState + 6); - self->SetZ(self->floorz); - self->Vel.Z = 0; - self->BounceFlags = BOUNCE_None; - self->flags &= ~MF_MISSILE; - } - CALL_ACTION(A_CheckThrowBomb, self); - return 0; -} diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp index 3223575c8..ae4399526 100644 --- a/src/g_hexen/a_hexenmisc.cpp +++ b/src/g_hexen/a_hexenmisc.cpp @@ -1,11 +1,10 @@ -#include "actor.h" +#include "d_player.h" #include "info.h" #include "p_local.h" #include "s_sound.h" #include "a_action.h" #include "m_random.h" #include "a_sharedglobal.h" -#include "a_hexenglobal.h" #include "i_system.h" #include "gi.h" #include "g_level.h" @@ -22,9 +21,9 @@ #include "p_maputl.h" #include "p_spec.h" #include "serializer.h" +#include "a_pickups.h" // Include all the Hexen stuff here to reduce compile time -#include "a_flechette.cpp" #include "a_flies.cpp" #include "a_heresiarch.cpp" #include "a_hexenspecialdecs.cpp" diff --git a/src/g_hexen/a_hexenspecialdecs.cpp b/src/g_hexen/a_hexenspecialdecs.cpp index 1745e6efc..899d9326d 100644 --- a/src/g_hexen/a_hexenspecialdecs.cpp +++ b/src/g_hexen/a_hexenspecialdecs.cpp @@ -264,20 +264,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_LeafCheck) return 0; } -//=========================================================================== -// -// A_PoisonShroom -// -//=========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_PoisonShroom) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->tics = 128 + (pr_shroom() << 1); - return 0; -} - //=========================================================================== // // A_SoAExplode - Suit of Armor Explode diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index a57d90bcd..2172d2a0c 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -729,7 +729,7 @@ bool AInventory::CallHandlePickup(AInventory *item) auto self = this; while (self != nullptr) { - IFVIRTUAL(AActor, HandlePickup) + IFVIRTUAL(AInventory, HandlePickup) { // Without the type cast this picks the 'void *' assignment... VMValue params[2] = { (DObject*)self, (DObject*)item }; @@ -794,6 +794,14 @@ void AInventory::GoAwayAndDie () } } +DEFINE_ACTION_FUNCTION(AInventory, GoAwayAndDie) +{ + PARAM_SELF_PROLOGUE(AInventory); + self->GoAwayAndDie(); + return 0; +} + + //=========================================================================== // // AInventory :: CreateCopy @@ -831,7 +839,7 @@ DEFINE_ACTION_FUNCTION(AInventory, CreateCopy) AInventory *AInventory::CallCreateCopy(AActor *other) { - IFVIRTUAL(AActor, CreateCopy) + IFVIRTUAL(AInventory, CreateCopy) { VMValue params[2] = { (DObject*)this, (DObject*)other }; VMReturn ret; diff --git a/src/namedef.h b/src/namedef.h index 779c2e132..413b68124 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -746,6 +746,11 @@ xx(StateLabel) xx(SpriteID) xx(TextureID) xx(Overlay) +xx(IsValid) +xx(IsNull) +xx(Exists) +xx(SetInvalid) +xx(SetNull) xx(A_Punch) xx(A_FirePistol) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 1e06f5751..72d79647f 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -7192,6 +7192,52 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) } } + // Note: These builtins would better be relegated to the actual type objects, instead of polluting this file, but that's a task for later. + + // Texture builtins. + if (Self->ValueType == TypeTextureID) + { + if (MethodName == NAME_IsValid || MethodName == NAME_IsNull || MethodName == NAME_Exists || MethodName == NAME_SetInvalid || MethodName == NAME_SetNull) + { + if (ArgList.Size() > 0) + { + ScriptPosition.Message(MSG_ERROR, "too many parameters in call to %s", MethodName.GetChars()); + delete this; + return nullptr; + } + // No need to create a dedicated node here, all builtins map directly to trivial operations. + Self->ValueType = TypeSInt32; // all builtins treat the texture index as integer. + FxExpression *x; + switch (MethodName) + { + case NAME_IsValid: + x = new FxCompareRel('>', Self, new FxConstant(0, ScriptPosition)); + break; + + case NAME_IsNull: + x = new FxCompareEq(TK_Eq, Self, new FxConstant(0, ScriptPosition)); + break; + + case NAME_Exists: + x = new FxCompareRel(TK_Geq, Self, new FxConstant(0, ScriptPosition)); + break; + + case NAME_SetInvalid: + x = new FxAssign(Self, new FxConstant(-1, ScriptPosition)); + break; + + case NAME_SetNull: + x = new FxAssign(Self, new FxConstant(0, ScriptPosition)); + break; + } + Self = nullptr; + SAFE_RESOLVE(x, ctx); + if (MethodName == NAME_SetInvalid || MethodName == NAME_SetNull) x->ValueType = TypeVoid; // override the default type of the assignment operator. + delete this; + return x; + } + } + if (Self->IsVector()) { // handle builtins: Vectors got 2: Length and Unit. diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 64a62a822..884bcc8a5 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -303,8 +303,8 @@ class Actor : Thinker native native Actor, Actor SpawnPlayerMissile(class type, double angle = 0, double x = 0, double y = 0, double z = 0, out FTranslatedLineTarget pLineTarget = null, bool nofreeaim = false, bool noautoaim = false, int aimflags = 0); native void SpawnTeleportFog(Vector3 pos, bool beforeTele, bool setTarget); native Actor RoughMonsterSearch(int distance, bool onlyseekable = false); - native int ApplyDamageFactor(FName damagetype, int damage); - native int GetModifiedDamage(FName damagetype, int damage, bool passive); + native int ApplyDamageFactor(Name damagetype, int damage); + native int GetModifiedDamage(Name damagetype, int damage, bool passive); void A_Light(int extralight) { if (player) player.extralight = clamp(extralight, -20, 20); } void A_Light0() { if (player) player.extralight = 0; } diff --git a/wadsrc/static/zscript/hexen/flechette.txt b/wadsrc/static/zscript/hexen/flechette.txt index c02477064..f8f6a0b8a 100644 --- a/wadsrc/static/zscript/hexen/flechette.txt +++ b/wadsrc/static/zscript/hexen/flechette.txt @@ -10,8 +10,6 @@ class PoisonBag : Actor +NOBLOCKMAP +NOGRAVITY } - native void A_PoisonBagInit(); - States { Spawn: @@ -21,6 +19,21 @@ class PoisonBag : Actor PSBG C 1 A_PoisonBagInit; Stop; } + + //=========================================================================== + // + // A_PoisonBagInit + // + //=========================================================================== + + void A_PoisonBagInit() + { + Actor mo = Spawn("PoisonCloud", (pos.xy, 28), ALLOW_REPLACE); + if (mo) + { + mo.target = target; + } + } } // Fire Bomb (Flechette used by Mage) --------------------------------------- @@ -74,9 +87,6 @@ class ThrowingBomb : Actor DeathSound "FlechetteExplode"; } - native void A_CheckThrowBomb(); - native void A_CheckThrowBomb2(); - States { Spawn: @@ -84,6 +94,7 @@ class ThrowingBomb : Actor THRW BCDE 3 A_CheckThrowBomb; THRW F 3 A_CheckThrowBomb2; Loop; + Tail: THRW G 6 A_CheckThrowBomb; THRW F 4 A_CheckThrowBomb; THRW H 6 A_CheckThrowBomb; @@ -102,11 +113,46 @@ class ThrowingBomb : Actor CFCF Z 3 Bright; Stop; } + + //=========================================================================== + // + // A_CheckThrowBomb + // + //=========================================================================== + + void A_CheckThrowBomb() + { + if (--health <= 0) + { + SetStateLabel("Death"); + } + } + + //=========================================================================== + // + // A_CheckThrowBomb2 + // + //=========================================================================== + + void A_CheckThrowBomb2() + { + // [RH] Check using actual velocity, although the vel.z < 2 check still stands + if (Vel.Z < 2 && Vel.Length() < 1.5) + { + SetStateLabel("Tail"); + SetZ(floorz); + Vel.Z = 0; + ClearBounce(); + bMissile = false; + } + A_CheckThrowBomb(); + } + } // Poison Bag Artifact (Flechette) ------------------------------------------ -class ArtiPoisonBag : Inventory native +class ArtiPoisonBag : Inventory { Default { @@ -125,64 +171,262 @@ class ArtiPoisonBag : Inventory native PSBG A -1; Stop; } + + //============================================================================ + // + // AArtiPoisonBag :: BeginPlay + // + //============================================================================ + + override void BeginPlay () + { + Super.BeginPlay (); + // If a subclass's specific icon is not defined, let it use the base class's. + if (!Icon.isValid()) + { + Inventory defbag = Inventory(GetDefaultByType("ArtiPoisonBag")); + Icon = defbag.Icon; + } + } + + //============================================================================ + // + // GetFlechetteType + // + //============================================================================ + + private class GetFlechetteType(Actor other) + { + class spawntype = null; + PlayerPawn pp = PlayerPawn(other); + if (pp) + { + spawntype = pp.FlechetteType; + } + if (spawntype == null) + { + // default fallback if nothing valid defined. + spawntype = "ArtiPoisonBag3"; + } + return spawntype; + } + + //============================================================================ + // + // AArtiPoisonBag :: HandlePickup + // + //============================================================================ + + override bool HandlePickup (Inventory item) + { + // Only do special handling when picking up the base class + if (item.GetClass() != "ArtiPoisonBag") + { + return Super.HandlePickup (item); + } + + if (GetClass() == GetFlechetteType(Owner)) + { + if (Amount < MaxAmount || sv_unlimited_pickup) + { + Amount += item.Amount; + if (Amount > MaxAmount && !sv_unlimited_pickup) + { + Amount = MaxAmount; + } + item.bPickupGood = true; + } + return true; + } + return false; + } + + //============================================================================ + // + // AArtiPoisonBag :: CreateCopy + // + //============================================================================ + + override Inventory CreateCopy (Actor other) + { + // Only the base class gets special handling + if (GetClass() != "ArtiPoisonBag") + { + return Super.CreateCopy (other); + } + + class spawntype = GetFlechetteType(other); + Inventory copy = Inventory(Spawn (spawntype)); + copy.Amount = Amount; + copy.MaxAmount = MaxAmount; + GoAwayAndDie (); + return copy; + } } // Poison Bag 1 (The Cleric's) ---------------------------------------------- -class ArtiPoisonBag1 : ArtiPoisonBag native +class ArtiPoisonBag1 : ArtiPoisonBag { Default { Inventory.Icon "ARTIPSB1"; Tag "$TAG_ARTIPOISONBAG1"; } + + override bool Use (bool pickup) + { + Actor mo = Spawn("PoisonBag", Owner.Vec3Offset( + 16 * cos(Owner.angle), + 24 * sin(Owner.angle), + -Owner.Floorclip + 8), ALLOW_REPLACE); + if (mo) + { + mo.target = Owner; + return true; + } + return false; + } + } // Poison Bag 2 (The Mage's) ------------------------------------------------ -class ArtiPoisonBag2 : ArtiPoisonBag native +class ArtiPoisonBag2 : ArtiPoisonBag { Default { Inventory.Icon "ARTIPSB2"; Tag "$TAG_ARTIPOISONBAG2"; } + + override bool Use (bool pickup) + { + Actor mo = Spawn("FireBomb", Owner.Vec3Offset( + 16 * cos(Owner.angle), + 24 * sin(Owner.angle), + -Owner.Floorclip + 8), ALLOW_REPLACE); + if (mo) + { + mo.target = Owner; + return true; + } + return false; + } + } // Poison Bag 3 (The Fighter's) --------------------------------------------- -class ArtiPoisonBag3 : ArtiPoisonBag native +class ArtiPoisonBag3 : ArtiPoisonBag { Default { Inventory.Icon "ARTIPSB3"; Tag "$TAG_ARTIPOISONBAG3"; } + + override bool Use (bool pickup) + { + Actor mo = Spawn("ThrowingBomb", Owner.Pos + (0,0,35. - Owner.Floorclip + (Owner.player? Owner.player.crouchoffset : 0)), ALLOW_REPLACE); + if (mo) + { + mo.angle = Owner.angle + (((random[PoisonBag]() & 7) - 4) * (360./256.)); + + /* Original flight code from Hexen + * mo.momz = 4*F.RACUNIT+((player.lookdir)<<(F.RACBITS-4)); + * mo.z += player.lookdir<<(F.RACBITS-4); + * P_ThrustMobj(mo, mo.ang, mo.info.speed); + * mo.momx += player.mo.momx>>1; + * mo.momy += player.mo.momy>>1; + */ + + // When looking straight ahead, it uses a z velocity of 4 while the xy velocity + // is as set by the projectile. To accommodate self with a proper trajectory, we + // aim the projectile ~20 degrees higher than we're looking at and increase the + // speed we fire at accordingly. + double orgpitch = -Owner.Pitch; + double modpitch = clamp(-Owner.Pitch + 20, -89., 89.); + double ang = mo.angle; + double speed = (mo.Speed, 4.).Length(); + double xyscale = speed * cos(modpitch); + + mo.Vel.Z = speed * sin(modpitch); + mo.Vel.X = xyscale * cos(ang) + Owner.Vel.X / 2; + mo.Vel.Y = xyscale * sin(ang) + Owner.Vel.Y / 2; + mo.AddZ(mo.Speed * sin(modpitch)); + + mo.target = Owner; + mo.tics -= random[PoisonBag]()&3; + mo.CheckMissileSpawn(Owner.radius); + return true; + } + return false; + } + + } // Poison Bag 4 (Custom Giver) ---------------------------------------------- -class ArtiPoisonBagGiver : ArtiPoisonBag native +class ArtiPoisonBagGiver : ArtiPoisonBag { Default { Inventory.Icon "ARTIPSB4"; } + + override bool Use (bool pickup) + { + Class missiletype = MissileName; + if (missiletype != null) + { + Actor mo = Spawn (missiletype, Owner.Pos, ALLOW_REPLACE); + if (mo != null) + { + Inventory inv = Inventory(mo); + if (inv && inv.CallTryPickup(Owner)) return true; + mo.Destroy(); // Destroy if not inventory or couldn't be picked up + } + } + return false; + } + } // Poison Bag 5 (Custom Thrower) -------------------------------------------- -class ArtiPoisonBagShooter : ArtiPoisonBag native +class ArtiPoisonBagShooter : ArtiPoisonBag { Default { Inventory.Icon "ARTIPSB5"; } + + override bool Use (bool pickup) + { + Class missiletype = MissileName; + if (missiletype != null) + { + Actor mo = Owner.SpawnPlayerMissile(missiletype); + if (mo != null) + { + // automatic handling of seeker missiles + if (mo.bSeekerMissile) + { + mo.tracer = Owner.target; + } + return true; + } + } + return false; + } + } // Poison Cloud ------------------------------------------------------------- -class PoisonCloud : Actor native +class PoisonCloud : Actor { Default { @@ -198,9 +442,6 @@ class PoisonCloud : Actor native DamageType "PoisonCloud"; } - native void A_PoisonBagDamage(); - native void A_PoisonBagCheck(); - States { Spawn: @@ -215,6 +456,97 @@ class PoisonCloud : Actor native PSBG FD 6; Stop; } + + //=========================================================================== + // + // + // + //=========================================================================== + + override void BeginPlay () + { + Vel.X = MinVel; // missile objects must move to impact other objects + special1 = 24+(random[PoisonCloud]() & 7); + special2 = 0; + } + + //=========================================================================== + // + // + // + //=========================================================================== + + override int DoSpecialDamage (Actor victim, int damage, Name damagetype) + { + if (victim.player) + { + bool mate = (target != null && victim.player != target.player && victim.IsTeammate (target)); + bool dopoison; + + if (!mate) + { + dopoison = victim.player.poisoncount < 4; + } + else + { + dopoison = victim.player.poisoncount < (int)(4. * level.teamdamage); + } + + if (dopoison) + { + int damage = 15 + (random[PoisonCloud]()&15); + if (mate) + { + damage = (int)(damage * level.teamdamage); + } + // Handle passive damage modifiers (e.g. PowerProtection) + damage = victim.GetModifiedDamage(damagetype, damage, true); + // Modify with damage factors + damage = victim.ApplyDamageFactor(damagetype, damage); + if (damage > 0) + { + victim.player.PoisonDamage (self, 15 + (random[PoisonCloud]() & 15), false); // Don't play painsound + + // If successful, play the poison sound. + if (victim.player.PoisonPlayer (self, self.target, 50)) + victim.A_PlaySound ("*poison", CHAN_VOICE); + } + } + return -1; + } + else if (!victim.bIsMonster) + { // only damage monsters/players with the poison cloud + return -1; + } + return damage; + } + + //=========================================================================== + // + // A_PoisonBagCheck + // + //=========================================================================== + + void A_PoisonBagCheck() + { + if (--special1 <= 0) + { + SetStateLabel("Death"); + } + } + + //=========================================================================== + // + // A_PoisonBagDamage + // + //=========================================================================== + + void A_PoisonBagDamage() + { + A_Explode(4, 40); + AddZ(BobSin(special2) / 16); + special2 = (special2 + 1) & 63; + } } // Poison Shroom ------------------------------------------------------------ @@ -238,8 +570,6 @@ class ZPoisonShroom : PoisonBag DeathSound "PoisonShroomDeath"; } - native void A_PoisonShroom(); - States { Spawn: @@ -255,5 +585,16 @@ class ZPoisonShroom : PoisonBag SHRM F -1; Stop; } + + //=========================================================================== + // + // A_PoisonShroom + // + //=========================================================================== + + void A_PoisonShroom() + { + tics = 128 + (random[PoisonShroom]() << 1); + } } diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index dab317ea6..25c94cb87 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -30,6 +30,7 @@ class Inventory : Actor native virtual native bool HandlePickup(Inventory item); virtual native Inventory CreateCopy(Actor other); + native void GoAwayAndDie(); // These are regular functions for the item itself. private native void A_RestoreSpecialDoomThing(); From f409a24d2d0ee06c5adb9de9c509724ef05c0232 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 27 Nov 2016 15:50:58 +0100 Subject: [PATCH 136/185] - fixed: Readonly pointers never were flagged as such. - fixed: Assignment from a readonly to a read-allowed pointer must be an error. - made GetDefaultByType a builtin so that it can do proper type assignment to the result, which for a function would be problematic in this case, even if automatic type deduction was implemented. Since this returns the class defaults which are not a real object, the result cannot be subjected to a type cast. - error out if a type cast of a readonly pointer is attempted. - fixed: FxBooleanNot could clobber a local variable because it used the source register to manipulate the result. --- src/dobjtype.cpp | 2 +- src/namedef.h | 1 + src/scripting/codegeneration/codegen.cpp | 100 +++++++++++++++++++++- src/scripting/codegeneration/codegen.h | 19 ++++ src/scripting/vm/vmframe.cpp | 2 +- wadsrc/static/zscript/actor.txt | 3 +- wadsrc/static/zscript/hexen/flechette.txt | 11 ++- 7 files changed, 125 insertions(+), 13 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index e9f574ea4..88c31d007 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -1688,7 +1688,7 @@ PPointer *NewPointer(PType *type, bool isconst) PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, &bucket); if (ptype == NULL) { - ptype = new PPointer(type); + ptype = new PPointer(type, isconst); TypeTable.AddType(ptype, RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, bucket); } return static_cast(ptype); diff --git a/src/namedef.h b/src/namedef.h index 413b68124..3a4a1c180 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -286,6 +286,7 @@ xx(Random2) xx(RandomPick) xx(FRandomPick) xx(GetClass) +xx(GetDefaultByType) xx(Exp) xx(Log10) xx(Ceil) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 72d79647f..db09a0387 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -262,7 +262,7 @@ static bool AreCompatiblePointerTypes(PType *dest, PType *source, bool forcompar auto fromtype = static_cast(source); auto totype = static_cast(dest); if (fromtype == nullptr) return true; - if (!forcompare && totype->IsConst && !fromtype->IsConst) return false; + if (!forcompare && totype->IsConst != fromtype->IsConst) return false; if (fromtype == totype) return true; if (fromtype->PointedType->IsKindOf(RUNTIME_CLASS(PClass)) && totype->PointedType->IsKindOf(RUNTIME_CLASS(PClass))) { @@ -1874,10 +1874,13 @@ ExpEmit FxUnaryNotBoolean::Emit(VMFunctionBuilder *build) assert(Operand->ValueType == TypeBool); assert(ValueType == TypeBool || IsInteger()); // this may have been changed by an int cast. ExpEmit from = Operand->Emit(build); + from.Free(build); + ExpEmit to(build, REGT_INT); assert(!from.Konst); // boolean not is the same as XOR-ing the lowest bit - build->Emit(OP_XOR_RK, from.RegNum, from.RegNum, build->GetConstantInt(1)); - return from; + + build->Emit(OP_XOR_RK, to.RegNum, from.RegNum, build->GetConstantInt(1)); + return to; } //========================================================================== @@ -4309,7 +4312,18 @@ FxExpression *FxDynamicCast::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); SAFE_RESOLVE(expr, ctx); + if (expr->ExprType == EFX_GetDefaultByType) + { + int a = 0; + } bool constflag = expr->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(expr->ValueType)->IsConst; + if (constflag) + { + // readonly pointers are normally only used for class defaults which lack type information to be cast properly, so we have to error out here. + ScriptPosition.Message(MSG_ERROR, "Cannot cast a readonly pointer"); + delete this; + return nullptr; + } expr = new FxTypeCast(expr, NewPointer(RUNTIME_CLASS(DObject), constflag), true, true); expr = expr->Resolve(ctx); if (expr == nullptr) @@ -7012,6 +7026,14 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) } break; + case NAME_GetDefaultByType: + if (CheckArgSize(NAME_GetDefaultByType, ArgList, 1, 1, ScriptPosition)) + { + func = new FxGetDefaultByType(ArgList[0]); + ArgList[0] = nullptr; + } + break; + case NAME_Random: // allow calling Random without arguments to default to (0, 255) if (ArgList.Size() == 0) @@ -8147,6 +8169,78 @@ ExpEmit FxGetClass::Emit(VMFunctionBuilder *build) // //========================================================================== +FxGetDefaultByType::FxGetDefaultByType(FxExpression *self) + :FxExpression(EFX_GetDefaultByType, self->ScriptPosition) +{ + Self = self; +} + +FxGetDefaultByType::~FxGetDefaultByType() +{ + SAFE_DELETE(Self); +} + +FxExpression *FxGetDefaultByType::Resolve(FCompileContext &ctx) +{ + SAFE_RESOLVE(Self, ctx); + PClass *cls = nullptr; + + if (Self->ValueType == TypeString || Self->ValueType == TypeName) + { + if (Self->isConstant()) + { + cls = PClass::FindActor(static_cast(Self)->GetValue().GetName()); + if (cls == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "GetDefaultByType() requires an actor class type, but got %s", static_cast(Self)->GetValue().GetString().GetChars()); + delete this; + return nullptr; + } + Self = new FxConstant(cls, NewClassPointer(cls), ScriptPosition); + } + else + { + // this is the ugly case. We do not know what we have and cannot do proper type casting. + // For now error out and let this case require explicit handling on the user side. + ScriptPosition.Message(MSG_ERROR, "GetDefaultByType() requires an actor class type", static_cast(Self)->GetValue().GetString().GetChars()); + delete this; + return nullptr; + } + } + else + { + auto cp = dyn_cast(Self->ValueType); + if (cp == nullptr || !cp->ClassRestriction->IsDescendantOf(RUNTIME_CLASS(AActor))) + { + ScriptPosition.Message(MSG_ERROR, "GetDefaultByType() requires an actor class type"); + delete this; + return nullptr; + } + cls = cp->ClassRestriction; + } + ValueType = NewPointer(cls, true); + return this; +} + +ExpEmit FxGetDefaultByType::Emit(VMFunctionBuilder *build) +{ + ExpEmit op = Self->Emit(build); + op.Free(build); + ExpEmit to(build, REGT_POINTER); + if (op.Konst) + { + build->Emit(OP_LKP, to.RegNum, op.RegNum); + op = to; + } + build->Emit(OP_LO, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults))); + return to; +} + +//========================================================================== +// +// +//========================================================================== + FxColorLiteral::FxColorLiteral(FArgumentList &args, FScriptPosition &sc) :FxExpression(EFX_ColorLiteral, sc) { diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index ae0581e05..e586f1fbe 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -289,6 +289,7 @@ enum EFxType EFX_NamedNode, EFX_GetClass, EFX_ColorLiteral, + EFX_GetDefaultByType, EFX_COUNT }; @@ -1542,6 +1543,24 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// FxFlopFunctionCall +// +//========================================================================== + +class FxGetDefaultByType : public FxExpression +{ + FxExpression *Self; + +public: + + FxGetDefaultByType(FxExpression *self); + ~FxGetDefaultByType(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxColorLiteral diff --git a/src/scripting/vm/vmframe.cpp b/src/scripting/vm/vmframe.cpp index 0ec6ec15b..428266d0f 100644 --- a/src/scripting/vm/vmframe.cpp +++ b/src/scripting/vm/vmframe.cpp @@ -424,7 +424,7 @@ int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMRetur { bool allocated = false; try - { + { if (func->Native) { return static_cast(func)->NativeCall(this, params, func->DefaultArgs, numparams, results, numresults); diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 884bcc8a5..739b5574f 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -238,7 +238,7 @@ class Actor : Thinker native VisiblePitch 0, 0; DefaultStateUsage SUF_ACTOR|SUF_OVERLAY; } - + // Functions // 'parked' global functions. @@ -268,7 +268,6 @@ class Actor : Thinker native virtual native bool SpecialBlastHandling (Actor source, double strength); - native static readonly GetDefaultByType(class cls); native static double GetDefaultSpeed(class type); native void RemoveFromHash(); native string GetTag(string defstr = ""); diff --git a/wadsrc/static/zscript/hexen/flechette.txt b/wadsrc/static/zscript/hexen/flechette.txt index f8f6a0b8a..fc9268c5b 100644 --- a/wadsrc/static/zscript/hexen/flechette.txt +++ b/wadsrc/static/zscript/hexen/flechette.txt @@ -28,7 +28,7 @@ class PoisonBag : Actor void A_PoisonBagInit() { - Actor mo = Spawn("PoisonCloud", (pos.xy, 28), ALLOW_REPLACE); + Actor mo = Spawn("PoisonCloud", pos + (0, 0, 28), ALLOW_REPLACE); if (mo) { mo.target = target; @@ -184,8 +184,7 @@ class ArtiPoisonBag : Inventory // If a subclass's specific icon is not defined, let it use the base class's. if (!Icon.isValid()) { - Inventory defbag = Inventory(GetDefaultByType("ArtiPoisonBag")); - Icon = defbag.Icon; + Icon = GetDefaultByType("ArtiPoisonBag").Icon; } } @@ -469,7 +468,7 @@ class PoisonCloud : Actor special1 = 24+(random[PoisonCloud]() & 7); special2 = 0; } - + //=========================================================================== // // @@ -482,7 +481,7 @@ class PoisonCloud : Actor { bool mate = (target != null && victim.player != target.player && victim.IsTeammate (target)); bool dopoison; - + if (!mate) { dopoison = victim.player.poisoncount < 4; @@ -494,7 +493,7 @@ class PoisonCloud : Actor if (dopoison) { - int damage = 15 + (random[PoisonCloud]()&15); + damage = 15 + (random[PoisonCloud]() & 15); if (mate) { damage = (int)(damage * level.teamdamage); From 2e99681cedc42749ccd98a4bd58b38581934fa52 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 27 Nov 2016 16:22:23 +0100 Subject: [PATCH 137/185] - fixed: When trying to calculate the damage for a blasted actor hitting another one, the velocity checks used the signed values, causing totally random damaging effects depending on the direction the objects were moving. This bug had been present in the original Hexen source as well. --- src/p_map.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index d102307bc..475cd3569 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -1256,7 +1256,7 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch { // ideally this should take the mass factor into account thing->Vel += tm.thing->Vel.XY(); - if ((thing->Vel.X + thing->Vel.Y) > 3.) + if (fabs(thing->Vel.X) + fabs(thing->Vel.Y) > 3.) { int newdam; damage = (tm.thing->Mass / 100) + 1; From 0488b18f8f1d381e49105256727d02abe7ed2c4e Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sat, 26 Nov 2016 13:26:44 +0200 Subject: [PATCH 138/185] Fixed junk character(s) left after removing portion of string See http://forum.zdoom.org/viewtopic.php?t=54379 --- src/zstring.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/zstring.cpp b/src/zstring.cpp index e8e867323..1999f54fe 100644 --- a/src/zstring.cpp +++ b/src/zstring.cpp @@ -397,6 +397,7 @@ void FString::Remove(size_t index, size_t remlen) if (Data()->RefCount == 1) { // Can do this in place memmove(Chars + index, Chars + index + remlen, Len() - index - remlen); + memset(Chars + Len() - remlen, 0, remlen); Data()->Len -= (unsigned)remlen; } else From aab304c0cf651f92c8db5500534be97b3224636d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 27 Nov 2016 17:43:11 +0100 Subject: [PATCH 139/185] - fixed: Lemon includes ParseTrace only in debug builds so the option to use it must be #ifdef'd. --- src/scripting/zscript/zcc_parser.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/scripting/zscript/zcc_parser.cpp b/src/scripting/zscript/zcc_parser.cpp index 989ec10ae..3b2ada4c8 100644 --- a/src/scripting/zscript/zcc_parser.cpp +++ b/src/scripting/zscript/zcc_parser.cpp @@ -303,6 +303,7 @@ static void DoParse(int lumpnum) parser = ZCCParseAlloc(malloc); ZCCParseState state; +#ifndef NDEBUG FILE *f = nullptr; const char *tracefile = Args->CheckValue("-tracefile"); if (tracefile != nullptr) @@ -311,6 +312,7 @@ static void DoParse(int lumpnum) char prompt = '\0'; ZCCParseTrace(f, &prompt); } +#endif sc.OpenLumpNum(lumpnum); auto saved = sc.SavePos(); @@ -360,10 +362,12 @@ static void DoParse(int lumpnum) I_Error("%d errors while parsing %s", FScriptPosition::ErrorCounter, Wads.GetLumpFullPath(lumpnum).GetChars()); } +#ifndef NDEBUG if (f != nullptr) { fclose(f); } +#endif // Make a dump of the AST before running the compiler for diagnostic purposes. if (Args->CheckParm("-dumpast")) From de6969997aa088b5d3566be321e0bd835de5b8dd Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 27 Nov 2016 18:52:24 +0100 Subject: [PATCH 140/185] - scriptified Hexen's flies. A few notes: * this accesses the lines array in sector_t which effectively is a pointer to an array of pointers - a type the parser can not represent. The compiler has no problems with it, so for now it is defined internally. * array sizes were limited to 65536 entries because the 'bound' instruction only existed as an immediate version with no provisions for larger values. For the static map arrays 65536 is not sufficient so now there are alternative instructions for these cases. * despite the above, at the moment there is no proper bounds checking for arrays that have no fixed size. To do this, a lot more work is needed. The type system as-is is not prepared for such a scenario. --- src/p_mobj.cpp | 1 + src/p_sectors.cpp | 16 ++++ src/r_defs.h | 2 - src/scripting/codegeneration/codegen.cpp | 98 +++++++++++++-------- src/scripting/codegeneration/codegen.h | 1 + src/scripting/thingdef_data.cpp | 12 ++- src/scripting/vm/vmbuilder.cpp | 2 +- src/scripting/vm/vmdisasm.cpp | 1 - src/scripting/vm/vmexec.h | 21 +++++ src/scripting/vm/vmops.h | 2 + src/scripting/zscript/zcc_parser.cpp | 2 + wadsrc/static/zscript/actor.txt | 1 + wadsrc/static/zscript/base.txt | 21 ++++- wadsrc/static/zscript/hexen/flies.txt | 106 ++++++++++++++++++++++- 14 files changed, 241 insertions(+), 45 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index ad1c317e8..358e46e8c 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -154,6 +154,7 @@ AActor::~AActor () extern FFlagDef InternalActorFlagDefs[]; extern FFlagDef ActorFlagDefs[]; +DEFINE_FIELD(AActor, snext) DEFINE_FIELD(AActor, player) DEFINE_FIELD_NAMED(AActor, __Pos, pos) DEFINE_FIELD_NAMED(AActor, __Pos.X, x) diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index 841401226..585c60f4b 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -1310,3 +1310,19 @@ DEFINE_FIELD_X(Sector, sector_t, SecActTarget) DEFINE_FIELD_X(Sector, sector_t, Portals) DEFINE_FIELD_X(Sector, sector_t, PortalGroup) DEFINE_FIELD_X(Sector, sector_t, sectornum) + +DEFINE_FIELD_X(Line, line_t, v1) +DEFINE_FIELD_X(Line, line_t, v2) +DEFINE_FIELD_X(Line, line_t, delta) +DEFINE_FIELD_X(Line, line_t, flags) +DEFINE_FIELD_X(Line, line_t, activation) +DEFINE_FIELD_X(Line, line_t, special) +DEFINE_FIELD_X(Line, line_t, args) +DEFINE_FIELD_X(Line, line_t, alpha) +DEFINE_FIELD_X(Line, line_t, sidedef) +DEFINE_FIELD_X(Line, line_t, bbox) +DEFINE_FIELD_X(Line, line_t, frontsector) +DEFINE_FIELD_X(Line, line_t, backsector) +DEFINE_FIELD_X(Line, line_t, validcount) +DEFINE_FIELD_X(Line, line_t, locknumber) +DEFINE_FIELD_X(Line, line_t, portalindex) diff --git a/src/r_defs.h b/src/r_defs.h index f33baeedc..9c2a822f2 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -1191,9 +1191,7 @@ struct side_t struct line_t { vertex_t *v1, *v2; // vertices, from v1 to v2 -private: DVector2 delta; // precalculated v2 - v1 for side checking -public: uint32_t flags; uint32_t activation; // activation type int special; diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index db09a0387..f63629bb5 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -6578,9 +6578,16 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) PArray *arraytype = dyn_cast(Array->ValueType); if (arraytype == nullptr) { - ScriptPosition.Message(MSG_ERROR, "'[]' can only be used with arrays."); - delete this; - return nullptr; + // Check if we got a pointer to an array. Some native data structures (like the line list in sectors) use this. + PPointer *ptype = dyn_cast(Array->ValueType); + if (ptype == nullptr || !ptype->PointedType->IsKindOf(RUNTIME_CLASS(PArray))) + { + ScriptPosition.Message(MSG_ERROR, "'[]' can only be used with arrays."); + delete this; + return nullptr; + } + arraytype = static_cast(ptype->PointedType); + arrayispointer = true; } if (index->isConstant()) { @@ -6592,37 +6599,40 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) return nullptr; } - // if this is an array within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset. - if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember) + if (!arrayispointer) { - auto parentfield = static_cast(Array)->membervar; - // PFields are garbage collected so this will be automatically taken care of later. - auto newfield = new PField(NAME_None, arraytype->ElementType, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset); - static_cast(Array)->membervar = newfield; - Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. - auto x = Array->Resolve(ctx); - Array = nullptr; - return x; - } - else if (Array->ExprType == EFX_GlobalVariable) - { - auto parentfield = static_cast(Array)->membervar; - auto newfield = new PField(NAME_None, arraytype->ElementType, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset); - static_cast(Array)->membervar = newfield; - Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. - auto x = Array->Resolve(ctx); - Array = nullptr; - return x; - } - else if (Array->ExprType == EFX_StackVariable) - { - auto parentfield = static_cast(Array)->membervar; - auto newfield = new PField(NAME_None, arraytype->ElementType, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset); - static_cast(Array)->ReplaceField(newfield); - Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. - auto x = Array->Resolve(ctx); - Array = nullptr; - return x; + // if this is an array within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset. + if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember) + { + auto parentfield = static_cast(Array)->membervar; + // PFields are garbage collected so this will be automatically taken care of later. + auto newfield = new PField(NAME_None, arraytype->ElementType, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset); + static_cast(Array)->membervar = newfield; + Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. + auto x = Array->Resolve(ctx); + Array = nullptr; + return x; + } + else if (Array->ExprType == EFX_GlobalVariable) + { + auto parentfield = static_cast(Array)->membervar; + auto newfield = new PField(NAME_None, arraytype->ElementType, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset); + static_cast(Array)->membervar = newfield; + Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. + auto x = Array->Resolve(ctx); + Array = nullptr; + return x; + } + else if (Array->ExprType == EFX_StackVariable) + { + auto parentfield = static_cast(Array)->membervar; + auto newfield = new PField(NAME_None, arraytype->ElementType, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset); + static_cast(Array)->ReplaceField(newfield); + Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. + auto x = Array->Resolve(ctx); + Array = nullptr; + return x; + } } } @@ -6644,8 +6654,17 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) { + PArray *arraytype; + + if (arrayispointer) + { + arraytype = static_cast(static_cast(Array->ValueType)->PointedType); + } + else + { + arraytype = static_cast(Array->ValueType); + } ExpEmit start = Array->Emit(build); - PArray *const arraytype = static_cast(Array->ValueType); /* what was this for? if (start.Konst) @@ -6700,7 +6719,16 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) else { ExpEmit indexv(index->Emit(build)); - build->Emit(OP_BOUND, indexv.RegNum, arraytype->ElementCount); + // Todo: For dynamically allocated arrays (like global sector and linedef tables) we need to get the bound value in here somehow. + // Right now their bounds are not properly checked for. + if (arraytype->ElementCount > 65535) + { + build->Emit(OP_BOUND_K, indexv.RegNum, build->GetConstantInt(arraytype->ElementCount)); + } + else + { + build->Emit(OP_BOUND, indexv.RegNum, arraytype->ElementCount); + } if (!start.Konst) { diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index e586f1fbe..5d0af0b49 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -1416,6 +1416,7 @@ public: FxExpression *index; bool AddressRequested; bool AddressWritable; + bool arrayispointer = false; FxArrayElement(FxExpression*, FxExpression*); ~FxArrayElement(); diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 7a3d3a7c6..6f0cad099 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -43,6 +43,7 @@ #include "d_player.h" #include "p_effect.h" #include "autosegs.h" +#include "p_maputl.h" #include "gi.h" static TArray properties; @@ -703,7 +704,11 @@ void InitThingdef() auto sptr = NewPointer(sstruct); sstruct->AddNativeField("soundtarget", TypeActor, myoffsetof(sector_t, SoundTarget)); - // expose the glibal Multiplayer variable. + // expose the global validcount variable. + PField *vcf = new PField("validcount", TypeSInt32, VARF_Native | VARF_Static, (intptr_t)&validcount); + GlobalSymbols.AddSymbol(vcf); + + // expose the global Multiplayer variable. PField *multif = new PField("multiplayer", TypeBool, VARF_Native | VARF_ReadOnly | VARF_Static, (intptr_t)&multiplayer); GlobalSymbols.AddSymbol(multif); @@ -726,6 +731,11 @@ void InitThingdef() PField *playerf = new PField("players", parray, VARF_Native | VARF_Static, (intptr_t)&players); GlobalSymbols.AddSymbol(playerf); + // set up the lines array in the sector struct. This is a bit messy because the type system is not prepared to handle a pointer to an array of pointers to a native struct even remotely well... + // As a result, the size has to be set to something large and arbritrary because it can change between maps. This will need some serious improvement when things get cleaned up. + pstruct = NewNativeStruct("Sector", nullptr); + pstruct->AddNativeField("lines", NewPointer(NewArray(NewPointer(NewNativeStruct("line", nullptr), false), 0x40000), false), myoffsetof(sector_t, lines), VARF_Native); + parray = NewArray(TypeBool, MAXPLAYERS); playerf = new PField("playeringame", parray, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&playeringame); GlobalSymbols.AddSymbol(playerf); diff --git a/src/scripting/vm/vmbuilder.cpp b/src/scripting/vm/vmbuilder.cpp index 74b7a3400..f358fce7b 100644 --- a/src/scripting/vm/vmbuilder.cpp +++ b/src/scripting/vm/vmbuilder.cpp @@ -779,6 +779,7 @@ VMFunction *FFunctionBuildList::AddFunction(PFunction *functype, FxExpression *c it.PrintableName = name; it.Function = new VMScriptFunction; it.Function->Name = functype->SymbolName; + it.Function->PrintableName = name; it.Function->ImplicitArgs = functype->GetImplicitArgs(); it.Proto = nullptr; it.FromDecorate = fromdecorate; @@ -881,7 +882,6 @@ void FFunctionBuildList::Build() DumpFunction(dump, sfunc, item.PrintableName.GetChars(), (int)item.PrintableName.Len()); codesize += sfunc->CodeSize; } - sfunc->PrintableName = item.PrintableName; sfunc->Unsafe = ctx.Unsafe; } catch (CRecoverableError &err) diff --git a/src/scripting/vm/vmdisasm.cpp b/src/scripting/vm/vmdisasm.cpp index cba67cbdc..88962bf68 100644 --- a/src/scripting/vm/vmdisasm.cpp +++ b/src/scripting/vm/vmdisasm.cpp @@ -104,7 +104,6 @@ #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 diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 4df76a73e..06c6ade8e 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -713,6 +713,7 @@ begin: assert(0); NEXTOP; + // Fixme: This really needs to throw something more informative than a number. Printing the message here instead of passing it to the exception is not sufficient. OP(BOUND): if (reg.d[a] >= BC) { @@ -722,6 +723,26 @@ begin: } NEXTOP; + OP(BOUND_K): + ASSERTKD(BC); + if (reg.d[a] >= konstd[BC]) + { + assert(false); + Printf("Array access out of bounds: Max. index = %u, current index = %u\n", konstd[BC], reg.d[a]); + THROW(X_ARRAY_OUT_OF_BOUNDS); + } + NEXTOP; + + OP(BOUND_R): + ASSERTD(B); + if (reg.d[a] >= reg.d[B]) + { + assert(false); + Printf("Array access out of bounds: Max. index = %u, current index = %u\n", reg.d[B], reg.d[a]); + THROW(X_ARRAY_OUT_OF_BOUNDS); + } + NEXTOP; + OP(CONCAT): ASSERTS(a); ASSERTS(B); ASSERTS(C); reg.s[a] = reg.s[B] + reg.s[C]; diff --git a/src/scripting/vm/vmops.h b/src/scripting/vm/vmops.h index b36f93881..e5b6d34eb 100644 --- a/src/scripting/vm/vmops.h +++ b/src/scripting/vm/vmops.h @@ -110,6 +110,8 @@ xx(CATCH, catch, CATCH, NOP, 0, 0), // A == 0: continue search on next try // A == 3: (pkB == ) then pc++ ; next instruction must JMP to another CATCH // for A > 0, exception is stored in pC xx(BOUND, bound, RII16, NOP, 0, 0), // if rA >= BC, throw exception +xx(BOUND_K, bound, LKI, NOP, 0, 0), // if rA >= const[BC], throw exception +xx(BOUND_R, bound, RIRI, NOP, 0, 0), // if rA >= rB, throw exception // String instructions. xx(CONCAT, concat, RSRSRS, NOP, 0, 0), // sA = sB..sC diff --git a/src/scripting/zscript/zcc_parser.cpp b/src/scripting/zscript/zcc_parser.cpp index 3b2ada4c8..64ac2c86d 100644 --- a/src/scripting/zscript/zcc_parser.cpp +++ b/src/scripting/zscript/zcc_parser.cpp @@ -346,7 +346,9 @@ static void DoParse(int lumpnum) } } +#ifndef NDEBUG if (f) fprintf(f, "Starting parsing %s\n", sc.String); +#endif ParseSingleFile(sc.String, 0, parser, state); } } diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 739b5574f..7b2b99570 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -11,6 +11,7 @@ class Actor : Thinker native // flags are not defined here, the native fields for those get synthesized from the internal tables. // for some comments on these fields, see their native representations in actor.h. + native readonly Actor snext; // next in sector list. native PlayerInfo Player; native readonly vector3 Pos; native vector3 Prev; diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 3766bb6b2..397ba4c32 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -129,6 +129,23 @@ struct F3DFloor native { } +struct Line native +{ + //native readonly vertex v1, v2; // vertices, from v1 to v2 + native readonly Vector2 delta; // precalculated v2 - v1 for side checking + native uint flags; + native uint activation; // activation type + native int special; + native int args[5]; // <--- hexen-style arguments (expanded to ZDoom's full width) + native double alpha; // <--- translucency (0=invisibile, FRACUNIT=opaque) + //native Side sidedef[2]; + native readonly double bbox[4]; // bounding box, for the extent of the LineDef. + native readonly Sector frontsector, backsector; + native int validcount; // if == validcount, already checked + native int locknumber; // [Dusk] lock number for special + native readonly uint portalindex; +} + struct Sector native { //secplane_t floorplane, ceilingplane; @@ -145,7 +162,7 @@ struct Sector native native readonly Vector2 centerspot; native int validcount; - //AActor* thinglist; + native Actor thinglist; native double friction, movefactor; native int terrainnum[2]; @@ -170,7 +187,7 @@ struct Sector native native int nextsec; native readonly int16 linecount; - //line_t **lines; + //line_t **lines; // this is defined internally to avoid exposing some overly complicated type to the parser native readonly Sector heightsec; diff --git a/wadsrc/static/zscript/hexen/flies.txt b/wadsrc/static/zscript/hexen/flies.txt index 464e6e9d9..d9800552b 100644 --- a/wadsrc/static/zscript/hexen/flies.txt +++ b/wadsrc/static/zscript/hexen/flies.txt @@ -15,9 +15,6 @@ class LittleFly : Actor ActiveSound "FlyBuzz"; } - native void A_FlySearch(); - native void A_FlyBuzz(); - States { Spawn: @@ -27,4 +24,107 @@ class LittleFly : Actor AFLY ABCD 3 A_FlyBuzz; Loop; } + + //=========================================================================== + // + // FindCorpse + // + // Finds a corpse to buzz around. We can't use a blockmap check because + // corpses generally aren't linked into the blockmap. + // + //=========================================================================== + + private Actor FindCorpse(sector sec, int recurselimit) + { + Actor fallback = null; + sec.validcount = validcount; + + // Search the current sector + for (Actor check = sec.thinglist; check != null; check = check.snext) + { + if (check == self) + continue; + if (!check.bCorpse) + continue; + if (!CheckSight(check)) + continue; + fallback = check; + if (random[Fly](0,1)) // 50% chance to try to pick a different corpse + continue; + return check; + } + if (--recurselimit <= 0 || (fallback != null && random[Fly](0,1))) + { + return fallback; + } + // Try neighboring sectors + for (int i = 0; i < sec.linecount; ++i) + { + line ln = sec.lines[i]; + sector sec2 = (ln.frontsector == sec) ? ln.backsector : ln.frontsector; + if (sec2 != null && sec2.validcount != validcount) + { + Actor neighbor = FindCorpse(sec2, recurselimit); + if (neighbor != null) + { + return neighbor; + } + } + } + return fallback; + } + + void A_FlySearch() + { + // The version from the retail beta is not so great for general use: + // 1. Pick one of the first fifty thinkers at random. + // 2. Starting from that thinker, find one that is an actor, not itself, + // and within sight. Give up after 100 sequential thinkers. + // It's effectively useless if there are more than 150 thinkers on a map. + // + // 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. + validcount++; + Actor other = FindCorpse(CurSector, 5); + if (other != null) + { + target = other; + SetStateLabel("Buzz"); + } + } + + void A_FlyBuzz() + { + Actor targ = target; + + if (targ == null || !targ.bCorpse || random[Fly]() < 5) + { + SetIdle(); + return; + } + + Angle = AngleTo(targ); + args[0]++; + if (!TryMove(Pos.XY + AngleToVector(angle, 6), true)) + { + SetIdle(true); + return; + } + if (args[0] & 2) + { + Vel.X += (random[Fly]() - 128) / 512.; + Vel.Y += (random[Fly]() - 128) / 512.; + } + int zrand = random[Fly](); + if (targ.pos.Z + 5. < pos.z && zrand > 150) + { + zrand = -zrand; + } + Vel.Z = zrand / 512.; + if (random[Fly]() < 40) + { + A_PlaySound(ActiveSound, CHAN_VOICE, 0.5f, false, ATTN_STATIC); + } + } } From 5ce5466e186e013c482e2f4b8a06d21dc5b92066 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 27 Nov 2016 20:14:43 +0100 Subject: [PATCH 141/185] - scriptified hexenspecialdecs. - made '->' a single token. Although ZScript does not use it, the parser tends to get confused and fatally chokes on leftover arrows so this ensures more robust error handling. --- src/CMakeLists.txt | 2 - src/g_hexen/a_flies.cpp | 110 ------ src/g_hexen/a_hexenmisc.cpp | 2 - src/g_hexen/a_hexenspecialdecs.cpp | 365 ------------------ src/g_level.cpp | 1 + src/p_things.cpp | 7 + src/sc_man_scanner.re | 3 +- src/sc_man_tokens.h | 1 + wadsrc/static/zscript/actor.txt | 1 + wadsrc/static/zscript/base.txt | 1 + .../static/zscript/hexen/hexenspecialdecs.txt | 291 +++++++++++++- 11 files changed, 284 insertions(+), 500 deletions(-) delete mode 100644 src/g_hexen/a_flies.cpp delete mode 100644 src/g_hexen/a_hexenspecialdecs.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2164e0a8b..6111d1714 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -859,9 +859,7 @@ set( NOT_COMPILED_SOURCE_FILES ${OTHER_SYSTEM_SOURCES} sc_man_scanner.h sc_man_scanner.re - g_hexen/a_flies.cpp g_hexen/a_heresiarch.cpp - g_hexen/a_hexenspecialdecs.cpp g_hexen/a_magecone.cpp g_hexen/a_magelightning.cpp g_hexen/a_magestaff.cpp diff --git a/src/g_hexen/a_flies.cpp b/src/g_hexen/a_flies.cpp deleted file mode 100644 index 7281dd8f2..000000000 --- a/src/g_hexen/a_flies.cpp +++ /dev/null @@ -1,110 +0,0 @@ -static FRandom pr_fly("GetOffMeFly"); - -//=========================================================================== -// -// FindCorpse -// -// Finds a corpse to buzz around. We can't use a blockmap check because -// corpses generally aren't linked into the blockmap. -// -//=========================================================================== - -static AActor *FindCorpse(AActor *fly, sector_t *sec, int recurselimit) -{ - AActor *fallback = NULL; - sec->validcount = validcount; - - // Search the current sector - for (AActor *check = sec->thinglist; check != NULL; check = check->snext) - { - if (check == fly) - continue; - if (!(check->flags & MF_CORPSE)) - continue; - if (!P_CheckSight(fly, check)) - continue; - fallback = check; - if (pr_fly(2)) // 50% chance to try to pick a different corpse - continue; - return check; - } - if (--recurselimit <= 0 || (fallback != NULL && pr_fly(2))) - { - return fallback; - } - // Try neighboring sectors - for (int i = 0; i < sec->linecount; ++i) - { - line_t *line = sec->lines[i]; - sector_t *sec2 = (line->frontsector == sec) ? line->backsector : line->frontsector; - if (sec2 != NULL && sec2->validcount != validcount) - { - AActor *neighbor = FindCorpse(fly, sec2, recurselimit); - if (neighbor != NULL) - { - return neighbor; - } - } - } - return fallback; -} - -DEFINE_ACTION_FUNCTION(AActor, A_FlySearch) -{ - // The version from the retail beta is not so great for general use: - // 1. Pick one of the first fifty thinkers at random. - // 2. Starting from that thinker, find one that is an actor, not itself, - // and within sight. Give up after 100 sequential thinkers. - // It's effectively useless if there are more than 150 thinkers on a map. - // - // 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_SELF_PROLOGUE(AActor); - - validcount++; - AActor *other = FindCorpse(self, self->Sector, 5); - if (other != NULL) - { - self->target = other; - self->SetState(self->FindState("Buzz")); - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_FlyBuzz) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *targ = self->target; - - if (targ == NULL || !(targ->flags & MF_CORPSE) || pr_fly() < 5) - { - self->SetIdle(); - return 0; - } - - self->Angles.Yaw = self->AngleTo(targ); - self->args[0]++; - if (!P_TryMove(self, self->Pos().XY() + self->Angles.Yaw.ToVector(6), true)) - { - self->SetIdle(true); - return 0; - } - if (self->args[0] & 2) - { - self->Vel.X += (pr_fly() - 128) / 512.; - self->Vel.Y += (pr_fly() - 128) / 512.; - } - int zrand = pr_fly(); - if (targ->Z() + 5. < self->Z() && zrand > 150) - { - zrand = -zrand; - } - self->Vel.Z = zrand / 512.; - if (pr_fly() < 40) - { - S_Sound(self, CHAN_VOICE, self->ActiveSound, 0.5f, ATTN_STATIC); - } - return 0; -} diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp index ae4399526..503ac6fbc 100644 --- a/src/g_hexen/a_hexenmisc.cpp +++ b/src/g_hexen/a_hexenmisc.cpp @@ -24,9 +24,7 @@ #include "a_pickups.h" // Include all the Hexen stuff here to reduce compile time -#include "a_flies.cpp" #include "a_heresiarch.cpp" -#include "a_hexenspecialdecs.cpp" #include "a_magecone.cpp" #include "a_magelightning.cpp" #include "a_magestaff.cpp" diff --git a/src/g_hexen/a_hexenspecialdecs.cpp b/src/g_hexen/a_hexenspecialdecs.cpp deleted file mode 100644 index 899d9326d..000000000 --- a/src/g_hexen/a_hexenspecialdecs.cpp +++ /dev/null @@ -1,365 +0,0 @@ -/* -** Decorations that do special things -*/ - -/* -#include "actor.h" -#include "info.h" -#include "a_action.h" -#include "m_random.h" -#include "s_sound.h" -#include "p_local.h" -#include "p_lnspec.h" -#include "a_hexenglobal.h" -#include "vm.h" -#include "g_level.h" -#include "doomstat.h" -*/ - -static FRandom pr_pottery ("PotteryExplode"); -static FRandom pr_bit ("PotteryChooseBit"); -static FRandom pr_drip ("CorpseBloodDrip"); -static FRandom pr_foo ("CorpseExplode"); -static FRandom pr_leaf ("LeafSpawn"); -static FRandom pr_leafthrust ("LeafThrust"); -static FRandom pr_leafcheck ("LeafCheck"); -static FRandom pr_shroom ("PoisonShroom"); -static FRandom pr_soaexplode ("SoAExplode"); - -// Pottery1 ------------------------------------------------------------------ - -void A_PotteryExplode (AActor *); -void A_PotteryChooseBit (AActor *); -void A_PotteryCheck (AActor *); - -//============================================================================ -// -// A_PotteryExplode -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_PotteryExplode) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo = NULL; - int i; - - for(i = (pr_pottery()&3)+3; i; i--) - { - mo = Spawn ("PotteryBit", self->Pos(), ALLOW_REPLACE); - if (mo) - { - mo->SetState (mo->SpawnState + (pr_pottery()%5)); - mo->Vel.X = pr_pottery.Random2() / 64.; - mo->Vel.Y = pr_pottery.Random2() / 64.; - mo->Vel.Z = ((pr_pottery() & 7) + 5) * 0.75; - } - } - S_Sound (mo, CHAN_BODY, "PotteryExplode", 1, ATTN_NORM); - // Spawn an item? - PClassActor *type = P_GetSpawnableType(self->args[0]); - if (type != NULL) - { - if (!((level.flags2 & LEVEL2_NOMONSTERS) || (dmflags & DF_NO_MONSTERS)) - || !(GetDefaultByType (type)->flags3 & MF3_ISMONSTER)) - { // Only spawn monsters if not -nomonsters - Spawn (type, self->Pos(), ALLOW_REPLACE); - } - } - return 0; -} - -//============================================================================ -// -// A_PotteryChooseBit -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_PotteryChooseBit) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->SetState (self->FindState(NAME_Death) + 1 + 2*(pr_bit()%5)); - self->tics = 256+(pr_bit()<<1); - return 0; -} - -//============================================================================ -// -// A_PotteryCheck -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_PotteryCheck) -{ - PARAM_SELF_PROLOGUE(AActor); - - int i; - - for(i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i]) - { - AActor *pmo = players[i].mo; - if (P_CheckSight (self, pmo) && (absangle(pmo->AngleTo(self), pmo->Angles.Yaw) <= 45)) - { // Previous state (pottery bit waiting state) - self->SetState (self->state - 1); - return 0; - } - } - } - return 0; -} - -// Lynched corpse (no heart) ------------------------------------------------ - -class AZCorpseLynchedNoHeart : public AActor -{ -DECLARE_CLASS (AZCorpseLynchedNoHeart, AActor) -public: - void PostBeginPlay (); -}; - -IMPLEMENT_CLASS(AZCorpseLynchedNoHeart, false, false) - -void AZCorpseLynchedNoHeart::PostBeginPlay () -{ - Super::PostBeginPlay (); - Spawn ("BloodPool", PosAtZ(floorz), ALLOW_REPLACE); -} - -//============================================================================ -// -// A_CorpseBloodDrip -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_CorpseBloodDrip) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (pr_drip() <= 128) - { - Spawn ("CorpseBloodDrip", self->PosPlusZ(self->Height / 2), ALLOW_REPLACE); - } - return 0; -} - -//============================================================================ -// -// A_CorpseExplode -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_CorpseExplode) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo; - int i; - - for (i = (pr_foo()&3)+3; i; i--) - { - mo = Spawn ("CorpseBit", self->Pos(), ALLOW_REPLACE); - if (mo) - { - mo->SetState (mo->SpawnState + (pr_foo()%3)); - mo->Vel.X = pr_foo.Random2() / 64.; - mo->Vel.Y = pr_foo.Random2() / 64.; - mo->Vel.Z = ((pr_foo() & 7) + 5) * 0.75; - } - } - // Spawn a skull - mo = Spawn ("CorpseBit", self->Pos(), ALLOW_REPLACE); - if (mo) - { - mo->SetState (mo->SpawnState + 3); - mo->Vel.X = pr_foo.Random2() / 64.; - mo->Vel.Y = pr_foo.Random2() / 64.; - mo->Vel.Z = ((pr_foo() & 7) + 5) * 0.75; - } - S_Sound (self, CHAN_BODY, self->DeathSound, 1, ATTN_IDLE); - self->Destroy (); - return 0; -} - -//============================================================================ -// -// A_LeafSpawn -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_LeafSpawn) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo; - int i; - - for (i = (pr_leaf()&3)+1; i; i--) - { - double xo = pr_leaf.Random2() / 4.; - double yo = pr_leaf.Random2() / 4.; - double zo = pr_leaf() / 4.; - mo = Spawn (pr_leaf()&1 ? PClass::FindActor ("Leaf1") : PClass::FindActor ("Leaf2"), - self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE); - - if (mo) - { - mo->Thrust(pr_leaf() / 128. + 3); - mo->target = self; - mo->special1 = 0; - } - } - return 0; -} - -//============================================================================ -// -// A_LeafThrust -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_LeafThrust) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (pr_leafthrust() <= 96) - { - self->Vel.Z += pr_leafthrust() / 128. + 1; - } - return 0; -} - -//============================================================================ -// -// A_LeafCheck -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_LeafCheck) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->special1++; - if (self->special1 >= 20) - { - self->SetState (NULL); - return 0; - } - DAngle ang = self->target ? self->target->Angles.Yaw : self->Angles.Yaw; - if (pr_leafcheck() > 64) - { - if (self->Vel.X == 0 && self->Vel.Y == 0) - { - self->Thrust(ang, pr_leafcheck() / 128. + 1); - } - return 0; - } - self->SetState (self->SpawnState + 7); - self->Vel.Z = pr_leafcheck() / 128. + 1; - self->Thrust(ang, pr_leafcheck() / 128. + 2); - self->flags |= MF_MISSILE; - return 0; -} - -//=========================================================================== -// -// A_SoAExplode - Suit of Armor Explode -// -//=========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_SoAExplode) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo; - int i; - - for (i = 0; i < 10; i++) - { - double xo = (pr_soaexplode() - 128) / 16.; - double yo = (pr_soaexplode() - 128) / 16.; - double zo = pr_soaexplode()*self->Height / 256.; - mo = Spawn ("ZArmorChunk", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE); - if (mo) - { - mo->SetState (mo->SpawnState + i); - mo->Vel.X = pr_soaexplode.Random2() / 64.; - mo->Vel.Y = pr_soaexplode.Random2() / 64.; - mo->Vel.Z = (pr_soaexplode() & 7) + 5; - } - } - // Spawn an item? - PClassActor *type = P_GetSpawnableType(self->args[0]); - if (type != NULL) - { - if (!((level.flags2 & LEVEL2_NOMONSTERS) || (dmflags & DF_NO_MONSTERS)) - || !(GetDefaultByType (type)->flags3 & MF3_ISMONSTER)) - { // Only spawn monsters if not -nomonsters - Spawn (type, self->Pos(), ALLOW_REPLACE); - } - } - S_Sound (self, CHAN_BODY, self->DeathSound, 1, ATTN_NORM); - self->Destroy (); - return 0; -} - -// Bell --------------------------------------------------------------------- - -class AZBell : public AActor -{ - DECLARE_CLASS (AZBell, AActor) -public: - void Activate (AActor *activator); -}; - -IMPLEMENT_CLASS(AZBell, false, false) - -void AZBell::Activate (AActor *activator) -{ - if (health > 0) - { - P_DamageMobj (this, activator, activator, 10, NAME_Melee, DMG_THRUSTLESS); // 'ring' the bell - } -} - -//=========================================================================== -// -// A_BellReset1 -// -//=========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_BellReset1) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->flags |= MF_NOGRAVITY; - self->Height *= 4; - if (self->special) - { // Initiate death action - P_ExecuteSpecial(self->special, NULL, NULL, false, self->args[0], - self->args[1], self->args[2], self->args[3], self->args[4]); - self->special = 0; - } - return 0; -} - -//=========================================================================== -// -// A_BellReset2 -// -//=========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_BellReset2) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->flags |= MF_SHOOTABLE; - self->flags &= ~MF_CORPSE; - self->flags6 &= ~MF6_KILLED; - self->health = 5; - return 0; -} - diff --git a/src/g_level.cpp b/src/g_level.cpp index 904b38b8a..ea34dc95c 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1889,6 +1889,7 @@ DEFINE_FIELD_BIT(FLevelLocals, flags2, missilesactivateimpact, LEVEL2_MISSILESAC DEFINE_FIELD_BIT(FLevelLocals, flags2, monsterfallingdamage, LEVEL2_MONSTERFALLINGDAMAGE) DEFINE_FIELD_BIT(FLevelLocals, flags2, checkswitchrange, LEVEL2_CHECKSWITCHRANGE) DEFINE_FIELD_BIT(FLevelLocals, flags2, polygrind, LEVEL2_POLYGRIND) +DEFINE_FIELD_BIT(FLevelLocals, flags2, nomonsters, LEVEL2_NOMONSTERS) //========================================================================== // diff --git a/src/p_things.cpp b/src/p_things.cpp index d94ba6a01..ea01d38ed 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -520,6 +520,13 @@ PClassActor *P_GetSpawnableType(int spawnnum) return NULL; } +DEFINE_ACTION_FUNCTION(AActor, GetSpawnableType) +{ + PARAM_PROLOGUE; + PARAM_INT(num); + ACTION_RETURN_OBJECT(P_GetSpawnableType(num)); +} + struct MapinfoSpawnItem { FName classname; // DECORATE is read after MAPINFO so we do not have the actual classes available here yet. diff --git a/src/sc_man_scanner.re b/src/sc_man_scanner.re index 59113e4a7..a57cc34ad 100644 --- a/src/sc_man_scanner.re +++ b/src/sc_man_scanner.re @@ -162,13 +162,11 @@ std2: 'private' { RET(TK_Private); } 'dot' { RET(TK_Dot); } 'cross' { RET(TK_Cross); } - 'ignores' { RET(TK_Ignores); } 'localized' { RET(TK_Localized); } 'latent' { RET(TK_Latent); } 'singular' { RET(TK_Singular); } 'config' { RET(TK_Config); } 'coerce' { RET(TK_Coerce); } - 'iterator' { RET(TK_Iterator); } 'optional' { RET(TK_Optional); } 'export' { RET(TK_Export); } 'virtual' { RET(TK_Virtual); } @@ -240,6 +238,7 @@ std2: "<>=" { RET(TK_LtGtEq); } "**" { RET(TK_MulMul); } "::" { RET(TK_ColonColon); } + "->" { RET(TK_Arrow); } ";" { StateOptions = false; RET(';'); } "{" { StateOptions = false; RET('{'); } "}" { RET('}'); } diff --git a/src/sc_man_tokens.h b/src/sc_man_tokens.h index dfa6c044c..c1ba10044 100644 --- a/src/sc_man_tokens.h +++ b/src/sc_man_tokens.h @@ -33,6 +33,7 @@ xx(TK_Neq, "'!='") xx(TK_ApproxEq, "'~=='") xx(TK_LtGtEq, "'<>='") xx(TK_MulMul, "'**'") +xx(TK_Arrow, "'->'") xx(TK_Action, "'action'") xx(TK_Break, "'break'") xx(TK_Case, "'case'") diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 7b2b99570..17dfea393 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -270,6 +270,7 @@ class Actor : Thinker native native static double GetDefaultSpeed(class type); + native static class GetSpawnableType(int spawnnum); native void RemoveFromHash(); native string GetTag(string defstr = ""); native double GetBobOffset(double frac = 0); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 397ba4c32..c0894eda8 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -92,6 +92,7 @@ struct LevelLocals native native bool monsterfallingdamage; native bool checkswitchrange; native bool polygrind; + native bool nomonsters; // level_info_t *info cannot be done yet. } diff --git a/wadsrc/static/zscript/hexen/hexenspecialdecs.txt b/wadsrc/static/zscript/hexen/hexenspecialdecs.txt index 558ef8395..feebf515f 100644 --- a/wadsrc/static/zscript/hexen/hexenspecialdecs.txt +++ b/wadsrc/static/zscript/hexen/hexenspecialdecs.txt @@ -95,7 +95,6 @@ class Pottery1 : Actor +NOICEDEATH } - native void A_PotteryExplode(); States { @@ -106,6 +105,40 @@ class Pottery1 : Actor POT1 A 0 A_PotteryExplode; Stop; } + + //============================================================================ + // + // A_PotteryExplode + // + //============================================================================ + + void A_PotteryExplode() + { + Actor mo = null; + int i; + + for(i = (random[Pottery]()&3)+3; i; i--) + { + mo = Spawn ("PotteryBit", Pos, ALLOW_REPLACE); + if (mo) + { + mo.SetState (mo.SpawnState + (random[Pottery]()%5)); + mo.Vel.X = random2[Pottery]() / 64.; + mo.Vel.Y = random2[Pottery]() / 64.; + mo.Vel.Z = ((random[Pottery]() & 7) + 5) * 0.75; + } + } + mo.A_PlaySound ("PotteryExplode", CHAN_BODY); + // Spawn an item? + Class type = GetSpawnableType(args[0]); + if (type != null) + { + if (!(level.nomonsters || sv_nomonsters) || !(GetDefaultByType (type).bIsMonster)) + { // Only spawn monsters if not -nomonsters + Spawn (type, Pos, ALLOW_REPLACE); + } + } + } } // Pottery2 ----------------------------------------------------------------- @@ -144,6 +177,8 @@ class Pottery3 : Pottery1 class PotteryBit : Actor { + State LoopState; + Default { Radius 5; @@ -153,9 +188,6 @@ class PotteryBit : Actor +NOICEDEATH } - native void A_PotteryChooseBit(); - native void A_PotteryCheck(); - States { Spawn: @@ -185,6 +217,42 @@ class PotteryBit : Actor PBIT J 1 A_PotteryCheck; Stop; } + + //============================================================================ + // + // A_PotteryChooseBit + // + //============================================================================ + + void A_PotteryChooseBit() + { + static const statelabel bits[] = { "Pottery1", "Pottery2", "Pottery3", "Pottery4", "Pottery5" }; + LoopState = FindState(bits[random[PotteryBit]() % 5]); // Save the state for jumping back to. + SetState (LoopState); + tics = 256 + (random[PotteryBit]() << 1); + } + + //============================================================================ + // + // A_PotteryCheck + // + //============================================================================ + + void A_PotteryCheck() + { + for(int i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i]) + { + Actor pmo = players[i].mo; + if (CheckSight (pmo) && (absangle(pmo.AngleTo(self), pmo.Angle) <= 45)) + { // jump back to previpusly set state. + SetState (LoopState); + return; + } + } + } + } } @@ -203,7 +271,7 @@ class BloodPool : Actor // Lynched corpse (no heart) ------------------------------------------------ -class ZCorpseLynchedNoHeart : Actor native +class ZCorpseLynchedNoHeart : Actor { Default { @@ -212,14 +280,32 @@ class ZCorpseLynchedNoHeart : Actor native +SOLID +SPAWNCEILING +NOGRAVITY } - native void A_CorpseBloodDrip(); - States { Spawn: CPS5 A 140 A_CorpseBloodDrip; Loop; } + + override void PostBeginPlay () + { + Super.PostBeginPlay (); + Spawn ("BloodPool", (pos.xy, floorz), ALLOW_REPLACE); + } + + //============================================================================ + // + // A_CorpseBloodDrip + // + //============================================================================ + + void A_CorpseBloodDrip() + { + if (random[CorpseDrip]() <= 128) + { + Spawn ("CorpseBloodDrip", pos + (0, 0, Height / 2), ALLOW_REPLACE); + } + } } @@ -289,8 +375,6 @@ class ZCorpseSitting : Actor DeathSound "FireDemonDeath"; } - native void A_CorpseExplode(); - States { Spawn: @@ -300,6 +384,40 @@ class ZCorpseSitting : Actor CPS6 A 1 A_CorpseExplode; Stop; } + + //============================================================================ + // + // A_CorpseExplode + // + //============================================================================ + + void A_CorpseExplode() + { + Actor mo; + + for (int i = (random[CorpseExplode]() & 3) + 3; i; i--) + { + mo = Spawn ("CorpseBit", Pos, ALLOW_REPLACE); + if (mo) + { + mo.SetState (mo.SpawnState + (random[CorpseExplode]() % 3)); + mo.Vel.X = random2[CorpseExplode]() / 64.; + mo.Vel.Y = random2[CorpseExplode]() / 64.; + mo.Vel.Z = ((random[CorpseExplode]() & 7) + 5) * 0.75; + } + } + // Spawn a skull + mo = Spawn ("CorpseBit", Pos, ALLOW_REPLACE); + if (mo) + { + mo.SetState (mo.SpawnState + 3); + mo.Vel.X = random2[CorpseExplode]() / 64.; + mo.Vel.Y = random2[CorpseExplode]() / 64.; + mo.Vel.Z = ((random[CorpseExplode]() & 7) + 5) * 0.75; + } + A_PlaySound (DeathSound, CHAN_BODY); + Destroy (); + } } @@ -313,7 +431,6 @@ class LeafSpawner : Actor +INVISIBLE } - native void A_LeafSpawn(); States { @@ -321,6 +438,32 @@ class LeafSpawner : Actor TNT1 A 20 A_LeafSpawn; Loop; } + + //============================================================================ + // + // A_LeafSpawn + // + //============================================================================ + + void A_LeafSpawn() + { + static const class leaves[] = { "Leaf1", "Leaf2" }; + + for (int i = (random[LeafSpawn]() & 3) + 1; i; i--) + { + double xo = random2[LeafSpawn]() / 4.; + double yo = random2[LeafSpawn]() / 4.; + double zo = random[LeafSpawn]() / 4.; + Actor mo = Spawn (leaves[random[LeafSpawn]()&1], Vec3Offset(xo, yo, zo), ALLOW_REPLACE); + + if (mo) + { + mo.Thrust(random[LeafSpawn]() / 128. + 3); + mo.target = self; + mo.special1 = 0; + } + } + } } @@ -338,15 +481,13 @@ class Leaf1 : Actor +NOICEDEATH } - native void A_LeafThrust(); - native void A_LeafCheck(); - States { Spawn: LEF1 ABC 4; LEF1 D 4 A_LeafThrust; LEF1 EFG 4; + Looping: LEF1 H 4 A_LeafThrust; LEF1 I 4; LEF1 AB 4; @@ -359,6 +500,49 @@ class Leaf1 : Actor LEF3 D 10 A_LeafCheck; Wait; } + + //============================================================================ + // + // A_LeafThrust + // + //============================================================================ + + void A_LeafThrust() + { + if (random[LeafThrust]() <= 96) + { + Vel.Z += random[LeafThrust]() / 128. + 1; + } + } + + //============================================================================ + // + // A_LeafCheck + // + //============================================================================ + + void A_LeafCheck() + { + special1++; + if (special1 >= 20) + { + Destroy(); + return; + } + double ang = target ? target.angle : angle; + if (random[LeafCheck]() > 64) + { + if (Vel.X == 0 && Vel.Y == 0) + { + Thrust(random[LeafCheck]() / 128. + 1, ang); + } + return; + } + SetStateLabel ("Looping"); + Vel.Z = random[LeafCheck]() / 128. + 1; + Thrust(random[LeafCheck]() / 128. + 2, ang); + bMissile = true; + } } @@ -556,8 +740,6 @@ class ZSuitOfArmor : Actor DeathSound "SuitofArmorBreak"; } - native void A_SoAExplode(); - States { Spawn: @@ -567,6 +749,41 @@ class ZSuitOfArmor : Actor ZSUI A 1 A_SoAExplode; Stop; } + + //=========================================================================== + // + // A_SoAExplode - Suit of Armor Explode + // + //=========================================================================== + + void A_SoAExplode() + { + for (int i = 0; i < 10; i++) + { + double xo = (random[SoAExplode]() - 128) / 16.; + double yo = (random[SoAExplode]() - 128) / 16.; + double zo = random[SoAExplode]() * Height / 256.; + Actor mo = Spawn ("ZArmorChunk", Vec3Offset(xo, yo, zo), ALLOW_REPLACE); + if (mo) + { + mo.SetState (mo.SpawnState + i); + mo.Vel.X = random2[SoAExplode]() / 64.; + mo.Vel.Y = random2[SoAExplode]() / 64.; + mo.Vel.Z = (random[SoAExplode]() & 7) + 5; + } + } + // Spawn an item? + Class type = GetSpawnableType(args[0]); + if (type != null) + { + if (!(level.nomonsters || sv_nomonsters) || !(GetDefaultByType (type).bIsMonster)) + { // Only spawn monsters if not -nomonsters + Spawn (type, Pos, ALLOW_REPLACE); + } + } + A_PlaySound (DeathSound, CHAN_BODY); + Destroy (); + } } @@ -608,7 +825,7 @@ class ZArmorChunk : Actor // Bell --------------------------------------------------------------------- -class ZBell : Actor native +class ZBell : Actor { Default { @@ -621,9 +838,6 @@ class ZBell : Actor native DeathSound "BellRing"; } - native void A_BellReset1(); - native void A_BellReset2(); - States { Spawn: @@ -665,6 +879,45 @@ class ZBell : Actor native BBLL A 1 A_BellReset2; Goto Spawn; } + + override void Activate (Actor activator) + { + if (health > 0) A_Die(); + { + DamageMobj (activator, activator, 10, 'Melee', DMG_THRUSTLESS); // 'ring' the bell + } + } + + //=========================================================================== + // + // A_BellReset1 + // + //=========================================================================== + + void A_BellReset1() + { + bNoGravity = true; + Height = Default.Height; + if (special) + { // Initiate death action + A_CallSpecial(special, args[0], args[1], args[2], args[3], args[4]); + special = 0; + } + } + + //=========================================================================== + // + // A_BellReset2 + // + //=========================================================================== + + void A_BellReset2() + { + bShootable = true; + bCorpse = false; + bKilled = false; + health = 5; + } } From 7b5a5896355e1bd32304623ebb47872d7e51a7be Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 27 Nov 2016 21:41:04 +0100 Subject: [PATCH 142/185] - scriptified Hexen's Frost shards. - scriptified all SpecialMissileHit methods. --- src/actor.h | 2 +- src/g_hexen/a_hexenmisc.cpp | 1 - src/g_hexen/a_magecone.cpp | 185 ------------------ src/g_hexen/a_magelightning.cpp | 93 --------- src/g_hexen/a_magestaff.cpp | 13 -- src/p_mobj.cpp | 15 +- wadsrc/static/zscript/actor.txt | 6 + wadsrc/static/zscript/hexen/magecone.txt | 144 +++++++++++++- wadsrc/static/zscript/hexen/magelightning.txt | 73 ++++++- wadsrc/static/zscript/hexen/magestaff.txt | 12 ++ 10 files changed, 242 insertions(+), 302 deletions(-) delete mode 100644 src/g_hexen/a_magecone.cpp diff --git a/src/actor.h b/src/actor.h index 4c0f33dde..578b094ed 100644 --- a/src/actor.h +++ b/src/actor.h @@ -667,7 +667,7 @@ public: // Called by PIT_CheckThing() and needed for some Hexen things. // Returns -1 for normal behavior, 0 to return false, and 1 to return true. // I'm not sure I like it this way, but it will do for now. - virtual int SpecialMissileHit (AActor *victim); + int SpecialMissileHit (AActor *victim); // Returns true if it's okay to switch target to "other" after being attacked by it. virtual bool OkayToSwitchTarget (AActor *other); diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp index 503ac6fbc..e6f27c434 100644 --- a/src/g_hexen/a_hexenmisc.cpp +++ b/src/g_hexen/a_hexenmisc.cpp @@ -25,7 +25,6 @@ // Include all the Hexen stuff here to reduce compile time #include "a_heresiarch.cpp" -#include "a_magecone.cpp" #include "a_magelightning.cpp" #include "a_magestaff.cpp" #include "a_serpent.cpp" diff --git a/src/g_hexen/a_magecone.cpp b/src/g_hexen/a_magecone.cpp deleted file mode 100644 index 102f68155..000000000 --- a/src/g_hexen/a_magecone.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/* -#include "actor.h" -#include "gi.h" -#include "m_random.h" -#include "s_sound.h" -#include "d_player.h" -#include "a_action.h" -#include "p_local.h" -#include "a_action.h" -#include "p_pspr.h" -#include "gstrings.h" -#include "a_hexenglobal.h" -#include "vm.h" -*/ - -const int SHARDSPAWN_LEFT = 1; -const int SHARDSPAWN_RIGHT = 2; -const int SHARDSPAWN_UP = 4; -const int SHARDSPAWN_DOWN = 8; - -static FRandom pr_cone ("FireConePL1"); - -void A_FireConePL1 (AActor *actor); -void A_ShedShard (AActor *); - -// Frost Missile ------------------------------------------------------------ - -class AFrostMissile : public AActor -{ - DECLARE_CLASS (AFrostMissile, AActor) -public: - int DoSpecialDamage (AActor *victim, int damage, FName damagetype); -}; - -IMPLEMENT_CLASS(AFrostMissile, false, false) - -int AFrostMissile::DoSpecialDamage (AActor *victim, int damage, FName damagetype) -{ - if (special2 > 0) - { - damage <<= special2; - } - return damage; -} - -//============================================================================ -// -// A_FireConePL1 -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FireConePL1) -{ - PARAM_ACTION_PROLOGUE(AActor); - - DAngle angle; - int damage; - DAngle slope; - int i; - AActor *mo; - bool conedone=false; - player_t *player; - FTranslatedLineTarget t; - - if (NULL == (player = self->player)) - { - return 0; - } - - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - S_Sound (self, CHAN_WEAPON, "MageShardsFire", 1, ATTN_NORM); - - damage = 90+(pr_cone()&15); - for (i = 0; i < 16; i++) - { - angle = self->Angles.Yaw + i*(45./16); - slope = P_AimLineAttack (self, angle, MELEERANGE, &t, 0., ALF_CHECK3D); - if (t.linetarget) - { - P_DamageMobj (t.linetarget, self, self, damage, NAME_Ice, DMG_USEANGLE, t.angleFromSource.Degrees); - conedone = true; - break; - } - } - - // didn't find any creatures, so fire projectiles - if (!conedone) - { - mo = P_SpawnPlayerMissile (self, RUNTIME_CLASS(AFrostMissile)); - if (mo) - { - mo->special1 = SHARDSPAWN_LEFT|SHARDSPAWN_DOWN|SHARDSPAWN_UP - |SHARDSPAWN_RIGHT; - mo->special2 = 3; // Set sperm count (levels of reproductivity) - mo->target = self; - mo->args[0] = 3; // Mark Initial shard as super damage - } - } - return 0; -} - -//============================================================================ -// -// A_ShedShard -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_ShedShard) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo; - int spawndir = self->special1; - int spermcount = self->special2; - - if (spermcount <= 0) - { - return 0; // No sperm left - } - self->special2 = 0; - spermcount--; - - // every so many calls, spawn a new missile in its set directions - if (spawndir & SHARDSPAWN_LEFT) - { - mo = P_SpawnMissileAngleZSpeed(self, self->Z(), RUNTIME_CLASS(AFrostMissile), - self->Angles.Yaw + 5, 0, (20. + 2 * spermcount), self->target); - if (mo) - { - mo->special1 = SHARDSPAWN_LEFT; - mo->special2 = spermcount; - mo->Vel.Z = self->Vel.Z; - mo->args[0] = (spermcount==3)?2:0; - } - } - if (spawndir & SHARDSPAWN_RIGHT) - { - mo = P_SpawnMissileAngleZSpeed(self, self->Z(), RUNTIME_CLASS(AFrostMissile), - self->Angles.Yaw - 5, 0, (20. + 2 * spermcount), self->target); - if (mo) - { - mo->special1 = SHARDSPAWN_RIGHT; - mo->special2 = spermcount; - mo->Vel.Z = self->Vel.Z; - mo->args[0] = (spermcount==3)?2:0; - } - } - if (spawndir & SHARDSPAWN_UP) - { - mo = P_SpawnMissileAngleZSpeed(self, self->Z() + 8., RUNTIME_CLASS(AFrostMissile), - self->Angles.Yaw, 0, (15. + 2 * spermcount), self->target); - if (mo) - { - mo->Vel.Z = self->Vel.Z; - if (spermcount & 1) // Every other reproduction - mo->special1 = SHARDSPAWN_UP | SHARDSPAWN_LEFT | SHARDSPAWN_RIGHT; - else - mo->special1 = SHARDSPAWN_UP; - mo->special2 = spermcount; - mo->args[0] = (spermcount==3)?2:0; - } - } - if (spawndir & SHARDSPAWN_DOWN) - { - mo = P_SpawnMissileAngleZSpeed(self, self->Z() - 4., RUNTIME_CLASS(AFrostMissile), - self->Angles.Yaw, 0, (15. + 2 * spermcount), self->target); - if (mo) - { - mo->Vel.Z = self->Vel.Z; - if (spermcount & 1) // Every other reproduction - mo->special1 = SHARDSPAWN_DOWN | SHARDSPAWN_LEFT | SHARDSPAWN_RIGHT; - else - mo->special1 = SHARDSPAWN_DOWN; - mo->special2 = spermcount; - mo->target = self->target; - 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 d5fcef880..794e6660b 100644 --- a/src/g_hexen/a_magelightning.cpp +++ b/src/g_hexen/a_magelightning.cpp @@ -25,99 +25,6 @@ static FRandom pr_hit ("LightningHit"); DECLARE_ACTION(A_LightningClip) DECLARE_ACTION(A_LightningZap) -// Lightning ---------------------------------------------------------------- - -class ALightning : public AActor -{ - DECLARE_CLASS (ALightning, AActor) -public: - int SpecialMissileHit (AActor *victim); -}; - -IMPLEMENT_CLASS(ALightning, false, false) - -int ALightning::SpecialMissileHit (AActor *thing) -{ - if (thing->flags&MF_SHOOTABLE && thing != target) - { - if (thing->Mass != INT_MAX) - { - thing->Vel.X += Vel.X / 16; - thing->Vel.Y += Vel.Y / 16; - } - if ((!thing->player && !(thing->flags2&MF2_BOSS)) - || !(level.time&1)) - { - P_DamageMobj(thing, this, target, 3, NAME_Electric); - if (!(S_IsActorPlayingSomething (this, CHAN_WEAPON, -1))) - { - S_Sound (this, CHAN_WEAPON, this->AttackSound, 1, ATTN_NORM); - } - if (thing->flags3&MF3_ISMONSTER && pr_hit() < 64) - { - thing->Howl (); - } - } - health--; - if (health <= 0 || thing->health <= 0) - { - return 0; - } - if (flags3 & MF3_FLOORHUGGER) - { - if (lastenemy && ! lastenemy->tracer) - { - lastenemy->tracer = thing; - } - } - else if (!tracer) - { - tracer = thing; - } - } - return 1; // lightning zaps through all sprites -} - -// Lightning Zap ------------------------------------------------------------ - -class ALightningZap : public AActor -{ - DECLARE_CLASS (ALightningZap, AActor) -public: - int SpecialMissileHit (AActor *thing); -}; - -IMPLEMENT_CLASS(ALightningZap, false, false) - -int ALightningZap::SpecialMissileHit (AActor *thing) -{ - AActor *lmo; - - if (thing->flags&MF_SHOOTABLE && thing != target) - { - lmo = lastenemy; - if (lmo) - { - if (lmo->flags3 & MF3_FLOORHUGGER) - { - if (lmo->lastenemy && !lmo->lastenemy->tracer) - { - lmo->lastenemy->tracer = thing; - } - } - else if (!lmo->tracer) - { - lmo->tracer = thing; - } - if (!(level.time&3)) - { - lmo->health--; - } - } - } - return -1; -} - //============================================================================ // // A_LightningReady diff --git a/src/g_hexen/a_magestaff.cpp b/src/g_hexen/a_magestaff.cpp index 27e9f5732..035744aba 100644 --- a/src/g_hexen/a_magestaff.cpp +++ b/src/g_hexen/a_magestaff.cpp @@ -72,24 +72,11 @@ class AMageStaffFX2 : public AActor { DECLARE_CLASS(AMageStaffFX2, AActor) public: - int SpecialMissileHit (AActor *victim); bool SpecialBlastHandling (AActor *source, double strength); }; IMPLEMENT_CLASS(AMageStaffFX2, false, false) -int AMageStaffFX2::SpecialMissileHit (AActor *victim) -{ - if (victim != target && - !victim->player && - !(victim->flags2 & MF2_BOSS)) - { - P_DamageMobj (victim, this, target, 10, NAME_Fire); - return 1; // Keep going - } - return -1; -} - bool AMageStaffFX2::SpecialBlastHandling (AActor *source, double strength) { // Reflect to originator diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 358e46e8c..250927a5a 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3357,6 +3357,7 @@ bool AActor::SpecialBlastHandling (AActor *source, double strength) } // This only gets called from the script side so we do not need a native wrapper like for the other virtual methods. +// This will be removed, once all actors overriding this method are exported. DEFINE_ACTION_FUNCTION(AActor, SpecialBlastHandling) { PARAM_SELF_PROLOGUE(AActor); @@ -3365,10 +3366,20 @@ DEFINE_ACTION_FUNCTION(AActor, SpecialBlastHandling) ACTION_RETURN_BOOL(self->SpecialBlastHandling(source, strength)); } - +// This virtual method only exists on the script side. int AActor::SpecialMissileHit (AActor *victim) { - return -1; + IFVIRTUAL(AActor, SpecialMissileHit) + { + VMValue params[2] = { (DObject*)this, victim }; + VMReturn ret; + int retval; + VMFrameStack stack; + ret.IntAt(&retval); + stack.Call(func, params, 2, &ret, 1, nullptr); + return retval; + } + else return -1; } bool AActor::AdjustReflectionAngle (AActor *thing, DAngle &angle) diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 17dfea393..189f70090 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -6,6 +6,7 @@ class Actor : Thinker native const FLOATRANDZ = ONCEILINGZ-1; const TELEFRAG_DAMAGE = 1000000; const MinVel = 1./65536; + const LARGE_MASS = 10000000; // not INT_MAX on purpose // flags are not defined here, the native fields for those get synthesized from the internal tables. @@ -268,6 +269,11 @@ class Actor : Thinker native virtual native bool UseInventory(Inventory item); virtual native bool SpecialBlastHandling (Actor source, double strength); + virtual int SpecialMissileHit (Actor victim) // for this no native version exists + { + return -1; + } + native static double GetDefaultSpeed(class type); native static class GetSpawnableType(int spawnnum); diff --git a/wadsrc/static/zscript/hexen/magecone.txt b/wadsrc/static/zscript/hexen/magecone.txt index a9f2d29dc..2bbd58f3d 100644 --- a/wadsrc/static/zscript/hexen/magecone.txt +++ b/wadsrc/static/zscript/hexen/magecone.txt @@ -17,8 +17,6 @@ class MWeapFrost : MageWeapon Tag "$TAG_MWEAPFROST"; } - action native void A_FireConePL1(); - States { Spawn: @@ -45,12 +43,68 @@ class MWeapFrost : MageWeapon CONE A 10 A_ReFire; Goto Ready; } + + //============================================================================ + // + // A_FireConePL1 + // + //============================================================================ + + action void A_FireConePL1() + { + bool conedone=false; + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + A_PlaySound ("MageShardsFire", CHAN_WEAPON); + + int damage = 90+(random[MageCone]() & 15); + for (int i = 0; i < 16; i++) + { + double ang = angle + i*(45./16); + double slope = AimLineAttack (ang, MELEERANGE, t, 0., ALF_CHECK3D); + if (t.linetarget) + { + t.linetarget.DamageMobj (self, self, damage, 'Ice', DMG_USEANGLE, t.angleFromSource); + conedone = true; + break; + } + } + + // didn't find any creatures, so fire projectiles + if (!conedone) + { + Actor mo = SpawnPlayerMissile ("FrostMissile"); + if (mo) + { + mo.special1 = FrostMissile.SHARDSPAWN_LEFT|FrostMissile.SHARDSPAWN_DOWN|FrostMissile.SHARDSPAWN_UP|FrostMissile.SHARDSPAWN_RIGHT; + mo.special2 = 3; // Set sperm count (levels of reproductivity) + mo.target = self; + mo.args[0] = 3; // Mark Initial shard as super damage + } + } + } } // Frost Missile ------------------------------------------------------------ -class FrostMissile : Actor native +class FrostMissile : Actor { + const SHARDSPAWN_LEFT = 1; + const SHARDSPAWN_RIGHT = 2; + const SHARDSPAWN_UP = 4; + const SHARDSPAWN_DOWN = 8; + Default { Speed 25; @@ -63,8 +117,6 @@ class FrostMissile : Actor native Obituary "$OB_MPMWEAPFROST"; } - native void A_ShedShard(); - States { Spawn: @@ -77,6 +129,88 @@ class FrostMissile : Actor native SHEX ABCDE 5 Bright; Stop; } + + override int DoSpecialDamage (Actor victim, int damage, Name damagetype) + { + if (special2 > 0) + { + damage <<= special2; + } + return damage; + } + + //============================================================================ + // + // A_ShedShard + // + //============================================================================ + + void A_ShedShard() + { + int spawndir = special1; + int spermcount = special2; + Actor mo; + + if (spermcount <= 0) + { + return; // No sperm left + } + special2 = 0; + spermcount--; + + // every so many calls, spawn a new missile in its set directions + if (spawndir & SHARDSPAWN_LEFT) + { + mo = SpawnMissileAngleZSpeed(pos.z, "FrostMissile", angle + 5, 0, (20. + 2 * spermcount), target); + if (mo) + { + mo.special1 = SHARDSPAWN_LEFT; + mo.special2 = spermcount; + mo.Vel.Z = Vel.Z; + mo.args[0] = (spermcount==3)?2:0; + } + } + if (spawndir & SHARDSPAWN_RIGHT) + { + mo = SpawnMissileAngleZSpeed(pos.z, "FrostMissile", angle - 5, 0, (20. + 2 * spermcount), target); + if (mo) + { + mo.special1 = SHARDSPAWN_RIGHT; + mo.special2 = spermcount; + mo.Vel.Z = Vel.Z; + mo.args[0] = (spermcount==3)?2:0; + } + } + if (spawndir & SHARDSPAWN_UP) + { + mo = SpawnMissileAngleZSpeed(pos.z + 8., "FrostMissile", angle, 0, (15. + 2 * spermcount), target); + if (mo) + { + mo.Vel.Z = Vel.Z; + if (spermcount & 1) // Every other reproduction + mo.special1 = SHARDSPAWN_UP | SHARDSPAWN_LEFT | SHARDSPAWN_RIGHT; + else + mo.special1 = SHARDSPAWN_UP; + mo.special2 = spermcount; + mo.args[0] = (spermcount==3)?2:0; + } + } + if (spawndir & SHARDSPAWN_DOWN) + { + mo = SpawnMissileAngleZSpeed(pos.z - 4., "FrostMissile", angle, 0, (15. + 2 * spermcount), target); + if (mo) + { + mo.Vel.Z = Vel.Z; + if (spermcount & 1) // Every other reproduction + mo.special1 = SHARDSPAWN_DOWN | SHARDSPAWN_LEFT | SHARDSPAWN_RIGHT; + else + mo.special1 = SHARDSPAWN_DOWN; + mo.special2 = spermcount; + mo.target = target; + mo.args[0] = (spermcount==3)?2:0; + } + } + } } // Ice Shard ---------------------------------------------------------------- diff --git a/wadsrc/static/zscript/hexen/magelightning.txt b/wadsrc/static/zscript/hexen/magelightning.txt index 154776d15..b778451ac 100644 --- a/wadsrc/static/zscript/hexen/magelightning.txt +++ b/wadsrc/static/zscript/hexen/magelightning.txt @@ -54,7 +54,7 @@ class MWeapLightning : MageWeapon // Ceiling Lightning -------------------------------------------------------- -class Lightning : Actor native +class Lightning : Actor { Default { @@ -63,6 +63,45 @@ class Lightning : Actor native ActiveSound "MageLightningContinuous"; Obituary "$OB_MPMWEAPLIGHTNING"; } + + override int SpecialMissileHit (Actor thing) + { + if (thing.bShootable && thing != target) + { + if (thing.Mass < LARGE_MASS) + { + thing.Vel.X += Vel.X / 16; + thing.Vel.Y += Vel.Y / 16; + } + if ((!thing.player && !thing.bBoss) || !(level.time&1)) + { + thing.DamageMobj(self, target, 3, 'Electric'); + A_PlaySound(self.AttackSound, CHAN_WEAPON, 1, true); + if (thing.bIsMonster && random[LightningHit]() < 64) + { + thing.Howl (); + } + } + health--; + if (health <= 0 || thing.health <= 0) + { + return 0; + } + if (bFloorHugger) + { + if (lastenemy && ! lastenemy.tracer) + { + lastenemy.tracer = thing; + } + } + else if (!tracer) + { + tracer = thing; + } + } + return 1; // lightning zaps through all sprites + } + } class LightningCeiling : Lightning @@ -141,7 +180,7 @@ class LightningFloor : LightningCeiling // Lightning Zap ------------------------------------------------------------ -class LightningZap : Actor native +class LightningZap : Actor { Default { @@ -166,4 +205,34 @@ class LightningZap : Actor native MLFX NOPQRSTU 2 Bright; Stop; } + + override int SpecialMissileHit (Actor thing) + { + Actor lmo; + + if (thing.bShootable && thing != target) + { + lmo = lastenemy; + if (lmo) + { + if (lmo.bFloorHugger) + { + if (lmo.lastenemy && !lmo.lastenemy.tracer) + { + lmo.lastenemy.tracer = thing; + } + } + else if (!lmo.tracer) + { + lmo.tracer = thing; + } + if (!(level.time&3)) + { + lmo.health--; + } + } + } + return -1; + } + } diff --git a/wadsrc/static/zscript/hexen/magestaff.txt b/wadsrc/static/zscript/hexen/magestaff.txt index c11542834..d485a72fa 100644 --- a/wadsrc/static/zscript/hexen/magestaff.txt +++ b/wadsrc/static/zscript/hexen/magestaff.txt @@ -157,4 +157,16 @@ class MageStaffFX2 : Actor native MSP2 I 4 Bright; Stop; } + + override int SpecialMissileHit (Actor victim) + { + if (victim != target && !victim.player && !victim.bBoss) + { + victim.DamageMobj (self, target, 10, 'Fire'); + return 1; // Keep going + } + return -1; + } + + } From f9a13880667bd3e486bada16f425ca33e3b9f1d0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 27 Nov 2016 22:14:18 +0100 Subject: [PATCH 143/185] - scriptified Hexen's lightning weapon. --- src/CMakeLists.txt | 2 - src/g_hexen/a_hexenmisc.cpp | 1 - src/g_hexen/a_magelightning.cpp | 274 ------------------ src/p_mobj.cpp | 9 + wadsrc/static/zscript/actor.txt | 1 + wadsrc/static/zscript/hexen/magelightning.txt | 230 ++++++++++++++- 6 files changed, 228 insertions(+), 289 deletions(-) delete mode 100644 src/g_hexen/a_magelightning.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6111d1714..1abd8e71b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -860,8 +860,6 @@ set( NOT_COMPILED_SOURCE_FILES sc_man_scanner.h sc_man_scanner.re g_hexen/a_heresiarch.cpp - g_hexen/a_magecone.cpp - g_hexen/a_magelightning.cpp g_hexen/a_magestaff.cpp g_hexen/a_serpent.cpp g_hexen/a_spike.cpp diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp index e6f27c434..45a407faa 100644 --- a/src/g_hexen/a_hexenmisc.cpp +++ b/src/g_hexen/a_hexenmisc.cpp @@ -25,7 +25,6 @@ // Include all the Hexen stuff here to reduce compile time #include "a_heresiarch.cpp" -#include "a_magelightning.cpp" #include "a_magestaff.cpp" #include "a_serpent.cpp" #include "a_spike.cpp" diff --git a/src/g_hexen/a_magelightning.cpp b/src/g_hexen/a_magelightning.cpp deleted file mode 100644 index 794e6660b..000000000 --- a/src/g_hexen/a_magelightning.cpp +++ /dev/null @@ -1,274 +0,0 @@ -/* -#include "actor.h" -#include "gi.h" -#include "m_random.h" -#include "s_sound.h" -#include "d_player.h" -#include "a_action.h" -#include "p_local.h" -#include "a_action.h" -#include "p_pspr.h" -#include "gstrings.h" -#include "a_hexenglobal.h" -#include "vm.h" -#include "g_level.h" -*/ - -#define ZAGSPEED 1. - -static FRandom pr_lightningready ("LightningReady"); -static FRandom pr_lightningclip ("LightningClip"); -static FRandom pr_zap ("LightningZap"); -static FRandom pr_zapf ("LightningZapF"); -static FRandom pr_hit ("LightningHit"); - -DECLARE_ACTION(A_LightningClip) -DECLARE_ACTION(A_LightningZap) - -//============================================================================ -// -// A_LightningReady -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_LightningReady) -{ - PARAM_ACTION_PROLOGUE(AActor); - - DoReadyWeapon(self); - if (pr_lightningready() < 160) - { - S_Sound (self, CHAN_WEAPON, "MageLightningReady", 1, ATTN_NORM); - } - return 0; -} - -//============================================================================ -// -// A_LightningClip -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_LightningClip) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *cMo; - AActor *target = NULL; - int zigZag; - - if (self->flags3 & MF3_FLOORHUGGER) - { - if (self->lastenemy == NULL) - { - return 0; - } - self->SetZ(self->floorz); - target = self->lastenemy->tracer; - } - else if (self->flags3 & MF3_CEILINGHUGGER) - { - self->SetZ(self->ceilingz - self->Height); - target = self->tracer; - } - if (self->flags3 & MF3_FLOORHUGGER) - { // floor lightning zig-zags, and forces the ceiling lightning to mimic - cMo = self->lastenemy; - zigZag = pr_lightningclip(); - if((zigZag > 128 && self->special1 < 2) || self->special1 < -2) - { - self->Thrust(self->Angles.Yaw + 90, ZAGSPEED); - if(cMo) - { - cMo->Thrust(self->Angles.Yaw + 90, ZAGSPEED); - } - self->special1++; - } - else - { - self->Thrust(self->Angles.Yaw - 90, ZAGSPEED); - if(cMo) - { - cMo->Thrust(self->Angles.Yaw - 90, ZAGSPEED); - } - self->special1--; - } - } - if(target) - { - if(target->health <= 0) - { - P_ExplodeMissile(self, NULL, NULL); - } - else - { - self->Angles.Yaw = self->AngleTo(target); - self->VelFromAngle(self->Speed / 2); - } - } - return 0; -} - - -//============================================================================ -// -// A_LightningZap -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_LightningZap) -{ - PARAM_SELF_PROLOGUE(AActor); - - PClassActor *lightning = PClass::FindActor(self->GetClass()->MissileName); - AActor *mo; - - 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 0; - } - double deltaX = (pr_zap() - 128) * self->radius / 256; - double deltaY = (pr_zap() - 128) * self->radius / 256; - double deltaZ = (self->flags3 & MF3_FLOORHUGGER) ? 10 : -10; - - mo = Spawn(lightning, self->Vec3Offset(deltaX, deltaY, deltaZ), ALLOW_REPLACE); - if (mo) - { - mo->lastenemy = self; - mo->Vel.X = self->Vel.X; - mo->Vel.Y = self->Vel.Y; - mo->Vel.Z = (self->flags3 & MF3_FLOORHUGGER) ? 20 : -20; - mo->target = self->target; - } - if ((self->flags3 & MF3_FLOORHUGGER) && pr_zapf() < 160) - { - S_Sound (self, CHAN_BODY, self->ActiveSound, 1, ATTN_NORM); - } - return 0; -} - -//============================================================================ -// -// A_MLightningAttack -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_MLightningAttack) -{ - PARAM_ACTION_PROLOGUE(AActor); - PARAM_CLASS_DEF(floor, AActor); - PARAM_CLASS_DEF(ceiling, AActor); - - AActor *fmo, *cmo; - - fmo = P_SpawnPlayerMissile (self, floor); - cmo = P_SpawnPlayerMissile (self, ceiling); - if (fmo) - { - fmo->special1 = 0; - fmo->lastenemy = cmo; - CALL_ACTION(A_LightningZap, fmo); - } - if (cmo) - { - cmo->tracer = NULL; - cmo->lastenemy = fmo; - CALL_ACTION(A_LightningZap, cmo); - } - S_Sound (self, CHAN_BODY, "MageLightningFire", 1, ATTN_NORM); - - if (self->player != NULL) - { - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL) - { - weapon->DepleteAmmo (weapon->bAltFire); - } - } - return 0; -} - -//============================================================================ -// -// A_ZapMimic -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_ZapMimic) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo; - - mo = self->lastenemy; - if (mo) - { - if (mo->state >= mo->FindState(NAME_Death)) - { - P_ExplodeMissile (self, NULL, NULL); - } - else - { - self->Vel.X = mo->Vel.X; - self->Vel.Y = mo->Vel.Y; - } - } - return 0; -} - -//============================================================================ -// -// A_LastZap -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_LastZap) -{ - PARAM_SELF_PROLOGUE(AActor); - 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->Vel.Z = 40; - mo->SetDamage(0); - } - return 0; -} - -//============================================================================ -// -// A_LightningRemove -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_LightningRemove) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo; - - mo = self->lastenemy; - if (mo) - { - mo->lastenemy = NULL; - P_ExplodeMissile (mo, NULL, NULL); - } - return 0; -} diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 250927a5a..22b52d18b 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1751,6 +1751,15 @@ void P_ExplodeMissile (AActor *mo, line_t *line, AActor *target) } } +DEFINE_ACTION_FUNCTION(AActor, ExplodeMissile) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_POINTER_DEF(line, line_t); + PARAM_OBJECT_DEF(target, AActor); + P_ExplodeMissile(self, line, target); + return 0; +} + void AActor::PlayBounceSound(bool onfloor) { diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 189f70090..94adbf227 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -289,6 +289,7 @@ class Actor : Thinker native native void NoiseAlert(Actor emitter, bool splash = false, double maxdist = 0); native void ClearBounce(); + native void ExplodeMissile(line lin = null, Actor target = null); native void RestoreDamage(); native int SpawnHealth(); native void SetDamage(int dmg); diff --git a/wadsrc/static/zscript/hexen/magelightning.txt b/wadsrc/static/zscript/hexen/magelightning.txt index b778451ac..343c96012 100644 --- a/wadsrc/static/zscript/hexen/magelightning.txt +++ b/wadsrc/static/zscript/hexen/magelightning.txt @@ -16,9 +16,6 @@ class MWeapLightning : MageWeapon Tag "$TAG_MWEAPLIGHTNING"; } - action native void A_LightningReady(); - action native void A_MLightningAttack(class floor = "LightningFloor", class ceiling = "LightningCeiling"); - States { Spawn: @@ -50,6 +47,57 @@ class MWeapLightning : MageWeapon MLNG B 2 Bright Offset (0, 40); Goto Ready; } + + //============================================================================ + // + // A_LightningReady + // + //============================================================================ + + action void A_LightningReady() + { + A_WeaponReady(); + if (random[LightningReady]() < 160) + { + A_PlaySound ("MageLightningReady", CHAN_WEAPON); + } + } + + //============================================================================ + // + // A_MLightningAttack + // + //============================================================================ + + action void A_MLightningAttack(class floor = "LightningFloor", class ceiling = "LightningCeiling") + { + LightningFloor fmo = LightningFloor(SpawnPlayerMissile (floor)); + LightningCeiling cmo = LightningCeiling(SpawnPlayerMissile (ceiling)); + if (fmo) + { + fmo.special1 = 0; + fmo.lastenemy = cmo; + fmo.A_LightningZap(); + } + if (cmo) + { + cmo.tracer = NULL; + cmo.lastenemy = fmo; + cmo.A_LightningZap(); + } + A_PlaySound ("MageLightningFire", CHAN_BODY); + + if (player != NULL) + { + Weapon weapon = player.ReadyWeapon; + if (weapon != NULL) + { + weapon.DepleteAmmo (weapon.bAltFire); + } + } + } + + } // Ceiling Lightning -------------------------------------------------------- @@ -76,7 +124,7 @@ class Lightning : Actor if ((!thing.player && !thing.bBoss) || !(level.time&1)) { thing.DamageMobj(self, target, 3, 'Electric'); - A_PlaySound(self.AttackSound, CHAN_WEAPON, 1, true); + A_PlaySound(AttackSound, CHAN_WEAPON, 1, true); if (thing.bIsMonster && random[LightningHit]() < 64) { thing.Howl (); @@ -106,6 +154,8 @@ class Lightning : Actor class LightningCeiling : Lightning { + const ZAGSPEED = 1; + Default { Health 144; @@ -118,10 +168,6 @@ class LightningCeiling : Lightning RenderStyle "Add"; } - native void A_LightningZap(); - native void A_LightningClip(); - native void A_LightningRemove(); - States { Spawn: @@ -143,6 +189,126 @@ class LightningCeiling : Lightning ACLO E 1050; Stop; } + + //============================================================================ + // + // A_LightningClip + // + //============================================================================ + + void A_LightningClip() + { + Actor cMo; + Actor target = NULL; + int zigZag; + + if (bFloorHugger) + { + if (lastenemy == NULL) + { + return; + } + SetZ(floorz); + target = lastenemy.tracer; + } + else if (bCeilingHugger) + { + SetZ(ceilingz - Height); + target = tracer; + } + if (bFloorHugger) + { // floor lightning zig-zags, and forces the ceiling lightning to mimic + cMo = lastenemy; + zigZag = random[LightningClip](); + if((zigZag > 128 && special1 < 2) || special1 < -2) + { + Thrust(ZAGSPEED, angle + 90); + if(cMo) + { + cMo.Thrust(ZAGSPEED, angle + 90); + } + special1++; + } + else + { + Thrust(ZAGSPEED,angle - 90); + if(cMo) + { + cMo.Thrust(ZAGSPEED, angle - 90); + } + special1--; + } + } + if(target) + { + if(target.health <= 0) + { + ExplodeMissile(); + } + else + { + angle = AngleTo(target); + VelFromAngle(Speed / 2); + } + } + } + + + //============================================================================ + // + // A_LightningZap + // + //============================================================================ + + void A_LightningZap() + { + Class lightning = MissileName; + if (lightning == NULL) lightning = "LightningZap"; + + A_LightningClip(); + + health -= 8; + if (health <= 0) + { + SetStateLabel ("Death"); + return; + } + double deltaX = (random[LightningZap]() - 128) * radius / 256; + double deltaY = (random[LightningZap]() - 128) * radius / 256; + double deltaZ = (bFloorHugger) ? 10 : -10; + + Actor mo = Spawn(lightning, Vec3Offset(deltaX, deltaY, deltaZ), ALLOW_REPLACE); + if (mo) + { + mo.lastenemy = self; + mo.Vel.X = Vel.X; + mo.Vel.Y = Vel.Y; + mo.Vel.Z = (bFloorHugger) ? 20 : -20; + mo.target = target; + } + if (bFloorHugger && random[LightningZap]() < 160) + { + A_PlaySound (ActiveSound, CHAN_BODY); + } + } + + //============================================================================ + // + // A_LightningRemove + // + //============================================================================ + + void A_LightningRemove() + { + Actor mo = lastenemy; + if (mo) + { + bNoTarget = true; // tell A_ZapMimic that we are dead. The original code did a state pointer compare which is not safe. + mo.lastenemy = NULL; + mo.ExplodeMissile (); + } + } + } // Floor Lightning ---------------------------------------------------------- @@ -156,8 +322,6 @@ class LightningFloor : LightningCeiling RenderStyle "Add"; } - native void A_LastZap(); - States { Spawn: @@ -176,6 +340,26 @@ class LightningFloor : LightningCeiling MLF2 P 1 Bright A_HideThing; Goto Super::Death + 19; } + + //============================================================================ + // + // A_LastZap + // + //============================================================================ + + void A_LastZap() + { + Class lightning = MissileName; + if (lightning == NULL) lightning = "LightningZap"; + + Actor mo = Spawn(lightning, self.Pos, ALLOW_REPLACE); + if (mo) + { + mo.SetStateLabel ("Death"); + mo.Vel.Z = 40; + mo.SetDamage(0); + } + } } // Lightning Zap ------------------------------------------------------------ @@ -194,8 +378,6 @@ class LightningZap : Actor Obituary "$OB_MPMWEAPLIGHTNING"; } - native void A_ZapMimic(); - States { Spawn: @@ -235,4 +417,28 @@ class LightningZap : Actor return -1; } + //============================================================================ + // + // A_ZapMimic + // + //============================================================================ + + void A_ZapMimic() + { + Actor mo = lastenemy; + if (mo) + { + if (mo.bNoTarget) + { + ExplodeMissile (); + } + else + { + Vel.X = mo.Vel.X; + Vel.Y = mo.Vel.Y; + } + } + } + + } From ebd2c27e0ab2cd54af4f7937f09d35c879f8cf79 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 28 Nov 2016 00:49:10 +0100 Subject: [PATCH 144/185] - scriptified Hexen's Bloodscourge and Serpent. - merged the FrontBlock searcher for the Bloodscourge into RoughMonsterSearch. This also fixes the bug that the searcher was not initialized properly for the MageBoss. --- src/CMakeLists.txt | 2 - src/g_hexen/a_hexenmisc.cpp | 2 - src/g_hexen/a_magestaff.cpp | 260 ---------------- src/g_hexen/a_serpent.cpp | 311 -------------------- src/p_enemy.cpp | 6 + src/p_local.h | 2 +- src/p_maputl.cpp | 54 +++- src/p_mobj.cpp | 7 + src/p_terrain.cpp | 15 + src/scripting/thingdef_data.cpp | 1 + src/scripting/vm/vm.h | 1 + wadsrc/static/zscript/actor.txt | 4 +- wadsrc/static/zscript/base.txt | 21 +- wadsrc/static/zscript/hexen/baseweapons.txt | 2 +- wadsrc/static/zscript/hexen/mageboss.txt | 37 ++- wadsrc/static/zscript/hexen/magestaff.txt | 132 ++++++++- wadsrc/static/zscript/hexen/serpent.txt | 270 ++++++++++++++++- 17 files changed, 507 insertions(+), 620 deletions(-) delete mode 100644 src/g_hexen/a_magestaff.cpp delete mode 100644 src/g_hexen/a_serpent.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1abd8e71b..40d227fa4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -860,8 +860,6 @@ set( NOT_COMPILED_SOURCE_FILES sc_man_scanner.h sc_man_scanner.re g_hexen/a_heresiarch.cpp - g_hexen/a_magestaff.cpp - g_hexen/a_serpent.cpp g_hexen/a_spike.cpp g_hexen/a_teleportother.cpp g_strife/a_acolyte.cpp diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp index 45a407faa..4cfd359f8 100644 --- a/src/g_hexen/a_hexenmisc.cpp +++ b/src/g_hexen/a_hexenmisc.cpp @@ -25,7 +25,5 @@ // Include all the Hexen stuff here to reduce compile time #include "a_heresiarch.cpp" -#include "a_magestaff.cpp" -#include "a_serpent.cpp" #include "a_spike.cpp" #include "a_teleportother.cpp" diff --git a/src/g_hexen/a_magestaff.cpp b/src/g_hexen/a_magestaff.cpp deleted file mode 100644 index 035744aba..000000000 --- a/src/g_hexen/a_magestaff.cpp +++ /dev/null @@ -1,260 +0,0 @@ -/* -#include "actor.h" -#include "info.h" -#include "p_local.h" -#include "m_random.h" -#include "s_sound.h" -#include "a_hexenglobal.h" -#include "gstrings.h" -#include "a_weaponpiece.h" -#include "vm.h" -#include "doomstat.h" -*/ - -class AMageWeapon : public AWeapon -{ - DECLARE_CLASS (AMageWeapon, AWeapon); -public: -}; - -IMPLEMENT_CLASS(AMageWeapon, false, false) - -static FRandom pr_mstafftrack ("MStaffTrack"); -static FRandom pr_bloodscourgedrop ("BloodScourgeDrop"); - -void A_MStaffTrack (AActor *); -void A_DropBloodscourgePieces (AActor *); -void A_MStaffAttack (AActor *actor); -void A_MStaffPalette (AActor *actor); - -static AActor *FrontBlockCheck (AActor *mo, int index, void *); -static divline_t BlockCheckLine; - -//========================================================================== -// The Mages's Staff (Bloodscourge) ----------------------------------------- - -class AMWeapBloodscourge : public AMageWeapon -{ - DECLARE_CLASS (AMWeapBloodscourge, AMageWeapon) -public: - - void Serialize(FSerializer &arc) - { - Super::Serialize (arc); - arc("mstaffcount", MStaffCount); - } - PalEntry GetBlend () - { - if (paletteflash & PF_HEXENWEAPONS) - { - if (MStaffCount == 3) - return PalEntry(128, 100, 73, 0); - else if (MStaffCount == 2) - return PalEntry(128, 125, 92, 0); - else if (MStaffCount == 1) - return PalEntry(128, 150, 110, 0); - else - return PalEntry(0, 0, 0, 0); - } - else - { - return PalEntry (MStaffCount * 128 / 3, 151, 110, 0); - } - } - BYTE MStaffCount; -}; - -IMPLEMENT_CLASS(AMWeapBloodscourge, false, false) - -// Mage Staff FX2 (Bloodscourge) -------------------------------------------- - -class AMageStaffFX2 : public AActor -{ - DECLARE_CLASS(AMageStaffFX2, AActor) -public: - bool SpecialBlastHandling (AActor *source, double strength); -}; - -IMPLEMENT_CLASS(AMageStaffFX2, false, false) - -bool AMageStaffFX2::SpecialBlastHandling (AActor *source, double strength) -{ - // Reflect to originator - tracer = target; - target = source; - return true; -} - -//============================================================================ - -//============================================================================ -// -// MStaffSpawn -// -//============================================================================ - -void MStaffSpawn (AActor *pmo, DAngle angle, AActor *alttarget) -{ - AActor *mo; - FTranslatedLineTarget t; - - mo = P_SpawnPlayerMissile (pmo, 0, 0, 8, RUNTIME_CLASS(AMageStaffFX2), angle, &t); - if (mo) - { - mo->target = pmo; - if (t.linetarget && !t.unlinked) - mo->tracer = t.linetarget; - else - mo->tracer = alttarget; - } -} - -//============================================================================ -// -// A_MStaffAttack -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_MStaffAttack) -{ - PARAM_ACTION_PROLOGUE(AActor); - - DAngle angle; - player_t *player; - FTranslatedLineTarget t; - - if (NULL == (player = self->player)) - { - return 0; - } - - AMWeapBloodscourge *weapon = static_cast (self->player->ReadyWeapon); - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - angle = self->Angles.Yaw; - - // [RH] Let's try and actually track what the player aimed at - P_AimLineAttack (self, angle, PLAYERMISSILERANGE, &t, 32.); - if (t.linetarget == NULL) - { - BlockCheckLine.x = self->X(); - BlockCheckLine.y = self->Y(); - BlockCheckLine.dx = -angle.Sin(); - BlockCheckLine.dy = -angle.Cos(); - t.linetarget = P_BlockmapSearch (self, 10, FrontBlockCheck); - } - MStaffSpawn (self, angle, t.linetarget); - MStaffSpawn (self, angle-5, t.linetarget); - MStaffSpawn (self, angle+5, t.linetarget); - S_Sound (self, CHAN_WEAPON, "MageStaffFire", 1, ATTN_NORM); - weapon->MStaffCount = 3; - return 0; -} - -//============================================================================ -// -// A_MStaffPalette -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_MStaffPalette) -{ - PARAM_ACTION_PROLOGUE(AActor); - - if (self->player != NULL) - { - AMWeapBloodscourge *weapon = static_cast (self->player->ReadyWeapon); - if (weapon != NULL && weapon->MStaffCount != 0) - { - weapon->MStaffCount--; - } - } - return 0; -} - -//============================================================================ -// -// A_MStaffTrack -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_MStaffTrack) -{ - PARAM_SELF_PROLOGUE(AActor); - - if ((self->tracer == 0) && (pr_mstafftrack()<50)) - { - self->tracer = P_RoughMonsterSearch (self, 10, true); - } - P_SeekerMissile(self, 2, 10); - return 0; -} - -//============================================================================ -// -// FrontBlockCheck -// -// [RH] Like RoughBlockCheck, but it won't return anything behind a line. -// -//============================================================================ - -static AActor *FrontBlockCheck (AActor *mo, int index, void *) -{ - FBlockNode *link; - - for (link = blocklinks[index]; link != NULL; link = link->NextActor) - { - if (link->Me != mo) - { - if (P_PointOnDivlineSide(link->Me->X(), link->Me->Y(), &BlockCheckLine) == 0 && - mo->IsOkayToAttack (link->Me)) - { - return link->Me; - } - } - } - return NULL; -} - -//============================================================================ -// -// MStaffSpawn2 - for use by mage class boss -// -//============================================================================ - -void MStaffSpawn2 (AActor *actor, DAngle angle) -{ - AActor *mo; - - mo = P_SpawnMissileAngleZ (actor, actor->Z()+40, RUNTIME_CLASS(AMageStaffFX2), angle, 0.); - if (mo) - { - mo->target = actor; - mo->tracer = P_BlockmapSearch (mo, 10, FrontBlockCheck); - } -} - -//============================================================================ -// -// A_MStaffAttack2 - for use by mage class boss -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_MageAttack) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (self->target == NULL) - { - return 0; - } - DAngle angle = self->Angles.Yaw; - MStaffSpawn2(self, angle); - MStaffSpawn2(self, angle - 5); - MStaffSpawn2(self, angle + 5); - S_Sound(self, CHAN_WEAPON, "MageStaffFire", 1, ATTN_NORM); - return 0; -} diff --git a/src/g_hexen/a_serpent.cpp b/src/g_hexen/a_serpent.cpp deleted file mode 100644 index 6f435747e..000000000 --- a/src/g_hexen/a_serpent.cpp +++ /dev/null @@ -1,311 +0,0 @@ -/* -#include "actor.h" -#include "info.h" -#include "p_local.h" -#include "s_sound.h" -#include "p_enemy.h" -#include "a_action.h" -#include "m_random.h" -#include "p_terrain.h" -#include "vm.h" -*/ - -static FRandom pr_serpentchase ("SerpentChase"); -static FRandom pr_serpenthump ("SerpentHump"); -static FRandom pr_serpentattack ("SerpentAttack"); -static FRandom pr_serpentmeattack ("SerpentMeAttack"); -static FRandom pr_serpentgibs ("SerpentGibs"); -static FRandom pr_delaygib ("DelayGib"); - -//============================================================================ -// -// A_SerpentUnHide -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SerpentUnHide) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->renderflags &= ~RF_INVISIBLE; - self->Floorclip = 24; - return 0; -} - -//============================================================================ -// -// A_SerpentHide -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SerpentHide) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->renderflags |= RF_INVISIBLE; - self->Floorclip = 0; - return 0; -} - -//============================================================================ -// -// A_SerpentRaiseHump -// -// Raises the hump above the surface by raising the floorclip level -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SerpentRaiseHump) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->Floorclip -= 4; - return 0; -} - -//============================================================================ -// -// A_SerpentLowerHump -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SerpentLowerHump) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->Floorclip += 4; - return 0; -} - -//============================================================================ -// -// A_SerpentHumpDecide -// -// Decided whether to hump up, or if the mobj is a serpent leader, -// to missile attack -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SerpentHumpDecide) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (self->MissileState != NULL) - { - if (pr_serpenthump() > 30) - { - return 0; - } - else if (pr_serpenthump() < 40) - { // Missile attack - self->SetState (self->MeleeState); - return 0; - } - } - else if (pr_serpenthump() > 3) - { - return 0; - } - if (!self->CheckMeleeRange ()) - { // The hump shouldn't occur when within melee range - if (self->MissileState != NULL && pr_serpenthump() < 128) - { - self->SetState (self->MeleeState); - } - else - { - self->SetState (self->FindState ("Hump")); - S_Sound (self, CHAN_BODY, "SerpentActive", 1, ATTN_NORM); - } - } - return 0; -} - -//============================================================================ -// -// A_SerpentCheckForAttack -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SerpentCheckForAttack) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (!self->target) - { - return 0; - } - if (self->MissileState != NULL) - { - if (!self->CheckMeleeRange ()) - { - self->SetState (self->FindState ("Attack")); - return 0; - } - } - if (P_CheckMeleeRange2 (self)) - { - self->SetState (self->FindState ("Walk")); - } - else if (self->CheckMeleeRange ()) - { - if (pr_serpentattack() < 32) - { - self->SetState (self->FindState ("Walk")); - } - else - { - self->SetState (self->FindState ("Attack")); - } - } - return 0; -} - -//============================================================================ -// -// A_SerpentChooseAttack -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SerpentChooseAttack) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (!self->target || self->CheckMeleeRange()) - { - return 0; - } - if (self->MissileState != NULL) - { - self->SetState (self->MissileState); - } - return 0; -} - -//============================================================================ -// -// A_SerpentMeleeAttack -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SerpentMeleeAttack) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (!self->target) - { - return 0; - } - if (self->CheckMeleeRange ()) - { - int damage = pr_serpentmeattack.HitDice (5); - 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, "SerpentMeleeHit", 1, ATTN_NORM); - } - if (pr_serpentmeattack() < 96) - { - CALL_ACTION(A_SerpentCheckForAttack, self); - } - return 0; -} - -//============================================================================ -// -// A_SerpentSpawnGibs -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SerpentSpawnGibs) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo; - static const char *GibTypes[] = - { - "SerpentGib3", - "SerpentGib2", - "SerpentGib1" - }; - - for (int i = countof(GibTypes)-1; i >= 0; --i) - { - double x = (pr_serpentgibs() - 128) / 16.; - double y = (pr_serpentgibs() - 128) / 16.; - - mo = Spawn (GibTypes[i], self->Vec2OffsetZ(x, y, self->floorz + 1), ALLOW_REPLACE); - if (mo) - { - mo->Vel.X = (pr_serpentgibs() - 128) / 1024.f; - mo->Vel.Y = (pr_serpentgibs() - 128) / 1024.f; - mo->Floorclip = 6; - } - } - return 0; -} - -//============================================================================ -// -// A_FloatGib -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FloatGib) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->Floorclip -= 1; - return 0; -} - -//============================================================================ -// -// A_SinkGib -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SinkGib) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->Floorclip += 1;; - return 0; -} - -//============================================================================ -// -// A_DelayGib -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_DelayGib) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->tics -= pr_delaygib()>>2; - return 0; -} - -//============================================================================ -// -// A_SerpentHeadCheck -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SerpentHeadCheck) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (self->Z() <= self->floorz) - { - if (Terrains[P_GetThingFloorType(self)].IsLiquid) - { - P_HitFloor (self); - self->SetState (NULL); - } - else - { - self->SetState (self->FindState(NAME_Death)); - } - } - return 0; -} - diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index a4be4dd1b..4f4920c6f 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -365,6 +365,12 @@ bool P_CheckMeleeRange2 (AActor *actor) return true; } +DEFINE_ACTION_FUNCTION(AActor, CheckMeleeRange2) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_INT(P_CheckMeleeRange2(self)); +} + //============================================================================= // diff --git a/src/p_local.h b/src/p_local.h index d759828dc..12b4a40a3 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -238,7 +238,7 @@ enum PCM AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, int, void *), void *params = NULL); -AActor *P_RoughMonsterSearch (AActor *mo, int distance, bool onlyseekable=false); +AActor *P_RoughMonsterSearch (AActor *mo, int distance, bool onlyseekable=false, bool frontonly = false); // // P_MAP diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 5bb3bea0f..2d2472cbd 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -45,7 +45,6 @@ #include "templates.h" #include "po_man.h" -static AActor *RoughBlockCheck (AActor *mo, int index, void *); sector_t *P_PointInSectorBuggy(double x, double y); int P_VanillaPointOnDivlineSide(double x, double y, const divline_t* line); @@ -1685,19 +1684,6 @@ FPathTraverse::~FPathTraverse() // distance is in MAPBLOCKUNITS //=========================================================================== -AActor *P_RoughMonsterSearch (AActor *mo, int distance, bool onlyseekable) -{ - return P_BlockmapSearch (mo, distance, RoughBlockCheck, (void *)onlyseekable); -} - -DEFINE_ACTION_FUNCTION(AActor, RoughMonsterSearch) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_INT(distance); - PARAM_BOOL_DEF(onlyseekable); - ACTION_RETURN_OBJECT(P_RoughMonsterSearch(self, distance, onlyseekable)); -} - AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, int, void *), void *params) { int blockX; @@ -1787,6 +1773,13 @@ AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, in return NULL; } +struct BlockCheckInfo +{ + bool onlyseekable; + bool frontonly; + divline_t frontline; +}; + //=========================================================================== // // RoughBlockCheck @@ -1795,14 +1788,19 @@ AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, in static AActor *RoughBlockCheck (AActor *mo, int index, void *param) { - bool onlyseekable = param != NULL; + BlockCheckInfo *info = (BlockCheckInfo *)param; + FBlockNode *link; for (link = blocklinks[index]; link != NULL; link = link->NextActor) { if (link->Me != mo) { - if (onlyseekable && !mo->CanSeek(link->Me)) + if (info->onlyseekable && !mo->CanSeek(link->Me)) + { + continue; + } + if (info->frontonly && P_PointOnDivlineSide(link->Me->X(), link->Me->Y(), &info->frontline) != 0) { continue; } @@ -1815,6 +1813,30 @@ static AActor *RoughBlockCheck (AActor *mo, int index, void *param) return NULL; } +AActor *P_RoughMonsterSearch(AActor *mo, int distance, bool onlyseekable, bool frontonly) +{ + BlockCheckInfo info; + info.onlyseekable = onlyseekable; + if ((info.frontonly = frontonly)) + { + info.frontline.x = mo->X(); + info.frontline.y = mo->Y(); + info.frontline.dx = -mo->Angles.Yaw.Sin(); + info.frontline.dy = -mo->Angles.Yaw.Cos(); + } + + return P_BlockmapSearch(mo, distance, RoughBlockCheck, (void *)&info); +} + +DEFINE_ACTION_FUNCTION(AActor, RoughMonsterSearch) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(distance); + PARAM_BOOL_DEF(onlyseekable); + PARAM_BOOL_DEF(frontonly); + ACTION_RETURN_OBJECT(P_RoughMonsterSearch(self, distance, onlyseekable, frontonly)); +} + //========================================================================== // // [RH] LinkToWorldForMapThing diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 22b52d18b..6268c9395 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -5908,6 +5908,13 @@ int P_GetThingFloorType (AActor *thing) } } +DEFINE_ACTION_FUNCTION(AActor, GetFloorTerrain) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_POINTER(&Terrains[P_GetThingFloorType(self)]); +} + + //--------------------------------------------------------------------------- // // FUNC P_HitWater diff --git a/src/p_terrain.cpp b/src/p_terrain.cpp index 2504bad94..3adc94876 100644 --- a/src/p_terrain.cpp +++ b/src/p_terrain.cpp @@ -724,3 +724,18 @@ FName P_GetTerrainName(int terrainnum) } } +DEFINE_FIELD_NAMED(FTerrainDef, Name, TerrainName) +DEFINE_FIELD(FTerrainDef, Splash) +DEFINE_FIELD(FTerrainDef, DamageAmount) +DEFINE_FIELD(FTerrainDef, DamageMOD) +DEFINE_FIELD(FTerrainDef, DamageTimeMask) +DEFINE_FIELD(FTerrainDef, FootClip) +DEFINE_FIELD(FTerrainDef, StepVolume) +DEFINE_FIELD(FTerrainDef, WalkStepTics) +DEFINE_FIELD(FTerrainDef, RunStepTics) +DEFINE_FIELD(FTerrainDef, LeftStepSound) +DEFINE_FIELD(FTerrainDef, RightStepSound) +DEFINE_FIELD(FTerrainDef, IsLiquid) +DEFINE_FIELD(FTerrainDef, AllowProtection) +DEFINE_FIELD(FTerrainDef, Friction) +DEFINE_FIELD(FTerrainDef, MoveFactor) diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 6f0cad099..d17e10420 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -45,6 +45,7 @@ #include "autosegs.h" #include "p_maputl.h" #include "gi.h" +#include "p_terrain.h" static TArray properties; static TArray AFTable; diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index c7082ff76..fdee430e1 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -1095,6 +1095,7 @@ void CallAction(VMFrameStack *stack, VMFunction *vmfunc, AActor *self); #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_POINTER(v) do { void *state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state, ATAG_GENERIC); 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_VEC2(v) do { DVector2 u = v; if (numret > 0) { assert(ret != nullptr); ret[0].SetVector2(u); return 1; } return 0; } while(0) diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 94adbf227..09b983843 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -288,6 +288,7 @@ class Actor : Thinker native native void SetFriendPlayer(PlayerInfo player); native void NoiseAlert(Actor emitter, bool splash = false, double maxdist = 0); native void ClearBounce(); + native TerrainDef GetFloorTerrain(); native void ExplodeMissile(line lin = null, Actor target = null); native void RestoreDamage(); @@ -310,7 +311,7 @@ class Actor : Thinker native native Actor SpawnMissileAngleZSpeed (double z, class type, double angle, double vz, double speed, Actor owner = null, bool checkspawn = true); native Actor, Actor SpawnPlayerMissile(class type, double angle = 0, double x = 0, double y = 0, double z = 0, out FTranslatedLineTarget pLineTarget = null, bool nofreeaim = false, bool noautoaim = false, int aimflags = 0); native void SpawnTeleportFog(Vector3 pos, bool beforeTele, bool setTarget); - native Actor RoughMonsterSearch(int distance, bool onlyseekable = false); + native Actor RoughMonsterSearch(int distance, bool onlyseekable = false, bool frontonly = false); native int ApplyDamageFactor(Name damagetype, int damage); native int GetModifiedDamage(Name damagetype, int damage, bool passive); @@ -329,6 +330,7 @@ class Actor : Thinker native native void SetIdle(bool nofunction = false); native bool CheckMeleeRange(); + native bool CheckMeleeRange2(); native int DamageMobj(Actor inflictor, Actor source, int damage, Name mod, int flags = 0, double angle = 0); native double AimLineAttack(double angle, double distance, out FTranslatedLineTarget pLineTarget = null, double vrange = 0., int flags = 0, Actor target = null, Actor friender = null); native Actor, int LineAttack(double angle, double distance, double pitch, int damage, Name damageType, class pufftype, int flags = 0, out FTranslatedLineTarget victim = null); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index c0894eda8..08d655caf 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -247,4 +247,23 @@ struct Wads } native static int CheckNumForName(string name, int ns, int wadnum = -1, bool exact = false); -} \ No newline at end of file +} + +struct TerrainDef native +{ + native Name TerrainName; + native int Splash; + native int DamageAmount; + native Name DamageMOD; + native int DamageTimeMask; + native double FootClip; + native float StepVolume; + native int WalkStepTics; + native int RunStepTics; + native Sound LeftStepSound; + native Sound RightStepSound; + native bool IsLiquid; + native bool AllowProtection; + native double Friction; + native double MoveFactor; +}; diff --git a/wadsrc/static/zscript/hexen/baseweapons.txt b/wadsrc/static/zscript/hexen/baseweapons.txt index b7e2bd398..a1e1af9bd 100644 --- a/wadsrc/static/zscript/hexen/baseweapons.txt +++ b/wadsrc/static/zscript/hexen/baseweapons.txt @@ -19,7 +19,7 @@ class ClericWeapon : Weapon } } -class MageWeapon : Weapon native +class MageWeapon : Weapon { Default { diff --git a/wadsrc/static/zscript/hexen/mageboss.txt b/wadsrc/static/zscript/hexen/mageboss.txt index f9637f8d1..0c081d786 100644 --- a/wadsrc/static/zscript/hexen/mageboss.txt +++ b/wadsrc/static/zscript/hexen/mageboss.txt @@ -18,8 +18,6 @@ class MageBoss : Actor Obituary "$OB_MBOSS"; } - native void A_MageAttack(); - States { Spawn: @@ -83,4 +81,39 @@ class MageBoss : Actor FDTH V 4 Bright; Stop; } + + //============================================================================ + // + // MStaffSpawn2 - for use by mage class boss + // + //============================================================================ + + void MStaffSpawn2 (double angle) + { + Actor mo = SpawnMissileAngleZ (pos.z + 40, "MageStaffFX2", angle, 0.); + if (mo) + { + mo.target = self; + mo.tracer = RoughMonsterSearch(10, true, true); + } + } + + //============================================================================ + // + // A_MStaffAttack2 - for use by mage class boss + // + //============================================================================ + + void A_MageAttack() + { + if (target == NULL) + { + return; + } + MStaffSpawn2(angle); + MStaffSpawn2(angle - 5); + MStaffSpawn2(angle + 5); + A_PlaySound("MageStaffFire", CHAN_WEAPON); + } + } diff --git a/wadsrc/static/zscript/hexen/magestaff.txt b/wadsrc/static/zscript/hexen/magestaff.txt index d485a72fa..e45095240 100644 --- a/wadsrc/static/zscript/hexen/magestaff.txt +++ b/wadsrc/static/zscript/hexen/magestaff.txt @@ -76,8 +76,10 @@ class BloodscourgeDrop : Actor // The Mages's Staff (Bloodscourge) ----------------------------------------- -class MWeapBloodscourge : MageWeapon native +class MWeapBloodscourge : MageWeapon { + int MStaffCount; + Default { Health 3; @@ -97,9 +99,6 @@ class MWeapBloodscourge : MageWeapon native Tag "$TAG_MWEAPBLOODSCOURGE"; } - action native void A_MStaffAttack(); - action native void A_MStaffPalette(); - States { Spawn: @@ -123,11 +122,104 @@ class MWeapBloodscourge : MageWeapon native MSTF J 5 Offset (0, 36); Goto Ready; } + + //============================================================================ + // + // + // + //============================================================================ + + override Color GetBlend () + { + if (paletteflash & PF_HEXENWEAPONS) + { + if (MStaffCount == 3) + return Color(128, 100, 73, 0); + else if (MStaffCount == 2) + return Color(128, 125, 92, 0); + else if (MStaffCount == 1) + return Color(128, 150, 110, 0); + else + return Color(0, 0, 0, 0); + } + else + { + return Color (MStaffCount * 128 / 3, 151, 110, 0); + } + } + + //============================================================================ + // + // MStaffSpawn + // + //============================================================================ + + private action void MStaffSpawn (double angle, Actor alttarget) + { + FTranslatedLineTarget t; + + Actor mo = SpawnPlayerMissile ("MageStaffFX2", angle, pLineTarget:t); + if (mo) + { + mo.target = self; + if (t.linetarget && !t.unlinked) + mo.tracer = t.linetarget; + else + mo.tracer = alttarget; + } + } + + //============================================================================ + // + // A_MStaffAttack + // + //============================================================================ + + action void A_MStaffAttack() + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != NULL) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + + // [RH] Let's try and actually track what the player aimed at + AimLineAttack (angle, PLAYERMISSILERANGE, t, 32.); + if (t.linetarget == NULL) + { + t.linetarget = RoughMonsterSearch(10, true, true); + } + MStaffSpawn (angle, t.linetarget); + MStaffSpawn (angle-5, t.linetarget); + MStaffSpawn (angle+5, t.linetarget); + A_PlaySound ("MageStaffFire", CHAN_WEAPON); + invoker.MStaffCount = 3; + } + + //============================================================================ + // + // A_MStaffPalette + // + //============================================================================ + + action void A_MStaffPalette() + { + if (invoker.MStaffCount > 0) invoker.MStaffCount--; + } } + // Mage Staff FX2 (Bloodscourge) -------------------------------------------- -class MageStaffFX2 : Actor native +class MageStaffFX2 : Actor { Default { @@ -143,7 +235,6 @@ class MageStaffFX2 : Actor native Obituary "$OB_MPMWEAPBLOODSCOURGE"; } - native void A_MStaffTrack(); States { @@ -158,6 +249,12 @@ class MageStaffFX2 : Actor native Stop; } + //============================================================================ + // + // + // + //============================================================================ + override int SpecialMissileHit (Actor victim) { if (victim != target && !victim.player && !victim.bBoss) @@ -168,5 +265,26 @@ class MageStaffFX2 : Actor native return -1; } - + override bool SpecialBlastHandling (Actor source, double strength) + { + // Reflect to originator + tracer = target; + target = source; + return true; + } + + //============================================================================ + // + // A_MStaffTrack + // + //============================================================================ + + void A_MStaffTrack() + { + if (tracer == null && random[MStaffTrack]() < 50) + { + tracer = RoughMonsterSearch (10, true); + } + A_SeekerMissile(2, 10); + } } diff --git a/wadsrc/static/zscript/hexen/serpent.txt b/wadsrc/static/zscript/hexen/serpent.txt index 70fb2195a..6eaafcfd1 100644 --- a/wadsrc/static/zscript/hexen/serpent.txt +++ b/wadsrc/static/zscript/hexen/serpent.txt @@ -24,16 +24,6 @@ class Serpent : Actor HitObituary "$OB_SERPENTHIT"; } - native void A_SerpentHumpDecide(); - native void A_SerpentHide(); - native void A_SerpentCheckForAttack(); - native void A_SerpentSpawnGibs(); - native void A_SerpentUnHide(); - native void A_SerpentRaiseHump(); - native void A_SerpentLowerHump(); - native void A_SerpentChooseAttack(); - native void A_SerpentMeleeAttack(); - States { Spawn: @@ -99,6 +89,203 @@ class Serpent : Actor SSPT N 5 A_SerpentMeleeAttack; Goto Dive; } + + //============================================================================ + // + // A_SerpentUnHide + // + //============================================================================ + + void A_SerpentUnHide() + { + bInvisible = false; + Floorclip = 24; + } + + //============================================================================ + // + // A_SerpentHide + // + //============================================================================ + + void A_SerpentHide() + { + bInvisible = true; + Floorclip = 0; + } + + //============================================================================ + // + // A_SerpentRaiseHump + // + // Raises the hump above the surface by raising the floorclip level + //============================================================================ + + void A_SerpentRaiseHump() + { + Floorclip -= 4; + } + + //============================================================================ + // + // A_SerpentLowerHump + // + //============================================================================ + + void A_SerpentLowerHump() + { + Floorclip += 4; + } + + //============================================================================ + // + // A_SerpentHumpDecide + // + // Decided whether to hump up, or if the mobj is a serpent leader, + // to missile attack + //============================================================================ + + void A_SerpentHumpDecide() + { + if (MissileState != NULL) + { + if (random[SerpentHump]() > 30) + { + return; + } + else if (random[SerpentHump]() < 40) + { // Missile attack + SetState (MeleeState); + return; + } + } + else if (random[SerpentHump]() > 3) + { + return; + } + if (!CheckMeleeRange ()) + { // The hump shouldn't occur when within melee range + if (MissileState != NULL && random[SerpentHump]() < 128) + { + SetState (MeleeState); + } + else + { + SetStateLabel("Hump"); + A_PlaySound ("SerpentActive", CHAN_BODY); + } + } + } + + //============================================================================ + // + // A_SerpentCheckForAttack + // + //============================================================================ + + void A_SerpentCheckForAttack() + { + if (!target) + { + return; + } + if (MissileState != NULL) + { + if (!CheckMeleeRange ()) + { + SetStateLabel ("Attack"); + return; + } + } + if (CheckMeleeRange2 ()) + { + SetStateLabel ("Walk"); + } + else if (CheckMeleeRange ()) + { + if (random[SerpentAttack]() < 32) + { + SetStateLabel ("Walk"); + } + else + { + SetStateLabel ("Attack"); + } + } + } + + //============================================================================ + // + // A_SerpentChooseAttack + // + //============================================================================ + + void A_SerpentChooseAttack() + { + if (!target || CheckMeleeRange()) + { + return; + } + if (MissileState != NULL) + { + SetState (MissileState); + } + } + + //============================================================================ + // + // A_SerpentMeleeAttack + // + //============================================================================ + + void A_SerpentMeleeAttack() + { + if (!target) + { + return; + } + if (CheckMeleeRange ()) + { + int damage = random[SerpentAttack](1, 8) * 5; + int newdam = target.DamageMobj (self, self, damage, 'Melee'); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + A_PlaySound ("SerpentMeleeHit", CHAN_BODY); + } + if (random[SerpentAttack]() < 96) + { + A_SerpentCheckForAttack(); + } + } + + //============================================================================ + // + // A_SerpentSpawnGibs + // + //============================================================================ + + void A_SerpentSpawnGibs() + { + static const class GibTypes[] = + { + "SerpentGib3", + "SerpentGib2", + "SerpentGib1" + }; + + for (int i = 2; i >= 0; --i) + { + double x = (random[SerpentGibs]() - 128) / 16.; + double y = (random[SerpentGibs]() - 128) / 16.; + + Actor mo = Spawn (GibTypes[i], Vec2OffsetZ(x, y, floorz + 1), ALLOW_REPLACE); + if (mo) + { + mo.Vel.X = (random[SerpentGibs]() - 128) / 1024.f; + mo.Vel.Y = (random[SerpentGibs]() - 128) / 1024.f; + mo.Floorclip = 6; + } + } + } } // Serpent Leader ----------------------------------------------------------- @@ -159,8 +346,6 @@ class SerpentHead : Actor +NOBLOCKMAP } - native void A_SerpentHeadCheck(); - States { Spawn: @@ -170,6 +355,28 @@ class SerpentHead : Actor SSXD S -1; Loop; } + + //============================================================================ + // + // A_SerpentHeadCheck + // + //============================================================================ + + void A_SerpentHeadCheck() + { + if (pos.z <= floorz) + { + if (GetFloorTerrain().IsLiquid) + { + HitFloor (); + Destroy(); + } + else + { + SetStateLabel ("NAME_Death"); + } + } + } } // Serpent Gib 1 ------------------------------------------------------------ @@ -183,10 +390,6 @@ class SerpentGib1 : Actor +NOBLOCKMAP +NOGRAVITY } - native void A_FloatGib(); - native void A_DelayGib(); - native void A_SinkGib(); - States { Spawn: @@ -199,6 +402,41 @@ class SerpentGib1 : Actor SSXD QQQ 8 A_SinkGib; Stop; } + + //============================================================================ + // + // A_FloatGib + // + //============================================================================ + + void A_FloatGib() + { + Floorclip -= 1; + } + + //============================================================================ + // + // A_SinkGib + // + //============================================================================ + + void A_SinkGib() + { + Floorclip += 1; + } + + //============================================================================ + // + // A_DelayGib + // + //============================================================================ + + void A_DelayGib() + { + tics -= random[DelayGib]() >> 2; + } + + } // Serpent Gib 2 ------------------------------------------------------------ From d4427e696d12efa08b0de90db9ff22640d4c0bc6 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 28 Nov 2016 01:30:36 +0100 Subject: [PATCH 145/185] - scriptified Hexen's Banishment Device. --- src/CMakeLists.txt | 1 - src/g_game.cpp | 19 +- src/g_hexen/a_hexenmisc.cpp | 1 - src/g_hexen/a_teleportother.cpp | 198 ------------------ wadsrc/static/zscript/base.txt | 6 + wadsrc/static/zscript/hexen/teleportother.txt | 134 +++++++++++- 6 files changed, 149 insertions(+), 210 deletions(-) delete mode 100644 src/g_hexen/a_teleportother.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 40d227fa4..553a66c12 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -861,7 +861,6 @@ set( NOT_COMPILED_SOURCE_FILES sc_man_scanner.re g_hexen/a_heresiarch.cpp g_hexen/a_spike.cpp - g_hexen/a_teleportother.cpp g_strife/a_acolyte.cpp g_strife/a_alienspectres.cpp g_strife/a_coin.cpp diff --git a/src/g_game.cpp b/src/g_game.cpp index 350669cfe..b5729283e 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1540,15 +1540,28 @@ DEFINE_ACTION_FUNCTION(DObject, G_PickDeathmatchStart) { PARAM_PROLOGUE; unsigned int selections = deathmatchstarts.Size(); - unsigned int i = pr_dmspawn() % selections; + DVector3 pos; + int angle; + if (selections == 0) + { + angle = INT_MAX; + pos = DVector3(0, 0, 0); + } + else + { + unsigned int i = pr_dmspawn() % selections; + angle = deathmatchstarts[i].angle; + pos = deathmatchstarts[i].pos; + } + if (numret > 1) { - ret[1].SetInt(deathmatchstarts[i].angle); + ret[1].SetInt(angle); numret = 2; } if (numret > 0) { - ret[0].SetVector(deathmatchstarts[i].pos); + ret[0].SetVector(pos); } return numret; } diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp index 4cfd359f8..f871e82d9 100644 --- a/src/g_hexen/a_hexenmisc.cpp +++ b/src/g_hexen/a_hexenmisc.cpp @@ -26,4 +26,3 @@ // Include all the Hexen stuff here to reduce compile time #include "a_heresiarch.cpp" #include "a_spike.cpp" -#include "a_teleportother.cpp" diff --git a/src/g_hexen/a_teleportother.cpp b/src/g_hexen/a_teleportother.cpp deleted file mode 100644 index 0e7dd018d..000000000 --- a/src/g_hexen/a_teleportother.cpp +++ /dev/null @@ -1,198 +0,0 @@ -/* -#include "info.h" -#include "a_pickups.h" -#include "a_artifacts.h" -#include "gstrings.h" -#include "p_local.h" -#include "s_sound.h" -#include "p_lnspec.h" -#include "m_random.h" -#include "vm.h" -#include "g_level.h" -#include "doomstat.h" -*/ - -#define TELEPORT_LIFE 1 - -static FRandom pr_telestarts ("TeleStarts"); -static FRandom pr_teledm ("TeleDM"); - -void A_TeloSpawnA (AActor *); -void A_TeloSpawnB (AActor *); -void A_TeloSpawnC (AActor *); -void A_TeloSpawnD (AActor *); -void A_CheckTeleRing (AActor *); -void P_TeleportToPlayerStarts (AActor *victim); -void P_TeleportToDeathmatchStarts (AActor *victim); - -// Teleport Other Artifact -------------------------------------------------- - -class AArtiTeleportOther : public AInventory -{ - DECLARE_CLASS (AArtiTeleportOther, AInventory) -public: - bool Use (bool pickup); -}; - -IMPLEMENT_CLASS(AArtiTeleportOther, false, false) - -// Teleport Other FX -------------------------------------------------------- - -class ATelOtherFX1 : public AActor -{ - DECLARE_CLASS (ATelOtherFX1, AActor) -public: - int DoSpecialDamage (AActor *target, int damage, FName damagetype); -}; - -IMPLEMENT_CLASS(ATelOtherFX1, false, false) - -static void TeloSpawn (AActor *source, const char *type) -{ - AActor *fx; - - fx = Spawn (type, source->Pos(), ALLOW_REPLACE); - if (fx) - { - fx->special1 = TELEPORT_LIFE; // Lifetime countdown - fx->Angles.Yaw = source->Angles.Yaw; - fx->target = source->target; - fx->Vel = source->Vel / 2; - } -} - -DEFINE_ACTION_FUNCTION(AActor, A_TeloSpawnA) -{ - PARAM_SELF_PROLOGUE(AActor); - TeloSpawn (self, "TelOtherFX2"); - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_TeloSpawnB) -{ - PARAM_SELF_PROLOGUE(AActor); - TeloSpawn (self, "TelOtherFX3"); - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_TeloSpawnC) -{ - PARAM_SELF_PROLOGUE(AActor); - TeloSpawn (self, "TelOtherFX4"); - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_TeloSpawnD) -{ - PARAM_SELF_PROLOGUE(AActor); - TeloSpawn (self, "TelOtherFX5"); - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_CheckTeleRing) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (self->special1-- <= 0) - { - self->SetState (self->FindState(NAME_Death)); - } - return 0; -} - -//=========================================================================== -// -// Activate Teleport Other -// -//=========================================================================== - -bool AArtiTeleportOther::Use (bool pickup) -{ - AActor *mo; - - mo = P_SpawnPlayerMissile (Owner, RUNTIME_CLASS(ATelOtherFX1)); - if (mo) - { - mo->target = Owner; - } - return true; -} - -//=========================================================================== -// -// Perform Teleport Other -// -//=========================================================================== - -int ATelOtherFX1::DoSpecialDamage (AActor *target, int damage, FName damagetype) -{ - if ((target->flags3 & MF3_ISMONSTER || target->player != NULL) && - !(target->flags2 & MF2_BOSS) && - !(target->flags3 & MF3_NOTELEOTHER)) - { - if (target->player) - { - if (deathmatch) - P_TeleportToDeathmatchStarts (target); - else - P_TeleportToPlayerStarts (target); - } - else - { - // If death action, run it upon teleport - if (target->flags3 & MF3_ISMONSTER && target->special) - { - target->RemoveFromHash (); - P_ExecuteSpecial(target->special, NULL, level.flags & LEVEL_ACTOWNSPECIAL - ? target : (AActor *)(this->target), false, target->args[0], target->args[1], - target->args[2], target->args[3], target->args[4]); - target->special = 0; - } - - // Send all monsters to deathmatch spots - P_TeleportToDeathmatchStarts (target); - } - } - return -1; -} - -//=========================================================================== -// -// P_TeleportToPlayerStarts -// -//=========================================================================== - -void P_TeleportToPlayerStarts (AActor *victim) -{ - DVector3 dest; - - FPlayerStart *start = G_PickPlayerStart(0, PPS_FORCERANDOM | PPS_NOBLOCKINGCHECK); - dest = start->pos; - dest.Z = ONFLOORZ; - P_Teleport (victim, dest, (double)start->angle, TELF_SOURCEFOG | TELF_DESTFOG); -} - -//=========================================================================== -// -// P_TeleportToDeathmatchStarts -// -//=========================================================================== - -void P_TeleportToDeathmatchStarts (AActor *victim) -{ - unsigned int i, selections; - DVector3 dest; - - selections = deathmatchstarts.Size (); - if (selections > 0) - { - i = pr_teledm() % selections; - dest = deathmatchstarts[i].pos; - dest.Z = ONFLOORZ; - P_Teleport (victim, dest, (double)deathmatchstarts[i].angle, TELF_SOURCEFOG | TELF_DESTFOG); - } - else - { - P_TeleportToPlayerStarts (victim); - } -} diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 08d655caf..3a96cbbcb 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -267,3 +267,9 @@ struct TerrainDef native native double Friction; native double MoveFactor; }; + +enum EPickStart +{ + PPS_FORCERANDOM = 1, + PPS_NOBLOCKINGCHECK = 2, +} diff --git a/wadsrc/static/zscript/hexen/teleportother.txt b/wadsrc/static/zscript/hexen/teleportother.txt index 2de144d5f..f7be0ebff 100644 --- a/wadsrc/static/zscript/hexen/teleportother.txt +++ b/wadsrc/static/zscript/hexen/teleportother.txt @@ -1,7 +1,7 @@ // Teleport Other Artifact -------------------------------------------------- -class ArtiTeleportOther : Inventory native +class ArtiTeleportOther : Inventory { Default { @@ -22,13 +22,29 @@ class ArtiTeleportOther : Inventory native TELO ABCD 5; Loop; } + + //=========================================================================== + // + // Activate Teleport Other + // + //=========================================================================== + + override bool Use (bool pickup) + { + Owner.SpawnPlayerMissile ("TelOtherFX1"); + return true; + } + + } // Teleport Other FX -------------------------------------------------------- -class TelOtherFX1 : Actor native +class TelOtherFX1 : Actor { + const TELEPORT_LIFE = 1; + Default { Damage 10001; @@ -41,11 +57,6 @@ class TelOtherFX1 : Actor native Speed 20; } - native void A_TeloSpawnA(); - native void A_TeloSpawnB(); - native void A_TeloSpawnC(); - native void A_TeloSpawnD(); - native void A_CheckTeleRing (); States { @@ -63,6 +74,115 @@ class TelOtherFX1 : Actor native TRNG E 3 Bright; Stop; } + + private void TeloSpawn (class type) + { + Actor fx = Spawn (type, pos, ALLOW_REPLACE); + if (fx) + { + fx.special1 = TELEPORT_LIFE; // Lifetime countdown + fx.angle = angle; + fx.target = target; + fx.Vel = Vel / 2; + } + } + + void A_TeloSpawnA() + { + TeloSpawn ("TelOtherFX2"); + } + + void A_TeloSpawnB() + { + TeloSpawn ("TelOtherFX3"); + } + + void A_TeloSpawnC() + { + TeloSpawn ("TelOtherFX4"); + } + + void A_TeloSpawnD() + { + TeloSpawn ("TelOtherFX5"); + } + + void A_CheckTeleRing () + { + if (self.special1-- <= 0) + { + self.SetStateLabel("Death"); + } + } + + //=========================================================================== + // + // Perform Teleport Other + // + //=========================================================================== + + override int DoSpecialDamage (Actor target, int damage, Name damagetype) + { + if ((target.bIsMonster || target.player != NULL) && + !target.bBoss && !target.bNoTeleOther) + { + if (target.player) + { + if (deathmatch) + P_TeleportToDeathmatchStarts (target); + else + P_TeleportToPlayerStarts (target); + } + else + { + // If death action, run it upon teleport + if (target.bIsMonster && target.special) + { + target.RemoveFromHash (); + Actor caller = level.ActOwnSpecial? target : self.target; + caller.A_CallSpecial(target.special, target.args[0], target.args[1], target.args[2], target.args[3], target.args[4]); + target.special = 0; + } + + // Send all monsters to deathmatch spots + P_TeleportToDeathmatchStarts (target); + } + } + return -1; + } + + //=========================================================================== + // + // P_TeleportToPlayerStarts + // + //=========================================================================== + + private static void P_TeleportToPlayerStarts (Actor victim) + { + Vector3 dest; + double destAngle; + + [dest, destAngle] = G_PickPlayerStart(0, PPS_FORCERANDOM | PPS_NOBLOCKINGCHECK); + dest.Z = ONFLOORZ; + victim.Teleport ((dest.xy, ONFLOORZ), destangle, TELF_SOURCEFOG | TELF_DESTFOG); + } + + //=========================================================================== + // + // P_TeleportToDeathmatchStarts + // + //=========================================================================== + + private void P_TeleportToDeathmatchStarts (Actor victim) + { + Vector3 dest; + double destAngle; + + [dest, destAngle] = G_PickDeathmatchStart(); + if (destAngle < 65536) victim.Teleport((dest.xy, ONFLOORZ), destangle, TELF_SOURCEFOG | TELF_DESTFOG); + else P_TeleportToPlayerStarts(victim); + } + } From 7ea9f60464cc065246be8b5862bff8b13f363141 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 28 Nov 2016 10:41:36 +0100 Subject: [PATCH 146/185] - scriptified the Acolyte. --- src/CMakeLists.txt | 1 - src/g_level.cpp | 5 +- src/g_strife/a_acolyte.cpp | 86 ------------------------ src/g_strife/a_strifestuff.cpp | 1 - src/p_user.cpp | 16 +++++ wadsrc/static/zscript/shared/player.txt | 2 + wadsrc/static/zscript/strife/acolyte.txt | 70 +++++++++++++++++-- 7 files changed, 87 insertions(+), 94 deletions(-) delete mode 100644 src/g_strife/a_acolyte.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 553a66c12..269fd3bd7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -861,7 +861,6 @@ set( NOT_COMPILED_SOURCE_FILES sc_man_scanner.re g_hexen/a_heresiarch.cpp g_hexen/a_spike.cpp - g_strife/a_acolyte.cpp g_strife/a_alienspectres.cpp g_strife/a_coin.cpp g_strife/a_crusader.cpp diff --git a/src/g_level.cpp b/src/g_level.cpp index ea34dc95c..0e7820d93 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -478,7 +478,8 @@ void G_InitNew (const char *mapname, bool bTitleLevel) // Set the initial quest log text for Strife. for (i = 0; i < MAXPLAYERS; ++i) { - players[i].SetLogText ("Find help"); + if (playeringame[i]) + players[i].SetLogText ("Find help"); } } @@ -1092,7 +1093,7 @@ void G_WorldDone (void) if (strncmp (nextlevel, "enDSeQ", 6) == 0) { FName endsequence = ENamedName(strtol(nextlevel.GetChars()+6, NULL, 16)); - // Strife needs a special case here to choose between good and sad ending. Bad is handled elsewherw. + // Strife needs a special case here to choose between good and sad ending. Bad is handled elsewhere. if (endsequence == NAME_Inter_Strife) { if (players[0].mo->FindInventory (QuestItemClasses[24]) || diff --git a/src/g_strife/a_acolyte.cpp b/src/g_strife/a_acolyte.cpp deleted file mode 100644 index f0ed0c414..000000000 --- a/src/g_strife/a_acolyte.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* -#include "actor.h" -#include "m_random.h" -#include "a_action.h" -#include "p_local.h" -#include "p_enemy.h" -#include "s_sound.h" -#include "a_strifeglobal.h" -#include "doomdata.h" -#include "vm.h" -#include "doomstat.h" -*/ - -//============================================================================ -// -// A_HideDecepticon -// -// Hide the Acolyte-to-be -> -// Hide the guy transforming into an Acolyte -> -// Hide the transformer -> -// Transformers are Autobots and Decepticons, and -// Decepticons are the bad guys, so... -> -// -// Hide the Decepticon! -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_HideDecepticon) -{ - PARAM_SELF_PROLOGUE(AActor); - - EV_DoDoor (DDoor::doorClose, NULL, self, 999, 8., 0, 0, 0); - if (self->target != NULL && self->target->player != NULL) - { - P_NoiseAlert (self->target, self); - } - return 0; -} - -//============================================================================ -// -// A_AcolyteDie -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_AcolyteDie) -{ - PARAM_SELF_PROLOGUE(AActor); - - int i; - - // [RH] Disable translucency here. - self->RenderStyle = STYLE_Normal; - - // Only the Blue Acolyte does extra stuff on death. - if (self->GetClass()->TypeName != NAME_AcolyteBlue) - return 0; - - // Make sure somebody is still alive - for (i = 0; i < MAXPLAYERS; ++i) - { - if (playeringame[i] && players[i].health > 0) - break; - } - if (i == MAXPLAYERS) - return 0; - - // Make sure all the other blue acolytes are dead. - TThinkerIterator iterator(NAME_AcolyteBlue); - AActor *other; - - while ( (other = iterator.Next ()) ) - { - if (other != self && other->health > 0) - { // Found a living one - return 0; - } - } - - players[i].mo->GiveInventoryType (QuestItemClasses[6]); - players[i].SetLogNumber (14); - S_StopSound (CHAN_VOICE); - S_Sound (CHAN_VOICE, "svox/voc14", 1, ATTN_NORM); - return 0; -} - diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp index 6815b1d49..ed56407f5 100644 --- a/src/g_strife/a_strifestuff.cpp +++ b/src/g_strife/a_strifestuff.cpp @@ -24,7 +24,6 @@ #include "vm.h" // Include all the other Strife stuff here to reduce compile time -#include "a_acolyte.cpp" #include "a_spectral.cpp" #include "a_alienspectres.cpp" #include "a_coin.cpp" diff --git a/src/p_user.cpp b/src/p_user.cpp index ce78d04a8..5f2d19cb4 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -486,6 +486,14 @@ void player_t::SetLogNumber (int num) } } +DEFINE_ACTION_FUNCTION(_PlayerInfo, SetLogNumber) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + PARAM_INT(log); + self->SetLogNumber(log); + return 0; +} + void player_t::SetLogText (const char *text) { LogText = text; @@ -496,6 +504,14 @@ void player_t::SetLogText (const char *text) AddToConsole(-1, "\n"); } +DEFINE_ACTION_FUNCTION(_PlayerInfo, SetLogText) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + PARAM_STRING(log); + self->SetLogText(log); + return 0; +} + int player_t::GetSpawnClass() { const PClass * type = PlayerClasses[CurrentPlayerClass].Type; diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index c7615e9c2..bcbc7db61 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -233,5 +233,7 @@ FWeaponSlots weapons; native void SetSafeFlash(Weapon weap, State flashstate, int index); native PSprite GetPSprite(int id); native PSprite FindPSprite(int id); + native void SetLogNumber (int text); + native void SetLogText (String text); } diff --git a/wadsrc/static/zscript/strife/acolyte.txt b/wadsrc/static/zscript/strife/acolyte.txt index 9a6b0105a..1c50b318c 100644 --- a/wadsrc/static/zscript/strife/acolyte.txt +++ b/wadsrc/static/zscript/strife/acolyte.txt @@ -26,8 +26,6 @@ class Acolyte : StrifeHumanoid Obituary "$OB_ACOLYTE"; } - native void A_AcolyteDie (); - States { Spawn: @@ -75,6 +73,49 @@ class Acolyte : StrifeHumanoid Stop; } + //============================================================================ + // + // A_AcolyteDie + // + //============================================================================ + + void A_AcolyteDie () + { + // [RH] Disable translucency here. + A_SetRenderStyle(1, STYLE_Normal); + + // Only the Blue Acolyte does extra stuff on death. + if (self is "AcolyteBlue") + { + int i; + // Make sure somebody is still alive + for (i = 0; i < MAXPLAYERS; ++i) + { + if (playeringame[i] && players[i].health > 0) + break; + } + if (i == MAXPLAYERS) + return; + + // Make sure all the other blue acolytes are dead. + ThinkerIterator it = ThinkerIterator.Create("AcolyteBlue"); + Actor other; + + while ( (other = Actor(it.Next ())) ) + { + if (other != self && other.health > 0) + { // Found a living one + return; + } + } + + players[i].mo.GiveInventoryType ("QuestItem7"); + players[i].SetLogNumber (14); + A_StopSound (CHAN_VOICE); + A_PlaySound ("svox/voc14", CHAN_VOICE); + } + } + //============================================================================ // // A_BeShadowyFoe @@ -238,8 +279,6 @@ class AcolyteToBe : Acolyte -ISMONSTER } - native void A_HideDecepticon (); - States { Spawn: @@ -251,4 +290,27 @@ class AcolyteToBe : Acolyte Death: Goto XDeath; } + + //============================================================================ + // + // A_HideDecepticon + // + // Hide the Acolyte-to-be -> + // Hide the guy transforming into an Acolyte -> + // Hide the transformer -> + // Transformers are Autobots and Decepticons, and + // Decepticons are the bad guys, so... -> + // + // Hide the Decepticon! + // + //============================================================================ + + void A_HideDecepticon () + { + Door_Close(999, 64); + if (target != null && target.player != null) + { + target.NoiseAlert (self); + } + } } From b171d6e21f22c7abf336aa11fc56074080e706ae Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 28 Nov 2016 11:52:03 +0100 Subject: [PATCH 147/185] - scriptified a_alienspectres.cpp. --- src/CMakeLists.txt | 1 - src/c_console.cpp | 15 ++ src/g_strife/a_alienspectres.cpp | 201 ------------------ src/g_strife/a_strifestuff.cpp | 1 - src/g_strife/a_strifeweapons.cpp | 34 --- src/p_enemy.cpp | 6 + src/p_interaction.cpp | 2 +- src/p_mobj.cpp | 42 ++++ src/s_sound.cpp | 10 + wadsrc/static/zscript/actor.txt | 4 +- wadsrc/static/zscript/base.txt | 2 + wadsrc/static/zscript/strife/acolyte.txt | 18 +- .../static/zscript/strife/alienspectres.txt | 112 +++++++++- wadsrc/static/zscript/strife/spectral.txt | 62 +++++- 14 files changed, 253 insertions(+), 257 deletions(-) delete mode 100644 src/g_strife/a_alienspectres.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 269fd3bd7..911fce1ed 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -861,7 +861,6 @@ set( NOT_COMPILED_SOURCE_FILES sc_man_scanner.re g_hexen/a_heresiarch.cpp g_hexen/a_spike.cpp - g_strife/a_alienspectres.cpp g_strife/a_coin.cpp g_strife/a_crusader.cpp g_strife/a_entityboss.cpp diff --git a/src/c_console.cpp b/src/c_console.cpp index 3064abb0d..1016be9fd 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -65,6 +65,7 @@ #include "g_level.h" #include "d_event.h" #include "d_player.h" +#include "gstrings.h" #include "c_consolebuffer.h" #include "gi.h" @@ -1729,6 +1730,20 @@ void C_MidPrintBold (FFont *font, const char *msg) } } +DEFINE_ACTION_FUNCTION(DObject, C_MidPrint) +{ + PARAM_PROLOGUE; + PARAM_STRING(font); + PARAM_STRING(text); + PARAM_BOOL_DEF(bold); + + FFont *fnt = FFont::FindFont(font); + const char *txt = GStrings(text); + if (!bold) C_MidPrint(fnt, txt); + else C_MidPrintBold(fnt, txt); + return 0; +} + /****** Tab completion code ******/ struct TabData diff --git a/src/g_strife/a_alienspectres.cpp b/src/g_strife/a_alienspectres.cpp deleted file mode 100644 index 194bfd9e0..000000000 --- a/src/g_strife/a_alienspectres.cpp +++ /dev/null @@ -1,201 +0,0 @@ -/* -#include "actor.h" -#include "m_random.h" -#include "a_action.h" -#include "p_local.h" -#include "p_enemy.h" -#include "s_sound.h" -#include "m_random.h" -#include "a_strifeglobal.h" -#include "c_console.h" -#include "gstrings.h" -#include "vm.h" -#include "doomstat.h" -*/ - -static FRandom pr_spectrespawn ("AlienSpectreSpawn"); -static FRandom pr_spectrechunk ("212e4"); - -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SpectreChunkSmall) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *foo = Spawn("AlienChunkSmall", self->PosPlusZ(10.), ALLOW_REPLACE); - - if (foo != NULL) - { - int t; - - t = pr_spectrechunk() & 15; - foo->Vel.X = (t - (pr_spectrechunk() & 7)); - - t = pr_spectrechunk() & 15; - foo->Vel.Y = (t - (pr_spectrechunk() & 7)); - - foo->Vel.Z = (pr_spectrechunk() & 15); - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_SpectreChunkLarge) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *foo = Spawn("AlienChunkLarge", self->PosPlusZ(10.), ALLOW_REPLACE); - - if (foo != NULL) - { - int t; - - t = pr_spectrechunk() & 7; - foo->Vel.X = (t - (pr_spectrechunk() & 15)); - - t = pr_spectrechunk() & 7; - foo->Vel.Y = (t - (pr_spectrechunk() & 15)); - - foo->Vel.Z = (pr_spectrechunk() & 7); - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_Spectre3Attack) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (self->target == NULL) - return 0; - - AActor *foo = Spawn("SpectralLightningV2", self->PosPlusZ(32.), ALLOW_REPLACE); - - foo->Vel.Z = -12; - foo->target = self; - foo->FriendPlayer = 0; - foo->tracer = self->target; - - self->Angles.Yaw -= 90.; - for (int i = 0; i < 20; ++i) - { - self->Angles.Yaw += 9.; - P_SpawnSubMissile (self, PClass::FindActor("SpectralLightningBall2"), self); - } - self->Angles.Yaw -= 90.; - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_AlienSpectreDeath) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *player; - char voc[32]; - int log; - int i; - - A_Unblock(self, true); // [RH] Need this for Sigil rewarding - if (!CheckBossDeath (self)) - { - return 0; - } - for (i = 0, player = NULL; i < MAXPLAYERS; ++i) - { - if (playeringame[i] && players[i].health > 0) - { - player = players[i].mo; - break; - } - } - if (player == NULL) - { - return 0; - } - - switch (self->GetClass()->TypeName) - { - case NAME_AlienSpectre1: - EV_DoFloor (DFloor::floorLowerToLowest, NULL, 999, 1., 0., -1, 0, false); - log = 95; - break; - - case NAME_AlienSpectre2: - C_MidPrint(SmallFont, GStrings("TXT_KILLED_BISHOP")); - log = 74; - player->GiveInventoryType (QuestItemClasses[20]); - break; - - case NAME_AlienSpectre3: - { - C_MidPrint(SmallFont, GStrings("TXT_KILLED_ORACLE")); - // If there are any Oracles still alive, kill them. - TThinkerIterator it(NAME_Oracle); - AActor *oracle; - - while ( (oracle = it.Next()) != NULL) - { - if (oracle->health > 0) - { - oracle->health = 0; - oracle->CallDie (self, self); - } - } - player->GiveInventoryType (QuestItemClasses[22]); - if (player->FindInventory (QuestItemClasses[20])) - { // If the Bishop is dead, set quest item 22 - player->GiveInventoryType (QuestItemClasses[21]); - } - if (player->FindInventory (QuestItemClasses[23]) == NULL) - { // Macil is calling us back... - log = 87; - } - else - { // You wield the power of the complete Sigil. - log = 85; - } - EV_DoDoor (DDoor::doorOpen, NULL, NULL, 222, 8., 0, 0, 0); - break; - } - - case NAME_AlienSpectre4: - C_MidPrint(SmallFont, GStrings("TXT_KILLED_MACIL")); - player->GiveInventoryType (QuestItemClasses[23]); - if (player->FindInventory (QuestItemClasses[24]) == NULL) - { // Richter has taken over. Macil is a snake. - log = 79; - } - else - { // Back to the factory for another Sigil! - log = 106; - } - break; - - case NAME_AlienSpectre5: - C_MidPrint(SmallFont, GStrings("TXT_KILLED_LOREMASTER")); - ASigil *sigil; - - player->GiveInventoryType (QuestItemClasses[25]); - if (!multiplayer) - { - player->GiveInventoryType (RUNTIME_CLASS(AUpgradeStamina)); - player->GiveInventoryType (RUNTIME_CLASS(AUpgradeAccuracy)); - } - sigil = player->FindInventory(); - if (sigil != NULL && sigil->NumPieces == 5) - { // You wield the power of the complete Sigil. - log = 85; - } - else - { // Another Sigil piece. Woohoo! - log = 83; - } - EV_DoFloor (DFloor::floorLowerToLowest, NULL, 666, 1., 0., -1, 0, false); - break; - - default: - 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_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp index ed56407f5..bf1379d3a 100644 --- a/src/g_strife/a_strifestuff.cpp +++ b/src/g_strife/a_strifestuff.cpp @@ -25,7 +25,6 @@ // Include all the other Strife stuff here to reduce compile time #include "a_spectral.cpp" -#include "a_alienspectres.cpp" #include "a_coin.cpp" #include "a_crusader.cpp" #include "a_entityboss.cpp" diff --git a/src/g_strife/a_strifeweapons.cpp b/src/g_strife/a_strifeweapons.cpp index 1909ec781..0630089d6 100644 --- a/src/g_strife/a_strifeweapons.cpp +++ b/src/g_strife/a_strifeweapons.cpp @@ -566,40 +566,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_MaulerTorpedoWave) return 0; } -AActor *P_SpawnSubMissile (AActor *source, PClassActor *type, AActor *target) -{ - AActor *other = Spawn (type, source->Pos(), ALLOW_REPLACE); - - if (other == NULL) - { - return NULL; - } - - other->target = target; - other->Angles.Yaw = source->Angles.Yaw; - other->VelFromAngle(); - - if (other->flags4 & MF4_SPECTRAL) - { - if (source->flags & MF_MISSILE && source->flags4 & MF4_SPECTRAL) - { - other->FriendPlayer = source->FriendPlayer; - } - else - { - other->SetFriendPlayer(target->player); - } - } - - if (P_CheckMissileSpawn (other, source->radius)) - { - DAngle pitch = P_AimLineAttack (source, source->Angles.Yaw, 1024.); - other->Vel.Z = -other->Speed * pitch.Sin(); - return other; - } - return NULL; -} - class APhosphorousFire : public AActor { DECLARE_CLASS (APhosphorousFire, AActor) diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 4f4920c6f..fcd8f9cee 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -3339,6 +3339,12 @@ bool CheckBossDeath (AActor *actor) return true; } +DEFINE_ACTION_FUNCTION(AActor, CheckBossDeath) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_BOOL(CheckBossDeath(self)); +} + // // A_BossDeath // Possibly trigger special effects if on a boss level diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index c2d958050..3c3347ec1 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -767,7 +767,7 @@ DEFINE_ACTION_FUNCTION(AActor, Die) PARAM_SELF_PROLOGUE(AActor); PARAM_OBJECT(source, AActor); PARAM_OBJECT(inflictor, AActor); - PARAM_INT(dmgflags); + PARAM_INT_DEF(dmgflags); self->Die(source, inflictor, dmgflags); return 0; } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 6268c9395..a52ee4976 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -6554,6 +6554,48 @@ DEFINE_ACTION_FUNCTION(AActor, SpawnMissileAngleZSpeed) ACTION_RETURN_OBJECT(P_SpawnMissileAngleZSpeed(self, z, type, angle, vz, speed, owner, checkspawn)); } + +AActor *P_SpawnSubMissile(AActor *source, PClassActor *type, AActor *target) +{ + AActor *other = Spawn(type, source->Pos(), ALLOW_REPLACE); + + if (other == NULL) + { + return NULL; + } + + other->target = target; + other->Angles.Yaw = source->Angles.Yaw; + other->VelFromAngle(); + + if (other->flags4 & MF4_SPECTRAL) + { + if (source->flags & MF_MISSILE && source->flags4 & MF4_SPECTRAL) + { + other->FriendPlayer = source->FriendPlayer; + } + else + { + other->SetFriendPlayer(target->player); + } + } + + if (P_CheckMissileSpawn(other, source->radius)) + { + DAngle pitch = P_AimLineAttack(source, source->Angles.Yaw, 1024.); + other->Vel.Z = -other->Speed * pitch.Sin(); + return other; + } + return NULL; +} + +DEFINE_ACTION_FUNCTION(AActor, SpawnSubMissile) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_CLASS(cls, AActor); + PARAM_OBJECT(target, AActor); + ACTION_RETURN_OBJECT(P_SpawnSubMissile(self, cls, target)); +} /* ================ = diff --git a/src/s_sound.cpp b/src/s_sound.cpp index a51a7101b..81b94b0f2 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -1232,6 +1232,16 @@ void S_Sound (int channel, FSoundID sound_id, float volume, float attenuation) S_StartSound (NULL, NULL, NULL, NULL, channel, sound_id, volume, attenuation); } +DEFINE_ACTION_FUNCTION(DObject, S_Sound) +{ + PARAM_PROLOGUE; + PARAM_SOUND(id); + PARAM_INT(channel); + PARAM_FLOAT_DEF(volume); + PARAM_FLOAT_DEF(attn); + return 0; +} + //========================================================================== // // S_Sound - An actor is source diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 09b983843..dd1bec839 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -264,7 +264,7 @@ class Actor : Thinker native virtual native void Activate(Actor activator); virtual native void Deactivate(Actor activator); virtual native int DoSpecialDamage (Actor target, int damage, Name damagetype); - virtual native void Die(Actor source, Actor inflictor, int dmgflags); + virtual native void Die(Actor source, Actor inflictor, int dmgflags = 0); virtual native bool Slam(Actor victim); virtual native bool UseInventory(Inventory item); virtual native bool SpecialBlastHandling (Actor source, double strength); @@ -309,11 +309,13 @@ class Actor : Thinker native native Actor SpawnMissileXYZ(Vector3 pos, Actor dest, Class type, bool checkspawn = true, Actor owner = null); native Actor SpawnMissileZ (double z, Actor dest, class type); native Actor SpawnMissileAngleZSpeed (double z, class type, double angle, double vz, double speed, Actor owner = null, bool checkspawn = true); + native Actor SpawnSubMissile(Class type, Actor target); native Actor, Actor SpawnPlayerMissile(class type, double angle = 0, double x = 0, double y = 0, double z = 0, out FTranslatedLineTarget pLineTarget = null, bool nofreeaim = false, bool noautoaim = false, int aimflags = 0); native void SpawnTeleportFog(Vector3 pos, bool beforeTele, bool setTarget); native Actor RoughMonsterSearch(int distance, bool onlyseekable = false, bool frontonly = false); native int ApplyDamageFactor(Name damagetype, int damage); native int GetModifiedDamage(Name damagetype, int damage, bool passive); + native bool CheckBossDeath(); void A_Light(int extralight) { if (player) player.extralight = clamp(extralight, -20, 20); } void A_Light0() { if (player) player.extralight = 0; } diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 3a96cbbcb..c76e4590e 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -8,6 +8,8 @@ class Object native native static vector3, int G_PickDeathmatchStart(); native static vector3, int G_PickPlayerStart(int pnum, int flags = 0); native static int GameType(); + native static void S_Sound (Sound sound_id, int channel, float volume = 1, float attenuation = ATTN_NORM); + native static void C_MidPrint(string fontname, string textlabel, bool bold = false); // always uses the stringtable. /*virtual*/ native void Destroy(); } diff --git a/wadsrc/static/zscript/strife/acolyte.txt b/wadsrc/static/zscript/strife/acolyte.txt index 1c50b318c..45f075d6b 100644 --- a/wadsrc/static/zscript/strife/acolyte.txt +++ b/wadsrc/static/zscript/strife/acolyte.txt @@ -98,21 +98,13 @@ class Acolyte : StrifeHumanoid return; // Make sure all the other blue acolytes are dead. - ThinkerIterator it = ThinkerIterator.Create("AcolyteBlue"); - Actor other; - - while ( (other = Actor(it.Next ())) ) + if (CheckBossDeath()) { - if (other != self && other.health > 0) - { // Found a living one - return; - } + players[i].mo.GiveInventoryType ("QuestItem7"); + players[i].SetLogNumber (14); + A_StopSound (CHAN_VOICE); + A_PlaySound ("svox/voc14", CHAN_VOICE); } - - players[i].mo.GiveInventoryType ("QuestItem7"); - players[i].SetLogNumber (14); - A_StopSound (CHAN_VOICE); - A_PlaySound ("svox/voc14", CHAN_VOICE); } } diff --git a/wadsrc/static/zscript/strife/alienspectres.txt b/wadsrc/static/zscript/strife/alienspectres.txt index 0fe9826f0..2beee63ea 100644 --- a/wadsrc/static/zscript/strife/alienspectres.txt +++ b/wadsrc/static/zscript/strife/alienspectres.txt @@ -32,8 +32,6 @@ class AlienSpectre1 : SpectralMonster +NOICEDEATH } - native void A_AlienSpectreDeath (); - States { Spawn: @@ -76,6 +74,116 @@ class AlienSpectre1 : SpectralMonster AL1P R 5 Bright A_AlienSpectreDeath; Stop; } + + //============================================================================ + + void A_AlienSpectreDeath () + { + PlayerPawn player = null; + int log = 0; + + A_NoBlocking(); // [RH] Need this for Sigil rewarding + if (!CheckBossDeath ()) + { + return; + } + for (int i = 0; i < MAXPLAYERS; ++i) + { + if (playeringame[i] && players[i].health > 0) + { + player = players[i].mo; + break; + } + } + if (player == null) + { + return; + } + + class cls = GetClass(); + if (cls == "AlienSpectre1") + { + Floor_LowerToLowest(999, 8); + log = 95; + } + else if (cls == "AlienSpectre2") + { + C_MidPrint("SmallFont", "TXT_KILLED_BISHOP"); + log = 74; + player.GiveInventoryType ("QuestItem21"); + } + else if (cls == "AlienSpectre3") + { + C_MidPrint("SmallFont", "TXT_KILLED_ORACLE"); + // If there are any Oracles still alive, kill them. + ThinkerIterator it = ThinkerIterator.Create("Oracle"); + Actor oracle; + + while ( (oracle = Actor(it.Next())) != null) + { + if (oracle.health > 0) + { + oracle.health = 0; + oracle.Die (self, self); + } + } + player.GiveInventoryType ("QuestItem23"); + if (player.FindInventory ("QuestItem21")) + { // If the Bishop is dead, set quest item 22 + player.GiveInventoryType ("QuestItem22"); + } + if (player.FindInventory ("QuestItem24") == null) + { // Macil is calling us back... + log = 87; + } + else + { // You wield the power of the complete Sigil. + log = 85; + } + Door_Open(222, 64); + } + else if (cls == "AlienSpectre4") + { + C_MidPrint("SmallFont", "TXT_KILLED_MACIL"); + player.GiveInventoryType ("QuestItem24"); + if (player.FindInventory ("QuestItem25") == null) + { // Richter has taken over. Macil is a snake. + log = 79; + } + else + { // Back to the factory for another Sigil! + log = 106; + } + } + else if (cls == "AlienSpectre5") + { + C_MidPrint("SmallFont", "TXT_KILLED_LOREMASTER"); + + player.GiveInventoryType ("QuestItem26"); + if (!multiplayer) + { + player.GiveInventoryType ("UpgradeStamina"); + player.GiveInventoryType ("UpgradeAccuracy"); + } + Sigil sigl = Sigil(player.FindInventory("Sigil")); + if (sigl != null /*&& sigl.NumPieces == 5*/) + { // You wield the power of the complete Sigil. + log = 85; + } + else + { // Another Sigil piece. Woohoo! + log = 83; + } + Floor_LowerToLowest(666, 8); + } + if (log > 0) + { + String voc = "svox/voc" .. log; + A_PlaySound(voc, CHAN_VOICE); + player.player.SetLogNumber (log); + } + } + } diff --git a/wadsrc/static/zscript/strife/spectral.txt b/wadsrc/static/zscript/strife/spectral.txt index d6a234904..9ea95ba1d 100644 --- a/wadsrc/static/zscript/strife/spectral.txt +++ b/wadsrc/static/zscript/strife/spectral.txt @@ -11,10 +11,66 @@ class SpectralMonster : Actor native +SPECTRAL +NOICEDEATH } + + //============================================================================ + + void A_SpectreChunkSmall () + { + Actor foo = Spawn("AlienChunkSmall", pos + (0, 0, 10), ALLOW_REPLACE); + + if (foo != null) + { + int t; + + t = random[SpectreChunk]() & 15; + foo.Vel.X = (t - (random[SpectreChunk]() & 7)); + + t = random[SpectreChunk]() & 15; + foo.Vel.Y = (t - (random[SpectreChunk]() & 7)); + + foo.Vel.Z = (random[SpectreChunk]() & 15); + } + } + + void A_SpectreChunkLarge () + { + Actor foo = Spawn("AlienChunkLarge", pos + (0, 0, 10), ALLOW_REPLACE); + + if (foo != null) + { + int t; + + t = random[SpectreChunk]() & 7; + foo.Vel.X = (t - (random[SpectreChunk]() & 15)); + + t = random[SpectreChunk]() & 7; + foo.Vel.Y = (t - (random[SpectreChunk]() & 15)); + + foo.Vel.Z = (random[SpectreChunk]() & 7); + } + } + + void A_Spectre3Attack () + { + if (target == null) + return; + + Actor foo = Spawn("SpectralLightningV2", Pos + (0, 0, 32), ALLOW_REPLACE); + + foo.Vel.Z = -12; + foo.target = self; + foo.FriendPlayer = 0; + foo.tracer = target; + + Angle -= 90.; + for (int i = 0; i < 20; ++i) + { + Angle += 9.; + SpawnSubMissile ("SpectralLightningBall2", self); + } + Angle -= 90.; + } - native void A_SpectreChunkSmall (); - native void A_SpectreChunkLarge (); - native void A_Spectre3Attack (); native void A_SpotLightning (); } From dc9ee0727a31beae12862a8453b80515aff3890c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 28 Nov 2016 12:55:33 +0100 Subject: [PATCH 148/185] - scriptified a_spectral.cpp. - consolidated A_Tracer and A_Tracer2. Note that this commit temporarily disables a few features in order to make it compile. --- src/CMakeLists.txt | 1 - src/actor.h | 1 + src/g_strife/a_entityboss.cpp | 5 +- src/g_strife/a_programmer.cpp | 26 ---- src/g_strife/a_spectral.cpp | 144 -------------------- src/g_strife/a_strifestuff.cpp | 1 - src/p_interaction.cpp | 3 +- src/p_mobj.cpp | 19 +++ src/p_user.cpp | 11 +- wadsrc/static/zscript/actor.txt | 2 +- wadsrc/static/zscript/doom/revenant.txt | 55 ++++---- wadsrc/static/zscript/strife/programmer.txt | 22 ++- wadsrc/static/zscript/strife/spectral.txt | 90 ++++++++++-- 13 files changed, 160 insertions(+), 220 deletions(-) delete mode 100644 src/g_strife/a_spectral.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 911fce1ed..21637c59b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -871,7 +871,6 @@ set( NOT_COMPILED_SOURCE_FILES g_strife/a_reaver.cpp g_strife/a_rebels.cpp g_strife/a_sentinel.cpp - g_strife/a_spectral.cpp g_strife/a_stalker.cpp g_strife/a_strifeitems.cpp g_strife/a_strifeweapons.cpp diff --git a/src/actor.h b/src/actor.h index 578b094ed..06a5e9f11 100644 --- a/src/actor.h +++ b/src/actor.h @@ -674,6 +674,7 @@ public: // Something just touched this actor. virtual void Touch (AActor *toucher); + void CallTouch(AActor *toucher); // Adds the item to this actor's inventory and sets its Owner. virtual void AddInventory (AInventory *item); diff --git a/src/g_strife/a_entityboss.cpp b/src/g_strife/a_entityboss.cpp index 535022901..7a6b6f027 100644 --- a/src/g_strife/a_entityboss.cpp +++ b/src/g_strife/a_entityboss.cpp @@ -36,7 +36,6 @@ void A_SpectralMissile (AActor *self, const char *missilename) } } -DECLARE_ACTION(A_SpotLightning) DECLARE_ACTION(A_Spectre3Attack) @@ -49,7 +48,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_EntityAttack) switch (pr_entity() % 5) { case 0: - CALL_ACTION(A_SpotLightning, self); + //CALL_ACTION(A_SpotLightning, self); break; case 2: @@ -57,7 +56,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_EntityAttack) break; case 3: - CALL_ACTION(A_Spectre3Attack, self); + //CALL_ACTION(A_Spectre3Attack, self); break; case 4: diff --git a/src/g_strife/a_programmer.cpp b/src/g_strife/a_programmer.cpp index 07f6a6c4c..a02848dd2 100644 --- a/src/g_strife/a_programmer.cpp +++ b/src/g_strife/a_programmer.cpp @@ -94,32 +94,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_ProgrammerMelee) return 0; } -//============================================================================ -// -// A_SpotLightning -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SpotLightning) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *spot; - - if (self->target == NULL) - return 0; - - spot = Spawn("SpectralLightningSpot", self->target->PosAtZ(self->target->floorz), ALLOW_REPLACE); - if (spot != NULL) - { - spot->threshold = 25; - spot->target = self; - spot->FriendPlayer = 0; - spot->tracer = self->target; - } - return 0; -} - //============================================================================ // // A_SpawnProgrammerBase diff --git a/src/g_strife/a_spectral.cpp b/src/g_strife/a_spectral.cpp deleted file mode 100644 index 4bd24bac7..000000000 --- a/src/g_strife/a_spectral.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/* -#include "actor.h" -#include "m_random.h" -#include "a_action.h" -#include "p_local.h" -#include "s_sound.h" -#include "m_random.h" -#include "a_strifeglobal.h" -#include "vm.h" -*/ - -class ASpectralMonster : public AActor -{ - DECLARE_CLASS (ASpectralMonster, AActor) -public: - void Touch (AActor *toucher); -}; - -IMPLEMENT_CLASS(ASpectralMonster, false, false) - -void ASpectralMonster::Touch (AActor *toucher) -{ - P_DamageMobj (toucher, this, this, 5, NAME_Melee); -} - - -DEFINE_ACTION_FUNCTION(AActor, A_SpectralLightningTail) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *foo = Spawn("SpectralLightningHTail", self->Vec3Offset(-self->Vel.X, -self->Vel.Y, 0.), ALLOW_REPLACE); - - foo->Angles.Yaw = self->Angles.Yaw; - foo->FriendPlayer = self->FriendPlayer; - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_SpectralBigBallLightning) -{ - PARAM_SELF_PROLOGUE(AActor); - - PClassActor *cls = PClass::FindActor("SpectralLightningH3"); - if (cls) - { - self->Angles.Yaw += 90.; - P_SpawnSubMissile (self, cls, self->target); - self->Angles.Yaw += 180.; - P_SpawnSubMissile (self, cls, self->target); - self->Angles.Yaw -= 270.; - P_SpawnSubMissile (self, cls, self->target); - } - return 0; -} - -static FRandom pr_zap5 ("Zap5"); - -DEFINE_ACTION_FUNCTION(AActor, A_SpectralLightning) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *flash; - - if (self->threshold != 0) - --self->threshold; - - self->Vel.X += pr_zap5.Random2(3); - self->Vel.Y += pr_zap5.Random2(3); - - double xo = pr_zap5.Random2(3) * 50.; - double yo = pr_zap5.Random2(3) * 50.; - - flash = Spawn (self->threshold > 25 ? PClass::FindActor(NAME_SpectralLightningV2) : - PClass::FindActor(NAME_SpectralLightningV1), self->Vec2OffsetZ(xo, yo, ONCEILINGZ), ALLOW_REPLACE); - - flash->target = self->target; - flash->Vel.Z = -18; - flash->FriendPlayer = self->FriendPlayer; - - flash = Spawn(NAME_SpectralLightningV2, self->PosAtZ(ONCEILINGZ), ALLOW_REPLACE); - - flash->target = self->target; - flash->Vel.Z = -18; - flash->FriendPlayer = self->FriendPlayer; - return 0; -} - -// In Strife, this number is stored in the data segment, but it doesn't seem to be -// altered anywhere. -#define TRACEANGLE (19.6875) - -DEFINE_ACTION_FUNCTION(AActor, A_Tracer2) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *dest; - double dist; - double slope; - - dest = self->tracer; - - if (!dest || dest->health <= 0 || self->Speed == 0 || !self->CanSeek(dest)) - return 0; - - DAngle exact = self->AngleTo(dest); - DAngle diff = deltaangle(self->Angles.Yaw, exact); - - if (diff < 0) - { - self->Angles.Yaw -= TRACEANGLE; - if (deltaangle(self->Angles.Yaw, exact) > 0) - self->Angles.Yaw = exact; - } - else if (diff > 0) - { - self->Angles.Yaw += TRACEANGLE; - if (deltaangle(self->Angles.Yaw, exact) < 0.) - self->Angles.Yaw = exact; - } - - self->VelFromAngle(); - - if (!(self->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER))) - { - // change slope - dist = self->DistanceBySpeed (dest, self->Speed); - if (dest->Height >= 56) - { - slope = (dest->Z()+40 - self->Z()) / dist; - } - else - { - slope = (dest->Z() + self->Height*(2./3) - self->Z()) / dist; - } - if (slope < self->Vel.Z) - { - self->Vel.Z -= 1 / 8.; - } - else - { - self->Vel.Z += 1 / 8.; - } - } - return 0; -} diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp index bf1379d3a..ad6afce60 100644 --- a/src/g_strife/a_strifestuff.cpp +++ b/src/g_strife/a_strifestuff.cpp @@ -24,7 +24,6 @@ #include "vm.h" // Include all the other Strife stuff here to reduce compile time -#include "a_spectral.cpp" #include "a_coin.cpp" #include "a_crusader.cpp" #include "a_entityboss.cpp" diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 3c3347ec1..41994c38e 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -105,8 +105,7 @@ void P_TouchSpecialThing (AActor *special, AActor *toucher) toucher->player->Bot->prev = toucher->player->Bot->dest; toucher->player->Bot->dest = NULL; } - - special->Touch (toucher); + special->CallTouch (toucher); } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index a52ee4976..6f0754a8f 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1440,6 +1440,25 @@ void AActor::Touch (AActor *toucher) { } +DEFINE_ACTION_FUNCTION(AActor, Touch) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(toucher, AActor); + self->Touch(toucher); + return 0; +} + +void AActor::CallTouch(AActor *toucher) +{ + IFVIRTUAL(AActor, Touch) + { + VMValue params[2] = { (DObject*)this, toucher }; + VMFrameStack stack; + stack.Call(func, params, 2, nullptr, 0, nullptr); + } + else Touch(toucher); +} + //============================================================================ // // AActor :: Grind diff --git a/src/p_user.cpp b/src/p_user.cpp index 5f2d19cb4..1033299e6 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -498,10 +498,13 @@ void player_t::SetLogText (const char *text) { LogText = text; - // Print log text to console - AddToConsole(-1, TEXTCOLOR_GOLD); - AddToConsole(-1, LogText); - AddToConsole(-1, "\n"); + if (mo->CheckLocalView(consoleplayer)) + { + // Print log text to console + AddToConsole(-1, TEXTCOLOR_GOLD); + AddToConsole(-1, LogText); + AddToConsole(-1, "\n"); + } } DEFINE_ACTION_FUNCTION(_PlayerInfo, SetLogText) diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index dd1bec839..cdcc630b5 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -268,6 +268,7 @@ class Actor : Thinker native virtual native bool Slam(Actor victim); virtual native bool UseInventory(Inventory item); virtual native bool SpecialBlastHandling (Actor source, double strength); + virtual native void Touch(Actor toucher); virtual int SpecialMissileHit (Actor victim) // for this no native version exists { @@ -617,7 +618,6 @@ class Actor : Thinker native native void A_TossGib(); native void A_SentinelBob(); native void A_SentinelRefire(); - native void A_Tracer2(); native void A_SetShadow(); native void A_ClearShadow(); native void A_GetHurt(); diff --git a/wadsrc/static/zscript/doom/revenant.txt b/wadsrc/static/zscript/doom/revenant.txt index 2fc35c60f..2fa335a2d 100644 --- a/wadsrc/static/zscript/doom/revenant.txt +++ b/wadsrc/static/zscript/doom/revenant.txt @@ -129,8 +129,6 @@ class RevenantTracerSmoke : Actor extend class Actor { - const TRACEANGLE = (16.875); - void A_SkelMissile() { if (target == null) return; @@ -166,33 +164,12 @@ extend class Actor } } - void A_Tracer() + void A_Tracer2(double traceang = 19.6875) { double dist; double slope; Actor dest; - Actor smoke; - // killough 1/18/98: this is why some missiles do not have smoke - // and some do. Also, internal demos start at random gametics, thus - // the bug in which revenants cause internal demos to go out of sync. - // - // killough 3/6/98: fix revenant internal demo bug by subtracting - // levelstarttic from gametic: - // - // [RH] level.time is always 0-based, so nothing special to do here. - - if (level.time & 3) return; - - // spawn a puff of smoke behind the rocket - SpawnPuff ("BulletPuff", pos, angle, angle, 3); - smoke = Spawn ("RevenantTracerSmoke", Vec3Offset(-Vel.X, -Vel.Y, 0.), ALLOW_REPLACE); - - smoke.Vel.Z = 1.; - smoke.tics -= random[Tracer](0, 3); - if (smoke.tics < 1) - smoke.tics = 1; - // adjust direction dest = tracer; @@ -205,13 +182,13 @@ extend class Actor if (diff < 0) { - angle -= TRACEANGLE; + angle -= traceang; if (deltaangle(angle, exact) > 0) angle = exact; } else if (diff > 0) { - angle += TRACEANGLE; + angle += traceang; if (deltaangle(angle, exact) < 0.) angle = exact; } @@ -238,5 +215,31 @@ extend class Actor Vel.Z += 1. / 8; } } + + void A_Tracer() + { + // killough 1/18/98: this is why some missiles do not have smoke + // and some do. Also, internal demos start at random gametics, thus + // the bug in which revenants cause internal demos to go out of sync. + // + // killough 3/6/98: fix revenant internal demo bug by subtracting + // levelstarttic from gametic: + // + // [RH] level.time is always 0-based, so nothing special to do here. + + if (level.time & 3) return; + + // spawn a puff of smoke behind the rocket + SpawnPuff ("BulletPuff", pos, angle, angle, 3); + Actor smoke = Spawn ("RevenantTracerSmoke", Vec3Offset(-Vel.X, -Vel.Y, 0.), ALLOW_REPLACE); + + smoke.Vel.Z = 1.; + smoke.tics -= random[Tracer](0, 3); + if (smoke.tics < 1) + smoke.tics = 1; + + // The rest of this function was identical with Strife's version, except for the angle being used. + A_Tracer2(16.875); + } } diff --git a/wadsrc/static/zscript/strife/programmer.txt b/wadsrc/static/zscript/strife/programmer.txt index dc88a790f..9ef9bdeb0 100644 --- a/wadsrc/static/zscript/strife/programmer.txt +++ b/wadsrc/static/zscript/strife/programmer.txt @@ -36,7 +36,6 @@ class Programmer : Actor native void A_ProgrammerMelee (); native void A_SpawnProgrammerBase (); native void A_ProgrammerDeath (); - native void A_SpotLightning(); States { @@ -80,6 +79,27 @@ class Programmer : Actor PRGR X -1 Bright A_ProgrammerDeath; Stop; } + + //============================================================================ + // + // A_SpotLightning + // + //============================================================================ + + void A_SpotLightning() + { + if (target == NULL) return; + + Actor spot = Spawn("SpectralLightningSpot", (target.pos.xy, target.floorz), ALLOW_REPLACE); + if (spot != NULL) + { + spot.threshold = 25; + spot.target = self; + spot.FriendPlayer = 0; + spot.tracer = target; + } + } + } diff --git a/wadsrc/static/zscript/strife/spectral.txt b/wadsrc/static/zscript/strife/spectral.txt index 9ea95ba1d..0878cff94 100644 --- a/wadsrc/static/zscript/strife/spectral.txt +++ b/wadsrc/static/zscript/strife/spectral.txt @@ -2,7 +2,7 @@ // base for all spectral monsters which hurt when being touched-------------- -class SpectralMonster : Actor native +class SpectralMonster : Actor { Default { @@ -11,6 +11,12 @@ class SpectralMonster : Actor native +SPECTRAL +NOICEDEATH } + + override void Touch (Actor toucher) + { + toucher.DamageMobj (self, self, 5, 'Melee'); + } + //============================================================================ @@ -71,7 +77,26 @@ class SpectralMonster : Actor native Angle -= 90.; } - native void A_SpotLightning (); + //============================================================================ + // + // A_SpotLightning + // + //============================================================================ + + void A_SpotLightning() + { + if (target == null) return; + + Actor spot = Spawn("SpectralLightningSpot", (target.pos.xy, target.floorz), ALLOW_REPLACE); + if (spot != null) + { + spot.threshold = 25; + spot.target = self; + spot.FriendPlayer = 0; + spot.tracer = target; + } + } + } @@ -180,7 +205,6 @@ class SpectralLightningH1 : SpectralLightningBase +SPECTRAL } - native void A_SpectralLightningTail (); States { @@ -189,6 +213,14 @@ class SpectralLightningH1 : SpectralLightningBase ZAP6 BC 4 Bright A_SpectralLightningTail; Loop; } + + void A_SpectralLightningTail () + { + Actor foo = Spawn("SpectralLightningHTail", Vec3Offset(-Vel.X, -Vel.Y, 0.), ALLOW_REPLACE); + + foo.Angle = Angle; + foo.FriendPlayer = FriendPlayer; + } } @@ -245,8 +277,6 @@ class SpectralLightningBigBall1 : SpectralLightningDeath2 +SPECTRAL } - native void A_SpectralBigBallLightning (); - States { Spawn: @@ -254,6 +284,21 @@ class SpectralLightningBigBall1 : SpectralLightningDeath2 ZAP7 CDE 6 Bright A_SpectralBigBallLightning; Loop; } + + void A_SpectralBigBallLightning () + { + Class cls = "SpectralLightningH3"; + if (cls) + { + angle += 90.; + SpawnSubMissile (cls, target); + angle += 180.; + SpawnSubMissile (cls, target); + angle -= 270.; + SpawnSubMissile (cls, target); + } + } + } @@ -315,8 +360,6 @@ class SpectralLightningSpot : SpectralLightningDeath1 Alpha 0.6; } - native void A_SpectralLightning (); - States { Spawn: @@ -325,6 +368,35 @@ class SpectralLightningSpot : SpectralLightningDeath1 ZAP5 CD 4 Bright A_Countdown; Loop; } + + void A_SpectralLightning () + { + if (threshold != 0) + --threshold; + + Vel.X += random2[Zap5](3); + Vel.Y += random2[Zap5](3); + + double xo = random2[Zap5](3) * 50.; + double yo = random2[Zap5](3) * 50.; + + class cls; + if (threshold > 25) cls = "SpectralLightningV2"; + else cls = "SpectralLightningV1"; + + Actor flash = Spawn (cls, Vec2OffsetZ(xo, yo, ONCEILINGZ), ALLOW_REPLACE); + + flash.target = target; + flash.Vel.Z = -18; + flash.FriendPlayer = FriendPlayer; + + flash = Spawn("SpectralLightningV2", (pos.xy, ONCEILINGZ), ALLOW_REPLACE); + + flash.target = target; + flash.Vel.Z = -18; + flash.FriendPlayer = FriendPlayer; + } + } // Sigil Lightning (Big Vertical #1) ---------------------------------------- @@ -357,7 +429,3 @@ class SpectralLightningBigV2 : SpectralLightningBigV1 Damage 60; } } - - - - From c9a4087c18fe35d82a2d6891c780590da80d6b28 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 28 Nov 2016 13:11:27 +0100 Subject: [PATCH 149/185] - scriptified a_entityboss.cpp. --- src/CMakeLists.txt | 1 - src/g_strife/a_entityboss.cpp | 114 -------------------- src/g_strife/a_strifestuff.cpp | 1 - wadsrc/static/zscript/strife/entityboss.txt | 101 +++++++++++++++-- 4 files changed, 94 insertions(+), 123 deletions(-) delete mode 100644 src/g_strife/a_entityboss.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 21637c59b..211411f20 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -863,7 +863,6 @@ set( NOT_COMPILED_SOURCE_FILES g_hexen/a_spike.cpp g_strife/a_coin.cpp g_strife/a_crusader.cpp - g_strife/a_entityboss.cpp g_strife/a_inquisitor.cpp g_strife/a_loremaster.cpp g_strife/a_oracle.cpp diff --git a/src/g_strife/a_entityboss.cpp b/src/g_strife/a_entityboss.cpp deleted file mode 100644 index 7a6b6f027..000000000 --- a/src/g_strife/a_entityboss.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* -#include "actor.h" -#include "m_random.h" -#include "a_action.h" -#include "p_local.h" -#include "p_enemy.h" -#include "s_sound.h" -#include "a_strifeglobal.h" -#include "vm.h" -#include "g_level.h" -*/ - -static FRandom pr_entity ("Entity"); - -DEFINE_ACTION_FUNCTION(AActor, A_SubEntityDeath) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (CheckBossDeath (self)) - { - G_ExitLevel (0, false); - } - return 0; -} - -void A_SpectralMissile (AActor *self, const char *missilename) -{ - if (self->target != NULL) - { - AActor *missile = P_SpawnMissileXYZ (self->PosPlusZ(32.), self, self->target, PClass::FindActor(missilename), false); - if (missile != NULL) - { - missile->tracer = self->target; - P_CheckMissileSpawn(missile, self->radius); - } - } -} - -DECLARE_ACTION(A_Spectre3Attack) - - -DEFINE_ACTION_FUNCTION(AActor, A_EntityAttack) -{ - PARAM_SELF_PROLOGUE(AActor); - - // 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) - { - case 0: - //CALL_ACTION(A_SpotLightning, self); - break; - - case 2: - A_SpectralMissile (self, "SpectralLightningH3"); - break; - - case 3: - //CALL_ACTION(A_Spectre3Attack, self); - break; - - case 4: - A_SpectralMissile (self, "SpectralLightningBigV2"); - break; - - case 1: - case 5: - A_SpectralMissile (self, "SpectralLightningBigBall2"); - break; - } - return 0; -} - - -DEFINE_ACTION_FUNCTION(AActor, A_SpawnEntity) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *entity = Spawn("EntityBoss", self->PosPlusZ(70.), ALLOW_REPLACE); - if (entity != NULL) - { - entity->Angles.Yaw = self->Angles.Yaw; - entity->CopyFriendliness(self, true); - entity->Vel.Z = 5; - entity->tracer = self; - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_EntityDeath) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *second; - double secondRadius = GetDefaultByName("EntitySecond")->radius * 2; - - static const double turns[3] = { 0, 90, -90 }; - const double velmul[3] = { 4.8828125f, secondRadius*4, secondRadius*4 }; - - AActor *spot = self->tracer; - if (spot == NULL) spot = self; - - for (int i = 0; i < 3; i++) - { - DAngle an = self->Angles.Yaw + turns[i]; - DVector3 pos = spot->Vec3Angle(secondRadius, an, self->tracer ? 70. : 0.); - - second = Spawn("EntitySecond", pos, ALLOW_REPLACE); - second->CopyFriendliness(self, true); - A_FaceTarget(second); - second->VelFromAngle(velmul[i], an); - } - return 0; -} diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp index ad6afce60..df89e614a 100644 --- a/src/g_strife/a_strifestuff.cpp +++ b/src/g_strife/a_strifestuff.cpp @@ -26,7 +26,6 @@ // Include all the other Strife stuff here to reduce compile time #include "a_coin.cpp" #include "a_crusader.cpp" -#include "a_entityboss.cpp" #include "a_inquisitor.cpp" #include "a_loremaster.cpp" //#include "a_macil.cpp" diff --git a/wadsrc/static/zscript/strife/entityboss.txt b/wadsrc/static/zscript/strife/entityboss.txt index 8ccdbbd02..daf1a78ee 100644 --- a/wadsrc/static/zscript/strife/entityboss.txt +++ b/wadsrc/static/zscript/strife/entityboss.txt @@ -32,7 +32,6 @@ class EntityPod : Actor SeeSound "misc/gibbed"; } - native void A_SpawnEntity (); States { @@ -47,10 +46,23 @@ class EntityPod : Actor PODD E -1; Stop; } + + void A_SpawnEntity () + { + Actor entity = Spawn("EntityBoss", pos + (0,0,70), ALLOW_REPLACE); + if (entity != null) + { + entity.Angle = self.Angle; + entity.CopyFriendliness(self, true); + entity.Vel.Z = 5; + entity.tracer = self; + } + } + } -// Entity Boss -------------------------------------------------------------- +// -------------------------------------------------------------- class EntityBoss : SpectralMonster { @@ -87,9 +99,6 @@ class EntityBoss : SpectralMonster Obituary "$OB_ENTITY"; } - native void A_EntityAttack(); - native void A_EntityDeath(); - States { Spawn: @@ -129,6 +138,76 @@ class EntityBoss : SpectralMonster MNAL Q 6 Bright A_EntityDeath; Stop; } + + // -------------------------------------------------------------- + + private void A_SpectralMissile (class missilename) + { + if (target != null) + { + Actor missile = SpawnMissileXYZ (Pos + (0,0,32), target, missilename, false); + if (missile != null) + { + missile.tracer = target; + missile.CheckMissileSpawn(radius); + } + } + } + + // -------------------------------------------------------------- + + void A_EntityAttack() + { + // 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 (random[Entity]() % 5) + { + case 0: + A_SpotLightning(); + break; + + case 2: + A_SpectralMissile ("SpectralLightningH3"); + break; + + case 3: + A_Spectre3Attack(); + break; + + case 4: + A_SpectralMissile ("SpectralLightningBigV2"); + break; + + default: + A_SpectralMissile ("SpectralLightningBigBall2"); + break; + } + } + + // -------------------------------------------------------------- + + void A_EntityDeath() + { + Actor second; + double secondRadius = GetDefaultByType("EntitySecond").radius * 2; + + static const double turns[] = { 0, 90, -90 }; + + Actor spot = tracer; + if (spot == null) spot = self; + + for (int i = 0; i < 3; i++) + { + double an = Angle + turns[i]; + Vector3 pos = spot.Vec3Angle(secondRadius, an, tracer ? 70. : 0.); + + second = Spawn("EntitySecond", pos, ALLOW_REPLACE); + second.CopyFriendliness(self, true); + second.A_FaceTarget(); + second.VelFromAngle(i == 0? 4.8828125 : secondRadius * 4., an); + } + } + } // Second Entity Boss ------------------------------------------------------- @@ -167,8 +246,6 @@ class EntitySecond : SpectralMonster Obituary "$OB_ENTITY"; } - native void A_SubEntityDeath (); - States { Spawn: @@ -202,6 +279,16 @@ class EntitySecond : SpectralMonster MDTH O 3 Bright A_SubEntityDeath; Stop; } + + // -------------------------------------------------------------- + + void A_SubEntityDeath () + { + if (CheckBossDeath ()) + { + Exit_Normal(0); + } + } } From 8551a4f6e123596812feca20c4622e9b9c22eda8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 28 Nov 2016 14:39:25 +0100 Subject: [PATCH 150/185] - scriptified the Sigil. This isn't fully tested yet. --- src/dobjtype.cpp | 10 + src/dobjtype.h | 1 + src/g_shared/a_pickups.cpp | 22 ++ src/g_shared/a_pickups.h | 1 + src/g_shared/sbarinfo_commands.cpp | 2 +- src/g_strife/a_strifeglobal.h | 14 - src/g_strife/a_strifeweapons.cpp | 432 --------------------- src/g_strife/strife_sbar.cpp | 2 +- src/m_cheat.cpp | 30 +- src/namedef.h | 5 + src/p_acs.cpp | 30 +- src/p_conversation.cpp | 2 +- src/p_enemy.cpp | 2 +- src/p_pspr.cpp | 9 + src/scripting/zscript/zcc_compile.cpp | 8 +- src/scripting/zscript/zcc_compile.h | 2 +- wadsrc/static/zscript/shared/inventory.txt | 1 + wadsrc/static/zscript/shared/player.txt | 3 + wadsrc/static/zscript/strife/sigil.txt | 368 +++++++++++++++++- 19 files changed, 450 insertions(+), 494 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 88c31d007..62a6a2b2d 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -3545,6 +3545,16 @@ const PClass *PClass::NativeClass() const return cls; } +VMFunction *PClass::FindFunction(FName clsname, FName funcname) +{ + auto cls = PClass::FindActor(clsname); + if (!cls) return nullptr; + auto func = dyn_cast(cls->Symbols.FindSymbol(funcname, true)); + if (!func) return nullptr; + return func->Variants[0].Implementation; +} + + /* FTypeTable **************************************************************/ //========================================================================== diff --git a/src/dobjtype.h b/src/dobjtype.h index b952a3c23..89d309156 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -859,6 +859,7 @@ public: 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); + static VMFunction *FindFunction(FName cls, FName func); PClass *FindClassTentative(FName name); static TArray AllClasses; diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index 2172d2a0c..cb5f4dd12 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -589,6 +589,28 @@ bool AInventory::SpecialDropAction (AActor *dropper) return false; } +DEFINE_ACTION_FUNCTION(AInventory, SpecialDropAction) +{ + PARAM_SELF_PROLOGUE(AInventory); + PARAM_OBJECT(dropper, AActor); + ACTION_RETURN_BOOL(self->SpecialDropAction(dropper)); +} + +bool AInventory::CallSpecialDropAction(AActor *dropper) +{ + IFVIRTUAL(AInventory, SpecialDropAction) + { + VMValue params[2] = { (DObject*)this, (DObject*)dropper }; + VMReturn ret; + VMFrameStack stack; + int retval; + ret.IntAt(&retval); + stack.Call(func, params, 2, &ret, 1, nullptr); + return !!retval; + } + return SpecialDropAction(dropper); +} + //=========================================================================== // // AInventory :: ShouldRespawn diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index 429b2ab90..e15f0724c 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -168,6 +168,7 @@ public: bool CallTryPickup (AActor *toucher, AActor **toucher_return = NULL); virtual void DoPickupSpecial (AActor *toucher); virtual bool SpecialDropAction (AActor *dropper); + bool CallSpecialDropAction(AActor *dropper); virtual bool DrawPowerup (int x, int y); virtual void DoEffect (); virtual bool Grind(bool items); diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index b3aecb0b5..f78c61040 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -268,7 +268,7 @@ class CommandDrawImage : public SBarInfoCommandFlowControl } else if(type == SIGIL) { - AInventory *item = statusBar->CPlayer->mo->FindInventory(); + AInventory *item = statusBar->CPlayer->mo->FindInventory(PClass::FindActor(NAME_Sigil)); if (item != NULL) texture = TexMan(item->Icon); } diff --git a/src/g_strife/a_strifeglobal.h b/src/g_strife/a_strifeglobal.h index 9e7f9148e..c07bce63c 100644 --- a/src/g_strife/a_strifeglobal.h +++ b/src/g_strife/a_strifeglobal.h @@ -49,20 +49,6 @@ public: bool TryPickup (AActor *&toucher); }; -class ASigil : public AWeapon -{ - DECLARE_CLASS (ASigil, AWeapon) -public: - bool HandlePickup (AInventory *item); - AInventory *CreateCopy (AActor *other); - - void Serialize(FSerializer &arc); - bool SpecialDropAction (AActor *dropper); - static int GiveSigilPiece (AActor *daPlayer); - void BeginPlay(); - - int NumPieces, DownPieces; -}; extern PClassActor *QuestItemClasses[31]; diff --git a/src/g_strife/a_strifeweapons.cpp b/src/g_strife/a_strifeweapons.cpp index 0630089d6..34862f943 100644 --- a/src/g_strife/a_strifeweapons.cpp +++ b/src/g_strife/a_strifeweapons.cpp @@ -698,435 +698,3 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireGrenade) return 0; } -// The Almighty Sigil! ------------------------------------------------------ - -IMPLEMENT_CLASS(ASigil, false, false) - -//============================================================================ -// -// ASigil :: Serialize -// -//============================================================================ - -void ASigil::BeginPlay() -{ - NumPieces = health; -} - -//============================================================================ -// -// ASigil :: Serialize -// -//============================================================================ - -void ASigil::Serialize(FSerializer &arc) -{ - Super::Serialize (arc); - arc("numpieces", NumPieces) - ("downpieces", DownPieces); -} - -//============================================================================ -// -// ASigil :: HandlePickup -// -//============================================================================ - -bool ASigil::HandlePickup (AInventory *item) -{ - if (item->IsKindOf (RUNTIME_CLASS(ASigil))) - { - int otherPieces = static_cast(item)->NumPieces; - if (otherPieces > NumPieces) - { - item->ItemFlags |= IF_PICKUPGOOD; - Icon = item->Icon; - // If the player is holding the Sigil right now, drop it and bring - // it back with the new piece(s) in view. - if (Owner->player != NULL && Owner->player->ReadyWeapon == this) - { - DownPieces = NumPieces; - Owner->player->PendingWeapon = this; - } - NumPieces = otherPieces; - } - return true; - } - return false; -} - -//============================================================================ -// -// ASigil :: CreateCopy -// -//============================================================================ - -AInventory *ASigil::CreateCopy (AActor *other) -{ - ASigil *copy = Spawn (); - copy->Amount = Amount; - copy->MaxAmount = MaxAmount; - copy->NumPieces = NumPieces; - copy->Icon = Icon; - GoAwayAndDie (); - return copy; -} - -//============================================================================ -// -// A_SelectPiece -// -// Decide which sprite frame this Sigil should use as an item, based on how -// many pieces it represents. -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SelectPiece) -{ - PARAM_ACTION_PROLOGUE(AActor); - - int pieces = MIN (static_cast(self)->NumPieces, 5); - - if (pieces > 1) - { - self->SetState (self->FindState("Spawn")+pieces); - } - return 0; -} - -//============================================================================ -// -// A_SelectSigilView -// -// Decide which first-person frame this Sigil should show, based on how many -// pieces it represents. Strife did this by selecting a flash that looked like -// the Sigil whenever you switched to it and at the end of an attack. I have -// chosen to make the weapon sprite choose the correct frame and let the flash -// be a regular flash. It means I need to use more states, but I think it's -// worth it. -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SelectSigilView) -{ - PARAM_ACTION_PROLOGUE(AActor); - - DPSprite *pspr; - int pieces; - - if (self->player == nullptr) - { - return 0; - } - pieces = static_cast(self->player->ReadyWeapon)->NumPieces; - pspr = self->player->GetPSprite(PSP_WEAPON); - pspr->SetState(pspr->GetState() + pieces); - return 0; -} - -//============================================================================ -// -// A_SelectSigilDown -// -// Same as A_SelectSigilView, except it uses DownPieces. This is so that when -// you pick up a Sigil, the old one will drop and *then* change to the new -// one. -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SelectSigilDown) -{ - PARAM_ACTION_PROLOGUE(AActor); - - DPSprite *pspr; - int pieces; - - if (self->player == nullptr) - { - return 0; - } - pieces = static_cast(self->player->ReadyWeapon)->DownPieces; - static_cast(self->player->ReadyWeapon)->DownPieces = 0; - if (pieces == 0) - { - pieces = static_cast(self->player->ReadyWeapon)->NumPieces; - } - pspr = self->player->GetPSprite(PSP_WEAPON); - pspr->SetState(pspr->GetState() + pieces); - return 0; -} - -//============================================================================ -// -// A_SelectSigilAttack -// -// Same as A_SelectSigilView, but used just before attacking. -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SelectSigilAttack) -{ - PARAM_ACTION_PROLOGUE(AActor); - - DPSprite *pspr; - int pieces; - - if (self->player == nullptr) - { - return 0; - } - pieces = static_cast(self->player->ReadyWeapon)->NumPieces; - pspr = self->player->GetPSprite(PSP_WEAPON); - pspr->SetState(pspr->GetState() + 4*pieces - 3); - return 0; -} - -//============================================================================ -// -// A_SigilCharge -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SigilCharge) -{ - PARAM_ACTION_PROLOGUE(AActor); - - S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM); - if (self->player != NULL) - { - self->player->extralight = 2; - } - return 0; -} - -//============================================================================ -// -// A_FireSigil1 -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FireSigil1) -{ - PARAM_ACTION_PROLOGUE(AActor); - - AActor *spot; - player_t *player = self->player; - FTranslatedLineTarget t; - - if (player == NULL || player->ReadyWeapon == NULL) - return 0; - - P_DamageMobj (self, self, NULL, 1*4, 0, DMG_NO_ARMOR); - S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM); - - P_BulletSlope (self, &t, ALF_PORTALRESTRICT); - if (t.linetarget != NULL) - { - spot = Spawn("SpectralLightningSpot", t.linetarget->PosAtZ(t.linetarget->floorz), ALLOW_REPLACE); - if (spot != NULL) - { - spot->tracer = t.linetarget; - } - } - else - { - spot = Spawn("SpectralLightningSpot", self->Pos(), ALLOW_REPLACE); - if (spot != NULL) - { - spot->VelFromAngle(28., self->Angles.Yaw); - } - } - if (spot != NULL) - { - spot->SetFriendPlayer(player); - spot->target = self; - } - return 0; -} - -//============================================================================ -// -// A_FireSigil2 -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FireSigil2) -{ - PARAM_ACTION_PROLOGUE(AActor); - - player_t *player = self->player; - - if (player == NULL || player->ReadyWeapon == NULL) - 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::FindActor("SpectralLightningH1")); - return 0; -} - -//============================================================================ -// -// A_FireSigil3 -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FireSigil3) -{ - PARAM_ACTION_PROLOGUE(AActor); - - AActor *spot; - player_t *player = self->player; - int i; - - if (player == NULL || player->ReadyWeapon == NULL) - return 0; - - P_DamageMobj (self, self, NULL, 3*4, 0, DMG_NO_ARMOR); - S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM); - - self->Angles.Yaw -= 90.; - for (i = 0; i < 20; ++i) - { - self->Angles.Yaw += 9.; - spot = P_SpawnSubMissile (self, PClass::FindActor("SpectralLightningBall1"), self); - if (spot != NULL) - { - spot->SetZ(self->Z() + 32); - } - } - self->Angles.Yaw -= 90.; - return 0; -} - -//============================================================================ -// -// A_FireSigil4 -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FireSigil4) -{ - PARAM_ACTION_PROLOGUE(AActor); - - AActor *spot; - player_t *player = self->player; - FTranslatedLineTarget t; - - if (player == NULL || player->ReadyWeapon == NULL) - return 0; - - P_DamageMobj (self, self, NULL, 4*4, 0, DMG_NO_ARMOR); - S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM); - - P_BulletSlope (self, &t, ALF_PORTALRESTRICT); - if (t.linetarget != NULL) - { - spot = P_SpawnPlayerMissile (self, 0,0,0, PClass::FindActor("SpectralLightningBigV1"), self->Angles.Yaw, &t, NULL, false, false, ALF_PORTALRESTRICT); - if (spot != NULL) - { - spot->tracer = t.linetarget; - } - } - else - { - spot = P_SpawnPlayerMissile (self, PClass::FindActor("SpectralLightningBigV1")); - if (spot != NULL) - { - spot->VelFromAngle(spot->Speed, self->Angles.Yaw); - } - } - return 0; -} - -//============================================================================ -// -// A_FireSigil5 -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FireSigil5) -{ - PARAM_ACTION_PROLOGUE(AActor); - - player_t *player = self->player; - - if (player == NULL || player->ReadyWeapon == NULL) - 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::FindActor("SpectralLightningBigBall1")); - return 0; -} - -//============================================================================ -// -// ASigil :: SpecialDropAction -// -// Monsters don't drop Sigil pieces. The Sigil pieces grab hold of the person -// who killed the dropper and automatically enter their inventory. That's the -// way it works if you believe Macil, anyway... -// -//============================================================================ - -bool ASigil::SpecialDropAction (AActor *dropper) -{ - // Give a Sigil piece to every player in the game - for (int i = 0; i < MAXPLAYERS; ++i) - { - if (playeringame[i] && players[i].mo != NULL) - { - GiveSigilPiece (players[i].mo); - Destroy (); - } - } - return true; -} - -//============================================================================ -// -// ASigil :: GiveSigilPiece -// -// Gives the actor another Sigil piece, up to 5. Returns the number of Sigil -// pieces the actor previously held. -// -//============================================================================ - -int ASigil::GiveSigilPiece (AActor *receiver) -{ - ASigil *sigil; - - sigil = receiver->FindInventory (); - if (sigil == NULL) - { - sigil = static_cast(Spawn("Sigil1")); - if (!sigil->CallTryPickup (receiver)) - { - sigil->Destroy (); - } - return 0; - } - else if (sigil->NumPieces < 5) - { - ++sigil->NumPieces; - static const char* sigils[5] = - { - "Sigil1", "Sigil2", "Sigil3", "Sigil4", "Sigil5" - }; - sigil->Icon = ((AInventory*)GetDefaultByName (sigils[MAX(0,sigil->NumPieces-1)]))->Icon; - // If the player has the Sigil out, drop it and bring it back up. - if (sigil->Owner->player != NULL && sigil->Owner->player->ReadyWeapon == sigil) - { - sigil->Owner->player->PendingWeapon = sigil; - sigil->DownPieces = sigil->NumPieces - 1; - } - return sigil->NumPieces - 1; - } - else - { - return 5; - } -} diff --git a/src/g_strife/strife_sbar.cpp b/src/g_strife/strife_sbar.cpp index 39f92d076..79a363d1c 100644 --- a/src/g_strife/strife_sbar.cpp +++ b/src/g_strife/strife_sbar.cpp @@ -439,7 +439,7 @@ private: } // Sigil - item = CPlayer->mo->FindInventory(); + item = CPlayer->mo->FindInventory(PClass::FindActor(NAME_Sigil)); if (item != NULL) { DrawImage (TexMan(item->Icon), 253, 7); diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index 7ba40f957..33a90c85f 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -483,18 +483,28 @@ void cht_DoCheat (player_t *player, int cheat) case CHT_LEGO: if (player->mo != NULL && player->health >= 0) { - int oldpieces = ASigil::GiveSigilPiece (player->mo); - item = player->mo->FindInventory (RUNTIME_CLASS(ASigil)); - - if (item != NULL) + static VMFunction *gsp = nullptr; + if (gsp == nullptr) gsp = PClass::FindFunction(NAME_Sigil, NAME_GiveSigilPiece); + if (gsp) { - if (oldpieces == 5) + VMValue params[1] = { player->mo }; + VMFrameStack stack; + VMReturn ret; + int oldpieces = 1; + ret.IntAt(&oldpieces); + stack.Call(gsp, params, 1, &ret, 1, nullptr); + item = player->mo->FindInventory(PClass::FindActor(NAME_Sigil)); + + if (item != NULL) { - item->Destroy (); - } - else - { - player->PendingWeapon = static_cast (item); + if (oldpieces == 5) + { + item->Destroy(); + } + else + { + player->PendingWeapon = static_cast (item); + } } } } diff --git a/src/namedef.h b/src/namedef.h index 3a4a1c180..9cb4e8d23 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -120,6 +120,11 @@ xx(ArtiPoisonBag3) // Strife quests xx(QuestItem) +xx(Sigil) +xx(ScriptedMarine) +xx(GiveSigilPiece) +xx(SetWeapon) +xx(SetSprite) // Armor xx(BasicArmor) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index a5b8b977d..97f660246 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -6112,29 +6112,25 @@ static bool CharArrayParms(int &capacity, int &offset, int &a, int *Stack, int & static void SetMarineWeapon(AActor *marine, int weapon) { static VMFunction *smw = nullptr; - if (smw == nullptr) + if (smw == nullptr) smw = PClass::FindFunction(NAME_ScriptedMarine, NAME_SetWeapon); + if (smw) { - auto cls = PClass::FindActor("ScriptedMarine"); - auto func = dyn_cast(cls->Symbols.FindSymbol("SetWeapon", true)); - smw = func->Variants[0].Implementation; + VMValue params[2] = { marine, weapon }; + VMFrameStack stack; + stack.Call(smw, params, 2, nullptr, 0, nullptr); } - VMValue params[2] = { marine, weapon }; - VMFrameStack stack; - stack.Call(smw, params, 2, nullptr, 0, nullptr); } static void SetMarineSprite(AActor *marine, PClassActor *source) { static VMFunction *sms = nullptr; - if (sms == nullptr) + if (sms == nullptr) sms = PClass::FindFunction(NAME_ScriptedMarine, NAME_SetSprite); + if (sms) { - auto cls = PClass::FindActor("ScriptedMarine"); - auto func = dyn_cast(cls->Symbols.FindSymbol("SetSprite", true)); - sms = func->Variants[0].Implementation; + VMValue params[2] = { marine, source }; + VMFrameStack stack; + stack.Call(sms, params, 2, nullptr, 0, nullptr); } - VMValue params[2] = { marine, source }; - VMFrameStack stack; - stack.Call(sms, params, 2, nullptr, 0, nullptr); } int DLevelScript::RunScript () @@ -8577,15 +8573,15 @@ scriptwait: case PCD_GETSIGILPIECES: { - ASigil *sigil; + AInventory *sigil; - if (activator == NULL || (sigil = activator->FindInventory()) == NULL) + if (activator == NULL || (sigil = activator->FindInventory(PClass::FindActor(NAME_Sigil))) == NULL) { PushToStack (0); } else { - PushToStack (sigil->NumPieces); + PushToStack (sigil->health); } } break; diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 404b2f2bc..95aabe44b 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -646,7 +646,7 @@ static void TakeStrifeItem (player_t *player, PClassActor *itemtype, int amount) return; // Don't take the sigil. - if (itemtype == RUNTIME_CLASS(ASigil)) + if (itemtype->GetClass()->TypeName == NAME_Sigil) return; player->mo->TakeInventory(itemtype, amount); diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index fcd8f9cee..3712ac86c 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -3209,7 +3209,7 @@ AInventory *P_DropItem (AActor *source, PClassActor *type, int dropamount, int c AInventory *inv = static_cast(mo); ModifyDropAmount(inv, dropamount); inv->ItemFlags |= IF_TOSSED; - if (inv->SpecialDropAction (source)) + if (inv->CallSpecialDropAction (source)) { // The special action indicates that the item should not spawn inv->Destroy(); diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index e2ea3084d..610ade35a 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -439,6 +439,15 @@ void DPSprite::SetState(FState *newstate, bool pending) return; } +DEFINE_ACTION_FUNCTION(DPSprite, SetState) +{ + PARAM_SELF_PROLOGUE(DPSprite); + PARAM_POINTER(state, FState); + PARAM_BOOL_DEF(pending); + self->SetState(state, pending); + return 0; +} + //--------------------------------------------------------------------------- // // PROC P_BringUpWeapon diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 56f991287..c454ced83 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2408,7 +2408,7 @@ static bool CheckRandom(ZCC_Expression *duration) // Sets up the action function call // //========================================================================== -FxExpression *ZCCCompiler::SetupActionFunction(PClass *cls, ZCC_TreeNode *af) +FxExpression *ZCCCompiler::SetupActionFunction(PClass *cls, ZCC_TreeNode *af, int StateFlags) { // We have 3 cases to consider here: // 1. A function without parameters. This can be called directly @@ -2436,7 +2436,9 @@ FxExpression *ZCCCompiler::SetupActionFunction(PClass *cls, ZCC_TreeNode *af) // We can use this function directly without wrapping it in a caller. auto selfclass = dyn_cast(afd->Variants[0].SelfClass); assert(selfclass != nullptr); // non classes are not supposed to get here. - if ((afd->Variants[0].Flags & VARF_Action) || !cls->IsDescendantOf(RUNTIME_CLASS(AStateProvider)) || !selfclass->IsDescendantOf(RUNTIME_CLASS(AStateProvider))) + + int comboflags = afd->Variants[0].UseFlags & StateFlags; + if (comboflags == StateFlags) // the function must satisfy all the flags the state requires { return new FxVMFunctionCall(new FxSelf(*af), afd, argumentlist, *af, false); } @@ -2627,7 +2629,7 @@ void ZCCCompiler::CompileStates() if (sl->Action != nullptr) { - auto code = SetupActionFunction(static_cast(c->Type()), sl->Action); + auto code = SetupActionFunction(static_cast(c->Type()), sl->Action, state.UseFlags); if (code != nullptr) { auto funcsym = CreateAnonymousFunction(c->Type(), nullptr, state.UseFlags); diff --git a/src/scripting/zscript/zcc_compile.h b/src/scripting/zscript/zcc_compile.h index 9599b4b96..8b3a9f5f1 100644 --- a/src/scripting/zscript/zcc_compile.h +++ b/src/scripting/zscript/zcc_compile.h @@ -108,7 +108,7 @@ private: void InitFunctions(); void CompileStates(); - FxExpression *SetupActionFunction(PClass *cls, ZCC_TreeNode *sl); + FxExpression *SetupActionFunction(PClass *cls, ZCC_TreeNode *sl, int stateflags); bool SimplifyingConstant; TArray Constants; diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index 25c94cb87..1bc695339 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -29,6 +29,7 @@ class Inventory : Actor native virtual native color GetBlend (); virtual native bool HandlePickup(Inventory item); virtual native Inventory CreateCopy(Actor other); + virtual native bool SpecialDropAction (Actor dropper); native void GoAwayAndDie(); diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index bcbc7db61..6d1b8abfc 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -133,6 +133,9 @@ class PSprite : Object native native bool bPowDouble; native bool bCVarFast; native bool bFlip; + + native void SetState(State newstate, bool pending = false); + } struct PlayerInfo native // this is what internally is known as player_t diff --git a/wadsrc/static/zscript/strife/sigil.txt b/wadsrc/static/zscript/strife/sigil.txt index d8b1f80f8..a9f802009 100644 --- a/wadsrc/static/zscript/strife/sigil.txt +++ b/wadsrc/static/zscript/strife/sigil.txt @@ -1,8 +1,11 @@ // The Almighty Sigil! ------------------------------------------------------ -class Sigil : Weapon native +class Sigil : Weapon { + // NUmPieces gets stored in 'health', so that it can be quickly accessed by ACS's GetSigilPieces function. + int downpieces; + Default { Weapon.Kickback 100; @@ -16,18 +19,7 @@ class Sigil : Weapon native Inventory.PickupMessage "$TXT_SIGIL"; } - action native void A_SelectPiece (); - action native void A_SelectSigilView (); - action native void A_SelectSigilDown (); - action native void A_SelectSigilAttack (); - action native void A_SigilCharge (); - action native void A_FireSigil1 (); - action native void A_FireSigil2 (); - action native void A_FireSigil3 (); - action native void A_FireSigil4 (); - action native void A_FireSigil5 (); - - States + States(Actor) { Spawn: SIGL A 1; @@ -41,6 +33,9 @@ class Sigil : Weapon native Stop; SIGL E -1; Stop; + } + States(Weapon) + { Ready: SIGH A 0 Bright A_SelectSigilView; Wait; @@ -120,6 +115,353 @@ class Sigil : Weapon native SIGF C 0 Bright A_Light0; Stop; } + + + //============================================================================ + // + // ASigil :: HandlePickup + // + //============================================================================ + + override bool HandlePickup (Inventory item) + { + if (item is "Sigil") + { + int otherPieces = item.health; + if (otherPieces > health) + { + item.bPickupGood = true; + Icon = item.Icon; + // If the player is holding the Sigil right now, drop it and bring + // it back with the new piece(s) in view. + if (Owner.player != null && Owner.player.ReadyWeapon == self) + { + DownPieces = health; + Owner.player.PendingWeapon = self; + } + health = otherPieces; + } + return true; + } + return false; + } + + //============================================================================ + // + // ASigil :: CreateCopy + // + //============================================================================ + + override Inventory CreateCopy (Actor other) + { + Sigil copy = Sigil(Spawn("Sigil")); + copy.Amount = Amount; + copy.MaxAmount = MaxAmount; + copy.health = health; + copy.Icon = Icon; + GoAwayAndDie (); + return copy; + } + + //============================================================================ + // + // A_SelectPiece + // + // Decide which sprite frame self Sigil should use as an item, based on how + // many pieces it represents. + // + //============================================================================ + + void A_SelectPiece () + { + int pieces = min (health, 5); + + if (pieces > 1) + { + SetState (FindState("Spawn") + pieces); + } + } + + //============================================================================ + // + // A_SelectSigilView + // + // Decide which first-person frame self Sigil should show, based on how many + // pieces it represents. Strife did self by selecting a flash that looked like + // the Sigil whenever you switched to it and at the end of an attack. I have + // chosen to make the weapon sprite choose the correct frame and let the flash + // be a regular flash. It means I need to use more states, but I think it's + // worth it. + // + //============================================================================ + + action void A_SelectSigilView () + { + if (player == null) + { + return; + } + PSprite pspr = player.GetPSprite(PSP_WEAPON); + pspr.SetState(pspr.CurState + invoker.health); + } + + //============================================================================ + // + // A_SelectSigilDown + // + // Same as A_SelectSigilView, except it uses DownPieces. self is so that when + // you pick up a Sigil, the old one will drop and *then* change to the new + // one. + // + //============================================================================ + + action void A_SelectSigilDown () + { + if (player == null) + { + return; + } + PSprite pspr = player.GetPSprite(PSP_WEAPON); + int pieces = invoker.downpieces; + if (pieces < 1 || pieces > 5) pieces = invoker.health; + pspr.SetState(pspr.CurState + pieces); + } + + //============================================================================ + // + // A_SelectSigilAttack + // + // Same as A_SelectSigilView, but used just before attacking. + // + //============================================================================ + + action void A_SelectSigilAttack () + { + if (player == null) + { + return; + } + PSprite pspr = player.GetPSprite(PSP_WEAPON); + pspr.SetState(pspr.CurState + (4 * invoker.health - 3)); + } + + //============================================================================ + // + // A_SigilCharge + // + //============================================================================ + + action void A_SigilCharge () + { + A_PlaySound ("weapons/sigilcharge", CHAN_WEAPON); + if (player != null) + { + player.extralight = 2; + } + } + + //============================================================================ + // + // A_FireSigil1 + // + //============================================================================ + + action void A_FireSigil1 () + { + Actor spot; + FTranslatedLineTarget t; + + if (player == null || player.ReadyWeapon == null) + return; + + DamageMobj (self, null, 1*4, 'Sigil', DMG_NO_ARMOR); + A_PlaySound ("weapons/sigilcharge", CHAN_WEAPON); + + BulletSlope (t, ALF_PORTALRESTRICT); + if (t.linetarget != null) + { + spot = Spawn("SpectralLightningSpot", (t.linetarget.pos.xy, t.linetarget.floorz), ALLOW_REPLACE); + if (spot != null) + { + spot.tracer = t.linetarget; + } + } + else + { + spot = Spawn("SpectralLightningSpot", Pos, ALLOW_REPLACE); + if (spot != null) + { + spot.VelFromAngle(28., angle); + } + } + if (spot != null) + { + spot.SetFriendPlayer(player); + spot.target = self; + } + } + + //============================================================================ + // + // A_FireSigil2 + // + //============================================================================ + + action void A_FireSigil2 () + { + if (player == null || player.ReadyWeapon == null) + return; + + DamageMobj (self, null, 2*4, 'Sigil', DMG_NO_ARMOR); + A_PlaySound ("weapons/sigilcharge", CHAN_WEAPON); + SpawnPlayerMissile ("SpectralLightningH1"); + } + + //============================================================================ + // + // A_FireSigil3 + // + //============================================================================ + + action void A_FireSigil3 () + { + if (player == null || player.ReadyWeapon == null) + return; + + DamageMobj (self, null, 3*4, 'Sigil', DMG_NO_ARMOR); + A_PlaySound ("weapons/sigilcharge", CHAN_WEAPON); + + angle -= 90.; + for (int i = 0; i < 20; ++i) + { + angle += 9.; + Actor spot = SpawnSubMissile ("SpectralLightningBall1", self); + if (spot != null) + { + spot.SetZ(pos.z + 32); + } + } + angle -= 90.; + } + + //============================================================================ + // + // A_FireSigil4 + // + //============================================================================ + + action void A_FireSigil4 () + { + FTranslatedLineTarget t; + + if (player == null || player.ReadyWeapon == null) + return; + + DamageMobj (self, null, 4*4, 'Sigil', DMG_NO_ARMOR); + A_PlaySound ("weapons/sigilcharge", CHAN_WEAPON); + + BulletSlope (t, ALF_PORTALRESTRICT); + if (t.linetarget != null) + { + Actor spot = SpawnPlayerMissile ("SpectralLightningBigV1", angle, pLineTarget: t, aimFlags: ALF_PORTALRESTRICT); + if (spot != null) + { + spot.tracer = t.linetarget; + } + } + else + { + Actor spot = SpawnPlayerMissile ("SpectralLightningBigV1"); + if (spot != null) + { + spot.VelFromAngle(spot.Speed, angle); + } + } + } + + //============================================================================ + // + // A_FireSigil5 + // + //============================================================================ + + action void A_FireSigil5 () + { + if (player == null || player.ReadyWeapon == null) + return; + + DamageMobj (self, null, 5*4, 'Sigil', DMG_NO_ARMOR); + A_PlaySound ("weapons/sigilcharge", CHAN_WEAPON); + + SpawnPlayerMissile ("SpectralLightningBigBall1"); + } + + //============================================================================ + // + // ASigil :: SpecialDropAction + // + // Monsters don't drop Sigil pieces. The Sigil pieces grab hold of the person + // who killed the dropper and automatically enter their inventory. That's the + // way it works if you believe Macil, anyway... + // + //============================================================================ + + override bool SpecialDropAction (Actor dropper) + { + // Give a Sigil piece to every player in the game + for (int i = 0; i < MAXPLAYERS; ++i) + { + if (playeringame[i] && players[i].mo != null) + { + GiveSigilPiece (players[i].mo); + Destroy (); + } + } + return true; + } + + //============================================================================ + // + // ASigil :: GiveSigilPiece + // + // Gives the actor another Sigil piece, up to 5. Returns the number of Sigil + // pieces the actor previously held. + // + //============================================================================ + + static int GiveSigilPiece (Actor receiver) + { + Sigil sigl = Sigil(receiver.FindInventory("Sigil")); + if (sigl == null) + { + sigl = Sigil(Spawn("Sigil1")); + if (!sigl.CallTryPickup (receiver)) + { + sigl.Destroy (); + } + return 0; + } + else if (sigl.health < 5) + { + ++sigl.health; + static const class sigils[] = + { + "Sigil1", "Sigil2", "Sigil3", "Sigil4", "Sigil5" + }; + sigl.Icon = GetDefaultByType(sigils[clamp(sigl.health, 1, 5)]).Icon; + // If the player has the Sigil out, drop it and bring it back up. + if (sigl.Owner.player != null && sigl.Owner.player.ReadyWeapon == sigl) + { + sigl.Owner.player.PendingWeapon = sigl; + sigl.DownPieces = sigl.health - 1; + } + return sigl.health - 1; + } + else + { + return 5; + } + } } // Sigil 1 ------------------------------------------------------------------ From 53318f4bdef9ce89a0495510b3cd44481319eafe Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 28 Nov 2016 15:51:07 +0100 Subject: [PATCH 151/185] - scriptified Reaver and Templar. --- src/CMakeLists.txt | 2 -- src/g_strife/a_reaver.cpp | 36 --------------------- src/g_strife/a_strifestuff.cpp | 2 -- src/g_strife/a_templar.cpp | 36 --------------------- wadsrc/static/zscript/strife/inquisitor.txt | 1 - wadsrc/static/zscript/strife/reaver.txt | 27 ++++++++++++++-- wadsrc/static/zscript/strife/sigil.txt | 2 +- wadsrc/static/zscript/strife/templar.txt | 18 ++++++++++- 8 files changed, 42 insertions(+), 82 deletions(-) delete mode 100644 src/g_strife/a_reaver.cpp delete mode 100644 src/g_strife/a_templar.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 211411f20..c5156cbf4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -867,13 +867,11 @@ set( NOT_COMPILED_SOURCE_FILES g_strife/a_loremaster.cpp g_strife/a_oracle.cpp g_strife/a_programmer.cpp - g_strife/a_reaver.cpp g_strife/a_rebels.cpp g_strife/a_sentinel.cpp g_strife/a_stalker.cpp g_strife/a_strifeitems.cpp g_strife/a_strifeweapons.cpp - g_strife/a_templar.cpp g_strife/a_thingstoblowup.cpp g_shared/sbarinfo_commands.cpp xlat/xlat_parser.y diff --git a/src/g_strife/a_reaver.cpp b/src/g_strife/a_reaver.cpp deleted file mode 100644 index 9c6e9f6b9..000000000 --- a/src/g_strife/a_reaver.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* -#include "actor.h" -#include "p_enemy.h" -#include "a_action.h" -#include "s_sound.h" -#include "m_random.h" -#include "p_local.h" -#include "a_strifeglobal.h" -#include "vm.h" -*/ - -static FRandom pr_reaverattack ("ReaverAttack"); - -DEFINE_ACTION_FUNCTION(AActor, A_ReaverRanged) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (self->target != NULL) - { - DAngle bangle; - DAngle pitch; - - A_FaceTarget (self); - S_Sound (self, CHAN_WEAPON, "reaver/attack", 1, ATTN_NORM); - bangle = self->Angles.Yaw; - pitch = P_AimLineAttack (self, bangle, MISSILERANGE); - - for (int i = 0; i < 3; ++i) - { - DAngle angle = bangle + pr_reaverattack.Random2() * (22.5 / 256); - int damage = ((pr_reaverattack() & 7) + 1) * 3; - P_LineAttack (self, angle, MISSILERANGE, pitch, damage, NAME_Hitscan, NAME_StrifePuff); - } - } - return 0; -} diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp index df89e614a..78ceaa097 100644 --- a/src/g_strife/a_strifestuff.cpp +++ b/src/g_strife/a_strifestuff.cpp @@ -31,13 +31,11 @@ //#include "a_macil.cpp" #include "a_oracle.cpp" #include "a_programmer.cpp" -#include "a_reaver.cpp" #include "a_rebels.cpp" #include "a_sentinel.cpp" #include "a_stalker.cpp" #include "a_strifeitems.cpp" #include "a_strifeweapons.cpp" -#include "a_templar.cpp" #include "a_thingstoblowup.cpp" // Notes so I don't forget them: diff --git a/src/g_strife/a_templar.cpp b/src/g_strife/a_templar.cpp deleted file mode 100644 index 0bfa00b24..000000000 --- a/src/g_strife/a_templar.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* -#include "actor.h" -#include "m_random.h" -#include "a_action.h" -#include "p_local.h" -#include "p_enemy.h" -#include "s_sound.h" -#include "a_strifeglobal.h" -#include "vm.h" -*/ - -static FRandom pr_templar ("Templar"); - -DEFINE_ACTION_FUNCTION(AActor, A_TemplarAttack) -{ - PARAM_SELF_PROLOGUE(AActor); - - int damage; - DAngle angle; - DAngle pitch; - - if (self->target == NULL) - return 0; - - S_Sound (self, CHAN_WEAPON, "templar/shoot", 1, ATTN_NORM); - A_FaceTarget (self); - pitch = P_AimLineAttack (self, self->Angles.Yaw, MISSILERANGE); - - for (int i = 0; i < 10; ++i) - { - damage = (pr_templar() & 4) * 2; - angle = self->Angles.Yaw + pr_templar.Random2() * (11.25 / 256); - P_LineAttack (self, angle, MISSILERANGE+64., pitch + pr_templar.Random2() * (7.097 / 256), damage, NAME_Hitscan, NAME_MaulerPuff); - } - return 0; -} diff --git a/wadsrc/static/zscript/strife/inquisitor.txt b/wadsrc/static/zscript/strife/inquisitor.txt index b27818a61..e7da303be 100644 --- a/wadsrc/static/zscript/strife/inquisitor.txt +++ b/wadsrc/static/zscript/strife/inquisitor.txt @@ -31,7 +31,6 @@ class Inquisitor : Actor native void A_InquisitorJump (); native void A_InquisitorCheckLand (); native void A_TossArm (); - native void A_ReaverRanged (); States { diff --git a/wadsrc/static/zscript/strife/reaver.txt b/wadsrc/static/zscript/strife/reaver.txt index 7656a37a9..d1c206b73 100644 --- a/wadsrc/static/zscript/strife/reaver.txt +++ b/wadsrc/static/zscript/strife/reaver.txt @@ -22,8 +22,6 @@ class Reaver : Actor Obituary "$OB_REAVER"; } - native void A_ReaverRanged (); - States { Spawn: @@ -64,4 +62,27 @@ class Reaver : Actor } } - \ No newline at end of file + +extend class Actor +{ + // The Inquisitor also uses this function + + void A_ReaverRanged () + { + if (target != null) + { + A_FaceTarget (); + A_PlaySound ("reaver/attack", CHAN_WEAPON); + double bangle = Angle; + double pitch = AimLineAttack (bangle, MISSILERANGE); + + for (int i = 0; i < 3; ++i) + { + double ang = bangle + Random2[ReaverAttack]() * (22.5 / 256); + int damage = ((random[ReaverAttack]() & 7) + 1) * 3; + LineAttack (ang, MISSILERANGE, pitch, damage, 'Hitscan', "StrifePuff"); + } + } + } + +} \ No newline at end of file diff --git a/wadsrc/static/zscript/strife/sigil.txt b/wadsrc/static/zscript/strife/sigil.txt index a9f802009..096915ccf 100644 --- a/wadsrc/static/zscript/strife/sigil.txt +++ b/wadsrc/static/zscript/strife/sigil.txt @@ -448,7 +448,7 @@ class Sigil : Weapon { "Sigil1", "Sigil2", "Sigil3", "Sigil4", "Sigil5" }; - sigl.Icon = GetDefaultByType(sigils[clamp(sigl.health, 1, 5)]).Icon; + sigl.Icon = GetDefaultByType(sigils[clamp(sigl.health, 1, 5)-1]).Icon; // If the player has the Sigil out, drop it and bring it back up. if (sigl.Owner.player != null && sigl.Owner.player.ReadyWeapon == sigl) { diff --git a/wadsrc/static/zscript/strife/templar.txt b/wadsrc/static/zscript/strife/templar.txt index 5b1605cf4..23290011c 100644 --- a/wadsrc/static/zscript/strife/templar.txt +++ b/wadsrc/static/zscript/strife/templar.txt @@ -25,7 +25,6 @@ class Templar : Actor Obituary "$OB_TEMPLAR"; DropItem "EnergyPod"; } - native void A_TemplarAttack(); States { @@ -64,5 +63,22 @@ class Templar : Actor PGRD \ -1; Stop; } + + void A_TemplarAttack() + { + if (target != null) + { + A_PlaySound ("templar/shoot", CHAN_WEAPON); + A_FaceTarget (); + double pitch = AimLineAttack (angle, MISSILERANGE); + + for (int i = 0; i < 10; ++i) + { + int damage = (random[Templar]() & 4) * 2; + double ang = angle + random2[Templar]() * (11.25 / 256); + LineAttack (ang, MISSILERANGE+64., pitch + random2[Templar]() * (7.097 / 256), damage, 'Hitscan', "MaulerPuff"); + } + } + } } From d2ce78fae7da67b8df0023cb66125fcc9bb0965e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 28 Nov 2016 16:19:01 +0100 Subject: [PATCH 152/185] - changed the return value of PickupMessage to an FString so that it can interface with scripts. - use standard convention of prefacing localizable strings with "$" for C_MidPrint. --- src/c_console.cpp | 2 +- src/d_dehacked.cpp | 2 +- src/d_dehacked.h | 2 +- src/g_shared/a_pickups.cpp | 33 +++++++++++++++---- src/g_shared/a_pickups.h | 7 ++-- src/g_shared/a_weaponpiece.cpp | 2 +- src/g_shared/a_weaponpiece.h | 2 +- src/g_strife/a_coin.cpp | 2 ++ src/g_strife/a_strifeglobal.h | 2 +- wadsrc/static/zscript/shared/inventory.txt | 1 + .../static/zscript/strife/alienspectres.txt | 8 ++--- 11 files changed, 44 insertions(+), 19 deletions(-) diff --git a/src/c_console.cpp b/src/c_console.cpp index 1016be9fd..691c4a3ca 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -1738,7 +1738,7 @@ DEFINE_ACTION_FUNCTION(DObject, C_MidPrint) PARAM_BOOL_DEF(bold); FFont *fnt = FFont::FindFont(font); - const char *txt = GStrings(text); + const char *txt = text[0] == '$'? GStrings(&text[1]) : text.GetChars(); if (!bold) C_MidPrint(fnt, txt); else C_MidPrintBold(fnt, txt); return 0; diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 624116e06..e9e5a58d0 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -3144,7 +3144,7 @@ bool ADehackedPickup::TryPickup (AActor *&toucher) return false; } -const char *ADehackedPickup::PickupMessage () +FString ADehackedPickup::PickupMessage () { if (RealPickup != nullptr) return RealPickup->PickupMessage (); diff --git a/src/d_dehacked.h b/src/d_dehacked.h index a622707a3..434853bf2 100644 --- a/src/d_dehacked.h +++ b/src/d_dehacked.h @@ -42,7 +42,7 @@ class ADehackedPickup : public AInventory HAS_OBJECT_POINTERS public: void Destroy() override; - const char *PickupMessage (); + FString PickupMessage (); bool ShouldRespawn (); bool ShouldStay (); bool TryPickup (AActor *&toucher); diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index cb5f4dd12..ad9fb70ce 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -475,7 +475,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialPosition) } int AInventory::StaticLastMessageTic; -const char *AInventory::StaticLastMessage; +FString AInventory::StaticLastMessage; IMPLEMENT_CLASS(AInventory, false, true) @@ -1205,10 +1205,10 @@ void AInventory::Touch (AActor *toucher) if (!(ItemFlags & IF_QUIET)) { - const char * message = PickupMessage (); + FString message = GetPickupMessage (); - if (message != NULL && *message != 0 && localview - && (StaticLastMessageTic != gametic || StaticLastMessage != message)) + if (message.IsNotEmpty() && localview + && (StaticLastMessageTic != gametic || StaticLastMessage.Compare(message))) { StaticLastMessageTic = gametic; StaticLastMessage = message; @@ -1283,11 +1283,32 @@ void AInventory::DoPickupSpecial (AActor *toucher) // //=========================================================================== -const char *AInventory::PickupMessage () +FString AInventory::PickupMessage () { return GetClass()->PickupMessage; } +DEFINE_ACTION_FUNCTION(AInventory, PickupMessage) +{ + PARAM_SELF_PROLOGUE(AInventory); + ACTION_RETURN_STRING(self->PickupMessage()); +} + +FString AInventory::GetPickupMessage() +{ + IFVIRTUAL(AInventory, PickupMessage) + { + VMValue params[1] = { (DObject*)this }; + VMReturn ret; + VMFrameStack stack; + FString retval; + ret.StringAt(&retval); + stack.Call(func, params, 1, &ret, 1, nullptr); + return retval; + } + else return PickupMessage(); +} + //=========================================================================== // // AInventory :: PlayPickupSound @@ -1884,7 +1905,7 @@ DEFINE_FIELD(AHealth, PrevHealth) // AHealth :: PickupMessage // //=========================================================================== -const char *AHealth::PickupMessage () +FString AHealth::PickupMessage () { int threshold = GetClass()->LowHealth; diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index e15f0724c..76a326254 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -173,7 +173,8 @@ public: virtual void DoEffect (); virtual bool Grind(bool items); - virtual const char *PickupMessage (); + virtual FString PickupMessage (); + FString GetPickupMessage(); virtual void PlayPickupSound (AActor *toucher); bool DoRespawn (); @@ -228,7 +229,7 @@ protected: private: static int StaticLastMessageTic; - static const char *StaticLastMessage; + static FString StaticLastMessage; }; class AStateProvider : public AInventory @@ -438,7 +439,7 @@ class AHealth : public AInventory public: int PrevHealth; virtual bool TryPickup (AActor *&other); - virtual const char *PickupMessage (); + virtual FString PickupMessage (); }; // HealthPickup is some item that gives the player health when used. diff --git a/src/g_shared/a_weaponpiece.cpp b/src/g_shared/a_weaponpiece.cpp index 52c9a9e38..bb98415fc 100644 --- a/src/g_shared/a_weaponpiece.cpp +++ b/src/g_shared/a_weaponpiece.cpp @@ -177,7 +177,7 @@ bool AWeaponPiece::PrivateShouldStay () // //=========================================================================== -const char *AWeaponPiece::PickupMessage () +FString AWeaponPiece::PickupMessage () { if (FullWeapon) { diff --git a/src/g_shared/a_weaponpiece.h b/src/g_shared/a_weaponpiece.h index 3a6fbcbd7..e293637cf 100644 --- a/src/g_shared/a_weaponpiece.h +++ b/src/g_shared/a_weaponpiece.h @@ -22,7 +22,7 @@ public: bool TryPickup (AActor *&toucher); bool TryPickupRestricted (AActor *&toucher); bool ShouldStay (); - virtual const char *PickupMessage (); + virtual FString PickupMessage (); virtual void PlayPickupSound (AActor *toucher); int PieceValue; diff --git a/src/g_strife/a_coin.cpp b/src/g_strife/a_coin.cpp index f74d92e55..a94b1375d 100644 --- a/src/g_strife/a_coin.cpp +++ b/src/g_strife/a_coin.cpp @@ -8,6 +8,7 @@ IMPLEMENT_CLASS(ACoin, false, false) +/* const char *ACoin::PickupMessage () { if (Amount == 1) @@ -22,6 +23,7 @@ const char *ACoin::PickupMessage () return msg; } } +*/ bool ACoin::HandlePickup (AInventory *item) { diff --git a/src/g_strife/a_strifeglobal.h b/src/g_strife/a_strifeglobal.h index c07bce63c..2561d961e 100644 --- a/src/g_strife/a_strifeglobal.h +++ b/src/g_strife/a_strifeglobal.h @@ -17,7 +17,7 @@ class ACoin : public AInventory { DECLARE_CLASS (ACoin, AInventory) public: - const char *PickupMessage (); + //const char *PickupMessage (); bool HandlePickup (AInventory *item); AInventory *CreateTossable (); AInventory *CreateCopy (AActor *other); diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index 1bc695339..d1164f2c4 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -30,6 +30,7 @@ class Inventory : Actor native virtual native bool HandlePickup(Inventory item); virtual native Inventory CreateCopy(Actor other); virtual native bool SpecialDropAction (Actor dropper); + virtual native String PickupMessage(); native void GoAwayAndDie(); diff --git a/wadsrc/static/zscript/strife/alienspectres.txt b/wadsrc/static/zscript/strife/alienspectres.txt index 2beee63ea..39cbc8331 100644 --- a/wadsrc/static/zscript/strife/alienspectres.txt +++ b/wadsrc/static/zscript/strife/alienspectres.txt @@ -108,13 +108,13 @@ class AlienSpectre1 : SpectralMonster } else if (cls == "AlienSpectre2") { - C_MidPrint("SmallFont", "TXT_KILLED_BISHOP"); + C_MidPrint("SmallFont", "$TXT_KILLED_BISHOP"); log = 74; player.GiveInventoryType ("QuestItem21"); } else if (cls == "AlienSpectre3") { - C_MidPrint("SmallFont", "TXT_KILLED_ORACLE"); + C_MidPrint("SmallFont", "$TXT_KILLED_ORACLE"); // If there are any Oracles still alive, kill them. ThinkerIterator it = ThinkerIterator.Create("Oracle"); Actor oracle; @@ -144,7 +144,7 @@ class AlienSpectre1 : SpectralMonster } else if (cls == "AlienSpectre4") { - C_MidPrint("SmallFont", "TXT_KILLED_MACIL"); + C_MidPrint("SmallFont", "$TXT_KILLED_MACIL"); player.GiveInventoryType ("QuestItem24"); if (player.FindInventory ("QuestItem25") == null) { // Richter has taken over. Macil is a snake. @@ -157,7 +157,7 @@ class AlienSpectre1 : SpectralMonster } else if (cls == "AlienSpectre5") { - C_MidPrint("SmallFont", "TXT_KILLED_LOREMASTER"); + C_MidPrint("SmallFont", "$TXT_KILLED_LOREMASTER"); player.GiveInventoryType ("QuestItem26"); if (!multiplayer) From 9064a5b0ac0c11a86a1e6da5559e2682f29bce00 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 28 Nov 2016 18:15:18 +0100 Subject: [PATCH 153/185] - scriptified Strife's coins. - added a String class to allow attaching methods to the builtin string type. This works by checking if the left side of the member accessor is a string and just replacing the tyoe in this one place, all the rest is automatic. --- src/dobjtype.cpp | 4 +- src/dobjtype.h | 1 + src/g_shared/a_artifacts.h | 1 + src/g_shared/a_pickups.cpp | 35 +++++++ src/g_shared/a_pickups.h | 5 +- src/g_shared/a_weapons.cpp | 2 +- src/g_strife/a_coin.cpp | 4 +- src/g_strife/a_strifeglobal.h | 10 -- src/g_strife/a_strifeitems.cpp | 2 +- src/p_conversation.cpp | 26 +++--- src/p_mobj.cpp | 2 +- src/scripting/codegeneration/codegen.cpp | 22 ++++- src/scripting/thingdef_data.cpp | 18 ++++ src/scripting/vm/vmdisasm.cpp | 4 + wadsrc/static/zscript/base.txt | 11 +++ wadsrc/static/zscript/shared/inventory.txt | 3 + wadsrc/static/zscript/strife/coin.txt | 104 ++++++++++++++++++++- 17 files changed, 221 insertions(+), 33 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 62a6a2b2d..7377af56b 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -89,6 +89,7 @@ PStateLabel *TypeStateLabel; PStruct *TypeVector2; PStruct *TypeVector3; PStruct *TypeColorStruct; +PStruct *TypeStringStruct; PPointer *TypeNullPtr; // PRIVATE DATA DEFINITIONS ------------------------------------------------ @@ -587,7 +588,8 @@ void PType::StaticInit() TypeTable.AddType(TypeSpriteID = new PSpriteID); TypeTable.AddType(TypeTextureID = new PTextureID); - TypeColorStruct = new PStruct("@ColorStruct", nullptr); //This name is intentionally obfuscated so that it cannot be used explicitly. The point of this type is to gain access to the single channels of a color value. + TypeColorStruct = NewStruct("@ColorStruct", nullptr); //This name is intentionally obfuscated so that it cannot be used explicitly. The point of this type is to gain access to the single channels of a color value. + TypeStringStruct = NewNativeStruct(NAME_String, nullptr); #ifdef __BIG_ENDIAN__ TypeColorStruct->AddField(NAME_a, TypeUInt8); TypeColorStruct->AddField(NAME_r, TypeUInt8); diff --git a/src/dobjtype.h b/src/dobjtype.h index 89d309156..ad626ee8b 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -945,6 +945,7 @@ extern PSpriteID *TypeSpriteID; extern PStruct *TypeVector2; extern PStruct *TypeVector3; extern PStruct *TypeColorStruct; +extern PStruct *TypeStringStruct; extern PStatePointer *TypeState; extern PStateLabel *TypeStateLabel; extern PPointer *TypeNullPtr; diff --git a/src/g_shared/a_artifacts.h b/src/g_shared/a_artifacts.h index 95de95086..c3a0f31f0 100644 --- a/src/g_shared/a_artifacts.h +++ b/src/g_shared/a_artifacts.h @@ -16,6 +16,7 @@ public: virtual bool HandlePickup (AInventory *item); virtual AInventory *CreateCopy (AActor *other); virtual AInventory *CreateTossable (); + virtual void Serialize(FSerializer &arc); virtual void OwnerDied (); diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index ad9fb70ce..df434baae 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -919,6 +919,27 @@ AInventory *AInventory::CreateTossable () return copy; } +DEFINE_ACTION_FUNCTION(AInventory, CreateTossable) +{ + PARAM_SELF_PROLOGUE(AInventory); + ACTION_RETURN_OBJECT(self->CreateTossable()); +} + +AInventory *AInventory::CallCreateTossable() +{ + IFVIRTUAL(AInventory, CreateTossable) + { + VMValue params[1] = { (DObject*)this }; + VMReturn ret; + VMFrameStack stack; + AInventory *retval; + ret.PointerAt((void**)&retval); + stack.Call(func, params, 1, &ret, 1, nullptr); + return retval; + } + else return CreateTossable(); +} + //=========================================================================== // // AInventory :: BecomeItem @@ -946,6 +967,13 @@ void AInventory::BecomeItem () SetState (FindState("Held")); } +DEFINE_ACTION_FUNCTION(AInventory, BecomeItem) +{ + PARAM_SELF_PROLOGUE(AInventory); + self->BecomeItem(); + return 0; +} + //=========================================================================== // // AInventory :: BecomePickup @@ -973,6 +1001,13 @@ void AInventory::BecomePickup () SetState (SpawnState); } +DEFINE_ACTION_FUNCTION(AInventory, BecomePickup) +{ + PARAM_SELF_PROLOGUE(AInventory); + self->BecomePickup(); + return 0; +} + //=========================================================================== // // AInventory :: AbsorbDamage diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index 76a326254..8fc96cd57 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -196,13 +196,14 @@ public: FSoundIDNoInit PickupSound; - virtual void BecomeItem (); - virtual void BecomePickup (); + void BecomeItem (); + void BecomePickup (); virtual void AttachToOwner (AActor *other); virtual void DetachFromOwner (); virtual AInventory *CreateCopy (AActor *other); AInventory *CallCreateCopy(AActor *other); virtual AInventory *CreateTossable (); + AInventory *CallCreateTossable(); virtual bool GoAway (); virtual void GoAwayAndDie (); virtual bool HandlePickup (AInventory *item); diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index c2feebec6..4f49ecd6f 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -424,7 +424,7 @@ AInventory *AWeapon::CreateTossable () (((AWeapon*)SisterWeapon->GetDefault())->AmmoGive1 > 0 || ((AWeapon*)SisterWeapon->GetDefault())->AmmoGive2 > 0)) { - return SisterWeapon->CreateTossable (); + return SisterWeapon->CallCreateTossable (); } AWeapon *copy = static_cast (Super::CreateTossable ()); diff --git a/src/g_strife/a_coin.cpp b/src/g_strife/a_coin.cpp index a94b1375d..dcbbecf10 100644 --- a/src/g_strife/a_coin.cpp +++ b/src/g_strife/a_coin.cpp @@ -6,9 +6,9 @@ // Coin --------------------------------------------------------------------- +/* IMPLEMENT_CLASS(ACoin, false, false) -/* const char *ACoin::PickupMessage () { if (Amount == 1) @@ -23,7 +23,6 @@ const char *ACoin::PickupMessage () return msg; } } -*/ bool ACoin::HandlePickup (AInventory *item) { @@ -108,3 +107,4 @@ AInventory *ACoin::CreateTossable () } return tossed; } +*/ diff --git a/src/g_strife/a_strifeglobal.h b/src/g_strife/a_strifeglobal.h index 2561d961e..adf8d59bf 100644 --- a/src/g_strife/a_strifeglobal.h +++ b/src/g_strife/a_strifeglobal.h @@ -13,16 +13,6 @@ public: bool Use (bool pickup); }; -class ACoin : public AInventory -{ - DECLARE_CLASS (ACoin, AInventory) -public: - //const char *PickupMessage (); - bool HandlePickup (AInventory *item); - AInventory *CreateTossable (); - AInventory *CreateCopy (AActor *other); -}; - class ADummyStrifeItem : public AInventory { DECLARE_CLASS (ADummyStrifeItem, AInventory) diff --git a/src/g_strife/a_strifeitems.cpp b/src/g_strife/a_strifeitems.cpp index 0586583ff..0f1132cbd 100644 --- a/src/g_strife/a_strifeitems.cpp +++ b/src/g_strife/a_strifeitems.cpp @@ -82,7 +82,7 @@ bool AHealthTraining::TryPickup (AActor *&toucher) if (Super::TryPickup (toucher)) { toucher->GiveInventoryType (PClass::FindActor("GunTraining")); - AInventory *coin = Spawn (); + AInventory *coin = (AInventory*)Spawn("Coin"); if (coin != NULL) { coin->Amount = toucher->player->mo->accuracy*5 + 300; diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 95aabe44b..bf1c392ae 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -1053,18 +1053,22 @@ public: if (ShowGold) { - AInventory *coin = cp->ConversationPC->FindInventory (RUNTIME_CLASS(ACoin)); - char goldstr[32]; + auto cointype = PClass::FindActor("Coin"); + if (cointype) + { + AInventory *coin = cp->ConversationPC->FindInventory(cointype); + char goldstr[32]; - mysnprintf (goldstr, countof(goldstr), "%d", coin != NULL ? coin->Amount : 0); - screen->DrawText (SmallFont, CR_GRAY, 21, 191, goldstr, DTA_320x200, true, - DTA_FillColor, 0, DTA_AlphaF, HR_SHADOW, TAG_DONE); - screen->DrawTexture (TexMan(((AInventory *)GetDefaultByType (RUNTIME_CLASS(ACoin)))->Icon), - 3, 190, DTA_320x200, true, - DTA_FillColor, 0, DTA_AlphaF, HR_SHADOW, TAG_DONE); - screen->DrawText (SmallFont, CR_GRAY, 20, 190, goldstr, DTA_320x200, true, TAG_DONE); - screen->DrawTexture (TexMan(((AInventory *)GetDefaultByType (RUNTIME_CLASS(ACoin)))->Icon), - 2, 189, DTA_320x200, true, TAG_DONE); + mysnprintf(goldstr, countof(goldstr), "%d", coin != NULL ? coin->Amount : 0); + screen->DrawText(SmallFont, CR_GRAY, 21, 191, goldstr, DTA_320x200, true, + DTA_FillColor, 0, DTA_AlphaF, HR_SHADOW, TAG_DONE); + screen->DrawTexture(TexMan(((AInventory *)GetDefaultByType(cointype))->Icon), + 3, 190, DTA_320x200, true, + DTA_FillColor, 0, DTA_AlphaF, HR_SHADOW, TAG_DONE); + screen->DrawText(SmallFont, CR_GRAY, 20, 190, goldstr, DTA_320x200, true, TAG_DONE); + screen->DrawTexture(TexMan(((AInventory *)GetDefaultByType(cointype))->Icon), + 2, 189, DTA_320x200, true, TAG_DONE); + } } y = mYpos; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 6f0754a8f..0f58b600c 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1002,7 +1002,7 @@ bool AActor::UseInventory(AInventory *item) AInventory *AActor::DropInventory (AInventory *item) { - AInventory *drop = item->CreateTossable (); + AInventory *drop = item->CallCreateTossable (); if (drop == NULL) { diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index f63629bb5..5277ad70e 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -5766,9 +5766,11 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) // allow accessing the color channels by mapping the type to a matching struct which defines them. if (Object->ValueType == TypeColor) + { Object->ValueType = TypeColorStruct; + } - if (Object->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) + else if (Object->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) { auto ptype = static_cast(Object->ValueType)->PointedType; if (ptype->IsKindOf(RUNTIME_CLASS(PStruct))) @@ -7306,6 +7308,12 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) } } + if (Self->ValueType == TypeString) + { + // same for String methods. It also uses a hidden struct type to define them. + Self->ValueType = TypeStringStruct; + } + if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) { auto ptype = static_cast(Self->ValueType)->PointedType; @@ -7876,8 +7884,16 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) { assert(Self != nullptr); selfemit = Self->Emit(build); - assert(selfemit.RegType == REGT_POINTER); - build->Emit(OP_PARAM, 0, selfemit.RegType, selfemit.RegNum); + assert((selfemit.RegType == REGT_POINTER) || (selfemit.Fixed && selfemit.Target)); + if (selfemit.Fixed && selfemit.Target) + { + // Address of a local variable. + build->Emit(OP_PARAM, 0, selfemit.RegType | REGT_ADDROF, selfemit.RegNum); + } + else + { + build->Emit(OP_PARAM, 0, selfemit.RegType, selfemit.RegNum); + } count += 1; if (Function->Variants[0].Flags & VARF_Action) { diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index d17e10420..a1542a8a5 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -46,6 +46,8 @@ #include "p_maputl.h" #include "gi.h" #include "p_terrain.h" +#include "gstrings.h" +#include "zstring.h" static TArray properties; static TArray AFTable; @@ -826,3 +828,19 @@ DEFINE_ACTION_FUNCTION(DObject, GameType) PARAM_PROLOGUE; ACTION_RETURN_INT(gameinfo.gametype); } + +DEFINE_ACTION_FUNCTION(FStringTable, Localize) +{ + PARAM_PROLOGUE; + PARAM_STRING(label); + ACTION_RETURN_STRING(GStrings(label)); +} + +DEFINE_ACTION_FUNCTION(FString, Replace) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + PARAM_STRING(s1); + PARAM_STRING(s2); + self->Substitute(*s1, *s2); + return 0; +} \ No newline at end of file diff --git a/src/scripting/vm/vmdisasm.cpp b/src/scripting/vm/vmdisasm.cpp index 88962bf68..2158139ab 100644 --- a/src/scripting/vm/vmdisasm.cpp +++ b/src/scripting/vm/vmdisasm.cpp @@ -289,6 +289,10 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction a &= CMP_CHECK | CMP_APPROX; cmp = true; } + if (code[i].op == OP_PARAM && code[i].b & REGT_ADDROF) + { + name = "parama"; + } if (cmp) { // Comparison instruction. Modify name for inverted test. if (!(a & CMP_CHECK)) diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index c76e4590e..8d2e7a71b 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -98,6 +98,11 @@ struct LevelLocals native // level_info_t *info cannot be done yet. } +struct StringTable native +{ + native static String Localize(String val); +} + // a few values of this need to be readable by the play code. // Most are handled at load time and are omitted here. struct DehInfo native @@ -275,3 +280,9 @@ enum EPickStart PPS_FORCERANDOM = 1, PPS_NOBLOCKINGCHECK = 2, } + +// Although String is a builtin type, this is a convenient way to attach methods to it. +struct String native +{ + native void Replace(String pattern, String replacement); +} diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index d1164f2c4..d3e50d198 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -29,10 +29,13 @@ class Inventory : Actor native virtual native color GetBlend (); virtual native bool HandlePickup(Inventory item); virtual native Inventory CreateCopy(Actor other); + virtual native Inventory CreateTossable(); virtual native bool SpecialDropAction (Actor dropper); virtual native String PickupMessage(); native void GoAwayAndDie(); + native void BecomeItem(); + native void BecomePickup(); // These are regular functions for the item itself. private native void A_RestoreSpecialDoomThing(); diff --git a/wadsrc/static/zscript/strife/coin.txt b/wadsrc/static/zscript/strife/coin.txt index a930cb0ba..b94a3f1d1 100644 --- a/wadsrc/static/zscript/strife/coin.txt +++ b/wadsrc/static/zscript/strife/coin.txt @@ -1,7 +1,7 @@ // Coin --------------------------------------------------------------------- -class Coin : Inventory native +class Coin : Inventory { Default { @@ -20,6 +20,108 @@ class Coin : Inventory native COIN A -1; Stop; } + + // Coin --------------------------------------------------------------------- + + override String PickupMessage () + { + if (Amount == 1) + { + return Super.PickupMessage(); + } + else + { + String msg = StringTable.Localize("TXT_XGOLD"); + msg.Replace("%d", "" .. Amount); + return msg; + } + } + + override bool HandlePickup (Inventory item) + { + if (item is "Coin") + { + if (Amount < MaxAmount) + { + if (MaxAmount - Amount < item.Amount) + { + Amount = MaxAmount; + } + else + { + Amount += item.Amount; + } + item.bPickupGood = true; + } + return true; + } + return false; + } + + override Inventory CreateCopy (Actor other) + { + if (GetClass() == "Coin") + { + return Super.CreateCopy (other); + } + Inventory copy = Inventory(Spawn("Coin")); + copy.Amount = Amount; + copy.BecomeItem (); + GoAwayAndDie (); + return copy; + } + + //=========================================================================== + // + // ACoin :: CreateTossable + // + // Gold drops in increments of 50 if you have that much, less if you don't. + // + //=========================================================================== + + override Inventory CreateTossable () + { + Coin tossed; + + if (bUndroppable || Owner == NULL || Amount <= 0) + { + return NULL; + } + if (Amount >= 50) + { + Amount -= 50; + tossed = Coin(Spawn("Gold50")); + } + else if (Amount >= 25) + { + Amount -= 25; + tossed = Coin(Spawn("Gold25")); + } + else if (Amount >= 10) + { + Amount -= 10; + tossed = Coin(Spawn("Gold10")); + } + else if (Amount > 1 || bKeepDepleted) + { + Amount -= 1; + tossed = Coin(Spawn("Coin")); + } + else // Amount == 1 && !(ItemFlags & IF_KEEPDEPLETED) + { + BecomePickup (); + tossed = self; + } + tossed.bSpecial = false; + tossed.bSolid = false; + tossed.DropTime = 30; + if (tossed != self && Amount <= 0) + { + Destroy (); + } + return tossed; + } + } From b8cf377d9e7a6825a5c2ec48399be122d5290e85 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 28 Nov 2016 18:36:13 +0100 Subject: [PATCH 154/185] - scriptified the Crusader. --- src/CMakeLists.txt | 1 - src/g_strife/a_coin.cpp | 110 ---------------------- src/g_strife/a_crusader.cpp | 100 -------------------- src/g_strife/a_strifestuff.cpp | 2 - src/p_mobj.cpp | 9 ++ wadsrc/static/zscript/actor.txt | 1 + wadsrc/static/zscript/strife/crusader.txt | 85 +++++++++++++++-- 7 files changed, 88 insertions(+), 220 deletions(-) delete mode 100644 src/g_strife/a_coin.cpp delete mode 100644 src/g_strife/a_crusader.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c5156cbf4..c8d560c2b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -861,7 +861,6 @@ set( NOT_COMPILED_SOURCE_FILES sc_man_scanner.re g_hexen/a_heresiarch.cpp g_hexen/a_spike.cpp - g_strife/a_coin.cpp g_strife/a_crusader.cpp g_strife/a_inquisitor.cpp g_strife/a_loremaster.cpp diff --git a/src/g_strife/a_coin.cpp b/src/g_strife/a_coin.cpp deleted file mode 100644 index dcbbecf10..000000000 --- a/src/g_strife/a_coin.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* -#include "a_pickups.h" -#include "a_strifeglobal.h" -#include "gstrings.h" -*/ - -// Coin --------------------------------------------------------------------- - -/* -IMPLEMENT_CLASS(ACoin, false, false) - -const char *ACoin::PickupMessage () -{ - if (Amount == 1) - { - return Super::PickupMessage(); - } - else - { - static char msg[64]; - - mysnprintf (msg, countof(msg), GStrings("TXT_XGOLD"), Amount); - return msg; - } -} - -bool ACoin::HandlePickup (AInventory *item) -{ - if (item->IsKindOf (RUNTIME_CLASS(ACoin))) - { - if (Amount < MaxAmount) - { - if (MaxAmount - Amount < item->Amount) - { - Amount = MaxAmount; - } - else - { - Amount += item->Amount; - } - item->ItemFlags |= IF_PICKUPGOOD; - } - return true; - } - return false; -} - -AInventory *ACoin::CreateCopy (AActor *other) -{ - if (GetClass() == RUNTIME_CLASS(ACoin)) - { - return Super::CreateCopy (other); - } - AInventory *copy = Spawn (); - copy->Amount = Amount; - copy->BecomeItem (); - GoAwayAndDie (); - return copy; -} - -//=========================================================================== -// -// ACoin :: CreateTossable -// -// Gold drops in increments of 50 if you have that much, less if you don't. -// -//=========================================================================== - -AInventory *ACoin::CreateTossable () -{ - ACoin *tossed; - - if ((ItemFlags & IF_UNDROPPABLE) || Owner == NULL || Amount <= 0) - { - return NULL; - } - if (Amount >= 50) - { - Amount -= 50; - tossed = static_cast(Spawn("Gold50", Owner->Pos(), NO_REPLACE)); - } - else if (Amount >= 25) - { - Amount -= 25; - tossed = static_cast(Spawn("Gold25", Owner->Pos(), NO_REPLACE)); - } - else if (Amount >= 10) - { - Amount -= 10; - tossed = static_cast(Spawn("Gold10", Owner->Pos(), NO_REPLACE)); - } - else if (Amount > 1 || (ItemFlags & IF_KEEPDEPLETED)) - { - Amount -= 1; - tossed = static_cast(Spawn("Coin", Owner->Pos(), NO_REPLACE)); - } - else // Amount == 1 && !(ItemFlags & IF_KEEPDEPLETED) - { - BecomePickup (); - tossed = this; - } - tossed->flags &= ~(MF_SPECIAL|MF_SOLID); - tossed->DropTime = 30; - if (tossed != this && Amount <= 0) - { - Destroy (); - } - return tossed; -} -*/ diff --git a/src/g_strife/a_crusader.cpp b/src/g_strife/a_crusader.cpp deleted file mode 100644 index 05835a5f9..000000000 --- a/src/g_strife/a_crusader.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* -#include "actor.h" -#include "m_random.h" -#include "a_action.h" -#include "p_local.h" -#include "p_enemy.h" -#include "s_sound.h" -#include "a_strifeglobal.h" -#include "vm.h" -*/ - -static bool CrusaderCheckRange (AActor *self) -{ - if (self->reactiontime == 0 && P_CheckSight (self, self->target)) - { - return self->Distance2D (self->target) < 264.; - } - return false; -} - -DEFINE_ACTION_FUNCTION(AActor, A_CrusaderChoose) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (self->target == NULL) - return 0; - - if (CrusaderCheckRange (self)) - { - A_FaceTarget (self); - self->Angles.Yaw -= 180./16; - P_SpawnMissileZAimed (self, self->Z() + 40, self->target, PClass::FindActor("FastFlameMissile")); - } - else - { - if (P_CheckMissileRange (self)) - { - A_FaceTarget (self); - P_SpawnMissileZAimed (self, self->Z() + 56, self->target, PClass::FindActor("CrusaderMissile")); - self->Angles.Yaw -= 45./32; - P_SpawnMissileZAimed (self, self->Z() + 40, self->target, PClass::FindActor("CrusaderMissile")); - self->Angles.Yaw += 45./16; - P_SpawnMissileZAimed (self, self->Z() + 40, self->target, PClass::FindActor("CrusaderMissile")); - self->Angles.Yaw -= 45./16; - self->reactiontime += 15; - } - self->SetState (self->SeeState); - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_CrusaderSweepLeft) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->Angles.Yaw += 90./16; - AActor *misl = P_SpawnMissileZAimed (self, self->Z() + 48, self->target, PClass::FindActor("FastFlameMissile")); - if (misl != NULL) - { - misl->Vel.Z += 1; - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_CrusaderSweepRight) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->Angles.Yaw -= 90./16; - AActor *misl = P_SpawnMissileZAimed (self, self->Z() + 48, self->target, PClass::FindActor("FastFlameMissile")); - if (misl != NULL) - { - misl->Vel.Z += 1; - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_CrusaderRefire) -{ - PARAM_SELF_PROLOGUE(AActor); - - 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_SELF_PROLOGUE(AActor); - - if (CheckBossDeath (self)) - { - EV_DoFloor (DFloor::floorLowerToLowest, NULL, 667, 1., 0., -1, 0, false); - } - return 0; -} diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp index 78ceaa097..d38e4130b 100644 --- a/src/g_strife/a_strifestuff.cpp +++ b/src/g_strife/a_strifestuff.cpp @@ -24,8 +24,6 @@ #include "vm.h" // Include all the other Strife stuff here to reduce compile time -#include "a_coin.cpp" -#include "a_crusader.cpp" #include "a_inquisitor.cpp" #include "a_loremaster.cpp" //#include "a_macil.cpp" diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 0f58b600c..93c9b80f3 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -6520,6 +6520,15 @@ AActor *P_SpawnMissileZAimed (AActor *source, double z, AActor *dest, PClassActo return P_SpawnMissileAngleZSpeed (source, z, type, an, vz, speed); } +DEFINE_ACTION_FUNCTION(AActor, SpawnMissileZAimed) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(z); + PARAM_OBJECT(dest, AActor); + PARAM_CLASS(type, AActor); + ACTION_RETURN_OBJECT(P_SpawnMissileZAimed(self, z, dest, type)); +} + //--------------------------------------------------------------------------- // // FUNC P_SpawnMissileAngleZSpeed diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index cdcc630b5..3b49e3e3c 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -310,6 +310,7 @@ class Actor : Thinker native native Actor SpawnMissileXYZ(Vector3 pos, Actor dest, Class type, bool checkspawn = true, Actor owner = null); native Actor SpawnMissileZ (double z, Actor dest, class type); native Actor SpawnMissileAngleZSpeed (double z, class type, double angle, double vz, double speed, Actor owner = null, bool checkspawn = true); + native Actor SpawnMissileZAimed (double z, Actor dest, Class type); native Actor SpawnSubMissile(Class type, Actor target); native Actor, Actor SpawnPlayerMissile(class type, double angle = 0, double x = 0, double y = 0, double z = 0, out FTranslatedLineTarget pLineTarget = null, bool nofreeaim = false, bool noautoaim = false, int aimflags = 0); native void SpawnTeleportFog(Vector3 pos, bool beforeTele, bool setTarget); diff --git a/wadsrc/static/zscript/strife/crusader.txt b/wadsrc/static/zscript/strife/crusader.txt index 02b08fc93..834464e06 100644 --- a/wadsrc/static/zscript/strife/crusader.txt +++ b/wadsrc/static/zscript/strife/crusader.txt @@ -28,12 +28,6 @@ class Crusader : Actor Obituary "$OB_CRUSADER"; } - native void A_CrusaderChoose (); - native void A_CrusaderSweepLeft (); - native void A_CrusaderSweepRight (); - native void A_CrusaderRefire (); - native void A_CrusaderDeath (); - States { Spawn: @@ -66,6 +60,83 @@ class Crusader : Actor ROB2 P -1 A_CrusaderDeath; Stop; } + +// Crusader ----------------------------------------------------------------- + + private bool CrusaderCheckRange () + { + if (reactiontime == 0 && CheckSight (target)) + { + return Distance2D (target) < 264.; + } + return false; + } + + void A_CrusaderChoose () + { + if (target == null) + return; + + if (CrusaderCheckRange ()) + { + A_FaceTarget (); + angle -= 180./16; + SpawnMissileZAimed (pos.z + 40, target, "FastFlameMissile"); + } + else + { + if (CheckMissileRange ()) + { + A_FaceTarget (); + SpawnMissileZAimed (pos.z + 56, target, "CrusaderMissile"); + angle -= 45./32; + SpawnMissileZAimed (pos.z + 40, target, "CrusaderMissile"); + angle += 45./16; + SpawnMissileZAimed (pos.z + 40, target, "CrusaderMissile"); + angle -= 45./16; + reactiontime += 15; + } + SetState (SeeState); + } + } + + void A_CrusaderSweepLeft () + { + angle += 90./16; + Actor misl = SpawnMissileZAimed (pos.z + 48, target, "FastFlameMissile"); + if (misl != null) + { + misl.Vel.Z += 1; + } + } + + void A_CrusaderSweepRight () + { + angle -= 90./16; + Actor misl = SpawnMissileZAimed (pos.z + 48, target, "FastFlameMissile"); + if (misl != null) + { + misl.Vel.Z += 1; + } + } + + void A_CrusaderRefire () + { + if (target == null || + target.health <= 0 || + !CheckSight (target)) + { + SetState (SeeState); + } + } + + void A_CrusaderDeath () + { + if (CheckBossDeath ()) + { + Floor_LowerToLowest(667, 8); + } + } } @@ -105,7 +176,7 @@ class CrusaderMissile : Actor MICR A 6 Bright A_RocketInFlight; Loop; Death: - SMIS A 0 Bright A_SetTranslucent(1,1); + SMIS A 0 Bright A_SetRenderStyle(1, STYLE_Normal); SMIS A 5 Bright; SMIS B 5 Bright; SMIS C 4 Bright; From bf1c2a7e51d1e0688adc215539635635ed76d9b8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 28 Nov 2016 18:49:25 +0100 Subject: [PATCH 155/185] - scriptified the Inquisitor. --- src/CMakeLists.txt | 2 - src/g_strife/a_inquisitor.cpp | 136 -------------------- src/g_strife/a_strifestuff.cpp | 2 - wadsrc/static/zscript/strife/inquisitor.txt | 112 ++++++++++++++-- 4 files changed, 104 insertions(+), 148 deletions(-) delete mode 100644 src/g_strife/a_inquisitor.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c8d560c2b..74760f138 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -861,8 +861,6 @@ set( NOT_COMPILED_SOURCE_FILES sc_man_scanner.re g_hexen/a_heresiarch.cpp g_hexen/a_spike.cpp - g_strife/a_crusader.cpp - g_strife/a_inquisitor.cpp g_strife/a_loremaster.cpp g_strife/a_oracle.cpp g_strife/a_programmer.cpp diff --git a/src/g_strife/a_inquisitor.cpp b/src/g_strife/a_inquisitor.cpp deleted file mode 100644 index a4c2d72f4..000000000 --- a/src/g_strife/a_inquisitor.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* -#include "actor.h" -#include "m_random.h" -#include "a_action.h" -#include "p_local.h" -#include "p_enemy.h" -#include "s_sound.h" -#include "vm.h" -*/ - -static FRandom pr_inq ("Inquisitor"); - -DEFINE_ACTION_FUNCTION(AActor, A_InquisitorWalk) -{ - PARAM_SELF_PROLOGUE(AActor); - - S_Sound (self, CHAN_BODY, "inquisitor/walk", 1, ATTN_NORM); - A_Chase (stack, self); - return 0; -} - -bool InquisitorCheckDistance (AActor *self) -{ - if (self->reactiontime == 0 && P_CheckSight (self, self->target)) - { - return self->Distance2D (self->target) < 264.; - } - return false; -} - -DEFINE_ACTION_FUNCTION(AActor, A_InquisitorDecide) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (self->target == NULL) - return 0; - - A_FaceTarget (self); - if (!InquisitorCheckDistance (self)) - { - self->SetState (self->FindState("Grenade")); - } - if (self->target->Z() != self->Z()) - { - if (self->Top() + 54 < self->ceilingz) - { - self->SetState (self->FindState("Jump")); - } - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_InquisitorAttack) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *proj; - - if (self->target == NULL) - return 0; - - A_FaceTarget (self); - - self->AddZ(32); - self->Angles.Yaw -= 45./32; - proj = P_SpawnMissileZAimed (self, self->Z(), self->target, PClass::FindActor("InquisitorShot")); - if (proj != NULL) - { - proj->Vel.Z += 9; - } - self->Angles.Yaw += 45./16; - proj = P_SpawnMissileZAimed (self, self->Z(), self->target, PClass::FindActor("InquisitorShot")); - if (proj != NULL) - { - proj->Vel.Z += 16; - } - self->AddZ(-32); - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_InquisitorJump) -{ - PARAM_SELF_PROLOGUE(AActor); - - double dist; - double speed; - - if (self->target == NULL) - return 0; - - S_Sound (self, CHAN_ITEM|CHAN_LOOP, "inquisitor/jump", 1, ATTN_NORM); - self->AddZ(64); - A_FaceTarget (self); - speed = self->Speed * (2./3); - self->VelFromAngle(speed); - dist = self->DistanceBySpeed(self->target, speed); - self->Vel.Z = (self->target->Z() - self->Z()) / dist; - self->reactiontime = 60; - self->flags |= MF_NOGRAVITY; - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_InquisitorCheckLand) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->reactiontime--; - if (self->reactiontime < 0 || - self->Vel.X == 0 || - self->Vel.Y == 0 || - self->Z() <= self->floorz) - { - self->SetState (self->SeeState); - self->reactiontime = 0; - self->flags &= ~MF_NOGRAVITY; - S_StopSound (self, CHAN_ITEM); - 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_SELF_PROLOGUE(AActor); - - AActor *foo = Spawn("InquisitorArm", self->PosPlusZ(24.), ALLOW_REPLACE); - foo->Angles.Yaw = self->Angles.Yaw - 90. + pr_inq.Random2() * (360./1024.); - foo->VelFromAngle(foo->Speed / 8); - foo->Vel.Z = pr_inq() / 64.; - return 0; -} - diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp index d38e4130b..ba316175d 100644 --- a/src/g_strife/a_strifestuff.cpp +++ b/src/g_strife/a_strifestuff.cpp @@ -24,9 +24,7 @@ #include "vm.h" // Include all the other Strife stuff here to reduce compile time -#include "a_inquisitor.cpp" #include "a_loremaster.cpp" -//#include "a_macil.cpp" #include "a_oracle.cpp" #include "a_programmer.cpp" #include "a_rebels.cpp" diff --git a/wadsrc/static/zscript/strife/inquisitor.txt b/wadsrc/static/zscript/strife/inquisitor.txt index e7da303be..ef73ade1e 100644 --- a/wadsrc/static/zscript/strife/inquisitor.txt +++ b/wadsrc/static/zscript/strife/inquisitor.txt @@ -25,13 +25,6 @@ class Inquisitor : Actor Obituary "$OB_INQUISITOR"; } - native void A_InquisitorWalk (); - native void A_InquisitorDecide (); - native void A_InquisitorAttack (); - native void A_InquisitorJump (); - native void A_InquisitorCheckLand (); - native void A_TossArm (); - States { Spawn: @@ -81,6 +74,109 @@ class Inquisitor : Actor RBB3 E -1; Stop; } + + + // Inquisitor --------------------------------------------------------------- + + void A_InquisitorWalk () + { + A_PlaySound ("inquisitor/walk", CHAN_BODY); + A_Chase (); + } + + private bool InquisitorCheckDistance () + { + if (reactiontime == 0 && CheckSight (target)) + { + return Distance2D (target) < 264.; + } + return false; + } + + void A_InquisitorDecide () + { + if (target == null) + return; + + A_FaceTarget (); + if (!InquisitorCheckDistance ()) + { + SetStateLabel("Grenade"); + } + if (target.pos.z != pos.z) + { + if (pos.z + height + 54 < ceilingz) + { + SetStateLabel("Jump"); + } + } + } + + void A_InquisitorAttack () + { + if (target == null) + return; + + A_FaceTarget (); + + AddZ(32); + angle -= 45./32; + Actor proj = SpawnMissileZAimed (pos.z, target, "InquisitorShot"); + if (proj != null) + { + proj.Vel.Z += 9; + } + angle += 45./16; + proj = SpawnMissileZAimed (pos.z, target, "InquisitorShot"); + if (proj != null) + { + proj.Vel.Z += 16; + } + AddZ(-32); + } + + void A_InquisitorJump () + { + if (target == null) + return; + + A_PlaySound ("inquisitor/jump", CHAN_ITEM, 1, true); + AddZ(64); + A_FaceTarget (); + speed = Speed * (2./3); + VelFromAngle(speed); + double dist = DistanceBySpeed(target, speed); + Vel.Z = (target.pos.z - pos.z) / dist; + reactiontime = 60; + bNoGravity = true; + } + + void A_InquisitorCheckLand () + { + reactiontime--; + if (reactiontime < 0 || + Vel.X == 0 || + Vel.Y == 0 || + pos.z <= floorz) + { + SetState (SeeState); + reactiontime = 0; + bNoGravity = false; + A_StopSound (CHAN_ITEM); + return; + } + A_PlaySound ("inquisitor/jump", CHAN_ITEM, 1, true); + } + + void A_TossArm () + { + Actor foo = Spawn("InquisitorArm", Pos + (0,0,24), ALLOW_REPLACE); + foo.angle = angle - 90. + Random2[Inquisitor]() * (360./1024.); + foo.VelFromAngle(foo.Speed / 8); + foo.Vel.Z = random[Inquisitor]() / 64.; + } + + } // Inquisitor Shot ---------------------------------------------------------- @@ -109,7 +205,7 @@ class InquisitorShot : Actor UBAM AB 3 A_Countdown; Loop; Death: - BNG2 A 0 Bright A_SetTranslucent(1,1); + BNG2 A 0 Bright A_SetRenderStyle(1, STYLE_Normal); BNG2 A 4 Bright A_Explode(192, 192, 1, 1); BNG2 B 4 Bright; BNG2 C 4 Bright; From 119bcb924d134db5befa459d89ee5b6664081508 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 28 Nov 2016 18:59:57 +0100 Subject: [PATCH 156/185] - scriptified the Loremaster. --- src/CMakeLists.txt | 1 - src/g_strife/a_loremaster.cpp | 43 --------------------- src/g_strife/a_strifestuff.cpp | 1 - src/p_mobj.cpp | 11 +++++- wadsrc/static/zscript/actor.txt | 1 + wadsrc/static/zscript/strife/loremaster.txt | 24 ++++++++++-- 6 files changed, 31 insertions(+), 50 deletions(-) delete mode 100644 src/g_strife/a_loremaster.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 74760f138..eddf2d9e9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -861,7 +861,6 @@ set( NOT_COMPILED_SOURCE_FILES sc_man_scanner.re g_hexen/a_heresiarch.cpp g_hexen/a_spike.cpp - g_strife/a_loremaster.cpp g_strife/a_oracle.cpp g_strife/a_programmer.cpp g_strife/a_rebels.cpp diff --git a/src/g_strife/a_loremaster.cpp b/src/g_strife/a_loremaster.cpp deleted file mode 100644 index 747ba326a..000000000 --- a/src/g_strife/a_loremaster.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* -#include "actor.h" -#include "a_action.h" -#include "a_strifeglobal.h" -#include "m_random.h" -#include "p_local.h" -#include "s_sound.h" -#include "vm.h" -*/ - -// Loremaster (aka Priest) -------------------------------------------------- - -class ALoreShot : public AActor -{ - DECLARE_CLASS (ALoreShot, AActor) -public: - int DoSpecialDamage (AActor *victim, int damage, FName damagetype); -}; - -IMPLEMENT_CLASS(ALoreShot, false, false) - -int ALoreShot::DoSpecialDamage (AActor *victim, int damage, FName damagetype) -{ - - if (victim != NULL && target != NULL && !(victim->flags7 & MF7_DONTTHRUST)) - { - DVector3 thrust = victim->Vec3To(target); - thrust.MakeResize(255. * 50 / MAX(victim->Mass, 1)); - victim->Vel += thrust; - } - return damage; -} - -DEFINE_ACTION_FUNCTION(AActor, A_LoremasterChain) -{ - PARAM_SELF_PROLOGUE(AActor); - - S_Sound (self, CHAN_BODY, "loremaster/active", 1, ATTN_NORM); - Spawn("LoreShot2", self->Pos(), ALLOW_REPLACE); - Spawn("LoreShot2", self->Vec3Offset(-self->Vel/2.), ALLOW_REPLACE); - Spawn("LoreShot2", self->Vec3Offset(-self->Vel), ALLOW_REPLACE); - return 0; -} diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp index ba316175d..e8ae59c18 100644 --- a/src/g_strife/a_strifestuff.cpp +++ b/src/g_strife/a_strifestuff.cpp @@ -24,7 +24,6 @@ #include "vm.h" // Include all the other Strife stuff here to reduce compile time -#include "a_loremaster.cpp" #include "a_oracle.cpp" #include "a_programmer.cpp" #include "a_rebels.cpp" diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 93c9b80f3..8424caee8 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -7509,13 +7509,20 @@ DEFINE_ACTION_FUNCTION(AActor, Vec2Angle) } +DEFINE_ACTION_FUNCTION(AActor, Vec3To) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(t, AActor) + ACTION_RETURN_VEC3(self->Vec3To(t)); +} + DEFINE_ACTION_FUNCTION(AActor, Vec3Angle) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT(length) - PARAM_ANGLE(angle); + PARAM_ANGLE(angle); PARAM_FLOAT(z); - PARAM_BOOL_DEF(absolute); + PARAM_BOOL_DEF(absolute); ACTION_RETURN_VEC3(self->Vec3Angle(length, angle, z, absolute)); } diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 3b49e3e3c..2d2725d1e 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -354,6 +354,7 @@ class Actor : Thinker native native double AngleTo(Actor target, bool absolute = false); native void AddZ(double zadd, bool moving = true); native void SetZ(double z); + native vector3 Vec3To(Actor other); native vector3 Vec3Offset(double x, double y, double z, bool absolute = false); native vector3 Vec3Angle(double length, double angle, double z = 0, bool absolute = false); native vector2 Vec2Angle(double length, double angle, bool absolute = false); diff --git a/wadsrc/static/zscript/strife/loremaster.txt b/wadsrc/static/zscript/strife/loremaster.txt index 4a48cf4d3..14571f91c 100644 --- a/wadsrc/static/zscript/strife/loremaster.txt +++ b/wadsrc/static/zscript/strife/loremaster.txt @@ -76,7 +76,7 @@ class Loremaster : Actor // Loremaster Projectile ---------------------------------------------------- -class LoreShot : Actor native +class LoreShot : Actor { Default { @@ -91,8 +91,6 @@ class LoreShot : Actor native ActiveSound "loremaster/swish"; } - native void A_LoremasterChain (); - States { Spawn: @@ -102,6 +100,26 @@ class LoreShot : Actor native OCLW A 6; Stop; } + + override int DoSpecialDamage (Actor victim, int damage, Name damagetype) + { + + if (victim != NULL && target != NULL && !victim.bDontThrust) + { + Vector3 thrust = victim.Vec3To(target); + victim.Vel += thrust.Unit() * (255. * 50 / max(victim.Mass, 1)); + } + return damage; + } + + void A_LoremasterChain () + { + A_PlaySound ("loremaster/active", CHAN_BODY); + Spawn("LoreShot2", Pos, ALLOW_REPLACE); + Spawn("LoreShot2", Vec3Offset(-Vel.x/2., -Vel.y/2., -Vel.z/2.), ALLOW_REPLACE); + Spawn("LoreShot2", Vec3Offset(-Vel.x, -Vel.y, -Vel.z), ALLOW_REPLACE); + } + } // Loremaster Subprojectile ------------------------------------------------- From 360cbfba2a843e5e828cf17706816dc2f8743d37 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 28 Nov 2016 19:42:26 +0100 Subject: [PATCH 157/185] - scriptified Oracle, Programmer and Rebels. --- src/CMakeLists.txt | 3 - src/actor.h | 2 +- src/g_strife/a_oracle.cpp | 26 ---- src/g_strife/a_programmer.cpp | 141 ------------------ src/g_strife/a_rebels.cpp | 124 --------------- src/g_strife/a_strifeitems.cpp | 14 +- src/g_strife/a_strifestuff.cpp | 3 - src/p_mobj.cpp | 7 + wadsrc/static/zscript/actor.txt | 4 +- wadsrc/static/zscript/strife/oracle.txt | 17 ++- wadsrc/static/zscript/strife/programmer.txt | 115 +++++++++++++- wadsrc/static/zscript/strife/rebels.txt | 73 ++++++++- .../static/zscript/strife/strifehumanoid.txt | 18 +++ 13 files changed, 233 insertions(+), 314 deletions(-) delete mode 100644 src/g_strife/a_oracle.cpp delete mode 100644 src/g_strife/a_programmer.cpp delete mode 100644 src/g_strife/a_rebels.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index eddf2d9e9..885b9fd91 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -861,9 +861,6 @@ set( NOT_COMPILED_SOURCE_FILES sc_man_scanner.re g_hexen/a_heresiarch.cpp g_hexen/a_spike.cpp - g_strife/a_oracle.cpp - g_strife/a_programmer.cpp - g_strife/a_rebels.cpp g_strife/a_sentinel.cpp g_strife/a_stalker.cpp g_strife/a_strifeitems.cpp diff --git a/src/actor.h b/src/actor.h index 06a5e9f11..8e1b16739 100644 --- a/src/actor.h +++ b/src/actor.h @@ -696,7 +696,7 @@ public: bool UseInventory(AInventory *item); // Tosses an item out of the inventory. - virtual AInventory *DropInventory (AInventory *item); + AInventory *DropInventory (AInventory *item); // Removes all items from the inventory. void ClearInventory(); diff --git a/src/g_strife/a_oracle.cpp b/src/g_strife/a_oracle.cpp deleted file mode 100644 index f49849922..000000000 --- a/src/g_strife/a_oracle.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/* -#include "actor.h" -#include "a_action.h" -#include "a_strifeglobal.h" -#include "p_enemy.h" -#include "r_defs.h" -#include "vm.h" -*/ - - -DEFINE_ACTION_FUNCTION(AActor, A_WakeOracleSpectre) -{ - PARAM_SELF_PROLOGUE(AActor); - - TThinkerIterator it(NAME_AlienSpectre3); - AActor *spectre = it.Next(); - - if (spectre != NULL && spectre->health > 0 && self->target != spectre) - { - spectre->Sector->SoundTarget = spectre->LastHeard = self->LastHeard; - 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 deleted file mode 100644 index a02848dd2..000000000 --- a/src/g_strife/a_programmer.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* -#include "actor.h" -#include "m_random.h" -#include "a_action.h" -#include "p_local.h" -#include "p_enemy.h" -#include "s_sound.h" -#include "a_strifeglobal.h" -#include "vm.h" -#include "g_level.h" -#include "doomstat.h" -*/ -static FRandom pr_prog ("Programmer"); - -// The Programmer level ending thing ---------------------------------------- -// [RH] I took some liberties to make this "cooler" than it was in Strife. - -class AProgLevelEnder : public AInventory -{ - DECLARE_CLASS (AProgLevelEnder, AInventory) -public: - void Tick (); - PalEntry GetBlend (); -}; - -IMPLEMENT_CLASS(AProgLevelEnder, false, false) - -//============================================================================ -// -// AProgLevelEnder :: Tick -// -// Fade to black, end the level, then unfade. -// -//============================================================================ - -void AProgLevelEnder::Tick () -{ - if (special2 == 0) - { // fade out over .66 second - special1 += 255 / (TICRATE*2/3); - if (++special1 >= 255) - { - special1 = 255; - special2 = 1; - G_ExitLevel (0, false); - } - } - else - { // fade in over two seconds - special1 -= 255 / (TICRATE*2); - if (special1 <= 0) - { - Destroy (); - } - } -} - -//============================================================================ -// -// AProgLevelEnder :: GetBlend -// -//============================================================================ - -PalEntry AProgLevelEnder::GetBlend () -{ - return PalEntry ((BYTE)special1, 0, 0, 0); -} - -//============================================================================ -// -// A_ProgrammerMelee -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_ProgrammerMelee) -{ - PARAM_SELF_PROLOGUE(AActor); - - int damage; - - if (self->target == NULL) - return 0; - - A_FaceTarget (self); - - if (!self->CheckMeleeRange ()) - 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; -} - -//============================================================================ -// -// A_SpawnProgrammerBase -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SpawnProgrammerBase) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *foo = Spawn("ProgrammerBase", self->PosPlusZ(24.), ALLOW_REPLACE); - if (foo != NULL) - { - foo->Angles.Yaw = self->Angles.Yaw + 180. + pr_prog.Random2() * (360. / 1024.); - foo->VelFromAngle(); - foo->Vel.Z = pr_prog() / 128.; - } - return 0; -} - -//============================================================================ -// -// A_ProgrammerDeath -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_ProgrammerDeath) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (!CheckBossDeath (self)) - return 0; - - for (int i = 0; i < MAXPLAYERS; ++i) - { - if (playeringame[i] && players[i].health > 0) - { - players[i].mo->GiveInventoryType (RUNTIME_CLASS(AProgLevelEnder)); - break; - } - } - // the sky change scripts are now done as special actions in MAPINFO - A_BossDeath(self); - return 0; -} diff --git a/src/g_strife/a_rebels.cpp b/src/g_strife/a_rebels.cpp deleted file mode 100644 index d3d68153f..000000000 --- a/src/g_strife/a_rebels.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* -#include "actor.h" -#include "m_random.h" -#include "a_action.h" -#include "p_local.h" -#include "p_enemy.h" -#include "s_sound.h" -#include "gi.h" -#include "a_sharedglobal.h" -#include "a_strifeglobal.h" -#include "vm.h" -#include "doomstat.h" -*/ - -static FRandom pr_shootgun ("ShootGun"); - -//============================================================================ -// -// A_ShootGun -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_ShootGun) -{ - PARAM_SELF_PROLOGUE(AActor); - - DAngle pitch; - - if (self->target == NULL) - return 0; - - S_Sound (self, CHAN_WEAPON, "monsters/rifle", 1, ATTN_NORM); - A_FaceTarget (self); - pitch = P_AimLineAttack (self, self->Angles.Yaw, MISSILERANGE); - P_LineAttack (self, self->Angles.Yaw + pr_shootgun.Random2() * (11.25 / 256), - MISSILERANGE, pitch, - 3*(pr_shootgun() % 5 + 1), NAME_Hitscan, NAME_StrifePuff); - return 0; -} - -// Teleporter Beacon -------------------------------------------------------- - -class ATeleporterBeacon : public AInventory -{ - DECLARE_CLASS (ATeleporterBeacon, AInventory) -public: - bool Use (bool pickup); -}; - -IMPLEMENT_CLASS(ATeleporterBeacon, false, false) - -bool ATeleporterBeacon::Use (bool pickup) -{ - AInventory *drop; - - // Increase the amount by one so that when DropInventory decrements it, - // the actor will have the same number of beacons that he started with. - // When we return to UseInventory, it will take care of decrementing - // Amount again and disposing of this item if there are no more. - Amount++; - drop = Owner->DropInventory (this); - if (drop == NULL) - { - Amount--; - return false; - } - else - { - drop->SetState(drop->FindState(NAME_Drop)); - drop->target = Owner; - return true; - } -} - -DEFINE_ACTION_FUNCTION(AActor, A_Beacon) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *owner = self->target; - AActor *rebel; - - rebel = Spawn("Rebel1", self->PosAtZ(self->floorz), ALLOW_REPLACE); - if (!P_TryMove (rebel, rebel->Pos(), true)) - { - rebel->Destroy (); - return 0; - } - // Once the rebels start teleporting in, you can't pick up the beacon anymore. - self->flags &= ~MF_SPECIAL; - static_cast(self)->DropTime = 0; - // Set up the new rebel. - rebel->threshold = rebel->DefThreshold; - rebel->target = NULL; - rebel->flags4 |= MF4_INCOMBAT; - rebel->LastHeard = owner; // Make sure the rebels look for targets - if (deathmatch) - { - rebel->health *= 2; - } - if (owner != NULL) - { - // Rebels are the same color as their owner (but only in multiplayer) - if (multiplayer) - { - rebel->Translation = owner->Translation; - } - rebel->SetFriendPlayer(owner->player); - // Set the rebel's target to whatever last hurt the player, so long as it's not - // one of the player's other rebels. - if (owner->target != NULL && !rebel->IsFriend (owner->target)) - { - rebel->target = owner->target; - } - } - - rebel->SetState (rebel->SeeState); - rebel->Angles.Yaw = self->Angles.Yaw; - P_SpawnTeleportFog(rebel, rebel->Vec3Angle(20., self->Angles.Yaw, 0), false, true); - if (--self->health < 0) - { - self->SetState(self->FindState(NAME_Death)); - } - return 0; -} diff --git a/src/g_strife/a_strifeitems.cpp b/src/g_strife/a_strifeitems.cpp index 0f1132cbd..aa48d9839 100644 --- a/src/g_strife/a_strifeitems.cpp +++ b/src/g_strife/a_strifeitems.cpp @@ -180,8 +180,18 @@ IMPLEMENT_CLASS(ARaiseAlarm, false, false) bool ARaiseAlarm::TryPickup (AActor *&toucher) { P_NoiseAlert (toucher, toucher); - VMFrameStack stack1, *stack = &stack1; - CALL_ACTION(A_WakeOracleSpectre, toucher); + /* + ThinkerIterator it = ThinkerIterator.Create("AlienSpectre3"); + Actor spectre = Actor(it.Next()); + + if (spectre != NULL && spectre.health > 0 && toucher != spectre) + { + spectre.CurSector.SoundTarget = spectre.LastHeard = toucher; + spectre.target = toucher; + spectre.SetState (spectre.SeeState); + } + + */ GoAwayAndDie (); return true; } diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp index e8ae59c18..0a2f5c5fd 100644 --- a/src/g_strife/a_strifestuff.cpp +++ b/src/g_strife/a_strifestuff.cpp @@ -24,9 +24,6 @@ #include "vm.h" // Include all the other Strife stuff here to reduce compile time -#include "a_oracle.cpp" -#include "a_programmer.cpp" -#include "a_rebels.cpp" #include "a_sentinel.cpp" #include "a_stalker.cpp" #include "a_strifeitems.cpp" diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 8424caee8..c85b8bbbc 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1018,6 +1018,13 @@ AInventory *AActor::DropInventory (AInventory *item) return drop; } +DEFINE_ACTION_FUNCTION(AActor, DropInventory) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(item, AInventory); + ACTION_RETURN_OBJECT(self->DropInventory(item)); +} + //============================================================================ // // AActor :: FindInventory diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 2d2725d1e..35dee8fba 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -372,12 +372,13 @@ class Actor : Thinker native native void PlayActiveSound(); native void Howl(); - // DECORATE compatible functions native bool CheckClass(class checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false); native Inventory FindInventory(class itemtype, bool subclass = false); native Inventory GiveInventoryType(class itemtype); + native Inventory DropInventory (Inventory item); native bool GiveAmmo (Class type, int amount); + // DECORATE compatible functions native int CountInv(class itemtype, int ptr_select = AAPTR_DEFAULT); native double GetDistance(bool checkz, int ptr = AAPTR_TARGET); native double GetAngle(int flags, int ptr = AAPTR_DEFAULT); @@ -701,7 +702,6 @@ class Actor : Thinker native native void A_ClearLastHeard(); native bool A_SelectWeapon(class whichweapon, int flags = 0); native void A_ClassBossHealth(); - native void A_ShootGun(); native void A_RocketInFlight(); native void A_Bang4Cloud(); native void A_DropFire(); diff --git a/wadsrc/static/zscript/strife/oracle.txt b/wadsrc/static/zscript/strife/oracle.txt index 6023629c2..740a7b69a 100644 --- a/wadsrc/static/zscript/strife/oracle.txt +++ b/wadsrc/static/zscript/strife/oracle.txt @@ -19,8 +19,6 @@ class Oracle : Actor DropItem "Meat"; } - native void A_WakeOracleSpectre (); - States { Spawn: @@ -35,4 +33,19 @@ class Oracle : Actor ORCL Q -1; Stop; } + + void A_WakeOracleSpectre () + { + ThinkerIterator it = ThinkerIterator.Create("AlienSpectre3"); + Actor spectre = Actor(it.Next()); + + if (spectre != NULL && spectre.health > 0 && self.target != spectre) + { + spectre.CurSector.SoundTarget = spectre.LastHeard = self.LastHeard; + spectre.target = self.target; + spectre.SetState (spectre.SeeState); + } + } + + } diff --git a/wadsrc/static/zscript/strife/programmer.txt b/wadsrc/static/zscript/strife/programmer.txt index 9ef9bdeb0..3fa34b659 100644 --- a/wadsrc/static/zscript/strife/programmer.txt +++ b/wadsrc/static/zscript/strife/programmer.txt @@ -33,10 +33,6 @@ class Programmer : Actor DropItem "Sigil1"; } - native void A_ProgrammerMelee (); - native void A_SpawnProgrammerBase (); - native void A_ProgrammerDeath (); - States { Spawn: @@ -80,6 +76,69 @@ class Programmer : Actor Stop; } + //============================================================================ + // + // A_ProgrammerMelee + // + //============================================================================ + + void A_ProgrammerMelee () + { + if (target == null) + return; + + A_FaceTarget (); + + if (!CheckMeleeRange ()) + return; + + A_PlaySound("programmer/clank", CHAN_WEAPON); + + int damage = ((random[Programmer]() % 10) + 1) * 6; + int newdam = DamageMobj (self, self, damage, 'Melee'); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + } + + //============================================================================ + // + // A_SpawnProgrammerBase + // + //============================================================================ + + void A_SpawnProgrammerBase () + { + Actor foo = Spawn("ProgrammerBase", Pos + (0,0,24), ALLOW_REPLACE); + if (foo != null) + { + foo.Angle = Angle + 180. + Random2[Programmer]() * (360. / 1024.); + foo.VelFromAngle(); + foo.Vel.Z = random[Programmer]() / 128.; + } + } + + //============================================================================ + // + // A_ProgrammerDeath + // + //============================================================================ + + void A_ProgrammerDeath () + { + if (!CheckBossDeath ()) + return; + + for (int i = 0; i < MAXPLAYERS; ++i) + { + if (playeringame[i] && players[i].health > 0) + { + players[i].mo.GiveInventoryType ("ProgLevelEnder"); + break; + } + } + // the sky change scripts are now done as special actions in MAPINFO + A_BossDeath(); + } + //============================================================================ // // A_SpotLightning @@ -88,10 +147,10 @@ class Programmer : Actor void A_SpotLightning() { - if (target == NULL) return; + if (target == null) return; Actor spot = Spawn("SpectralLightningSpot", (target.pos.xy, target.floorz), ALLOW_REPLACE); - if (spot != NULL) + if (spot != null) { spot.threshold = 25; spot.target = self; @@ -127,10 +186,52 @@ class ProgrammerBase : Actor // The Programmer level ending thing ---------------------------------------- -class ProgLevelEnder : Inventory native +class ProgLevelEnder : Inventory { Default { +INVENTORY.UNDROPPABLE } + + + //============================================================================ + // + // AProgLevelEnder :: Tick + // + // Fade to black, end the level, then unfade. + // + //============================================================================ + + override void Tick () + { + if (special2 == 0) + { // fade out over .66 second + special1 += 255 / (TICRATE*2/3); + if (++special1 >= 255) + { + special1 = 255; + special2 = 1; + Exit_Normal(0); + } + } + else + { // fade in over two seconds + special1 -= 255 / (TICRATE*2); + if (special1 <= 0) + { + Destroy (); + } + } + } + + //============================================================================ + // + // AProgLevelEnder :: GetBlend + // + //============================================================================ + + override Color GetBlend () + { + return Color(special1, 0, 0, 0); + } } diff --git a/wadsrc/static/zscript/strife/rebels.txt b/wadsrc/static/zscript/strife/rebels.txt index d9e65560f..24deea25b 100644 --- a/wadsrc/static/zscript/strife/rebels.txt +++ b/wadsrc/static/zscript/strife/rebels.txt @@ -107,7 +107,7 @@ class Rebel6 : Rebel // Teleporter Beacon -------------------------------------------------------- -class TeleporterBeacon : Inventory native +class TeleporterBeacon : Inventory { Default { @@ -122,8 +122,6 @@ class TeleporterBeacon : Inventory native Inventory.PickupMessage "$TXT_BEACON"; } - native void A_Beacon (); - States { Spawn: @@ -137,4 +135,73 @@ class TeleporterBeacon : Inventory native BEAC A 1 A_FadeOut(0.015); Loop; } + + // Teleporter Beacon -------------------------------------------------------- + + override bool Use (bool pickup) + { + // Increase the amount by one so that when DropInventory decrements it, + // the actor will have the same number of beacons that he started with. + // When we return to UseInventory, it will take care of decrementing + // Amount again and disposing of self item if there are no more. + Amount++; + Inventory drop = Owner.DropInventory (self); + if (drop == null) + { + Amount--; + return false; + } + else + { + drop.SetStateLabel("Drop"); + drop.target = Owner; + return true; + } + } + + void A_Beacon() + { + Actor owner = target; + Actor rebel = Spawn("Rebel1", (pos.xy, floorz), ALLOW_REPLACE); + if (!rebel.TryMove (rebel.Pos.xy, true)) + { + rebel.Destroy (); + return; + } + // Once the rebels start teleporting in, you can't pick up the beacon anymore. + bSpecial = false; + Inventory(self).DropTime = 0; + // Set up the new rebel. + rebel.threshold = rebel.DefThreshold; + rebel.target = null; + rebel.bInCombat = true; + rebel.LastHeard = owner; // Make sure the rebels look for targets + if (deathmatch) + { + rebel.health *= 2; + } + if (owner != null) + { + // Rebels are the same color as their owner (but only in multiplayer) + if (multiplayer) + { + rebel.Translation = owner.Translation; + } + rebel.SetFriendPlayer(owner.player); + // Set the rebel's target to whatever last hurt the player, so long as it's not + // one of the player's other rebels. + if (owner.target != null && !rebel.IsFriend (owner.target)) + { + rebel.target = owner.target; + } + } + + rebel.SetState (rebel.SeeState); + rebel.Angle = Angle; + rebel.SpawnTeleportFog(rebel.Vec3Angle(20., Angle, 0), false, true); + if (--health < 0) + { + SetStateLabel("Death"); + } + } } \ No newline at end of file diff --git a/wadsrc/static/zscript/strife/strifehumanoid.txt b/wadsrc/static/zscript/strife/strifehumanoid.txt index 7ac776026..7cec969ea 100644 --- a/wadsrc/static/zscript/strife/strifehumanoid.txt +++ b/wadsrc/static/zscript/strife/strifehumanoid.txt @@ -56,3 +56,21 @@ class FireDroplet : Actor } +extend class Actor +{ + //============================================================================ + // + // A_ShootGun + // + //============================================================================ + + void A_ShootGun() + { + if (!target) return; + A_PlaySound ("monsters/rifle", CHAN_WEAPON); + A_FaceTarget (); + double pitch = AimLineAttack (angle, MISSILERANGE); + LineAttack (Angle + Random2[ShootGun]() * (11.25 / 256), MISSILERANGE, pitch, 3*(random[ShootGun]() % 5 + 1), 'Hitscan', "StrifePuff"); + } + +} \ No newline at end of file From dd5494d848f0ca07dd77ecc1e624b0a419d56fca Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 28 Nov 2016 19:56:16 +0100 Subject: [PATCH 158/185] - scriptified Stalker and Sentinel. --- src/CMakeLists.txt | 2 - src/g_strife/a_sentinel.cpp | 95 ----------------------- src/g_strife/a_stalker.cpp | 88 --------------------- src/g_strife/a_strifestuff.cpp | 2 - wadsrc/static/zscript/actor.txt | 2 - wadsrc/static/zscript/strife/sentinel.txt | 79 ++++++++++++++++++- wadsrc/static/zscript/strife/stalker.txt | 68 ++++++++++++++-- 7 files changed, 139 insertions(+), 197 deletions(-) delete mode 100644 src/g_strife/a_sentinel.cpp delete mode 100644 src/g_strife/a_stalker.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 885b9fd91..841521802 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -861,8 +861,6 @@ set( NOT_COMPILED_SOURCE_FILES sc_man_scanner.re g_hexen/a_heresiarch.cpp g_hexen/a_spike.cpp - g_strife/a_sentinel.cpp - g_strife/a_stalker.cpp g_strife/a_strifeitems.cpp g_strife/a_strifeweapons.cpp g_strife/a_thingstoblowup.cpp diff --git a/src/g_strife/a_sentinel.cpp b/src/g_strife/a_sentinel.cpp deleted file mode 100644 index 44946c84a..000000000 --- a/src/g_strife/a_sentinel.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* -#include "actor.h" -#include "p_enemy.h" -#include "a_action.h" -#include "p_local.h" -#include "m_random.h" -#include "vm.h" -*/ - -static FRandom pr_sentinelrefire ("SentinelRefire"); - -DEFINE_ACTION_FUNCTION(AActor, A_SentinelBob) -{ - PARAM_SELF_PROLOGUE(AActor); - - double minz, maxz; - - if (self->flags & MF_INFLOAT) - { - self->Vel.Z = 0; - return 0; - } - if (self->threshold != 0) - return 0; - - maxz = self->ceilingz - self->Height - 16; - minz = self->floorz + 96; - if (minz > maxz) - { - minz = maxz; - } - if (minz < self->Z()) - { - self->Vel.Z -= 1; - } - else - { - self->Vel.Z += 1; - } - self->reactiontime = (minz >= self->Z()) ? 4 : 0; - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_SentinelAttack) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *missile, *trail; - - // [BB] Without a target the P_SpawnMissileZAimed call will crash. - if (!self->target) - { - return 0; - } - - missile = P_SpawnMissileZAimed (self, self->Z() + 32, self->target, PClass::FindActor("SentinelFX2")); - - if (missile != NULL && (missile->Vel.X != 0 || missile->Vel.Y != 0)) - { - for (int i = 8; i > 1; --i) - { - trail = Spawn("SentinelFX1", - self->Vec3Angle(missile->radius*i, missile->Angles.Yaw, 32 + missile->Vel.Z / 4 * i), ALLOW_REPLACE); - if (trail != NULL) - { - trail->target = self; - trail->Vel = missile->Vel; - P_CheckMissileSpawn (trail, self->radius); - } - } - missile->AddZ(missile->Vel.Z / 4); - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_SentinelRefire) -{ - PARAM_SELF_PROLOGUE(AActor); - - A_FaceTarget (self); - - if (pr_sentinelrefire() >= 30) - { - if (self->target == NULL || - self->target->health <= 0 || - !P_CheckSight (self, self->target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES) || - P_HitFriend(self) || - (self->MissileState == NULL && !self->CheckMeleeRange()) || - pr_sentinelrefire() < 40) - { - self->SetState (self->SeeState); - } - } - return 0; -} diff --git a/src/g_strife/a_stalker.cpp b/src/g_strife/a_stalker.cpp deleted file mode 100644 index 9189ef8de..000000000 --- a/src/g_strife/a_stalker.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* -#include "actor.h" -#include "m_random.h" -#include "a_action.h" -#include "p_local.h" -#include "p_enemy.h" -#include "s_sound.h" -#include "vm.h" -*/ - -static FRandom pr_stalker ("Stalker"); - - -DEFINE_ACTION_FUNCTION(AActor, A_StalkerChaseDecide) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (!(self->flags & MF_NOGRAVITY)) - { - self->SetState (self->FindState("SeeFloor")); - } - else if (self->ceilingz > self->Top()) - { - self->SetState (self->FindState("Drop")); - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_StalkerLookInit) -{ - PARAM_SELF_PROLOGUE(AActor); - - FState *state; - if (self->flags & MF_NOGRAVITY) - { - state = self->FindState("LookCeiling"); - } - else - { - state = self->FindState("LookFloor"); - } - if (self->state->NextState != state) - { - self->SetState (state); - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_StalkerDrop) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->flags5 &= ~MF5_NOVERTICALMELEERANGE; - self->flags &= ~MF_NOGRAVITY; - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_StalkerAttack) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (self->flags & MF_NOGRAVITY) - { - self->SetState (self->FindState("Drop")); - } - else if (self->target != NULL) - { - A_FaceTarget (self); - if (self->CheckMeleeRange ()) - { - int damage = (pr_stalker() & 7) * 2 + 2; - - int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); - } - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_StalkerWalk) -{ - PARAM_SELF_PROLOGUE(AActor); - - S_Sound (self, CHAN_BODY, "stalker/walk", 1, ATTN_NORM); - A_Chase (stack, self); - return 0; -} - diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp index 0a2f5c5fd..3d475a58b 100644 --- a/src/g_strife/a_strifestuff.cpp +++ b/src/g_strife/a_strifestuff.cpp @@ -24,8 +24,6 @@ #include "vm.h" // Include all the other Strife stuff here to reduce compile time -#include "a_sentinel.cpp" -#include "a_stalker.cpp" #include "a_strifeitems.cpp" #include "a_strifeweapons.cpp" #include "a_thingstoblowup.cpp" diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 35dee8fba..2d716f444 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -619,8 +619,6 @@ class Actor : Thinker native native void A_Wander(int flags = 0); native void A_Look2(); native void A_TossGib(); - native void A_SentinelBob(); - native void A_SentinelRefire(); native void A_SetShadow(); native void A_ClearShadow(); native void A_GetHurt(); diff --git a/wadsrc/static/zscript/strife/sentinel.txt b/wadsrc/static/zscript/strife/sentinel.txt index 946a99ea2..e9e6255d4 100644 --- a/wadsrc/static/zscript/strife/sentinel.txt +++ b/wadsrc/static/zscript/strife/sentinel.txt @@ -28,8 +28,6 @@ class Sentinel : Actor Obituary "$OB_SENTINEL"; } - native void A_SentinelAttack (); - States { Spawn: @@ -56,6 +54,34 @@ class Sentinel : Actor SEWR J 5; Stop; } + + void A_SentinelAttack () + { + // [BB] Without a target the P_SpawnMissileZAimed call will crash. + if (!target) + { + return; + } + + Actor missile = SpawnMissileZAimed (pos.z + 32, target, "SentinelFX2"); + + if (missile != NULL && (missile.Vel.X != 0 || missile.Vel.Y != 0)) + { + for (int i = 8; i > 1; --i) + { + Actor trail = Spawn("SentinelFX1", Vec3Angle(missile.radius*i, missile.angle, 32 + missile.Vel.Z / 4 * i), ALLOW_REPLACE); + if (trail != NULL) + { + trail.target = self; + trail.Vel = missile.Vel; + trail.CheckMissileSpawn (radius); + } + } + missile.AddZ(missile.Vel.Z / 4); + } + } + + } // Sentinel FX 1 ------------------------------------------------------------ @@ -102,3 +128,52 @@ class SentinelFX2 : SentinelFX1 } } + +extend class Actor +{ + // These are used elsewhere, too. + void A_SentinelBob() + { + if (bInFloat) + { + Vel.Z = 0; + return; + } + if (threshold != 0) + return; + + double maxz = ceilingz - Height - 16; + double minz = floorz + 96; + if (minz > maxz) + { + minz = maxz; + } + if (minz < pos.z) + { + Vel.Z -= 1; + } + else + { + Vel.Z += 1; + } + reactiontime = (minz >= pos.z) ? 4 : 0; + } + + void A_SentinelRefire() + { + A_FaceTarget (); + + if (random[SentinelRefire]() >= 30) + { + if (target == NULL || + target.health <= 0 || + !CheckSight (target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES) || + HitFriend() || + (MissileState == NULL && !CheckMeleeRange()) || + random[SentinelRefire]() < 40) + { + SetState (SeeState); + } + } + } +} \ No newline at end of file diff --git a/wadsrc/static/zscript/strife/stalker.txt b/wadsrc/static/zscript/strife/stalker.txt index 51a919041..cede9cae1 100644 --- a/wadsrc/static/zscript/strife/stalker.txt +++ b/wadsrc/static/zscript/strife/stalker.txt @@ -28,12 +28,6 @@ class Stalker : Actor HitObituary "$OB_STALKER"; } - native void A_StalkerLookInit (); - native void A_StalkerChaseDecide (); - native void A_StalkerWalk (); - native void A_StalkerDrop (); - native void A_StalkerAttack (); - States { Spawn: @@ -76,4 +70,66 @@ class Stalker : Actor STLK "XYZ[" 4 Bright; Stop; } + + void A_StalkerChaseDecide () + { + if (!bNoGravity) + { + SetStateLabel("SeeFloor"); + } + else if (ceilingz > pos.z + height) + { + SetStateLabel("Drop"); + } + } + + void A_StalkerLookInit () + { + State st; + if (!bNoGravity) + { + st = FindState("LookCeiling"); + } + else + { + st = FindState("LookFloor"); + } + if (st.NextState != st) + { + SetState (st); + } + } + + void A_StalkerDrop () + { + bNoVerticalMeleeRange = false; + bNoGravity = false; + } + + void A_StalkerAttack () + { + if (bNoGravity) + { + SetStateLabel("Drop"); + } + else if (target != null) + { + A_FaceTarget (); + if (CheckMeleeRange ()) + { + int damage = (random[Stalker]() & 7) * 2 + 2; + + int newdam = target.DamageMobj (self, self, damage, 'Melee'); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + } + } + } + + void A_StalkerWalk () + { + A_PlaySound ("stalker/walk", CHAN_BODY); + A_Chase (); + } + + } From caef5344b0304b07dcb14eba1424a0934c47934f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 28 Nov 2016 21:33:14 +0100 Subject: [PATCH 159/185] - scriptified a_thingstoblowup.cpp. - changed the power crystal floor movement to use DFloor instead of an incomplete in-place hack to ensure that everything is processed properly. --- src/CMakeLists.txt | 1 - src/g_strife/a_strifestuff.cpp | 42 ------ src/g_strife/a_thingstoblowup.cpp | 121 ------------------ src/p_floor.cpp | 15 +++ src/scripting/codegeneration/codegen.cpp | 3 +- wadsrc/static/zscript/actor.txt | 5 - wadsrc/static/zscript/base.txt | 68 ++++++++++ .../static/zscript/strife/strifehumanoid.txt | 27 ++++ .../static/zscript/strife/thingstoblowup.txt | 86 ++++++++++++- 9 files changed, 194 insertions(+), 174 deletions(-) delete mode 100644 src/g_strife/a_thingstoblowup.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 841521802..3ca87affa 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -863,7 +863,6 @@ set( NOT_COMPILED_SOURCE_FILES g_hexen/a_spike.cpp g_strife/a_strifeitems.cpp g_strife/a_strifeweapons.cpp - g_strife/a_thingstoblowup.cpp g_shared/sbarinfo_commands.cpp xlat/xlat_parser.y xlat_parser.c diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp index 3d475a58b..18a758e2e 100644 --- a/src/g_strife/a_strifestuff.cpp +++ b/src/g_strife/a_strifestuff.cpp @@ -26,7 +26,6 @@ // Include all the other Strife stuff here to reduce compile time #include "a_strifeitems.cpp" #include "a_strifeweapons.cpp" -#include "a_thingstoblowup.cpp" // Notes so I don't forget them: // Strife does some extra stuff in A_Explode if a player caused the explosion. (probably NoiseAlert) @@ -67,47 +66,6 @@ int AForceFieldGuard::TakeSpecialDamage (AActor *inflictor, AActor *source, int return health; } -// Kneeling Guy ------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_SetShadow) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->flags |= MF_STRIFEx8000000|MF_SHADOW; - self->RenderStyle = STYLE_Translucent; - self->Alpha = HR_SHADOW; - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_ClearShadow) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->flags &= ~(MF_STRIFEx8000000|MF_SHADOW); - self->RenderStyle = STYLE_Normal; - self->Alpha = 1.; - return 0; -} - -static FRandom pr_gethurt ("HurtMe!"); - -DEFINE_ACTION_FUNCTION(AActor, A_GetHurt) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->flags4 |= MF4_INCOMBAT; - if ((pr_gethurt() % 5) == 0) - { - S_Sound (self, CHAN_VOICE, self->PainSound, 1, ATTN_NORM); - self->health--; - } - if (self->health <= 0) - { - self->CallDie (self->target, self->target); - } - return 0; -} - // Klaxon Warning Light ----------------------------------------------------- DEFINE_ACTION_FUNCTION(AActor, A_TurretLook) diff --git a/src/g_strife/a_thingstoblowup.cpp b/src/g_strife/a_thingstoblowup.cpp deleted file mode 100644 index 08670d484..000000000 --- a/src/g_strife/a_thingstoblowup.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* -#include "actor.h" -#include "m_random.h" -#include "p_local.h" -#include "c_console.h" -#include "p_enemy.h" -#include "a_action.h" -#include "gstrings.h" -#include "vm.h" -#include "vm.h" -#include "doomstat.h" -*/ - -static FRandom pr_bang4cloud ("Bang4Cloud"); -static FRandom pr_lightout ("LightOut"); - -DEFINE_ACTION_FUNCTION(AActor, A_Bang4Cloud) -{ - PARAM_SELF_PROLOGUE(AActor); - - double xo = (pr_bang4cloud.Random2() & 3) * (10. / 64); - double yo = (pr_bang4cloud.Random2() & 3) * (10. / 64); - Spawn("Bang4Cloud", self->Vec3Offset(xo, yo, 0.), ALLOW_REPLACE); - return 0; -} - -// ------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_GiveQuestItem) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_INT(questitem); - - // Give one of these quest items to every player in the game - if (questitem >= 0 && questitem < (int)countof(QuestItemClasses)) - { - for (int i = 0; i < MAXPLAYERS; ++i) - { - if (playeringame[i]) - { - AInventory *item = static_cast(Spawn (QuestItemClasses[questitem - 1])); - if (!item->CallTryPickup (players[i].mo)) - { - item->Destroy (); - } - } - } - } - - char messageid[64]; - - mysnprintf(messageid, countof(messageid), "TXT_QUEST_%d", questitem); - const char * name = GStrings[messageid]; - - if (name != NULL) - { - C_MidPrint (SmallFont, name); - } - return 0; -} - -// PowerCrystal ------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_ExtraLightOff) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (self->target != NULL && self->target->player != NULL) - { - self->target->player->extralight = 0; - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_Explode512) -{ - PARAM_SELF_PROLOGUE(AActor); - - P_RadiusAttack (self, self->target, 512, 512, NAME_None, RADF_HURTSOURCE); - if (self->target != NULL && self->target->player != NULL) - { - self->target->player->extralight = 5; - } - P_CheckSplash(self, 512); - - // Strife didn't do this next part, but it looks good - self->RenderStyle = STYLE_Add; - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_LightGoesOut) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *foo; - sector_t *sec = self->Sector; - vertex_t *spot; - double newheight; - - sec->SetLightLevel(0); - - double oldtheight = sec->floorplane.fD(); - newheight = sec->FindLowestFloorSurrounding(&spot); - sec->floorplane.setD(sec->floorplane.PointToDist (spot, newheight)); - double newtheight = sec->floorplane.fD(); - sec->ChangePlaneTexZ(sector_t::floor, newtheight - oldtheight); - sec->CheckPortalPlane(sector_t::floor); - - for (int i = 0; i < 8; ++i) - { - foo = Spawn("Rubble1", self->Pos(), ALLOW_REPLACE); - if (foo != NULL) - { - int t = pr_lightout() & 15; - foo->Vel.X = t - (pr_lightout() & 7); - foo->Vel.Y = pr_lightout.Random2() & 7; - foo->Vel.Z = 7 + (pr_lightout() & 3); - } - } - return 0; -} diff --git a/src/p_floor.cpp b/src/p_floor.cpp index 0431fa808..8fd5ad038 100644 --- a/src/p_floor.cpp +++ b/src/p_floor.cpp @@ -492,6 +492,21 @@ bool P_CreateFloor(sector_t *sec, DFloor::EFloor floortype, line_t *line, return true; } +DEFINE_ACTION_FUNCTION(DFloor, CreateFloor) +{ + PARAM_PROLOGUE; + PARAM_POINTER(sec, sector_t); + PARAM_INT(floortype); + PARAM_POINTER(ln, line_t); + PARAM_FLOAT(speed); + PARAM_FLOAT_DEF(height); + PARAM_INT_DEF(crush); + PARAM_INT_DEF(change); + PARAM_BOOL_DEF(hereticlower); + PARAM_BOOL_DEF(hexencrush); + ACTION_RETURN_BOOL(P_CreateFloor(sec, (DFloor::EFloor)floortype, ln, speed, height, crush, change, hexencrush, hereticlower)); +} + //========================================================================== // // HANDLE FLOOR TYPES diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 5277ad70e..6912755b4 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -9512,7 +9512,8 @@ int BuiltinNameToClass(VMFrameStack *stack, VMValue *param, TArray &def if (!cls->IsDescendantOf(desttype)) { - Printf("class '%s' is not compatible with '%s'\n", clsname.GetChars(), desttype->TypeName.GetChars()); + // Let the caller check this. The message can be enabled for diagnostic purposes. + DPrintf(DMSG_SPAMMY, "class '%s' is not compatible with '%s'\n", clsname.GetChars(), desttype->TypeName.GetChars()); cls = nullptr; } ret->SetPointer(const_cast(cls), ATAG_OBJECT); diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 2d716f444..90cffb81a 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -619,9 +619,6 @@ class Actor : Thinker native native void A_Wander(int flags = 0); native void A_Look2(); native void A_TossGib(); - native void A_SetShadow(); - native void A_ClearShadow(); - native void A_GetHurt(); native void A_TurretLook(); native void A_KlaxonBlare(); native void A_Countdown(); @@ -701,9 +698,7 @@ class Actor : Thinker native native bool A_SelectWeapon(class whichweapon, int flags = 0); native void A_ClassBossHealth(); native void A_RocketInFlight(); - native void A_Bang4Cloud(); native void A_DropFire(); - native void A_GiveQuestItem(int itemno); native void A_RemoveForcefield(); native void A_SetAngle(double angle = 0, int flags = 0, int ptr = AAPTR_DEFAULT); native void A_SetPitch(double pitch, int flags = 0, int ptr = AAPTR_DEFAULT); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 8d2e7a71b..6f9b2dfe1 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -212,6 +212,28 @@ struct Sector native native uint16 ZoneNumber; native uint16 MoreFlags; + + enum ESectorFlags + { + SECF_SILENT = 1, // actors in sector make no noise + SECF_NOFALLINGDAMAGE= 2, // No falling damage in this sector + SECF_FLOORDROP = 4, // all actors standing on this floor will remain on it when it lowers very fast. + SECF_NORESPAWN = 8, // players can not respawn in this sector + SECF_FRICTION = 16, // sector has friction enabled + SECF_PUSH = 32, // pushers enabled + SECF_SILENTMOVE = 64, // Sector movement makes mo sound (Eternity got this so this may be useful for an extended cross-port standard.) + SECF_DMGTERRAINFX = 128, // spawns terrain splash when inflicting damage + SECF_ENDGODMODE = 256, // getting damaged by this sector ends god mode + SECF_ENDLEVEL = 512, // ends level when health goes below 10 + SECF_HAZARD = 1024, // Change to Strife's delayed damage handling. + + SECF_WASSECRET = 1 << 30, // a secret that was discovered + SECF_SECRET = 1 << 31, // a secret sector + + SECF_DAMAGEFLAGS = SECF_ENDGODMODE|SECF_ENDLEVEL|SECF_DMGTERRAINFX|SECF_HAZARD, + SECF_NOMODIFY = SECF_SECRET|SECF_WASSECRET, // not modifiable by Sector_ChangeFlags + SECF_SPECIALFLAGS = SECF_DAMAGEFLAGS|SECF_FRICTION|SECF_PUSH, // these flags originate from 'special and must be transferrable by floor thinkers + } native uint Flags; native SectorAction SecActTarget; @@ -286,3 +308,49 @@ struct String native { native void Replace(String pattern, String replacement); } + +class Floor : Thinker native +{ + // only here so that some constants and functions can be added. Not directly usable yet. + enum EFloor + { + floorLowerToLowest, + floorLowerToNearest, + floorLowerToHighest, + floorLowerByValue, + floorRaiseByValue, + floorRaiseToHighest, + floorRaiseToNearest, + floorRaiseAndCrush, + floorRaiseAndCrushDoom, + floorCrushStop, + floorLowerInstant, + floorRaiseInstant, + floorMoveToValue, + floorRaiseToLowestCeiling, + floorRaiseByTexture, + + floorLowerAndChange, + floorRaiseAndChange, + + floorRaiseToLowest, + floorRaiseToCeiling, + floorLowerToLowestCeiling, + floorLowerByTexture, + floorLowerToCeiling, + + donutRaise, + + buildStair, + waitStair, + resetStair, + + // Not to be used as parameters to EV_DoFloor() + genFloorChg0, + genFloorChgT, + genFloorChg + }; + + native static bool CreateFloor(sector sec, EFloor floortype, line ln, double speed, double height = 0, int crush = -1, int change = 0, bool hexencrush = false, bool hereticlower = false); + +} \ No newline at end of file diff --git a/wadsrc/static/zscript/strife/strifehumanoid.txt b/wadsrc/static/zscript/strife/strifehumanoid.txt index 7cec969ea..0686ec098 100644 --- a/wadsrc/static/zscript/strife/strifehumanoid.txt +++ b/wadsrc/static/zscript/strife/strifehumanoid.txt @@ -72,5 +72,32 @@ extend class Actor double pitch = AimLineAttack (angle, MISSILERANGE); LineAttack (Angle + Random2[ShootGun]() * (11.25 / 256), MISSILERANGE, pitch, 3*(random[ShootGun]() % 5 + 1), 'Hitscan', "StrifePuff"); } + + // Kneeling Guy ------------------------------------------------------------- + void A_SetShadow() + { + bShadow = true; + A_SetRenderStyle(HR_SHADOW, STYLE_Translucent); + } + + void A_ClearShadow() + { + bShadow = false; + A_SetRenderStyle(1, STYLE_Normal); + } + + void A_GetHurt() + { + bInCombat = true; + if ((random[HurtMe]() % 5) == 0) + { + A_PlaySound (PainSound, CHAN_VOICE); + health--; + } + if (health <= 0) + { + Die (target, target); + } + } } \ No newline at end of file diff --git a/wadsrc/static/zscript/strife/thingstoblowup.txt b/wadsrc/static/zscript/strife/thingstoblowup.txt index dbbad8ed6..5e5bfac21 100644 --- a/wadsrc/static/zscript/strife/thingstoblowup.txt +++ b/wadsrc/static/zscript/strife/thingstoblowup.txt @@ -1,4 +1,42 @@ +extend class Actor +{ + void A_Bang4Cloud() + { + double xo = (random[Bang4Cloud]() & 3) * (10. / 64); + double yo = (random[Bang4Cloud]() & 3) * (10. / 64); + Spawn("Bang4Cloud", Vec3Offset(xo, yo, 0.), ALLOW_REPLACE); + } + + void A_GiveQuestItem(int questitem) + { + // Give one of these quest items to every player in the game + if (questitem >= 0) + { + String itemname = "QuestItem" .. questitem; + class item = itemname; + if (item != null) + { + for (int i = 0; i < MAXPLAYERS; ++i) + { + if (playeringame[i]) + { + players[i].mo.GiveInventoryType(item); + } + } + } + } + + String msgid = "TXT_QUEST_" .. questitem; + String msg = StringTable.Localize(msgid); + + if (msg != msgid) // if both are identical there was no message of this name in the stringtable. + { + C_MidPrint ("SmallFont", msg); + } + } + +} // A Cloud used for varius explosions --------------------------------------- // This actor has no direct equivalent in strife. To create this, Strife @@ -121,10 +159,6 @@ class PowerCrystal : Actor ActiveSound "misc/reactor"; } - native void A_ExtraLightOff (); - native void A_Explode512 (); - native void A_LightGoesOut (); - States { Spawn: @@ -150,4 +184,48 @@ class PowerCrystal : Actor BOOM VWXY 3 Bright; Stop; } + + // PowerCrystal ------------------------------------------------------------------- + + void A_ExtraLightOff() + { + if (target != NULL && target.player != NULL) + { + target.player.extralight = 0; + } + } + + void A_Explode512() + { + A_Explode(512, 512); + if (target != NULL && target.player != NULL) + { + target.player.extralight = 5; + } + A_SetRenderStyle(1, STYLE_Add); + } + + void A_LightGoesOut() + { + sector sec = CurSector; + + sec.Flags |= Sector.SECF_SILENTMOVE; + sec.lightlevel = 0; + // Do this right with proper checks instead of just hacking the floor height. + Floor.CreateFloor(sec, Floor.floorLowerToLowest, null, 65536.); + + + for (int i = 0; i < 8; ++i) + { + Actor foo = Spawn("Rubble1", Pos, ALLOW_REPLACE); + if (foo != NULL) + { + int t = random[LightOut]() & 15; + foo.Vel.X = t - (random[LightOut]() & 7); + foo.Vel.Y = random2[LightOut]() & 7; + foo.Vel.Z = 7 + (random[LightOut]() & 3); + } + } + } + } From edd8e51a691a5ad1a79cb9dcaedafaf27895c965 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 28 Nov 2016 23:30:14 +0100 Subject: [PATCH 160/185] - scriptified most of a_strifestuff.cpp. --- src/g_strife/a_strifestuff.cpp | 246 ------------------ src/p_actionfunctions.cpp | 29 +++ src/p_enemy.cpp | 5 +- src/p_states.cpp | 13 + src/scripting/thingdef_data.cpp | 6 + wadsrc/static/zscript.txt | 2 + wadsrc/static/zscript/actor.txt | 12 +- wadsrc/static/zscript/base.txt | 2 + wadsrc/static/zscript/shared/player.txt | 9 + wadsrc/static/zscript/strife/acolyte.txt | 2 +- wadsrc/static/zscript/strife/klaxon.txt | 125 +++++++++ .../static/zscript/strife/strifefunctions.txt | 120 +++++++++ .../static/zscript/strife/strifehumanoid.txt | 47 ---- wadsrc/static/zscript/strife/strifeplayer.txt | 68 ++++- wadsrc/static/zscript/strife/strifestuff.txt | 73 ------ 15 files changed, 376 insertions(+), 383 deletions(-) create mode 100644 wadsrc/static/zscript/strife/klaxon.txt create mode 100644 wadsrc/static/zscript/strife/strifefunctions.txt diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp index 18a758e2e..20fe55de3 100644 --- a/src/g_strife/a_strifestuff.cpp +++ b/src/g_strife/a_strifestuff.cpp @@ -66,70 +66,6 @@ int AForceFieldGuard::TakeSpecialDamage (AActor *inflictor, AActor *source, int return health; } -// Klaxon Warning Light ----------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_TurretLook) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *target; - - if (self->flags5 & MF5_INCONVERSATION) - return 0; - - self->threshold = 0; - target = self->LastHeard; - if (target != NULL && - target->health > 0 && - target->flags & MF_SHOOTABLE && - (self->flags & MF_FRIENDLY) != (target->flags & MF_FRIENDLY)) - { - self->target = target; - if ((self->flags & MF_AMBUSH) && !P_CheckSight (self, target)) - { - return 0; - } - if (self->SeeSound != 0) - { - S_Sound (self, CHAN_VOICE, self->SeeSound, 1, ATTN_NORM); - } - self->LastHeard = NULL; - self->threshold = 10; - self->SetState (self->SeeState); - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_KlaxonBlare) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (--self->reactiontime < 0) - { - self->target = NULL; - self->reactiontime = self->GetDefault()->reactiontime; - CALL_ACTION(A_TurretLook, self); - if (self->target == NULL) - { - self->SetIdle(); - } - else - { - self->reactiontime = 50; - } - } - if (self->reactiontime == 2) - { - // [RH] Unalert monsters near the alarm and not just those in the same sector as it. - P_NoiseAlert (NULL, self, false); - } - else if (self->reactiontime > 50) - { - S_Sound (self, CHAN_VOICE, "misc/alarm", 1, ATTN_NORM); - } - return 0; -} - // Power Coupling ----------------------------------------------------------- class APowerCoupling : public AActor @@ -183,185 +119,3 @@ public: IMPLEMENT_CLASS(AMeat, false, false) -//========================================================================== -// -// A_TossGib -// -//========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_TossGib) -{ - PARAM_SELF_PROLOGUE(AActor); - - const char *gibtype = (self->flags & MF_NOBLOOD) ? "Junk" : "Meat"; - AActor *gib = Spawn (gibtype, self->PosPlusZ(24.), ALLOW_REPLACE); - - if (gib == NULL) - { - return 0; - } - - gib->Angles.Yaw = pr_gibtosser() * (360 / 256.f); - gib->VelFromAngle(pr_gibtosser() & 15); - gib->Vel.Z = pr_gibtosser() & 15; - return 0; -} - -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FLoopActiveSound) -{ - PARAM_SELF_PROLOGUE(AActor); - - 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_SELF_PROLOGUE(AActor); - - if (--self->reactiontime <= 0) - { - P_ExplodeMissile (self, NULL, NULL); - self->flags &= ~MF_SKULLFLY; - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_LoopActiveSound) -{ - PARAM_SELF_PROLOGUE(AActor); - - 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_SELF_PROLOGUE(AActor); - - sector_t *sec = self->Sector; - - if (self->Z() == sec->floorplane.ZatPoint(self) && sec->PortalBlocksMovement(sector_t::floor)) - { - if (sec->special == Damage_InstantDeath) - { - P_DamageMobj (self, NULL, NULL, 999, NAME_InstantDeath); - } - else if (sec->special == Scroll_StrifeCurrent) - { - int anglespeed = tagManager.GetFirstSectorTag(sec) - 100; - double speed = (anglespeed % 10) / 16.; - DAngle an = (anglespeed / 10) * (360 / 8.); - self->Thrust(an, speed); - } - } - return 0; -} - -//============================================================================ -// -// A_ClearSoundTarget -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_ClearSoundTarget) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *actor; - - self->Sector->SoundTarget = NULL; - for (actor = self->Sector->thinglist; actor != NULL; actor = actor->snext) - { - actor->LastHeard = NULL; - } - return 0; -} - - -DEFINE_ACTION_FUNCTION(AActor, A_ItBurnsItBurns) -{ - PARAM_SELF_PROLOGUE(AActor); - - S_Sound (self, CHAN_VOICE, "human/imonfire", 1, ATTN_NORM); - - if (self->player != nullptr && self->player->mo == self) - { - P_SetPsprite(self->player, PSP_STRIFEHANDS, self->FindState("FireHands")); - - self->player->ReadyWeapon = nullptr; - self->player->PendingWeapon = WP_NOCHANGE; - self->player->playerstate = PST_LIVE; - self->player->extralight = 3; - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_DropFire) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *drop = Spawn("FireDroplet", self->PosPlusZ(24.), ALLOW_REPLACE); - drop->Vel.Z = -1.; - P_RadiusAttack (self, self, 64, 64, NAME_Fire, 0); - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_CrispyPlayer) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (self->player != nullptr && self->player->mo == self) - { - DPSprite *psp; - psp = self->player->GetPSprite(PSP_STRIFEHANDS); - - FState *firehandslower = self->FindState("FireHandsLower"); - FState *firehands = self->FindState("FireHands"); - FState *state = psp->GetState(); - - if (state != nullptr && firehandslower != nullptr && firehands != nullptr && firehands < firehandslower) - { - self->player->playerstate = PST_DEAD; - psp->SetState(state + (firehandslower - firehands)); - } - else if (state == nullptr) - { - psp->SetState(nullptr); - } - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_HandLower) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (self->player != nullptr) - { - DPSprite *psp = self->player->GetPSprite(PSP_STRIFEHANDS); - - if (psp->GetState() == nullptr) - { - psp->SetState(nullptr); - return 0; - } - - psp->y += 9; - if (psp->y > WEAPONBOTTOM*2) - { - psp->SetState(nullptr); - } - - if (self->player->extralight > 0) self->player->extralight--; - } - return 0; -} diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index d33695a1b..a23e9943a 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -6807,3 +6807,32 @@ DEFINE_ACTION_FUNCTION(AActor, A_SetTranslation) self->SetTranslation(trname); return 0; } + +//========================================================================== +// +// +// +//========================================================================== + +DEFINE_ACTION_FUNCTION(AActor, A_CheckTerrain) +{ + PARAM_SELF_PROLOGUE(AActor); + + sector_t *sec = self->Sector; + + if (self->Z() == sec->floorplane.ZatPoint(self) && sec->PortalBlocksMovement(sector_t::floor)) + { + if (sec->special == Damage_InstantDeath) + { + P_DamageMobj(self, NULL, NULL, 999, NAME_InstantDeath); + } + else if (sec->special == Scroll_StrifeCurrent) + { + int anglespeed = tagManager.GetFirstSectorTag(sec) - 100; + double speed = (anglespeed % 10) / 16.; + DAngle an = (anglespeed / 10) * (360 / 8.); + self->Thrust(an, speed); + } + } + return 0; +} diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 3712ac86c..4d9393152 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -265,10 +265,11 @@ void P_NoiseAlert (AActor *target, AActor *emitter, bool splash, double maxdist) DEFINE_ACTION_FUNCTION(AActor, NoiseAlert) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(emitter, AActor); + PARAM_OBJECT(target, AActor); PARAM_BOOL_DEF(splash); PARAM_FLOAT_DEF(maxdist); - P_NoiseAlert(self, emitter, splash, maxdist); + // Note that the emitter is self, not the target of the alert! Target can be NULL. + P_NoiseAlert(target, self, splash, maxdist); return 0; } diff --git a/src/p_states.cpp b/src/p_states.cpp index f141cb550..7daaa5e41 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -1078,3 +1078,16 @@ DEFINE_FIELD_BIT(FState, StateFlags, bNoDelay, STF_NODELAY) DEFINE_FIELD_BIT(FState, StateFlags, bSameFrame, STF_SAMEFRAME) DEFINE_FIELD_BIT(FState, StateFlags, bCanRaise, STF_CANRAISE) DEFINE_FIELD_BIT(FState, StateFlags, bDehacked, STF_DEHACKED) + +DEFINE_ACTION_FUNCTION(FState, DistanceTo) +{ + PARAM_SELF_STRUCT_PROLOGUE(FState); + PARAM_POINTER(other, FState); + + // Safely calculate the distance between two states. + auto o1 = FState::StaticFindStateOwner(self); + int retv; + if (other < o1->OwnedStates || other >= o1->OwnedStates + o1->NumOwnedStates) retv = INT_MIN; + else retv = int(other - self); + ACTION_RETURN_INT(retv); +} diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index a1542a8a5..ee7cae76c 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -743,6 +743,12 @@ void InitThingdef() playerf = new PField("playeringame", parray, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&playeringame); GlobalSymbols.AddSymbol(playerf); + // Argh. It sucks when bad hacks need to be supported. WP_NOCHANGE is just a bogus pointer but it used everywhere as a special flag. + // It cannot be defined as constant because constants can either be numbers or strings but nothing else, so the only 'solution' + // is to create a static variable from it and reference that in the script. Yuck!!! + static AWeapon *wpnochg = WP_NOCHANGE; + playerf = new PField("WP_NOCHANGE", NewPointer(RUNTIME_CLASS(AWeapon), false), VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&wpnochg); + GlobalSymbols.AddSymbol(playerf); // this needs to be done manually until it can be given a proper type. RUNTIME_CLASS(AActor)->AddNativeField("DecalGenerator", NewPointer(TypeVoid), myoffsetof(AActor, DecalGenerator)); diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index fa0cebd96..d3ed13d7e 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -166,6 +166,7 @@ zscript/strife/coin.txt zscript/strife/crusader.txt zscript/strife/entityboss.txt zscript/strife/inquisitor.txt +zscript/strife/klaxon.txt zscript/strife/loremaster.txt zscript/strife/macil.txt zscript/strife/merchants.txt @@ -181,6 +182,7 @@ zscript/strife/sentinel.txt zscript/strife/stalker.txt zscript/strife/strifeammo.txt zscript/strife/strifearmor.txt +zscript/strife/strifefunctions.txt zscript/strife/strifeitems.txt zscript/strife/strifekeys.txt zscript/strife/strifestuff.txt diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 90cffb81a..7dbb5ee55 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -287,7 +287,7 @@ class Actor : Thinker native native bool isTeammate(Actor other); native int PlayerNumber(); native void SetFriendPlayer(PlayerInfo player); - native void NoiseAlert(Actor emitter, bool splash = false, double maxdist = 0); + native void NoiseAlert(Actor target, bool splash = false, double maxdist = 0); native void ClearBounce(); native TerrainDef GetFloorTerrain(); @@ -615,16 +615,11 @@ class Actor : Thinker native native void A_PlayerScream(); native void A_SkullPop(class skulltype = "BloodySkull"); native void A_CheckPlayerDone(); + native void A_CheckTerrain(); native void A_Wander(int flags = 0); native void A_Look2(); - native void A_TossGib(); - native void A_TurretLook(); - native void A_KlaxonBlare(); - native void A_Countdown(); native void A_AlertMonsters(double maxdist = 0, int flags = 0); - native void A_ClearSoundTarget(); - native void A_CheckTerrain(); deprecated native void A_MissileAttack(); deprecated native void A_MeleeAttack(); @@ -633,8 +628,6 @@ class Actor : Thinker native native void A_WolfAttack(int flags = 0, sound whattoplay = "weapons/pistol", double snipe = 1.0, int maxdamage = 64, int blocksize = 128, int pointblank = 2, int longrange = 4, double runspeed = 160.0, class pufftype = "BulletPuff"); native void A_PlaySound(sound whattoplay = "weapons/pistol", int slot = CHAN_BODY, double volume = 1.0, bool looping = false, double attenuation = ATTN_NORM, bool local = false); deprecated void A_PlayWeaponSound(sound whattoplay) { A_PlaySound(whattoplay, CHAN_WEAPON); } - native void A_FLoopActiveSound(); - native void A_LoopActiveSound(); native void A_StopSound(int slot = CHAN_VOICE); // Bad default but that's what is originally was... deprecated native void A_PlaySoundEx(sound whattoplay, name slot, bool looping = false, int attenuation = 0); deprecated native void A_StopSoundEx(name slot); @@ -698,7 +691,6 @@ class Actor : Thinker native native bool A_SelectWeapon(class whichweapon, int flags = 0); native void A_ClassBossHealth(); native void A_RocketInFlight(); - native void A_DropFire(); native void A_RemoveForcefield(); native void A_SetAngle(double angle = 0, int flags = 0, int ptr = AAPTR_DEFAULT); native void A_SetPitch(double pitch, int flags = 0, int ptr = AAPTR_DEFAULT); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 6f9b2dfe1..0f9c4f23d 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -131,6 +131,8 @@ struct State native native bool bSameFrame; native bool bCanRaise; native bool bDehacked; + + native int DistanceTo(state other); } struct F3DFloor native diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 6d1b8abfc..aa9b4a066 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -138,6 +138,15 @@ class PSprite : Object native } +enum EPlayerState +{ + PST_LIVE, // Playing or camping. + PST_DEAD, // Dead on the ground, view follows killer. + PST_REBORN, // Ready to restart/respawn??? + PST_ENTER, // [BC] Entered the game + PST_GONE // Player has left the game +} + struct PlayerInfo native // this is what internally is known as player_t { native readonly PlayerPawn mo; diff --git a/wadsrc/static/zscript/strife/acolyte.txt b/wadsrc/static/zscript/strife/acolyte.txt index 45f075d6b..6ae44f7f4 100644 --- a/wadsrc/static/zscript/strife/acolyte.txt +++ b/wadsrc/static/zscript/strife/acolyte.txt @@ -302,7 +302,7 @@ class AcolyteToBe : Acolyte Door_Close(999, 64); if (target != null && target.player != null) { - target.NoiseAlert (self); + NoiseAlert (target); } } } diff --git a/wadsrc/static/zscript/strife/klaxon.txt b/wadsrc/static/zscript/strife/klaxon.txt new file mode 100644 index 000000000..51c4d7df2 --- /dev/null +++ b/wadsrc/static/zscript/strife/klaxon.txt @@ -0,0 +1,125 @@ +// Klaxon Warning Light ----------------------------------------------------- + +class KlaxonWarningLight : Actor +{ + Default + { + ReactionTime 60; + Radius 5; + +NOBLOCKMAP +AMBUSH + +SPAWNCEILING +NOGRAVITY + +FIXMAPTHINGPOS +NOSPLASHALERT + +SYNCHRONIZED + } + States + { + Spawn: + KLAX A 5 A_TurretLook; + Loop; + See: + KLAX B 6 A_KlaxonBlare; + KLAX C 60; + Loop; + } + +} + +// CeilingTurret ------------------------------------------------------------ + +class CeilingTurret : Actor +{ + Default + { + Health 125; + Speed 0; + Painchance 0; + Mass 10000000; + Monster; + -SOLID + -CANPASS + +AMBUSH + +SPAWNCEILING + +NOGRAVITY + +NOBLOOD + +NOSPLASHALERT + +DONTFALL + MinMissileChance 150; + DeathSound "turret/death"; + } + States + { + Spawn: + TURT A 5 A_TurretLook; + Loop; + See: + TURT A 2 A_Chase; + Loop; + Missile: + Pain: + TURT B 4 Slow A_ShootGun; + TURT D 3 Slow A_SentinelRefire; + TURT A 4 A_SentinelRefire; + Loop; + Death: + BALL A 6 Bright A_Scream; + BALL BCDE 6 Bright; + TURT C -1; + Stop; + } +} + + +extend class Actor +{ + void A_TurretLook() + { + if (bInConversation) + return; + + threshold = 0; + Actor targ = LastHeard; + if (targ != NULL && targ.health > 0 && targ.bShootable && !IsFriend(targ)) + { + target = targ; + if (bAmbush && !CheckSight (targ)) + { + return; + } + if (SeeSound != 0) + { + A_PlaySound (SeeSound, CHAN_VOICE); + } + LastHeard = NULL; + threshold = 10; + SetState (SeeState); + } + } + + void A_KlaxonBlare() + { + if (--reactiontime < 0) + { + target = NULL; + reactiontime = Default.reactiontime; + A_TurretLook(); + if (target == NULL) + { + SetIdle(); + } + else + { + reactiontime = 50; + } + } + if (reactiontime == 2) + { + // [RH] Unalert monsters near the alarm and not just those in the same sector as it. + NoiseAlert (NULL, false); + } + else if (reactiontime > 50) + { + A_PlaySound ("misc/alarm", CHAN_VOICE); + } + } + +} \ No newline at end of file diff --git a/wadsrc/static/zscript/strife/strifefunctions.txt b/wadsrc/static/zscript/strife/strifefunctions.txt new file mode 100644 index 000000000..ed7db24d3 --- /dev/null +++ b/wadsrc/static/zscript/strife/strifefunctions.txt @@ -0,0 +1,120 @@ +// common Strife action functions. + +extend class Actor +{ + + //============================================================================ + + void A_FLoopActiveSound() + { + if (ActiveSound != 0 && !(level.time & 7)) + { + A_PlaySound (ActiveSound, CHAN_VOICE); + } + } + + void A_LoopActiveSound() + { + A_PlaySound(ActiveSound, CHAN_VOICE, 1, true); + } + + //============================================================================ + // + // + // + //============================================================================ + + void A_Countdown() + { + if (--reactiontime <= 0) + { + ExplodeMissile (); + bSkullFly = false; + } + } + + //============================================================================ + // + // A_ClearSoundTarget + // + //============================================================================ + + void A_ClearSoundTarget() + { + CurSector.SoundTarget = null; + for (Actor mo = CurSector.thinglist; mo != null; mo = mo.snext) + { + mo.LastHeard = null; + } + } + + //========================================================================== + // + // A_TossGib + // + //========================================================================== + + void A_TossGib() + { + class gibtype; + if (bNoBlood) gibtype = "Junk"; + else gibtype = "Meat"; + Actor gib = Spawn (gibtype, pos + (0,0,24), ALLOW_REPLACE); + + if (gib == null) + { + return; + } + + gib.Angle = random[GibTosser]() * (360 / 256.f); + gib.VelFromAngle(random[GibTosser]() & 15); + gib.Vel.Z = random[GibTosser]() & 15; + } + + // A_ShootGun ------------------------------------------------------------- + + void A_ShootGun() + { + if (!target) return; + A_PlaySound ("monsters/rifle", CHAN_WEAPON); + A_FaceTarget (); + double pitch = AimLineAttack (angle, MISSILERANGE); + LineAttack (Angle + Random2[ShootGun]() * (11.25 / 256), MISSILERANGE, pitch, 3*(random[ShootGun]() % 5 + 1), 'Hitscan', "StrifePuff"); + } + + // Kneeling Guy ------------------------------------------------------------- + + void A_SetShadow() + { + bShadow = true; + A_SetRenderStyle(HR_SHADOW, STYLE_Translucent); + } + + void A_ClearShadow() + { + bShadow = false; + A_SetRenderStyle(1, STYLE_Normal); + } + + void A_GetHurt() + { + bInCombat = true; + if ((random[HurtMe]() % 5) == 0) + { + A_PlaySound (PainSound, CHAN_VOICE); + health--; + } + if (health <= 0) + { + Die (target, target); + } + } + + void A_DropFire() + { + Actor drop = Spawn("FireDroplet", pos + (0,0,24), ALLOW_REPLACE); + drop.Vel.Z = -1.; + A_Explode(64, 64, XF_NOSPLASH, damagetype: 'Fire'); + } + +} diff --git a/wadsrc/static/zscript/strife/strifehumanoid.txt b/wadsrc/static/zscript/strife/strifehumanoid.txt index 0686ec098..26709cd93 100644 --- a/wadsrc/static/zscript/strife/strifehumanoid.txt +++ b/wadsrc/static/zscript/strife/strifehumanoid.txt @@ -54,50 +54,3 @@ class FireDroplet : Actor Stop; } } - - -extend class Actor -{ - //============================================================================ - // - // A_ShootGun - // - //============================================================================ - - void A_ShootGun() - { - if (!target) return; - A_PlaySound ("monsters/rifle", CHAN_WEAPON); - A_FaceTarget (); - double pitch = AimLineAttack (angle, MISSILERANGE); - LineAttack (Angle + Random2[ShootGun]() * (11.25 / 256), MISSILERANGE, pitch, 3*(random[ShootGun]() % 5 + 1), 'Hitscan', "StrifePuff"); - } - - // Kneeling Guy ------------------------------------------------------------- - - void A_SetShadow() - { - bShadow = true; - A_SetRenderStyle(HR_SHADOW, STYLE_Translucent); - } - - void A_ClearShadow() - { - bShadow = false; - A_SetRenderStyle(1, STYLE_Normal); - } - - void A_GetHurt() - { - bInCombat = true; - if ((random[HurtMe]() % 5) == 0) - { - A_PlaySound (PainSound, CHAN_VOICE); - health--; - } - if (health <= 0) - { - Die (target, target); - } - } -} \ No newline at end of file diff --git a/wadsrc/static/zscript/strife/strifeplayer.txt b/wadsrc/static/zscript/strife/strifeplayer.txt index 0b61e3122..2033fdb5e 100644 --- a/wadsrc/static/zscript/strife/strifeplayer.txt +++ b/wadsrc/static/zscript/strife/strifeplayer.txt @@ -36,10 +36,6 @@ class StrifePlayer : PlayerPawn Player.Colorset 7, "Blue", 0x90, 0x9F, 0x92, 0x20, 0x3F, 0x00, 0x1F, 0x50, 0x5F, 0x40, 0x4F, 0xC1, 0xCF, 0x01, 0x0F, 0xC0,0xC0,1,1, 0xD0, 0xDF, 0x10, 0x1F; } - native void A_ItBurnsItBurns(); - native void A_CrispyPlayer(); - native void A_HandLower(); - States { Spawn: @@ -101,5 +97,69 @@ class StrifePlayer : PlayerPawn WAVE ABCD 3 A_HandLower; Loop; } + + void A_ItBurnsItBurns() + { + A_PlaySound ("human/imonfire", CHAN_VOICE); + + if (player != null && player.mo == self) + { + player.SetPsprite(PSP_STRIFEHANDS, FindState("FireHands")); + + player.ReadyWeapon = null; + player.PendingWeapon = WP_NOCHANGE; + player.playerstate = PST_LIVE; + player.extralight = 3; + } + } + + void A_CrispyPlayer() + { + if (player != null && player.mo == self) + { + PSprite psp = player.GetPSprite(PSP_STRIFEHANDS); + + State firehandslower = FindState("FireHandsLower"); + State firehands = FindState("FireHands"); + + if (psp.CurState != null && firehandslower != null && firehands != null) + { + // Calculate state to go to. + int dist = firehands.DistanceTo(psp.curState); + if (dist > 0) + { + player.playerstate = PST_DEAD; + psp.SetState(firehandslower + dist); + return; + } + } + player.playerstate = PST_DEAD; + psp.SetState(null); + } + } + + void A_HandLower() + { + if (player != null) + { + PSprite psp = player.GetPSprite(PSP_STRIFEHANDS); + + if (psp.CurState == null) + { + psp.SetState(null); + return; + } + + psp.y += 9; + if (psp.y > WEAPONBOTTOM*2) + { + psp.SetState(null); + } + + if (player.extralight > 0) player.extralight--; + } + return; + } + } diff --git a/wadsrc/static/zscript/strife/strifestuff.txt b/wadsrc/static/zscript/strife/strifestuff.txt index e72e8d924..38a27889f 100644 --- a/wadsrc/static/zscript/strife/strifestuff.txt +++ b/wadsrc/static/zscript/strife/strifestuff.txt @@ -1796,81 +1796,8 @@ class KneelingGuy : Actor NEAL J -1; Stop; } - - } -// Klaxon Warning Light ----------------------------------------------------- - -class KlaxonWarningLight : Actor -{ - Default - { - ReactionTime 60; - Radius 5; - +NOBLOCKMAP +AMBUSH - +SPAWNCEILING +NOGRAVITY - +FIXMAPTHINGPOS +NOSPLASHALERT - +SYNCHRONIZED - } - States - { - Spawn: - KLAX A 5 A_TurretLook; - Loop; - See: - KLAX B 6 A_KlaxonBlare; - KLAX C 60; - Loop; - } - -} - -// CeilingTurret ------------------------------------------------------------ - -class CeilingTurret : Actor -{ - Default - { - Health 125; - Speed 0; - Painchance 0; - Mass 10000000; - Monster; - -SOLID - -CANPASS - +AMBUSH - +SPAWNCEILING - +NOGRAVITY - +NOBLOOD - +NOSPLASHALERT - +DONTFALL - MinMissileChance 150; - DeathSound "turret/death"; - } - States - { - Spawn: - TURT A 5 A_TurretLook; - Loop; - See: - TURT A 2 A_Chase; - Loop; - Missile: - Pain: - TURT B 4 Slow A_ShootGun; - TURT D 3 Slow A_SentinelRefire; - TURT A 4 A_SentinelRefire; - Loop; - Death: - BALL A 6 Bright A_Scream; - BALL BCDE 6 Bright; - TURT C -1; - Stop; - } -} - - // Power Coupling ----------------------------------------------------------- class PowerCoupling : Actor native From 55b549c0c63476abe5b8f448ecece0e56d4c363a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 29 Nov 2016 00:16:30 +0100 Subject: [PATCH 161/185] - converted the rest of a_strifestuff.cpp. - changed some very old A_Explode calls which passed all values as integer literals. --- src/actor.h | 1 + src/g_strife/a_strifeitems.cpp | 20 ----- src/g_strife/a_strifestuff.cpp | 84 ------------------- src/p_enemy.cpp | 9 ++ src/p_interaction.cpp | 2 +- src/p_lnspec.cpp | 14 +--- src/p_mobj.cpp | 26 ++++++ src/p_sectors.cpp | 28 +++++++ src/p_spec.cpp | 1 + src/r_defs.h | 1 + wadsrc/static/zscript/actor.txt | 3 +- wadsrc/static/zscript/base.txt | 1 + wadsrc/static/zscript/strife/crusader.txt | 6 +- wadsrc/static/zscript/strife/inquisitor.txt | 8 +- wadsrc/static/zscript/strife/reaver.txt | 2 +- wadsrc/static/zscript/strife/strifebishop.txt | 6 +- .../static/zscript/strife/strifefunctions.txt | 5 ++ wadsrc/static/zscript/strife/strifeitems.txt | 4 +- wadsrc/static/zscript/strife/strifestuff.txt | 53 +++++++++++- .../static/zscript/strife/strifeweapons.txt | 8 +- 20 files changed, 143 insertions(+), 139 deletions(-) diff --git a/src/actor.h b/src/actor.h index 8e1b16739..b627bac66 100644 --- a/src/actor.h +++ b/src/actor.h @@ -638,6 +638,7 @@ public: // Like DoSpecialDamage, but called on the actor receiving the damage. virtual int TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FName damagetype); + int CallTakeSpecialDamage(AActor *inflictor, AActor *source, int damage, FName damagetype); // Centaurs and ettins squeal when electrocuted, poisoned, or "holy"-ed // Made a metadata property so no longer virtual diff --git a/src/g_strife/a_strifeitems.cpp b/src/g_strife/a_strifeitems.cpp index aa48d9839..b9f3f288e 100644 --- a/src/g_strife/a_strifeitems.cpp +++ b/src/g_strife/a_strifeitems.cpp @@ -21,26 +21,6 @@ IMPLEMENT_CLASS(ADegninOre, false, false) -DEFINE_ACTION_FUNCTION(AActor, A_RemoveForceField) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->flags &= ~MF_SPECIAL; - - for (int i = 0; i < self->Sector->linecount; ++i) - { - line_t *line = self->Sector->lines[i]; - if (line->backsector != NULL && line->special == ForceField) - { - line->flags &= ~(ML_BLOCKING|ML_BLOCKEVERYTHING); - line->special = 0; - line->sidedef[0]->SetTexture(side_t::mid, FNullTextureID()); - line->sidedef[1]->SetTexture(side_t::mid, FNullTextureID()); - } - } - return 0; -} - bool ADegninOre::Use (bool pickup) { if (pickup) diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp index 20fe55de3..6537f180e 100644 --- a/src/g_strife/a_strifestuff.cpp +++ b/src/g_strife/a_strifestuff.cpp @@ -28,13 +28,6 @@ #include "a_strifeweapons.cpp" // Notes so I don't forget them: -// Strife does some extra stuff in A_Explode if a player caused the explosion. (probably NoiseAlert) -// See the instructions @ 21249. -// -// Strife's FLOATSPEED is 5 and not 4. -// -// In P_CheckMissileRange, mobjtypes 53,54,55,56,57,58 shift the distance right 4 bits (some, but not all the acolytes) -// mobjtypes 61,63,91 shift it right 1 bit // // When shooting missiles at something, if MF_SHADOW is set, the angle is adjusted with the formula: // angle += pr_spawnmissile.Random2() << 21 @@ -42,80 +35,3 @@ // angle += pr_spawnmissile.Random2() << 22 // Note that these numbers are different from those used by all the other Doom engine games. -static FRandom pr_gibtosser ("GibTosser"); - -// Force Field Guard -------------------------------------------------------- - -void A_RemoveForceField (AActor *); - -class AForceFieldGuard : public AActor -{ - DECLARE_CLASS (AForceFieldGuard, AActor) -public: - int TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FName damagetype); -}; - -IMPLEMENT_CLASS(AForceFieldGuard, false, false) - -int AForceFieldGuard::TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FName damagetype) -{ - if (inflictor == NULL || !inflictor->IsKindOf (RUNTIME_CLASS(ADegninOre))) - { - return -1; - } - return health; -} - -// Power Coupling ----------------------------------------------------------- - -class APowerCoupling : public AActor -{ - DECLARE_CLASS (APowerCoupling, AActor) -public: - void Die (AActor *source, AActor *inflictor, int dmgflags); -}; - -IMPLEMENT_CLASS(APowerCoupling, false, false) - -void APowerCoupling::Die (AActor *source, AActor *inflictor, int dmgflags) -{ - Super::Die (source, inflictor, dmgflags); - - int i; - - for (i = 0; i < MAXPLAYERS; ++i) - if (playeringame[i] && players[i].health > 0) - break; - - if (i == MAXPLAYERS) - return; - - // [RH] In case the player broke it with the dagger, alert the guards now. - if (LastHeard != source) - { - P_NoiseAlert (source, this); - } - EV_DoDoor (DDoor::doorClose, NULL, players[i].mo, 225, 2., 0, 0, 0); - EV_DoFloor (DFloor::floorLowerToHighest, NULL, 44, 1., 0., -1, 0, false); - players[i].mo->GiveInventoryType (QuestItemClasses[5]); - S_Sound (CHAN_VOICE, "svox/voc13", 1, ATTN_NORM); - players[i].SetLogNumber (13); - P_DropItem (this, PClass::FindActor("BrokenPowerCoupling"), -1, 256); - Destroy (); -} - -// Gibs for things that bleed ----------------------------------------------- - -class AMeat : public AActor -{ - DECLARE_CLASS (AMeat, AActor) -public: - void BeginPlay () - { - // Strife used mod 19, but there are 20 states. Hmm. - SetState (SpawnState + pr_gibtosser() % 20); - } -}; - -IMPLEMENT_CLASS(AMeat, false, false) - diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 4d9393152..6a59986c0 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -3224,6 +3224,15 @@ AInventory *P_DropItem (AActor *source, PClassActor *type, int dropamount, int c return NULL; } +DEFINE_ACTION_FUNCTION(AActor, DoDropItem) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_CLASS(cls, AActor); + PARAM_INT(amt); + PARAM_INT(chance); + ACTION_RETURN_OBJECT(P_DropItem(self, cls, amt, chance)); +} + //============================================================================ // // P_TossItem diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 41994c38e..a5fcc2dda 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1121,7 +1121,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, if (damage >= 0) { - damage = target->TakeSpecialDamage(inflictor, source, damage, mod); + damage = target->CallTakeSpecialDamage(inflictor, source, damage, mod); } // '<0' is handled below. This only handles the case where damage gets reduced to 0. diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index e41912e23..1f318f559 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -347,7 +347,7 @@ FUNC(LS_Floor_LowerToHighest) } FUNC(LS_Floor_LowerToHighestEE) -// Floor_LowerToHighest (tag, speed, change) +// Floor_LowerToHighestEE (tag, speed, change) { return EV_DoFloor (DFloor::floorLowerToHighest, ln, arg0, SPEED(arg1), 0, -1, CHANGE(arg2), false); } @@ -3152,17 +3152,7 @@ FUNC(LS_ClearForceField) sector_t *sec = §ors[secnum]; rtn = true; - for (int i = 0; i < sec->linecount; ++i) - { - line_t *line = sec->lines[i]; - if (line->backsector != NULL && line->special == ForceField) - { - line->flags &= ~(ML_BLOCKING|ML_BLOCKEVERYTHING); - line->special = 0; - line->sidedef[0]->SetTexture(side_t::mid, FNullTextureID()); - line->sidedef[1]->SetTexture(side_t::mid, FNullTextureID()); - } - } + sec->RemoveForceField(); } return rtn; } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index c85b8bbbc..7257eff95 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -7018,6 +7018,32 @@ int AActor::TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FN return (death == NULL) ? -1 : damage; } +DEFINE_ACTION_FUNCTION(AActor, TakeSpecialDamage) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(inflictor, AActor); + PARAM_OBJECT(source, AActor); + PARAM_INT(damage); + PARAM_NAME(damagetype); + ACTION_RETURN_INT(self->TakeSpecialDamage(inflictor, source, damage, damagetype)); +} + +int AActor::CallTakeSpecialDamage(AActor *inflictor, AActor *source, int damage, FName damagetype) +{ + IFVIRTUAL(AActor, TakeSpecialDamage) + { + VMValue params[5] = { (DObject*)this, inflictor, source, damage, damagetype.GetIndex() }; + VMReturn ret; + VMFrameStack stack; + int retval; + ret.IntAt(&retval); + stack.Call(func, params, 5, &ret, 1, nullptr); + return retval; + } + else return TakeSpecialDamage(inflictor, source, damage, damagetype); + +} + void AActor::Crash() { // [RC] Weird that this forces the Crash state regardless of flag. diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index 585c60f4b..e6302199b 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -22,6 +22,7 @@ //----------------------------------------------------------------------------- #include "p_spec.h" +#include "p_lnspec.h" #include "c_cvars.h" #include "doomstat.h" #include "g_level.h" @@ -1075,6 +1076,33 @@ double sector_t::NextLowestFloorAt(double x, double y, double z, int flags, doub } } + //=========================================================================== + // + // + // + //=========================================================================== + + void sector_t::RemoveForceField() + { + for (int i = 0; i < linecount; ++i) + { + line_t *line = lines[i]; + if (line->backsector != NULL && line->special == ForceField) + { + line->flags &= ~(ML_BLOCKING | ML_BLOCKEVERYTHING); + line->special = 0; + line->sidedef[0]->SetTexture(side_t::mid, FNullTextureID()); + line->sidedef[1]->SetTexture(side_t::mid, FNullTextureID()); + } + } + } + + DEFINE_ACTION_FUNCTION(_Sector, RemoveForceField) + { + PARAM_SELF_STRUCT_PROLOGUE(sector_t); + self->RemoveForceField(); + return 0; + } //=========================================================================== // // diff --git a/src/p_spec.cpp b/src/p_spec.cpp index c9a8294b5..eb6b9bea7 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -1591,3 +1591,4 @@ void sector_t::AdjustFloorClip () const } } } + diff --git a/src/r_defs.h b/src/r_defs.h index 9c2a822f2..a7de16c59 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -625,6 +625,7 @@ public: sector_t *NextSpecialSector (int type, sector_t *prev) const; // [RH] double FindLowestCeilingPoint(vertex_t **v) const; double FindHighestFloorPoint(vertex_t **v) const; + void RemoveForceField(); void AdjustFloorClip () const; void SetColor(int r, int g, int b, int desat); diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 7dbb5ee55..c5052ab79 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -264,6 +264,7 @@ class Actor : Thinker native virtual native void Activate(Actor activator); virtual native void Deactivate(Actor activator); virtual native int DoSpecialDamage (Actor target, int damage, Name damagetype); + virtual native int TakeSpecialDamage (Actor inflictor, Actor source, int damage, Name damagetype); virtual native void Die(Actor source, Actor inflictor, int dmgflags = 0); virtual native bool Slam(Actor victim); virtual native bool UseInventory(Inventory item); @@ -290,6 +291,7 @@ class Actor : Thinker native native void NoiseAlert(Actor target, bool splash = false, double maxdist = 0); native void ClearBounce(); native TerrainDef GetFloorTerrain(); + native Inventory DoDropItem(Class type, int dropamount, int chance); native void ExplodeMissile(line lin = null, Actor target = null); native void RestoreDamage(); @@ -691,7 +693,6 @@ class Actor : Thinker native native bool A_SelectWeapon(class whichweapon, int flags = 0); native void A_ClassBossHealth(); native void A_RocketInFlight(); - native void A_RemoveForcefield(); native void A_SetAngle(double angle = 0, int flags = 0, int ptr = AAPTR_DEFAULT); native void A_SetPitch(double pitch, int flags = 0, int ptr = AAPTR_DEFAULT); native void A_SetRoll(double roll, int flags = 0, int ptr = AAPTR_DEFAULT); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 0f9c4f23d..b0abc73ec 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -247,6 +247,7 @@ struct Sector native native double, Sector, F3DFloor NextHighestCeilingAt(double x, double y, double bottomz, double topz, int flags = 0); + native void RemoveForceField(); } struct Wads diff --git a/wadsrc/static/zscript/strife/crusader.txt b/wadsrc/static/zscript/strife/crusader.txt index 834464e06..ce2ba6ef8 100644 --- a/wadsrc/static/zscript/strife/crusader.txt +++ b/wadsrc/static/zscript/strife/crusader.txt @@ -52,11 +52,11 @@ class Crusader : Actor ROB2 G 3 A_Scream; ROB2 H 5 A_TossGib; ROB2 I 4 Bright A_TossGib; - ROB2 J 4 Bright A_Explode(64,64,1,1); + ROB2 J 4 Bright A_Explode(64, 64, alert:true); ROB2 K 4 Bright A_Fall; - ROB2 L 4 A_Explode(64,64,1,1); + ROB2 L 4 A_Explode(64, 64, alert:true); ROB2 MN 4 A_TossGib; - ROB2 O 4 A_Explode(64,64,1,1); + ROB2 O 4 A_Explode(64, 64, alert:true); ROB2 P -1 A_CrusaderDeath; Stop; } diff --git a/wadsrc/static/zscript/strife/inquisitor.txt b/wadsrc/static/zscript/strife/inquisitor.txt index ef73ade1e..6d3c5bc7f 100644 --- a/wadsrc/static/zscript/strife/inquisitor.txt +++ b/wadsrc/static/zscript/strife/inquisitor.txt @@ -58,16 +58,16 @@ class Inquisitor : Actor ROB3 L 4 A_TossGib; ROB3 M 4 A_Scream; ROB3 N 4 A_TossGib; - ROB3 O 4 Bright A_Explode(128,128,1,1); + ROB3 O 4 Bright A_Explode(128, 128, alert:true); ROB3 P 4 Bright A_TossGib; ROB3 Q 4 Bright A_NoBlocking; ROB3 RSTUV 4 A_TossGib; - ROB3 W 4 Bright A_Explode(128,128,1,1); + ROB3 W 4 Bright A_Explode(128, 128, alert:true); ROB3 XY 4 Bright A_TossGib; ROB3 Z 4 A_TossGib; ROB3 [ 4 A_TossGib; ROB3 \ 3 A_TossGib; - ROB3 ] 3 Bright A_Explode(128,128,1,1); + ROB3 ] 3 Bright A_Explode(128, 128, alert:true); RBB3 A 3 Bright A_TossArm; RBB3 B 3 Bright A_TossGib; RBB3 CD 3 A_TossGib; @@ -206,7 +206,7 @@ class InquisitorShot : Actor Loop; Death: BNG2 A 0 Bright A_SetRenderStyle(1, STYLE_Normal); - BNG2 A 4 Bright A_Explode(192, 192, 1, 1); + BNG2 A 4 Bright A_Explode(192, 192, alert:true); BNG2 B 4 Bright; BNG2 C 4 Bright; BNG2 D 4 Bright; diff --git a/wadsrc/static/zscript/strife/reaver.txt b/wadsrc/static/zscript/strife/reaver.txt index d1c206b73..6ebcd47e2 100644 --- a/wadsrc/static/zscript/strife/reaver.txt +++ b/wadsrc/static/zscript/strife/reaver.txt @@ -49,7 +49,7 @@ class Reaver : Actor ROB1 L 5; ROB1 M 5 A_NoBlocking; ROB1 NOP 5; - ROB1 Q 6 A_Explode(32,32,1,1); + ROB1 Q 6 A_Explode(32, 32, alert:true); ROB1 R -1; Stop; XDeath: diff --git a/wadsrc/static/zscript/strife/strifebishop.txt b/wadsrc/static/zscript/strife/strifebishop.txt index 98b09ecee..b7de186a2 100644 --- a/wadsrc/static/zscript/strife/strifebishop.txt +++ b/wadsrc/static/zscript/strife/strifebishop.txt @@ -47,7 +47,7 @@ class StrifeBishop : Actor MLDR G 3 Bright; MLDR H 5 Bright A_Scream; MLDR I 4 Bright A_TossGib; - MLDR J 4 Bright A_Explode(64,64,1,1); + MLDR J 4 Bright A_Explode(64, 64, alert:true); MLDR KL 3 Bright; MLDR M 4 Bright A_NoBlocking; MLDR N 4 Bright; @@ -88,8 +88,8 @@ class BishopMissile : Actor MISS B 3 Bright A_Tracer2; Loop; Death: - SMIS A 0 Bright A_SetTranslucent(1,1); - SMIS A 5 Bright A_Explode(64,64,1,1); + SMIS A 0 Bright A_SetRenderStyle(1, STYLE_Normal); + SMIS A 5 Bright A_Explode(64, 64, alert:true); SMIS B 5 Bright; SMIS C 4 Bright; SMIS DEFG 2 Bright; diff --git a/wadsrc/static/zscript/strife/strifefunctions.txt b/wadsrc/static/zscript/strife/strifefunctions.txt index ed7db24d3..febb2fdcb 100644 --- a/wadsrc/static/zscript/strife/strifefunctions.txt +++ b/wadsrc/static/zscript/strife/strifefunctions.txt @@ -117,4 +117,9 @@ extend class Actor A_Explode(64, 64, XF_NOSPLASH, damagetype: 'Fire'); } + void A_RemoveForceField() + { + bSpecial = false; + CurSector.RemoveForceField(); + } } diff --git a/wadsrc/static/zscript/strife/strifeitems.txt b/wadsrc/static/zscript/strife/strifeitems.txt index cfc939413..4d8e3d5e4 100644 --- a/wadsrc/static/zscript/strife/strifeitems.txt +++ b/wadsrc/static/zscript/strife/strifeitems.txt @@ -415,9 +415,9 @@ class DegninOre : Inventory native Stop; Death: XPRK A 1 A_RemoveForceField; - BNG3 A 0 A_SetTranslucent(1,1); + BNG3 A 0 A_SetRenderStyle(1, STYLE_Normal); BNG3 A 0 A_Scream; - BNG3 A 3 Bright A_Explode(192,192,1,1); + BNG3 A 3 Bright A_Explode(192, 192, alert:true); BNG3 BCDEFGH 3 Bright; Stop; } diff --git a/wadsrc/static/zscript/strife/strifestuff.txt b/wadsrc/static/zscript/strife/strifestuff.txt index 38a27889f..12502ad0d 100644 --- a/wadsrc/static/zscript/strife/strifestuff.txt +++ b/wadsrc/static/zscript/strife/strifestuff.txt @@ -192,7 +192,7 @@ class ExplosiveBarrel2 : Actor BART B 2 Bright A_Scream; BART CD 2 Bright; BART E 2 Bright A_NoBlocking; - BART F 2 Bright A_Explode(64, 64, 1, 1); + BART F 2 Bright A_Explode(64, 64, alert:true); BART GHIJ 2 Bright; BART K 3 Bright; BART L -1; @@ -1726,7 +1726,7 @@ class TargetPractice : Actor // Force Field Guard -------------------------------------------------------- -class ForceFieldGuard : Actor native +class ForceFieldGuard : Actor { Default { @@ -1748,6 +1748,16 @@ class ForceFieldGuard : Actor native TNT1 A 1 A_RemoveForceField; Stop; } + + override int TakeSpecialDamage (Actor inflictor, Actor source, int damage, Name damagetype) + { + if (inflictor == NULL || !(inflictor is "DegninOre")) + { + return -1; + } + return health; + } + } // Kneeling Guy ------------------------------------------------------------- @@ -1800,7 +1810,7 @@ class KneelingGuy : Actor // Power Coupling ----------------------------------------------------------- -class PowerCoupling : Actor native +class PowerCoupling : Actor { Default { @@ -1821,11 +1831,39 @@ class PowerCoupling : Actor native COUP AB 5; Loop; } + + override void Die (Actor source, Actor inflictor, int dmgflags) + { + Super.Die (source, inflictor, dmgflags); + + int i; + + for (i = 0; i < MAXPLAYERS; ++i) + if (playeringame[i] && players[i].health > 0) + break; + + if (i == MAXPLAYERS) + return; + + // [RH] In case the player broke it with the dagger, alert the guards now. + if (LastHeard != source) + { + NoiseAlert (source); + } + Door_Close(225, 16); + Floor_LowerToHighestEE(44, 8); + players[i].mo.GiveInventoryType ("QuestItem6"); + S_Sound ("svox/voc13", CHAN_VOICE); + players[i].SetLogNumber (13); + DoDropItem ("BrokenPowerCoupling", -1, 256); + Destroy (); + } + } // Gibs for things that bleed ----------------------------------------------- -class Meat : Actor native +class Meat : Actor { Default { @@ -1875,6 +1913,13 @@ class Meat : Actor native MEAT T 700; Stop; } + + override void BeginPlay () + { + // Strife used mod 19, but there are 20 states. Hmm. + SetState (SpawnState + random[GibTosser]() % 20); + } + } // Gibs for things that don't bleed ----------------------------------------- diff --git a/wadsrc/static/zscript/strife/strifeweapons.txt b/wadsrc/static/zscript/strife/strifeweapons.txt index 968e4c4c5..0180ea445 100644 --- a/wadsrc/static/zscript/strife/strifeweapons.txt +++ b/wadsrc/static/zscript/strife/strifeweapons.txt @@ -418,8 +418,8 @@ class MiniMissile : Actor MICR A 6 Bright A_RocketInFlight; Loop; Death: - SMIS A 0 Bright A_SetTranslucent(1,1); - SMIS A 5 Bright A_Explode(64,64,1,1); + SMIS A 0 Bright A_SetRenderStyle(1, STYLE_Normal); + SMIS A 5 Bright A_Explode(64, 64, alert:true); SMIS B 5 Bright; SMIS C 4 Bright; SMIS DEFG 2 Bright; @@ -715,8 +715,8 @@ class HEGrenade : Actor Loop; Death: BNG4 A 0 Bright A_NoGravity; - BNG4 A 0 Bright A_SetTranslucent(1,1); - BNG4 A 2 Bright A_Explode(192,192,1,1); + BNG4 A 0 Bright A_SetRenderStyle(1, STYLE_Normal); + BNG4 A 2 Bright A_Explode(192, 192, alert:true); BNG4 BCDEFGHIJKLMN 3 Bright; Stop; } From 3af9232fca01dbcd30abf0242cf67bf57c80a216 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 29 Nov 2016 12:17:05 +0100 Subject: [PATCH 162/185] - scriptified a_strifeitems.cpp and a_debris.cpp. - Changed the glass shards so that they do not have to override FloorBounceMissile. It was the only place where this was virtually overridden and provided little usefulness. - made 'out' variables work. - fixed virtual call handling for HandlePickup. --- src/CMakeLists.txt | 2 - src/actor.h | 7 +- src/d_player.h | 2 +- src/g_level.cpp | 1 - src/g_shared/a_debris.cpp | 27 -- src/g_shared/a_pickups.cpp | 25 +- src/g_shared/a_pickups.h | 4 +- src/g_shared/sbarinfo.cpp | 1 - src/g_strife/a_strifeglobal.h | 38 -- src/g_strife/a_strifeitems.cpp | 377 ------------------ src/g_strife/a_strifestuff.cpp | 2 - src/g_strife/strife_sbar.cpp | 1 - src/m_cheat.cpp | 1 - src/p_acs.cpp | 1 - src/p_conversation.cpp | 3 +- src/p_lnspec.cpp | 5 +- src/p_mobj.cpp | 27 +- src/p_user.cpp | 4 +- src/scripting/codegeneration/codegen.cpp | 39 +- src/scripting/thingdef_data.cpp | 7 + src/scripting/zscript/zcc_compile.cpp | 19 +- src/virtual.h | 7 +- wadsrc/static/zscript/actor.txt | 3 +- wadsrc/static/zscript/constants.txt | 22 + wadsrc/static/zscript/doom/scriptedmarine.txt | 2 +- wadsrc/static/zscript/shared/debris.txt | 12 +- wadsrc/static/zscript/shared/inventory.txt | 3 +- wadsrc/static/zscript/strife/acolyte.txt | 4 +- wadsrc/static/zscript/strife/strifeitems.txt | 256 +++++++++++- 29 files changed, 374 insertions(+), 528 deletions(-) delete mode 100644 src/g_shared/a_debris.cpp delete mode 100644 src/g_strife/a_strifeitems.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3ca87affa..923d545e0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -861,7 +861,6 @@ set( NOT_COMPILED_SOURCE_FILES sc_man_scanner.re g_hexen/a_heresiarch.cpp g_hexen/a_spike.cpp - g_strife/a_strifeitems.cpp g_strife/a_strifeweapons.cpp g_shared/sbarinfo_commands.cpp xlat/xlat_parser.y @@ -1119,7 +1118,6 @@ set (PCH_SOURCES g_shared/a_artifacts.cpp g_shared/a_bridge.cpp g_shared/a_camera.cpp - g_shared/a_debris.cpp g_shared/a_decals.cpp g_shared/a_fastprojectile.cpp g_shared/a_flashfader.cpp diff --git a/src/actor.h b/src/actor.h index b627bac66..0b6c58c19 100644 --- a/src/actor.h +++ b/src/actor.h @@ -648,7 +648,7 @@ public: void PlayBounceSound(bool onfloor); // Called when an actor with MF_MISSILE and MF2_FLOORBOUNCE hits the floor - virtual bool FloorBounceMissile (secplane_t &plane); + bool FloorBounceMissile (secplane_t &plane); // Called when an actor is to be reflected by a disc of repulsion. // Returns true to continue normal blast processing. @@ -682,7 +682,7 @@ public: // Give an item to the actor and pick it up. // Returns true if the item pickup succeeded. - virtual bool GiveInventory (PClassInventory *type, int amount, bool givecheat = false); + bool GiveInventory (PClassInventory *type, int amount, bool givecheat = false); // Removes the item from the inventory list. virtual void RemoveInventory (AInventory *item); @@ -693,8 +693,7 @@ public: virtual bool TakeInventory (PClassActor *itemclass, int amount, bool fromdecorate = false, bool notakeinfinite = false); // Uses an item and removes it from the inventory. - virtual bool DoUseInventory (AInventory *item); - bool UseInventory(AInventory *item); + virtual bool UseInventory (AInventory *item); // Tosses an item out of the inventory. AInventory *DropInventory (AInventory *item); diff --git a/src/d_player.h b/src/d_player.h index af06e9730..d1678b619 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -109,7 +109,7 @@ public: virtual void Tick(); virtual void AddInventory (AInventory *item); virtual void RemoveInventory (AInventory *item); - virtual bool DoUseInventory (AInventory *item); + virtual bool UseInventory (AInventory *item); virtual void MarkPrecacheSounds () const; virtual void PlayIdle (); diff --git a/src/g_level.cpp b/src/g_level.cpp index 0e7820d93..4bb78461a 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -79,7 +79,6 @@ #include "v_palette.h" #include "menu/menu.h" #include "a_sharedglobal.h" -#include "a_strifeglobal.h" #include "r_data/colormaps.h" #include "r_renderer.h" #include "r_utility.h" diff --git a/src/g_shared/a_debris.cpp b/src/g_shared/a_debris.cpp deleted file mode 100644 index 0932088c2..000000000 --- a/src/g_shared/a_debris.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "actor.h" -#include "info.h" -#include "m_random.h" -#include "m_fixed.h" - -// Stained glass ------------------------------------------------------------ - -class AGlassShard : public AActor -{ - DECLARE_CLASS (AGlassShard, AActor) -public: - bool FloorBounceMissile (secplane_t &plane) - { - if (!Super::FloorBounceMissile (plane)) - { - if (fabs (Vel.Z) < 0.5) - { - Destroy (); - } - return false; - } - return true; - } -}; - -IMPLEMENT_CLASS(AGlassShard, false, false) - diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index df434baae..38d068bd7 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -11,7 +11,6 @@ #include "c_dispatch.h" #include "gstrings.h" #include "templates.h" -#include "a_strifeglobal.h" #include "a_morph.h" #include "a_specialspot.h" #include "g_level.h" @@ -751,7 +750,7 @@ bool AInventory::CallHandlePickup(AInventory *item) auto self = this; while (self != nullptr) { - IFVIRTUAL(AInventory, HandlePickup) + IFVIRTUALPTR(self, AInventory, HandlePickup) { // Without the type cast this picks the 'void *' assignment... VMValue params[2] = { (DObject*)self, (DObject*)item }; @@ -1684,6 +1683,13 @@ bool AInventory::TryPickup (AActor *&toucher) return true; } +DEFINE_ACTION_FUNCTION(AInventory, TryPickup) +{ + PARAM_SELF_PROLOGUE(AInventory); + PARAM_POINTER(toucher, AActor*); + ACTION_RETURN_BOOL(self->TryPickup(*toucher)); +} + //=========================================================================== // // AInventory :: TryPickupRestricted @@ -1710,7 +1716,20 @@ bool AInventory::CallTryPickup (AActor *toucher, AActor **toucher_return) bool res; if (CanPickup(toucher)) - res = TryPickup(toucher); + { + bool res; + IFVIRTUAL(AInventory, TryPickup) + { + VMValue params[2] = { (DObject*)this, (void*)&toucher }; + VMReturn ret; + VMFrameStack stack; + int retval; + ret.IntAt(&retval); + stack.Call(func, params, 2, &ret, 1, nullptr); + res = !!retval; + } + else res = TryPickup(toucher); + } else if (!(ItemFlags & IF_RESTRICTABSOLUTELY)) res = TryPickupRestricted(toucher); // let an item decide for itself how it will handle this else diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index 8fc96cd57..48afac226 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -222,9 +222,9 @@ public: virtual PalEntry GetBlend (); PalEntry CallGetBlend(); -protected: virtual bool TryPickup (AActor *&toucher); virtual bool TryPickupRestricted (AActor *&toucher); +protected: bool CanPickup(AActor * toucher); void GiveQuest(AActor * toucher); @@ -600,5 +600,7 @@ public: bool TryPickup(AActor *&toucher); }; +extern PClassActor *QuestItemClasses[31]; + #endif //__A_PICKUPS_H__ diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index ed91be4c7..4bb9d5b81 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -52,7 +52,6 @@ #include "r_data/r_translate.h" #include "a_artifacts.h" #include "a_weaponpiece.h" -#include "a_strifeglobal.h" #include "g_level.h" #include "v_palette.h" #include "p_acs.h" diff --git a/src/g_strife/a_strifeglobal.h b/src/g_strife/a_strifeglobal.h index adf8d59bf..9206dd08c 100644 --- a/src/g_strife/a_strifeglobal.h +++ b/src/g_strife/a_strifeglobal.h @@ -4,42 +4,4 @@ #include "info.h" #include "a_pickups.h" -// Base class for every humanoid in Strife that can go into -// a fire or electric death. -class ADegninOre : public AInventory -{ - DECLARE_CLASS (ADegninOre, AInventory) -public: - bool Use (bool pickup); -}; - -class ADummyStrifeItem : public AInventory -{ - DECLARE_CLASS (ADummyStrifeItem, AInventory) -}; - -class AUpgradeStamina : public ADummyStrifeItem -{ - DECLARE_CLASS (AUpgradeStamina, ADummyStrifeItem) -public: - bool TryPickup (AActor *&toucher); -}; - -class AUpgradeAccuracy : public ADummyStrifeItem -{ - DECLARE_CLASS (AUpgradeAccuracy, ADummyStrifeItem) -public: - bool TryPickup (AActor *&toucher); -}; - -class ASlideshowStarter : public ADummyStrifeItem -{ - DECLARE_CLASS (ASlideshowStarter, ADummyStrifeItem) -public: - bool TryPickup (AActor *&toucher); -}; - - -extern PClassActor *QuestItemClasses[31]; - #endif diff --git a/src/g_strife/a_strifeitems.cpp b/src/g_strife/a_strifeitems.cpp deleted file mode 100644 index b9f3f288e..000000000 --- a/src/g_strife/a_strifeitems.cpp +++ /dev/null @@ -1,377 +0,0 @@ -/* -#include "info.h" -#include "a_pickups.h" -#include "d_player.h" -#include "gstrings.h" -#include "p_local.h" -#include "p_spec.h" -#include "a_strifeglobal.h" -#include "p_lnspec.h" -#include "p_enemy.h" -#include "s_sound.h" -#include "d_event.h" -#include "a_keys.h" -#include "c_console.h" -#include "templates.h" -#include "vm.h" -#include "g_level.h" -#include "doomstat.h" -*/ -// Degnin Ore --------------------------------------------------------------- - -IMPLEMENT_CLASS(ADegninOre, false, false) - -bool ADegninOre::Use (bool pickup) -{ - if (pickup) - { - return false; - } - else - { - AInventory *drop; - - // Increase the amount by one so that when DropInventory decrements it, - // the actor will have the same number of beacons that he started with. - // When we return to UseInventory, it will take care of decrementing - // Amount again and disposing of this item if there are no more. - Amount++; - drop = Owner->DropInventory (this); - if (drop == NULL) - { - Amount--; - return false; - } - return true; - } -} - -// Health Training ---------------------------------------------------------- - -class AHealthTraining : public AInventory -{ - DECLARE_CLASS (AHealthTraining, AInventory) -public: - bool TryPickup (AActor *&toucher); -}; - -IMPLEMENT_CLASS(AHealthTraining, false, false) - -bool AHealthTraining::TryPickup (AActor *&toucher) -{ - if (Super::TryPickup (toucher)) - { - toucher->GiveInventoryType (PClass::FindActor("GunTraining")); - AInventory *coin = (AInventory*)Spawn("Coin"); - if (coin != NULL) - { - coin->Amount = toucher->player->mo->accuracy*5 + 300; - if (!coin->CallTryPickup (toucher)) - { - coin->Destroy (); - } - } - return true; - } - return false; -} - -// Scanner ------------------------------------------------------------------ - -class AScanner : public APowerupGiver -{ - DECLARE_CLASS (AScanner, APowerupGiver) -public: - bool Use (bool pickup); -}; - -IMPLEMENT_CLASS(AScanner, false, false) - -bool AScanner::Use (bool pickup) -{ - if (!(level.flags2 & LEVEL2_ALLMAP)) - { - if (Owner->CheckLocalView (consoleplayer)) - { - C_MidPrint(SmallFont, GStrings("TXT_NEEDMAP")); - } - return false; - } - return Super::Use (pickup); -} - -// Prison Pass -------------------------------------------------------------- - -class APrisonPass : public AKey -{ - DECLARE_CLASS (APrisonPass, AKey) -public: - bool TryPickup (AActor *&toucher); - bool SpecialDropAction (AActor *dropper); -}; - -IMPLEMENT_CLASS(APrisonPass, false, false) - -bool APrisonPass::TryPickup (AActor *&toucher) -{ - Super::TryPickup (toucher); - EV_DoDoor (DDoor::doorOpen, NULL, toucher, 223, 2., 0, 0, 0); - toucher->GiveInventoryType (QuestItemClasses[9]); - return true; -} - -//============================================================================ -// -// APrisonPass :: SpecialDropAction -// -// Trying to make a monster that drops a prison pass turns it into an -// OpenDoor223 item instead. That means the only way to get it in Strife -// is through dialog, which is why it doesn't have its own sprite. -// -//============================================================================ - -bool APrisonPass::SpecialDropAction (AActor *dropper) -{ - EV_DoDoor (DDoor::doorOpen, NULL, dropper, 223, 2., 0, 0, 0); - Destroy (); - return true; -} - - -//--------------------------------------------------------------------------- -// Dummy items. They are just used by Strife to perform --------------------- -// actions and cannot be held. ---------------------------------------------- -//--------------------------------------------------------------------------- - -IMPLEMENT_CLASS(ADummyStrifeItem, false, false) - -// Sound the alarm! --------------------------------------------------------- - -class ARaiseAlarm : public ADummyStrifeItem -{ - DECLARE_CLASS (ARaiseAlarm, ADummyStrifeItem) -public: - bool TryPickup (AActor *&toucher); - bool SpecialDropAction (AActor *dropper); -}; - -IMPLEMENT_CLASS(ARaiseAlarm, false, false) - -bool ARaiseAlarm::TryPickup (AActor *&toucher) -{ - P_NoiseAlert (toucher, toucher); - /* - ThinkerIterator it = ThinkerIterator.Create("AlienSpectre3"); - Actor spectre = Actor(it.Next()); - - if (spectre != NULL && spectre.health > 0 && toucher != spectre) - { - spectre.CurSector.SoundTarget = spectre.LastHeard = toucher; - spectre.target = toucher; - spectre.SetState (spectre.SeeState); - } - - */ - GoAwayAndDie (); - return true; -} - -bool ARaiseAlarm::SpecialDropAction (AActor *dropper) -{ - if (dropper->target != nullptr) - { - P_NoiseAlert(dropper->target, dropper->target); - if (dropper->target->CheckLocalView(consoleplayer)) - { - Printf("You Fool! You've set off the alarm.\n"); - } - } - Destroy (); - return true; -} - -// Open door tag 222 -------------------------------------------------------- - -class AOpenDoor222 : public ADummyStrifeItem -{ - DECLARE_CLASS (AOpenDoor222, ADummyStrifeItem) -public: - bool TryPickup (AActor *&toucher); -}; - -IMPLEMENT_CLASS(AOpenDoor222, false, false) - -bool AOpenDoor222::TryPickup (AActor *&toucher) -{ - EV_DoDoor (DDoor::doorOpen, NULL, toucher, 222, 2., 0, 0, 0); - GoAwayAndDie (); - return true; -} - -// Close door tag 222 ------------------------------------------------------- - -class ACloseDoor222 : public ADummyStrifeItem -{ - DECLARE_CLASS (ACloseDoor222, ADummyStrifeItem) -public: - bool TryPickup (AActor *&toucher); - bool SpecialDropAction (AActor *dropper); -}; - -IMPLEMENT_CLASS(ACloseDoor222, false, false) - -bool ACloseDoor222::TryPickup (AActor *&toucher) -{ - EV_DoDoor (DDoor::doorClose, NULL, toucher, 222, 2., 0, 0, 0); - GoAwayAndDie (); - return true; -} - -bool ACloseDoor222::SpecialDropAction (AActor *dropper) -{ - EV_DoDoor (DDoor::doorClose, NULL, dropper, 222, 2., 0, 0, 0); - if (dropper->target != nullptr) - { - if (dropper->target->CheckLocalView(consoleplayer)) - { - Printf("You're dead! You set off the alarm.\n"); - } - P_NoiseAlert(dropper->target, dropper->target); - } - Destroy (); - return true; -} - -// Open door tag 224 -------------------------------------------------------- - -class AOpenDoor224 : public ADummyStrifeItem -{ - DECLARE_CLASS (AOpenDoor224, ADummyStrifeItem) -public: - bool TryPickup (AActor *&toucher); - bool SpecialDropAction (AActor *dropper); -}; - -IMPLEMENT_CLASS(AOpenDoor224, false, false) - -bool AOpenDoor224::TryPickup (AActor *&toucher) -{ - EV_DoDoor (DDoor::doorOpen, NULL, toucher, 224, 2., 0, 0, 0); - GoAwayAndDie (); - return true; -} - -bool AOpenDoor224::SpecialDropAction (AActor *dropper) -{ - EV_DoDoor (DDoor::doorOpen, NULL, dropper, 224, 2., 0, 0, 0); - Destroy (); - return true; -} - -// Ammo --------------------------------------------------------------------- - -class AAmmoFillup : public ADummyStrifeItem -{ - DECLARE_CLASS (AAmmoFillup, ADummyStrifeItem) -public: - bool TryPickup (AActor *&toucher); -}; - -IMPLEMENT_CLASS(AAmmoFillup, false, false) - -bool AAmmoFillup::TryPickup (AActor *&toucher) -{ - PClassActor *clip = PClass::FindActor(NAME_ClipOfBullets); - if (clip != NULL) - { - AInventory *item = toucher->FindInventory(clip); - if (item == NULL) - { - item = toucher->GiveInventoryType (clip); - if (item != NULL) - { - item->Amount = 50; - } - } - else if (item->Amount < 50) - { - item->Amount = 50; - } - else - { - return false; - } - GoAwayAndDie (); - } - return true; -} - -// Health ------------------------------------------------------------------- - -class AHealthFillup : public ADummyStrifeItem -{ - DECLARE_CLASS (AHealthFillup, ADummyStrifeItem) -public: - bool TryPickup (AActor *&toucher); -}; - -IMPLEMENT_CLASS(AHealthFillup, false, false) - -bool AHealthFillup::TryPickup (AActor *&toucher) -{ - static const int skillhealths[5] = { -100, -75, -50, -50, -100 }; - - int index = clamp(gameskill, 0,4); - if (!P_GiveBody (toucher, skillhealths[index])) - { - return false; - } - GoAwayAndDie (); - return true; -} - -// Upgrade Stamina ---------------------------------------------------------- - -IMPLEMENT_CLASS(AUpgradeStamina, false, false) - -bool AUpgradeStamina::TryPickup (AActor *&toucher) -{ - if (toucher->player == NULL) - return false; - - toucher->player->mo->stamina += Amount; - if (toucher->player->mo->stamina >= MaxAmount) - toucher->player->mo->stamina = MaxAmount; - - P_GiveBody (toucher, -100); - GoAwayAndDie (); - return true; -} - -// Upgrade Accuracy --------------------------------------------------------- - -IMPLEMENT_CLASS(AUpgradeAccuracy, false, false) - -bool AUpgradeAccuracy::TryPickup (AActor *&toucher) -{ - if (toucher->player == NULL || toucher->player->mo->accuracy >= 100) - return false; - toucher->player->mo->accuracy += 10; - GoAwayAndDie (); - return true; -} - -// Start a slideshow -------------------------------------------------------- - -IMPLEMENT_CLASS(ASlideshowStarter, false, false) - -bool ASlideshowStarter::TryPickup (AActor *&toucher) -{ - gameaction = ga_slideshow; - if (level.levelnum == 10) - { - toucher->GiveInventoryType (QuestItemClasses[16]); - } - GoAwayAndDie (); - return true; -} diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp index 6537f180e..e93c13600 100644 --- a/src/g_strife/a_strifestuff.cpp +++ b/src/g_strife/a_strifestuff.cpp @@ -6,7 +6,6 @@ #include "d_player.h" #include "a_action.h" #include "p_local.h" -#include "a_strifeglobal.h" #include "p_enemy.h" #include "p_lnspec.h" #include "c_console.h" @@ -24,7 +23,6 @@ #include "vm.h" // Include all the other Strife stuff here to reduce compile time -#include "a_strifeitems.cpp" #include "a_strifeweapons.cpp" // Notes so I don't forget them: diff --git a/src/g_strife/strife_sbar.cpp b/src/g_strife/strife_sbar.cpp index 79a363d1c..c12c7a723 100644 --- a/src/g_strife/strife_sbar.cpp +++ b/src/g_strife/strife_sbar.cpp @@ -12,7 +12,6 @@ #include "m_swap.h" #include "templates.h" #include "a_keys.h" -#include "a_strifeglobal.h" #include "gi.h" #include "g_level.h" #include "colormatcher.h" diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index 33a90c85f..f5cd56848 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -30,7 +30,6 @@ #include "doomstat.h" #include "gstrings.h" #include "p_local.h" -#include "a_strifeglobal.h" #include "gi.h" #include "p_enemy.h" #include "sbar.h" diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 97f660246..a71110674 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -58,7 +58,6 @@ #include "sbar.h" #include "m_swap.h" #include "a_sharedglobal.h" -#include "a_strifeglobal.h" #include "v_video.h" #include "w_wad.h" #include "r_sky.h" diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index bf1c392ae..5fd21e73b 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -44,7 +44,6 @@ #include "m_random.h" #include "gi.h" #include "templates.h" -#include "a_strifeglobal.h" #include "a_keys.h" #include "p_enemy.h" #include "gstrings.h" @@ -1357,7 +1356,7 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply } } - if (reply->GiveType->IsDescendantOf(RUNTIME_CLASS(ASlideshowStarter))) + if (reply->GiveType->IsDescendantOf(PClass::FindActor("SlideshowStarter"))) gameaction = ga_slideshow; } else diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 1f318f559..179e057b3 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -50,7 +50,6 @@ #include "gi.h" #include "m_random.h" #include "p_conversation.h" -#include "a_strifeglobal.h" #include "r_data/r_translate.h" #include "p_3dmidtex.h" #include "d_net.h" @@ -3220,8 +3219,8 @@ FUNC(LS_GlassBreak) if (it != NULL) { it->GiveInventoryType (QuestItemClasses[28]); - it->GiveInventoryType (RUNTIME_CLASS(AUpgradeAccuracy)); - it->GiveInventoryType (RUNTIME_CLASS(AUpgradeStamina)); + it->GiveInventoryType (PClass::FindActor("UpgradeAccuracy")); + it->GiveInventoryType (PClass::FindActor("UpgradeStamina")); } } } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 7257eff95..d76832c59 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -942,7 +942,7 @@ AInventory *AActor::FirstInv () // //============================================================================ -bool AActor::DoUseInventory (AInventory *item) +bool AActor::UseInventory (AInventory *item) { // No using items if you're dead. if (health <= 0) @@ -973,23 +973,7 @@ DEFINE_ACTION_FUNCTION(AActor, UseInventory) { PARAM_SELF_PROLOGUE(AActor); PARAM_OBJECT(item, AInventory); - ACTION_RETURN_BOOL(self->DoUseInventory(item)); -} - -bool AActor::UseInventory(AInventory *item) -{ - IFVIRTUAL(AActor, UseInventory) - { - // Without the type cast this picks the 'void *' assignment... - VMValue params[2] = { (DObject*)this, (DObject*)item }; - VMReturn ret; - VMFrameStack stack; - int retval; - ret.IntAt(&retval); - stack.Call(func, params, 2, &ret, 1, nullptr); - return !!retval; - } - else return DoUseInventory(item); + ACTION_RETURN_BOOL(self->UseInventory(item)); } //=========================================================================== @@ -1304,6 +1288,13 @@ bool AActor::CheckLocalView (int playernum) const return false; } +DEFINE_ACTION_FUNCTION(AActor, CheckLocalView) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(cp); + ACTION_RETURN_BOOL(self->CheckLocalView(cp)); +} + //============================================================================ // // AActor :: IsInsideVisibleAngles diff --git a/src/p_user.cpp b/src/p_user.cpp index 1033299e6..1ac60ba35 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -901,7 +901,7 @@ void APlayerPawn::RemoveInventory (AInventory *item) // //=========================================================================== -bool APlayerPawn::DoUseInventory (AInventory *item) +bool APlayerPawn::UseInventory (AInventory *item) { const PClass *itemtype = item->GetClass(); @@ -915,7 +915,7 @@ bool APlayerPawn::DoUseInventory (AInventory *item) return false; } - if (!Super::DoUseInventory (item)) + if (!Super::UseInventory (item)) { // Heretic and Hexen advance the inventory cursor if the use failed. // Should this behavior be retained? diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 6912755b4..2eb6cfec6 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -5822,10 +5822,30 @@ bool FxLocalVariable::RequestAddress(FCompileContext &ctx, bool *writable) ExpEmit FxLocalVariable::Emit(VMFunctionBuilder *build) { - ExpEmit ret(Variable->RegNum + RegOffset, Variable->ValueType->GetRegType(), false, true); - ret.RegCount = ValueType->GetRegCount(); - if (AddressRequested) ret.Target = true; - return ret; + // 'Out' variables are actually pointers but this fact must be hidden to the script. + if (Variable->VarFlags & VARF_Out) + { + if (!AddressRequested) + { + ExpEmit reg(build, ValueType->GetRegType(), ValueType->GetRegCount()); + build->Emit(ValueType->GetLoadOp(), reg.RegNum, Variable->RegNum, build->GetConstantInt(RegOffset)); + return reg; + } + else + { + if (RegOffset == 0) return ExpEmit(Variable->RegNum, REGT_POINTER, false, true); + ExpEmit reg(build, REGT_POINTER); + build->Emit(OP_ADDA_RK, reg.RegNum, Variable->RegNum, build->GetConstantInt(RegOffset)); + return reg; + } + } + else + { + ExpEmit ret(Variable->RegNum + RegOffset, Variable->ValueType->GetRegType(), false, true); + ret.RegCount = ValueType->GetRegCount(); + if (AddressRequested) ret.Target = true; + return ret; + } } @@ -7781,7 +7801,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) } FxExpression *x; - if (!(flag & VARF_Ref)) + if (!(flag & (VARF_Ref|VARF_Out))) { x = new FxTypeCast(ArgList[i], type, false); x = x->Resolve(ctx); @@ -7793,7 +7813,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) if (ArgList[i] != nullptr && ArgList[i]->ValueType != TypeNullPtr) { ArgList[i]->RequestAddress(ctx, &writable); - ArgList[i]->ValueType = NewPointer(ArgList[i]->ValueType); + if (flag & VARF_Ref) ArgList[i]->ValueType = NewPointer(ArgList[i]->ValueType); // For a reference argument the types must match 100%. if (type != ArgList[i]->ValueType) { @@ -9917,10 +9937,15 @@ ExpEmit FxLocalVariableDeclaration::Emit(VMFunctionBuilder *build) { if (Init == nullptr) { - if (RegNum == -1) RegNum = build->Registers[ValueType->GetRegType()].Get(RegCount); + if (RegNum == -1) + { + if (!(VarFlags & VARF_Out)) RegNum = build->Registers[ValueType->GetRegType()].Get(RegCount); + else RegNum = build->Registers[REGT_POINTER].Get(1); + } } else { + assert(!(VarFlags & VARF_Out)); // 'out' variables should never be initialized, they can only exist as function parameters. ExpEmit emitval = Init->Emit(build); int regtype = emitval.RegType; diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index ee7cae76c..65a979edd 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -48,6 +48,7 @@ #include "p_terrain.h" #include "gstrings.h" #include "zstring.h" +#include "d_event.h" static TArray properties; static TArray AFTable; @@ -743,6 +744,12 @@ void InitThingdef() playerf = new PField("playeringame", parray, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&playeringame); GlobalSymbols.AddSymbol(playerf); + playerf = new PField("gameaction", TypeUInt8, VARF_Native | VARF_Static, (intptr_t)&gameaction); + GlobalSymbols.AddSymbol(playerf); + + playerf = new PField("consoleplayer", TypeSInt32, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&consoleplayer); + GlobalSymbols.AddSymbol(playerf); + // Argh. It sucks when bad hacks need to be supported. WP_NOCHANGE is just a bogus pointer but it used everywhere as a special flag. // It cannot be defined as constant because constants can either be numbers or strings but nothing else, so the only 'solution' // is to create a static variable from it and reference that in the script. Yuck!!! diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index c454ced83..4eab47c1b 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2169,17 +2169,16 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool { auto type = DetermineType(c->Type(), p, f->Name, p->Type, false, false); int flags = 0; - if (p->Flags & ZCC_In) flags |= VARF_In; - if (p->Flags & ZCC_Out) flags |= VARF_Out; - if ((type->IsA(RUNTIME_CLASS(PStruct))) || (flags & VARF_Out)) + if (type->IsA(RUNTIME_CLASS(PStruct)) && type != TypeVector2 && type != TypeVector3) { - // 'out' parameters and all structs except vectors are passed by reference - if ((flags & VARF_Out) || (type != TypeVector2 && type != TypeVector3)) - { - type = NewPointer(type); - flags |= VARF_Ref; - } - else if (type == TypeVector2) + // Structs are being passed by pointer, but unless marked 'out' that pointer must be readonly. + type = NewPointer(type /*, !(p->Flags & ZCC_Out)*/); + flags |= VARF_Ref; + } + else if (type->GetRegType() != REGT_NIL) + { + if (p->Flags & ZCC_Out) flags |= VARF_Out; + if (type == TypeVector2) { elementcount = 2; } diff --git a/src/virtual.h b/src/virtual.h index 8485dec07..844c51d38 100644 --- a/src/virtual.h +++ b/src/virtual.h @@ -7,15 +7,14 @@ inline unsigned GetVirtualIndex(PClass *cls, const char *funcname) return VIndex; } -#define IFVIRTUAL(cls, funcname) \ +#define IFVIRTUALPTR(self, cls, funcname) \ static unsigned VIndex = ~0u; \ if (VIndex == ~0u) { \ VIndex = GetVirtualIndex(RUNTIME_CLASS(cls), #funcname); \ assert(VIndex != ~0u); \ } \ - auto clss = GetClass(); \ + auto clss = self->GetClass(); \ VMFunction *func = clss->Virtuals.Size() > VIndex? clss->Virtuals[VIndex] : nullptr; \ if (func != nullptr) - - +#define IFVIRTUAL(cls, funcname) IFVIRTUALPTR(this, cls, funcname) diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index c5052ab79..25d164d29 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -267,7 +267,6 @@ class Actor : Thinker native virtual native int TakeSpecialDamage (Actor inflictor, Actor source, int damage, Name damagetype); virtual native void Die(Actor source, Actor inflictor, int dmgflags = 0); virtual native bool Slam(Actor victim); - virtual native bool UseInventory(Inventory item); virtual native bool SpecialBlastHandling (Actor source, double strength); virtual native void Touch(Actor toucher); @@ -292,6 +291,7 @@ class Actor : Thinker native native void ClearBounce(); native TerrainDef GetFloorTerrain(); native Inventory DoDropItem(Class type, int dropamount, int chance); + native bool CheckLocalView(int consoleplayer); native void ExplodeMissile(line lin = null, Actor target = null); native void RestoreDamage(); @@ -378,6 +378,7 @@ class Actor : Thinker native native Inventory FindInventory(class itemtype, bool subclass = false); native Inventory GiveInventoryType(class itemtype); native Inventory DropInventory (Inventory item); + native bool UseInventory(Inventory item); native bool GiveAmmo (Class type, int amount); // DECORATE compatible functions diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index 5f86282a8..8180e6710 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -1015,3 +1015,25 @@ enum PaletteFlashFlags PF_ICE = 4, PF_HAZARD = 8, }; + +enum EGameAction +{ + ga_nothing, + ga_loadlevel, + ga_newgame, + ga_newgame2, + ga_recordgame, + ga_loadgame, + ga_loadgamehidecon, + ga_loadgameplaydemo, + ga_autoloadgame, + ga_savegame, + ga_autosave, + ga_playdemo, + ga_completed, + ga_slideshow, + ga_worlddone, + ga_screenshot, + ga_togglemap, + ga_fullconsole, +}; diff --git a/wadsrc/static/zscript/doom/scriptedmarine.txt b/wadsrc/static/zscript/doom/scriptedmarine.txt index 3987bc795..22766ac90 100644 --- a/wadsrc/static/zscript/doom/scriptedmarine.txt +++ b/wadsrc/static/zscript/doom/scriptedmarine.txt @@ -175,7 +175,7 @@ class ScriptedMarine : Actor // //============================================================================ - private bool GetWeaponStates(int weap, WeaponStates wstates) + private bool GetWeaponStates(int weap, out WeaponStates wstates) { static const statelabel MeleeNames[] = { diff --git a/wadsrc/static/zscript/shared/debris.txt b/wadsrc/static/zscript/shared/debris.txt index 24eae25be..3ffcea057 100644 --- a/wadsrc/static/zscript/shared/debris.txt +++ b/wadsrc/static/zscript/shared/debris.txt @@ -187,7 +187,7 @@ class Dirt6 : Actor // Stained glass ------------------------------------------------------------ -class GlassShard : Actor native +class GlassShard : Actor { Default { @@ -199,6 +199,16 @@ class GlassShard : Actor native BounceType "HexenCompat"; BounceFactor 0.3; } + + override void Tick() + { + Super.Tick(); + if (Vel.Z > 0 && Vel.Z < 0.5 && pos.z < floorz + 1) + { + Destroy (); + } + } + } class SGShard1 : GlassShard diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index d3e50d198..dbede839f 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -41,7 +41,8 @@ class Inventory : Actor native private native void A_RestoreSpecialDoomThing(); private native void A_RestoreSpecialThing1(); private native void A_RestoreSpecialThing2(); - + + virtual native bool TryPickup(in out Actor toucher); native bool, Actor CallTryPickup(Actor toucher); States(Actor, Overlay, Weapon, Item) diff --git a/wadsrc/static/zscript/strife/acolyte.txt b/wadsrc/static/zscript/strife/acolyte.txt index 6ae44f7f4..e5a019ea8 100644 --- a/wadsrc/static/zscript/strife/acolyte.txt +++ b/wadsrc/static/zscript/strife/acolyte.txt @@ -97,8 +97,8 @@ class Acolyte : StrifeHumanoid if (i == MAXPLAYERS) return; - // Make sure all the other blue acolytes are dead. - if (CheckBossDeath()) + // Make sure all the other blue acolytes are dead, but do this only once in case of simultaneous kills. + if (CheckBossDeath() && !players[i].mo.FindInventory("QuestItem7")) { players[i].mo.GiveInventoryType ("QuestItem7"); players[i].SetLogNumber (14); diff --git a/wadsrc/static/zscript/strife/strifeitems.txt b/wadsrc/static/zscript/strife/strifeitems.txt index 4d8e3d5e4..6d8037771 100644 --- a/wadsrc/static/zscript/strife/strifeitems.txt +++ b/wadsrc/static/zscript/strife/strifeitems.txt @@ -389,7 +389,7 @@ class Communicator : Inventory // Degnin Ore --------------------------------------------------------------- -class DegninOre : Inventory native +class DegninOre : Inventory { Default { @@ -421,6 +421,32 @@ class DegninOre : Inventory native BNG3 BCDEFGH 3 Bright; Stop; } + + override bool Use (bool pickup) + { + if (pickup) + { + return false; + } + else + { + Inventory drop; + + // Increase the amount by one so that when DropInventory decrements it, + // the actor will have the same number of beacons that he started with. + // When we return to UseInventory, it will take care of decrementing + // Amount again and disposing of this item if there are no more. + Amount++; + drop = Owner.DropInventory (self); + if (drop == NULL) + { + Amount--; + return false; + } + return true; + } + } + } // Gun Training ------------------------------------------------------------- @@ -446,7 +472,7 @@ class GunTraining : Inventory // Health Training ---------------------------------------------------------- -class HealthTraining : Inventory native +class HealthTraining : Inventory { Default { @@ -463,13 +489,23 @@ class HealthTraining : Inventory native HELT A -1; Stop; } + + override bool TryPickup (in out Actor toucher) + { + if (Super.TryPickup(toucher)) + { + toucher.GiveInventoryType ("GunTraining"); + toucher.A_GiveInventory("Coin", toucher.player.mo.accuracy*5 + 300); + return true; + } + return false; + } + } - - // Scanner ------------------------------------------------------------------ -class Scanner : PowerupGiver native +class Scanner : PowerupGiver { Default { @@ -488,11 +524,25 @@ class Scanner : PowerupGiver native PMUP AB 6; Loop; } + + override bool Use (bool pickup) + { + if (!level.AllMap) + { + if (Owner.CheckLocalView (consoleplayer)) + { + C_MidPrint("SmallFont", "$TXT_NEEDMAP"); + } + return false; + } + return Super.Use (pickup); + } + } // Prison Pass -------------------------------------------------------------- -class PrisonPass : Key native +class PrisonPass : Key { Default { @@ -506,6 +556,32 @@ class PrisonPass : Key native TOKN A -1; Stop; } + + override bool TryPickup (in out Actor toucher) + { + Super.TryPickup (toucher); + Door_Open(223, 16); + toucher.GiveInventoryType ("QuestItem10"); + return true; + } + + //============================================================================ + // + // APrisonPass :: SpecialDropAction + // + // Trying to make a monster that drops a prison pass turns it into an + // OpenDoor223 item instead. That means the only way to get it in Strife + // is through dialog, which is why it doesn't have its own sprite. + // + //============================================================================ + + override bool SpecialDropAction (Actor dropper) + { + Door_Open(223, 16); + Destroy (); + return true; + } + } //--------------------------------------------------------------------------- @@ -513,7 +589,7 @@ class PrisonPass : Key native // actions and cannot be held. ---------------------------------------------- //--------------------------------------------------------------------------- -class DummyStrifeItem : Inventory native +class DummyStrifeItem : Inventory { States { @@ -525,73 +601,221 @@ class DummyStrifeItem : Inventory native // Sound the alarm! --------------------------------------------------------- -class RaiseAlarm : DummyStrifeItem native +class RaiseAlarm : DummyStrifeItem { Default { Tag "$TAG_ALARM"; } + + override bool TryPickup (in out Actor toucher) + { + toucher.NoiseAlert (toucher); + + ThinkerIterator it = ThinkerIterator.Create("AlienSpectre3"); + Actor spectre = Actor(it.Next()); + + if (spectre != NULL && spectre.health > 0 && toucher != spectre) + { + spectre.CurSector.SoundTarget = spectre.LastHeard = toucher; + spectre.target = toucher; + spectre.SetState (spectre.SeeState); + } + GoAwayAndDie (); + return true; + } + + override bool SpecialDropAction (Actor dropper) + { + if (dropper.target != null) + { + dropper.target.NoiseAlert(dropper.target); + if (dropper.target.CheckLocalView(consoleplayer)) + { + A_Log("You Fool! You've set off the alarm."); + } + } + Destroy (); + return true; + } + } // Open door tag 222 -------------------------------------------------------- -class OpenDoor222 : DummyStrifeItem native +class OpenDoor222 : DummyStrifeItem { + override bool TryPickup (in out Actor toucher) + { + Door_Open(222, 16); + GoAwayAndDie (); + return true; + } + } // Close door tag 222 ------------------------------------------------------- -class CloseDoor222 : DummyStrifeItem native +class CloseDoor222 : DummyStrifeItem { + override bool TryPickup (in out Actor toucher) + { + Door_Close(222, 16); + GoAwayAndDie (); + return true; + } + + override bool SpecialDropAction (Actor dropper) + { + Door_Close(222, 16); + if (dropper.target != null) + { + if (dropper.target.CheckLocalView(consoleplayer)) + { + A_Log("You're dead! You set off the alarm."); + } + dropper.target.NoiseAlert(dropper.target); + } + Destroy (); + return true; + } + } // Open door tag 224 -------------------------------------------------------- -class OpenDoor224 : DummyStrifeItem native +class OpenDoor224 : DummyStrifeItem { + override bool TryPickup (in out Actor toucher) + { + Door_Open(224, 16); + GoAwayAndDie (); + return true; + } + + override bool SpecialDropAction (Actor dropper) + { + Door_Open(224, 16); + Destroy (); + return true; + } + } // Ammo --------------------------------------------------------------------- -class AmmoFillup : DummyStrifeItem native +class AmmoFillup : DummyStrifeItem { Default { Tag "$TAG_AMMOFILLUP"; } + + override bool TryPickup (in out Actor toucher) + { + Inventory item = toucher.FindInventory("ClipOfBullets"); + if (item == NULL) + { + item = toucher.GiveInventoryType ("ClipOfBullets"); + if (item != NULL) + { + item.Amount = 50; + } + } + else if (item.Amount < 50) + { + item.Amount = 50; + } + else + { + return false; + } + GoAwayAndDie (); + return true; + } + } // Health ------------------------------------------------------------------- -class HealthFillup : DummyStrifeItem native +class HealthFillup : DummyStrifeItem { Default { Tag "$TAG_HEALTHFILLUP"; } + + override bool TryPickup (in out Actor toucher) + { + static const int skillhealths[] = { -100, -75, -50, -50, -100 }; + + int index = clamp(skill, 0,4); + if (!toucher.GiveBody (skillhealths[index])) + { + return false; + } + GoAwayAndDie (); + return true; + } + } // Upgrade Stamina ---------------------------------------------------------- -class UpgradeStamina : DummyStrifeItem native +class UpgradeStamina : DummyStrifeItem { Default { Inventory.Amount 10; Inventory.MaxAmount 100; } + + override bool TryPickup (in out Actor toucher) + { + if (toucher.player == NULL) + return false; + + toucher.player.mo.stamina += Amount; + if (toucher.player.mo.stamina >= MaxAmount) + toucher.player.mo.stamina = MaxAmount; + + toucher.GiveBody (-100); + GoAwayAndDie (); + return true; + } + } // Upgrade Accuracy --------------------------------------------------------- -class UpgradeAccuracy : DummyStrifeItem native +class UpgradeAccuracy : DummyStrifeItem { + override bool TryPickup (in out Actor toucher) + { + if (toucher.player == NULL || toucher.player.mo.accuracy >= 100) + return false; + toucher.player.mo.accuracy += 10; + GoAwayAndDie (); + return true; + } + } // Start a slideshow -------------------------------------------------------- -class SlideshowStarter : DummyStrifeItem native +class SlideshowStarter : DummyStrifeItem { + override bool TryPickup (in out Actor toucher) + { + gameaction = ga_slideshow; + if (level.levelnum == 10) + { + toucher.GiveInventoryType ("QuestItem17"); + } + GoAwayAndDie (); + return true; + } + } From be5ba70ed245064a62f6f8204cbb934525a3e739 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 29 Nov 2016 13:00:07 +0100 Subject: [PATCH 163/185] - scriptified Strife's dagger and crossbow. --- src/g_strife/a_strifeweapons.cpp | 247 ------------------ src/p_enemy.cpp | 64 +++++ src/p_mobj.cpp | 5 + src/scripting/zscript/zcc-parse.lemon | 2 +- wadsrc/static/zscript.txt | 2 + wadsrc/static/zscript/actor.txt | 3 +- .../static/zscript/strife/strifefunctions.txt | 60 ++++- .../static/zscript/strife/strifeweapons.txt | 206 --------------- .../static/zscript/strife/weaponcrossbow.txt | 227 ++++++++++++++++ wadsrc/static/zscript/strife/weapondagger.txt | 69 +++++ 10 files changed, 428 insertions(+), 457 deletions(-) create mode 100644 wadsrc/static/zscript/strife/weaponcrossbow.txt create mode 100644 wadsrc/static/zscript/strife/weapondagger.txt diff --git a/src/g_strife/a_strifeweapons.cpp b/src/g_strife/a_strifeweapons.cpp index 34862f943..67c8c8c17 100644 --- a/src/g_strife/a_strifeweapons.cpp +++ b/src/g_strife/a_strifeweapons.cpp @@ -16,7 +16,6 @@ // hacking more stuff in the executable, be sure to give // all Strife missiles the MF4_STRIFEDAMAGE flag. -static FRandom pr_jabdagger ("JabDagger"); static FRandom pr_electric ("FireElectric"); static FRandom pr_sgunshot ("StrifeGunShot"); static FRandom pr_minimissile ("MiniMissile"); @@ -29,252 +28,6 @@ static FRandom pr_phburn ("PhBurn"); void A_LoopActiveSound (AActor *); void A_Countdown (AActor *); -// Punch Dagger ------------------------------------------------------------- - -//============================================================================ -// -// P_DaggerAlert -// -//============================================================================ - -void P_DaggerAlert (AActor *target, AActor *emitter) -{ - AActor *looker; - sector_t *sec = emitter->Sector; - - if (emitter->LastHeard != NULL) - return; - if (emitter->health <= 0) - return; - if (!(emitter->flags3 & MF3_ISMONSTER)) - return; - if (emitter->flags4 & MF4_INCOMBAT) - return; - emitter->flags4 |= MF4_INCOMBAT; - - emitter->target = target; - FState *painstate = emitter->FindState(NAME_Pain, NAME_Dagger); - if (painstate != NULL) - { - emitter->SetState (painstate); - } - - for (looker = sec->thinglist; looker != NULL; looker = looker->snext) - { - if (looker == emitter || looker == target) - continue; - - if (looker->health <= 0) - continue; - - if (!(looker->flags4 & MF4_SEESDAGGERS)) - continue; - - if (!(looker->flags4 & MF4_INCOMBAT)) - { - if (!P_CheckSight (looker, target) && !P_CheckSight (looker, emitter)) - continue; - - looker->target = target; - if (looker->SeeSound) - { - S_Sound (looker, CHAN_VOICE, looker->SeeSound, 1, ATTN_NORM); - } - looker->SetState (looker->SeeState); - looker->flags4 |= MF4_INCOMBAT; - } - } -} - -//============================================================================ -// -// A_JabDagger -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_JabDagger) -{ - PARAM_ACTION_PROLOGUE(AActor); - - DAngle angle; - int damage; - DAngle pitch; - int power; - FTranslatedLineTarget t; - - power = MIN(10, self->player->mo->stamina / 10); - damage = (pr_jabdagger() % (power + 8)) * (power + 2); - - if (self->FindInventory()) - { - damage *= 10; - } - - angle = self->Angles.Yaw + pr_jabdagger.Random2() * (5.625 / 256); - pitch = P_AimLineAttack (self, angle, 80.); - P_LineAttack (self, angle, 80., pitch, damage, NAME_Melee, "StrifeSpark", true, &t); - - // turn to face target - if (t.linetarget) - { - S_Sound (self, CHAN_WEAPON, - t.linetarget->flags & MF_NOBLOOD ? "misc/metalhit" : "misc/meathit", - 1, ATTN_NORM); - self->Angles.Yaw = t.angleFromSource; - self->flags |= MF_JUSTATTACKED; - P_DaggerAlert (self, t.linetarget); - } - else - { - S_Sound (self, CHAN_WEAPON, "misc/swish", 1, ATTN_NORM); - } - return 0; -} - -//============================================================================ -// -// A_AlertMonsters -// -//============================================================================ - -enum -{ - AMF_TARGETEMITTER = 1, - AMF_TARGETNONPLAYER = 2, - AMF_EMITFROMTARGET = 4, -}; - -DEFINE_ACTION_FUNCTION(AActor, A_AlertMonsters) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_FLOAT_DEF(maxdist); - PARAM_INT_DEF(Flags); - - AActor * target = NULL; - AActor * emitter = self; - - if (self->player != NULL || (Flags & AMF_TARGETEMITTER)) - { - target = self; - } - else if (self->target != NULL && (Flags & AMF_TARGETNONPLAYER)) - { - target = self->target; - } - else if (self->target != NULL && self->target->player != NULL) - { - target = self->target; - } - - if (Flags & AMF_EMITFROMTARGET) emitter = target; - - if (target != NULL && emitter != NULL) - { - P_NoiseAlert(target, emitter, false, maxdist); - } - return 0; -} - -// Poison Bolt -------------------------------------------------------------- - -class APoisonBolt : public AActor -{ - DECLARE_CLASS (APoisonBolt, AActor) -public: - int DoSpecialDamage (AActor *target, int damage, FName damagetype); -}; - -IMPLEMENT_CLASS(APoisonBolt, false, false) - -int APoisonBolt::DoSpecialDamage (AActor *target, int damage, FName damagetype) -{ - if (target->flags & MF_NOBLOOD) - { - return -1; - } - if (target->health < 1000000) - { - if (!(target->flags2 & MF2_BOSS)) - return target->health + 10; - else - return 50; - } - return 1; -} - -// Strife's Crossbow -------------------------------------------------------- - -//============================================================================ -// -// A_ClearFlash -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_ClearFlash) -{ - PARAM_ACTION_PROLOGUE(AActor); - - player_t *player = self->player; - - if (player == nullptr) - return 0; - - P_SetPsprite (player, PSP_FLASH, nullptr); - return 0; -} - -//============================================================================ -// -// A_ShowElectricFlash -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_ShowElectricFlash) -{ - PARAM_ACTION_PROLOGUE(AActor); - - if (self->player != nullptr) - { - P_SetPsprite (self->player, PSP_FLASH, self->player->ReadyWeapon->FindState(NAME_Flash)); - } - return 0; -} - -//============================================================================ -// -// A_FireElectric -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FireArrow) -{ - PARAM_ACTION_PROLOGUE(AActor); - PARAM_CLASS(ti, AActor); - - DAngle savedangle; - - if (self->player == NULL) - return 0; - - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - - if (ti) - { - savedangle = self->Angles.Yaw; - self->Angles.Yaw += pr_electric.Random2() * (5.625/256) * self->player->mo->AccuracyFactor(); - self->player->mo->PlayAttacking2 (); - P_SpawnPlayerMissile (self, ti); - self->Angles.Yaw = savedangle; - S_Sound (self, CHAN_WEAPON, "weapons/xbowshoot", 1, ATTN_NORM); - } - return 0; -} - // Assault Gun -------------------------------------------------------------- //============================================================================ diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 6a59986c0..3d9122930 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -273,6 +273,70 @@ DEFINE_ACTION_FUNCTION(AActor, NoiseAlert) return 0; } +//============================================================================ +// +// P_DaggerAlert +// +//============================================================================ + +void P_DaggerAlert(AActor *target, AActor *emitter) +{ + AActor *looker; + sector_t *sec = emitter->Sector; + + if (emitter->LastHeard != NULL) + return; + if (emitter->health <= 0) + return; + if (!(emitter->flags3 & MF3_ISMONSTER)) + return; + if (emitter->flags4 & MF4_INCOMBAT) + return; + emitter->flags4 |= MF4_INCOMBAT; + + emitter->target = target; + FState *painstate = emitter->FindState(NAME_Pain, NAME_Dagger); + if (painstate != NULL) + { + emitter->SetState(painstate); + } + + for (looker = sec->thinglist; looker != NULL; looker = looker->snext) + { + if (looker == emitter || looker == target) + continue; + + if (looker->health <= 0) + continue; + + if (!(looker->flags4 & MF4_SEESDAGGERS)) + continue; + + if (!(looker->flags4 & MF4_INCOMBAT)) + { + if (!P_CheckSight(looker, target) && !P_CheckSight(looker, emitter)) + continue; + + looker->target = target; + if (looker->SeeSound) + { + S_Sound(looker, CHAN_VOICE, looker->SeeSound, 1, ATTN_NORM); + } + looker->SetState(looker->SeeState); + looker->flags4 |= MF4_INCOMBAT; + } + } +} + +DEFINE_ACTION_FUNCTION(AActor, DaggerAlert) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(target, AActor); + // Note that the emitter is self, not the target of the alert! Target can be NULL. + P_DaggerAlert(target, self); + return 0; +} + //---------------------------------------------------------------------------- // diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index d76832c59..04a9e9433 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -7598,6 +7598,11 @@ DEFINE_ACTION_FUNCTION(AActor, ClearBounce) return 0; } +DEFINE_ACTION_FUNCTION(AActor, AccuracyFactor) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_FLOAT(self->AccuracyFactor()); +} //---------------------------------------------------------------------------- // diff --git a/src/scripting/zscript/zcc-parse.lemon b/src/scripting/zscript/zcc-parse.lemon index ccd7e6e84..685c401e7 100644 --- a/src/scripting/zscript/zcc-parse.lemon +++ b/src/scripting/zscript/zcc-parse.lemon @@ -740,7 +740,7 @@ type_name(X) ::= DOT dottable_id(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 VECTOR2 VECTOR3 NAME MAP ARRAY VOID STATE COLOR UINT8 INT8 UINT16 INT16. + SBYTE BYTE SHORT USHORT INT UINT BOOL FLOAT DOUBLE STRING VECTOR2 VECTOR3 NAME MAP ARRAY VOID STATE COLOR SOUND UINT8 INT8 UINT16 INT16. /* Aggregate types */ %type aggregate_type {ZCC_Type *} diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index d3ed13d7e..4b646be4a 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -189,6 +189,8 @@ zscript/strife/strifestuff.txt zscript/strife/thingstoblowup.txt zscript/strife/templar.txt zscript/strife/zombie.txt +zscript/strife/weapondagger.txt +zscript/strife/weaponcrossbow.txt zscript/strife/sigil.txt zscript/chex/chexmonsters.txt diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 25d164d29..a5e0db153 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -288,6 +288,7 @@ class Actor : Thinker native native int PlayerNumber(); native void SetFriendPlayer(PlayerInfo player); native void NoiseAlert(Actor target, bool splash = false, double maxdist = 0); + native void DaggerAlert(Actor target); native void ClearBounce(); native TerrainDef GetFloorTerrain(); native Inventory DoDropItem(Class type, int dropamount, int chance); @@ -380,6 +381,7 @@ class Actor : Thinker native native Inventory DropInventory (Inventory item); native bool UseInventory(Inventory item); native bool GiveAmmo (Class type, int amount); + native float AccuracyFactor(); // DECORATE compatible functions native int CountInv(class itemtype, int ptr_select = AAPTR_DEFAULT); @@ -622,7 +624,6 @@ class Actor : Thinker native native void A_Wander(int flags = 0); native void A_Look2(); - native void A_AlertMonsters(double maxdist = 0, int flags = 0); deprecated native void A_MissileAttack(); deprecated native void A_MeleeAttack(); diff --git a/wadsrc/static/zscript/strife/strifefunctions.txt b/wadsrc/static/zscript/strife/strifefunctions.txt index febb2fdcb..f95ebcfcc 100644 --- a/wadsrc/static/zscript/strife/strifefunctions.txt +++ b/wadsrc/static/zscript/strife/strifefunctions.txt @@ -71,7 +71,11 @@ extend class Actor gib.Vel.Z = random[GibTosser]() & 15; } - // A_ShootGun ------------------------------------------------------------- + //========================================================================== + // + // + // + //========================================================================== void A_ShootGun() { @@ -82,7 +86,11 @@ extend class Actor LineAttack (Angle + Random2[ShootGun]() * (11.25 / 256), MISSILERANGE, pitch, 3*(random[ShootGun]() % 5 + 1), 'Hitscan', "StrifePuff"); } - // Kneeling Guy ------------------------------------------------------------- + //========================================================================== + // + // + // + //========================================================================== void A_SetShadow() { @@ -96,6 +104,12 @@ extend class Actor A_SetRenderStyle(1, STYLE_Normal); } + //========================================================================== + // + // + // + //========================================================================== + void A_GetHurt() { bInCombat = true; @@ -110,6 +124,12 @@ extend class Actor } } + //========================================================================== + // + // + // + //========================================================================== + void A_DropFire() { Actor drop = Spawn("FireDroplet", pos + (0,0,24), ALLOW_REPLACE); @@ -117,9 +137,45 @@ extend class Actor A_Explode(64, 64, XF_NOSPLASH, damagetype: 'Fire'); } + //========================================================================== + // + // + // + //========================================================================== + void A_RemoveForceField() { bSpecial = false; CurSector.RemoveForceField(); } + + //========================================================================== + // + // + // + //========================================================================== + + void A_AlertMonsters(double maxdist = 0, int flags = 0) + { + Actor target = null; + Actor emitter = self; + + if (player != null || (Flags & AMF_TARGETEMITTER)) + { + target = self; + } + else if (target != null && (self.target.player != null || (Flags & AMF_TARGETNONPLAYER))) + { + target = self.target; + } + + if (Flags & AMF_EMITFROMTARGET) emitter = target; + + if (target != null && emitter != null) + { + emitter.NoiseAlert(target, false, maxdist); + } + } + + } diff --git a/wadsrc/static/zscript/strife/strifeweapons.txt b/wadsrc/static/zscript/strife/strifeweapons.txt index 0180ea445..a2475397d 100644 --- a/wadsrc/static/zscript/strife/strifeweapons.txt +++ b/wadsrc/static/zscript/strife/strifeweapons.txt @@ -50,212 +50,6 @@ class StrifeSpark : StrifePuff } } -// Punch Dagger ------------------------------------------------------------- - -class PunchDagger : StrifeWeapon -{ - Default - { - Weapon.SelectionOrder 3900; - +WEAPON.NOALERT - Obituary "$OB_MPPUNCHDAGGER"; - Tag "$TAG_PUNCHDAGGER"; - } - - action native void A_JabDagger (); - - States - { - Ready: - PNCH A 1 A_WeaponReady; - Loop; - Deselect: - PNCH A 1 A_Lower; - Loop; - Select: - PNCH A 1 A_Raise; - Loop; - Fire: - PNCH B 4; - PNCH C 4 A_JabDagger; - PNCH D 5; - PNCH C 4; - PNCH B 5 A_ReFire; - Goto Ready; - } - -} - - -// The base for Strife projectiles that die with ZAP1 ----------------------- - -class StrifeZap1 : Actor -{ - Default - { - +NOBLOCKMAP - +NOGRAVITY - +DROPOFF - } - States - { - Spawn: - Death: - ZAP1 A 3 A_AlertMonsters; - ZAP1 BCDEFE 3; - ZAP1 DCB 2; - ZAP1 A 1; - Stop; - } -} - - -// Electric Bolt ------------------------------------------------------------ - -class ElectricBolt : StrifeZap1 -{ - Default - { - Speed 30; - Radius 10; - Height 10; - Damage 10; - Projectile; - +STRIFEDAMAGE - MaxStepHeight 4; - SeeSound "misc/swish"; - ActiveSound "misc/swish"; - DeathSound "weapons/xbowhit"; - Obituary "$OB_MPELECTRICBOLT"; - } - States - { - Spawn: - AROW A 10 A_LoopActiveSound; - Loop; - } -} - - -// Poison Bolt -------------------------------------------------------------- - -class PoisonBolt : Actor native -{ - Default - { - Speed 30; - Radius 10; - Height 10; - Damage 500; - Projectile; - +STRIFEDAMAGE - MaxStepHeight 4; - SeeSound "misc/swish"; - ActiveSound "misc/swish"; - Obituary "$OB_MPPOISONBOLT"; - } - States - { - Spawn: - ARWP A 10 A_LoopActiveSound; - Loop; - Death: - AROW A 1; - Stop; - } -} - - -// Strife's Crossbow -------------------------------------------------------- - -class StrifeCrossbow : StrifeWeapon -{ - Default - { - +FLOORCLIP - Weapon.SelectionOrder 1200; - +WEAPON.NOALERT - Weapon.AmmoUse1 1; - Weapon.AmmoGive1 8; - Weapon.AmmoType1 "ElectricBolts"; - Weapon.SisterWeapon "StrifeCrossbow2"; - Inventory.PickupMessage "$TXT_STRIFECROSSBOW"; - Tag "$TAG_STRIFECROSSBOW1"; - Inventory.Icon "CBOWA0"; - } - - action native void A_ClearFlash (); - action native void A_ShowElectricFlash (); - action native void A_FireArrow (class proj); - - States - { - Spawn: - CBOW A -1; - Stop; - Ready: - XBOW A 0 A_ShowElectricFlash; - XBOW A 1 A_WeaponReady; - Wait; - Deselect: - XBOW A 1 A_Lower; - Loop; - Select: - XBOW A 1 A_Raise; - Loop; - Fire: - XBOW A 3 A_ClearFlash; - XBOW B 6 A_FireArrow("ElectricBolt"); - XBOW C 4; - XBOW D 6; - XBOW E 3; - XBOW F 5; - XBOW G 0 A_ShowElectricFlash; - XBOW G 5 A_CheckReload; - Goto Ready+1; - Flash: - XBOW KLM 5; - Loop; - } -} - - -class StrifeCrossbow2 : StrifeCrossbow -{ - Default - { - Weapon.SelectionOrder 2700; - Weapon.AmmoUse1 1; - Weapon.AmmoGive1 0; - Weapon.AmmoType1 "PoisonBolts"; - Weapon.SisterWeapon "StrifeCrossbow"; - Tag "$TAG_STRIFECROSSBOW2"; - } - States - { - Ready: - XBOW H 1 A_WeaponReady; - Loop; - Deselect: - XBOW H 1 A_Lower; - Loop; - Select: - XBOW H 1 A_Raise; - Loop; - Fire: - XBOW H 3; - XBOW B 6 A_FireArrow("PoisonBolt"); - XBOW C 4; - XBOW D 6; - XBOW E 3; - XBOW I 5; - XBOW J 5 A_CheckReload; - Goto Ready; - Flash: - Stop; - } -} - // Assault Gun -------------------------------------------------------------- class AssaultGun : StrifeWeapon diff --git a/wadsrc/static/zscript/strife/weaponcrossbow.txt b/wadsrc/static/zscript/strife/weaponcrossbow.txt new file mode 100644 index 000000000..1617fbfcd --- /dev/null +++ b/wadsrc/static/zscript/strife/weaponcrossbow.txt @@ -0,0 +1,227 @@ +// Strife's Crossbow -------------------------------------------------------- + +class StrifeCrossbow : StrifeWeapon +{ + Default + { + +FLOORCLIP + Weapon.SelectionOrder 1200; + +WEAPON.NOALERT + Weapon.AmmoUse1 1; + Weapon.AmmoGive1 8; + Weapon.AmmoType1 "ElectricBolts"; + Weapon.SisterWeapon "StrifeCrossbow2"; + Inventory.PickupMessage "$TXT_STRIFECROSSBOW"; + Tag "$TAG_STRIFECROSSBOW1"; + Inventory.Icon "CBOWA0"; + } + + States + { + Spawn: + CBOW A -1; + Stop; + Ready: + XBOW A 0 A_ShowElectricFlash; + XBOW A 1 A_WeaponReady; + Wait; + Deselect: + XBOW A 1 A_Lower; + Loop; + Select: + XBOW A 1 A_Raise; + Loop; + Fire: + XBOW A 3 A_ClearFlash; + XBOW B 6 A_FireArrow("ElectricBolt"); + XBOW C 4; + XBOW D 6; + XBOW E 3; + XBOW F 5; + XBOW G 0 A_ShowElectricFlash; + XBOW G 5 A_CheckReload; + Goto Ready+1; + Flash: + XBOW KLM 5; + Loop; + } + + //============================================================================ + // + // A_ClearFlash + // + //============================================================================ + + action void A_ClearFlash () + { + if (player == null) + return; + + player.SetPsprite (PSP_FLASH, null); + } + + //============================================================================ + // + // A_ShowElectricFlash + // + //============================================================================ + + action void A_ShowElectricFlash () + { + if (player != null) + { + player.SetPsprite (PSP_FLASH, player.ReadyWeapon.FindState('Flash')); + } + } + + //============================================================================ + // + // A_FireElectric + // + //============================================================================ + + action void A_FireArrow (class proj) + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + if (proj) + { + double savedangle = angle; + angle += Random2[Electric]() * (5.625/256) * AccuracyFactor(); + player.mo.PlayAttacking2 (); + SpawnPlayerMissile (proj); + angle = savedangle; + A_PlaySound ("weapons/xbowshoot", CHAN_WEAPON); + } + } +} + + +class StrifeCrossbow2 : StrifeCrossbow +{ + Default + { + Weapon.SelectionOrder 2700; + Weapon.AmmoUse1 1; + Weapon.AmmoGive1 0; + Weapon.AmmoType1 "PoisonBolts"; + Weapon.SisterWeapon "StrifeCrossbow"; + Tag "$TAG_STRIFECROSSBOW2"; + } + States + { + Ready: + XBOW H 1 A_WeaponReady; + Loop; + Deselect: + XBOW H 1 A_Lower; + Loop; + Select: + XBOW H 1 A_Raise; + Loop; + Fire: + XBOW H 3; + XBOW B 6 A_FireArrow("PoisonBolt"); + XBOW C 4; + XBOW D 6; + XBOW E 3; + XBOW I 5; + XBOW J 5 A_CheckReload; + Goto Ready; + Flash: + Stop; + } +} + +// Electric Bolt ------------------------------------------------------------ + +class ElectricBolt : Actor +{ + Default + { + Speed 30; + Radius 10; + Height 10; + Damage 10; + Projectile; + +STRIFEDAMAGE + +NOBLOCKMAP + +NOGRAVITY + +DROPOFF + MaxStepHeight 4; + SeeSound "misc/swish"; + ActiveSound "misc/swish"; + DeathSound "weapons/xbowhit"; + Obituary "$OB_MPELECTRICBOLT"; + } + States + { + Spawn: + AROW A 10 A_LoopActiveSound; + Loop; + Death: + ZAP1 A 3 A_AlertMonsters; + ZAP1 BCDEFE 3; + ZAP1 DCB 2; + ZAP1 A 1; + Stop; + } +} + + +// Poison Bolt -------------------------------------------------------------- + +class PoisonBolt : Actor +{ + Default + { + Speed 30; + Radius 10; + Height 10; + Damage 500; + Projectile; + +STRIFEDAMAGE + MaxStepHeight 4; + SeeSound "misc/swish"; + ActiveSound "misc/swish"; + Obituary "$OB_MPPOISONBOLT"; + } + States + { + Spawn: + ARWP A 10 A_LoopActiveSound; + Loop; + Death: + AROW A 1; + Stop; + } + + override int DoSpecialDamage (Actor target, int damage, Name damagetype) + { + if (target.bNoBlood) + { + return -1; + } + if (target.health < 1000000) + { + if (!target.bBoss) + return target.health + 10; + else + return 50; + } + return 1; + } + + +} + + diff --git a/wadsrc/static/zscript/strife/weapondagger.txt b/wadsrc/static/zscript/strife/weapondagger.txt new file mode 100644 index 000000000..24aef209b --- /dev/null +++ b/wadsrc/static/zscript/strife/weapondagger.txt @@ -0,0 +1,69 @@ + +// Punch Dagger ------------------------------------------------------------- + +class PunchDagger : StrifeWeapon +{ + Default + { + Weapon.SelectionOrder 3900; + +WEAPON.NOALERT + Obituary "$OB_MPPUNCHDAGGER"; + Tag "$TAG_PUNCHDAGGER"; + } + + States + { + Ready: + PNCH A 1 A_WeaponReady; + Loop; + Deselect: + PNCH A 1 A_Lower; + Loop; + Select: + PNCH A 1 A_Raise; + Loop; + Fire: + PNCH B 4; + PNCH C 4 A_JabDagger; + PNCH D 5; + PNCH C 4; + PNCH B 5 A_ReFire; + Goto Ready; + } + + //============================================================================ + // + // A_JabDagger + // + //============================================================================ + + action void A_JabDagger () + { + FTranslatedLineTarget t; + + int power = MIN(10, stamina / 10); + int damage = (random[JabDagger]() % (power + 8)) * (power + 2); + + if (FindInventory("PowerStrength")) + { + damage *= 10; + } + + double angle = angle + random2[JabDagger]() * (5.625 / 256); + double pitch = AimLineAttack (angle, 80.); + LineAttack (angle, 80., pitch, damage, 'Melee', "StrifeSpark", true, t); + + // turn to face target + if (t.linetarget) + { + S_Sound (t.linetarget.bNoBlood ? sound("misc/metalhit") : sound("misc/meathit"), CHAN_WEAPON); + angle = t.angleFromSource; + bJustAttacked = true; + t.linetarget.DaggerAlert (self); + } + else + { + A_PlaySound ("misc/swish", CHAN_WEAPON); + } + } +} From 5beebb83b741b0ef43cb4ef6e65e7d2c24ba4302 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 29 Nov 2016 13:28:43 +0100 Subject: [PATCH 164/185] - scriptified Strife's assault gun and missile launcher. --- src/g_shared/a_pickups.cpp | 1 - src/g_strife/a_strifeweapons.cpp | 109 ----------- wadsrc/static/zscript.txt | 2 + wadsrc/static/zscript/actor.txt | 1 - wadsrc/static/zscript/constants.txt | 9 + wadsrc/static/zscript/shared/inventory.txt | 1 - .../static/zscript/strife/strifefunctions.txt | 19 +- .../static/zscript/strife/strifeweapons.txt | 171 ------------------ .../static/zscript/strife/weaponassault.txt | 94 ++++++++++ .../static/zscript/strife/weaponmissile.txt | 137 ++++++++++++++ 10 files changed, 260 insertions(+), 284 deletions(-) create mode 100644 wadsrc/static/zscript/strife/weaponassault.txt create mode 100644 wadsrc/static/zscript/strife/weaponmissile.txt diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index 38d068bd7..ad843667a 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -1717,7 +1717,6 @@ bool AInventory::CallTryPickup (AActor *toucher, AActor **toucher_return) bool res; if (CanPickup(toucher)) { - bool res; IFVIRTUAL(AInventory, TryPickup) { VMValue params[2] = { (DObject*)this, (void*)&toucher }; diff --git a/src/g_strife/a_strifeweapons.cpp b/src/g_strife/a_strifeweapons.cpp index 67c8c8c17..8492789db 100644 --- a/src/g_strife/a_strifeweapons.cpp +++ b/src/g_strife/a_strifeweapons.cpp @@ -30,117 +30,8 @@ void A_Countdown (AActor *); // Assault Gun -------------------------------------------------------------- -//============================================================================ -// -// P_StrifeGunShot -// -//============================================================================ - -void P_StrifeGunShot (AActor *mo, bool accurate, DAngle pitch) -{ - DAngle angle; - int damage; - - damage = 4*(pr_sgunshot()%3+1); - angle = mo->Angles.Yaw; - - if (mo->player != NULL && !accurate) - { - angle += pr_sgunshot.Random2() * (22.5 / 256) * mo->player->mo->AccuracyFactor(); - } - - P_LineAttack (mo, angle, PLAYERMISSILERANGE, pitch, damage, NAME_Hitscan, NAME_StrifePuff); -} - -//============================================================================ -// -// A_FireAssaultGun -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FireAssaultGun) -{ - PARAM_ACTION_PROLOGUE(AActor); - - bool accurate; - - S_Sound (self, CHAN_WEAPON, "weapons/assaultgun", 1, ATTN_NORM); - - if (self->player != NULL) - { - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - self->player->mo->PlayAttacking2 (); - accurate = !self->player->refire; - } - else - { - accurate = true; - } - - P_StrifeGunShot (self, accurate, P_BulletSlope (self)); - return 0; -} - // Mini-Missile Launcher ---------------------------------------------------- -//============================================================================ -// -// A_FireMiniMissile -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FireMiniMissile) -{ - PARAM_ACTION_PROLOGUE(AActor); - - player_t *player = self->player; - DAngle savedangle; - - if (self->player == NULL) - return 0; - - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - - savedangle = self->Angles.Yaw; - self->Angles.Yaw += pr_minimissile.Random2() * (11.25 / 256) * player->mo->AccuracyFactor(); - player->mo->PlayAttacking2 (); - P_SpawnPlayerMissile (self, PClass::FindActor("MiniMissile")); - self->Angles.Yaw = savedangle; - return 0; -} - -//============================================================================ -// -// A_RocketInFlight -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_RocketInFlight) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *trail; - - S_Sound (self, CHAN_VOICE, "misc/missileinflight", 1, ATTN_NORM); - P_SpawnPuff (self, PClass::FindActor("MiniMissilePuff"), self->Pos(), self->Angles.Yaw - 180, self->Angles.Yaw - 180, 2, PF_HITTHING); - trail = Spawn("RocketTrail", self->Vec3Offset(-self->Vel.X, -self->Vel.Y, 0.), ALLOW_REPLACE); - if (trail != NULL) - { - trail->Vel.Z = 1; - } - return 0; -} - // Flame Thrower ------------------------------------------------------------ //============================================================================ diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 4b646be4a..eb6e30dcb 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -191,6 +191,8 @@ zscript/strife/templar.txt zscript/strife/zombie.txt zscript/strife/weapondagger.txt zscript/strife/weaponcrossbow.txt +zscript/strife/weaponassault.txt +zscript/strife/weaponmissile.txt zscript/strife/sigil.txt zscript/chex/chexmonsters.txt diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index a5e0db153..5279372fd 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -694,7 +694,6 @@ class Actor : Thinker native native void A_ClearLastHeard(); native bool A_SelectWeapon(class whichweapon, int flags = 0); native void A_ClassBossHealth(); - native void A_RocketInFlight(); native void A_SetAngle(double angle = 0, int flags = 0, int ptr = AAPTR_DEFAULT); native void A_SetPitch(double pitch, int flags = 0, int ptr = AAPTR_DEFAULT); native void A_SetRoll(double roll, int flags = 0, int ptr = AAPTR_DEFAULT); diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index 8180e6710..2ccfb7048 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -1037,3 +1037,12 @@ enum EGameAction ga_togglemap, ga_fullconsole, }; + +enum EPuffFlags +{ + PF_HITTHING = 1, + PF_MELEERANGE = 2, + PF_TEMPORARY = 4, + PF_HITTHINGBLEED = 8, + PF_NORANDOMZ = 16 +}; diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index dbede839f..5192b4c93 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -83,7 +83,6 @@ class StateProvider : Inventory native action native void A_ClearReFire(); action native void A_CheckReload(); action native void A_GunFlash(statelabel flash = null, int flags = 0); - action native void A_FireAssaultGun(); action native state A_CheckForReload(int counter, statelabel label, bool dontincrement = false); action native void A_ResetReloadCounter(); } diff --git a/wadsrc/static/zscript/strife/strifefunctions.txt b/wadsrc/static/zscript/strife/strifefunctions.txt index f95ebcfcc..7cfdf3974 100644 --- a/wadsrc/static/zscript/strife/strifefunctions.txt +++ b/wadsrc/static/zscript/strife/strifefunctions.txt @@ -1,4 +1,4 @@ -// common Strife action functions. +// common Strife action functions that are used by multiple different actors extend class Actor { @@ -177,5 +177,22 @@ extend class Actor } } + //============================================================================ + // + // A_RocketInFlight + // + //============================================================================ + + void A_RocketInFlight() + { + A_PlaySound ("misc/missileinflight", CHAN_VOICE); + SpawnPuff ("MiniMissilePuff", Pos, Angle - 180, Angle - 180, 2, PF_HITTHING); + Actor trail = Spawn("RocketTrail", Vec3Offset(-Vel.X, -Vel.Y, 0.), ALLOW_REPLACE); + if (trail != null) + { + trail.Vel.Z = 1; + } + } + } diff --git a/wadsrc/static/zscript/strife/strifeweapons.txt b/wadsrc/static/zscript/strife/strifeweapons.txt index a2475397d..ae0bc1284 100644 --- a/wadsrc/static/zscript/strife/strifeweapons.txt +++ b/wadsrc/static/zscript/strife/strifeweapons.txt @@ -50,177 +50,6 @@ class StrifeSpark : StrifePuff } } -// Assault Gun -------------------------------------------------------------- - -class AssaultGun : StrifeWeapon -{ - Default - { - +FLOORCLIP - Weapon.SelectionOrder 600; - Weapon.AmmoUse1 1; - Weapon.AmmoGive1 20; - Weapon.AmmoType1 "ClipOfBullets"; - Inventory.Icon "RIFLA0"; - Tag "$TAG_ASSAULTGUN"; - Inventory.PickupMessage "$TXT_ASSAULTGUN"; - Obituary "$OB_MPASSAULTGUN"; - } - States - { - Spawn: - RIFL A -1; - Stop; - Ready: - RIFG A 1 A_WeaponReady; - Loop; - Deselect: - RIFG B 1 A_Lower; - Loop; - Select: - RIFG A 1 A_Raise; - Loop; - Fire: - RIFF AB 3 A_FireAssaultGun; - RIFG D 3 A_FireAssaultGun; - RIFG C 0 A_ReFire; - RIFG B 2 A_Light0; - Goto Ready; - } -} - - -// Standing variant of the assault gun -------------------------------------- - -class AssaultGunStanding : WeaponGiver -{ - Default - { - DropItem "AssaultGun"; - Inventory.PickupMessage "$TXT_ASSAULTGUN"; - } - States - { - Spawn: - RIFL B -1; - Stop; - } -} - - -// Mini-Missile Launcher ---------------------------------------------------- - - -class MiniMissileLauncher : StrifeWeapon -{ - Default - { - +FLOORCLIP - Weapon.SelectionOrder 1800; - Weapon.AmmoUse1 1; - Weapon.AmmoGive1 8; - Weapon.AmmoType1 "MiniMissiles"; - Inventory.Icon "MMSLA0"; - Tag "$TAG_MMLAUNCHER"; - Inventory.PickupMessage "$TXT_MMLAUNCHER"; - } - - action native void A_FireMiniMissile (); - - States - { - Spawn: - MMSL A -1; - Stop; - Ready: - MMIS A 1 A_WeaponReady; - Loop; - Deselect: - MMIS A 1 A_Lower; - Loop; - Select: - MMIS A 1 A_Raise; - Loop; - Fire: - MMIS A 4 A_FireMiniMissile; - MMIS B 4 A_Light1; - MMIS C 5 Bright; - MMIS D 2 Bright A_Light2; - MMIS E 2 Bright; - MMIS F 2 Bright A_Light0; - MMIS F 0 A_ReFire; - Goto Ready; - } -} - - -// Rocket Trail ------------------------------------------------------------- - -class RocketTrail : Actor -{ - Default - { - +NOBLOCKMAP - +NOGRAVITY - RenderStyle "Translucent"; - Alpha 0.25; - SeeSound "misc/missileinflight"; - } - States - { - Spawn: - PUFY BCBCD 4; - Stop; - } -} - -// Rocket Puff -------------------------------------------------------------- - -class MiniMissilePuff : StrifePuff -{ - Default - { - -ALLOWPARTICLES - } - States - { - Spawn: - Goto Crash; - } -} - -// Mini Missile ------------------------------------------------------------- - -class MiniMissile : Actor -{ - Default - { - Speed 20; - Radius 10; - Height 14; - Damage 10; - Projectile; - +STRIFEDAMAGE - MaxStepHeight 4; - SeeSound "weapons/minimissile"; - DeathSound "weapons/minimissilehit"; - Obituary "$OB_MPMINIMISSILELAUNCHER"; - } - States - { - Spawn: - MICR A 6 Bright A_RocketInFlight; - Loop; - Death: - SMIS A 0 Bright A_SetRenderStyle(1, STYLE_Normal); - SMIS A 5 Bright A_Explode(64, 64, alert:true); - SMIS B 5 Bright; - SMIS C 4 Bright; - SMIS DEFG 2 Bright; - Stop; - } -} - // Flame Thrower ------------------------------------------------------------ class FlameThrower : StrifeWeapon diff --git a/wadsrc/static/zscript/strife/weaponassault.txt b/wadsrc/static/zscript/strife/weaponassault.txt new file mode 100644 index 000000000..c382d8e84 --- /dev/null +++ b/wadsrc/static/zscript/strife/weaponassault.txt @@ -0,0 +1,94 @@ +// Assault Gun -------------------------------------------------------------- + +class AssaultGun : StrifeWeapon +{ + Default + { + +FLOORCLIP + Weapon.SelectionOrder 600; + Weapon.AmmoUse1 1; + Weapon.AmmoGive1 20; + Weapon.AmmoType1 "ClipOfBullets"; + Inventory.Icon "RIFLA0"; + Tag "$TAG_ASSAULTGUN"; + Inventory.PickupMessage "$TXT_ASSAULTGUN"; + Obituary "$OB_MPASSAULTGUN"; + } + States + { + Spawn: + RIFL A -1; + Stop; + Ready: + RIFG A 1 A_WeaponReady; + Loop; + Deselect: + RIFG B 1 A_Lower; + Loop; + Select: + RIFG A 1 A_Raise; + Loop; + Fire: + RIFF AB 3 A_FireAssaultGun; + RIFG D 3 A_FireAssaultGun; + RIFG C 0 A_ReFire; + RIFG B 2 A_Light0; + Goto Ready; + } +} + +extend class StateProvider +{ + //============================================================================ + // + // A_FireAssaultGun + // + //============================================================================ + + void A_FireAssaultGun() + { + if (player == null) + { + return; + } + + A_PlaySound ("weapons/assaultgun", CHAN_WEAPON); + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + player.mo.PlayAttacking2 (); + + int damage = 4*(random[StrifeGun]() % 3 + 1); + double ang = angle; + + if (player.refire) + { + ang += Random2[StrifeGun]() * (22.5 / 256) * AccuracyFactor(); + } + LineAttack (ang, PLAYERMISSILERANGE, BulletSlope (), damage, 'Hitscan', "StrifePuff"); + } +} + + +// Standing variant of the assault gun -------------------------------------- + +class AssaultGunStanding : WeaponGiver +{ + Default + { + DropItem "AssaultGun"; + Inventory.PickupMessage "$TXT_ASSAULTGUN"; + } + States + { + Spawn: + RIFL B -1; + Stop; + } +} + + diff --git a/wadsrc/static/zscript/strife/weaponmissile.txt b/wadsrc/static/zscript/strife/weaponmissile.txt new file mode 100644 index 000000000..589f75493 --- /dev/null +++ b/wadsrc/static/zscript/strife/weaponmissile.txt @@ -0,0 +1,137 @@ +// Mini-Missile Launcher ---------------------------------------------------- + +class MiniMissileLauncher : StrifeWeapon +{ + Default + { + +FLOORCLIP + Weapon.SelectionOrder 1800; + Weapon.AmmoUse1 1; + Weapon.AmmoGive1 8; + Weapon.AmmoType1 "MiniMissiles"; + Inventory.Icon "MMSLA0"; + Tag "$TAG_MMLAUNCHER"; + Inventory.PickupMessage "$TXT_MMLAUNCHER"; + } + + States + { + Spawn: + MMSL A -1; + Stop; + Ready: + MMIS A 1 A_WeaponReady; + Loop; + Deselect: + MMIS A 1 A_Lower; + Loop; + Select: + MMIS A 1 A_Raise; + Loop; + Fire: + MMIS A 4 A_FireMiniMissile; + MMIS B 4 A_Light1; + MMIS C 5 Bright; + MMIS D 2 Bright A_Light2; + MMIS E 2 Bright; + MMIS F 2 Bright A_Light0; + MMIS F 0 A_ReFire; + Goto Ready; + } + + //============================================================================ + // + // A_FireMiniMissile + // + //============================================================================ + + action void A_FireMiniMissile () + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + + double savedangle = angle; + angle += Random2[MiniMissile]() * (11.25 / 256) * AccuracyFactor(); + player.mo.PlayAttacking2 (); + SpawnPlayerMissile ("MiniMissile"); + angle = savedangle; + } +} + + +// Rocket Trail ------------------------------------------------------------- + +class RocketTrail : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + RenderStyle "Translucent"; + Alpha 0.25; + SeeSound "misc/missileinflight"; + } + States + { + Spawn: + PUFY BCBCD 4; + Stop; + } +} + +// Rocket Puff -------------------------------------------------------------- + +class MiniMissilePuff : StrifePuff +{ + Default + { + -ALLOWPARTICLES + } + States + { + Spawn: + Goto Crash; + } +} + +// Mini Missile ------------------------------------------------------------- + +class MiniMissile : Actor +{ + Default + { + Speed 20; + Radius 10; + Height 14; + Damage 10; + Projectile; + +STRIFEDAMAGE + MaxStepHeight 4; + SeeSound "weapons/minimissile"; + DeathSound "weapons/minimissilehit"; + Obituary "$OB_MPMINIMISSILELAUNCHER"; + } + States + { + Spawn: + MICR A 6 Bright A_RocketInFlight; + Loop; + Death: + SMIS A 0 Bright A_SetRenderStyle(1, STYLE_Normal); + SMIS A 5 Bright A_Explode(64, 64, alert:true); + SMIS B 5 Bright; + SMIS C 4 Bright; + SMIS DEFG 2 Bright; + Stop; + } +} + From b625156df63dd2434cef8b0ec5dc42983ed344e3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 29 Nov 2016 14:12:39 +0100 Subject: [PATCH 165/185] - scriptified Strife's flamethrower and grenade launcher. --- src/g_strife/a_strifeweapons.cpp | 179 ---------- src/p_glnodes.cpp | 1 - src/p_maputl.cpp | 1 - src/p_mobj.cpp | 9 + src/p_sectors.cpp | 39 +++ wadsrc/static/zscript.txt | 2 + wadsrc/static/zscript/actor.txt | 1 + wadsrc/static/zscript/base.txt | 3 + .../static/zscript/strife/strifeweapons.txt | 288 ---------------- wadsrc/static/zscript/strife/weaponflamer.txt | 118 +++++++ .../static/zscript/strife/weapongrenade.txt | 315 ++++++++++++++++++ 11 files changed, 487 insertions(+), 469 deletions(-) create mode 100644 wadsrc/static/zscript/strife/weaponflamer.txt create mode 100644 wadsrc/static/zscript/strife/weapongrenade.txt diff --git a/src/g_strife/a_strifeweapons.cpp b/src/g_strife/a_strifeweapons.cpp index 8492789db..bcedd1429 100644 --- a/src/g_strife/a_strifeweapons.cpp +++ b/src/g_strife/a_strifeweapons.cpp @@ -34,53 +34,6 @@ void A_Countdown (AActor *); // Flame Thrower ------------------------------------------------------------ -//============================================================================ -// -// A_FlameDie -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FlameDie) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->flags |= MF_NOGRAVITY; - self->Vel.Z = pr_flamedie() & 3; - return 0; -} - -//============================================================================ -// -// A_FireFlamer -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FireFlamer) -{ - PARAM_ACTION_PROLOGUE(AActor); - - player_t *player = self->player; - - if (player != NULL) - { - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - player->mo->PlayAttacking2 (); - } - - self->Angles.Yaw += pr_flamethrower.Random2() * (5.625/256.); - self = P_SpawnPlayerMissile (self, PClass::FindActor("FlameMissile")); - if (self != NULL) - { - self->Vel.Z += 5; - } - return 0; -} - // Mauler ------------------------------------------------------------------- //============================================================================ @@ -210,135 +163,3 @@ DEFINE_ACTION_FUNCTION(AActor, A_MaulerTorpedoWave) return 0; } -class APhosphorousFire : public AActor -{ - DECLARE_CLASS (APhosphorousFire, AActor) -public: - int DoSpecialDamage (AActor *target, int damage, FName damagetype); -}; - -IMPLEMENT_CLASS(APhosphorousFire, false, false) - -int APhosphorousFire::DoSpecialDamage (AActor *target, int damage, FName damagetype) -{ - if (target->flags & MF_NOBLOOD) - { - return damage / 2; - } - return Super::DoSpecialDamage (target, damage, damagetype); -} - -DEFINE_ACTION_FUNCTION(AActor, A_BurnArea) -{ - PARAM_SELF_PROLOGUE(AActor); - - P_RadiusAttack (self, self->target, 128, 128, self->DamageType, RADF_HURTSOURCE); - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_Burnination) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->Vel.Z -= 8; - self->Vel.X += (pr_phburn.Random2 (3)); - self->Vel.Y += (pr_phburn.Random2 (3)); - S_Sound (self, CHAN_VOICE, "world/largefire", 1, ATTN_NORM); - - // Only the main fire spawns more. - if (!(self->flags & MF_DROPPED)) - { - // Original x and y offsets seemed to be like this: - // x + (((pr_phburn() + 12) & 31) << F.RACBITS); - // - // But that creates a lop-sided burn because it won't use negative offsets. - int xofs, xrand = pr_phburn(); - int yofs, yrand = pr_phburn(); - - // Adding 12 is pointless if you're going to mask it afterward. - xofs = xrand & 31; - if (xrand & 128) - { - xofs = -xofs; - } - - yofs = yrand & 31; - if (yrand & 128) - { - yofs = -yofs; - } - - DVector2 pos = self->Vec2Offset((double)xofs, (double)yofs); - sector_t * sector = P_PointInSector(pos); - - // The sector's floor is too high so spawn the flame elsewhere. - if (sector->floorplane.ZatPoint(pos) > self->Z() + self->MaxStepHeight) - { - pos = self->Pos(); - } - - AActor *drop = Spawn (DVector3(pos, self->Z() + 4.), ALLOW_REPLACE); - if (drop != NULL) - { - drop->Vel.X = self->Vel.X + pr_phburn.Random2 (7); - drop->Vel.Y = self->Vel.Y + pr_phburn.Random2 (7); - drop->Vel.Z = self->Vel.Z - 1; - drop->reactiontime = (pr_phburn() & 3) + 2; - drop->flags |= MF_DROPPED; - } - } - return 0; -} - -//============================================================================ -// -// A_FireGrenade -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FireGrenade) -{ - PARAM_ACTION_PROLOGUE(AActor); - PARAM_CLASS(grenadetype, AActor); - PARAM_ANGLE(angleofs); - PARAM_STATE(flash) - - player_t *player = self->player; - AActor *grenade; - DAngle an; - AWeapon *weapon; - - if (player == nullptr || grenadetype == nullptr) - return 0; - - if ((weapon = player->ReadyWeapon) == nullptr) - return 0; - - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - - P_SetPsprite (player, PSP_FLASH, flash, true); - - if (grenadetype != nullptr) - { - self->AddZ(32); - grenade = P_SpawnSubMissile (self, grenadetype, self); - self->AddZ(-32); - if (grenade == nullptr) - return 0; - - if (grenade->SeeSound != 0) - { - S_Sound (grenade, CHAN_VOICE, grenade->SeeSound, 1, ATTN_NORM); - } - - grenade->Vel.Z = (-self->Angles.Pitch.TanClamped()) * grenade->Speed + 8; - - DVector2 offset = self->Angles.Yaw.ToVector(self->radius + grenade->radius); - DAngle an = self->Angles.Yaw + angleofs; - offset += an.ToVector(15); - grenade->SetOrigin(grenade->Vec3Offset(offset.X, offset.Y, 0.), false); - } - return 0; -} - diff --git a/src/p_glnodes.cpp b/src/p_glnodes.cpp index 39c8f8e0d..26e341aab 100644 --- a/src/p_glnodes.cpp +++ b/src/p_glnodes.cpp @@ -1356,7 +1356,6 @@ subsector_t *P_PointInSubsector (double x, double y) return (subsector_t *)((BYTE *)node - 1); } - //========================================================================== // // PointOnLine diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 2d2472cbd..16fc790c0 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -1971,4 +1971,3 @@ sector_t *P_PointInSectorBuggy(double x, double y) subsector_t *ssec = (subsector_t *)((BYTE *)node - 1); return ssec->sector; } - diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 04a9e9433..5e2a9f039 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -7560,6 +7560,15 @@ DEFINE_ACTION_FUNCTION(AActor, Vec2OffsetZ) ACTION_RETURN_VEC3(self->Vec2OffsetZ(x, y, z, absolute)); } +DEFINE_ACTION_FUNCTION(AActor, Vec2Offset) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_BOOL_DEF(absolute); + ACTION_RETURN_VEC2(self->Vec2Offset(x, y, absolute)); +} + DEFINE_ACTION_FUNCTION(AActor, Vec3Offset) { PARAM_SELF_PROLOGUE(AActor); diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index e6302199b..2b8097e55 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -1050,6 +1050,35 @@ double sector_t::NextLowestFloorAt(double x, double y, double z, int flags, doub } } +DEFINE_ACTION_FUNCTION(_Sector, NextLowestFloorAt) +{ + PARAM_SELF_STRUCT_PROLOGUE(sector_t); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + PARAM_INT_DEF(flags); + PARAM_FLOAT_DEF(steph); + sector_t *resultsec; + F3DFloor *resultff; + double resultheight = self->NextLowestFloorAt(x, y, z, flags, steph, &resultsec, &resultff); + + if (numret > 2) + { + ret[2].SetPointer(resultff, ATAG_GENERIC); + numret = 3; + } + if (numret > 1) + { + ret[1].SetPointer(resultsec, ATAG_GENERIC); + } + if (numret > 0) + { + ret[0].SetFloat(resultheight); + } + return numret; +} + + //=========================================================================== // // @@ -1103,6 +1132,16 @@ double sector_t::NextLowestFloorAt(double x, double y, double z, int flags, doub self->RemoveForceField(); return 0; } + + + DEFINE_ACTION_FUNCTION(_Sector, PointInSector) + { + PARAM_PROLOGUE; + PARAM_FLOAT(x); + PARAM_FLOAT(y); + ACTION_RETURN_POINTER(P_PointInSector(x, y)); + } + //=========================================================================== // // diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index eb6e30dcb..cbba151f5 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -193,6 +193,8 @@ zscript/strife/weapondagger.txt zscript/strife/weaponcrossbow.txt zscript/strife/weaponassault.txt zscript/strife/weaponmissile.txt +zscript/strife/weaponflamer.txt +zscript/strife/weapongrenade.txt zscript/strife/sigil.txt zscript/chex/chexmonsters.txt diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 5279372fd..37306db39 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -361,6 +361,7 @@ class Actor : Thinker native native vector3 Vec3Offset(double x, double y, double z, bool absolute = false); native vector3 Vec3Angle(double length, double angle, double z = 0, bool absolute = false); native vector2 Vec2Angle(double length, double angle, bool absolute = false); + native vector2 Vec2Offset(double x, double y, bool absolute = false); native vector3 Vec2OffsetZ(double x, double y, double atz, bool absolute = false); native void VelFromAngle(double speed = 0, double angle = 0); native void Thrust(double speed = 0, double angle = 0); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index b0abc73ec..08125952d 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -247,7 +247,10 @@ struct Sector native native double, Sector, F3DFloor NextHighestCeilingAt(double x, double y, double bottomz, double topz, int flags = 0); + native double, Sector, F3DFloor NextLowestFloorAt(double x, double y, double z, int flags = 0, double steph = 0); + native void RemoveForceField(); + native static Sector PointInSector(Vector2 pt); } struct Wads diff --git a/wadsrc/static/zscript/strife/strifeweapons.txt b/wadsrc/static/zscript/strife/strifeweapons.txt index ae0bc1284..9e2f2c84f 100644 --- a/wadsrc/static/zscript/strife/strifeweapons.txt +++ b/wadsrc/static/zscript/strife/strifeweapons.txt @@ -50,88 +50,6 @@ class StrifeSpark : StrifePuff } } -// Flame Thrower ------------------------------------------------------------ - -class FlameThrower : StrifeWeapon -{ - Default - { - +FLOORCLIP - Weapon.SelectionOrder 2100; - Weapon.Kickback 0; - Weapon.AmmoUse1 1; - Weapon.AmmoGive1 100; - Weapon.UpSound "weapons/flameidle"; - Weapon.ReadySound "weapons/flameidle"; - Weapon.AmmoType1 "EnergyPod"; - Inventory.Icon "FLAMA0"; - Tag "$TAG_FLAMER"; - Inventory.PickupMessage "$TXT_FLAMER"; - } - - action native void A_FireFlamer (); - - States - { - Spawn: - FLAM A -1; - Stop; - Ready: - FLMT AB 3 A_WeaponReady; - Loop; - Deselect: - FLMT A 1 A_Lower; - Loop; - Select: - FLMT A 1 A_Raise; - Loop; - Fire: - FLMF A 2 A_FireFlamer; - FLMF B 3 A_ReFire; - Goto Ready; - } -} - - -// Flame Thrower Projectile ------------------------------------------------- - -class FlameMissile : Actor -{ - Default - { - Speed 15; - Height 11; - Radius 8; - Mass 10; - Damage 4; - DamageType "Fire"; - ReactionTime 8; - Projectile; - -NOGRAVITY - +STRIFEDAMAGE - MaxStepHeight 4; - RenderStyle "Add"; - SeeSound "weapons/flamethrower"; - Obituary "$OB_MPFLAMETHROWER"; - } - - native void A_FlameDie (); - - States - { - Spawn: - FRBL AB 3 Bright; - FRBL C 3 Bright A_Countdown; - Loop; - Death: - FRBL D 5 Bright A_FlameDie; - FRBL EFGHI 5 Bright; - Stop; - } - -} - - // Mauler ------------------------------------------------------------------- // The scatter version @@ -306,209 +224,3 @@ class MaulerTorpedoWave : Actor } -// High-Explosive Grenade --------------------------------------------------- - -class HEGrenade : Actor -{ - Default - { - Speed 15; - Radius 13; - Height 13; - Mass 20; - Damage 1; - Reactiontime 30; - Projectile; - -NOGRAVITY - +STRIFEDAMAGE - +BOUNCEONACTORS - +EXPLODEONWATER - MaxStepHeight 4; - BounceType "Doom"; - BounceFactor 0.5; - BounceCount 2; - SeeSound "weapons/hegrenadeshoot"; - DeathSound "weapons/hegrenadebang"; - Obituary "$OB_MPSTRIFEGRENADE"; - } - States - { - Spawn: - GRAP AB 3 A_Countdown; - Loop; - Death: - BNG4 A 0 Bright A_NoGravity; - BNG4 A 0 Bright A_SetRenderStyle(1, STYLE_Normal); - BNG4 A 2 Bright A_Explode(192, 192, alert:true); - BNG4 BCDEFGHIJKLMN 3 Bright; - Stop; - } -} - -// White Phosphorous Grenade ------------------------------------------------ - -class PhosphorousGrenade : Actor -{ - Default - { - Speed 15; - Radius 13; - Height 13; - Mass 20; - Damage 1; - Reactiontime 40; - Projectile; - -NOGRAVITY - +STRIFEDAMAGE - +BOUNCEONACTORS - +EXPLODEONWATER - BounceType "Doom"; - MaxStepHeight 4; - BounceFactor 0.5; - BounceCount 2; - SeeSound "weapons/phgrenadeshoot"; - DeathSound "weapons/phgrenadebang"; - Obituary "$OB_MPPHOSPHOROUSGRENADE"; - } - States - { - Spawn: - GRIN AB 3 A_Countdown; - Loop; - Death: - BNG3 A 2 A_SpawnItemEx("PhosphorousFire"); - Stop; - } -} - -// Fire from the Phoshorous Grenade ----------------------------------------- - -class PhosphorousFire : Actor native -{ - Default - { - Reactiontime 120; - DamageType "Fire"; - +NOBLOCKMAP - +FLOORCLIP - +NOTELEPORT - +NODAMAGETHRUST - +DONTSPLASH - RenderStyle "Add"; - Obituary "$OB_MPPHOSPHOROUSGRENADE"; - } - - native void A_Burnarea (); - native void A_Burnination (); - - States - { - Spawn: - BNG3 B 2 Bright A_Burnarea; - BNG3 C 2 Bright A_Countdown; - FLBE A 2 Bright A_Burnination; - FLBE B 2 Bright A_Countdown; - FLBE C 2 Bright A_Burnarea; - FLBE D 3 Bright A_Countdown; - FLBE E 3 Bright A_Burnarea; - FLBE F 3 Bright A_Countdown; - FLBE G 3 Bright A_Burnination; - Goto Spawn+5; - Death: - FLBE H 2 Bright; - FLBE I 2 Bright A_Burnination; - FLBE JK 2 Bright; - Stop; - } -} - -// High-Explosive Grenade Launcher ------------------------------------------ - -class StrifeGrenadeLauncher : StrifeWeapon -{ - Default - { - +FLOORCLIP - Weapon.SelectionOrder 2400; - Weapon.AmmoUse1 1; - Weapon.AmmoGive1 12; - Weapon.AmmoType1 "HEGrenadeRounds"; - Weapon.SisterWeapon "StrifeGrenadeLauncher2"; - Inventory.Icon "GRNDA0"; - Tag "$TAG_GLAUNCHER1"; - Inventory.PickupMessage "$TXT_GLAUNCHER"; - } - - action native void A_FireGrenade (class grenadetype, double angleofs, statelabel flash); - - States - { - Spawn: - GRND A -1; - Stop; - Ready: - GREN A 1 A_WeaponReady; - Loop; - Deselect: - GREN A 1 A_Lower; - Loop; - Select: - GREN A 1 A_Raise; - Loop; - Fire: - GREN A 5 A_FireGrenade("HEGrenade", -90, "Flash"); - GREN B 10; - GREN A 5 A_FireGrenade("HEGrenade", 90, "Flash2"); - GREN C 10; - GREN A 0 A_ReFire; - Goto Ready; - Flash: - GREF A 5 Bright A_Light1; - Goto LightDone; - Flash2: - GREF B 5 Bright A_Light2; - Goto LightDone; - } - -} - -// White Phosphorous Grenade Launcher --------------------------------------- - -class StrifeGrenadeLauncher2 : StrifeGrenadeLauncher -{ - Default - { - Weapon.SelectionOrder 3200; - Weapon.AmmoUse1 1; - Weapon.AmmoGive1 0; - Weapon.AmmoType1 "PhosphorusGrenadeRounds"; - Weapon.SisterWeapon "StrifeGrenadeLauncher"; - Tag "$TAG_GLAUNCHER2"; - } - States - { - Ready: - GREN D 1 A_WeaponReady; - Loop; - Deselect: - GREN D 1 A_Lower; - Loop; - Select: - GREN D 1 A_Raise; - Loop; - Fire: - GREN D 5 A_FireGrenade("PhosphorousGrenade", -90, "Flash"); - GREN E 10; - GREN D 5 A_FireGrenade("PhosphorousGrenade", 90, "Flash2"); - GREN F 10; - GREN A 0 A_ReFire; - Goto Ready; - Flash: - GREF C 5 Bright A_Light1; - Goto LightDone; - Flash2: - GREF D 5 Bright A_Light2; - Goto LightDone; - } -} - diff --git a/wadsrc/static/zscript/strife/weaponflamer.txt b/wadsrc/static/zscript/strife/weaponflamer.txt new file mode 100644 index 000000000..9a47bc242 --- /dev/null +++ b/wadsrc/static/zscript/strife/weaponflamer.txt @@ -0,0 +1,118 @@ +// Flame Thrower ------------------------------------------------------------ + +class FlameThrower : StrifeWeapon +{ + Default + { + +FLOORCLIP + Weapon.SelectionOrder 2100; + Weapon.Kickback 0; + Weapon.AmmoUse1 1; + Weapon.AmmoGive1 100; + Weapon.UpSound "weapons/flameidle"; + Weapon.ReadySound "weapons/flameidle"; + Weapon.AmmoType1 "EnergyPod"; + Inventory.Icon "FLAMA0"; + Tag "$TAG_FLAMER"; + Inventory.PickupMessage "$TXT_FLAMER"; + } + + States + { + Spawn: + FLAM A -1; + Stop; + Ready: + FLMT AB 3 A_WeaponReady; + Loop; + Deselect: + FLMT A 1 A_Lower; + Loop; + Select: + FLMT A 1 A_Raise; + Loop; + Fire: + FLMF A 2 A_FireFlamer; + FLMF B 3 A_ReFire; + Goto Ready; + } + + //============================================================================ + // + // A_FireFlamer + // + //============================================================================ + + action void A_FireFlamer () + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + + player.mo.PlayAttacking2 (); + + Angle += Random2[Flamethrower]() * (5.625/256.); + Actor mo = SpawnPlayerMissile ("FlameMissile"); + if (mo != NULL) + { + mo.Vel.Z += 5; + } + } +} + + +// Flame Thrower Projectile ------------------------------------------------- + +class FlameMissile : Actor +{ + Default + { + Speed 15; + Height 11; + Radius 8; + Mass 10; + Damage 4; + DamageType "Fire"; + ReactionTime 8; + Projectile; + -NOGRAVITY + +STRIFEDAMAGE + MaxStepHeight 4; + RenderStyle "Add"; + SeeSound "weapons/flamethrower"; + Obituary "$OB_MPFLAMETHROWER"; + } + + States + { + Spawn: + FRBL AB 3 Bright; + FRBL C 3 Bright A_Countdown; + Loop; + Death: + FRBL D 5 Bright A_FlameDie; + FRBL EFGHI 5 Bright; + Stop; + } + + //============================================================================ + // + // A_FlameDie + // + //============================================================================ + + void A_FlameDie () + { + bNoGravity = true; + Vel.Z = random[FlameDie]() & 3; + } +} + diff --git a/wadsrc/static/zscript/strife/weapongrenade.txt b/wadsrc/static/zscript/strife/weapongrenade.txt new file mode 100644 index 000000000..7a775c57b --- /dev/null +++ b/wadsrc/static/zscript/strife/weapongrenade.txt @@ -0,0 +1,315 @@ +// High-Explosive Grenade Launcher ------------------------------------------ + +class StrifeGrenadeLauncher : StrifeWeapon +{ + Default + { + +FLOORCLIP + Weapon.SelectionOrder 2400; + Weapon.AmmoUse1 1; + Weapon.AmmoGive1 12; + Weapon.AmmoType1 "HEGrenadeRounds"; + Weapon.SisterWeapon "StrifeGrenadeLauncher2"; + Inventory.Icon "GRNDA0"; + Tag "$TAG_GLAUNCHER1"; + Inventory.PickupMessage "$TXT_GLAUNCHER"; + } + + States + { + Spawn: + GRND A -1; + Stop; + Ready: + GREN A 1 A_WeaponReady; + Loop; + Deselect: + GREN A 1 A_Lower; + Loop; + Select: + GREN A 1 A_Raise; + Loop; + Fire: + GREN A 5 A_FireGrenade("HEGrenade", -90, "Flash"); + GREN B 10; + GREN A 5 A_FireGrenade("HEGrenade", 90, "Flash2"); + GREN C 10; + GREN A 0 A_ReFire; + Goto Ready; + Flash: + GREF A 5 Bright A_Light1; + Goto LightDone; + Flash2: + GREF B 5 Bright A_Light2; + Goto LightDone; + } + + //============================================================================ + // + // A_FireGrenade + // + //============================================================================ + + action void A_FireGrenade (class grenadetype, double angleofs, statelabel flash) + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + + player.SetPsprite (PSP_FLASH, weapon.FindState(flash), true); + } + + if (grenadetype != null) + { + AddZ(32); + Actor grenade = SpawnSubMissile (grenadetype, self); + AddZ(-32); + if (grenade == null) + return; + + if (grenade.SeeSound != 0) + { + grenade.A_PlaySound (grenade.SeeSound, CHAN_VOICE); + } + + grenade.Vel.Z = (-clamp(tan(Pitch), -5, 5)) * grenade.Speed + 8; + + Vector2 offset = AngleToVector(angle, radius + grenade.radius); + double an = Angle + angleofs; + offset += AngleToVector(an, 15); + grenade.SetOrigin(grenade.Vec3Offset(offset.X, offset.Y, 0.), false); + } + } +} + +// White Phosphorous Grenade Launcher --------------------------------------- + +class StrifeGrenadeLauncher2 : StrifeGrenadeLauncher +{ + Default + { + Weapon.SelectionOrder 3200; + Weapon.AmmoUse1 1; + Weapon.AmmoGive1 0; + Weapon.AmmoType1 "PhosphorusGrenadeRounds"; + Weapon.SisterWeapon "StrifeGrenadeLauncher"; + Tag "$TAG_GLAUNCHER2"; + } + States + { + Ready: + GREN D 1 A_WeaponReady; + Loop; + Deselect: + GREN D 1 A_Lower; + Loop; + Select: + GREN D 1 A_Raise; + Loop; + Fire: + GREN D 5 A_FireGrenade("PhosphorousGrenade", -90, "Flash"); + GREN E 10; + GREN D 5 A_FireGrenade("PhosphorousGrenade", 90, "Flash2"); + GREN F 10; + GREN A 0 A_ReFire; + Goto Ready; + Flash: + GREF C 5 Bright A_Light1; + Goto LightDone; + Flash2: + GREF D 5 Bright A_Light2; + Goto LightDone; + } +} + +// High-Explosive Grenade --------------------------------------------------- + +class HEGrenade : Actor +{ + Default + { + Speed 15; + Radius 13; + Height 13; + Mass 20; + Damage 1; + Reactiontime 30; + Projectile; + -NOGRAVITY + +STRIFEDAMAGE + +BOUNCEONACTORS + +EXPLODEONWATER + MaxStepHeight 4; + BounceType "Doom"; + BounceFactor 0.5; + BounceCount 2; + SeeSound "weapons/hegrenadeshoot"; + DeathSound "weapons/hegrenadebang"; + Obituary "$OB_MPSTRIFEGRENADE"; + } + States + { + Spawn: + GRAP AB 3 A_Countdown; + Loop; + Death: + BNG4 A 0 Bright A_NoGravity; + BNG4 A 0 Bright A_SetRenderStyle(1, STYLE_Normal); + BNG4 A 2 Bright A_Explode(192, 192, alert:true); + BNG4 BCDEFGHIJKLMN 3 Bright; + Stop; + } +} + +// White Phosphorous Grenade ------------------------------------------------ + +class PhosphorousGrenade : Actor +{ + Default + { + Speed 15; + Radius 13; + Height 13; + Mass 20; + Damage 1; + Reactiontime 40; + Projectile; + -NOGRAVITY + +STRIFEDAMAGE + +BOUNCEONACTORS + +EXPLODEONWATER + BounceType "Doom"; + MaxStepHeight 4; + BounceFactor 0.5; + BounceCount 2; + SeeSound "weapons/phgrenadeshoot"; + DeathSound "weapons/phgrenadebang"; + Obituary "$OB_MPPHOSPHOROUSGRENADE"; + } + States + { + Spawn: + GRIN AB 3 A_Countdown; + Loop; + Death: + BNG3 A 2 A_SpawnItemEx("PhosphorousFire"); + Stop; + } +} + +// Fire from the Phoshorous Grenade ----------------------------------------- + +class PhosphorousFire : Actor +{ + Default + { + Reactiontime 120; + DamageType "Fire"; + +NOBLOCKMAP + +FLOORCLIP + +NOTELEPORT + +NODAMAGETHRUST + +DONTSPLASH + RenderStyle "Add"; + Obituary "$OB_MPPHOSPHOROUSGRENADE"; + } + + States + { + Spawn: + BNG3 B 2 Bright A_Burnarea; + BNG3 C 2 Bright A_Countdown; + FLBE A 2 Bright A_Burnination; + FLBE B 2 Bright A_Countdown; + FLBE C 2 Bright A_Burnarea; + FLBE D 3 Bright A_Countdown; + FLBE E 3 Bright A_Burnarea; + FLBE F 3 Bright A_Countdown; + FLBE G 3 Bright A_Burnination; + Goto Spawn+5; + Death: + FLBE H 2 Bright; + FLBE I 2 Bright A_Burnination; + FLBE JK 2 Bright; + Stop; + } + + int DoSpecialDamage (Actor target, int damage, Name damagetype) + { + if (target.bNoBlood) + { + return damage / 2; + } + return Super.DoSpecialDamage (target, damage, damagetype); + } + + // This function is mostly redundant and only kept in case some mod references it. + void A_Burnarea () + { + A_Explode(128, 128); + } + + void A_Burnination () + { + Vel.Z -= 8; + Vel.X += (random2[PHBurn] (3)); + Vel.Y += (random2[PHBurn] (3)); + A_PlaySound ("world/largefire", CHAN_VOICE); + + // Only the main fire spawns more. + if (!bDropped) + { + // Original x and y offsets seemed to be like this: + // x + (((pr_phburn() + 12) & 31) << F.RACBITS); + // + // But that creates a lop-sided burn because it won't use negative offsets. + int xofs, xrand = random[PHBurn](); + int yofs, yrand = random[PHBurn](); + + // Adding 12 is pointless if you're going to mask it afterward. + xofs = xrand & 31; + if (xrand & 128) + { + xofs = -xofs; + } + + yofs = yrand & 31; + if (yrand & 128) + { + yofs = -yofs; + } + + Vector2 newpos = Vec2Offset(xofs, yofs); + + Sector sec = Sector.PointInSector(newpos); + // Consider portals and 3D floors instead of just using the current sector's z. + double floorh = sec.NextLowestFloorAt(newpos.x, newpos.y, pos.z+4, 0, MaxStepHeight); + + // The sector's floor is too high so spawn the flame elsewhere. + if (floorh + MaxStepHeight) + { + newpos = Pos.xy; + } + + Actor drop = Spawn("PhosphorousFire", (newpos, pos.z + 4.), ALLOW_REPLACE); + if (drop != NULL) + { + drop.Vel.X = Vel.X + random2[PHBurn] (7); + drop.Vel.Y = Vel.Y + random2[PHBurn] (7); + drop.Vel.Z = Vel.Z - 1; + drop.reactiontime = (random[PHBurn]() & 3) + 2; + drop.bDropped = true; + } + } + } + + +} + From e01f680b72393f0332f8a1e7a7b224cfd6a9ea2d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 29 Nov 2016 14:32:49 +0100 Subject: [PATCH 166/185] - scriptified the Mauler, completing Strife. --- src/CMakeLists.txt | 2 - src/g_strife/a_strifeglobal.h | 7 - src/g_strife/a_strifestuff.cpp | 35 --- src/g_strife/a_strifeweapons.cpp | 165 ---------- wadsrc/static/zscript.txt | 1 + wadsrc/static/zscript/strife/strifestuff.txt | 9 + .../static/zscript/strife/strifeweapons.txt | 174 ----------- wadsrc/static/zscript/strife/weaponmauler.txt | 286 ++++++++++++++++++ 8 files changed, 296 insertions(+), 383 deletions(-) delete mode 100644 src/g_strife/a_strifeglobal.h delete mode 100644 src/g_strife/a_strifestuff.cpp delete mode 100644 src/g_strife/a_strifeweapons.cpp create mode 100644 wadsrc/static/zscript/strife/weaponmauler.txt diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 923d545e0..2d0474794 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -861,7 +861,6 @@ set( NOT_COMPILED_SOURCE_FILES sc_man_scanner.re g_hexen/a_heresiarch.cpp g_hexen/a_spike.cpp - g_strife/a_strifeweapons.cpp g_shared/sbarinfo_commands.cpp xlat/xlat_parser.y xlat_parser.c @@ -1111,7 +1110,6 @@ set (PCH_SOURCES wi_stuff.cpp zstrformat.cpp g_hexen/a_hexenmisc.cpp - g_strife/a_strifestuff.cpp g_strife/strife_sbar.cpp g_shared/a_action.cpp g_shared/a_armor.cpp diff --git a/src/g_strife/a_strifeglobal.h b/src/g_strife/a_strifeglobal.h deleted file mode 100644 index 9206dd08c..000000000 --- a/src/g_strife/a_strifeglobal.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __A_STRIFEGLOBAL_H__ -#define __A_STRIFEGLOBAL_H__ - -#include "info.h" -#include "a_pickups.h" - -#endif diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp deleted file mode 100644 index e93c13600..000000000 --- a/src/g_strife/a_strifestuff.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "actor.h" -#include "g_level.h" -#include "gi.h" -#include "m_random.h" -#include "s_sound.h" -#include "d_player.h" -#include "a_action.h" -#include "p_local.h" -#include "p_enemy.h" -#include "p_lnspec.h" -#include "c_console.h" -#include "vm.h" -#include "doomstat.h" -#include "gstrings.h" -#include "a_keys.h" -#include "a_sharedglobal.h" -#include "templates.h" -#include "d_event.h" -#include "v_font.h" -#include "serializer.h" -#include "p_spec.h" -#include "portal.h" -#include "vm.h" - -// Include all the other Strife stuff here to reduce compile time -#include "a_strifeweapons.cpp" - -// Notes so I don't forget them: -// -// When shooting missiles at something, if MF_SHADOW is set, the angle is adjusted with the formula: -// angle += pr_spawnmissile.Random2() << 21 -// When MF_STRIFEx4000000 is set, the angle is adjusted similarly: -// angle += pr_spawnmissile.Random2() << 22 -// Note that these numbers are different from those used by all the other Doom engine games. - diff --git a/src/g_strife/a_strifeweapons.cpp b/src/g_strife/a_strifeweapons.cpp deleted file mode 100644 index bcedd1429..000000000 --- a/src/g_strife/a_strifeweapons.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/* -#include "a_pickups.h" -#include "p_local.h" -#include "m_random.h" -#include "a_strifeglobal.h" -#include "s_sound.h" -#include "p_enemy.h" -#include "templates.h" -#include "vm.h" -#include "doomstat.h" -*/ - -// Note: Strife missiles do 1-4 times their damage amount. -// Doom missiles do 1-8 times their damage amount, so to -// make the strife missiles do proper damage without -// hacking more stuff in the executable, be sure to give -// all Strife missiles the MF4_STRIFEDAMAGE flag. - -static FRandom pr_electric ("FireElectric"); -static FRandom pr_sgunshot ("StrifeGunShot"); -static FRandom pr_minimissile ("MiniMissile"); -static FRandom pr_flamethrower ("FlameThrower"); -static FRandom pr_flamedie ("FlameDie"); -static FRandom pr_mauler1 ("Mauler1"); -static FRandom pr_mauler2 ("Mauler2"); -static FRandom pr_phburn ("PhBurn"); - -void A_LoopActiveSound (AActor *); -void A_Countdown (AActor *); - -// Assault Gun -------------------------------------------------------------- - -// Mini-Missile Launcher ---------------------------------------------------- - -// Flame Thrower ------------------------------------------------------------ - -// Mauler ------------------------------------------------------------------- - -//============================================================================ -// -// A_FireMauler1 -// -// Hey! This is exactly the same as a super shotgun except for the sound -// and the bullet puffs and the disintegration death. -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FireMauler1) -{ - PARAM_ACTION_PROLOGUE(AActor); - - if (self->player != NULL) - { - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - // Strife apparently didn't show the player shooting. Let's fix that. - self->player->mo->PlayAttacking2 (); - } - - S_Sound (self, CHAN_WEAPON, "weapons/mauler1", 1, ATTN_NORM); - - - DAngle bpitch = P_BulletSlope (self); - - for (int i = 0; i < 20; ++i) - { - int damage = 5 * (pr_mauler1() % 3 + 1); - DAngle angle = self->Angles.Yaw + pr_mauler1.Random2() * (11.25 / 256); - DAngle pitch = bpitch + pr_mauler1.Random2() * (7.097 / 256); - - // Strife used a range of 2112 units for the mauler to signal that - // it should use a different puff. ZDoom's default range is longer - // than this, so let's not handicap it by being too faithful to the - // original. - P_LineAttack (self, angle, PLAYERMISSILERANGE, pitch, damage, NAME_Hitscan, NAME_MaulerPuff); - } - return 0; -} - -//============================================================================ -// -// A_FireMauler2Pre -// -// Makes some noise and moves the psprite. -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FireMauler2Pre) -{ - PARAM_ACTION_PROLOGUE(AActor); - - S_Sound (self, CHAN_WEAPON, "weapons/mauler2charge", 1, ATTN_NORM); - - if (self->player != nullptr) - { - self->player->GetPSprite(PSP_WEAPON)->x += pr_mauler2.Random2() / 64.; - self->player->GetPSprite(PSP_WEAPON)->y += pr_mauler2.Random2() / 64.; - } - return 0; -} - -//============================================================================ -// -// A_FireMauler2Pre -// -// Fires the torpedo. -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FireMauler2) -{ - PARAM_ACTION_PROLOGUE(AActor); - - if (self->player != NULL) - { - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - self->player->mo->PlayAttacking2 (); - } - P_SpawnPlayerMissile (self, PClass::FindActor("MaulerTorpedo")); - P_DamageMobj (self, self, NULL, 20, self->DamageType); - self->Thrust(self->Angles.Yaw+180., 7.8125); - return 0; -} - -//============================================================================ -// -// A_MaulerTorpedoWave -// -// Launches lots of balls when the torpedo hits something. -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_MaulerTorpedoWave) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *wavedef = GetDefaultByName("MaulerTorpedoWave"); - double savedz; - self->Angles.Yaw += 180.; - - // If the torpedo hit the ceiling, it should still spawn the wave - savedz = self->Z(); - if (wavedef && self->ceilingz < self->Z() + wavedef->Height) - { - self->SetZ(self->ceilingz - wavedef->Height); - } - - for (int i = 0; i < 80; ++i) - { - self->Angles.Yaw += 4.5; - P_SpawnSubMissile (self, PClass::FindActor("MaulerTorpedoWave"), self->target); - } - self->SetZ(savedz); - return 0; -} - diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index cbba151f5..82810185a 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -195,6 +195,7 @@ zscript/strife/weaponassault.txt zscript/strife/weaponmissile.txt zscript/strife/weaponflamer.txt zscript/strife/weapongrenade.txt +zscript/strife/weaponmauler.txt zscript/strife/sigil.txt zscript/chex/chexmonsters.txt diff --git a/wadsrc/static/zscript/strife/strifestuff.txt b/wadsrc/static/zscript/strife/strifestuff.txt index 12502ad0d..20bee61d0 100644 --- a/wadsrc/static/zscript/strife/strifestuff.txt +++ b/wadsrc/static/zscript/strife/strifestuff.txt @@ -1,3 +1,12 @@ +// Notes so I don't forget them: +// +// When shooting missiles at something, if MF_SHADOW is set, the angle is adjusted with the formula: +// angle += pr_spawnmissile.Random2() << 21 +// When MF_STRIFEx4000000 is set, the angle is adjusted similarly: +// angle += pr_spawnmissile.Random2() << 22 +// Note that these numbers are different from those used by all the other Doom engine games. + + // Tank 1 Huge ------------------------------------------------------------ class Tank1 : Actor diff --git a/wadsrc/static/zscript/strife/strifeweapons.txt b/wadsrc/static/zscript/strife/strifeweapons.txt index 9e2f2c84f..5cb01342e 100644 --- a/wadsrc/static/zscript/strife/strifeweapons.txt +++ b/wadsrc/static/zscript/strife/strifeweapons.txt @@ -50,177 +50,3 @@ class StrifeSpark : StrifePuff } } -// Mauler ------------------------------------------------------------------- -// The scatter version - -class Mauler : StrifeWeapon -{ - Default - { - +FLOORCLIP - Weapon.SelectionOrder 300; - Weapon.AmmoUse1 20; - Weapon.AmmoGive1 40; - Weapon.AmmoType1 "EnergyPod"; - Weapon.SisterWeapon "Mauler2"; - Inventory.Icon "TRPDA0"; - Tag "$TAG_MAULER1"; - Inventory.PickupMessage "$TXT_MAULER"; - Obituary "$OB_MPMAULER1"; - } - - action native void A_FireMauler1 (); - - States - { - Ready: - MAUL FGHA 6 A_WeaponReady; - Loop; - Deselect: - MAUL A 1 A_Lower; - Loop; - Select: - MAUL A 1 A_Raise; - Loop; - Fire: - BLSF A 5 Bright A_FireMauler1; - MAUL B 3 Bright A_Light1; - MAUL C 2 A_Light2; - MAUL DE 2; - MAUL A 7 A_Light0; - MAUL H 7; - MAUL G 7 A_CheckReload; - Goto Ready; - Spawn: - TRPD A -1; - Stop; - } -} - - -// Mauler Torpedo version --------------------------------------------------- - -class Mauler2 : Mauler -{ - Default - { - Weapon.SelectionOrder 3300; - Weapon.AmmoUse1 30; - Weapon.AmmoGive1 0; - Weapon.AmmoType1 "EnergyPod"; - Weapon.SisterWeapon "Mauler"; - Tag "$TAG_MAULER2"; - } - - action native void A_FireMauler2Pre (); - action native void A_FireMauler2 (); - - States - { - Ready: - MAUL IJKL 7 A_WeaponReady; - Loop; - Deselect: - MAUL I 1 A_Lower; - Loop; - Select: - MAUL I 1 A_Raise; - Loop; - Fire: - MAUL I 20 A_FireMauler2Pre; - MAUL J 10 A_Light1; - BLSF A 10 Bright A_FireMauler2; - MAUL B 10 Bright A_Light2; - MAUL C 2; - MAUL D 2 A_Light0; - MAUL E 2 A_ReFire; - Goto Ready; - } -} - - -// Mauler "Bullet" Puff ----------------------------------------------------- - -class MaulerPuff : Actor -{ - Default - { - +NOBLOCKMAP - +NOGRAVITY - +PUFFONACTORS - RenderStyle "Add"; - DamageType "Disintegrate"; - } - States - { - Spawn: - MPUF AB 5; - POW1 ABCDE 4; - Stop; - } -} - -// The Mauler's Torpedo ----------------------------------------------------- - -class MaulerTorpedo : Actor -{ - Default - { - Speed 20; - Height 8; - Radius 13; - Damage 1; - DamageType "Disintegrate"; - Projectile; - +STRIFEDAMAGE - MaxStepHeight 4; - RenderStyle "Add"; - SeeSound "weapons/mauler2fire"; - DeathSound "weapons/mauler2hit"; - Obituary "$OB_MPMAULER"; - } - - native void A_MaulerTorpedoWave (); - - States - { - Spawn: - TORP ABCD 4 Bright; - Loop; - Death: - THIT AB 8 Bright; - THIT C 8 Bright A_MaulerTorpedoWave; - THIT DE 8 Bright; - Stop; - } -} - - -// The mini torpedoes shot by the big torpedo -------------------------------- - -class MaulerTorpedoWave : Actor -{ - Default - { - Speed 35; - Radius 13; - Height 13; - Damage 10; - DamageType "Disintegrate"; - Projectile; - +STRIFEDAMAGE - MaxStepHeight 4; - RenderStyle "Add"; - Obituary "$OB_MPMAULER"; - } - States - { - Spawn: - TWAV AB 9 Bright; - Death: - TWAV C 9 Bright; - Stop; - } -} - - diff --git a/wadsrc/static/zscript/strife/weaponmauler.txt b/wadsrc/static/zscript/strife/weaponmauler.txt new file mode 100644 index 000000000..80f3afcde --- /dev/null +++ b/wadsrc/static/zscript/strife/weaponmauler.txt @@ -0,0 +1,286 @@ +// Mauler ------------------------------------------------------------------- +// The scatter version + +class Mauler : StrifeWeapon +{ + Default + { + +FLOORCLIP + Weapon.SelectionOrder 300; + Weapon.AmmoUse1 20; + Weapon.AmmoGive1 40; + Weapon.AmmoType1 "EnergyPod"; + Weapon.SisterWeapon "Mauler2"; + Inventory.Icon "TRPDA0"; + Tag "$TAG_MAULER1"; + Inventory.PickupMessage "$TXT_MAULER"; + Obituary "$OB_MPMAULER1"; + } + + States + { + Ready: + MAUL FGHA 6 A_WeaponReady; + Loop; + Deselect: + MAUL A 1 A_Lower; + Loop; + Select: + MAUL A 1 A_Raise; + Loop; + Fire: + BLSF A 5 Bright A_FireMauler1; + MAUL B 3 Bright A_Light1; + MAUL C 2 A_Light2; + MAUL DE 2; + MAUL A 7 A_Light0; + MAUL H 7; + MAUL G 7 A_CheckReload; + Goto Ready; + Spawn: + TRPD A -1; + Stop; + } + + //============================================================================ + // + // A_FireMauler1 + // + // Hey! This is exactly the same as a super shotgun except for the sound + // and the bullet puffs and the disintegration death. + // + //============================================================================ + + action void A_FireMauler1() + { + if (player == null) + { + return; + } + + A_PlaySound ("weapons/mauler1", CHAN_WEAPON); + Weapon weap = player.ReadyWeapon; + if (weap != null) + { + if (!weap.DepleteAmmo (weap.bAltFire, true, 2)) + return; + + } + player.mo.PlayAttacking2 (); + + double pitch = BulletSlope (); + + for (int i = 0 ; i < 20 ; i++) + { + int damage = 5 * random[Mauler1](1, 3); + double ang = angle + Random2[Mauler1]() * (11.25 / 256); + + // Strife used a range of 2112 units for the mauler to signal that + // it should use a different puff. ZDoom's default range is longer + // than this, so let's not handicap it by being too faithful to the + // original. + + LineAttack (ang, PLAYERMISSILERANGE, pitch + Random2[Mauler1]() * (7.097 / 256), damage, 'Hitscan', "MaulerPuff"); + } + } +} + + +// Mauler Torpedo version --------------------------------------------------- + +class Mauler2 : Mauler +{ + Default + { + Weapon.SelectionOrder 3300; + Weapon.AmmoUse1 30; + Weapon.AmmoGive1 0; + Weapon.AmmoType1 "EnergyPod"; + Weapon.SisterWeapon "Mauler"; + Tag "$TAG_MAULER2"; + } + + States + { + Ready: + MAUL IJKL 7 A_WeaponReady; + Loop; + Deselect: + MAUL I 1 A_Lower; + Loop; + Select: + MAUL I 1 A_Raise; + Loop; + Fire: + MAUL I 20 A_FireMauler2Pre; + MAUL J 10 A_Light1; + BLSF A 10 Bright A_FireMauler2; + MAUL B 10 Bright A_Light2; + MAUL C 2; + MAUL D 2 A_Light0; + MAUL E 2 A_ReFire; + Goto Ready; + } + + //============================================================================ + // + // A_FireMauler2Pre + // + // Makes some noise and moves the psprite. + // + //============================================================================ + + action void A_FireMauler2Pre () + { + A_PlaySound ("weapons/mauler2charge", CHAN_WEAPON); + + if (player != null) + { + PSprite psp = player.GetPSprite(PSP_WEAPON); + psp.x += Random2[Mauler2]() / 64.; + psp.y += Random2[Mauler2]() / 64.; + } + } + + //============================================================================ + // + // A_FireMauler2Pre + // + // Fires the torpedo. + // + //============================================================================ + + action void A_FireMauler2 () + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + player.mo.PlayAttacking2 (); + + SpawnPlayerMissile ("MaulerTorpedo"); + DamageMobj (self, null, 20, 'Disintegrate'); + Thrust(7.8125, Angle+180.); + } +} + + +// Mauler "Bullet" Puff ----------------------------------------------------- + +class MaulerPuff : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + +PUFFONACTORS + RenderStyle "Add"; + DamageType "Disintegrate"; + } + States + { + Spawn: + MPUF AB 5; + POW1 ABCDE 4; + Stop; + } +} + +// The Mauler's Torpedo ----------------------------------------------------- + +class MaulerTorpedo : Actor +{ + Default + { + Speed 20; + Height 8; + Radius 13; + Damage 1; + DamageType "Disintegrate"; + Projectile; + +STRIFEDAMAGE + MaxStepHeight 4; + RenderStyle "Add"; + SeeSound "weapons/mauler2fire"; + DeathSound "weapons/mauler2hit"; + Obituary "$OB_MPMAULER"; + } + + States + { + Spawn: + TORP ABCD 4 Bright; + Loop; + Death: + THIT AB 8 Bright; + THIT C 8 Bright A_MaulerTorpedoWave; + THIT DE 8 Bright; + Stop; + } + + //============================================================================ + // + // A_MaulerTorpedoWave + // + // Launches lots of balls when the torpedo hits something. + // + //============================================================================ + + action void A_MaulerTorpedoWave() + { + readonly wavedef = GetDefaultByType("MaulerTorpedoWave"); + double savedz = pos.z; + angle += 180.; + + // If the torpedo hit the ceiling, it should still spawn the wave + if (wavedef && ceilingz < pos.z + wavedef.Height) + { + SetZ(ceilingz - wavedef.Height); + } + + for (int i = 0; i < 80; ++i) + { + Angle += 4.5; + SpawnSubMissile ("MaulerTorpedoWave", target); + } + SetZ(savedz); + } +} + + +// The mini torpedoes shot by the big torpedo -------------------------------- + +class MaulerTorpedoWave : Actor +{ + Default + { + Speed 35; + Radius 13; + Height 13; + Damage 10; + DamageType "Disintegrate"; + Projectile; + +STRIFEDAMAGE + MaxStepHeight 4; + RenderStyle "Add"; + Obituary "$OB_MPMAULER"; + } + States + { + Spawn: + TWAV AB 9 Bright; + Death: + TWAV C 9 Bright; + Stop; + } + +} + + From f5b3429274b4ad232408bd32799ffb98be1a0d3a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 29 Nov 2016 15:24:38 +0100 Subject: [PATCH 167/185] - partial scriptification of the Heresiarch --- src/g_hexen/a_heresiarch.cpp | 386 +------------------- wadsrc/static/zscript/doom/bossbrain.txt | 4 +- wadsrc/static/zscript/hexen/heresiarch.txt | 387 ++++++++++++++++++++- 3 files changed, 372 insertions(+), 405 deletions(-) diff --git a/src/g_hexen/a_heresiarch.cpp b/src/g_hexen/a_heresiarch.cpp index a53d9926d..38d916094 100644 --- a/src/g_hexen/a_heresiarch.cpp +++ b/src/g_hexen/a_heresiarch.cpp @@ -11,23 +11,6 @@ #include "g_level.h" */ -//============================================================================ -// -// Sorcerer stuff -// -// Sorcerer Variables -// specialf1 Angle of ball 1 (all others relative to that) -// StopBall which ball to stop at in stop mode (MT_???) -// args[0] Defense time -// args[1] Number of full rotations since stopping mode -// args[2] Target orbit speed for acceleration/deceleration -// args[3] Movement mode (see SORC_ macros) -// args[4] Current ball orbit speed -// Sorcerer Ball Variables -// specialf1 Previous angle of ball (for woosh) -// special2 Countdown of rapid fire (FX4) -//============================================================================ - #define SORCBALL_INITIAL_SPEED 7 #define SORCBALL_TERMINAL_SPEED 25 #define SORCBALL_SPEED_ROTATIONS 5 @@ -209,42 +192,7 @@ void ASorcBall1::DoFireSpell () } } -//============================================================================ -// -// A_SorcSpinBalls -// -// Spawn spinning balls above head - actor is sorcerer -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SorcSpinBalls) -{ - PARAM_SELF_PROLOGUE(AHeresiarch); - - AActor *mo; - - self->SpawnState += 2; // [RH] Don't spawn balls again - A_SlowBalls(self); - self->args[0] = 0; // Currently no defense - self->args[3] = SORC_NORMAL; - self->args[4] = SORCBALL_INITIAL_SPEED; // Initial orbit speed - self->BallAngle = 1.; - - DVector3 pos = self->PosPlusZ(-self->Floorclip + self->Height); - - mo = Spawn("SorcBall1", pos, NO_REPLACE); - if (mo) - { - mo->target = self; - mo->special2 = SORCFX4_RAPIDFIRE_TIME; - } - mo = Spawn("SorcBall2", pos, NO_REPLACE); - if (mo) mo->target = self; - mo = Spawn("SorcBall3", pos, NO_REPLACE); - if (mo) mo->target = self; - return 0; -} - - +DEFINE_FIELD(AHeresiarch, BallAngle); //============================================================================ // // A_SorcBallOrbit @@ -370,38 +318,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcBallOrbit) return 0; } -//============================================================================ -// -// A_SpeedBalls -// -// Set balls to speed mode - self is sorcerer -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SpeedBalls) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->args[3] = SORC_ACCELERATE; // speed mode - self->args[2] = SORCBALL_TERMINAL_SPEED; // target speed - return 0; -} - - -//============================================================================ -// -// A_SlowBalls -// -// Set balls to slow mode - actor is sorcerer -// -//============================================================================ - -void A_SlowBalls(AActor *self) -{ - self->args[3] = SORC_DECELERATE; // slow mode - self->args[2] = SORCBALL_INITIAL_SPEED; // target speed -} - //============================================================================ // // A_StopBalls @@ -666,303 +582,3 @@ void A_SorcOffense2(AActor *self) } } -//============================================================================ -// -// A_SorcBossAttack -// -// Resume ball spinning -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SorcBossAttack) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->args[3] = SORC_ACCELERATE; - self->args[2] = SORCBALL_INITIAL_SPEED; - return 0; -} - -//============================================================================ -// -// A_SpawnFizzle -// -// spell cast magic fizzle -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SpawnFizzle) -{ - PARAM_SELF_PROLOGUE(AActor); - int speed = (int)self->Speed; - DAngle rangle; - AActor *mo; - int ix; - - DVector3 pos = self->Vec3Angle(5., self->Angles.Yaw, -self->Floorclip + self->Height / 2. ); - for (ix=0; ix<5; ix++) - { - mo = Spawn("SorcSpark1", pos, ALLOW_REPLACE); - if (mo) - { - rangle = self->Angles.Yaw + (pr_heresiarch() % 5) * (4096 / 360.); - mo->Vel.X = (pr_heresiarch() % speed) * rangle.Cos(); - mo->Vel.Y = (pr_heresiarch() % speed) * rangle.Sin(); - mo->Vel.Z = 2; - } - } - return 0; -} - - -//============================================================================ -// -// A_SorcFX1Seek -// -// Yellow spell - offense -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SorcFX1Seek) -{ - PARAM_SELF_PROLOGUE(AActor); - - A_DoBounceCheck (self, "SorcererHeadScream"); - P_SeekerMissile(self, 2, 6); - return 0; -} - - -//============================================================================ -// -// A_SorcFX2Split -// -// Blue spell - defense -// -//============================================================================ -// -// FX2 Variables -// specialf1 current angle -// special2 -// args[0] 0 = CW, 1 = CCW -// args[1] -//============================================================================ - -// Split ball in two -DEFINE_ACTION_FUNCTION(AActor, A_SorcFX2Split) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo; - - mo = Spawn(self->GetClass(), self->Pos(), NO_REPLACE); - if (mo) - { - mo->target = self->target; - mo->args[0] = 0; // CW - mo->specialf1 = self->Angles.Yaw.Degrees; // Set angle - mo->SetState (mo->FindState("Orbit")); - } - mo = Spawn(self->GetClass(), self->Pos(), NO_REPLACE); - if (mo) - { - mo->target = self->target; - mo->args[0] = 1; // CCW - mo->specialf1 = self->Angles.Yaw.Degrees; // Set angle - mo->SetState (mo->FindState("Orbit")); - } - self->Destroy (); - return 0; -} - -//============================================================================ -// -// A_SorcFX2Orbit -// -// Orbit FX2 about sorcerer -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SorcFX2Orbit) -{ - PARAM_SELF_PROLOGUE(AActor); - - DAngle angle; - DVector3 pos; - AActor *parent = self->target; - - // [RH] If no parent, then disappear - if (parent == NULL) - { - self->Destroy(); - return 0; - } - - double dist = parent->radius; - - if ((parent->health <= 0) || // Sorcerer is dead - (!parent->args[0])) // Time expired - { - self->SetState (self->FindState(NAME_Death)); - parent->args[0] = 0; - parent->flags2 &= ~MF2_REFLECTIVE; - parent->flags2 &= ~MF2_INVULNERABLE; - } - - if (self->args[0] && (parent->args[0]-- <= 0)) // Time expired - { - self->SetState (self->FindState(NAME_Death)); - parent->args[0] = 0; - parent->flags2 &= ~MF2_REFLECTIVE; - } - - // Move to new position based on angle - if (self->args[0]) // Counter clock-wise - { - self->specialf1 += 10; - angle = self->specialf1; - pos = parent->Vec3Angle(dist, angle, parent->Floorclip + SORC_DEFENSE_HEIGHT); - pos.Z += 15 * angle.Cos(); - // Spawn trailer - Spawn("SorcFX2T1", pos, ALLOW_REPLACE); - } - else // Clock wise - { - self->specialf1 -= 10; - angle = self->specialf1; - pos = parent->Vec3Angle(dist, angle, parent->Floorclip + SORC_DEFENSE_HEIGHT); - pos.Z += 20 * angle.Sin(); - // Spawn trailer - Spawn("SorcFX2T1", pos, ALLOW_REPLACE); - } - - self->SetOrigin (pos, true); - self->floorz = parent->floorz; - self->ceilingz = parent->ceilingz; - return 0; -} - -//============================================================================ -// -// A_SpawnBishop -// -// Green spell - spawn bishops -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SpawnBishop) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo; - mo = Spawn("Bishop", self->Pos(), ALLOW_REPLACE); - if (mo) - { - if (!P_TestMobjLocation(mo)) - { - mo->ClearCounters(); - mo->Destroy (); - } - else if (self->target != NULL) - { // [RH] Make the new bishops inherit the Heriarch's target - mo->CopyFriendliness (self->target, true); - mo->master = self->target; - } - } - self->Destroy (); - return 0; -} - -//============================================================================ -// -// A_SorcererBishopEntry -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SorcererBishopEntry) -{ - PARAM_SELF_PROLOGUE(AActor); - - Spawn("SorcFX3Explosion", self->Pos(), ALLOW_REPLACE); - S_Sound (self, CHAN_VOICE, self->SeeSound, 1, ATTN_NORM); - return 0; -} - -//============================================================================ -// -// A_SorcFX4Check -// -// FX4 - rapid fire balls -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SorcFX4Check) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (self->special2-- <= 0) - { - self->SetState (self->FindState(NAME_Death)); - } - return 0; -} - -//============================================================================ -// -// A_SorcBallPop -// -// Ball death - bounce away in a random direction -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SorcBallPop) -{ - PARAM_SELF_PROLOGUE(AActor); - - S_Sound (self, CHAN_BODY, "SorcererBallPop", 1, ATTN_NONE); - self->flags &= ~MF_NOGRAVITY; - self->Gravity = 1. / 8;; - - self->Vel.X = ((pr_heresiarch()%10)-5); - self->Vel.Y = ((pr_heresiarch()%10)-5); - self->Vel.Z = (2+(pr_heresiarch()%3)); - self->args[4] = BOUNCE_TIME_UNIT; // Bounce time unit - self->args[3] = 5; // Bounce time in seconds - return 0; -} - -//============================================================================ -// -// A_DoBounceCheck -// -//============================================================================ - -void A_DoBounceCheck (AActor *self, const char *sound) -{ - if (self->args[4]-- <= 0) - { - if (self->args[3]-- <= 0) - { - self->SetState (self->FindState(NAME_Death)); - S_Sound (self, CHAN_BODY, sound, 1, ATTN_NONE); - } - else - { - self->args[4] = BOUNCE_TIME_UNIT; - } - } -} - -//============================================================================ -// -// A_BounceCheck -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_BounceCheck) -{ - PARAM_SELF_PROLOGUE(AActor); - - A_DoBounceCheck (self, "SorcererBigBallExplode"); - return 0; -} diff --git a/wadsrc/static/zscript/doom/bossbrain.txt b/wadsrc/static/zscript/doom/bossbrain.txt index e6a13317f..2a3f39265 100644 --- a/wadsrc/static/zscript/doom/bossbrain.txt +++ b/wadsrc/static/zscript/doom/bossbrain.txt @@ -262,12 +262,12 @@ extend class Actor if (!isdefault) { - A_PlaySound(self.AttackSound, CHAN_WEAPON); + A_PlaySound(self.AttackSound, CHAN_WEAPON, 1., false, ATTN_NONE); } else { // compatibility fallback - A_PlaySound("brain/spit", CHAN_WEAPON); + A_PlaySound("brain/spit", CHAN_WEAPON, 1., false, ATTN_NONE); } } } diff --git a/wadsrc/static/zscript/hexen/heresiarch.txt b/wadsrc/static/zscript/hexen/heresiarch.txt index 7d3ba63a5..cf0b16372 100644 --- a/wadsrc/static/zscript/hexen/heresiarch.txt +++ b/wadsrc/static/zscript/hexen/heresiarch.txt @@ -1,8 +1,52 @@ // The Heresiarch him/itself ------------------------------------------------ +//============================================================================ +// +// Sorcerer stuff +// +// Sorcerer Variables +// specialf1 Angle of ball 1 (all others relative to that) +// StopBall which ball to stop at in stop mode (MT_???) +// args[0] Defense time +// args[1] Number of full rotations since stopping mode +// args[2] Target orbit speed for acceleration/deceleration +// args[3] Movement mode (see SORC_ macros) +// args[4] Current ball orbit speed +// Sorcerer Ball Variables +// specialf1 Previous angle of ball (for woosh) +// special2 Countdown of rapid fire (FX4) +//============================================================================ + class Heresiarch native { + + const SORCBALL_INITIAL_SPEED = 7; + const SORCBALL_TERMINAL_SPEED = 25; + const SORCBALL_SPEED_ROTATIONS = 5; + const SORC_DEFENSE_TIME = 255; + const SORC_DEFENSE_HEIGHT = 45; + const BOUNCE_TIME_UNIT = (35/2); + const SORCFX4_RAPIDFIRE_TIME = (6*3); // 3 seconds + const SORCFX4_SPREAD_ANGLE = 20; + + enum ESorc + { + SORC_DECELERATE, + SORC_ACCELERATE, + SORC_STOPPING, + SORC_FIRESPELL, + SORC_STOPPED, + SORC_NORMAL, + SORC_FIRING_SPELL + } + + const BALL1_ANGLEOFFSET = 0.; + const BALL2_ANGLEOFFSET = 120.; + const BALL3_ANGLEOFFSET = 240.; + + native double BallAngle; + Default { Health 5000; @@ -27,11 +71,6 @@ class Heresiarch native Obituary "$OB_HERESIARCH"; } - native void A_SorcSpinBalls(); - native void A_SpeedBalls(); - native void A_SorcBossAttack(); - native void A_SpawnFizzle(); - States { Spawn: @@ -71,6 +110,105 @@ class Heresiarch native SORC Z -1 Bright; Stop; } + + //============================================================================ + // + // A_SorcSpinBalls + // + // Spawn spinning balls above head - actor is sorcerer + //============================================================================ + + void A_SorcSpinBalls() + { + A_SlowBalls(); + args[0] = 0; // Currently no defense + args[3] = SORC_NORMAL; + args[4] = SORCBALL_INITIAL_SPEED; // Initial orbit speed + BallAngle = 1.; + + Vector3 ballpos = (pos.xy, -Floorclip + Height); + + Actor mo = Spawn("SorcBall1", pos, NO_REPLACE); + if (mo) + { + mo.target = self; + mo.special2 = SORCFX4_RAPIDFIRE_TIME; + } + mo = Spawn("SorcBall2", pos, NO_REPLACE); + if (mo) mo.target = self; + mo = Spawn("SorcBall3", pos, NO_REPLACE); + if (mo) mo.target = self; + } + + + //============================================================================ + // + // A_SpeedBalls + // + // Set balls to speed mode - self is sorcerer + // + //============================================================================ + + void A_SpeedBalls() + { + args[3] = SORC_ACCELERATE; // speed mode + args[2] = SORCBALL_TERMINAL_SPEED; // target speed + } + + + //============================================================================ + // + // A_SlowBalls + // + // Set balls to slow mode - actor is sorcerer + // + //============================================================================ + + void A_SlowBalls() + { + args[3] = SORC_DECELERATE; // slow mode + args[2] = SORCBALL_INITIAL_SPEED; // target speed + } + + //============================================================================ + // + // A_SorcBossAttack + // + // Resume ball spinning + // + //============================================================================ + + void A_SorcBossAttack() + { + args[3] = SORC_ACCELERATE; + args[2] = SORCBALL_INITIAL_SPEED; + } + + //============================================================================ + // + // A_SpawnFizzle + // + // spell cast magic fizzle + // + //============================================================================ + + void A_SpawnFizzle() + { + Vector3 pos = Vec3Angle(5., Angle, -Floorclip + Height / 2. ); + for (int ix=0; ix<5; ix++) + { + Actor mo = Spawn("SorcSpark1", pos, ALLOW_REPLACE); + if (mo) + { + double rangle = Angle + (random[Heresiarch]() % 5) * (4096 / 360.); + mo.Vel.X = (random[Heresiarch]() % speed) * cos(rangle); + mo.Vel.Y = (random[Heresiarch]() % speed) * sin(rangle); + mo.Vel.Z = 2; + } + } + } + + } // Base class for the balls flying around the Heresiarch's head ------------- @@ -94,14 +232,56 @@ class SorcBall native } native void A_SorcBallOrbit(); - native void A_SorcBallPop(); - native void A_BounceCheck (); void A_SorcBallExplode() { - bNOBOUNCESOUND = true; + bNoBounceSound = true; A_Explode(255, 255); } + + //============================================================================ + // + // A_SorcBallPop + // + // Ball death - bounce away in a random direction + // + //============================================================================ + + void A_SorcBallPop() + { + A_PlaySound ("SorcererBallPop", CHAN_BODY, 1, false, ATTN_NONE); + bNoGravity = false; + Gravity = 1. / 8; + + Vel.X = ((random[Heresiarch]()%10)-5); + Vel.Y = ((random[Heresiarch]()%10)-5); + Vel.Z = (2+(random[Heresiarch]()%3)); + args[4] = Heresiarch.BOUNCE_TIME_UNIT; // Bounce time unit + args[3] = 5; // Bounce time in seconds + } + + //============================================================================ + // + // A_BounceCheck + // + //============================================================================ + + void A_BounceCheck () + { + if (args[4]-- <= 0) + { + if (args[3]-- <= 0) + { + SetStateLabel("Death"); + A_PlaySound ("SorcererBigBallExplode", CHAN_BODY, 1, false, ATTN_NONE); + } + else + { + args[4] = Heresiarch.BOUNCE_TIME_UNIT; + } + } + } + } // First ball (purple) - fires projectiles ---------------------------------- @@ -191,8 +371,6 @@ class SorcFX1 : Actor DeathSound "SorcererHeadScream"; } - native void A_SorcFX1Seek(); - States { Spawn: @@ -204,6 +382,32 @@ class SorcFX1 : Actor FHFX SS 6 Bright; Stop; } + + //============================================================================ + // + // A_SorcFX1Seek + // + // Yellow spell - offense + // + //============================================================================ + + void A_SorcFX1Seek() + { + if (args[4]-- <= 0) + { + if (args[3]-- <= 0) + { + SetStateLabel("Death"); + A_PlaySound ("SorcererHeadScream", CHAN_BODY, 1, false, ATTN_NONE); + } + else + { + args[4] = Heresiarch.BOUNCE_TIME_UNIT; + } + } + A_SeekerMissile(2, 6); + } + } @@ -221,9 +425,6 @@ class SorcFX2 : Actor +NOTELEPORT } - native void A_SorcFX2Split(); - native void A_SorcFX2Orbit (); - states { Spawn: @@ -237,6 +438,106 @@ class SorcFX2 : Actor SBS2 A 10; Stop; } + + //============================================================================ + // + // A_SorcFX2Split + // + // Blue spell - defense + // + //============================================================================ + // + // FX2 Variables + // specialf1 current angle + // special2 + // args[0] 0 = CW, 1 = CCW + // args[1] + //============================================================================ + + // Split ball in two + void A_SorcFX2Split() + { + Actor mo = Spawn(GetClass(), Pos, NO_REPLACE); + if (mo) + { + mo.target = target; + mo.args[0] = 0; // CW + mo.specialf1 = Angle; // Set angle + mo.SetStateLabel("Orbit"); + } + mo = Spawn(GetClass(), Pos, NO_REPLACE); + if (mo) + { + mo.target = target; + mo.args[0] = 1; // CCW + mo.specialf1 = Angle; // Set angle + mo.SetStateLabel("Orbit"); + } + Destroy (); + } + + //============================================================================ + // + // A_SorcFX2Orbit + // + // Orbit FX2 about sorcerer + // + //============================================================================ + + void A_SorcFX2Orbit () + { + Actor parent = target; + + // [RH] If no parent, then disappear + if (parent == NULL) + { + Destroy(); + return; + } + + double dist = parent.radius; + + if ((parent.health <= 0) || // Sorcerer is dead + (!parent.args[0])) // Time expired + { + SetStateLabel("Death"); + parent.args[0] = 0; + parent.bReflective = false; + parent.bInvulnerable = false; + } + + if (args[0] && (parent.args[0]-- <= 0)) // Time expired + { + SetStateLabel("Death"); + parent.args[0] = 0; + parent.bReflective = false; + } + + Vector3 posi; + // Move to new position based on angle + if (args[0]) // Counter clock-wise + { + specialf1 += 10; + angle = specialf1; + posi = parent.Vec3Angle(dist, angle, parent.Floorclip + Heresiarch.SORC_DEFENSE_HEIGHT); + posi.Z += 15 * cos(angle); + // Spawn trailer + Spawn("SorcFX2T1", pos, ALLOW_REPLACE); + } + else // Clock wise + { + specialf1 -= 10; + angle = specialf1; + posi = parent.Vec3Angle(dist, angle, parent.Floorclip + Heresiarch.SORC_DEFENSE_HEIGHT); + posi.Z += 20 * sin(angle); + // Spawn trailer + Spawn("SorcFX2T1", pos, ALLOW_REPLACE); + } + + SetOrigin (posi, true); + floorz = parent.floorz; + ceilingz = parent.ceilingz; + } } // The translucent trail behind SorcFX2 ------------------------------------- @@ -271,9 +572,6 @@ class SorcFX3 : Actor SeeSound "SorcererBishopSpawn"; } - native void A_SpawnBishop(); - native void A_SorcererBishopEntry(); - States { Spawn: @@ -287,6 +585,45 @@ class SorcFX3 : Actor BISH G 3 A_SpawnBishop; Stop; } + + //============================================================================ + // + // A_SorcererBishopEntry + // + //============================================================================ + + void A_SorcererBishopEntry() + { + Spawn("SorcFX3Explosion", Pos, ALLOW_REPLACE); + A_PlaySound (SeeSound, CHAN_VOICE); + } + + //============================================================================ + // + // A_SpawnBishop + // + // Green spell - spawn bishops + // + //============================================================================ + + void A_SpawnBishop() + { + Actor mo = Spawn("Bishop", Pos, ALLOW_REPLACE); + if (mo) + { + if (!mo.TestMobjLocation()) + { + mo.ClearCounters(); + mo.Destroy (); + } + else if (target != NULL) + { // [RH] Make the new bishops inherit the Heriarch's target + mo.CopyFriendliness (target, true); + mo.master = target; + } + } + Destroy (); + } } @@ -326,8 +663,6 @@ class SorcFX4 : Actor DeathSound "SorcererBallExplode"; } - native void A_SorcFX4Check(); - States { Spawn: @@ -339,6 +674,22 @@ class SorcFX4 : Actor SBS4 FGH 2 Bright; Stop; } + + //============================================================================ + // + // A_SorcFX4Check + // + // FX4 - rapid fire balls + // + //============================================================================ + + void A_SorcFX4Check() + { + if (special2-- <= 0) + { + SetStateLabel ("Death"); + } + } } From f17f6c30c2faa4eb464ea407332f38e189780094 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 29 Nov 2016 17:17:10 +0100 Subject: [PATCH 168/185] - scriptified the Heresiarch. --- src/CMakeLists.txt | 1 - src/g_hexen/a_heresiarch.cpp | 584 --------------------- src/g_hexen/a_hexenmisc.cpp | 1 - src/scripting/thingdef_data.cpp | 10 +- src/scripting/zscript/zcc_compile.cpp | 19 + wadsrc/static/zscript/base.txt | 1 + wadsrc/static/zscript/hexen/heresiarch.txt | 441 +++++++++++++++- 7 files changed, 461 insertions(+), 596 deletions(-) delete mode 100644 src/g_hexen/a_heresiarch.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2d0474794..c7228edd8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -859,7 +859,6 @@ set( NOT_COMPILED_SOURCE_FILES ${OTHER_SYSTEM_SOURCES} sc_man_scanner.h sc_man_scanner.re - g_hexen/a_heresiarch.cpp g_hexen/a_spike.cpp g_shared/sbarinfo_commands.cpp xlat/xlat_parser.y diff --git a/src/g_hexen/a_heresiarch.cpp b/src/g_hexen/a_heresiarch.cpp deleted file mode 100644 index 38d916094..000000000 --- a/src/g_hexen/a_heresiarch.cpp +++ /dev/null @@ -1,584 +0,0 @@ -/* -#include "actor.h" -#include "info.h" -#include "p_local.h" -#include "s_sound.h" -#include "a_action.h" -#include "m_random.h" -#include "a_hexenglobal.h" -#include "i_system.h" -#include "vm.h" -#include "g_level.h" -*/ - -#define SORCBALL_INITIAL_SPEED 7 -#define SORCBALL_TERMINAL_SPEED 25 -#define SORCBALL_SPEED_ROTATIONS 5 -#define SORC_DEFENSE_TIME 255 -#define SORC_DEFENSE_HEIGHT 45 -#define BOUNCE_TIME_UNIT (35/2) -#define SORCFX4_RAPIDFIRE_TIME (6*3) // 3 seconds -#define SORCFX4_SPREAD_ANGLE 20 - -#define SORC_DECELERATE 0 -#define SORC_ACCELERATE 1 -#define SORC_STOPPING 2 -#define SORC_FIRESPELL 3 -#define SORC_STOPPED 4 -#define SORC_NORMAL 5 -#define SORC_FIRING_SPELL 6 - -#define BALL1_ANGLEOFFSET 0. -#define BALL2_ANGLEOFFSET 120. -#define BALL3_ANGLEOFFSET 240. - -void A_SlowBalls (AActor *actor); -void A_StopBalls (AActor *actor); -void A_AccelBalls (AActor *actor); -void A_DecelBalls (AActor *actor); -void A_SorcOffense2 (AActor *actor); -void A_DoBounceCheck (AActor *actor, const char *sound); - -static FRandom pr_heresiarch ("Heresiarch"); - -// The Heresiarch him/itself ------------------------------------------------ - -class AHeresiarch : public AActor -{ - DECLARE_CLASS (AHeresiarch, AActor) -public: - PClassActor *StopBall; - DAngle BallAngle; - - - void Serialize(FSerializer &arc); - void Die (AActor *source, AActor *inflictor, int dmgflags); -}; - -IMPLEMENT_CLASS(AHeresiarch, false, false) - -void AHeresiarch::Serialize(FSerializer &arc) -{ - Super::Serialize (arc); - arc("stopball", StopBall) - ("ballangle", BallAngle); -} - -void AHeresiarch::Die (AActor *source, AActor *inflictor, int dmgflags) -{ - // The heresiarch just executes a script instead of a special upon death - int script = special; - special = 0; - - Super::Die (source, inflictor, dmgflags); - - if (script != 0) - { - P_StartScript (this, NULL, script, level.MapName, NULL, 0, 0); - } -} - -// Base class for the balls flying around the Heresiarch's head ------------- - -class ASorcBall : public AActor -{ - DECLARE_CLASS (ASorcBall, AActor) -public: - virtual void DoFireSpell (); - virtual void SorcUpdateBallAngle (); - virtual void CastSorcererSpell (); - DAngle AngleOffset; - DAngle OldAngle; - - - - void Serialize(FSerializer &arc) - { - Super::Serialize (arc); - arc("angleoffset", AngleOffset) - ("oldangle", OldAngle); - } - - bool SpecialBlastHandling (AActor *source, double strength) - { // don't blast sorcerer balls - return false; - } -}; - -IMPLEMENT_CLASS(ASorcBall, false, false) - -// First ball (purple) - fires projectiles ---------------------------------- - -class ASorcBall1 : public ASorcBall -{ - DECLARE_CLASS (ASorcBall1, ASorcBall) -public: - void BeginPlay () - { - Super::BeginPlay (); - AngleOffset = BALL1_ANGLEOFFSET; - } - virtual void DoFireSpell (); - virtual void SorcUpdateBallAngle (); - virtual void CastSorcererSpell (); -}; - -IMPLEMENT_CLASS(ASorcBall1, false, false) - -// Second ball (blue) - generates the shield -------------------------------- - -class ASorcBall2 : public ASorcBall -{ - DECLARE_CLASS (ASorcBall2, ASorcBall) -public: - void BeginPlay () - { - Super::BeginPlay (); - AngleOffset = BALL2_ANGLEOFFSET; - } - virtual void CastSorcererSpell (); -}; - -IMPLEMENT_CLASS(ASorcBall2, false, false) - -// Third ball (green) - summons Bishops ------------------------------------- - -class ASorcBall3 : public ASorcBall -{ - DECLARE_CLASS (ASorcBall3, ASorcBall) -public: - void BeginPlay () - { - Super::BeginPlay (); - AngleOffset = BALL3_ANGLEOFFSET; - } - virtual void CastSorcererSpell (); -}; - -IMPLEMENT_CLASS(ASorcBall3, false, false) - -// Sorcerer spell 1 (The burning, bouncing head thing) ---------------------- - -//============================================================================ -// -// SorcBall::DoFireSpell -// -//============================================================================ - -void ASorcBall::DoFireSpell () -{ - CastSorcererSpell (); - target->args[3] = SORC_STOPPED; -} - -//============================================================================ -// -// SorcBall1::DoFireSpell -// -//============================================================================ - -void ASorcBall1::DoFireSpell () -{ - if (pr_heresiarch() < 200) - { - S_Sound (target, CHAN_VOICE, "SorcererSpellCast", 1, ATTN_NONE); - special2 = SORCFX4_RAPIDFIRE_TIME; - args[4] = 128; - target->args[3] = SORC_FIRING_SPELL; - } - else - { - Super::DoFireSpell (); - } -} - -DEFINE_FIELD(AHeresiarch, BallAngle); -//============================================================================ -// -// A_SorcBallOrbit -// -// - actor is ball -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SorcBallOrbit) -{ - PARAM_SELF_PROLOGUE(ASorcBall); - - // [RH] If no parent, then die instead of crashing - if (self->target == NULL) - { - self->SetState (self->FindState(NAME_Pain)); - return 0; - } - - int mode = self->target->args[3]; - AHeresiarch *parent = barrier_cast(self->target); - double dist = parent->radius - (self->radius*2); - -#if 0 - // This cannot happen anymore because this is defined locally in SorcBall - if (!self->IsKindOf (RUNTIME_CLASS(ASorcBall))) - { - I_Error ("Corrupted sorcerer:\nTried to use a %s", self->GetClass()->TypeName.GetChars()); - } -#endif - - if (self->target->health <= 0) - { - self->SetState (self->FindState(NAME_Pain)); - return 0; - } - - DAngle prevangle = self->OldAngle; - DAngle baseangle = parent->BallAngle; - DAngle angle = baseangle + self->AngleOffset; - - self->Angles.Yaw = angle; - - switch (mode) - { - case SORC_NORMAL: // Balls rotating normally - self->SorcUpdateBallAngle (); - break; - - case SORC_DECELERATE: // Balls decelerating - A_DecelBalls(self); - self->SorcUpdateBallAngle (); - break; - - case SORC_ACCELERATE: // Balls accelerating - A_AccelBalls(self); - self->SorcUpdateBallAngle (); - break; - - case SORC_STOPPING: // Balls stopping - if ((parent->StopBall == self->GetClass()) && - (parent->args[1] > SORCBALL_SPEED_ROTATIONS) && - absangle(angle, parent->Angles.Yaw) < 42.1875) - { - // Can stop now - self->target->args[3] = SORC_FIRESPELL; - self->target->args[4] = 0; - // Set angle so self angle == sorcerer angle - parent->BallAngle = parent->Angles.Yaw - self->AngleOffset; - } - else - { - self->SorcUpdateBallAngle (); - } - break; - - case SORC_FIRESPELL: // Casting spell - if (parent->StopBall == self->GetClass()) - { - // Put sorcerer into special throw spell anim - if (parent->health > 0) - parent->SetState (parent->FindState("Attack1")); - - self->DoFireSpell (); - } - break; - - case SORC_FIRING_SPELL: - if (parent->StopBall == self->GetClass()) - { - if (self->special2-- <= 0) - { - // Done rapid firing - parent->args[3] = SORC_STOPPED; - // Back to orbit balls - if (parent->health > 0) - parent->SetState (parent->FindState("Attack2")); - } - else - { - // Do rapid fire spell - A_SorcOffense2(self); - } - } - break; - - case SORC_STOPPED: // Balls stopped - default: - break; - } - - if ( angle.BAMs() < prevangle.BAMs() && (parent->args[4]==SORCBALL_TERMINAL_SPEED)) - { - parent->args[1]++; // Bump rotation counter - // Completed full rotation - make woosh sound - S_Sound (self, CHAN_BODY, "SorcererBallWoosh", 1, ATTN_NORM); - } - self->OldAngle = angle; // Set previous angle - - DVector3 pos = parent->Vec3Angle(dist, angle, -parent->Floorclip + parent->Height); - self->SetOrigin (pos, true); - self->floorz = parent->floorz; - self->ceilingz = parent->ceilingz; - return 0; -} - -//============================================================================ -// -// A_StopBalls -// -// Instant stop when rotation gets to ball in special2 -// self is sorcerer -// -//============================================================================ - -void A_StopBalls(AActor *scary) -{ - AHeresiarch *self = static_cast (scary); - int chance = pr_heresiarch(); - self->args[3] = SORC_STOPPING; // stopping mode - self->args[1] = 0; // Reset rotation counter - - if ((self->args[0] <= 0) && (chance < 200)) - { - self->StopBall = RUNTIME_CLASS(ASorcBall2); // Blue - } - else if((self->health < (self->SpawnHealth() >> 1)) && - (chance < 200)) - { - self->StopBall = RUNTIME_CLASS(ASorcBall3); // Green - } - else - { - self->StopBall = RUNTIME_CLASS(ASorcBall1); // Yellow - } -} - -//============================================================================ -// -// A_AccelBalls -// -// Increase ball orbit speed - actor is ball -// -//============================================================================ - -void A_AccelBalls(AActor *self) -{ - AActor *sorc = self->target; - - if (sorc->args[4] < sorc->args[2]) - { - sorc->args[4]++; - } - else - { - sorc->args[3] = SORC_NORMAL; - if (sorc->args[4] >= SORCBALL_TERMINAL_SPEED) - { - // Reached terminal velocity - stop balls - A_StopBalls(sorc); - } - } -} - -//============================================================================ -// -// A_DecelBalls -// -// Decrease ball orbit speed - actor is ball -// -//============================================================================ - -void A_DecelBalls(AActor *self) -{ - AActor *sorc = self->target; - - if (sorc->args[4] > sorc->args[2]) - { - sorc->args[4]--; - } - else - { - sorc->args[3] = SORC_NORMAL; - } -} - -//============================================================================ -// -// ASorcBall1::SorcUpdateBallAngle -// -// Update angle if first ball -//============================================================================ - -void ASorcBall1::SorcUpdateBallAngle () -{ - barrier_cast(target)->BallAngle += target->args[4]; -} - -//============================================================================ -// -// ASorcBall::SorcUpdateBallAngle -// -//============================================================================ - -void ASorcBall::SorcUpdateBallAngle () -{ -} - -//============================================================================ -// -// ASorcBall::CastSorcererSpell -// -// Make noise and change the parent sorcerer's animation -// -//============================================================================ - -void ASorcBall::CastSorcererSpell () -{ - S_Sound (target, CHAN_VOICE, "SorcererSpellCast", 1, ATTN_NONE); - - // Put sorcerer into throw spell animation - if (target->health > 0) - target->SetState (target->FindState("Attack2")); -} - -//============================================================================ -// -// ASorcBall2::CastSorcererSpell -// -// Defensive -// -//============================================================================ - -void ASorcBall2::CastSorcererSpell () -{ - Super::CastSorcererSpell (); - - AActor *parent = target; - AActor *mo; - - mo = Spawn("SorcFX2", PosPlusZ(parent->Floorclip + SORC_DEFENSE_HEIGHT), ALLOW_REPLACE); - parent->flags2 |= MF2_REFLECTIVE|MF2_INVULNERABLE; - parent->args[0] = SORC_DEFENSE_TIME; - if (mo) mo->target = parent; -} - -//============================================================================ -// -// ASorcBall3::CastSorcererSpell -// -// Reinforcements -// -//============================================================================ - -void ASorcBall3::CastSorcererSpell () -{ - Super::CastSorcererSpell (); - - AActor *mo; - DAngle ang1, ang2; - AActor *parent = target; - - ang1 = Angles.Yaw.Degrees - 45; - ang2 = Angles.Yaw.Degrees + 45; - PClassActor *cls = PClass::FindActor("SorcFX3"); - if (health < (SpawnHealth()/3)) - { // Spawn 2 at a time - mo = P_SpawnMissileAngle(parent, cls, ang1, 4.); - if (mo) mo->target = parent; - mo = P_SpawnMissileAngle(parent, cls, ang2, 4.); - if (mo) mo->target = parent; - } - else - { - if (pr_heresiarch() < 128) - ang1 = ang2; - mo = P_SpawnMissileAngle(parent, cls, ang1, 4.); - if (mo) mo->target = parent; - } -} - - -/* -void A_SpawnReinforcements(AActor *actor) -{ - AActor *parent = self->target; - AActor *mo; - DAngle ang; - - ang = P_Random(); - mo = P_SpawnMissileAngle(actor, MT_SORCFX3, ang, 5.); - if (mo) mo->target = parent; -} -*/ - -//============================================================================ -// -// SorcBall1::CastSorcererSpell -// -// Offensive -// -//============================================================================ - -void ASorcBall1::CastSorcererSpell () -{ - Super::CastSorcererSpell (); - - AActor *mo; - DAngle ang1, ang2; - AActor *parent = target; - - ang1 = Angles.Yaw.Degrees + 70; - ang2 = Angles.Yaw.Degrees - 70; - PClassActor *cls = PClass::FindActor("SorcFX1"); - mo = P_SpawnMissileAngle (parent, cls, ang1, 0); - if (mo) - { - mo->target = parent; - mo->tracer = parent->target; - mo->args[4] = BOUNCE_TIME_UNIT; - mo->args[3] = 15; // Bounce time in seconds - } - mo = P_SpawnMissileAngle (parent, cls, ang2, 0); - if (mo) - { - mo->target = parent; - mo->tracer = parent->target; - mo->args[4] = BOUNCE_TIME_UNIT; - mo->args[3] = 15; // Bounce time in seconds - } -} - -//============================================================================ -// -// A_SorcOffense2 -// -// Actor is ball -// -//============================================================================ - -void A_SorcOffense2(AActor *self) -{ - DAngle ang1; - AActor *mo; - double delta; - int index; - AActor *parent = self->target; - AActor *dest = parent->target; - double dist; - - // [RH] If no enemy, then don't try to shoot. - if (dest == NULL) - { - return; - } - - index = self->args[4]; - self->args[4] = (self->args[4] + 15) & 255; - delta = DAngle(index * (360 / 256.f)).Sin() * SORCFX4_SPREAD_ANGLE; - - ang1 = self->Angles.Yaw + delta; - mo = P_SpawnMissileAngle(parent, PClass::FindActor("SorcFX4"), ang1, 0); - if (mo) - { - mo->special2 = 35*5/2; // 5 seconds - dist = mo->DistanceBySpeed(dest, mo->Speed); - mo->Vel.Z = (dest->Z() - mo->Z()) / dist; - } -} - diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp index f871e82d9..1f4aa18eb 100644 --- a/src/g_hexen/a_hexenmisc.cpp +++ b/src/g_hexen/a_hexenmisc.cpp @@ -24,5 +24,4 @@ #include "a_pickups.h" // Include all the Hexen stuff here to reduce compile time -#include "a_heresiarch.cpp" #include "a_spike.cpp" diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 65a979edd..b34157b36 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -842,6 +842,13 @@ DEFINE_ACTION_FUNCTION(DObject, GameType) ACTION_RETURN_INT(gameinfo.gametype); } +DEFINE_ACTION_FUNCTION(DObject, BAM) +{ + PARAM_PROLOGUE; + PARAM_FLOAT(ang); + ACTION_RETURN_INT(DAngle(ang).BAMs()); +} + DEFINE_ACTION_FUNCTION(FStringTable, Localize) { PARAM_PROLOGUE; @@ -856,4 +863,5 @@ DEFINE_ACTION_FUNCTION(FString, Replace) PARAM_STRING(s2); self->Substitute(*s1, *s2); return 0; -} \ No newline at end of file +} + diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 4eab47c1b..ae666a2f7 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2285,6 +2285,25 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool sym->AddVariant(NewPrototype(rets, args), argflags, argnames, afd == nullptr ? nullptr : *(afd->VMPointer), varflags, useflags); c->Type()->Symbols.ReplaceSymbol(sym); + auto cls = dyn_cast(c->Type()); + PFunction *virtsym = nullptr; + if (cls != nullptr && cls->ParentClass != nullptr) virtsym = dyn_cast(cls->ParentClass->Symbols.FindSymbol(FName(f->Name), true)); + unsigned vindex = ~0u; + if (virtsym != nullptr) vindex = virtsym->Variants[0].Implementation->VirtualIndex; + + if (vindex != ~0u || (varflags & VARF_Virtual)) + { + // Todo: Check if the declaration is legal. + + // First step: compare prototypes - if they do not match the virtual base method does not apply. + + // Second step: Check flags. Possible cases: + // 1. Base method is final: Error. + // 2. This method is override: Base virtual method must exist + // 3. This method is virtual but not override: Base may not have a virtual method with the same prototype. + } + + if (!(f->Flags & ZCC_Native)) { if (f->Body == nullptr) diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 08125952d..b5ffe3a06 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -10,6 +10,7 @@ class Object native native static int GameType(); native static void S_Sound (Sound sound_id, int channel, float volume = 1, float attenuation = ATTN_NORM); native static void C_MidPrint(string fontname, string textlabel, bool bold = false); // always uses the stringtable. + native static uint BAM(double angle); /*virtual*/ native void Destroy(); } diff --git a/wadsrc/static/zscript/hexen/heresiarch.txt b/wadsrc/static/zscript/hexen/heresiarch.txt index cf0b16372..9cfdde19d 100644 --- a/wadsrc/static/zscript/hexen/heresiarch.txt +++ b/wadsrc/static/zscript/hexen/heresiarch.txt @@ -18,7 +18,7 @@ // special2 Countdown of rapid fire (FX4) //============================================================================ -class Heresiarch native +class Heresiarch : Actor { const SORCBALL_INITIAL_SPEED = 7; @@ -45,7 +45,8 @@ class Heresiarch native const BALL2_ANGLEOFFSET = 120.; const BALL3_ANGLEOFFSET = 240.; - native double BallAngle; + double BallAngle; + class StopBall; Default { @@ -110,7 +111,50 @@ class Heresiarch native SORC Z -1 Bright; Stop; } + + void Die (Actor source, Actor inflictor, int dmgflags) + { + // The heresiarch just executes a script instead of a special upon death + int script = special; + special = 0; + + Super.Die (source, inflictor, dmgflags); + + if (script != 0) + { + ACS_Execute(script, 0); + } + } + //============================================================================ + // + // A_StopBalls + // + // Instant stop when rotation gets to ball in special2 + // self is sorcerer + // + //============================================================================ + + void A_StopBalls() + { + int chance = random[Heresiarch](); + args[3] = SORC_STOPPING; // stopping mode + args[1] = 0; // Reset rotation counter + + if ((args[0] <= 0) && (chance < 200)) + { + StopBall = "SorcBall2"; // Blue + } + else if((health < (SpawnHealth() >> 1)) && (chance < 200)) + { + StopBall = "SorcBall3"; // Green + } + else + { + StopBall = "SorcBall1"; // Yellow + } + } + //============================================================================ // // A_SorcSpinBalls @@ -213,7 +257,7 @@ class Heresiarch native // Base class for the balls flying around the Heresiarch's head ------------- -class SorcBall native +class SorcBall : Actor { Default { @@ -231,8 +275,239 @@ class SorcBall native DeathSound "SorcererBigBallExplode"; } - native void A_SorcBallOrbit(); + double OldAngle, AngleOffset; + + //============================================================================ + // + // SorcBall::DoFireSpell + // + //============================================================================ + + virtual void DoFireSpell () + { + CastSorcererSpell (); + target.args[3] = Heresiarch.SORC_STOPPED; + } + + virtual void SorcUpdateBallAngle () + { + } + + override bool SpecialBlastHandling (Actor source, double strength) + { // don't blast sorcerer balls + return false; + } + + //============================================================================ + // + // ASorcBall::CastSorcererSpell + // + // Make noise and change the parent sorcerer's animation + // + //============================================================================ + + virtual void CastSorcererSpell () + { + target.A_PlaySound ("SorcererSpellCast", CHAN_VOICE); + + // Put sorcerer into throw spell animation + if (target.health > 0) + target.SetStateLabel ("Attack2"); + } + + //============================================================================ + // + // A_SorcBallOrbit + // + // - actor is ball + //============================================================================ + + void A_SorcBallOrbit() + { + // [RH] If no parent, then die instead of crashing + if (target == null || target.health <= 0) + { + SetStateLabel ("Pain"); + return; + } + + int mode = target.args[3]; + Heresiarch parent = Heresiarch(target); + double dist = parent.radius - (radius*2); + + double prevangle = OldAngle; + double baseangle = parent.BallAngle; + double curangle = baseangle + AngleOffset; + + angle = curangle; + + switch (mode) + { + case Heresiarch.SORC_NORMAL: // Balls rotating normally + SorcUpdateBallAngle (); + break; + + case Heresiarch.SORC_DECELERATE: // Balls decelerating + A_DecelBalls(); + SorcUpdateBallAngle (); + break; + + case Heresiarch.SORC_ACCELERATE: // Balls accelerating + A_AccelBalls(); + SorcUpdateBallAngle (); + break; + + case Heresiarch.SORC_STOPPING: // Balls stopping + if ((parent.StopBall == GetClass()) && + (parent.args[1] > Heresiarch.SORCBALL_SPEED_ROTATIONS) && + absangle(curangle, parent.angle) < 42.1875) + { + // Can stop now + target.args[3] = Heresiarch.SORC_FIRESPELL; + target.args[4] = 0; + // Set angle so self angle == sorcerer angle + parent.BallAngle = parent.angle - AngleOffset; + } + else + { + SorcUpdateBallAngle (); + } + break; + + case Heresiarch.SORC_FIRESPELL: // Casting spell + if (parent.StopBall == GetClass()) + { + // Put sorcerer into special throw spell anim + if (parent.health > 0) + parent.SetStateLabel("Attack1"); + + DoFireSpell (); + } + break; + + case Heresiarch.SORC_FIRING_SPELL: + if (parent.StopBall == GetClass()) + { + if (special2-- <= 0) + { + // Done rapid firing + parent.args[3] = Heresiarch.SORC_STOPPED; + // Back to orbit balls + if (parent.health > 0) + parent.SetStateLabel("Attack2"); + } + else + { + // Do rapid fire spell + A_SorcOffense2(); + } + } + break; + + default: + break; + } + + // The comparison here depends on binary angle semantics and cannot be done in floating point. + // It also requires very exact conversion that must be done natively. + if (BAM(curangle) < BAM(prevangle) && (parent.args[4] == Heresiarch.SORCBALL_TERMINAL_SPEED)) + { + parent.args[1]++; // Bump rotation counter + // Completed full rotation - make woosh sound + A_PlaySound ("SorcererBallWoosh", CHAN_BODY); + } + OldAngle = curangle; // Set previous angle + + Vector3 pos = parent.Vec3Angle(dist, curangle, -parent.Floorclip + parent.Height); + SetOrigin (pos, true); + floorz = parent.floorz; + ceilingz = parent.ceilingz; + } + + //============================================================================ + // + // A_SorcOffense2 + // + // Actor is ball + // + //============================================================================ + + void A_SorcOffense2() + { + Actor parent = target; + Actor dest = parent.target; + + // [RH] If no enemy, then don't try to shoot. + if (dest == null) + { + return; + } + + int index = args[4]; + args[4] = (args[4] + 15) & 255; + double delta = sin(index * (360 / 256.f)) * Heresiarch.SORCFX4_SPREAD_ANGLE; + + double ang1 = Angle + delta; + Actor mo = parent.SpawnMissileAngle("SorcFX4", ang1, 0); + if (mo) + { + mo.special2 = 35*5/2; // 5 seconds + double dist = mo.DistanceBySpeed(dest, mo.Speed); + mo.Vel.Z = (dest.pos.z - mo.pos.z) / dist; + } + } + + //============================================================================ + // + // A_AccelBalls + // + // Increase ball orbit speed - actor is ball + // + //============================================================================ + + void A_AccelBalls() + { + Heresiarch sorc = Heresiarch(target); + + if (sorc.args[4] < sorc.args[2]) + { + sorc.args[4]++; + } + else + { + sorc.args[3] = Heresiarch.SORC_NORMAL; + if (sorc.args[4] >= Heresiarch.SORCBALL_TERMINAL_SPEED) + { + // Reached terminal velocity - stop balls + sorc.A_StopBalls(); + } + } + } + + //============================================================================ + // + // A_DecelBalls + // + // Decrease ball orbit speed - actor is ball + // + //============================================================================ + + void A_DecelBalls() + { + Actor sorc = target; + + if (sorc.args[4] > sorc.args[2]) + { + sorc.args[4]--; + } + else + { + sorc.args[3] = Heresiarch.SORC_NORMAL; + } + } + + void A_SorcBallExplode() { bNoBounceSound = true; @@ -286,7 +561,7 @@ class SorcBall native // First ball (purple) - fires projectiles ---------------------------------- -class SorcBall1 : SorcBall native +class SorcBall1 : SorcBall { States { @@ -303,12 +578,90 @@ class SorcBall1 : SorcBall native SBS4 FGH 6; Stop; } + + override void BeginPlay () + { + Super.BeginPlay (); + AngleOffset = Heresiarch.BALL1_ANGLEOFFSET; + A_Log("Ball1 begins " .. AngleOffset); + } + + //============================================================================ + // + // SorcBall1::CastSorcererSpell + // + // Offensive + // + //============================================================================ + + override void CastSorcererSpell () + { + Super.CastSorcererSpell (); + + Actor parent = target; + + double ang1 = Angle + 70; + double ang2 = Angle - 70; + Class cls = "SorcFX1"; + Actor mo = parent.SpawnMissileAngle (cls, ang1, 0); + if (mo) + { + mo.target = parent; + mo.tracer = parent.target; + mo.args[4] = Heresiarch.BOUNCE_TIME_UNIT; + mo.args[3] = 15; // Bounce time in seconds + } + mo = parent.SpawnMissileAngle (cls, ang2, 0); + if (mo) + { + mo.target = parent; + mo.tracer = parent.target; + mo.args[4] = Heresiarch.BOUNCE_TIME_UNIT; + mo.args[3] = 15; // Bounce time in seconds + } + } + + + //============================================================================ + // + // ASorcBall1::SorcUpdateBallAngle + // + // Update angle if first ball + //============================================================================ + + override void SorcUpdateBallAngle () + { + (Heresiarch(target)).BallAngle += target.args[4]; + } + + //============================================================================ + // + // SorcBall1::DoFireSpell + // + //============================================================================ + + override void DoFireSpell () + { + if (random[Heresiarch]() < 200) + { + target.A_PlaySound ("SorcererSpellCast", CHAN_VOICE, 1, false, ATTN_NONE); + special2 = Heresiarch.SORCFX4_RAPIDFIRE_TIME; + args[4] = 128; + target.args[3] = Heresiarch.SORC_FIRING_SPELL; + } + else + { + Super.DoFireSpell (); + } + } + + } // Second ball (blue) - generates the shield -------------------------------- -class SorcBall2 : SorcBall native +class SorcBall2 : SorcBall { States { @@ -325,11 +678,40 @@ class SorcBall2 : SorcBall native SBS3 FGH 6; Stop; } + + override void BeginPlay () + { + Super.BeginPlay (); + AngleOffset = Heresiarch.BALL2_ANGLEOFFSET; + A_Log("Ball2 begins " .. AngleOffset); + } + + //============================================================================ + // + // ASorcBall2::CastSorcererSpell + // + // Defensive + // + //============================================================================ + + override void CastSorcererSpell () + { + Super.CastSorcererSpell (); + + Actor parent = target; + Actor mo = Spawn("SorcFX2", Pos + (0, 0, parent.Floorclip + Heresiarch.SORC_DEFENSE_HEIGHT), ALLOW_REPLACE); + bReflective = true; + bInvulnerable = true; + parent.args[0] = Heresiarch.SORC_DEFENSE_TIME; + if (mo) mo.target = parent; + } + + } // Third ball (green) - summons Bishops ------------------------------------- -class SorcBall3 : SorcBall native +class SorcBall3 : SorcBall { States { @@ -346,6 +728,47 @@ class SorcBall3 : SorcBall native SBS3 FGH 6; Stop; } + + override void BeginPlay () + { + Super.BeginPlay (); + AngleOffset = Heresiarch.BALL3_ANGLEOFFSET; + A_Log("Ball3 begins " .. AngleOffset); + } + + //============================================================================ + // + // ASorcBall3::CastSorcererSpell + // + // Reinforcements + // + //============================================================================ + + override void CastSorcererSpell () + { + Actor mo; + Super.CastSorcererSpell (); + Actor parent = target; + + double ang1 = Angle - 45; + double ang2 = Angle + 45; + Class cls = "SorcFX3"; + if (health < (SpawnHealth()/3)) + { // Spawn 2 at a time + mo = parent.SpawnMissileAngle(cls, ang1, 4.); + if (mo) mo.target = parent; + mo = parent.SpawnMissileAngle(cls, ang2, 4.); + if (mo) mo.target = parent; + } + else + { + if (random[Heresiarch]() < 128) ang1 = ang2; + mo = parent.SpawnMissileAngle(cls, ang1, 4.); + if (mo) mo.target = parent; + } + } + + } @@ -489,7 +912,7 @@ class SorcFX2 : Actor Actor parent = target; // [RH] If no parent, then disappear - if (parent == NULL) + if (parent == null) { Destroy(); return; @@ -616,7 +1039,7 @@ class SorcFX3 : Actor mo.ClearCounters(); mo.Destroy (); } - else if (target != NULL) + else if (target != null) { // [RH] Make the new bishops inherit the Heriarch's target mo.CopyFriendliness (target, true); mo.master = target; From 0c969746d07a003f581ae350f9b01372099c32b9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 29 Nov 2016 18:42:48 +0100 Subject: [PATCH 169/185] - scriptified Hexen's spike, which was the last remaining item in the game directories. - added a BlockThingsIterator for scripts. --- src/CMakeLists.txt | 5 -- src/g_hexen/a_hexenmisc.cpp | 27 -------- src/g_hexen/a_spike.cpp | 90 --------------------------- src/p_map.cpp | 22 ++++--- src/p_maputl.cpp | 69 ++++++++++++++++++++ wadsrc/static/zscript/actor.txt | 2 +- wadsrc/static/zscript/base.txt | 11 ++++ wadsrc/static/zscript/hexen/spike.txt | 56 ++++++++++++++++- 8 files changed, 146 insertions(+), 136 deletions(-) delete mode 100644 src/g_hexen/a_hexenmisc.cpp delete mode 100644 src/g_hexen/a_spike.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c7228edd8..071fc5ce7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -828,7 +828,6 @@ endif() file( GLOB HEADER_FILES ${EXTRA_HEADER_DIRS} fragglescript/*.h - g_hexen/*.h g_shared/*.h g_strife/*.h intermission/*.h @@ -859,7 +858,6 @@ set( NOT_COMPILED_SOURCE_FILES ${OTHER_SYSTEM_SOURCES} sc_man_scanner.h sc_man_scanner.re - g_hexen/a_spike.cpp g_shared/sbarinfo_commands.cpp xlat/xlat_parser.y xlat_parser.c @@ -1108,7 +1106,6 @@ set (PCH_SOURCES w_wad.cpp wi_stuff.cpp zstrformat.cpp - g_hexen/a_hexenmisc.cpp g_strife/strife_sbar.cpp g_shared/a_action.cpp g_shared/a_armor.cpp @@ -1258,7 +1255,6 @@ endif() target_link_libraries( zdoom ${ZDOOM_LIBS} gdtoa dumb lzma ) include_directories( . - g_hexen g_strife g_shared oplsynth @@ -1389,7 +1385,6 @@ source_group("External\\Math" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/m source_group("External\\RapidJSON" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rapidjson/.+") source_group("Externak\\SFMT" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sfmt/.+") source_group("FraggleScript" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/fragglescript/.+") -source_group("Games\\Hexen Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_hexen/.+") source_group("Games\\Strife Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_strife/.+") source_group("Intermission" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/intermission/.+") source_group("Menu" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/menu/.+") diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp deleted file mode 100644 index 1f4aa18eb..000000000 --- a/src/g_hexen/a_hexenmisc.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "d_player.h" -#include "info.h" -#include "p_local.h" -#include "s_sound.h" -#include "a_action.h" -#include "m_random.h" -#include "a_sharedglobal.h" -#include "i_system.h" -#include "gi.h" -#include "g_level.h" -#include "p_enemy.h" -#include "a_weaponpiece.h" -#include "doomstat.h" -#include "p_lnspec.h" -#include "p_terrain.h" -#include "m_bbox.h" -#include "v_palette.h" -#include "g_game.h" -#include "p_blockmap.h" -#include "r_utility.h" -#include "p_maputl.h" -#include "p_spec.h" -#include "serializer.h" -#include "a_pickups.h" - -// Include all the Hexen stuff here to reduce compile time -#include "a_spike.cpp" diff --git a/src/g_hexen/a_spike.cpp b/src/g_hexen/a_spike.cpp deleted file mode 100644 index cd0d2e891..000000000 --- a/src/g_hexen/a_spike.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* -#include "actor.h" -#include "info.h" -#include "m_random.h" -#include "p_enemy.h" -#include "p_local.h" -#include "a_sharedglobal.h" -#include "s_sound.h" -#include "m_bbox.h" -#include "vm.h" -*/ - -static FRandom pr_thrustraise ("ThrustRaise"); - -// Spike (thrust floor) ----------------------------------------------------- - -// AThrustFloor is just a container for all the spike states. -// All the real spikes subclass it. - -class AThrustFloor : public AActor -{ - DECLARE_CLASS (AThrustFloor, AActor) -public: - - void Activate (AActor *activator); - void Deactivate (AActor *activator); -}; - -IMPLEMENT_CLASS(AThrustFloor, false, false) - -void AThrustFloor::Activate (AActor *activator) -{ - if (args[0] == 0) - { - S_Sound (this, CHAN_BODY, "ThrustSpikeLower", 1, ATTN_NORM); - renderflags &= ~RF_INVISIBLE; - if (args[1]) - SetState (FindState ("BloodThrustRaise")); - else - SetState (FindState ("ThrustRaise")); - } -} - -void AThrustFloor::Deactivate (AActor *activator) -{ - if (args[0] == 1) - { - S_Sound (this, CHAN_BODY, "ThrustSpikeRaise", 1, ATTN_NORM); - if (args[1]) - SetState (FindState ("BloodThrustLower")); - else - SetState (FindState ("ThrustLower")); - } -} - -DEFINE_ACTION_FUNCTION(AActor, A_ThrustImpale) -{ - PARAM_SELF_PROLOGUE(AActor); - - // This doesn't need to iterate through portals. - - FPortalGroupArray check; - FMultiBlockThingsIterator it(check, self); - FMultiBlockThingsIterator::CheckResult cres; - while (it.Next(&cres)) - { - double blockdist = self->radius + cres.thing->radius; - if (fabs(cres.thing->X() - cres.Position.X) >= blockdist || fabs(cres.thing->Y() - cres.Position.Y) >= blockdist) - continue; - - // Q: Make this z-aware for everything? It never was before. - if (cres.thing->Top() < self->Z() || cres.thing->Z() > self->Top()) - { - if (self->Sector->PortalGroup != cres.thing->Sector->PortalGroup) - continue; - } - - if (!(cres.thing->flags & MF_SHOOTABLE) ) - continue; - - if (cres.thing == self) - continue; // don't clip against self - - int newdam = P_DamageMobj (cres.thing, self, self, 10001, NAME_Crush); - P_TraceBleed (newdam > 0 ? newdam : 10001, cres.thing); - self->args[1] = 1; // Mark thrust thing as bloody - } - return 0; -} - diff --git a/src/p_map.cpp b/src/p_map.cpp index 367c35fd0..c5780eedc 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -4652,16 +4652,6 @@ void P_TraceBleed(int damage, AActor *target, AActor *missile) P_TraceBleed(damage, target->PosPlusZ(target->Height/2), target, missile->AngleTo(target), pitch); } -DEFINE_ACTION_FUNCTION(AActor, TraceBleed) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_INT(damage); - PARAM_OBJECT(missile, AActor); - - P_TraceBleed(damage, self, missile); - return 0; -} - //========================================================================== // // @@ -4706,6 +4696,18 @@ void P_TraceBleed(int damage, AActor *target) } } +DEFINE_ACTION_FUNCTION(AActor, TraceBleed) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(damage); + PARAM_OBJECT(missile, AActor); + + if (missile) P_TraceBleed(damage, self, missile); + else P_TraceBleed(damage, self); + return 0; +} + + //========================================================================== // // [RH] Rail gun stuffage diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 16fc790c0..aa29a1c5e 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -1152,6 +1152,75 @@ void FMultiBlockThingsIterator::Reset() startIteratorForGroup(basegroup); } +//=========================================================================== +// +// and the scriptable version +// +//=========================================================================== + +class DBlockThingsIterator : public DObject, public FMultiBlockThingsIterator +{ + DECLARE_CLASS(DBlockThingsIterator, DObject); + FPortalGroupArray check; +public: + FMultiBlockThingsIterator::CheckResult cres; + +public: + bool Next() + { + return FMultiBlockThingsIterator::Next(&cres); + } + + DBlockThingsIterator(AActor *origin = nullptr, double checkradius = -1, bool ignorerestricted = false) + : FMultiBlockThingsIterator(check, origin, checkradius, ignorerestricted) + { + cres.thing = nullptr; + cres.Position.Zero(); + cres.portalflags = 0; + } + + DBlockThingsIterator(double checkx, double checky, double checkz, double checkh, double checkradius, bool ignorerestricted, sector_t *newsec) + : FMultiBlockThingsIterator(check, checkx, checky, checkz, checkh, checkradius, ignorerestricted, newsec) + { + cres.thing = nullptr; + cres.Position.Zero(); + cres.portalflags = 0; + } +}; + +IMPLEMENT_CLASS(DBlockThingsIterator, false, false); + +DEFINE_ACTION_FUNCTION(DBlockThingsIterator, Create) +{ + PARAM_PROLOGUE; + PARAM_OBJECT(origin, AActor); + PARAM_FLOAT_DEF(radius); + PARAM_BOOL_DEF(ignore); + ACTION_RETURN_OBJECT(new DBlockThingsIterator(origin, radius, ignore)); +} + +DEFINE_ACTION_FUNCTION(DBlockThingsIterator, CreateFromPos) +{ + PARAM_PROLOGUE; + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + PARAM_FLOAT(h); + PARAM_FLOAT(radius); + PARAM_BOOL(ignore); + ACTION_RETURN_OBJECT(new DBlockThingsIterator(x, y, z, h, radius, ignore, nullptr)); +} + +DEFINE_ACTION_FUNCTION(DBlockThingsIterator, Next) +{ + PARAM_SELF_PROLOGUE(DBlockThingsIterator); + ACTION_RETURN_BOOL(self->Next()); +} + +DEFINE_FIELD_NAMED(DBlockThingsIterator, cres.thing, thing); +DEFINE_FIELD_NAMED(DBlockThingsIterator, cres.Position, position); +DEFINE_FIELD_NAMED(DBlockThingsIterator, cres.portalflags, portalflags); + //=========================================================================== // // FPathTraverse :: Intercepts diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 37306db39..c3dc3c1dd 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -387,7 +387,7 @@ class Actor : Thinker native // DECORATE compatible functions native int CountInv(class itemtype, int ptr_select = AAPTR_DEFAULT); native double GetDistance(bool checkz, int ptr = AAPTR_TARGET); - native double GetAngle(int flags, int ptr = AAPTR_DEFAULT); + native double GetAngle(int flags, int ptr = AAPTR_TARGET); native double GetZAt(double px = 0, double py = 0, double angle = 0, int flags = 0, int pick_pointer = AAPTR_DEFAULT); native int GetSpawnHealth(); native int GetGibHealth(); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index b5ffe3a06..73f515f71 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -42,6 +42,17 @@ class ActorIterator : Object native native void Reinit(); } +class BlockThingsIterator : Object native +{ + native Actor thing; + native Vector3 position; + native int portalflags; + + native static BlockThingsIterator Create(Actor origin, double checkradius = -1, bool ignorerestricted = false); + native static BlockThingsIterator CreateFromPos(double checkx, double checky, double checkz, double checkh, double checkradius, bool ignorerestricted); + native bool Next(); +} + class DropItem : Object native { native readonly DropItem Next; diff --git a/wadsrc/static/zscript/hexen/spike.txt b/wadsrc/static/zscript/hexen/spike.txt index 8d418d55a..248c95726 100644 --- a/wadsrc/static/zscript/hexen/spike.txt +++ b/wadsrc/static/zscript/hexen/spike.txt @@ -18,7 +18,7 @@ class DirtClump : Actor // Spike (thrust floor) ----------------------------------------------------- -class ThrustFloor : Actor native +class ThrustFloor : Actor { Default { @@ -26,8 +26,6 @@ class ThrustFloor : Actor native Height 128; } - native void A_ThrustImpale(); - States { ThrustRaising: @@ -78,6 +76,31 @@ class ThrustFloor : Actor native Loop; } + override void Activate (Actor activator) + { + if (args[0] == 0) + { + A_PlaySound ("ThrustSpikeLower", CHAN_BODY); + bInvisible = false; + if (args[1]) + SetStateLabel("BloodThrustRaise"); + else + SetStateLabel("ThrustRaise"); + } + } + + override void Deactivate (Actor activator) + { + if (args[0] == 1) + { + A_PlaySound ("ThrustSpikeRaise", CHAN_BODY); + if (args[1]) + SetStateLabel("BloodThrustLower"); + else + SetStateLabel("ThrustLower"); + } + } + //=========================================================================== // // Thrust floor stuff @@ -150,6 +173,33 @@ class ThrustFloor : Actor native } + void A_ThrustImpale() + { + BlockThingsIterator it = BlockThingsIterator.Create(self); + while (it.Next()) + { + double blockdist = radius + it.thing.radius; + if (abs(it.thing.pos.x - it.Position.X) >= blockdist || abs(it.thing.pos.y - it.Position.Y) >= blockdist) + continue; + + // Q: Make this z-aware for everything? It never was before. + if (it.thing.pos.z + it.thing.height < pos.z || it.thing.pos.z > pos.z + height) + { + if (CurSector.PortalGroup != it.thing.CurSector.PortalGroup) + continue; + } + + if (!it.thing.bShootable) + continue; + + if (it.thing == self) + continue; // don't clip against self + + int newdam = it.thing.DamageMobj (self, self, 10001, 'Crush'); + it.thing.TraceBleed (newdam > 0 ? newdam : 10001, null); + args[1] = 1; // Mark thrust thing as bloody + } + } } // Spike up ----------------------------------------------------------------- From a13e23dbe65328c6e0f587d8fd3ba6d6244b4ce5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 29 Nov 2016 19:50:34 +0100 Subject: [PATCH 170/185] - scriptified some trivial stuff from g_shared. --- src/CMakeLists.txt | 6 -- src/am_map.cpp | 4 +- src/dthinker.cpp | 7 ++ src/g_shared/a_action.cpp | 77 ------------------- src/g_shared/a_action.h | 29 ------- src/g_shared/a_hatetarget.cpp | 76 ------------------ src/g_shared/a_mapmarker.cpp | 69 ----------------- src/g_shared/a_randomspawner.cpp | 1 - src/g_shared/a_secrettrigger.cpp | 66 ---------------- src/g_shared/a_setcolor.cpp | 33 -------- src/g_shared/a_sharedglobal.h | 9 --- src/g_shared/a_spark.cpp | 55 ------------- src/g_shared/a_waterzone.cpp | 53 ------------- src/p_actionfunctions.cpp | 1 - src/p_effect.cpp | 10 +++ src/p_enemy.cpp | 1 - src/p_mobj.cpp | 1 - src/p_sectors.cpp | 20 +++++ src/p_spec.cpp | 9 +++ src/scripting/decorate/olddecorations.cpp | 1 - src/scripting/decorate/thingdef_states.cpp | 1 - src/scripting/thingdef.cpp | 1 - src/scripting/thingdef_properties.cpp | 1 - wadsrc/static/zscript/actor.txt | 3 +- wadsrc/static/zscript/base.txt | 58 ++++++++++++-- wadsrc/static/zscript/raven/minotaur.txt | 47 +++++++++++ wadsrc/static/zscript/shared/hatetarget.txt | 30 +++++++- wadsrc/static/zscript/shared/mapmarker.txt | 33 +++++++- .../static/zscript/shared/secrettrigger.txt | 16 +++- wadsrc/static/zscript/shared/setcolor.txt | 21 ++++- wadsrc/static/zscript/shared/sharedmisc.txt | 18 ++++- wadsrc/static/zscript/shared/spark.txt | 10 ++- wadsrc/static/zscript/shared/waterzone.txt | 11 ++- 33 files changed, 276 insertions(+), 502 deletions(-) delete mode 100644 src/g_shared/a_action.h delete mode 100644 src/g_shared/a_hatetarget.cpp delete mode 100644 src/g_shared/a_mapmarker.cpp delete mode 100644 src/g_shared/a_secrettrigger.cpp delete mode 100644 src/g_shared/a_setcolor.cpp delete mode 100644 src/g_shared/a_spark.cpp delete mode 100644 src/g_shared/a_waterzone.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 071fc5ce7..111b2663c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1116,25 +1116,19 @@ set (PCH_SOURCES g_shared/a_fastprojectile.cpp g_shared/a_flashfader.cpp g_shared/a_fountain.cpp - g_shared/a_hatetarget.cpp g_shared/a_keys.cpp g_shared/a_lightning.cpp - g_shared/a_mapmarker.cpp g_shared/a_morph.cpp g_shared/a_movingcamera.cpp g_shared/a_pickups.cpp g_shared/a_puzzleitems.cpp g_shared/a_quake.cpp g_shared/a_randomspawner.cpp - g_shared/a_secrettrigger.cpp g_shared/a_sectoraction.cpp - g_shared/a_setcolor.cpp g_shared/a_skies.cpp g_shared/a_soundenvironment.cpp g_shared/a_soundsequence.cpp - g_shared/a_spark.cpp g_shared/a_specialspot.cpp - g_shared/a_waterzone.cpp g_shared/a_weaponpiece.cpp g_shared/a_weapons.cpp g_shared/hudmessages.cpp diff --git a/src/am_map.cpp b/src/am_map.cpp index d74927b68..99fda3bd6 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -2963,8 +2963,8 @@ void AM_drawAuthorMarkers () // [RH] Draw any actors derived from AMapMarker on the automap. // If args[0] is 0, then the actor's sprite is drawn at its own location. // Otherwise, its sprite is drawn at the location of any actors whose TIDs match args[0]. - TThinkerIterator it (STAT_MAPMARKER); - AMapMarker *mark; + TThinkerIterator it ("MapMarker", STAT_MAPMARKER); + AActor *mark; while ((mark = it.Next()) != NULL) { diff --git a/src/dthinker.cpp b/src/dthinker.cpp index d214b28e9..7c8bf1bf5 100644 --- a/src/dthinker.cpp +++ b/src/dthinker.cpp @@ -387,6 +387,13 @@ void DThinker::ChangeStatNum (int statnum) list->AddTail(this); } +DEFINE_ACTION_FUNCTION(DThinker, ChangeStatNum) +{ + PARAM_SELF_PROLOGUE(DThinker); + PARAM_INT(stat); + self->ChangeStatNum(stat); + return 0; +} //========================================================================== // // Mark the first thinker of each list diff --git a/src/g_shared/a_action.cpp b/src/g_shared/a_action.cpp index 3938a9743..afe188019 100644 --- a/src/g_shared/a_action.cpp +++ b/src/g_shared/a_action.cpp @@ -1,7 +1,6 @@ #include "actor.h" #include "p_conversation.h" #include "p_lnspec.h" -#include "a_action.h" #include "m_random.h" #include "s_sound.h" #include "d_player.h" @@ -18,39 +17,6 @@ static FRandom pr_icesettics ("IceSetTics"); static FRandom pr_freeze ("FreezeDeathChunks"); -// SwitchableDecoration: Activate and Deactivate change state --------------- - -class ASwitchableDecoration : public AActor -{ - DECLARE_CLASS (ASwitchableDecoration, AActor) -public: - void Activate (AActor *activator); - void Deactivate (AActor *activator); -}; - -IMPLEMENT_CLASS(ASwitchableDecoration, false, false) - -void ASwitchableDecoration::Activate (AActor *activator) -{ - SetState (FindState(NAME_Active)); -} - -void ASwitchableDecoration::Deactivate (AActor *activator) -{ - SetState (FindState(NAME_Inactive)); -} - -// SwitchingDecoration: Only Activate changes state ------------------------- - -class ASwitchingDecoration : public ASwitchableDecoration -{ - DECLARE_CLASS (ASwitchingDecoration, ASwitchableDecoration) -public: - void Deactivate (AActor *activator) {} -}; - -IMPLEMENT_CLASS(ASwitchingDecoration, false, false) - //---------------------------------------------------------------------------- // // PROC A_NoBlocking @@ -412,46 +378,3 @@ DEFINE_ACTION_FUNCTION(AActor, A_DeQueueCorpse) return 0; } -//=========================================================================== -// -// FaceMovementDirection -// -//=========================================================================== - -void FaceMovementDirection(AActor *actor) -{ - switch (actor->movedir) - { - case DI_EAST: - actor->Angles.Yaw = 0.; - break; - case DI_NORTHEAST: - actor->Angles.Yaw = 45.; - break; - case DI_NORTH: - actor->Angles.Yaw = 90.; - break; - case DI_NORTHWEST: - actor->Angles.Yaw = 135.; - break; - case DI_WEST: - actor->Angles.Yaw = 180.; - break; - case DI_SOUTHWEST: - actor->Angles.Yaw = 225.; - break; - case DI_SOUTH: - actor->Angles.Yaw = 270.; - break; - case DI_SOUTHEAST: - actor->Angles.Yaw = 315.; - break; - } -} - -DEFINE_ACTION_FUNCTION(AActor, FaceMovementDirection) -{ - PARAM_SELF_PROLOGUE(AActor); - FaceMovementDirection(self); - return 0; -} diff --git a/src/g_shared/a_action.h b/src/g_shared/a_action.h deleted file mode 100644 index 7c5e00a79..000000000 --- a/src/g_shared/a_action.h +++ /dev/null @@ -1,29 +0,0 @@ -class AActor; - -/* -void A_NoBlocking (AActor *); -void A_HideThing (AActor *); -void A_UnHideThing (AActor *); -void A_FreezeDeath (AActor *); -void A_FreezeDeathChunks (AActor *); -void A_GenericFreezeDeath (AActor *); -void A_IceSetTics (AActor *); -void A_IceCheckHeadDone (AActor *); -void A_QueueCorpse (AActor *); -void A_DeQueueCorpse (AActor *); -void A_SetInvulnerable (AActor *); -void A_UnSetInvulnerable (AActor *); -void A_SetReflective (AActor *); -void A_UnSetReflective (AActor *); -void A_SetReflectiveInvulnerable (AActor *); -void A_UnSetReflectiveInvulnerable (AActor *); -void A_SetShootable (AActor *); -void A_UnSetShootable (AActor *); -void A_SetFloorClip (AActor *); -void A_UnSetFloorClip (AActor *); -void A_NoGravity (AActor *); -void A_SkullPop (AActor *); -*/ - - -void FaceMovementDirection (AActor *); diff --git a/src/g_shared/a_hatetarget.cpp b/src/g_shared/a_hatetarget.cpp deleted file mode 100644 index 8d5b0fa72..000000000 --- a/src/g_shared/a_hatetarget.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* -** a_hatetarget.cpp -** Something for monsters to hate and shoot at -** -**--------------------------------------------------------------------------- -** Copyright 2003-2006 Randy Heit -** 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. -** -** 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 "actor.h" -#include "info.h" -#include "m_fixed.h" - -// Hate Target -------------------------------------------------------------- - -class AHateTarget : public AActor -{ - DECLARE_CLASS(AHateTarget, AActor) -public: - void BeginPlay(); - int TakeSpecialDamage(AActor *inflictor, AActor *source, int damage, FName damagetype); -}; - -IMPLEMENT_CLASS(AHateTarget, false, false) - -void AHateTarget::BeginPlay() -{ - Super::BeginPlay(); - if (SpawnAngle != 0) - { // Each degree translates into 10 units of health - health = SpawnAngle * 10; - } - else - { - special2 = 1; - health = 1000001; - } -} - -int AHateTarget::TakeSpecialDamage(AActor *inflictor, AActor *source, int damage, FName damagetype) -{ - if (special2 != 0) - { - return 0; - } - else - { - return damage; - } -} - diff --git a/src/g_shared/a_mapmarker.cpp b/src/g_shared/a_mapmarker.cpp deleted file mode 100644 index 524bfca44..000000000 --- a/src/g_shared/a_mapmarker.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* -** a_mapmarker.cpp -** An actor that appears on the automap instead of in the 3D view. -** -**--------------------------------------------------------------------------- -** Copyright 2006 Randy Heit -** 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. -** -** 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 "a_sharedglobal.h" -#include "statnums.h" - -// Map Marker -------------------------------------------------------------- -// -// This class uses the following argument: -// args[0] == 0, shows the sprite at this actor -// != 0, shows the sprite for all actors whose TIDs match instead -// -// args[1] == 0, show the sprite always -// == 1, show the sprite only after its sector has been drawn -// -// To enable display of the sprite, activate it. To turn off the sprite, -// deactivate it. -// -// All the code to display it is in am_map.cpp. -// -//-------------------------------------------------------------------------- - -IMPLEMENT_CLASS(AMapMarker, false, false) - -void AMapMarker::BeginPlay () -{ - ChangeStatNum (STAT_MAPMARKER); -} - -void AMapMarker::Activate (AActor *activator) -{ - flags2 |= MF2_DORMANT; -} - -void AMapMarker::Deactivate (AActor *activator) -{ - flags2 &= ~MF2_DORMANT; -} diff --git a/src/g_shared/a_randomspawner.cpp b/src/g_shared/a_randomspawner.cpp index 0cecfd115..d5a396d0d 100644 --- a/src/g_shared/a_randomspawner.cpp +++ b/src/g_shared/a_randomspawner.cpp @@ -13,7 +13,6 @@ #include "s_sound.h" #include "statnums.h" #include "gstrings.h" -#include "a_action.h" #include "v_text.h" #include "doomstat.h" #include "doomdata.h" diff --git a/src/g_shared/a_secrettrigger.cpp b/src/g_shared/a_secrettrigger.cpp deleted file mode 100644 index 509ec47e9..000000000 --- a/src/g_shared/a_secrettrigger.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* -** a_secrettrigger.cpp -** A thing that counts toward the secret count when activated -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** 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. -** -** 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 "actor.h" -#include "g_level.h" -#include "c_console.h" -#include "info.h" -#include "s_sound.h" -#include "d_player.h" -#include "doomstat.h" -#include "v_font.h" -#include "p_spec.h" - -class ASecretTrigger : public AActor -{ - DECLARE_CLASS (ASecretTrigger, AActor) -public: - void PostBeginPlay (); - void Activate (AActor *activator); -}; - -IMPLEMENT_CLASS(ASecretTrigger, false, false) - -void ASecretTrigger::PostBeginPlay () -{ - Super::PostBeginPlay (); - level.total_secrets++; -} - -void ASecretTrigger::Activate (AActor *activator) -{ - P_GiveSecret(activator, args[0] <= 1, (args[0] == 0 || args[0] == 2), -1); - Destroy (); -} - diff --git a/src/g_shared/a_setcolor.cpp b/src/g_shared/a_setcolor.cpp deleted file mode 100644 index e8a11b850..000000000 --- a/src/g_shared/a_setcolor.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "r_defs.h" -#include "actor.h" -#include "info.h" - -class AColorSetter : public AActor -{ - DECLARE_CLASS(AColorSetter, AActor) - - void PostBeginPlay() - { - Super::PostBeginPlay(); - Sector->SetColor(args[0], args[1], args[2], args[3]); - Destroy(); - } - -}; - -IMPLEMENT_CLASS(AColorSetter, false, false) - -class AFadeSetter : public AActor -{ - DECLARE_CLASS(AFadeSetter, AActor) - - void PostBeginPlay() - { - Super::PostBeginPlay(); - Sector->SetFade(args[0], args[1], args[2]); - Destroy(); - } - -}; - -IMPLEMENT_CLASS(AFadeSetter, false, false) diff --git a/src/g_shared/a_sharedglobal.h b/src/g_shared/a_sharedglobal.h index a690107c9..0087690f7 100644 --- a/src/g_shared/a_sharedglobal.h +++ b/src/g_shared/a_sharedglobal.h @@ -214,15 +214,6 @@ public: ActorFlags FlagsSave; }; -class AMapMarker : public AActor -{ - DECLARE_CLASS(AMapMarker, AActor) -public: - void BeginPlay (); - void Activate (AActor *activator); - void Deactivate (AActor *activator); -}; - class AFastProjectile : public AActor { DECLARE_CLASS(AFastProjectile, AActor) diff --git a/src/g_shared/a_spark.cpp b/src/g_shared/a_spark.cpp deleted file mode 100644 index f13c7178f..000000000 --- a/src/g_shared/a_spark.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* -** a_spark.cpp -** Actor that makes a particle spark when activated -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** 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. -** -** 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 "actor.h" -#include "info.h" -#include "m_random.h" -#include "p_effect.h" -#include "s_sound.h" - -class ASpark : public AActor -{ - DECLARE_CLASS (ASpark, AActor) -public: - void Activate (AActor *activator); -}; - -IMPLEMENT_CLASS(ASpark, false, false) - -void ASpark::Activate (AActor *activator) -{ - Super::Activate (activator); - P_DrawSplash (args[0] ? args[0] : 32, Pos(), Angles.Yaw, 1); - S_Sound (this, CHAN_AUTO, "world/spark", 1, ATTN_STATIC); -} diff --git a/src/g_shared/a_waterzone.cpp b/src/g_shared/a_waterzone.cpp deleted file mode 100644 index 2245b22bd..000000000 --- a/src/g_shared/a_waterzone.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* -** a_waterzone.cpp -** Actor that makes BOOM deep water swimmable -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** 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. -** -** 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 "info.h" -#include "r_defs.h" - -class AWaterZone : public AActor -{ - DECLARE_CLASS (AWaterZone, AActor) -public: - void PostBeginPlay (); -}; - -IMPLEMENT_CLASS(AWaterZone, false, false) - -void AWaterZone::PostBeginPlay () -{ - Super::PostBeginPlay (); - Sector->MoreFlags |= SECF_UNDERWATER; - Destroy (); -} - diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index a23e9943a..99d38b2c1 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -53,7 +53,6 @@ #include "p_lnspec.h" #include "p_effect.h" #include "p_enemy.h" -#include "a_action.h" #include "decallib.h" #include "m_random.h" #include "i_system.h" diff --git a/src/p_effect.cpp b/src/p_effect.cpp index ec051c299..42e82d740 100644 --- a/src/p_effect.cpp +++ b/src/p_effect.cpp @@ -574,6 +574,16 @@ void P_DrawSplash (int count, const DVector3 &pos, DAngle angle, int kind) } } +DEFINE_ACTION_FUNCTION(AActor, DrawSplash) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(count); + PARAM_FLOAT(angle); + PARAM_INT(kind); + P_DrawSplash(count, self->Pos(), angle, kind); + return 0; +} + void P_DrawSplash2 (int count, const DVector3 &pos, DAngle angle, int updown, int kind) { int color1, color2, zadd; diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 3d9122930..64e4feb4a 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -42,7 +42,6 @@ #include "c_cvars.h" #include "p_enemy.h" #include "a_sharedglobal.h" -#include "a_action.h" #include "d_dehacked.h" #include "g_level.h" #include "r_utility.h" diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 5e2a9f039..7decbe9ad 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -47,7 +47,6 @@ #include "p_acs.h" #include "cmdlib.h" #include "decallib.h" -#include "a_action.h" #include "a_keys.h" #include "p_conversation.h" #include "g_game.h" diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index 2b8097e55..22ef88358 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -700,6 +700,16 @@ void sector_t::SetColor(int r, int g, int b, int desat) P_RecalculateAttachedLights(this); } +DEFINE_ACTION_FUNCTION(_Sector, SetColor) +{ + PARAM_SELF_STRUCT_PROLOGUE(sector_t); + PARAM_COLOR(color); + PARAM_INT(desat); + self->ColorMap = GetSpecialLights(color, self->ColorMap->Fade, desat); + P_RecalculateAttachedLights(self); + return 0; +} + void sector_t::SetFade(int r, int g, int b) { PalEntry fade = PalEntry (r,g,b); @@ -707,6 +717,16 @@ void sector_t::SetFade(int r, int g, int b) P_RecalculateAttachedLights(this); } +DEFINE_ACTION_FUNCTION(_Sector, SetFade) +{ + PARAM_SELF_STRUCT_PROLOGUE(sector_t); + PARAM_COLOR(fade); + self->ColorMap = GetSpecialLights(self->ColorMap->Color, fade, self->ColorMap->Desaturate); + P_RecalculateAttachedLights(self); + return 0; +} + + //=========================================================================== // // sector_t :: ClosestPoint diff --git a/src/p_spec.cpp b/src/p_spec.cpp index eb6b9bea7..e4aea5595 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -552,6 +552,15 @@ void P_GiveSecret(AActor *actor, bool printmessage, bool playsound, int sectornu level.found_secrets++; } +DEFINE_ACTION_FUNCTION(AActor, GiveSecret) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_BOOL(printmessage); + PARAM_BOOL(playsound); + P_GiveSecret(self, printmessage, playsound, -1); + return 0; +} + //============================================================================ // // P_PlayerOnSpecialFlat diff --git a/src/scripting/decorate/olddecorations.cpp b/src/scripting/decorate/olddecorations.cpp index 8321a8f89..400444340 100644 --- a/src/scripting/decorate/olddecorations.cpp +++ b/src/scripting/decorate/olddecorations.cpp @@ -44,7 +44,6 @@ #include "s_sound.h" #include "cmdlib.h" #include "p_lnspec.h" -#include "a_action.h" #include "decallib.h" #include "i_system.h" #include "thingdef.h" diff --git a/src/scripting/decorate/thingdef_states.cpp b/src/scripting/decorate/thingdef_states.cpp index 3b4abe002..1cb0a91af 100644 --- a/src/scripting/decorate/thingdef_states.cpp +++ b/src/scripting/decorate/thingdef_states.cpp @@ -45,7 +45,6 @@ #include "templates.h" #include "cmdlib.h" #include "p_lnspec.h" -#include "a_action.h" #include "p_local.h" #include "v_palette.h" #include "doomerrors.h" diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index 5708f89d2..77120c947 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -50,7 +50,6 @@ #include "s_sound.h" #include "cmdlib.h" #include "p_lnspec.h" -#include "a_action.h" #include "decallib.h" #include "m_random.h" #include "i_system.h" diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 8586d32af..cfadc53bf 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -49,7 +49,6 @@ #include "s_sound.h" #include "cmdlib.h" #include "p_lnspec.h" -#include "a_action.h" #include "decallib.h" #include "m_random.h" #include "i_system.h" diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index c3dc3c1dd..b4b4afeb1 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -302,7 +302,6 @@ class Actor : Thinker native native void SetOrigin(vector3 newpos, bool moving); native void SetXYZ(vector3 newpos); native Actor GetPointer(int aaptr); - native void FaceMovementDirection(); native double BulletSlope(out FTranslatedLineTarget pLineTarget = null, int aimflags = 0); native Actor AimTarget(); native bool CheckMissileSpawn(double maxdist); @@ -375,6 +374,8 @@ class Actor : Thinker native native name GetSpecies(); native void PlayActiveSound(); native void Howl(); + native void DrawSplash (int count, double angle, int kind); + native void GiveSecret(bool printmsg = true, bool playsound = true); native bool CheckClass(class checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false); native Inventory FindInventory(class itemtype, bool subclass = false); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 73f515f71..b1d9526ce 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -17,20 +17,47 @@ class Object native class Thinker : Object native { + enum EStatnums + { + // Thinkers that don't actually think + STAT_INFO, // An info queue + STAT_DECAL, // A decal + STAT_AUTODECAL, // A decal that can be automatically deleted + STAT_CORPSEPOINTER, // An entry in Hexen's corpse queue + STAT_TRAVELLING, // An actor temporarily travelling to a new map + + // Thinkers that do think + STAT_FIRST_THINKING=32, + STAT_SCROLLER=STAT_FIRST_THINKING, // A DScroller thinker + STAT_PLAYER, // A player actor + STAT_BOSSTARGET, // A boss brain target + STAT_LIGHTNING, // The lightning thinker + STAT_DECALTHINKER, // An object that thinks for a decal + STAT_INVENTORY, // An inventory item + STAT_LIGHT, // A sector light effect + STAT_LIGHTTRANSFER, // A sector light transfer. These must be ticked after the light effects. + STAT_EARTHQUAKE, // Earthquake actors + STAT_MAPMARKER, // Map marker actors + + STAT_DEFAULT = 100, // Thinkers go here unless specified otherwise. + STAT_SECTOREFFECT, // All sector effects that cause floor and ceiling movement + STAT_ACTORMOVER, // actor movers + STAT_SCRIPTS, // The ACS thinker. This is to ensure that it can't tick before all actors called PostBeginPlay + STAT_BOT, // Bot thinker + MAX_STATNUM = 127 + } + const TICRATE = 35; virtual native void Tick(); virtual native void PostBeginPlay(); + virtual native void ChangeStatNum(int stat); } class ThinkerIterator : Object native { - enum EStatnums - { - MAX_STATNUM = 127 - } - native static ThinkerIterator Create(class type = "Actor", int statnum=MAX_STATNUM+1); + native static ThinkerIterator Create(class type = "Actor", int statnum=Thinker.MAX_STATNUM+1); native Thinker Next(bool exact = false); native void Reinit(); } @@ -87,11 +114,11 @@ struct LevelLocals native native readonly int maptype; native readonly String Music; native readonly int musicorder; - native readonly int total_secrets; + native int total_secrets; native int found_secrets; - native readonly int total_items; + native int total_items; native int found_items; - native readonly int total_monsters; + native int total_monsters; native int killed_monsters; native double gravity; native double aircontrol; @@ -225,6 +252,19 @@ struct Sector native native int16 leakydamage; native uint16 ZoneNumber; + + enum ESectorMoreFlags + { + SECMF_FAKEFLOORONLY = 2, // when used as heightsec in R_FakeFlat, only copies floor + SECMF_CLIPFAKEPLANES = 4, // as a heightsec, clip planes to target sector's planes + SECMF_NOFAKELIGHT = 8, // heightsec does not change lighting + SECMF_IGNOREHEIGHTSEC= 16, // heightsec is only for triggering sector actions + SECMF_UNDERWATER = 32, // sector is underwater + SECMF_FORCEDUNDERWATER= 64, // sector is forced to be underwater + SECMF_UNDERWATERMASK = 32+64, + SECMF_DRAWN = 128, // sector has been drawn at least once + SECMF_HIDDEN = 256, // Do not draw on textured automap + } native uint16 MoreFlags; enum ESectorFlags @@ -263,6 +303,8 @@ struct Sector native native void RemoveForceField(); native static Sector PointInSector(Vector2 pt); + native void SetColor(color c, int desat = 0); + native void SetFade(color c); } struct Wads diff --git a/wadsrc/static/zscript/raven/minotaur.txt b/wadsrc/static/zscript/raven/minotaur.txt index fa40cbec1..5e3d0cfe3 100644 --- a/wadsrc/static/zscript/raven/minotaur.txt +++ b/wadsrc/static/zscript/raven/minotaur.txt @@ -757,3 +757,50 @@ class MinotaurSmokeExit : Actor } } +extend class Actor +{ + enum dirtype_t + { + DI_EAST, + DI_NORTHEAST, + DI_NORTH, + DI_NORTHWEST, + DI_WEST, + DI_SOUTHWEST, + DI_SOUTH, + DI_SOUTHEAST, + DI_NODIR, + NUMDIRS + }; + + void FaceMovementDirection() + { + switch (movedir) + { + case DI_EAST: + angle = 0.; + break; + case DI_NORTHEAST: + angle = 45.; + break; + case DI_NORTH: + angle = 90.; + break; + case DI_NORTHWEST: + angle = 135.; + break; + case DI_WEST: + angle = 180.; + break; + case DI_SOUTHWEST: + angle = 225.; + break; + case DI_SOUTH: + angle = 270.; + break; + case DI_SOUTHEAST: + angle = 315.; + break; + } + } +} \ No newline at end of file diff --git a/wadsrc/static/zscript/shared/hatetarget.txt b/wadsrc/static/zscript/shared/hatetarget.txt index 6d2263f61..e90abcdbb 100644 --- a/wadsrc/static/zscript/shared/hatetarget.txt +++ b/wadsrc/static/zscript/shared/hatetarget.txt @@ -2,7 +2,7 @@ // Hate Target -------------------------------------------------------------- -class HateTarget : Actor native +class HateTarget : Actor { default { @@ -19,4 +19,32 @@ class HateTarget : Actor native Spawn: TNT1 A -1; } + + override void BeginPlay() + { + Super.BeginPlay(); + if (SpawnAngle != 0) + { // Each degree translates into 10 units of health + health = SpawnAngle * 10; + } + else + { + special2 = 1; + health = 1000001; + } + } + + override int TakeSpecialDamage(Actor inflictor, Actor source, int damage, Name damagetype) + { + if (special2 != 0) + { + return 0; + } + else + { + return damage; + } + } + + } \ No newline at end of file diff --git a/wadsrc/static/zscript/shared/mapmarker.txt b/wadsrc/static/zscript/shared/mapmarker.txt index 1afa00459..25e197307 100644 --- a/wadsrc/static/zscript/shared/mapmarker.txt +++ b/wadsrc/static/zscript/shared/mapmarker.txt @@ -1,5 +1,20 @@ +// Map Marker -------------------------------------------------------------- +// +// This class uses the following argument: +// args[0] == 0, shows the sprite at this actor +// != 0, shows the sprite for all actors whose TIDs match instead +// +// args[1] == 0, show the sprite always +// == 1, show the sprite only after its sector has been drawn +// +// To enable display of the sprite, activate it. To turn off the sprite, +// deactivate it. +// +// All the code to display it is in am_map.cpp. +// +//-------------------------------------------------------------------------- -class MapMarker : Actor native +class MapMarker : Actor { default { @@ -15,4 +30,20 @@ class MapMarker : Actor native AMRK A -1; Stop; } + + override void BeginPlay () + { + ChangeStatNum (STAT_MAPMARKER); + } + + override void Activate (Actor activator) + { + bDormant = true; + } + + override void Deactivate (Actor activator) + { + bDormant = false; + } + } diff --git a/wadsrc/static/zscript/shared/secrettrigger.txt b/wadsrc/static/zscript/shared/secrettrigger.txt index 48c93686e..c60399600 100644 --- a/wadsrc/static/zscript/shared/secrettrigger.txt +++ b/wadsrc/static/zscript/shared/secrettrigger.txt @@ -1,5 +1,5 @@ -class SecretTrigger : Actor native +class SecretTrigger : Actor { default { @@ -8,5 +8,19 @@ class SecretTrigger : Actor native +NOGRAVITY +DONTSPLASH } + + override void PostBeginPlay () + { + Super.PostBeginPlay (); + level.total_secrets++; + } + + override void Activate (Actor activator) + { + activator.GiveSecret(args[0] <= 1, (args[0] == 0 || args[0] == 2)); + Destroy (); + } + + } diff --git a/wadsrc/static/zscript/shared/setcolor.txt b/wadsrc/static/zscript/shared/setcolor.txt index 8689e5fd1..18105ef54 100644 --- a/wadsrc/static/zscript/shared/setcolor.txt +++ b/wadsrc/static/zscript/shared/setcolor.txt @@ -1,4 +1,4 @@ -class ColorSetter : Actor native +class ColorSetter : Actor { default { @@ -7,10 +7,18 @@ class ColorSetter : Actor native +DONTSPLASH RenderStyle "None"; } + + override void PostBeginPlay() + { + Super.PostBeginPlay(); + CurSector.SetColor(color(args[0], args[1], args[2]), args[3]); + Destroy(); + } + } -class FadeSetter : Actor native +class FadeSetter : Actor { default { @@ -19,4 +27,13 @@ class FadeSetter : Actor native +DONTSPLASH RenderStyle "None"; } + + void PostBeginPlay() + { + Super.PostBeginPlay(); + CurSector.SetFade(color(args[0], args[1], args[2])); + Destroy(); + } + + } diff --git a/wadsrc/static/zscript/shared/sharedmisc.txt b/wadsrc/static/zscript/shared/sharedmisc.txt index 5989702fd..6da942e39 100644 --- a/wadsrc/static/zscript/shared/sharedmisc.txt +++ b/wadsrc/static/zscript/shared/sharedmisc.txt @@ -157,13 +157,25 @@ class CustomSprite : Actor native // SwitchableDecoration: Activate and Deactivate change state -------------- -class SwitchableDecoration : Actor native +class SwitchableDecoration : Actor { + override void Activate (Actor activator) + { + SetStateLabel("Active"); + } + + override void Deactivate (Actor activator) + { + SetStateLabel("Inactive"); + } + } - -class SwitchingDecoration : SwitchableDecoration native +class SwitchingDecoration : SwitchableDecoration { + override void Deactivate (Actor activator) + { + } } // Random spawner ---------------------------------------------------------- diff --git a/wadsrc/static/zscript/shared/spark.txt b/wadsrc/static/zscript/shared/spark.txt index 5adffdfe1..c5ae6a455 100644 --- a/wadsrc/static/zscript/shared/spark.txt +++ b/wadsrc/static/zscript/shared/spark.txt @@ -1,5 +1,5 @@ -class Spark : Actor native +class Spark : Actor { default { @@ -8,4 +8,12 @@ class Spark : Actor native +NOGRAVITY +DONTSPLASH } + + override void Activate (Actor activator) + { + Super.Activate (activator); + DrawSplash (args[0] ? args[0] : 32, Angle, 1); + A_PlaySound ("world/spark", CHAN_AUTO, 1, false, ATTN_STATIC); + } + } \ No newline at end of file diff --git a/wadsrc/static/zscript/shared/waterzone.txt b/wadsrc/static/zscript/shared/waterzone.txt index 975c8a473..49d950b00 100644 --- a/wadsrc/static/zscript/shared/waterzone.txt +++ b/wadsrc/static/zscript/shared/waterzone.txt @@ -1,4 +1,4 @@ -class WaterZone : Actor native +class WaterZone : Actor { default { @@ -7,4 +7,13 @@ class WaterZone : Actor native +NOGRAVITY +DONTSPLASH } + + override void PostBeginPlay () + { + Super.PostBeginPlay (); + CurSector.MoreFlags |= Sector.SECMF_UNDERWATER; + Destroy (); + } + + } From 91934665729693e4be7092549f885b0813fdc80e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 29 Nov 2016 20:16:14 +0100 Subject: [PATCH 171/185] - scriptified ASecurityCamera and AAimingCamera. This concludes this round of script converesions of internal classes. --- src/CMakeLists.txt | 1 - src/g_shared/a_camera.cpp | 200 ------------------------ src/p_mobj.cpp | 7 + wadsrc/static/zscript/actor.txt | 1 + wadsrc/static/zscript/shared/camera.txt | 107 ++++++++++++- 5 files changed, 110 insertions(+), 206 deletions(-) delete mode 100644 src/g_shared/a_camera.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 111b2663c..d1e90581c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1111,7 +1111,6 @@ set (PCH_SOURCES g_shared/a_armor.cpp g_shared/a_artifacts.cpp g_shared/a_bridge.cpp - g_shared/a_camera.cpp g_shared/a_decals.cpp g_shared/a_fastprojectile.cpp g_shared/a_flashfader.cpp diff --git a/src/g_shared/a_camera.cpp b/src/g_shared/a_camera.cpp deleted file mode 100644 index a0bc40ce3..000000000 --- a/src/g_shared/a_camera.cpp +++ /dev/null @@ -1,200 +0,0 @@ -/* -** a_camera.cpp -** Implements the Duke Nukem 3D-ish security camera -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** 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. -** -** 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 "actor.h" -#include "info.h" -#include "a_sharedglobal.h" -#include "p_local.h" -#include "serializer.h" -#include "math/cmath.h" - -/* -== SecurityCamera -== -== args[0] = pitch -== args[1] = amount camera turns to either side of its initial position -== (in degrees) -== args[2] = octics to complete one cycle -*/ - -class ASecurityCamera : public AActor -{ - DECLARE_CLASS (ASecurityCamera, AActor) -public: - void PostBeginPlay (); - void Tick (); - - - void Serialize(FSerializer &arc); -protected: - DAngle Center; - DAngle Acc; - DAngle Delta; - DAngle Range; -}; - -IMPLEMENT_CLASS(ASecurityCamera, false, false) - -void ASecurityCamera::Serialize(FSerializer &arc) -{ - Super::Serialize (arc); - arc("center", Center) - ("acc", Acc) - ("delta", Delta) - ("range", Range); -} - -void ASecurityCamera::PostBeginPlay () -{ - Super::PostBeginPlay (); - Center = Angles.Yaw; - if (args[2]) - Delta = 360. / (args[2] * TICRATE / 8); - else - Delta = 0.; - if (args[1]) - Delta /= 2; - Acc = 0.; - Angles.Pitch = (double)clamp((signed char)args[0], -89, 89); - Range = (double)args[1]; -} - -void ASecurityCamera::Tick () -{ - Acc += Delta; - if (Range != 0) - Angles.Yaw = Center + Range * Acc.Sin(); - else if (Delta != 0) - Angles.Yaw = Acc; -} - -/* -== AimingCamera -== -== args[0] = pitch -== args[1] = max turn (in degrees) -== args[2] = max pitch turn (in degrees) -== args[3] = tid of thing to look at -== -== Also uses: -== tracer: thing to look at -*/ - -class AAimingCamera : public ASecurityCamera -{ - DECLARE_CLASS (AAimingCamera, ASecurityCamera) -public: - void PostBeginPlay (); - void Tick (); - - - void Serialize(FSerializer &arc); -protected: - DAngle MaxPitchChange; -}; - -IMPLEMENT_CLASS(AAimingCamera, false, false) - -void AAimingCamera::Serialize(FSerializer &arc) -{ - Super::Serialize (arc); - arc("maxpitchchange", MaxPitchChange); -} - -void AAimingCamera::PostBeginPlay () -{ - int changepitch = args[2]; - - args[2] = 0; - Super::PostBeginPlay (); - MaxPitchChange = double(changepitch / TICRATE); - Range /= TICRATE; - - TActorIterator iterator (args[3]); - tracer = iterator.Next (); - if (tracer == NULL) - { - //Printf ("AimingCamera %d: Can't find TID %d\n", tid, args[3]); - } - else - { // Don't try for a new target upon losing this one. - args[3] = 0; - } -} - -void AAimingCamera::Tick () -{ - if (tracer == NULL && args[3] != 0) - { // Recheck, in case something with this TID was created since the last time. - TActorIterator iterator (args[3]); - tracer = iterator.Next (); - } - if (tracer != NULL) - { - DAngle delta; - int dir = P_FaceMobj (this, tracer, &delta); - if (delta > Range) - { - delta = Range; - } - if (dir) - { - Angles.Yaw += delta; - } - else - { - Angles.Yaw -= delta; - } - if (MaxPitchChange != 0) - { // Aim camera's pitch; use floats for precision - DVector2 vect = tracer->Vec2To(this); - double dz = Z() - tracer->Z() - tracer->Height/2; - double dist = vect.Length(); - DAngle desiredPitch = dist != 0.f ? VecToAngle(dist, dz) : 0.; - DAngle diff = deltaangle(Angles.Pitch, desiredPitch); - if (fabs (diff) < MaxPitchChange) - { - Angles.Pitch = desiredPitch; - } - else if (diff < 0) - { - Angles.Pitch -= MaxPitchChange; - } - else - { - Angles.Pitch += MaxPitchChange; - } - } - } -} diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 7decbe9ad..9c0f587eb 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -7539,6 +7539,13 @@ DEFINE_ACTION_FUNCTION(AActor, Vec3To) ACTION_RETURN_VEC3(self->Vec3To(t)); } +DEFINE_ACTION_FUNCTION(AActor, Vec2To) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(t, AActor) + ACTION_RETURN_VEC2(self->Vec2To(t)); +} + DEFINE_ACTION_FUNCTION(AActor, Vec3Angle) { PARAM_SELF_PROLOGUE(AActor); diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index b4b4afeb1..15c643047 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -356,6 +356,7 @@ class Actor : Thinker native native double AngleTo(Actor target, bool absolute = false); native void AddZ(double zadd, bool moving = true); native void SetZ(double z); + native vector2 Vec2To(Actor other); native vector3 Vec3To(Actor other); native vector3 Vec3Offset(double x, double y, double z, bool absolute = false); native vector3 Vec3Angle(double length, double angle, double z = 0, bool absolute = false); diff --git a/wadsrc/static/zscript/shared/camera.txt b/wadsrc/static/zscript/shared/camera.txt index 9420c98d5..abb394745 100644 --- a/wadsrc/static/zscript/shared/camera.txt +++ b/wadsrc/static/zscript/shared/camera.txt @@ -9,21 +9,118 @@ class DoomBuilderCamera : Actor } -class SecurityCamera : Actor native +class SecurityCamera : Actor { default { +NOBLOCKMAP +NOGRAVITY +DONTSPLASH - } - default - { RenderStyle "None"; CameraHeight 0; } + + double Center; + double Acc; + double Delta; + double Range; + + override void PostBeginPlay () + { + Super.PostBeginPlay (); + Center = Angle; + if (args[2]) + Delta = 360. / (args[2] * TICRATE / 8); + else + Delta = 0.; + if (args[1]) + Delta /= 2; + Acc = 0.; + Pitch = clamp(args[0], -89, 89); + Range = args[1]; + } + + override void Tick () + { + Acc += Delta; + if (Range != 0) + Angle = Center + Range * sin(Acc); + else if (Delta != 0) + Angle = Acc; + } + + } -class AimingCamera : SecurityCamera native +class AimingCamera : SecurityCamera { + double MaxPitchChange; + + override void PostBeginPlay () + { + int changepitch = args[2]; + + args[2] = 0; + Super.PostBeginPlay (); + MaxPitchChange = double(changepitch / TICRATE); + Range /= TICRATE; + + ActorIterator it = ActorIterator.Create(args[3]); + tracer = it.Next (); + if (tracer == NULL) + { + //Printf ("AimingCamera %d: Can't find TID %d\n", tid, args[3]); + } + else + { // Don't try for a new target upon losing this one. + args[3] = 0; + } + } + + override void Tick () + { + if (tracer == NULL && args[3] != 0) + { // Recheck, in case something with this TID was created since the last time. + ActorIterator it = ActorIterator.Create(args[3]); + tracer = it.Next (); + } + if (tracer != NULL) + { + double dir = deltaangle(angle, AngleTo(tracer)); + double delta = abs(dir); + if (delta > Range) + { + delta = Range; + } + if (dir > 0) + { + Angle += delta; + } + else + { + Angle -= delta; + } + if (MaxPitchChange != 0) + { // Aim camera's pitch; use floats for precision + Vector2 vect = tracer.Vec2To(self); + double dz = pos.z - tracer.pos.z - tracer.Height/2; + double dist = vect.Length(); + double desiredPitch = dist != 0.f ? VectorAngle(dist, dz) : 0.; + double diff = deltaangle(pitch, desiredPitch); + if (abs (diff) < MaxPitchChange) + { + pitch = desiredPitch; + } + else if (diff < 0) + { + pitch -= MaxPitchChange; + } + else + { + pitch += MaxPitchChange; + } + } + } + } + } From 4372a14479765b1114564587170dd1c1b782362c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 29 Nov 2016 20:28:04 +0100 Subject: [PATCH 172/185] - fixed: Giving several morph items in the same tic could lead to an invalid Owner pointer in APowerupGiver::Use. --- src/g_shared/a_artifacts.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index 99a4f46d8..5866e8b2a 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -72,6 +72,7 @@ DEFINE_FIELD(APowerupGiver, Strength) bool APowerupGiver::Use (bool pickup) { if (PowerupType == NULL) return true; // item is useless + if (Owner == nullptr) return true; APowerup *power = static_cast (Spawn (PowerupType)); From bbf62132d83645557368f7abd846ec234b7d2b1f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 30 Nov 2016 01:25:51 +0100 Subject: [PATCH 173/185] - added a larger batch of function exports. - cleaned up the virtual function interface of APlayerPawn which still had many virtual declarations from old times when class properties were handled through virtual overrides. None of this makes sense these days anymore. --- src/d_player.h | 39 ++--- src/info.cpp | 7 + src/p_ceiling.cpp | 16 ++ src/p_enemy.cpp | 43 +++++- src/p_interaction.cpp | 14 ++ src/p_map.cpp | 43 ++++++ src/p_mobj.cpp | 187 +++++++++++++++++++++++- src/p_user.cpp | 27 +++- src/s_sound.cpp | 11 ++ wadsrc/static/zscript/actor.txt | 47 +++++- wadsrc/static/zscript/base.txt | 92 +++++++++++- wadsrc/static/zscript/shared/player.txt | 13 ++ 12 files changed, 498 insertions(+), 41 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index d1678b619..95a288ebd 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -105,29 +105,36 @@ public: virtual void Serialize(FSerializer &arc); - virtual void PostBeginPlay(); - virtual void Tick(); - virtual void AddInventory (AInventory *item); - virtual void RemoveInventory (AInventory *item); - virtual bool UseInventory (AInventory *item); - virtual void MarkPrecacheSounds () const; + virtual void PostBeginPlay() override; + virtual void Tick() override; + virtual void AddInventory (AInventory *item) override; + virtual void RemoveInventory (AInventory *item) override; + virtual bool UseInventory (AInventory *item) override; + virtual void MarkPrecacheSounds () const override; + virtual void BeginPlay () override; + virtual void Die (AActor *source, AActor *inflictor, int dmgflags) override; + virtual bool UpdateWaterLevel (bool splash) override; - virtual void PlayIdle (); - virtual void PlayRunning (); - virtual void ThrowPoisonBag (); - virtual void TweakSpeeds (double &forwardmove, double &sidemove); + bool ResetAirSupply (bool playgasp = true); + int GetMaxHealth() const; + void TweakSpeeds (double &forwardmove, double &sidemove); void MorphPlayerThink (); - virtual void ActivateMorphWeapon (); + void ActivateMorphWeapon (); AWeapon *PickNewWeapon (PClassAmmo *ammotype); AWeapon *BestWeapon (PClassAmmo *ammotype); void CheckWeaponSwitch(PClassAmmo *ammotype); - virtual void GiveDeathmatchInventory (); - virtual void FilterCoopRespawnInventory (APlayerPawn *oldplayer); + void GiveDeathmatchInventory (); + void FilterCoopRespawnInventory (APlayerPawn *oldplayer); void SetupWeaponSlots (); void GiveDefaultInventory (); + + // These are virtual on the script side only. + void PlayIdle(); + void PlayRunning(); void PlayAttacking (); void PlayAttacking2 (); + const char *GetSoundClass () const; enum EInvulState @@ -138,8 +145,6 @@ public: INVUL_GetAlpha }; - void BeginPlay (); - void Die (AActor *source, AActor *inflictor, int dmgflags); int crouchsprite; int MaxHealth; @@ -171,10 +176,6 @@ public: // [SP] ViewBob Multiplier double ViewBob; - bool UpdateWaterLevel (bool splash); - bool ResetAirSupply (bool playgasp = true); - - int GetMaxHealth() const; }; class APlayerChunk : public APlayerPawn diff --git a/src/info.cpp b/src/info.cpp index 8a2842ff4..69605d454 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -151,6 +151,13 @@ int GetSpriteIndex(const char * spritename, bool add) return (lastindex = (int)sprites.Push (temp)); } +DEFINE_ACTION_FUNCTION(AActor, GetSpriteIndex) +{ + PARAM_PROLOGUE; + PARAM_NAME(sprt); + ACTION_RETURN_INT(GetSpriteIndex(sprt.GetChars(), false)); +} + IMPLEMENT_CLASS(PClassActor, false, true) IMPLEMENT_POINTERS_START(PClassActor) diff --git a/src/p_ceiling.cpp b/src/p_ceiling.cpp index a38a17f9c..932b4c649 100644 --- a/src/p_ceiling.cpp +++ b/src/p_ceiling.cpp @@ -458,6 +458,22 @@ bool P_CreateCeiling(sector_t *sec, DCeiling::ECeiling type, line_t *line, int t return ceiling != NULL; } +DEFINE_ACTION_FUNCTION(DCeiling, CreateCeiling) +{ + PARAM_PROLOGUE; + PARAM_POINTER(sec, sector_t); + PARAM_INT(type); + PARAM_POINTER(ln, line_t); + PARAM_FLOAT(speed); + PARAM_FLOAT(speed2); + PARAM_FLOAT_DEF(height); + PARAM_INT_DEF(crush); + PARAM_INT_DEF(silent); + PARAM_INT_DEF(change); + PARAM_INT_DEF(crushmode); + ACTION_RETURN_BOOL(P_CreateCeiling(sec, (DCeiling::ECeiling)type, ln, 0, speed, speed2, height, crush, silent, change, (DCeiling::ECrushMode)crushmode)); +} + //============================================================================ // // EV_DoCeiling diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 64e4feb4a..5b2ba6d65 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -1283,6 +1283,14 @@ void P_RandomChaseDir (AActor *actor) actor->movedir = DI_NODIR; // cannot move } +DEFINE_ACTION_FUNCTION(AActor, RandomChaseDir) +{ + PARAM_SELF_PROLOGUE(AActor); + P_RandomChaseDir(self); + return 0; +} + + //--------------------------------------------------------------------------- // // P_IsVisible @@ -1335,6 +1343,15 @@ bool P_IsVisible(AActor *lookee, AActor *other, INTBOOL allaround, FLookExParams return P_CheckSight(lookee, other, SF_SEEPASTSHOOTABLELINES); } +DEFINE_ACTION_FUNCTION(AActor, IsVisible) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(other, AActor); + PARAM_BOOL(allaround); + PARAM_POINTER_DEF(params, FLookExParams); + ACTION_RETURN_BOOL(P_IsVisible(self, other, allaround, params)); +} + //--------------------------------------------------------------------------- // // FUNC P_LookForMonsters @@ -1388,6 +1405,12 @@ bool P_LookForMonsters (AActor *actor) return false; } +DEFINE_ACTION_FUNCTION(AActor, LookForMonsters) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_BOOL(P_LookForMonsters(self)); +} + //============================================================================ // // LookForTIDinBlock @@ -1560,6 +1583,14 @@ bool P_LookForTID (AActor *actor, INTBOOL allaround, FLookExParams *params) return false; } +DEFINE_ACTION_FUNCTION(AActor, LookForTID) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_BOOL(allaround); + PARAM_POINTER_DEF(params, FLookExParams); + ACTION_RETURN_BOOL(P_LookForTID(self, allaround, params)); +} + //============================================================================ // // LookForEnemiesinBlock @@ -1699,6 +1730,15 @@ bool P_LookForEnemies (AActor *actor, INTBOOL allaround, FLookExParams *params) return false; } +DEFINE_ACTION_FUNCTION(AActor, LookForEnemies) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_BOOL(allaround); + PARAM_POINTER_DEF(params, FLookExParams); + ACTION_RETURN_BOOL(P_LookForEnemies(self, allaround, params)); +} + + /* ================ = @@ -1886,7 +1926,8 @@ DEFINE_ACTION_FUNCTION(AActor, LookForPlayers) { PARAM_SELF_PROLOGUE(AActor); PARAM_BOOL(allaround); - ACTION_RETURN_BOOL(P_LookForPlayers(self, allaround, nullptr)); + PARAM_POINTER_DEF(params, FLookExParams); + ACTION_RETURN_BOOL(P_LookForPlayers(self, allaround, params)); } // diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index a5fcc2dda..e0e3e62b9 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1636,6 +1636,20 @@ void P_PoisonMobj (AActor *target, AActor *inflictor, AActor *source, int damage } +DEFINE_ACTION_FUNCTION(AActor, PoisonMobj) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(inflictor, AActor); + PARAM_OBJECT(source, AActor); + PARAM_INT(damage); + PARAM_INT(duration); + PARAM_INT(period); + PARAM_NAME(mod); + P_PoisonMobj(self, inflictor, source, damage, duration, period, mod); + return 0; +} + + bool AActor::OkayToSwitchTarget (AActor *other) { if (other == this) diff --git a/src/p_map.cpp b/src/p_map.cpp index c5780eedc..11036d171 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -297,6 +297,14 @@ void P_FindFloorCeiling(AActor *actor, int flags) } } +DEFINE_ACTION_FUNCTION(AActor, FindFloorCeiling) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT_DEF(flags); + P_FindFloorCeiling(self, flags); + return 0; +} + // Debug CCMD for checking errors in the MultiBlockLinesIterator (needs to be removed when this code is complete) CCMD(ffcf) { @@ -661,6 +669,21 @@ double P_GetMoveFactor(const AActor *mo, double *frictionp) return movefactor; } +DEFINE_ACTION_FUNCTION(AActor, GetFriction) +{ + PARAM_SELF_PROLOGUE(AActor); + double friction, movefactor = P_GetMoveFactor(self, &friction); + if (numret > 1) + { + numret = 2; + ret[1].SetFloat(movefactor); + } + if (numret > 0) + { + ret[0].SetFloat(friction); + } + return numret; +} //========================================================================== // @@ -1885,6 +1908,26 @@ bool P_TestMobjZ(AActor *actor, bool quick, AActor **pOnmobj) return onmobj == NULL; } +DEFINE_ACTION_FUNCTION(AActor, TestMobjZ) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_BOOL_DEF(quick); + + AActor *on = nullptr;; + bool retv = P_TestMobjZ(self, quick, &on); + if (numret > 1) + { + numret = 2; + ret[1].SetPointer(on, ATAG_OBJECT); + } + if (numret > 0) + { + ret[0].SetInt(retv); + } + return numret; +} + + //============================================================================= // // P_FakeZMovement diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 9c0f587eb..d099a8e77 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -568,6 +568,13 @@ bool AActor::InStateSequence(FState * newstate, FState * basestate) return false; } +DEFINE_ACTION_FUNCTION(AActor, InStateSequence) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_POINTER(newstate, FState); + PARAM_POINTER(basestate, FState); + ACTION_RETURN_BOOL(self->InStateSequence(newstate, basestate)); +} //========================================================================== // // AActor::GetTics @@ -736,6 +743,15 @@ void AActor::AddInventory (AInventory *item) Inventory->InventoryID = InventoryID++; } +DEFINE_ACTION_FUNCTION(AActor, AddInventory) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(item, AInventory); + self->AddInventory(item); + return 0; +} + + //============================================================================ // // AActor :: GiveInventory @@ -795,6 +811,14 @@ bool AActor::GiveInventory(PClassInventory *type, int amount, bool givecheat) return result; } +DEFINE_ACTION_FUNCTION(AActor, Inventory) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(item, AInventory); + ACTION_RETURN_BOOL(self->UseInventory(item)); +} + + //============================================================================ // // AActor :: RemoveInventory @@ -822,6 +846,15 @@ void AActor::RemoveInventory(AInventory *item) } } +DEFINE_ACTION_FUNCTION(AActor, RemoveInventory) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(item, AInventory); + self->RemoveInventory(item); + return 0; +} + + //============================================================================ // // AActor :: TakeInventory @@ -1186,6 +1219,14 @@ void AActor::ClearInventory() } } +DEFINE_ACTION_FUNCTION(AActor, ClearInventory) +{ + PARAM_SELF_PROLOGUE(AActor); + self->ClearInventory(); + return 0; +} + + //============================================================================ // // AActor :: CopyFriendliness @@ -3176,6 +3217,18 @@ DEFINE_ACTION_FUNCTION(AActor, RemoveFromHash) return 0; } +DEFINE_ACTION_FUNCTION(AActor, ChangeTid) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(tid); + self->RemoveFromHash(); + self->tid = tid; + self->AddToHash(); + return 0; +} + + + //========================================================================== // // P_IsTIDUsed @@ -3258,6 +3311,17 @@ int P_FindUniqueTID(int start_tid, int limit) return 0; } +DEFINE_ACTION_FUNCTION(AActor, FindUniqueTid) +{ + PARAM_PROLOGUE; + PARAM_INT_DEF(start); + PARAM_INT_DEF(limit); + ACTION_RETURN_INT(P_FindUniqueTID(start, limit)); +} + + + + CCMD(utid) { Printf("%d\n", @@ -3537,6 +3601,14 @@ void AActor::SetShade (int r, int g, int b) fillcolor = MAKEARGB(ColorMatcher.Pick (r, g, b), r, g, b); } +DEFINE_ACTION_FUNCTION(AActor, SetShade) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(color); + self->SetShade(color); + return 0; +} + void AActor::SetPitch(DAngle p, bool interpolate, bool forceclamp) { if (player != NULL || forceclamp) @@ -5777,6 +5849,19 @@ void P_SpawnBlood (const DVector3 &pos1, DAngle dir, int damage, AActor *origina P_DrawSplash2 (40, pos, dir, 2, bloodcolor); } +DEFINE_ACTION_FUNCTION(AActor, SpawnBlood) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + PARAM_ANGLE(dir); + PARAM_INT(damage); + P_SpawnBlood(DVector3(x, y, z), dir, damage, self); + return 0; +} + + //--------------------------------------------------------------------------- // // PROC P_BloodSplatter @@ -5859,6 +5944,20 @@ void P_BloodSplatter2 (const DVector3 &pos, AActor *originator, DAngle hitangle) } } +DEFINE_ACTION_FUNCTION(AActor, BloodSplatter) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + PARAM_ANGLE(dir); + PARAM_BOOL_DEF(axe); + if (axe) P_BloodSplatter2(DVector3(x, y, z), self, dir); + else P_BloodSplatter(DVector3(x, y, z), self, dir); + return 0; +} + + //--------------------------------------------------------------------------- // // PROC P_RipperBlood @@ -6078,6 +6177,20 @@ foundone: return plane == &sec->floorplane ? Terrains[terrainnum].IsLiquid : false; } +DEFINE_ACTION_FUNCTION(AActor, HitWater) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_POINTER(sec, sector_t); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + PARAM_BOOL_DEF(checkabove); + PARAM_BOOL_DEF(alert); + PARAM_BOOL_DEF(force); + ACTION_RETURN_BOOL(P_HitWater(self, sec, DVector3(x, y, z), checkabove, alert, force)); +} + + //--------------------------------------------------------------------------- // // FUNC P_HitFloor @@ -6284,6 +6397,15 @@ void P_PlaySpawnSound(AActor *missile, AActor *spawner) } } +DEFINE_ACTION_FUNCTION(AActor, PlaySpawnSound) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(missile, AActor); + P_PlaySpawnSound(missile, self); + return 0; +} + + static double GetDefaultSpeed(PClassActor *type) { if (type == NULL) @@ -6911,6 +7033,14 @@ bool AActor::IsHostile (AActor *other) return true; } +DEFINE_ACTION_FUNCTION(AActor, isHostile) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(other, AActor); + ACTION_RETURN_BOOL(self->IsHostile(other)); +} + + //========================================================================== // // AActor :: DoSpecialDamage @@ -7179,6 +7309,13 @@ double AActor::GetCameraHeight() const return GetClass()->CameraHeight == INT_MIN ? Height / 2 : GetClass()->CameraHeight; } +DEFINE_ACTION_FUNCTION(AActor, GetCameraHeight) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_FLOAT(self->GetCameraHeight()); +} + + DDropItem *AActor::GetDropItems() const { return GetClass()->DropItems; @@ -7196,6 +7333,13 @@ double AActor::GetGravity() const return level.gravity * Sector->gravity * Gravity * 0.00125; } +DEFINE_ACTION_FUNCTION(AActor, GetGravity) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_FLOAT(self->GetGravity()); +} + + // killough 11/98: // Whether an object is "sentient" or not. Used for environmental influences. // (left precisely the same as MBF even though it doesn't make much sense.) @@ -7240,14 +7384,17 @@ DEFINE_ACTION_FUNCTION(AActor, GetTag) void AActor::SetTag(const char *def) { - if (def == NULL || *def == 0) - { - Tag = NULL; - } - else - { - Tag = mStringPropertyData.Alloc(def); - } + if (def == NULL || *def == 0) Tag = nullptr; + else Tag = mStringPropertyData.Alloc(def); +} + +DEFINE_ACTION_FUNCTION(AActor, SetTag) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_STRING(def); + if (def.IsEmpty()) self->Tag = nullptr; + else self->Tag = self->mStringPropertyData.Alloc(def); + return 0; } @@ -7392,6 +7539,13 @@ DEFINE_ACTION_FUNCTION(AActor, Distance2D) ACTION_RETURN_FLOAT(self->Distance2D(other)); } +DEFINE_ACTION_FUNCTION(AActor, Distance3D) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(other, AActor); + ACTION_RETURN_FLOAT(self->Distance3D(other)); +} + DEFINE_ACTION_FUNCTION(AActor, AddZ) { PARAM_SELF_PROLOGUE(AActor); @@ -7455,6 +7609,17 @@ DEFINE_ACTION_FUNCTION(AActor, VelFromAngle) return 0; } +// This combines all 3 variations of the internal function +DEFINE_ACTION_FUNCTION(AActor, Vel3DFromAngle) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(speed); + PARAM_ANGLE(angle); + PARAM_ANGLE(pitch); + self->Vel3DFromAngle(pitch, angle, speed); + return 0; +} + // This combines all 3 variations of the internal function DEFINE_ACTION_FUNCTION(AActor, Thrust) { @@ -7619,6 +7784,12 @@ DEFINE_ACTION_FUNCTION(AActor, AccuracyFactor) ACTION_RETURN_FLOAT(self->AccuracyFactor()); } +DEFINE_ACTION_FUNCTION(AActor, CountsAsKill) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_FLOAT(self->CountsAsKill()); +} + //---------------------------------------------------------------------------- // // DropItem handling diff --git a/src/p_user.cpp b/src/p_user.cpp index 1ac60ba35..66437d430 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -1285,6 +1285,13 @@ bool APlayerPawn::ResetAirSupply (bool playgasp) return wasdrowning; } +DEFINE_ACTION_FUNCTION(APlayerPawn, ResetAirSupply) +{ + PARAM_SELF_PROLOGUE(APlayerPawn); + PARAM_BOOL_DEF(playgasp); + ACTION_RETURN_BOOL(self->ResetAirSupply(playgasp)); +} + //=========================================================================== // // Animations @@ -1293,14 +1300,22 @@ bool APlayerPawn::ResetAirSupply (bool playgasp) void APlayerPawn::PlayIdle () { - if (InStateSequence(state, SeeState)) - SetState (SpawnState); + IFVIRTUAL(APlayerPawn, PlayIdle) + { + VMValue params[1] = { (DObject*)this }; + VMFrameStack stack; + stack.Call(func, params, 1, nullptr, 0, nullptr); + } } void APlayerPawn::PlayRunning () { - if (InStateSequence(state, SpawnState) && SeeState != NULL) - SetState (SeeState); + IFVIRTUAL(APlayerPawn, PlayRunning) + { + VMValue params[1] = { (DObject*)this }; + VMFrameStack stack; + stack.Call(func, params, 1, nullptr, 0, nullptr); + } } void APlayerPawn::PlayAttacking () @@ -1323,10 +1338,6 @@ void APlayerPawn::PlayAttacking2 () } } -void APlayerPawn::ThrowPoisonBag () -{ -} - //=========================================================================== // // APlayerPawn :: GiveDefaultInventory diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 81b94b0f2..fd15b9491 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -2607,6 +2607,17 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) return false; } +DEFINE_ACTION_FUNCTION(DObject, S_ChangeMusic) +{ + PARAM_PROLOGUE; + PARAM_STRING(music); + PARAM_INT_DEF(order); + PARAM_BOOL(looping); + PARAM_BOOL(force); + ACTION_RETURN_BOOL(S_ChangeMusic(music, order, looping, force)); +} + + //========================================================================== // // S_RestartMusic diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 15c643047..5eebb7350 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -33,7 +33,7 @@ class Actor : Thinker native native vector2 Scale; native TextureID picnum; native double Alpha; - native color fillcolor; + native readonly color fillcolor; // must be set with SetShade to initialize correctly. native Sector CurSector; native double CeilingZ; native double FloorZ; @@ -276,10 +276,16 @@ class Actor : Thinker native } + native static int GetSpriteIndex(name sprt); native static double GetDefaultSpeed(class type); native static class GetSpawnableType(int spawnnum); native void RemoveFromHash(); + native void ChangeTid(int newtid); + native static int FindUniqueTid(int start = 0, int limit = 0); + native void SetShade(color col); + native string GetTag(string defstr = ""); + native void SetTag(string defstr = ""); native double GetBobOffset(double frac = 0); native void ClearCounters(); native bool GiveBody (int num, int max=0); @@ -299,6 +305,7 @@ class Actor : Thinker native native int SpawnHealth(); native void SetDamage(int dmg); native double Distance2D(Actor other); + native double Distance3D(Actor other); native void SetOrigin(vector3 newpos, bool moving); native void SetXYZ(vector3 newpos); native Actor GetPointer(int aaptr); @@ -328,7 +335,12 @@ class Actor : Thinker native void A_LightInverse() { if (player) player.extralight = 0x80000000; } native Actor OldSpawnMissile(Actor dest, class type, Actor owner = null); - native Actor SpawnPuff(class pufftype, vector3 pos, double hitdir, double particledir, int updown, int flags = 0, Actor vict = null); + native Actor SpawnPuff(class pufftype, vector3 pos, double hitdir, double particledir, int updown, int flags = 0, Actor victim = null); + native void SpawnBlood (Vector3 pos1, double dir, int damage); + native void BloodSplatter (Vector3 pos, double hitangle, bool axe = false); + native bool HitWater (sector sec, Vector3 pos, bool checkabove = false, bool alert = true, bool force = false); + native void PlaySpawnSound(Actor missile); + native bool CountsAsKill(); native bool Teleport(Vector3 pos, double angle, int flags); native void TraceBleed(int damage, Actor missile); @@ -338,13 +350,32 @@ class Actor : Thinker native native bool CheckMeleeRange(); native bool CheckMeleeRange2(); native int DamageMobj(Actor inflictor, Actor source, int damage, Name mod, int flags = 0, double angle = 0); + native void PoisonMobj (Actor inflictor, Actor source, int damage, int duration, int period, Name type); native double AimLineAttack(double angle, double distance, out FTranslatedLineTarget pLineTarget = null, double vrange = 0., int flags = 0, Actor target = null, Actor friender = null); native Actor, int LineAttack(double angle, double distance, double pitch, int damage, Name damageType, class pufftype, int flags = 0, out FTranslatedLineTarget victim = null); native bool CheckSight(Actor target, int flags = 0); + native bool IsVisible(Actor other, bool allaround, LookExParams params = null); native bool HitFriend(); native bool MonsterMove(); + + native void FindFloorCeiling(int flags = 0); + native double, double GetFriction(); + native bool, Actor TestMobjZ(bool quick = false); + native bool InStateSequence(State newstate, State basestate); + + bool TryWalk () + { + if (!MonsterMove ()) + { + return false; + } + movecount = random[TryWalk]() & 15; + return true; + } + native bool TryMove(vector2 newpos, int dropoff); native void NewChaseDir(); + native void RandomChaseDir(); native bool CheckMissileRange(); native bool SetState(state st, bool nofunction = false); native state FindState(statelabel st, bool exact = false); @@ -364,12 +395,17 @@ class Actor : Thinker native native vector2 Vec2Offset(double x, double y, bool absolute = false); native vector3 Vec2OffsetZ(double x, double y, double atz, bool absolute = false); native void VelFromAngle(double speed = 0, double angle = 0); + native void Vel3DFromAngle(double speed, double angle, double pitch); native void Thrust(double speed = 0, double angle = 0); native bool isFriend(Actor other); + native bool isHostile(Actor other); native void AdjustFloorClip(); native DropItem GetDropItems(); native void CopyFriendliness (Actor other, bool changeTarget, bool resetHealth = true); - native bool LookForPlayers(bool allaround); + native bool LookForMonsters(); + native bool LookForTid(bool allaround, LookExParams params = null); + native bool LookForEnemies(bool allaround, LookExParams params = null); + native bool LookForPlayers(bool allaround, LookExParams params = null); native bool TeleportMove(Vector3 pos, bool telefrag, bool modifyactor = true); native double DistanceBySpeed(Actor other, double speed); native name GetSpecies(); @@ -377,8 +413,13 @@ class Actor : Thinker native native void Howl(); native void DrawSplash (int count, double angle, int kind); native void GiveSecret(bool printmsg = true, bool playsound = true); + native void GetCameraHeight(); + native void GetGravity(); native bool CheckClass(class checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false); + native void AddInventory(Inventory inv); + native void RemoveInventory(Inventory inv); + native void ClearInventory(); native Inventory FindInventory(class itemtype, bool subclass = false); native Inventory GiveInventoryType(class itemtype); native Inventory DropInventory (Inventory item); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index b1d9526ce..6db88ab0a 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -9,6 +9,7 @@ class Object native native static vector3, int G_PickPlayerStart(int pnum, int flags = 0); native static int GameType(); native static void S_Sound (Sound sound_id, int channel, float volume = 1, float attenuation = ATTN_NORM); + native static bool S_ChangeMusic(String music_name, int order = 0, bool looping = true, bool force = false); native static void C_MidPrint(string fontname, string textlabel, bool bold = false); // always uses the stringtable. native static uint BAM(double angle); @@ -180,6 +181,40 @@ struct F3DFloor native struct Line native { + enum ELineFlags + { + ML_BLOCKING =0x00000001, // solid, is an obstacle + ML_BLOCKMONSTERS =0x00000002, // blocks monsters only + ML_TWOSIDED =0x00000004, // backside will not be present at all if not two sided + ML_DONTPEGTOP = 0x00000008, // upper texture unpegged + ML_DONTPEGBOTTOM = 0x00000010, // lower texture unpegged + ML_SECRET = 0x00000020, // don't map as two sided: IT'S A SECRET! + ML_SOUNDBLOCK = 0x00000040, // don't let sound cross two of these + ML_DONTDRAW = 0x00000080, // don't draw on the automap + ML_MAPPED = 0x00000100, // set if already drawn in automap + ML_REPEAT_SPECIAL = 0x00000200, // special is repeatable + ML_ADDTRANS = 0x00000400, // additive translucency (can only be set internally) + + // Extended flags + ML_MONSTERSCANACTIVATE = 0x00002000, // [RH] Monsters (as well as players) can activate the line + ML_BLOCK_PLAYERS = 0x00004000, + ML_BLOCKEVERYTHING = 0x00008000, // [RH] Line blocks everything + ML_ZONEBOUNDARY = 0x00010000, + ML_RAILING = 0x00020000, + ML_BLOCK_FLOATERS = 0x00040000, + ML_CLIP_MIDTEX = 0x00080000, // Automatic for every Strife line + ML_WRAP_MIDTEX = 0x00100000, + ML_3DMIDTEX = 0x00200000, + ML_CHECKSWITCHRANGE = 0x00400000, + ML_FIRSTSIDEONLY = 0x00800000, // activated only when crossed from front side + ML_BLOCKPROJECTILE = 0x01000000, + ML_BLOCKUSE = 0x02000000, // blocks all use actions through this line + ML_BLOCKSIGHT = 0x04000000, // blocks monster line of sight + ML_BLOCKHITSCAN = 0x08000000, // blocks hitscan attacks + ML_3DMIDTEX_IMPASS = 0x10000000, // [TP] if 3D midtex, behaves like a height-restricted ML_BLOCKING + }; + + //native readonly vertex v1, v2; // vertices, from v1 to v2 native readonly Vector2 delta; // precalculated v2 - v1 for side checking native uint flags; @@ -411,6 +446,59 @@ class Floor : Thinker native genFloorChg }; - native static bool CreateFloor(sector sec, EFloor floortype, line ln, double speed, double height = 0, int crush = -1, int change = 0, bool hexencrush = false, bool hereticlower = false); + native static bool CreateFloor(sector sec, EFloor floortype, line ln, double speed, double height = 0, int crush = -1, int change = 0, bool crushmode = false, bool hereticlower = false); +} + +class Ceiling : Thinker native +{ + enum ECeiling + { + ceilLowerByValue, + ceilRaiseByValue, + ceilMoveToValue, + ceilLowerToHighestFloor, + ceilLowerInstant, + ceilRaiseInstant, + ceilCrushAndRaise, + ceilLowerAndCrush, + ceil_placeholder, + ceilCrushRaiseAndStay, + ceilRaiseToNearest, + ceilLowerToLowest, + ceilLowerToFloor, + + // The following are only used by Generic_Ceiling + ceilRaiseToHighest, + ceilLowerToHighest, + ceilRaiseToLowest, + ceilLowerToNearest, + ceilRaiseToHighestFloor, + ceilRaiseToFloor, + ceilRaiseByTexture, + ceilLowerByTexture, + + genCeilingChg0, + genCeilingChgT, + genCeilingChg + } + + enum ECrushMode + { + crushDoom = 0, + crushHexen = 1, + crushSlowdown = 2 + } -} \ No newline at end of file + native bool CreateCeiling(sector sec, int type, line ln, double speed, double speed2, double height = 0, int crush = -1, int silent = 0, int change = 0, int crushmode = crushDoom); + +} + +struct LookExParams +{ + double Fov; + double minDist; + double maxDist; + double maxHeardist; + int flags; + State seestate; +}; diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index aa9b4a066..2f6dc4bc1 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -77,6 +77,18 @@ class PlayerPawn : Actor native Obituary "$OB_MPDEFAULT"; } + virtual void PlayIdle () + { + if (InStateSequence(CurState, SeeState)) + SetState (SpawnState); + } + + virtual void PlayRunning () + { + if (InStateSequence(CurState, SpawnState) && SeeState != NULL) + SetState (SeeState); + } + virtual void PlayAttacking () { if (MissileState != null) SetState (MissileState); @@ -92,6 +104,7 @@ class PlayerPawn : Actor native } native int GetMaxHealth(); + native bool ResetAirSupply (bool playgasp = false); } class PlayerChunk : PlayerPawn native From fb3bde0e0d0554e1f4f53eec1c25fc42d4f78cec Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 30 Nov 2016 01:39:06 +0100 Subject: [PATCH 174/185] - cleaned up and grouped the virtual function declarations in AActor to ensure that everything has been properly exported. - removed the native parts of SpecialBlastHandling. Since this is called from the script side and the only remaining native remnant was an empty function it's now 100% scripted. --- src/actor.h | 46 ++++++++++++++++++--------------- src/p_mobj.cpp | 15 ----------- wadsrc/static/zscript/actor.txt | 8 +++++- 3 files changed, 32 insertions(+), 37 deletions(-) diff --git a/src/actor.h b/src/actor.h index 0b6c58c19..18b128215 100644 --- a/src/actor.h +++ b/src/actor.h @@ -585,11 +585,13 @@ public: AActor () throw(); AActor (const AActor &other) throw(); AActor &operator= (const AActor &other); - void Destroy () override; ~AActor (); - void Serialize(FSerializer &arc); - void PostSerialize(); + virtual void Destroy() override; + virtual void Serialize(FSerializer &arc) override; + virtual void PostSerialize() override; + virtual void PostBeginPlay() override; // Called immediately before the actor's first tick + virtual void Tick() override; static AActor *StaticSpawn (PClassActor *type, const DVector3 &pos, replace_t allowreplacement, bool SpawningMapThing = false); @@ -614,18 +616,17 @@ public: virtual void BeginPlay(); // Called immediately after the actor is created void CallBeginPlay(); - virtual void PostBeginPlay(); // Called immediately before the actor's first tick + void LevelSpawned(); // Called after BeginPlay if this actor was spawned by the world virtual void HandleSpawnFlags(); // Translates SpawnFlags into in-game flags. virtual void MarkPrecacheSounds() const; // Marks sounds used by this actor for precaching. virtual void Activate (AActor *activator); - virtual void Deactivate (AActor *activator); void CallActivate(AActor *activator); - void CallDeactivate(AActor *activator); - virtual void Tick (); + virtual void Deactivate(AActor *activator); + void CallDeactivate(AActor *activator); // Called when actor dies virtual void Die (AActor *source, AActor *inflictor, int dmgflags = 0); @@ -640,6 +641,16 @@ public: virtual int TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FName damagetype); int CallTakeSpecialDamage(AActor *inflictor, AActor *source, int damage, FName damagetype); + // Actor had MF_SKULLFLY set and rammed into something + // Returns false to stop moving and true to keep moving + virtual bool Slam(AActor *victim); + bool CallSlam(AActor *victim); + + // Something just touched this actor. + virtual void Touch(AActor *toucher); + void CallTouch(AActor *toucher); + + // Centaurs and ettins squeal when electrocuted, poisoned, or "holy"-ed // Made a metadata property so no longer virtual void Howl (); @@ -650,32 +661,25 @@ public: // Called when an actor with MF_MISSILE and MF2_FLOORBOUNCE hits the floor bool FloorBounceMissile (secplane_t &plane); - // Called when an actor is to be reflected by a disc of repulsion. - // Returns true to continue normal blast processing. - virtual bool SpecialBlastHandling (AActor *source, double strength); - // Called by RoughBlockCheck bool IsOkayToAttack (AActor *target); // Plays the actor's ActiveSound if its voice isn't already making noise. void PlayActiveSound (); - // Actor had MF_SKULLFLY set and rammed into something - // Returns false to stop moving and true to keep moving - virtual bool Slam (AActor *victim); - bool CallSlam(AActor *victim); - // Called by PIT_CheckThing() and needed for some Hexen things. // Returns -1 for normal behavior, 0 to return false, and 1 to return true. // I'm not sure I like it this way, but it will do for now. + // (virtual on the script side only) int SpecialMissileHit (AActor *victim); // Returns true if it's okay to switch target to "other" after being attacked by it. - virtual bool OkayToSwitchTarget (AActor *other); + bool OkayToSwitchTarget (AActor *other); - // Something just touched this actor. - virtual void Touch (AActor *toucher); - void CallTouch(AActor *toucher); + // Note: Although some of the inventory functions are virtual, this + // is not exposed to scripts, as the only class overriding them is + // APlayerPawn for some specific handling for players. None of this + // should ever be overridden by custom classes. // Adds the item to this actor's inventory and sets its Owner. virtual void AddInventory (AInventory *item); @@ -760,7 +764,7 @@ public: DVector3 GetPortalTransition(double byoffset, sector_t **pSec = NULL); // What species am I? - virtual FName GetSpecies(); + FName GetSpecies(); // set translation void SetTranslation(FName trname); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index d099a8e77..78487185c 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3440,21 +3440,6 @@ bool AActor::CallSlam(AActor *thing) -bool AActor::SpecialBlastHandling (AActor *source, double strength) -{ - return true; -} - -// This only gets called from the script side so we do not need a native wrapper like for the other virtual methods. -// This will be removed, once all actors overriding this method are exported. -DEFINE_ACTION_FUNCTION(AActor, SpecialBlastHandling) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(source, AActor); - PARAM_FLOAT(strength); - ACTION_RETURN_BOOL(self->SpecialBlastHandling(source, strength)); -} - // This virtual method only exists on the script side. int AActor::SpecialMissileHit (AActor *victim) { diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 5eebb7350..9bf4fdcd9 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -267,9 +267,15 @@ class Actor : Thinker native virtual native int TakeSpecialDamage (Actor inflictor, Actor source, int damage, Name damagetype); virtual native void Die(Actor source, Actor inflictor, int dmgflags = 0); virtual native bool Slam(Actor victim); - virtual native bool SpecialBlastHandling (Actor source, double strength); virtual native void Touch(Actor toucher); + // Called when an actor is to be reflected by a disc of repulsion. + // Returns true to continue normal blast processing. + virtual bool SpecialBlastHandling (Actor source, double strength) // this is entirely on the script side with no native part at all. + { + return true; + } + virtual int SpecialMissileHit (Actor victim) // for this no native version exists { return -1; From 0cd6cec5319a8f1d671899d0b455d4b184f68470 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 30 Nov 2016 01:49:36 +0100 Subject: [PATCH 175/185] - scriptified the SectorFlagSetter. --- src/g_shared/a_skies.cpp | 15 --------------- wadsrc/static/zscript/shared/sharedmisc.txt | 8 +++++++- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/src/g_shared/a_skies.cpp b/src/g_shared/a_skies.cpp index d42324936..9e99d9368 100644 --- a/src/g_shared/a_skies.cpp +++ b/src/g_shared/a_skies.cpp @@ -177,18 +177,3 @@ void ASectorSilencer::Destroy () Super::Destroy (); } -class ASectorFlagSetter : public AActor -{ - DECLARE_CLASS (ASectorFlagSetter, AActor) -public: - void BeginPlay (); -}; - -IMPLEMENT_CLASS(ASectorFlagSetter, false, false) - -void ASectorFlagSetter::BeginPlay () -{ - Super::BeginPlay (); - Sector->Flags |= args[0]; -} - diff --git a/wadsrc/static/zscript/shared/sharedmisc.txt b/wadsrc/static/zscript/shared/sharedmisc.txt index 6da942e39..1b5ad4ee9 100644 --- a/wadsrc/static/zscript/shared/sharedmisc.txt +++ b/wadsrc/static/zscript/shared/sharedmisc.txt @@ -193,7 +193,7 @@ class RandomSpawner : Actor native // Sector flag setter ------------------------------------------------------ -class SectorFlagSetter : Actor native +class SectorFlagSetter : Actor { Default { @@ -202,6 +202,12 @@ class SectorFlagSetter : Actor native +DONTSPLASH RenderStyle "None"; } + + override void BeginPlay () + { + Super.BeginPlay (); + CurSector.Flags |= args[0]; + } } // Marker for sounds : Actor ------------------------------------------------------- From 661692062d9e5faa9fb303407abf2962147af459 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 30 Nov 2016 09:53:16 +0100 Subject: [PATCH 176/185] - fixed: FxIdentifier::Resolve checked all cases of what an identifier can be, even if it already found a proper match. --- src/scripting/codegeneration/codegen.cpp | 26 ++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 2eb6cfec6..42c526d0a 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -5521,6 +5521,7 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) self = self->Resolve(ctx); newex = ResolveMember(ctx, ctx.Function->Variants[0].SelfClass, self, ctx.Function->Variants[0].SelfClass); ABORT(newex); + goto foundit; } } @@ -5531,8 +5532,7 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) { ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as class constant\n", Identifier.GetChars()); newex = FxConstant::MakeConstant(sym, ScriptPosition); - delete this; - return newex->Resolve(ctx); + goto foundit; } // Do this check for ZScript as well, so that a clearer error message can be printed. MSG_OPTERROR will default to MSG_ERROR there. else if (ctx.Function->Variants[0].SelfClass != ctx.Class && sym->IsKindOf(RUNTIME_CLASS(PField))) @@ -5543,6 +5543,7 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) ABORT(newex); ScriptPosition.Message(MSG_OPTERROR, "Self pointer used in ambiguous context; VM execution may abort!"); ctx.Unsafe = true; + goto foundit; } else { @@ -5573,16 +5574,20 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) { ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as global constant\n", Identifier.GetChars()); newex = FxConstant::MakeConstant(sym, ScriptPosition); + goto foundit; } else if (sym->IsKindOf(RUNTIME_CLASS(PField))) { // internally defined global variable ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as global variable\n", Identifier.GetChars()); newex = new FxGlobalVariable(static_cast(sym), ScriptPosition); + goto foundit; } else { ScriptPosition.Message(MSG_ERROR, "Invalid global identifier '%s'\n", Identifier.GetChars()); + delete this; + return nullptr; } } @@ -5591,6 +5596,7 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) { ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as line special %d\n", Identifier.GetChars(), num); newex = new FxConstant(num, ScriptPosition); + goto foundit; } auto cvar = FindCVar(Identifier.GetChars(), nullptr); @@ -5603,14 +5609,14 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) return nullptr; } newex = new FxCVar(cvar, ScriptPosition); + goto foundit; } - if (newex == nullptr) - { - ScriptPosition.Message(MSG_ERROR, "Unknown identifier '%s'", Identifier.GetChars()); - delete this; - return nullptr; - } + ScriptPosition.Message(MSG_ERROR, "Unknown identifier '%s'", Identifier.GetChars()); + delete this; + return nullptr; + +foundit: delete this; return newex? newex->Resolve(ctx) : nullptr; } @@ -5733,6 +5739,10 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) // because the resulting value type would cause problems in nearly every other place where identifiers are being used. ccls = FindStructType(static_cast(Object)->Identifier); if (ccls != nullptr) static_cast(Object)->noglobal = true; + if (ccls && ccls->TypeName == FName("Tracer")) + { + int a = 0; + } } SAFE_RESOLVE(Object, ctx); From b1910effd6070eab476b1bd22cc67d4cd341f150 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 30 Nov 2016 09:54:37 +0100 Subject: [PATCH 177/185] - remove debug code. --- src/scripting/codegeneration/codegen.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 42c526d0a..7408573a0 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -5739,10 +5739,6 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) // because the resulting value type would cause problems in nearly every other place where identifiers are being used. ccls = FindStructType(static_cast(Object)->Identifier); if (ccls != nullptr) static_cast(Object)->noglobal = true; - if (ccls && ccls->TypeName == FName("Tracer")) - { - int a = 0; - } } SAFE_RESOLVE(Object, ctx); From 014e04ce820a67aae7cb925edb8917c7d7c3c450 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 30 Nov 2016 10:28:02 +0100 Subject: [PATCH 178/185] - copied inventory files to their own folder. It's about time this stuff is getting cleaned up seriously. Both a_pickups.cpp and a_artifacts.cpp are so overstuffed that it has become a chore finding stuff in there. --- src/CMakeLists.txt | 17 ++++++++++------- src/{g_shared => g_inventory}/a_armor.cpp | 0 src/{g_shared => g_inventory}/a_artifacts.cpp | 0 src/{g_shared => g_inventory}/a_artifacts.h | 0 src/{g_shared => g_inventory}/a_keys.cpp | 0 src/{g_shared => g_inventory}/a_keys.h | 0 src/{g_shared => g_inventory}/a_pickups.cpp | 0 src/{g_shared => g_inventory}/a_pickups.h | 0 src/{g_shared => g_inventory}/a_puzzleitems.cpp | 0 src/{g_shared => g_inventory}/a_weaponpiece.cpp | 0 src/{g_shared => g_inventory}/a_weaponpiece.h | 0 src/{g_shared => g_inventory}/a_weapons.cpp | 0 src/p_acs.cpp | 3 +-- 13 files changed, 11 insertions(+), 9 deletions(-) rename src/{g_shared => g_inventory}/a_armor.cpp (100%) rename src/{g_shared => g_inventory}/a_artifacts.cpp (100%) rename src/{g_shared => g_inventory}/a_artifacts.h (100%) rename src/{g_shared => g_inventory}/a_keys.cpp (100%) rename src/{g_shared => g_inventory}/a_keys.h (100%) rename src/{g_shared => g_inventory}/a_pickups.cpp (100%) rename src/{g_shared => g_inventory}/a_pickups.h (100%) rename src/{g_shared => g_inventory}/a_puzzleitems.cpp (100%) rename src/{g_shared => g_inventory}/a_weaponpiece.cpp (100%) rename src/{g_shared => g_inventory}/a_weaponpiece.h (100%) rename src/{g_shared => g_inventory}/a_weapons.cpp (100%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d1e90581c..be6c0ac73 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -829,6 +829,7 @@ file( GLOB HEADER_FILES ${EXTRA_HEADER_DIRS} fragglescript/*.h g_shared/*.h + g_inventory/*.h g_strife/*.h intermission/*.h menu/*.h @@ -1106,21 +1107,23 @@ set (PCH_SOURCES w_wad.cpp wi_stuff.cpp zstrformat.cpp + g_inventory/a_armor.cpp + g_inventory/a_artifacts.cpp + g_inventory/a_keys.cpp + g_inventory/a_pickups.cpp + g_inventory/a_puzzleitems.cpp + g_inventory/a_weaponpiece.cpp + g_inventory/a_weapons.cpp g_strife/strife_sbar.cpp g_shared/a_action.cpp - g_shared/a_armor.cpp - g_shared/a_artifacts.cpp g_shared/a_bridge.cpp g_shared/a_decals.cpp g_shared/a_fastprojectile.cpp g_shared/a_flashfader.cpp g_shared/a_fountain.cpp - g_shared/a_keys.cpp g_shared/a_lightning.cpp g_shared/a_morph.cpp g_shared/a_movingcamera.cpp - g_shared/a_pickups.cpp - g_shared/a_puzzleitems.cpp g_shared/a_quake.cpp g_shared/a_randomspawner.cpp g_shared/a_sectoraction.cpp @@ -1128,8 +1131,6 @@ set (PCH_SOURCES g_shared/a_soundenvironment.cpp g_shared/a_soundsequence.cpp g_shared/a_specialspot.cpp - g_shared/a_weaponpiece.cpp - g_shared/a_weapons.cpp g_shared/hudmessages.cpp g_shared/sbarinfo.cpp g_shared/sbar_mugshot.cpp @@ -1250,6 +1251,7 @@ target_link_libraries( zdoom ${ZDOOM_LIBS} gdtoa dumb lzma ) include_directories( . g_strife g_shared + g_inventory oplsynth sound textures @@ -1380,6 +1382,7 @@ source_group("Externak\\SFMT" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/s source_group("FraggleScript" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/fragglescript/.+") source_group("Games\\Strife Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_strife/.+") source_group("Intermission" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/intermission/.+") +source_group("Inventory" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_inventory/.+") source_group("Menu" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/menu/.+") source_group("Render Core\\Render Headers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/r_.+\\.h$") source_group("Render Core\\Render Sources" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/r_.+\\.cpp$") diff --git a/src/g_shared/a_armor.cpp b/src/g_inventory/a_armor.cpp similarity index 100% rename from src/g_shared/a_armor.cpp rename to src/g_inventory/a_armor.cpp diff --git a/src/g_shared/a_artifacts.cpp b/src/g_inventory/a_artifacts.cpp similarity index 100% rename from src/g_shared/a_artifacts.cpp rename to src/g_inventory/a_artifacts.cpp diff --git a/src/g_shared/a_artifacts.h b/src/g_inventory/a_artifacts.h similarity index 100% rename from src/g_shared/a_artifacts.h rename to src/g_inventory/a_artifacts.h diff --git a/src/g_shared/a_keys.cpp b/src/g_inventory/a_keys.cpp similarity index 100% rename from src/g_shared/a_keys.cpp rename to src/g_inventory/a_keys.cpp diff --git a/src/g_shared/a_keys.h b/src/g_inventory/a_keys.h similarity index 100% rename from src/g_shared/a_keys.h rename to src/g_inventory/a_keys.h diff --git a/src/g_shared/a_pickups.cpp b/src/g_inventory/a_pickups.cpp similarity index 100% rename from src/g_shared/a_pickups.cpp rename to src/g_inventory/a_pickups.cpp diff --git a/src/g_shared/a_pickups.h b/src/g_inventory/a_pickups.h similarity index 100% rename from src/g_shared/a_pickups.h rename to src/g_inventory/a_pickups.h diff --git a/src/g_shared/a_puzzleitems.cpp b/src/g_inventory/a_puzzleitems.cpp similarity index 100% rename from src/g_shared/a_puzzleitems.cpp rename to src/g_inventory/a_puzzleitems.cpp diff --git a/src/g_shared/a_weaponpiece.cpp b/src/g_inventory/a_weaponpiece.cpp similarity index 100% rename from src/g_shared/a_weaponpiece.cpp rename to src/g_inventory/a_weaponpiece.cpp diff --git a/src/g_shared/a_weaponpiece.h b/src/g_inventory/a_weaponpiece.h similarity index 100% rename from src/g_shared/a_weaponpiece.h rename to src/g_inventory/a_weaponpiece.h diff --git a/src/g_shared/a_weapons.cpp b/src/g_inventory/a_weapons.cpp similarity index 100% rename from src/g_shared/a_weapons.cpp rename to src/g_inventory/a_weapons.cpp diff --git a/src/p_acs.cpp b/src/p_acs.cpp index a71110674..96949dd96 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -82,8 +82,7 @@ #include "i_music.h" #include "serializer.h" #include "thingdef.h" - -#include "g_shared/a_pickups.h" +#include "a_pickups.h" extern FILE *Logfile; From 78fa0760797b034c885ff90fb7a3441523ed64ff Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 30 Nov 2016 10:55:03 +0100 Subject: [PATCH 179/185] - moved armor class declarations to their own file and added necessary #includes only to those files actually using them. - added copyright headers to a_armor.cpp and a_keys.cpp. --- src/ct_chat.cpp | 1 + src/d_dehacked.cpp | 1 + src/g_inventory/a_armor.cpp | 69 ++++++++++++++++++++- src/g_inventory/a_armor.h | 89 +++++++++++++++++++++++++++ src/g_inventory/a_keys.cpp | 64 +++++++++++++++++++ src/g_inventory/a_pickups.h | 85 ------------------------- src/g_shared/a_morph.cpp | 1 + src/g_shared/sbarinfo.cpp | 1 + src/g_shared/shared_hud.cpp | 1 + src/g_strife/strife_sbar.cpp | 1 + src/m_cheat.cpp | 1 + src/p_acs.cpp | 1 + src/p_actionfunctions.cpp | 1 + src/p_mobj.cpp | 1 + src/p_user.cpp | 1 + src/scripting/thingdef_properties.cpp | 1 + 16 files changed, 233 insertions(+), 86 deletions(-) create mode 100644 src/g_inventory/a_armor.h diff --git a/src/ct_chat.cpp b/src/ct_chat.cpp index 3c0994a3b..0a92a58b9 100644 --- a/src/ct_chat.cpp +++ b/src/ct_chat.cpp @@ -31,6 +31,7 @@ #include "templates.h" #include "d_net.h" #include "d_event.h" +#include "a_armor.h" #define QUEUESIZE 128 #define MESSAGESIZE 128 diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index e9e5a58d0..630586b0d 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -74,6 +74,7 @@ #include "info.h" #include "v_text.h" #include "vmbuilder.h" +#include "a_armor.h" // [SO] Just the way Randy said to do it :) // [RH] Made this CVAR_SERVERINFO diff --git a/src/g_inventory/a_armor.cpp b/src/g_inventory/a_armor.cpp index 25d45d35d..ebe8f49f6 100644 --- a/src/g_inventory/a_armor.cpp +++ b/src/g_inventory/a_armor.cpp @@ -1,8 +1,44 @@ +/* +** a_armor.cpp +** Implements all variations of armor objects +** +**--------------------------------------------------------------------------- +** Copyright 2002-2016 Randy Heit +** Copyright 2006-2016 Cheistoph Oelckers +** 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. +** +** 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 "info.h" #include "gi.h" #include "a_pickups.h" +#include "a_armor.h" #include "templates.h" #include "g_level.h" #include "d_player.h" @@ -15,6 +51,13 @@ IMPLEMENT_CLASS(ABasicArmorPickup, false, false) IMPLEMENT_CLASS(ABasicArmorBonus, false, false) IMPLEMENT_CLASS(AHexenArmor, false, false) +//=========================================================================== +// +// +// BasicArmor +// +// +//=========================================================================== DEFINE_FIELD(ABasicArmor, AbsorbCount) DEFINE_FIELD(ABasicArmor, SavePercent) @@ -198,6 +241,15 @@ void ABasicArmor::AbsorbDamage (int damage, FName damageType, int &newdamage) } } +//=========================================================================== +// +// +// BasicArmorPickup +// +// +//=========================================================================== + + DEFINE_FIELD(ABasicArmorPickup, SavePercent) DEFINE_FIELD(ABasicArmorPickup, MaxAbsorb) DEFINE_FIELD(ABasicArmorPickup, MaxFullAbsorb) @@ -291,10 +343,13 @@ bool ABasicArmorPickup::Use (bool pickup) //=========================================================================== // -// ABasicArmorBonus +// +// BasicArmorBonus +// // //=========================================================================== + DEFINE_FIELD(ABasicArmorBonus, SavePercent) DEFINE_FIELD(ABasicArmorBonus, MaxSaveAmount) DEFINE_FIELD(ABasicArmorBonus, MaxAbsorb) @@ -406,6 +461,13 @@ bool ABasicArmorBonus::Use (bool pickup) return true; } +//=========================================================================== +// +// +// HexenArmor +// +// +//=========================================================================== DEFINE_FIELD(AHexenArmor, Slots) DEFINE_FIELD(AHexenArmor, SlotsIncrement) @@ -573,6 +635,11 @@ void AHexenArmor::AbsorbDamage (int damage, FName damageType, int &newdamage) } } +//=========================================================================== +// +// AHexenArmor :: DepleteOrDestroy +// +//=========================================================================== void AHexenArmor::DepleteOrDestroy() { diff --git a/src/g_inventory/a_armor.h b/src/g_inventory/a_armor.h new file mode 100644 index 000000000..b7b2dad3e --- /dev/null +++ b/src/g_inventory/a_armor.h @@ -0,0 +1,89 @@ +#pragma once + +#include "a_pickups.h" + +// Armor absorbs some damage for the player. +class AArmor : public AInventory +{ + DECLARE_CLASS (AArmor, AInventory) +}; + +// Basic armor absorbs a specific percent of the damage. You should +// never pickup a BasicArmor. Instead, you pickup a BasicArmorPickup +// or BasicArmorBonus and those gives you BasicArmor when it activates. +class ABasicArmor : public AArmor +{ + DECLARE_CLASS (ABasicArmor, AArmor) +public: + + virtual void Serialize(FSerializer &arc); + virtual void Tick (); + virtual AInventory *CreateCopy (AActor *other); + virtual bool HandlePickup (AInventory *item); + virtual void AbsorbDamage (int damage, FName damageType, int &newdamage); + + int AbsorbCount; + double SavePercent; + int MaxAbsorb; + int MaxFullAbsorb; + int BonusCount; + FNameNoInit ArmorType; + int ActualSaveAmount; +}; + +// BasicArmorPickup replaces the armor you have. +class ABasicArmorPickup : public AArmor +{ + DECLARE_CLASS (ABasicArmorPickup, AArmor) +public: + + virtual void Serialize(FSerializer &arc); + virtual AInventory *CreateCopy (AActor *other); + virtual bool Use (bool pickup); + + double SavePercent; + int MaxAbsorb; + int MaxFullAbsorb; + int SaveAmount; +}; + +// BasicArmorBonus adds to the armor you have. +class ABasicArmorBonus : public AArmor +{ + DECLARE_CLASS (ABasicArmorBonus, AArmor) +public: + + virtual void Serialize(FSerializer &arc); + virtual AInventory *CreateCopy (AActor *other); + virtual bool Use (bool pickup); + + double SavePercent; // The default, for when you don't already have armor + int MaxSaveAmount; + int MaxAbsorb; + int MaxFullAbsorb; + int SaveAmount; + int BonusCount; + int BonusMax; +}; + +// Hexen armor consists of four separate armor types plus a conceptual armor +// type (the player himself) that work together as a single armor. +class AHexenArmor : public AArmor +{ + DECLARE_CLASS (AHexenArmor, AArmor) +public: + + virtual void Serialize(FSerializer &arc); + virtual AInventory *CreateCopy (AActor *other); + virtual AInventory *CreateTossable (); + virtual bool HandlePickup (AInventory *item); + virtual void AbsorbDamage (int damage, FName damageType, int &newdamage); + void DepleteOrDestroy(); + + double Slots[5]; + double SlotsIncrement[4]; + +protected: + bool AddArmorToSlot (AActor *actor, int slot, int amount); +}; + diff --git a/src/g_inventory/a_keys.cpp b/src/g_inventory/a_keys.cpp index fc9363be5..a2b5b308a 100644 --- a/src/g_inventory/a_keys.cpp +++ b/src/g_inventory/a_keys.cpp @@ -1,3 +1,36 @@ +/* +** a_keys.cpp +** Implements all keys and associated data +** +**--------------------------------------------------------------------------- +** Copyright 2005-2016 Cheistoph Oelckers +** 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. +** +** 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 "a_keys.h" #include "tarray.h" #include "gi.h" @@ -12,6 +45,18 @@ #include "v_font.h" +//=========================================================================== +// +// Data for the LOCKDEFS +// +//=========================================================================== + + +//=========================================================================== +// +// +//=========================================================================== + struct OneKey { PClassActor *key; @@ -45,6 +90,11 @@ struct OneKey } }; +//=========================================================================== +// +// +//=========================================================================== + struct Keygroup { TArray anykeylist; @@ -59,6 +109,11 @@ struct Keygroup } }; +//=========================================================================== +// +// +//=========================================================================== + struct Lock { TArray keylist; @@ -100,6 +155,10 @@ struct Lock } }; +//=========================================================================== +// +// +//=========================================================================== static Lock *locks[256]; // all valid locks static bool keysdone=false; // have the locks been initialized? @@ -490,6 +549,11 @@ bool AKey::HandlePickup (AInventory *item) return false; } +//=========================================================================== +// +// +//=========================================================================== + bool AKey::ShouldStay () { return !!multiplayer; diff --git a/src/g_inventory/a_pickups.h b/src/g_inventory/a_pickups.h index 48afac226..56caabf3c 100644 --- a/src/g_inventory/a_pickups.h +++ b/src/g_inventory/a_pickups.h @@ -458,91 +458,6 @@ public: virtual bool Use (bool pickup); }; -// Armor absorbs some damage for the player. -class AArmor : public AInventory -{ - DECLARE_CLASS (AArmor, AInventory) -}; - -// Basic armor absorbs a specific percent of the damage. You should -// never pickup a BasicArmor. Instead, you pickup a BasicArmorPickup -// or BasicArmorBonus and those gives you BasicArmor when it activates. -class ABasicArmor : public AArmor -{ - DECLARE_CLASS (ABasicArmor, AArmor) -public: - - virtual void Serialize(FSerializer &arc); - virtual void Tick (); - virtual AInventory *CreateCopy (AActor *other); - virtual bool HandlePickup (AInventory *item); - virtual void AbsorbDamage (int damage, FName damageType, int &newdamage); - - int AbsorbCount; - double SavePercent; - int MaxAbsorb; - int MaxFullAbsorb; - int BonusCount; - FNameNoInit ArmorType; - int ActualSaveAmount; -}; - -// BasicArmorPickup replaces the armor you have. -class ABasicArmorPickup : public AArmor -{ - DECLARE_CLASS (ABasicArmorPickup, AArmor) -public: - - virtual void Serialize(FSerializer &arc); - virtual AInventory *CreateCopy (AActor *other); - virtual bool Use (bool pickup); - - double SavePercent; - int MaxAbsorb; - int MaxFullAbsorb; - int SaveAmount; -}; - -// BasicArmorBonus adds to the armor you have. -class ABasicArmorBonus : public AArmor -{ - DECLARE_CLASS (ABasicArmorBonus, AArmor) -public: - - virtual void Serialize(FSerializer &arc); - virtual AInventory *CreateCopy (AActor *other); - virtual bool Use (bool pickup); - - double SavePercent; // The default, for when you don't already have armor - int MaxSaveAmount; - int MaxAbsorb; - int MaxFullAbsorb; - int SaveAmount; - int BonusCount; - int BonusMax; -}; - -// Hexen armor consists of four separate armor types plus a conceptual armor -// type (the player himself) that work together as a single armor. -class AHexenArmor : public AArmor -{ - DECLARE_CLASS (AHexenArmor, AArmor) -public: - - virtual void Serialize(FSerializer &arc); - virtual AInventory *CreateCopy (AActor *other); - virtual AInventory *CreateTossable (); - virtual bool HandlePickup (AInventory *item); - virtual void AbsorbDamage (int damage, FName damageType, int &newdamage); - void DepleteOrDestroy(); - - double Slots[5]; - double SlotsIncrement[4]; - -protected: - bool AddArmorToSlot (AActor *actor, int slot, int amount); -}; - // PuzzleItems work in conjunction with the UsePuzzleItem special class PClassPuzzleItem : public PClassInventory { diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 2f986c201..ad15cb081 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -14,6 +14,7 @@ #include "serializer.h" #include "p_enemy.h" #include "d_player.h" +#include "a_armor.h" #include "r_data/sprites.h" static FRandom pr_morphmonst ("MorphMonster"); diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index 4bb9d5b81..f2852919d 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -45,6 +45,7 @@ #include "st_stuff.h" #include "m_swap.h" #include "a_keys.h" +#include "a_armor.h" #include "templates.h" #include "i_system.h" #include "sbarinfo.h" diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 4733c6e41..c6e12918d 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -43,6 +43,7 @@ #include "c_cvars.h" #include "w_wad.h" #include "a_keys.h" +#include "a_armor.h" #include "sbar.h" #include "sc_man.h" #include "templates.h" diff --git a/src/g_strife/strife_sbar.cpp b/src/g_strife/strife_sbar.cpp index c12c7a723..3a242f80c 100644 --- a/src/g_strife/strife_sbar.cpp +++ b/src/g_strife/strife_sbar.cpp @@ -12,6 +12,7 @@ #include "m_swap.h" #include "templates.h" #include "a_keys.h" +#include "a_armor.h" #include "gi.h" #include "g_level.h" #include "colormatcher.h" diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index f5cd56848..6bd6b3862 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -47,6 +47,7 @@ #include "serializer.h" #include "r_utility.h" #include "a_morph.h" +#include "a_armor.h" // [RH] Actually handle the cheat. The cheat code in st_stuff.c now just // writes some bytes to the network data stream, and the network code diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 96949dd96..93d0cd45b 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -83,6 +83,7 @@ #include "serializer.h" #include "thingdef.h" #include "a_pickups.h" +#include "a_armor.h" extern FILE *Logfile; diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 99d38b2c1..8981538e7 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -78,6 +78,7 @@ #include "v_text.h" #include "thingdef.h" #include "math/cmath.h" +#include "a_armor.h" AActor *SingleActorFromTID(int tid, AActor *defactor); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 78487185c..7c7d97cf2 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -69,6 +69,7 @@ #include "thingdef.h" #include "d_player.h" #include "virtual.h" +#include "a_armor.h" // MACROS ------------------------------------------------------------------ diff --git a/src/p_user.cpp b/src/p_user.cpp index 66437d430..e92b560db 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -59,6 +59,7 @@ #include "a_morph.h" #include "p_spec.h" #include "virtual.h" +#include "a_armor.h" static FRandom pr_skullpop ("SkullPop"); diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index cfadc53bf..e85b6a1d9 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -46,6 +46,7 @@ #include "templates.h" #include "r_defs.h" #include "a_pickups.h" +#include "a_armor.h" #include "s_sound.h" #include "cmdlib.h" #include "p_lnspec.h" From 229c55ce61b5be24fc7d2a489017d988c711d67d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 30 Nov 2016 12:24:50 +0100 Subject: [PATCH 180/185] - moved ammo to its own file, including the backpack. - moved weapon declarations to their own header. --- src/CMakeLists.txt | 1 + src/b_think.cpp | 1 + src/d_dehacked.cpp | 1 + src/d_player.h | 1 + src/fragglescript/t_func.cpp | 1 + src/g_inventory/a_ammo.cpp | 381 ++++++++++++++++++++++++++ src/g_inventory/a_ammo.h | 47 ++++ src/g_inventory/a_pickups.cpp | 343 +---------------------- src/g_inventory/a_pickups.h | 268 ------------------ src/g_inventory/a_puzzleitems.cpp | 64 ++++- src/g_inventory/a_weaponpiece.cpp | 63 +++++ src/g_inventory/a_weaponpiece.h | 1 + src/g_inventory/a_weapons.cpp | 36 +++ src/g_inventory/a_weapons.h | 230 ++++++++++++++++ src/g_shared/sbarinfo.cpp | 1 + src/g_shared/shared_hud.cpp | 1 + src/g_strife/strife_sbar.cpp | 1 + src/m_cheat.cpp | 1 + src/p_acs.cpp | 1 + src/p_enemy.cpp | 1 + src/p_mobj.cpp | 1 + src/p_user.cpp | 1 + src/scripting/thingdef_properties.cpp | 1 + 23 files changed, 836 insertions(+), 611 deletions(-) create mode 100644 src/g_inventory/a_ammo.cpp create mode 100644 src/g_inventory/a_ammo.h create mode 100644 src/g_inventory/a_weapons.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index be6c0ac73..126554496 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1107,6 +1107,7 @@ set (PCH_SOURCES w_wad.cpp wi_stuff.cpp zstrformat.cpp + g_inventory/a_ammo.cpp g_inventory/a_armor.cpp g_inventory/a_artifacts.cpp g_inventory/a_keys.cpp diff --git a/src/b_think.cpp b/src/b_think.cpp index d097db864..7dd196622 100644 --- a/src/b_think.cpp +++ b/src/b_think.cpp @@ -21,6 +21,7 @@ #include "d_event.h" #include "d_player.h" #include "vectors.h" +#include "a_ammo.h" static FRandom pr_botmove ("BotMove"); diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 630586b0d..62daefcaa 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -75,6 +75,7 @@ #include "v_text.h" #include "vmbuilder.h" #include "a_armor.h" +#include "a_ammo.h" // [SO] Just the way Randy said to do it :) // [RH] Made this CVAR_SERVERINFO diff --git a/src/d_player.h b/src/d_player.h index 95a288ebd..4cdfb8b79 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -30,6 +30,7 @@ #include "doomstat.h" #include "a_artifacts.h" +#include "a_weapons.h" // The player data structure depends on a number // of other structs: items (internal inventory), diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index 7266daf40..6b0059981 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -69,6 +69,7 @@ #include "p_setup.h" #include "p_spec.h" #include "r_utility.h" +#include "a_ammo.h" #include "math/cmath.h" static FRandom pr_script("FScript"); diff --git a/src/g_inventory/a_ammo.cpp b/src/g_inventory/a_ammo.cpp new file mode 100644 index 000000000..23a922187 --- /dev/null +++ b/src/g_inventory/a_ammo.cpp @@ -0,0 +1,381 @@ +/* +** a_ammo.cpp +** Implements ammo and backpack items. +** +**--------------------------------------------------------------------------- +** Copyright 2000-2016 Randy Heit +** Copyright 2006-2016 Cheistoph Oelckers +** 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. +** +** 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 "c_dispatch.h" +#include "d_player.h" +#include "serializer.h" + +IMPLEMENT_CLASS(PClassAmmo, false, false) + +PClassAmmo::PClassAmmo() +{ + DropAmount = 0; +} + +void PClassAmmo::DeriveData(PClass *newclass) +{ + assert(newclass->IsKindOf(RUNTIME_CLASS(PClassAmmo))); + Super::DeriveData(newclass); + PClassAmmo *newc = static_cast(newclass); + + newc->DropAmount = DropAmount; +} + +IMPLEMENT_CLASS(AAmmo, false, false) + +DEFINE_FIELD(AAmmo, BackpackAmount) +DEFINE_FIELD(AAmmo, BackpackMaxAmount) + +//=========================================================================== +// +// AAmmo :: Serialize +// +//=========================================================================== + +void AAmmo::Serialize(FSerializer &arc) +{ + Super::Serialize (arc); + auto def = (AAmmo*)GetDefault(); + arc("backpackamount", BackpackAmount, def->BackpackAmount) + ("backpackmaxamount", BackpackMaxAmount, def->BackpackMaxAmount); +} + +//=========================================================================== +// +// AAmmo :: GetParentAmmo +// +// Returns the least-derived ammo type that this ammo is a descendant of. +// That is, if this ammo is an immediate subclass of Ammo, then this ammo's +// type is returned. If this ammo's superclass is not Ammo, then this +// function travels up the inheritance chain until it finds a type that is +// an immediate subclass of Ammo and returns that. +// +// The intent of this is that all unique ammo types will be immediate +// subclasses of Ammo. To make different pickups with different ammo amounts, +// you subclass the type of ammo you want a different amount for and edit +// that. +// +//=========================================================================== + +PClassActor *AAmmo::GetParentAmmo () const +{ + PClass *type = GetClass(); + + while (type->ParentClass != RUNTIME_CLASS(AAmmo) && type->ParentClass != NULL) + { + type = type->ParentClass; + } + return static_cast(type); +} + +//=========================================================================== +// +// AAmmo :: HandlePickup +// +//=========================================================================== +EXTERN_CVAR(Bool, sv_unlimited_pickup) + +bool AAmmo::HandlePickup (AInventory *item) +{ + if (GetClass() == item->GetClass() || + (item->IsKindOf (RUNTIME_CLASS(AAmmo)) && static_cast(item)->GetParentAmmo() == GetClass())) + { + if (Amount < MaxAmount || sv_unlimited_pickup) + { + int receiving = item->Amount; + + if (!(item->ItemFlags & IF_IGNORESKILL)) + { // extra ammo in baby mode and nightmare mode + receiving = int(receiving * G_SkillProperty(SKILLP_AmmoFactor)); + } + int oldamount = Amount; + + if (Amount > 0 && Amount + receiving < 0) + { + Amount = 0x7fffffff; + } + else + { + Amount += receiving; + } + if (Amount > MaxAmount && !sv_unlimited_pickup) + { + Amount = MaxAmount; + } + item->ItemFlags |= IF_PICKUPGOOD; + + // If the player previously had this ammo but ran out, possibly switch + // to a weapon that uses it, but only if the player doesn't already + // have a weapon pending. + + assert (Owner != NULL); + + if (oldamount == 0 && Owner != NULL && Owner->player != NULL) + { + barrier_cast(Owner)->CheckWeaponSwitch(GetClass()); + } + } + return true; + } + return false; +} + +//=========================================================================== +// +// AAmmo :: CreateCopy +// +//=========================================================================== + +AInventory *AAmmo::CreateCopy (AActor *other) +{ + AInventory *copy; + int amount = Amount; + + // extra ammo in baby mode and nightmare mode + if (!(ItemFlags&IF_IGNORESKILL)) + { + amount = int(amount * G_SkillProperty(SKILLP_AmmoFactor)); + } + + if (GetClass()->ParentClass != RUNTIME_CLASS(AAmmo) && GetClass() != RUNTIME_CLASS(AAmmo)) + { + PClassActor *type = GetParentAmmo(); + if (!GoAway ()) + { + Destroy (); + } + + copy = static_cast(Spawn (type)); + copy->Amount = amount; + copy->BecomeItem (); + } + else + { + copy = Super::CreateCopy (other); + copy->Amount = amount; + } + if (copy->Amount > copy->MaxAmount) + { // Don't pick up more ammo than you're supposed to be able to carry. + copy->Amount = copy->MaxAmount; + } + return copy; +} + +//=========================================================================== +// +// AAmmo :: CreateTossable +// +//=========================================================================== + +AInventory *AAmmo::CreateTossable() +{ + AInventory *copy = Super::CreateTossable(); + if (copy != NULL) + { // Do not increase ammo by dropping it and picking it back up at + // certain skill levels. + copy->ItemFlags |= IF_IGNORESKILL; + } + return copy; +} + + +// Backpack ----------------------------------------------------------------- + +IMPLEMENT_CLASS(ABackpackItem, false, false) + +DEFINE_FIELD(ABackpackItem, bDepleted) + +//=========================================================================== +// +// ABackpackItem :: Serialize +// +//=========================================================================== + +void ABackpackItem::Serialize(FSerializer &arc) +{ + Super::Serialize (arc); + auto def = (ABackpackItem*)GetDefault(); + arc("bdepleted", bDepleted, def->bDepleted); +} + +//=========================================================================== +// +// ABackpackItem :: CreateCopy +// +// A backpack is being added to a player who doesn't yet have one. Give them +// every kind of ammo, and increase their max amounts. +// +//=========================================================================== + +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 < PClassActor::AllActorClasses.Size(); ++i) + { + PClass *type = PClassActor::AllActorClasses[i]; + + if (type->ParentClass == RUNTIME_CLASS(AAmmo)) + { + 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)) + { + amount = int(amount * G_SkillProperty(SKILLP_AmmoFactor)); + } + if (amount < 0) amount = 0; + if (ammo == NULL) + { // The player did not have the ammo. Add it. + ammo = static_cast(Spawn(atype)); + ammo->Amount = bDepleted ? 0 : amount; + if (ammo->BackpackMaxAmount > ammo->MaxAmount) + { + ammo->MaxAmount = ammo->BackpackMaxAmount; + } + if (ammo->Amount > ammo->MaxAmount) + { + ammo->Amount = ammo->MaxAmount; + } + ammo->AttachToOwner (other); + } + else + { // The player had the ammo. Give some more. + if (ammo->MaxAmount < ammo->BackpackMaxAmount) + { + ammo->MaxAmount = ammo->BackpackMaxAmount; + } + if (!bDepleted && ammo->Amount < ammo->MaxAmount) + { + ammo->Amount += amount; + if (ammo->Amount > ammo->MaxAmount) + { + ammo->Amount = ammo->MaxAmount; + } + } + } + } + } + return Super::CreateCopy (other); +} + +//=========================================================================== +// +// ABackpackItem :: HandlePickup +// +// When the player picks up another backpack, just give them more ammo. +// +//=========================================================================== + +bool ABackpackItem::HandlePickup (AInventory *item) +{ + // Since you already have a backpack, that means you already have every + // kind of ammo in your inventory, so we don't need to look at the + // entire PClass list to discover what kinds of ammo exist, and we don't + // have to alter the MaxAmount either. + if (item->IsKindOf (RUNTIME_CLASS(ABackpackItem))) + { + for (AInventory *probe = Owner->Inventory; probe != NULL; probe = probe->Inventory) + { + if (probe->GetClass()->ParentClass == RUNTIME_CLASS(AAmmo)) + { + if (probe->Amount < probe->MaxAmount || sv_unlimited_pickup) + { + int amount = static_cast(probe->GetDefault())->BackpackAmount; + // extra ammo in baby mode and nightmare mode + if (!(item->ItemFlags&IF_IGNORESKILL)) + { + amount = int(amount * G_SkillProperty(SKILLP_AmmoFactor)); + } + probe->Amount += amount; + if (probe->Amount > probe->MaxAmount && !sv_unlimited_pickup) + { + probe->Amount = probe->MaxAmount; + } + } + } + } + // The pickup always succeeds, even if you didn't get anything + item->ItemFlags |= IF_PICKUPGOOD; + return true; + } + return false; +} + +//=========================================================================== +// +// ABackpackItem :: CreateTossable +// +// The tossed backpack must not give out any more ammo, otherwise a player +// could cheat by dropping their backpack and picking it up for more ammo. +// +//=========================================================================== + +AInventory *ABackpackItem::CreateTossable () +{ + ABackpackItem *pack = static_cast(Super::CreateTossable()); + if (pack != NULL) + { + pack->bDepleted = true; + } + return pack; +} + +//=========================================================================== +// +// ABackpackItem :: DetachFromOwner +// +//=========================================================================== + +void ABackpackItem::DetachFromOwner () +{ + // When removing a backpack, drop the player's ammo maximums to normal + AInventory *item; + + for (item = Owner->Inventory; item != NULL; item = item->Inventory) + { + if (item->GetClass()->ParentClass == RUNTIME_CLASS(AAmmo) && + item->MaxAmount == static_cast(item)->BackpackMaxAmount) + { + item->MaxAmount = static_cast(item->GetDefault())->MaxAmount; + if (item->Amount > item->MaxAmount) + { + item->Amount = item->MaxAmount; + } + } + } +} + diff --git a/src/g_inventory/a_ammo.h b/src/g_inventory/a_ammo.h new file mode 100644 index 000000000..fe5e1759e --- /dev/null +++ b/src/g_inventory/a_ammo.h @@ -0,0 +1,47 @@ +#pragma once +#include "a_pickups.h" + +// Ammo: Something a weapon needs to operate +class PClassAmmo : public PClassInventory +{ + DECLARE_CLASS(PClassAmmo, PClassInventory) +protected: + virtual void DeriveData(PClass *newclass); +public: + PClassAmmo(); + + int DropAmount; // Specifies the amount for a dropped ammo item. +}; + +class AAmmo : public AInventory +{ + DECLARE_CLASS_WITH_META(AAmmo, AInventory, PClassAmmo) +public: + + void Serialize(FSerializer &arc); + AInventory *CreateCopy (AActor *other); + bool HandlePickup (AInventory *item); + PClassActor *GetParentAmmo () const; + AInventory *CreateTossable (); + + int BackpackAmount, BackpackMaxAmount; +}; + + +// A backpack gives you one clip of each ammo and doubles your +// normal maximum ammo amounts. +class ABackpackItem : public AInventory +{ + DECLARE_CLASS (ABackpackItem, AInventory) +public: + + void Serialize(FSerializer &arc); + bool HandlePickup (AInventory *item); + AInventory *CreateCopy (AActor *other); + AInventory *CreateTossable (); + void DetachFromOwner (); + + bool bDepleted; +}; + + diff --git a/src/g_inventory/a_pickups.cpp b/src/g_inventory/a_pickups.cpp index ad843667a..84b8b366f 100644 --- a/src/g_inventory/a_pickups.cpp +++ b/src/g_inventory/a_pickups.cpp @@ -20,8 +20,10 @@ #include "p_spec.h" #include "serializer.h" #include "virtual.h" +#include "a_ammo.h" static FRandom pr_restore ("RestorePos"); +EXTERN_CVAR(Bool, sv_unlimited_pickup) IMPLEMENT_CLASS(PClassInventory, false, false) @@ -70,179 +72,6 @@ void PClassInventory::Finalize(FStateDefinitions &statedef) ((AActor*)Defaults)->flags |= MF_SPECIAL; } -IMPLEMENT_CLASS(PClassAmmo, false, false) - -PClassAmmo::PClassAmmo() -{ - DropAmount = 0; -} - -void PClassAmmo::DeriveData(PClass *newclass) -{ - assert(newclass->IsKindOf(RUNTIME_CLASS(PClassAmmo))); - Super::DeriveData(newclass); - PClassAmmo *newc = static_cast(newclass); - - newc->DropAmount = DropAmount; -} - -IMPLEMENT_CLASS(AAmmo, false, false) - -DEFINE_FIELD(AAmmo, BackpackAmount) -DEFINE_FIELD(AAmmo, BackpackMaxAmount) - -//=========================================================================== -// -// AAmmo :: Serialize -// -//=========================================================================== - -void AAmmo::Serialize(FSerializer &arc) -{ - Super::Serialize (arc); - auto def = (AAmmo*)GetDefault(); - arc("backpackamount", BackpackAmount, def->BackpackAmount) - ("backpackmaxamount", BackpackMaxAmount, def->BackpackMaxAmount); -} - -//=========================================================================== -// -// AAmmo :: GetParentAmmo -// -// Returns the least-derived ammo type that this ammo is a descendant of. -// That is, if this ammo is an immediate subclass of Ammo, then this ammo's -// type is returned. If this ammo's superclass is not Ammo, then this -// function travels up the inheritance chain until it finds a type that is -// an immediate subclass of Ammo and returns that. -// -// The intent of this is that all unique ammo types will be immediate -// subclasses of Ammo. To make different pickups with different ammo amounts, -// you subclass the type of ammo you want a different amount for and edit -// that. -// -//=========================================================================== - -PClassActor *AAmmo::GetParentAmmo () const -{ - PClass *type = GetClass(); - - while (type->ParentClass != RUNTIME_CLASS(AAmmo) && type->ParentClass != NULL) - { - type = type->ParentClass; - } - return static_cast(type); -} - -//=========================================================================== -// -// AAmmo :: HandlePickup -// -//=========================================================================== -EXTERN_CVAR(Bool, sv_unlimited_pickup) - -bool AAmmo::HandlePickup (AInventory *item) -{ - if (GetClass() == item->GetClass() || - (item->IsKindOf (RUNTIME_CLASS(AAmmo)) && static_cast(item)->GetParentAmmo() == GetClass())) - { - if (Amount < MaxAmount || sv_unlimited_pickup) - { - int receiving = item->Amount; - - if (!(item->ItemFlags & IF_IGNORESKILL)) - { // extra ammo in baby mode and nightmare mode - receiving = int(receiving * G_SkillProperty(SKILLP_AmmoFactor)); - } - int oldamount = Amount; - - if (Amount > 0 && Amount + receiving < 0) - { - Amount = 0x7fffffff; - } - else - { - Amount += receiving; - } - if (Amount > MaxAmount && !sv_unlimited_pickup) - { - Amount = MaxAmount; - } - item->ItemFlags |= IF_PICKUPGOOD; - - // If the player previously had this ammo but ran out, possibly switch - // to a weapon that uses it, but only if the player doesn't already - // have a weapon pending. - - assert (Owner != NULL); - - if (oldamount == 0 && Owner != NULL && Owner->player != NULL) - { - barrier_cast(Owner)->CheckWeaponSwitch(GetClass()); - } - } - return true; - } - return false; -} - -//=========================================================================== -// -// AAmmo :: CreateCopy -// -//=========================================================================== - -AInventory *AAmmo::CreateCopy (AActor *other) -{ - AInventory *copy; - int amount = Amount; - - // extra ammo in baby mode and nightmare mode - if (!(ItemFlags&IF_IGNORESKILL)) - { - amount = int(amount * G_SkillProperty(SKILLP_AmmoFactor)); - } - - if (GetClass()->ParentClass != RUNTIME_CLASS(AAmmo) && GetClass() != RUNTIME_CLASS(AAmmo)) - { - PClassActor *type = GetParentAmmo(); - if (!GoAway ()) - { - Destroy (); - } - - copy = static_cast(Spawn (type)); - copy->Amount = amount; - copy->BecomeItem (); - } - else - { - copy = Super::CreateCopy (other); - copy->Amount = amount; - } - if (copy->Amount > copy->MaxAmount) - { // Don't pick up more ammo than you're supposed to be able to carry. - copy->Amount = copy->MaxAmount; - } - return copy; -} - -//=========================================================================== -// -// AAmmo :: CreateTossable -// -//=========================================================================== - -AInventory *AAmmo::CreateTossable() -{ - AInventory *copy = Super::CreateTossable(); - if (copy != NULL) - { // Do not increase ammo by dropping it and picking it back up at - // certain skill levels. - copy->ItemFlags |= IF_IGNORESKILL; - } - return copy; -} - //--------------------------------------------------------------------------- // // FUNC P_GiveBody @@ -2068,174 +1897,6 @@ void AHealthPickup::Serialize(FSerializer &arc) arc("autousemode", autousemode, def->autousemode); } -// Backpack ----------------------------------------------------------------- - -IMPLEMENT_CLASS(ABackpackItem, false, false) - -DEFINE_FIELD(ABackpackItem, bDepleted) - -//=========================================================================== -// -// ABackpackItem :: Serialize -// -//=========================================================================== - -void ABackpackItem::Serialize(FSerializer &arc) -{ - Super::Serialize (arc); - auto def = (ABackpackItem*)GetDefault(); - arc("bdepleted", bDepleted, def->bDepleted); -} - -//=========================================================================== -// -// ABackpackItem :: CreateCopy -// -// A backpack is being added to a player who doesn't yet have one. Give them -// every kind of ammo, and increase their max amounts. -// -//=========================================================================== - -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 < PClassActor::AllActorClasses.Size(); ++i) - { - PClass *type = PClassActor::AllActorClasses[i]; - - if (type->ParentClass == RUNTIME_CLASS(AAmmo)) - { - 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)) - { - amount = int(amount * G_SkillProperty(SKILLP_AmmoFactor)); - } - if (amount < 0) amount = 0; - if (ammo == NULL) - { // The player did not have the ammo. Add it. - ammo = static_cast(Spawn(atype)); - ammo->Amount = bDepleted ? 0 : amount; - if (ammo->BackpackMaxAmount > ammo->MaxAmount) - { - ammo->MaxAmount = ammo->BackpackMaxAmount; - } - if (ammo->Amount > ammo->MaxAmount) - { - ammo->Amount = ammo->MaxAmount; - } - ammo->AttachToOwner (other); - } - else - { // The player had the ammo. Give some more. - if (ammo->MaxAmount < ammo->BackpackMaxAmount) - { - ammo->MaxAmount = ammo->BackpackMaxAmount; - } - if (!bDepleted && ammo->Amount < ammo->MaxAmount) - { - ammo->Amount += amount; - if (ammo->Amount > ammo->MaxAmount) - { - ammo->Amount = ammo->MaxAmount; - } - } - } - } - } - return Super::CreateCopy (other); -} - -//=========================================================================== -// -// ABackpackItem :: HandlePickup -// -// When the player picks up another backpack, just give them more ammo. -// -//=========================================================================== - -bool ABackpackItem::HandlePickup (AInventory *item) -{ - // Since you already have a backpack, that means you already have every - // kind of ammo in your inventory, so we don't need to look at the - // entire PClass list to discover what kinds of ammo exist, and we don't - // have to alter the MaxAmount either. - if (item->IsKindOf (RUNTIME_CLASS(ABackpackItem))) - { - for (AInventory *probe = Owner->Inventory; probe != NULL; probe = probe->Inventory) - { - if (probe->GetClass()->ParentClass == RUNTIME_CLASS(AAmmo)) - { - if (probe->Amount < probe->MaxAmount || sv_unlimited_pickup) - { - int amount = static_cast(probe->GetDefault())->BackpackAmount; - // extra ammo in baby mode and nightmare mode - if (!(item->ItemFlags&IF_IGNORESKILL)) - { - amount = int(amount * G_SkillProperty(SKILLP_AmmoFactor)); - } - probe->Amount += amount; - if (probe->Amount > probe->MaxAmount && !sv_unlimited_pickup) - { - probe->Amount = probe->MaxAmount; - } - } - } - } - // The pickup always succeeds, even if you didn't get anything - item->ItemFlags |= IF_PICKUPGOOD; - return true; - } - return false; -} - -//=========================================================================== -// -// ABackpackItem :: CreateTossable -// -// The tossed backpack must not give out any more ammo, otherwise a player -// could cheat by dropping their backpack and picking it up for more ammo. -// -//=========================================================================== - -AInventory *ABackpackItem::CreateTossable () -{ - ABackpackItem *pack = static_cast(Super::CreateTossable()); - if (pack != NULL) - { - pack->bDepleted = true; - } - return pack; -} - -//=========================================================================== -// -// ABackpackItem :: DetachFromOwner -// -//=========================================================================== - -void ABackpackItem::DetachFromOwner () -{ - // When removing a backpack, drop the player's ammo maximums to normal - AInventory *item; - - for (item = Owner->Inventory; item != NULL; item = item->Inventory) - { - if (item->GetClass()->ParentClass == RUNTIME_CLASS(AAmmo) && - item->MaxAmount == static_cast(item)->BackpackMaxAmount) - { - item->MaxAmount = static_cast(item->GetDefault())->MaxAmount; - if (item->Amount > item->MaxAmount) - { - item->Amount = item->MaxAmount; - } - } - } -} - //=========================================================================== // // ABackpack diff --git a/src/g_inventory/a_pickups.h b/src/g_inventory/a_pickups.h index 56caabf3c..00a8e6546 100644 --- a/src/g_inventory/a_pickups.h +++ b/src/g_inventory/a_pickups.h @@ -9,92 +9,9 @@ class player_t; class FConfigFile; -class AWeapon; -class PClassWeapon; class PClassPlayerPawn; struct visstyle_t; -class FWeaponSlot -{ -public: - FWeaponSlot() { Clear(); } - FWeaponSlot(const FWeaponSlot &other) { Weapons = other.Weapons; } - FWeaponSlot &operator= (const FWeaponSlot &other) { Weapons = other.Weapons; return *this; } - void Clear() { Weapons.Clear(); } - bool AddWeapon (const char *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 (PClassWeapon *type); - - inline PClassWeapon *GetWeapon (int index) const - { - if ((unsigned)index < Weapons.Size()) - { - return Weapons[index].Type; - } - else - { - return NULL; - } - } - - friend struct FWeaponSlots; - -private: - struct WeaponInfo - { - PClassWeapon *Type; - int Position; - }; - void SetInitialPositions(); - void Sort(); - TArray Weapons; -}; -// FWeaponSlots::AddDefaultWeapon return codes -enum ESlotDef -{ - SLOTDEF_Exists, // Weapon was already assigned a slot - SLOTDEF_Added, // Weapon was successfully added - SLOTDEF_Full // The specifed slot was full -}; - -struct FWeaponSlots -{ - FWeaponSlots() { Clear(); } - FWeaponSlots(const FWeaponSlots &other); - - FWeaponSlot Slots[NUM_WEAPON_SLOTS]; - - AWeapon *PickNextWeapon (player_t *player); - AWeapon *PickPrevWeapon (player_t *player); - - void Clear (); - bool LocateWeapon (PClassWeapon *type, int *const slot, int *const index); - ESlotDef AddDefaultWeapon (int slot, PClassWeapon *type); - void AddExtraWeapons(); - void SetFromGameInfo(); - 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, PClassWeapon *type, bool feedback); - void AddSlotDefault(int slot, PClassWeapon *type, bool feedback); - -}; - -void P_PlaybackKeyConfWeapons(FWeaponSlots *slots); -void Net_WriteWeapon(PClassWeapon *type); -PClassWeapon *Net_ReadWeapon(BYTE **stream); - -void P_SetupWeapons_ntohton(); -void P_WriteDemoWeaponsChunk(BYTE **demo); -void P_ReadDemoWeaponsChunk(BYTE **demo); - /************************************************************************/ /* Class definitions */ /************************************************************************/ @@ -252,174 +169,6 @@ public: bool SpecialDropAction (AActor *dropper); }; -// Ammo: Something a weapon needs to operate -class PClassAmmo : public PClassInventory -{ - DECLARE_CLASS(PClassAmmo, PClassInventory) -protected: - virtual void DeriveData(PClass *newclass); -public: - PClassAmmo(); - - int DropAmount; // Specifies the amount for a dropped ammo item. -}; - -class AAmmo : public AInventory -{ - DECLARE_CLASS_WITH_META(AAmmo, AInventory, PClassAmmo) -public: - - void Serialize(FSerializer &arc); - AInventory *CreateCopy (AActor *other); - bool HandlePickup (AInventory *item); - PClassActor *GetParentAmmo () const; - AInventory *CreateTossable (); - - int BackpackAmount, BackpackMaxAmount; -}; - -// A weapon is just that. -class PClassWeapon : public PClassInventory -{ - DECLARE_CLASS(PClassWeapon, PClassInventory); -protected: - virtual void DeriveData(PClass *newclass); -public: - PClassWeapon(); - virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass); - void Finalize(FStateDefinitions &statedef); - - int SlotNumber; - int SlotPriority; -}; - -class AWeapon : public AStateProvider -{ - DECLARE_CLASS_WITH_META(AWeapon, AStateProvider, PClassWeapon) - HAS_OBJECT_POINTERS -public: - DWORD WeaponFlags; - 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; - float YAdjust; // For viewing the weapon fullscreen (visual only so no need to be a double) - FSoundIDNoInit UpSound, ReadySound; // Sounds when coming up and idle - 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 - double MoveCombatDist; // Used by bots, but do they *really* need it? - int ReloadCounter; // For A_CheckForReload - int BobStyle; // [XA] Bobbing style. Defines type of bobbing (e.g. Normal, Alpha) (visual only so no need to be a double) - float BobSpeed; // [XA] Bobbing speed. Defines how quickly a weapon bobs. - float BobRangeX, BobRangeY; // [XA] Bobbing range. Defines how far a weapon bobs in either direction. - - // In-inventory instance variables - TObjPtr Ammo1, Ammo2; - TObjPtr SisterWeapon; - float FOVScale; - int Crosshair; // 0 to use player's crosshair - bool GivenAsMorphWeapon; - - bool bAltFire; // Set when this weapon's alternate fire is used. - - virtual void MarkPrecacheSounds() const; - - virtual void Serialize(FSerializer &arc); - virtual bool ShouldStay (); - virtual void AttachToOwner (AActor *other); - virtual bool HandlePickup (AInventory *item); - virtual AInventory *CreateCopy (AActor *other); - virtual AInventory *CreateTossable (); - virtual bool TryPickup (AActor *&toucher); - virtual bool TryPickupRestricted (AActor *&toucher); - virtual bool PickupForAmmo (AWeapon *ownedWeapon); - virtual bool Use (bool pickup); - virtual void Destroy() override; - - FState *GetUpState (); - FState *GetDownState (); - FState *GetReadyState (); - FState *GetAtkState (bool hold); - FState *GetAltAtkState (bool hold); - FState *GetStateForButtonName (FName button); - - virtual void PostMorphWeapon (); - virtual void EndPowerup (); - void CallEndPowerup(); - - enum - { - PrimaryFire, - AltFire, - EitherFire - }; - bool CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo=false, int ammocount = -1); - bool DepleteAmmo (bool altFire, bool checkEnough=true, int ammouse = -1); - - enum - { - BobNormal, - BobInverse, - BobAlpha, - BobInverseAlpha, - BobSmooth, - BobInverseSmooth - }; - -protected: - AAmmo *AddAmmo (AActor *other, PClassActor *ammotype, int amount); - bool AddExistingAmmo (AAmmo *ammo, int amount); - AWeapon *AddWeapon (PClassWeapon *weapon); -}; - -enum -{ - WIF_NOAUTOFIRE = 0x00000001, // weapon does not autofire - WIF_READYSNDHALF = 0x00000002, // ready sound is played ~1/2 the time - WIF_DONTBOB = 0x00000004, // don't bob the weapon - WIF_AXEBLOOD = 0x00000008, // weapon makes axe blood on impact (Hexen only) - WIF_NOALERT = 0x00000010, // weapon does not alert monsters - WIF_AMMO_OPTIONAL = 0x00000020, // weapon can use ammo but does not require it - WIF_ALT_AMMO_OPTIONAL = 0x00000040, // alternate fire can use ammo but does not require it - WIF_PRIMARY_USES_BOTH = 0x00000080, // primary fire uses both ammo - WIF_ALT_USES_BOTH = 0x00000100, // alternate fire uses both ammo - WIF_WIMPY_WEAPON = 0x00000200, // change away when ammo for another weapon is replenished - WIF_POWERED_UP = 0x00000400, // this is a tome-of-power'ed version of its sister - WIF_AMMO_CHECKBOTH = 0x00000800, // check for both primary and secondary fire before switching it off - WIF_NO_AUTO_SWITCH = 0x00001000, // never switch to this weapon when it's picked up - WIF_STAFF2_KICKBACK = 0x00002000, // the powered-up Heretic staff has special kickback - WIF_NOAUTOAIM = 0x00004000, // this weapon never uses autoaim (useful for ballistic projectiles) - WIF_MELEEWEAPON = 0x00008000, // melee weapon. Used by bots and monster AI. - WIF_DEHAMMO = 0x00010000, // Uses Doom's original amount of ammo for the respective attack functions so that old DEHACKED patches work as intended. - // AmmoUse1 will be set to the first attack's ammo use so that checking for empty weapons still works - WIF_NODEATHDESELECT = 0x00020000, // Don't jump to the Deselect state when the player dies - WIF_NODEATHINPUT = 0x00040000, // The weapon cannot be fired/reloaded/whatever when the player is dead - WIF_CHEATNOTWEAPON = 0x08000000, // Give cheat considers this not a weapon (used by Sigil) - - // Flags used only by bot AI: - - WIF_BOT_REACTION_SKILL_THING = 1<<31, // I don't understand this - WIF_BOT_EXPLOSIVE = 1<<30, // weapon fires an explosive - WIF_BOT_BFG = 1<<28, // this is a BFG -}; - -class AWeaponGiver : public AWeapon -{ - DECLARE_CLASS(AWeaponGiver, AWeapon) - -public: - bool TryPickup(AActor *&toucher); - - void Serialize(FSerializer &arc); - - double DropAmmoFactor; -}; - - // Health is some item that gives the player health when picked up. class PClassHealth : public PClassInventory { @@ -488,23 +237,6 @@ public: bool TryPickup (AActor *&toucher); }; -// A backpack gives you one clip of each ammo and doubles your -// normal maximum ammo amounts. -class ABackpackItem : public AInventory -{ - DECLARE_CLASS (ABackpackItem, AInventory) -public: - - void Serialize(FSerializer &arc); - bool HandlePickup (AInventory *item); - AInventory *CreateCopy (AActor *other); - AInventory *CreateTossable (); - void DetachFromOwner (); - - bool bDepleted; -}; - - // A score item is picked up without being added to the inventory. // It differs from FakeInventory by doing nothing more than increasing the player's score. class AScoreItem : public AInventory diff --git a/src/g_inventory/a_puzzleitems.cpp b/src/g_inventory/a_puzzleitems.cpp index 0d63bb00c..e2a538387 100644 --- a/src/g_inventory/a_puzzleitems.cpp +++ b/src/g_inventory/a_puzzleitems.cpp @@ -1,3 +1,38 @@ +/* +** a_puzzleitems.cpp +** Implements Hexen's puzzle items. +** +**--------------------------------------------------------------------------- +** Copyright 2002-2016 Randy Heit +** Copyright 2006-2016 Cheistoph Oelckers +** 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. +** +** 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 "info.h" #include "a_pickups.h" #include "a_artifacts.h" @@ -8,7 +43,17 @@ #include "doomstat.h" #include "v_font.h" + IMPLEMENT_CLASS(PClassPuzzleItem, false, false) +IMPLEMENT_CLASS(APuzzleItem, false, false) + +DEFINE_FIELD(APuzzleItem, PuzzleItemNumber) + +//=========================================================================== +// +// +// +//=========================================================================== void PClassPuzzleItem::DeriveData(PClass *newclass) { @@ -17,9 +62,12 @@ void PClassPuzzleItem::DeriveData(PClass *newclass) static_cast(newclass)->PuzzFailMessage = PuzzFailMessage; } -IMPLEMENT_CLASS(APuzzleItem, false, false) -DEFINE_FIELD(APuzzleItem, PuzzleItemNumber) +//=========================================================================== +// +// +// +//=========================================================================== bool APuzzleItem::HandlePickup (AInventory *item) { @@ -31,6 +79,12 @@ bool APuzzleItem::HandlePickup (AInventory *item) return Super::HandlePickup (item); } +//=========================================================================== +// +// +// +//=========================================================================== + bool APuzzleItem::Use (bool pickup) { if (P_UsePuzzleItem (Owner, PuzzleItemNumber)) @@ -49,6 +103,12 @@ bool APuzzleItem::Use (bool pickup) return false; } +//=========================================================================== +// +// +// +//=========================================================================== + bool APuzzleItem::ShouldStay () { return !!multiplayer; diff --git a/src/g_inventory/a_weaponpiece.cpp b/src/g_inventory/a_weaponpiece.cpp index bb98415fc..b504559bd 100644 --- a/src/g_inventory/a_weaponpiece.cpp +++ b/src/g_inventory/a_weaponpiece.cpp @@ -1,3 +1,38 @@ +/* +** a_weaponpieces.cpp +** Implements generic weapon pieces +** +**--------------------------------------------------------------------------- +** Copyright 2006-2016 Cheistoph Oelckers +** Copyright 2006-2016 Randy Heit +** 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. +** +** 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 "a_pickups.h" #include "a_weaponpiece.h" #include "doomstat.h" @@ -9,6 +44,12 @@ IMPLEMENT_CLASS(AWeaponHolder, false, false) DEFINE_FIELD(AWeaponHolder, PieceMask); DEFINE_FIELD(AWeaponHolder, PieceWeapon); +//=========================================================================== +// +// +// +//=========================================================================== + void PClassWeaponPiece::ReplaceClassRef(PClass *oldclass, PClass *newclass) { Super::ReplaceClassRef(oldclass, newclass); @@ -19,6 +60,11 @@ void PClassWeaponPiece::ReplaceClassRef(PClass *oldclass, PClass *newclass) } } +//=========================================================================== +// +// +// +//=========================================================================== void AWeaponHolder::Serialize(FSerializer &arc) { @@ -33,6 +79,11 @@ IMPLEMENT_POINTERS_START(AWeaponPiece) IMPLEMENT_POINTER(FullWeapon) IMPLEMENT_POINTERS_END +//=========================================================================== +// +// +// +//=========================================================================== void AWeaponPiece::Serialize(FSerializer &arc) { @@ -151,11 +202,23 @@ bool AWeaponPiece::TryPickup (AActor *&toucher) return true; } +//=========================================================================== +// +// +// +//=========================================================================== + bool AWeaponPiece::ShouldStay () { return PrivateShouldStay (); } +//=========================================================================== +// +// +// +//=========================================================================== + bool AWeaponPiece::PrivateShouldStay () { // We want a weapon piece to behave like a weapon, so follow the exact diff --git a/src/g_inventory/a_weaponpiece.h b/src/g_inventory/a_weaponpiece.h index e293637cf..bcaa261cb 100644 --- a/src/g_inventory/a_weaponpiece.h +++ b/src/g_inventory/a_weaponpiece.h @@ -1,5 +1,6 @@ #pragma once #include "a_pickups.h" +#include "a_weapons.h" // class PClassWeaponPiece : public PClassInventory diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index 4f49ecd6f..90a217495 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -1,3 +1,38 @@ +/* +** a_weapons.cpp +** Implements weapon handling +** +**--------------------------------------------------------------------------- +** Copyright 2000-2016 Randy Heit +** Copyright 2006-2016 Cheistoph Oelckers +** 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. +** +** 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 "a_pickups.h" @@ -19,6 +54,7 @@ #include "serializer.h" #include "thingdef.h" #include "virtual.h" +#include "a_ammo.h" #define BONUSADD 6 diff --git a/src/g_inventory/a_weapons.h b/src/g_inventory/a_weapons.h new file mode 100644 index 000000000..786f6189b --- /dev/null +++ b/src/g_inventory/a_weapons.h @@ -0,0 +1,230 @@ +#pragma once + +#include "a_ammo.h" + +class PClassWeapon; +class AWeapon; + +class FWeaponSlot +{ +public: + FWeaponSlot() { Clear(); } + FWeaponSlot(const FWeaponSlot &other) { Weapons = other.Weapons; } + FWeaponSlot &operator= (const FWeaponSlot &other) { Weapons = other.Weapons; return *this; } + void Clear() { Weapons.Clear(); } + bool AddWeapon (const char *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 (PClassWeapon *type); + + inline PClassWeapon *GetWeapon (int index) const + { + if ((unsigned)index < Weapons.Size()) + { + return Weapons[index].Type; + } + else + { + return NULL; + } + } + + friend struct FWeaponSlots; + +private: + struct WeaponInfo + { + PClassWeapon *Type; + int Position; + }; + void SetInitialPositions(); + void Sort(); + TArray Weapons; +}; +// FWeaponSlots::AddDefaultWeapon return codes +enum ESlotDef +{ + SLOTDEF_Exists, // Weapon was already assigned a slot + SLOTDEF_Added, // Weapon was successfully added + SLOTDEF_Full // The specifed slot was full +}; + +struct FWeaponSlots +{ + FWeaponSlots() { Clear(); } + FWeaponSlots(const FWeaponSlots &other); + + FWeaponSlot Slots[NUM_WEAPON_SLOTS]; + + AWeapon *PickNextWeapon (player_t *player); + AWeapon *PickPrevWeapon (player_t *player); + + void Clear (); + bool LocateWeapon (PClassWeapon *type, int *const slot, int *const index); + ESlotDef AddDefaultWeapon (int slot, PClassWeapon *type); + void AddExtraWeapons(); + void SetFromGameInfo(); + 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, PClassWeapon *type, bool feedback); + void AddSlotDefault(int slot, PClassWeapon *type, bool feedback); + +}; + +void P_PlaybackKeyConfWeapons(FWeaponSlots *slots); +void Net_WriteWeapon(PClassWeapon *type); +PClassWeapon *Net_ReadWeapon(BYTE **stream); + +void P_SetupWeapons_ntohton(); +void P_WriteDemoWeaponsChunk(BYTE **demo); +void P_ReadDemoWeaponsChunk(BYTE **demo); + + +// A weapon is just that. +class PClassWeapon : public PClassInventory +{ + DECLARE_CLASS(PClassWeapon, PClassInventory); +protected: + virtual void DeriveData(PClass *newclass); +public: + PClassWeapon(); + virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass); + void Finalize(FStateDefinitions &statedef); + + int SlotNumber; + int SlotPriority; +}; + +class AWeapon : public AStateProvider +{ + DECLARE_CLASS_WITH_META(AWeapon, AStateProvider, PClassWeapon) + HAS_OBJECT_POINTERS +public: + DWORD WeaponFlags; + 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; + float YAdjust; // For viewing the weapon fullscreen (visual only so no need to be a double) + FSoundIDNoInit UpSound, ReadySound; // Sounds when coming up and idle + 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 + double MoveCombatDist; // Used by bots, but do they *really* need it? + int ReloadCounter; // For A_CheckForReload + int BobStyle; // [XA] Bobbing style. Defines type of bobbing (e.g. Normal, Alpha) (visual only so no need to be a double) + float BobSpeed; // [XA] Bobbing speed. Defines how quickly a weapon bobs. + float BobRangeX, BobRangeY; // [XA] Bobbing range. Defines how far a weapon bobs in either direction. + + // In-inventory instance variables + TObjPtr Ammo1, Ammo2; + TObjPtr SisterWeapon; + float FOVScale; + int Crosshair; // 0 to use player's crosshair + bool GivenAsMorphWeapon; + + bool bAltFire; // Set when this weapon's alternate fire is used. + + virtual void MarkPrecacheSounds() const; + + virtual void Serialize(FSerializer &arc); + virtual bool ShouldStay (); + virtual void AttachToOwner (AActor *other); + virtual bool HandlePickup (AInventory *item); + virtual AInventory *CreateCopy (AActor *other); + virtual AInventory *CreateTossable (); + virtual bool TryPickup (AActor *&toucher); + virtual bool TryPickupRestricted (AActor *&toucher); + virtual bool PickupForAmmo (AWeapon *ownedWeapon); + virtual bool Use (bool pickup); + virtual void Destroy() override; + + FState *GetUpState (); + FState *GetDownState (); + FState *GetReadyState (); + FState *GetAtkState (bool hold); + FState *GetAltAtkState (bool hold); + FState *GetStateForButtonName (FName button); + + virtual void PostMorphWeapon (); + virtual void EndPowerup (); + void CallEndPowerup(); + + enum + { + PrimaryFire, + AltFire, + EitherFire + }; + bool CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo=false, int ammocount = -1); + bool DepleteAmmo (bool altFire, bool checkEnough=true, int ammouse = -1); + + enum + { + BobNormal, + BobInverse, + BobAlpha, + BobInverseAlpha, + BobSmooth, + BobInverseSmooth + }; + +protected: + AAmmo *AddAmmo (AActor *other, PClassActor *ammotype, int amount); + bool AddExistingAmmo (AAmmo *ammo, int amount); + AWeapon *AddWeapon (PClassWeapon *weapon); +}; + +enum +{ + WIF_NOAUTOFIRE = 0x00000001, // weapon does not autofire + WIF_READYSNDHALF = 0x00000002, // ready sound is played ~1/2 the time + WIF_DONTBOB = 0x00000004, // don't bob the weapon + WIF_AXEBLOOD = 0x00000008, // weapon makes axe blood on impact (Hexen only) + WIF_NOALERT = 0x00000010, // weapon does not alert monsters + WIF_AMMO_OPTIONAL = 0x00000020, // weapon can use ammo but does not require it + WIF_ALT_AMMO_OPTIONAL = 0x00000040, // alternate fire can use ammo but does not require it + WIF_PRIMARY_USES_BOTH = 0x00000080, // primary fire uses both ammo + WIF_ALT_USES_BOTH = 0x00000100, // alternate fire uses both ammo + WIF_WIMPY_WEAPON = 0x00000200, // change away when ammo for another weapon is replenished + WIF_POWERED_UP = 0x00000400, // this is a tome-of-power'ed version of its sister + WIF_AMMO_CHECKBOTH = 0x00000800, // check for both primary and secondary fire before switching it off + WIF_NO_AUTO_SWITCH = 0x00001000, // never switch to this weapon when it's picked up + WIF_STAFF2_KICKBACK = 0x00002000, // the powered-up Heretic staff has special kickback + WIF_NOAUTOAIM = 0x00004000, // this weapon never uses autoaim (useful for ballistic projectiles) + WIF_MELEEWEAPON = 0x00008000, // melee weapon. Used by bots and monster AI. + WIF_DEHAMMO = 0x00010000, // Uses Doom's original amount of ammo for the respective attack functions so that old DEHACKED patches work as intended. + // AmmoUse1 will be set to the first attack's ammo use so that checking for empty weapons still works + WIF_NODEATHDESELECT = 0x00020000, // Don't jump to the Deselect state when the player dies + WIF_NODEATHINPUT = 0x00040000, // The weapon cannot be fired/reloaded/whatever when the player is dead + WIF_CHEATNOTWEAPON = 0x08000000, // Give cheat considers this not a weapon (used by Sigil) + + // Flags used only by bot AI: + + WIF_BOT_REACTION_SKILL_THING = 1<<31, // I don't understand this + WIF_BOT_EXPLOSIVE = 1<<30, // weapon fires an explosive + WIF_BOT_BFG = 1<<28, // this is a BFG +}; + +class AWeaponGiver : public AWeapon +{ + DECLARE_CLASS(AWeaponGiver, AWeapon) + +public: + bool TryPickup(AActor *&toucher); + + void Serialize(FSerializer &arc); + + double DropAmmoFactor; +}; + diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index f2852919d..8ca8d6816 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -59,6 +59,7 @@ #include "gstrings.h" #include "version.h" #include "cmdlib.h" +#include "a_ammo.h" #define ARTIFLASH_OFFSET (statusBar->invBarOffset+6) enum diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index c6e12918d..a061dbf59 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -44,6 +44,7 @@ #include "w_wad.h" #include "a_keys.h" #include "a_armor.h" +#include "a_ammo.h" #include "sbar.h" #include "sc_man.h" #include "templates.h" diff --git a/src/g_strife/strife_sbar.cpp b/src/g_strife/strife_sbar.cpp index 3a242f80c..973364cf7 100644 --- a/src/g_strife/strife_sbar.cpp +++ b/src/g_strife/strife_sbar.cpp @@ -13,6 +13,7 @@ #include "templates.h" #include "a_keys.h" #include "a_armor.h" +#include "a_ammo.h" #include "gi.h" #include "g_level.h" #include "colormatcher.h" diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index 6bd6b3862..53405017a 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -48,6 +48,7 @@ #include "r_utility.h" #include "a_morph.h" #include "a_armor.h" +#include "a_ammo.h" // [RH] Actually handle the cheat. The cheat code in st_stuff.c now just // writes some bytes to the network data stream, and the network code diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 93d0cd45b..ba086da3a 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -84,6 +84,7 @@ #include "thingdef.h" #include "a_pickups.h" #include "a_armor.h" +#include "a_ammo.h" extern FILE *Logfile; diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 5b2ba6d65..29128c8b7 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -51,6 +51,7 @@ #include "p_spec.h" #include "p_checkposition.h" #include "math/cmath.h" +#include "a_ammo.h" #include "gi.h" diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 7c7d97cf2..2d36136f3 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -70,6 +70,7 @@ #include "d_player.h" #include "virtual.h" #include "a_armor.h" +#include "a_ammo.h" // MACROS ------------------------------------------------------------------ diff --git a/src/p_user.cpp b/src/p_user.cpp index e92b560db..11857631a 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -60,6 +60,7 @@ #include "p_spec.h" #include "virtual.h" #include "a_armor.h" +#include "a_ammo.h" static FRandom pr_skullpop ("SkullPop"); diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index e85b6a1d9..e87602114 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -70,6 +70,7 @@ #include "r_data/colormaps.h" #include "a_weaponpiece.h" #include "vmbuilder.h" +#include "a_ammo.h" extern TArray OptionalClassPtrs; From b0f3121bec0e9b265b11f002f93a18f8ffa829d2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 30 Nov 2016 13:36:13 +0100 Subject: [PATCH 181/185] - split up zscript/shared/inventory.txt. - moved health items to their own file. - scriptified ScoreItem and MapRevealer whose entire functionality was a small TryPickup method. - fixed: bit fields in global variables were not correctly written. This should conclude the inventory cleanup. It is now possible again to find things in there. --- src/CMakeLists.txt | 1 + src/b_think.cpp | 1 + src/d_dehacked.cpp | 1 + src/d_net.cpp | 1 + src/dobjtype.cpp | 2 + src/g_inventory/a_artifacts.cpp | 2 + src/g_inventory/a_health.cpp | 301 ++++++++++ src/g_inventory/a_health.h | 42 ++ src/g_inventory/a_keys.h | 24 + src/g_inventory/a_pickups.cpp | 311 ---------- src/g_inventory/a_pickups.h | 78 --- src/g_inventory/a_puzzleitems.cpp | 1 + src/p_actionfunctions.cpp | 1 + src/p_interaction.cpp | 1 + src/p_mobj.cpp | 1 + src/scripting/codegeneration/codegen.cpp | 16 +- src/scripting/codegeneration/codegen.h | 4 + src/scripting/thingdef_properties.cpp | 2 + wadsrc/static/zscript.txt | 6 +- wadsrc/static/zscript/shared/armor.txt | 72 +++ wadsrc/static/zscript/shared/inv_misc.txt | 87 +++ wadsrc/static/zscript/shared/inventory.txt | 560 +----------------- .../shared/{pickups.txt => itemeffects.txt} | 0 wadsrc/static/zscript/shared/powerups.txt | 282 +++++++++ wadsrc/static/zscript/shared/weapons.txt | 144 +++++ 25 files changed, 982 insertions(+), 959 deletions(-) create mode 100644 src/g_inventory/a_health.cpp create mode 100644 src/g_inventory/a_health.h create mode 100644 wadsrc/static/zscript/shared/armor.txt create mode 100644 wadsrc/static/zscript/shared/inv_misc.txt rename wadsrc/static/zscript/shared/{pickups.txt => itemeffects.txt} (100%) create mode 100644 wadsrc/static/zscript/shared/powerups.txt create mode 100644 wadsrc/static/zscript/shared/weapons.txt diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 126554496..83dad3b9d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1110,6 +1110,7 @@ set (PCH_SOURCES g_inventory/a_ammo.cpp g_inventory/a_armor.cpp g_inventory/a_artifacts.cpp + g_inventory/a_health.cpp g_inventory/a_keys.cpp g_inventory/a_pickups.cpp g_inventory/a_puzzleitems.cpp diff --git a/src/b_think.cpp b/src/b_think.cpp index 7dd196622..e41433fa3 100644 --- a/src/b_think.cpp +++ b/src/b_think.cpp @@ -22,6 +22,7 @@ #include "d_player.h" #include "vectors.h" #include "a_ammo.h" +#include "a_health.h" static FRandom pr_botmove ("BotMove"); diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 62daefcaa..c0ea00f5e 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -76,6 +76,7 @@ #include "vmbuilder.h" #include "a_armor.h" #include "a_ammo.h" +#include "a_health.h" // [SO] Just the way Randy said to do it :) // [RH] Made this CVAR_SERVERINFO diff --git a/src/d_net.cpp b/src/d_net.cpp index 261133867..4bda25510 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -61,6 +61,7 @@ #include "p_spec.h" #include "hardware.h" #include "r_utility.h" +#include "a_keys.h" #include "intermission/intermission.h" EXTERN_CVAR (Int, disableautosave) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 7377af56b..dba554498 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -50,6 +50,8 @@ #include "d_player.h" #include "doomerrors.h" #include "fragglescript/t_fs.h" +#include "a_keys.h" +#include "a_health.h" // MACROS ------------------------------------------------------------------ diff --git a/src/g_inventory/a_artifacts.cpp b/src/g_inventory/a_artifacts.cpp index 5866e8b2a..1198b9153 100644 --- a/src/g_inventory/a_artifacts.cpp +++ b/src/g_inventory/a_artifacts.cpp @@ -40,6 +40,7 @@ static FRandom pr_torch ("Torch"); #define TIMEFREEZE_TICS ( 12 * TICRATE ) */ + IMPLEMENT_CLASS(APowerup, false, false) // Powerup-Giver ------------------------------------------------------------- @@ -56,6 +57,7 @@ void PClassPowerupGiver::ReplaceClassRef(PClass *oldclass, PClass *newclass) } } +IMPLEMENT_CLASS(APowerupGiver, false, false) DEFINE_FIELD(APowerupGiver, PowerupType) DEFINE_FIELD(APowerupGiver, EffectTics) diff --git a/src/g_inventory/a_health.cpp b/src/g_inventory/a_health.cpp new file mode 100644 index 000000000..58cd86e2a --- /dev/null +++ b/src/g_inventory/a_health.cpp @@ -0,0 +1,301 @@ +/* +** a_health.cpp +** All health items +** +**--------------------------------------------------------------------------- +** Copyright 2000-2016 Randy Heit +** Copyright 2006-2016 Cheistoph Oelckers +** 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. +** +** 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 "d_player.h" +#include "a_morph.h" +#include "a_health.h" +#include "serializer.h" + +//--------------------------------------------------------------------------- +// +// FUNC P_GiveBody +// +// Returns false if the body isn't needed at all. +// +//--------------------------------------------------------------------------- + +bool P_GiveBody (AActor *actor, int num, int max) +{ + if (actor->health <= 0 || (actor->player != NULL && actor->player->playerstate == PST_DEAD)) + { // Do not heal dead things. + return false; + } + + player_t *player = actor->player; + + num = clamp(num, -65536, 65536); // prevent overflows for bad values + if (player != NULL) + { + // Max is 0 by default, preserving default behavior for P_GiveBody() + // calls while supporting AHealth. + if (max <= 0) + { + max = static_cast(actor)->GetMaxHealth() + player->mo->stamina; + // [MH] First step in predictable generic morph effects + if (player->morphTics) + { + if (player->MorphStyle & MORPH_FULLHEALTH) + { + if (!(player->MorphStyle & MORPH_ADDSTAMINA)) + { + max -= player->mo->stamina; + } + } + else // old health behaviour + { + max = MAXMORPHHEALTH; + if (player->MorphStyle & MORPH_ADDSTAMINA) + { + max += player->mo->stamina; + } + } + } + } + // [RH] For Strife: A negative body sets you up with a percentage + // of your full health. + if (num < 0) + { + num = max * -num / 100; + if (player->health < num) + { + player->health = num; + actor->health = num; + return true; + } + } + else if (num > 0) + { + if (player->health < max) + { + num = int(num * G_SkillProperty(SKILLP_HealthFactor)); + if (num < 1) num = 1; + player->health += num; + if (player->health > max) + { + player->health = max; + } + actor->health = player->health; + return true; + } + } + } + else + { + // Parameter value for max is ignored on monsters, preserving original + // behaviour on AHealth as well as on existing calls to P_GiveBody(). + max = actor->SpawnHealth(); + if (num < 0) + { + num = max * -num / 100; + if (actor->health < num) + { + actor->health = num; + return true; + } + } + else if (actor->health < max) + { + actor->health += num; + if (actor->health > max) + { + actor->health = max; + } + return true; + } + } + return false; +} + +DEFINE_ACTION_FUNCTION(AActor, GiveBody) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(num); + PARAM_INT_DEF(max); + ACTION_RETURN_BOOL(P_GiveBody(self, num, max)); +} + +//=========================================================================== +// +// Classes +// +//=========================================================================== + +IMPLEMENT_CLASS(PClassHealth, false, false) +IMPLEMENT_CLASS(AHealth, false, false) +DEFINE_FIELD(AHealth, PrevHealth) + +//=========================================================================== +// +// PClassHealth Constructor +// +//=========================================================================== + +PClassHealth::PClassHealth() +{ + LowHealth = 0; +} + +//=========================================================================== +// +// PClassHealth :: DeriveData +// +//=========================================================================== + +void PClassHealth::DeriveData(PClass *newclass) +{ + assert(newclass->IsKindOf(RUNTIME_CLASS(PClassHealth))); + Super::DeriveData(newclass); + PClassHealth *newc = static_cast(newclass); + + newc->LowHealth = LowHealth; + newc->LowHealthMessage = LowHealthMessage; +} + + +//=========================================================================== +// +// AHealth :: PickupMessage +// +//=========================================================================== +FString AHealth::PickupMessage () +{ + int threshold = GetClass()->LowHealth; + + if (PrevHealth < threshold) + { + FString message = GetClass()->LowHealthMessage; + + if (message.IsNotEmpty()) + { + return message; + } + } + return Super::PickupMessage(); +} + +//=========================================================================== +// +// AHealth :: TryPickup +// +//=========================================================================== + +bool AHealth::TryPickup (AActor *&other) +{ + PrevHealth = other->player != NULL ? other->player->health : other->health; + + // P_GiveBody adds one new feature, applied only if it is possible to pick up negative health: + // Negative values are treated as positive percentages, ie Amount -100 means 100% health, ignoring max amount. + if (P_GiveBody(other, Amount, MaxAmount)) + { + GoAwayAndDie(); + return true; + } + return false; +} + +IMPLEMENT_CLASS(AHealthPickup, false, false) + +DEFINE_FIELD(AHealthPickup, autousemode) + +//=========================================================================== +// +// AHealthPickup :: CreateCopy +// +//=========================================================================== + +AInventory *AHealthPickup::CreateCopy (AActor *other) +{ + AInventory *copy = Super::CreateCopy (other); + copy->health = health; + return copy; +} + +//=========================================================================== +// +// AHealthPickup :: CreateTossable +// +//=========================================================================== + +AInventory *AHealthPickup::CreateTossable () +{ + AInventory *copy = Super::CreateTossable (); + if (copy != NULL) + { + copy->health = health; + } + return copy; +} + +//=========================================================================== +// +// AHealthPickup :: HandlePickup +// +//=========================================================================== + +bool AHealthPickup::HandlePickup (AInventory *item) +{ + // HealthPickups that are the same type but have different health amounts + // do not count as the same item. + if (item->health == health) + { + return Super::HandlePickup (item); + } + return false; +} + +//=========================================================================== +// +// AHealthPickup :: Use +// +//=========================================================================== + +bool AHealthPickup::Use (bool pickup) +{ + return P_GiveBody (Owner, health, 0); +} + +//=========================================================================== +// +// AHealthPickup :: Serialize +// +//=========================================================================== + +void AHealthPickup::Serialize(FSerializer &arc) +{ + Super::Serialize(arc); + auto def = (AHealthPickup*)GetDefault(); + arc("autousemode", autousemode, def->autousemode); +} + diff --git a/src/g_inventory/a_health.h b/src/g_inventory/a_health.h new file mode 100644 index 000000000..a462bbfbd --- /dev/null +++ b/src/g_inventory/a_health.h @@ -0,0 +1,42 @@ +#pragma once + +#include "a_pickups.h" + +// Health is some item that gives the player health when picked up. +class PClassHealth : public PClassInventory +{ + DECLARE_CLASS(PClassHealth, PClassInventory) +protected: +public: + PClassHealth(); + virtual void DeriveData(PClass *newclass); + + FString LowHealthMessage; + int LowHealth; +}; + +class AHealth : public AInventory +{ + DECLARE_CLASS_WITH_META(AHealth, AInventory, PClassHealth) + +public: + int PrevHealth; + virtual bool TryPickup (AActor *&other); + virtual FString PickupMessage (); +}; + +// HealthPickup is some item that gives the player health when used. +class AHealthPickup : public AInventory +{ + DECLARE_CLASS (AHealthPickup, AInventory) +public: + int autousemode; + + + virtual void Serialize(FSerializer &arc); + virtual AInventory *CreateCopy (AActor *other); + virtual AInventory *CreateTossable (); + virtual bool HandlePickup (AInventory *item); + virtual bool Use (bool pickup); +}; + diff --git a/src/g_inventory/a_keys.h b/src/g_inventory/a_keys.h index 8222aa694..fd46b416c 100644 --- a/src/g_inventory/a_keys.h +++ b/src/g_inventory/a_keys.h @@ -21,4 +21,28 @@ void P_DeinitKeyMessages (); int P_GetMapColorForLock (int lock); int P_GetMapColorForKey (AInventory *key); + +// PuzzleItems work in conjunction with the UsePuzzleItem special +class PClassPuzzleItem : public PClassInventory +{ + DECLARE_CLASS(PClassPuzzleItem, PClassInventory); +protected: +public: + virtual void DeriveData(PClass *newclass); + FString PuzzFailMessage; +}; + +class APuzzleItem : public AInventory +{ + DECLARE_CLASS_WITH_META(APuzzleItem, AInventory, PClassPuzzleItem) +public: + + bool ShouldStay (); + bool Use (bool pickup); + bool HandlePickup (AInventory *item); + + int PuzzleItemNumber; +}; + + #endif diff --git a/src/g_inventory/a_pickups.cpp b/src/g_inventory/a_pickups.cpp index 84b8b366f..cf5dddcf3 100644 --- a/src/g_inventory/a_pickups.cpp +++ b/src/g_inventory/a_pickups.cpp @@ -72,114 +72,6 @@ void PClassInventory::Finalize(FStateDefinitions &statedef) ((AActor*)Defaults)->flags |= MF_SPECIAL; } -//--------------------------------------------------------------------------- -// -// FUNC P_GiveBody -// -// Returns false if the body isn't needed at all. -// -//--------------------------------------------------------------------------- - -bool P_GiveBody (AActor *actor, int num, int max) -{ - if (actor->health <= 0 || (actor->player != NULL && actor->player->playerstate == PST_DEAD)) - { // Do not heal dead things. - return false; - } - - player_t *player = actor->player; - - num = clamp(num, -65536, 65536); // prevent overflows for bad values - if (player != NULL) - { - // Max is 0 by default, preserving default behavior for P_GiveBody() - // calls while supporting AHealth. - if (max <= 0) - { - max = static_cast(actor)->GetMaxHealth() + player->mo->stamina; - // [MH] First step in predictable generic morph effects - if (player->morphTics) - { - if (player->MorphStyle & MORPH_FULLHEALTH) - { - if (!(player->MorphStyle & MORPH_ADDSTAMINA)) - { - max -= player->mo->stamina; - } - } - else // old health behaviour - { - max = MAXMORPHHEALTH; - if (player->MorphStyle & MORPH_ADDSTAMINA) - { - max += player->mo->stamina; - } - } - } - } - // [RH] For Strife: A negative body sets you up with a percentage - // of your full health. - if (num < 0) - { - num = max * -num / 100; - if (player->health < num) - { - player->health = num; - actor->health = num; - return true; - } - } - else if (num > 0) - { - if (player->health < max) - { - num = int(num * G_SkillProperty(SKILLP_HealthFactor)); - if (num < 1) num = 1; - player->health += num; - if (player->health > max) - { - player->health = max; - } - actor->health = player->health; - return true; - } - } - } - else - { - // Parameter value for max is ignored on monsters, preserving original - // behaviour on AHealth as well as on existing calls to P_GiveBody(). - max = actor->SpawnHealth(); - if (num < 0) - { - num = max * -num / 100; - if (actor->health < num) - { - actor->health = num; - return true; - } - } - else if (actor->health < max) - { - actor->health += num; - if (actor->health > max) - { - actor->health = max; - } - return true; - } - } - return false; -} - -DEFINE_ACTION_FUNCTION(AActor, GiveBody) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_INT(num); - PARAM_INT_DEF(max); - ACTION_RETURN_BOOL(P_GiveBody(self, num, max)); -} - //--------------------------------------------------------------------------- // // PROC A_RestoreSpecialThing1 @@ -1379,12 +1271,6 @@ bool AInventory::DrawPowerup (int x, int y) return false; } -/***************************************************************************/ -/* AArtifact implementation */ -/***************************************************************************/ - -IMPLEMENT_CLASS(APowerupGiver, false, false) - //=========================================================================== // // AInventory :: DoRespawn @@ -1748,200 +1634,3 @@ bool ACustomInventory::TryPickup (AActor *&toucher) } return useok; } - -IMPLEMENT_CLASS(PClassHealth, false, false) - -//=========================================================================== -// -// PClassHealth Constructor -// -//=========================================================================== - -PClassHealth::PClassHealth() -{ - LowHealth = 0; -} - -//=========================================================================== -// -// PClassHealth :: DeriveData -// -//=========================================================================== - -void PClassHealth::DeriveData(PClass *newclass) -{ - assert(newclass->IsKindOf(RUNTIME_CLASS(PClassHealth))); - Super::DeriveData(newclass); - PClassHealth *newc = static_cast(newclass); - - newc->LowHealth = LowHealth; - newc->LowHealthMessage = LowHealthMessage; -} - -IMPLEMENT_CLASS(AHealth, false, false) - -DEFINE_FIELD(AHealth, PrevHealth) - -//=========================================================================== -// -// AHealth :: PickupMessage -// -//=========================================================================== -FString AHealth::PickupMessage () -{ - int threshold = GetClass()->LowHealth; - - if (PrevHealth < threshold) - { - FString message = GetClass()->LowHealthMessage; - - if (message.IsNotEmpty()) - { - return message; - } - } - return Super::PickupMessage(); -} - -//=========================================================================== -// -// AHealth :: TryPickup -// -//=========================================================================== - -bool AHealth::TryPickup (AActor *&other) -{ - PrevHealth = other->player != NULL ? other->player->health : other->health; - - // P_GiveBody adds one new feature, applied only if it is possible to pick up negative health: - // Negative values are treated as positive percentages, ie Amount -100 means 100% health, ignoring max amount. - if (P_GiveBody(other, Amount, MaxAmount)) - { - GoAwayAndDie(); - return true; - } - return false; -} - -IMPLEMENT_CLASS(AHealthPickup, false, false) - -DEFINE_FIELD(AHealthPickup, autousemode) - -//=========================================================================== -// -// AHealthPickup :: CreateCopy -// -//=========================================================================== - -AInventory *AHealthPickup::CreateCopy (AActor *other) -{ - AInventory *copy = Super::CreateCopy (other); - copy->health = health; - return copy; -} - -//=========================================================================== -// -// AHealthPickup :: CreateTossable -// -//=========================================================================== - -AInventory *AHealthPickup::CreateTossable () -{ - AInventory *copy = Super::CreateTossable (); - if (copy != NULL) - { - copy->health = health; - } - return copy; -} - -//=========================================================================== -// -// AHealthPickup :: HandlePickup -// -//=========================================================================== - -bool AHealthPickup::HandlePickup (AInventory *item) -{ - // HealthPickups that are the same type but have different health amounts - // do not count as the same item. - if (item->health == health) - { - return Super::HandlePickup (item); - } - return false; -} - -//=========================================================================== -// -// AHealthPickup :: Use -// -//=========================================================================== - -bool AHealthPickup::Use (bool pickup) -{ - return P_GiveBody (Owner, health); -} - -//=========================================================================== -// -// AHealthPickup :: Serialize -// -//=========================================================================== - -void AHealthPickup::Serialize(FSerializer &arc) -{ - Super::Serialize(arc); - auto def = (AHealthPickup*)GetDefault(); - arc("autousemode", autousemode, def->autousemode); -} - -//=========================================================================== -// -// ABackpack -// -//=========================================================================== - -IMPLEMENT_CLASS(AMapRevealer, false, false) - -//=========================================================================== -// -// AMapRevealer :: TryPickup -// -// The MapRevealer doesn't actually go in your inventory. Instead, it sets -// a flag on the level. -// -//=========================================================================== - -bool AMapRevealer::TryPickup (AActor *&toucher) -{ - level.flags2 |= LEVEL2_ALLMAP; - GoAwayAndDie (); - return true; -} - - -//=========================================================================== -// -// AScoreItem -// -//=========================================================================== - -IMPLEMENT_CLASS(AScoreItem, false, false) - -//=========================================================================== -// -// AScoreItem :: TryPickup -// -// Adds the value (Amount) of the item to the toucher's Score property. -// -//=========================================================================== - -bool AScoreItem::TryPickup (AActor *&toucher) -{ - toucher->Score += Amount; - GoAwayAndDie(); - return true; -} - diff --git a/src/g_inventory/a_pickups.h b/src/g_inventory/a_pickups.h index 00a8e6546..b366a6031 100644 --- a/src/g_inventory/a_pickups.h +++ b/src/g_inventory/a_pickups.h @@ -169,84 +169,6 @@ public: bool SpecialDropAction (AActor *dropper); }; -// Health is some item that gives the player health when picked up. -class PClassHealth : public PClassInventory -{ - DECLARE_CLASS(PClassHealth, PClassInventory) -protected: -public: - PClassHealth(); - virtual void DeriveData(PClass *newclass); - - FString LowHealthMessage; - int LowHealth; -}; - -class AHealth : public AInventory -{ - DECLARE_CLASS_WITH_META(AHealth, AInventory, PClassHealth) - -public: - int PrevHealth; - virtual bool TryPickup (AActor *&other); - virtual FString PickupMessage (); -}; - -// HealthPickup is some item that gives the player health when used. -class AHealthPickup : public AInventory -{ - DECLARE_CLASS (AHealthPickup, AInventory) -public: - int autousemode; - - - virtual void Serialize(FSerializer &arc); - virtual AInventory *CreateCopy (AActor *other); - virtual AInventory *CreateTossable (); - virtual bool HandlePickup (AInventory *item); - virtual bool Use (bool pickup); -}; - -// PuzzleItems work in conjunction with the UsePuzzleItem special -class PClassPuzzleItem : public PClassInventory -{ - DECLARE_CLASS(PClassPuzzleItem, PClassInventory); -protected: -public: - virtual void DeriveData(PClass *newclass); - FString PuzzFailMessage; -}; - -class APuzzleItem : public AInventory -{ - DECLARE_CLASS_WITH_META(APuzzleItem, AInventory, PClassPuzzleItem) -public: - - bool ShouldStay (); - bool Use (bool pickup); - bool HandlePickup (AInventory *item); - - int PuzzleItemNumber; -}; - -// A MapRevealer reveals the whole map for the player who picks it up. -class AMapRevealer : public AInventory -{ - DECLARE_CLASS (AMapRevealer, AInventory) -public: - bool TryPickup (AActor *&toucher); -}; - -// A score item is picked up without being added to the inventory. -// It differs from FakeInventory by doing nothing more than increasing the player's score. -class AScoreItem : public AInventory -{ - DECLARE_CLASS (AScoreItem, AInventory) - -public: - bool TryPickup(AActor *&toucher); -}; - extern PClassActor *QuestItemClasses[31]; diff --git a/src/g_inventory/a_puzzleitems.cpp b/src/g_inventory/a_puzzleitems.cpp index e2a538387..7617f6383 100644 --- a/src/g_inventory/a_puzzleitems.cpp +++ b/src/g_inventory/a_puzzleitems.cpp @@ -42,6 +42,7 @@ #include "c_console.h" #include "doomstat.h" #include "v_font.h" +#include "a_keys.h" IMPLEMENT_CLASS(PClassPuzzleItem, false, false) diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 8981538e7..bc217f4ae 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -79,6 +79,7 @@ #include "thingdef.h" #include "math/cmath.h" #include "a_armor.h" +#include "a_health.h" AActor *SingleActorFromTID(int tid, AActor *defactor); diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index e0e3e62b9..eae7edb00 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -59,6 +59,7 @@ #include "d_netinf.h" #include "a_morph.h" #include "virtual.h" +#include "a_health.h" static FRandom pr_obituary ("Obituary"); static FRandom pr_botrespawn ("BotRespawn"); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 2d36136f3..572c7656f 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -71,6 +71,7 @@ #include "virtual.h" #include "a_armor.h" #include "a_ammo.h" +#include "a_health.h" // MACROS ------------------------------------------------------------------ diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 7408573a0..eaeca6e9d 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -2248,16 +2248,7 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx) } // Special case: Assignment to a bitfield. - if (Base->ExprType == EFX_StructMember || Base->ExprType == EFX_ClassMember) - { - auto f = static_cast(Base)->membervar; - if (f->BitValue != -1 && !ctx.CheckReadOnly(f->Flags)) - { - IsBitWrite = f->BitValue; - return this; - } - } - + IsBitWrite = Base->GetBitValue(); return this; } @@ -5743,6 +5734,11 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) SAFE_RESOLVE(Object, ctx); + if (Identifier == FName("allmap")) + { + int a = 2; + } + // check for class or struct constants if the left side is a type name. if (Object->ValueType == TypeError) { diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index 5d0af0b49..c54c8dc62 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -318,6 +318,7 @@ public: virtual PPrototype *ReturnProto(); virtual VMFunction *GetDirectFunction(); virtual bool CheckReturn() { return false; } + virtual int GetBitValue() { return -1; } bool IsNumeric() const { return ValueType->isNumeric(); } bool IsFloat() const { return ValueType->GetRegType() == REGT_FLOAT && ValueType->GetRegCount() == 1; } bool IsInteger() const { return ValueType->isNumeric() && (ValueType->GetRegType() == REGT_INT); } @@ -1266,6 +1267,7 @@ public: FxExpression *Resolve(FCompileContext&); bool RequestAddress(FCompileContext &ctx, bool *writable); ExpEmit Emit(VMFunctionBuilder *build); + virtual int GetBitValue() { return membervar->BitValue; } }; class FxCVar : public FxExpression @@ -1296,6 +1298,7 @@ public: FxExpression *Resolve(FCompileContext&); bool RequestAddress(FCompileContext &ctx, bool *writable); ExpEmit Emit(VMFunctionBuilder *build); + virtual int GetBitValue() { return membervar->BitValue; } }; //========================================================================== @@ -1349,6 +1352,7 @@ public: FxExpression *Resolve(FCompileContext&); bool RequestAddress(FCompileContext &ctx, bool *writable); ExpEmit Emit(VMFunctionBuilder *build); + virtual int GetBitValue() { return membervar->BitValue; } }; //========================================================================== diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index e87602114..9bff91a80 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -71,6 +71,8 @@ #include "a_weaponpiece.h" #include "vmbuilder.h" #include "a_ammo.h" +#include "a_health.h" +#include "a_keys.h" extern TArray OptionalClassPtrs; diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 82810185a..a2b89da01 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -4,6 +4,10 @@ zscript/actor.txt zscript/actor_checks.txt zscript/shared/inventory.txt +zscript/shared/inv_misc.txt +zscript/shared/weapons.txt +zscript/shared/armor.txt +zscript/shared/powerups.txt zscript/shared/player.txt zscript/shared/morph.txt zscript/shared/botstuff.txt @@ -12,7 +16,7 @@ zscript/shared/blood.txt zscript/shared/debris.txt zscript/shared/decal.txt zscript/shared/splashes.txt -zscript/shared/pickups.txt +zscript/shared/itemeffects.txt zscript/shared/fountain.txt zscript/shared/spark.txt zscript/shared/soundsequence.txt diff --git a/wadsrc/static/zscript/shared/armor.txt b/wadsrc/static/zscript/shared/armor.txt new file mode 100644 index 000000000..3e7f57e21 --- /dev/null +++ b/wadsrc/static/zscript/shared/armor.txt @@ -0,0 +1,72 @@ +class Armor : Inventory native +{ + Default + { + Inventory.PickupSound "misc/armor_pkup"; + } +} + +class BasicArmor : Armor native +{ + + native int AbsorbCount; + native double SavePercent; + native int MaxAbsorb; + native int MaxFullAbsorb; + native int BonusCount; + native Name ArmorType; + native int ActualSaveAmount; + + Default + { + +Inventory.KEEPDEPLETED + } +} + +class BasicArmorBonus : Armor native +{ + native double SavePercent; // The default, for when you don't already have armor + native int MaxSaveAmount; + native int MaxAbsorb; + native int MaxFullAbsorb; + native int SaveAmount; + native int BonusCount; + native int BonusMax; + + Default + { + +Inventory.AUTOACTIVATE + +Inventory.ALWAYSPICKUP + Inventory.MaxAmount 0; + Armor.SavePercent 33.335; + } +} + +class BasicArmorPickup : Armor native +{ + + native double SavePercent; + native int MaxAbsorb; + native int MaxFullAbsorb; + native int SaveAmount; + + Default + { + +Inventory.AUTOACTIVATE; + Inventory.MaxAmount 0; + } +} + +class HexenArmor : Armor native +{ + + native double Slots[5]; + native double SlotsIncrement[4]; + + Default + { + +Inventory.KEEPDEPLETED + +Inventory.UNDROPPABLE + } +} + diff --git a/wadsrc/static/zscript/shared/inv_misc.txt b/wadsrc/static/zscript/shared/inv_misc.txt new file mode 100644 index 000000000..032c9e826 --- /dev/null +++ b/wadsrc/static/zscript/shared/inv_misc.txt @@ -0,0 +1,87 @@ +class ScoreItem : Inventory +{ + Default + { + Height 10; + +COUNTITEM + Inventory.Amount 1; + +Inventory.ALWAYSPICKUP + } + + override bool TryPickup (in out Actor toucher) + { + toucher.Score += Amount; + GoAwayAndDie(); + return true; + } +} + +class Health : Inventory native +{ + native int PrevHealth; + + Default + { + Inventory.Amount 1; + Inventory.MaxAmount 0; + Inventory.PickupSound "misc/health_pkup"; + } +} + +class HealthPickup : Inventory native +{ + native int autousemode; + + Default + { + Inventory.DefMaxAmount; + +INVENTORY.INVBAR + } +} + +class Key : Inventory native +{ + native uint8 KeyNumber; + + Default + { + +DONTGIB; // Don't disappear due to a crusher + Inventory.InterHubAmount 0; + Inventory.PickupSound "misc/k_pkup"; + } +} + +class MapRevealer : Inventory +{ + //=========================================================================== + // + // AMapRevealer :: TryPickup + // + // A MapRevealer reveals the whole map for the player who picks it up. + // The MapRevealer doesn't actually go in your inventory. Instead, it sets + // a flag on the level. + // + //=========================================================================== + + override bool TryPickup (in out Actor toucher) + { + level.allmap = true; + GoAwayAndDie (); + return true; + } +} + +class PuzzleItem : Inventory native +{ + native int PuzzleItemNumber; + + Default + { + +NOGRAVITY + +INVENTORY.INVBAR + Inventory.DefMaxAmount; + Inventory.UseSound "PuzzleSuccess"; + Inventory.PickupSound "misc/i_pkup"; + } +} + diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index 5192b4c93..4e5c13d88 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -87,108 +87,10 @@ class StateProvider : Inventory native action native void A_ResetReloadCounter(); } -class ScoreItem : Inventory native +class DehackedPickup : Inventory native { - Default - { - Height 10; - +COUNTITEM - Inventory.Amount 1; - +Inventory.ALWAYSPICKUP - } } -class Ammo : Inventory native -{ - native int BackpackAmount; - native int BackpackMaxAmount; - - Default - { - +INVENTORY.KEEPDEPLETED - Inventory.PickupSound "misc/ammo_pkup"; - } -} - -class BackpackItem : Inventory native -{ - native bool bDepleted; -} - -class Armor : Inventory native -{ - Default - { - Inventory.PickupSound "misc/armor_pkup"; - } -} - -class BasicArmor : Armor native -{ - - native int AbsorbCount; - native double SavePercent; - native int MaxAbsorb; - native int MaxFullAbsorb; - native int BonusCount; - native Name ArmorType; - native int ActualSaveAmount; - - Default - { - +Inventory.KEEPDEPLETED - } -} - -class BasicArmorBonus : Armor native -{ - native double SavePercent; // The default, for when you don't already have armor - native int MaxSaveAmount; - native int MaxAbsorb; - native int MaxFullAbsorb; - native int SaveAmount; - native int BonusCount; - native int BonusMax; - - Default - { - +Inventory.AUTOACTIVATE - +Inventory.ALWAYSPICKUP - Inventory.MaxAmount 0; - Armor.SavePercent 33.335; - } -} - -class BasicArmorPickup : Armor native -{ - - native double SavePercent; - native int MaxAbsorb; - native int MaxFullAbsorb; - native int SaveAmount; - - Default - { - +Inventory.AUTOACTIVATE; - Inventory.MaxAmount 0; - } -} - -class HexenArmor : Armor native -{ - - native double Slots[5]; - native double SlotsIncrement[4]; - - Default - { - +Inventory.KEEPDEPLETED - +Inventory.UNDROPPABLE - } -} - -class DehackedPickup : Inventory native {} - class FakeInventory : Inventory native { native bool Respawnable; @@ -201,463 +103,3 @@ class CustomInventory : StateProvider native DefaultStateUsage SUF_ACTOR|SUF_OVERLAY|SUF_ITEM; } } - -class Health : Inventory native -{ - native int PrevHealth; - - Default - { - Inventory.Amount 1; - Inventory.MaxAmount 0; - Inventory.PickupSound "misc/health_pkup"; - } -} - -class HealthPickup : Inventory native -{ - native int autousemode; - - Default - { - Inventory.DefMaxAmount; - +INVENTORY.INVBAR - } -} - -class Key : Inventory native -{ - native uint8 KeyNumber; - - Default - { - +DONTGIB; // Don't disappear due to a crusher - Inventory.InterHubAmount 0; - Inventory.PickupSound "misc/k_pkup"; - } -} - -class PowerupGiver : Inventory native -{ - - native Class PowerupType; - native int EffectTics; // Non-0 to override the powerup's default tics - native color BlendColor; // Non-0 to override the powerup's default blend - native Name Mode; // Meaning depends on powerup - used for Invulnerability and Invisibility - native double Strength; // Meaning depends on powerup - currently used only by Invisibility - - Default - { - Inventory.DefMaxAmount; - +INVENTORY.INVBAR - +INVENTORY.FANCYPICKUPSOUND - Inventory.PickupSound "misc/p_pkup"; - } -} - -class Powerup : Inventory native -{ - native int EffectTics; - native color BlendColor; - native Name Mode; // Meaning depends on powerup - used for Invulnerability and Invisibility - native double Strength; // Meaning depends on powerup - currently used only by Invisibility -} - -class PowerInvulnerable : Powerup native -{ - Default - { - Powerup.Duration -30; - inventory.icon "SPSHLD0"; - } -} - -class PowerStrength : Powerup native -{ - Default - { - Powerup.Duration 1; - Powerup.Color "ff 00 00", 0.5; - +INVENTORY.HUBPOWER - } -} - -class PowerInvisibility : Powerup native -{ - Default - { - +SHADOW; - Powerup.Duration -60; - Powerup.Strength 80; - Powerup.Mode "Fuzzy"; - } -} - -class PowerGhost : PowerInvisibility -{ - Default - { - +GHOST; - Powerup.Duration -60; - Powerup.Strength 60; - Powerup.Mode "None"; - } -} - -class PowerShadow : PowerInvisibility -{ - Default - { - +INVENTORY.HUBPOWER - Powerup.Duration -55; - Powerup.Strength 75; - Powerup.Mode "Cumulative"; - } -} - -class PowerIronFeet : Powerup native -{ - Default - { - Powerup.Duration -60; - Powerup.Color "00 ff 00", 0.125; - } -} - -class PowerMask : PowerIronFeet native -{ - Default - { - Powerup.Duration -80; - Powerup.Color "00 00 00", 0; - +INVENTORY.HUBPOWER - Inventory.Icon "I_MASK"; - } -} - -class PowerLightAmp : Powerup native -{ - Default - { - Powerup.Duration -120; - } -} - -class PowerTorch : PowerLightAmp native {} - -class PowerFlight : Powerup native -{ - Default - { - Powerup.Duration -60; - +INVENTORY.HUBPOWER - } -} - -class PowerWeaponLevel2 : Powerup native -{ - Default - { - Powerup.Duration -40; - Inventory.Icon "SPINBK0"; - +INVENTORY.NOTELEPORTFREEZE - } -} - -class PowerSpeed : Powerup native -{ - native int SpeedFlags; - - Default - { - Powerup.Duration -45; - Speed 1.5; - Inventory.Icon "SPBOOT0"; - +INVENTORY.NOTELEPORTFREEZE - } -} - -// Player Speed Trail (used by the Speed Powerup) ---------------------------- - -class PlayerSpeedTrail : Actor -{ - Default - { - +NOBLOCKMAP - +NOGRAVITY - Alpha 0.6; - RenderStyle "Translucent"; - } - - override void Tick() - { - Alpha -= .6 / 8; - if (Alpha <= 0) - { - Destroy (); - } - } -} - -class PowerMinotaur : Powerup native -{ - Default - { - Powerup.Duration -25; - Inventory.Icon "SPMINO0"; - } -} - -class PowerTargeter : Powerup native -{ - Default - { - Powerup.Duration -160; - +INVENTORY.HUBPOWER - } - States - { - Targeter: - TRGT A -1; - Stop; - TRGT B -1; - Stop; - TRGT C -1; - Stop; - } -} - -class PowerFrightener : Powerup native -{ - Default - { - Powerup.Duration -60; - } -} - -class PowerBuddha : Powerup native -{ - Default - { - Powerup.Duration -60; - } -} - -class PowerScanner : Powerup native -{ - Default - { - Powerup.Duration -80; - +INVENTORY.HUBPOWER - } -} - -class PowerTimeFreezer : Powerup native -{ - Default - { - Powerup.Duration -12; - } -} - -class PowerDamage : Powerup native -{ - Default - { - Powerup.Duration -25; - } -} - -class PowerProtection : Powerup native -{ - Default - { - Powerup.Duration -25; - } -} - -class PowerDrain : Powerup native -{ - Default - { - Powerup.Duration -60; - } -} - -class PowerRegeneration : Powerup native -{ - Default - { - Powerup.Duration -120; - Powerup.Strength 5; - } -} - -class PowerHighJump : Powerup native {} - -class PowerDoubleFiringSpeed : Powerup native {} - -class PowerMorph : Powerup native -{ - native Class PlayerClass; - native Class MorphFlash, UnMorphFlash; - native int MorphStyle; - native PlayerInfo MorphedPlayer; - native bool bInUndoMorph; - - Default - { - Powerup.Duration -40; - } -} - -class PowerInfiniteAmmo : Powerup native -{ - Default - { - Powerup.Duration -30; - } -} - -class MapRevealer : Inventory native {} - -class PuzzleItem : Inventory native -{ - native int PuzzleItemNumber; - - Default - { - +NOGRAVITY - +INVENTORY.INVBAR - Inventory.DefMaxAmount; - Inventory.UseSound "PuzzleSuccess"; - Inventory.PickupSound "misc/i_pkup"; - } -} - -class Weapon : StateProvider native -{ - enum EFireMode - { - PrimaryFire, - AltFire, - EitherFire - }; - - native uint WeaponFlags; - native class AmmoType1, AmmoType2; // Types of ammo used by this weapon - native int AmmoGive1, AmmoGive2; // Amount of each ammo to get when picking up weapon - native int MinAmmo1, MinAmmo2; // Minimum ammo needed to switch to this weapon - native int AmmoUse1, AmmoUse2; // How much ammo to use with each shot - native int Kickback; - native float YAdjust; // For viewing the weapon fullscreen (visual only so no need to be a double) - native sound UpSound, ReadySound; // Sounds when coming up and idle - native class SisterWeaponType; // Another weapon to pick up with this one - native class ProjectileType; // Projectile used by primary attack - native class AltProjectileType; // Projectile used by alternate attack - native int SelectionOrder; // Lower-numbered weapons get picked first - native int MinSelAmmo1, MinSelAmmo2; // Ignore in BestWeapon() if inadequate ammo - native double MoveCombatDist; // Used by bots, but do they *really* need it? - native int ReloadCounter; // For A_CheckForReload - native int BobStyle; // [XA] Bobbing style. Defines type of bobbing (e.g. Normal, Alpha) (visual only so no need to be a double) - native float BobSpeed; // [XA] Bobbing speed. Defines how quickly a weapon bobs. - native float BobRangeX, BobRangeY; // [XA] Bobbing range. Defines how far a weapon bobs in either direction. - native Ammo Ammo1, Ammo2; // In-inventory instance variables - native Weapon SisterWeapon; - native float FOVScale; - native int Crosshair; // 0 to use player's crosshair - native bool GivenAsMorphWeapon; - native bool bAltFire; // Set when this weapon's alternate fire is used. - native readonly bool bDehAmmo; - - Default - { - Inventory.PickupSound "misc/w_pkup"; - Weapon.DefaultKickback; - Weapon.BobSpeed 1.0; - Weapon.BobRangeX 1.0; - Weapon.BobRangeY 1.0; - +WEAPONSPAWN - DefaultStateUsage SUF_ACTOR|SUF_OVERLAY|SUF_WEAPON; - } - States - { - LightDone: - SHTG E 0 A_Light0; - Stop; - } - - native bool CheckAmmo(int fireMode, bool autoSwitch, bool requireAmmo = false, int ammocount = -1); - native bool DepleteAmmo(bool altFire, bool checkEnough = true, int ammouse = -1); - native virtual void EndPowerup(); - - virtual State GetReadyState () - { - return FindState('Ready'); - } - - virtual State GetUpState () - { - return FindState('Select'); - } - - virtual State GetDownState () - { - return FindState('Deselect'); - } - - virtual State GetAtkState (bool hold) - { - State s = null; - if (hold) s = FindState('Hold'); - if (s == null) s = FindState('Fire'); - return s; - } - - virtual State GetAltAtkState (bool hold) - { - State s = null; - if (hold) s = FindState('AltHold'); - if (s == null) s = FindState('AltFire'); - return s; - } - - native action void A_ZoomFactor(double scale = 1, int flags = 0); - native action void A_SetCrosshair(int xhair); - const ZOOM_INSTANT = 1; - const ZOOM_NOSCALETURNING = 2; - -} - -class WeaponGiver : Weapon native -{ - - native double DropAmmoFactor; - - Default - { - Weapon.AmmoGive1 -1; - Weapon.AmmoGive2 -1; - } -} - -class WeaponHolder : Inventory native -{ - native int PieceMask; - native Class PieceWeapon; - - Default - { - +NOBLOCKMAP - +NOSECTOR - +INVENTORY.UNDROPPABLE - } -} - -class WeaponPiece : Inventory native -{ - Default - { - +WEAPONSPAWN; - } -} diff --git a/wadsrc/static/zscript/shared/pickups.txt b/wadsrc/static/zscript/shared/itemeffects.txt similarity index 100% rename from wadsrc/static/zscript/shared/pickups.txt rename to wadsrc/static/zscript/shared/itemeffects.txt diff --git a/wadsrc/static/zscript/shared/powerups.txt b/wadsrc/static/zscript/shared/powerups.txt new file mode 100644 index 000000000..4c7a84efe --- /dev/null +++ b/wadsrc/static/zscript/shared/powerups.txt @@ -0,0 +1,282 @@ +class PowerupGiver : Inventory native +{ + + native Class PowerupType; + native int EffectTics; // Non-0 to override the powerup's default tics + native color BlendColor; // Non-0 to override the powerup's default blend + native Name Mode; // Meaning depends on powerup - used for Invulnerability and Invisibility + native double Strength; // Meaning depends on powerup - currently used only by Invisibility + + Default + { + Inventory.DefMaxAmount; + +INVENTORY.INVBAR + +INVENTORY.FANCYPICKUPSOUND + Inventory.PickupSound "misc/p_pkup"; + } +} + +class Powerup : Inventory native +{ + native int EffectTics; + native color BlendColor; + native Name Mode; // Meaning depends on powerup - used for Invulnerability and Invisibility + native double Strength; // Meaning depends on powerup - currently used only by Invisibility +} + +class PowerInvulnerable : Powerup native +{ + Default + { + Powerup.Duration -30; + inventory.icon "SPSHLD0"; + } +} + +class PowerStrength : Powerup native +{ + Default + { + Powerup.Duration 1; + Powerup.Color "ff 00 00", 0.5; + +INVENTORY.HUBPOWER + } +} + +class PowerInvisibility : Powerup native +{ + Default + { + +SHADOW; + Powerup.Duration -60; + Powerup.Strength 80; + Powerup.Mode "Fuzzy"; + } +} + +class PowerGhost : PowerInvisibility +{ + Default + { + +GHOST; + Powerup.Duration -60; + Powerup.Strength 60; + Powerup.Mode "None"; + } +} + +class PowerShadow : PowerInvisibility +{ + Default + { + +INVENTORY.HUBPOWER + Powerup.Duration -55; + Powerup.Strength 75; + Powerup.Mode "Cumulative"; + } +} + +class PowerIronFeet : Powerup native +{ + Default + { + Powerup.Duration -60; + Powerup.Color "00 ff 00", 0.125; + } +} + +class PowerMask : PowerIronFeet native +{ + Default + { + Powerup.Duration -80; + Powerup.Color "00 00 00", 0; + +INVENTORY.HUBPOWER + Inventory.Icon "I_MASK"; + } +} + +class PowerLightAmp : Powerup native +{ + Default + { + Powerup.Duration -120; + } +} + +class PowerTorch : PowerLightAmp native {} + +class PowerFlight : Powerup native +{ + Default + { + Powerup.Duration -60; + +INVENTORY.HUBPOWER + } +} + +class PowerWeaponLevel2 : Powerup native +{ + Default + { + Powerup.Duration -40; + Inventory.Icon "SPINBK0"; + +INVENTORY.NOTELEPORTFREEZE + } +} + +class PowerSpeed : Powerup native +{ + native int SpeedFlags; + + Default + { + Powerup.Duration -45; + Speed 1.5; + Inventory.Icon "SPBOOT0"; + +INVENTORY.NOTELEPORTFREEZE + } +} + +// Player Speed Trail (used by the Speed Powerup) ---------------------------- + +class PlayerSpeedTrail : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + Alpha 0.6; + RenderStyle "Translucent"; + } + + override void Tick() + { + Alpha -= .6 / 8; + if (Alpha <= 0) + { + Destroy (); + } + } +} + +class PowerMinotaur : Powerup native +{ + Default + { + Powerup.Duration -25; + Inventory.Icon "SPMINO0"; + } +} + +class PowerTargeter : Powerup native +{ + Default + { + Powerup.Duration -160; + +INVENTORY.HUBPOWER + } + States + { + Targeter: + TRGT A -1; + Stop; + TRGT B -1; + Stop; + TRGT C -1; + Stop; + } +} + +class PowerFrightener : Powerup native +{ + Default + { + Powerup.Duration -60; + } +} + +class PowerBuddha : Powerup native +{ + Default + { + Powerup.Duration -60; + } +} + +class PowerScanner : Powerup native +{ + Default + { + Powerup.Duration -80; + +INVENTORY.HUBPOWER + } +} + +class PowerTimeFreezer : Powerup native +{ + Default + { + Powerup.Duration -12; + } +} + +class PowerDamage : Powerup native +{ + Default + { + Powerup.Duration -25; + } +} + +class PowerProtection : Powerup native +{ + Default + { + Powerup.Duration -25; + } +} + +class PowerDrain : Powerup native +{ + Default + { + Powerup.Duration -60; + } +} + +class PowerRegeneration : Powerup native +{ + Default + { + Powerup.Duration -120; + Powerup.Strength 5; + } +} + +class PowerHighJump : Powerup native {} + +class PowerDoubleFiringSpeed : Powerup native {} + +class PowerMorph : Powerup native +{ + native Class PlayerClass; + native Class MorphFlash, UnMorphFlash; + native int MorphStyle; + native PlayerInfo MorphedPlayer; + native bool bInUndoMorph; + + Default + { + Powerup.Duration -40; + } +} + +class PowerInfiniteAmmo : Powerup native +{ + Default + { + Powerup.Duration -30; + } +} + diff --git a/wadsrc/static/zscript/shared/weapons.txt b/wadsrc/static/zscript/shared/weapons.txt new file mode 100644 index 000000000..c3ebf299d --- /dev/null +++ b/wadsrc/static/zscript/shared/weapons.txt @@ -0,0 +1,144 @@ +class Weapon : StateProvider native +{ + enum EFireMode + { + PrimaryFire, + AltFire, + EitherFire + }; + + native uint WeaponFlags; + native class AmmoType1, AmmoType2; // Types of ammo used by this weapon + native int AmmoGive1, AmmoGive2; // Amount of each ammo to get when picking up weapon + native int MinAmmo1, MinAmmo2; // Minimum ammo needed to switch to this weapon + native int AmmoUse1, AmmoUse2; // How much ammo to use with each shot + native int Kickback; + native float YAdjust; // For viewing the weapon fullscreen (visual only so no need to be a double) + native sound UpSound, ReadySound; // Sounds when coming up and idle + native class SisterWeaponType; // Another weapon to pick up with this one + native class ProjectileType; // Projectile used by primary attack + native class AltProjectileType; // Projectile used by alternate attack + native int SelectionOrder; // Lower-numbered weapons get picked first + native int MinSelAmmo1, MinSelAmmo2; // Ignore in BestWeapon() if inadequate ammo + native double MoveCombatDist; // Used by bots, but do they *really* need it? + native int ReloadCounter; // For A_CheckForReload + native int BobStyle; // [XA] Bobbing style. Defines type of bobbing (e.g. Normal, Alpha) (visual only so no need to be a double) + native float BobSpeed; // [XA] Bobbing speed. Defines how quickly a weapon bobs. + native float BobRangeX, BobRangeY; // [XA] Bobbing range. Defines how far a weapon bobs in either direction. + native Ammo Ammo1, Ammo2; // In-inventory instance variables + native Weapon SisterWeapon; + native float FOVScale; + native int Crosshair; // 0 to use player's crosshair + native bool GivenAsMorphWeapon; + native bool bAltFire; // Set when this weapon's alternate fire is used. + native readonly bool bDehAmmo; + + Default + { + Inventory.PickupSound "misc/w_pkup"; + Weapon.DefaultKickback; + Weapon.BobSpeed 1.0; + Weapon.BobRangeX 1.0; + Weapon.BobRangeY 1.0; + +WEAPONSPAWN + DefaultStateUsage SUF_ACTOR|SUF_OVERLAY|SUF_WEAPON; + } + States + { + LightDone: + SHTG E 0 A_Light0; + Stop; + } + + native bool CheckAmmo(int fireMode, bool autoSwitch, bool requireAmmo = false, int ammocount = -1); + native bool DepleteAmmo(bool altFire, bool checkEnough = true, int ammouse = -1); + native virtual void EndPowerup(); + + virtual State GetReadyState () + { + return FindState('Ready'); + } + + virtual State GetUpState () + { + return FindState('Select'); + } + + virtual State GetDownState () + { + return FindState('Deselect'); + } + + virtual State GetAtkState (bool hold) + { + State s = null; + if (hold) s = FindState('Hold'); + if (s == null) s = FindState('Fire'); + return s; + } + + virtual State GetAltAtkState (bool hold) + { + State s = null; + if (hold) s = FindState('AltHold'); + if (s == null) s = FindState('AltFire'); + return s; + } + + native action void A_ZoomFactor(double scale = 1, int flags = 0); + native action void A_SetCrosshair(int xhair); + const ZOOM_INSTANT = 1; + const ZOOM_NOSCALETURNING = 2; + +} + +class WeaponGiver : Weapon native +{ + + native double DropAmmoFactor; + + Default + { + Weapon.AmmoGive1 -1; + Weapon.AmmoGive2 -1; + } +} + +class WeaponHolder : Inventory native +{ + native int PieceMask; + native Class PieceWeapon; + + Default + { + +NOBLOCKMAP + +NOSECTOR + +INVENTORY.UNDROPPABLE + } +} + +class WeaponPiece : Inventory native +{ + Default + { + +WEAPONSPAWN; + } +} + +class Ammo : Inventory native +{ + native int BackpackAmount; + native int BackpackMaxAmount; + + Default + { + +INVENTORY.KEEPDEPLETED + Inventory.PickupSound "misc/ammo_pkup"; + } +} + +class BackpackItem : Inventory native +{ + native bool bDepleted; +} + From 8a50004f55b4524c19c9bfb576d5f7b52c4fcfb8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 30 Nov 2016 15:54:01 +0100 Subject: [PATCH 182/185] - cleanup of the virtual function definitions for inventory items. Let's better use 'virtual' and 'override' everywhere to make sure that nothing gets overlooked. - added call wrappers and script hooks for all relevant virtuals in AInventory. - made GetSpeedFactor and GetNoTeleportFreeze entirely scripted because they are too trivial - also do them iteratively, just like HandlePickup, because it's just a better way to do this stuff. --- src/d_dehacked.cpp | 2 +- src/g_inventory/a_ammo.h | 18 +-- src/g_inventory/a_armor.h | 34 ++-- src/g_inventory/a_artifacts.cpp | 26 --- src/g_inventory/a_artifacts.h | 148 ++++++++--------- src/g_inventory/a_health.h | 14 +- src/g_inventory/a_keys.h | 10 +- src/g_inventory/a_pickups.cpp | 179 ++++++++++++++++++--- src/g_inventory/a_pickups.h | 119 ++++++++------ src/g_inventory/a_weaponpiece.cpp | 2 +- src/g_inventory/a_weaponpiece.h | 14 +- src/g_inventory/a_weapons.cpp | 4 +- src/g_inventory/a_weapons.h | 31 ++-- src/g_shared/a_morph.cpp | 15 +- wadsrc/static/zscript/shared/inventory.txt | 13 +- wadsrc/static/zscript/shared/powerups.txt | 6 + 16 files changed, 390 insertions(+), 245 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index c0ea00f5e..e2c5a6ea3 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -3157,7 +3157,7 @@ FString ADehackedPickup::PickupMessage () bool ADehackedPickup::ShouldStay () { if (RealPickup != nullptr) - return RealPickup->ShouldStay (); + return RealPickup->CallShouldStay (); else return true; } diff --git a/src/g_inventory/a_ammo.h b/src/g_inventory/a_ammo.h index fe5e1759e..643d4b924 100644 --- a/src/g_inventory/a_ammo.h +++ b/src/g_inventory/a_ammo.h @@ -18,11 +18,11 @@ class AAmmo : public AInventory DECLARE_CLASS_WITH_META(AAmmo, AInventory, PClassAmmo) public: - void Serialize(FSerializer &arc); - AInventory *CreateCopy (AActor *other); - bool HandlePickup (AInventory *item); + virtual void Serialize(FSerializer &arc) override; + virtual AInventory *CreateCopy (AActor *other) override; + virtual bool HandlePickup (AInventory *item) override; + virtual AInventory *CreateTossable () override; PClassActor *GetParentAmmo () const; - AInventory *CreateTossable (); int BackpackAmount, BackpackMaxAmount; }; @@ -35,11 +35,11 @@ class ABackpackItem : public AInventory DECLARE_CLASS (ABackpackItem, AInventory) public: - void Serialize(FSerializer &arc); - bool HandlePickup (AInventory *item); - AInventory *CreateCopy (AActor *other); - AInventory *CreateTossable (); - void DetachFromOwner (); + virtual void Serialize(FSerializer &arc) override; + virtual bool HandlePickup (AInventory *item) override; + virtual AInventory *CreateCopy (AActor *other) override; + virtual AInventory *CreateTossable () override; + virtual void DetachFromOwner () override; bool bDepleted; }; diff --git a/src/g_inventory/a_armor.h b/src/g_inventory/a_armor.h index b7b2dad3e..63febda91 100644 --- a/src/g_inventory/a_armor.h +++ b/src/g_inventory/a_armor.h @@ -16,11 +16,11 @@ class ABasicArmor : public AArmor DECLARE_CLASS (ABasicArmor, AArmor) public: - virtual void Serialize(FSerializer &arc); - virtual void Tick (); - virtual AInventory *CreateCopy (AActor *other); - virtual bool HandlePickup (AInventory *item); - virtual void AbsorbDamage (int damage, FName damageType, int &newdamage); + virtual void Serialize(FSerializer &arc) override; + virtual void Tick () override; + virtual AInventory *CreateCopy (AActor *other) override; + virtual bool HandlePickup (AInventory *item) override; + virtual void AbsorbDamage (int damage, FName damageType, int &newdamage) override; int AbsorbCount; double SavePercent; @@ -37,9 +37,9 @@ class ABasicArmorPickup : public AArmor DECLARE_CLASS (ABasicArmorPickup, AArmor) public: - virtual void Serialize(FSerializer &arc); - virtual AInventory *CreateCopy (AActor *other); - virtual bool Use (bool pickup); + virtual void Serialize(FSerializer &arc) override; + virtual AInventory *CreateCopy (AActor *other) override; + virtual bool Use (bool pickup) override; double SavePercent; int MaxAbsorb; @@ -53,9 +53,9 @@ class ABasicArmorBonus : public AArmor DECLARE_CLASS (ABasicArmorBonus, AArmor) public: - virtual void Serialize(FSerializer &arc); - virtual AInventory *CreateCopy (AActor *other); - virtual bool Use (bool pickup); + virtual void Serialize(FSerializer &arc) override; + virtual AInventory *CreateCopy (AActor *other) override; + virtual bool Use (bool pickup) override; double SavePercent; // The default, for when you don't already have armor int MaxSaveAmount; @@ -73,12 +73,12 @@ class AHexenArmor : public AArmor DECLARE_CLASS (AHexenArmor, AArmor) public: - virtual void Serialize(FSerializer &arc); - virtual AInventory *CreateCopy (AActor *other); - virtual AInventory *CreateTossable (); - virtual bool HandlePickup (AInventory *item); - virtual void AbsorbDamage (int damage, FName damageType, int &newdamage); - void DepleteOrDestroy(); + virtual void Serialize(FSerializer &arc) override; + virtual AInventory *CreateCopy (AActor *other) override; + virtual AInventory *CreateTossable () override; + virtual bool HandlePickup (AInventory *item) override; + virtual void AbsorbDamage (int damage, FName damageType, int &newdamage) override; + virtual void DepleteOrDestroy() override; double Slots[5]; double SlotsIncrement[4]; diff --git a/src/g_inventory/a_artifacts.cpp b/src/g_inventory/a_artifacts.cpp index 1198b9153..a75b9ecd4 100644 --- a/src/g_inventory/a_artifacts.cpp +++ b/src/g_inventory/a_artifacts.cpp @@ -373,18 +373,6 @@ void APowerup::OwnerDied () Destroy (); } -//=========================================================================== -// -// AInventory :: GetNoTeleportFreeze -// -//=========================================================================== - -bool APowerup::GetNoTeleportFreeze () -{ - if (ItemFlags & IF_NOTELEPORTFREEZE) return true; - return Super::GetNoTeleportFreeze(); -} - // Invulnerability Powerup --------------------------------------------------- IMPLEMENT_CLASS(APowerInvulnerable, false, false) @@ -1213,20 +1201,6 @@ void APowerSpeed::Serialize(FSerializer &arc) arc("speedflags", SpeedFlags); } -//=========================================================================== -// -// APowerSpeed :: GetSpeedFactor -// -//=========================================================================== - -double APowerSpeed ::GetSpeedFactor () -{ - if (Inventory != NULL) - return Speed * Inventory->GetSpeedFactor(); - else - return Speed; -} - //=========================================================================== // // APowerSpeed :: DoEffect diff --git a/src/g_inventory/a_artifacts.h b/src/g_inventory/a_artifacts.h index c3a0f31f0..7e9956d73 100644 --- a/src/g_inventory/a_artifacts.h +++ b/src/g_inventory/a_artifacts.h @@ -11,18 +11,15 @@ class APowerup : public AInventory { DECLARE_CLASS (APowerup, AInventory) public: - virtual void Tick (); + virtual void Tick () override; virtual void Destroy () override; - virtual bool HandlePickup (AInventory *item); - virtual AInventory *CreateCopy (AActor *other); - virtual AInventory *CreateTossable (); - - - virtual void Serialize(FSerializer &arc); - virtual void OwnerDied (); - virtual bool GetNoTeleportFreeze(); - virtual PalEntry GetBlend (); - virtual bool DrawPowerup (int x, int y); + virtual bool HandlePickup (AInventory *item) override; + virtual AInventory *CreateCopy (AActor *other) override; + virtual AInventory *CreateTossable () override; + virtual void Serialize(FSerializer &arc) override; + virtual void OwnerDied () override; + virtual PalEntry GetBlend () override; + virtual bool DrawPowerup (int x, int y) override; int EffectTics; PalEntry BlendColor; @@ -31,7 +28,7 @@ public: protected: virtual void InitEffect (); - virtual void DoEffect (); + virtual void DoEffect () override; virtual void EndEffect (); friend void EndAllPowerupEffects(AInventory *item); @@ -52,9 +49,8 @@ class APowerupGiver : public AInventory { DECLARE_CLASS_WITH_META (APowerupGiver, AInventory, PClassPowerupGiver) public: - virtual bool Use (bool pickup); - - virtual void Serialize(FSerializer &arc); + virtual bool Use (bool pickup) override; + virtual void Serialize(FSerializer &arc) override; PClassActor *PowerupType; @@ -68,10 +64,10 @@ class APowerInvulnerable : public APowerup { DECLARE_CLASS (APowerInvulnerable, APowerup) protected: - void InitEffect (); - void DoEffect (); - void EndEffect (); - int AlterWeaponSprite (visstyle_t *vis); + virtual void InitEffect () override; + virtual void DoEffect () override; + virtual void EndEffect () override; + virtual int AlterWeaponSprite (visstyle_t *vis) override; }; class APowerStrength : public APowerup @@ -80,44 +76,44 @@ class APowerStrength : public APowerup public: PalEntry GetBlend (); protected: - void InitEffect (); - void Tick (); - bool HandlePickup (AInventory *item); + virtual void InitEffect () override; + virtual void Tick () override; + virtual bool HandlePickup (AInventory *item) override; }; class APowerInvisibility : public APowerup { DECLARE_CLASS (APowerInvisibility, APowerup) protected: - bool HandlePickup (AInventory *item); - void InitEffect (); - void DoEffect (); - void EndEffect (); - int AlterWeaponSprite (visstyle_t *vis); + virtual bool HandlePickup (AInventory *item) override; + virtual void InitEffect () override; + virtual void DoEffect () override; + virtual void EndEffect () override; + virtual int AlterWeaponSprite (visstyle_t *vis) override; }; class APowerIronFeet : public APowerup { DECLARE_CLASS (APowerIronFeet, APowerup) public: - void AbsorbDamage (int damage, FName damageType, int &newdamage); - void DoEffect (); + virtual void AbsorbDamage (int damage, FName damageType, int &newdamage) override; + virtual void DoEffect () override; }; class APowerMask : public APowerIronFeet { DECLARE_CLASS (APowerMask, APowerIronFeet) public: - void AbsorbDamage (int damage, FName damageType, int &newdamage); - void DoEffect (); + virtual void AbsorbDamage (int damage, FName damageType, int &newdamage) override; + virtual void DoEffect () override; }; class APowerLightAmp : public APowerup { DECLARE_CLASS (APowerLightAmp, APowerup) protected: - void DoEffect (); - void EndEffect (); + virtual void DoEffect () override; + virtual void EndEffect () override; }; class APowerTorch : public APowerLightAmp @@ -125,9 +121,9 @@ class APowerTorch : public APowerLightAmp DECLARE_CLASS (APowerTorch, APowerLightAmp) public: - virtual void Serialize(FSerializer &arc); + virtual void Serialize(FSerializer &arc) override; protected: - void DoEffect (); + virtual void DoEffect () override; int NewTorch, NewTorchDelta; }; @@ -135,14 +131,13 @@ class APowerFlight : public APowerup { DECLARE_CLASS (APowerFlight, APowerup) public: - bool DrawPowerup (int x, int y); - - virtual void Serialize(FSerializer &arc); + virtual bool DrawPowerup (int x, int y) override; + virtual void Serialize(FSerializer &arc) override; protected: - void InitEffect (); - void Tick (); - void EndEffect (); + virtual void InitEffect () override; + virtual void Tick () override; + virtual void EndEffect () override; private: bool HitCenterFrame; @@ -152,18 +147,17 @@ class APowerWeaponLevel2 : public APowerup { DECLARE_CLASS (APowerWeaponLevel2, APowerup) protected: - void InitEffect (); - void EndEffect (); + virtual void InitEffect () override; + virtual void EndEffect () override; }; class APowerSpeed : public APowerup { DECLARE_CLASS (APowerSpeed, APowerup) protected: - void DoEffect (); + virtual void DoEffect () override; - virtual void Serialize(FSerializer &arc); - double GetSpeedFactor(); + virtual void Serialize(FSerializer &arc) override; public: int SpeedFlags; }; @@ -184,95 +178,95 @@ class APowerTargeter : public APowerup { DECLARE_CLASS (APowerTargeter, APowerup) protected: - void InitEffect (); - void DoEffect (); - void EndEffect (); + virtual void InitEffect () override; + virtual void DoEffect () override; + virtual void EndEffect () override; void PositionAccuracy (); - void Travelled (); - void AttachToOwner(AActor *other); - bool HandlePickup(AInventory *item); + virtual void Travelled () override; + virtual void AttachToOwner(AActor *other) override; + virtual bool HandlePickup(AInventory *item) override; }; class APowerFrightener : public APowerup { DECLARE_CLASS (APowerFrightener, APowerup) protected: - void InitEffect (); - void EndEffect (); + virtual void InitEffect () override; + virtual void EndEffect () override; }; class APowerBuddha : public APowerup { DECLARE_CLASS (APowerBuddha, APowerup) protected: - void InitEffect (); - void EndEffect (); + virtual void InitEffect () override; + virtual void EndEffect () override; }; class APowerTimeFreezer : public APowerup { DECLARE_CLASS( APowerTimeFreezer, APowerup ) protected: - void InitEffect( ); - void DoEffect( ); - void EndEffect( ); + virtual void InitEffect() override; + virtual void DoEffect() override; + virtual void EndEffect() override; }; class APowerDamage : public APowerup { DECLARE_CLASS( APowerDamage, APowerup ) protected: - void InitEffect (); - void EndEffect (); - virtual void ModifyDamage (int damage, FName damageType, int &newdamage, bool passive); + virtual void InitEffect () override; + virtual void EndEffect () override; + virtual void ModifyDamage (int damage, FName damageType, int &newdamage, bool passive) override; }; class APowerProtection : public APowerup { DECLARE_CLASS( APowerProtection, APowerup ) protected: - void InitEffect (); - void EndEffect (); - virtual void ModifyDamage (int damage, FName damageType, int &newdamage, bool passive); + virtual void InitEffect () override; + virtual void EndEffect () override; + virtual void ModifyDamage (int damage, FName damageType, int &newdamage, bool passive) override; }; class APowerDrain : public APowerup { DECLARE_CLASS( APowerDrain, APowerup ) protected: - void InitEffect( ); - void EndEffect( ); + virtual void InitEffect() override; + virtual void EndEffect() override; }; class APowerRegeneration : public APowerup { DECLARE_CLASS( APowerRegeneration, APowerup ) protected: - void DoEffect(); + virtual void DoEffect() override; }; class APowerHighJump : public APowerup { DECLARE_CLASS( APowerHighJump, APowerup ) protected: - void InitEffect( ); - void EndEffect( ); + virtual void InitEffect() override; + virtual void EndEffect() override; }; class APowerDoubleFiringSpeed : public APowerup { DECLARE_CLASS( APowerDoubleFiringSpeed, APowerup ) protected: - void InitEffect( ); - void EndEffect( ); + virtual void InitEffect() override; + virtual void EndEffect() override; }; class APowerInfiniteAmmo : public APowerup { DECLARE_CLASS( APowerInfiniteAmmo, APowerup ) protected: - void InitEffect( ); - void EndEffect( ); + virtual void InitEffect() override; + virtual void EndEffect() override; }; class APowerMorph : public APowerup @@ -280,7 +274,7 @@ class APowerMorph : public APowerup DECLARE_CLASS( APowerMorph, APowerup ) public: - virtual void Serialize(FSerializer &arc); + virtual void Serialize(FSerializer &arc) override; void SetNoCallUndoMorph() { bInUndoMorph = true; } // Variables @@ -291,8 +285,8 @@ public: bool bInUndoMorph; // Because P_UndoPlayerMorph() can call EndEffect recursively protected: - void InitEffect (); - void EndEffect (); + virtual void InitEffect () override; + virtual void EndEffect () override; }; #endif //__A_ARTIFACTS_H__ diff --git a/src/g_inventory/a_health.h b/src/g_inventory/a_health.h index a462bbfbd..af282031c 100644 --- a/src/g_inventory/a_health.h +++ b/src/g_inventory/a_health.h @@ -21,8 +21,8 @@ class AHealth : public AInventory public: int PrevHealth; - virtual bool TryPickup (AActor *&other); - virtual FString PickupMessage (); + virtual bool TryPickup (AActor *&other) override; + virtual FString PickupMessage () override; }; // HealthPickup is some item that gives the player health when used. @@ -33,10 +33,10 @@ public: int autousemode; - virtual void Serialize(FSerializer &arc); - virtual AInventory *CreateCopy (AActor *other); - virtual AInventory *CreateTossable (); - virtual bool HandlePickup (AInventory *item); - virtual bool Use (bool pickup); + virtual void Serialize(FSerializer &arc) override; + virtual AInventory *CreateCopy (AActor *other) override; + virtual AInventory *CreateTossable () override; + virtual bool HandlePickup (AInventory *item) override; + virtual bool Use (bool pickup) override; }; diff --git a/src/g_inventory/a_keys.h b/src/g_inventory/a_keys.h index fd46b416c..eda0473a3 100644 --- a/src/g_inventory/a_keys.h +++ b/src/g_inventory/a_keys.h @@ -7,12 +7,12 @@ class AKey : public AInventory { DECLARE_CLASS (AKey, AInventory) public: - virtual bool HandlePickup (AInventory *item); + virtual bool HandlePickup (AInventory *item) override; BYTE KeyNumber; protected: - virtual bool ShouldStay (); + virtual bool ShouldStay () override; }; bool P_CheckKeys (AActor *owner, int keynum, bool remote); @@ -37,9 +37,9 @@ class APuzzleItem : public AInventory DECLARE_CLASS_WITH_META(APuzzleItem, AInventory, PClassPuzzleItem) public: - bool ShouldStay (); - bool Use (bool pickup); - bool HandlePickup (AInventory *item); + virtual bool ShouldStay () override; + virtual bool Use (bool pickup) override; + virtual bool HandlePickup (AInventory *item) override; int PuzzleItemNumber; }; diff --git a/src/g_inventory/a_pickups.cpp b/src/g_inventory/a_pickups.cpp index cf5dddcf3..237de2ce9 100644 --- a/src/g_inventory/a_pickups.cpp +++ b/src/g_inventory/a_pickups.cpp @@ -399,6 +399,25 @@ void AInventory::DoEffect () { } +DEFINE_ACTION_FUNCTION(AInventory, DoEffect) +{ + PARAM_SELF_PROLOGUE(AInventory); + self->DoEffect(); + return 0; +} + +void AInventory::CallDoEffect() +{ + IFVIRTUAL(AInventory, DoEffect) + { + VMValue params[1] = { (DObject*)this }; + VMFrameStack stack; + stack.Call(func, params, 1, nullptr, 0, nullptr); + } + else DoEffect(); +} + + //=========================================================================== // // AInventory :: Travelled @@ -437,7 +456,7 @@ bool AInventory::HandlePickup (AInventory *item) { if (item->GetClass() == GetClass()) { - if (Amount < MaxAmount || (sv_unlimited_pickup && !item->ShouldStay())) + if (Amount < MaxAmount || (sv_unlimited_pickup && !item->CallShouldStay())) { if (Amount > 0 && Amount + item->Amount < 0) { @@ -506,7 +525,7 @@ bool AInventory::GoAway () return false; } - if (!ShouldStay ()) + if (!CallShouldStay ()) { Hide (); if (ShouldRespawn ()) @@ -776,16 +795,25 @@ void AInventory::ModifyDamage (int damage, FName damageType, int &newdamage, boo // //=========================================================================== -double AInventory::GetSpeedFactor () +double AInventory::GetSpeedFactor() { - if (Inventory != NULL) + double factor = 1.; + auto self = this; + while (self != nullptr) { - return Inventory->GetSpeedFactor(); - } - else - { - return 1.; + IFVIRTUALPTR(self, AInventory, GetSpeedFactor) + { + VMValue params[2] = { (DObject*)self }; + VMReturn ret; + VMFrameStack stack; + double retval; + ret.FloatAt(&retval); + stack.Call(func, params, 1, &ret, 1, nullptr); + factor *= retval; + } + self = self->Inventory; } + return factor; } //=========================================================================== @@ -796,15 +824,22 @@ double AInventory::GetSpeedFactor () bool AInventory::GetNoTeleportFreeze () { - // do not check the flag here because it's only active when used on PowerUps, not on PowerupGivers. - if (Inventory != NULL) + auto self = this; + while (self != nullptr) { - return Inventory->GetNoTeleportFreeze(); - } - else - { - return false; + IFVIRTUALPTR(self, AInventory, GetNoTeleportFreeze) + { + VMValue params[2] = { (DObject*)self }; + VMReturn ret; + VMFrameStack stack; + int retval; + ret.IntAt(&retval); + stack.Call(func, params, 1, &ret, 1, nullptr); + if (retval) return true; + } + self = self->Inventory; } + return false; } //=========================================================================== @@ -953,7 +988,7 @@ void AInventory::Touch (AActor *toucher) if (!CallTryPickup (toucher, &toucher)) return; // This is the only situation when a pickup flash should ever play. - if (PickupFlash != NULL && !ShouldStay()) + if (PickupFlash != NULL && !CallShouldStay()) { Spawn(PickupFlash, Pos(), ALLOW_REPLACE); } @@ -1102,6 +1137,26 @@ void AInventory::PlayPickupSound (AActor *toucher) S_Sound (toucher, chan, PickupSound, 1, atten); } +DEFINE_ACTION_FUNCTION(AInventory, PlayPickupSound) +{ + PARAM_SELF_PROLOGUE(AInventory); + PARAM_OBJECT(other, AActor); + self->PlayPickupSound(other); + return 0; +} + +void AInventory::CallPlayPickupSound(AActor *other) +{ + IFVIRTUAL(AInventory, PlayPickupSound) + { + VMValue params[2] = { (DObject*)this, (DObject*)other }; + VMFrameStack stack; + stack.Call(func, params, 2, nullptr, 0, nullptr); + } + else PlayPickupSound(other); +} + + //=========================================================================== // // AInventory :: ShouldStay @@ -1115,6 +1170,28 @@ bool AInventory::ShouldStay () return false; } +DEFINE_ACTION_FUNCTION(AInventory, ShouldStay) +{ + PARAM_SELF_PROLOGUE(AInventory); + ACTION_RETURN_BOOL(self->ShouldStay()); +} + +bool AInventory::CallShouldStay() +{ + IFVIRTUAL(AInventory, ShouldStay) + { + VMValue params[1] = { (DObject*)this }; + VMReturn ret; + VMFrameStack stack; + int retval; + ret.IntAt(&retval); + stack.Call(func, params, 1, &ret, 1, nullptr); + return !!retval; + } + else return ShouldStay(); +} + + //=========================================================================== // // AInventory :: Destroy @@ -1416,6 +1493,14 @@ bool AInventory::TryPickupRestricted (AActor *&toucher) return false; } +DEFINE_ACTION_FUNCTION(AInventory, TryPickupRestricted) +{ + PARAM_SELF_PROLOGUE(AInventory); + PARAM_POINTER(toucher, AActor*); + ACTION_RETURN_BOOL(self->TryPickupRestricted(*toucher)); +} + + //=========================================================================== // // AInventory :: CallTryPickup @@ -1445,14 +1530,27 @@ bool AInventory::CallTryPickup (AActor *toucher, AActor **toucher_return) else res = TryPickup(toucher); } else if (!(ItemFlags & IF_RESTRICTABSOLUTELY)) - res = TryPickupRestricted(toucher); // let an item decide for itself how it will handle this + { + // let an item decide for itself how it will handle this + IFVIRTUAL(AInventory, TryPickupRestricted) + { + VMValue params[2] = { (DObject*)this, (void*)&toucher }; + VMReturn ret; + VMFrameStack stack; + int retval; + ret.IntAt(&retval); + stack.Call(func, params, 2, &ret, 1, nullptr); + res = !!retval; + } + else res = TryPickupRestricted(toucher); + } else return false; // Morph items can change the toucher so we need an option to return this info. if (toucher_return != NULL) *toucher_return = toucher; - if (!res && (ItemFlags & IF_ALWAYSPICKUP) && !ShouldStay()) + if (!res && (ItemFlags & IF_ALWAYSPICKUP) && !CallShouldStay()) { res = true; GoAwayAndDie(); @@ -1576,6 +1674,26 @@ void AInventory::AttachToOwner (AActor *other) other->AddInventory (this); } +DEFINE_ACTION_FUNCTION(AInventory, AttachToOwner) +{ + PARAM_SELF_PROLOGUE(AInventory); + PARAM_OBJECT(other, AActor); + self->AttachToOwner(other); + return 0; +} + +void AInventory::CallAttachToOwner(AActor *other) +{ + IFVIRTUAL(AInventory, AttachToOwner) + { + VMValue params[2] = { (DObject*)this, (DObject*)other }; + VMFrameStack stack; + stack.Call(func, params, 2, nullptr, 0, nullptr); + } + else AttachToOwner(other); +} + + //=========================================================================== // // AInventory :: DetachFromOwner @@ -1589,6 +1707,29 @@ void AInventory::DetachFromOwner () { } +DEFINE_ACTION_FUNCTION(AInventory, DetachFromOwner) +{ + PARAM_SELF_PROLOGUE(AInventory); + self->DetachFromOwner(); + return 0; +} + +void AInventory::CallDetachFromOwner() +{ + IFVIRTUAL(AInventory, DetachFromOwner) + { + VMValue params[1] = { (DObject*)this }; + VMFrameStack stack; + stack.Call(func, params, 1, nullptr, 0, nullptr); + } + else DetachFromOwner(); +} + +//=========================================================================== +//=========================================================================== + + + IMPLEMENT_CLASS(AStateProvider, false, false) IMPLEMENT_CLASS(ACustomInventory, false, false) diff --git a/src/g_inventory/a_pickups.h b/src/g_inventory/a_pickups.h index b366a6031..99dad8713 100644 --- a/src/g_inventory/a_pickups.h +++ b/src/g_inventory/a_pickups.h @@ -70,31 +70,87 @@ class AInventory : public AActor DECLARE_CLASS_WITH_META(AInventory, AActor, PClassInventory) HAS_OBJECT_POINTERS public: - virtual void Touch (AActor *toucher); - virtual void Serialize(FSerializer &arc); - - virtual void MarkPrecacheSounds() const; - virtual void BeginPlay (); + virtual void Touch (AActor *toucher) override; + virtual void Serialize(FSerializer &arc) override; + virtual void MarkPrecacheSounds() const override; + virtual void BeginPlay () override; virtual void Destroy () override; + virtual void Tick() override; + virtual bool Grind(bool items) override; + + // virtual methods that only get overridden by special internal classes, like DehackedPickup. + // There is no need to expose these to scripts. virtual void DepleteOrDestroy (); - virtual void Tick (); virtual bool ShouldRespawn (); - virtual bool ShouldStay (); - virtual void Hide (); - bool CallTryPickup (AActor *toucher, AActor **toucher_return = NULL); virtual void DoPickupSpecial (AActor *toucher); + + // methods that can be overridden by scripts, plus their callers. virtual bool SpecialDropAction (AActor *dropper); bool CallSpecialDropAction(AActor *dropper); - virtual bool DrawPowerup (int x, int y); - virtual void DoEffect (); - virtual bool Grind(bool items); - virtual FString PickupMessage (); + virtual bool TryPickup(AActor *&toucher); + virtual bool TryPickupRestricted(AActor *&toucher); + bool CallTryPickup(AActor *toucher, AActor **toucher_return = NULL); // This wraps both virtual methods plus a few more checks. + + virtual AInventory *CreateCopy(AActor *other); + AInventory *CallCreateCopy(AActor *other); + + virtual AInventory *CreateTossable(); + AInventory *CallCreateTossable(); + + virtual FString PickupMessage(); FString GetPickupMessage(); - virtual void PlayPickupSound (AActor *toucher); - bool DoRespawn (); + virtual bool HandlePickup(AInventory *item); + bool CallHandlePickup(AInventory *item); + + virtual bool Use(bool pickup); + bool CallUse(bool pickup); + + virtual PalEntry GetBlend(); + PalEntry CallGetBlend(); + + virtual bool ShouldStay(); + bool CallShouldStay(); + + virtual void DoEffect(); + void CallDoEffect(); + + virtual void PlayPickupSound(AActor *toucher); + void CallPlayPickupSound(AActor *toucher); + + virtual void AttachToOwner(AActor *other); + void CallAttachToOwner(AActor *other); + + virtual void DetachFromOwner(); + void CallDetachFromOwner(); + + // still need to be done. + virtual void AbsorbDamage(int damage, FName damageType, int &newdamage); + virtual void ModifyDamage(int damage, FName damageType, int &newdamage, bool passive); + + // visual stuff is for later. Right now the VM has not yet access to the needed functionality. + virtual bool DrawPowerup(int x, int y); + virtual int AlterWeaponSprite(visstyle_t *vis); + + + // virtual on the script side only. + double GetSpeedFactor(); + bool GetNoTeleportFreeze(); + // Stuff for later when more features are exported. + virtual void Travelled(); + virtual void OwnerDied(); + + + bool GoAway(); + void GoAwayAndDie(); + + void Hide(); + void BecomeItem (); + void BecomePickup (); + + bool DoRespawn(); AInventory *PrevItem(); // Returns the item preceding this one in the list. AInventory *PrevInv(); // Returns the previous item with IF_INVBAR set. AInventory *NextInv(); // Returns the next item with IF_INVBAR set. @@ -113,34 +169,7 @@ public: FSoundIDNoInit PickupSound; - void BecomeItem (); - void BecomePickup (); - virtual void AttachToOwner (AActor *other); - virtual void DetachFromOwner (); - virtual AInventory *CreateCopy (AActor *other); - AInventory *CallCreateCopy(AActor *other); - virtual AInventory *CreateTossable (); - AInventory *CallCreateTossable(); - virtual bool GoAway (); - virtual void GoAwayAndDie (); - virtual bool HandlePickup (AInventory *item); - bool CallHandlePickup(AInventory *item); - virtual bool Use (bool pickup); - bool CallUse(bool pickup); - virtual void Travelled (); - virtual void OwnerDied (); - virtual void AbsorbDamage (int damage, FName damageType, int &newdamage); - virtual void ModifyDamage (int damage, FName damageType, int &newdamage, bool passive); - virtual double GetSpeedFactor(); - virtual bool GetNoTeleportFreeze(); - virtual int AlterWeaponSprite (visstyle_t *vis); - - virtual PalEntry GetBlend (); - PalEntry CallGetBlend(); - - virtual bool TryPickup (AActor *&toucher); - virtual bool TryPickupRestricted (AActor *&toucher); protected: bool CanPickup(AActor * toucher); void GiveQuest(AActor * toucher); @@ -164,9 +193,9 @@ public: // This is used when an inventory item's use state sequence is executed. bool CallStateChain (AActor *actor, FState *state); - bool TryPickup (AActor *&toucher); - bool Use (bool pickup); - bool SpecialDropAction (AActor *dropper); + virtual bool TryPickup (AActor *&toucher) override; + virtual bool Use (bool pickup) override; + virtual bool SpecialDropAction (AActor *dropper) override; }; extern PClassActor *QuestItemClasses[31]; diff --git a/src/g_inventory/a_weaponpiece.cpp b/src/g_inventory/a_weaponpiece.cpp index b504559bd..e1a7fe33b 100644 --- a/src/g_inventory/a_weaponpiece.cpp +++ b/src/g_inventory/a_weaponpiece.cpp @@ -103,7 +103,7 @@ void AWeaponPiece::Serialize(FSerializer &arc) bool AWeaponPiece::TryPickupRestricted (AActor *&toucher) { // Wrong class, but try to pick up for ammo - if (ShouldStay()) + if (CallShouldStay()) { // Can't pick up weapons for other classes in coop netplay return false; } diff --git a/src/g_inventory/a_weaponpiece.h b/src/g_inventory/a_weaponpiece.h index bcaa261cb..e0db15007 100644 --- a/src/g_inventory/a_weaponpiece.h +++ b/src/g_inventory/a_weaponpiece.h @@ -19,12 +19,12 @@ protected: bool PrivateShouldStay (); public: - void Serialize(FSerializer &arc); - bool TryPickup (AActor *&toucher); - bool TryPickupRestricted (AActor *&toucher); - bool ShouldStay (); - virtual FString PickupMessage (); - virtual void PlayPickupSound (AActor *toucher); + virtual void Serialize(FSerializer &arc) override; + virtual bool TryPickup (AActor *&toucher) override; + virtual bool TryPickupRestricted (AActor *&toucher) override; + virtual bool ShouldStay () override; + virtual FString PickupMessage () override; + virtual void PlayPickupSound (AActor *toucher) override; int PieceValue; PClassActor *WeaponClass; @@ -42,5 +42,5 @@ public: PClassActor * PieceWeapon; - void Serialize(FSerializer &arc); + virtual void Serialize(FSerializer &arc) override; }; diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index 90a217495..3fd4bc939 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -275,7 +275,7 @@ void AWeapon::MarkPrecacheSounds() const bool AWeapon::TryPickupRestricted (AActor *&toucher) { // Wrong class, but try to pick up for ammo - if (ShouldStay()) + if (CallShouldStay()) { // Can't pick up weapons for other classes in coop netplay return false; } @@ -398,7 +398,7 @@ bool AWeapon::PickupForAmmo (AWeapon *ownedWeapon) bool gotstuff = false; // Don't take ammo if the weapon sticks around. - if (!ShouldStay ()) + if (!CallShouldStay ()) { int oldamount1 = 0; int oldamount2 = 0; diff --git a/src/g_inventory/a_weapons.h b/src/g_inventory/a_weapons.h index 786f6189b..c6424075d 100644 --- a/src/g_inventory/a_weapons.h +++ b/src/g_inventory/a_weapons.h @@ -137,26 +137,30 @@ public: virtual void MarkPrecacheSounds() const; - virtual void Serialize(FSerializer &arc); - virtual bool ShouldStay (); - virtual void AttachToOwner (AActor *other); - virtual bool HandlePickup (AInventory *item); - virtual AInventory *CreateCopy (AActor *other); - virtual AInventory *CreateTossable (); - virtual bool TryPickup (AActor *&toucher); - virtual bool TryPickupRestricted (AActor *&toucher); - virtual bool PickupForAmmo (AWeapon *ownedWeapon); - virtual bool Use (bool pickup); + virtual void Serialize(FSerializer &arc) override; + virtual bool ShouldStay () override; + virtual void AttachToOwner (AActor *other) override; + virtual bool HandlePickup (AInventory *item) override; + virtual AInventory *CreateCopy (AActor *other) override; + virtual AInventory *CreateTossable () override; + virtual bool TryPickup (AActor *&toucher) override; + virtual bool TryPickupRestricted (AActor *&toucher) override; + virtual bool Use (bool pickup) override; virtual void Destroy() override; + bool PickupForAmmo(AWeapon *ownedWeapon); + void PostMorphWeapon(); + + // scripted virtuals. FState *GetUpState (); FState *GetDownState (); FState *GetReadyState (); FState *GetAtkState (bool hold); FState *GetAltAtkState (bool hold); + FState *GetStateForButtonName (FName button); - virtual void PostMorphWeapon (); + virtual void EndPowerup (); void CallEndPowerup(); @@ -221,9 +225,8 @@ class AWeaponGiver : public AWeapon DECLARE_CLASS(AWeaponGiver, AWeapon) public: - bool TryPickup(AActor *&toucher); - - void Serialize(FSerializer &arc); + virtual bool TryPickup(AActor *&toucher) override; + virtual void Serialize(FSerializer &arc) override; double DropAmmoFactor; }; diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index ad15cb081..f22318839 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -138,20 +138,7 @@ bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntyp AInventory *next = item->Inventory; if (item->IsKindOf (RUNTIME_CLASS(AArmor))) { - if (item->IsKindOf (RUNTIME_CLASS(AHexenArmor))) - { - // Set the HexenArmor slots to 0, except the class slot. - AHexenArmor *hxarmor = static_cast(item); - hxarmor->Slots[0] = 0; - hxarmor->Slots[1] = 0; - hxarmor->Slots[2] = 0; - hxarmor->Slots[3] = 0; - hxarmor->Slots[4] = spawntype->HexenArmor[0]; - } - else - { - item->DepleteOrDestroy(); - } + item->DepleteOrDestroy(); } item = next; } diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index 4e5c13d88..06e4d7552 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -32,7 +32,15 @@ class Inventory : Actor native virtual native Inventory CreateTossable(); virtual native bool SpecialDropAction (Actor dropper); virtual native String PickupMessage(); + virtual native bool ShouldStay(); + virtual native void DoEffect(); + virtual native void PlayPickupSound(Actor user); + virtual native void AttachToOwner(Actor user); + virtual native void DetachFromOwner(); + virtual double GetSpeedFactor() { return 1; } + virtual bool GetNoTeleportFreeze() { return false; } + native void GoAwayAndDie(); native void BecomeItem(); native void BecomePickup(); @@ -42,7 +50,10 @@ class Inventory : Actor native private native void A_RestoreSpecialThing1(); private native void A_RestoreSpecialThing2(); - virtual native bool TryPickup(in out Actor toucher); + // In this case the caller function is more than a simple wrapper around the virtual method and + // is what must be actually called to pick up an item. + virtual protected native bool TryPickup(in out Actor toucher); + virtual protected native bool TryPickupRestricted(in out Actor toucher); native bool, Actor CallTryPickup(Actor toucher); States(Actor, Overlay, Weapon, Item) diff --git a/wadsrc/static/zscript/shared/powerups.txt b/wadsrc/static/zscript/shared/powerups.txt index 4c7a84efe..0cd735c81 100644 --- a/wadsrc/static/zscript/shared/powerups.txt +++ b/wadsrc/static/zscript/shared/powerups.txt @@ -22,6 +22,10 @@ class Powerup : Inventory native native color BlendColor; native Name Mode; // Meaning depends on powerup - used for Invulnerability and Invisibility native double Strength; // Meaning depends on powerup - currently used only by Invisibility + + // Note, that while this is an inventory flag, it only has meaning on an active powerup. + virtual bool GetNoTeleportFreeze() { return bNoTeleportFreeze; } + } class PowerInvulnerable : Powerup native @@ -136,6 +140,8 @@ class PowerSpeed : Powerup native Inventory.Icon "SPBOOT0"; +INVENTORY.NOTELEPORTFREEZE } + + override double GetSpeedFactor() { return Speed; } } // Player Speed Trail (used by the Speed Powerup) ---------------------------- From 47884f8a7151ad3c3e06017039b230d7b674cd1a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 30 Nov 2016 16:19:13 +0100 Subject: [PATCH 183/185] - fixed a few bad declarations. --- wadsrc/static/zscript/actor.txt | 4 ++-- wadsrc/static/zscript/shared/powerups.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 9bf4fdcd9..abcd58b50 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -419,8 +419,8 @@ class Actor : Thinker native native void Howl(); native void DrawSplash (int count, double angle, int kind); native void GiveSecret(bool printmsg = true, bool playsound = true); - native void GetCameraHeight(); - native void GetGravity(); + native double GetCameraHeight(); + native double GetGravity(); native bool CheckClass(class checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false); native void AddInventory(Inventory inv); diff --git a/wadsrc/static/zscript/shared/powerups.txt b/wadsrc/static/zscript/shared/powerups.txt index 0cd735c81..d28799ff2 100644 --- a/wadsrc/static/zscript/shared/powerups.txt +++ b/wadsrc/static/zscript/shared/powerups.txt @@ -24,7 +24,7 @@ class Powerup : Inventory native native double Strength; // Meaning depends on powerup - currently used only by Invisibility // Note, that while this is an inventory flag, it only has meaning on an active powerup. - virtual bool GetNoTeleportFreeze() { return bNoTeleportFreeze; } + override bool GetNoTeleportFreeze() { return bNoTeleportFreeze; } } From 86544086df642e9c29fbc58931db4208caab079d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 30 Nov 2016 17:15:01 +0100 Subject: [PATCH 184/185] - allow the VM to run on one global stack per thread. It is utterly pointless to require every function that wants to make a VM call to allocate a new stack first. The allocation overhead doubles the time to set up the call. With one stack, previously allocated memory can be reused. The only important thing is, if this ever gets used in a multithreaded environment to have the stack being declared as thread_local, although for ZDoom this is of no consequence. - eliminated all cases where native code was calling other native code through the VM interface. After scriptifying the game code, only 5 places were left which were quickly eliminated. This was mostly to ensure that the native VM function parameters do not need to be propagated further than absolutely necessary. --- src/actor.h | 2 + src/d_dehacked.cpp | 2 - src/dthinker.cpp | 6 +- src/g_inventory/a_pickups.cpp | 105 ++++------------------- src/g_inventory/a_weapons.cpp | 18 ++-- src/g_shared/a_action.cpp | 30 +++---- src/g_shared/a_bridge.cpp | 20 +++-- src/g_shared/a_fastprojectile.cpp | 3 +- src/info.cpp | 5 +- src/m_cheat.cpp | 3 +- src/p_acs.cpp | 6 +- src/p_actionfunctions.cpp | 7 +- src/p_enemy.cpp | 24 ++---- src/p_enemy.h | 10 +-- src/p_interaction.cpp | 3 +- src/p_mobj.cpp | 91 ++++++++++++++++---- src/p_user.cpp | 15 ++-- src/scripting/codegeneration/codegen.cpp | 12 +-- src/scripting/vm/vm.h | 14 +-- src/scripting/vm/vmexec.cpp | 6 ++ src/scripting/vm/vmframe.cpp | 11 +-- src/scripting/zscript/zcc_compile.cpp | 6 +- wadsrc/static/zscript/actor.txt | 6 +- 23 files changed, 176 insertions(+), 229 deletions(-) diff --git a/src/actor.h b/src/actor.h index 18b128215..6718e0931 100644 --- a/src/actor.h +++ b/src/actor.h @@ -667,6 +667,8 @@ public: // Plays the actor's ActiveSound if its voice isn't already making noise. void PlayActiveSound (); + void RestoreSpecialPosition(); + // Called by PIT_CheckThing() and needed for some Hexen things. // Returns -1 for normal behavior, 0 to return false, and 1 to return true. // I'm not sure I like it this way, but it will do for now. diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index e2c5a6ea3..6f9687aea 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -174,8 +174,6 @@ struct AmmoPerAttack VMFunction *ptr; }; -DECLARE_ACTION(A_Punch) - // Default ammo use of the various weapon attacks static AmmoPerAttack AmmoPerAttacks[] = { { NAME_A_Punch, 0}, diff --git a/src/dthinker.cpp b/src/dthinker.cpp index 7c8bf1bf5..fd20a4e79 100644 --- a/src/dthinker.cpp +++ b/src/dthinker.cpp @@ -313,8 +313,7 @@ void DThinker::CallPostBeginPlay() { // Without the type cast this picks the 'void *' assignment... VMValue params[1] = { (DObject*)this }; - VMFrameStack stack; - stack.Call(func, params, 1, nullptr, 0, nullptr); + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); } else { @@ -557,8 +556,7 @@ void DThinker::CallTick() { // Without the type cast this picks the 'void *' assignment... VMValue params[1] = { (DObject*)this }; - VMFrameStack stack; - stack.Call(func, params, 1, nullptr, 0, nullptr); + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); } else Tick(); } diff --git a/src/g_inventory/a_pickups.cpp b/src/g_inventory/a_pickups.cpp index 237de2ce9..91b88a053 100644 --- a/src/g_inventory/a_pickups.cpp +++ b/src/g_inventory/a_pickups.cpp @@ -22,7 +22,6 @@ #include "virtual.h" #include "a_ammo.h" -static FRandom pr_restore ("RestorePos"); EXTERN_CVAR(Bool, sv_unlimited_pickup) IMPLEMENT_CLASS(PClassInventory, false, false) @@ -137,63 +136,6 @@ DEFINE_ACTION_FUNCTION(AInventory, A_RestoreSpecialDoomThing) return 0; } -//--------------------------------------------------------------------------- -// -// PROP A_RestoreSpecialPosition -// -//--------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialPosition) -{ - PARAM_SELF_PROLOGUE(AActor); - - // Move item back to its original location - DVector2 sp = self->SpawnPoint; - - self->UnlinkFromWorld(); - self->SetXY(sp); - self->LinkToWorld(true); - self->SetZ(self->Sector->floorplane.ZatPoint(sp)); - P_FindFloorCeiling(self, FFCF_ONLYSPAWNPOS | FFCF_NOPORTALS); // no portal checks here so that things get spawned in this sector. - - if (self->flags & MF_SPAWNCEILING) - { - self->SetZ(self->ceilingz - self->Height - self->SpawnPoint.Z); - } - else if (self->flags2 & MF2_SPAWNFLOAT) - { - double space = self->ceilingz - self->Height - self->floorz; - if (space > 48) - { - space -= 40; - self->SetZ((space * pr_restore()) / 256. + self->floorz + 40); - } - else - { - self->SetZ(self->floorz); - } - } - else - { - self->SetZ(self->SpawnPoint.Z + self->floorz); - } - // Redo floor/ceiling check, in case of 3D floors and portals - P_FindFloorCeiling(self, FFCF_SAMESECTOR | FFCF_ONLY3DFLOORS | FFCF_3DRESTRICT); - if (self->Z() < self->floorz) - { // Do not reappear under the floor, even if that's where we were for the - // initial spawn. - self->SetZ(self->floorz); - } - if ((self->flags & MF_SOLID) && (self->Top() > self->ceilingz)) - { // Do the same for the ceiling. - self->SetZ(self->ceilingz - self->Height); - } - // Do not interpolate from the position the actor was at when it was - // picked up, in case that is different from where it is now. - self->ClearInterpolation(); - return 0; -} - int AInventory::StaticLastMessageTic; FString AInventory::StaticLastMessage; @@ -322,10 +264,9 @@ bool AInventory::CallSpecialDropAction(AActor *dropper) { VMValue params[2] = { (DObject*)this, (DObject*)dropper }; VMReturn ret; - VMFrameStack stack; int retval; ret.IntAt(&retval); - stack.Call(func, params, 2, &ret, 1, nullptr); + GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); return !!retval; } return SpecialDropAction(dropper); @@ -412,7 +353,7 @@ void AInventory::CallDoEffect() { VMValue params[1] = { (DObject*)this }; VMFrameStack stack; - stack.Call(func, params, 1, nullptr, 0, nullptr); + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); } else DoEffect(); } @@ -495,10 +436,9 @@ bool AInventory::CallHandlePickup(AInventory *item) // Without the type cast this picks the 'void *' assignment... VMValue params[2] = { (DObject*)self, (DObject*)item }; VMReturn ret; - VMFrameStack stack; int retval; ret.IntAt(&retval); - stack.Call(func, params, 2, &ret, 1, nullptr); + GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); if (retval) return true; } else if (self->HandlePickup(item)) return true; @@ -604,10 +544,9 @@ AInventory *AInventory::CallCreateCopy(AActor *other) { VMValue params[2] = { (DObject*)this, (DObject*)other }; VMReturn ret; - VMFrameStack stack; AInventory *retval; ret.PointerAt((void**)&retval); - stack.Call(func, params, 2, &ret, 1, nullptr); + GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); return retval; } else return CreateCopy(other); @@ -670,10 +609,9 @@ AInventory *AInventory::CallCreateTossable() { VMValue params[1] = { (DObject*)this }; VMReturn ret; - VMFrameStack stack; AInventory *retval; ret.PointerAt((void**)&retval); - stack.Call(func, params, 1, &ret, 1, nullptr); + GlobalVMStack.Call(func, params, 1, &ret, 1, nullptr); return retval; } else return CreateTossable(); @@ -805,10 +743,9 @@ double AInventory::GetSpeedFactor() { VMValue params[2] = { (DObject*)self }; VMReturn ret; - VMFrameStack stack; double retval; ret.FloatAt(&retval); - stack.Call(func, params, 1, &ret, 1, nullptr); + GlobalVMStack.Call(func, params, 1, &ret, 1, nullptr); factor *= retval; } self = self->Inventory; @@ -831,10 +768,9 @@ bool AInventory::GetNoTeleportFreeze () { VMValue params[2] = { (DObject*)self }; VMReturn ret; - VMFrameStack stack; int retval; ret.IntAt(&retval); - stack.Call(func, params, 1, &ret, 1, nullptr); + GlobalVMStack.Call(func, params, 1, &ret, 1, nullptr); if (retval) return true; } self = self->Inventory; @@ -884,10 +820,9 @@ bool AInventory::CallUse(bool pickup) { VMValue params[2] = { (DObject*)this, pickup }; VMReturn ret; - VMFrameStack stack; int retval; ret.IntAt(&retval); - stack.Call(func, params, 2, &ret, 1, nullptr); + GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); return !!retval; } @@ -1090,10 +1025,9 @@ FString AInventory::GetPickupMessage() { VMValue params[1] = { (DObject*)this }; VMReturn ret; - VMFrameStack stack; FString retval; ret.StringAt(&retval); - stack.Call(func, params, 1, &ret, 1, nullptr); + GlobalVMStack.Call(func, params, 1, &ret, 1, nullptr); return retval; } else return PickupMessage(); @@ -1150,8 +1084,7 @@ void AInventory::CallPlayPickupSound(AActor *other) IFVIRTUAL(AInventory, PlayPickupSound) { VMValue params[2] = { (DObject*)this, (DObject*)other }; - VMFrameStack stack; - stack.Call(func, params, 2, nullptr, 0, nullptr); + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); } else PlayPickupSound(other); } @@ -1182,10 +1115,9 @@ bool AInventory::CallShouldStay() { VMValue params[1] = { (DObject*)this }; VMReturn ret; - VMFrameStack stack; int retval; ret.IntAt(&retval); - stack.Call(func, params, 1, &ret, 1, nullptr); + GlobalVMStack.Call(func, params, 1, &ret, 1, nullptr); return !!retval; } else return ShouldStay(); @@ -1264,10 +1196,9 @@ PalEntry AInventory::CallGetBlend() { VMValue params[1] = { (DObject*)this }; VMReturn ret; - VMFrameStack stack; int retval; ret.IntAt(&retval); - stack.Call(func, params, 1, &ret, 1, nullptr); + GlobalVMStack.Call(func, params, 1, &ret, 1, nullptr); return retval; } else return GetBlend(); @@ -1521,10 +1452,9 @@ bool AInventory::CallTryPickup (AActor *toucher, AActor **toucher_return) { VMValue params[2] = { (DObject*)this, (void*)&toucher }; VMReturn ret; - VMFrameStack stack; int retval; ret.IntAt(&retval); - stack.Call(func, params, 2, &ret, 1, nullptr); + GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); res = !!retval; } else res = TryPickup(toucher); @@ -1536,10 +1466,9 @@ bool AInventory::CallTryPickup (AActor *toucher, AActor **toucher_return) { VMValue params[2] = { (DObject*)this, (void*)&toucher }; VMReturn ret; - VMFrameStack stack; int retval; ret.IntAt(&retval); - stack.Call(func, params, 2, &ret, 1, nullptr); + GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); res = !!retval; } else res = TryPickupRestricted(toucher); @@ -1687,8 +1616,7 @@ void AInventory::CallAttachToOwner(AActor *other) IFVIRTUAL(AInventory, AttachToOwner) { VMValue params[2] = { (DObject*)this, (DObject*)other }; - VMFrameStack stack; - stack.Call(func, params, 2, nullptr, 0, nullptr); + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); } else AttachToOwner(other); } @@ -1719,8 +1647,7 @@ void AInventory::CallDetachFromOwner() IFVIRTUAL(AInventory, DetachFromOwner) { VMValue params[1] = { (DObject*)this }; - VMFrameStack stack; - stack.Call(func, params, 1, nullptr, 0, nullptr); + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); } else DetachFromOwner(); } diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index 3fd4bc939..19a30dcd8 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -845,8 +845,7 @@ void AWeapon::CallEndPowerup() { // Without the type cast this picks the 'void *' assignment... VMValue params[1] = { (DObject*)this }; - VMFrameStack stack; - stack.Call(func, params, 1, nullptr, 0, nullptr); + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); } else EndPowerup(); } @@ -864,10 +863,9 @@ FState *AWeapon::GetUpState () { VMValue params[1] = { (DObject*)this }; VMReturn ret; - VMFrameStack stack; FState *retval; ret.PointerAt((void**)&retval); - stack.Call(func, params, 1, &ret, 1, nullptr); + GlobalVMStack.Call(func, params, 1, &ret, 1, nullptr); return retval; } return nullptr; @@ -885,10 +883,9 @@ FState *AWeapon::GetDownState () { VMValue params[1] = { (DObject*)this }; VMReturn ret; - VMFrameStack stack; FState *retval; ret.PointerAt((void**)&retval); - stack.Call(func, params, 1, &ret, 1, nullptr); + GlobalVMStack.Call(func, params, 1, &ret, 1, nullptr); return retval; } return nullptr; @@ -906,10 +903,9 @@ FState *AWeapon::GetReadyState () { VMValue params[1] = { (DObject*)this }; VMReturn ret; - VMFrameStack stack; FState *retval; ret.PointerAt((void**)&retval); - stack.Call(func, params, 1, &ret, 1, nullptr); + GlobalVMStack.Call(func, params, 1, &ret, 1, nullptr); return retval; } return nullptr; @@ -927,10 +923,9 @@ FState *AWeapon::GetAtkState (bool hold) { VMValue params[2] = { (DObject*)this, hold }; VMReturn ret; - VMFrameStack stack; FState *retval; ret.PointerAt((void**)&retval); - stack.Call(func, params, 2, &ret, 1, nullptr); + GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); return retval; } return nullptr; @@ -948,10 +943,9 @@ FState *AWeapon::GetAltAtkState (bool hold) { VMValue params[2] = { (DObject*)this, hold }; VMReturn ret; - VMFrameStack stack; FState *retval; ret.PointerAt((void**)&retval); - stack.Call(func, params, 2, &ret, 1, nullptr); + GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); return retval; } return nullptr; diff --git a/src/g_shared/a_action.cpp b/src/g_shared/a_action.cpp index afe188019..2e4597617 100644 --- a/src/g_shared/a_action.cpp +++ b/src/g_shared/a_action.cpp @@ -121,35 +121,19 @@ DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeath) return 0; } -//========================================================================== -// -// A_GenericFreezeDeath -// -//========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_GenericFreezeDeath) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->Translation = TRANSLATION(TRANSLATION_Standard, 7); - CALL_ACTION(A_FreezeDeath, self); - return 0; -} - //============================================================================ // // A_IceSetTics // //============================================================================ -DEFINE_ACTION_FUNCTION(AActor, A_IceSetTics) +void IceSetTics(AActor *self) { - PARAM_SELF_PROLOGUE(AActor); int floor; - self->tics = 70+(pr_icesettics()&63); - floor = P_GetThingFloorType (self); + self->tics = 70 + (pr_icesettics() & 63); + floor = P_GetThingFloorType(self); if (Terrains[floor].DamageMOD == NAME_Fire) { self->tics >>= 2; @@ -158,6 +142,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_IceSetTics) { self->tics <<= 1; } +} + +DEFINE_ACTION_FUNCTION(AActor, A_IceSetTics) +{ + PARAM_SELF_PROLOGUE(AActor); + IceSetTics(self); return 0; } @@ -203,7 +193,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeathChunks) mo->Vel.X = pr_freeze.Random2() / 128.; mo->Vel.Y = pr_freeze.Random2() / 128.; mo->Vel.Z = (mo->Z() - self->Z()) / self->Height * 4; - CALL_ACTION(A_IceSetTics, mo); // set a random tic wait + IceSetTics(mo); // set a random tic wait mo->RenderStyle = self->RenderStyle; mo->Alpha = self->Alpha; } diff --git a/src/g_shared/a_bridge.cpp b/src/g_shared/a_bridge.cpp index 556767f37..138210061 100644 --- a/src/g_shared/a_bridge.cpp +++ b/src/g_shared/a_bridge.cpp @@ -89,24 +89,22 @@ void ACustomBridge::Destroy() // target pointer to center mobj // angle angle of ball -DEFINE_ACTION_FUNCTION(AActor, A_BridgeOrbit) +static void BridgeOrbit(AActor *self) { - PARAM_SELF_PROLOGUE(AActor); - if (self->target == NULL) { // Don't crash if somebody spawned this into the world // independantly of a Bridge actor. - return 0; + return; } // Set default values // Every five tics, Hexen moved the ball 3/256th of a revolution. - DAngle rotationspeed = 45./32*3/5; + DAngle rotationspeed = 45. / 32 * 3 / 5; double rotationradius = ORBIT_RADIUS; // If the bridge is custom, set non-default values if any. // Set angular speed; 1--128: counterclockwise rotation ~=1--180°; 129--255: clockwise rotation ~= 180--1° - if (self->target->args[3] > 128) rotationspeed = 45./32 * (self->target->args[3]-256) / TICRATE; - else if (self->target->args[3] > 0) rotationspeed = 45./32 * (self->target->args[3]) / TICRATE; + if (self->target->args[3] > 128) rotationspeed = 45. / 32 * (self->target->args[3] - 256) / TICRATE; + else if (self->target->args[3] > 0) rotationspeed = 45. / 32 * (self->target->args[3]) / TICRATE; // Set rotation radius if (self->target->args[4]) rotationradius = ((self->target->args[4] * self->target->radius) / 100); @@ -114,6 +112,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_BridgeOrbit) self->SetOrigin(self->target->Vec3Angle(rotationradius, self->Angles.Yaw, 0), true); self->floorz = self->target->floorz; self->ceilingz = self->target->ceilingz; +} + +DEFINE_ACTION_FUNCTION(AActor, A_BridgeOrbit) +{ + PARAM_SELF_PROLOGUE(AActor); + BridgeOrbit(self); return 0; } @@ -140,7 +144,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BridgeInit) ball = Spawn(balltype, self->Pos(), ALLOW_REPLACE); ball->Angles.Yaw = startangle + (45./32) * (256/ballcount) * i; ball->target = self; - CALL_ACTION(A_BridgeOrbit, ball); + BridgeOrbit(ball); } return 0; } diff --git a/src/g_shared/a_fastprojectile.cpp b/src/g_shared/a_fastprojectile.cpp index c68fa800c..fb0faef0f 100644 --- a/src/g_shared/a_fastprojectile.cpp +++ b/src/g_shared/a_fastprojectile.cpp @@ -139,8 +139,7 @@ void AFastProjectile::Tick () { // Without the type cast this picks the 'void *' assignment... VMValue params[1] = { (DObject*)this }; - VMFrameStack stack; - stack.Call(func, params, 1, nullptr, 0, nullptr); + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); } } } diff --git a/src/info.cpp b/src/info.cpp index 69605d454..b8bf3acde 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -75,7 +75,6 @@ bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info, { ActionCycles.Clock(); - VMFrameStack stack; VMValue params[3] = { self, stateowner, VMValue(info, ATAG_GENERIC) }; // If the function returns a state, store it at *stateret. // If it doesn't return a state but stateret is non-NULL, we need @@ -92,13 +91,13 @@ bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info, } if (stateret == NULL) { - stack.Call(ActionFunc, params, ActionFunc->ImplicitArgs, NULL, 0, NULL); + GlobalVMStack.Call(ActionFunc, params, ActionFunc->ImplicitArgs, NULL, 0, NULL); } else { VMReturn ret; ret.PointerAt((void **)stateret); - stack.Call(ActionFunc, params, ActionFunc->ImplicitArgs, &ret, 1, NULL); + GlobalVMStack.Call(ActionFunc, params, ActionFunc->ImplicitArgs, &ret, 1, NULL); } ActionCycles.Unclock(); return true; diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index 53405017a..53ae789c6 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -489,11 +489,10 @@ void cht_DoCheat (player_t *player, int cheat) if (gsp) { VMValue params[1] = { player->mo }; - VMFrameStack stack; VMReturn ret; int oldpieces = 1; ret.IntAt(&oldpieces); - stack.Call(gsp, params, 1, &ret, 1, nullptr); + GlobalVMStack.Call(gsp, params, 1, &ret, 1, nullptr); item = player->mo->FindInventory(PClass::FindActor(NAME_Sigil)); if (item != NULL) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index ba086da3a..6a7c9d10c 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -6116,8 +6116,7 @@ static void SetMarineWeapon(AActor *marine, int weapon) if (smw) { VMValue params[2] = { marine, weapon }; - VMFrameStack stack; - stack.Call(smw, params, 2, nullptr, 0, nullptr); + GlobalVMStack.Call(smw, params, 2, nullptr, 0, nullptr); } } @@ -6128,8 +6127,7 @@ static void SetMarineSprite(AActor *marine, PClassActor *source) if (sms) { VMValue params[2] = { marine, source }; - VMFrameStack stack; - stack.Call(sms, params, 2, nullptr, 0, nullptr); + GlobalVMStack.Call(sms, params, 2, nullptr, 0, nullptr); } } diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index bc217f4ae..477ed37f2 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -148,7 +148,6 @@ bool ACustomInventory::CallStateChain (AActor *actor, FState *state) state->ActionFunc = nullptr; } - VMFrameStack stack; PPrototype *proto = state->ActionFunc->Proto; VMReturn *wantret; FStateParamInfo stp = { state, STATE_StateChain, PSP_WEAPON }; @@ -184,7 +183,7 @@ bool ACustomInventory::CallStateChain (AActor *actor, FState *state) numret = 2; } } - stack.Call(state->ActionFunc, params, state->ActionFunc->ImplicitArgs, wantret, numret); + GlobalVMStack.Call(state->ActionFunc, params, state->ActionFunc->ImplicitArgs, wantret, numret); // As long as even one state succeeds, the whole chain succeeds unless aborted below. // A state that wants to jump does not count as "succeeded". if (nextstate == NULL) @@ -3802,8 +3801,6 @@ static void CheckStopped(AActor *self) // //=========================================================================== -DECLARE_ACTION(A_RestoreSpecialPosition) - enum RS_Flags { RSF_FOG=1, @@ -3822,7 +3819,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Respawn) self->flags |= MF_SOLID; self->Height = self->GetDefault()->Height; self->radius = self->GetDefault()->radius; - CALL_ACTION(A_RestoreSpecialPosition, self); + self->RestoreSpecialPosition(); if (flags & RSF_TELEFRAG) { diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 29128c8b7..751f92a30 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -2285,12 +2285,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_Wander) return 0; } -// [MC] I had to move this out from within A_Wander in order to allow flags to -// pass into it. That meant replacing the CALL_ACTION(A_Wander) functions with -// just straight up defining A_Wander in order to compile. Looking around though, -// actors from the games themselves just do a straight A_Chase call itself so -// I saw no harm in it. - void A_Wander(AActor *self, int flags) { // [RH] Strife probably clears this flag somewhere, but I couldn't find where. @@ -2403,7 +2397,7 @@ nosee: //============================================================================= #define CLASS_BOSS_STRAFE_RANGE 64*10 -void A_DoChase (VMFrameStack *stack, AActor *actor, bool fastchase, FState *meleestate, FState *missilestate, bool playactive, bool nightmarefast, bool dontmove, int flags) +void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missilestate, bool playactive, bool nightmarefast, bool dontmove, int flags) { if (actor->flags5 & MF5_INCONVERSATION) @@ -2533,7 +2527,7 @@ void A_DoChase (VMFrameStack *stack, AActor *actor, bool fastchase, FState *mele { if (actor->flags & MF_FRIENDLY) { - //CALL_ACTION(A_Look, actor); + //A_Look(actor); if (actor->target == NULL) { if (!dontmove) A_Wander(actor); @@ -2931,12 +2925,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_Chase) if ((flags & CHF_RESURRECT) && P_CheckForResurrection(self, false)) return 0; - A_DoChase(stack, self, !!(flags&CHF_FASTCHASE), melee, missile, !(flags&CHF_NOPLAYACTIVE), + A_DoChase(self, !!(flags&CHF_FASTCHASE), melee, missile, !(flags&CHF_NOPLAYACTIVE), !!(flags&CHF_NIGHTMAREFAST), !!(flags&CHF_DONTMOVE), flags); } else // this is the old default A_Chase { - A_DoChase(stack, self, false, self->MeleeState, self->MissileState, true, gameinfo.nightmarefast, false, flags); + A_DoChase(self, false, self->MeleeState, self->MissileState, true, gameinfo.nightmarefast, false, flags); } return 0; } @@ -2944,7 +2938,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Chase) DEFINE_ACTION_FUNCTION(AActor, A_FastChase) { PARAM_SELF_PROLOGUE(AActor); - A_DoChase(stack, self, true, self->MeleeState, self->MissileState, true, true, false, 0); + A_DoChase(self, true, self->MeleeState, self->MissileState, true, true, false, 0); return 0; } @@ -2953,7 +2947,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_VileChase) PARAM_SELF_PROLOGUE(AActor); if (!P_CheckForResurrection(self, true)) { - A_DoChase(stack, self, false, self->MeleeState, self->MissileState, true, gameinfo.nightmarefast, false, 0); + A_DoChase(self, false, self->MeleeState, self->MissileState, true, gameinfo.nightmarefast, false, 0); } return 0; } @@ -2967,16 +2961,16 @@ DEFINE_ACTION_FUNCTION(AActor, A_ExtChase) PARAM_BOOL_DEF (nightmarefast); // Now that A_Chase can handle state label parameters, this function has become rather useless... - A_DoChase(stack, self, false, + A_DoChase(self, false, domelee ? self->MeleeState : NULL, domissile ? self->MissileState : NULL, playactive, nightmarefast, false, 0); return 0; } // for internal use -void A_Chase(VMFrameStack *stack, AActor *self) +void A_Chase(AActor *self) { - A_DoChase(stack, self, false, self->MeleeState, self->MissileState, true, gameinfo.nightmarefast, false, 0); + A_DoChase(self, false, self->MeleeState, self->MissileState, true, gameinfo.nightmarefast, false, 0); } //============================================================================= diff --git a/src/p_enemy.h b/src/p_enemy.h index a9aa40dc2..a0e829c71 100644 --- a/src/p_enemy.h +++ b/src/p_enemy.h @@ -60,18 +60,10 @@ bool P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params); void A_Weave(AActor *self, int xyspeed, int zspeed, double xydist, double zdist); void A_Unblock(AActor *self, bool drop); -DECLARE_ACTION(A_Look) -DECLARE_ACTION(A_BossDeath) -DECLARE_ACTION(A_Pain) -DECLARE_ACTION(A_MonsterRail) -DECLARE_ACTION(A_NoBlocking) -DECLARE_ACTION(A_Scream) -DECLARE_ACTION(A_FreezeDeath) -DECLARE_ACTION(A_FreezeDeathChunks) void A_BossDeath(AActor *self); void A_Wander(AActor *self, int flags = 0); -void A_Chase(VMFrameStack *stack, AActor *self); +void A_Chase(AActor *self); void A_FaceTarget(AActor *actor); void A_Face(AActor *self, AActor *other, DAngle max_turn = 0., DAngle max_pitch = 270., DAngle ang_offset = 0., DAngle pitch_offset = 0., int flags = 0, double z_add = 0); diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index eae7edb00..e6729096c 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -777,8 +777,7 @@ void AActor::CallDie(AActor *source, AActor *inflictor, int dmgflags) IFVIRTUAL(AActor, Die) { VMValue params[4] = { (DObject*)this, source, inflictor, dmgflags }; - VMFrameStack stack; - stack.Call(func, params, 4, nullptr, 0, nullptr); + GlobalVMStack.Call(func, params, 4, nullptr, 0, nullptr); } else return Die(source, inflictor, dmgflags); } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 572c7656f..f1f33425a 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1494,8 +1494,7 @@ void AActor::CallTouch(AActor *toucher) IFVIRTUAL(AActor, Touch) { VMValue params[2] = { (DObject*)this, toucher }; - VMFrameStack stack; - stack.Call(func, params, 2, nullptr, 0, nullptr); + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); } else Touch(toucher); } @@ -3360,7 +3359,6 @@ int AActor::GetMissileDamage (int mask, int add) assert(false && "No damage function found"); return 0; } - VMFrameStack stack; VMValue param = this; VMReturn result; @@ -3368,7 +3366,7 @@ int AActor::GetMissileDamage (int mask, int add) result.IntAt(&amount); - if (stack.Call(DamageFunc, ¶m, 1, &result, 1) < 1) + if (GlobalVMStack.Call(DamageFunc, ¶m, 1, &result, 1) < 1) { // No results return 0; } @@ -3431,10 +3429,9 @@ bool AActor::CallSlam(AActor *thing) { VMValue params[2] = { (DObject*)this, thing }; VMReturn ret; - VMFrameStack stack; int retval; ret.IntAt(&retval); - stack.Call(func, params, 2, &ret, 1, nullptr); + GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); return !!retval; } @@ -3451,9 +3448,8 @@ int AActor::SpecialMissileHit (AActor *victim) VMValue params[2] = { (DObject*)this, victim }; VMReturn ret; int retval; - VMFrameStack stack; ret.IntAt(&retval); - stack.Call(func, params, 2, &ret, 1, nullptr); + GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); return retval; } else return -1; @@ -4777,8 +4773,7 @@ void AActor::CallBeginPlay() { // Without the type cast this picks the 'void *' assignment... VMValue params[1] = { (DObject*)this }; - VMFrameStack stack; - stack.Call(func, params, 1, nullptr, 0, nullptr); + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); } else BeginPlay(); } @@ -4859,8 +4854,7 @@ void AActor::CallActivate(AActor *activator) { // Without the type cast this picks the 'void *' assignment... VMValue params[2] = { (DObject*)this, (DObject*)activator }; - VMFrameStack stack; - stack.Call(func, params, 2, nullptr, 0, nullptr); + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); } else Activate(activator); } @@ -4906,8 +4900,7 @@ void AActor::CallDeactivate(AActor *activator) { // Without the type cast this picks the 'void *' assignment... VMValue params[2] = { (DObject*)this, (DObject*)activator }; - VMFrameStack stack; - stack.Call(func, params, 2, nullptr, 0, nullptr); + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); } else Deactivate(activator); } @@ -7076,10 +7069,9 @@ int AActor::CallDoSpecialDamage(AActor *target, int damage, FName damagetype) // Without the type cast this picks the 'void *' assignment... VMValue params[4] = { (DObject*)this, (DObject*)target, damage, damagetype.GetIndex() }; VMReturn ret; - VMFrameStack stack; int retval; ret.IntAt(&retval); - stack.Call(func, params, 4, &ret, 1, nullptr); + GlobalVMStack.Call(func, params, 4, &ret, 1, nullptr); return retval; } else return DoSpecialDamage(target, damage, damagetype); @@ -7142,10 +7134,9 @@ int AActor::CallTakeSpecialDamage(AActor *inflictor, AActor *source, int damage, { VMValue params[5] = { (DObject*)this, inflictor, source, damage, damagetype.GetIndex() }; VMReturn ret; - VMFrameStack stack; int retval; ret.IntAt(&retval); - stack.Call(func, params, 5, &ret, 1, nullptr); + GlobalVMStack.Call(func, params, 5, &ret, 1, nullptr); return retval; } else return TakeSpecialDamage(inflictor, source, damage, damagetype); @@ -7468,6 +7459,70 @@ void AActor::SetTranslation(FName trname) // silently ignore if the name does not exist, this would create some insane message spam otherwise. } +//--------------------------------------------------------------------------- +// +// PROP A_RestoreSpecialPosition +// +//--------------------------------------------------------------------------- +static FRandom pr_restore("RestorePos"); + +void AActor::RestoreSpecialPosition() +{ + // Move item back to its original location + DVector2 sp = SpawnPoint; + + UnlinkFromWorld(); + SetXY(sp); + LinkToWorld(true); + SetZ(Sector->floorplane.ZatPoint(sp)); + P_FindFloorCeiling(this, FFCF_ONLYSPAWNPOS | FFCF_NOPORTALS); // no portal checks here so that things get spawned in this sector. + + if (flags & MF_SPAWNCEILING) + { + SetZ(ceilingz - Height - SpawnPoint.Z); + } + else if (flags2 & MF2_SPAWNFLOAT) + { + double space = ceilingz - Height - floorz; + if (space > 48) + { + space -= 40; + SetZ((space * pr_restore()) / 256. + floorz + 40); + } + else + { + SetZ(floorz); + } + } + else + { + SetZ(SpawnPoint.Z + floorz); + } + // Redo floor/ceiling check, in case of 3D floors and portals + P_FindFloorCeiling(this, FFCF_SAMESECTOR | FFCF_ONLY3DFLOORS | FFCF_3DRESTRICT); + if (Z() < floorz) + { // Do not reappear under the floor, even if that's where we were for the + // initial spawn. + SetZ(floorz); + } + if ((flags & MF_SOLID) && (Top() > ceilingz)) + { // Do the same for the ceiling. + SetZ(ceilingz - Height); + } + // Do not interpolate from the position the actor was at when it was + // picked up, in case that is different from where it is now. + ClearInterpolation(); +} + +DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialPosition) +{ + PARAM_SELF_PROLOGUE(AActor); + self->RestoreSpecialPosition(); + return 0; +} + + + class DActorIterator : public DObject, public NActorIterator { diff --git a/src/p_user.cpp b/src/p_user.cpp index 11857631a..74b07e0ca 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -1305,8 +1305,7 @@ void APlayerPawn::PlayIdle () IFVIRTUAL(APlayerPawn, PlayIdle) { VMValue params[1] = { (DObject*)this }; - VMFrameStack stack; - stack.Call(func, params, 1, nullptr, 0, nullptr); + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); } } @@ -1315,8 +1314,7 @@ void APlayerPawn::PlayRunning () IFVIRTUAL(APlayerPawn, PlayRunning) { VMValue params[1] = { (DObject*)this }; - VMFrameStack stack; - stack.Call(func, params, 1, nullptr, 0, nullptr); + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); } } @@ -1325,8 +1323,7 @@ void APlayerPawn::PlayAttacking () IFVIRTUAL(APlayerPawn, PlayAttacking) { VMValue params[1] = { (DObject*)this }; - VMFrameStack stack; - stack.Call(func, params, 1, nullptr, 0, nullptr); + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); } } @@ -1335,8 +1332,7 @@ void APlayerPawn::PlayAttacking2 () IFVIRTUAL(APlayerPawn, PlayAttacking2) { VMValue params[1] = { (DObject*)this }; - VMFrameStack stack; - stack.Call(func, params, 1, nullptr, 0, nullptr); + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); } } @@ -1426,8 +1422,7 @@ void APlayerPawn::MorphPlayerThink () IFVIRTUAL(APlayerPawn, MorphPlayerThink) { VMValue params[1] = { (DObject*)this }; - VMFrameStack stack; - stack.Call(func, params, 1, nullptr, 0, nullptr); + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); } } diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index eaeca6e9d..28b20e289 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -4228,7 +4228,7 @@ PPrototype *FxTypeCheck::ReturnProto() // //========================================================================== -int BuiltinTypeCheck(VMFrameStack *stack, VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret) +int BuiltinTypeCheck(VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret) { assert(numparam == 2); PARAM_POINTER_AT(0, obj, DObject); @@ -5030,7 +5030,7 @@ FxExpression *FxRandom::Resolve(FCompileContext &ctx) // //========================================================================== -int BuiltinRandom(VMFrameStack *stack, VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret) +int BuiltinRandom(VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret) { assert(numparam >= 1 && numparam <= 3); FRandom *rng = reinterpret_cast(param[0].a); @@ -5284,7 +5284,7 @@ FxFRandom::FxFRandom(FRandom *r, FxExpression *mi, FxExpression *ma, const FScri // //========================================================================== -int BuiltinFRandom(VMFrameStack *stack, VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret) +int BuiltinFRandom(VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret) { assert(numparam == 1 || numparam == 3); FRandom *rng = reinterpret_cast(param[0].a); @@ -7558,7 +7558,7 @@ FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx) // //========================================================================== -int BuiltinCallLineSpecial(VMFrameStack *stack, VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret) +int BuiltinCallLineSpecial(VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret) { assert(numparam > 2 && numparam < 8); assert(param[0].Type == REGT_INT); @@ -9518,7 +9518,7 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx) // //========================================================================== -int BuiltinNameToClass(VMFrameStack *stack, VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret) +int BuiltinNameToClass(VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret) { assert(numparam == 2); assert(numret == 1); @@ -9650,7 +9650,7 @@ FxExpression *FxClassPtrCast::Resolve(FCompileContext &ctx) // //========================================================================== -int BuiltinClassCast(VMFrameStack *stack, VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret) +int BuiltinClassCast(VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret) { PARAM_PROLOGUE; PARAM_CLASS(from, DObject); diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index fdee430e1..9bd0a4bc9 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -867,7 +867,7 @@ class VMNativeFunction : public VMFunction { DECLARE_CLASS(VMNativeFunction, VMFunction); public: - typedef int (*NativeCallType)(VMFrameStack *stack, VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret); + typedef int (*NativeCallType)(VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret); VMNativeFunction() : NativeCall(NULL) { Native = true; } VMNativeFunction(NativeCallType call) : NativeCall(call) { Native = true; } @@ -930,6 +930,9 @@ enum EVMEngine VMEngine_Checked }; +extern thread_local VMFrameStack GlobalVMStack; + + void VMSelectEngine(EVMEngine engine); extern int (*VMExec)(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret); void VMFillParams(VMValue *params, VMFrame *callee, int numparam); @@ -938,8 +941,8 @@ 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, TArray &defaultparam, int numparam, VMReturn *ret, int numret -#define VM_ARGS_NAMES stack, param, defaultparam, numparam, ret, numret +#define VM_ARGS VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret +#define VM_ARGS_NAMES param, defaultparam, numparam, ret, numret // Use these to collect the parameters in a native function. // variable name at position

@@ -1012,7 +1015,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction #define PARAM_OBJECT_DEF(x,type) ++paramnum; PARAM_OBJECT_DEF_AT(paramnum,x,type) #define PARAM_CLASS_DEF(x,base) ++paramnum; PARAM_CLASS_DEF_AT(paramnum,x,base) -typedef int(*actionf_p)(VMFrameStack *stack, VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret);/*(VM_ARGS)*/ +typedef int(*actionf_p)(VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret);/*(VM_ARGS)*/ struct FieldDesc { @@ -1048,7 +1051,6 @@ struct AFuncDesc // 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) extern VMNativeFunction *AActor_##name##_VMPtr; #define DEFINE_ACTION_FUNCTION(cls, name) \ static int AF_##cls##_##name(VM_ARGS); \ @@ -1090,8 +1092,6 @@ struct AFuncDesc MSVC_FSEG FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr GCC_FSEG = &VMField_##cls##_##scriptname; class AActor; -void CallAction(VMFrameStack *stack, VMFunction *vmfunc, AActor *self); -#define CALL_ACTION(name, self) CallAction(stack, AActor_##name##_VMPtr, self); #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) diff --git a/src/scripting/vm/vmexec.cpp b/src/scripting/vm/vmexec.cpp index 750c384e0..f51038f36 100644 --- a/src/scripting/vm/vmexec.cpp +++ b/src/scripting/vm/vmexec.cpp @@ -146,6 +146,12 @@ VMExec_Checked::Exec #endif ; +// Note: If the VM is being used in multiple threads, this should be declared as thread_local. +// ZDoom doesn't need this at the moment so this is disabled. + +thread_local VMFrameStack GlobalVMStack; + + //=========================================================================== // // VMSelectEngine diff --git a/src/scripting/vm/vmframe.cpp b/src/scripting/vm/vmframe.cpp index 428266d0f..d3ce5d5f9 100644 --- a/src/scripting/vm/vmframe.cpp +++ b/src/scripting/vm/vmframe.cpp @@ -422,12 +422,13 @@ VMFrame *VMFrameStack::PopFrame() int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMReturn *results, int numresults, VMException **trap) { + assert(this == VMGlobalStack); // why would anyone even want to create a local stack? bool allocated = false; try { if (func->Native) { - return static_cast(func)->NativeCall(this, params, func->DefaultArgs, numparams, results, numresults); + return static_cast(func)->NativeCall(params, func->DefaultArgs, numparams, results, numresults); } else { @@ -503,11 +504,3 @@ int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMRetur throw; } } - -class AActor; -void CallAction(VMFrameStack *stack, VMFunction *vmfunc, AActor *self) -{ - // Without the type cast this picks the 'void *' assignment... - VMValue params[3] = { (DObject*)self, (DObject*)self, VMValue(nullptr, ATAG_GENERIC) }; - stack->Call(vmfunc, params, vmfunc->ImplicitArgs, nullptr, 0, nullptr); -} diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index ae666a2f7..2b86e58e1 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2362,7 +2362,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool { if (vindex != -1) { - Error(p, "Function %s attempts to override parent function without 'override' qualifier", FName(f->Name).GetChars()); + Error(f, "Function %s attempts to override parent function without 'override' qualifier", FName(f->Name).GetChars()); } sym->Variants[0].Implementation->VirtualIndex = clstype->Virtuals.Push(sym->Variants[0].Implementation); } @@ -3267,3 +3267,7 @@ FArgumentList &ZCCCompiler::ConvertNodeList(FArgumentList &args, ZCC_TreeNode *h } return args; } + +void func() +{ +} \ No newline at end of file diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index abcd58b50..bd00ffc98 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -666,7 +666,11 @@ class Actor : Thinker native native void A_FastChase(); native void A_FreezeDeath(); native void A_FreezeDeathChunks(); - native void A_GenericFreezeDeath(); + void A_GenericFreezeDeath() + { + A_SetTranslation('Ice'); + A_FreezeDeath(); + } native void A_PlayerScream(); native void A_SkullPop(class skulltype = "BloodySkull"); native void A_CheckPlayerDone(); From 83d7f63364b6f16b1cc493989b1c78c8d25cdce8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 30 Nov 2016 18:43:10 +0100 Subject: [PATCH 185/185] - missed these in the last commit. --- src/scripting/vm/vmexec.h | 4 ++-- src/scripting/zscript/zcc_compile.cpp | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 06c6ade8e..225c73cab 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -573,7 +573,7 @@ begin: FillReturns(reg, f, returns, pc+1, C); if (call->Native) { - numret = static_cast(call)->NativeCall(stack, reg.param + f->NumParam - B, call->DefaultArgs, B, returns, C); + numret = static_cast(call)->NativeCall(reg.param + f->NumParam - B, call->DefaultArgs, B, returns, C); } else { @@ -617,7 +617,7 @@ begin: if (call->Native) { - return static_cast(call)->NativeCall(stack, reg.param + f->NumParam - B, call->DefaultArgs, B, ret, numret); + return static_cast(call)->NativeCall(reg.param + f->NumParam - B, call->DefaultArgs, B, ret, numret); } else { // FIXME: Not a true tail call diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 2b86e58e1..6eb675b89 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -3267,7 +3267,3 @@ FArgumentList &ZCCCompiler::ConvertNodeList(FArgumentList &args, ZCC_TreeNode *h } return args; } - -void func() -{ -} \ No newline at end of file