gzdoom/src/fragglescript/t_script.h

698 lines
18 KiB
C++

// Emacs style mode select -*- C++ -*-
//----------------------------------------------------------------------------
//
// Copyright(C) 2000 Simon Howard
// Copyright(C) 2002-2008 Christoph Oelckers
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
//---------------------------------------------------------------------------
//
// FraggleScript is from SMMU which is under the GPL. Technically,
// therefore, combining the FraggleScript code with the non-free
// ZDoom code is a violation of the GPL.
//
// As this may be a problem for you, I hereby grant an exception to my
// copyright on the SMMU source (including FraggleScript). You may use
// any code from SMMU in (G)ZDoom, provided that:
//
// * For any binary release of the port, the source code is also made
// available.
// * The copyright notice is kept on any file containing my code.
//
//
#ifndef __T_SCRIPT_H__
#define __T_SCRIPT_H__
#include "p_setup.h"
#include "p_lnspec.h"
#include "m_fixed.h"
#include "actor.h"
#ifdef _MSC_VER
// This pragma saves 8kb of wasted code.
#pragma pointers_to_members( full_generality, single_inheritance )
#endif
class DRunningScript;
inline bool isop(int c)
{
return !( ( (c)<='Z' && (c)>='A') || ( (c)<='z' && (c)>='a') ||
( (c)<='9' && (c)>='0') || ( (c)=='_') );
}
//==========================================================================
//
//
//
//==========================================================================
enum
{
svt_string,
svt_int,
svt_mobj, // a map object
svt_function, // functions are stored as variables
svt_label, // labels for goto calls are variables
svt_const, // const
svt_fixed, // haleyjd: fixed-point int - 8-17 std
svt_pInt, // pointer to game int
svt_pMobj, // pointer to game mobj
svt_linespec, // line special (can be used as both function and constant)
};
//==========================================================================
//
//
//
//==========================================================================
struct svalue_t
{
int type;
FString string;
union
{
int i;
fixed_t f; // haleyjd: 8-17
AActor *mobj;
} value;
svalue_t()
{
type = svt_int;
value.i = 0;
}
svalue_t(const svalue_t & other)
{
type = other.type;
string = other.string;
value = other.value;
}
};
int intvalue(const svalue_t & v);
fixed_t fixedvalue(const svalue_t & v);
double floatvalue(const svalue_t & v);
const char *stringvalue(const svalue_t & v);
AActor *actorvalue(const svalue_t &svalue);
//==========================================================================
//
// varoius defines collected in a nicer manner
//
//==========================================================================
enum
{
VARIABLESLOTS = 16,
SECTIONSLOTS = 17,
T_MAXTOKENS = 256,
TOKENLENGTH = 128,
MAXARGS = 128,
MAXSCRIPTS = 257,
};
//==========================================================================
//
// One variable
//
//==========================================================================
struct FParser;
struct DFsVariable : public DObject
{
DECLARE_CLASS(DFsVariable, DObject)
HAS_OBJECT_POINTERS
public:
FString Name;
TObjPtr<DFsVariable> next; // for hashing
int type; // svt_string or svt_int: same as in svalue_t
FString string;
TObjPtr<AActor> actor;
union value_t
{
SDWORD i;
fixed_t fixed; // haleyjd: fixed-point
// the following are only used in the global script so we don't need to bother with them
// when serializing variables.
int *pI; // pointer to game int
AActor **pMobj; // pointer to game obj
void (FParser::*handler)(); // for functions
const FLineSpecial *ls;
} value;
public:
DFsVariable(const char *_name = "");
void GetValue(svalue_t &result);
void SetValue(const svalue_t &newvalue);
void Serialize(FArchive &ar);
};
//==========================================================================
//
// hash the variables for speed: this is the hashkey
//
//==========================================================================
inline int variable_hash(const char *n)
{
return
(n[0]? ( ( n[0] + n[1] +
(n[1] ? n[2] +
(n[2] ? n[3] : 0) : 0) ) % VARIABLESLOTS ) :0);
}
//==========================================================================
//
// Sections
//
//==========================================================================
enum // section types
{
st_empty, // empty {} braces
st_if,
st_elseif,
st_else,
st_loop,
};
struct DFsSection : public DObject
{
DECLARE_CLASS(DFsSection, DObject)
HAS_OBJECT_POINTERS
public:
int type;
int start_index;
int end_index;
int loop_index;
TObjPtr<DFsSection> next; // for hashing
DFsSection()
{
next = NULL;
}
void Serialize(FArchive &ar);
};
//==========================================================================
//
// Tokens
//
//==========================================================================
enum tokentype_t
{
name_, // a name, eg 'count1' or 'frag'
number,
operator_,
string_,
unset,
function // function name
};
enum // brace types: where current_section is a { or }
{
bracket_open,
bracket_close
};
//==========================================================================
//
// Errors
//
//==========================================================================
class CFsError
{
public:
// trying to throw strings crashes VC++ badly so we have to use a static buffer. :(
char msg[2048];
CFsError(const FString &in)
{
strncpy(msg, in, 2047);
msg[2047]=0;
}
};
// throw this object to regularly terminate a script's execution.
class CFsTerminator
{
int fill;
};
//==========================================================================
//
// Scripts
//
//==========================================================================
class DFsScript : public DObject
{
DECLARE_CLASS(DFsScript, DObject)
HAS_OBJECT_POINTERS
public:
// script data
char *data;
int scriptnum; // this script's number
int len;
// {} sections
TObjPtr<DFsSection> sections[SECTIONSLOTS];
// variables:
TObjPtr<DFsVariable> variables[VARIABLESLOTS];
// ptr to the parent script
// the parent script is the script above this level
// eg. individual linetrigger scripts are children
// of the levelscript, which is a child of the
// global_script
TObjPtr<DFsScript> parent;
// haleyjd: 8-17
// child scripts.
// levelscript holds ptrs to all of the level's scripts
// here.
TObjPtr<DFsScript> children[MAXSCRIPTS];
TObjPtr<AActor> trigger; // object which triggered this script
bool lastiftrue; // haleyjd: whether last "if" statement was
// true or false
DFsScript();
void Destroy();
void Serialize(FArchive &ar);
DFsVariable *NewVariable(const char *name, int vtype);
void NewFunction(const char *name, void (FParser::*handler)());
DFsVariable *VariableForName(const char *name);
DFsVariable *FindVariable(const char *name);
void ClearVariables(bool complete= false);
DFsVariable *NewLabel(char *labelptr);
char *LabelValue(const svalue_t &v);
char *SectionStart(const DFsSection *sec);
char *SectionEnd(const DFsSection *sec);
char *SectionLoop(const DFsSection *sec);
void ClearSections();
void ClearChildren();
int MakeIndex(const char *p) { return int(p-data); }
// preprocessor
int section_hash(const char *b) { return MakeIndex(b) % SECTIONSLOTS; }
DFsSection *NewSection(const char *brace);
DFsSection *FindSectionStart(const char *brace);
DFsSection *FindSectionEnd(const char *brace);
char *ProcessFindChar(char *data, char find);
void DryRunScript();
void Preprocess();
void ParseInclude(char *lumpname);
void ParseScript(char *rover = NULL);
void ParseData(char *rover, char *data, char *end);
};
//==========================================================================
//
// The script parser
//
//==========================================================================
struct FParser
{
struct operator_t
{
const char *string;
void (FParser::*handler)(svalue_t &, int, int, int); // left, mid, right
int direction;
};
enum
{
forward,
backward
};
static operator_t operators[];
static int num_operators;
char *LineStart;
char *Rover;
char *Tokens[T_MAXTOKENS];
tokentype_t TokenType[T_MAXTOKENS];
int NumTokens;
DFsScript *Script; // the current script
DFsSection *Section;
DFsSection *PrevSection;
int BraceType;
int t_argc; // number of arguments
svalue_t *t_argv; // arguments
svalue_t t_return; // returned value
FString t_func; // name of current function
FParser(DFsScript *scr)
{
LineStart = NULL;
Rover = NULL;
Tokens[0] = new char[scr->len+32]; // 32 for safety. FS seems to need a few bytes more than the script's actual length.
NumTokens = 0;
Script = scr;
Section = PrevSection = NULL;
BraceType = 0;
}
~FParser()
{
if (Tokens[0]) delete [] Tokens[0];
}
void NextToken();
char *GetTokens(char *s);
void PrintTokens();
void ErrorMessage(FString msg);
void Run(char *rover, char *data, char *end);
void RunStatement();
int FindOperator(int start, int stop, const char *value);
int FindOperatorBackwards(int start, int stop, const char *value);
void SimpleEvaluate(svalue_t &, int n);
void PointlessBrackets(int *start, int *stop);
void EvaluateExpression(svalue_t &, int start, int stop);
void EvaluateFunction(svalue_t &, int start, int stop);
void OPequals(svalue_t &, int, int, int); // =
void OPplus(svalue_t &, int, int, int); // +
void OPminus(svalue_t &, int, int, int); // -
void OPmultiply(svalue_t &, int, int, int); // *
void OPdivide(svalue_t &, int, int, int); // /
void OPremainder(svalue_t &, int, int, int); // %
void OPor(svalue_t &, int, int, int); // ||
void OPand(svalue_t &, int, int, int); // &&
void OPnot(svalue_t &, int, int, int); // !
void OPor_bin(svalue_t &, int, int, int); // |
void OPand_bin(svalue_t &, int, int, int); // &
void OPnot_bin(svalue_t &, int, int, int); // ~
void OPcmp(svalue_t &, int, int, int); // ==
void OPnotcmp(svalue_t &, int, int, int); // !=
void OPlessthan(svalue_t &, int, int, int); // <
void OPgreaterthan(svalue_t &, int, int, int); // >
void OPincrement(svalue_t &, int, int, int); // ++
void OPdecrement(svalue_t &, int, int, int); // --
void OPstructure(svalue_t &, int, int, int); // in t_vari.c
void OPlessthanorequal(svalue_t &, int, int, int); // <=
void OPgreaterthanorequal(svalue_t &, int, int, int); // >=
void spec_brace();
bool spec_if();
bool spec_elseif(bool lastif);
void spec_else(bool lastif);
void spec_for();
void spec_while();
void CreateVariable(int newvar_type, DFsScript *newvar_script, int start, int stop);
void ParseVarLine(int newvar_type, DFsScript *newvar_script, int start);
bool spec_variable();
void spec_script();
DFsSection *looping_section();
FString GetFormatString(int startarg);
bool CheckArgs(int cnt);
void SF_Print();
void SF_Rnd();
void SF_Continue();
void SF_Break();
void SF_Goto();
void SF_Return();
void SF_Include();
void SF_Input();
void SF_Beep();
void SF_Clock();
void SF_ExitLevel();
void SF_Tip();
void SF_TimedTip();
void SF_PlayerTip();
void SF_Message();
void SF_PlayerMsg();
void SF_PlayerInGame();
void SF_PlayerName();
void SF_PlayerObj();
void SF_StartScript(); // FPUKE needs to access this
void SF_ScriptRunning();
void SF_Wait();
void SF_TagWait();
void SF_ScriptWait();
void SF_ScriptWaitPre(); // haleyjd: new wait types
void SF_Player();
void SF_Spawn();
void SF_RemoveObj();
void SF_KillObj();
void SF_ObjX();
void SF_ObjY();
void SF_ObjZ();
void SF_ObjAngle();
void SF_Teleport();
void SF_SilentTeleport();
void SF_DamageObj();
void SF_ObjSector();
void SF_ObjHealth();
void SF_ObjFlag();
void SF_PushThing();
void SF_ReactionTime();
void SF_MobjTarget();
void SF_MobjMomx();
void SF_MobjMomy();
void SF_MobjMomz();
void SF_PointToAngle();
void SF_PointToDist();
void SF_SetCamera();
void SF_ClearCamera();
void SF_StartSound();
void SF_StartSectorSound();
void SF_FloorHeight();
void SF_MoveFloor();
void SF_CeilingHeight();
void SF_MoveCeiling();
void SF_LightLevel();
void SF_FadeLight();
void SF_FloorTexture();
void SF_SectorColormap();
void SF_CeilingTexture();
void SF_ChangeHubLevel();
void SF_StartSkill();
void SF_OpenDoor();
void SF_CloseDoor();
void SF_RunCommand();
void SF_LineTrigger();
void SF_ChangeMusic();
void SF_SetLineBlocking();
void SF_SetLineMonsterBlocking();
void SF_SetLineTexture();
void SF_Max();
void SF_Min();
void SF_Abs();
void SF_Gameskill();
void SF_Gamemode();
void SF_IsPlayerObj();
void SF_PlayerKeys();
void SF_PlayerAmmo();
void SF_MaxPlayerAmmo();
void SF_PlayerWeapon();
void SF_PlayerSelectedWeapon();
void SF_GiveInventory();
void SF_TakeInventory();
void SF_CheckInventory();
void SF_SetWeapon();
void SF_MoveCamera();
void SF_ObjAwaken();
void SF_AmbientSound();
void SF_ExitSecret();
void SF_MobjValue();
void SF_StringValue();
void SF_IntValue();
void SF_FixedValue();
void SF_SpawnExplosion();
void SF_RadiusAttack();
void SF_SetObjPosition();
void SF_TestLocation();
void SF_HealObj(); //no pain sound
void SF_ObjDead();
void SF_SpawnMissile();
void SF_MapThingNumExist();
void SF_MapThings();
void SF_ObjState();
void SF_LineFlag();
void SF_PlayerAddFrag();
void SF_SkinColor();
void SF_PlayDemo();
void SF_CheckCVar();
void SF_Resurrect();
void SF_LineAttack();
void SF_ObjType();
void SF_Sin();
void SF_ASin();
void SF_Cos();
void SF_ACos();
void SF_Tan();
void SF_ATan();
void SF_Exp();
void SF_Log();
void SF_Sqrt();
void SF_Floor();
void SF_Pow();
void SF_NewHUPic();
void SF_DeleteHUPic();
void SF_ModifyHUPic();
void SF_SetHUPicDisplay();
void SF_SetCorona();
void SF_Ls();
void SF_LevelNum();
void SF_MobjRadius();
void SF_MobjHeight();
void SF_ThingCount();
void SF_SetColor();
void SF_SpawnShot2();
void SF_KillInSector();
void SF_SectorType();
void SF_SetLineTrigger();
void SF_ChangeTag();
void SF_WallGlow();
void RunLineSpecial(const FLineSpecial *);
DRunningScript *SaveCurrentScript();
};
//==========================================================================
//
// Running scripts
//
//==========================================================================
enum waittype_e
{
wt_none, // not waiting
wt_delay, // wait for a set amount of time
wt_tagwait, // wait for sector to stop moving
wt_scriptwait, // wait for script to finish
wt_scriptwaitpre, // haleyjd - wait for script to start
};
class DRunningScript : public DObject
{
DECLARE_CLASS(DRunningScript, DObject)
HAS_OBJECT_POINTERS
public:
DRunningScript(AActor *trigger=NULL, DFsScript *owner = NULL, int index = 0) ;
void Destroy();
void Serialize(FArchive &arc);
TObjPtr<DFsScript> script;
// where we are
int save_point;
int wait_type;
int wait_data; // data for wait: tagnum, counter, script number etc
// saved variables
TObjPtr<DFsVariable> variables[VARIABLESLOTS];
TObjPtr<DRunningScript> prev, next; // for chain
TObjPtr<AActor> trigger;
};
//-----------------------------------------------------------------------------
//
// This thinker eliminates the need to call the Fragglescript functions from the main code
//
//-----------------------------------------------------------------------------
class DFraggleThinker : public DThinker
{
DECLARE_CLASS(DFraggleThinker, DThinker)
HAS_OBJECT_POINTERS
public:
TObjPtr<DFsScript> LevelScript;
TObjPtr<DRunningScript> RunningScripts;
TArray<TObjPtr<AActor> > SpawnedThings;
bool nocheckposition;
DFraggleThinker();
void Destroy();
void Serialize(FArchive & arc);
void Tick();
size_t PropagateMark();
size_t PointerSubstitution (DObject *old, DObject *notOld);
bool wait_finished(DRunningScript *script);
void AddRunningScript(DRunningScript *runscr);
static TObjPtr<DFraggleThinker> ActiveThinker;
};
//-----------------------------------------------------------------------------
//
// Global stuff
//
//-----------------------------------------------------------------------------
#include "t_fs.h"
void script_error(const char *s, ...);
void FS_EmulateCmd(char * string);
extern AActor *trigger_obj;
extern DFsScript *global_script;
#endif