diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a5c5fd3e3..f96bf7d36 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -838,7 +838,6 @@ set( NOT_COMPILED_SOURCE_FILES g_doom/a_archvile.cpp g_doom/a_bossbrain.cpp g_doom/a_doomweaps.cpp - g_doom/a_fatso.cpp g_doom/a_keen.cpp g_doom/a_lostsoul.cpp g_doom/a_painelemental.cpp diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 064f37c02..cc699ac47 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -1488,6 +1488,14 @@ static int PatchFrame (int frameNum) 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_STATE(state); + ACTION_RETURN_BOOL(state != nullptr && (state->DefineFlags & SDF_DEHACKED)); +} + static int PatchSprite (int sprNum) { int result; diff --git a/src/dobject.cpp b/src/dobject.cpp index 4acb86ce4..beef73c89 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -349,6 +349,13 @@ void DObject::Destroy () ObjectFlags = (ObjectFlags & ~OF_Fixed) | OF_EuthanizeMe; } +DEFINE_ACTION_FUNCTION(DObject, Destroy) +{ + PARAM_SELF_PROLOGUE(DObject); + self->Destroy(); + return 0; +} + //========================================================================== // // diff --git a/src/g_doom/a_doommisc.cpp b/src/g_doom/a_doommisc.cpp index df42bfa7b..29e2fc8ee 100644 --- a/src/g_doom/a_doommisc.cpp +++ b/src/g_doom/a_doommisc.cpp @@ -25,7 +25,6 @@ #include "a_archvile.cpp" #include "a_bossbrain.cpp" #include "a_doomweaps.cpp" -#include "a_fatso.cpp" #include "a_keen.cpp" #include "a_lostsoul.cpp" #include "a_painelemental.cpp" diff --git a/src/g_doom/a_fatso.cpp b/src/g_doom/a_fatso.cpp deleted file mode 100644 index ea2d8f397..000000000 --- a/src/g_doom/a_fatso.cpp +++ /dev/null @@ -1,84 +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 "gstrings.h" -#include "a_action.h" -#include "vm.h" -*/ - -// -// Mancubus attack, -// firing three missiles in three different directions? -// Doesn't look like it. -// -// -// killough 9/98: a mushroom explosion effect, sorta :) -// Original idea: Linguica -// - -enum -{ - MSF_Standard = 0, - MSF_Classic = 1, - MSF_DontHurt = 2, -}; - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Mushroom) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_CLASS_DEF (spawntype, AActor) - PARAM_INT_DEF (n) - PARAM_INT_DEF (flags) - PARAM_FLOAT_DEF (vrange) - PARAM_FLOAT_DEF (hrange) - - int i, j; - - if (n == 0) - { - n = self->GetMissileDamage(0, 1); - } - if (spawntype == NULL) - { - spawntype = PClass::FindActor("FatShot"); - } - - P_RadiusAttack (self, self->target, 128, 128, self->DamageType, (flags & MSF_DontHurt) ? 0 : RADF_HURTSOURCE); - P_CheckSplash(self, 128.); - - // Now launch mushroom cloud - AActor *target = Spawn("Mapspot", self->Pos(), NO_REPLACE); // We need something to aim at. - AActor *master = (flags & MSF_DontHurt) ? (AActor*)(self->target) : self; - target->Height = self->Height; - for (i = -n; i <= n; i += 8) - { - for (j = -n; j <= n; j += 8) - { - AActor *mo; - target->SetXYZ( - self->X() + i, // Aim in many directions from source - self->Y() + j, - self->Z() + (P_AproxDistance(i,j) * vrange)); // Aim up fairly high - if ((flags & MSF_Classic) || // Flag explicitely set, or no flags and compat options - (flags == 0 && (self->state->DefineFlags & SDF_DEHACKED) && (i_compatflags & COMPATF_MUSHROOM))) - { // Use old function for MBF compatibility - mo = P_OldSpawnMissile (self, master, target, spawntype); - } - else // Use normal function - { - mo = P_SpawnMissile(self, target, spawntype, master); - } - if (mo != NULL) - { // Slow it down a bit - mo->Vel *= hrange; - mo->flags &= ~MF_NOGRAVITY; // Make debris fall under gravity - } - } - } - target->Destroy(); - return 0; -} diff --git a/src/info.h b/src/info.h index 2155734ad..ad25bdcaf 100644 --- a/src/info.h +++ b/src/info.h @@ -67,7 +67,7 @@ enum EStateDefineFlags SDF_DEHACKED = 8, // Identify a state as having been modified by a dehacked lump }; -enum EStateType +enum EStateType : int // this must ensure proper alignment. { STATE_Actor, STATE_Psprite, diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 754ec516a..3fd1be9a1 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4258,6 +4258,17 @@ AActor *AActor::StaticSpawn (PClassActor *type, const DVector3 &pos, replace_t a return actor; } +DEFINE_ACTION_FUNCTION(AActor, Spawn) +{ + PARAM_PROLOGUE; + PARAM_CLASS(type, AActor); + PARAM_FLOAT_DEF(x); + PARAM_FLOAT_DEF(y); + PARAM_FLOAT_DEF(z); + PARAM_INT_DEF(flags); + ACTION_RETURN_OBJECT(AActor::StaticSpawn(type, DVector3(x, y, z), replace_t(flags))); +} + PClassActor *ClassForSpawn(FName classname) { PClass *cls = PClass::FindClass(classname); @@ -5951,6 +5962,16 @@ AActor *P_OldSpawnMissile(AActor *source, AActor *owner, AActor *dest, PClassAct return th; } +DEFINE_ACTION_FUNCTION(AActor, OldSpawnMissile) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(dest, AActor); + PARAM_CLASS(type, AActor); + PARAM_OBJECT_DEF(owner, AActor); + ACTION_RETURN_OBJECT(P_OldSpawnMissile(self, owner, dest, type)); +} + + //--------------------------------------------------------------------------- // // FUNC P_SpawnMissileAngle @@ -6616,6 +6637,16 @@ DEFINE_ACTION_FUNCTION(AActor, VelFromAngle) return 0; } +DEFINE_ACTION_FUNCTION(AActor, SetXYZ) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + self->SetXYZ(x, y, z); + return 0; +} + //---------------------------------------------------------------------------- // // DropItem handling diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index a0ccbb2c8..4fa6da73e 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -156,7 +156,7 @@ void FCompileContext::CheckReturn(PPrototype *proto, FScriptPosition &pos) if (fail) { - pos.Message(MSG_ERROR, "All return expressions must deduce to the same type"); + pos.Message(MSG_ERROR, "Return type mismatch"); } } @@ -214,7 +214,7 @@ static PSymbolTable Builtins; static PSymbol *FindBuiltinFunction(FName funcname, VMNativeFunction::NativeCallType func) { PSymbol *sym = Builtins.FindSymbol(funcname, false); - if (sym == NULL) + if (sym == nullptr) { PSymbolVMFunction *symfunc = new PSymbolVMFunction(funcname); VMNativeFunction *calldec = new VMNativeFunction(func, funcname); @@ -282,7 +282,7 @@ bool FxExpression::isConstant() const VMFunction *FxExpression::GetDirectFunction() { - return NULL; + return nullptr; } //========================================================================== @@ -387,7 +387,7 @@ FxExpression *FxConstant::MakeConstant(PSymbol *sym, const FScriptPosition &pos) { FxExpression *x; PSymbolConstNumeric *csym = dyn_cast(sym); - if (csym != NULL) + if (csym != nullptr) { if (csym->ValueType->IsA(RUNTIME_CLASS(PInt))) { @@ -400,13 +400,13 @@ FxExpression *FxConstant::MakeConstant(PSymbol *sym, const FScriptPosition &pos) else { pos.Message(MSG_ERROR, "Invalid constant '%s'\n", csym->SymbolName.GetChars()); - return NULL; + return nullptr; } } else { pos.Message(MSG_ERROR, "'%s' is not a constant\n", sym->SymbolName.GetChars()); - x = NULL; + x = nullptr; } return x; } @@ -794,7 +794,7 @@ FxExpression *FxIntCast::Resolve(FCompileContext &ctx) { FxExpression *x = basex; x->ValueType = ValueType; - basex = NULL; + basex = nullptr; delete this; return x; } @@ -833,7 +833,7 @@ FxExpression *FxIntCast::Resolve(FCompileContext &ctx) } ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); delete this; - return NULL; + return nullptr; } //========================================================================== @@ -891,7 +891,7 @@ FxExpression *FxFloatCast::Resolve(FCompileContext &ctx) if (basex->IsFloat()) { FxExpression *x = basex; - basex = NULL; + basex = nullptr; delete this; return x; } @@ -923,7 +923,7 @@ FxExpression *FxFloatCast::Resolve(FCompileContext &ctx) { ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); delete this; - return NULL; + return nullptr; } } @@ -982,7 +982,7 @@ FxExpression *FxNameCast::Resolve(FCompileContext &ctx) if (basex->ValueType == TypeName) { FxExpression *x = basex; - basex = NULL; + basex = nullptr; delete this; return x; } @@ -1001,7 +1001,7 @@ FxExpression *FxNameCast::Resolve(FCompileContext &ctx) { ScriptPosition.Message(MSG_ERROR, "Cannot convert to name"); delete this; - return NULL; + return nullptr; } } @@ -1060,7 +1060,7 @@ FxExpression *FxStringCast::Resolve(FCompileContext &ctx) if (basex->ValueType == TypeString) { FxExpression *x = basex; - basex = NULL; + basex = nullptr; delete this; return x; } @@ -1091,7 +1091,7 @@ FxExpression *FxStringCast::Resolve(FCompileContext &ctx) { ScriptPosition.Message(MSG_ERROR, "Cannot convert to string"); delete this; - return NULL; + return nullptr; } } @@ -1158,7 +1158,7 @@ FxExpression *FxColorCast::Resolve(FCompileContext &ctx) { FxExpression *x = basex; x->ValueType = TypeColor; - basex = NULL; + basex = nullptr; delete this; return x; } @@ -1177,7 +1177,7 @@ FxExpression *FxColorCast::Resolve(FCompileContext &ctx) { ScriptPosition.Message(MSG_ERROR, "Cannot convert to color"); delete this; - return NULL; + return nullptr; } } @@ -1237,7 +1237,7 @@ FxExpression *FxSoundCast::Resolve(FCompileContext &ctx) { FxExpression *x = basex; x->ValueType = TypeSound; - basex = NULL; + basex = nullptr; delete this; return x; } @@ -1256,7 +1256,7 @@ FxExpression *FxSoundCast::Resolve(FCompileContext &ctx) { ScriptPosition.Message(MSG_ERROR, "Cannot convert to sound"); delete this; - return NULL; + return nullptr; } } @@ -1318,6 +1318,7 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx) // first deal with the simple types if (ValueType == TypeError || basex->ValueType == TypeError) { + ScriptPosition.Message(MSG_ERROR, "Trying to cast to invalid type. This error message means that somewhere in the script compiler an error check is missing."); delete this; return nullptr; } @@ -1502,7 +1503,7 @@ FxExpression *FxPlusSign::Resolve(FCompileContext& ctx) if (Operand->IsNumeric() || Operand->IsVector()) { FxExpression *e = Operand; - Operand = NULL; + Operand = nullptr; delete this; return e; } @@ -1510,7 +1511,7 @@ FxExpression *FxPlusSign::Resolve(FCompileContext& ctx) { ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); delete this; - return NULL; + return nullptr; } } @@ -1571,7 +1572,7 @@ FxExpression *FxMinusSign::Resolve(FCompileContext& ctx) { ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); delete this; - return NULL; + return nullptr; } } @@ -1587,7 +1588,14 @@ ExpEmit FxMinusSign::Emit(VMFunctionBuilder *build) ExpEmit from = Operand->Emit(build); assert(from.Konst == 0); assert(ValueType->GetRegCount() == from.RegCount); - // Do it in-place. + // 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; + } + if (ValueType->GetRegType() == REGT_INT) { build->Emit(OP_NEG, from.RegNum, from.RegNum, 0); @@ -1653,10 +1661,10 @@ FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx) // DECORATE allows floats here so cast them to int. Operand = new FxIntCast(Operand, true); Operand = Operand->Resolve(ctx); - if (Operand == NULL) + if (Operand == nullptr) { delete this; - return NULL; + return nullptr; } } @@ -1665,7 +1673,7 @@ FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx) { ScriptPosition.Message(MSG_ERROR, "Integer type expected"); delete this; - return NULL; + return nullptr; } if (Operand->isConstant()) @@ -1804,13 +1812,13 @@ FxExpression *FxSizeAlign::Resolve(FCompileContext& ctx) { ScriptPosition.Message(MSG_ERROR, "cannot determine %s of a constant", Which == TK_AlignOf? "alignment" : "size"); delete this; - return NULL; + return nullptr; } else if (!Operand->RequestAddress(nullptr)) { ScriptPosition.Message(MSG_ERROR, "Operand must be addressable to determine %s", Which == TK_AlignOf ? "alignment" : "size"); delete this; - return NULL; + return nullptr; } else { @@ -2513,7 +2521,8 @@ FxAddSub::FxAddSub(int o, FxExpression *l, FxExpression *r) FxExpression *FxAddSub::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); - if (!ResolveLR(ctx, true)) return NULL; + if (!ResolveLR(ctx, true)) + return nullptr; if (!IsNumeric() && !IsVector()) { @@ -2652,13 +2661,14 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); - if (!ResolveLR(ctx, true)) return NULL; + if (!ResolveLR(ctx, true)) + return nullptr; if (!IsNumeric() && !IsVector()) { ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); delete this; - return NULL; + return nullptr; } else if (left->isConstant() && right->isConstant()) { @@ -2672,7 +2682,7 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx) { ScriptPosition.Message(MSG_ERROR, "Division by 0"); delete this; - return NULL; + return nullptr; } v = Operator == '*'? v1 * v2 : @@ -2693,7 +2703,7 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx) { ScriptPosition.Message(MSG_ERROR, "Division by 0"); delete this; - return NULL; + return nullptr; } v = Operator == '*'? v1 * v2 : @@ -2820,7 +2830,8 @@ FxExpression *FxPow::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); - if (!ResolveLR(ctx, true)) return nullptr; + if (!ResolveLR(ctx, true)) + return nullptr; if (!IsNumeric()) { @@ -2879,13 +2890,14 @@ FxCompareRel::FxCompareRel(int o, FxExpression *l, FxExpression *r) FxExpression *FxCompareRel::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); - if (!ResolveLR(ctx, true)) return NULL; + if (!ResolveLR(ctx, true)) + return nullptr; if (!IsNumeric()) { ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); delete this; - return NULL; + return nullptr; } else if (left->isConstant() && right->isConstant()) { @@ -3038,19 +3050,20 @@ FxExpression *FxCompareEq::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); - if (!ResolveLR(ctx, true)) return NULL; + if (!ResolveLR(ctx, true)) + return nullptr; if (!left || !right) { delete this; - return NULL; + return nullptr; } if (!IsNumeric() && !IsPointer() && !IsVector() && ValueType != TypeName) { ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); delete this; - return NULL; + return nullptr; } if (Operator == TK_ApproxEq && left->ValueType->GetRegType() != REGT_FLOAT && left->ValueType->GetRegType() != REGT_STRING) @@ -3174,7 +3187,8 @@ FxBinaryInt::FxBinaryInt(int o, FxExpression *l, FxExpression *r) FxExpression *FxBinaryInt::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); - if (!ResolveLR(ctx, false)) return NULL; + if (!ResolveLR(ctx, false)) + return nullptr; if (IsFloat() && ctx.FromDecorate) { @@ -3189,10 +3203,10 @@ FxExpression *FxBinaryInt::Resolve(FCompileContext& ctx) right = new FxIntCast(right, ctx.FromDecorate); right = right->Resolve(ctx); } - if (left == NULL || right == NULL) + if (left == nullptr || right == nullptr) { delete this; - return NULL; + return nullptr; } ValueType = TypeSInt32; } @@ -3201,7 +3215,7 @@ FxExpression *FxBinaryInt::Resolve(FCompileContext& ctx) { ScriptPosition.Message(MSG_ERROR, "Integer type expected"); delete this; - return NULL; + return nullptr; } else if (left->isConstant() && right->isConstant()) { @@ -3322,7 +3336,8 @@ FxLtGtEq::FxLtGtEq(FxExpression *l, FxExpression *r) FxExpression *FxLtGtEq::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); - if (!ResolveLR(ctx, true)) return NULL; + if (!ResolveLR(ctx, true)) + return nullptr; if (!left->IsNumeric() || !right->IsNumeric()) { @@ -3467,14 +3482,14 @@ FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx) else if (b_left==1) { FxExpression *x = right; - right=NULL; + right=nullptr; delete this; return x; } else if (b_right==1) { FxExpression *x = left; - left=NULL; + left=nullptr; delete this; return x; } @@ -3496,14 +3511,14 @@ FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx) else if (b_left==0) { FxExpression *x = right; - right=NULL; + right=nullptr; delete this; return x; } else if (b_right==0) { FxExpression *x = left; - left=NULL; + left=nullptr; delete this; return x; } @@ -3723,7 +3738,7 @@ ExpEmit FxTypeCheck::Emit(VMFunctionBuilder *build) PSymbol *sym = FindBuiltinFunction(NAME_BuiltinTypeCheck, BuiltinTypeCheck); assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); - assert(((PSymbolVMFunction *)sym)->Function != NULL); + assert(((PSymbolVMFunction *)sym)->Function != nullptr); auto callfunc = ((PSymbolVMFunction *)sym)->Function; int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); @@ -3813,7 +3828,7 @@ FxExpression *FxConditional::Resolve(FCompileContext& ctx) FxExpression *e = result? truex:falsex; delete (result? falsex:truex); - falsex = truex = NULL; + falsex = truex = nullptr; delete this; return e; } @@ -3867,9 +3882,22 @@ ExpEmit FxConditional::Emit(VMFunctionBuilder *build) ExpEmit trueop = truex->Emit(build); if (trueop.Konst) { - assert(trueop.RegType == REGT_FLOAT); - out = ExpEmit(build, REGT_FLOAT); - build->Emit(OP_LKF, out.RegNum, trueop.RegNum); + if (trueop.RegType == REGT_FLOAT) + { + out = ExpEmit(build, REGT_FLOAT); + build->Emit(OP_LKF, out.RegNum, trueop.RegNum); + } + else if (trueop.RegType == REGT_POINTER) + { + out = ExpEmit(build, REGT_POINTER); + build->Emit(OP_LKP, out.RegNum, trueop.RegNum); + } + else + { + assert(trueop.RegType == REGT_STRING); + out = ExpEmit(build, REGT_STRING); + build->Emit(OP_LKS, out.RegNum, trueop.RegNum); + } } else { @@ -3892,8 +3920,22 @@ ExpEmit FxConditional::Emit(VMFunctionBuilder *build) ExpEmit falseop = falsex->Emit(build); if (falseop.Konst) { - assert(falseop.RegType == REGT_FLOAT); - build->Emit(OP_LKF, out.RegNum, falseop.RegNum); + if (falseop.RegType == REGT_FLOAT) + { + out = ExpEmit(build, REGT_FLOAT); + build->Emit(OP_LKF, out.RegNum, falseop.RegNum); + } + else if (falseop.RegType == REGT_POINTER) + { + out = ExpEmit(build, REGT_POINTER); + build->Emit(OP_LKP, out.RegNum, falseop.RegNum); + } + else + { + assert(falseop.RegType == REGT_STRING); + out = ExpEmit(build, REGT_STRING); + build->Emit(OP_LKS, out.RegNum, falseop.RegNum); + } } else { @@ -3901,17 +3943,7 @@ ExpEmit FxConditional::Emit(VMFunctionBuilder *build) // returned by "true" so that only one register is returned by // this tree. falseop.Free(build); - if (falseop.RegType == REGT_INT) - { - build->Emit(OP_MOVE, out.RegNum, falseop.RegNum, 0); - } - else - { - assert(falseop.RegType == REGT_FLOAT); - assert(falseop.RegCount == out.RegCount); - static int flops[] = { OP_MOVEF, OP_MOVEV2, OP_MOVEV3 }; - build->Emit(flops[falseop.RegNum], out.RegNum, falseop.RegNum, 0); - } + build->Emit(falsex->ValueType->GetMoveOp(), out.RegNum, falseop.RegNum, 0); } } build->BackpatchToHere(truejump); @@ -3958,7 +3990,7 @@ FxExpression *FxAbs::Resolve(FCompileContext &ctx) { ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); delete this; - return NULL; + return nullptr; } else if (val->isConstant()) { @@ -3976,7 +4008,7 @@ FxExpression *FxAbs::Resolve(FCompileContext &ctx) default: // shouldn't happen delete this; - return NULL; + return nullptr; } FxExpression *x = new FxConstant(value, ScriptPosition); delete this; @@ -4047,7 +4079,7 @@ FxExpression *FxATan2::Resolve(FCompileContext &ctx) { ScriptPosition.Message(MSG_ERROR, "numeric value expected for parameter"); delete this; - return NULL; + return nullptr; } if (yval->isConstant() && xval->isConstant()) { @@ -4151,7 +4183,7 @@ FxExpression *FxMinMax::Resolve(FCompileContext &ctx) { ScriptPosition.Message(MSG_ERROR, "Arguments must be of type int or float"); delete this; - return NULL; + return nullptr; } } if (floatcount != 0) @@ -4230,7 +4262,7 @@ FxExpression *FxMinMax::Resolve(FCompileContext &ctx) } } delete choices[j]; - choices[j] = NULL; + choices[j] = nullptr; choices.Delete(j); } } @@ -4329,12 +4361,12 @@ FxRandom::FxRandom(FRandom * r, FxExpression *mi, FxExpression *ma, const FScrip : FxExpression(EFX_Random, pos) { EmitTail = false; - if (mi != NULL && ma != NULL) + if (mi != nullptr && ma != nullptr) { min = new FxIntCast(mi, nowarn); max = new FxIntCast(ma, nowarn); } - else min = max = NULL; + else min = max = nullptr; rng = r; ValueType = TypeSInt32; } @@ -4424,13 +4456,13 @@ ExpEmit FxRandom::Emit(VMFunctionBuilder *build) PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandom, BuiltinRandom); assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); - assert(((PSymbolVMFunction *)sym)->Function != NULL); + assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); - if (min != NULL && max != NULL) + if (min != nullptr && max != nullptr) { EmitParameter(build, min, ScriptPosition); EmitParameter(build, max, ScriptPosition); @@ -4545,7 +4577,7 @@ ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build) PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandom, BuiltinRandom); assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); - assert(((PSymbolVMFunction *)sym)->Function != NULL); + assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); @@ -4623,9 +4655,9 @@ ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build) // //========================================================================== FxFRandom::FxFRandom(FRandom *r, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos) -: FxRandom(r, NULL, NULL, pos, true) +: FxRandom(r, nullptr, nullptr, pos, true) { - if (mi != NULL && ma != NULL) + if (mi != nullptr && ma != nullptr) { min = new FxFloatCast(mi); max = new FxFloatCast(ma); @@ -4670,13 +4702,13 @@ ExpEmit FxFRandom::Emit(VMFunctionBuilder *build) PSymbol *sym = FindBuiltinFunction(NAME_BuiltinFRandom, BuiltinFRandom); assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); - assert(((PSymbolVMFunction *)sym)->Function != NULL); + assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); - if (min != NULL && max != NULL) + if (min != nullptr && max != nullptr) { EmitParameter(build, min, ScriptPosition); EmitParameter(build, max, ScriptPosition); @@ -4764,7 +4796,7 @@ ExpEmit FxRandom2::Emit(VMFunctionBuilder *build) PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandom, BuiltinRandom); assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); - assert(((PSymbolVMFunction *)sym)->Function != NULL); + assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); @@ -4896,7 +4928,7 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) } // now check the global identifiers. - else if ((sym = ctx.FindGlobal(Identifier)) != NULL) + else if ((sym = ctx.FindGlobal(Identifier)) != nullptr) { if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) { @@ -4910,7 +4942,7 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) } // and line specials - else if ((num = P_FindLineSpecial(Identifier, NULL, NULL))) + else if ((num = P_FindLineSpecial(Identifier, nullptr, nullptr))) { ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as line special %d\n", Identifier.GetChars(), num); newex = new FxConstant(num, ScriptPosition); @@ -5355,25 +5387,25 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) // DECORATE allows floats here so cast them to int. index = new FxIntCast(index, ctx.FromDecorate); index = index->Resolve(ctx); - if (index == NULL) + if (index == nullptr) { delete this; - return NULL; + return nullptr; } } if (index->ValueType->GetRegType() != REGT_INT && index->ValueType != TypeName) { ScriptPosition.Message(MSG_ERROR, "Array index must be integer"); delete this; - return NULL; + return nullptr; } PArray *arraytype = dyn_cast(Array->ValueType); - if (arraytype == NULL) + if (arraytype == nullptr) { ScriptPosition.Message(MSG_ERROR, "'[]' can only be used with arrays."); delete this; - return NULL; + return nullptr; } if (index->isConstant()) { @@ -5382,7 +5414,7 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) { ScriptPosition.Message(MSG_ERROR, "Array index out of bounds"); delete this; - return NULL; + return nullptr; } } @@ -5392,13 +5424,13 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) // int arrays only for now ScriptPosition.Message(MSG_ERROR, "Only numeric arrays are supported."); delete this; - return NULL; + return nullptr; } if (!Array->RequestAddress(&AddressWritable)) { ScriptPosition.Message(MSG_ERROR, "Unable to dereference array."); delete this; - return NULL; + return nullptr; } return this; } @@ -5901,12 +5933,12 @@ FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx) bool failed = false; SAFE_RESOLVE_OPT(Self, ctx); - if (ArgList != NULL) + if (ArgList != nullptr) { for (unsigned i = 0; i < ArgList->Size(); i++) { (*ArgList)[i] = (*ArgList)[i]->Resolve(ctx); - if ((*ArgList)[i] == NULL) + if ((*ArgList)[i] == nullptr) { failed = true; } @@ -5934,7 +5966,7 @@ FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx) if (failed) { delete this; - return NULL; + return nullptr; } } ValueType = TypeSInt32; @@ -5959,7 +5991,7 @@ int BuiltinCallLineSpecial(VMFrameStack *stack, VMValue *param, TArray { v[i - 2] = param[i].i; } - ACTION_RETURN_INT(P_ExecuteSpecial(param[0].i, NULL, reinterpret_cast(param[1].a), false, v[0], v[1], v[2], v[3], v[4])); + ACTION_RETURN_INT(P_ExecuteSpecial(param[0].i, nullptr, reinterpret_cast(param[1].a), false, v[0], v[1], v[2], v[3], v[4])); } ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) @@ -5970,7 +6002,7 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) // fixme: This really should use the Self pointer that got passed to this class instead of just using the first argument from the function. // Once static functions are possible, or specials can be called through a member access operator this won't work anymore. build->Emit(OP_PARAM, 0, REGT_POINTER, 0); // pass self - if (ArgList != NULL) + if (ArgList != nullptr) { for (; i < ArgList->Size(); ++i) { @@ -6002,7 +6034,7 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) PSymbol *sym = FindBuiltinFunction(NAME_BuiltinCallLineSpecial, BuiltinCallLineSpecial); assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); - assert(((PSymbolVMFunction *)sym)->Function != NULL); + assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; if (EmitTail) @@ -6144,7 +6176,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) if (failed) { delete this; - return NULL; + return nullptr; } TArray &rets = proto->ReturnTypes; if (rets.Size() > 0) @@ -6207,7 +6239,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) } } // Emit code to pass explicit parameters - if (ArgList != NULL) + if (ArgList != nullptr) { for (unsigned i = 0; i < ArgList->Size(); ++i) { @@ -6311,25 +6343,25 @@ FxExpression *FxFlopFunctionCall::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); - if (ArgList == NULL || ArgList->Size() != 1) + if (ArgList == nullptr || ArgList->Size() != 1) { ScriptPosition.Message(MSG_ERROR, "%s only has one parameter", FName(FxFlops[Index].Name).GetChars()); delete this; - return NULL; + return nullptr; } (*ArgList)[0] = (*ArgList)[0]->Resolve(ctx); - if ((*ArgList)[0] == NULL) + if ((*ArgList)[0] == nullptr) { delete this; - return NULL; + return nullptr; } if (!(*ArgList)[0]->IsNumeric()) { ScriptPosition.Message(MSG_ERROR, "numeric value expected for parameter"); delete this; - return NULL; + return nullptr; } if ((*ArgList)[0]->isConstant()) { @@ -6417,7 +6449,7 @@ FxExpression *FxSequence::Resolve(FCompileContext &ctx) CHECKRESOLVED(); for (unsigned i = 0; i < Expressions.Size(); ++i) { - if (NULL == (Expressions[i] = Expressions[i]->Resolve(ctx))) + if (nullptr == (Expressions[i] = Expressions[i]->Resolve(ctx))) { delete this; return nullptr; @@ -6455,7 +6487,7 @@ VMFunction *FxSequence::GetDirectFunction() { return Expressions[0]->GetDirectFunction(); } - return NULL; + return nullptr; } //========================================================================== @@ -6792,7 +6824,7 @@ FxIfStatement::FxIfStatement(FxExpression *cond, FxExpression *true_part, WhenFalse = false_part; if (WhenTrue != nullptr) WhenTrue->NeedResult = false; if (WhenFalse != nullptr) WhenFalse->NeedResult = false; - assert(cond != NULL); + assert(cond != nullptr); } FxIfStatement::~FxIfStatement() @@ -6840,8 +6872,8 @@ FxExpression *FxIfStatement::Resolve(FCompileContext &ctx) FxExpression *e = result ? WhenTrue : WhenFalse; delete (result ? WhenFalse : WhenTrue); - WhenTrue = WhenFalse = NULL; - if (e == NULL) e = new FxNop(ScriptPosition); // create a dummy if this statement gets completely removed by optimizing out the constant parts. + WhenTrue = WhenFalse = nullptr; + if (e == nullptr) e = new FxNop(ScriptPosition); // create a dummy if this statement gets completely removed by optimizing out the constant parts. delete this; return e; } @@ -6861,7 +6893,7 @@ ExpEmit FxIfStatement::Emit(VMFunctionBuilder *build) ExpEmit cond = Condition->Emit(build); assert(cond.RegType != REGT_STRING && !cond.Konst); - if (WhenTrue != NULL) + if (WhenTrue != nullptr) { path1 = WhenTrue; path2 = WhenFalse; @@ -6871,9 +6903,9 @@ ExpEmit FxIfStatement::Emit(VMFunctionBuilder *build) { // When there is only a false path, reverse the condition so we can // treat it as a true path. - assert(WhenFalse != NULL); + assert(WhenFalse != nullptr); path1 = WhenFalse; - path2 = NULL; + path2 = nullptr; condcheck = 0; } @@ -6900,7 +6932,7 @@ ExpEmit FxIfStatement::Emit(VMFunctionBuilder *build) // Evaluate first path v = path1->Emit(build); v.Free(build); - if (path2 != NULL) + if (path2 != nullptr) { size_t path1jump = build->Emit(OP_JMP, 0); // Evaluate second path @@ -7412,18 +7444,18 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx) { ScriptPosition.Message(MSG_ERROR, "Cannot convert %s to class type", basex->ValueType->DescriptiveName()); delete this; - return NULL; + return nullptr; } if (basex->isConstant()) { FName clsname = static_cast(basex)->GetValue().GetName(); - PClass *cls = NULL; + PClass *cls = nullptr; if (clsname != NAME_None) { cls = PClass::FindClass(clsname); - if (cls == NULL) + if (cls == nullptr) { /* lax */ // Since this happens in released WADs it must pass without a terminal error... :( @@ -7437,7 +7469,7 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx) { ScriptPosition.Message(MSG_ERROR, "class '%s' is not compatible with '%s'", clsname.GetChars(), desttype->TypeName.GetChars()); delete this; - return NULL; + return nullptr; } ScriptPosition.Message(MSG_DEBUG, "resolving '%s' as class name", clsname.GetChars()); } @@ -7474,7 +7506,7 @@ int BuiltinNameToClass(VMFrameStack *stack, VMValue *param, TArray &def if (!cls->IsDescendantOf(desttype)) { Printf("class '%s' is not compatible with '%s'", clsname.GetChars(), desttype->TypeName.GetChars()); - cls = NULL; + cls = nullptr; } ret->SetPointer(const_cast(cls), ATAG_OBJECT); return 1; @@ -7484,7 +7516,7 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build) { if (basex->ValueType != TypeName) { - return ExpEmit(build->GetConstantAddress(NULL, ATAG_OBJECT), REGT_POINTER, true); + return ExpEmit(build->GetConstantAddress(nullptr, ATAG_OBJECT), REGT_POINTER, true); } ExpEmit clsname = basex->Emit(build); assert(!clsname.Konst); @@ -7497,7 +7529,7 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build) PSymbol *sym = FindBuiltinFunction(NAME_BuiltinNameToClass, BuiltinNameToClass); assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); - assert(((PSymbolVMFunction *)sym)->Function != NULL); + assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1); @@ -7526,7 +7558,7 @@ FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx) ScriptPosition.Message(MSG_ERROR, "%s: Attempt to jump to non existing state index %d", ctx.Class->TypeName.GetChars(), index); delete this; - return NULL; + return nullptr; } FxExpression *x = new FxConstant(aclass->OwnedStates + index, ScriptPosition); delete this; @@ -7677,7 +7709,7 @@ FxMultiNameState::FxMultiNameState(const char *_statestring, const FScriptPositi } names = MakeStateNameList(statestring); names.Insert(0, scopename); - scope = NULL; + scope = nullptr; } //========================================================================== @@ -7693,7 +7725,7 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) if (names[0] == NAME_None) { - scope = NULL; + scope = nullptr; } else if (names[0] == NAME_Super) { @@ -7702,27 +7734,27 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) else { scope = PClass::FindActor(names[0]); - if (scope == NULL) + if (scope == nullptr) { ScriptPosition.Message(MSG_ERROR, "Unknown class '%s' in state label", names[0].GetChars()); delete this; - return NULL; + return nullptr; } else if (!scope->IsAncestorOf(ctx.Class)) { ScriptPosition.Message(MSG_ERROR, "'%s' is not an ancestor of '%s'", names[0].GetChars(), ctx.Class->TypeName.GetChars()); delete this; - return NULL; + return nullptr; } } - if (scope != NULL) + if (scope != nullptr) { - FState *destination = NULL; + FState *destination = nullptr; // If the label is class specific we can resolve it right here if (names[1] != NAME_None) { destination = scope->FindState(names.Size()-1, &names[1], false); - if (destination == NULL) + if (destination == nullptr) { ScriptPosition.Message(MSG_OPTERROR, "Unknown state jump destination"); /* lax */ @@ -7749,7 +7781,7 @@ static int DoFindState(VMFrameStack *stack, VMValue *param, int numparam, VMRetu { PARAM_OBJECT_AT(0, self, AActor); FState *state = self->GetClass()->FindState(numparam - 1, names); - if (state == NULL) + if (state == nullptr) { const char *dot = ""; Printf("Jump target '"); @@ -7822,7 +7854,7 @@ ExpEmit FxMultiNameState::Emit(VMFunctionBuilder *build) } assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); - assert(((PSymbolVMFunction *)sym)->Function != NULL); + assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), names.Size() + 1, 1); diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index f071614a8..6c47fabe0 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -671,7 +671,7 @@ void InitThingdef() symt.AddSymbol(new PField(NAME_Score, TypeSInt32, VARF_Native, myoffsetof(AActor, Score))); symt.AddSymbol(new PField(NAME_Accuracy, TypeSInt32, VARF_Native, myoffsetof(AActor, accuracy))); symt.AddSymbol(new PField(NAME_Stamina, TypeSInt32, VARF_Native, myoffsetof(AActor, stamina))); - symt.AddSymbol(new PField(NAME_Height, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Height))); + symt.AddSymbol(new PField(NAME_Height, TypeFloat64, VARF_Native, myoffsetof(AActor, Height))); symt.AddSymbol(new PField(NAME_Radius, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, radius))); symt.AddSymbol(new PField(NAME_ReactionTime, TypeSInt32, VARF_Native, myoffsetof(AActor, reactiontime))); symt.AddSymbol(new PField(NAME_MeleeRange, TypeFloat64, VARF_Native, myoffsetof(AActor, meleerange))); @@ -698,6 +698,7 @@ void InitThingdef() symt.AddSymbol(new PField("Pos", TypeVector3, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos))); symt.AddSymbol(new PField("Vel", TypeVector3, VARF_Native, myoffsetof(AActor, Vel))); symt.AddSymbol(new PField("Scale", TypeVector2, VARF_Native, myoffsetof(AActor, Scale))); + symt.AddSymbol(new PField("CurState", TypeState, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, state))); // has to be renamed on the script side because it clashes with the same named type. symt.AddSymbol(new PField("SeeState", TypeState, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, SeeState))); symt.AddSymbol(new PField(NAME_Target, TypeActor, VARF_Native, myoffsetof(AActor, target))); symt.AddSymbol(new PField(NAME_Master, TypeActor, VARF_Native, myoffsetof(AActor, master))); diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 78a448f7c..9e8b84163 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1490,6 +1490,7 @@ PType *ZCCCompiler::ResolveUserType(ZCC_BasicType *type, PSymbolTable *symt) } return type; } + Error(type, "Unable to resolve %s as type.", FName(type->UserType->Id).GetChars()); return TypeError; } @@ -2186,8 +2187,8 @@ static bool CheckRandom(ZCC_Expression *duration) FxExpression *ZCCCompiler::SetupActionFunction(PClass *cls, ZCC_TreeNode *af) { // We have 3 cases to consider here: - // 1. An action function without parameters. This can be called directly - // 2. An action functon with parameters or a non-action function. This needs to be wrapped into a helper function to set everything up. + // 1. A function without parameters. This can be called directly + // 2. A functon with parameters. This needs to be wrapped into a helper function to set everything up. // 3. An anonymous function. // 1. and 2. are exposed through AST_ExprFunctionCall @@ -2236,9 +2237,10 @@ void ZCCCompiler::CompileStates() { for (auto c : Classes) { + if (!c->Type()->IsDescendantOf(RUNTIME_CLASS(AActor))) { - Error(c->cls, "%s: States can only be defined for actors.", c->Type()->TypeName.GetChars()); + if (c->States.Size()) Error(c->cls, "%s: States can only be defined for actors.", c->Type()->TypeName.GetChars()); continue; } FString statename; // The state builder wants the label as one complete string, not separated into tokens. diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 6de64d07e..8ea4bb114 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -1,3 +1,4 @@ +zscript/base.txt zscript/constants.txt zscript/actor.txt diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 18f0facd0..4fc18d75d 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -53,9 +53,13 @@ class Actor : Thinker native return GetPointer(ptr_select1) == GetPointer(ptr_select2); } + native static bool isDehState(state st); native void SetOrigin(vector3 newpos, bool moving); + native void SetXYZ(vector3 newpos); native Actor GetPointer(int aaptr); + 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 OldSpawnMissile(Actor dest, class type, Actor owner = null); 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); @@ -228,7 +232,6 @@ class Actor : Thinker native native void A_SpawnFly(class spawntype = null); // needs special treatment for default native void A_BrainExplode(); native void A_Detonate(); - native void A_Mushroom(class spawntype = "FatShot", int numspawns = 0, int flags = 0, float vrange = 4.0, float hrange = 0.5); native bool A_CallSpecial(int special, int arg1=0, int arg2=0, int arg3=0, int arg4=0, int arg5=0); native void A_SetFloorClip(); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt new file mode 100644 index 000000000..bda63f059 --- /dev/null +++ b/wadsrc/static/zscript/base.txt @@ -0,0 +1,8 @@ +class Object native +{ + /*virtual*/ native void Destroy(); +} + +class Thinker : Object native +{ +} \ No newline at end of file diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index b14634e0d..5cbbbaf9e 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -876,3 +876,9 @@ enum EDmgFlags DMG_NO_PROTECT = 256, DMG_USEANGLE = 512, } + +enum EReplace +{ + NO_REPLACE = 0, + ALLOW_REPLACE = 1 +} diff --git a/wadsrc/static/zscript/doom/fatso.txt b/wadsrc/static/zscript/doom/fatso.txt index c477cbb44..d1a456d16 100644 --- a/wadsrc/static/zscript/doom/fatso.txt +++ b/wadsrc/static/zscript/doom/fatso.txt @@ -110,6 +110,12 @@ extend class Actor A_PlaySound("fatso/raiseguns", CHAN_WEAPON); } + // + // Mancubus attack, + // firing three missiles in three different directions? + // Doesn't look like it. + // + void A_FatAttack1(class spawntype = "FatShot") { if (target) @@ -163,5 +169,54 @@ extend class Actor } } } + + // + // killough 9/98: a mushroom explosion effect, sorta :) + // Original idea: Linguica + // + + void A_Mushroom(class spawntype = "FatShot", int numspawns = 0, int flags = 0, float vrange = 4.0, float hrange = 0.5) + { + int i, j; + + if (numspawns == 0) + { + numspawns = GetMissileDamage(0, 1); + } + + A_Explode(128, 128, (flags & MSF_DontHurt) ? 0 : XF_HURTSOURCE); + + // Now launch mushroom cloud + Actor aimtarget = Spawn("Mapspot", pos, NO_REPLACE); // We need something to aim at. + Actor owner = (flags & MSF_DontHurt) ? target : self; + aimtarget.Height = Height; + + bool shootmode = ((flags & MSF_Classic) || // Flag explicitely set, or no flags and compat options + (flags == 0 && isDehState(CurState) && GetCVar("compat_mushroom"))); + + for (i = -numspawns; i <= numspawns; i += 8) + { + for (j = -numspawns; j <= numspawns; j += 8) + { + Actor mo; + aimtarget.SetXYZ(pos + (i, j, (i, j).Length() * vrange)); // Aim up fairly high + if (shootmode) + { // Use old function for MBF compatibility + mo = OldSpawnMissile(aimtarget, spawntype, owner); + } + else // Use normal function + { + mo = SpawnMissile(aimtarget, spawntype, owner); + } + if (mo) + { // Slow it down a bit + mo.Vel *= hrange; + mo.bNoGravity = false; // Make debris fall under gravity + } + } + } + aimtarget.Destroy(); + } + }