mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-27 14:22:13 +00:00
Merge branch 'master' of https://github.com/rheit/zdoom
This commit is contained in:
commit
50765f8b79
17 changed files with 830 additions and 46 deletions
|
@ -382,6 +382,7 @@ enum ActorFlag7
|
||||||
MF7_ALLOWTHRUFLAGS = 0x00400000, // [MC] Allow THRUACTORS and the likes on puffs to prevent mod breakage.
|
MF7_ALLOWTHRUFLAGS = 0x00400000, // [MC] Allow THRUACTORS and the likes on puffs to prevent mod breakage.
|
||||||
MF7_USEKILLSCRIPTS = 0x00800000, // [JM] Use "KILL" Script on death if not forced by GameInfo.
|
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_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.
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- mobj.renderflags ---
|
// --- mobj.renderflags ---
|
||||||
|
@ -978,6 +979,8 @@ public:
|
||||||
DVector3 __Pos; // double underscores so that it won't get used by accident. Access to this should be exclusively through the designated access functions.
|
DVector3 __Pos; // double underscores so that it won't get used by accident. Access to this should be exclusively through the designated access functions.
|
||||||
DVector3 OldRenderPos;
|
DVector3 OldRenderPos;
|
||||||
|
|
||||||
|
DAngle SpriteAngle;
|
||||||
|
DAngle SpriteRotation;
|
||||||
DRotator Angles;
|
DRotator Angles;
|
||||||
DVector3 Vel;
|
DVector3 Vel;
|
||||||
double Speed;
|
double Speed;
|
||||||
|
|
|
@ -214,6 +214,7 @@ xx(Brainexplode)
|
||||||
// Weapon animator names.
|
// Weapon animator names.
|
||||||
xx(Select)
|
xx(Select)
|
||||||
xx(Deselect)
|
xx(Deselect)
|
||||||
|
xx(DeadLowered)
|
||||||
xx(Ready)
|
xx(Ready)
|
||||||
xx(Fire)
|
xx(Fire)
|
||||||
xx(Hold)
|
xx(Hold)
|
||||||
|
|
|
@ -161,7 +161,7 @@ PClassActor *P_GetSpawnableType(int spawnnum);
|
||||||
void InitSpawnablesFromMapinfo();
|
void InitSpawnablesFromMapinfo();
|
||||||
int P_Thing_CheckInputNum(player_t *p, int inputnum);
|
int P_Thing_CheckInputNum(player_t *p, int inputnum);
|
||||||
int P_Thing_Warp(AActor *caller, AActor *reference, double xofs, double yofs, double zofs, DAngle angle, int flags, double heightoffset, double radiusoffset, DAngle pitch);
|
int P_Thing_Warp(AActor *caller, AActor *reference, double xofs, double yofs, double zofs, DAngle angle, int flags, double heightoffset, double radiusoffset, DAngle pitch);
|
||||||
bool P_Thing_CheckProximity(AActor *self, PClass *classname, double distance, int count, int flags, int ptr);
|
int P_Thing_CheckProximity(AActor *self, PClass *classname, double distance, int count, int flags, int ptr, bool counting = false);
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
|
|
@ -383,6 +383,11 @@ void AActor::Serialize(FArchive &arc)
|
||||||
<< RipLevelMin
|
<< RipLevelMin
|
||||||
<< RipLevelMax;
|
<< RipLevelMax;
|
||||||
arc << DefThreshold;
|
arc << DefThreshold;
|
||||||
|
if (SaveVersion >= 4549)
|
||||||
|
{
|
||||||
|
arc << SpriteAngle;
|
||||||
|
arc << SpriteRotation;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
FString tagstr;
|
FString tagstr;
|
||||||
|
|
|
@ -1087,7 +1087,7 @@ DEFINE_ACTION_FUNCTION(AInventory, A_Lower)
|
||||||
{ // Player is dead, so don't bring up a pending weapon
|
{ // Player is dead, so don't bring up a pending weapon
|
||||||
// Player is dead, so keep the weapon off screen
|
// Player is dead, so keep the weapon off screen
|
||||||
P_SetPsprite(player, PSP_FLASH, nullptr);
|
P_SetPsprite(player, PSP_FLASH, nullptr);
|
||||||
psp->SetState(nullptr);
|
psp->SetState(player->ReadyWeapon->FindState(NAME_DeadLowered));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// [RH] Clear the flash state. Only needed for Strife.
|
// [RH] Clear the flash state. Only needed for Strife.
|
||||||
|
|
|
@ -696,16 +696,16 @@ int P_Thing_CheckInputNum(player_t *p, int inputnum)
|
||||||
}
|
}
|
||||||
return renum;
|
return renum;
|
||||||
}
|
}
|
||||||
bool P_Thing_CheckProximity(AActor *self, PClass *classname, double distance, int count, int flags, int ptr)
|
int P_Thing_CheckProximity(AActor *self, PClass *classname, double distance, int count, int flags, int ptr, bool counting)
|
||||||
{
|
{
|
||||||
AActor *ref = COPY_AAPTR(self, ptr);
|
AActor *ref = COPY_AAPTR(self, ptr);
|
||||||
|
|
||||||
// We need these to check out.
|
// We need these to check out.
|
||||||
if (!ref || !classname || distance <= 0)
|
if (!ref || !classname || distance <= 0)
|
||||||
return false;
|
return 0;
|
||||||
|
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
bool result = false;
|
int result = 0;
|
||||||
double closer = distance, farther = 0, current = distance;
|
double closer = distance, farther = 0, current = distance;
|
||||||
const bool ptrWillChange = !!(flags & (CPXF_SETTARGET | CPXF_SETMASTER | CPXF_SETTRACER));
|
const bool ptrWillChange = !!(flags & (CPXF_SETTARGET | CPXF_SETMASTER | CPXF_SETTRACER));
|
||||||
const bool ptrDistPref = !!(flags & (CPXF_CLOSEST | CPXF_FARTHEST));
|
const bool ptrDistPref = !!(flags & (CPXF_CLOSEST | CPXF_FARTHEST));
|
||||||
|
@ -740,7 +740,7 @@ bool P_Thing_CheckProximity(AActor *self, PClass *classname, double distance, in
|
||||||
if ((ref->Distance2D(mo) < distance &&
|
if ((ref->Distance2D(mo) < distance &&
|
||||||
((flags & CPXF_NOZ) ||
|
((flags & CPXF_NOZ) ||
|
||||||
((ref->Z() > mo->Z() && ref->Z() - mo->Top() < distance) ||
|
((ref->Z() > mo->Z() && ref->Z() - mo->Top() < distance) ||
|
||||||
(ref->Z() <= mo->Z() && mo->Z() - ref->Top() < distance)))))
|
(ref->Z() <= mo->Z() && mo->Z() - ref->Top() < distance)))))
|
||||||
{
|
{
|
||||||
if ((flags & CPXF_CHECKSIGHT) && !(P_CheckSight(mo, ref, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY)))
|
if ((flags & CPXF_CHECKSIGHT) && !(P_CheckSight(mo, ref, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY)))
|
||||||
continue;
|
continue;
|
||||||
|
@ -766,19 +766,19 @@ bool P_Thing_CheckProximity(AActor *self, PClass *classname, double distance, in
|
||||||
{
|
{
|
||||||
if (!(flags & (CPXF_COUNTDEAD | CPXF_DEADONLY)))
|
if (!(flags & (CPXF_COUNTDEAD | CPXF_DEADONLY)))
|
||||||
continue;
|
continue;
|
||||||
counter++;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (flags & CPXF_DEADONLY)
|
if (flags & CPXF_DEADONLY)
|
||||||
continue;
|
continue;
|
||||||
counter++;
|
|
||||||
}
|
}
|
||||||
|
counter++;
|
||||||
|
|
||||||
// Abort if the number of matching classes nearby is greater, we have obviously succeeded in our goal.
|
// Abort if the number of matching classes nearby is greater, we have obviously succeeded in our goal.
|
||||||
if (counter > count)
|
// Don't abort if calling the counting version CheckProximity non-action function.
|
||||||
|
if (!counting && counter > count)
|
||||||
{
|
{
|
||||||
result = (flags & (CPXF_LESSOREQUAL | CPXF_EXACT)) ? false : true;
|
result = (flags & (CPXF_LESSOREQUAL | CPXF_EXACT)) ? 0 : 1;
|
||||||
|
|
||||||
// However, if we have one SET* flag and either the closest or farthest flags, keep the function going.
|
// However, if we have one SET* flag and either the closest or farthest flags, keep the function going.
|
||||||
if (ptrWillChange && ptrDistPref)
|
if (ptrWillChange && ptrDistPref)
|
||||||
|
@ -805,12 +805,14 @@ bool P_Thing_CheckProximity(AActor *self, PClass *classname, double distance, in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (counter == count)
|
if (!counting)
|
||||||
result = true;
|
{
|
||||||
else if (counter < count)
|
if (counter == count)
|
||||||
result = !!((flags & CPXF_LESSOREQUAL) && !(flags & CPXF_EXACT));
|
result = 1;
|
||||||
|
else if (counter < count)
|
||||||
return result;
|
result = !!((flags & CPXF_LESSOREQUAL) && !(flags & CPXF_EXACT)) ? 1 : 0;
|
||||||
|
}
|
||||||
|
return counting ? counter : result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int P_Thing_Warp(AActor *caller, AActor *reference, double xofs, double yofs, double zofs, DAngle angle, int flags, double heightoffset, double radiusoffset, DAngle pitch)
|
int P_Thing_Warp(AActor *caller, AActor *reference, double xofs, double yofs, double zofs, DAngle angle, int flags, double heightoffset, double radiusoffset, DAngle pitch)
|
||||||
|
|
|
@ -809,11 +809,17 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor
|
||||||
angle_t rot;
|
angle_t rot;
|
||||||
if (sprframe->Texture[0] == sprframe->Texture[1])
|
if (sprframe->Texture[0] == sprframe->Texture[1])
|
||||||
{
|
{
|
||||||
rot = (ang - thing->Angles.Yaw + 45.0/2*9).BAMs() >> 28;
|
if (thing->flags7 & MF7_SPRITEANGLE)
|
||||||
|
rot = (thing->SpriteAngle + 45.0 / 2 * 9).BAMs() >> 28;
|
||||||
|
else
|
||||||
|
rot = (ang - (thing->Angles.Yaw + thing->SpriteRotation) + 45.0 / 2 * 9).BAMs() >> 28;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rot = (ang - thing->Angles.Yaw + (45.0/2*9-180.0/16)).BAMs() >> 28;
|
if (thing->flags7 & MF7_SPRITEANGLE)
|
||||||
|
rot = (thing->SpriteAngle + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28;
|
||||||
|
else
|
||||||
|
rot = (ang - (thing->Angles.Yaw + thing->SpriteRotation) + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28;
|
||||||
}
|
}
|
||||||
picnum = sprframe->Texture[rot];
|
picnum = sprframe->Texture[rot];
|
||||||
if (sprframe->Flip & (1 << rot))
|
if (sprframe->Flip & (1 << rot))
|
||||||
|
@ -848,11 +854,17 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor
|
||||||
angle_t rot;
|
angle_t rot;
|
||||||
if (sprframe->Texture[0] == sprframe->Texture[1])
|
if (sprframe->Texture[0] == sprframe->Texture[1])
|
||||||
{
|
{
|
||||||
rot = (ang - thing->Angles.Yaw + 45.0 / 2 * 9).BAMs() >> 28;
|
if (thing->flags7 & MF7_SPRITEANGLE)
|
||||||
|
rot = (thing->SpriteAngle + 45.0 / 2 * 9).BAMs() >> 28;
|
||||||
|
else
|
||||||
|
rot = (ang - (thing->Angles.Yaw + thing->SpriteRotation) + 45.0 / 2 * 9).BAMs() >> 28;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rot = (ang - thing->Angles.Yaw + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28;
|
if (thing->flags7 & MF7_SPRITEANGLE)
|
||||||
|
rot = (thing->SpriteAngle + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28;
|
||||||
|
else
|
||||||
|
rot = (ang - (thing->Angles.Yaw + thing->SpriteRotation) + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28;
|
||||||
}
|
}
|
||||||
picnum = sprframe->Texture[rot];
|
picnum = sprframe->Texture[rot];
|
||||||
if (sprframe->Flip & (1 << rot))
|
if (sprframe->Flip & (1 << rot))
|
||||||
|
|
|
@ -395,6 +395,64 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetGibHealth)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// GetSpriteAngle
|
||||||
|
//
|
||||||
|
// NON-ACTION function returns the sprite angle of a pointer.
|
||||||
|
//==========================================================================
|
||||||
|
DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetSpriteAngle)
|
||||||
|
{
|
||||||
|
if (numret > 0)
|
||||||
|
{
|
||||||
|
assert(ret != NULL);
|
||||||
|
PARAM_SELF_PROLOGUE(AActor);
|
||||||
|
PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; }
|
||||||
|
|
||||||
|
AActor *target = COPY_AAPTR(self, ptr);
|
||||||
|
if (target == nullptr)
|
||||||
|
{
|
||||||
|
ret->SetFloat(0.0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const double ang = target->SpriteAngle.Degrees;
|
||||||
|
ret->SetFloat(ang);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// GetSpriteRotation
|
||||||
|
//
|
||||||
|
// NON-ACTION function returns the sprite rotation of a pointer.
|
||||||
|
//==========================================================================
|
||||||
|
DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetSpriteRotation)
|
||||||
|
{
|
||||||
|
if (numret > 0)
|
||||||
|
{
|
||||||
|
assert(ret != NULL);
|
||||||
|
PARAM_SELF_PROLOGUE(AActor);
|
||||||
|
PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; }
|
||||||
|
|
||||||
|
AActor *target = COPY_AAPTR(self, ptr);
|
||||||
|
if (target == nullptr)
|
||||||
|
{
|
||||||
|
ret->SetFloat(0.0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const double ang = target->SpriteRotation.Degrees;
|
||||||
|
ret->SetFloat(ang);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// GetZAt
|
// GetZAt
|
||||||
|
@ -585,6 +643,38 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetPlayerInput)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// CountProximity
|
||||||
|
//
|
||||||
|
// NON-ACTION function of A_CheckProximity that returns how much it counts.
|
||||||
|
// Takes a pointer as anyone may or may not be a player.
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION_PARAMS(AActor, CountProximity)
|
||||||
|
{
|
||||||
|
if (numret > 0)
|
||||||
|
{
|
||||||
|
PARAM_SELF_PROLOGUE(AActor);
|
||||||
|
PARAM_CLASS(classname, AActor);
|
||||||
|
PARAM_FLOAT(distance);
|
||||||
|
PARAM_INT_OPT(flags) { flags = 0; }
|
||||||
|
PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; }
|
||||||
|
|
||||||
|
AActor *mobj = COPY_AAPTR(self, ptr);
|
||||||
|
if (mobj == nullptr)
|
||||||
|
{
|
||||||
|
ret->SetInt(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret->SetInt(P_Thing_CheckProximity(self, classname, distance, 0, flags, ptr, true));
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
//
|
//
|
||||||
// __decorate_internal_state__
|
// __decorate_internal_state__
|
||||||
|
@ -7202,7 +7292,7 @@ enum CPSFFlags
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CopySpriteFrame)
|
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CopySpriteFrame)
|
||||||
{
|
{
|
||||||
PARAM_SELF_PROLOGUE(AActor);
|
PARAM_ACTION_PROLOGUE;
|
||||||
PARAM_INT(from);
|
PARAM_INT(from);
|
||||||
PARAM_INT(to);
|
PARAM_INT(to);
|
||||||
PARAM_INT_OPT(flags) { flags = 0; }
|
PARAM_INT_OPT(flags) { flags = 0; }
|
||||||
|
@ -7219,3 +7309,49 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CopySpriteFrame)
|
||||||
if (!(flags & CPSF_NOFRAME)) copyto->frame = copyfrom->frame;
|
if (!(flags & CPSF_NOFRAME)) copyto->frame = copyfrom->frame;
|
||||||
ACTION_RETURN_BOOL(true);
|
ACTION_RETURN_BOOL(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// A_SetSpriteAngle(angle, ptr)
|
||||||
|
//
|
||||||
|
// Specifies which angle the actor must always draw its sprite from.
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpriteAngle)
|
||||||
|
{
|
||||||
|
PARAM_ACTION_PROLOGUE;
|
||||||
|
PARAM_FLOAT_OPT(angle) { angle = 0.; }
|
||||||
|
PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; }
|
||||||
|
|
||||||
|
AActor *mobj = COPY_AAPTR(self, ptr);
|
||||||
|
|
||||||
|
if (mobj == nullptr)
|
||||||
|
{
|
||||||
|
ACTION_RETURN_BOOL(false);
|
||||||
|
}
|
||||||
|
mobj->SpriteAngle = angle;
|
||||||
|
ACTION_RETURN_BOOL(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// A_SetSpriteRotation(angle, ptr)
|
||||||
|
//
|
||||||
|
// Specifies how much to fake a sprite rotation.
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpriteRotation)
|
||||||
|
{
|
||||||
|
PARAM_ACTION_PROLOGUE;
|
||||||
|
PARAM_ANGLE_OPT(angle) { angle = 0.; }
|
||||||
|
PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; }
|
||||||
|
|
||||||
|
AActor *mobj = COPY_AAPTR(self, ptr);
|
||||||
|
|
||||||
|
if (mobj == nullptr)
|
||||||
|
{
|
||||||
|
ACTION_RETURN_BOOL(false);
|
||||||
|
}
|
||||||
|
mobj->SpriteRotation = angle;
|
||||||
|
ACTION_RETURN_BOOL(true);
|
||||||
|
}
|
||||||
|
|
|
@ -259,6 +259,7 @@ static FFlagDef ActorFlagDefs[]=
|
||||||
DEFINE_FLAG(MF7, ALLOWTHRUFLAGS, AActor, flags7),
|
DEFINE_FLAG(MF7, ALLOWTHRUFLAGS, AActor, flags7),
|
||||||
DEFINE_FLAG(MF7, USEKILLSCRIPTS, AActor, flags7),
|
DEFINE_FLAG(MF7, USEKILLSCRIPTS, AActor, flags7),
|
||||||
DEFINE_FLAG(MF7, NOKILLSCRIPTS, AActor, flags7),
|
DEFINE_FLAG(MF7, NOKILLSCRIPTS, AActor, flags7),
|
||||||
|
DEFINE_FLAG(MF7, SPRITEANGLE, AActor, flags7),
|
||||||
|
|
||||||
// Effect flags
|
// Effect flags
|
||||||
DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects),
|
DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects),
|
||||||
|
|
|
@ -48,8 +48,10 @@
|
||||||
#define RESOLVE(p,c) if (p!=NULL) p = p->Resolve(c)
|
#define RESOLVE(p,c) if (p!=NULL) p = p->Resolve(c)
|
||||||
#define ABORT(p) if (!(p)) { delete this; return NULL; }
|
#define ABORT(p) if (!(p)) { delete this; return NULL; }
|
||||||
#define SAFE_RESOLVE(p,c) RESOLVE(p,c); ABORT(p)
|
#define SAFE_RESOLVE(p,c) RESOLVE(p,c); ABORT(p)
|
||||||
|
#define SAFE_RESOLVE_OPT(p,c) if (p!=NULL) { SAFE_RESOLVE(p,c) }
|
||||||
|
|
||||||
class VMFunctionBuilder;
|
class VMFunctionBuilder;
|
||||||
|
class FxJumpStatement;
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
|
@ -59,21 +61,15 @@ class VMFunctionBuilder;
|
||||||
|
|
||||||
struct FCompileContext
|
struct FCompileContext
|
||||||
{
|
{
|
||||||
PClassActor *cls;
|
TArray<FxJumpStatement *> Jumps;
|
||||||
|
PClassActor *Class;
|
||||||
|
|
||||||
FCompileContext(PClassActor *_cls = NULL)
|
FCompileContext(PClassActor *cls = nullptr);
|
||||||
{
|
|
||||||
cls = _cls;
|
|
||||||
}
|
|
||||||
|
|
||||||
PSymbol *FindInClass(FName identifier)
|
PSymbol *FindInClass(FName identifier);
|
||||||
{
|
PSymbol *FindGlobal(FName identifier);
|
||||||
return cls ? cls->Symbols.FindSymbol(identifier, true) : NULL;
|
|
||||||
}
|
void HandleJumps(int token, FxExpression *handler);
|
||||||
PSymbol *FindGlobal(FName identifier)
|
|
||||||
{
|
|
||||||
return GlobalSymbols.FindSymbol(identifier, true);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -212,6 +208,8 @@ public:
|
||||||
|
|
||||||
virtual ExpEmit Emit(VMFunctionBuilder *build);
|
virtual ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
|
|
||||||
|
TArray<FxJumpStatement *> JumpAddresses;
|
||||||
|
|
||||||
FScriptPosition ScriptPosition;
|
FScriptPosition ScriptPosition;
|
||||||
PType *ValueType;
|
PType *ValueType;
|
||||||
|
|
||||||
|
@ -930,6 +928,80 @@ public:
|
||||||
ExpEmit Emit(VMFunctionBuilder *build);
|
ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FxWhileLoop
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
class FxWhileLoop : public FxExpression
|
||||||
|
{
|
||||||
|
FxExpression *Condition;
|
||||||
|
FxExpression *Code;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FxWhileLoop(FxExpression *condition, FxExpression *code, const FScriptPosition &pos);
|
||||||
|
~FxWhileLoop();
|
||||||
|
FxExpression *Resolve(FCompileContext&);
|
||||||
|
ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
|
};
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FxDoWhileLoop
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
class FxDoWhileLoop : public FxExpression
|
||||||
|
{
|
||||||
|
FxExpression *Condition;
|
||||||
|
FxExpression *Code;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FxDoWhileLoop(FxExpression *condition, FxExpression *code, const FScriptPosition &pos);
|
||||||
|
~FxDoWhileLoop();
|
||||||
|
FxExpression *Resolve(FCompileContext&);
|
||||||
|
ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
|
};
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FxForLoop
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
class FxForLoop : public FxExpression
|
||||||
|
{
|
||||||
|
FxExpression *Init;
|
||||||
|
FxExpression *Condition;
|
||||||
|
FxExpression *Iteration;
|
||||||
|
FxExpression *Code;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FxForLoop(FxExpression *init, FxExpression *condition, FxExpression *iteration, FxExpression *code, const FScriptPosition &pos);
|
||||||
|
~FxForLoop();
|
||||||
|
FxExpression *Resolve(FCompileContext&);
|
||||||
|
ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
|
};
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FxJumpStatement
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
class FxJumpStatement : public FxExpression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FxJumpStatement(int token, const FScriptPosition &pos);
|
||||||
|
FxExpression *Resolve(FCompileContext&);
|
||||||
|
ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
|
|
||||||
|
int Token;
|
||||||
|
size_t Address;
|
||||||
|
FxExpression *AddressResolver;
|
||||||
|
};
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// FxReturnStatement
|
// FxReturnStatement
|
||||||
|
|
|
@ -85,6 +85,45 @@ static const FLOP FxFlops[] =
|
||||||
{ NAME_TanH, FLOP_TANH, [](double v) { return g_tanh(v); } },
|
{ NAME_TanH, FLOP_TANH, [](double v) { return g_tanh(v); } },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FCompileContext
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FCompileContext::FCompileContext(PClassActor *cls) : Class(cls)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PSymbol *FCompileContext::FindInClass(FName identifier)
|
||||||
|
{
|
||||||
|
return Class ? Class->Symbols.FindSymbol(identifier, true) : nullptr;
|
||||||
|
}
|
||||||
|
PSymbol *FCompileContext::FindGlobal(FName identifier)
|
||||||
|
{
|
||||||
|
return GlobalSymbols.FindSymbol(identifier, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCompileContext::HandleJumps(int token, FxExpression *handler)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < Jumps.Size(); i++)
|
||||||
|
{
|
||||||
|
if (Jumps[i]->Token == token)
|
||||||
|
{
|
||||||
|
Jumps[i]->AddressResolver = handler;
|
||||||
|
handler->JumpAddresses.Push(Jumps[i]);
|
||||||
|
Jumps.Delete(i);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// ExpEmit
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
ExpEmit::ExpEmit(VMFunctionBuilder *build, int type)
|
ExpEmit::ExpEmit(VMFunctionBuilder *build, int type)
|
||||||
: RegNum(build->Registers[type].Get(1)), RegType(type), Konst(false), Fixed(false)
|
: RegNum(build->Registers[type].Get(1)), RegType(type), Konst(false), Fixed(false)
|
||||||
{
|
{
|
||||||
|
@ -2838,14 +2877,14 @@ FxSelf::FxSelf(const FScriptPosition &pos)
|
||||||
FxExpression *FxSelf::Resolve(FCompileContext& ctx)
|
FxExpression *FxSelf::Resolve(FCompileContext& ctx)
|
||||||
{
|
{
|
||||||
CHECKRESOLVED();
|
CHECKRESOLVED();
|
||||||
if (!ctx.cls)
|
if (!ctx.Class)
|
||||||
{
|
{
|
||||||
// can't really happen with DECORATE's expression evaluator.
|
// can't really happen with DECORATE's expression evaluator.
|
||||||
ScriptPosition.Message(MSG_ERROR, "self used outside of a member function");
|
ScriptPosition.Message(MSG_ERROR, "self used outside of a member function");
|
||||||
delete this;
|
delete this;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
ValueType = ctx.cls;
|
ValueType = ctx.Class;
|
||||||
ValueType = NewPointer(RUNTIME_CLASS(DObject));
|
ValueType = NewPointer(RUNTIME_CLASS(DObject));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -3818,6 +3857,369 @@ ExpEmit FxIfStatement::Emit(VMFunctionBuilder *build)
|
||||||
return ExpEmit();
|
return ExpEmit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FxWhileLoop
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FxWhileLoop::FxWhileLoop(FxExpression *condition, FxExpression *code, const FScriptPosition &pos)
|
||||||
|
: FxExpression(pos), Condition(condition), Code(code)
|
||||||
|
{
|
||||||
|
ValueType = TypeVoid;
|
||||||
|
}
|
||||||
|
|
||||||
|
FxWhileLoop::~FxWhileLoop()
|
||||||
|
{
|
||||||
|
SAFE_DELETE(Condition);
|
||||||
|
SAFE_DELETE(Code);
|
||||||
|
}
|
||||||
|
|
||||||
|
FxExpression *FxWhileLoop::Resolve(FCompileContext &ctx)
|
||||||
|
{
|
||||||
|
CHECKRESOLVED();
|
||||||
|
SAFE_RESOLVE(Condition, ctx);
|
||||||
|
SAFE_RESOLVE_OPT(Code, ctx);
|
||||||
|
|
||||||
|
ctx.HandleJumps(TK_Break, this);
|
||||||
|
ctx.HandleJumps(TK_Continue, this);
|
||||||
|
|
||||||
|
if (Condition->ValueType != TypeBool)
|
||||||
|
{
|
||||||
|
Condition = new FxBoolCast(Condition);
|
||||||
|
SAFE_RESOLVE(Condition, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Condition->isConstant())
|
||||||
|
{
|
||||||
|
if (static_cast<FxConstant *>(Condition)->GetValue().GetBool() == false)
|
||||||
|
{ // Nothing happens
|
||||||
|
FxExpression *nop = new FxNop(ScriptPosition);
|
||||||
|
delete this;
|
||||||
|
return nop;
|
||||||
|
}
|
||||||
|
else if (Code == nullptr)
|
||||||
|
{ // "while (true) { }"
|
||||||
|
// Someone could be using this for testing.
|
||||||
|
ScriptPosition.Message(MSG_WARNING, "Infinite empty loop");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpEmit FxWhileLoop::Emit(VMFunctionBuilder *build)
|
||||||
|
{
|
||||||
|
assert(Condition->ValueType == TypeBool);
|
||||||
|
|
||||||
|
size_t loopstart, loopend;
|
||||||
|
size_t jumpspot;
|
||||||
|
|
||||||
|
// Evaluate the condition and execute/break out of the loop.
|
||||||
|
loopstart = build->GetAddress();
|
||||||
|
if (!Condition->isConstant())
|
||||||
|
{
|
||||||
|
ExpEmit cond = Condition->Emit(build);
|
||||||
|
build->Emit(OP_TEST, cond.RegNum, 0);
|
||||||
|
jumpspot = build->Emit(OP_JMP, 0);
|
||||||
|
cond.Free(build);
|
||||||
|
}
|
||||||
|
else assert(static_cast<FxConstant *>(Condition)->GetValue().GetBool() == true);
|
||||||
|
|
||||||
|
// Execute the loop's content.
|
||||||
|
if (Code != nullptr)
|
||||||
|
{
|
||||||
|
ExpEmit code = Code->Emit(build);
|
||||||
|
code.Free(build);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop back.
|
||||||
|
build->Backpatch(build->Emit(OP_JMP, 0), loopstart);
|
||||||
|
loopend = build->GetAddress();
|
||||||
|
|
||||||
|
if (!Condition->isConstant())
|
||||||
|
{
|
||||||
|
build->Backpatch(jumpspot, loopend);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Give a proper address to any break/continue statement within this loop.
|
||||||
|
for (unsigned int i = 0; i < JumpAddresses.Size(); i++)
|
||||||
|
{
|
||||||
|
if (JumpAddresses[i]->Token == TK_Break)
|
||||||
|
{
|
||||||
|
build->Backpatch(JumpAddresses[i]->Address, loopend);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // Continue statement.
|
||||||
|
build->Backpatch(JumpAddresses[i]->Address, loopstart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExpEmit();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FxDoWhileLoop
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FxDoWhileLoop::FxDoWhileLoop(FxExpression *condition, FxExpression *code, const FScriptPosition &pos)
|
||||||
|
: FxExpression(pos), Condition(condition), Code(code)
|
||||||
|
{
|
||||||
|
ValueType = TypeVoid;
|
||||||
|
}
|
||||||
|
|
||||||
|
FxDoWhileLoop::~FxDoWhileLoop()
|
||||||
|
{
|
||||||
|
SAFE_DELETE(Condition);
|
||||||
|
SAFE_DELETE(Code);
|
||||||
|
}
|
||||||
|
|
||||||
|
FxExpression *FxDoWhileLoop::Resolve(FCompileContext &ctx)
|
||||||
|
{
|
||||||
|
CHECKRESOLVED();
|
||||||
|
SAFE_RESOLVE(Condition, ctx);
|
||||||
|
SAFE_RESOLVE_OPT(Code, ctx);
|
||||||
|
|
||||||
|
ctx.HandleJumps(TK_Break, this);
|
||||||
|
ctx.HandleJumps(TK_Continue, this);
|
||||||
|
|
||||||
|
if (Condition->ValueType != TypeBool)
|
||||||
|
{
|
||||||
|
Condition = new FxBoolCast(Condition);
|
||||||
|
SAFE_RESOLVE(Condition, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Condition->isConstant())
|
||||||
|
{
|
||||||
|
if (static_cast<FxConstant *>(Condition)->GetValue().GetBool() == false)
|
||||||
|
{ // The code executes once, if any.
|
||||||
|
if (JumpAddresses.Size() == 0)
|
||||||
|
{ // We would still have to handle the jumps however.
|
||||||
|
FxExpression *e = Code;
|
||||||
|
if (e == nullptr) e = new FxNop(ScriptPosition);
|
||||||
|
Code = nullptr;
|
||||||
|
delete this;
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Code == nullptr)
|
||||||
|
{ // "do { } while (true);"
|
||||||
|
// Someone could be using this for testing.
|
||||||
|
ScriptPosition.Message(MSG_WARNING, "Infinite empty loop");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpEmit FxDoWhileLoop::Emit(VMFunctionBuilder *build)
|
||||||
|
{
|
||||||
|
assert(Condition->ValueType == TypeBool);
|
||||||
|
|
||||||
|
size_t loopstart, loopend;
|
||||||
|
size_t codestart;
|
||||||
|
|
||||||
|
// Execute the loop's content.
|
||||||
|
codestart = build->GetAddress();
|
||||||
|
if (Code != nullptr)
|
||||||
|
{
|
||||||
|
ExpEmit code = Code->Emit(build);
|
||||||
|
code.Free(build);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Evaluate the condition and execute/break out of the loop.
|
||||||
|
loopstart = build->GetAddress();
|
||||||
|
if (!Condition->isConstant())
|
||||||
|
{
|
||||||
|
ExpEmit cond = Condition->Emit(build);
|
||||||
|
build->Emit(OP_TEST, cond.RegNum, 1);
|
||||||
|
cond.Free(build);
|
||||||
|
build->Backpatch(build->Emit(OP_JMP, 0), codestart);
|
||||||
|
}
|
||||||
|
else if (static_cast<FxConstant *>(Condition)->GetValue().GetBool() == true)
|
||||||
|
{ // Always looping
|
||||||
|
build->Backpatch(build->Emit(OP_JMP, 0), codestart);
|
||||||
|
}
|
||||||
|
loopend = build->GetAddress();
|
||||||
|
|
||||||
|
// Give a proper address to any break/continue statement within this loop.
|
||||||
|
for (unsigned int i = 0; i < JumpAddresses.Size(); i++)
|
||||||
|
{
|
||||||
|
if (JumpAddresses[i]->Token == TK_Break)
|
||||||
|
{
|
||||||
|
build->Backpatch(JumpAddresses[i]->Address, loopend);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // Continue statement.
|
||||||
|
build->Backpatch(JumpAddresses[i]->Address, loopstart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExpEmit();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FxForLoop
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FxForLoop::FxForLoop(FxExpression *init, FxExpression *condition, FxExpression *iteration, FxExpression *code, const FScriptPosition &pos)
|
||||||
|
: FxExpression(pos), Init(init), Condition(condition), Iteration(iteration), Code(code)
|
||||||
|
{
|
||||||
|
ValueType = TypeVoid;
|
||||||
|
}
|
||||||
|
|
||||||
|
FxForLoop::~FxForLoop()
|
||||||
|
{
|
||||||
|
SAFE_DELETE(Init);
|
||||||
|
SAFE_DELETE(Condition);
|
||||||
|
SAFE_DELETE(Iteration);
|
||||||
|
SAFE_DELETE(Code);
|
||||||
|
}
|
||||||
|
|
||||||
|
FxExpression *FxForLoop::Resolve(FCompileContext &ctx)
|
||||||
|
{
|
||||||
|
CHECKRESOLVED();
|
||||||
|
SAFE_RESOLVE_OPT(Init, ctx);
|
||||||
|
SAFE_RESOLVE_OPT(Condition, ctx);
|
||||||
|
SAFE_RESOLVE_OPT(Iteration, ctx);
|
||||||
|
SAFE_RESOLVE_OPT(Code, ctx);
|
||||||
|
|
||||||
|
ctx.HandleJumps(TK_Break, this);
|
||||||
|
ctx.HandleJumps(TK_Continue, this);
|
||||||
|
|
||||||
|
if (Condition != nullptr)
|
||||||
|
{
|
||||||
|
if (Condition->ValueType != TypeBool)
|
||||||
|
{
|
||||||
|
Condition = new FxBoolCast(Condition);
|
||||||
|
SAFE_RESOLVE(Condition, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Condition->isConstant())
|
||||||
|
{
|
||||||
|
if (static_cast<FxConstant *>(Condition)->GetValue().GetBool() == false)
|
||||||
|
{ // Nothing happens
|
||||||
|
FxExpression *nop = new FxNop(ScriptPosition);
|
||||||
|
delete this;
|
||||||
|
return nop;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // "for (..; true; ..)"
|
||||||
|
delete Condition;
|
||||||
|
Condition = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Condition == nullptr && Code == nullptr)
|
||||||
|
{ // "for (..; ; ..) { }"
|
||||||
|
// Someone could be using this for testing.
|
||||||
|
ScriptPosition.Message(MSG_WARNING, "Infinite empty loop");
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpEmit FxForLoop::Emit(VMFunctionBuilder *build)
|
||||||
|
{
|
||||||
|
assert((Condition && Condition->ValueType == TypeBool && !Condition->isConstant()) || Condition == nullptr);
|
||||||
|
|
||||||
|
size_t loopstart, loopend;
|
||||||
|
size_t codestart;
|
||||||
|
size_t jumpspot;
|
||||||
|
|
||||||
|
// Init statement.
|
||||||
|
if (Init != nullptr)
|
||||||
|
{
|
||||||
|
ExpEmit init = Init->Emit(build);
|
||||||
|
init.Free(build);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Evaluate the condition and execute/break out of the loop.
|
||||||
|
codestart = build->GetAddress();
|
||||||
|
if (Condition != nullptr)
|
||||||
|
{
|
||||||
|
ExpEmit cond = Condition->Emit(build);
|
||||||
|
build->Emit(OP_TEST, cond.RegNum, 0);
|
||||||
|
cond.Free(build);
|
||||||
|
jumpspot = build->Emit(OP_JMP, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute the loop's content.
|
||||||
|
if (Code != nullptr)
|
||||||
|
{
|
||||||
|
ExpEmit code = Code->Emit(build);
|
||||||
|
code.Free(build);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iteration statement.
|
||||||
|
loopstart = build->GetAddress();
|
||||||
|
if (Iteration != nullptr)
|
||||||
|
{
|
||||||
|
ExpEmit iter = Iteration->Emit(build);
|
||||||
|
iter.Free(build);
|
||||||
|
}
|
||||||
|
build->Backpatch(build->Emit(OP_JMP, 0), codestart);
|
||||||
|
|
||||||
|
// End of loop.
|
||||||
|
loopend = build->GetAddress();
|
||||||
|
if (Condition != nullptr)
|
||||||
|
{
|
||||||
|
build->Backpatch(jumpspot, loopend);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Give a proper address to any break/continue statement within this loop.
|
||||||
|
for (unsigned int i = 0; i < JumpAddresses.Size(); i++)
|
||||||
|
{
|
||||||
|
if (JumpAddresses[i]->Token == TK_Break)
|
||||||
|
{
|
||||||
|
build->Backpatch(JumpAddresses[i]->Address, loopend);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // Continue statement.
|
||||||
|
build->Backpatch(JumpAddresses[i]->Address, loopstart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExpEmit();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FxJumpStatement
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FxJumpStatement::FxJumpStatement(int token, const FScriptPosition &pos)
|
||||||
|
: FxExpression(pos), Token(token), AddressResolver(nullptr)
|
||||||
|
{
|
||||||
|
ValueType = TypeVoid;
|
||||||
|
}
|
||||||
|
|
||||||
|
FxExpression *FxJumpStatement::Resolve(FCompileContext &ctx)
|
||||||
|
{
|
||||||
|
CHECKRESOLVED();
|
||||||
|
|
||||||
|
ctx.Jumps.Push(this);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpEmit FxJumpStatement::Emit(VMFunctionBuilder *build)
|
||||||
|
{
|
||||||
|
if (AddressResolver == nullptr)
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Jump statement %s has nowhere to go!", FScanner::TokenName(Token));
|
||||||
|
}
|
||||||
|
|
||||||
|
Address = build->Emit(OP_JMP, 0);
|
||||||
|
|
||||||
|
return ExpEmit();
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -4008,19 +4410,19 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build)
|
||||||
FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx)
|
FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx)
|
||||||
{
|
{
|
||||||
CHECKRESOLVED();
|
CHECKRESOLVED();
|
||||||
if (ctx.cls->NumOwnedStates == 0)
|
if (ctx.Class->NumOwnedStates == 0)
|
||||||
{
|
{
|
||||||
// This can't really happen
|
// This can't really happen
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
if (ctx.cls->NumOwnedStates <= index)
|
if (ctx.Class->NumOwnedStates <= index)
|
||||||
{
|
{
|
||||||
ScriptPosition.Message(MSG_ERROR, "%s: Attempt to jump to non existing state index %d",
|
ScriptPosition.Message(MSG_ERROR, "%s: Attempt to jump to non existing state index %d",
|
||||||
ctx.cls->TypeName.GetChars(), index);
|
ctx.Class->TypeName.GetChars(), index);
|
||||||
delete this;
|
delete this;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
FxExpression *x = new FxConstant(ctx.cls->OwnedStates + index, ScriptPosition);
|
FxExpression *x = new FxConstant(ctx.Class->OwnedStates + index, ScriptPosition);
|
||||||
delete this;
|
delete this;
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
@ -4068,7 +4470,7 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx)
|
||||||
}
|
}
|
||||||
else if (names[0] == NAME_Super)
|
else if (names[0] == NAME_Super)
|
||||||
{
|
{
|
||||||
scope = dyn_cast<PClassActor>(ctx.cls->ParentClass);
|
scope = dyn_cast<PClassActor>(ctx.Class->ParentClass);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -4079,9 +4481,9 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx)
|
||||||
delete this;
|
delete this;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
else if (!scope->IsDescendantOf(ctx.cls))
|
else if (!scope->IsDescendantOf(ctx.Class))
|
||||||
{
|
{
|
||||||
ScriptPosition.Message(MSG_ERROR, "'%s' is not an ancestor of '%s'", names[0].GetChars(),ctx.cls->TypeName.GetChars());
|
ScriptPosition.Message(MSG_ERROR, "'%s' is not an ancestor of '%s'", names[0].GetChars(),ctx.Class->TypeName.GetChars());
|
||||||
delete this;
|
delete this;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1345,6 +1345,24 @@ DEFINE_PROPERTY(gravity, F, Actor)
|
||||||
defaults->Gravity = i;
|
defaults->Gravity = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
DEFINE_PROPERTY(spriteangle, F, Actor)
|
||||||
|
{
|
||||||
|
PROP_DOUBLE_PARM(i, 0);
|
||||||
|
defaults->SpriteAngle = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
DEFINE_PROPERTY(spriterotation, F, Actor)
|
||||||
|
{
|
||||||
|
PROP_DOUBLE_PARM(i, 0);
|
||||||
|
defaults->SpriteRotation = i;
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -480,6 +480,93 @@ static FxExpression *ParseIf(FScanner &sc, FState state, FString statestring, Ba
|
||||||
return add;
|
return add;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static FxExpression *ParseWhile(FScanner &sc, FState state, FString statestring, Baggage &bag,
|
||||||
|
PPrototype *&retproto, bool &lastwasret)
|
||||||
|
{
|
||||||
|
FxExpression *cond, *code;
|
||||||
|
PPrototype *proto;
|
||||||
|
bool ret;
|
||||||
|
|
||||||
|
sc.MustGetStringName("(");
|
||||||
|
cond = ParseExpression(sc, bag.Info);
|
||||||
|
sc.MustGetStringName(")");
|
||||||
|
sc.MustGetStringName("{"); // Enforce braces like for if statements.
|
||||||
|
|
||||||
|
code = ParseActions(sc, state, statestring, bag, proto, ret);
|
||||||
|
sc.MustGetString();
|
||||||
|
|
||||||
|
retproto = ReturnCheck(retproto, proto, sc);
|
||||||
|
lastwasret = false; // A while loop always jumps back.
|
||||||
|
|
||||||
|
return new FxWhileLoop(cond, code, sc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static FxExpression *ParseDoWhile(FScanner &sc, FState state, FString statestring, Baggage &bag,
|
||||||
|
PPrototype *&retproto, bool &lastwasret)
|
||||||
|
{
|
||||||
|
FxExpression *cond, *code;
|
||||||
|
PPrototype *proto;
|
||||||
|
bool ret;
|
||||||
|
|
||||||
|
sc.MustGetStringName("{"); // Enforce braces like for if statements.
|
||||||
|
code = ParseActions(sc, state, statestring, bag, proto, ret);
|
||||||
|
|
||||||
|
sc.MustGetStringName("while");
|
||||||
|
sc.MustGetStringName("(");
|
||||||
|
cond = ParseExpression(sc, bag.Info);
|
||||||
|
sc.MustGetStringName(")");
|
||||||
|
sc.MustGetStringName(";");
|
||||||
|
sc.MustGetString();
|
||||||
|
|
||||||
|
retproto = ReturnCheck(retproto, proto, sc);
|
||||||
|
lastwasret = false;
|
||||||
|
|
||||||
|
return new FxDoWhileLoop(cond, code, sc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static FxExpression *ParseFor(FScanner &sc, FState state, FString statestring, Baggage &bag,
|
||||||
|
PPrototype *&retproto, bool &lastwasret)
|
||||||
|
{
|
||||||
|
FxExpression *init = nullptr;
|
||||||
|
FxExpression *cond = nullptr;
|
||||||
|
FxExpression *iter = nullptr;
|
||||||
|
FxExpression *code = nullptr;
|
||||||
|
PPrototype *proto;
|
||||||
|
bool ret;
|
||||||
|
|
||||||
|
// Parse the statements.
|
||||||
|
sc.MustGetStringName("(");
|
||||||
|
sc.MustGetString();
|
||||||
|
if (!sc.Compare(";"))
|
||||||
|
{
|
||||||
|
init = ParseAction(sc, state, statestring, bag); // That's all DECORATE can handle for now.
|
||||||
|
sc.MustGetStringName(";");
|
||||||
|
}
|
||||||
|
sc.MustGetString();
|
||||||
|
if (!sc.Compare(";"))
|
||||||
|
{
|
||||||
|
sc.UnGet();
|
||||||
|
cond = ParseExpression(sc, bag.Info);
|
||||||
|
sc.MustGetStringName(";");
|
||||||
|
}
|
||||||
|
sc.MustGetString();
|
||||||
|
if (!sc.Compare(")"))
|
||||||
|
{
|
||||||
|
iter = ParseAction(sc, state, statestring, bag);
|
||||||
|
sc.MustGetStringName(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now parse the loop's content.
|
||||||
|
sc.MustGetStringName("{"); // Enforce braces like for if statements.
|
||||||
|
code = ParseActions(sc, state, statestring, bag, proto, ret);
|
||||||
|
sc.MustGetString();
|
||||||
|
|
||||||
|
retproto = ReturnCheck(retproto, proto, sc);
|
||||||
|
lastwasret = false;
|
||||||
|
|
||||||
|
return new FxForLoop(init, cond, iter, code, sc);
|
||||||
|
}
|
||||||
|
|
||||||
FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag,
|
FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag,
|
||||||
PPrototype *&retproto, bool &endswithret)
|
PPrototype *&retproto, bool &endswithret)
|
||||||
{
|
{
|
||||||
|
@ -505,9 +592,21 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg
|
||||||
FxExpression *add;
|
FxExpression *add;
|
||||||
lastwasret = false;
|
lastwasret = false;
|
||||||
if (sc.Compare("if"))
|
if (sc.Compare("if"))
|
||||||
{ // Hangle an if statement
|
{ // Handle an if statement
|
||||||
add = ParseIf(sc, state, statestring, bag, proto, lastwasret);
|
add = ParseIf(sc, state, statestring, bag, proto, lastwasret);
|
||||||
}
|
}
|
||||||
|
else if (sc.Compare("while"))
|
||||||
|
{ // Handle a while loop
|
||||||
|
add = ParseWhile(sc, state, statestring, bag, proto, lastwasret);
|
||||||
|
}
|
||||||
|
else if (sc.Compare("do"))
|
||||||
|
{ // Handle a do-while loop
|
||||||
|
add = ParseDoWhile(sc, state, statestring, bag, proto, lastwasret);
|
||||||
|
}
|
||||||
|
else if (sc.Compare("for"))
|
||||||
|
{ // Handle a for loop
|
||||||
|
add = ParseFor(sc, state, statestring, bag, proto, lastwasret);
|
||||||
|
}
|
||||||
else if (sc.Compare("return"))
|
else if (sc.Compare("return"))
|
||||||
{ // Handle a return statement
|
{ // Handle a return statement
|
||||||
lastwasret = true;
|
lastwasret = true;
|
||||||
|
@ -529,6 +628,18 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg
|
||||||
sc.MustGetString();
|
sc.MustGetString();
|
||||||
add = new FxReturnStatement(retexp, sc);
|
add = new FxReturnStatement(retexp, sc);
|
||||||
}
|
}
|
||||||
|
else if (sc.Compare("break"))
|
||||||
|
{
|
||||||
|
add = new FxJumpStatement(TK_Break, sc);
|
||||||
|
sc.MustGetStringName(";");
|
||||||
|
sc.MustGetString();
|
||||||
|
}
|
||||||
|
else if (sc.Compare("continue"))
|
||||||
|
{
|
||||||
|
add = new FxJumpStatement(TK_Continue, sc);
|
||||||
|
sc.MustGetStringName(";");
|
||||||
|
sc.MustGetString();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{ // Handle a regular action function call
|
{ // Handle a regular action function call
|
||||||
add = ParseAction(sc, state, statestring, bag);
|
add = ParseAction(sc, state, statestring, bag);
|
||||||
|
|
|
@ -76,7 +76,7 @@ const char *GetVersionString();
|
||||||
|
|
||||||
// Use 4500 as the base git save version, since it's higher than the
|
// Use 4500 as the base git save version, since it's higher than the
|
||||||
// SVN revision ever got.
|
// SVN revision ever got.
|
||||||
#define SAVEVER 4548
|
#define SAVEVER 4549
|
||||||
|
|
||||||
#define SAVEVERSTRINGIFY2(x) #x
|
#define SAVEVERSTRINGIFY2(x) #x
|
||||||
#define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x)
|
#define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x)
|
||||||
|
|
|
@ -436,6 +436,17 @@ bool VMFunctionBuilder::RegAvailability::Reuse(int reg)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// VMFunctionBuilder :: GetAddress
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
size_t VMFunctionBuilder::GetAddress()
|
||||||
|
{
|
||||||
|
return Code.Size();
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// VMFunctionBuilder :: Emit
|
// VMFunctionBuilder :: Emit
|
||||||
|
|
|
@ -34,6 +34,9 @@ public:
|
||||||
int GetConstantAddress(void *ptr, VM_ATAG tag);
|
int GetConstantAddress(void *ptr, VM_ATAG tag);
|
||||||
int GetConstantString(FString str);
|
int GetConstantString(FString str);
|
||||||
|
|
||||||
|
// Returns the address of the next instruction to be emitted.
|
||||||
|
size_t GetAddress();
|
||||||
|
|
||||||
// Returns the address of the newly-emitted instruction.
|
// Returns the address of the newly-emitted instruction.
|
||||||
size_t Emit(int opcode, int opa, int opb, int opc);
|
size_t Emit(int opcode, int opa, int opb, int opc);
|
||||||
size_t Emit(int opcode, int opa, VM_SHALF opbc);
|
size_t Emit(int opcode, int opa, VM_SHALF opbc);
|
||||||
|
|
|
@ -35,6 +35,8 @@ ACTOR Actor native //: Thinker
|
||||||
BloodType "Blood", "BloodSplatter", "AxeBlood"
|
BloodType "Blood", "BloodSplatter", "AxeBlood"
|
||||||
ExplosionDamage 128
|
ExplosionDamage 128
|
||||||
MissileHeight 32
|
MissileHeight 32
|
||||||
|
SpriteAngle 0
|
||||||
|
SpriteRotation 0
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
native bool CheckClass(class<Actor> checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false);
|
native bool CheckClass(class<Actor> checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false);
|
||||||
|
@ -48,6 +50,9 @@ ACTOR Actor native //: Thinker
|
||||||
native float GetCrouchFactor(int ptr = AAPTR_PLAYER1);
|
native float GetCrouchFactor(int ptr = AAPTR_PLAYER1);
|
||||||
native float GetCVar(string cvar);
|
native float GetCVar(string cvar);
|
||||||
native int GetPlayerInput(int inputnum, int ptr = AAPTR_DEFAULT);
|
native int GetPlayerInput(int inputnum, int ptr = AAPTR_DEFAULT);
|
||||||
|
native int CountProximity(class<Actor> classname, float distance, int flags = 0, int ptr = AAPTR_DEFAULT);
|
||||||
|
native float GetSpriteAngle(int ptr = AAPTR_DEFAULT);
|
||||||
|
native float GetSpriteRotation(int ptr = AAPTR_DEFAULT);
|
||||||
|
|
||||||
// Action functions
|
// Action functions
|
||||||
// Meh, MBF redundant functions. Only for DeHackEd support.
|
// Meh, MBF redundant functions. Only for DeHackEd support.
|
||||||
|
@ -331,6 +336,8 @@ ACTOR Actor native //: Thinker
|
||||||
action native bool A_FaceMovementDirection(float offset = 0, float anglelimit = 0, float pitchlimit = 0, int flags = 0, int ptr = AAPTR_DEFAULT);
|
action native bool A_FaceMovementDirection(float offset = 0, float anglelimit = 0, float pitchlimit = 0, int flags = 0, int ptr = AAPTR_DEFAULT);
|
||||||
action native int A_ClearOverlays(int sstart = 0, int sstop = 0, bool safety = true);
|
action native int A_ClearOverlays(int sstart = 0, int sstop = 0, bool safety = true);
|
||||||
action native bool A_CopySpriteFrame(int from, int to, int flags = 0);
|
action native bool A_CopySpriteFrame(int from, int to, int flags = 0);
|
||||||
|
action native bool A_SetSpriteAngle(float angle = 0, int ptr = AAPTR_DEFAULT);
|
||||||
|
action native bool A_SetSpriteRotation(float angle = 0, int ptr = AAPTR_DEFAULT);
|
||||||
|
|
||||||
native void A_RearrangePointers(int newtarget, int newmaster = AAPTR_DEFAULT, int newtracer = AAPTR_DEFAULT, int flags=0);
|
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);
|
native void A_TransferPointer(int ptr_source, int ptr_recepient, int sourcefield, int recepientfield=AAPTR_DEFAULT, int flags=0);
|
||||||
|
|
Loading…
Reference in a new issue