diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index e9f574ea43..88c31d0078 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 413b681245..3a4a1c1800 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 72d79647f0..db09a0387a 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 ae0581e05b..e586f1fbe3 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 0ec6ec15b6..428266d0fa 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 884bcc8a52..739b5574fc 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 f8f6a0b8a3..fc9268c5b0 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);