Merge branch 'zscript' of https://github.com/rheit/zdoom into gz-zscript

# Conflicts:
#	wadsrc/static/zscript.txt
This commit is contained in:
Christoph Oelckers 2016-12-03 18:51:10 +01:00
commit fbc8d0e83c
93 changed files with 1312 additions and 994 deletions

View file

@ -473,6 +473,11 @@ static AMColorset AMMod;
static AMColorset AMModOverlay;
void AM_ClearColorsets()
{
AMModOverlay.defined = false;
AMMod.defined = false;
}
//=============================================================================
//
//

View file

@ -27,6 +27,7 @@ class FSerializer;
void AM_StaticInit();
void AM_ClearColorsets(); // reset data for a restart.
// Called by main loop.
bool AM_Responder (event_t* ev, bool last);

View file

@ -15,6 +15,7 @@
#include "cmdlib.h"
#include "i_system.h"
#include "v_text.h"
#include "sc_man.h"
#include <sys/types.h>
#include <sys/stat.h>
@ -324,7 +325,7 @@ FString ExtractFileBase (const char *path, bool include_extension)
//
//==========================================================================
int ParseHex (const char *hex)
int ParseHex (const char *hex, FScriptPosition *sc)
{
const char *str;
int num;
@ -342,7 +343,8 @@ int ParseHex (const char *hex)
else if (*str >= 'A' && *str <= 'F')
num += 10 + *str-'A';
else {
Printf ("Bad hex number: %s\n",hex);
if (!sc) Printf ("Bad hex number: %s\n",hex);
else sc->Message(MSG_WARNING, "Bad hex number: %s", hex);
return 0;
}
str++;
@ -351,21 +353,6 @@ int ParseHex (const char *hex)
return num;
}
//==========================================================================
//
// ParseNum
//
//==========================================================================
int ParseNum (const char *str)
{
if (str[0] == '$')
return ParseHex (str+1);
if (str[0] == '0' && str[1] == 'x')
return ParseHex (str+2);
return atol (str);
}
//==========================================================================
//
// IsNum

View file

@ -33,8 +33,8 @@ void DefaultExtension (FString &path, const char *extension);
FString ExtractFilePath (const char *path);
FString ExtractFileBase (const char *path, bool keep_extension=false);
int ParseHex (const char *str);
int ParseNum (const char *str);
struct FScriptPosition;
int ParseHex(const char *str, FScriptPosition *sc = nullptr);
bool IsNum (const char *str); // [RH] added
char *copystring(const char *s);

View file

@ -3020,6 +3020,7 @@ void FinishDehPatch ()
while (subclass == nullptr);
AActor *defaults2 = GetDefaultByType (subclass);
memcpy ((void *)defaults2, (void *)defaults1, sizeof(AActor));
// Make a copy of the replaced class's state labels
FStateDefinitions statedef;

View file

@ -193,10 +193,10 @@ void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize)
{
sc.MustGetStringName("=");
sc.MustGetString();
iwad->FgColor = V_GetColor(NULL, sc.String);
iwad->FgColor = V_GetColor(NULL, sc);
sc.MustGetStringName(",");
sc.MustGetString();
iwad->BkColor = V_GetColor(NULL, sc.String);
iwad->BkColor = V_GetColor(NULL, sc);
}
else if (sc.Compare("Load"))
{

View file

@ -1027,6 +1027,12 @@ void D_DoomLoop ()
}
D_ErrorCleanup ();
}
catch (CVMAbortException &error)
{
error.MaybePrintMessage();
Printf("%s", error.stacktrace);
D_ErrorCleanup();
}
}
}
@ -1838,10 +1844,10 @@ static FString ParseGameInfo(TArray<FString> &pwads, const char *fn, const char
else if (!nextKey.CompareNoCase("STARTUPCOLORS"))
{
sc.MustGetString();
DoomStartupInfo.FgColor = V_GetColor(NULL, sc.String);
DoomStartupInfo.FgColor = V_GetColor(NULL, sc);
sc.MustGetStringName(",");
sc.MustGetString();
DoomStartupInfo.BkColor = V_GetColor(NULL, sc.String);
DoomStartupInfo.BkColor = V_GetColor(NULL, sc);
}
else if (!nextKey.CompareNoCase("STARTUPTYPE"))
{
@ -2592,44 +2598,48 @@ void D_DoomMain (void)
G_DeferedPlayDemo (v);
D_DoomLoop (); // never returns
}
v = Args->CheckValue ("-timedemo");
if (v)
else
{
G_TimeDemo (v);
D_DoomLoop (); // never returns
}
if (gameaction != ga_loadgame && gameaction != ga_loadgamehidecon)
{
if (autostart || netgame)
v = Args->CheckValue("-timedemo");
if (v)
{
// Do not do any screenwipes when autostarting a game.
if (!Args->CheckParm("-warpwipe"))
{
NoWipe = TICRATE;
}
CheckWarpTransMap (startmap, true);
if (demorecording)
G_BeginRecording (startmap);
G_InitNew (startmap, false);
if (StoredWarp.IsNotEmpty())
{
AddCommandString(StoredWarp.LockBuffer());
StoredWarp = NULL;
}
G_TimeDemo(v);
D_DoomLoop(); // never returns
}
else
{
D_StartTitle (); // start up intro loop
if (gameaction != ga_loadgame && gameaction != ga_loadgamehidecon)
{
if (autostart || netgame)
{
// Do not do any screenwipes when autostarting a game.
if (!Args->CheckParm("-warpwipe"))
{
NoWipe = TICRATE;
}
CheckWarpTransMap(startmap, true);
if (demorecording)
G_BeginRecording(startmap);
G_InitNew(startmap, false);
if (StoredWarp.IsNotEmpty())
{
AddCommandString(StoredWarp.LockBuffer());
StoredWarp = NULL;
}
}
else
{
D_StartTitle(); // start up intro loop
}
}
else if (demorecording)
{
G_BeginRecording(NULL);
}
atterm(D_QuitNetGame); // killough
}
}
else if (demorecording)
{
G_BeginRecording (NULL);
}
atterm (D_QuitNetGame); // killough
}
else
{
@ -2643,7 +2653,7 @@ void D_DoomMain (void)
}
D_DoomLoop (); // this only returns if a 'restart' CCMD is given.
maxberestart:
//
// Clean up after a restart
//
@ -2654,6 +2664,7 @@ void D_DoomMain (void)
M_ClearMenus(); // close menu if open
F_EndFinale(); // If an intermission is active, end it now
AM_ClearColorsets();
// clean up game state
ST_Clear();

View file

@ -81,7 +81,6 @@ public:
FPlayerColorSet *GetColorSet(int setnum) { return ColorSets.CheckKey(setnum); }
void SetPainFlash(FName type, PalEntry color);
bool GetPainFlash(FName type, PalEntry *color) const;
virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass);
FString DisplayName; // Display name (used in menus, etc.)
FString SoundClass; // Sound class

View file

@ -532,7 +532,7 @@ void FDecalLib::ParseDecal (FScanner &sc)
sc.MustGetString ();
if (!sc.Compare("BloodDefault"))
{
newdecal.ShadeColor = V_GetColor (NULL, sc.String);
newdecal.ShadeColor = V_GetColor (NULL, sc);
}
else
{
@ -547,8 +547,8 @@ void FDecalLib::ParseDecal (FScanner &sc)
case DECAL_COLORS:
DWORD startcolor, endcolor;
sc.MustGetString (); startcolor = V_GetColor (NULL, sc.String);
sc.MustGetString (); endcolor = V_GetColor (NULL, sc.String);
sc.MustGetString (); startcolor = V_GetColor (NULL, sc);
sc.MustGetString (); endcolor = V_GetColor (NULL, sc);
newdecal.Translation = GenerateTranslation (startcolor, endcolor)->Index;
break;
@ -819,7 +819,7 @@ void FDecalLib::ParseColorchanger (FScanner &sc)
else if (sc.Compare ("Color"))
{
sc.MustGetString ();
goal = V_GetColor (NULL, sc.String);
goal = V_GetColor (NULL, sc);
}
else
{

View file

@ -423,7 +423,7 @@ size_t DObject::PointerSubstitution (DObject *old, DObject *notOld)
//
//==========================================================================
size_t DObject::StaticPointerSubstitution (DObject *old, DObject *notOld)
size_t DObject::StaticPointerSubstitution (DObject *old, DObject *notOld, bool scandefaults)
{
DObject *probe;
size_t changed = 0;
@ -438,6 +438,20 @@ size_t DObject::StaticPointerSubstitution (DObject *old, DObject *notOld)
last = probe;
}
if (scandefaults)
{
for (auto p : PClassActor::AllActorClasses)
{
auto def = GetDefaultByType(p);
if (def != nullptr)
{
def->Class = p;
def->DObject::PointerSubstitution(old, notOld);
def->Class = nullptr; // reset pointer. Defaults should not have a valid class pointer.
}
}
}
// Go through the bodyque.
for (i = 0; i < BODYQUESIZE; ++i)
{

View file

@ -482,7 +482,7 @@ public:
// change any pointers from the old object to the new object,
// use this method.
virtual size_t PointerSubstitution (DObject *old, DObject *notOld);
static size_t StaticPointerSubstitution (DObject *old, DObject *notOld);
static size_t StaticPointerSubstitution (DObject *old, DObject *notOld, bool scandefaults = false);
PClass *GetClass() const
{

View file

@ -3008,8 +3008,6 @@ PClass *ClassReg::RegisterClass()
&PClassPlayerPawn::RegistrationInfo,
&PClassType::RegistrationInfo,
&PClassClass::RegistrationInfo,
&PClassWeaponPiece::RegistrationInfo,
&PClassPowerupGiver::RegistrationInfo,
};
// Skip classes that have already been registered
@ -3332,15 +3330,15 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size)
}
else
{
PClassActor::AllActorClasses.Pop(); // remove the newly added class from the list
// todo: replace all affected fields
for (unsigned i = 0; i < PClassActor::AllActorClasses.Size(); i++)
{
PClassActor::AllActorClasses[i]->ReplaceClassRef(existclass, type);
if (PClassActor::AllActorClasses[i] == existclass)
PClassActor::AllActorClasses[i] = static_cast<PClassActor*>(type);
}
TypeTable.ReplaceType(type, existclass, bucket);
StaticPointerSubstitution(existclass, type, true); // replace the old one, also in the actor defaults.
// Delete the old class from the class lists, both the full one and the actor list.
auto index = PClassActor::AllActorClasses.Find(static_cast<PClassActor*>(existclass));
if (index < PClassActor::AllActorClasses.Size()) PClassActor::AllActorClasses.Delete(index);
index = PClass::AllClasses.Find(existclass);
if (index < PClass::AllClasses.Size()) PClass::AllClasses.Delete(index);
// Now we can destroy the old class as nothing should reference it anymore
existclass->Destroy();
}
return type;
}

View file

@ -56,6 +56,12 @@ public:
strncpy (m_Message, message, MAX_ERRORTEXT-1);
m_Message[MAX_ERRORTEXT-1] = '\0';
}
void AppendMessage(const char *message)
{
size_t len = strlen(m_Message);
strncpy(m_Message + len, message, MAX_ERRORTEXT - 1 - len);
m_Message[MAX_ERRORTEXT - 1] = '\0';
}
const char *GetMessage (void) const
{
if (m_Message[0] != '\0')
@ -64,7 +70,7 @@ public:
return NULL;
}
private:
protected:
char m_Message[MAX_ERRORTEXT];
};

View file

@ -2014,13 +2014,13 @@ void FParser::SF_CeilingTexture(void)
void FParser::SF_ChangeHubLevel(void)
{
I_Error("FS hub system permanently disabled\n");
script_error("FS hub system permanently disabled\n");
}
// for start map: start new game on a particular skill
void FParser::SF_StartSkill(void)
{
I_Error("startskill is not supported by this implementation!\n");
script_error("startskill is not supported by this implementation!\n");
}
//==========================================================================

View file

@ -113,7 +113,7 @@ void FParser::NextToken()
}
if(!Section)
{
I_Error("section not found!\n");
script_error("section not found!\n");
return;
}
}
@ -708,6 +708,18 @@ void FParser::EvaluateExpression(svalue_t &result, int start, int stop)
//
//==========================================================================
void FS_Error(const char *error, ...)
{
va_list argptr;
char errortext[MAX_ERRORTEXT];
va_start(argptr, error);
myvsnprintf(errortext, MAX_ERRORTEXT, error, argptr);
va_end(argptr);
throw CFraggleScriptError(errortext);
}
void FParser::ErrorMessage(FString msg)
{
int linenum = 0;
@ -721,7 +733,7 @@ void FParser::ErrorMessage(FString msg)
}
//lineinfo.Format("Script %d, line %d: ", Script->scriptnum, linenum);
I_Error("Script %d, line %d: %s", Script->scriptnum, linenum, msg.GetChars());
FS_Error("Script %d, line %d: %s", Script->scriptnum, linenum, msg.GetChars());
}
//==========================================================================

View file

@ -251,7 +251,7 @@ void DFsScript::ParseScript(char *position)
FParser parse(this);
parse.Run(position, data, data + len);
}
catch (CRecoverableError &err)
catch (CFraggleScriptError &err)
{
Printf ("%s\n", err.GetMessage());
}

View file

@ -41,12 +41,22 @@
#include "p_lnspec.h"
#include "m_fixed.h"
#include "actor.h"
#include "doomerrors.h"
#ifdef _MSC_VER
// This pragma saves 8kb of wasted code.
#pragma pointers_to_members( full_generality, single_inheritance )
#endif
class CFraggleScriptError : public CDoomError
{
public:
CFraggleScriptError() : CDoomError() {}
CFraggleScriptError(const char *message) : CDoomError(message) {}
};
class DRunningScript;

View file

@ -45,19 +45,12 @@ IMPLEMENT_CLASS(APowerup, false, false)
// Powerup-Giver -------------------------------------------------------------
IMPLEMENT_CLASS(PClassPowerupGiver, false, false)
void PClassPowerupGiver::ReplaceClassRef(PClass *oldclass, PClass *newclass)
{
Super::ReplaceClassRef(oldclass, newclass);
APowerupGiver *def = (APowerupGiver*)Defaults;
if (def != NULL)
{
if (def->PowerupType == oldclass) def->PowerupType = static_cast<PClassWeapon *>(newclass);
}
}
IMPLEMENT_CLASS(APowerupGiver, false, true)
IMPLEMENT_CLASS(APowerupGiver, false, false)
IMPLEMENT_POINTERS_START(APowerupGiver)
IMPLEMENT_POINTER(PowerupType)
IMPLEMENT_POINTERS_END
DEFINE_FIELD(APowerupGiver, PowerupType)
DEFINE_FIELD(APowerupGiver, EffectTics)
@ -1855,7 +1848,14 @@ void APowerDoubleFiringSpeed::EndEffect( )
// Morph powerup ------------------------------------------------------
IMPLEMENT_CLASS(APowerMorph, false, false)
IMPLEMENT_CLASS(APowerMorph, false, true)
IMPLEMENT_POINTERS_START(APowerMorph)
IMPLEMENT_POINTER(PlayerClass)
IMPLEMENT_POINTER(MorphFlash)
IMPLEMENT_POINTER(UnMorphFlash)
IMPLEMENT_POINTERS_END
DEFINE_FIELD(APowerMorph, PlayerClass)
DEFINE_FIELD(APowerMorph, MorphFlash)
@ -1916,19 +1916,12 @@ void APowerMorph::EndEffect( )
{
Super::EndEffect();
// Abort if owner already destroyed
if (Owner == NULL)
// Abort if owner already destroyed or unmorphed
if (Owner == nullptr || MorphedPlayer == nullptr)
{
assert(MorphedPlayer == NULL);
return;
}
// Abort if owner already unmorphed
if (MorphedPlayer == NULL)
{
return;
}
// Abort if owner is dead; their Die() method will
// take care of any required unmorphing on death.
if (MorphedPlayer->health <= 0)

View file

@ -35,19 +35,11 @@ protected:
friend void InitAllPowerupEffects(AInventory *item);
};
class PClassPowerupGiver: public PClassInventory
{
DECLARE_CLASS(PClassPowerupGiver, PClassInventory)
protected:
public:
virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass);
};
// An artifact is an item that gives the player a powerup when activated.
class APowerupGiver : public AInventory
{
DECLARE_CLASS_WITH_META (APowerupGiver, AInventory, PClassPowerupGiver)
DECLARE_CLASS (APowerupGiver, AInventory)
HAS_OBJECT_POINTERS
public:
virtual bool Use (bool pickup) override;
virtual void Serialize(FSerializer &arc) override;
@ -272,6 +264,7 @@ protected:
class APowerMorph : public APowerup
{
DECLARE_CLASS( APowerMorph, APowerup )
HAS_OBJECT_POINTERS
public:
virtual void Serialize(FSerializer &arc) override;

View file

@ -45,9 +45,9 @@ void PClassInventory::DeriveData(PClass *newclass)
newc->RestrictedToPlayerClass = RestrictedToPlayerClass;
}
void PClassInventory::ReplaceClassRef(PClass *oldclass, PClass *newclass)
size_t PClassInventory::PointerSubstitution(DObject *oldclass, DObject *newclass)
{
Super::ReplaceClassRef(oldclass, newclass);
size_t changed = Super::PointerSubstitution(oldclass, newclass);
AInventory *def = (AInventory*)Defaults;
if (def != NULL)
{
@ -55,14 +55,21 @@ void PClassInventory::ReplaceClassRef(PClass *oldclass, PClass *newclass)
for (unsigned i = 0; i < ForbiddenToPlayerClass.Size(); i++)
{
if (ForbiddenToPlayerClass[i] == oldclass)
{
ForbiddenToPlayerClass[i] = static_cast<PClassPlayerPawn*>(newclass);
changed++;
}
}
for (unsigned i = 0; i < RestrictedToPlayerClass.Size(); i++)
{
if (RestrictedToPlayerClass[i] == oldclass)
{
RestrictedToPlayerClass[i] = static_cast<PClassPlayerPawn*>(newclass);
changed++;
}
}
}
return changed;
}
void PClassInventory::Finalize(FStateDefinitions &statedef)
@ -254,7 +261,7 @@ bool AInventory::SpecialDropAction (AActor *dropper)
DEFINE_ACTION_FUNCTION(AInventory, SpecialDropAction)
{
PARAM_SELF_PROLOGUE(AInventory);
PARAM_OBJECT(dropper, AActor);
PARAM_OBJECT_NOT_NULL(dropper, AActor);
ACTION_RETURN_BOOL(self->SpecialDropAction(dropper));
}
@ -422,7 +429,7 @@ bool AInventory::HandlePickup (AInventory *item)
DEFINE_ACTION_FUNCTION(AInventory, HandlePickup)
{
PARAM_SELF_PROLOGUE(AInventory);
PARAM_OBJECT(item, AInventory);
PARAM_OBJECT_NOT_NULL(item, AInventory);
ACTION_RETURN_BOOL(self->HandlePickup(item));
}
@ -1409,7 +1416,7 @@ bool AInventory::TryPickup (AActor *&toucher)
DEFINE_ACTION_FUNCTION(AInventory, TryPickup)
{
PARAM_SELF_PROLOGUE(AInventory);
PARAM_POINTER(toucher, AActor*);
PARAM_POINTER_NOT_NULL(toucher, AActor*);
ACTION_RETURN_BOOL(self->TryPickup(*toucher));
}
@ -1427,7 +1434,7 @@ bool AInventory::TryPickupRestricted (AActor *&toucher)
DEFINE_ACTION_FUNCTION(AInventory, TryPickupRestricted)
{
PARAM_SELF_PROLOGUE(AInventory);
PARAM_POINTER(toucher, AActor*);
PARAM_POINTER_NOT_NULL(toucher, AActor*);
ACTION_RETURN_BOOL(self->TryPickupRestricted(*toucher));
}
@ -1606,7 +1613,7 @@ void AInventory::AttachToOwner (AActor *other)
DEFINE_ACTION_FUNCTION(AInventory, AttachToOwner)
{
PARAM_SELF_PROLOGUE(AInventory);
PARAM_OBJECT(other, AActor);
PARAM_OBJECT_NOT_NULL(other, AActor);
self->AttachToOwner(other);
return 0;
}

View file

@ -55,7 +55,7 @@ class PClassInventory : public PClassActor
public:
PClassInventory();
virtual void DeriveData(PClass *newclass);
virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass);
virtual size_t PointerSubstitution(DObject *oldclass, DObject *newclass);
void Finalize(FStateDefinitions &statedef);
FString PickupMessage;

View file

@ -38,7 +38,6 @@
#include "doomstat.h"
#include "serializer.h"
IMPLEMENT_CLASS(PClassWeaponPiece, false, false)
IMPLEMENT_CLASS(AWeaponHolder, false, false)
DEFINE_FIELD(AWeaponHolder, PieceMask);
@ -50,22 +49,6 @@ DEFINE_FIELD(AWeaponHolder, PieceWeapon);
//
//===========================================================================
void PClassWeaponPiece::ReplaceClassRef(PClass *oldclass, PClass *newclass)
{
Super::ReplaceClassRef(oldclass, newclass);
AWeaponPiece *def = (AWeaponPiece*)Defaults;
if (def != NULL)
{
if (def->WeaponClass == oldclass) def->WeaponClass = static_cast<PClassWeapon *>(newclass);
}
}
//===========================================================================
//
//
//
//===========================================================================
void AWeaponHolder::Serialize(FSerializer &arc)
{
Super::Serialize(arc);
@ -77,6 +60,7 @@ IMPLEMENT_CLASS(AWeaponPiece, false, true)
IMPLEMENT_POINTERS_START(AWeaponPiece)
IMPLEMENT_POINTER(FullWeapon)
IMPLEMENT_POINTER(WeaponClass)
IMPLEMENT_POINTERS_END
//===========================================================================

View file

@ -2,18 +2,9 @@
#include "a_pickups.h"
#include "a_weapons.h"
//
class PClassWeaponPiece : public PClassInventory
{
DECLARE_CLASS(PClassWeaponPiece, PClassInventory)
protected:
public:
virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass);
};
class AWeaponPiece : public AInventory
{
DECLARE_CLASS_WITH_META(AWeaponPiece, AInventory, PClassWeaponPiece)
DECLARE_CLASS(AWeaponPiece, AInventory)
HAS_OBJECT_POINTERS
protected:
bool PrivateShouldStay ();

View file

@ -66,6 +66,9 @@ IMPLEMENT_POINTERS_START(AWeapon)
IMPLEMENT_POINTER(Ammo1)
IMPLEMENT_POINTER(Ammo2)
IMPLEMENT_POINTER(SisterWeapon)
IMPLEMENT_POINTER(AmmoType1)
IMPLEMENT_POINTER(AmmoType2)
IMPLEMENT_POINTER(SisterWeaponType)
IMPLEMENT_POINTERS_END
DEFINE_FIELD(AWeapon, WeaponFlags)
@ -148,24 +151,6 @@ void PClassWeapon::DeriveData(PClass *newclass)
}
//===========================================================================
//
//
//
//===========================================================================
void PClassWeapon::ReplaceClassRef(PClass *oldclass, PClass *newclass)
{
Super::ReplaceClassRef(oldclass, newclass);
AWeapon *def = (AWeapon*)Defaults;
if (def != NULL)
{
if (def->AmmoType1 == oldclass) def->AmmoType1 = static_cast<PClassAmmo *>(newclass);
if (def->AmmoType2 == oldclass) def->AmmoType2 = static_cast<PClassAmmo *>(newclass);
if (def->SisterWeaponType == oldclass) def->SisterWeaponType = static_cast<PClassWeapon *>(newclass);
}
}
//===========================================================================
//
//

View file

@ -95,7 +95,6 @@ protected:
virtual void DeriveData(PClass *newclass);
public:
PClassWeapon();
virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass);
void Finalize(FStateDefinitions &statedef);
int SlotNumber;

View file

@ -860,14 +860,14 @@ DEFINE_MAP_OPTION(fade, true)
{
parse.ParseAssign();
parse.sc.MustGetString();
info->fadeto = V_GetColor(NULL, parse.sc.String);
info->fadeto = V_GetColor(NULL, parse.sc);
}
DEFINE_MAP_OPTION(outsidefog, true)
{
parse.ParseAssign();
parse.sc.MustGetString();
info->outsidefog = V_GetColor(NULL, parse.sc.String);
info->outsidefog = V_GetColor(NULL, parse.sc);
}
DEFINE_MAP_OPTION(titlepatch, true)

View file

@ -13,7 +13,6 @@
#include "r_data/r_translate.h"
static FRandom pr_freezedeath ("FreezeDeath");
static FRandom pr_icesettics ("IceSetTics");
static FRandom pr_freeze ("FreezeDeathChunks");
@ -121,36 +120,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeath)
return 0;
}
//============================================================================
//
// A_IceSetTics
//
//============================================================================
void IceSetTics(AActor *self)
{
int floor;
self->tics = 70 + (pr_icesettics() & 63);
floor = P_GetThingFloorType(self);
if (Terrains[floor].DamageMOD == NAME_Fire)
{
self->tics >>= 2;
}
else if (Terrains[floor].DamageMOD == NAME_Ice)
{
self->tics <<= 1;
}
}
DEFINE_ACTION_FUNCTION(AActor, A_IceSetTics)
{
PARAM_SELF_PROLOGUE(AActor);
IceSetTics(self);
return 0;
}
//============================================================================
//
// A_FreezeDeathChunks
@ -193,7 +162,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeathChunks)
mo->Vel.X = pr_freeze.Random2() / 128.;
mo->Vel.Y = pr_freeze.Random2() / 128.;
mo->Vel.Z = (mo->Z() - self->Z()) / self->Height * 4;
IceSetTics(mo); // set a random tic wait
mo->RenderStyle = self->RenderStyle;
mo->Alpha = self->Alpha;
}

View file

@ -114,7 +114,7 @@ static void BridgeOrbit(AActor *self)
self->ceilingz = self->target->ceilingz;
}
DEFINE_ACTION_FUNCTION(AActor, A_BridgeOrbit)
DEFINE_ACTION_FUNCTION(ABridgeBall, A_BridgeOrbit)
{
PARAM_SELF_PROLOGUE(AActor);
BridgeOrbit(self);
@ -122,7 +122,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BridgeOrbit)
}
DEFINE_ACTION_FUNCTION(AActor, A_BridgeInit)
DEFINE_ACTION_FUNCTION(ACustomBridge, A_BridgeInit)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_CLASS_DEF(balltype, AActor);

View file

@ -363,7 +363,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag,
DEFINE_ACTION_FUNCTION(_PlayerInfo, UndoPlayerMorph)
{
PARAM_SELF_STRUCT_PROLOGUE(player_t);
PARAM_POINTER(player, player_t);
PARAM_POINTER_NOT_NULL(player, player_t);
PARAM_INT_DEF(unmorphflag);
PARAM_BOOL_DEF(force);
ACTION_RETURN_BOOL(P_UndoPlayerMorph(self, player, unmorphflag, force));
@ -613,7 +613,14 @@ void InitAllPowerupEffects(AInventory *item)
// Base class for morphing projectiles --------------------------------------
IMPLEMENT_CLASS(AMorphProjectile, false, false)
IMPLEMENT_CLASS(AMorphProjectile, false, true)
IMPLEMENT_POINTERS_START(AMorphProjectile)
IMPLEMENT_POINTER(PlayerClass)
IMPLEMENT_POINTER(MonsterClass)
IMPLEMENT_POINTER(MorphFlash)
IMPLEMENT_POINTER(UnMorphFlash)
IMPLEMENT_POINTERS_END
DEFINE_FIELD(AMorphProjectile, PlayerClass)
DEFINE_FIELD(AMorphProjectile, MonsterClass)

View file

@ -187,6 +187,7 @@ private:
class AMorphProjectile : public AActor
{
DECLARE_CLASS (AMorphProjectile, AActor)
HAS_OBJECT_POINTERS;
public:
int DoSpecialDamage (AActor *target, int damage, FName damagetype);

View file

@ -265,6 +265,7 @@ DEFINE_ACTION_FUNCTION(DSpotState, GetSpotState)
FSpotList *DSpotState::FindSpotList(PClassActor *type)
{
if (type == nullptr) return nullptr;
for(unsigned i = 0; i < SpotLists.Size(); i++)
{
if (SpotLists[i].Type == type) return &SpotLists[i];
@ -401,10 +402,10 @@ void ASpecialSpot::Destroy()
// will build a list of all mace spots in the level and spawn a
// mace. The rest of the spots will do nothing.
DEFINE_ACTION_FUNCTION(AActor, A_SpawnSingleItem)
DEFINE_ACTION_FUNCTION(ASpecialSpot, A_SpawnSingleItem)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_CLASS (cls, AActor);
PARAM_SELF_PROLOGUE(ASpecialSpot);
PARAM_CLASS_NOT_NULL(cls, AActor);
PARAM_INT_DEF (fail_sp)
PARAM_INT_DEF (fail_co)
PARAM_INT_DEF (fail_dm)

View file

@ -89,16 +89,35 @@ bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info,
stateret = NULL;
}
}
if (stateret == NULL)
try
{
GlobalVMStack.Call(ActionFunc, params, ActionFunc->ImplicitArgs, NULL, 0, NULL);
if (stateret == NULL)
{
GlobalVMStack.Call(ActionFunc, params, ActionFunc->ImplicitArgs, NULL, 0, NULL);
}
else
{
VMReturn ret;
ret.PointerAt((void **)stateret);
GlobalVMStack.Call(ActionFunc, params, ActionFunc->ImplicitArgs, &ret, 1, NULL);
}
}
else
catch (CVMAbortException &err)
{
VMReturn ret;
ret.PointerAt((void **)stateret);
GlobalVMStack.Call(ActionFunc, params, ActionFunc->ImplicitArgs, &ret, 1, NULL);
err.MaybePrintMessage();
auto owner = FState::StaticFindStateOwner(this);
int offs = int(this - owner->OwnedStates);
const char *callinfo = "";
if (info != nullptr && info->mStateType == STATE_Psprite)
{
if (stateowner->IsKindOf(RUNTIME_CLASS(AWeapon)) && stateowner != self) callinfo = "weapon ";
else callinfo = "overlay ";
}
err.stacktrace.AppendFormat("Called from %sstate %s.%d in %s\n", callinfo, owner->TypeName.GetChars(), offs, stateowner->GetClass()->TypeName.GetChars());
throw;
throw;
}
ActionCycles.Unclock();
return true;
}
@ -619,19 +638,18 @@ void PClassActor::SetPainChance(FName type, int chance)
//
//==========================================================================
void PClassActor::ReplaceClassRef(PClass *oldclass, PClass *newclass)
size_t PClassActor::PointerSubstitution(DObject *oldclass, DObject *newclass)
{
auto changed = Super::PointerSubstitution(oldclass, newclass);
for (unsigned i = 0; i < VisibleToPlayerClass.Size(); i++)
{
if (VisibleToPlayerClass[i] == oldclass)
{
VisibleToPlayerClass[i] = static_cast<PClassPlayerPawn*>(newclass);
changed++;
}
}
AActor *def = (AActor*)Defaults;
if (def != NULL)
{
if (def->TeleFogSourceType == oldclass) def->TeleFogSourceType = static_cast<PClassActor *>(newclass);
if (def->TeleFogDestType == oldclass) def->TeleFogDestType = static_cast<PClassActor *>(newclass);
}
return changed;
}
//==========================================================================

View file

@ -248,7 +248,7 @@ public:
PClassActor();
~PClassActor();
virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass);
virtual size_t PointerSubstitution(DObject *oldclass, DObject *newclass);
void BuildDefaults();
void ApplyDefaults(BYTE *defaults);
void RegisterIDs();

View file

@ -400,10 +400,10 @@ static void ParseListMenuBody(FScanner &sc, FListMenuDescriptor *desc)
int y = sc.Number;
sc.MustGetStringName(",");
sc.MustGetString();
PalEntry c1 = V_GetColor(NULL, sc.String);
PalEntry c1 = V_GetColor(NULL, sc);
sc.MustGetStringName(",");
sc.MustGetString();
PalEntry c2 = V_GetColor(NULL, sc.String);
PalEntry c2 = V_GetColor(NULL, sc);
if (sc.CheckString(","))
{
sc.MustGetNumber();

View file

@ -715,6 +715,7 @@ xx(String)
xx(Vector)
xx(Map)
xx(Array)
xx(Include)
xx(Sound)
xx(State)
xx(Fixed)

View file

@ -183,7 +183,19 @@ bool ACustomInventory::CallStateChain (AActor *actor, FState *state)
numret = 2;
}
}
GlobalVMStack.Call(state->ActionFunc, params, state->ActionFunc->ImplicitArgs, wantret, numret);
try
{
GlobalVMStack.Call(state->ActionFunc, params, state->ActionFunc->ImplicitArgs, wantret, numret);
}
catch (CVMAbortException &err)
{
err.MaybePrintMessage();
auto owner = FState::StaticFindStateOwner(state);
int offs = int(state - owner->OwnedStates);
err.stacktrace.AppendFormat("Called from state %s.%d in inventory state chain in %s\n", owner->TypeName.GetChars(), offs, GetClass()->TypeName.GetChars());
throw;
}
// As long as even one state succeeds, the whole chain succeeds unless aborted below.
// A state that wants to jump does not count as "succeeded".
if (nextstate == NULL)
@ -247,7 +259,7 @@ DEFINE_ACTION_FUNCTION(AActor, CheckClass)
PARAM_BOOL_DEF (match_superclass);
self = COPY_AAPTR(self, pick_pointer);
if (self == NULL)
if (self == nullptr || checktype == nullptr)
{
ret->SetInt(false);
}
@ -1773,9 +1785,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_CustomComboAttack)
// State jump function
//
//==========================================================================
DEFINE_ACTION_FUNCTION(AActor, A_JumpIfNoAmmo)
DEFINE_ACTION_FUNCTION(AStateProvider, A_JumpIfNoAmmo)
{
PARAM_ACTION_PROLOGUE(AActor);
PARAM_ACTION_PROLOGUE(AStateProvider);
PARAM_STATE_ACTION(jump);
if (!ACTION_CALL_FROM_PSPRITE() || self->player->ReadyWeapon == nullptr)
@ -1844,9 +1856,9 @@ static void AimBulletMissile(AActor *proj, AActor *puff, int flags, bool temp, b
}
}
DEFINE_ACTION_FUNCTION(AActor, A_FireBullets)
DEFINE_ACTION_FUNCTION(AStateProvider, A_FireBullets)
{
PARAM_ACTION_PROLOGUE(AActor);
PARAM_ACTION_PROLOGUE(AStateProvider);
PARAM_ANGLE (spread_xy);
PARAM_ANGLE (spread_z);
PARAM_INT (numbullets);
@ -1974,9 +1986,9 @@ enum FP_Flags
FPF_TRANSFERTRANSLATION = 2,
FPF_NOAUTOAIM = 4,
};
DEFINE_ACTION_FUNCTION(AActor, A_FireCustomMissile)
DEFINE_ACTION_FUNCTION(AStateProvider, A_FireCustomMissile)
{
PARAM_ACTION_PROLOGUE(AActor);
PARAM_ACTION_PROLOGUE(AStateProvider);
PARAM_CLASS (ti, AActor);
PARAM_ANGLE_DEF (angle);
PARAM_BOOL_DEF (useammo);
@ -2051,9 +2063,9 @@ enum
CPF_STEALARMOR = 32,
};
DEFINE_ACTION_FUNCTION(AActor, A_CustomPunch)
DEFINE_ACTION_FUNCTION(AStateProvider, A_CustomPunch)
{
PARAM_ACTION_PROLOGUE(AActor);
PARAM_ACTION_PROLOGUE(AStateProvider);
PARAM_INT (damage);
PARAM_BOOL_DEF (norandom);
PARAM_INT_DEF (flags);
@ -2155,9 +2167,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_CustomPunch)
// customizable railgun attack function
//
//==========================================================================
DEFINE_ACTION_FUNCTION(AActor, A_RailAttack)
DEFINE_ACTION_FUNCTION(AStateProvider, A_RailAttack)
{
PARAM_ACTION_PROLOGUE(AActor);
PARAM_ACTION_PROLOGUE(AStateProvider);
PARAM_INT (damage);
PARAM_INT_DEF (spawnofs_xy);
PARAM_BOOL_DEF (useammo);
@ -4443,9 +4455,9 @@ DEFINE_ACTION_FUNCTION(AActor, CheckIfInTargetLOS)
//
//===========================================================================
DEFINE_ACTION_FUNCTION(AActor, A_CheckForReload)
DEFINE_ACTION_FUNCTION(AStateProvider, A_CheckForReload)
{
PARAM_ACTION_PROLOGUE(AActor);
PARAM_ACTION_PROLOGUE(AStateProvider);
if ( self->player == NULL || self->player->ReadyWeapon == NULL )
{
@ -4496,9 +4508,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckForReload)
//
//===========================================================================
DEFINE_ACTION_FUNCTION(AActor, A_ResetReloadCounter)
DEFINE_ACTION_FUNCTION(AStateProvider, A_ResetReloadCounter)
{
PARAM_ACTION_PROLOGUE(AActor);
PARAM_ACTION_PROLOGUE(AStateProvider);
if (self->player == NULL || self->player->ReadyWeapon == NULL)
return 0;

View file

@ -461,7 +461,7 @@ bool P_CreateCeiling(sector_t *sec, DCeiling::ECeiling type, line_t *line, int t
DEFINE_ACTION_FUNCTION(DCeiling, CreateCeiling)
{
PARAM_PROLOGUE;
PARAM_POINTER(sec, sector_t);
PARAM_POINTER_NOT_NULL(sec, sector_t);
PARAM_INT(type);
PARAM_POINTER(ln, line_t);
PARAM_FLOAT(speed);

View file

@ -1307,6 +1307,11 @@ bool P_IsVisible(AActor *lookee, AActor *other, INTBOOL allaround, FLookExParams
double mindist;
DAngle fov;
if (other == nullptr)
{
return false;
}
if (params != NULL)
{
maxdist = params->maxDist;
@ -3323,15 +3328,6 @@ AInventory *P_DropItem (AActor *source, PClassActor *type, int dropamount, int c
return NULL;
}
DEFINE_ACTION_FUNCTION(AActor, DoDropItem)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_CLASS(cls, AActor);
PARAM_INT(amt);
PARAM_INT(chance);
ACTION_RETURN_OBJECT(P_DropItem(self, cls, amt, chance));
}
//============================================================================
//
// P_TossItem

View file

@ -495,7 +495,7 @@ bool P_CreateFloor(sector_t *sec, DFloor::EFloor floortype, line_t *line,
DEFINE_ACTION_FUNCTION(DFloor, CreateFloor)
{
PARAM_PROLOGUE;
PARAM_POINTER(sec, sector_t);
PARAM_POINTER_NOT_NULL(sec, sector_t);
PARAM_INT(floortype);
PARAM_POINTER(ln, line_t);
PARAM_FLOAT(speed);

View file

@ -1639,7 +1639,7 @@ void P_PoisonMobj (AActor *target, AActor *inflictor, AActor *source, int damage
DEFINE_ACTION_FUNCTION(AActor, PoisonMobj)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(inflictor, AActor);
PARAM_OBJECT_NOT_NULL(inflictor, AActor);
PARAM_OBJECT(source, AActor);
PARAM_INT(damage);
PARAM_INT(duration);

View file

@ -4513,6 +4513,7 @@ DEFINE_ACTION_FUNCTION(AActor, LineAttack)
PARAM_POINTER_DEF(victim, FTranslatedLineTarget);
int acdmg;
if (puffType == nullptr) puffType = PClass::FindActor("BulletPuff"); // P_LineAttack does not work without a puff to take info from.
auto puff = P_LineAttack(self, angle, distance, pitch, damage, damageType, puffType, flags, victim, &acdmg);
if (numret > 0) ret[0].SetPointer(puff, ATAG_OBJECT);
if (numret > 1) ret[1].SetInt(acdmg), numret = 2;
@ -4716,7 +4717,7 @@ DEFINE_ACTION_FUNCTION(_FTranslatedLineTarget, TraceBleed)
{
PARAM_SELF_STRUCT_PROLOGUE(FTranslatedLineTarget);
PARAM_INT(damage);
PARAM_OBJECT(missile, AActor);
PARAM_OBJECT_NOT_NULL(missile, AActor);
P_TraceBleed(damage, self, missile);
return 0;

View file

@ -1193,7 +1193,7 @@ IMPLEMENT_CLASS(DBlockThingsIterator, false, false);
DEFINE_ACTION_FUNCTION(DBlockThingsIterator, Create)
{
PARAM_PROLOGUE;
PARAM_OBJECT(origin, AActor);
PARAM_OBJECT_NOT_NULL(origin, AActor);
PARAM_FLOAT_DEF(radius);
PARAM_BOOL_DEF(ignore);
ACTION_RETURN_OBJECT(new DBlockThingsIterator(origin, radius, ignore));

View file

@ -145,6 +145,8 @@ IMPLEMENT_POINTERS_START(AActor)
IMPLEMENT_POINTER(Poisoner)
IMPLEMENT_POINTER(DamageFunc)
IMPLEMENT_POINTER(alternative)
IMPLEMENT_POINTER(TeleFogSourceType)
IMPLEMENT_POINTER(TeleFogDestType)
IMPLEMENT_POINTERS_END
AActor::~AActor ()
@ -749,7 +751,7 @@ void AActor::AddInventory (AInventory *item)
DEFINE_ACTION_FUNCTION(AActor, AddInventory)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(item, AInventory);
PARAM_OBJECT_NOT_NULL(item, AInventory);
self->AddInventory(item);
return 0;
}
@ -817,7 +819,7 @@ bool AActor::GiveInventory(PClassInventory *type, int amount, bool givecheat)
DEFINE_ACTION_FUNCTION(AActor, Inventory)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(item, AInventory);
PARAM_OBJECT_NOT_NULL(item, AInventory);
ACTION_RETURN_BOOL(self->UseInventory(item));
}
@ -852,7 +854,7 @@ void AActor::RemoveInventory(AInventory *item)
DEFINE_ACTION_FUNCTION(AActor, RemoveInventory)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(item, AInventory);
PARAM_OBJECT_NOT_NULL(item, AInventory);
self->RemoveInventory(item);
return 0;
}
@ -1007,7 +1009,7 @@ bool AActor::UseInventory (AInventory *item)
DEFINE_ACTION_FUNCTION(AActor, UseInventory)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(item, AInventory);
PARAM_OBJECT_NOT_NULL(item, AInventory);
ACTION_RETURN_BOOL(self->UseInventory(item));
}
@ -1040,7 +1042,7 @@ AInventory *AActor::DropInventory (AInventory *item)
DEFINE_ACTION_FUNCTION(AActor, DropInventory)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(item, AInventory);
PARAM_OBJECT_NOT_NULL(item, AInventory);
ACTION_RETURN_OBJECT(self->DropInventory(item));
}
@ -1261,7 +1263,7 @@ void AActor::CopyFriendliness (AActor *other, bool changeTarget, bool resetHealt
DEFINE_ACTION_FUNCTION(AActor, CopyFriendliness)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(other, AActor);
PARAM_OBJECT_NOT_NULL(other, AActor);
PARAM_BOOL_DEF(changetarget);
PARAM_BOOL_DEF(resethealth);
self->CopyFriendliness(other, changetarget, resethealth);
@ -1484,7 +1486,7 @@ void AActor::Touch (AActor *toucher)
DEFINE_ACTION_FUNCTION(AActor, Touch)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(toucher, AActor);
PARAM_OBJECT_NOT_NULL(toucher, AActor);
self->Touch(toucher);
return 0;
}
@ -1998,7 +2000,7 @@ bool AActor::CanSeek(AActor *target) const
DEFINE_ACTION_FUNCTION(AActor, CanSeek)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(target, AActor);
PARAM_OBJECT_NOT_NULL(target, AActor);
ACTION_RETURN_BOOL(self->CanSeek(target));
}
@ -4667,7 +4669,7 @@ AActor *AActor::StaticSpawn (PClassActor *type, const DVector3 &pos, replace_t a
DEFINE_ACTION_FUNCTION(AActor, Spawn)
{
PARAM_PROLOGUE;
PARAM_CLASS(type, AActor);
PARAM_CLASS_NOT_NULL(type, AActor);
PARAM_FLOAT_DEF(x);
PARAM_FLOAT_DEF(y);
PARAM_FLOAT_DEF(z);
@ -5654,6 +5656,8 @@ AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, const DVector3 &pos1
AActor *puff;
DVector3 pos = pos1;
if (pufftype == nullptr) return nullptr;
if (!(flags & PF_NORANDOMZ)) pos.Z += pr_spawnpuff.Random2() / 64.;
puff = Spawn(pufftype, pos, ALLOW_REPLACE);
if (puff == NULL) return NULL;
@ -6161,7 +6165,7 @@ foundone:
DEFINE_ACTION_FUNCTION(AActor, HitWater)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_POINTER(sec, sector_t);
PARAM_POINTER_NOT_NULL(sec, sector_t);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
PARAM_FLOAT(z);
@ -6381,7 +6385,7 @@ void P_PlaySpawnSound(AActor *missile, AActor *spawner)
DEFINE_ACTION_FUNCTION(AActor, PlaySpawnSound)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(missile, AActor);
PARAM_OBJECT_NOT_NULL(missile, AActor);
P_PlaySpawnSound(missile, self);
return 0;
}
@ -6413,47 +6417,11 @@ DEFINE_ACTION_FUNCTION(AActor, GetDefaultSpeed)
//
//---------------------------------------------------------------------------
AActor *P_SpawnMissile (AActor *source, AActor *dest, PClassActor *type, AActor *owner)
{
if (source == NULL)
{
return NULL;
}
return P_SpawnMissileXYZ (source->PosPlusZ(32 + source->GetBobOffset()), source, dest, type, true, owner);
}
DEFINE_ACTION_FUNCTION(AActor, SpawnMissile)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(dest, AActor);
PARAM_CLASS(type, AActor);
PARAM_OBJECT_DEF(owner, AActor);
ACTION_RETURN_OBJECT(P_SpawnMissile(self, dest, type, owner));
}
AActor *P_SpawnMissileZ (AActor *source, double z, AActor *dest, PClassActor *type)
{
if (source == NULL)
{
return NULL;
}
return P_SpawnMissileXYZ (source->PosAtZ(z), source, dest, type);
}
DEFINE_ACTION_FUNCTION(AActor, SpawnMissileZ)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_FLOAT(z);
PARAM_OBJECT(dest, AActor);
PARAM_CLASS(type, AActor);
ACTION_RETURN_OBJECT(P_SpawnMissileZ(self, z, dest, type));
}
AActor *P_SpawnMissileXYZ (DVector3 pos, AActor *source, AActor *dest, PClassActor *type, bool checkspawn, AActor *owner)
{
if (source == NULL)
if (source == nullptr || type == nullptr)
{
return NULL;
return nullptr;
}
if (dest == NULL)
@ -6528,19 +6496,56 @@ DEFINE_ACTION_FUNCTION(AActor, SpawnMissileXYZ)
PARAM_FLOAT(x);
PARAM_FLOAT(y);
PARAM_FLOAT(z);
PARAM_OBJECT(dest, AActor);
PARAM_OBJECT_NOT_NULL(dest, AActor);
PARAM_CLASS(type, AActor);
PARAM_BOOL_DEF(check);
PARAM_OBJECT_DEF(owner, AActor);
ACTION_RETURN_OBJECT(P_SpawnMissileXYZ(DVector3(x,y,z), self, dest, type, check, owner));
}
AActor *P_SpawnMissile(AActor *source, AActor *dest, PClassActor *type, AActor *owner)
{
if (source == nullptr)
{
return nullptr;
}
return P_SpawnMissileXYZ(source->PosPlusZ(32 + source->GetBobOffset()), source, dest, type, true, owner);
}
DEFINE_ACTION_FUNCTION(AActor, SpawnMissile)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT_NOT_NULL(dest, AActor);
PARAM_CLASS(type, AActor);
PARAM_OBJECT_DEF(owner, AActor);
ACTION_RETURN_OBJECT(P_SpawnMissile(self, dest, type, owner));
}
AActor *P_SpawnMissileZ(AActor *source, double z, AActor *dest, PClassActor *type)
{
if (source == nullptr)
{
return nullptr;
}
return P_SpawnMissileXYZ(source->PosAtZ(z), source, dest, type);
}
DEFINE_ACTION_FUNCTION(AActor, SpawnMissileZ)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_FLOAT(z);
PARAM_OBJECT_NOT_NULL(dest, AActor);
PARAM_CLASS(type, AActor);
ACTION_RETURN_OBJECT(P_SpawnMissileZ(self, z, dest, type));
}
AActor *P_OldSpawnMissile(AActor *source, AActor *owner, AActor *dest, PClassActor *type)
{
if (source == NULL)
if (source == nullptr || type == nullptr)
{
return NULL;
return nullptr;
}
AActor *th = Spawn (type, source->PosPlusZ(32.), ALLOW_REPLACE);
@ -6566,7 +6571,7 @@ AActor *P_OldSpawnMissile(AActor *source, AActor *owner, AActor *dest, PClassAct
DEFINE_ACTION_FUNCTION(AActor, OldSpawnMissile)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(dest, AActor);
PARAM_OBJECT_NOT_NULL(dest, AActor);
PARAM_CLASS(type, AActor);
PARAM_OBJECT_DEF(owner, AActor);
ACTION_RETURN_OBJECT(P_OldSpawnMissile(self, owner, dest, type));
@ -6584,7 +6589,7 @@ DEFINE_ACTION_FUNCTION(AActor, OldSpawnMissile)
AActor *P_SpawnMissileAngle (AActor *source, PClassActor *type, DAngle angle, double vz)
{
if (source == NULL)
if (source == nullptr || type == nullptr)
{
return NULL;
}
@ -6593,14 +6598,18 @@ AActor *P_SpawnMissileAngle (AActor *source, PClassActor *type, DAngle angle, do
AActor *P_SpawnMissileAngleZ (AActor *source, double z, PClassActor *type, DAngle angle, double vz)
{
if (type == nullptr)
{
return nullptr;
}
return P_SpawnMissileAngleZSpeed (source, z, type, angle, vz, GetDefaultSpeed (type));
}
AActor *P_SpawnMissileZAimed (AActor *source, double z, AActor *dest, PClassActor *type)
{
if (source == NULL)
if (source == nullptr || type == nullptr)
{
return NULL;
return nullptr;
}
DAngle an;
double dist;
@ -6624,7 +6633,7 @@ DEFINE_ACTION_FUNCTION(AActor, SpawnMissileZAimed)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_FLOAT(z);
PARAM_OBJECT(dest, AActor);
PARAM_OBJECT_NOT_NULL(dest, AActor);
PARAM_CLASS(type, AActor);
ACTION_RETURN_OBJECT(P_SpawnMissileZAimed(self, z, dest, type));
}
@ -6641,9 +6650,9 @@ DEFINE_ACTION_FUNCTION(AActor, SpawnMissileZAimed)
AActor *P_SpawnMissileAngleZSpeed (AActor *source, double z,
PClassActor *type, DAngle angle, double vz, double speed, AActor *owner, bool checkspawn)
{
if (source == NULL)
if (source == nullptr || type == nullptr)
{
return NULL;
return nullptr;
}
AActor *mo;
@ -6687,9 +6696,9 @@ AActor *P_SpawnSubMissile(AActor *source, PClassActor *type, AActor *target)
{
AActor *other = Spawn(type, source->Pos(), ALLOW_REPLACE);
if (other == NULL)
if (source == nullptr || type == nullptr)
{
return NULL;
return nullptr;
}
other->target = target;
@ -6721,7 +6730,7 @@ DEFINE_ACTION_FUNCTION(AActor, SpawnSubMissile)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_CLASS(cls, AActor);
PARAM_OBJECT(target, AActor);
PARAM_OBJECT_NOT_NULL(target, AActor);
ACTION_RETURN_OBJECT(P_SpawnSubMissile(self, cls, target));
}
/*
@ -6751,6 +6760,11 @@ AActor *P_SpawnPlayerMissile (AActor *source, double x, double y, double z,
PClassActor *type, DAngle angle, FTranslatedLineTarget *pLineTarget, AActor **pMissileActor,
bool nofreeaim, bool noautoaim, int aimflags)
{
if (source == nullptr || type == nullptr)
{
return nullptr;
}
static const double angdiff[3] = { -5.625, 5.625, 0 };
DAngle an = angle;
DAngle pitch;
@ -6758,10 +6772,6 @@ AActor *P_SpawnPlayerMissile (AActor *source, double x, double y, double z,
AActor *defaultobject = GetDefaultByType(type);
DAngle vrange = nofreeaim ? 35. : 0.;
if (source == NULL)
{
return NULL;
}
if (!pLineTarget) pLineTarget = &scratch;
if (source->player && source->player->ReadyWeapon && ((source->player->ReadyWeapon->WeaponFlags & WIF_NOAUTOAIM) || noautoaim))
{
@ -6908,7 +6918,7 @@ bool AActor::IsTeammate (AActor *other)
DEFINE_ACTION_FUNCTION(AActor, isTeammate)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(other, AActor);
PARAM_OBJECT_NOT_NULL(other, AActor);
ACTION_RETURN_BOOL(self->IsTeammate(other));
}
@ -6980,7 +6990,7 @@ bool AActor::IsFriend (AActor *other)
DEFINE_ACTION_FUNCTION(AActor, isFriend)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(other, AActor);
PARAM_OBJECT_NOT_NULL(other, AActor);
ACTION_RETURN_BOOL(self->IsFriend(other));
}
@ -7017,7 +7027,7 @@ bool AActor::IsHostile (AActor *other)
DEFINE_ACTION_FUNCTION(AActor, isHostile)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(other, AActor);
PARAM_OBJECT_NOT_NULL(other, AActor);
ACTION_RETURN_BOOL(self->IsHostile(other));
}
@ -7056,7 +7066,7 @@ int AActor::DoSpecialDamage (AActor *target, int damage, FName damagetype)
DEFINE_ACTION_FUNCTION(AActor, DoSpecialDamage)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(target, AActor);
PARAM_OBJECT_NOT_NULL(target, AActor);
PARAM_INT(damage);
PARAM_NAME(damagetype);
ACTION_RETURN_INT(self->DoSpecialDamage(target, damage, damagetype));
@ -7578,14 +7588,14 @@ DEFINE_ACTION_FUNCTION(AActor, absangle) // should this be global?
DEFINE_ACTION_FUNCTION(AActor, Distance2D)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(other, AActor);
PARAM_OBJECT_NOT_NULL(other, AActor);
ACTION_RETURN_FLOAT(self->Distance2D(other));
}
DEFINE_ACTION_FUNCTION(AActor, Distance3D)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(other, AActor);
PARAM_OBJECT_NOT_NULL(other, AActor);
ACTION_RETURN_FLOAT(self->Distance3D(other));
}
@ -7618,7 +7628,7 @@ DEFINE_ACTION_FUNCTION(AActor, GetDefaultByType)
{
PARAM_PROLOGUE;
PARAM_CLASS(cls, AActor);
ACTION_RETURN_OBJECT(GetDefaultByType(cls));
ACTION_RETURN_OBJECT(cls == nullptr? nullptr : GetDefaultByType(cls));
}
DEFINE_ACTION_FUNCTION(AActor, GetBobOffset)
@ -7690,7 +7700,7 @@ DEFINE_ACTION_FUNCTION(AActor, Thrust)
DEFINE_ACTION_FUNCTION(AActor, AngleTo)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(targ, AActor);
PARAM_OBJECT_NOT_NULL(targ, AActor);
PARAM_BOOL_DEF(absolute);
ACTION_RETURN_FLOAT(self->AngleTo(targ, absolute).Degrees);
}
@ -7715,7 +7725,7 @@ DEFINE_ACTION_FUNCTION(AActor, RotateVector)
DEFINE_ACTION_FUNCTION(AActor, DistanceBySpeed)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(targ, AActor);
PARAM_OBJECT_NOT_NULL(targ, AActor);
PARAM_FLOAT(speed);
ACTION_RETURN_FLOAT(self->DistanceBySpeed(targ, speed));
}
@ -7743,14 +7753,14 @@ DEFINE_ACTION_FUNCTION(AActor, Vec2Angle)
DEFINE_ACTION_FUNCTION(AActor, Vec3To)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(t, AActor)
PARAM_OBJECT_NOT_NULL(t, AActor)
ACTION_RETURN_VEC3(self->Vec3To(t));
}
DEFINE_ACTION_FUNCTION(AActor, Vec2To)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(t, AActor)
PARAM_OBJECT_NOT_NULL(t, AActor)
ACTION_RETURN_VEC2(self->Vec2To(t));
}
@ -7911,5 +7921,6 @@ void PrintMiscActorInfo(AActor *query)
query->floorz, query->ceilingz);
Printf("\nSpeed= %f, velocity= x:%f, y:%f, z:%f, combined:%f.\n",
query->Speed, query->Vel.X, query->Vel.Y, query->Vel.Z, query->Vel.Length());
Printf("Scale: x:%f, y:%f\n", query->Scale.X, query->Scale.Y);
}
}

View file

@ -828,7 +828,7 @@ void DoReadyWeapon(AActor *self)
DEFINE_ACTION_FUNCTION(AStateProvider, A_WeaponReady)
{
PARAM_ACTION_PROLOGUE(AActor);
PARAM_ACTION_PROLOGUE(AStateProvider);
PARAM_INT_DEF(flags);
DoReadyWeaponToSwitch(self, !(flags & WRF_NoSwitch));
@ -960,7 +960,7 @@ static void P_CheckWeaponButtons (player_t *player)
DEFINE_ACTION_FUNCTION(AStateProvider, A_ReFire)
{
PARAM_ACTION_PROLOGUE(AActor);
PARAM_ACTION_PROLOGUE(AStateProvider);
PARAM_STATE_ACTION_DEF(state);
A_ReFire(self, state);
return 0;
@ -998,7 +998,7 @@ void A_ReFire(AActor *self, FState *state)
DEFINE_ACTION_FUNCTION(AStateProvider, A_ClearReFire)
{
PARAM_ACTION_PROLOGUE(AActor);
PARAM_ACTION_PROLOGUE(AStateProvider);
player_t *player = self->player;
if (NULL != player)
@ -1020,7 +1020,7 @@ DEFINE_ACTION_FUNCTION(AStateProvider, A_ClearReFire)
DEFINE_ACTION_FUNCTION(AStateProvider, A_CheckReload)
{
PARAM_ACTION_PROLOGUE(AActor);
PARAM_ACTION_PROLOGUE(AStateProvider);
if (self->player != NULL)
{
@ -1208,7 +1208,7 @@ DEFINE_ACTION_FUNCTION(AActor, OverlayID)
DEFINE_ACTION_FUNCTION(AStateProvider, A_Lower)
{
PARAM_ACTION_PROLOGUE(AActor);
PARAM_ACTION_PROLOGUE(AStateProvider);
player_t *player = self->player;
DPSprite *psp;
@ -1254,9 +1254,9 @@ DEFINE_ACTION_FUNCTION(AStateProvider, A_Lower)
//
//---------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_Raise)
DEFINE_ACTION_FUNCTION(AStateProvider, A_Raise)
{
PARAM_ACTION_PROLOGUE(AActor);
PARAM_ACTION_PROLOGUE(AStateProvider);
if (self == nullptr)
{
@ -1368,7 +1368,7 @@ enum GF_Flags
DEFINE_ACTION_FUNCTION(AStateProvider, A_GunFlash)
{
PARAM_ACTION_PROLOGUE(AActor);
PARAM_ACTION_PROLOGUE(AStateProvider);
PARAM_STATE_ACTION_DEF(flash);
PARAM_INT_DEF(flags);
@ -1605,38 +1605,40 @@ void player_t::DestroyPSprites()
void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int index)
{
PClassActor *cls = weapon->GetClass();
while (cls != RUNTIME_CLASS(AWeapon))
if (flashstate != nullptr)
{
if (flashstate >= cls->OwnedStates && flashstate < cls->OwnedStates + cls->NumOwnedStates)
PClassActor *cls = weapon->GetClass();
while (cls != RUNTIME_CLASS(AWeapon))
{
// The flash state belongs to this class.
// Now let's check if the actually wanted state does also
if (flashstate + index < cls->OwnedStates + cls->NumOwnedStates)
if (flashstate >= cls->OwnedStates && flashstate < cls->OwnedStates + cls->NumOwnedStates)
{
// we're ok so set the state
P_SetPsprite(player, PSP_FLASH, flashstate + index, true);
return;
}
else
{
// oh, no! The state is beyond the end of the state table so use the original flash state.
P_SetPsprite(player, PSP_FLASH, flashstate, true);
return;
// The flash state belongs to this class.
// Now let's check if the actually wanted state does also
if (flashstate + index < cls->OwnedStates + cls->NumOwnedStates)
{
// we're ok so set the state
P_SetPsprite(player, PSP_FLASH, flashstate + index, true);
return;
}
else
{
// oh, no! The state is beyond the end of the state table so use the original flash state.
P_SetPsprite(player, PSP_FLASH, flashstate, true);
return;
}
}
// try again with parent class
cls = static_cast<PClassActor *>(cls->ParentClass);
}
// if we get here the state doesn't seem to belong to any class in the inheritance chain
// This can happen with Dehacked if the flash states are remapped.
// The only way to check this would be to go through all Dehacked modifiable actors, convert
// their states into a single flat array and find the correct one.
// Rather than that, just check to make sure it belongs to something.
if (FState::StaticFindStateOwner(flashstate + index) == NULL)
{ // Invalid state. With no index offset, it should at least be valid.
index = 0;
}
// try again with parent class
cls = static_cast<PClassActor *>(cls->ParentClass);
}
// if we get here the state doesn't seem to belong to any class in the inheritance chain
// This can happen with Dehacked if the flash states are remapped.
// The only way to check this would be to go through all Dehacked modifiable actors, convert
// their states into a single flat array and find the correct one.
// Rather than that, just check to make sure it belongs to something.
if (FState::StaticFindStateOwner(flashstate + index) == NULL)
{ // Invalid state. With no index offset, it should at least be valid.
index = 0;
}
P_SetPsprite(player, PSP_FLASH, flashstate + index, true);
}
@ -1644,7 +1646,7 @@ void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int i
DEFINE_ACTION_FUNCTION(_PlayerInfo, SetSafeFlash)
{
PARAM_SELF_STRUCT_PROLOGUE(player_t);
PARAM_OBJECT(weapon, AWeapon);
PARAM_OBJECT_NOT_NULL(weapon, AWeapon);
PARAM_POINTER(state, FState);
PARAM_INT(index);
P_SetSafeFlash(weapon, self, state, index);

View file

@ -908,7 +908,7 @@ done:
DEFINE_ACTION_FUNCTION(AActor, CheckSight)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(target, AActor);
PARAM_OBJECT_NOT_NULL(target, AActor);
PARAM_INT_DEF(flags);
ACTION_RETURN_BOOL(P_CheckSight(self, target, flags));
}

View file

@ -178,8 +178,8 @@ void P_SetSlope (secplane_t *plane, bool setCeil, int xyangi, int zangi, const D
if (ib_compatflags & BCOMPATF_SETSLOPEOVERFLOW)
{
// We have to consider an integer multiplication overflow here.
norm[0] = FixedToFloat(FloatToFixed(zang.Cos()) * FloatToFixed(xyang.Cos()));
norm[1] = FixedToFloat(FloatToFixed(zang.Cos()) * FloatToFixed(xyang.Sin()));
norm[0] = FixedToFloat(FloatToFixed(zang.Cos()) * FloatToFixed(xyang.Cos())) / 65536.;
norm[1] = FixedToFloat(FloatToFixed(zang.Cos()) * FloatToFixed(xyang.Sin())) / 65536.;
}
else
{

View file

@ -1083,11 +1083,12 @@ DEFINE_ACTION_FUNCTION(FState, DistanceTo)
{
PARAM_SELF_STRUCT_PROLOGUE(FState);
PARAM_POINTER(other, FState);
// Safely calculate the distance between two states.
auto o1 = FState::StaticFindStateOwner(self);
int retv;
if (other < o1->OwnedStates || other >= o1->OwnedStates + o1->NumOwnedStates) retv = INT_MIN;
else retv = int(other - self);
int retv = INT_MIN;
if (other != nullptr)
{
// Safely calculate the distance between two states.
auto o1 = FState::StaticFindStateOwner(self);
if (other >= o1->OwnedStates && other < o1->OwnedStates + o1->NumOwnedStates) retv = int(other - self);
}
ACTION_RETURN_INT(retv);
}

View file

@ -608,6 +608,7 @@ static void ParseSpawnMap(FScanner &sc, SpawnMap & themap, const char *descript)
}
defined[ednum] = true;
editem.classname = sc.String;
editem.linenum = sc.Line;
themap.Insert(ednum, editem);
}

View file

@ -607,16 +607,6 @@ bool PClassPlayerPawn::GetPainFlash(FName type, PalEntry *color) const
return false;
}
void PClassPlayerPawn::ReplaceClassRef(PClass *oldclass, PClass *newclass)
{
Super::ReplaceClassRef(oldclass, newclass);
APlayerPawn *def = (APlayerPawn*)Defaults;
if (def != NULL)
{
if (def->FlechetteType == oldclass) def->FlechetteType = static_cast<PClassInventory *>(newclass);
}
}
//===========================================================================
//
// player_t :: SendPitchLimits
@ -648,6 +638,7 @@ IMPLEMENT_CLASS(APlayerPawn, false, true)
IMPLEMENT_POINTERS_START(APlayerPawn)
IMPLEMENT_POINTER(InvFirst)
IMPLEMENT_POINTER(InvSel)
IMPLEMENT_POINTER(FlechetteType)
IMPLEMENT_POINTERS_END
IMPLEMENT_CLASS(APlayerChunk, false, false)

View file

@ -1775,7 +1775,14 @@ void PO_Init (void)
}
}
}
// clear all polyobj specials so that they do not obstruct using other lines.
for (int i = 0; i < numlines; i++)
{
if (lines[i].special == Polyobj_ExplicitLine || lines[i].special == Polyobj_StartLine)
{
lines[i].special = 0;
}
}
}
//==========================================================================

View file

@ -1007,7 +1007,7 @@ void FScanner::CheckOpen()
//==========================================================================
int FScriptPosition::ErrorCounter;
int FScriptPosition::WarnCounter;
bool FScriptPosition::StrictErrors; // makes all OPTERRPR messages real errors.
bool FScriptPosition::StrictErrors; // makes all OPTERROR messages real errors.
FScriptPosition::FScriptPosition(const FScriptPosition &other)
{

View file

@ -288,6 +288,60 @@ ExpEmit FxExpression::Emit (VMFunctionBuilder *build)
}
//==========================================================================
//
// Emits a statement and records its position in the source.
//
//==========================================================================
void FxExpression::EmitStatement(VMFunctionBuilder *build)
{
build->BeginStatement(this);
ExpEmit exp = Emit(build);
exp.Free(build);
build->EndStatement();
}
//==========================================================================
//
//
//
//==========================================================================
void FxExpression::EmitCompare(VMFunctionBuilder *build, bool invert, TArray<size_t> &patchspots_yes, TArray<size_t> &patchspots_no)
{
ExpEmit op = Emit(build);
ExpEmit i;
assert(op.RegType != REGT_NIL && op.RegCount == 1 && !op.Konst);
switch (op.RegType)
{
case REGT_INT:
build->Emit(OP_EQ_K, !invert, op.RegNum, build->GetConstantInt(0));
break;
case REGT_FLOAT:
build->Emit(OP_EQF_K, !invert, op.RegNum, build->GetConstantFloat(0));
break;
case REGT_POINTER:
build->Emit(OP_EQA_K, !invert, op.RegNum, build->GetConstantAddress(0, ATAG_GENERIC));
break;
case REGT_STRING:
i = ExpEmit(build, REGT_INT);
build->Emit(OP_LENS, i.RegNum, op.RegNum);
build->Emit(OP_EQ_K, !invert, i.RegNum, build->GetConstantInt(0));
i.Free(build);
break;
default:
break;
}
patchspots_no.Push(build->Emit(OP_JMP, 0));
op.Free(build);
}
//==========================================================================
//
//
@ -584,7 +638,7 @@ static ExpEmit EmitKonst(VMFunctionBuilder *build, ExpEmit &emit)
ExpEmit FxVectorValue::Emit(VMFunctionBuilder *build)
{
// no const handling here. Ultimstely it's too rarely used (i.e. the only fully constant vector ever allocated in ZDoom is the 0-vector in a very few places)
// no const handling here. Ultimately it's too rarely used (i.e. the only fully constant vector ever allocated in ZDoom is the 0-vector in a very few places)
// and the negatives (excessive allocation of float constants) outweigh the positives (saved a few instructions)
assert(xyz[0] != nullptr);
assert(xyz[1] != nullptr);
@ -757,26 +811,7 @@ ExpEmit FxBoolCast::Emit(VMFunctionBuilder *build)
{
ExpEmit to(build, REGT_INT);
from.Free(build);
// Preload result with 0.
build->Emit(OP_LI, to.RegNum, 0);
// Check source against 0.
if (from.RegType == REGT_INT)
{
build->Emit(OP_EQ_R, 1, from.RegNum, to.RegNum);
}
else if (from.RegType == REGT_FLOAT)
{
build->Emit(OP_EQF_K, 1, from.RegNum, build->GetConstantFloat(0.));
}
else if (from.RegType == REGT_POINTER)
{
build->Emit(OP_EQA_K, 1, from.RegNum, build->GetConstantAddress(nullptr, ATAG_GENERIC));
}
build->Emit(OP_JMP, 1);
// Reload result with 1 if the comparison fell through.
build->Emit(OP_LI, to.RegNum, 1);
build->Emit(OP_CASTB, to.RegNum, from.RegNum, from.RegType == REGT_INT ? CASTB_I : from.RegType == REGT_FLOAT ? CASTB_F : CASTB_A);
return to;
}
else
@ -791,6 +826,17 @@ ExpEmit FxBoolCast::Emit(VMFunctionBuilder *build)
//
//==========================================================================
void FxBoolCast::EmitCompare(VMFunctionBuilder *build, bool invert, TArray<size_t> &patchspots_yes, TArray<size_t> &patchspots_no)
{
basex->EmitCompare(build, invert, patchspots_yes, patchspots_no);
}
//==========================================================================
//
//
//
//==========================================================================
FxIntCast::FxIntCast(FxExpression *x, bool nowarn, bool explicitly)
: FxExpression(EFX_IntCast, x->ScriptPosition)
{
@ -1210,7 +1256,7 @@ FxExpression *FxColorCast::Resolve(FCompileContext &ctx)
}
else
{
FxExpression *x = new FxConstant(V_GetColor(nullptr, constval.GetString()), ScriptPosition);
FxExpression *x = new FxConstant(V_GetColor(nullptr, constval.GetString(), &ScriptPosition), ScriptPosition);
delete this;
return x;
}
@ -1788,10 +1834,11 @@ FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx)
{
int result = ~static_cast<FxConstant *>(Operand)->GetValue().GetInt();
FxExpression *e = new FxConstant(result, ScriptPosition);
e->ValueType = Operand->ValueType == TypeUInt32 ? TypeUInt32 : TypeSInt32;
delete this;
return e;
}
ValueType = TypeSInt32;
ValueType = Operand->ValueType == TypeUInt32? TypeUInt32 : TypeSInt32;
return this;
}
@ -1889,6 +1936,17 @@ ExpEmit FxUnaryNotBoolean::Emit(VMFunctionBuilder *build)
//
//==========================================================================
void FxUnaryNotBoolean::EmitCompare(VMFunctionBuilder *build, bool invert, TArray<size_t> &patchspots_yes, TArray<size_t> &patchspots_no)
{
Operand->EmitCompare(build, !invert, patchspots_yes, patchspots_no);
}
//==========================================================================
//
//
//
//==========================================================================
FxSizeAlign::FxSizeAlign(FxExpression *operand, int which)
: FxExpression(EFX_SizeAlign, operand->ScriptPosition)
{
@ -2261,14 +2319,29 @@ ExpEmit FxAssign::Emit(VMFunctionBuilder *build)
ExpEmit pointer = Base->Emit(build);
Address = pointer;
ExpEmit result = Right->Emit(build);
ExpEmit result;
bool intconst = false;
int intconstval;
if (Right->isConstant() && Right->ValueType->GetRegType() == REGT_INT)
{
intconst = true;
intconstval = static_cast<FxConstant*>(Right)->GetValue().GetInt();
result.Konst = true;
result.RegType = REGT_INT;
}
else
{
result = Right->Emit(build);
}
assert(result.RegType <= REGT_TYPE);
if (pointer.Target)
{
if (result.Konst)
{
build->Emit(loadops[result.RegType], pointer.RegNum, result.RegNum);
if (intconst) build->EmitLoadInt(pointer.RegNum, intconstval);
else build->Emit(loadops[result.RegType], pointer.RegNum, result.RegNum);
}
else
{
@ -2280,7 +2353,8 @@ ExpEmit FxAssign::Emit(VMFunctionBuilder *build)
if (result.Konst)
{
ExpEmit temp(build, result.RegType);
build->Emit(loadops[result.RegType], temp.RegNum, result.RegNum);
if (intconst) build->EmitLoadInt(temp.RegNum, intconstval);
else build->Emit(loadops[result.RegType], temp.RegNum, result.RegNum);
result.Free(build);
result = temp;
}
@ -3141,7 +3215,7 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx)
//
//==========================================================================
ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build)
ExpEmit FxCompareRel::EmitCommon(VMFunctionBuilder *build, bool forcompare, bool invert)
{
ExpEmit op1 = left->Emit(build);
ExpEmit op2 = right->Emit(build);
@ -3171,11 +3245,15 @@ ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build)
{
op2.Free(build);
}
if (invert) a ^= CMP_CHECK;
build->Emit(OP_LI, to.RegNum, 0, 0);
if (!forcompare) build->Emit(OP_LI, to.RegNum, 0, 0);
build->Emit(OP_CMPS, a, op1.RegNum, op2.RegNum);
build->Emit(OP_JMP, 1);
build->Emit(OP_LI, to.RegNum, 1);
if (!forcompare)
{
build->Emit(OP_JMP, 1);
build->Emit(OP_LI, to.RegNum, 1);
}
return to;
}
else
@ -3214,16 +3292,32 @@ ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build)
{
op1.Free(build);
}
if (invert) check ^= 1;
// See FxBoolCast for comments, since it's the same thing.
build->Emit(OP_LI, to.RegNum, 0, 0);
if (!forcompare) build->Emit(OP_LI, to.RegNum, 0, 0);
build->Emit(instr, check, op1.RegNum, op2.RegNum);
build->Emit(OP_JMP, 1);
build->Emit(OP_LI, to.RegNum, 1);
if (!forcompare)
{
build->Emit(OP_JMP, 1);
build->Emit(OP_LI, to.RegNum, 1);
}
return to;
}
}
ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build)
{
return EmitCommon(build, false, false);
}
void FxCompareRel::EmitCompare(VMFunctionBuilder *build, bool invert, TArray<size_t> &patchspots_yes, TArray<size_t> &patchspots_no)
{
ExpEmit emit = EmitCommon(build, true, invert);
emit.Free(build);
patchspots_no.Push(build->Emit(OP_JMP, 0));
}
//==========================================================================
//
//
@ -3421,7 +3515,7 @@ error:
//
//==========================================================================
ExpEmit FxCompareEq::Emit(VMFunctionBuilder *build)
ExpEmit FxCompareEq::EmitCommon(VMFunctionBuilder *build, bool forcompare, bool invert)
{
ExpEmit op1 = left->Emit(build);
ExpEmit op2 = right->Emit(build);
@ -3435,13 +3529,17 @@ ExpEmit FxCompareEq::Emit(VMFunctionBuilder *build)
int a = Operator == TK_Eq ? CMP_EQ :
Operator == TK_Neq ? CMP_EQ | CMP_CHECK : CMP_EQ | CMP_APPROX;
if (op1.Konst) a|= CMP_BK;
if (op1.Konst) a |= CMP_BK;
if (op2.Konst) a |= CMP_CK;
if (invert) a ^= CMP_CHECK;
build->Emit(OP_LI, to.RegNum, 0, 0);
if (!forcompare) build->Emit(OP_LI, to.RegNum, 0, 0);
build->Emit(OP_CMPS, a, op1.RegNum, op2.RegNum);
build->Emit(OP_JMP, 1);
build->Emit(OP_LI, to.RegNum, 1);
if (!forcompare)
{
build->Emit(OP_JMP, 1);
build->Emit(OP_LI, to.RegNum, 1);
}
op1.Free(build);
op2.Free(build);
return to;
@ -3474,14 +3572,29 @@ ExpEmit FxCompareEq::Emit(VMFunctionBuilder *build)
}
// See FxUnaryNotBoolean for comments, since it's the same thing.
build->Emit(OP_LI, to.RegNum, 0, 0);
build->Emit(instr, Operator == TK_ApproxEq ? CMP_APPROX : ((Operator != TK_Eq) ? CMP_CHECK : 0), op1.RegNum, op2.RegNum);
build->Emit(OP_JMP, 1);
build->Emit(OP_LI, to.RegNum, 1);
if (!forcompare) build->Emit(OP_LI, to.RegNum, 0, 0);
build->Emit(instr, int(invert) ^ (Operator == TK_ApproxEq ? CMP_APPROX : ((Operator != TK_Eq) ? CMP_CHECK : 0)), op1.RegNum, op2.RegNum);
if (!forcompare)
{
build->Emit(OP_JMP, 1);
build->Emit(OP_LI, to.RegNum, 1);
}
return to;
}
}
ExpEmit FxCompareEq::Emit(VMFunctionBuilder *build)
{
return EmitCommon(build, false, false);
}
void FxCompareEq::EmitCompare(VMFunctionBuilder *build, bool invert, TArray<size_t> &patchspots_yes, TArray<size_t> &patchspots_no)
{
ExpEmit emit = EmitCommon(build, true, invert);
emit.Free(build);
patchspots_no.Push(build->Emit(OP_JMP, 0));
}
//==========================================================================
//
//
@ -4078,23 +4191,19 @@ void FxBinaryLogical::Flatten()
ExpEmit FxBinaryLogical::Emit(VMFunctionBuilder *build)
{
TArray<size_t> patchspots;
TArray<size_t> yes, no;
bool invert = Operator == TK_OrOr;
int zero = build->GetConstantInt(0);
for (unsigned i = 0; i < list.Size(); i++)
{
assert(list[i]->ValueType->GetRegType() == REGT_INT);
ExpEmit op1 = list[i]->Emit(build);
assert(!op1.Konst);
op1.Free(build);
build->Emit(OP_EQ_K, (Operator == TK_AndAnd) ? 1 : 0, op1.RegNum, zero);
patchspots.Push(build->Emit(OP_JMP, 0, 0, 0));
list[i]->EmitCompare(build, invert, yes, no);
}
build->BackpatchListToHere(yes);
ExpEmit to(build, REGT_INT);
build->Emit(OP_LI, to.RegNum, (Operator == TK_AndAnd) ? 1 : 0);
build->Emit(OP_JMP, 1);
build->BackpatchListToHere(no);
auto ctarget = build->Emit(OP_LI, to.RegNum, (Operator == TK_AndAnd) ? 0 : 1);
for (auto addr : patchspots) build->Backpatch(addr, ctarget);
list.DeleteAndClear();
list.ShrinkToFit();
return to;
@ -4464,21 +4573,17 @@ FxExpression *FxConditional::Resolve(FCompileContext& ctx)
ExpEmit FxConditional::Emit(VMFunctionBuilder *build)
{
size_t truejump, falsejump;
ExpEmit out;
size_t truejump;
ExpEmit out, falseout;
// The true and false expressions ought to be assigned to the
// same temporary instead of being copied to it. Oh well; good enough
// for now.
ExpEmit cond = condition->Emit(build);
assert(cond.RegType == REGT_INT && !cond.Konst);
TArray<size_t> yes, no;
condition->EmitCompare(build, false, yes, no);
// Test condition.
build->Emit(OP_EQ_K, 1, cond.RegNum, build->GetConstantInt(0));
falsejump = build->Emit(OP_JMP, 0);
cond.Free(build);
build->BackpatchListToHere(yes);
// Evaluate true expression.
if (truex->isConstant() && truex->ValueType->GetRegType() == REGT_INT)
{
out = ExpEmit(build, REGT_INT);
@ -4518,7 +4623,7 @@ ExpEmit FxConditional::Emit(VMFunctionBuilder *build)
truejump = build->Emit(OP_JMP, 0);
// Evaluate false expression.
build->BackpatchToHere(falsejump);
build->BackpatchListToHere(no);
if (falsex->isConstant() && falsex->ValueType->GetRegType() == REGT_INT)
{
build->EmitLoadInt(out.RegNum, static_cast<FxConstant *>(falsex)->GetValue().GetInt());
@ -4591,7 +4696,13 @@ FxExpression *FxAbs::Resolve(FCompileContext &ctx)
CHECKRESOLVED();
SAFE_RESOLVE(val, ctx);
if (val->ValueType == TypeBool) // abs of a boolean is always the same as the operand
{
auto v = val;
val = nullptr;
delete this;
return v;
}
if (!val->IsNumeric())
{
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
@ -5590,8 +5701,7 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx)
goto foundit;
}
auto cvar = FindCVar(Identifier.GetChars(), nullptr);
if (cvar != nullptr)
if (auto *cvar = FindCVar(Identifier.GetChars(), nullptr))
{
if (cvar->GetFlags() & CVAR_USERINFO)
{
@ -8424,9 +8534,7 @@ ExpEmit FxSequence::Emit(VMFunctionBuilder *build)
{
for (unsigned i = 0; i < Expressions.Size(); ++i)
{
ExpEmit v = Expressions[i]->Emit(build);
// Throw away any result. We don't care about it.
v.Free(build);
Expressions[i]->EmitStatement(build);
}
return ExpEmit();
}
@ -8722,7 +8830,7 @@ ExpEmit FxSwitchStatement::Emit(VMFunctionBuilder *build)
break;
default:
line->Emit(build);
line->EmitStatement(build);
break;
}
}
@ -8876,68 +8984,28 @@ FxExpression *FxIfStatement::Resolve(FCompileContext &ctx)
ExpEmit FxIfStatement::Emit(VMFunctionBuilder *build)
{
ExpEmit v;
size_t jumpspot;
FxExpression *path1, *path2;
int condcheck;
size_t jumpspot = ~0u;
// This is pretty much copied from FxConditional, except we don't
// keep any results.
ExpEmit cond = Condition->Emit(build);
assert(cond.RegType != REGT_STRING && !cond.Konst);
TArray<size_t> yes, no;
Condition->EmitCompare(build, false, yes, no);
if (WhenTrue != nullptr)
{
path1 = WhenTrue;
path2 = WhenFalse;
condcheck = 1;
build->BackpatchListToHere(yes);
WhenTrue->EmitStatement(build);
}
if (WhenFalse != nullptr)
{
if (!WhenTrue->CheckReturn()) jumpspot = build->Emit(OP_JMP, 0); // no need to emit a jump if the block returns.
build->BackpatchListToHere(no);
WhenFalse->EmitStatement(build);
if (jumpspot != ~0u) build->BackpatchToHere(jumpspot);
if (WhenTrue == nullptr) build->BackpatchListToHere(yes);
}
else
{
// When there is only a false path, reverse the condition so we can
// treat it as a true path.
assert(WhenFalse != nullptr);
path1 = WhenFalse;
path2 = nullptr;
condcheck = 0;
build->BackpatchListToHere(no);
}
// Test condition.
switch (cond.RegType)
{
default:
case REGT_INT:
build->Emit(OP_EQ_K, condcheck, cond.RegNum, build->GetConstantInt(0));
break;
case REGT_FLOAT:
build->Emit(OP_EQF_K, condcheck, cond.RegNum, build->GetConstantFloat(0));
break;
case REGT_POINTER:
build->Emit(OP_EQA_K, condcheck, cond.RegNum, build->GetConstantAddress(nullptr, ATAG_GENERIC));
break;
}
jumpspot = build->Emit(OP_JMP, 0);
cond.Free(build);
// Evaluate first path
v = path1->Emit(build);
v.Free(build);
if (path2 != nullptr)
{
size_t path1jump;
// if the branch ends with a return we do not need a terminating jmp.
if (!path1->CheckReturn()) path1jump = build->Emit(OP_JMP, 0);
else path1jump = 0xffffffff;
// Evaluate second path
build->BackpatchToHere(jumpspot);
v = path2->Emit(build);
v.Free(build);
jumpspot = path1jump;
}
if (jumpspot != 0xffffffff) build->BackpatchToHere(jumpspot);
return ExpEmit();
}
@ -9045,35 +9113,27 @@ ExpEmit FxWhileLoop::Emit(VMFunctionBuilder *build)
assert(Condition->ValueType == TypeBool);
size_t loopstart, loopend;
size_t jumpspot;
TArray<size_t> yes, no;
// 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);
Condition->EmitCompare(build, false, yes, no);
}
else assert(static_cast<FxConstant *>(Condition)->GetValue().GetBool() == true);
build->BackpatchListToHere(yes);
// Execute the loop's content.
if (Code != nullptr)
{
ExpEmit code = Code->Emit(build);
code.Free(build);
Code->EmitStatement(build);
}
// Loop back.
build->Backpatch(build->Emit(OP_JMP, 0), loopstart);
build->BackpatchListToHere(no);
loopend = build->GetAddress();
if (!Condition->isConstant())
{
build->Backpatch(jumpspot, loopend);
}
Backpatch(build, loopstart, loopend);
return ExpEmit();
}
@ -9142,25 +9202,23 @@ ExpEmit FxDoWhileLoop::Emit(VMFunctionBuilder *build)
codestart = build->GetAddress();
if (Code != nullptr)
{
ExpEmit code = Code->Emit(build);
code.Free(build);
Code->EmitStatement(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);
TArray<size_t> yes, no;
Condition->EmitCompare(build, true, yes, no);
build->BackpatchList(no, codestart);
build->BackpatchListToHere(yes);
}
else if (static_cast<FxConstant *>(Condition)->GetValue().GetBool() == true)
{ // Always looping
build->Backpatch(build->Emit(OP_JMP, 0), codestart);
}
loopend = build->GetAddress();
Backpatch(build, loopstart, loopend);
return ExpEmit();
@ -9234,7 +9292,7 @@ ExpEmit FxForLoop::Emit(VMFunctionBuilder *build)
size_t loopstart, loopend;
size_t codestart;
size_t jumpspot;
TArray<size_t> yes, no;
// Init statement (only used by DECORATE. ZScript is pulling it before the loop statement and enclosing the entire loop in a compound statement so that Init can have local variables.)
if (Init != nullptr)
@ -9247,17 +9305,14 @@ ExpEmit FxForLoop::Emit(VMFunctionBuilder *build)
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);
Condition->EmitCompare(build, false, yes, no);
}
build->BackpatchListToHere(yes);
// Execute the loop's content.
if (Code != nullptr)
{
ExpEmit code = Code->Emit(build);
code.Free(build);
Code->EmitStatement(build);
}
// Iteration statement.
@ -9271,10 +9326,7 @@ ExpEmit FxForLoop::Emit(VMFunctionBuilder *build)
// End of loop.
loopend = build->GetAddress();
if (Condition != nullptr)
{
build->Backpatch(jumpspot, loopend);
}
build->BackpatchListToHere(no);
Backpatch(build, loopstart, loopend);
return ExpEmit();
@ -9655,7 +9707,7 @@ int BuiltinClassCast(VMValue *param, TArray<VMValue> &defaultparam, int numparam
PARAM_PROLOGUE;
PARAM_CLASS(from, DObject);
PARAM_CLASS(to, DObject);
ACTION_RETURN_OBJECT(from->IsDescendantOf(to) ? from : nullptr);
ACTION_RETURN_OBJECT(from && to && from->IsDescendantOf(to) ? from : nullptr);
}
ExpEmit FxClassPtrCast::Emit(VMFunctionBuilder *build)
@ -9923,6 +9975,19 @@ FxExpression *FxLocalVariableDeclaration::Resolve(FCompileContext &ctx)
if (Init) Init = new FxTypeCast(Init, ValueType, false);
SAFE_RESOLVE_OPT(Init, ctx);
}
if (Name != NAME_None)
{
for (auto l : ctx.Block->LocalVars)
{
if (l->Name == Name)
{
ScriptPosition.Message(MSG_ERROR, "Local variable %s already defined", Name.GetChars());
l->ScriptPosition.Message(MSG_ERROR, "Original definition is here ");
delete this;
return nullptr;
}
}
}
ctx.Block->LocalVars.Push(this);
return this;
}

View file

@ -328,6 +328,8 @@ public:
bool IsObject() const { return ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && !ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) && ValueType != TypeNullPtr && static_cast<PPointer*>(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass)); }
virtual ExpEmit Emit(VMFunctionBuilder *build);
void EmitStatement(VMFunctionBuilder *build);
virtual void EmitCompare(VMFunctionBuilder *build, bool invert, TArray<size_t> &patchspots_yes, TArray<size_t> &patchspots_no);
FScriptPosition ScriptPosition;
PType *ValueType = nullptr;
@ -565,6 +567,7 @@ public:
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
void EmitCompare(VMFunctionBuilder *build, bool invert, TArray<size_t> &patchspots_yes, TArray<size_t> &patchspots_no);
};
class FxIntCast : public FxExpression
@ -734,6 +737,7 @@ public:
~FxUnaryNotBoolean();
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
void EmitCompare(VMFunctionBuilder *build, bool invert, TArray<size_t> &patchspots_yes, TArray<size_t> &patchspots_no);
};
//==========================================================================
@ -934,7 +938,9 @@ public:
FxCompareRel(int, FxExpression*, FxExpression*);
FxExpression *Resolve(FCompileContext&);
ExpEmit EmitCommon(VMFunctionBuilder *build, bool forcompare, bool invert);
ExpEmit Emit(VMFunctionBuilder *build);
void EmitCompare(VMFunctionBuilder *build, bool invert, TArray<size_t> &patchspots_yes, TArray<size_t> &patchspots_no);
};
//==========================================================================
@ -949,7 +955,9 @@ public:
FxCompareEq(int, FxExpression*, FxExpression*);
FxExpression *Resolve(FCompileContext&);
ExpEmit EmitCommon(VMFunctionBuilder *build, bool forcompare, bool invert);
ExpEmit Emit(VMFunctionBuilder *build);
void EmitCompare(VMFunctionBuilder *build, bool invert, TArray<size_t> &patchspots_yes, TArray<size_t> &patchspots_no);
};
//==========================================================================

View file

@ -165,7 +165,7 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool c
}
else
{
int c = V_GetColor (NULL, sc.String);
int c = V_GetColor (NULL, sc);
// 0 needs to be the default so we have to mark the color.
v = MAKEARGB(1, RPART(c), GPART(c), BPART(c));
}

View file

@ -343,7 +343,7 @@ endofstate:
if (ScriptCode != nullptr)
{
auto funcsym = CreateAnonymousFunction(actor, nullptr, state.UseFlags);
state.ActionFunc = FunctionBuildList.AddFunction(funcsym, ScriptCode, FStringf("%s.StateFunction.%d", actor->TypeName.GetChars(), bag.statedef.GetStateCount()), true);
state.ActionFunc = FunctionBuildList.AddFunction(funcsym, ScriptCode, FStringf("%s.StateFunction.%d", actor->TypeName.GetChars(), bag.statedef.GetStateCount()), true, bag.statedef.GetStateCount(), int(statestring.Len()), sc.LumpNum);
}
int count = bag.statedef.AddStates(&state, statestring, scp);
if (count < 0)

View file

@ -68,7 +68,6 @@
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
void InitThingdef();
TArray<PClassActor **> OptionalClassPtrs;
// STATIC FUNCTION PROTOTYPES --------------------------------------------
PClassActor *QuestItemClasses[31];
@ -220,7 +219,7 @@ PFunction *FindClassMemberFunction(PStruct *selfcls, PStruct *funccls, FName nam
//
//==========================================================================
void CreateDamageFunction(PClassActor *info, AActor *defaults, FxExpression *id, bool fromDecorate)
void CreateDamageFunction(PClassActor *info, AActor *defaults, FxExpression *id, bool fromDecorate, int lumpnum)
{
if (id == nullptr)
{
@ -230,7 +229,7 @@ void CreateDamageFunction(PClassActor *info, AActor *defaults, FxExpression *id,
{
auto dmg = new FxReturnStatement(new FxIntCast(id, true), id->ScriptPosition);
auto funcsym = CreateAnonymousFunction(info, TypeSInt32, 0);
defaults->DamageFunc = FunctionBuildList.AddFunction(funcsym, dmg, FStringf("%s.DamageFunction", info->TypeName.GetChars()), fromDecorate);
defaults->DamageFunc = FunctionBuildList.AddFunction(funcsym, dmg, FStringf("%s.DamageFunction", info->TypeName.GetChars()), fromDecorate, -1, 0, lumpnum);
}
}
@ -365,7 +364,7 @@ static void CheckStates(PClassActor *obj)
void ParseScripts();
void ParseAllDecorate();
void LoadActors ()
void LoadActors()
{
cycle_t timer;
@ -387,8 +386,9 @@ void LoadActors ()
}
FScriptPosition::ResetErrorCounter();
for (auto ti : PClassActor::AllActorClasses)
for (int i = PClassActor::AllActorClasses.Size() - 1; i >= 0; i--)
{
auto ti = PClassActor::AllActorClasses[i];
if (ti->Size == TentativeClass)
{
if (ti->ObjectFlags & OF_Transient)
@ -396,10 +396,7 @@ void LoadActors ()
Printf(TEXTCOLOR_ORANGE "Class %s referenced but not defined\n", ti->TypeName.GetChars());
FScriptPosition::WarnCounter++;
DObject::StaticPointerSubstitution(ti, nullptr);
for (auto op : OptionalClassPtrs)
{
if (*op == ti) *op = nullptr;
}
PClassActor::AllActorClasses.Delete(i);
}
else
{
@ -418,7 +415,7 @@ void LoadActors ()
CheckStates(ti);
if (ti->bDecorateClass && ti->IsDescendantOf(RUNTIME_CLASS(AStateProvider)))
{
// either a DECORATE based weapon or CustomInventory.
@ -427,7 +424,7 @@ void LoadActors ()
// hits an unsafe state. If we can find something here it can be handled wuth a compile error rather than a runtime error.
CheckForUnsafeStates(ti);
}
}
if (FScriptPosition::ErrorCounter > 0)
{
@ -445,6 +442,4 @@ void LoadActors ()
QuestItemClasses[i] = PClass::FindActor(fmt);
}
StateSourceLines.Clear();
OptionalClassPtrs.Clear();
OptionalClassPtrs.ShrinkToFit();
}

View file

@ -160,7 +160,7 @@ FName CheckCastKludges(FName in);
void SetImplicitArgs(TArray<PType *> *args, TArray<DWORD> *argflags, TArray<FName> *argnames, PStruct *cls, DWORD funcflags, int useflags);
PFunction *CreateAnonymousFunction(PClass *containingclass, PType *returntype, int flags);
PFunction *FindClassMemberFunction(PStruct *cls, PStruct *funccls, FName name, FScriptPosition &sc, bool *error);
void CreateDamageFunction(PClassActor *info, AActor *defaults, FxExpression *id, bool fromDecorate);
void CreateDamageFunction(PClassActor *info, AActor *defaults, FxExpression *id, bool fromDecorate, int lumpnum);
//==========================================================================
//

View file

@ -583,35 +583,24 @@ FPropertyInfo *FindProperty(const char * string)
AFuncDesc *FindFunction(PStruct *cls, const char * string)
{
for (int i = 0; i < 2; i++)
int min = 0, max = AFTable.Size() - 1;
while (min <= max)
{
// Since many functions have been declared with Actor as owning class, despite being members of something else, let's hack around this until they have been fixed or exported.
// Since most of these are expected to be scriptified anyway, there's no point fixing them all before they get exported.
if (i == 1)
int mid = (min + max) / 2;
int lexval = stricmp(cls->TypeName.GetChars(), AFTable[mid].ClassName + 1);
if (lexval == 0) lexval = stricmp(string, AFTable[mid].FuncName);
if (lexval == 0)
{
if (!cls->IsKindOf(RUNTIME_CLASS(PClassActor))) break;
cls = RUNTIME_CLASS(AActor);
return &AFTable[mid];
}
int min = 0, max = AFTable.Size() - 1;
while (min <= max)
else if (lexval > 0)
{
int mid = (min + max) / 2;
int lexval = stricmp(cls->TypeName.GetChars(), AFTable[mid].ClassName + 1);
if (lexval == 0) lexval = stricmp(string, AFTable[mid].FuncName);
if (lexval == 0)
{
return &AFTable[mid];
}
else if (lexval > 0)
{
min = mid + 1;
}
else
{
max = mid - 1;
}
min = mid + 1;
}
else
{
max = mid - 1;
}
}
return nullptr;

View file

@ -74,8 +74,6 @@
#include "a_health.h"
#include "a_keys.h"
extern TArray<PClassActor **> OptionalClassPtrs;
//==========================================================================
//
// Gets a class pointer and performs an error check for correct type
@ -666,7 +664,7 @@ DEFINE_PROPERTY(damage, X, Actor)
defaults->DamageVal = dmgval;
// Only DECORATE can get here with a valid expression.
CreateDamageFunction(bag.Info, defaults, id, true);
CreateDamageFunction(bag.Info, defaults, id, true, bag.Lumpnum);
}
//==========================================================================
@ -2307,8 +2305,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, color, C_f, Inventory)
*pBlendColor = MakeSpecialColormap(65535);
return;
}
color = V_GetColor(NULL, name);
color = V_GetColor(NULL, name, &bag.ScriptPosition);
}
if (PROP_PARM_COUNT > 2)
{
@ -2998,7 +2995,6 @@ DEFINE_CLASS_PROPERTY(playerclass, S, MorphProjectile)
{
PROP_STRING_PARM(str, 0);
defaults->PlayerClass = FindClassTentativePlayerPawn(str, bag.fromDecorate);
if (bag.fromDecorate) OptionalClassPtrs.Push((PClassActor**)&defaults->PlayerClass);
}
//==========================================================================
@ -3008,7 +3004,6 @@ DEFINE_CLASS_PROPERTY(monsterclass, S, MorphProjectile)
{
PROP_STRING_PARM(str, 0);
defaults->MonsterClass = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
if (bag.fromDecorate) OptionalClassPtrs.Push(&defaults->MonsterClass);
}
//==========================================================================
@ -3036,7 +3031,6 @@ DEFINE_CLASS_PROPERTY(morphflash, S, MorphProjectile)
{
PROP_STRING_PARM(str, 0);
defaults->MorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
if (bag.fromDecorate) OptionalClassPtrs.Push(&defaults->MorphFlash);
}
//==========================================================================
@ -3046,7 +3040,6 @@ DEFINE_CLASS_PROPERTY(unmorphflash, S, MorphProjectile)
{
PROP_STRING_PARM(str, 0);
defaults->UnMorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
if (bag.fromDecorate) OptionalClassPtrs.Push(&defaults->UnMorphFlash);
}
//==========================================================================
@ -3056,7 +3049,6 @@ DEFINE_CLASS_PROPERTY(playerclass, S, PowerMorph)
{
PROP_STRING_PARM(str, 0);
defaults->PlayerClass = FindClassTentativePlayerPawn(str, bag.fromDecorate);
if (bag.fromDecorate) OptionalClassPtrs.Push((PClassActor**)&defaults->PlayerClass);
}
//==========================================================================
@ -3075,7 +3067,6 @@ DEFINE_CLASS_PROPERTY(morphflash, S, PowerMorph)
{
PROP_STRING_PARM(str, 0);
defaults->MorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
if (bag.fromDecorate) OptionalClassPtrs.Push(&defaults->MorphFlash);
}
//==========================================================================
@ -3085,7 +3076,6 @@ DEFINE_CLASS_PROPERTY(unmorphflash, S, PowerMorph)
{
PROP_STRING_PARM(str, 0);
defaults->UnMorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
if (bag.fromDecorate) OptionalClassPtrs.Push(&defaults->UnMorphFlash);
}

View file

@ -5,6 +5,7 @@
#include "autosegs.h"
#include "vectors.h"
#include "cmdlib.h"
#include "doomerrors.h"
#define MAX_RETURNS 8 // Maximum number of results a function called by script code can return
#define MAX_TRY_DEPTH 8 // Maximum number of nested TRYs in a single function
@ -130,6 +131,11 @@ enum
CAST_V32S,
CAST_SID2S,
CAST_TID2S,
CASTB_I,
CASTB_F,
CASTB_A,
CASTB_S
};
// Register types for VMParam
@ -184,6 +190,14 @@ enum EVMAbortException
X_BAD_SELF,
};
class CVMAbortException : public CDoomError
{
public:
static FString stacktrace;
CVMAbortException(EVMAbortException reason, const char *moreinfo, va_list ap);
void MaybePrintMessage();
};
enum EVMOpMode
{
MODE_ASHIFT = 0,
@ -795,6 +809,12 @@ union FVoidObj
void *v;
};
struct FStatementInfo
{
uint16_t InstructionIndex;
uint16_t LineNumber;
};
class VMScriptFunction : public VMFunction
{
DECLARE_CLASS(VMScriptFunction, VMFunction);
@ -802,18 +822,21 @@ public:
VMScriptFunction(FName name=NAME_None);
~VMScriptFunction();
size_t PropagateMark();
void Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta);
void Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta, int numlinenumbers);
VM_ATAG *KonstATags() { return (VM_UBYTE *)(KonstA + NumKonstA); }
const VM_ATAG *KonstATags() const { return (VM_UBYTE *)(KonstA + NumKonstA); }
VMOP *Code;
FStatementInfo *LineInfo;
FString SourceFileName;
int *KonstD;
double *KonstF;
FString *KonstS;
FVoidObj *KonstA;
int ExtraSpace;
int CodeSize; // Size of code in instructions (not bytes)
unsigned LineInfoCount;
VM_UBYTE NumRegD;
VM_UBYTE NumRegF;
VM_UBYTE NumRegS;
@ -829,6 +852,7 @@ public:
void InitExtra(void *addr);
void DestroyExtra(void *addr);
int AllocExtraStack(PType *type);
int PCToLine(const VMOP *pc);
};
class VMFrameStack
@ -946,6 +970,9 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
// Use these to collect the parameters in a native function.
// variable name <x> at position <p>
void NullParam(const char *varname);
#define PARAM_NULLCHECK(ptr, var) (ptr == nullptr? NullParam(#var), ptr : ptr)
// For required parameters.
#define PARAM_INT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); int x = param[p].i;
@ -961,6 +988,9 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
#define PARAM_POINTER_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)param[p].a;
#define PARAM_OBJECT_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); type *x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type)));
#define PARAM_CLASS_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); base::MetaClass *x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base)));
#define PARAM_POINTER_NOT_NULL_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)PARAM_NULLCHECK(param[p].a, #x);
#define PARAM_OBJECT_NOT_NULL_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); type *x = (type *)PARAM_NULLCHECK(param[p].a, #x); assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type)));
#define PARAM_CLASS_NOT_NULL_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); base::MetaClass *x = (base::MetaClass *)PARAM_NULLCHECK(param[p].a, #x); assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base)));
#define PARAM_EXISTS(p) ((p) < numparam)
#define ASSERTINT(p) assert((p).Type == REGT_INT)
@ -983,6 +1013,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
#define PARAM_POINTER_DEF_AT(p,x,t) t *x; if (PARAM_EXISTS(p)) { ASSERTPOINTER(param[p]); x = (t*)param[p].a; } else { ASSERTPOINTER(defaultparam[p]); x = (t*)defaultparam[p].a; }
#define PARAM_OBJECT_DEF_AT(p,x,t) t *x; if (PARAM_EXISTS(p)) { ASSERTOBJECT(param[p]); x = (t*)param[p].a; } else { ASSERTOBJECT(defaultparam[p]); x = (t*)defaultparam[p].a; }
#define PARAM_CLASS_DEF_AT(p,x,t) t::MetaClass *x; if (PARAM_EXISTS(p)) { ASSERTOBJECT(param[p]); x = (t::MetaClass*)param[p].a; } else { ASSERTOBJECT(defaultparam[p]); x = (t::MetaClass*)defaultparam[p].a; }
#define PARAM_CLASS_DEF_NOT_NULL_AT(p,x,t) t::MetaClass *x; if (PARAM_EXISTS(p)) { ASSERTOBJECT(param[p]); x = (t::MetaClass*)PARAM_NULLCHECK(param[p].a, #x); } else { ASSERTOBJECT(defaultparam[p]); x = (t::MetaClass*)PARAM_NULLCHECK(defaultparam[p].a, #x); }
// The above, but with an automatically increasing position index.
#define PARAM_PROLOGUE int paramnum = -1;
@ -1000,6 +1031,9 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
#define PARAM_POINTER(x,type) ++paramnum; PARAM_POINTER_AT(paramnum,x,type)
#define PARAM_OBJECT(x,type) ++paramnum; PARAM_OBJECT_AT(paramnum,x,type)
#define PARAM_CLASS(x,base) ++paramnum; PARAM_CLASS_AT(paramnum,x,base)
#define PARAM_POINTER_NOT_NULL(x,type) ++paramnum; PARAM_POINTER_NOT_NULL_AT(paramnum,x,type)
#define PARAM_OBJECT_NOT_NULL(x,type) ++paramnum; PARAM_OBJECT_NOT_NULL_AT(paramnum,x,type)
#define PARAM_CLASS_NOT_NULL(x,base) ++paramnum; PARAM_CLASS_NOT_NULL_AT(paramnum,x,base)
#define PARAM_INT_DEF(x) ++paramnum; PARAM_INT_DEF_AT(paramnum,x)
#define PARAM_BOOL_DEF(x) ++paramnum; PARAM_BOOL_DEF_AT(paramnum,x)
@ -1014,6 +1048,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
#define PARAM_POINTER_DEF(x,type) ++paramnum; PARAM_POINTER_DEF_AT(paramnum,x,type)
#define PARAM_OBJECT_DEF(x,type) ++paramnum; PARAM_OBJECT_DEF_AT(paramnum,x,type)
#define PARAM_CLASS_DEF(x,base) ++paramnum; PARAM_CLASS_DEF_AT(paramnum,x,base)
#define PARAM_CLASS_DEF_NOT_NULL(x,base) ++paramnum; PARAM_CLASS_DEF_NOT_NULL_AT(paramnum,x,base)
typedef int(*actionf_p)(VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret);/*(VM_ARGS)*/
@ -1115,8 +1150,8 @@ class AActor;
// callingstate - State this action was called from
#define PARAM_ACTION_PROLOGUE(type) \
PARAM_PROLOGUE; \
PARAM_OBJECT (self, type); \
PARAM_OBJECT (stateowner, AActor) \
PARAM_OBJECT (self, AActor); \
PARAM_OBJECT (stateowner, type) \
PARAM_POINTER (stateinfo, FStateParamInfo) \
// Number of action paramaters

View file

@ -75,18 +75,45 @@ VMFunctionBuilder::~VMFunctionBuilder()
//==========================================================================
//
// VMFunctionBuilder :: MakeFunction
// VMFunctionBuilder :: BeginStatement
//
// Creates a new VMScriptFunction out of the data passed to this class.
// Records the start of a new statement.
//
//==========================================================================
void VMFunctionBuilder::BeginStatement(FxExpression *stmt)
{
// pop empty statement records.
while (LineNumbers.Size() > 0 && LineNumbers.Last().InstructionIndex == Code.Size()) LineNumbers.Pop();
// only add a new entry if the line number differs.
if (LineNumbers.Size() == 0 || stmt->ScriptPosition.ScriptLine != LineNumbers.Last().LineNumber)
{
FStatementInfo si = { (uint16_t)Code.Size(), (uint16_t)stmt->ScriptPosition.ScriptLine };
LineNumbers.Push(si);
}
StatementStack.Push(stmt);
}
void VMFunctionBuilder::EndStatement()
{
// pop empty statement records.
while (LineNumbers.Size() > 0 && LineNumbers.Last().InstructionIndex == Code.Size()) LineNumbers.Pop();
StatementStack.Pop();
// Re-enter the previous statement.
if (StatementStack.Size() > 0)
{
FStatementInfo si = { (uint16_t)Code.Size(), (uint16_t)StatementStack.Last()->ScriptPosition.ScriptLine };
LineNumbers.Push(si);
}
}
void VMFunctionBuilder::MakeFunction(VMScriptFunction *func)
{
func->Alloc(Code.Size(), IntConstantList.Size(), FloatConstantList.Size(), StringConstantList.Size(), AddressConstantList.Size());
func->Alloc(Code.Size(), IntConstantList.Size(), FloatConstantList.Size(), StringConstantList.Size(), AddressConstantList.Size(), LineNumbers.Size());
// Copy code block.
memcpy(func->Code, &Code[0], Code.Size() * sizeof(VMOP));
memcpy(func->LineInfo, &LineNumbers[0], LineNumbers.Size() * sizeof(LineNumbers[0]));
// Create constant tables.
if (IntConstantList.Size() > 0)
@ -734,6 +761,13 @@ void VMFunctionBuilder::Backpatch(size_t loc, size_t target)
Code[loc].i24 = offset;
}
void VMFunctionBuilder::BackpatchList(TArray<size_t> &locs, size_t target)
{
for (auto loc : locs)
Backpatch(loc, target);
}
//==========================================================================
//
// VMFunctionBuilder :: BackpatchToHere
@ -748,6 +782,12 @@ void VMFunctionBuilder::BackpatchToHere(size_t loc)
Backpatch(loc, Code.Size());
}
void VMFunctionBuilder::BackpatchListToHere(TArray<size_t> &locs)
{
for (auto loc : locs)
Backpatch(loc, Code.Size());
}
//==========================================================================
//
// FFunctionBuildList
@ -867,7 +907,10 @@ void FFunctionBuildList::Build()
// Emit code
try
{
sfunc->SourceFileName = item.Code->ScriptPosition.FileName; // remember the file name for printing error messages if something goes wrong in the VM.
buildit.BeginStatement(item.Code);
item.Code->Emit(&buildit);
buildit.EndStatement();
buildit.MakeFunction(sfunc);
sfunc->NumArgs = 0;
// NumArgs for the VMFunction must be the amount of stack elements, which can differ from the amount of logical function arguments if vectors are in the list.

View file

@ -4,6 +4,7 @@
#include "dobject.h"
class VMFunctionBuilder;
class FxExpression;
struct ExpEmit
{
@ -42,6 +43,8 @@ public:
VMFunctionBuilder(int numimplicits);
~VMFunctionBuilder();
void BeginStatement(FxExpression *stmt);
void EndStatement();
void MakeFunction(VMScriptFunction *func);
// Returns the constant register holding the value.
@ -69,6 +72,8 @@ public:
void Backpatch(size_t addr, size_t target);
void BackpatchToHere(size_t addr);
void BackpatchList(TArray<size_t> &addrs, size_t target);
void BackpatchListToHere(TArray<size_t> &addrs);
// Write out complete constant tables.
void FillIntConstants(int *konst);
@ -95,6 +100,9 @@ private:
VM_ATAG Tag;
};
TArray<FStatementInfo> LineNumbers;
TArray<FxExpression *> StatementStack;
TArray<int> IntConstantList;
TArray<double> FloatConstantList;
TArray<void *> AddressConstantList;
@ -141,7 +149,7 @@ class FFunctionBuildList
TArray<Item> mItems;
public:
VMFunction *AddFunction(PFunction *func, FxExpression *code, const FString &name, bool fromdecorate, int currentstate = -1, int statecnt = 0, int lumpnum = -1);
VMFunction *AddFunction(PFunction *func, FxExpression *code, const FString &name, bool fromdecorate, int currentstate, int statecnt, int lumpnum);
void Build();
};

View file

@ -90,6 +90,7 @@
#define THROW MODE_AIMMZ | MODE_BCTHROW
#define CATCH MODE_AIMMZ | MODE_BCCATCH
#define CAST MODE_AX | MODE_BX | MODE_CIMMZ | MODE_BCCAST
#define CASTB MODE_AI | MODE_BX | MODE_CIMMZ | MODE_BCCAST
#define RSRSRS MODE_AS | MODE_BS | MODE_CS
#define RIRS MODE_AI | MODE_BS | MODE_CUNUSED
@ -381,10 +382,18 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
break;
default:
if ((mode & MODE_BCTYPE) == MODE_BCCAST)
{
switch (code[i].c)
{
case CASTB_I:
mode = MODE_AI | MODE_BI | MODE_CUNUSED;
break;
case CASTB_A:
mode = MODE_AI | MODE_BP | MODE_CUNUSED;
break;
case CAST_I2F:
case CAST_U2F:
mode = MODE_AF | MODE_BI | MODE_CUNUSED;
@ -398,6 +407,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
break;
case CAST_F2I:
case CAST_F2U:
case CASTB_F:
mode = MODE_AI | MODE_BF | MODE_CUNUSED;
break;
case CAST_F2S:
@ -412,6 +422,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
case CAST_S2So:
case CAST_S2N:
case CAST_S2I:
case CASTB_S:
mode = MODE_AI | MODE_BS | MODE_CUNUSED;
break;
case CAST_S2F:

View file

@ -40,6 +40,11 @@
#include "textures/textures.h"
#include "math/cmath.h"
// This must be a separate function because the VC compiler would otherwise allocate memory on the stack for every separate instance of the exception object that may get thrown.
void ThrowAbortException(EVMAbortException reason, const char *moreinfo, ...);
// intentionally implemented in a different source file tp prevent inlining.
void ThrowVMException(VMException *x);
#define IMPLEMENT_VMEXEC
#if !defined(COMPGOTO) && defined(__GNUC__)
@ -82,8 +87,6 @@
#define ASSERTKA(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstA)
#define ASSERTKS(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstS)
#define THROW(x) throw(EVMAbortException(x))
#define CMPJMP(test) \
if ((test) == (a & CMP_CHECK)) { \
assert(pc[1].op == OP_JMP); \
@ -93,7 +96,7 @@
}
#define GETADDR(a,o,x) \
if (a == NULL) { THROW(x); } \
if (a == NULL) { ThrowAbortException(x, nullptr); } \
ptr = (VM_SBYTE *)a + o
static const VM_UWORD ZapTable[16] =
@ -228,3 +231,5 @@ void VMFillParams(VMValue *params, VMFrame *callee, int numparam)
}
}
}

View file

@ -2,7 +2,6 @@
#error vmexec.h must not be #included outside vmexec.cpp. Use vm.h instead.
#endif
static int Exec(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret)
{
#if COMPGOTO
@ -419,12 +418,12 @@ begin:
if (C == CAST_I2F)
{
ASSERTF(a); ASSERTD(B);
reg.f[A] = reg.d[B];
reg.f[a] = reg.d[B];
}
else if (C == CAST_F2I)
{
ASSERTD(a); ASSERTF(B);
reg.d[A] = (int)reg.f[B];
reg.d[a] = (int)reg.f[B];
}
else
{
@ -432,6 +431,29 @@ begin:
}
NEXTOP;
OP(CASTB):
if (C == CASTB_I)
{
ASSERTD(a); ASSERTD(B);
reg.d[a] = !!reg.d[B];
}
else if (C == CASTB_F)
{
ASSERTD(a); ASSERTF(B);
reg.d[a] = reg.f[B] != 0;
}
else if (C == CASTB_A)
{
ASSERTD(a); ASSERTA(B);
reg.d[a] = reg.a[B] != nullptr;
}
else
{
ASSERTD(a); ASSERTS(B);
reg.d[a] = reg.s[B].Len() > 0;
}
NEXTOP;
OP(TEST):
ASSERTD(a);
if (reg.d[a] != BC)
@ -573,7 +595,17 @@ begin:
FillReturns(reg, f, returns, pc+1, C);
if (call->Native)
{
numret = static_cast<VMNativeFunction *>(call)->NativeCall(reg.param + f->NumParam - B, call->DefaultArgs, B, returns, C);
try
{
numret = static_cast<VMNativeFunction *>(call)->NativeCall(reg.param + f->NumParam - B, call->DefaultArgs, B, returns, C);
}
catch (CVMAbortException &err)
{
err.MaybePrintMessage();
err.stacktrace.AppendFormat("Called from %s\n", call->PrintableName.GetChars());
// PrintParameters(reg.param + f->NumParam - B, B);
throw;
}
}
else
{
@ -617,7 +649,17 @@ begin:
if (call->Native)
{
return static_cast<VMNativeFunction *>(call)->NativeCall(reg.param + f->NumParam - B, call->DefaultArgs, B, ret, numret);
try
{
return static_cast<VMNativeFunction *>(call)->NativeCall(reg.param + f->NumParam - B, call->DefaultArgs, B, ret, numret);
}
catch (CVMAbortException &err)
{
err.MaybePrintMessage();
err.stacktrace.AppendFormat("Called from %s\n", call->PrintableName.GetChars());
// PrintParameters(reg.param + f->NumParam - B, B);
throw;
}
}
else
{ // FIXME: Not a true tail call
@ -681,7 +723,7 @@ begin:
assert(try_depth < MAX_TRY_DEPTH);
if (try_depth >= MAX_TRY_DEPTH)
{
THROW(X_TOO_MANY_TRIES);
ThrowAbortException(X_TOO_MANY_TRIES, nullptr);
}
assert((pc + JMPOFS(pc) + 1)->op == OP_CATCH);
exception_frames[try_depth++] = pc + JMPOFS(pc) + 1;
@ -694,17 +736,17 @@ begin:
if (a == 0)
{
ASSERTA(B);
throw((VMException *)reg.a[B]);
ThrowVMException((VMException *)reg.a[B]);
}
else if (a == 1)
{
ASSERTKA(B);
assert(konstatag[B] == ATAG_OBJECT);
throw((VMException *)konsta[B].o);
ThrowVMException((VMException *)konsta[B].o);
}
else
{
THROW(BC);
ThrowAbortException(EVMAbortException(BC), nullptr);
}
NEXTOP;
OP(CATCH):
@ -713,13 +755,10 @@ begin:
assert(0);
NEXTOP;
// Fixme: This really needs to throw something more informative than a number. Printing the message here instead of passing it to the exception is not sufficient.
OP(BOUND):
if (reg.d[a] >= BC)
{
assert(false);
Printf("Array access out of bounds: Max. index = %u, current index = %u\n", BC, reg.d[a]);
THROW(X_ARRAY_OUT_OF_BOUNDS);
ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Max.index = %u, current index = %u\n", BC, reg.d[a]);
}
NEXTOP;
@ -727,9 +766,7 @@ begin:
ASSERTKD(BC);
if (reg.d[a] >= konstd[BC])
{
assert(false);
Printf("Array access out of bounds: Max. index = %u, current index = %u\n", konstd[BC], reg.d[a]);
THROW(X_ARRAY_OUT_OF_BOUNDS);
ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Max.index = %u, current index = %u\n", konstd[BC], reg.d[a]);
}
NEXTOP;
@ -737,9 +774,7 @@ begin:
ASSERTD(B);
if (reg.d[a] >= reg.d[B])
{
assert(false);
Printf("Array access out of bounds: Max. index = %u, current index = %u\n", reg.d[B], reg.d[a]);
THROW(X_ARRAY_OUT_OF_BOUNDS);
ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Max.index = %u, current index = %u\n", reg.d[B], reg.d[a]);
}
NEXTOP;
@ -886,7 +921,7 @@ begin:
ASSERTD(a); ASSERTD(B); ASSERTD(C);
if (reg.d[C] == 0)
{
THROW(X_DIVISION_BY_ZERO);
ThrowAbortException(X_DIVISION_BY_ZERO, nullptr);
}
reg.d[a] = reg.d[B] / reg.d[C];
NEXTOP;
@ -894,7 +929,7 @@ begin:
ASSERTD(a); ASSERTD(B); ASSERTKD(C);
if (konstd[C] == 0)
{
THROW(X_DIVISION_BY_ZERO);
ThrowAbortException(X_DIVISION_BY_ZERO, nullptr);
}
reg.d[a] = reg.d[B] / konstd[C];
NEXTOP;
@ -902,7 +937,7 @@ begin:
ASSERTD(a); ASSERTKD(B); ASSERTD(C);
if (reg.d[C] == 0)
{
THROW(X_DIVISION_BY_ZERO);
ThrowAbortException(X_DIVISION_BY_ZERO, nullptr);
}
reg.d[a] = konstd[B] / reg.d[C];
NEXTOP;
@ -911,7 +946,7 @@ begin:
ASSERTD(a); ASSERTD(B); ASSERTD(C);
if (reg.d[C] == 0)
{
THROW(X_DIVISION_BY_ZERO);
ThrowAbortException(X_DIVISION_BY_ZERO, nullptr);
}
reg.d[a] = int((unsigned)reg.d[B] / (unsigned)reg.d[C]);
NEXTOP;
@ -919,7 +954,7 @@ begin:
ASSERTD(a); ASSERTD(B); ASSERTKD(C);
if (konstd[C] == 0)
{
THROW(X_DIVISION_BY_ZERO);
ThrowAbortException(X_DIVISION_BY_ZERO, nullptr);
}
reg.d[a] = int((unsigned)reg.d[B] / (unsigned)konstd[C]);
NEXTOP;
@ -927,7 +962,7 @@ begin:
ASSERTD(a); ASSERTKD(B); ASSERTD(C);
if (reg.d[C] == 0)
{
THROW(X_DIVISION_BY_ZERO);
ThrowAbortException(X_DIVISION_BY_ZERO, nullptr);
}
reg.d[a] = int((unsigned)konstd[B] / (unsigned)reg.d[C]);
NEXTOP;
@ -936,7 +971,7 @@ begin:
ASSERTD(a); ASSERTD(B); ASSERTD(C);
if (reg.d[C] == 0)
{
THROW(X_DIVISION_BY_ZERO);
ThrowAbortException(X_DIVISION_BY_ZERO, nullptr);
}
reg.d[a] = reg.d[B] % reg.d[C];
NEXTOP;
@ -944,7 +979,7 @@ begin:
ASSERTD(a); ASSERTD(B); ASSERTKD(C);
if (konstd[C] == 0)
{
THROW(X_DIVISION_BY_ZERO);
ThrowAbortException(X_DIVISION_BY_ZERO, nullptr);
}
reg.d[a] = reg.d[B] % konstd[C];
NEXTOP;
@ -952,7 +987,7 @@ begin:
ASSERTD(a); ASSERTKD(B); ASSERTD(C);
if (reg.d[C] == 0)
{
THROW(X_DIVISION_BY_ZERO);
ThrowAbortException(X_DIVISION_BY_ZERO, nullptr);
}
reg.d[a] = konstd[B] % reg.d[C];
NEXTOP;
@ -961,7 +996,7 @@ begin:
ASSERTD(a); ASSERTD(B); ASSERTD(C);
if (reg.d[C] == 0)
{
THROW(X_DIVISION_BY_ZERO);
ThrowAbortException(X_DIVISION_BY_ZERO, nullptr);
}
reg.d[a] = int((unsigned)reg.d[B] % (unsigned)reg.d[C]);
NEXTOP;
@ -969,7 +1004,7 @@ begin:
ASSERTD(a); ASSERTD(B); ASSERTKD(C);
if (konstd[C] == 0)
{
THROW(X_DIVISION_BY_ZERO);
ThrowAbortException(X_DIVISION_BY_ZERO, nullptr);
}
reg.d[a] = int((unsigned)reg.d[B] % (unsigned)konstd[C]);
NEXTOP;
@ -977,7 +1012,7 @@ begin:
ASSERTD(a); ASSERTKD(B); ASSERTD(C);
if (reg.d[C] == 0)
{
THROW(X_DIVISION_BY_ZERO);
ThrowAbortException(X_DIVISION_BY_ZERO, nullptr);
}
reg.d[a] = int((unsigned)konstd[B] % (unsigned)reg.d[C]);
NEXTOP;
@ -1155,7 +1190,7 @@ begin:
ASSERTF(a); ASSERTF(B); ASSERTF(C);
if (reg.f[C] == 0.)
{
THROW(X_DIVISION_BY_ZERO);
ThrowAbortException(X_DIVISION_BY_ZERO, nullptr);
}
reg.f[a] = reg.f[B] / reg.f[C];
NEXTOP;
@ -1163,7 +1198,7 @@ begin:
ASSERTF(a); ASSERTF(B); ASSERTKF(C);
if (konstf[C] == 0.)
{
THROW(X_DIVISION_BY_ZERO);
ThrowAbortException(X_DIVISION_BY_ZERO, nullptr);
}
reg.f[a] = reg.f[B] / konstf[C];
NEXTOP;
@ -1171,7 +1206,7 @@ begin:
ASSERTF(a); ASSERTKF(B); ASSERTF(C);
if (reg.f[C] == 0.)
{
THROW(X_DIVISION_BY_ZERO);
ThrowAbortException(X_DIVISION_BY_ZERO, nullptr);
}
reg.f[a] = konstf[B] / reg.f[C];
NEXTOP;
@ -1182,7 +1217,7 @@ begin:
Do_MODF:
if (fc == 0.)
{
THROW(X_DIVISION_BY_ZERO);
ThrowAbortException(X_DIVISION_BY_ZERO, nullptr);
}
reg.f[a] = luai_nummod(fb, fc);
NEXTOP;
@ -1595,6 +1630,13 @@ begin:
// Nothing caught it. Rethrow and let somebody else deal with it.
throw;
}
catch (CVMAbortException &err)
{
err.MaybePrintMessage();
err.stacktrace.AppendFormat("Called from %s at %s, line %d\n", sfunc->PrintableName.GetChars(), sfunc->SourceFileName.GetChars(), sfunc->PCToLine(pc));
// PrintParameters(reg.param + f->NumParam - B, B);
throw;
}
return 0;
}
@ -1827,12 +1869,12 @@ static void SetReturn(const VMRegisters &reg, VMFrame *frame, VMReturn *ret, VM_
case REGT_FLOAT:
if (regtype & REGT_KONST)
{
assert(regnum + ((regtype & REGT_KONST) ? 2u : 0u) < func->NumKonstF);
assert(regnum < func->NumKonstF);
src = &func->KonstF[regnum];
}
else
{
assert(regnum + ((regtype & REGT_KONST) ? 2u : 0u) < frame->NumRegF);
assert(regnum < frame->NumRegF);
src = &reg.f[regnum];
}
if (regtype & REGT_MULTIREG3)

View file

@ -3,6 +3,7 @@
**
**---------------------------------------------------------------------------
** Copyright -2016 Randy Heit
** Copyright 2016 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
@ -33,6 +34,7 @@
#include <new>
#include "dobject.h"
#include "v_text.h"
IMPLEMENT_CLASS(VMException, false, false)
IMPLEMENT_CLASS(VMFunction, true, true)
@ -48,11 +50,13 @@ VMScriptFunction::VMScriptFunction(FName name)
{
Native = false;
Name = name;
LineInfo = nullptr;
Code = NULL;
KonstD = NULL;
KonstF = NULL;
KonstS = NULL;
KonstA = NULL;
LineInfoCount = 0;
ExtraSpace = 0;
CodeSize = 0;
NumRegD = 0;
@ -82,7 +86,7 @@ VMScriptFunction::~VMScriptFunction()
}
}
void VMScriptFunction::Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta)
void VMScriptFunction::Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta, int numlinenumbers)
{
assert(Code == NULL);
assert(numops > 0);
@ -90,14 +94,27 @@ void VMScriptFunction::Alloc(int numops, int numkonstd, int numkonstf, int numko
assert(numkonstf >= 0 && numkonstf <= 65535);
assert(numkonsts >= 0 && numkonsts <= 65535);
assert(numkonsta >= 0 && numkonsta <= 65535);
assert(numlinenumbers >= 0 && numlinenumbers <= 65535);
void *mem = M_Malloc(numops * sizeof(VMOP) +
numkonstd * sizeof(int) +
numkonstf * sizeof(double) +
numkonsts * sizeof(FString) +
numkonsta * (sizeof(FVoidObj) + 1));
numkonsta * (sizeof(FVoidObj) + 1) +
numlinenumbers * sizeof(FStatementInfo));
Code = (VMOP *)mem;
mem = (void *)((VMOP *)mem + numops);
if (numlinenumbers > 0)
{
LineInfo = (FStatementInfo*)mem;
LineInfoCount = numlinenumbers;
mem = LineInfo + numlinenumbers;
}
else
{
LineInfo = nullptr;
LineInfoCount = 0;
}
if (numkonstd > 0)
{
KonstD = (int *)mem;
@ -190,6 +207,20 @@ int VMScriptFunction::AllocExtraStack(PType *type)
return address;
}
int VMScriptFunction::PCToLine(const VMOP *pc)
{
int PCIndex = int(pc - Code);
if (LineInfoCount == 1) return LineInfo[0].LineNumber;
for (unsigned i = 1; i < LineInfoCount; i++)
{
if (LineInfo[i].InstructionIndex > PCIndex)
{
return LineInfo[i - 1].LineNumber;
}
}
return -1;
}
//===========================================================================
//
// VMFrame :: InitRegS
@ -422,7 +453,7 @@ VMFrame *VMFrameStack::PopFrame()
int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMReturn *results, int numresults, VMException **trap)
{
assert(this == VMGlobalStack); // why would anyone even want to create a local stack?
assert(this == &GlobalVMStack); // why would anyone even want to create a local stack?
bool allocated = false;
try
{
@ -453,48 +484,6 @@ int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMRetur
}
throw;
}
catch (EVMAbortException exception)
{
if (allocated)
{
PopFrame();
}
if (trap != nullptr)
{
*trap = nullptr;
}
Printf("VM execution aborted: ");
switch (exception)
{
case X_READ_NIL:
Printf("tried to read from address zero.");
break;
case X_WRITE_NIL:
Printf("tried to write to address zero.");
break;
case X_TOO_MANY_TRIES:
Printf("too many try-catch blocks.");
break;
case X_ARRAY_OUT_OF_BOUNDS:
Printf("array access out of bounds.");
break;
case X_DIVISION_BY_ZERO:
Printf("division by zero.");
break;
case X_BAD_SELF:
Printf("invalid self pointer.");
break;
}
Printf("\n");
return -1;
}
catch (...)
{
if (allocated)
@ -504,3 +493,83 @@ int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMRetur
throw;
}
}
// Exception stuff for the VM is intentionally placed there, because having this in vmexec.cpp would subject it to inlining
// which we do not want because it increases the local stack requirements of Exec which are already too high.
FString CVMAbortException::stacktrace;
CVMAbortException::CVMAbortException(EVMAbortException reason, const char *moreinfo, va_list ap)
{
SetMessage("VM execution aborted: ");
switch (reason)
{
case X_READ_NIL:
AppendMessage("tried to read from address zero.");
break;
case X_WRITE_NIL:
AppendMessage("tried to write to address zero.");
break;
case X_TOO_MANY_TRIES:
AppendMessage("too many try-catch blocks.");
break;
case X_ARRAY_OUT_OF_BOUNDS:
AppendMessage("array access out of bounds.");
break;
case X_DIVISION_BY_ZERO:
AppendMessage("division by zero.");
break;
case X_BAD_SELF:
AppendMessage("invalid self pointer.");
break;
default:
{
size_t len = strlen(m_Message);
mysnprintf(m_Message + len, MAX_ERRORTEXT - len, "Unknown reason %d", reason);
break;
}
}
if (moreinfo != nullptr)
{
AppendMessage(" ");
size_t len = strlen(m_Message);
myvsnprintf(m_Message + len, MAX_ERRORTEXT - len, moreinfo, ap);
}
stacktrace = "";
}
// Print this only once on the first catch block.
void CVMAbortException::MaybePrintMessage()
{
auto m = GetMessage();
if (m != nullptr)
{
Printf(TEXTCOLOR_RED);
Printf("%s\n", m);
SetMessage("");
}
}
void ThrowAbortException(EVMAbortException reason, const char *moreinfo, ...)
{
va_list ap;
va_start(ap, moreinfo);
throw CVMAbortException(reason, moreinfo, ap);
va_end(ap);
}
void NullParam(const char *varname)
{
ThrowAbortException(X_READ_NIL, "In function parameter %s", varname);
}
void ThrowVMException(VMException *x)
{
throw x;
}

View file

@ -83,6 +83,7 @@ xx(MOVEA, mov, RPRP, NOP, 0, 0), // aA = aB
xx(MOVEV2, mov2, RFRF, NOP, 0, 0), // fA = fB (2 elements)
xx(MOVEV3, mov3, RFRF, NOP, 0, 0), // fA = fB (3 elements)
xx(CAST, cast, CAST, NOP, 0, 0), // xA = xB, conversion specified by C
xx(CASTB, castb, CAST, NOP, 0, 0), // xA = !!xB, type specified by C
// Control flow.
xx(TEST, test, RII16, NOP, 0, 0), // if (dA != BC) then pc++

View file

@ -140,6 +140,7 @@ external_declaration(X) ::= class_definition(A). { X = A; /*X-overwrites-A*
external_declaration(X) ::= struct_def(A). { X = A; /*X-overwrites-A*/ }
external_declaration(X) ::= enum_def(A). { X = A; /*X-overwrites-A*/ }
external_declaration(X) ::= const_def(A). { X = A; /*X-overwrites-A*/ }
external_declaration(X) ::= include_def. { X = nullptr; }
/* Optional bits. */
opt_semicolon ::= .
@ -156,6 +157,11 @@ opt_expr(X) ::= .
opt_expr(X) ::= expr(X).
include_def ::= INCLUDE string_constant(A).
{
AddInclude(A);
}
/************ Class Definition ************/
/* Can only occur at global scope. */

View file

@ -1842,7 +1842,7 @@ void ZCCCompiler::ProcessDefaultProperty(PClassActor *cls, ZCC_PropertyStmt *pro
if (namenode->Id == NAME_DamageFunction)
{
auto x = ConvertNode(prop->Values);
CreateDamageFunction(cls, (AActor *)bag.Info->Defaults, x, false);
CreateDamageFunction(cls, (AActor *)bag.Info->Defaults, x, false, Lump);
((AActor *)bag.Info->Defaults)->DamageVal = -1;
return;
}

View file

@ -44,7 +44,19 @@
#include "zcc_parser.h"
#include "zcc_compile.h"
TArray<FString> Includes;
TArray<FScriptPosition> IncludeLocs;
static FString ZCCTokenName(int terminal);
void AddInclude(ZCC_ExprConstant *node)
{
assert(node->Type == TypeString);
if (Includes.Find(*node->StringVal) >= Includes.Size())
{
Includes.Push(*node->StringVal);
IncludeLocs.Push(*node);
}
}
#include "zcc-parse.h"
#include "zcc-parse.c"
@ -152,6 +164,7 @@ static void InitTokenMap()
TOKENDEF2(TK_Name, ZCC_NAME, NAME_Name);
TOKENDEF2(TK_Map, ZCC_MAP, NAME_Map);
TOKENDEF2(TK_Array, ZCC_ARRAY, NAME_Array);
TOKENDEF2(TK_Include, ZCC_INCLUDE, NAME_Include);
TOKENDEF (TK_Void, ZCC_VOID);
TOKENDEF (TK_True, ZCC_TRUE);
TOKENDEF (TK_False, ZCC_FALSE);
@ -316,42 +329,24 @@ static void DoParse(int lumpnum)
sc.OpenLumpNum(lumpnum);
auto saved = sc.SavePos();
bool parsed = false;
if (sc.GetToken())
{
if (sc.TokenType == TK_Class || sc.TokenType == TK_Enum || sc.TokenType == TK_Struct || sc.TokenType == TK_Const || sc.TokenType == TK_Native)
{
if (sc.CheckToken(TK_Identifier))
{
// This looks like an actual definition file and not a file list.
ParseSingleFile(nullptr, lumpnum, parser, state);
parsed = true;
}
}
}
if (!parsed)
{
sc.RestorePos(saved);
// parse all files from this list in one go.
while (sc.GetString())
{
FixPathSeperator(sc.String);
if (Wads.GetLumpFile(sc.LumpNum) == 0)
{
int includefile = Wads.GetLumpFile(Wads.CheckNumForFullName(sc.String, true));
if (includefile != 0)
{
I_FatalError("File %s is overriding core lump %s.",
Wads.GetWadFullName(includefile), sc.String);
}
}
#ifndef NDEBUG
if (f) fprintf(f, "Starting parsing %s\n", sc.String);
#endif
ParseSingleFile(sc.String, 0, parser, state);
ParseSingleFile(nullptr, lumpnum, parser, state);
for (unsigned i = 0; i < Includes.Size(); i++)
{
lumpnum = Wads.CheckNumForFullName(Includes[i], true);
if (lumpnum == -1)
{
IncludeLocs[i].Message(MSG_ERROR, "Include script lump %s not found", Includes[i].GetChars());
}
else
{
ParseSingleFile(nullptr, lumpnum, parser, state);
}
}
Includes.Clear();
Includes.ShrinkToFit();
IncludeLocs.Clear();
IncludeLocs.ShrinkToFit();
value.Int = -1;
value.SourceLoc = sc.GetMessageLine();

View file

@ -182,7 +182,7 @@ void FTeam::ParseTeamDefinition (FScanner &Scan)
case TEAMINFO_PlayerColor:
Scan.MustGetString ();
Team.m_iPlayerColor = V_GetColor (NULL, Scan.String);
Team.m_iPlayerColor = V_GetColor (NULL, Scan);
break;
case TEAMINFO_TextColor:

View file

@ -1098,7 +1098,7 @@ void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part, TexInit &init)
if (!sc.CheckNumber())
{
sc.MustGetString();
part.Blend = V_GetColor(NULL, sc.String);
part.Blend = V_GetColor(NULL, sc);
}
else
{

View file

@ -211,6 +211,7 @@ FPNGTexture::FPNGTexture (FileReader &lump, int lumpnum, const FString &filename
int i;
if (lumpnum == -1) fr = &lump;
else fr = nullptr;
UseType = TEX_MiscPatch;
LeftOffset = 0;

View file

@ -2300,19 +2300,19 @@ void V_InitFontColors ()
else if (sc.Compare ("Flat:"))
{
sc.MustGetString();
logcolor = V_GetColor (NULL, sc.String);
logcolor = V_GetColor (NULL, sc);
}
else
{
// Get first color
c = V_GetColor (NULL, sc.String);
c = V_GetColor (NULL, sc);
tparm.Start[0] = RPART(c);
tparm.Start[1] = GPART(c);
tparm.Start[2] = BPART(c);
// Get second color
sc.MustGetString();
c = V_GetColor (NULL, sc.String);
c = V_GetColor (NULL, sc);
tparm.End[0] = RPART(c);
tparm.End[1] = GPART(c);
tparm.End[2] = BPART(c);

View file

@ -44,6 +44,7 @@
#include "i_video.h"
#include "v_video.h"
#include "v_text.h"
#include "sc_man.h"
#include "w_wad.h"
@ -437,7 +438,7 @@ void DCanvas::ReleaseScreenshotBuffer()
//
//==========================================================================
int V_GetColorFromString (const DWORD *palette, const char *cstr)
int V_GetColorFromString (const DWORD *palette, const char *cstr, FScriptPosition *sc)
{
int c[3], i, p;
char val[3];
@ -456,7 +457,7 @@ int V_GetColorFromString (const DWORD *palette, const char *cstr)
{
val[0] = cstr[1 + i*2];
val[1] = cstr[2 + i*2];
c[i] = ParseHex (val);
c[i] = ParseHex (val, sc);
}
}
else if (len == 4)
@ -465,7 +466,7 @@ int V_GetColorFromString (const DWORD *palette, const char *cstr)
for (i = 0; i < 3; ++i)
{
val[1] = val[0] = cstr[1 + i];
c[i] = ParseHex (val);
c[i] = ParseHex (val, sc);
}
}
else
@ -518,7 +519,7 @@ normal:
{
val[1] = val[0];
}
c[i] = ParseHex (val);
c[i] = ParseHex (val, sc);
}
}
}
@ -538,7 +539,7 @@ normal:
//
//==========================================================================
FString V_GetColorStringByName (const char *name)
FString V_GetColorStringByName (const char *name, FScriptPosition *sc)
{
FMemLump rgbNames;
char *rgbEnd;
@ -552,7 +553,8 @@ FString V_GetColorStringByName (const char *name)
rgblump = Wads.CheckNumForName ("X11R6RGB");
if (rgblump == -1)
{
Printf ("X11R6RGB lump not found\n");
if (!sc) Printf ("X11R6RGB lump not found\n");
else sc->Message(MSG_WARNING, "X11R6RGB lump not found");
return FString();
}
@ -614,7 +616,8 @@ FString V_GetColorStringByName (const char *name)
}
if (rgb < rgbEnd)
{
Printf ("X11R6RGB lump is corrupt\n");
if (!sc) Printf ("X11R6RGB lump is corrupt\n");
else sc->Message(MSG_WARNING, "X11R6RGB lump is corrupt");
}
return FString();
}
@ -627,22 +630,28 @@ FString V_GetColorStringByName (const char *name)
//
//==========================================================================
int V_GetColor (const DWORD *palette, const char *str)
int V_GetColor (const DWORD *palette, const char *str, FScriptPosition *sc)
{
FString string = V_GetColorStringByName (str);
FString string = V_GetColorStringByName (str, sc);
int res;
if (!string.IsEmpty())
{
res = V_GetColorFromString (palette, string);
res = V_GetColorFromString (palette, string, sc);
}
else
{
res = V_GetColorFromString (palette, str);
res = V_GetColorFromString (palette, str, sc);
}
return res;
}
int V_GetColor(const DWORD *palette, FScanner &sc)
{
FScriptPosition scc = sc;
return V_GetColor(palette, sc.String, &scc);
}
//==========================================================================
//
// BuildTransTable

View file

@ -497,15 +497,17 @@ void V_Shutdown ();
void V_MarkRect (int x, int y, int width, int height);
class FScanner;
// Returns the closest color to the one desired. String
// should be of the form "rr gg bb".
int V_GetColorFromString (const DWORD *palette, const char *colorstring);
int V_GetColorFromString (const DWORD *palette, const char *colorstring, FScriptPosition *sc = nullptr);
// Scans through the X11R6RGB lump for a matching color
// and returns a color string suitable for V_GetColorFromString.
FString V_GetColorStringByName (const char *name);
FString V_GetColorStringByName (const char *name, FScriptPosition *sc = nullptr);
// Tries to get color by name, then by string
int V_GetColor (const DWORD *palette, const char *str);
int V_GetColor (const DWORD *palette, const char *str, FScriptPosition *sc = nullptr);
int V_GetColor(const DWORD *palette, FScanner &sc);
void V_DrawFrame (int left, int top, int width, int height);
// If the view size is not full screen, draws a border around it.

View file

@ -298,17 +298,68 @@ protected:
friend struct FStringData;
public:
bool operator == (const FString &other) const
{
return Compare(other) == 0;
}
bool operator != (const FString &other) const
{
return Compare(other) != 0;
}
bool operator < (const FString &other) const
{
return Compare(other) < 0;
}
bool operator > (const FString &other) const
{
return Compare(other) > 0;
}
bool operator <= (const FString &other) const
{
return Compare(other) <= 0;
}
bool operator >= (const FString &other) const
{
return Compare(other) >= 0;
}
bool operator == (const char *) const = delete;
bool operator != (const char *) const = delete;
bool operator < (const char *) const = delete;
bool operator > (const char *) const = delete;
bool operator <= (const char *) const = delete;
bool operator >= (const char *) const = delete;
bool operator == (FName) const = delete;
bool operator != (FName) const = delete;
bool operator < (FName) const = delete;
bool operator > (FName) const = delete;
bool operator <= (FName) const = delete;
bool operator >= (FName) const = delete;
private:
// Prevent these from being called as current practices are to use Compare.
// Without this FStrings will be accidentally compared against char* ptrs.
bool operator == (const FString &illegal) const;
bool operator != (const FString &illegal) const;
bool operator < (const FString &illegal) const;
bool operator > (const FString &illegal) const;
bool operator <= (const FString &illegal) const;
bool operator >= (const FString &illegal) const;
};
bool operator == (const char *, const FString &) = delete;
bool operator != (const char *, const FString &) = delete;
bool operator < (const char *, const FString &) = delete;
bool operator > (const char *, const FString &) = delete;
bool operator <= (const char *, const FString &) = delete;
bool operator >= (const char *, const FString &) = delete;
bool operator == (FName, const FString &) = delete;
bool operator != (FName, const FString &) = delete;
bool operator < (FName, const FString &) = delete;
bool operator > (FName, const FString &) = delete;
bool operator <= (FName, const FString &) = delete;
bool operator >= (FName, const FString &) = delete;
class FStringf : public FString
{
public:

View file

@ -27,6 +27,7 @@
setwallyscale 717 front bot 1.090909
setslopeoverflow
polyobj
}
B2D8DA03489D1C67F60DC87FBC4EA338 // map01 - Massmouth 2

View file

@ -255,28 +255,24 @@ map E1M5 lookup "CHUSTR_E1M5"
cluster 1
{
flat = "FLOOR4_8"
music = "$MUSIC_VICTOR"
exittext = lookup, "CE1TEXT"
}
cluster 2
{
flat = "SFLR6_1"
music = "$MUSIC_VICTOR"
exittext = lookup, "CE2TEXT"
}
cluster 3
{
flat = "MFLR8_4"
music = "$MUSIC_VICTOR"
exittext = lookup, "CE3TEXT"
}
cluster 4
{
flat = "MFLR8_3"
music = "$MUSIC_VICTOR"
exittext = lookup, "CE4TEXT"
}

View file

@ -506,28 +506,24 @@ map E4M9 lookup "HUSTR_E4M9"
cluster 1
{
flat = "$bgflatE1"
music = "$MUSIC_VICTOR"
exittext = lookup, "E1TEXT"
}
cluster 2
{
flat = "$bgflatE2"
music = "$MUSIC_VICTOR"
exittext = lookup, "E2TEXT"
}
cluster 3
{
flat = "$bgflatE3"
music = "$MUSIC_VICTOR"
exittext = lookup, "E3TEXT"
}
cluster 4
{
flat = "$bgflatE4"
music = "$MUSIC_VICTOR"
exittext = lookup, "E4TEXT"
}

View file

@ -380,7 +380,6 @@ map MAP32 lookup "HUSTR_32"
cluster 5
{
flat = "$BGFLAT06"
music = "$MUSIC_READ_M"
exittext = lookup, "C1TEXT"
}
@ -390,7 +389,6 @@ cluster 5
cluster 6
{
flat = "$BGFLAT11"
music = "$MUSIC_READ_M"
exittext = lookup, "C2TEXT"
}
@ -400,7 +398,6 @@ cluster 6
cluster 7
{
flat = "$BGFLAT20"
music = "$MUSIC_READ_M"
exittext = lookup, "C3TEXT"
}
@ -409,7 +406,6 @@ cluster 7
cluster 8
{
flat = "$BGFLAT30"
music = "$MUSIC_READ_M"
exittext = lookup, "C4TEXT"
}
@ -418,7 +414,6 @@ cluster 8
cluster 9
{
flat = "$BGFLAT15"
music = "$MUSIC_READ_M"
entertext = lookup, "C5TEXT"
}
@ -427,7 +422,6 @@ cluster 9
cluster 10
{
flat = "$BGFLAT31"
music = "$MUSIC_READ_M"
entertext = lookup, "C6TEXT"
}
@ -537,7 +531,6 @@ map LEVEL09 lookup "NHUSTR_9"
cluster 11
{
flat = "SLIME16"
music = "$MUSIC_READ_M"
exittext = lookup, "NERVETEXT"
}

View file

@ -805,35 +805,30 @@ map E6M3 "Untitled"
cluster 1
{
flat = "FLOOR25"
music = "MUS_CPTD"
exittext = lookup, "HE1TEXT"
}
cluster 2
{
flat = "FLATHUH1"
music = "MUS_CPTD"
exittext = lookup, "HE2TEXT"
}
cluster 3
{
flat = "FLTWAWA2"
music = "MUS_CPTD"
exittext = lookup, "HE3TEXT"
}
cluster 4
{
flat = "FLOOR28"
music = "MUS_CPTD"
exittext = lookup, "HE4TEXT"
}
cluster 5
{
flat = "FLOOR08"
music = "MUS_CPTD"
exittext = lookup, "HE5TEXT"
}

View file

@ -464,7 +464,6 @@ cluster 1
hub
exittext = "clus1msg"
exittextislump
music = "hub"
pic = "interpic"
}
@ -473,7 +472,6 @@ cluster 2
hub
exittext = "clus2msg"
exittextislump
music = "hub"
pic = "interpic"
}
@ -482,7 +480,6 @@ cluster 3
hub
exittext = "clus3msg"
exittextislump
music = "hub"
pic = "interpic"
}
@ -491,7 +488,6 @@ cluster 4
hub
exittext = "clus4msg"
exittextislump
music = "hub"
pic = "interpic"
}

View file

@ -374,7 +374,6 @@ map MAP32 lookup "PHUSTR_32"
cluster 5
{
flat = "$BGFLAT06"
music = "$MUSIC_READ_M"
exittext = lookup, "P1TEXT"
}
@ -383,7 +382,6 @@ cluster 5
cluster 6
{
flat = "$BGFLAT11"
music = "$MUSIC_READ_M"
exittext = lookup, "P2TEXT"
}
@ -392,7 +390,6 @@ cluster 6
cluster 7
{
flat = "$BGFLAT20"
music = "$MUSIC_READ_M"
exittext = lookup, "P3TEXT"
}
@ -401,7 +398,6 @@ cluster 7
cluster 8
{
flat = "$BGFLAT30"
music = "$MUSIC_READ_M"
exittext = lookup, "P4TEXT"
}
@ -410,7 +406,6 @@ cluster 8
cluster 9
{
flat = "$BGFLAT15"
music = "$MUSIC_READ_M"
entertext = lookup, "P5TEXT"
}
@ -419,7 +414,6 @@ cluster 9
cluster 10
{
flat = "$BGFLAT31"
music = "$MUSIC_READ_M"
entertext = lookup, "P6TEXT"
}

View file

@ -374,7 +374,6 @@ map MAP32 lookup "THUSTR_32"
cluster 5
{
flat = "$BGFLAT06"
music = "$MUSIC_READ_M"
exittext = lookup, "T1TEXT"
}
@ -383,7 +382,6 @@ cluster 5
cluster 6
{
flat = "$BGFLAT11"
music = "$MUSIC_READ_M"
exittext = lookup, "T2TEXT"
}
@ -392,7 +390,6 @@ cluster 6
cluster 7
{
flat = "$BGFLAT20"
music = "$MUSIC_READ_M"
exittext = lookup, "T3TEXT"
}
@ -401,7 +398,6 @@ cluster 7
cluster 8
{
flat = "$BGFLAT30"
music = "$MUSIC_READ_M"
exittext = lookup, "T4TEXT"
}
@ -410,7 +406,6 @@ cluster 8
cluster 9
{
flat = "$BGFLAT15"
music = "$MUSIC_READ_M"
entertext = lookup, "T5TEXT"
}
@ -419,6 +414,5 @@ cluster 9
cluster 10
{
flat = "$BGFLAT31"
music = "$MUSIC_READ_M"
entertext = lookup, "T6TEXT"
}

View file

@ -1,212 +1,212 @@
zscript/base.txt
zscript/constants.txt
zscript/actor.txt
zscript/actor_checks.txt
#include "zscript/base.txt"
#include "zscript/constants.txt"
#include "zscript/actor.txt"
#include "zscript/actor_checks.txt"
zscript/shared/inventory.txt
zscript/shared/inv_misc.txt
zscript/shared/weapons.txt
zscript/shared/armor.txt
zscript/shared/powerups.txt
zscript/shared/player.txt
zscript/shared/morph.txt
zscript/shared/botstuff.txt
zscript/shared/sharedmisc.txt
zscript/shared/blood.txt
zscript/shared/debris.txt
zscript/shared/decal.txt
zscript/shared/splashes.txt
zscript/shared/itemeffects.txt
zscript/shared/fountain.txt
zscript/shared/spark.txt
zscript/shared/soundsequence.txt
zscript/shared/soundenvironment.txt
zscript/shared/bridge.txt
zscript/shared/specialspot.txt
zscript/shared/teleport.txt
zscript/shared/camera.txt
zscript/shared/movingcamera.txt
zscript/shared/mapmarker.txt
zscript/shared/waterzone.txt
zscript/shared/skies.txt
zscript/shared/hatetarget.txt
zscript/shared/secrettrigger.txt
zscript/shared/setcolor.txt
zscript/shared/sectoraction.txt
zscript/shared/ice.txt
zscript/shared/dog.txt
zscript/shared/fastprojectile.txt
zscript/shared/dynlights.txt
#include "zscript/shared/inventory.txt"
#include "zscript/shared/inv_misc.txt"
#include "zscript/shared/weapons.txt"
#include "zscript/shared/armor.txt"
#include "zscript/shared/powerups.txt"
#include "zscript/shared/player.txt"
#include "zscript/shared/morph.txt"
#include "zscript/shared/botstuff.txt"
#include "zscript/shared/sharedmisc.txt"
#include "zscript/shared/blood.txt"
#include "zscript/shared/debris.txt"
#include "zscript/shared/decal.txt"
#include "zscript/shared/splashes.txt"
#include "zscript/shared/itemeffects.txt"
#include "zscript/shared/fountain.txt"
#include "zscript/shared/spark.txt"
#include "zscript/shared/soundsequence.txt"
#include "zscript/shared/soundenvironment.txt"
#include "zscript/shared/bridge.txt"
#include "zscript/shared/specialspot.txt"
#include "zscript/shared/teleport.txt"
#include "zscript/shared/camera.txt"
#include "zscript/shared/movingcamera.txt"
#include "zscript/shared/mapmarker.txt"
#include "zscript/shared/waterzone.txt"
#include "zscript/shared/skies.txt"
#include "zscript/shared/hatetarget.txt"
#include "zscript/shared/secrettrigger.txt"
#include "zscript/shared/setcolor.txt"
#include "zscript/shared/sectoraction.txt"
#include "zscript/shared/ice.txt"
#include "zscript/shared/dog.txt"
#include "zscript/shared/fastprojectile.txt"
#include "zscript/shared/dynlights.txt"
zscript/doom/doomplayer.txt
zscript/doom/possessed.txt
zscript/doom/doomimp.txt
zscript/doom/demon.txt
zscript/doom/lostsoul.txt
zscript/doom/cacodemon.txt
zscript/doom/bruiser.txt
zscript/doom/revenant.txt
zscript/doom/arachnotron.txt
zscript/doom/fatso.txt
zscript/doom/painelemental.txt
zscript/doom/archvile.txt
zscript/doom/cyberdemon.txt
zscript/doom/spidermaster.txt
zscript/doom/keen.txt
zscript/doom/bossbrain.txt
zscript/doom/weaponfist.txt
zscript/doom/weaponpistol.txt
zscript/doom/weaponshotgun.txt
zscript/doom/weaponssg.txt
zscript/doom/weaponchaingun.txt
zscript/doom/weaponchainsaw.txt
zscript/doom/weaponrlaunch.txt
zscript/doom/weaponplasma.txt
zscript/doom/weaponbfg.txt
#include "zscript/doom/doomplayer.txt"
#include "zscript/doom/possessed.txt"
#include "zscript/doom/doomimp.txt"
#include "zscript/doom/demon.txt"
#include "zscript/doom/lostsoul.txt"
#include "zscript/doom/cacodemon.txt"
#include "zscript/doom/bruiser.txt"
#include "zscript/doom/revenant.txt"
#include "zscript/doom/arachnotron.txt"
#include "zscript/doom/fatso.txt"
#include "zscript/doom/painelemental.txt"
#include "zscript/doom/archvile.txt"
#include "zscript/doom/cyberdemon.txt"
#include "zscript/doom/spidermaster.txt"
#include "zscript/doom/keen.txt"
#include "zscript/doom/bossbrain.txt"
#include "zscript/doom/weaponfist.txt"
#include "zscript/doom/weaponpistol.txt"
#include "zscript/doom/weaponshotgun.txt"
#include "zscript/doom/weaponssg.txt"
#include "zscript/doom/weaponchaingun.txt"
#include "zscript/doom/weaponchainsaw.txt"
#include "zscript/doom/weaponrlaunch.txt"
#include "zscript/doom/weaponplasma.txt"
#include "zscript/doom/weaponbfg.txt"
zscript/doom/deadthings.txt
zscript/doom/doomammo.txt
zscript/doom/doomarmor.txt
zscript/doom/doomartifacts.txt
zscript/doom/doomhealth.txt
zscript/doom/doomkeys.txt
zscript/doom/doommisc.txt
zscript/doom/doomdecorations.txt
zscript/doom/doomweapons.txt
zscript/doom/stealthmonsters.txt
zscript/doom/scriptedmarine.txt
#include "zscript/doom/deadthings.txt"
#include "zscript/doom/doomammo.txt"
#include "zscript/doom/doomarmor.txt"
#include "zscript/doom/doomartifacts.txt"
#include "zscript/doom/doomhealth.txt"
#include "zscript/doom/doomkeys.txt"
#include "zscript/doom/doommisc.txt"
#include "zscript/doom/doomdecorations.txt"
#include "zscript/doom/doomweapons.txt"
#include "zscript/doom/stealthmonsters.txt"
#include "zscript/doom/scriptedmarine.txt"
zscript/raven/artiegg.txt
zscript/raven/artitele.txt
zscript/raven/ravenartifacts.txt
zscript/raven/ravenhealth.txt
zscript/raven/ravenambient.txt
zscript/raven/minotaur.txt
#include "zscript/raven/artiegg.txt"
#include "zscript/raven/artitele.txt"
#include "zscript/raven/ravenartifacts.txt"
#include "zscript/raven/ravenhealth.txt"
#include "zscript/raven/ravenambient.txt"
#include "zscript/raven/minotaur.txt"
zscript/heretic/hereticplayer.txt
zscript/heretic/hereticammo.txt
zscript/heretic/hereticarmor.txt
zscript/heretic/hereticartifacts.txt
zscript/heretic/heretickeys.txt
zscript/heretic/hereticdecorations.txt
zscript/heretic/hereticmisc.txt
zscript/heretic/mummy.txt
zscript/heretic/clink.txt
zscript/heretic/beast.txt
zscript/heretic/snake.txt
zscript/heretic/hereticimp.txt
zscript/heretic/knight.txt
zscript/heretic/wizard.txt
zscript/heretic/ironlich.txt
zscript/heretic/dsparil.txt
zscript/heretic/chicken.txt
zscript/heretic/weaponstaff.txt
zscript/heretic/weaponwand.txt
zscript/heretic/weaponcrossbow.txt
zscript/heretic/weapongauntlets.txt
zscript/heretic/weaponmace.txt
zscript/heretic/weaponblaster.txt
zscript/heretic/weaponskullrod.txt
zscript/heretic/weaponphoenix.txt
#include "zscript/heretic/hereticplayer.txt"
#include "zscript/heretic/hereticammo.txt"
#include "zscript/heretic/hereticarmor.txt"
#include "zscript/heretic/hereticartifacts.txt"
#include "zscript/heretic/heretickeys.txt"
#include "zscript/heretic/hereticdecorations.txt"
#include "zscript/heretic/hereticmisc.txt"
#include "zscript/heretic/mummy.txt"
#include "zscript/heretic/clink.txt"
#include "zscript/heretic/beast.txt"
#include "zscript/heretic/snake.txt"
#include "zscript/heretic/hereticimp.txt"
#include "zscript/heretic/knight.txt"
#include "zscript/heretic/wizard.txt"
#include "zscript/heretic/ironlich.txt"
#include "zscript/heretic/dsparil.txt"
#include "zscript/heretic/chicken.txt"
#include "zscript/heretic/weaponstaff.txt"
#include "zscript/heretic/weaponwand.txt"
#include "zscript/heretic/weaponcrossbow.txt"
#include "zscript/heretic/weapongauntlets.txt"
#include "zscript/heretic/weaponmace.txt"
#include "zscript/heretic/weaponblaster.txt"
#include "zscript/heretic/weaponskullrod.txt"
#include "zscript/heretic/weaponphoenix.txt"
zscript/hexen/baseweapons.txt
zscript/hexen/korax.txt
zscript/hexen/fighterplayer.txt
zscript/hexen/clericplayer.txt
zscript/hexen/mageplayer.txt
zscript/hexen/pig.txt
zscript/hexen/flame.txt
zscript/hexen/flies.txt
zscript/hexen/hexenarmor.txt
zscript/hexen/hexendecorations.txt
zscript/hexen/hexenkeys.txt
zscript/hexen/hexenspecialdecs.txt
zscript/hexen/mana.txt
zscript/hexen/puzzleitems.txt
zscript/hexen/scriptprojectiles.txt
zscript/hexen/speedboots.txt
zscript/hexen/ettin.txt
zscript/hexen/centaur.txt
zscript/hexen/demons.txt
zscript/hexen/firedemon.txt
zscript/hexen/fog.txt
zscript/hexen/summon.txt
zscript/hexen/flechette.txt
zscript/hexen/clericboss.txt
zscript/hexen/fighterboss.txt
zscript/hexen/mageboss.txt
zscript/hexen/bats.txt
zscript/hexen/bishop.txt
zscript/hexen/blastradius.txt
zscript/hexen/boostarmor.txt
zscript/hexen/clericmace.txt
zscript/hexen/clericflame.txt
zscript/hexen/clericholy.txt
zscript/hexen/clericstaff.txt
zscript/hexen/magewand.txt
zscript/hexen/magecone.txt
zscript/hexen/magelightning.txt
zscript/hexen/magestaff.txt
zscript/hexen/fighterfist.txt
zscript/hexen/fighteraxe.txt
zscript/hexen/fighterhammer.txt
zscript/hexen/fighterquietus.txt
zscript/hexen/dragon.txt
zscript/hexen/healingradius.txt
zscript/hexen/teleportother.txt
zscript/hexen/iceguy.txt
zscript/hexen/serpent.txt
zscript/hexen/spike.txt
zscript/hexen/wraith.txt
zscript/hexen/heresiarch.txt
#include "zscript/hexen/baseweapons.txt"
#include "zscript/hexen/korax.txt"
#include "zscript/hexen/fighterplayer.txt"
#include "zscript/hexen/clericplayer.txt"
#include "zscript/hexen/mageplayer.txt"
#include "zscript/hexen/pig.txt"
#include "zscript/hexen/flame.txt"
#include "zscript/hexen/flies.txt"
#include "zscript/hexen/hexenarmor.txt"
#include "zscript/hexen/hexendecorations.txt"
#include "zscript/hexen/hexenkeys.txt"
#include "zscript/hexen/hexenspecialdecs.txt"
#include "zscript/hexen/mana.txt"
#include "zscript/hexen/puzzleitems.txt"
#include "zscript/hexen/scriptprojectiles.txt"
#include "zscript/hexen/speedboots.txt"
#include "zscript/hexen/ettin.txt"
#include "zscript/hexen/centaur.txt"
#include "zscript/hexen/demons.txt"
#include "zscript/hexen/firedemon.txt"
#include "zscript/hexen/fog.txt"
#include "zscript/hexen/summon.txt"
#include "zscript/hexen/flechette.txt"
#include "zscript/hexen/clericboss.txt"
#include "zscript/hexen/fighterboss.txt"
#include "zscript/hexen/mageboss.txt"
#include "zscript/hexen/bats.txt"
#include "zscript/hexen/bishop.txt"
#include "zscript/hexen/blastradius.txt"
#include "zscript/hexen/boostarmor.txt"
#include "zscript/hexen/clericmace.txt"
#include "zscript/hexen/clericflame.txt"
#include "zscript/hexen/clericholy.txt"
#include "zscript/hexen/clericstaff.txt"
#include "zscript/hexen/magewand.txt"
#include "zscript/hexen/magecone.txt"
#include "zscript/hexen/magelightning.txt"
#include "zscript/hexen/magestaff.txt"
#include "zscript/hexen/fighterfist.txt"
#include "zscript/hexen/fighteraxe.txt"
#include "zscript/hexen/fighterhammer.txt"
#include "zscript/hexen/fighterquietus.txt"
#include "zscript/hexen/dragon.txt"
#include "zscript/hexen/healingradius.txt"
#include "zscript/hexen/teleportother.txt"
#include "zscript/hexen/iceguy.txt"
#include "zscript/hexen/serpent.txt"
#include "zscript/hexen/spike.txt"
#include "zscript/hexen/wraith.txt"
#include "zscript/hexen/heresiarch.txt"
zscript/strife/strifehumanoid.txt
zscript/strife/strifeplayer.txt
zscript/strife/strifeweapons.txt
zscript/strife/spectral.txt
zscript/strife/acolyte.txt
zscript/strife/alienspectres.txt
zscript/strife/beggars.txt
zscript/strife/coin.txt
zscript/strife/crusader.txt
zscript/strife/entityboss.txt
zscript/strife/inquisitor.txt
zscript/strife/klaxon.txt
zscript/strife/loremaster.txt
zscript/strife/macil.txt
zscript/strife/merchants.txt
zscript/strife/peasants.txt
zscript/strife/strifebishop.txt
zscript/strife/oracle.txt
zscript/strife/programmer.txt
zscript/strife/questitems.txt
zscript/strife/ratbuddy.txt
zscript/strife/rebels.txt
zscript/strife/reaver.txt
zscript/strife/sentinel.txt
zscript/strife/stalker.txt
zscript/strife/strifeammo.txt
zscript/strife/strifearmor.txt
zscript/strife/strifefunctions.txt
zscript/strife/strifeitems.txt
zscript/strife/strifekeys.txt
zscript/strife/strifestuff.txt
zscript/strife/thingstoblowup.txt
zscript/strife/templar.txt
zscript/strife/zombie.txt
zscript/strife/weapondagger.txt
zscript/strife/weaponcrossbow.txt
zscript/strife/weaponassault.txt
zscript/strife/weaponmissile.txt
zscript/strife/weaponflamer.txt
zscript/strife/weapongrenade.txt
zscript/strife/weaponmauler.txt
zscript/strife/sigil.txt
#include "zscript/strife/strifehumanoid.txt"
#include "zscript/strife/strifeplayer.txt"
#include "zscript/strife/strifeweapons.txt"
#include "zscript/strife/spectral.txt"
#include "zscript/strife/acolyte.txt"
#include "zscript/strife/alienspectres.txt"
#include "zscript/strife/beggars.txt"
#include "zscript/strife/coin.txt"
#include "zscript/strife/crusader.txt"
#include "zscript/strife/entityboss.txt"
#include "zscript/strife/inquisitor.txt"
#include "zscript/strife/klaxon.txt"
#include "zscript/strife/loremaster.txt"
#include "zscript/strife/macil.txt"
#include "zscript/strife/merchants.txt"
#include "zscript/strife/peasants.txt"
#include "zscript/strife/strifebishop.txt"
#include "zscript/strife/oracle.txt"
#include "zscript/strife/programmer.txt"
#include "zscript/strife/questitems.txt"
#include "zscript/strife/ratbuddy.txt"
#include "zscript/strife/rebels.txt"
#include "zscript/strife/reaver.txt"
#include "zscript/strife/sentinel.txt"
#include "zscript/strife/stalker.txt"
#include "zscript/strife/strifeammo.txt"
#include "zscript/strife/strifearmor.txt"
#include "zscript/strife/strifefunctions.txt"
#include "zscript/strife/strifeitems.txt"
#include "zscript/strife/strifekeys.txt"
#include "zscript/strife/strifestuff.txt"
#include "zscript/strife/thingstoblowup.txt"
#include "zscript/strife/templar.txt"
#include "zscript/strife/zombie.txt"
#include "zscript/strife/weapondagger.txt"
#include "zscript/strife/weaponcrossbow.txt"
#include "zscript/strife/weaponassault.txt"
#include "zscript/strife/weaponmissile.txt"
#include "zscript/strife/weaponflamer.txt"
#include "zscript/strife/weapongrenade.txt"
#include "zscript/strife/weaponmauler.txt"
#include "zscript/strife/sigil.txt"
zscript/chex/chexmonsters.txt
zscript/chex/chexkeys.txt
zscript/chex/chexammo.txt
zscript/chex/chexweapons.txt
zscript/chex/chexitems.txt
zscript/chex/chexdecorations.txt
zscript/chex/chexplayer.txt
#include "zscript/chex/chexmonsters.txt"
#include "zscript/chex/chexkeys.txt"
#include "zscript/chex/chexammo.txt"
#include "zscript/chex/chexweapons.txt"
#include "zscript/chex/chexitems.txt"
#include "zscript/chex/chexdecorations.txt"
#include "zscript/chex/chexplayer.txt"

View file

@ -303,7 +303,6 @@ class Actor : Thinker native
native void DaggerAlert(Actor target);
native void ClearBounce();
native TerrainDef GetFloorTerrain();
native Inventory DoDropItem(Class<Actor> type, int dropamount, int chance);
native bool CheckLocalView(int consoleplayer);
native void ExplodeMissile(line lin = null, Actor target = null);

View file

@ -368,6 +368,9 @@ enum EActivationFlags
THINGSPEC_ClearSpecial = 32,
THINGSPEC_NoDeathSpecial = 64,
THINGSPEC_TriggerActs = 128,
THINGSPEC_Activate = 1<<8, // The thing is activated when triggered
THINGSPEC_Deactivate = 1<<9, // The thing is deactivated when triggered
THINGSPEC_Switch = 1<<10, // The thing is alternatively activated and deactivated when triggered
// Shorter aliases for same
AF_Default = 0,
@ -379,6 +382,9 @@ enum EActivationFlags
AF_ClearSpecial = 32,
AF_NoDeathSpecial = 64,
AF_TriggerActs = 128,
AF_Activate = 1<<8, // The thing is activated when triggered
AF_Deactivate = 1<<9, // The thing is deactivated when triggered
AF_Switch = 1<<10, // The thing is alternatively activated and deactivated when triggered
};

View file

@ -59,7 +59,7 @@ class GoldWand : HereticWeapon
return;
}
double pitch = BulletSlope();
int damage = 7 + random[FireGoldWand]() & 7;
int damage = 7 + (random[FireGoldWand]() & 7);
double ang = angle;
if (player.refire)
{

View file

@ -583,7 +583,6 @@ class SorcBall1 : SorcBall
{
Super.BeginPlay ();
AngleOffset = Heresiarch.BALL1_ANGLEOFFSET;
A_Log("Ball1 begins " .. AngleOffset);
}
//============================================================================
@ -683,7 +682,6 @@ class SorcBall2 : SorcBall
{
Super.BeginPlay ();
AngleOffset = Heresiarch.BALL2_ANGLEOFFSET;
A_Log("Ball2 begins " .. AngleOffset);
}
//============================================================================
@ -733,7 +731,6 @@ class SorcBall3 : SorcBall
{
Super.BeginPlay ();
AngleOffset = Heresiarch.BALL3_ANGLEOFFSET;
A_Log("Ball3 begins " .. AngleOffset);
}
//============================================================================

View file

@ -13,7 +13,7 @@ class SoundWind : Actor
States
{
Spawn:
TNT1 A 2 A_PlaySound("world/wind", CHAN_6);
TNT1 A 2 A_PlaySound("world/wind", CHAN_6, 1, true);
Loop;
}
}
@ -36,7 +36,7 @@ class SoundWaterfall : Actor
States
{
Spawn:
TNT1 A 2 A_PlaySound("world/waterfall", CHAN_6);
TNT1 A 2 A_PlaySound("world/waterfall", CHAN_6, 1, true);
Loop;
}
}

View file

@ -21,12 +21,24 @@ class IceChunk : Actor
+NOBLOCKMAP
+MOVEWITHSECTOR
}
native void A_IceSetTics ();
void A_IceSetTics ()
{
tics = 70 + (random[IceTics]() & 63);
Name dtype = GetFloorTerrain().DamageMOD;
if (dtype == 'Fire')
{
tics >>= 2;
}
else if (dtype == 'Ice')
{
tics <<= 1;
}
}
States
{
Spawn:
ICEC A 1;
ICEC ABCD 10 A_IceSetTics;
Stop;
}

View file

@ -1864,7 +1864,7 @@ class PowerCoupling : Actor
players[i].mo.GiveInventoryType ("QuestItem6");
S_Sound ("svox/voc13", CHAN_VOICE);
players[i].SetLogNumber (13);
DoDropItem ("BrokenPowerCoupling", -1, 256);
A_DropItem ("BrokenPowerCoupling", -1, 256);
Destroy ();
}