4368 lines
79 KiB
C++
4368 lines
79 KiB
C++
#include "g_local.h"
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#define VC_EXTRALEAN
|
|
#include <windows.h>
|
|
#include "ds.h"
|
|
|
|
#define SCRIPT_SAVE_VERSION 2
|
|
|
|
List<Variable *> GlobalVariables;
|
|
List<CScript *> Scripts;
|
|
|
|
template<class T> size_t tWrite(T *ptr,FILE *FH,int n=1)
|
|
{
|
|
return fwrite(ptr,n,sizeof(T),FH);
|
|
}
|
|
|
|
template<class T> size_t tRead(T *ptr,FILE *FH,int n=1)
|
|
{
|
|
return fread(ptr,n,sizeof(T),FH);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef _HERETIC2_
|
|
extern "C"
|
|
{
|
|
#endif
|
|
extern void Use_Multi(edict_t *self, edict_t *other, edict_t *activator);
|
|
extern void c_swapplayer(edict_t *Self,edict_t *Cinematic);
|
|
extern void remove_non_cinematic_entites(edict_t *owner);
|
|
extern void reinstate_non_cinematic_entites(edict_t *owner);
|
|
extern cvar_t *Cvar_Set (char *var_name, char *value);
|
|
|
|
|
|
#ifdef _HERETIC2_
|
|
}
|
|
#endif
|
|
|
|
#ifdef _HERETIC2_
|
|
int msg_animtype [NUM_MESSAGES] =
|
|
{
|
|
MSG_C_ACTION1,
|
|
MSG_C_ACTION2,
|
|
MSG_C_ACTION3,
|
|
MSG_C_ACTION4,
|
|
MSG_C_ACTION5,
|
|
MSG_C_ACTION6,
|
|
MSG_C_ACTION7,
|
|
MSG_C_ACTION8,
|
|
MSG_C_ACTION9,
|
|
MSG_C_ACTION10,
|
|
MSG_C_ACTION11,
|
|
MSG_C_ACTION12,
|
|
MSG_C_ACTION13,
|
|
MSG_C_ACTION14,
|
|
MSG_C_ACTION15,
|
|
MSG_C_ACTION16,
|
|
MSG_C_ACTION17,
|
|
MSG_C_ACTION18,
|
|
MSG_C_ACTION19,
|
|
MSG_C_ACTION20,
|
|
MSG_C_ATTACK1,
|
|
MSG_C_ATTACK2,
|
|
MSG_C_ATTACK3,
|
|
MSG_C_BACKPEDAL1,
|
|
MSG_C_DEATH1,
|
|
MSG_C_DEATH2,
|
|
MSG_C_DEATH3,
|
|
MSG_C_DEATH4,
|
|
MSG_C_GIB1,
|
|
MSG_C_IDLE1,
|
|
MSG_C_IDLE2,
|
|
MSG_C_IDLE3,
|
|
MSG_C_IDLE4,
|
|
MSG_C_IDLE5,
|
|
MSG_C_IDLE6,
|
|
MSG_C_JUMP1,
|
|
MSG_C_PAIN1,
|
|
MSG_C_PAIN2,
|
|
MSG_C_PAIN3,
|
|
MSG_C_PIVOTLEFTGO,
|
|
MSG_C_PIVOTLEFT,
|
|
MSG_C_PIVOTLEFTSTOP,
|
|
MSG_C_PIVOTRIGHTGO,
|
|
MSG_C_PIVOTRIGHT,
|
|
MSG_C_PIVOTRIGHTSTOP,
|
|
MSG_C_RUN1,
|
|
MSG_C_STEPLEFT,
|
|
MSG_C_STEPRIGHT,
|
|
MSG_C_THINKAGAIN,
|
|
MSG_C_TRANS1,
|
|
MSG_C_TRANS2,
|
|
MSG_C_TRANS3,
|
|
MSG_C_TRANS4,
|
|
MSG_C_TRANS5,
|
|
MSG_C_TRANS6,
|
|
MSG_C_WALKSTART,
|
|
MSG_C_WALK1,
|
|
MSG_C_WALK2,
|
|
MSG_C_WALK3,
|
|
MSG_C_WALK4,
|
|
MSG_C_WALKSTOP1,
|
|
MSG_C_WALKSTOP2,
|
|
MSG_C_ATTACK4,
|
|
MSG_C_ATTACK5,
|
|
};
|
|
|
|
#define MAX_CINESNDS 255
|
|
|
|
typedef struct CinematicSound_s
|
|
{
|
|
edict_t *ent;
|
|
int channel;
|
|
} CinematicSound_t;
|
|
|
|
CinematicSound_t CinematicSound[MAX_CINESNDS];
|
|
|
|
int CinematicSound_cnt; // Count of the current # of sounds executed
|
|
|
|
#endif
|
|
|
|
//==========================================================================
|
|
|
|
typedef struct RestoreList_s
|
|
{
|
|
int ID;
|
|
void *(*alloc_func)(FILE *, void *);
|
|
} RestoreList_t;
|
|
|
|
void *RF_IntVar(FILE *FH, void *Data)
|
|
{
|
|
return new IntVar(FH, (CScript *)Data);
|
|
}
|
|
|
|
void *RF_FloatVar(FILE *FH, void *Data)
|
|
{
|
|
return new FloatVar(FH, (CScript *)Data);
|
|
}
|
|
|
|
void *RF_VectorVar(FILE *FH, void *Data)
|
|
{
|
|
return new VectorVar(FH, (CScript *)Data);
|
|
}
|
|
|
|
void *RF_EntityVar(FILE *FH, void *Data)
|
|
{
|
|
return new EntityVar(FH, (CScript *)Data);
|
|
}
|
|
|
|
void *RF_StringVar(FILE *FH, void *Data)
|
|
{
|
|
return new StringVar(FH, (CScript *)Data);
|
|
}
|
|
|
|
void *RF_VariableVar(FILE *FH, void *Data)
|
|
{
|
|
return new VariableVar(FH, (CScript *)Data);
|
|
}
|
|
|
|
void *RF_FieldVariableVar(FILE *FH, void *Data)
|
|
{
|
|
return new FieldVariableVar(FH, (CScript *)Data);
|
|
}
|
|
|
|
void *RF_Signaler(FILE *FH, void *Data)
|
|
{
|
|
return new Signaler(FH, (CScript *)Data);
|
|
}
|
|
|
|
void *RF_MoveDoneEvent(FILE *FH, void *Data)
|
|
{
|
|
return new MoveDoneEvent(FH, (CScript *)Data);
|
|
}
|
|
|
|
void *RF_RotateDoneEvent(FILE *FH, void *Data)
|
|
{
|
|
return new RotateDoneEvent(FH, (CScript *)Data);
|
|
}
|
|
|
|
void *RF_ExecuteEvent(FILE *FH, void *Data)
|
|
{
|
|
return new ExecuteEvent(FH, (CScript *)Data);
|
|
}
|
|
|
|
void *RF_WaitEvent(FILE *FH, void *Data)
|
|
{
|
|
return new WaitEvent(FH, (CScript *)Data);
|
|
}
|
|
|
|
void *RF_Script(FILE *FH, void *Data)
|
|
{
|
|
return new CScript(FH);
|
|
}
|
|
|
|
void *RF_FieldDef(FILE *FH, void *Data)
|
|
{
|
|
return new FieldDef(FH, (CScript *)Data);
|
|
}
|
|
|
|
#define RLID_INTVAR 1
|
|
#define RLID_FLOATVAR 2
|
|
#define RLID_VECTORVAR 3
|
|
#define RLID_ENTITYVAR 4
|
|
#define RLID_STRINGVAR 5
|
|
#define RLID_VARIABLEVAR 6
|
|
#define RLID_FIELDVARIABLEVAR 7
|
|
#define RLID_SIGNALER 8
|
|
#define RLID_MOVEDONEEVENT 9
|
|
#define RLID_ROTATEDONEEVENT 10
|
|
#define RLID_EXECUTEEVENT 11
|
|
#define RLID_WAITEVENT 12
|
|
#define RLID_SCRIPT 13
|
|
#define RLID_FIELDDEF 14
|
|
|
|
RestoreList_t ScriptRL[] =
|
|
{
|
|
{ RLID_INTVAR, RF_IntVar },
|
|
{ RLID_FLOATVAR, RF_FloatVar },
|
|
{ RLID_VECTORVAR, RF_VectorVar },
|
|
{ RLID_ENTITYVAR, RF_EntityVar },
|
|
{ RLID_STRINGVAR, RF_StringVar },
|
|
{ RLID_VARIABLEVAR, RF_VariableVar },
|
|
{ RLID_FIELDVARIABLEVAR, RF_FieldVariableVar },
|
|
{ RLID_SIGNALER, RF_Signaler },
|
|
{ RLID_MOVEDONEEVENT, RF_MoveDoneEvent },
|
|
{ RLID_ROTATEDONEEVENT, RF_RotateDoneEvent },
|
|
{ RLID_EXECUTEEVENT, RF_ExecuteEvent },
|
|
{ RLID_WAITEVENT, RF_WaitEvent },
|
|
{ RLID_SCRIPT, RF_Script },
|
|
{ RLID_FIELDDEF, RF_FieldDef },
|
|
|
|
{ 0, NULL },
|
|
};
|
|
|
|
void *RestoreObject(FILE *FH, RestoreList_t *RestoreList, void *Data)
|
|
{
|
|
int ID;
|
|
RestoreList_t *pos;
|
|
|
|
fread(&ID, 1, sizeof(ID), FH);
|
|
|
|
for(pos = RestoreList; pos->alloc_func; pos++)
|
|
{
|
|
if (pos->ID == ID)
|
|
{
|
|
return pos->alloc_func(FH, Data);
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//==========================================================================
|
|
|
|
void ReadEnt(edict_t **to,FILE *FH)
|
|
{
|
|
int index;
|
|
tRead(&index,FH);
|
|
if (index<0||index>=globals.num_edicts)
|
|
{
|
|
assert(index==-1); //else invalid edict number
|
|
*to=0;
|
|
}
|
|
else
|
|
*to=g_edicts+index;
|
|
}
|
|
|
|
void WriteEnt(edict_t **to,FILE *FH)
|
|
{
|
|
int index;
|
|
if (*to)
|
|
{
|
|
index=(*to)-g_edicts;
|
|
assert(index>=0&&index<globals.num_edicts); //else invalid edict pointer
|
|
}
|
|
else
|
|
index=-1;
|
|
tWrite(&index,FH);
|
|
}
|
|
|
|
//==========================================================================
|
|
|
|
extern "C" void ProcessScripts(void)
|
|
{
|
|
List<CScript *>::Iter is;
|
|
|
|
if (Scripts.Size())
|
|
{
|
|
for (is=Scripts.Begin();is != Scripts.End();is++)
|
|
{
|
|
(*is)->Think();
|
|
}
|
|
}
|
|
}
|
|
|
|
extern "C" void ShutdownScripts(qboolean Complete)
|
|
{
|
|
List<CScript *>::Iter is;
|
|
List<Variable *>::Iter iv;
|
|
int i;
|
|
edict_t *ent;
|
|
|
|
while(Scripts.Size())
|
|
{
|
|
is=Scripts.Begin();
|
|
delete (*is);
|
|
|
|
Scripts.Erase(is);
|
|
}
|
|
|
|
for(i = 0, ent = g_edicts; i < globals.num_edicts; i++, ent++)
|
|
{
|
|
ent->Script = NULL;
|
|
}
|
|
|
|
if (Complete)
|
|
{
|
|
while(GlobalVariables.Size())
|
|
{
|
|
iv=GlobalVariables.Begin();
|
|
delete (*iv);
|
|
|
|
GlobalVariables.Erase(iv);
|
|
}
|
|
}
|
|
}
|
|
|
|
extern "C" void SaveScripts(FILE *FH, qboolean DoGlobals)
|
|
{
|
|
int size;
|
|
List<CScript *>::Iter is;
|
|
List<Variable *>::Iter iv;
|
|
|
|
size = SCRIPT_SAVE_VERSION;
|
|
fwrite(&size, 1, sizeof(size), FH);
|
|
|
|
if (DoGlobals)
|
|
{
|
|
size = GlobalVariables.Size();
|
|
fwrite(&size, 1, sizeof(size), FH);
|
|
|
|
for (iv=GlobalVariables.Begin();iv != GlobalVariables.End();iv++)
|
|
{
|
|
(*iv)->Write(FH, NULL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
size = Scripts.Size();
|
|
fwrite(&size, 1, sizeof(size), FH);
|
|
|
|
for (is=Scripts.Begin();is != Scripts.End();is++)
|
|
{
|
|
(*is)->Write(FH);
|
|
}
|
|
}
|
|
}
|
|
|
|
extern "C" void LoadScripts(FILE *FH, qboolean DoGlobals)
|
|
{
|
|
int size, i;
|
|
edict_t *ent;
|
|
|
|
fread(&size, 1, sizeof(size), FH);
|
|
if (size != SCRIPT_SAVE_VERSION)
|
|
{
|
|
gi.error("LoadScripts(): Expecting version %d, found version %d", SCRIPT_SAVE_VERSION, size);
|
|
}
|
|
|
|
if (DoGlobals)
|
|
{
|
|
ShutdownScripts(true);
|
|
|
|
fread(&size, 1, sizeof(size), FH);
|
|
|
|
for(i=0;i<size;i++)
|
|
{
|
|
GlobalVariables.PushBack((Variable *)RestoreObject(FH, ScriptRL, NULL));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ShutdownScripts(false);
|
|
|
|
for(i = 0, ent = g_edicts; i < globals.num_edicts; i++, ent++)
|
|
{
|
|
ent->Script = NULL;
|
|
}
|
|
|
|
fread(&size, 1, sizeof(size), FH);
|
|
|
|
for(i=0;i<size;i++)
|
|
{
|
|
Scripts.PushBack((CScript *)RestoreObject(FH, ScriptRL, NULL));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void script_use(edict_t *ent, edict_t *other, edict_t *activator)
|
|
{
|
|
ent->Script->AddEvent(new ExecuteEvent(level.time, other, activator) );
|
|
}
|
|
|
|
/*QUAKED script_runner (.5 .5 .5) (-8 -8 -8) (8 8 8)
|
|
set Script to the name of the script to run when triggered
|
|
use parm1 through parm16 to send parameters to the script
|
|
*/
|
|
extern "C" void SP_script_runner (edict_t *ent)
|
|
{
|
|
char temp[MAX_PATH];
|
|
int i;
|
|
|
|
sprintf(temp,"ds/%s.os",st.script);
|
|
ent->Script = new CScript(temp, ent);
|
|
Scripts.PushBack(ent->Script);
|
|
|
|
for(i=0;i<NUM_PARMS;i++)
|
|
{
|
|
if (st.parms[i])
|
|
{
|
|
ent->Script->SetParameter(st.parms[i]);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
#ifdef _HERETIC2_
|
|
ent->movetype = PHYSICSTYPE_NONE;
|
|
#else
|
|
ent->movetype = MOVETYPE_NONE;
|
|
#endif
|
|
ent->solid = SOLID_NOT;
|
|
ent->svflags |= SVF_NOCLIENT;
|
|
ent->use = script_use;
|
|
|
|
// gi.setmodel (ent, ent->model);
|
|
// gi.linkentity (ent);
|
|
}
|
|
|
|
/*QUAKE script_parms (.5 .5 .5) ?
|
|
target the script_runner object
|
|
use parm1 through parm16 to send parameters to the script
|
|
*/
|
|
extern "C" void SP_parms (edict_t *ent)
|
|
{
|
|
}
|
|
|
|
//==========================================================================
|
|
|
|
Variable *FindGlobal(char *Name)
|
|
{
|
|
List<Variable *>::Iter iv;
|
|
|
|
if (GlobalVariables.Size())
|
|
{
|
|
for (iv=GlobalVariables.Begin();iv != GlobalVariables.End();iv++)
|
|
{
|
|
if (strcmp(Name, (*iv)->GetName()) == 0)
|
|
{
|
|
return *iv;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
bool NewGlobal(Variable *Which)
|
|
{
|
|
Variable *Check;
|
|
|
|
Check = FindGlobal(Which->GetName());
|
|
if (Check)
|
|
{ // already exists
|
|
return false;
|
|
}
|
|
|
|
GlobalVariables.PushBack(Which);
|
|
|
|
return true;
|
|
}
|
|
|
|
//==========================================================================
|
|
|
|
Variable::Variable(char *NewName, VariableT NewType)
|
|
{
|
|
strcpy(Name,NewName);
|
|
Type = NewType;
|
|
}
|
|
|
|
Variable::Variable(FILE *FH, CScript *Script)
|
|
{
|
|
int index;
|
|
|
|
fread(Name, 1, sizeof(Name), FH);
|
|
fread(&Type, 1, sizeof(Type), FH);
|
|
fread(&index, 1, sizeof(index), FH);
|
|
|
|
if (Script && index != -1)
|
|
{
|
|
Script->SetVarIndex(index, this);
|
|
}
|
|
}
|
|
|
|
void Variable::Write(FILE *FH, CScript *Script, int ID)
|
|
{
|
|
int index = -1;
|
|
|
|
fwrite(&ID, 1, sizeof(ID), FH);
|
|
fwrite(Name, 1, sizeof(Name), FH);
|
|
fwrite(&Type, 1, sizeof(Type), FH);
|
|
|
|
if (Script)
|
|
{
|
|
index = Script->LookupVarIndex(this);
|
|
}
|
|
fwrite(&index, 1, sizeof(index), FH);
|
|
}
|
|
|
|
void Variable::Debug(CScript *Script)
|
|
{
|
|
Script->DebugLine(" Name: %s\n",Name);
|
|
}
|
|
|
|
//==========================================================================
|
|
|
|
IntVar::IntVar(char *Name, int InitValue)
|
|
:Variable(Name, TypeINT)
|
|
{
|
|
Value = InitValue;
|
|
}
|
|
|
|
IntVar::IntVar(FILE *FH, CScript *Script)
|
|
:Variable(FH, Script)
|
|
{
|
|
fread(&Value, 1, sizeof(Value), FH);
|
|
}
|
|
|
|
void IntVar::Write(FILE *FH, CScript *Script, int ID)
|
|
{
|
|
Variable::Write(FH, Script, RLID_INTVAR);
|
|
|
|
fwrite(&Value, 1, sizeof(Value), FH);
|
|
}
|
|
|
|
void IntVar::ReadValue(CScript *Script)
|
|
{
|
|
Value = Script->ReadInt();
|
|
}
|
|
|
|
void IntVar::Debug(CScript *Script)
|
|
{
|
|
Variable::Debug(Script);
|
|
|
|
Script->DebugLine(" Integer Value: %d\n",Value);
|
|
}
|
|
|
|
void IntVar::Signal(edict_t *Which)
|
|
{
|
|
Value++;
|
|
}
|
|
|
|
void IntVar::ClearSignal(void)
|
|
{
|
|
Value = 0;
|
|
}
|
|
|
|
Variable *IntVar::operator +(Variable *VI)
|
|
{
|
|
return new IntVar("",Value + VI->GetIntValue());
|
|
}
|
|
|
|
Variable *IntVar::operator -(Variable *VI)
|
|
{
|
|
return new IntVar("",Value - VI->GetIntValue());
|
|
}
|
|
|
|
Variable *IntVar::operator *(Variable *VI)
|
|
{
|
|
return new IntVar("",Value * VI->GetIntValue());
|
|
}
|
|
|
|
Variable *IntVar::operator /(Variable *VI)
|
|
{
|
|
return new IntVar("",Value / VI->GetIntValue());
|
|
}
|
|
|
|
void IntVar::operator =(Variable *VI)
|
|
{
|
|
Value = VI->GetIntValue();
|
|
}
|
|
|
|
//==========================================================================
|
|
|
|
FloatVar::FloatVar(char *Name, float InitValue)
|
|
:Variable(Name, TypeFLOAT)
|
|
{
|
|
Value = InitValue;
|
|
}
|
|
|
|
FloatVar::FloatVar(FILE *FH, CScript *Script)
|
|
:Variable(FH, Script)
|
|
{
|
|
fread(&Value, 1, sizeof(Value), FH);
|
|
}
|
|
|
|
void FloatVar::Write(FILE *FH, CScript *Script, int ID)
|
|
{
|
|
Variable::Write(FH, Script, RLID_FLOATVAR);
|
|
|
|
fwrite(&Value, 1, sizeof(Value), FH);
|
|
}
|
|
|
|
void FloatVar::ReadValue(CScript *Script)
|
|
{
|
|
Value = Script->ReadFloat();
|
|
}
|
|
|
|
void FloatVar::Debug(CScript *Script)
|
|
{
|
|
Variable::Debug(Script);
|
|
|
|
Script->DebugLine(" Float Value: %0.f\n",Value);
|
|
}
|
|
|
|
Variable *FloatVar::operator +(Variable *VI)
|
|
{
|
|
return new FloatVar("",Value + VI->GetFloatValue());
|
|
}
|
|
|
|
Variable *FloatVar::operator -(Variable *VI)
|
|
{
|
|
return new FloatVar("",Value - VI->GetFloatValue());
|
|
}
|
|
|
|
Variable *FloatVar::operator *(Variable *VI)
|
|
{
|
|
return new FloatVar("",Value * VI->GetFloatValue());
|
|
}
|
|
|
|
Variable *FloatVar::operator /(Variable *VI)
|
|
{
|
|
return new FloatVar("",Value / VI->GetFloatValue());
|
|
}
|
|
|
|
void FloatVar::operator =(Variable *VI)
|
|
{
|
|
Value = VI->GetFloatValue();
|
|
}
|
|
|
|
//==========================================================================
|
|
|
|
VectorVar::VectorVar(char *Name, float InitValueX, float InitValueY, float InitValueZ)
|
|
:Variable(Name, TypeVECTOR)
|
|
{
|
|
Value[0] = InitValueX;
|
|
Value[1] = InitValueY;
|
|
Value[2] = InitValueZ;
|
|
}
|
|
|
|
VectorVar::VectorVar(vec3_t NewValue)
|
|
:Variable("", TypeVECTOR)
|
|
{
|
|
VectorCopy(NewValue, Value);
|
|
}
|
|
|
|
VectorVar::VectorVar(FILE *FH, CScript *Script)
|
|
:Variable(FH, Script)
|
|
{
|
|
fread(&Value, 1, sizeof(Value), FH);
|
|
}
|
|
|
|
void VectorVar::Write(FILE *FH, CScript *Script, int ID)
|
|
{
|
|
Variable::Write(FH, Script, RLID_VECTORVAR);
|
|
|
|
fwrite(Value, 1, sizeof(Value), FH);
|
|
}
|
|
|
|
void VectorVar::GetVectorValue(vec3_t &VecValue)
|
|
{
|
|
VecValue[0] = Value[0];
|
|
VecValue[1] = Value[1];
|
|
VecValue[2] = Value[2];
|
|
}
|
|
|
|
void VectorVar::ReadValue(CScript *Script)
|
|
{
|
|
Value[0] = Script->ReadFloat();
|
|
Value[1] = Script->ReadFloat();
|
|
Value[2] = Script->ReadFloat();
|
|
}
|
|
|
|
void VectorVar::Debug(CScript *Script)
|
|
{
|
|
Variable::Debug(Script);
|
|
|
|
Script->DebugLine(" Vector Value: [%0.f, %0.f, %0.f]\n",Value[0],Value[1],Value[2]);
|
|
}
|
|
|
|
Variable *VectorVar::operator +(Variable *VI)
|
|
{
|
|
vec3_t V2, NewV;
|
|
|
|
if (VI->GetType() == TypeINT || VI->GetType() == TypeFLOAT)
|
|
{
|
|
V2[0] = V2[1] = V2[2] = VI->GetFloatValue();
|
|
}
|
|
else
|
|
{
|
|
VI->GetVectorValue(V2);
|
|
}
|
|
|
|
NewV[0] = Value[0] + V2[0];
|
|
NewV[1] = Value[1] + V2[1];
|
|
NewV[2] = Value[2] + V2[2];
|
|
|
|
return new VectorVar("", NewV[0], NewV[1], NewV[2]);
|
|
}
|
|
|
|
Variable *VectorVar::operator -(Variable *VI)
|
|
{
|
|
vec3_t V2, NewV;
|
|
|
|
if (VI->GetType() == TypeINT || VI->GetType() == TypeFLOAT)
|
|
{
|
|
V2[0] = V2[1] = V2[2] = VI->GetFloatValue();
|
|
}
|
|
else
|
|
{
|
|
VI->GetVectorValue(V2);
|
|
}
|
|
|
|
NewV[0] = Value[0] - V2[0];
|
|
NewV[1] = Value[1] - V2[1];
|
|
NewV[2] = Value[2] - V2[2];
|
|
|
|
return new VectorVar("", NewV[0], NewV[1], NewV[2]);
|
|
}
|
|
|
|
Variable *VectorVar::operator *(Variable *VI)
|
|
{
|
|
vec3_t V2, NewV;
|
|
|
|
if (VI->GetType() == TypeINT || VI->GetType() == TypeFLOAT)
|
|
{
|
|
V2[0] = V2[1] = V2[2] = VI->GetFloatValue();
|
|
}
|
|
else
|
|
{
|
|
VI->GetVectorValue(V2);
|
|
}
|
|
|
|
NewV[0] = Value[0] * V2[0];
|
|
NewV[1] = Value[1] * V2[1];
|
|
NewV[2] = Value[2] * V2[2];
|
|
|
|
return new VectorVar("", NewV[0], NewV[1], NewV[2]);
|
|
}
|
|
|
|
Variable *VectorVar::operator /(Variable *VI)
|
|
{
|
|
vec3_t V2, NewV;
|
|
|
|
if (VI->GetType() == TypeINT || VI->GetType() == TypeFLOAT)
|
|
{
|
|
V2[0] = V2[1] = V2[2] = VI->GetFloatValue();
|
|
}
|
|
else
|
|
{
|
|
VI->GetVectorValue(V2);
|
|
}
|
|
|
|
NewV[0] = Value[0] / V2[0];
|
|
NewV[1] = Value[1] / V2[1];
|
|
NewV[2] = Value[2] / V2[2];
|
|
|
|
return new VectorVar("", NewV[0], NewV[1], NewV[2]);
|
|
}
|
|
|
|
void VectorVar::operator =(Variable *VI)
|
|
{
|
|
VI->GetVectorValue(Value);
|
|
}
|
|
|
|
bool VectorVar::operator ==(Variable *VI)
|
|
{
|
|
vec3_t vec;
|
|
|
|
if (VI->GetType() == TypeINT || VI->GetType() == TypeFLOAT)
|
|
{
|
|
return VectorLength(Value) == VI->GetFloatValue();
|
|
}
|
|
else if (VI->GetType() == TypeVECTOR)
|
|
{
|
|
VI->GetVectorValue(vec);
|
|
|
|
return (VectorCompare(Value, vec) == 1); // VC6 gives a warning about converting int to bool
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool VectorVar::operator !=(Variable *VI)
|
|
{
|
|
vec3_t vec;
|
|
|
|
if (VI->GetType() == TypeINT || VI->GetType() == TypeFLOAT)
|
|
{
|
|
return VectorLength(Value) != VI->GetFloatValue();
|
|
}
|
|
else if (VI->GetType() == TypeVECTOR)
|
|
{
|
|
VI->GetVectorValue(vec);
|
|
|
|
return !VectorCompare(Value, vec);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool VectorVar::operator <(Variable *VI)
|
|
{
|
|
vec3_t vec;
|
|
float compare;
|
|
|
|
if (VI->GetType() == TypeINT || VI->GetType() == TypeFLOAT)
|
|
{
|
|
compare = VI->GetFloatValue();
|
|
}
|
|
else if (VI->GetType() == TypeVECTOR)
|
|
{
|
|
VI->GetVectorValue(vec);
|
|
compare = VectorLength(vec);
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return VectorLength(Value) < compare;
|
|
}
|
|
|
|
bool VectorVar::operator <=(Variable *VI)
|
|
{
|
|
vec3_t vec;
|
|
float compare;
|
|
|
|
if (VI->GetType() == TypeINT || VI->GetType() == TypeFLOAT)
|
|
{
|
|
compare = VI->GetFloatValue();
|
|
}
|
|
else if (VI->GetType() == TypeVECTOR)
|
|
{
|
|
VI->GetVectorValue(vec);
|
|
compare = VectorLength(vec);
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return VectorLength(Value) <= compare;
|
|
}
|
|
|
|
bool VectorVar::operator >(Variable *VI)
|
|
{
|
|
vec3_t vec;
|
|
float compare;
|
|
|
|
if (VI->GetType() == TypeINT || VI->GetType() == TypeFLOAT)
|
|
{
|
|
compare = VI->GetFloatValue();
|
|
}
|
|
else if (VI->GetType() == TypeVECTOR)
|
|
{
|
|
VI->GetVectorValue(vec);
|
|
compare = VectorLength(vec);
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return VectorLength(Value) > compare;
|
|
}
|
|
|
|
bool VectorVar::operator >=(Variable *VI)
|
|
{
|
|
vec3_t vec;
|
|
float compare;
|
|
|
|
if (VI->GetType() == TypeINT || VI->GetType() == TypeFLOAT)
|
|
{
|
|
compare = VI->GetFloatValue();
|
|
}
|
|
else if (VI->GetType() == TypeVECTOR)
|
|
{
|
|
VI->GetVectorValue(vec);
|
|
compare = VectorLength(vec);
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return VectorLength(Value) >= compare;
|
|
}
|
|
|
|
//==========================================================================
|
|
|
|
EntityVar::EntityVar(char *Name, int InitValue)
|
|
:Variable(Name, TypeENTITY)
|
|
{
|
|
if (InitValue == -1)
|
|
{
|
|
Value = NULL;
|
|
}
|
|
else
|
|
{
|
|
Value = &g_edicts[InitValue];
|
|
}
|
|
}
|
|
|
|
EntityVar::EntityVar(edict_t *Which)
|
|
:Variable("", TypeENTITY)
|
|
{
|
|
Value = Which;
|
|
}
|
|
|
|
EntityVar::EntityVar(FILE *FH, CScript *Script)
|
|
:Variable(FH, Script)
|
|
{
|
|
int index;
|
|
|
|
fread(&index, 1, sizeof(index), FH);
|
|
|
|
if (index == -1)
|
|
{
|
|
Value = NULL;
|
|
}
|
|
else
|
|
{
|
|
Value = &g_edicts[index];
|
|
}
|
|
}
|
|
|
|
void EntityVar::Write(FILE *FH, CScript *Script, int ID)
|
|
{
|
|
int index;
|
|
|
|
Variable::Write(FH, Script, RLID_ENTITYVAR);
|
|
|
|
index = GetIntValue();
|
|
fwrite(&index, 1, sizeof(index), FH);
|
|
}
|
|
|
|
void EntityVar::ReadValue(CScript *Script)
|
|
{
|
|
int Index;
|
|
|
|
Index = Script->ReadInt();
|
|
if (Index == -1)
|
|
{
|
|
Value = NULL;
|
|
}
|
|
else
|
|
{
|
|
Value = &g_edicts[Index];
|
|
}
|
|
}
|
|
|
|
void EntityVar::Debug(CScript *Script)
|
|
{
|
|
Variable::Debug(Script);
|
|
|
|
Script->DebugLine(" Entity Value: %d\n",GetIntValue());
|
|
}
|
|
|
|
int EntityVar::GetIntValue(void)
|
|
{
|
|
if (Value)
|
|
{
|
|
return Value - g_edicts;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void EntityVar::operator =(Variable *VI)
|
|
{
|
|
Value = VI->GetEdictValue();
|
|
}
|
|
|
|
bool EntityVar::operator ==(Variable *VI)
|
|
{
|
|
if (VI->GetType() == TypeINT)
|
|
{
|
|
return GetIntValue() == VI->GetIntValue();
|
|
}
|
|
else if (VI->GetType() == TypeENTITY)
|
|
{
|
|
return GetEdictValue() == VI->GetEdictValue();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool EntityVar::operator !=(Variable *VI)
|
|
{
|
|
if (VI->GetType() == TypeINT)
|
|
{
|
|
return GetIntValue() != VI->GetIntValue();
|
|
}
|
|
else if (VI->GetType() == TypeENTITY)
|
|
{
|
|
return GetEdictValue() != VI->GetEdictValue();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//==========================================================================
|
|
|
|
StringVar::StringVar(char *Name, char *InitValue)
|
|
:Variable(Name, TypeSTRING)
|
|
{
|
|
strcpy(Value, InitValue);
|
|
}
|
|
|
|
StringVar::StringVar(FILE *FH, CScript *Script)
|
|
:Variable(FH, Script)
|
|
{
|
|
fread(&Value, 1, sizeof(Value), FH);
|
|
}
|
|
|
|
void StringVar::Write(FILE *FH, CScript *Script, int ID)
|
|
{
|
|
Variable::Write(FH, Script, RLID_STRINGVAR);
|
|
|
|
fwrite(&Value, 1, sizeof(Value), FH);
|
|
}
|
|
|
|
void StringVar::ReadValue(CScript *Script)
|
|
{
|
|
strcpy(Value, Script->ReadString());
|
|
}
|
|
|
|
//==========================================================================
|
|
|
|
VariableVar::VariableVar(char *Name)
|
|
:Variable(Name, TypeUNKNOWN)
|
|
{
|
|
Value = NULL;
|
|
}
|
|
|
|
VariableVar::VariableVar(FILE *FH, CScript *Script)
|
|
:Variable(FH, Script)
|
|
{
|
|
int index;
|
|
|
|
fread(&index, 1, sizeof(index), FH);
|
|
Value = Script->LookupVar(index);
|
|
}
|
|
|
|
void VariableVar::Write(FILE *FH, CScript *Script, int ID)
|
|
{
|
|
int index;
|
|
|
|
Variable::Write(FH, Script, RLID_VARIABLEVAR);
|
|
|
|
index = Script->LookupVarIndex(Value);
|
|
fwrite(&index, 1, sizeof(index), FH);
|
|
}
|
|
|
|
void VariableVar::ReadValue(CScript *Script)
|
|
{
|
|
int Index;
|
|
|
|
Index = Script->ReadInt();
|
|
|
|
Value = Script->LookupVar(Index);
|
|
|
|
if (Value)
|
|
{
|
|
Type = Value->GetType();
|
|
}
|
|
}
|
|
|
|
void VariableVar::Debug(CScript *Script)
|
|
{
|
|
Value->Debug(Script);
|
|
}
|
|
|
|
//==========================================================================
|
|
|
|
FieldVariableVar::FieldVariableVar(char *Name)
|
|
:Variable(Name, TypeUNKNOWN)
|
|
{
|
|
Value = NULL;
|
|
Field = NULL;
|
|
}
|
|
|
|
FieldVariableVar::FieldVariableVar(FILE *FH, CScript *Script)
|
|
:Variable(FH, Script)
|
|
{
|
|
int index;
|
|
|
|
fread(&index, 1, sizeof(index), FH);
|
|
Value = Script->LookupVar(index);
|
|
|
|
fread(&index, 1, sizeof(index), FH);
|
|
Field = Script->LookupField(index);
|
|
}
|
|
|
|
void FieldVariableVar::Write(FILE *FH, CScript *Script, int ID)
|
|
{
|
|
int index;
|
|
|
|
Variable::Write(FH, Script, RLID_FIELDVARIABLEVAR);
|
|
|
|
index = Script->LookupVarIndex(Value);
|
|
fwrite(&index, 1, sizeof(index), FH);
|
|
|
|
index = Script->LookupFieldIndex(Field);
|
|
fwrite(&index, 1, sizeof(index), FH);
|
|
}
|
|
|
|
void FieldVariableVar::ReadValue(CScript *Script)
|
|
{
|
|
int Index;
|
|
|
|
Index = Script->ReadInt();
|
|
Value = Script->LookupVar(Index);
|
|
|
|
Index = Script->ReadInt();
|
|
Field = Script->LookupField(Index);
|
|
}
|
|
|
|
void FieldVariableVar::Debug(CScript *Script)
|
|
{
|
|
Value->Debug(Script);
|
|
}
|
|
|
|
int FieldVariableVar::GetIntValue(void)
|
|
{
|
|
return Field->GetIntValue(Value);
|
|
}
|
|
|
|
float FieldVariableVar::GetFloatValue(void)
|
|
{
|
|
return Field->GetFloatValue(Value);
|
|
}
|
|
|
|
void FieldVariableVar::GetVectorValue(vec3_t &VecValue)
|
|
{
|
|
Field->GetVectorValue(Value, VecValue);
|
|
}
|
|
|
|
edict_t *FieldVariableVar::GetEdictValue(void)
|
|
{
|
|
return Field->GetEdictValue(Value);
|
|
}
|
|
|
|
char *FieldVariableVar::GetStringValue(void)
|
|
{
|
|
return Field->GetStringValue(Value);
|
|
}
|
|
|
|
Variable *FieldVariableVar::operator +(Variable *VI)
|
|
{
|
|
Variable *Result, *Val;
|
|
|
|
Val = Field->GetValue(Value);
|
|
|
|
Result = (*Val) + VI;
|
|
|
|
delete Val;
|
|
|
|
return Result;
|
|
}
|
|
|
|
Variable *FieldVariableVar::operator -(Variable *VI)
|
|
{
|
|
Variable *Result, *Val;
|
|
|
|
Val = Field->GetValue(Value);
|
|
|
|
Result = (*Val) - VI;
|
|
|
|
delete Val;
|
|
|
|
return Result;
|
|
}
|
|
|
|
Variable *FieldVariableVar::operator *(Variable *VI)
|
|
{
|
|
Variable *Result, *Val;
|
|
|
|
Val = Field->GetValue(Value);
|
|
|
|
Result = (*Val) * VI;
|
|
|
|
delete Val;
|
|
|
|
return Result;
|
|
}
|
|
|
|
Variable *FieldVariableVar::operator /(Variable *VI)
|
|
{
|
|
Variable *Result, *Val;
|
|
|
|
Val = Field->GetValue(Value);
|
|
|
|
Result = (*Val) / VI;
|
|
|
|
delete Val;
|
|
|
|
return Result;
|
|
}
|
|
|
|
void FieldVariableVar::operator =(Variable *VI)
|
|
{
|
|
Field->SetValue(Value, VI);
|
|
}
|
|
|
|
bool FieldVariableVar::operator ==(Variable *VI)
|
|
{
|
|
return (*Value) == VI;
|
|
}
|
|
|
|
bool FieldVariableVar::operator !=(Variable *VI)
|
|
{
|
|
return (*Value) != VI;
|
|
}
|
|
|
|
bool FieldVariableVar::operator <(Variable *VI)
|
|
{
|
|
return (*Value) < VI;
|
|
}
|
|
|
|
bool FieldVariableVar::operator <=(Variable *VI)
|
|
{
|
|
return (*Value) <= VI;
|
|
}
|
|
|
|
bool FieldVariableVar::operator >(Variable *VI)
|
|
{
|
|
return (*Value) > VI;
|
|
}
|
|
|
|
bool FieldVariableVar::operator >=(Variable *VI)
|
|
{
|
|
return (*Value) >= VI;
|
|
}
|
|
|
|
//==========================================================================
|
|
|
|
Signaler::Signaler(edict_t *NewEdict, Variable *NewVar, SignalT NewSignalType)
|
|
{
|
|
Edict = NewEdict;
|
|
Var = NewVar;
|
|
SignalType = NewSignalType;
|
|
}
|
|
|
|
Signaler::Signaler(FILE *FH, CScript *Script)
|
|
{
|
|
ReadEnt(&Edict,FH);
|
|
tRead(&SignalType, FH);
|
|
|
|
Var = (Variable *)RestoreObject(FH, ScriptRL, Script);
|
|
}
|
|
|
|
Signaler::~Signaler(void)
|
|
{
|
|
if (Var)
|
|
{
|
|
delete Var;
|
|
}
|
|
}
|
|
|
|
void Signaler::Write(FILE *FH, CScript *Script)
|
|
{
|
|
int index;
|
|
|
|
index = RLID_SIGNALER;
|
|
fwrite(&index, 1, sizeof(index), FH);
|
|
|
|
WriteEnt(&Edict,FH);
|
|
tWrite(&SignalType, FH);
|
|
|
|
Var->Write(FH, Script);
|
|
}
|
|
|
|
bool Signaler::Test(edict_t *Which, SignalT WhichType)
|
|
{
|
|
if (WhichType != SignalType)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (Edict != Which)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Var->Signal(Which);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Signaler::operator ==(Signaler *SI)
|
|
{
|
|
if (Var == SI->GetVar())
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void script_signaler(edict_t *which, SignalT SignalType)
|
|
{
|
|
List<CScript *>::Iter is;
|
|
|
|
if (Scripts.Size())
|
|
{
|
|
for (is=Scripts.Begin();is != Scripts.End();is++)
|
|
{
|
|
(*is)->CheckSignalers(which, SignalType);
|
|
}
|
|
}
|
|
}
|
|
|
|
void move_signaler(edict_t *which)
|
|
{
|
|
script_signaler(which, SIGNAL_MOVE);
|
|
}
|
|
|
|
void rotate_signaler(edict_t *which)
|
|
{
|
|
script_signaler(which, SIGNAL_ROTATE);
|
|
}
|
|
|
|
void animate_signaler(edict_t *which)
|
|
{
|
|
script_signaler(which, SIGNAL_ANIMATE);
|
|
}
|
|
|
|
//==========================================================================
|
|
|
|
// Fields are just yucky now - once H2 finals, I'm going to change them completely
|
|
|
|
#define SPEC_X -1
|
|
#define SPEC_Y -2
|
|
#define SPEC_Z -3
|
|
#define SPEC_DELTA_ANGLES -4
|
|
#define SPEC_P_ORIGIN -5
|
|
|
|
static field_t script_fields[] =
|
|
{
|
|
{ "x", SPEC_X, F_FLOAT },
|
|
{ "y", SPEC_Y, F_FLOAT },
|
|
{ "z", SPEC_Z, F_FLOAT },
|
|
{ "origin", FOFS(s.origin), F_VECTOR },
|
|
{ "movetype", FOFS(movetype), F_INT },
|
|
{ "start_origin", FOFS(moveinfo.start_origin), F_VECTOR },
|
|
{ "distance", FOFS(moveinfo.distance), F_FLOAT },
|
|
{ "owner", FOFS(owner), F_EDICT },
|
|
{ "wait", FOFS(wait), F_FLOAT },
|
|
{ "velocity", FOFS(velocity), F_VECTOR },
|
|
{ "angle_velocity", FOFS(avelocity), F_VECTOR },
|
|
{ "team_chain", FOFS(teamchain), F_EDICT },
|
|
{ "yaw_speed", FOFS(yaw_speed), F_FLOAT },
|
|
{ "modelindex", FOFS(s.modelindex), F_INT },
|
|
{ "count", FOFS(count), F_INT },
|
|
{ "solid", FOFS(solid), F_INT },
|
|
{ "angles", FOFS(s.angles), F_VECTOR },
|
|
{ "start_angles", FOFS(moveinfo.start_angles), F_VECTOR },
|
|
{ "state", FOFS(moveinfo.state), F_INT },
|
|
#ifdef _HERETIC2_
|
|
{ "c_mode", FOFS(monsterinfo.c_mode), F_INT },
|
|
{ "skinnum", FOFS(s.skinnum), F_INT },
|
|
{ "ideal_yaw", FOFS(ideal_yaw), F_FLOAT },
|
|
{ "delta_angles", SPEC_DELTA_ANGLES, F_VECTOR },
|
|
{ "p_origin", SPEC_P_ORIGIN, F_VECTOR },
|
|
{ "takedamage", FOFS(takedamage), F_INT },
|
|
#endif
|
|
|
|
{ NULL, 0, F_INT }
|
|
};
|
|
|
|
FieldDef::FieldDef(CScript *Script)
|
|
{
|
|
field_t *Field;
|
|
bool Found;
|
|
|
|
strcpy(Name, Script->ReadString());
|
|
Type = (VariableT)Script->ReadByte();
|
|
|
|
FieldType = F_IGNORE;
|
|
Offset = -1;
|
|
|
|
Found = false;
|
|
for (Field = script_fields; Field->name; Field++)
|
|
{
|
|
if (strcmp(Name, Field->name) == 0)
|
|
{
|
|
Offset = Field->ofs;
|
|
FieldType = Field->type;
|
|
Found = true;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!Found)
|
|
{
|
|
#ifdef _DEVEL
|
|
Com_Printf("Unknown field '%s'\n",Name);
|
|
#endif //_DEVEL
|
|
}
|
|
}
|
|
|
|
FieldDef::FieldDef(FILE *FH, CScript *Script)
|
|
{
|
|
int index;
|
|
bool Found;
|
|
field_t *Field;
|
|
|
|
fread(Name, 1, sizeof(Name), FH);
|
|
fread(&Type, 1, sizeof(Type), FH);
|
|
|
|
fread(&index, 1, sizeof(index), FH);
|
|
if (Script && index != -1)
|
|
{
|
|
Script->SetFieldIndex(index, this);
|
|
}
|
|
|
|
FieldType = F_IGNORE;
|
|
Offset = -1;
|
|
|
|
Found = false;
|
|
for (Field = script_fields; Field->name; Field++)
|
|
{
|
|
if (strcmp(Name, Field->name) == 0)
|
|
{
|
|
Offset = Field->ofs;
|
|
FieldType = Field->type;
|
|
Found = true;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!Found)
|
|
{
|
|
#ifdef _DEVEL
|
|
Com_Printf("Unknown field '%s'\n",Name);
|
|
#endif //_DEVEL
|
|
}
|
|
}
|
|
|
|
void FieldDef::Write(FILE *FH, CScript *Script)
|
|
{
|
|
int index;
|
|
|
|
index = RLID_FIELDDEF;
|
|
fwrite(&index, 1, sizeof(index), FH);
|
|
|
|
fwrite(Name, 1, sizeof(Name), FH);
|
|
fwrite(&Type, 1, sizeof(Type), FH);
|
|
|
|
index = -1;
|
|
if (Script)
|
|
{
|
|
index = Script->LookupFieldIndex(this);
|
|
}
|
|
fwrite(&index, 1, sizeof(index), FH);
|
|
}
|
|
|
|
byte *FieldDef::GetOffset(Variable *Var)
|
|
{
|
|
edict_t *ent;
|
|
byte *b, *Dest;
|
|
|
|
Dest = NULL;
|
|
|
|
switch(Offset)
|
|
{
|
|
case SPEC_X:
|
|
break;
|
|
case SPEC_Y:
|
|
break;
|
|
case SPEC_Z:
|
|
break;
|
|
case SPEC_DELTA_ANGLES:
|
|
ent = Var->GetEdictValue();
|
|
if (ent && ent->client)
|
|
{
|
|
Dest = (byte *)&ent->client->ps.pmove.delta_angles;
|
|
}
|
|
break;
|
|
#ifdef _HERETIC2_
|
|
case SPEC_P_ORIGIN:
|
|
ent = Var->GetEdictValue();
|
|
if (ent && ent->client)
|
|
{
|
|
Dest = (byte *)&ent->client->playerinfo.origin;
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
ent = Var->GetEdictValue();
|
|
if (ent)
|
|
{
|
|
b = (byte *)ent;
|
|
Dest = b+Offset;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return Dest;
|
|
}
|
|
|
|
Variable *FieldDef::GetValue(Variable *Var)
|
|
{
|
|
vec3_t vec;
|
|
|
|
switch(FieldType)
|
|
{
|
|
case F_INT:
|
|
return new IntVar("", GetIntValue(Var) );
|
|
break;
|
|
|
|
case F_FLOAT:
|
|
return new FloatVar("", GetFloatValue(Var) );
|
|
break;
|
|
|
|
case F_EDICT:
|
|
return new EntityVar(GetEdictValue(Var));
|
|
break;
|
|
|
|
case F_VECTOR:
|
|
GetVectorValue(Var, vec);
|
|
return new VectorVar(vec);
|
|
break;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int FieldDef::GetIntValue(Variable *Var)
|
|
{
|
|
byte *Dest;
|
|
vec3_t data;
|
|
|
|
Dest = GetOffset(Var);
|
|
|
|
if (FieldType != F_INT || !Dest)
|
|
{
|
|
switch(Offset)
|
|
{
|
|
case SPEC_X:
|
|
Var->GetVectorValue(data);
|
|
return (int)data[0];
|
|
break;
|
|
case SPEC_Y:
|
|
Var->GetVectorValue(data);
|
|
return (int)data[1];
|
|
break;
|
|
case SPEC_Z:
|
|
Var->GetVectorValue(data);
|
|
return (int)data[2];
|
|
break;
|
|
}
|
|
|
|
return 0.0;
|
|
}
|
|
|
|
return *(int *)(Dest);
|
|
}
|
|
|
|
float FieldDef::GetFloatValue(Variable *Var)
|
|
{
|
|
byte *Dest;
|
|
vec3_t data;
|
|
|
|
Dest = GetOffset(Var);
|
|
|
|
if (FieldType != F_FLOAT || !Dest)
|
|
{
|
|
switch(Offset)
|
|
{
|
|
case SPEC_X:
|
|
Var->GetVectorValue(data);
|
|
return data[0];
|
|
break;
|
|
case SPEC_Y:
|
|
Var->GetVectorValue(data);
|
|
return data[1];
|
|
break;
|
|
case SPEC_Z:
|
|
Var->GetVectorValue(data);
|
|
return data[2];
|
|
break;
|
|
}
|
|
|
|
return 0.0;
|
|
}
|
|
|
|
return *(float *)(Dest);
|
|
}
|
|
|
|
void FieldDef::GetVectorValue(Variable *Var, vec3_t &VecValue)
|
|
{
|
|
byte *Dest;
|
|
|
|
Dest = GetOffset(Var);
|
|
|
|
if (FieldType != F_VECTOR || !Dest)
|
|
{
|
|
VectorCopy(vec3_origin, VecValue);
|
|
return;
|
|
}
|
|
|
|
VectorCopy(*(vec3_t *)(Dest), VecValue);
|
|
}
|
|
|
|
edict_t *FieldDef::GetEdictValue(Variable *Var)
|
|
{
|
|
byte *Dest;
|
|
|
|
Dest = GetOffset(Var);
|
|
|
|
if (FieldType != F_EDICT || !Dest)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return *(edict_t **)(Dest);
|
|
}
|
|
|
|
char *FieldDef::GetStringValue(Variable *Var)
|
|
{
|
|
return "";
|
|
}
|
|
|
|
void FieldDef::SetValue(Variable *Var, Variable *Value)
|
|
{
|
|
byte *Dest;
|
|
vec3_t data;
|
|
VectorVar *new_var;
|
|
|
|
Dest = GetOffset(Var);
|
|
if (Dest == NULL)
|
|
{
|
|
switch(Offset)
|
|
{
|
|
case SPEC_X:
|
|
Var->GetVectorValue(data);
|
|
data[0] = Value->GetFloatValue();
|
|
new_var = new VectorVar(data);
|
|
*Var = new_var;
|
|
delete new_var;
|
|
break;
|
|
case SPEC_Y:
|
|
Var->GetVectorValue(data);
|
|
data[1] = Value->GetFloatValue();
|
|
new_var = new VectorVar(data);
|
|
*Var = new_var;
|
|
delete new_var;
|
|
break;
|
|
case SPEC_Z:
|
|
Var->GetVectorValue(data);
|
|
data[2] = Value->GetFloatValue();
|
|
new_var = new VectorVar(data);
|
|
*Var = new_var;
|
|
delete new_var;
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
switch(FieldType)
|
|
{
|
|
case F_INT:
|
|
*(int *)(Dest) = Value->GetIntValue();
|
|
break;
|
|
case F_FLOAT:
|
|
*(float *)(Dest) = Value->GetFloatValue();
|
|
break;
|
|
case F_EDICT:
|
|
*(edict_t **)(Dest) = Value->GetEdictValue();
|
|
break;
|
|
case F_VECTOR:
|
|
Value->GetVectorValue(*(vec3_t *)(Dest));
|
|
break;
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
|
|
Event::Event(float NewTime, EventT NewType)
|
|
{
|
|
Time = floor((NewTime + 0.05) * 10) / 10; // avoids stupid math rounding errors
|
|
Type = NewType;
|
|
}
|
|
|
|
Event::Event(FILE *FH, CScript *Script)
|
|
{
|
|
tRead(&Time,FH);
|
|
tRead(&Type,FH);
|
|
tRead(&Priority,FH);
|
|
}
|
|
|
|
void Event::Write(FILE *FH, CScript *Script, int ID)
|
|
{
|
|
fwrite(&ID, 1, sizeof(ID), FH);
|
|
tWrite(&Time,FH);
|
|
tWrite(&Type,FH);
|
|
tWrite(&Priority,FH);
|
|
}
|
|
|
|
bool Event::Process(CScript *Script)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//==========================================================================
|
|
|
|
MoveDoneEvent::MoveDoneEvent(float NewTime, edict_t *NewEnt)
|
|
:Event(NewTime, EVENT_MOVE_DONE)
|
|
{
|
|
Ent = NewEnt;
|
|
|
|
Priority = 10;
|
|
}
|
|
|
|
MoveDoneEvent::MoveDoneEvent(FILE *FH, CScript *Script)
|
|
:Event(FH, Script)
|
|
{
|
|
ReadEnt(&Ent,FH);
|
|
}
|
|
|
|
void MoveDoneEvent::Write(FILE *FH, CScript *Script, int ID)
|
|
{
|
|
Event::Write(FH, Script, RLID_MOVEDONEEVENT);
|
|
WriteEnt(&Ent,FH);
|
|
}
|
|
|
|
bool MoveDoneEvent::Process(CScript *Script)
|
|
{
|
|
if (level.time < Time)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
Script->Move_Done(Ent);
|
|
move_signaler(Ent);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//==========================================================================
|
|
|
|
RotateDoneEvent::RotateDoneEvent(float NewTime, edict_t *NewEnt)
|
|
:Event(NewTime, EVENT_ROTATE_DONE)
|
|
{
|
|
Ent = NewEnt;
|
|
|
|
Priority = 10;
|
|
}
|
|
|
|
RotateDoneEvent::RotateDoneEvent(FILE *FH, CScript *Script)
|
|
:Event(FH, Script)
|
|
{
|
|
ReadEnt(&Ent,FH);
|
|
}
|
|
|
|
void RotateDoneEvent::Write(FILE *FH, CScript *Script, int ID)
|
|
{
|
|
Event::Write(FH, Script, RLID_ROTATEDONEEVENT);
|
|
WriteEnt(&Ent,FH);
|
|
}
|
|
|
|
bool RotateDoneEvent::Process(CScript *Script)
|
|
{
|
|
if (level.time < Time)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
Script->Rotate_Done(Ent);
|
|
rotate_signaler(Ent);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//==========================================================================
|
|
|
|
ExecuteEvent::ExecuteEvent(float NewTime, edict_t *NewOther, edict_t *NewActivator)
|
|
:Event(NewTime, EVENT_SCRIPT_EXECUTE)
|
|
{
|
|
Other = NewOther;
|
|
Activator = NewActivator;
|
|
|
|
Priority = 0;
|
|
}
|
|
|
|
ExecuteEvent::ExecuteEvent(FILE *FH, CScript *Script)
|
|
:Event(FH, Script)
|
|
{
|
|
ReadEnt(&Other,FH);
|
|
ReadEnt(&Activator,FH);
|
|
}
|
|
|
|
void ExecuteEvent::Write(FILE *FH, CScript *Script, int ID)
|
|
{
|
|
Event::Write(FH, Script, RLID_EXECUTEEVENT);
|
|
WriteEnt(&Other,FH);
|
|
WriteEnt(&Activator,FH);
|
|
}
|
|
|
|
bool ExecuteEvent::Process(CScript *Script)
|
|
{
|
|
if (level.time < Time)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (Script->CheckWait())
|
|
{
|
|
Script->Execute(Other,Activator);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//==========================================================================
|
|
|
|
WaitEvent::WaitEvent(float NewTime)
|
|
:Event(NewTime, EVENT_SCRIPT_WAIT)
|
|
{
|
|
Priority = 0;
|
|
}
|
|
|
|
WaitEvent::WaitEvent(FILE *FH, CScript *Script)
|
|
:Event(FH, Script)
|
|
{
|
|
}
|
|
|
|
void WaitEvent::Write(FILE *FH, CScript *Script, int ID)
|
|
{
|
|
Event::Write(FH, Script, RLID_WAITEVENT);
|
|
}
|
|
|
|
bool WaitEvent::Process(CScript *Script)
|
|
{
|
|
if (level.time < Time)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
Script->ClearTimeWait();
|
|
|
|
if (Script->CheckWait())
|
|
{
|
|
Script->Execute(NULL,NULL);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//==========================================================================
|
|
|
|
CScript::CScript(char *ScriptName, edict_t *new_owner)
|
|
{
|
|
Clear(true);
|
|
|
|
owner = new_owner;
|
|
strcpy(Name, ScriptName);
|
|
|
|
LoadFile();
|
|
}
|
|
|
|
CScript::CScript(FILE *FH)
|
|
{
|
|
int index;
|
|
int size;
|
|
int i;
|
|
char name[VAR_LENGTH];
|
|
|
|
Clear(true);
|
|
|
|
fread(Name, 1, sizeof(Name), FH);
|
|
LoadFile();
|
|
|
|
fread(&ScriptCondition, 1, sizeof(ScriptCondition), FH);
|
|
fread(&ConditionInfo, 1, sizeof(ConditionInfo), FH);
|
|
fread(&Length, 1, sizeof(Length), FH);
|
|
fread(&Position, 1, sizeof(Position), FH);
|
|
fread(&DebugFlags, 1, sizeof(DebugFlags), FH);
|
|
|
|
fread(&index, 1, sizeof(index), FH);
|
|
if (index != -1)
|
|
{
|
|
owner = &g_edicts[index];
|
|
owner->Script = this;
|
|
}
|
|
|
|
fread(&index, 1, sizeof(index), FH);
|
|
if (index != -1)
|
|
{
|
|
other = &g_edicts[index];
|
|
}
|
|
|
|
fread(&index, 1, sizeof(index), FH);
|
|
if (index != -1)
|
|
{
|
|
activator = &g_edicts[index];
|
|
}
|
|
|
|
fread(&size, 1, sizeof(size), FH);
|
|
for(i=0;i<size;i++)
|
|
{ // fields - they'll put themselves in
|
|
RestoreObject(FH, ScriptRL, this);
|
|
}
|
|
|
|
fread(&size, 1, sizeof(size), FH);
|
|
for (i=0;i<size;i++)
|
|
{
|
|
fread(&index, 1, sizeof(index), FH);
|
|
fread(name, 1, VAR_LENGTH, FH);
|
|
|
|
VarIndex[index] = FindGlobal(name);
|
|
}
|
|
|
|
fread(&size, 1, sizeof(size), FH);
|
|
for(i=0;i<size;i++)
|
|
{
|
|
LocalVariables.PushBack((Variable *)RestoreObject(FH, ScriptRL, this));
|
|
}
|
|
|
|
fread(&size, 1, sizeof(size), FH);
|
|
for(i=0;i<size;i++)
|
|
{
|
|
ParameterVariables.PushBack((Variable *)RestoreObject(FH, ScriptRL, this));
|
|
}
|
|
|
|
fread(&size, 1, sizeof(size), FH);
|
|
for(i=0;i<size;i++)
|
|
{
|
|
Stack.PushBack((Variable *)RestoreObject(FH, ScriptRL, this));
|
|
}
|
|
|
|
fread(&size, 1, sizeof(size), FH);
|
|
for(i=0;i<size;i++)
|
|
{
|
|
Waiting.PushBack((Variable *)RestoreObject(FH, ScriptRL, this));
|
|
}
|
|
|
|
fread(&size, 1, sizeof(size), FH);
|
|
for(i=0;i<size;i++)
|
|
{
|
|
Signalers.PushBack((Signaler *)RestoreObject(FH, ScriptRL, this));
|
|
}
|
|
|
|
fread(&size, 1, sizeof(size), FH);
|
|
for(i=0;i<size;i++)
|
|
{
|
|
ParameterValues.PushBack((StringVar *)RestoreObject(FH, ScriptRL, this));
|
|
}
|
|
|
|
fread(&size, 1, sizeof(size), FH);
|
|
for(i=0;i<size;i++)
|
|
{
|
|
Events.PushBack((Event *)RestoreObject(FH, ScriptRL, this));
|
|
}
|
|
}
|
|
|
|
CScript::~CScript(void)
|
|
{
|
|
Free(true);
|
|
}
|
|
|
|
void CScript::LoadFile(void)
|
|
{
|
|
int Version;
|
|
|
|
Length = gi.FS_LoadFile(Name, (void **)&Data);
|
|
if (Length == -1)
|
|
{
|
|
Com_Printf("***********************************************\n");
|
|
Com_Printf("Could not open script %s\n",Name);
|
|
Com_Printf("***********************************************\n");
|
|
}
|
|
else
|
|
{
|
|
Version = ReadInt();
|
|
|
|
if (Version != SCRIPT_VERSION)
|
|
{
|
|
Com_Printf("***********************************************\n");
|
|
Com_Printf("Bad script version for %s: found %d, expecting %d\n",Name,Version,SCRIPT_VERSION);
|
|
Com_Printf("***********************************************\n");
|
|
}
|
|
else
|
|
{
|
|
ScriptCondition = COND_READY;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CScript::Free(bool DoData)
|
|
{
|
|
int i;
|
|
List<Variable *>::Iter iv;
|
|
List<Signaler *>::Iter is;
|
|
List<StringVar *>::Iter isv;
|
|
List<Event *>::Iter iev;
|
|
|
|
if (Data && DoData)
|
|
{
|
|
gi.FS_FreeFile(Data);
|
|
Data = NULL;
|
|
}
|
|
|
|
while(LocalVariables.Size())
|
|
{
|
|
iv=LocalVariables.Begin();
|
|
delete (*iv);
|
|
|
|
LocalVariables.Erase(iv);
|
|
}
|
|
|
|
while(ParameterVariables.Size())
|
|
{
|
|
iv=ParameterVariables.Begin();
|
|
delete (*iv);
|
|
|
|
ParameterVariables.Erase(iv);
|
|
}
|
|
|
|
while(Stack.Size())
|
|
{
|
|
iv=Stack.Begin();
|
|
delete (*iv);
|
|
|
|
Stack.Erase(iv);
|
|
}
|
|
|
|
while(Waiting.Size())
|
|
{
|
|
iv=Waiting.Begin();
|
|
delete (*iv);
|
|
|
|
Waiting.Erase(iv);
|
|
}
|
|
|
|
while(Signalers.Size())
|
|
{
|
|
is=Signalers.Begin();
|
|
delete (*is);
|
|
|
|
Signalers.Erase(is);
|
|
}
|
|
|
|
while(ParameterValues.Size())
|
|
{
|
|
isv=ParameterValues.Begin();
|
|
delete (*isv);
|
|
|
|
ParameterValues.Erase(isv);
|
|
}
|
|
|
|
while(Events.Size())
|
|
{
|
|
iev=Events.Begin();
|
|
delete (*iev);
|
|
|
|
Events.Erase(iev);
|
|
}
|
|
|
|
for(i=0;i<MAX_INDEX;i++)
|
|
{
|
|
if (Fields[i])
|
|
{
|
|
delete Fields[i];
|
|
}
|
|
}
|
|
|
|
Clear(DoData);
|
|
}
|
|
|
|
void CScript::Clear(bool DoData)
|
|
{
|
|
if (DoData)
|
|
{
|
|
Data = NULL;
|
|
}
|
|
|
|
owner = other = activator = NULL;
|
|
|
|
memset(Fields, 0, sizeof(Fields));
|
|
memset(VarIndex, 0, sizeof(VarIndex));
|
|
|
|
DebugFlags = 0;
|
|
memset(Name, 0, sizeof(Name));
|
|
|
|
ScriptCondition = COND_COMPLETED;
|
|
ConditionInfo = 0;
|
|
Data = NULL;
|
|
Position = 0;
|
|
Length = 0;
|
|
}
|
|
|
|
void CScript::Write(FILE *FH)
|
|
{
|
|
int index;
|
|
int size;
|
|
List<Variable *>::Iter iv;
|
|
List<Signaler *>::Iter is;
|
|
List<StringVar *>::Iter isv;
|
|
List<Event *>::Iter iev;
|
|
int i;
|
|
|
|
index = RLID_SCRIPT;
|
|
fwrite(&index, 1, sizeof(index), FH);
|
|
|
|
fwrite(Name, 1, sizeof(Name), FH);
|
|
fwrite(&ScriptCondition, 1, sizeof(ScriptCondition), FH);
|
|
fwrite(&ConditionInfo, 1, sizeof(ConditionInfo), FH);
|
|
fwrite(&Length, 1, sizeof(Length), FH);
|
|
fwrite(&Position, 1, sizeof(Position), FH);
|
|
fwrite(&DebugFlags, 1, sizeof(DebugFlags), FH);
|
|
|
|
index = -1;
|
|
if (owner)
|
|
{
|
|
index = owner - g_edicts;
|
|
}
|
|
fwrite(&index, 1, sizeof(index), FH);
|
|
|
|
index = -1;
|
|
if (other)
|
|
{
|
|
index = other - g_edicts;
|
|
}
|
|
fwrite(&index, 1, sizeof(index), FH);
|
|
|
|
index = -1;
|
|
if (activator)
|
|
{
|
|
index = activator - g_edicts;
|
|
}
|
|
fwrite(&index, 1, sizeof(index), FH);
|
|
|
|
size = 0;
|
|
for(i=0,size=0;i<MAX_INDEX;i++)
|
|
{
|
|
if (Fields[i])
|
|
{
|
|
size++;
|
|
}
|
|
}
|
|
fwrite(&size, 1, sizeof(size), FH);
|
|
for(i=0;i<MAX_INDEX;i++)
|
|
{
|
|
if (Fields[i])
|
|
{
|
|
Fields[i]->Write(FH, this);
|
|
}
|
|
}
|
|
|
|
size = 0;
|
|
for (iv=GlobalVariables.Begin();iv != GlobalVariables.End();iv++)
|
|
{
|
|
if (LookupVarIndex(*iv) != -1)
|
|
{
|
|
size++;
|
|
}
|
|
}
|
|
fwrite(&size, 1, sizeof(size), FH);
|
|
for (iv=GlobalVariables.Begin();iv != GlobalVariables.End();iv++)
|
|
{
|
|
index = LookupVarIndex(*iv);
|
|
if (index != -1)
|
|
{
|
|
fwrite(&index, 1, sizeof(index), FH);
|
|
fwrite((*iv)->GetName(), 1, VAR_LENGTH, FH);
|
|
}
|
|
}
|
|
|
|
size = LocalVariables.Size();
|
|
fwrite(&size, 1, sizeof(size), FH);
|
|
for (iv=LocalVariables.Begin();iv != LocalVariables.End();iv++)
|
|
{
|
|
(*iv)->Write(FH, this);
|
|
}
|
|
|
|
size = ParameterVariables.Size();
|
|
fwrite(&size, 1, sizeof(size), FH);
|
|
for (iv=ParameterVariables.Begin();iv != ParameterVariables.End();iv++)
|
|
{
|
|
(*iv)->Write(FH, this);
|
|
}
|
|
|
|
size = Stack.Size();
|
|
fwrite(&size, 1, sizeof(size), FH);
|
|
for (iv=Stack.Begin();iv != Stack.End();iv++)
|
|
{
|
|
(*iv)->Write(FH, this);
|
|
}
|
|
|
|
size = Waiting.Size();
|
|
fwrite(&size, 1, sizeof(size), FH);
|
|
for (iv=Waiting.Begin();iv != Waiting.End();iv++)
|
|
{
|
|
(*iv)->Write(FH, this);
|
|
}
|
|
|
|
size = Signalers.Size();
|
|
fwrite(&size, 1, sizeof(size), FH);
|
|
for (is=Signalers.Begin();is != Signalers.End();is++)
|
|
{
|
|
(*is)->Write(FH, this);
|
|
}
|
|
|
|
|
|
size = ParameterValues.Size();
|
|
fwrite(&size, 1, sizeof(size), FH);
|
|
for (isv=ParameterValues.Begin();isv != ParameterValues.End();isv++)
|
|
{
|
|
(*isv)->Write(FH, this);
|
|
}
|
|
|
|
size = Events.Size();
|
|
fwrite(&size, 1, sizeof(size), FH);
|
|
for (iev=Events.Begin();iev != Events.End();iev++)
|
|
{
|
|
(*iev)->Write(FH, this);
|
|
}
|
|
}
|
|
|
|
int CScript::LookupVarIndex(Variable *Var)
|
|
{
|
|
int i;
|
|
|
|
for(i=0;i<MAX_INDEX;i++)
|
|
{
|
|
if (VarIndex[i] == Var)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
int CScript::LookupFieldIndex(FieldDef *Field)
|
|
{
|
|
int i;
|
|
|
|
for(i=0;i<MAX_INDEX;i++)
|
|
{
|
|
if (Fields[i] == Field)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void CScript::SetParameter(char *Value)
|
|
{
|
|
ParameterValues.PushBack(new StringVar("parm",Value));
|
|
}
|
|
|
|
unsigned char CScript::ReadByte(void)
|
|
{
|
|
return Data[Position++];
|
|
}
|
|
|
|
int CScript::ReadInt(void)
|
|
{
|
|
union
|
|
{
|
|
int oldvalue;
|
|
unsigned char newvalue[4];
|
|
};
|
|
|
|
newvalue[0] = ReadByte();
|
|
newvalue[1] = ReadByte();
|
|
newvalue[2] = ReadByte();
|
|
newvalue[3] = ReadByte();
|
|
|
|
return oldvalue;
|
|
}
|
|
|
|
float CScript::ReadFloat(void)
|
|
{
|
|
union
|
|
{
|
|
float oldvalue;
|
|
unsigned char newvalue[4];
|
|
};
|
|
|
|
newvalue[0] = ReadByte();
|
|
newvalue[1] = ReadByte();
|
|
newvalue[2] = ReadByte();
|
|
newvalue[3] = ReadByte();
|
|
|
|
return oldvalue;
|
|
}
|
|
|
|
char *CScript::ReadString(void)
|
|
{
|
|
char *Pos;
|
|
|
|
Pos = (char *)&Data[Position];
|
|
|
|
while(ReadByte())
|
|
{
|
|
}
|
|
|
|
return Pos;
|
|
}
|
|
|
|
Variable *CScript::ReadDeclaration(int &Index)
|
|
{
|
|
int Type;
|
|
char *Name;
|
|
Variable *RetVal;
|
|
|
|
Name = ReadString();
|
|
Type = ReadByte();
|
|
Index = ReadInt();
|
|
|
|
RetVal = NULL;
|
|
switch(Type)
|
|
{
|
|
case TypeINT:
|
|
RetVal = new IntVar(Name);
|
|
break;
|
|
case TypeFLOAT:
|
|
RetVal = new FloatVar(Name);
|
|
break;
|
|
case TypeVECTOR:
|
|
RetVal = new VectorVar(Name);
|
|
break;
|
|
case TypeENTITY:
|
|
RetVal = new EntityVar(Name);
|
|
break;
|
|
case TypeSTRING:
|
|
RetVal = new StringVar(Name);
|
|
break;
|
|
case TypeUNKNOWN:
|
|
break;
|
|
}
|
|
|
|
if (Index >= MAX_INDEX)
|
|
{
|
|
Error("Index out of range: %d > %d",Index,MAX_INDEX);
|
|
}
|
|
|
|
VarIndex[Index] = RetVal;
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
void CScript::PushStack(Variable *VI)
|
|
{
|
|
if (!VI)
|
|
{
|
|
Error("Illegal push");
|
|
}
|
|
|
|
Stack.PushBack(VI);
|
|
}
|
|
|
|
Variable *CScript::PopStack(void)
|
|
{
|
|
Variable *Value;
|
|
List<Variable *>::Iter iv;
|
|
|
|
if (Stack.Size())
|
|
{
|
|
iv = --Stack.End();
|
|
Value = *iv;
|
|
Stack.PopBack();
|
|
|
|
return Value;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void CScript::HandleGlobal(bool Assignment)
|
|
{
|
|
Variable *Var;
|
|
int Index;
|
|
|
|
Var = ReadDeclaration(Index);
|
|
|
|
if (Assignment)
|
|
{
|
|
Var->ReadValue(this);
|
|
}
|
|
|
|
if (!NewGlobal(Var))
|
|
{
|
|
VarIndex[Index] = FindGlobal(Var->GetName());
|
|
|
|
delete Var;
|
|
}
|
|
}
|
|
|
|
void CScript::HandleLocal(bool Assignment)
|
|
{
|
|
Variable *Var;
|
|
int Index;
|
|
|
|
Var = ReadDeclaration(Index);
|
|
|
|
if (Assignment)
|
|
{
|
|
Var->ReadValue(this);
|
|
}
|
|
|
|
NewLocal(Var);
|
|
}
|
|
|
|
void CScript::HandleParameter(bool Assignment)
|
|
{
|
|
Variable *Var;
|
|
int Index;
|
|
|
|
Var = ReadDeclaration(Index);
|
|
|
|
if (Assignment)
|
|
{
|
|
Var->ReadValue(this);
|
|
}
|
|
|
|
NewParameter(Var);
|
|
}
|
|
|
|
void CScript::HandleField(void)
|
|
{
|
|
int Index;
|
|
FieldDef *NewField;
|
|
|
|
NewField = new FieldDef(this);
|
|
|
|
Index = ReadInt();
|
|
if (Index < 0 || Index >= MAX_INDEX)
|
|
{
|
|
Error("Index for field out of range: %d > %d\n",Index,MAX_INDEX);
|
|
}
|
|
|
|
Fields[Index] = NewField;
|
|
}
|
|
|
|
void CScript::HandleGoto(void)
|
|
{
|
|
Position = ReadInt();
|
|
}
|
|
|
|
Variable *CScript::HandleSpawn(void)
|
|
{
|
|
int Count;
|
|
edict_t *ent;
|
|
Variable *Name;
|
|
Variable *Value;
|
|
field_t *f;
|
|
const char *NameValue;
|
|
byte *b;
|
|
|
|
ent = G_Spawn();
|
|
|
|
for(Count = ReadByte(); Count; Count--)
|
|
{
|
|
Name = PopStack();
|
|
Value = PopStack();
|
|
if (!Name || !Value)
|
|
{
|
|
Error("Invalid stack for HandleSpawn()");
|
|
}
|
|
|
|
NameValue = Name->GetStringValue();
|
|
|
|
for (f=fields ; f->name ; f++)
|
|
{
|
|
if (!Q_stricmp(f->name, (char *)NameValue) )
|
|
{
|
|
if (f->flags & FFL_SPAWNTEMP)
|
|
{
|
|
b = (byte *)&st;
|
|
}
|
|
else
|
|
{
|
|
b = (byte *)ent;
|
|
}
|
|
|
|
switch (f->type)
|
|
{
|
|
case F_LSTRING:
|
|
*(char **)(b+f->ofs) = ED_NewString (Value->GetStringValue());
|
|
break;
|
|
case F_VECTOR:
|
|
Value->GetVectorValue(*(vec3_t *)(b+f->ofs));
|
|
break;
|
|
case F_INT:
|
|
*(int *)(b+f->ofs) = Value->GetIntValue();
|
|
break;
|
|
case F_FLOAT:
|
|
*(float *)(b+f->ofs) = Value->GetFloatValue();
|
|
break;
|
|
case F_ANGLEHACK:
|
|
((float *)(b+f->ofs))[0] = 0;
|
|
((float *)(b+f->ofs))[1] = Value->GetFloatValue();
|
|
((float *)(b+f->ofs))[2] = 0;
|
|
break;
|
|
case F_IGNORE:
|
|
break;
|
|
#ifdef _HERETIC2_
|
|
case F_RGBA:
|
|
break;
|
|
case F_RGB:
|
|
break;
|
|
#endif
|
|
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
ED_CallSpawn(ent);
|
|
|
|
return new EntityVar(ent);
|
|
}
|
|
|
|
Variable *CScript::HandleBuiltinFunction(void)
|
|
{
|
|
int Index;
|
|
edict_t *Search;
|
|
Variable *V1;
|
|
Variable *Var;
|
|
|
|
Index = ReadByte();
|
|
switch(Index)
|
|
{
|
|
case FUNC_FIND_ENTITY_WITH_TARGET:
|
|
V1 = PopStack();
|
|
Search = G_Find(NULL, FOFS(targetname), V1->GetStringValue());
|
|
Var = new EntityVar(Search);
|
|
|
|
delete V1;
|
|
break;
|
|
|
|
case FUNC_SIN:
|
|
V1 = PopStack();
|
|
Var = new FloatVar( "", sin( DEG2RAD(V1->GetFloatValue()) ));
|
|
|
|
delete V1;
|
|
break;
|
|
|
|
case FUNC_COS:
|
|
V1 = PopStack();
|
|
Var = new FloatVar("", cos( DEG2RAD(V1->GetFloatValue()) ));
|
|
|
|
delete V1;
|
|
break;
|
|
|
|
case FUNC_FIND_ENTITY_WITH_SCRIPT:
|
|
V1 = PopStack();
|
|
Search = G_Find(NULL, FOFS(scripttarget), V1->GetStringValue());
|
|
Var = new EntityVar(Search);
|
|
|
|
delete V1;
|
|
break;
|
|
|
|
case FUNC_SPAWN:
|
|
Var = HandleSpawn();
|
|
break;
|
|
|
|
case FUNC_GET_OTHER:
|
|
Var = new EntityVar(other);
|
|
break;
|
|
|
|
case FUNC_GET_ACTIVATOR:
|
|
Var = new EntityVar(activator);
|
|
break;
|
|
}
|
|
|
|
return Var;
|
|
}
|
|
|
|
void CScript::HandlePush(void)
|
|
{
|
|
int Type;
|
|
Variable *Var;
|
|
|
|
Type = ReadByte();
|
|
switch(Type)
|
|
{
|
|
case PUSH_CONST_INT:
|
|
Var = new IntVar();
|
|
Var->ReadValue(this);
|
|
break;
|
|
case PUSH_CONST_FLOAT:
|
|
Var = new FloatVar();
|
|
Var->ReadValue(this);
|
|
break;
|
|
case PUSH_CONST_VECTOR:
|
|
Var = new VectorVar();
|
|
Var->ReadValue(this);
|
|
break;
|
|
case PUSH_CONST_ENTITY:
|
|
Var = new EntityVar();
|
|
Var->ReadValue(this);
|
|
break;
|
|
case PUSH_CONST_STRING:
|
|
Var = new StringVar();
|
|
Var->ReadValue(this);
|
|
break;
|
|
case PUSH_VAR:
|
|
Var = new VariableVar();
|
|
((VariableVar *)Var)->ReadValue(this);
|
|
break;
|
|
case PUSH_VAR_WITH_FIELD:
|
|
Var = new FieldVariableVar();
|
|
((VariableVar *)Var)->ReadValue(this);
|
|
break;
|
|
case PUSH_FUNCTION:
|
|
Var = HandleBuiltinFunction();
|
|
break;
|
|
}
|
|
|
|
PushStack(Var);
|
|
}
|
|
|
|
void CScript::HandlePop(void)
|
|
{
|
|
Variable *V;
|
|
|
|
V = PopStack();
|
|
if (V)
|
|
{
|
|
delete V;
|
|
}
|
|
}
|
|
|
|
void CScript::HandleAssignment(void)
|
|
{
|
|
Variable *Value, *Assignee;
|
|
|
|
Assignee = PopStack();
|
|
Value = PopStack();
|
|
if (Value == NULL || Assignee == NULL)
|
|
{
|
|
Error("Invalid stack for Add");
|
|
}
|
|
|
|
(*Assignee) = Value;
|
|
|
|
delete Assignee;
|
|
delete Value;
|
|
}
|
|
|
|
void CScript::HandleAdd(void)
|
|
{
|
|
Variable *V1, *V2;
|
|
|
|
V1 = PopStack();
|
|
V2 = PopStack();
|
|
if (V1 == NULL || V2 == NULL)
|
|
{
|
|
Error("Invalid stack for Add");
|
|
}
|
|
|
|
PushStack((*V1) + V2);
|
|
|
|
delete V1;
|
|
delete V2;
|
|
}
|
|
|
|
void CScript::HandleSubtract(void)
|
|
{
|
|
Variable *V1, *V2;
|
|
|
|
V1 = PopStack();
|
|
V2 = PopStack();
|
|
if (V1 == NULL || V2 == NULL)
|
|
{
|
|
Error("Invalid stack for Subtract");
|
|
}
|
|
|
|
PushStack((*V1) - V2);
|
|
|
|
delete V1;
|
|
delete V2;
|
|
}
|
|
|
|
void CScript::HandleMultiply(void)
|
|
{
|
|
Variable *V1, *V2;
|
|
|
|
V1 = PopStack();
|
|
V2 = PopStack();
|
|
if (V1 == NULL || V2 == NULL)
|
|
{
|
|
Error("Invalid stack for Multiply");
|
|
}
|
|
|
|
PushStack((*V1) * V2);
|
|
|
|
delete V1;
|
|
delete V2;
|
|
}
|
|
|
|
void CScript::HandleDivide(void)
|
|
{
|
|
Variable *V1, *V2;
|
|
|
|
V1 = PopStack();
|
|
V2 = PopStack();
|
|
if (V1 == NULL || V2 == NULL)
|
|
{
|
|
Error("Invalid stack for Divide");
|
|
}
|
|
|
|
PushStack((*V1) / V2);
|
|
|
|
delete V1;
|
|
delete V2;
|
|
}
|
|
|
|
void CScript::HandleDebug(void)
|
|
{
|
|
List<Variable *>::Iter iv;
|
|
int Flags;
|
|
|
|
Flags = ReadByte();
|
|
|
|
if (Flags)
|
|
{
|
|
if (Flags & DEBUG_ENABLE)
|
|
{
|
|
Flags &= ~DEBUG_ENABLE;
|
|
DebugFlags |= Flags;
|
|
}
|
|
else
|
|
{
|
|
DebugFlags &= ~Flags;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StartDebug();
|
|
|
|
if (ParameterVariables.Size())
|
|
{
|
|
DebugLine(" Parameters:\n");
|
|
for (iv=ParameterVariables.Begin();iv != ParameterVariables.End();iv++)
|
|
{
|
|
(*iv)->Debug(this);
|
|
}
|
|
}
|
|
|
|
if (GlobalVariables.Size())
|
|
{
|
|
DebugLine(" Global Variables:\n");
|
|
for (iv=GlobalVariables.Begin();iv != GlobalVariables.End();iv++)
|
|
{
|
|
(*iv)->Debug(this);
|
|
}
|
|
}
|
|
|
|
if (LocalVariables.Size())
|
|
{
|
|
DebugLine(" Local Variables:\n");
|
|
for (iv=LocalVariables.Begin();iv != LocalVariables.End();iv++)
|
|
{
|
|
(*iv)->Debug(this);
|
|
}
|
|
}
|
|
EndDebug();
|
|
}
|
|
}
|
|
|
|
void CScript::HandleDebugStatement(void)
|
|
{
|
|
DebugLine("%s\n",ReadString());
|
|
}
|
|
|
|
void CScript::HandleAddAssignment(void)
|
|
{
|
|
Variable *Value, *Assignee;
|
|
|
|
Assignee = PopStack();
|
|
Value = PopStack();
|
|
if (Value == NULL || Assignee == NULL)
|
|
{
|
|
Error("Invalid stack for AddAssignment");
|
|
}
|
|
|
|
(*Assignee) = (*Assignee) + Value;
|
|
|
|
delete Assignee;
|
|
delete Value;
|
|
}
|
|
|
|
void CScript::HandleSubtractAssignment(void)
|
|
{
|
|
Variable *Value, *Assignee;
|
|
|
|
Assignee = PopStack();
|
|
Value = PopStack();
|
|
if (Value == NULL || Assignee == NULL)
|
|
{
|
|
Error("Invalid stack for SubtractAssignment");
|
|
}
|
|
|
|
(*Assignee) = (*Assignee) - Value;
|
|
|
|
delete Assignee;
|
|
delete Value;
|
|
}
|
|
|
|
void CScript::HandleMultiplyAssignment(void)
|
|
{
|
|
Variable *Value, *Assignee;
|
|
|
|
Assignee = PopStack();
|
|
Value = PopStack();
|
|
if (Value == NULL || Assignee == NULL)
|
|
{
|
|
Error("Invalid stack for MultiplyAssignment");
|
|
}
|
|
|
|
(*Assignee) = (*Assignee) * Value;
|
|
|
|
delete Assignee;
|
|
delete Value;
|
|
}
|
|
|
|
void CScript::HandleDivideAssignment(void)
|
|
{
|
|
Variable *Value, *Assignee;
|
|
|
|
Assignee = PopStack();
|
|
Value = PopStack();
|
|
if (Value == NULL || Assignee == NULL)
|
|
{
|
|
Error("Invalid stack for DivideAssignment");
|
|
}
|
|
|
|
(*Assignee) = (*Assignee) / Value;
|
|
|
|
delete Assignee;
|
|
delete Value;
|
|
}
|
|
|
|
bool CScript::HandleWait(bool ForAll)
|
|
{
|
|
int count;
|
|
Variable *VI;
|
|
|
|
count = ReadByte();
|
|
if (count & WAIT_CLEAR)
|
|
{
|
|
ConditionInfo = WAIT_CLEAR;
|
|
}
|
|
else
|
|
{
|
|
ConditionInfo = 0;
|
|
}
|
|
|
|
count &= ~WAIT_CLEAR;
|
|
|
|
for(;count;count--)
|
|
{
|
|
VI = PopStack();
|
|
if (!VI)
|
|
{
|
|
Error("Invalid stack for HandleWait");
|
|
}
|
|
|
|
Waiting.PushBack(VI);
|
|
}
|
|
|
|
if (ForAll)
|
|
{
|
|
ScriptCondition = COND_WAIT_ALL;
|
|
}
|
|
else
|
|
{
|
|
ScriptCondition = COND_WAIT_ANY;
|
|
}
|
|
|
|
if (CheckWait())
|
|
{
|
|
FinishWait(NULL,false);
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CScript::HandleTimeWait(void)
|
|
{
|
|
Variable *V;
|
|
float NextTime;
|
|
|
|
V = PopStack();
|
|
if (!V)
|
|
{
|
|
Error("Invalid stack for Time Wait");
|
|
}
|
|
|
|
NextTime = level.time + V->GetFloatValue();
|
|
if (NextTime <= level.time)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
AddEvent(new WaitEvent(NextTime) );
|
|
|
|
ScriptCondition = COND_WAIT_TIME;
|
|
|
|
return true;
|
|
}
|
|
|
|
void CScript::HandleIf(void)
|
|
{
|
|
int Condition;
|
|
int Location;
|
|
Variable *V1, *V2;
|
|
bool Result;
|
|
|
|
Condition = ReadByte();
|
|
Location = ReadInt();
|
|
|
|
V2 = PopStack();
|
|
V1 = PopStack();
|
|
|
|
if (V1 == NULL || V2 == NULL)
|
|
{
|
|
Error("Invalid stack for If");
|
|
}
|
|
|
|
Result = false;
|
|
|
|
switch(Condition)
|
|
{
|
|
case COND_EQUAL:
|
|
if ((*V1) == V2)
|
|
{
|
|
Result = true;
|
|
}
|
|
break;
|
|
case COND_LESS_THAN:
|
|
if ((*V1) < V2)
|
|
{
|
|
Result = true;
|
|
}
|
|
break;
|
|
case COND_LESS_THAN_EQUAL:
|
|
if ((*V1) <= V2)
|
|
{
|
|
Result = true;
|
|
}
|
|
break;
|
|
case COND_GREATER_THAN:
|
|
if ((*V1) > V2)
|
|
{
|
|
Result = true;
|
|
}
|
|
break;
|
|
case COND_GREATER_THAN_EQUAL:
|
|
if ((*V1) >= V2)
|
|
{
|
|
Result = true;
|
|
}
|
|
break;
|
|
case COND_NOT_EQUAL:
|
|
if ((*V1) != V2)
|
|
{
|
|
Result = true;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (!Result)
|
|
{
|
|
Position = Location;
|
|
}
|
|
}
|
|
|
|
void CScript::HandlePrint(void)
|
|
{
|
|
int Flags;
|
|
Variable *Text, *Entity, *Level;
|
|
char *TextValue;
|
|
int LevelValue;
|
|
edict_t *ent;
|
|
#ifdef _HERETIC2_
|
|
int TextIndex;
|
|
#endif
|
|
|
|
Entity = Level = NULL;
|
|
LevelValue = PRINT_HIGH;
|
|
ent = NULL;
|
|
|
|
Flags = ReadByte();
|
|
|
|
Text = PopStack();
|
|
if (!Text)
|
|
{
|
|
Error("Invalid stack for Print");
|
|
}
|
|
if (Text->GetType() == TypeSTRING)
|
|
{
|
|
TextValue = Text->GetStringValue();
|
|
}
|
|
else
|
|
{
|
|
#ifdef _HERETIC2_
|
|
TextIndex = Text->GetIntValue();
|
|
TextValue = message_text[TextIndex].string;
|
|
#else
|
|
TextValue = "";
|
|
#endif
|
|
}
|
|
|
|
if (Flags & PRINT_LEVEL)
|
|
{
|
|
Level = PopStack();
|
|
if (!Level)
|
|
{
|
|
Error("Invalid stack for Print");
|
|
}
|
|
LevelValue = Level->GetIntValue();
|
|
}
|
|
|
|
if (Flags & PRINT_ENTITY)
|
|
{
|
|
Entity = PopStack();
|
|
if (!Entity)
|
|
{
|
|
Error("Invalid stack for Print");
|
|
}
|
|
ent = Entity->GetEdictValue();
|
|
}
|
|
|
|
#ifdef _HERETIC2_
|
|
if (!sv_jumpcinematic->value || !sv_cinematicfreeze->value)
|
|
#endif
|
|
{
|
|
#ifdef _HERETIC2_
|
|
if (Flags & PRINT_CAPTIONED)
|
|
{
|
|
if (ent)
|
|
{
|
|
gi.captionprintf(ent, TextIndex); // Send the ID for the text to the single player
|
|
}
|
|
else
|
|
{
|
|
gi.bcaption(PRINT_HIGH, TextIndex); // Send the ID for the text to all players
|
|
}
|
|
}
|
|
else
|
|
#endif // _HERETIC2_
|
|
if (Flags & PRINT_CENTERED)
|
|
{
|
|
if (ent)
|
|
{
|
|
#ifdef _HERETIC2_
|
|
gi.levelmsg_centerprintf(ent, TextIndex); // Send the ID over the net rather than the string itself...
|
|
#else
|
|
gi.centerprintf(ent, TextValue);
|
|
#endif // _HERETIC2_
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ent)
|
|
{
|
|
gi.cprintf(ent, LevelValue, TextValue);
|
|
}
|
|
else
|
|
{
|
|
gi.bprintf(LevelValue, TextValue);
|
|
}
|
|
}
|
|
}
|
|
|
|
delete Text;
|
|
if (Entity)
|
|
{
|
|
delete Entity;
|
|
}
|
|
if (Level)
|
|
{
|
|
delete Level;
|
|
}
|
|
}
|
|
|
|
void CScript::HandlePlaySound(void)
|
|
{
|
|
int Flags;
|
|
Variable *SoundName, *Entity, *Volume, *Attenuation, *Channel, *TimeDelay;
|
|
char *SoundValue;
|
|
float VolumeValue, AttenuationValue, TimeDelayValue;
|
|
int ChannelValue;
|
|
edict_t *ent;
|
|
|
|
|
|
Entity = Volume = Attenuation = Channel = TimeDelay = NULL;
|
|
ent = NULL;
|
|
VolumeValue = 1.0;
|
|
AttenuationValue = ATTN_NORM;
|
|
|
|
#ifdef _HERETIC2_
|
|
ChannelValue = CHAN_VOICE;
|
|
#else
|
|
ChannelValue = CHAN_AUTO;
|
|
#endif
|
|
|
|
TimeDelayValue = 0.0;
|
|
|
|
Flags = ReadByte();
|
|
|
|
SoundName = PopStack();
|
|
if (!SoundName)
|
|
{
|
|
Error("Invalid stack for PlaySound");
|
|
}
|
|
SoundValue = SoundName->GetStringValue();
|
|
|
|
if (Flags & PLAY_SOUND_TIMEDELAY)
|
|
{
|
|
TimeDelay = PopStack();
|
|
if (!TimeDelay)
|
|
{
|
|
Error("Invalid stack for PlaySound");
|
|
}
|
|
TimeDelayValue = TimeDelay->GetFloatValue();
|
|
}
|
|
|
|
if (Flags & PLAY_SOUND_CHANNEL)
|
|
{
|
|
Channel = PopStack();
|
|
if (!Channel)
|
|
{
|
|
Error("Invalid stack for PlaySound");
|
|
}
|
|
ChannelValue = Channel->GetIntValue();
|
|
}
|
|
|
|
if (Flags & PLAY_SOUND_ATTENUATION)
|
|
{
|
|
Attenuation = PopStack();
|
|
if (!Attenuation)
|
|
{
|
|
Error("Invalid stack for PlaySound");
|
|
}
|
|
AttenuationValue = Attenuation->GetFloatValue();
|
|
}
|
|
|
|
if (Flags & PLAY_SOUND_VOLUME)
|
|
{
|
|
Volume = PopStack();
|
|
if (!Volume)
|
|
{
|
|
Error("Invalid stack for PlaySound");
|
|
}
|
|
VolumeValue = Volume->GetFloatValue();
|
|
}
|
|
|
|
if (Flags & PLAY_SOUND_ENTITY)
|
|
{
|
|
Entity = PopStack();
|
|
if (!Entity)
|
|
{
|
|
Error("Invalid stack for PlaySound");
|
|
}
|
|
ent = Entity->GetEdictValue();
|
|
}
|
|
|
|
#ifdef _HERETIC2_
|
|
if (sv_cinematicfreeze->value) // In cinematic freezes, all sounds should be full volume. Thus is it written.
|
|
{
|
|
AttenuationValue = ATTN_NONE;
|
|
CinematicSound[CinematicSound_cnt].ent = ent;
|
|
CinematicSound[CinematicSound_cnt].channel = ChannelValue;
|
|
|
|
if (CinematicSound_cnt < MAX_CINESNDS-1 )
|
|
++CinematicSound_cnt;
|
|
}
|
|
#endif
|
|
|
|
#ifdef _HERETIC2_
|
|
if (!sv_jumpcinematic->value || !sv_cinematicfreeze->value)
|
|
#endif
|
|
{
|
|
gi.sound(ent, ChannelValue, gi.soundindex(SoundValue), VolumeValue, AttenuationValue, TimeDelayValue);
|
|
}
|
|
|
|
delete SoundName;
|
|
if (Entity)
|
|
{
|
|
delete Entity;
|
|
}
|
|
if (Volume)
|
|
{
|
|
delete Volume;
|
|
}
|
|
if (Attenuation)
|
|
{
|
|
delete Attenuation;
|
|
}
|
|
if (Channel)
|
|
{
|
|
delete Channel;
|
|
}
|
|
if (TimeDelay)
|
|
{
|
|
delete TimeDelay;
|
|
}
|
|
}
|
|
|
|
void CScript::HandleFeature(bool Enable)
|
|
{
|
|
int FeatureType;
|
|
#ifdef _HERETIC2_
|
|
int i,null_snd;
|
|
#endif
|
|
|
|
FeatureType = ReadByte();
|
|
|
|
switch(FeatureType)
|
|
{
|
|
case FEATURE_TRIGGER:
|
|
HandleTrigger(Enable);
|
|
break;
|
|
|
|
case FEATURE_AMBIENT_SOUNDS:
|
|
break;
|
|
|
|
case FEATURE_CINEMATICS:
|
|
#ifdef _HERETIC2_
|
|
if (Enable)
|
|
{
|
|
CinematicSound_cnt = 0;
|
|
Cvar_Set("sv_cinematicfreeze","1");
|
|
remove_non_cinematic_entites(NULL);
|
|
}
|
|
else
|
|
{
|
|
if (sv_jumpcinematic->value == 2) // Jump sent from client
|
|
{
|
|
Cvar_Set("sv_jumpcinematic","0");
|
|
null_snd = gi.soundindex("misc/null.wav");
|
|
gi.bcaption(PRINT_HIGH, 270); // Send the ID for the text to all players
|
|
for (i=0;i<CinematicSound_cnt;++i)
|
|
{
|
|
if (CinematicSound[i].ent) // Does the entity still exist
|
|
{
|
|
gi.sound(CinematicSound[i].ent, CinematicSound[i].channel,
|
|
null_snd, 1, ATTN_NORM, 0);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Cvar_Set("sv_cinematicfreeze","0");
|
|
reinstate_non_cinematic_entites(NULL);
|
|
}
|
|
#endif
|
|
break;
|
|
|
|
case FEATURE_PLAGUE_SKINS:
|
|
#ifdef _HERETIC2_
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CScript::HandleCacheSound(void)
|
|
{
|
|
Variable *SoundName;
|
|
char *SoundValue;
|
|
|
|
#ifdef _HERETIC2_
|
|
// jscott - sound is being cached here, update status bar
|
|
#endif
|
|
|
|
SoundName = PopStack();
|
|
if (!SoundName)
|
|
{
|
|
Error("Invalid stack for HandleChacheSound");
|
|
}
|
|
SoundValue = SoundName->GetStringValue();
|
|
|
|
#ifdef _HERETIC2_
|
|
if (!sv_jumpcinematic->value || !sv_cinematicfreeze->value)
|
|
#endif
|
|
{
|
|
gi.soundindex(SoundValue);
|
|
}
|
|
|
|
delete SoundName;
|
|
}
|
|
|
|
void CScript::HandleMove(void)
|
|
{
|
|
int Flags;
|
|
Variable *Signaler, *Rate, *Duration, *Amount, *Entity;
|
|
edict_t *ent;
|
|
vec3_t Vec,Dest,Diff;
|
|
vec_t Length;
|
|
|
|
Signaler = Rate = Duration = NULL;
|
|
|
|
Flags = ReadByte();
|
|
|
|
if (Flags & MOVE_SIGNALER)
|
|
{
|
|
Signaler = PopStack();
|
|
}
|
|
|
|
if (Flags & MOVE_RATE)
|
|
{
|
|
Rate = PopStack();
|
|
}
|
|
|
|
if (Flags & MOVE_DURATION)
|
|
{
|
|
Duration = PopStack();
|
|
}
|
|
|
|
Amount = PopStack();
|
|
Entity = PopStack();
|
|
|
|
Amount->GetVectorValue(Vec);
|
|
|
|
ent = Entity->GetEdictValue();
|
|
if (ent)
|
|
{
|
|
if (!Rate && !Duration)
|
|
{
|
|
VectorAdd(ent->s.origin, Vec, ent->s.origin);
|
|
if (ent->chain)
|
|
{
|
|
VectorAdd(ent->chain->s.origin, Vec, ent->chain->s.origin);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!(Flags & MOVE_ABSOLUTE))
|
|
{
|
|
VectorAdd(ent->s.origin, Vec, Dest);
|
|
}
|
|
else
|
|
{
|
|
VectorCopy(Vec, Dest);
|
|
}
|
|
|
|
VectorSubtract(ent->s.origin, Dest, Diff);
|
|
Length = VectorLength(Diff);
|
|
|
|
if (Rate && Duration)
|
|
{
|
|
ent->moveinfo.decel = ent->moveinfo.accel = ent->moveinfo.speed = Rate->GetFloatValue();
|
|
Length = Rate->GetFloatValue() * Duration->GetFloatValue();
|
|
VectorNormalize(Diff);
|
|
VectorMA(ent->s.origin, Length, Diff, Dest);
|
|
}
|
|
else if (Rate)
|
|
{
|
|
ent->moveinfo.decel = ent->moveinfo.accel = ent->moveinfo.speed = Rate->GetFloatValue();
|
|
}
|
|
else
|
|
{
|
|
ent->moveinfo.decel = ent->moveinfo.accel = ent->moveinfo.speed = Length / Duration->GetFloatValue();
|
|
}
|
|
|
|
if (DebugFlags & DEBUG_MOVE)
|
|
{
|
|
StartDebug();
|
|
DebugLine(" Moving Entity %d\n",Entity->GetIntValue());
|
|
DebugLine(" From (%7.3f, %7.3f, %7.3f)\n",ent->s.origin[0],ent->s.origin[1],ent->s.origin[2]);
|
|
DebugLine(" To (%7.3f, %7.3f, %7.3f)\n",Dest[0], Dest[1], Dest[2]);
|
|
EndDebug();
|
|
}
|
|
|
|
if (Signaler)
|
|
{
|
|
AddSignaler(ent, Signaler, SIGNAL_MOVE);
|
|
}
|
|
|
|
Move(ent, Dest);
|
|
}
|
|
}
|
|
|
|
delete Amount;
|
|
delete Entity;
|
|
// Signaling routine will handle this
|
|
// if (Signaler)
|
|
// {
|
|
// delete Signaler;
|
|
// }
|
|
if (Rate)
|
|
{
|
|
delete Rate;
|
|
}
|
|
if (Duration)
|
|
{
|
|
delete Duration;
|
|
}
|
|
}
|
|
|
|
void CScript::HandleRotate(void)
|
|
{
|
|
int Flags;
|
|
Variable *Signaler, *Rate, *Duration, *Amount, *Entity;
|
|
edict_t *ent;
|
|
vec3_t Vec,Dest,Diff;
|
|
vec_t Length;
|
|
|
|
Signaler = Rate = Duration = NULL;
|
|
|
|
Flags = ReadByte();
|
|
|
|
if (Flags & ROTATE_SIGNALER)
|
|
{
|
|
Signaler = PopStack();
|
|
}
|
|
|
|
if (Flags & ROTATE_RATE)
|
|
{
|
|
Rate = PopStack();
|
|
}
|
|
|
|
if (Flags & ROTATE_DURATION)
|
|
{
|
|
Duration = PopStack();
|
|
}
|
|
|
|
Amount = PopStack();
|
|
Entity = PopStack();
|
|
|
|
Amount->GetVectorValue(Vec);
|
|
|
|
ent = Entity->GetEdictValue();
|
|
if (ent)
|
|
{
|
|
if (!Rate && !Duration)
|
|
{
|
|
VectorAdd(ent->s.angles, Vec, ent->s.angles);
|
|
if (ent->chain)
|
|
{
|
|
VectorAdd(ent->chain->s.angles, Vec, ent->chain->s.angles);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!(Flags & MOVE_ABSOLUTE))
|
|
{
|
|
VectorAdd(ent->s.angles, Vec, Dest);
|
|
}
|
|
else
|
|
{
|
|
VectorCopy(Vec, Dest);
|
|
}
|
|
|
|
VectorSubtract(ent->s.angles, Dest, Diff);
|
|
Length = VectorLength(Diff);
|
|
|
|
if (Rate && Duration)
|
|
{
|
|
ent->moveinfo.speed = Rate->GetFloatValue();
|
|
Length = Rate->GetFloatValue() * Duration->GetFloatValue();
|
|
VectorNormalize(Diff);
|
|
VectorMA(ent->s.angles, Length, Diff, Dest);
|
|
}
|
|
else if (Rate)
|
|
{
|
|
ent->moveinfo.speed = Rate->GetFloatValue();
|
|
}
|
|
else
|
|
{
|
|
ent->moveinfo.speed = Length / Duration->GetFloatValue();
|
|
}
|
|
|
|
VectorCopy(Dest, ent->moveinfo.start_angles);
|
|
VectorCopy(Dest, ent->moveinfo.end_angles);
|
|
|
|
if (DebugFlags & DEBUG_ROTATE)
|
|
{
|
|
StartDebug();
|
|
DebugLine(" Rotating Entity %d\n",Entity->GetIntValue());
|
|
DebugLine(" From (%7.3f, %7.3f, %7.3f)\n",ent->s.angles[0],ent->s.angles[1],ent->s.angles[2]);
|
|
DebugLine(" To (%7.3f, %7.3f, %7.3f)\n",ent->moveinfo.end_angles[0], ent->moveinfo.end_angles[1], ent->moveinfo.end_angles[2]);
|
|
EndDebug();
|
|
}
|
|
|
|
if (Signaler)
|
|
{
|
|
AddSignaler(ent, Signaler, SIGNAL_ROTATE);
|
|
}
|
|
Rotate(ent);
|
|
}
|
|
}
|
|
|
|
delete Amount;
|
|
delete Entity;
|
|
// Signaling routine will handle this
|
|
// if (Signaler)
|
|
// {
|
|
// delete Signaler;
|
|
// }
|
|
if (Rate)
|
|
{
|
|
delete Rate;
|
|
}
|
|
if (Duration)
|
|
{
|
|
delete Duration;
|
|
}
|
|
}
|
|
|
|
void CScript::HandleUse(void)
|
|
{
|
|
Variable *Entity;
|
|
edict_t *use_ent;
|
|
|
|
Entity = PopStack();
|
|
|
|
use_ent = Entity->GetEdictValue();
|
|
if (use_ent && use_ent->use)
|
|
{
|
|
use_ent->use(use_ent,other,activator);
|
|
}
|
|
|
|
delete Entity;
|
|
}
|
|
|
|
void CScript::HandleTrigger(bool Enable)
|
|
{
|
|
Variable *Entity;
|
|
edict_t *trigger_ent;
|
|
|
|
Entity = PopStack();
|
|
|
|
trigger_ent = Entity->GetEdictValue();
|
|
if (trigger_ent)
|
|
{
|
|
if (Enable)
|
|
{
|
|
trigger_ent->solid = SOLID_TRIGGER;
|
|
trigger_ent->use = Use_Multi;
|
|
gi.linkentity (trigger_ent);
|
|
}
|
|
else
|
|
{
|
|
trigger_ent->solid = SOLID_NOT;
|
|
trigger_ent->use = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CScript::HandleAnimate(void)
|
|
{
|
|
int Flags;
|
|
Variable *Signaler, *Moving, *Turning, *Repeat, *Action, *Entity, *Source;
|
|
edict_t *ent, *SourceEnt;
|
|
vec3_t MovingVal;
|
|
vec3_t TurningVal;
|
|
int RepeatVal, ActionVal;
|
|
|
|
void (*SignalerRoutine)(edict_t*);
|
|
|
|
SignalerRoutine = NULL;
|
|
Signaler = Moving = Turning = Repeat = Action = Entity = Source = NULL;
|
|
SourceEnt = NULL;
|
|
VectorCopy(vec3_origin, MovingVal);
|
|
VectorCopy(vec3_origin, TurningVal);
|
|
RepeatVal = 0;
|
|
|
|
Flags = ReadByte();
|
|
|
|
if (Flags & ANIMATE_SOURCE)
|
|
{
|
|
Source = PopStack();
|
|
SourceEnt = Source->GetEdictValue();
|
|
}
|
|
|
|
if (Flags & ANIMATE_SIGNALER)
|
|
{
|
|
Signaler = PopStack();
|
|
}
|
|
|
|
if (Flags & ANIMATE_MOVING)
|
|
{
|
|
Moving = PopStack();
|
|
Moving->GetVectorValue(MovingVal);
|
|
}
|
|
|
|
if (Flags & ANIMATE_TURNING)
|
|
{
|
|
Turning = PopStack();
|
|
Turning->GetVectorValue(TurningVal);
|
|
}
|
|
|
|
if (Flags & ANIMATE_REPEAT)
|
|
{
|
|
Repeat = PopStack();
|
|
RepeatVal = Repeat->GetIntValue();
|
|
}
|
|
|
|
|
|
Action = PopStack();
|
|
ActionVal = Action->GetIntValue();
|
|
|
|
Entity = PopStack();
|
|
ent = Entity->GetEdictValue();
|
|
|
|
if (ent)
|
|
{
|
|
if (Signaler)
|
|
{
|
|
AddSignaler(ent, Signaler, SIGNAL_ANIMATE);
|
|
SignalerRoutine = animate_signaler;
|
|
}
|
|
|
|
#ifdef _HERETIC2_
|
|
/*
|
|
switch(Action->GetIntValue())
|
|
{ // Hardcoded yuckiness
|
|
case 0:
|
|
PostGameMessage(ent, MSG_C_WALK, PRI_DIRECTIVE, "iig",(int)MovingVal[0],(int)TurningVal[0],SignalerRoutine);
|
|
break;
|
|
case 1:
|
|
PostGameMessage(ent, MSG_C_RUN, PRI_DIRECTIVE, "iig",(int)MovingVal[0],(int)TurningVal[0],SignalerRoutine);
|
|
break;
|
|
case 2:
|
|
PostGameMessage(ent, MSG_C_IDLE, PRI_DIRECTIVE, "ig",(int)TurningVal[0],SignalerRoutine);
|
|
break;
|
|
case 3:
|
|
PostGameMessage(ent, MSG_C_ATTACK1, PRI_DIRECTIVE, "g",SignalerRoutine);
|
|
break;
|
|
case 4:
|
|
PostGameMessage(ent, MSG_C_ATTACK2, PRI_DIRECTIVE, "g",SignalerRoutine);
|
|
break;
|
|
case 5:
|
|
PostGameMessage(ent, MSG_C_ATTACK3, PRI_DIRECTIVE, "g",SignalerRoutine);
|
|
break;
|
|
case 6:
|
|
PostGameMessage(ent, MSG_C_BACKPEDAL, PRI_DIRECTIVE, "iig",(int)MovingVal[0],(int)TurningVal[0],SignalerRoutine);
|
|
break;
|
|
case 7:
|
|
PostGameMessage(ent, MSG_C_DEATH1, PRI_DIRECTIVE,"ig",(int)TurningVal[0],SignalerRoutine);
|
|
break;
|
|
case 8:
|
|
PostGameMessage(ent, MSG_C_PAIN1, PRI_DIRECTIVE,"ig",RepeatVal,SignalerRoutine);
|
|
break;
|
|
case 9:
|
|
PostGameMessage(ent, MSG_C_PAIN2, PRI_DIRECTIVE,"g",SignalerRoutine);
|
|
break;
|
|
default:
|
|
break;
|
|
} */
|
|
|
|
PostGameMessage(ent,(enum G_MsgID_e) msg_animtype[ActionVal], PRI_DIRECTIVE, "iiige",(int)MovingVal[0],(int)TurningVal[0],(int)RepeatVal,SignalerRoutine,activator);
|
|
#endif
|
|
}
|
|
|
|
delete Action;
|
|
delete Entity;
|
|
if (Source)
|
|
{
|
|
delete Source;
|
|
}
|
|
// Signaling routine will handle this
|
|
// if (Signaler)
|
|
// {
|
|
// delete Signaler;
|
|
// }
|
|
if (Repeat)
|
|
{
|
|
delete Repeat;
|
|
}
|
|
if (Turning)
|
|
{
|
|
delete Turning;
|
|
}
|
|
if (Moving)
|
|
{
|
|
delete Moving;
|
|
}
|
|
}
|
|
|
|
|
|
void CScript::HandleCopyPlayerAttributes(void)
|
|
{
|
|
Variable *Player, *Destination;
|
|
edict_t *PlayerEnt, *DestinationEnt;
|
|
|
|
Destination = PopStack();
|
|
if (!Destination)
|
|
{
|
|
Error("Invalid stack for HandleCopyPlayerAttributes()");
|
|
}
|
|
DestinationEnt = Destination->GetEdictValue();
|
|
|
|
Player = PopStack();
|
|
if (!Player)
|
|
{
|
|
Error("Invalid stack for HandleCopyPlayerAttributes()");
|
|
}
|
|
PlayerEnt = Player->GetEdictValue();
|
|
|
|
#ifdef _HERETIC2_
|
|
c_swapplayer (PlayerEnt,DestinationEnt);
|
|
#endif
|
|
}
|
|
|
|
void CScript::HandleSetViewAngles(void)
|
|
{
|
|
Variable *Player, *Angles;
|
|
edict_t *PlayerEnt;
|
|
vec3_t vec;
|
|
#ifdef _HERETIC2_
|
|
vec3_t HoldAngles;
|
|
#endif
|
|
|
|
Angles = PopStack();
|
|
if (!Angles)
|
|
{
|
|
Error("Invalid stack for HandleSetViewAngles()");
|
|
}
|
|
Angles->GetVectorValue(vec);
|
|
|
|
Player = PopStack();
|
|
if (!Player)
|
|
{
|
|
Error("Invalid stack for HandleSetViewAngles()");
|
|
}
|
|
PlayerEnt = Player->GetEdictValue();
|
|
|
|
#ifdef _HERETIC2_
|
|
// use PlayerEnt and vec
|
|
// set angles
|
|
Angles->GetVectorValue(HoldAngles);
|
|
|
|
PlayerEnt->client->ps.pmove.delta_angles[PITCH]=0;
|
|
PlayerEnt->client->ps.pmove.delta_angles[YAW]=ANGLE2SHORT(HoldAngles[YAW]-PlayerEnt->client->resp.cmd_angles[YAW]);
|
|
PlayerEnt->client->ps.pmove.delta_angles[ROLL]=0;
|
|
|
|
PlayerEnt->s.angles[PITCH]=0;
|
|
PlayerEnt->s.angles[YAW]=HoldAngles[YAW];
|
|
PlayerEnt->s.angles[ROLL]=0;
|
|
|
|
#endif
|
|
}
|
|
|
|
void CScript::HandleSetCacheSize(void)
|
|
{
|
|
Variable *CacheSize;
|
|
|
|
CacheSize = PopStack();
|
|
if (!CacheSize)
|
|
{
|
|
Error("Invalid stack for HandleSetCacheSize()");
|
|
}
|
|
|
|
#ifdef _HERETIC2_
|
|
// jscott int size; size = CacheSize->GetIntValue();
|
|
#endif
|
|
}
|
|
|
|
void CScript::Move_Done(edict_t *ent)
|
|
{
|
|
VectorClear (ent->velocity);
|
|
|
|
VectorCopy(ent->moveinfo.end_origin, ent->s.origin);
|
|
}
|
|
|
|
void CScript::Move(edict_t *ent, vec3_t Dest)
|
|
{
|
|
float frames;
|
|
|
|
VectorCopy(Dest, ent->moveinfo.end_origin);
|
|
|
|
VectorSubtract (ent->moveinfo.end_origin, ent->s.origin, ent->moveinfo.dir);
|
|
ent->moveinfo.remaining_distance = VectorNormalize (ent->moveinfo.dir);
|
|
if (ent->moveinfo.remaining_distance <= 0)
|
|
{
|
|
frames = 0;
|
|
}
|
|
else
|
|
{
|
|
frames = floor((ent->moveinfo.remaining_distance / ent->moveinfo.speed) / FRAMETIME) + 1;
|
|
}
|
|
|
|
VectorScale (ent->moveinfo.dir, ent->moveinfo.remaining_distance/frames/FRAMETIME, ent->velocity);
|
|
|
|
AddEvent(new MoveDoneEvent(level.time + (frames * FRAMETIME), ent));
|
|
}
|
|
|
|
void CScript::Rotate_Done (edict_t *ent)
|
|
{
|
|
VectorClear (ent->avelocity);
|
|
}
|
|
|
|
void CScript::Rotate(edict_t *ent)
|
|
{
|
|
float distance;
|
|
vec3_t destdelta;
|
|
float frames;
|
|
|
|
VectorSubtract (ent->moveinfo.start_angles, ent->s.angles, destdelta);
|
|
|
|
distance = VectorNormalize (destdelta);
|
|
if (ent->moveinfo.speed <= 0)
|
|
{
|
|
frames = 0;
|
|
VectorClear (ent->avelocity);
|
|
}
|
|
else
|
|
{
|
|
frames = floor((distance / ent->moveinfo.speed) / FRAMETIME) + 1;
|
|
VectorScale (destdelta, distance/frames/FRAMETIME, ent->avelocity);
|
|
}
|
|
|
|
AddEvent(new RotateDoneEvent(level.time + (frames * FRAMETIME), ent));
|
|
}
|
|
|
|
void CScript::AddEvent(Event *Which)
|
|
{
|
|
List<Event *>::Iter ie;
|
|
float time;
|
|
|
|
if (Events.Size())
|
|
{
|
|
time = Which->GetTime();
|
|
for (ie=Events.Begin();ie != Events.End();ie++)
|
|
{
|
|
if ( (*ie)->GetTime() > time)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
Events.Insert(ie, Which);
|
|
}
|
|
else
|
|
{
|
|
Events.PushBack(Which);
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
float testtime;
|
|
|
|
time = 0;
|
|
for (ie=Events.Begin();ie != Events.End();ie++)
|
|
{
|
|
testtime = (*ie)->GetTime();
|
|
if (testtime < time)
|
|
{
|
|
DebugBreak();
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void CScript::ProcessEvents(void)
|
|
{
|
|
List<Event *>::Iter ie, next;
|
|
|
|
while(Events.Size())
|
|
{
|
|
ie = Events.Begin();
|
|
|
|
if ((*ie)->Process(this))
|
|
{
|
|
delete (*ie);
|
|
Events.Erase(ie);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CScript::ClearTimeWait(void)
|
|
{
|
|
if (ScriptCondition == COND_WAIT_TIME)
|
|
{
|
|
ScriptCondition = COND_READY;
|
|
}
|
|
}
|
|
|
|
void CScript::AddSignaler(edict_t *Edict, Variable *Var, SignalT SignalType)
|
|
{
|
|
List<Signaler *>::Iter is;
|
|
Signaler *NewSig;
|
|
|
|
NewSig = new Signaler(Edict, Var, SignalType);
|
|
|
|
// Note that this check does not need to be in there - signalers are very flexible, but if used
|
|
// incorrectly, they can result in weird behavior - this check prevents more than one command using
|
|
// the same signal varaible prior to a wait command
|
|
for (is=Signalers.Begin();is != Signalers.End();is++)
|
|
{
|
|
if (*(*is) == NewSig)
|
|
{
|
|
Error("Renner Error #1: Variable '%s' is being used for multiple signals", Var->GetName() );
|
|
}
|
|
}
|
|
|
|
Signalers.PushBack(NewSig);
|
|
}
|
|
|
|
void CScript::CheckSignalers(edict_t *Which, SignalT SignalType)
|
|
{
|
|
List<Signaler *>::Iter is, next;
|
|
bool DoCheckWait = false;
|
|
|
|
if (Signalers.Size())
|
|
{
|
|
for (is=Signalers.Begin();is != Signalers.End();is = next)
|
|
{
|
|
next = is;
|
|
next++;
|
|
if ((*is)->Test(Which, SignalType))
|
|
{
|
|
delete (*is);
|
|
Signalers.Erase(is);
|
|
|
|
DoCheckWait = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (DoCheckWait && (ScriptCondition == COND_WAIT_ANY || ScriptCondition == COND_WAIT_ALL))
|
|
{
|
|
if (CheckWait())
|
|
{
|
|
FinishWait(Which, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CScript::CheckWait(void)
|
|
{
|
|
List<Variable *>::Iter iv;
|
|
int count, needed;
|
|
|
|
if (ScriptCondition == COND_WAIT_ALL)
|
|
{
|
|
needed = Waiting.Size();
|
|
}
|
|
else if (ScriptCondition == COND_WAIT_ANY)
|
|
{
|
|
needed = 1;
|
|
}
|
|
else if (ScriptCondition == COND_WAIT_TIME)
|
|
{
|
|
return false;
|
|
}
|
|
else if (ScriptCondition == COND_READY)
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
count = 0;
|
|
if (Waiting.Size())
|
|
{
|
|
for (iv=Waiting.Begin();iv != Waiting.End();iv++)
|
|
{
|
|
if ( (*iv)->GetIntValue())
|
|
{
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (count == needed)
|
|
{
|
|
ScriptCondition = COND_READY;
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void CScript::FinishWait(edict_t *Which, bool NoExecute)
|
|
{
|
|
List<Variable *>::Iter iv;
|
|
|
|
if (Waiting.Size())
|
|
{
|
|
for (iv=Waiting.Begin();iv != Waiting.End();iv++)
|
|
{
|
|
if (ConditionInfo == WAIT_CLEAR)
|
|
{
|
|
(*iv)->ClearSignal();
|
|
}
|
|
|
|
delete *iv;
|
|
}
|
|
}
|
|
Waiting.Erase(Waiting.Begin(), Waiting.End() );
|
|
|
|
if (NoExecute)
|
|
{
|
|
Execute(Which, NULL);
|
|
}
|
|
}
|
|
|
|
void CScript::Error (char *error, ...)
|
|
{
|
|
va_list argptr;
|
|
char text[1024];
|
|
|
|
va_start (argptr, error);
|
|
vsprintf (text, error, argptr);
|
|
va_end (argptr);
|
|
|
|
gi.error(text);
|
|
}
|
|
|
|
void CScript::StartDebug(void)
|
|
{
|
|
DebugLine("-------------------------------\n");
|
|
DebugLine("Script: %s\n",Name);
|
|
DebugLine(" DEBUG at %d\n",Position);
|
|
}
|
|
|
|
void CScript::EndDebug(void)
|
|
{
|
|
DebugLine("-------------------------------\n");
|
|
}
|
|
|
|
void CScript::DebugLine (char *debugtext, ...)
|
|
{
|
|
va_list argptr;
|
|
char text[1024];
|
|
|
|
va_start (argptr, debugtext);
|
|
vsprintf (text, debugtext, argptr);
|
|
va_end (argptr);
|
|
|
|
Com_Printf("%s",text);
|
|
|
|
#ifdef _DEBUG
|
|
OutputDebugString(text);
|
|
#endif
|
|
}
|
|
|
|
void CScript::Think(void)
|
|
{
|
|
ProcessEvents();
|
|
}
|
|
|
|
ScriptConditionT CScript::Execute(edict_t *new_other, edict_t *new_activator)
|
|
{
|
|
bool Done;
|
|
int InstructionCount;
|
|
|
|
if (ScriptCondition != COND_READY)
|
|
{
|
|
return ScriptCondition;
|
|
}
|
|
|
|
if (DebugFlags & DEBUG_TIME)
|
|
{
|
|
StartDebug();
|
|
DebugLine(" Current Time: %10.1f\n",level.time);
|
|
EndDebug();
|
|
}
|
|
|
|
if (new_other)
|
|
{
|
|
other = new_other;
|
|
}
|
|
if (new_activator)
|
|
{
|
|
activator = new_activator;
|
|
}
|
|
|
|
InstructionCount = 0;
|
|
Done = false;
|
|
while (!Done)
|
|
{
|
|
InstructionCount++;
|
|
if (InstructionCount > INSTRUCTION_MAX)
|
|
{
|
|
Error("Runaway loop for script");
|
|
}
|
|
|
|
switch(ReadByte())
|
|
{
|
|
case CODE_NEW_GLOBAL:
|
|
HandleGlobal(false);
|
|
break;
|
|
case CODE_NEW_GLOBAL_PLUS_ASSIGNMENT:
|
|
HandleGlobal(true);
|
|
break;
|
|
case CODE_NEW_LOCAL:
|
|
HandleLocal(false);
|
|
break;
|
|
case CODE_NEW_LOCAL_PLUS_ASSIGNMENT:
|
|
HandleLocal(true);
|
|
break;
|
|
case CODE_NEW_PARAMETER:
|
|
HandleParameter(false);
|
|
break;
|
|
case CODE_NEW_PARAMETER_PLUS_DEFAULT:
|
|
HandleParameter(true);
|
|
break;
|
|
case CODE_FIELD:
|
|
HandleField();
|
|
break;
|
|
case CODE_ASSIGNMENT:
|
|
HandleAssignment();
|
|
break;
|
|
case CODE_ADD:
|
|
HandleAdd();
|
|
break;
|
|
case CODE_SUBTRACT:
|
|
HandleSubtract();
|
|
break;
|
|
case CODE_MULTIPLY:
|
|
HandleMultiply();
|
|
break;
|
|
case CODE_DIVIDE:
|
|
HandleDivide();
|
|
break;
|
|
case CODE_ADD_ASSIGNMENT:
|
|
HandleAddAssignment();
|
|
break;
|
|
case CODE_SUBTRACT_ASSIGNMENT:
|
|
HandleSubtractAssignment();
|
|
break;
|
|
case CODE_MULTIPLY_ASSIGNMENT:
|
|
HandleMultiplyAssignment();
|
|
break;
|
|
case CODE_DIVIDE_ASSIGNMENT:
|
|
HandleDivideAssignment();
|
|
break;
|
|
case CODE_GOTO:
|
|
HandleGoto();
|
|
break;
|
|
case CODE_PUSH:
|
|
HandlePush();
|
|
break;
|
|
case CODE_POP:
|
|
HandlePop();
|
|
break;
|
|
case CODE_IF:
|
|
HandleIf();
|
|
break;
|
|
case CODE_EXIT:
|
|
ScriptCondition = COND_COMPLETED;
|
|
Done = true;
|
|
break;
|
|
case CODE_SUSPEND:
|
|
//ScriptCondition = COND_SUSPENDED;
|
|
Done = true;
|
|
break;
|
|
case CODE_DEBUG:
|
|
HandleDebug();
|
|
break;
|
|
case CODE_WAIT_SECONDS:
|
|
Done = HandleTimeWait();
|
|
break;
|
|
case CODE_WAIT_ALL:
|
|
Done = HandleWait(true);
|
|
break;
|
|
case CODE_WAIT_ANY:
|
|
Done = HandleWait(false);
|
|
break;
|
|
case CODE_MOVE:
|
|
HandleMove();
|
|
break;
|
|
case CODE_ROTATE:
|
|
HandleRotate();
|
|
break;
|
|
case CODE_USE:
|
|
HandleUse();
|
|
break;
|
|
case CODE_COPY_PLAYER_ATTRIBUTES:
|
|
HandleCopyPlayerAttributes();
|
|
break;
|
|
case CODE_SET_VIEW_ANGLES:
|
|
HandleSetViewAngles();
|
|
break;
|
|
case CODE_SET_CACHE_SIZE:
|
|
HandleSetCacheSize();
|
|
break;
|
|
case CODE_ANIMATE:
|
|
HandleAnimate();
|
|
break;
|
|
case CODE_PRINT:
|
|
HandlePrint();
|
|
break;
|
|
case CODE_PLAY_SOUND:
|
|
HandlePlaySound();
|
|
break;
|
|
case CODE_ENABLE:
|
|
HandleFeature(true);
|
|
break;
|
|
case CODE_DISABLE:
|
|
HandleFeature(false);
|
|
break;
|
|
case CODE_DEBUG_STATEMENT:
|
|
HandleDebugStatement();
|
|
break;
|
|
case CODE_CACHE_SOUND:
|
|
HandleCacheSound();
|
|
break;
|
|
default:
|
|
Done = true;
|
|
break;
|
|
}
|
|
|
|
if (Position >= Length)
|
|
{
|
|
Done = true;
|
|
ScriptCondition = COND_COMPLETED;
|
|
}
|
|
}
|
|
|
|
return ScriptCondition;
|
|
}
|
|
|
|
Variable *CScript::FindLocal(char *Name)
|
|
{
|
|
List<Variable *>::Iter iv;
|
|
|
|
if (LocalVariables.Size())
|
|
{
|
|
for (iv=LocalVariables.Begin();iv != LocalVariables.End();iv++)
|
|
{
|
|
if (strcmp(Name, (*iv)->GetName()) == 0)
|
|
{
|
|
return *iv;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
bool CScript::NewLocal(Variable *Which)
|
|
{
|
|
Variable *Check;
|
|
|
|
Check = FindLocal(Which->GetName());
|
|
if (Check)
|
|
{ // already exists
|
|
return false;
|
|
}
|
|
|
|
LocalVariables.PushBack(Which);
|
|
|
|
return true;
|
|
}
|
|
|
|
Variable *CScript::FindParameter(char *Name)
|
|
{
|
|
List<Variable *>::Iter iv;
|
|
|
|
if (ParameterVariables.Size())
|
|
{
|
|
for (iv=ParameterVariables.Begin();iv != ParameterVariables.End();iv++)
|
|
{
|
|
if (strcmp(Name, (*iv)->GetName()) == 0)
|
|
{
|
|
return *iv;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
bool CScript::NewParameter(Variable *Which)
|
|
{
|
|
Variable *Check;
|
|
StringVar *ParmValue;
|
|
edict_t *Search;
|
|
Variable *temp;
|
|
vec3_t vec;
|
|
|
|
Check = FindParameter(Which->GetName());
|
|
if (Check)
|
|
{ // already exists
|
|
return false;
|
|
}
|
|
|
|
ParameterVariables.PushBack(Which);
|
|
|
|
if (!ParameterValues.Size())
|
|
{
|
|
Error("Missing Parameter");
|
|
}
|
|
|
|
ParmValue = *ParameterValues.Begin();
|
|
ParameterValues.Erase(ParameterValues.Begin());
|
|
|
|
switch(Which->GetType())
|
|
{
|
|
case TypeENTITY:
|
|
Search = G_Find(NULL, FOFS(targetname), ParmValue->GetStringValue());
|
|
temp = new EntityVar(Search);
|
|
break;
|
|
|
|
case TypeINT:
|
|
temp = new IntVar("parm",atol(ParmValue->GetStringValue()));
|
|
break;
|
|
|
|
case TypeFLOAT:
|
|
temp = new FloatVar("parm",atof(ParmValue->GetStringValue()));
|
|
break;
|
|
|
|
case TypeVECTOR:
|
|
sscanf (ParmValue->GetStringValue(), "%f %f %f", &vec[0], &vec[1], &vec[2]);
|
|
temp = new VectorVar("parm",vec[0],vec[1],vec[2]);
|
|
break;
|
|
|
|
default:
|
|
delete ParmValue;
|
|
return false;
|
|
break;
|
|
}
|
|
|
|
(*Which) = temp;
|
|
|
|
delete temp;
|
|
delete ParmValue;
|
|
|
|
return true;
|
|
}
|
|
|
|
//==========================================================================
|
|
|