This commit is contained in:
Rachael Alexanderson 2017-01-11 18:54:43 -05:00
commit a3ad22a460
13 changed files with 207 additions and 21 deletions

View file

@ -708,11 +708,15 @@ protected:
class PStruct : public PNamedType class PStruct : public PNamedType
{ {
DECLARE_CLASS(PStruct, PNamedType); DECLARE_CLASS(PStruct, PNamedType);
public: public:
PStruct(FName name, PTypeBase *outer); PStruct(FName name, PTypeBase *outer);
TArray<PField *> Fields; TArray<PField *> Fields;
bool HasNativeFields; bool HasNativeFields;
// Some internal structs require explicit construction and destruction of fields the VM cannot handle directly so use thes two functions for it.
VMFunction *mConstructor = nullptr;
VMFunction *mDestructor = nullptr;
virtual PField *AddField(FName name, PType *type, DWORD flags=0); 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 = 0); virtual PField *AddNativeField(FName name, PType *type, size_t address, DWORD flags = 0, int bitvalue = 0);

View file

@ -4408,6 +4408,8 @@ enum EACSFunctions
ACSF_DamageActor, // [arookas] ACSF_DamageActor, // [arookas]
ACSF_SetActorFlag, ACSF_SetActorFlag,
ACSF_SetTranslation, ACSF_SetTranslation,
ACSF_GetActorFloorTexture,
ACSF_GetActorFloorTerrain,
// OpenGL stuff // OpenGL stuff
@ -6100,6 +6102,35 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
break; break;
} }
case ACSF_GetActorFloorTexture:
{
auto a = SingleActorFromTID(args[0], activator);
if (a != nullptr)
{
return GlobalACSStrings.AddString(TexMan[a->floorpic]->Name);
}
else
{
return GlobalACSStrings.AddString("");
}
break;
}
case ACSF_GetActorFloorTerrain:
{
auto a = SingleActorFromTID(args[0], activator);
if (a != nullptr)
{
return GlobalACSStrings.AddString(Terrains[a->floorterrain].Name);
}
else
{
return GlobalACSStrings.AddString("");
}
break;
}
default: default:
break; break;

View file

@ -261,7 +261,7 @@ bool P_CheckPosition(AActor *thing, const DVector2 &pos, FCheckPosition &tm, boo
AActor *P_CheckOnmobj (AActor *thing); AActor *P_CheckOnmobj (AActor *thing);
void P_FakeZMovement (AActor *mo); void P_FakeZMovement (AActor *mo);
bool P_TryMove(AActor* thing, const DVector2 &pos, int dropoff, const secplane_t * onfloor, FCheckPosition &tm, bool missileCheck = false); bool P_TryMove(AActor* thing, const DVector2 &pos, int dropoff, const secplane_t * onfloor, FCheckPosition &tm, bool missileCheck = false);
bool P_TryMove(AActor* thing, const DVector2 &pos, int dropoff, const secplane_t * onfloor = NULL); bool P_TryMove(AActor* thing, const DVector2 &pos, int dropoff, const secplane_t * onfloor = NULL, bool missilecheck = false);
bool P_CheckMove(AActor *thing, const DVector2 &pos, int flags = 0); bool P_CheckMove(AActor *thing, const DVector2 &pos, int flags = 0);
void P_ApplyTorque(AActor *mo); void P_ApplyTorque(AActor *mo);

View file

@ -84,6 +84,49 @@ TArray<spechit_t> spechit;
TArray<spechit_t> portalhit; TArray<spechit_t> portalhit;
// FCheckPosition requires explicit contstruction and destruction when used in the VM
DEFINE_ACTION_FUNCTION(_FCheckPosition, _Constructor)
{
PARAM_SELF_STRUCT_PROLOGUE(FCheckPosition);
new(self) FCheckPosition;
return 0;
}
DEFINE_ACTION_FUNCTION(_FCheckPosition, _Destructor)
{
PARAM_SELF_STRUCT_PROLOGUE(FCheckPosition);
self->~FCheckPosition();
return 0;
}
DEFINE_ACTION_FUNCTION(_FCheckPosition, ClearLastRipped)
{
PARAM_SELF_STRUCT_PROLOGUE(FCheckPosition);
self->LastRipped.Clear();
return 0;
}
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, thing);
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, pos);
DEFINE_FIELD_NAMED_X(FCheckPosition, FCheckPosition, sector, cursector);
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, floorz);
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, ceilingz);
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, dropoffz);
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, floorpic);
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, floorterrain);
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, floorsector);
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, ceilingpic);
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, ceilingsector);
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, touchmidtex);
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, abovemidtex);
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, floatok);
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, FromPMove);
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, ceilingline);
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, stepthing);
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, DoRipping);
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, portalstep);
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, PushTime);
//========================================================================== //==========================================================================
// //
// CanCollideWith // CanCollideWith
@ -1845,8 +1888,17 @@ DEFINE_ACTION_FUNCTION(AActor, CheckPosition)
PARAM_FLOAT(x); PARAM_FLOAT(x);
PARAM_FLOAT(y); PARAM_FLOAT(y);
PARAM_BOOL_DEF(actorsonly); PARAM_BOOL_DEF(actorsonly);
PARAM_POINTER_DEF(tm, FCheckPosition);
if (tm)
{
ACTION_RETURN_BOOL(P_CheckPosition(self, DVector2(x, y), *tm, actorsonly));
}
else
{
ACTION_RETURN_BOOL(P_CheckPosition(self, DVector2(x, y), actorsonly)); ACTION_RETURN_BOOL(P_CheckPosition(self, DVector2(x, y), actorsonly));
} }
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// //
@ -2637,10 +2689,10 @@ pushline:
bool P_TryMove(AActor *thing, const DVector2 &pos, bool P_TryMove(AActor *thing, const DVector2 &pos,
int dropoff, // killough 3/15/98: allow dropoff as option int dropoff, // killough 3/15/98: allow dropoff as option
const secplane_t *onfloor) // [RH] Let P_TryMove keep the thing on the floor const secplane_t *onfloor, bool missilecheck) // [RH] Let P_TryMove keep the thing on the floor
{ {
FCheckPosition tm; FCheckPosition tm;
return P_TryMove(thing, pos, dropoff, onfloor, tm); return P_TryMove(thing, pos, dropoff, onfloor, tm, missilecheck);
} }
DEFINE_ACTION_FUNCTION(AActor, TryMove) DEFINE_ACTION_FUNCTION(AActor, TryMove)
@ -2649,7 +2701,16 @@ DEFINE_ACTION_FUNCTION(AActor, TryMove)
PARAM_FLOAT(x); PARAM_FLOAT(x);
PARAM_FLOAT(y); PARAM_FLOAT(y);
PARAM_INT(dropoff); PARAM_INT(dropoff);
ACTION_RETURN_BOOL(P_TryMove(self, DVector2(x, y), dropoff)); PARAM_BOOL_DEF(missilecheck);
PARAM_POINTER_DEF(tm, FCheckPosition);
if (tm == nullptr)
{
ACTION_RETURN_BOOL(P_TryMove(self, DVector2(x, y), dropoff, nullptr, missilecheck));
}
else
{
ACTION_RETURN_BOOL(P_TryMove(self, DVector2(x, y), dropoff, nullptr, *tm, missilecheck));
}
} }

View file

@ -5160,6 +5160,7 @@ ExpEmit FxRandom::Emit(VMFunctionBuilder *build)
assert(((PSymbolVMFunction *)sym)->Function != nullptr); assert(((PSymbolVMFunction *)sym)->Function != nullptr);
callfunc = ((PSymbolVMFunction *)sym)->Function; callfunc = ((PSymbolVMFunction *)sym)->Function;
if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use
int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K);
build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG));
@ -5410,6 +5411,7 @@ ExpEmit FxFRandom::Emit(VMFunctionBuilder *build)
assert(((PSymbolVMFunction *)sym)->Function != nullptr); assert(((PSymbolVMFunction *)sym)->Function != nullptr);
callfunc = ((PSymbolVMFunction *)sym)->Function; callfunc = ((PSymbolVMFunction *)sym)->Function;
if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use
int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K);
build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG));
@ -5504,6 +5506,7 @@ ExpEmit FxRandom2::Emit(VMFunctionBuilder *build)
assert(((PSymbolVMFunction *)sym)->Function != nullptr); assert(((PSymbolVMFunction *)sym)->Function != nullptr);
callfunc = ((PSymbolVMFunction *)sym)->Function; callfunc = ((PSymbolVMFunction *)sym)->Function;
if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use
int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K);
build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG));
@ -7801,6 +7804,7 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build)
ArgList.DeleteAndClear(); ArgList.DeleteAndClear();
ArgList.ShrinkToFit(); ArgList.ShrinkToFit();
if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use
if (EmitTail) if (EmitTail)
{ {
build->Emit(OP_TAIL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2 + i, 0); build->Emit(OP_TAIL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2 + i, 0);
@ -8072,6 +8076,8 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
assert(build->Registers[REGT_POINTER].GetMostUsed() >= build->NumImplicits); assert(build->Registers[REGT_POINTER].GetMostUsed() >= build->NumImplicits);
int count = 0; int count = 0;
if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use
if (count == 1) if (count == 1)
{ {
ExpEmit reg; ExpEmit reg;
@ -9508,6 +9514,19 @@ ExpEmit FxReturnStatement::Emit(VMFunctionBuilder *build)
{ {
ExpEmit out(0, REGT_NIL); ExpEmit out(0, REGT_NIL);
// call the destructors for all structs requiring one.
// go in reverse order of construction
for (int i = build->ConstructedStructs.Size() - 1; i >= 0; i--)
{
auto pstr = static_cast<PStruct*>(build->ConstructedStructs[i]->ValueType);
assert(pstr->mDestructor != nullptr);
ExpEmit reg(build, REGT_POINTER);
build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(build->ConstructedStructs[i]->StackOffset));
build->Emit(OP_PARAM, 0, reg.RegType, reg.RegNum);
build->Emit(OP_CALL_K, build->GetConstantAddress(pstr->mDestructor, ATAG_OBJECT), 1, 0);
reg.Free(build);
}
// If we return nothing, use a regular RET opcode. // If we return nothing, use a regular RET opcode.
// Otherwise just return the value we're given. // Otherwise just return the value we're given.
if (Value == nullptr) if (Value == nullptr)
@ -10173,6 +10192,19 @@ ExpEmit FxLocalVariableDeclaration::Emit(VMFunctionBuilder *build)
else else
{ {
// Init arrays and structs. // Init arrays and structs.
if (ValueType->IsA(RUNTIME_CLASS(PStruct)))
{
auto pstr = static_cast<PStruct*>(ValueType);
if (pstr->mConstructor != nullptr)
{
ExpEmit reg(build, REGT_POINTER);
build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(StackOffset));
build->Emit(OP_PARAM, 0, reg.RegType, reg.RegNum);
build->Emit(OP_CALL_K, build->GetConstantAddress(pstr->mConstructor, ATAG_OBJECT), 1, 0);
reg.Free(build);
}
if (pstr->mDestructor != nullptr) build->ConstructedStructs.Push(this);
}
} }
return ExpEmit(); return ExpEmit();
} }
@ -10184,6 +10216,22 @@ void FxLocalVariableDeclaration::Release(VMFunctionBuilder *build)
{ {
build->Registers[ValueType->GetRegType()].Return(RegNum, RegCount); build->Registers[ValueType->GetRegType()].Return(RegNum, RegCount);
} }
else
{
if (ValueType->IsA(RUNTIME_CLASS(PStruct)))
{
auto pstr = static_cast<PStruct*>(ValueType);
if (pstr->mDestructor != nullptr)
{
ExpEmit reg(build, REGT_POINTER);
build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(StackOffset));
build->Emit(OP_PARAM, 0, reg.RegType, reg.RegNum);
build->Emit(OP_CALL_K, build->GetConstantAddress(pstr->mDestructor, ATAG_OBJECT), 1, 0);
reg.Free(build);
}
build->ConstructedStructs.Delete(build->ConstructedStructs.Find(this));
}
}
// Stack space will not be released because that would make controlled destruction impossible. // 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. // For that all local stack variables need to live for the entire execution of a function.
} }

View file

@ -1993,6 +1993,7 @@ class FxLocalVariableDeclaration : public FxExpression
public: public:
int StackOffset = -1; int StackOffset = -1;
int RegNum = -1; int RegNum = -1;
bool constructed = false;
FxLocalVariableDeclaration(PType *type, FName name, FxExpression *initval, int varflags, const FScriptPosition &p); FxLocalVariableDeclaration(PType *type, FName name, FxExpression *initval, int varflags, const FScriptPosition &p);
~FxLocalVariableDeclaration(); ~FxLocalVariableDeclaration();

View file

@ -37,9 +37,7 @@
** **
*/ */
#define private public // this file needs public access to TArray's private 'Count' field so just hack the visibility qualifiers here
#include "tarray.h" #include "tarray.h"
#undef private
#include "dobject.h" #include "dobject.h"
#include "thingdef.h" #include "thingdef.h"
// We need one specific type for each of the 7 integral VM types and instantiate the needed functions for each of them. // We need one specific type for each of the 7 integral VM types and instantiate the needed functions for each of them.
@ -775,10 +773,10 @@ DEFINE_ACTION_FUNCTION(FDynArray_String, Clear)
return 0; return 0;
} }
DEFINE_FIELD_NAMED(FDynArray_I8, Count, Size) // clashes with type 'Inventory'. DEFINE_FIELD_NAMED_X(DynArray_I8, FArray, Count, Size)
DEFINE_FIELD_NAMED(FDynArray_I16, Count, Size) // clashes with type 'Inventory'. DEFINE_FIELD_NAMED_X(DynArray_I16, FArray, Count, Size)
DEFINE_FIELD_NAMED(FDynArray_I32, Count, Size) // clashes with type 'Inventory'. DEFINE_FIELD_NAMED_X(DynArray_I32, FArray, Count, Size)
DEFINE_FIELD_NAMED(FDynArray_F32, Count, Size) // clashes with type 'Inventory'. DEFINE_FIELD_NAMED_X(DynArray_F32, FArray, Count, Size)
DEFINE_FIELD_NAMED(FDynArray_F64, Count, Size) // clashes with type 'Inventory'. DEFINE_FIELD_NAMED_X(DynArray_F64, FArray, Count, Size)
DEFINE_FIELD_NAMED(FDynArray_Ptr, Count, Size) // clashes with type 'Inventory'. DEFINE_FIELD_NAMED_X(DynArray_Ptr, FArray, Count, Size)
DEFINE_FIELD_NAMED(FDynArray_String, Count, Size) // clashes with type 'Inventory'. DEFINE_FIELD_NAMED_X(DynArray_String, FArray, Count, Size)

View file

@ -50,6 +50,8 @@
#include "zstring.h" #include "zstring.h"
#include "d_event.h" #include "d_event.h"
#include "g_levellocals.h" #include "g_levellocals.h"
#include "vm.h"
#include "p_checkposition.h"
static TArray<FPropertyInfo*> properties; static TArray<FPropertyInfo*> properties;
static TArray<AFuncDesc> AFTable; static TArray<AFuncDesc> AFTable;
@ -856,6 +858,14 @@ void InitThingdef()
qsort(&AFTable[0], AFTable.Size(), sizeof(AFTable[0]), funccmp); qsort(&AFTable[0], AFTable.Size(), sizeof(AFTable[0]), funccmp);
} }
// Add the constructor and destructor to FCheckPosition.
auto fcp = NewStruct("FCheckPosition", nullptr);
fcp->mConstructor = *FindFunction(fcp, "_Constructor")->VMPointer;
fcp->mDestructor = *FindFunction(fcp, "_Destructor")->VMPointer;
fcp->Size = sizeof(FCheckPosition);
fcp->Align = alignof(FCheckPosition);
FieldTable.Clear(); FieldTable.Clear();
if (FieldTable.Size() == 0) if (FieldTable.Size() == 0)
{ {

View file

@ -1116,9 +1116,9 @@ struct AFuncDesc
MSVC_FSEG FieldDesc const *const VMField_##icls##_##name##_HookPtr GCC_FSEG = &VMField_##icls##_##name; MSVC_FSEG FieldDesc const *const VMField_##icls##_##name##_HookPtr GCC_FSEG = &VMField_##icls##_##name;
#define DEFINE_FIELD_NAMED_X(cls, icls, name, scriptname) \ #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 }; \ static const FieldDesc VMField_##cls##_##scriptname = { "A" #cls, #scriptname, (unsigned)myoffsetof(icls, name), (unsigned)sizeof(icls::name), 0 }; \
extern FieldDesc const *const VMField_##icls##_##scriptname##_HookPtr; \ extern FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr; \
MSVC_FSEG FieldDesc const *const VMField_##icls##_##scriptname##_HookPtr GCC_FSEG = &VMField_##icls##_##scriptname; MSVC_FSEG FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr GCC_FSEG = &VMField_##cls##_##scriptname;
#define DEFINE_FIELD_X_BIT(cls, icls, name, bitval) \ #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 }; \ static const FieldDesc VMField_##icls##_##name = { "A" #cls, #name, (unsigned)myoffsetof(icls, name), (unsigned)sizeof(icls::name), bitval }; \

View file

@ -5,6 +5,7 @@
class VMFunctionBuilder; class VMFunctionBuilder;
class FxExpression; class FxExpression;
class FxLocalVariableDeclaration;
struct ExpEmit struct ExpEmit
{ {
@ -92,6 +93,7 @@ public:
// keep the frame pointer, if needed, in a register because the LFP opcode is hideously inefficient, requiring more than 20 instructions on x64. // 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; ExpEmit FramePointer;
TArray<FxLocalVariableDeclaration *> ConstructedStructs;
private: private:
struct AddrKonst struct AddrKonst

View file

@ -71,8 +71,8 @@ protected:
struct FArray struct FArray
{ {
void *Array; void *Array;
unsigned int Most;
unsigned int Count; unsigned int Count;
unsigned int Most;
}; };
// T is the type stored in the array. // T is the type stored in the array.

View file

@ -1337,7 +1337,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE nothing, LPSTR cmdline, int n
_CrtSetDbgFlag (_CrtSetDbgFlag(0) | _CRTDBG_LEAK_CHECK_DF); _CrtSetDbgFlag (_CrtSetDbgFlag(0) | _CRTDBG_LEAK_CHECK_DF);
// Use this to break at a specific allocation number. // Use this to break at a specific allocation number.
_crtBreakAlloc = 124459; //_crtBreakAlloc = 53039;
#endif #endif
DoMain (hInstance); DoMain (hInstance);

View file

@ -1,3 +1,34 @@
struct FCheckPosition
{
// in
native Actor thing;
native Vector3 pos;
// out
native Sector cursector;
native double floorz;
native double ceilingz;
native double dropoffz;
native TextureID floorpic;
native int floorterrain;
native Sector floorsector;
native TextureID ceilingpic;
native Sector ceilingsector;
native bool touchmidtex;
native bool abovemidtex;
native bool floatok;
native bool FromPMove;
native line ceilingline;
native Actor stepthing;
native bool DoRipping;
native bool portalstep;
native int PushTime;
native void ClearLastRipped();
}
class Actor : Thinker native class Actor : Thinker native
{ {
const DEFAULT_HEALTH = 1000; const DEFAULT_HEALTH = 1000;
@ -327,7 +358,7 @@ class Actor : Thinker native
native double BulletSlope(out FTranslatedLineTarget pLineTarget = null, int aimflags = 0); native double BulletSlope(out FTranslatedLineTarget pLineTarget = null, int aimflags = 0);
native Actor AimTarget(); native Actor AimTarget();
native bool CheckMissileSpawn(double maxdist); native bool CheckMissileSpawn(double maxdist);
native bool CheckPosition(Vector2 pos, bool actorsonly = false); native bool CheckPosition(Vector2 pos, bool actorsonly = false, FCheckPosition tm = null);
native bool TestMobjLocation(); native bool TestMobjLocation();
native static Actor Spawn(class<Actor> type, vector3 pos = (0,0,0), int replace = NO_REPLACE); native static Actor Spawn(class<Actor> type, vector3 pos = (0,0,0), int replace = NO_REPLACE);
native Actor SpawnMissile(Actor dest, class<Actor> type, Actor owner = null); native Actor SpawnMissile(Actor dest, class<Actor> type, Actor owner = null);
@ -388,7 +419,7 @@ class Actor : Thinker native
return true; return true;
} }
native bool TryMove(vector2 newpos, int dropoff); native bool TryMove(vector2 newpos, int dropoff, bool missilecheck = false, FCheckPosition tm = null);
native void NewChaseDir(); native void NewChaseDir();
native void RandomChaseDir(); native void RandomChaseDir();
native bool CheckMissileRange(); native bool CheckMissileRange();