openclonk/src/game/script/C4Script.cpp

6369 lines
215 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
/*
* OpenClonk, http://www.openclonk.org
* Copyright (c) 1998-2000, 2004, 2008 Matthes Bender
* Copyright (c) 2001-2008 Peter Wortmann
* Copyright (c) 2001-2009 Sven Eberhardt
* Copyright (c) 2001 Michael Käser
* Copyright (c) 2004-2005, 2007-2008 Armin Burgmeier
* Copyright (c) 2004-2009 Günther Brammer
*
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
*
* Portions might be copyrighted by other authors who have contributed
* to OpenClonk.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
* See isc_license.txt for full license and disclaimer.
*
* "Clonk" is a registered trademark of Matthes Bender.
* See clonk_trademark_license.txt for full license.
*/
/* Functions mapped by C4Script */
#include <C4Include.h>
#include <C4Script.h>
#include <C4Version.h>
#ifndef BIG_C4INCLUDE
#include <C4Application.h>
#include <C4Object.h>
#include <C4ObjectInfo.h>
#include <C4ObjectCom.h>
#include <C4Random.h>
#include <C4Command.h>
#include <C4Console.h>
#include <C4Viewport.h>
#include <C4Log.h>
#include <C4ObjectInfoList.h>
#include <C4Player.h>
#include <C4ObjectMenu.h>
#include <C4RankSystem.h>
#include <C4PXS.h>
#include <C4MessageInput.h>
#include <C4GameMessage.h>
#include <C4Weather.h>
#include <C4GraphicsResource.h>
#include <C4GraphicsSystem.h>
#include <C4Texture.h>
#include <C4PlayerList.h>
#include <C4Game.h>
#include <C4GameObjects.h>
#include <C4GameControl.h>
#endif
//========================== Some Support Functions =======================================
char pscOSTR[500];
const long MaxFnStringParLen=500;
inline const static char *FnStringPar(C4String *pString)
{
return pString ? pString->GetCStr() : "";
}
inline C4String *String(const char * str)
{
return str ? ::Strings.RegString(str) : NULL;
}
static StdStrBuf FnStringFormat(C4AulContext *cthr, const char *szFormatPar, C4Value * Par0=0, C4Value * Par1=0, C4Value * Par2=0, C4Value * Par3=0,
C4Value * Par4=0, C4Value * Par5=0, C4Value * Par6=0, C4Value * Par7=0, C4Value * Par8=0, C4Value * Par9=0)
{
C4Value * Par[11];
Par[0]=Par0; Par[1]=Par1; Par[2]=Par2; Par[3]=Par3; Par[4]=Par4;
Par[5]=Par5; Par[6]=Par6; Par[7]=Par7; Par[8]=Par8; Par[9]=Par9;
Par[10] = 0;
int cPar=0;
StdStrBuf StringBuf("", false);
const char * cpFormat = szFormatPar;
const char * cpType;
char szField[MaxFnStringParLen+1];
while (*cpFormat)
{
// Copy normal stuff
while (*cpFormat && (*cpFormat!='%'))
StringBuf.AppendChar(*cpFormat++);
// Field
if (*cpFormat=='%')
{
// Scan field type
for (cpType=cpFormat+1; *cpType && (*cpType=='.' || Inside(*cpType,'0','9')); cpType++) {}
// Copy field
SCopy(cpFormat,szField,cpType-cpFormat+1);
// Insert field by type
switch (*cpType)
{
// number
case 'd': case 'x': case 'X': case 'c':
{
if (!Par[cPar]) throw new C4AulExecError(cthr->Obj, "format placeholder without parameter");
StringBuf.AppendFormat(szField, Par[cPar++]->getInt());
cpFormat+=SLen(szField);
break;
}
// C4ID
case 'i':
{
if (!Par[cPar]) throw new C4AulExecError(cthr->Obj, "format placeholder without parameter");
C4ID id = Par[cPar++]->getC4ID();
StringBuf.Append(C4IdText(id));
cpFormat+=SLen(szField);
break;
}
// C4Value
case 'v':
{
if (!Par[cPar]) throw new C4AulExecError(cthr->Obj, "format placeholder without parameter");
StringBuf.Append(static_cast<const StdStrBuf&>(Par[cPar++]->GetDataString()));
cpFormat+=SLen(szField);
break;
}
// String
case 's':
{
// get string
if (!Par[cPar]) throw new C4AulExecError(cthr->Obj, "format placeholder without parameter");
const char *szStr = "(null)";
if (Par[cPar]->GetData())
{
C4String * pStr = Par[cPar++]->getStr();
if (!pStr) throw new C4AulExecError(cthr->Obj, "string format placeholder without string");
szStr = pStr->GetCStr();
}
StringBuf.AppendFormat(szField, szStr);
cpFormat+=SLen(szField);
break;
}
case '%':
StringBuf.AppendChar('%');
cpFormat+=SLen(szField);
break;
// Undefined / Empty
default:
StringBuf.AppendChar('%');
cpFormat++;
break;
}
}
}
return StringBuf;
}
bool CheckEnergyNeedChain(C4Object *pObj, C4ObjectList &rEnergyChainChecked)
{
if (!pObj) return false;
// No recursion, flag check
if (rEnergyChainChecked.GetLink(pObj)) return false;
rEnergyChainChecked.Add(pObj, C4ObjectList::stNone);
// This object needs energy
if (pObj->Def->LineConnect & C4D_Power_Consumer)
if (pObj->NeedEnergy)
return true;
// Check all power line connected structures
C4Object *cline; C4ObjectLink *clnk;
for (clnk=::Objects.First; clnk && (cline=clnk->Obj); clnk=clnk->Next)
if (cline->Status) if (cline->Def->id==C4ID_PowerLine)
if (cline->Action.Target==pObj)
if (CheckEnergyNeedChain(cline->Action.Target2,rEnergyChainChecked))
return true;
return false;
}
DWORD StringBitEval(const char *str)
{
DWORD rval=0;
for (int cpos=0; str && str[cpos]; cpos++)
if ((str[cpos]!='_') && (str[cpos]!=' '))
rval += 1 << cpos;
return rval;
}
typedef int32_t t_int;
typedef bool t_bool;
typedef C4ID t_id;
typedef C4Object *t_object;
typedef C4String *t_string;
typedef C4Value &t_ref;
typedef C4Value &t_any;
typedef C4ValueArray *t_array;
inline t_int getPar_int(C4Value *pVal) { return pVal->getInt(); }
inline t_bool getPar_bool(C4Value *pVal) { return pVal->getBool(); }
inline t_id getPar_id(C4Value *pVal) { return pVal->getC4ID(); }
inline t_object getPar_object(C4Value *pVal) { return pVal->getObj(); }
inline t_string getPar_string(C4Value *pVal) { return pVal->getStr(); }
inline t_ref getPar_ref(C4Value *pVal) { return pVal->GetRefVal(); }
inline t_any getPar_any(C4Value *pVal) { return pVal->GetRefVal(); }
inline t_array getPar_array(C4Value *pVal) { return pVal->getArray(); }
#define PAR(type, name) t_##type name = getPar_##type(pPars++)
// Allow parameters to be nil
template<typename T>
class Nillable
{
bool _nil;
T _val;
public:
inline Nillable(const T &value) : _nil(!value && !C4Value::IsNullableType(C4ValueConv<T>::Type())), _val(value) {}
inline Nillable(const C4NullValue &) : _nil(true), _val(T()) {}
inline bool IsNil() const { return _nil; }
inline operator T() const { return _val; }
inline Nillable<T> &operator =(const T &val)
{
_val = val;
_nil = !val && !C4Value::IsNullableType(C4ValueConv<T>::Type());
return *this;
}
inline Nillable<T> &operator =(const Nillable<T> &val)
{
_val = val._val;
_nil = val._nil;
return *this;
}
// Some operators
inline Nillable<T> &operator ++() { ++_val; return *this; }
inline T operator ++(int) { T v(_val++); return v; }
inline Nillable<T> &operator --() { --_val; return *this; }
inline T operator --(int) { T v(_val--); return v; }
};
template<typename T>
struct C4ValueConv<Nillable<T> >
{
inline static Nillable<T> FromC4V(C4Value &v) { if (v.GetType() == C4V_Any) return C4VNull; else return C4ValueConv<T>::FromC4V(v); }
inline static Nillable<T> _FromC4V(C4Value &v) { if (v.GetType() == C4V_Any) return C4VNull; else return C4ValueConv<T>::_FromC4V(v); }
inline static C4V_Type Type() { return C4ValueConv<T>::Type(); }
inline static C4Value ToC4V(const Nillable<T> &v) { if(v.IsNil()) return C4VNull; else return C4ValueConv<T>::ToC4V(v.operator T()); }
};
template<>
class Nillable<void>
{
public:
inline Nillable(const C4NullValue &) {}
inline bool IsNil() const { return true; }
};
template<>
struct C4ValueConv<Nillable<void> >
{
inline static C4V_Type Type() { return C4VNull.GetType(); }
inline static C4Value ToC4V(const Nillable<void> &) { return C4VNull; }
};
// Some functions require object context.
// Using this type instead of C4AulContext guarantees validity of Obj member.
// Don't add any members to this class, or breakage will occur.
class C4AulObjectContext : public C4AulContext {};
// Some functions are callable in definition context only.
// This exception gets thrown if they are called from anywhere else.
class NeedDefinitionContext : public C4AulExecError
{
public:
NeedDefinitionContext(const char *function) : C4AulExecError(NULL, FormatString("%s: must be called from definition context", function).getData()) {}
};
// Other functions are callable in object context only.
// This exception gets thrown if they are called from anywhere else.
class NeedObjectContext : public C4AulExecError
{
public:
NeedObjectContext(const char *function) : C4AulExecError(NULL, FormatString("%s: must be called from object context", function).getData()) {}
};
// Then there's functions that don't care, but need either defn or object context.
// This exception gets thrown if those are called from global scripts.
class NeedNonGlobalContext : public C4AulExecError
{
public:
NeedNonGlobalContext(const char *function) : C4AulExecError(NULL, FormatString("%s: call must not be from global context", function).getData()) {}
};
// return type of functions returning nil
typedef Nillable<void> C4Void;
//=============================== C4Script Functions ====================================
static C4Object *Fn_this(C4AulContext *cthr)
{
return cthr->Obj;
}
static C4Void Fn_goto(C4AulContext *cthr, long iCounter)
{
Game.Script.Counter=iCounter;
return C4VNull;
}
static bool FnChangeDef(C4AulObjectContext *cthr, C4ID to_id)
{
return !!cthr->Obj->ChangeDef(to_id);
}
static C4Void FnExplode(C4AulObjectContext *cthr, long iLevel, C4ID idEffect, C4String *szEffect)
{
cthr->Obj->Explode(iLevel, idEffect, FnStringPar(szEffect));
return C4VNull;
}
static bool FnIncinerate(C4AulObjectContext *cthr, Nillable<long> causedBy)
{
long iCausedBy = causedBy;
if (causedBy.IsNil()) iCausedBy = cthr->Obj->Controller;
return !!cthr->Obj->Incinerate(iCausedBy);
}
static bool FnIncinerateLandscape(C4AulContext *cthr, long iX, long iY)
{
if (cthr->Obj) { iX += cthr->Obj->GetX(); iY += cthr->Obj->GetY(); }
return !!::Landscape.Incinerate(iX, iY);
}
static bool FnExtinguish(C4AulObjectContext *cthr)
{
// extinguish all fires
return !!cthr->Obj->Extinguish(0);
}
static C4Void FnSetSolidMask(C4AulObjectContext *cthr, long iX, long iY, long iWdt, long iHgt, long iTX, long iTY)
{
cthr->Obj->SetSolidMask(iX,iY,iWdt,iHgt,iTX,iTY);
return C4VNull;
}
static C4Void FnSetGravity(C4AulContext *cthr, long iGravity)
{
::Landscape.Gravity = itofix(BoundBy<long>(iGravity,-300,300)) / 500;
return C4VNull;
}
static long FnGetGravity(C4AulContext *cthr)
{
return fixtoi(::Landscape.Gravity * 500);
}
static C4Void FnDeathAnnounce(C4AulObjectContext *cthr)
{
const long MaxDeathMsg=7;
// Check if crew member has an own death message
*pscOSTR=0;
char *szMsg;
if (cthr->Obj->Info)
if(*(szMsg = cthr->Obj->Info->DeathMessage))
sprintf(pscOSTR, "%s", szMsg);
if (!*pscOSTR)
{
char idDeathMsg[128+1]; sprintf(idDeathMsg, "IDS_OBJ_DEATH%d", 1 + SafeRandom(MaxDeathMsg));
sprintf(pscOSTR,LoadResStr(idDeathMsg) ,cthr->Obj->GetName());
}
if (!Game.C4S.Head.Film)
GameMsgObject(pscOSTR,cthr->Obj);
return C4VNull;
}
static bool FnGrabContents(C4AulObjectContext *cthr, C4Object *from)
{
if (!from) return false;
if (cthr->Obj == from) return false;
cthr->Obj->GrabContents(from);
return true;
}
static bool FnPunch(C4AulObjectContext *cthr, C4Object *target, long punch)
{
if (!target) return false;
return !!ObjectComPunch(cthr->Obj,target,punch);
}
static bool FnKill(C4AulContext *cthr, C4Object *pObj, bool fForced)
{
if (!pObj) pObj=cthr->Obj; if (!pObj) return false;
if (!pObj->GetAlive()) return false;
// Trace kills by player-owned objects
// Do not trace for NO_OWNER, because that would include e.g. the Suicide-rule
if (cthr->Obj && ValidPlr(cthr->Obj->Controller)) pObj->UpdatLastEnergyLossCause(cthr->Obj->Controller);
// Do the kill
pObj->AssignDeath(!!fForced);
return true;
}
static C4Void FnFling(C4AulObjectContext *cthr, long iXDir, long iYDir, long iPrec, bool fAddSpeed)
{
if (!iPrec) iPrec=1;
cthr->Obj->Fling(itofix(iXDir, iPrec),itofix(iYDir, iPrec),fAddSpeed);
// unstick from ground, because Fling command may be issued in an Action-callback,
// where attach-values have already been determined for that frame
cthr->Obj->Action.t_attach=0;
return C4VNull;
}
static bool FnJump(C4AulObjectContext *cthr)
{
return !!ObjectComJump(cthr->Obj);
}
static bool FnEnter(C4AulObjectContext *cthr, C4Object *pTarget)
{
return !!cthr->Obj->Enter(pTarget);
}
static bool FnExit(C4AulObjectContext *cthr, long tx, long ty, long tr, long txdir, long tydir, long trdir)
{
tx+=cthr->Obj->GetX();
ty+=cthr->Obj->GetY();
ObjectComCancelAttach(cthr->Obj);
return !!cthr->Obj->Exit(tx,
ty+cthr->Obj->Shape.y,
tr,
itofix(txdir),itofix(tydir),
itofix(trdir) / 10);
}
static bool FnCollect(C4AulObjectContext *cthr, C4Object *pItem)
{
// local call / safety
if (!pItem) return false;
// check OCF of collector (MaxCarry)
if (cthr->Obj->OCF & OCF_Collection)
// collect
return !!cthr->Obj->Collect(pItem);
// failure
return false;
}
static C4Void FnRemoveObject(C4AulObjectContext *cthr, bool fEjectContents)
{
cthr->Obj->AssignRemoval(fEjectContents);
return C4VNull;
}
static C4Void FnSetPosition(C4AulObjectContext *cthr, long iX, long iY, bool fCheckBounds)
{
if (fCheckBounds)
{
// BoundsCheck takes ref to int and not to long
int32_t i_x = iX, i_y = iY;
cthr->Obj->BoundsCheck(i_x, i_y);
iX = i_x; iY = i_y;
}
cthr->Obj->ForcePosition(iX,iY);
// update liquid
cthr->Obj->UpdateInLiquid();
return C4VNull;
}
static C4Void FnDoCon(C4AulObjectContext *cthr, long iChange) // in percent
{
cthr->Obj->DoCon(FullCon*iChange/100);
return C4VNull;
}
static long FnGetCon(C4AulObjectContext *cthr) // in percent
{
return 100*cthr->Obj->GetCon()/FullCon;
}
static C4Void FnDoEnergy(C4AulObjectContext *cthr, long iChange, bool fExact, Nillable<long> iEngType, Nillable<long> iCausedBy)
{
if (iEngType.IsNil()) iEngType = C4FxCall_EngScript;
if (iCausedBy.IsNil())
//if (cthr->Caller && cthr->Caller->Obj)
// iCausedBy = cthr->Caller->Obj->Controller;
//else
iCausedBy = NO_OWNER;
cthr->Obj->DoEnergy(iChange, fExact, iEngType, iCausedBy);
return C4VNull;
}
static C4Void FnDoBreath(C4AulObjectContext *cthr, long iChange)
{
cthr->Obj->DoBreath(iChange);
return C4VNull;
}
static C4Void FnDoDamage(C4AulObjectContext *cthr, long iChange, Nillable<long> iDmgType, Nillable<long> iCausedBy)
{
if (iDmgType.IsNil()) iDmgType = C4FxCall_DmgScript;
if (iCausedBy.IsNil())
//if (cthr->Caller && cthr->Caller->Obj)
// iCausedBy = cthr->Caller->Obj->Controller;
//else
iCausedBy = NO_OWNER;
cthr->Obj->DoDamage(iChange,iCausedBy, iDmgType);
return C4VNull;
}
static bool FnDoMagicEnergy(C4AulObjectContext *cthr, long iChange, bool fAllowPartial)
{
// Physical modification factor
iChange *= MagicPhysicalFactor;
// Maximum load
if (iChange>0)
if (cthr->Obj->MagicEnergy+iChange>cthr->Obj->GetPhysical()->Magic)
{
if (!fAllowPartial) return false;
iChange = cthr->Obj->GetPhysical()->Magic - cthr->Obj->MagicEnergy;
if (!iChange) return false;
// partial change to max allowed
}
// Insufficient load
if (iChange<0)
if (cthr->Obj->MagicEnergy+iChange<0)
{
if (!fAllowPartial) return false;
iChange = -cthr->Obj->MagicEnergy;
if (!iChange) return false;
// partial change to zero allowed
}
// Change energy level
cthr->Obj->MagicEnergy=BoundBy<long>(cthr->Obj->MagicEnergy+iChange,0,cthr->Obj->GetPhysical()->Magic);
cthr->Obj->ViewEnergy = C4ViewDelay;
return true;
}
static long FnGetMagicEnergy(C4AulObjectContext *cthr)
{
return cthr->Obj->MagicEnergy/MagicPhysicalFactor;
}
enum PhysicalMode
{
PHYS_Current = 0,
PHYS_Permanent = 1,
PHYS_Temporary = 2,
PHYS_StackTemporary = 3
};
static bool FnSetPhysical(C4AulObjectContext *cthr, C4String *szPhysical, long iValue, long iMode)
{
// Get physical offset
C4PhysicalInfo::Offset off;
if (!C4PhysicalInfo::GetOffsetByName(FnStringPar(szPhysical), &off)) return false;
// Set by mode
switch (static_cast<PhysicalMode>(iMode)) // Cast so compiler may warn when new modes are added but not handled
{
// Currently active physical
case PHYS_Current:
// Info objects or temporary mode only
if (!cthr->Obj->PhysicalTemporary) if (!cthr->Obj->Info || Game.Parameters.UseFairCrew) return false;
// Set physical
cthr->Obj->GetPhysical()->*off = iValue;
return true;
// Permanent physical
case PHYS_Permanent:
// Info objects only
if (!cthr->Obj->Info) return false;
// In fair crew mode, changing the permanent physicals is only allowed via TrainPhysical
// Otherwise, stuff like SetPhysical(..., GetPhysical(...)+1, ...) would screw up the crew in fair crew mode
if (Game.Parameters.UseFairCrew) return false;
// Set physical
cthr->Obj->Info->Physical.*off = iValue;
return true;
// Temporary physical
case PHYS_Temporary:
case PHYS_StackTemporary:
// Automatically switch to temporary mode
if (!cthr->Obj->PhysicalTemporary)
{
cthr->Obj->TemporaryPhysical = *(cthr->Obj->GetPhysical());
cthr->Obj->PhysicalTemporary = true;
}
// if old value is to be remembered, register the change
if (iMode == PHYS_StackTemporary)
cthr->Obj->TemporaryPhysical.RegisterChange(off);
// Set physical
cthr->Obj->TemporaryPhysical.*off = iValue;
return true;
}
// Invalid mode
throw new C4AulExecError(cthr->Obj, FormatString("SetPhysical: invalid physical mode %i", iMode).getData());
}
static bool FnTrainPhysical(C4AulObjectContext *cthr, C4String *szPhysical, long iTrainBy, long iMaxTrain)
{
// Get physical offset
C4PhysicalInfo::Offset off;
if (!C4PhysicalInfo::GetOffsetByName(FnStringPar(szPhysical), &off)) return false;
// train it
return cthr->Obj->TrainPhysical(off, iTrainBy, iMaxTrain);
}
static bool FnResetPhysical(C4AulObjectContext *cthr, C4String *sPhysical)
{
const char *szPhysical = FnStringPar(sPhysical);
// Reset to permanent physical
if (!cthr->Obj->PhysicalTemporary) return false;
// reset specified physical only?
if (szPhysical && *szPhysical)
{
C4PhysicalInfo::Offset off;
if (!C4PhysicalInfo::GetOffsetByName(szPhysical, &off)) return false;
if (!cthr->Obj->TemporaryPhysical.ResetPhysical(off)) return false;
// if other physical changes remain, do not reset complete physicals
if (cthr->Obj->TemporaryPhysical.HasChanges(cthr->Obj->GetPhysical(true))) return true;
}
// actual reset of temp physicals
cthr->Obj->PhysicalTemporary = false;
cthr->Obj->TemporaryPhysical.Default();
return true;
}
static Nillable<long> FnGetPhysical(C4AulContext *cthr, C4String *szPhysical, long iMode)
{
// Get physical offset
C4PhysicalInfo::Offset off;
if (!C4PhysicalInfo::GetOffsetByName(FnStringPar(szPhysical), &off)) return C4VNull;
// no object context?
if (!cthr->Obj)
{
// def given?
if (cthr->Def)
{
// get def
// return physical value
return cthr->Def->Physical.*off;
}
return C4VNull;
}
assert(cthr->Obj);
// Get by mode
switch (static_cast<PhysicalMode>(iMode))
{
// Currently active physical
case PHYS_Current:
// Get physical
return cthr->Obj->GetPhysical()->*off;
// Permanent physical
case PHYS_Permanent:
// Info objects only
if (!cthr->Obj->Info) return C4VNull;
// In fair crew mode, scripts may not read permanent physical values - fallback to fair def physical instead!
if (Game.Parameters.UseFairCrew)
if (cthr->Obj->Info->pDef)
return cthr->Obj->Info->pDef->GetFairCrewPhysicals()->*off;
else
return cthr->Obj->Def->GetFairCrewPhysicals()->*off;
// Get physical
return cthr->Obj->Info->Physical.*off;
// Temporary physical
case PHYS_Temporary:
// Info objects only
if (!cthr->Obj->Info) return C4VNull;
// Only if in temporary mode
if (!cthr->Obj->PhysicalTemporary) return C4VNull;
// Get physical
return cthr->Obj->TemporaryPhysical.*off;
}
// Invalid mode
throw new C4AulExecError(cthr->Obj, FormatString("GetPhysical: invalid physical mode %i", iMode).getData());
}
static C4Void FnSetEntrance(C4AulObjectContext *cthr, bool e_status)
{
cthr->Obj->EntranceStatus = e_status;
return C4VNull;
}
static C4Void FnSetXDir(C4AulObjectContext *cthr, long nxdir, long iPrec)
{
// precision (default 10.0)
if (!iPrec) iPrec=10;
// update xdir
cthr->Obj->xdir=itofix(nxdir, iPrec);
// special: negative dirs must be rounded
//if (nxdir<0) pObj->xdir += FIXED100(-50)/iPrec;
cthr->Obj->Mobile=1;
// success
return C4VNull;
}
static C4Void FnSetRDir(C4AulObjectContext *cthr, long nrdir, long iPrec)
{
// precision (default 10.0)
if (!iPrec) iPrec=10;
// update rdir
cthr->Obj->rdir=itofix(nrdir, iPrec);
// special: negative dirs must be rounded
//if (nrdir<0) pObj->rdir += FIXED100(-50)/iPrec;
cthr->Obj->Mobile=1;
// success
return C4VNull;
}
static C4Void FnSetYDir(C4AulObjectContext *cthr, long nydir, long iPrec)
{
// precision (default 10.0)
if (!iPrec) iPrec=10;
// update ydir
cthr->Obj->ydir=itofix(nydir, iPrec);
// special: negative dirs must be rounded
//if (nydir<0) pObj->ydir += FIXED100(-50)/iPrec;
cthr->Obj->Mobile=1;
return C4VNull;
}
static C4Void FnSetR(C4AulObjectContext *cthr, long nr)
{
// set rotation
cthr->Obj->SetRotation(nr);
// success
return C4VNull;
}
static bool FnSetAction(C4AulObjectContext *cthr, C4String *szAction,
C4Object *pTarget, C4Object *pTarget2, bool fDirect)
{
if (!szAction) return false;
return !!cthr->Obj->SetActionByName(FnStringPar(szAction),pTarget,pTarget2,
C4Object::SAC_StartCall | C4Object::SAC_AbortCall,!!fDirect);
}
static bool FnSetBridgeActionData(C4AulObjectContext *cthr, long iBridgeLength, bool fMoveClonk, bool fWall, long iBridgeMaterial)
{
if (!cthr->Obj->Status) return false;
// action must be BRIDGE
if (!cthr->Obj->Action.pActionDef) return false;
if (cthr->Obj->Action.pActionDef->GetPropertyInt(P_Procedure) != DFA_BRIDGE) return false;
// set data
cthr->Obj->Action.SetBridgeData(iBridgeLength, fMoveClonk, fWall, iBridgeMaterial);
return true;
}
static bool FnSetActionData(C4AulObjectContext *cthr, long iData)
{
if (!cthr->Obj->Status) return false;
// bridge: Convert from old style
if (cthr->Obj->Action.pActionDef && (cthr->Obj->Action.pActionDef->GetPropertyInt(P_Procedure) == DFA_BRIDGE))
return FnSetBridgeActionData(cthr, 0, false, false, iData);
// attach: check for valid vertex indices
if (cthr->Obj->Action.pActionDef && (cthr->Obj->Action.pActionDef->GetPropertyInt(P_Procedure) == DFA_ATTACH)) // Fixed Action.Act check here... matthes
if (((iData&255) >= C4D_MaxVertex) || ((iData>>8) >= C4D_MaxVertex))
return false;
// set data
cthr->Obj->Action.Data = iData;
return true;
}
static long FnGetActionData(C4AulObjectContext *cthr)
{
// get data
return cthr->Obj->Action.Data;
}
static C4Void FnSetComDir(C4AulObjectContext *cthr, long ncomdir)
{
cthr->Obj->Action.ComDir=ncomdir;
return C4VNull;
}
static C4Void FnSetDir(C4AulObjectContext *cthr, long ndir)
{
cthr->Obj->SetDir(ndir);
return C4VNull;
}
static C4Void FnSetCategory(C4AulObjectContext *cthr, long iCategory)
{
if (!(iCategory & C4D_SortLimit)) iCategory |= (cthr->Obj->Category & C4D_SortLimit);
cthr->Obj->SetCategory(iCategory);
return C4VNull;
}
static C4Void FnSetAlive(C4AulObjectContext *cthr, bool nalv)
{
cthr->Obj->SetAlive(nalv);
return C4VNull;
}
static bool FnSetOwner(C4AulObjectContext *cthr, long iOwner)
{
// Set owner
return !!cthr->Obj->SetOwner(iOwner);
}
static bool FnSetPhase(C4AulObjectContext *cthr, long iVal)
{
return !!cthr->Obj->SetPhase(iVal);
}
static bool FnExecuteCommand(C4AulObjectContext *cthr)
{
return !!cthr->Obj->ExecuteCommand();
}
static C4Value FnSetCommand(C4AulContext *cthr, C4Value *pPars)
{
PAR(string, szCommand); PAR(object, pTarget); PAR(any, Tx); PAR(int, iTy);
PAR(object, pTarget2); PAR(any, Data); PAR(int, iRetries);
// Object
if (!cthr->Obj)
throw NeedObjectContext("SetCommand");
// Command
if (!szCommand) return C4VFalse;
long iCommand = CommandByName(FnStringPar(szCommand));
if (!iCommand) { cthr->Obj->ClearCommands(); return C4VFalse; }
// Special: convert iData to szText
C4String *szText=NULL;
if (iCommand==C4CMD_Call)
szText=Data.getStr();
else
Tx.ConvertTo(C4V_Int);
// Set
cthr->Obj->SetCommand(iCommand,pTarget,Tx,iTy,pTarget2,false,Data,iRetries,szText);
// Success
return C4VTrue;
}
static C4Value FnAddCommand(C4AulContext *cthr, C4Value *pPars)
{
PAR(string, szCommand); PAR(object, pTarget); PAR(any, Tx); PAR(int, iTy);
PAR(object, pTarget2); PAR(int, iUpdateInterval); PAR(any, Data); PAR(int, iRetries); PAR(int, iBaseMode);
// Object
if (!cthr->Obj)
throw NeedObjectContext("AddCommand");
// Command
if (!szCommand) return C4VFalse;
long iCommand = CommandByName(FnStringPar(szCommand));
if (!iCommand) return C4VFalse;
// Special: convert iData to szText
C4String *szText=NULL;
if (iCommand==C4CMD_Call)
szText=Data.getStr();
else
Tx.ConvertTo(C4V_Int);
// Add
return C4VBool(cthr->Obj->AddCommand(iCommand,pTarget,Tx,iTy,iUpdateInterval,pTarget2,true,Data,false,iRetries,szText,iBaseMode));
}
static C4Value FnAppendCommand(C4AulContext *cthr, C4Value *pPars)
{
PAR(string, szCommand); PAR(object, pTarget); PAR(any, Tx); PAR(int, iTy);
PAR(object, pTarget2); PAR(int, iUpdateInterval); PAR(any, Data); PAR(int, iRetries); PAR(int, iBaseMode);
// Object
if (!cthr->Obj)
throw NeedObjectContext("AppendCommand");
// Command
if (!szCommand) return C4VFalse;
long iCommand = CommandByName(FnStringPar(szCommand));
if (!iCommand) return C4VFalse;
// Special: convert iData to szText
C4String *szText=NULL;
if (iCommand==C4CMD_Call)
szText=Data.getStr();
else
Tx.ConvertTo(C4V_Int);
// Add
return C4VBool(cthr->Obj->AddCommand(iCommand,pTarget,Tx,iTy,iUpdateInterval,pTarget2,true,Data,true,iRetries,szText,iBaseMode));
}
static C4Value FnGetCommand(C4AulContext *cthr, C4Value *pPars)
{
PAR(int, iElement); PAR(int, iCommandNum);
// safety
if (!cthr->Obj)
throw NeedObjectContext("GetCommand");
C4Command * Command = cthr->Obj->Command;
// Move through list to Command iCommandNum
while (Command && iCommandNum--) Command = Command->Next;
// Object has no command or iCommandNum was to high or < 0
if (!Command) return C4VNull;
// Return command element
switch (iElement)
{
case 0: // Name
return C4VString(CommandName(Command->Command));
case 1: // Target
return C4VObj(Command->Target);
case 2: // Tx
return Command->Tx;
case 3: // Ty
return C4VInt(Command->Ty);
case 4: // Target2
return C4VObj(Command->Target2);
case 5: // Data
return Command->Command == C4CMD_Call ? C4VString(Command->Text) : Command->Data;
}
// Undefined element
return C4VNull;
}
static bool FnFinishCommand(C4AulObjectContext *cthr, bool fSuccess, long iCommandNum)
{
C4Command * Command = cthr->Obj->Command;
// Move through list to Command iCommandNum
while (Command && iCommandNum--) Command = Command->Next;
// Object has no command or iCommandNum was to high or < 0
if (!Command) return false;
if (!fSuccess) ++(Command->Failures);
else Command->Finished = true;
return true;
}
static C4Value FnPlayerObjectCommand(C4AulContext *cthr, C4Value *pPars)
{
PAR(int, iPlr); PAR(string, szCommand); PAR(object, pTarget); PAR(any, Tx); PAR(int, iTy);
PAR(object, pTarget2); PAR(any, Data);
// Player
if (!ValidPlr(iPlr) || !szCommand) return C4VFalse;
C4Player *pPlr = ::Players.Get(iPlr);
// Command
long iCommand = CommandByName(FnStringPar(szCommand)); if (!iCommand) return C4VFalse;
// Special: convert iData to szText
const char *szText=NULL;
int32_t iTx;
if (iCommand==C4CMD_Call)
{
szText=FnStringPar(Data.getStr());
iTx=Tx.GetData().Int;
}
else
{
iTx=Tx.getInt();
}
// Set
pPlr->ObjectCommand(iCommand, pTarget, iTx, iTy, pTarget2, Data, C4P_Command_Set);
// Success
return C4VTrue;
}
static C4String *FnGetAction(C4AulObjectContext *cthr)
{
if (!cthr->Obj->Action.pActionDef) return String("Idle");
return String(cthr->Obj->Action.pActionDef->GetName());
}
static C4PropList * FnCreatePropList(C4AulContext *cthr, C4PropList * prototype)
{
return new C4PropList(prototype);
}
static C4Value FnGetProperty_C4V(C4AulContext *cthr, C4Value * key_C4V, C4Value * pObj_C4V)
{
C4PropList * pObj = pObj_C4V->_getPropList();
if (!pObj) pObj=cthr->Obj;
if (!pObj) pObj=cthr->Def;
if (!pObj) return C4VNull;
C4String * key = key_C4V->_getStr();
if(!key) return C4VNull;
C4Value r;
pObj->GetProperty(key, r);
return r;
}
static C4Value FnSetProperty_C4V(C4AulContext *cthr, C4Value * key_C4V, C4Value * to, C4Value * pObj_C4V)
{
C4PropList * pObj = pObj_C4V->_getPropList();
if (!pObj) pObj=cthr->Obj;
if (!pObj) pObj=cthr->Def;
if (!pObj) return C4VFalse;
C4String * key = key_C4V->_getStr();
if(!key) return C4VFalse;
pObj->SetProperty(key, *to);
return C4VTrue;
}
static C4String *FnGetName(C4AulContext *cthr)
{
if (!cthr->Obj)
if (!cthr->Def)
throw new NeedNonGlobalContext("GetName");
else
return String(cthr->Def->GetName());
else
return String(cthr->Obj->GetName());
}
static bool FnSetName(C4AulContext *cthr, C4String *pNewName, bool fSetInInfo, bool fMakeValidIfExists)
{
if (!cthr->Obj)
{
if (!cthr->Def)
throw new NeedNonGlobalContext("SetName");
else if (fSetInInfo)
return false;
// Definition name
cthr->Def->SetName(FnStringPar(pNewName));
return true;
} else {
// Object name
if (fSetInInfo)
{
// setting name in info
C4ObjectInfo *pInfo = cthr->Obj->Info;
if (!pInfo) return false;
const char *szName = pNewName->GetCStr();
// empty names are bad; e.g., could cause problems in savegames
if (!szName || !*szName) return false;
// name must not be too long
if (SLen(szName) > C4MaxName) return false;
// any change at all?
if (SEqual(szName, pInfo->Name)) return true;
// make sure names in info list aren't duplicated
// querying owner info list here isn't 100% accurate, as infos might have been stolen by other players
// however, there is no good way to track the original list ATM
C4ObjectInfoList *pInfoList = NULL;
C4Player *pOwner = ::Players.Get(cthr->Obj->Owner);
if (pOwner) pInfoList = &pOwner->CrewInfoList;
char NameBuf[C4MaxName+1];
if (pInfoList) if (pInfoList->NameExists(szName))
{
if (!fMakeValidIfExists) return false;
SCopy(szName, NameBuf, C4MaxName);
pInfoList->MakeValidName(NameBuf);
szName = NameBuf;
}
SCopy(szName, pInfo->Name, C4MaxName);
cthr->Obj->SetName(); // make sure object uses info name
}
else
{
if (!pNewName) cthr->Obj->SetName();
else cthr->Obj->SetName(pNewName->GetCStr());
}
}
return true;
}
static C4String *FnGetDesc(C4AulContext *cthr)
{
assert(!cthr->Obj || cthr->Def);
// find def
if (!cthr->Def)
throw new NeedNonGlobalContext("GetDesc");
// return desc
return String(cthr->Def->GetDesc());
}
static C4String *FnGetPlayerName(C4AulContext *cthr, long iPlayer)
{
if (!ValidPlr(iPlayer)) return NULL;
return String(::Players.Get(iPlayer)->GetName());
}
static C4String *FnGetTaggedPlayerName(C4AulContext *cthr, long iPlayer)
{
C4Player *pPlr = ::Players.Get(iPlayer);
if (!pPlr) return NULL;
DWORD dwClr = pPlr->ColorDw; C4GUI::MakeColorReadableOnBlack(dwClr);
return String(FormatString("<c %x>%s</c>", dwClr&0xffffff, pPlr->GetName()).getData());
}
static long FnGetPlayerType(C4AulContext *cthr, long iPlayer)
{
C4Player *pPlr = ::Players.Get(iPlayer);
if (!pPlr) return 0;
return pPlr->GetType();
}
static C4Object *FnGetActionTarget(C4AulObjectContext *cthr, long target_index)
{
if (target_index==0) return cthr->Obj->Action.Target;
if (target_index==1) return cthr->Obj->Action.Target2;
return NULL;
}
static C4Void FnSetActionTargets(C4AulObjectContext *cthr, C4Object *pTarget1, C4Object *pTarget2)
{
// set targets
cthr->Obj->Action.Target=pTarget1;
cthr->Obj->Action.Target2=pTarget2;
return C4VNull;
}
static long FnGetDir(C4AulObjectContext *cthr)
{
return cthr->Obj->Action.Dir;
}
static bool FnGetEntrance(C4AulObjectContext *cthr)
{
return cthr->Obj->EntranceStatus;
}
static long FnGetPhase(C4AulObjectContext *cthr)
{
return cthr->Obj->Action.Phase;
}
static long FnGetEnergy(C4AulObjectContext *cthr)
{
return 100*cthr->Obj->Energy/C4MaxPhysical;
}
static long FnGetBreath(C4AulObjectContext *cthr)
{
return 100*cthr->Obj->Breath/C4MaxPhysical;
}
static long FnGetMass(C4AulContext *cthr)
{
if (!cthr->Obj)
if (!cthr->Def)
throw new NeedNonGlobalContext("GetMass");
else
return cthr->Def->Mass;
else
return cthr->Obj->Mass;
}
static long FnGetRDir(C4AulObjectContext *cthr, long iPrec)
{
if (!iPrec) iPrec = 10;
return fixtoi(cthr->Obj->rdir, iPrec);
}
static long FnGetXDir(C4AulObjectContext *cthr, long iPrec)
{
if (!iPrec) iPrec = 10;
return fixtoi(cthr->Obj->xdir, iPrec);
}
static long FnGetYDir(C4AulObjectContext *cthr, long iPrec)
{
if (!iPrec) iPrec = 10;
return fixtoi(cthr->Obj->ydir, iPrec);
}
static long FnGetR(C4AulObjectContext *cthr)
{
// Adjust range
long iR = cthr->Obj->r;
while (iR>180) iR-=360;
while (iR<-180) iR+=360;
return iR;
}
static long FnGetComDir(C4AulObjectContext *cthr)
{
return cthr->Obj->Action.ComDir;
}
static Nillable<long> FnGetX(C4AulContext *cthr)
{
if (!cthr->Obj) return C4VNull;
return cthr->Obj->GetX();
}
static long FnGetVertexNum(C4AulObjectContext *cthr)
{
return cthr->Obj->Shape.VtxNum;
}
enum VertexDataIndex
{
VTX_X,
VTX_Y,
VTX_CNAT,
VTX_Friction
};
enum VertexUpdateMode
{
VTX_SetNonpermanent,
VTX_SetPermanent,
VTX_SetPermanentUpd
};
static Nillable<long> FnGetVertex(C4AulObjectContext *cthr, long iIndex, long iValueToGet)
{
if (cthr->Obj->Shape.VtxNum<1) return C4VNull;
iIndex=Min<long>(iIndex,cthr->Obj->Shape.VtxNum-1);
switch (static_cast<VertexDataIndex>(iValueToGet))
{
case VTX_X: return cthr->Obj->Shape.VtxX[iIndex]; break;
case VTX_Y: return cthr->Obj->Shape.VtxY[iIndex]; break;
case VTX_CNAT: return cthr->Obj->Shape.VtxCNAT[iIndex]; break;
case VTX_Friction: return cthr->Obj->Shape.VtxFriction[iIndex]; break;
default:
DebugLog(FormatString("GetVertex: Unknown vertex attribute: %ld", iValueToGet).getData());
return C4VNull;
break;
}
// impossible mayhem!
assert(!"FnGetVertex: unreachable code reached");
return C4VNull;
}
static bool FnSetVertex(C4AulObjectContext *cthr, long iIndex, long iValueToSet, long iValue, long iOwnVertexMode)
{
// own vertex mode?
if (iOwnVertexMode)
{
// enter own custom vertex mode if not already set
if (!cthr->Obj->fOwnVertices)
{
cthr->Obj->Shape.CreateOwnOriginalCopy(cthr->Obj->Def->Shape);
cthr->Obj->fOwnVertices = 1;
}
// set vertices at end of buffer
iIndex += C4D_VertexCpyPos;
}
// range check
if (!Inside<long>(iIndex,0,C4D_MaxVertex-1)) return false;
// set desired value
switch (static_cast<VertexDataIndex>(iValueToSet))
{
case VTX_X: cthr->Obj->Shape.VtxX[iIndex]=iValue; break;
case VTX_Y: cthr->Obj->Shape.VtxY[iIndex]=iValue; break;
case VTX_CNAT: cthr->Obj->Shape.VtxCNAT[iIndex]=iValue; break;
case VTX_Friction: cthr->Obj->Shape.VtxFriction[iIndex]=iValue; break;
default:
DebugLogF("SetVertex: Unknown vertex attribute: %ld", iValueToSet);
return false;
break;
}
// vertex update desired?
if (iOwnVertexMode==VTX_SetPermanentUpd) cthr->Obj->UpdateShape(true);
return true;
}
static bool FnAddVertex(C4AulObjectContext *cthr, long iX, long iY)
{
return !!cthr->Obj->Shape.AddVertex(iX,iY);
}
static bool FnRemoveVertex(C4AulObjectContext *cthr, long iIndex)
{
return !!cthr->Obj->Shape.RemoveVertex(iIndex);
}
static C4Void FnSetContactDensity(C4AulObjectContext *cthr, long iDensity)
{
cthr->Obj->Shape.ContactDensity = iDensity;
return C4VNull;
}
static Nillable<long> FnGetY(C4AulContext *cthr)
{
if (!cthr->Obj) return C4VNull;
return cthr->Obj->GetY();
}
static bool FnGetAlive(C4AulObjectContext *cthr)
{
return cthr->Obj->GetAlive();
}
static long FnGetOwner(C4AulObjectContext *cthr)
{
return cthr->Obj->Owner;
}
static long FnGetController(C4AulObjectContext *cthr)
{
return cthr->Obj->Controller;
}
static bool FnSetController(C4AulObjectContext *cthr, long iNewController)
{
// validate player
if (iNewController != NO_OWNER && !ValidPlr(iNewController)) return false;
// Set controller
cthr->Obj->Controller = iNewController;
return true;
}
static long FnGetKiller(C4AulObjectContext *cthr)
{
return cthr->Obj->LastEnergyLossCausePlayer;
}
static bool FnSetKiller(C4AulObjectContext *cthr, long iNewKiller)
{
// validate player
if (iNewKiller != NO_OWNER && !ValidPlr(iNewKiller)) return false;
// set killer as last energy loss cause
cthr->Obj->LastEnergyLossCausePlayer = iNewKiller;
return true;
}
static long FnGetCategory(C4AulContext *cthr)
{
if (!cthr->Obj)
if (!cthr->Def)
throw new NeedNonGlobalContext("GetCategory");
else
return cthr->Def->Category;
else
return cthr->Obj->Category;
}
static long FnGetOCF(C4AulObjectContext *cthr)
{
return cthr->Obj->OCF;
}
static long FnGetDamage(C4AulObjectContext *cthr)
{
return cthr->Obj->Damage;
}
static long FnGetValue(C4AulContext *cthr, C4Object *pInBase, long iForPlayer)
{
if (!cthr->Obj)
if (!cthr->Def)
throw new NeedNonGlobalContext("GetValue");
else
return cthr->Def->GetValue(pInBase, iForPlayer);
else
return cthr->Obj->GetValue(pInBase, iForPlayer);
}
static long FnGetRank(C4AulObjectContext *cthr)
{
if (!cthr->Obj->Info) return 0;
return cthr->Obj->Info->Rank;
}
static long FnGetActTime(C4AulObjectContext *cthr)
{
return cthr->Obj->Action.Time;
}
static C4ID FnGetID(C4AulObjectContext *cthr)
{
// return id of object
return cthr->Obj->Def->id;
}
static long FnGetBase(C4AulObjectContext *cthr)
{
return cthr->Obj->Base;
}
static Nillable<C4ID> FnGetMenu(C4AulObjectContext *cthr)
{
if (cthr->Obj->Menu && cthr->Obj->Menu->IsActive())
return C4ID(cthr->Obj->Menu->GetIdentification());
return C4VNull;
}
static bool FnCreateMenu(C4AulObjectContext *cthr, C4ID iSymbol, C4Object *pCommandObj,
long iExtra, C4String *szCaption, long iExtraData,
long iStyle, bool fPermanent, C4ID idMenuID)
{
if (pCommandObj)
// object menu: Validate object
if (!pCommandObj->Status) return false;
// else scenario script callback: No command object OK
// Create symbol
C4Def *pDef;
C4FacetSurface fctSymbol;
fctSymbol.Create(C4SymbolSize,C4SymbolSize);
if (pDef = C4Id2Def(iSymbol)) pDef->Draw(fctSymbol);
// Clear any old menu, init new menu
if (!cthr->Obj->CloseMenu(false)) return false;
if (!cthr->Obj->Menu) cthr->Obj->Menu = new C4ObjectMenu; else cthr->Obj->Menu->ClearItems(true);
cthr->Obj->Menu->Init(fctSymbol,FnStringPar(szCaption),pCommandObj,iExtra,iExtraData,idMenuID ? idMenuID : iSymbol,iStyle,true);
// Set permanent
cthr->Obj->Menu->SetPermanent(fPermanent);
return true;
}
const int C4MN_Add_ImgRank = 1,
C4MN_Add_ImgIndexed = 2,
C4MN_Add_ImgObjRank = 3,
C4MN_Add_ImgObject = 4,
C4MN_Add_ImgTextSpec = 5,
C4MN_Add_ImgColor = 6,
C4MN_Add_MaxImage = 127, // mask for param which decides what to draw as the menu symbol
C4MN_Add_PassValue = 128,
C4MN_Add_ForceCount = 256,
C4MN_Add_ForceNoDesc = 512;
#ifndef _MSC_VER
#define _snprintf snprintf
#endif
static C4Value FnAddMenuItem(C4AulContext *cthr, C4Value *pPars)
{
PAR(string, szCaption);
PAR(string, szCommand);
PAR(id, idItem);
PAR(int, iCount);
PAR(any, Parameter);
PAR(string, szInfoCaption);
PAR(int, iExtra);
PAR(any, XPar);
PAR(any, XPar2);
if (!cthr->Obj)
throw new NeedObjectContext("AddMenuItem");
if (!cthr->Obj->Menu) return C4VFalse;
char caption[256+1];
char parameter[256+1];
char dummy[256+1];
char command[512+1];
char command2[512+1];
char infocaption[C4MaxTitle+1];
// get needed symbol size
int iSymbolSize = cthr->Obj->Menu->GetSymbolSize();
// Check specified def
C4Def *pDef = C4Id2Def(idItem);
if (!pDef) pDef=cthr->Obj->Def;
// Compose caption with def name
if(szCaption)
{
const char * s = FnStringPar(szCaption);
const char * sep = strstr(s, "%s");
if (sep)
{
strncpy(caption, s, Min<intptr_t>(sep - s,256));
caption[Min<intptr_t>(sep - s,256)] = 0;
strncat(caption, pDef->GetName(), 256);
strncat(caption, sep + 2, 256);
}
else
{
strncpy(caption, s, 256);
caption[256] = 0;
}
}
else
caption[0] = 0;
// create string to include type-information in command
switch(Parameter.GetType())
{
case C4V_Int:
sprintf(parameter, "%d", Parameter.getInt());
break;
case C4V_Bool:
SCopy(Parameter.getBool() ? "true" : "false", parameter);
break;
case C4V_C4Object:
case C4V_PropList:
sprintf(parameter, "Object(%d)", Parameter.getPropList()->Number);
break;
case C4V_String:
// note this breaks if there is '"' in the string.
parameter[0] = '"';
SCopy(Parameter.getStr()->GetCStr(), parameter + 1, sizeof(command)-3);
SAppendChar('"', command);
break;
case C4V_Any:
SCopy("nil", parameter);
break;
case C4V_Array:
// Arrays were never allowed, so tell the scripter
throw new C4AulExecError(cthr->Obj, "array as parameter to AddMenuItem");
default:
return C4VBool(false);
}
// own value
bool fOwnValue = false; long iValue=0;
if (iExtra & C4MN_Add_PassValue)
{
fOwnValue = true;
iValue = XPar2.getInt();
}
// New Style: native script command
int i = 0;
for(; i < SLen(FnStringPar(szCommand)); i++)
if(!IsIdentifier(FnStringPar(szCommand)[i]))
break;
if (i < SLen(FnStringPar(szCommand)))
{
// Search for "%d" an replace it by "%s" for insertion of formatted parameter
SCopy(FnStringPar(szCommand), dummy, 256);
char* pFound = const_cast<char*>(SSearch(dummy, "%d"));
if (pFound != 0)
*(pFound - 1) = 's';
// Compose left-click command
sprintf(command, dummy, parameter, 0);
// Compose right-click command
sprintf(command2, dummy, parameter, 1);
}
// Old style: function name with id and parameter
else
{
const char *szScriptCom = FnStringPar(szCommand);
if (szScriptCom && *szScriptCom)
{
if (iExtra & C4MN_Add_PassValue)
{
// with value
sprintf(command,"%s(%s,%s,0,%ld)",szScriptCom,C4IdText(idItem),parameter,iValue);
sprintf(command2,"%s(%s,%s,1,%ld)",szScriptCom,C4IdText(idItem),parameter,iValue);
}
else
{
// without value
sprintf(command,"%s(%s,%s)",szScriptCom,C4IdText(idItem),parameter);
sprintf(command2,"%s(%s,%s,1)",szScriptCom,C4IdText(idItem),parameter);
}
}
else
{
// no command
*command = *command2 = '\0';
}
}
// Info caption
SCopy(FnStringPar(szInfoCaption),infocaption,C4MaxTitle);
// Default info caption by def desc
if (!infocaption[0] && !(iExtra & C4MN_Add_ForceNoDesc)) SCopy(pDef->GetDesc(),infocaption,C4MaxTitle);
// Create symbol
C4FacetSurface fctSymbol;
switch (iExtra & C4MN_Add_MaxImage)
{
case C4MN_Add_ImgRank:
{
// symbol by rank
C4Facet *pfctRankSym = &::GraphicsResource.fctRank;
int32_t iRankSymNum = ::GraphicsResource.iNumRanks;
if (pDef && pDef->pRankSymbols)
{
pfctRankSym = pDef->pRankSymbols;
iRankSymNum = pDef->iNumRankSymbols;
}
C4RankSystem::DrawRankSymbol(&fctSymbol, iCount, pfctRankSym, iRankSymNum, true);
iCount=0;
break;
}
case C4MN_Add_ImgIndexed:
// draw indexed facet
fctSymbol.Create(iSymbolSize,iSymbolSize);
pDef->Draw(fctSymbol, false, 0, NULL, XPar.getInt());
break;
case C4MN_Add_ImgObjRank:
{
// draw current gfx of XPar_C4V including rank
if (XPar.GetType() != C4V_C4Object) return C4VFalse;
C4Object *pGfxObj = XPar.getObj();
if (pGfxObj && pGfxObj->Status)
{
// create graphics
// get rank gfx
C4Facet *pRankRes=&::GraphicsResource.fctRank;
long iRankCnt=::GraphicsResource.iNumRanks;
C4Def *pDef=pGfxObj->Def;
if (pDef->pRankSymbols)
{
pRankRes=pDef->pRankSymbols;
iRankCnt=pDef->iNumRankSymbols;
}
// context menu
C4Facet fctRank;
if (cthr->Obj->Menu->IsContextMenu())
{
// context menu entry: left object gfx
long C4MN_SymbolSize = cthr->Obj->Menu->GetItemHeight();
fctSymbol.Create(C4MN_SymbolSize * 2,C4MN_SymbolSize);
fctSymbol.Wdt = C4MN_SymbolSize;
pGfxObj->Def->Draw(fctSymbol, false, pGfxObj->Color, pGfxObj);
// right of it the rank
fctRank = fctSymbol;
fctRank.X = C4MN_SymbolSize;
fctSymbol.Wdt *= 2;
}
else
{
// regular menu: draw object picture
fctSymbol.Create(iSymbolSize,iSymbolSize);
pGfxObj->Def->Draw(fctSymbol, false, pGfxObj->Color, pGfxObj);
// rank at top-right corner
fctRank = fctSymbol;
fctRank.X = fctRank.Wdt - pRankRes->Wdt;
fctRank.Wdt = pRankRes->Wdt;
fctRank.Hgt = pRankRes->Hgt;
}
// draw rank
if (pGfxObj->Info)
{
C4Facet fctBackup = (const C4Facet &) fctSymbol;
fctSymbol.Set(fctRank);
C4RankSystem::DrawRankSymbol(&fctSymbol, pGfxObj->Info->Rank, pRankRes, iRankCnt, true);
fctSymbol.Set(fctBackup);
}
}
}
break;
case C4MN_Add_ImgObject:
{
// draw object picture
if (XPar.GetType() != C4V_C4Object)
throw new C4AulExecError(cthr->Obj,
FormatString("call to \"%s\" parameter %d: got \"%s\", but expected \"%s\"!",
"AddMenuItem", 8, XPar.GetTypeName(), GetC4VName(C4V_C4Object)
).getData());
C4Object *pGfxObj = XPar.getObj();
fctSymbol.Wdt = fctSymbol.Hgt = iSymbolSize;
pGfxObj->Picture2Facet(fctSymbol);
}
break;
case C4MN_Add_ImgTextSpec:
{
C4FacetSurface fctSymSpec;
uint32_t dwClr = XPar.getInt();
if (!szCaption || !Game.DrawTextSpecImage(fctSymSpec, caption, dwClr ? dwClr : 0xff))
return C4Value();
fctSymbol.Create(iSymbolSize,iSymbolSize);
fctSymSpec.Draw(fctSymbol, true);
*caption = '\0';
}
break;
case C4MN_Add_ImgColor:
// draw colored def facet
fctSymbol.Create(iSymbolSize,iSymbolSize);
pDef->Draw(fctSymbol, false, XPar.getInt());
break;
default:
// default: by def, if it is not specifically NONE
if (idItem != C4Id("NONE"))
{
fctSymbol.Create(iSymbolSize,iSymbolSize);
pDef->Draw(fctSymbol);
}
else
{
// otherwise: Clear symbol!
}
break;
}
// Convert default zero count to no count
if (iCount==0 && !(iExtra & C4MN_Add_ForceCount)) iCount=C4MN_Item_NoCount;
// menuitems without commands are never selectable
bool fIsSelectable = !!*command;
// Add menu item
cthr->Obj->Menu->Add(caption,fctSymbol,command,iCount,NULL,infocaption,idItem,command2,fOwnValue,iValue,fIsSelectable);
return C4VTrue;
}
static bool FnSelectMenuItem(C4AulObjectContext *cthr, long iItem)
{
if (!cthr->Obj->Menu) return false;
return !!cthr->Obj->Menu->SetSelection(iItem, false, true);
}
static bool FnSetMenuDecoration(C4AulObjectContext *cthr, C4ID idNewDeco)
{
if (!cthr->Obj->Menu) return false;
C4GUI::FrameDecoration *pNewDeco = new C4GUI::FrameDecoration();
if (!pNewDeco->SetByDef(idNewDeco))
{
delete pNewDeco;
return false;
}
cthr->Obj->Menu->SetFrameDeco(pNewDeco);
return true;
}
static bool FnSetMenuTextProgress(C4AulObjectContext *cthr, long iNewProgress)
{
if (!cthr->Obj->Menu) return false;
return cthr->Obj->Menu->SetTextProgress(iNewProgress, false);
}
// Check / Status
static C4Object *FnContained(C4AulObjectContext *cthr)
{
return cthr->Obj->Contained;
}
static C4Object *FnContents(C4AulObjectContext *cthr, long index)
{
// Special: objects attaching to another object
// cannot be accessed by FnContents
C4Object *cobj;
while (cobj=cthr->Obj->Contents.GetObject(index++))
if (cobj->GetProcedure()!=DFA_ATTACH) return cobj;
return NULL;
}
static bool FnShiftContents(C4AulObjectContext *cthr, bool fShiftBack, C4ID idTarget, bool fDoCalls)
{
// regular shift
if (!idTarget) return !!cthr->Obj->ShiftContents(fShiftBack, fDoCalls);
// check if ID is present within target
C4Object *pNewFront = cthr->Obj->Contents.Find(idTarget);
if (!pNewFront) return false;
// select it
cthr->Obj->DirectComContents(pNewFront, fDoCalls);
// done, success
return true;
}
static C4Object *FnScrollContents(C4AulObjectContext *cthr)
{
C4Object *pMove = cthr->Obj->Contents.GetObject();
if (pMove)
{
cthr->Obj->Contents.Remove(pMove);
cthr->Obj->Contents.Add(pMove,C4ObjectList::stNone);
}
return cthr->Obj->Contents.GetObject();
}
static long FnContentsCount(C4AulObjectContext *cthr, C4ID id)
{
return cthr->Obj->Contents.ObjectCount(id);
}
static C4Object *FnFindContents(C4AulObjectContext *cthr, C4ID c_id)
{
return cthr->Obj->Contents.Find(c_id);
}
static C4Object *FnFindOtherContents(C4AulObjectContext *cthr, C4ID c_id)
{
return cthr->Obj->Contents.FindOther(c_id);
}
static bool FnActIdle(C4AulObjectContext *cthr)
{
return !cthr->Obj->Action.pActionDef;
}
static bool FnCheckEnergyNeedChain(C4AulObjectContext *cthr)
{
C4ObjectList EnergyChainChecked;
return CheckEnergyNeedChain(cthr->Obj,EnergyChainChecked);
}
static bool FnEnergyCheck(C4AulObjectContext *cthr, long energy)
{
if (!(Game.Rules & C4RULE_StructuresNeedEnergy)
|| (cthr->Obj->Energy>=energy)
|| !(cthr->Obj->Def->LineConnect & C4D_Power_Consumer))
{
cthr->Obj->NeedEnergy=0;
return true;
}
cthr->Obj->NeedEnergy=1;
return false;
}
static bool FnStuck(C4AulObjectContext *cthr)
{
return !!cthr->Obj->Shape.CheckContact(cthr->Obj->GetX(),cthr->Obj->GetY());
}
static bool FnInLiquid(C4AulObjectContext *cthr)
{
return cthr->Obj->InLiquid;
}
static bool FnOnFire(C4AulObjectContext *cthr)
{
if (cthr->Obj->GetOnFire()) return true;
// check for effect
if (!cthr->Obj->pEffects) return false;
return !!cthr->Obj->pEffects->Get(C4Fx_AnyFire);
}
static bool FnComponentAll(C4AulObjectContext *cthr, C4ID c_id)
{
long cnt;
C4IDList Components;
cthr->Obj->Def->GetComponents(&Components, cthr->Obj, cthr->Obj);
for (cnt=0; Components.GetID(cnt); cnt++)
if (Components.GetID(cnt)!=c_id)
if (Components.GetCount(cnt)>0)
return false;
return true;
}
static C4Object *FnCreateObject(C4AulContext *cthr,
C4PropList * PropList, long iXOffset, long iYOffset, Nillable<long> owner)
{
if (cthr->Obj) // Local object calls override
{
iXOffset+=cthr->Obj->GetX();
iYOffset+=cthr->Obj->GetY();
}
long iOwner = owner;
if (owner.IsNil())
if (cthr->Obj)
iOwner = cthr->Obj->Controller;
else
iOwner = NO_OWNER;
C4Object *pNewObj = Game.CreateObject(PropList,cthr->Obj,iOwner,iXOffset,iYOffset);
// Set initial controller to creating controller, so more complicated cause-effect-chains can be traced back to the causing player
if (pNewObj && cthr->Obj && cthr->Obj->Controller > NO_OWNER) pNewObj->Controller = cthr->Obj->Controller;
return pNewObj;
}
static C4Object *FnCreateConstruction(C4AulContext *cthr,
C4PropList * PropList, long iXOffset, long iYOffset, Nillable<long> owner,
long iCompletion, bool fTerrain, bool fCheckSite)
{
// Local object calls override position offset, owner
if (cthr->Obj)
{
iXOffset+=cthr->Obj->GetX();
iYOffset+=cthr->Obj->GetY();
}
// Check site
if (fCheckSite)
if (!ConstructionCheck(PropList,iXOffset,iYOffset,cthr->Obj))
return NULL;
long iOwner = owner;
if (owner.IsNil())
if (cthr->Obj)
iOwner = cthr->Obj->Controller;
else
iOwner = NO_OWNER;
// Create site object
C4Object *pNewObj = Game.CreateObjectConstruction(PropList,cthr->Obj,iOwner,iXOffset,iYOffset,iCompletion*FullCon/100,fTerrain);
// Set initial controller to creating controller, so more complicated cause-effect-chains can be traced back to the causing player
if (pNewObj && cthr->Obj && cthr->Obj->Controller>NO_OWNER) pNewObj->Controller = cthr->Obj->Controller;
return pNewObj;
}
static C4Object *FnCreateContents(C4AulObjectContext *cthr, C4PropList * PropList, Nillable<long> iCount)
{
// default amount parameter
if (iCount.IsNil()) iCount = 1;
// create objects
C4Object *pNewObj = NULL;
while (iCount-- > 0) pNewObj = cthr->Obj->CreateContents(PropList);
// controller will automatically be set upon entrance
// return last created
return pNewObj;
}
static C4Object *FnComposeContents(C4AulObjectContext *cthr, C4ID c_id)
{
return cthr->Obj->ComposeContents(c_id);
}
static bool FnFindConstructionSite(C4AulContext *cthr, C4PropList * PropList, C4Value * VarX, C4Value * VarY)
{
// Get def Old-style implementation (fixed)...
C4Def *pDef;
if (!(pDef=PropList->GetDef())) return false;
// Get thread vars
if(!cthr->Caller) return false;
C4Value& V1 = VarX->GetRefVal();
C4Value& V2 = VarY->GetRefVal();
// Construction check at starting position
if (ConstructionCheck(PropList,V1.getInt(),V2.getInt()))
return true;
// Search for real
int32_t v1 = V1.getInt(), v2 = V2.getInt();
bool result = !!FindConSiteSpot(v1, v2,
pDef->Shape.Wdt,pDef->Shape.Hgt,
pDef->Category,
20);
V1 = C4VInt(v1); V2 = C4VInt(v2);
return result;
}
static C4Object *FnFindBase(C4AulContext *cthr, long iOwner, long iIndex)
{
if (!ValidPlr(iOwner)) return NULL;
return Game.FindBase(iOwner,iIndex);
}
C4FindObject *CreateCriterionsFromPars(C4Value *pPars, C4FindObject **pFOs, C4SortObject **pSOs)
{
int i, iCnt = 0, iSortCnt = 0;
// Read all parameters
for(i = 0; i < C4AUL_MAX_Par; i++)
{
PAR(any, Data);
// No data given?
if(!Data) break;
// Construct
C4SortObject *pSO = NULL;
C4FindObject *pFO = C4FindObject::CreateByValue(Data, pSOs ? &pSO : NULL);
// Add FindObject
if(pFO)
{
pFOs[iCnt++] = pFO;
}
// Add SortObject
if (pSO)
{
pSOs[iSortCnt++] = pSO;
}
}
// No criterions?
if(!iCnt)
{
for (i = 0; i < iSortCnt; ++i) delete pSOs[i];
return NULL;
}
// create sort criterion
C4SortObject *pSO = NULL;
if (iSortCnt)
{
if (iSortCnt == 1)
pSO = pSOs[0];
else
pSO = new C4SortObjectMultiple(iSortCnt, pSOs, false);
}
// Create search object
C4FindObject *pFO;
if(iCnt == 1)
pFO = pFOs[0];
else
pFO = new C4FindObjectAnd(iCnt, pFOs, false);
if (pSO) pFO->SetSort(pSO);
return pFO;
}
static bool FnMakeCrewMember(C4AulObjectContext *cthr, long iPlayer)
{
if (!ValidPlr(iPlayer)) return false;
return !!::Players.Get(iPlayer)->MakeCrewMember(cthr->Obj);
}
static C4Value FnObjectCount(C4AulContext *cthr, C4Value *pPars)
{
// Create FindObject-structure
C4FindObject *pFOs[C4AUL_MAX_Par];
C4FindObject *pFO = CreateCriterionsFromPars(pPars, pFOs, NULL);
// Error?
if(!pFO)
throw new C4AulExecError(cthr->Obj, "ObjectCount: No valid search criterions supplied!");
// Search
int32_t iCnt = pFO->Count(::Objects, ::Objects.Sectors);
// Free
delete pFO;
// Return
return C4VInt(iCnt);
}
static C4Value FnFindObject(C4AulContext *cthr, C4Value *pPars)
{
// Create FindObject-structure
C4FindObject *pFOs[C4AUL_MAX_Par];
C4SortObject *pSOs[C4AUL_MAX_Par];
C4FindObject *pFO = CreateCriterionsFromPars(pPars, pFOs, pSOs);
// Error?
if(!pFO)
throw new C4AulExecError(cthr->Obj, "FindObject: No valid search criterions supplied!");
// Search
C4Object *pObj = pFO->Find(::Objects, ::Objects.Sectors);
// Free
delete pFO;
// Return
return C4VObj(pObj);
}
static C4Value FnFindObjects(C4AulContext *cthr, C4Value *pPars)
{
// Create FindObject-structure
C4FindObject *pFOs[C4AUL_MAX_Par];
C4SortObject *pSOs[C4AUL_MAX_Par];
C4FindObject *pFO = CreateCriterionsFromPars(pPars, pFOs, pSOs);
// Error?
if(!pFO)
throw new C4AulExecError(cthr->Obj, "FindObjects: No valid search criterions supplied!");
// Search
C4ValueArray *pResult = pFO->FindMany(::Objects, ::Objects.Sectors);
// Free
delete pFO;
// Return
return C4VArray(pResult);
}
static bool FnGrabObjectInfo(C4AulObjectContext *cthr, C4Object *pFrom)
{
// local call, safety
if (!pFrom) return false;
// grab info
return !!cthr->Obj->GrabInfo(pFrom);
}
static bool FnSmoke(C4AulContext *cthr, long tx, long ty, long level, long dwClr)
{
if (cthr->Obj) { tx+=cthr->Obj->GetX(); ty+=cthr->Obj->GetY(); }
Smoke(tx,ty,level,dwClr);
return true;
}
static bool FnBubble(C4AulContext *cthr, long tx, long ty)
{
if (cthr->Obj) { tx+=cthr->Obj->GetX(); ty+=cthr->Obj->GetY(); }
BubbleOut(tx,ty);
return true;
}
static bool FnInsertMaterial(C4AulContext *cthr, long mat, long x, long y, long vx, long vy)
{
if (cthr->Obj) { x+=cthr->Obj->GetX(); y+=cthr->Obj->GetY(); }
return !!::Landscape.InsertMaterial(mat,x,y,vx,vy);
}
static long FnGetMaterialCount(C4AulContext *cthr, long iMaterial, bool fReal)
{
if(!MatValid(iMaterial)) return -1;
if(fReal || !::MaterialMap.Map[iMaterial].MinHeightCount)
return ::Landscape.MatCount[iMaterial];
else
return ::Landscape.EffectiveMatCount[iMaterial];
}
static long FnGetMaterial(C4AulContext *cthr, long x, long y)
{
if (cthr->Obj) { x+=cthr->Obj->GetX(); y+=cthr->Obj->GetY(); }
return GBackMat(x,y);
}
static C4String *FnGetTexture(C4AulContext* cthr, long x, long y)
{
// Get texture
int32_t iTex = PixCol2Tex(GBackPix(x, y));
if(!iTex) return NULL;
// Get material-texture mapping
const C4TexMapEntry *pTex = ::TextureMap.GetEntry(iTex);
if(!pTex) return NULL;
// Return tex name
return String(pTex->GetTextureName());
}
static bool FnGBackSolid(C4AulContext *cthr, long x, long y)
{
if (cthr->Obj) { x+=cthr->Obj->GetX(); y+=cthr->Obj->GetY(); }
return GBackSolid(x,y);
}
static bool FnGBackSemiSolid(C4AulContext *cthr, long x, long y)
{
if (cthr->Obj) { x+=cthr->Obj->GetX(); y+=cthr->Obj->GetY(); }
return GBackSemiSolid(x,y);
}
static bool FnGBackLiquid(C4AulContext *cthr, long x, long y)
{
if (cthr->Obj) { x+=cthr->Obj->GetX(); y+=cthr->Obj->GetY(); }
return GBackLiquid(x,y);
}
static bool FnGBackSky(C4AulContext *cthr, long x, long y)
{
if (cthr->Obj) { x+=cthr->Obj->GetX(); y+=cthr->Obj->GetY(); }
return !GBackIFT(x, y);
}
static long FnExtractMaterialAmount(C4AulContext *cthr, long x, long y, long mat, long amount)
{
if (cthr->Obj) { x+=cthr->Obj->GetX(); y+=cthr->Obj->GetY(); }
long extracted=0; for (;extracted<amount; extracted++)
{
if (GBackMat(x,y)!=mat) return extracted;
if (::Landscape.ExtractMaterial(x,y)!=mat) return extracted;
}
return extracted;
}
static C4Void FnBlastObjects(C4AulContext *cthr, long iX, long iY, long iLevel, C4Object *pInObj, Nillable<long> iCausedBy)
{
if (iCausedBy.IsNil() && cthr->Obj) iCausedBy = cthr->Obj->Controller;
Game.BlastObjects(iX,iY,iLevel,pInObj,iCausedBy,cthr->Obj);
return C4VNull;
}
static bool FnBlastObject(C4AulObjectContext *cthr, long iLevel, Nillable<long> iCausedBy)
{
if (iCausedBy.IsNil() && cthr->Obj) iCausedBy = cthr->Obj->Controller;
if (!cthr->Obj->Status) return false;
cthr->Obj->Blast(iLevel, iCausedBy);
return true;
}
static C4Void FnBlastFree(C4AulContext *cthr, long iX, long iY, long iLevel, Nillable<long> iCausedBy)
{
if (iCausedBy.IsNil() && cthr->Obj) iCausedBy = cthr->Obj->Controller;
if (cthr->Obj)
{
iX += cthr->Obj->GetX();
iY += cthr->Obj->GetY();
}
int grade = BoundBy<int>((iLevel/10)-1,1,3);
::Landscape.BlastFree(iX, iY, iLevel, grade, iCausedBy);
return C4VNull;
}
static bool FnSound(C4AulContext *cthr, C4String *szSound, bool fGlobal, Nillable<long> iLevel, Nillable<long> iAtPlayer, long iLoop, bool fMultiple, long iCustomFalloffDistance)
{
// play here?
if (!iAtPlayer.IsNil())
{
// get player to play at
C4Player *pPlr = ::Players.Get(iAtPlayer);
// not existant? fail
if (!pPlr) return false;
// network client: don't play here
// return true for network sync
if (!pPlr->LocalControl) return true;
}
// even less than nothing?
if (iLevel<0) return true;
// default sound level
if (iLevel.IsNil() || iLevel>100)
iLevel=100;
// target object
C4Object *pObj = NULL;
if (!fGlobal) pObj = cthr->Obj;
// already playing?
if(iLoop >= 0 && !fMultiple && GetSoundInstance(FnStringPar(szSound), pObj))
return false;
// try to play effect
if(iLoop >= 0)
StartSoundEffect(FnStringPar(szSound),!!iLoop,iLevel,pObj, iCustomFalloffDistance);
else
StopSoundEffect(FnStringPar(szSound),pObj);
// always return true (network safety!)
return true;
}
static bool FnMusic(C4AulContext *cthr, C4String *szSongname, bool fLoop)
{
// FIXME: Script should not influence the user's configuration
if (!szSongname)
{
Config.Sound.RXMusic=false;
Application.MusicSystem.Stop();
}
else
{
Config.Sound.RXMusic=true;
Application.MusicSystem.Stop();
if (!Application.MusicSystem.Play(FnStringPar(szSongname), !!fLoop))
{
Config.Sound.RXMusic=false;
return true;
}
}
return true;
}
static long FnMusicLevel(C4AulContext *cthr, long iLevel)
{
Game.SetMusicLevel(iLevel);
return Application.MusicSystem.SetVolume(iLevel);
}
static long FnSetPlayList(C4AulContext *cth, C4String *szPlayList)
{
long iFilesInPlayList = Application.MusicSystem.SetPlayList(FnStringPar(szPlayList));
Game.PlayList.Copy(FnStringPar(szPlayList));
// network/record/replay: return 0
if(::Control.SyncMode()) return 0;
return iFilesInPlayList;
}
static bool FnGameOver(C4AulContext *cthr, long iGameOverValue /* provided for future compatibility */)
{
return !!Game.DoGameOver();
}
static bool FnGainMissionAccess(C4AulContext *cthr, C4String *szPassword)
{
if (SLen(Config.General.MissionAccess)+SLen(FnStringPar(szPassword))+3>CFG_MaxString) return false;
SAddModule(Config.General.MissionAccess,FnStringPar(szPassword));
return true;
}
static C4Value FnLog_C4V(C4AulContext *cthr, C4Value *szMessage, C4Value * iPar0, C4Value * iPar1, C4Value * iPar2, C4Value * iPar3, C4Value * iPar4, C4Value * iPar5, C4Value * iPar6, C4Value * iPar7, C4Value * iPar8)
{
Log(FnStringFormat(cthr, FnStringPar(szMessage->getStr()),iPar0,iPar1,iPar2,iPar3,iPar4,iPar5,iPar6,iPar7,iPar8).getData());
return C4VBool(true);
}
static C4Value FnDebugLog_C4V(C4AulContext *cthr, C4Value *szMessage, C4Value * iPar0, C4Value * iPar1, C4Value * iPar2, C4Value * iPar3, C4Value * iPar4, C4Value * iPar5, C4Value * iPar6, C4Value * iPar7, C4Value * iPar8)
{
DebugLog(FnStringFormat(cthr, FnStringPar(szMessage->getStr()),iPar0,iPar1,iPar2,iPar3,iPar4,iPar5,iPar6,iPar7,iPar8).getData());
return C4VBool(true);
}
static C4Value FnFormat_C4V(C4AulContext *cthr, C4Value *szFormat, C4Value * iPar0, C4Value * iPar1, C4Value * iPar2, C4Value * iPar3, C4Value * iPar4, C4Value * iPar5, C4Value * iPar6, C4Value * iPar7, C4Value * iPar8)
{
return C4VString(FnStringFormat(cthr, FnStringPar(szFormat->getStr()),iPar0,iPar1,iPar2,iPar3,iPar4,iPar5,iPar6,iPar7,iPar8));
}
static C4ID FnC4Id(C4AulContext *cthr, C4String *szID)
{
return(C4Id(FnStringPar(szID)));
}
static C4Value FnPlayerMessage_C4V(C4AulContext *cthr, C4Value * iPlayer, C4Value *c4vMessage, C4Value *c4vObj, C4Value * iPar0, C4Value * iPar1, C4Value * iPar2, C4Value * iPar3, C4Value * iPar4, C4Value * iPar5, C4Value * iPar6)
{
char buf[MaxFnStringParLen+1];
C4String * szMessage = c4vMessage->getStr();
C4Object * pObj = c4vObj->getObj();
if (!szMessage) return C4VBool(false);
// Speech
bool fSpoken=false;
if (SCopySegment(FnStringPar(szMessage),1,buf,'$'))
if (StartSoundEffect(buf,false,100,pObj ? pObj : cthr->Obj))
fSpoken=true;
// Text
if (!fSpoken)
if (SCopySegment(FnStringFormat(cthr,FnStringPar(szMessage),iPar0,iPar1,iPar2,iPar3,iPar4,iPar5,iPar6).getData(),0,buf,'$'))
if (pObj) GameMsgObjectPlayer(buf,pObj,iPlayer->getInt());
else GameMsgPlayer(buf, iPlayer->getInt());
return C4VBool(true);
}
static C4Value FnMessage_C4V(C4AulContext *cthr, C4Value *c4vMessage, C4Value *c4vObj, C4Value * iPar0, C4Value * iPar1, C4Value * iPar2, C4Value * iPar3, C4Value * iPar4, C4Value * iPar5, C4Value * iPar6, C4Value * iPar7)
{
char buf[MaxFnStringParLen+1];
C4String * szMessage = c4vMessage->getStr();
if (!szMessage) return C4VBool(false);
// Speech
bool fSpoken=false;
if (SCopySegment(FnStringPar(szMessage),1,buf,'$'))
if (StartSoundEffect(buf,false,100,cthr->Obj))
fSpoken=true;
// Text
C4Object * pObj = c4vObj->getObj();
if (!fSpoken)
if (SCopySegment(FnStringFormat(cthr,FnStringPar(szMessage),iPar0,iPar1,iPar2,iPar3,iPar4,iPar5,iPar6,iPar7).getData(),0,buf,'$'))
if (pObj) GameMsgObject(buf,pObj);
else GameMsgGlobal(buf);
return C4VBool(true);
}
static C4Value FnAddMessage_C4V(C4AulContext *cthr, C4Value *c4vMessage, C4Value *c4vObj, C4Value * iPar0, C4Value * iPar1, C4Value * iPar2, C4Value * iPar3, C4Value * iPar4, C4Value * iPar5, C4Value * iPar6, C4Value * iPar7)
{
C4String * szMessage = c4vMessage->getStr();
if (!szMessage) return C4VBool(false);
C4Object * pObj = c4vObj->getObj();
if (pObj) ::Messages.Append(C4GM_Target,FnStringFormat(cthr,FnStringPar(szMessage),iPar0,iPar1,iPar2,iPar3,iPar4,iPar5,iPar6,iPar7).getData(),pObj,NO_OWNER,0,0,FWhite);
else ::Messages.Append(C4GM_Global,FnStringFormat(cthr,FnStringPar(szMessage),iPar0,iPar1,iPar2,iPar3,iPar4,iPar5,iPar6,iPar7).getData(),0,ANY_OWNER,0,0,FWhite);
return C4VBool(true);
}
static C4Value FnPlrMessage_C4V(C4AulContext *cthr, C4Value *c4vMessage, C4Value * iPlr, C4Value * iPar0, C4Value * iPar1, C4Value * iPar2, C4Value * iPar3, C4Value * iPar4, C4Value * iPar5, C4Value * iPar6, C4Value * iPar7)
{
char buf[MaxFnStringParLen+1];
C4String * szMessage = c4vMessage->getStr();
if (!szMessage) return C4VBool(false);
// Speech
bool fSpoken=false;
if (SCopySegment(FnStringPar(szMessage),1,buf,'$'))
if (StartSoundEffect(buf,false,100,cthr->Obj))
fSpoken=true;
// Text
if (!fSpoken)
if (SCopySegment(FnStringFormat(cthr,FnStringPar(szMessage),iPar0,iPar1,iPar2,iPar3,iPar4,iPar5,iPar6,iPar7).getData(),0,buf,'$'))
if (ValidPlr(iPlr->getInt())) GameMsgPlayer(buf,iPlr->getInt());
else GameMsgGlobal(buf);
return C4VBool(true);
}
static bool FnScriptGo(C4AulContext *cthr, bool go)
{
Game.Script.Go=!!go;
return true;
}
static long FnMaterial(C4AulContext *cthr, C4String *mat_name)
{
return ::MaterialMap.Get(FnStringPar(mat_name));
}
C4Object* FnPlaceVegetation(C4AulContext *cthr, C4ID id, long iX, long iY, long iWdt, long iHgt, long iGrowth)
{
// Local call: relative coordinates
if (cthr->Obj) { iX+=cthr->Obj->GetX(); iY+=cthr->Obj->GetY(); }
// Place vegetation
return Game.PlaceVegetation(id,iX,iY,iWdt,iHgt,iGrowth);
}
C4Object* FnPlaceAnimal(C4AulContext *cthr, C4ID id)
{
return Game.PlaceAnimal(id);
}
static bool FnDrawVolcanoBranch(C4AulContext *cthr, long mat, long fx, long fy, long tx, long ty, long size)
{
long cx,cx2,cy;
for (cy=ty; cy<fy; cy++)
{
cx=fx+(tx-fx)*(cy-fy)/(ty-fy);
for (cx2=cx-size/2; cx2<cx+size/2; cx2++)
SBackPix(cx2,cy,Mat2PixColDefault(mat)+GBackIFT(cx2,cy));
}
return true;
}
static bool FnHostile(C4AulContext *cthr, long iPlr1, long iPlr2, bool fCheckOneWayOnly)
{
if (fCheckOneWayOnly)
{
return ::Players.HostilityDeclared(iPlr1,iPlr2);
}
else
return !!Hostile(iPlr1,iPlr2);
}
static bool FnSetHostility(C4AulContext *cthr, long iPlr, long iPlr2, bool fHostile, bool fSilent, bool fNoCalls)
{
C4Player *pPlr = ::Players.Get(iPlr);
if (!pPlr) return false;
// do rejection test first
if (!fNoCalls)
{
if (!!Game.Script.GRBroadcast(PSF_RejectHostilityChange, &C4AulParSet(C4VInt(iPlr), C4VInt(iPlr2), C4VBool(fHostile)), true, true))
return false;
}
// OK; set hostility
bool fOldHostility = ::Players.HostilityDeclared(iPlr, iPlr2);
if (!pPlr->SetHostility(iPlr2,fHostile, fSilent)) return false;
// calls afterwards
Game.Script.GRBroadcast(PSF_OnHostilityChange, &C4AulParSet(C4VInt(iPlr), C4VInt(iPlr2), C4VBool(fHostile), C4VBool(fOldHostility)), true);
return true;
}
static bool FnSetPlrView(C4AulContext *cthr, long iPlr, C4Object *tobj)
{
if (!ValidPlr(iPlr)) return false;
::Players.Get(iPlr)->SetViewMode(C4PVM_Target,tobj);
return true;
}
static bool FnSetPlrShowControl(C4AulContext *cthr, long iPlr, C4String *defstring)
{
if (!ValidPlr(iPlr)) return false;
::Players.Get(iPlr)->ShowControl=StringBitEval(FnStringPar(defstring));
return true;
}
static bool FnSetPlrShowCommand(C4AulContext *cthr, long iPlr, long iCom)
{
if (!ValidPlr(iPlr)) return false;
::Players.Get(iPlr)->FlashCom=iCom;
if (!Config.Graphics.ShowCommands) Config.Graphics.ShowCommands=true;
return true;
}
static bool FnSetPlrShowControlPos(C4AulContext *cthr, long iPlr, long pos)
{
if (!ValidPlr(iPlr)) return false;
::Players.Get(iPlr)->ShowControlPos=pos;
return true;
}
static C4String *FnGetPlrControlName(C4AulContext *cthr, long iPlr, long iCon, bool fShort)
{
return String(PlrControlKeyName(iPlr,iCon,fShort).getData());
}
static long FnGetPlrViewMode(C4AulContext *cthr, long iPlr)
{
if (!ValidPlr(iPlr)) return -1;
if (::Control.SyncMode()) return -1;
return ::Players.Get(iPlr)->ViewMode;
}
static C4Object *FnGetPlrView(C4AulContext *cthr, long iPlr)
{
C4Player *pPlr = ::Players.Get(iPlr);
if (!pPlr || pPlr->ViewMode != C4PVM_Target) return NULL;
return pPlr->ViewTarget;
}
static bool FnDoHomebaseMaterial(C4AulContext *cthr, long iPlr, C4ID id, long iChange)
{
// validity check
if (!ValidPlr(iPlr)) return false;
C4Def *pDef = C4Id2Def(id);
if (!pDef) return false;
// add to material
long iLastcount = ::Players.Get(iPlr)->HomeBaseMaterial.GetIDCount(id);
return ::Players.Get(iPlr)->HomeBaseMaterial.SetIDCount(id,iLastcount+iChange,true);
}
static bool FnDoHomebaseProduction(C4AulContext *cthr, long iPlr, C4ID id, long iChange)
{
// validity check
if (!ValidPlr(iPlr)) return false;
C4Def *pDef = C4Id2Def(id);
if (!pDef) return false;
// add to material
long iLastcount = ::Players.Get(iPlr)->HomeBaseProduction.GetIDCount(id);
return ::Players.Get(iPlr)->HomeBaseProduction.SetIDCount(id,iLastcount+iChange,true);
}
static bool FnSetPlrKnowledge(C4AulContext *cthr, long iPlr, C4ID id, bool fRemove)
{
C4Player *pPlr=::Players.Get(iPlr);
if (!pPlr) return false;
if (fRemove)
{
long iIndex=pPlr->Knowledge.GetIndex(id);
if (iIndex<0) return false;
return pPlr->Knowledge.DeleteItem(iIndex);
}
else
{
if(!C4Id2Def(id)) return false;
return pPlr->Knowledge.SetIDCount(id,1,true);
}
}
static bool FnSetComponent(C4AulObjectContext *cthr, C4ID idComponent, long iCount)
{
return cthr->Obj->Component.SetIDCount(idComponent,iCount,true);
}
static C4Value FnGetPlrKnowledge_C4V(C4AulContext *cthr, C4Value* iPlr_C4V, C4Value* id_C4V, C4Value* iIndex_C4V, C4Value* dwCategory_C4V)
{
long iPlr = iPlr_C4V->getInt();
C4ID id = id_C4V->getC4ID();
long iIndex = iIndex_C4V->getInt();
DWORD dwCategory = dwCategory_C4V->getInt();
if (!ValidPlr(iPlr)) return C4VBool(false);
// Search by id, check if available, return bool
if (id) return C4VBool(::Players.Get(iPlr)->Knowledge.GetIDCount(id,1) != 0);
// Search indexed item of given category, return C4ID
return C4VID(::Players.Get(iPlr)->Knowledge.GetID( ::Definitions, dwCategory, iIndex ));
}
static C4ID FnGetDefinition(C4AulContext *cthr, long iIndex, long dwCategory)
{
C4Def *pDef;
// Default: all categories
if (!dwCategory) dwCategory=C4D_All;
// Get def
if (!(pDef = ::Definitions.GetDef(iIndex,dwCategory))) return C4ID_None;
// Return id
return pDef->id;
}
static C4Value FnGetComponent_C4V(C4AulContext *cthr, C4Value* idComponent_C4V, C4Value* iIndex_C4V, C4Value* pObj_C4V, C4Value* idDef_C4V)
{
C4ID idComponent = idComponent_C4V->getC4ID();
long iIndex = iIndex_C4V->getInt();
C4Object *pObj = pObj_C4V->getObj();
C4ID idDef = idDef_C4V->getC4ID();
// Def component - as seen by scope object as builder
if (idDef)
{
// Get def
C4Def *pDef=C4Id2Def(idDef); if (!pDef) return C4Value();
// Component count
if (idComponent) return C4VInt(pDef->GetComponentCount(idComponent, cthr->Obj));
// Indexed component
return C4VID(pDef->GetIndexedComponent(iIndex, cthr->Obj));
}
// Object component
else
{
// Get object
if (!pObj) pObj=cthr->Obj; if (!pObj) return C4Value();
// Component count
if (idComponent) return C4VInt(pObj->Component.GetIDCount(idComponent));
// Indexed component
return C4VID(pObj->Component.GetID(iIndex));
}
return C4Value();
}
static C4Value FnGetHomebaseMaterial_C4V(C4AulContext *cthr, C4Value* iPlr_C4V, C4Value* id_C4V, C4Value* iIndex_C4V, C4Value* dwCategory_C4V)
{
long iPlr = iPlr_C4V->getInt();
C4ID id = id_C4V->getC4ID();
long iIndex = iIndex_C4V->getInt();
DWORD dwCategory = dwCategory_C4V->getInt();
if (!ValidPlr(iPlr)) return C4VBool(false);
// Search by id, return available count
if (id) return C4VInt(::Players.Get(iPlr)->HomeBaseMaterial.GetIDCount(id));
// Search indexed item of given category, return C4ID
return C4VID(::Players.Get(iPlr)->HomeBaseMaterial.GetID( ::Definitions, dwCategory, iIndex ));
}
static C4Value FnGetHomebaseProduction_C4V(C4AulContext *cthr, C4Value* iPlr_C4V, C4Value* id_C4V, C4Value* iIndex_C4V, C4Value* dwCategory_C4V)
{
long iPlr = iPlr_C4V->getInt();
C4ID id = id_C4V->getC4ID();
long iIndex = iIndex_C4V->getInt();
DWORD dwCategory = dwCategory_C4V->getInt();
if (!ValidPlr(iPlr)) return C4VBool(false);
// Search by id, return available count
if (id) return C4VInt(::Players.Get(iPlr)->HomeBaseProduction.GetIDCount(id));
// Search indexed item of given category, return C4ID
return C4VID(::Players.Get(iPlr)->HomeBaseProduction.GetID( ::Definitions, dwCategory, iIndex ));
}
static long FnSetPlrMagic(C4AulContext *cthr, long iPlr, C4ID id, bool fRemove)
{
C4Player *pPlr=::Players.Get(iPlr);
if (!pPlr) return false;
if (fRemove)
{
long iIndex=pPlr->Magic.GetIndex(id);
if (iIndex<0) return false;
return pPlr->Magic.DeleteItem(iIndex);
}
else
{
if(!C4Id2Def(id)) return false;
return pPlr->Magic.SetIDCount(id,1,true);
}
}
static C4Value FnGetPlrMagic_C4V(C4AulContext *cthr, C4Value* iPlr_C4V, C4Value* id_C4V, C4Value* iIndex_C4V)
{
long iPlr = iPlr_C4V->getInt();
C4ID id = id_C4V->getC4ID();
long iIndex = iIndex_C4V->getInt();
if (!ValidPlr(iPlr)) return C4VBool(false);
// Search by id, check if available, return bool
if (id) return C4VBool(::Players.Get(iPlr)->Magic.GetIDCount(id,1) != 0);
// Search indexed item of given category, return C4ID
return C4VID(::Players.Get(iPlr)->Magic.GetID( ::Definitions, C4D_Magic, iIndex ));
}
static long FnGetWealth(C4AulContext *cthr, long iPlr)
{
if (!ValidPlr(iPlr)) return 0;
return ::Players.Get(iPlr)->Wealth;
}
static bool FnSetWealth(C4AulContext *cthr, long iPlr, long iValue)
{
if (!ValidPlr(iPlr)) return false;
::Players.Get(iPlr)->Wealth = BoundBy<long>(iValue,0,100000);
return true;
}
static long FnDoScore(C4AulContext *cthr, long iPlr, long iChange)
{
if (!ValidPlr(iPlr)) return false;
return ::Players.Get(iPlr)->DoPoints(iChange);
}
static long FnGetPlrValue(C4AulContext *cthr, long iPlr)
{
if (!ValidPlr(iPlr)) return 0;
return ::Players.Get(iPlr)->Value;
}
static long FnGetPlrValueGain(C4AulContext *cthr, long iPlr)
{
if (!ValidPlr(iPlr)) return 0;
return ::Players.Get(iPlr)->ValueGain;
}
static long FnGetScore(C4AulContext *cthr, long iPlr)
{
if (!ValidPlr(iPlr)) return 0;
return ::Players.Get(iPlr)->Points;
}
static C4Object *FnGetHiRank(C4AulContext *cthr, long iPlr)
{
if (!ValidPlr(iPlr)) return false;
return ::Players.Get(iPlr)->GetHiRankActiveCrew(false);
}
static C4Object *FnGetCrew(C4AulContext *cthr, long iPlr, long index)
{
if (!ValidPlr(iPlr)) return false;
return ::Players.Get(iPlr)->Crew.GetObject(index);
}
static long FnGetCrewCount(C4AulContext *cthr, long iPlr)
{
if (!ValidPlr(iPlr)) return 0;
return ::Players.Get(iPlr)->Crew.ObjectCount();
}
static long FnGetPlayerCount(C4AulContext *cthr, long iType)
{
if (!iType)
return ::Players.GetCount();
else
return ::Players.GetCount((C4PlayerType) iType);
}
static long FnGetPlayerByIndex(C4AulContext *cthr, long iIndex, long iType)
{
C4Player *pPlayer;
if (iType)
pPlayer = ::Players.GetByIndex(iIndex, (C4PlayerType) iType);
else
pPlayer = ::Players.GetByIndex(iIndex);
if(!pPlayer) return NO_OWNER;
return pPlayer->Number;
}
static long FnEliminatePlayer(C4AulContext *cthr, long iPlr, bool fRemoveDirect)
{
C4Player *pPlr=::Players.Get(iPlr);
if (!pPlr) return false;
// direct removal?
if (fRemoveDirect)
{
// do direct removal (no fate)
return ::Players.CtrlRemove(iPlr, false);
}
else
{
// do regular elimination
if (pPlr->Eliminated) return false;
pPlr->Eliminate();
}
return true;
}
static bool FnSurrenderPlayer(C4AulContext *cthr, long iPlr)
{
C4Player *pPlr=::Players.Get(iPlr);
if (!pPlr) return false;
if (pPlr->Eliminated) return false;
pPlr->Surrender();
return true;
}
static bool FnSetLeaguePerformance(C4AulContext *cthr, long iScore)
{
Game.RoundResults.SetLeaguePerformance(iScore);
return true;
}
static const int32_t CSPF_FixedAttributes = 1<<0,
CSPF_NoScenarioInit = 1<<1,
CSPF_NoEliminationCheck = 1<<2,
CSPF_Invisible = 1<<3;
static bool FnCreateScriptPlayer(C4AulContext *cthr, C4String *szName, long dwColor, long idTeam, long dwFlags, C4ID idExtra)
{
// safety
if (!szName || !szName->GetData().getLength()) return false;
// this script command puts a new script player info into the list
// the actual join will be delayed and synchronized via queue
// processed by control host only - clients/replay/etc. will perform the join via queue
if (!::Control.isCtrlHost()) return true;
C4PlayerInfo *pScriptPlrInfo = new C4PlayerInfo();
uint32_t dwInfoFlags = 0u;
if (dwFlags & CSPF_FixedAttributes ) dwInfoFlags |= C4PlayerInfo::PIF_AttributesFixed;
if (dwFlags & CSPF_NoScenarioInit ) dwInfoFlags |= C4PlayerInfo::PIF_NoScenarioInit;
if (dwFlags & CSPF_NoEliminationCheck) dwInfoFlags |= C4PlayerInfo::PIF_NoEliminationCheck;
if (dwFlags & CSPF_Invisible ) dwInfoFlags |= C4PlayerInfo::PIF_Invisible;
pScriptPlrInfo->SetAsScriptPlayer(szName->GetCStr(), dwColor, dwInfoFlags, idExtra);
pScriptPlrInfo->SetTeam(idTeam);
C4ClientPlayerInfos JoinPkt(NULL, true, pScriptPlrInfo);
// add to queue!
Game.PlayerInfos.DoPlayerInfoUpdate(&JoinPkt);
// always successful for sync reasons
return true;
}
static C4Object *FnGetCursor(C4AulContext *cthr, long iPlr, long iIndex)
{
// get player
C4Player *pPlr = ::Players.Get(iPlr);
// invalid player?
if (!pPlr) return NULL;
// first index is always the cursor
if (!iIndex) return pPlr->Cursor;
// iterate through selected crew for iIndex times
// status needs not be checked, as dead objects are never in Crew list
C4Object *pCrew;
for (C4ObjectLink *pLnk=pPlr->Crew.First; pLnk; pLnk=pLnk->Next)
// get crew object
if (pCrew = pLnk->Obj)
// is it selected?
if (pCrew->Select)
// is it not the cursor? (which is always first)
if (pCrew != pPlr->Cursor)
// enough searched?
if (!--iIndex)
// return it
return pCrew;
// nothing found at that index
return NULL;
}
static C4Object *FnGetViewCursor(C4AulContext *cthr, long iPlr)
{
// get player
C4Player *pPlr = ::Players.Get(iPlr);
// get viewcursor
return pPlr ? pPlr->ViewCursor : NULL;
}
static C4Object *FnGetCaptain(C4AulContext *cthr, long iPlr)
{
if (!ValidPlr(iPlr)) return false;
return ::Players.Get(iPlr)->Captain;
}
static bool FnSetCursor(C4AulContext *cthr, long iPlr, C4Object *pObj, bool fNoSelectMark, bool fNoSelectArrow, bool fNoSelectCrew)
{
C4Player *pPlr = ::Players.Get(iPlr);
if (!pPlr || (pObj && !pObj->Status)) return false;
pPlr->SetCursor(pObj, !fNoSelectMark, !fNoSelectArrow);
if (!fNoSelectCrew) pPlr->SelectCrew(pObj, true);
return true;
}
static bool FnSetViewCursor(C4AulContext *cthr, long iPlr, C4Object *pObj)
{
// get player
C4Player *pPlr = ::Players.Get(iPlr);
// invalid player?
if (!pPlr) return false;
// set viewcursor
pPlr->ViewCursor = pObj;
return true;
}
static bool FnSelectCrew(C4AulContext *cthr, long iPlr, C4Object *pObj, bool fSelect, bool fNoCursorAdjust)
{
C4Player *pPlr = ::Players.Get(iPlr);
if (!pPlr || !pObj) return false;
if (fNoCursorAdjust)
{ if (fSelect) pObj->DoSelect(); else pObj->UnSelect(); }
else
pPlr->SelectCrew(pObj,fSelect);
return true;
}
static long FnGetSelectCount(C4AulContext *cthr, long iPlr)
{
if (!ValidPlr(iPlr)) return false;
return ::Players.Get(iPlr)->SelectCount;
}
static bool FnSetCrewStatus(C4AulObjectContext *cthr, long iPlr, bool fInCrew)
{
// validate player
C4Player *pPlr = ::Players.Get(iPlr);
if (!pPlr) return false;
// set crew status
return !!pPlr->SetObjectCrewStatus(cthr->Obj, fInCrew);
}
static long FnGetWind(C4AulContext *cthr, long x, long y, bool fGlobal)
{
// global wind
if (fGlobal) return ::Weather.Wind;
// local wind
if (cthr->Obj) { x+=cthr->Obj->GetX(); y+=cthr->Obj->GetY(); }
return ::Weather.GetWind(x,y);
}
static C4Void FnSetWind(C4AulContext *cthr, long iWind)
{
::Weather.SetWind(iWind);
return C4VNull;
}
static C4Void FnSetTemperature(C4AulContext *cthr, long iTemperature)
{
::Weather.SetTemperature(iTemperature);
return C4VNull;
}
static long FnGetTemperature(C4AulContext *cthr)
{
return ::Weather.GetTemperature();
}
static C4Void FnSetSeason(C4AulContext *cthr, long iSeason)
{
::Weather.SetSeason(iSeason);
return C4VNull;
}
static long FnGetSeason(C4AulContext *cthr)
{
return ::Weather.GetSeason();
}
static C4Void FnSetClimate(C4AulContext *cthr, long iClimate)
{
::Weather.SetClimate(iClimate);
return C4VNull;
}
static long FnGetClimate(C4AulContext *cthr)
{
return ::Weather.GetClimate();
}
static long FnLandscapeWidth(C4AulContext *cthr)
{
return GBackWdt;
}
static long FnLandscapeHeight(C4AulContext *cthr)
{
return GBackHgt;
}
static C4Void FnShakeFree(C4AulContext *cthr, long x, long y, long rad)
{
::Landscape.ShakeFree(x,y,rad);
return C4VNull;
}
static C4Void FnShakeObjects(C4AulContext *cthr, long x, long y, long rad)
{
Game.ShakeObjects(x,y,rad);
return C4VNull;
}
static C4Void FnDigFree(C4AulContext *cthr, long x, long y, long rad, bool fRequest)
{
::Landscape.DigFree(x,y,rad,fRequest,cthr->Obj);
return C4VNull;
}
static C4Void FnDigFreeRect(C4AulContext *cthr, long iX, long iY, long iWdt, long iHgt, bool fRequest)
{
::Landscape.DigFreeRect(iX,iY,iWdt,iHgt,fRequest,cthr->Obj);
return C4VNull;
}
static C4Void FnFreeRect(C4AulContext *cthr, long iX, long iY, long iWdt, long iHgt, long iFreeDensity)
{
if (iFreeDensity)
::Landscape.ClearRectDensity(iX,iY,iWdt,iHgt,iFreeDensity);
else
::Landscape.ClearRect(iX,iY,iWdt,iHgt);
return C4VNull;
}
static bool FnPathFree(C4AulContext *cthr, long X1, long Y1, long X2, long Y2)
{
return !!PathFree(X1, Y1, X2, Y2);
}
static C4Value FnPathFree2_C4V(C4AulContext *cthr, C4Value * X1, C4Value * Y1, C4Value * X2, C4Value * Y2)
{
int32_t x = -1, y = -1;
// Do not use getInt on the references, because it destroys them.
bool r = !!PathFree(X1->GetRefVal().getInt(), Y1->GetRefVal().getInt(), X2->getInt(), Y2->getInt(), &x, &y);
if (!r)
{
*X1 = C4VInt(x);
*Y1 = C4VInt(y);
}
return C4VBool(r);
}
static long FnSetTransferZone(C4AulObjectContext *cthr, long iX, long iY, long iWdt, long iHgt)
{
iX+=cthr->Obj->GetX(); iY+=cthr->Obj->GetY();
return Game.TransferZones.Set(iX,iY,iWdt,iHgt,cthr->Obj);
}
static C4Value FnEqual_C4V(C4AulContext *cthr, C4Value * Val1, C4Value * Val2)
{
return C4VBool(Val1->GetData()==Val2->GetData());
}
static long FnAbs(C4AulContext *cthr, long iVal)
{
return Abs(iVal);
}
static long FnSin(C4AulContext *cthr, long iAngle, long iRadius, long iPrec)
{
if(!iPrec) iPrec = 1;
// Precalculate the modulo operation so the C4Fixed argument to Sin does not overflow
iAngle %= 360 * iPrec;
// Let itofix and fixtoi handle the division and multiplication because that can handle higher ranges
return fixtoi(Sin(itofix(iAngle, iPrec)), iRadius);
}
static long FnCos(C4AulContext *cthr, long iAngle, long iRadius, long iPrec)
{
if(!iPrec) iPrec = 1;
iAngle %= 360 * iPrec;
return fixtoi(Cos(itofix(iAngle, iPrec)), iRadius);
}
static long FnSqrt(C4AulContext *cthr, long iValue)
{
if (iValue<0) return 0;
long iSqrt = long(sqrt(double(iValue)));
if(iSqrt * iSqrt < iValue) iSqrt++;
if(iSqrt * iSqrt > iValue) iSqrt--;
return iSqrt;
}
static long FnAngle(C4AulContext *cthr, long iX1, long iY1, long iX2, long iY2, long iPrec)
{
long iAngle;
// Standard prec
if(!iPrec) iPrec = 1;
long dx=iX2-iX1,dy=iY2-iY1;
if (!dx) if (dy>0) return 180 * iPrec; else return 0;
if (!dy) if (dx>0) return 90 * iPrec; else return 270 * iPrec;
iAngle = static_cast<long>(180.0 * iPrec * atan2(static_cast<double>(Abs(dy)), static_cast<double>(Abs(dx))) / pi);
if (iX2>iX1 )
{
if (iY2<iY1) iAngle = (90 * iPrec) - iAngle;
else iAngle = (90 * iPrec) + iAngle;
}
else
{
if (iY2<iY1) iAngle = (270 * iPrec) + iAngle;
else iAngle = (270 * iPrec) - iAngle;
}
return iAngle;
}
static long FnArcSin(C4AulContext *cthr, long iVal, long iRadius)
{
// safety
if (!iRadius) return 0;
if (iVal > iRadius) return 0;
// calc arcsin
double f1 = iVal;
f1 = asin(f1/iRadius)*180.0/pi;
// return rounded angle
return (long) floor(f1+0.5);
}
static long FnArcCos(C4AulContext *cthr, long iVal, long iRadius)
{
// safety
if (!iRadius) return 0;
if (iVal > iRadius) return 0;
// calc arccos
double f1 = iVal;
f1 = acos(f1/iRadius)*180.0/pi;
// return rounded angle
return (long) floor(f1+0.5);
}
static long FnMin(C4AulContext *cthr, long iVal1, long iVal2)
{
return Min(iVal1,iVal2);
}
static long FnMax(C4AulContext *cthr, long iVal1, long iVal2)
{
return Max(iVal1,iVal2);
}
static long FnDistance(C4AulContext *cthr, long iX1, long iY1, long iX2, long iY2)
{
return Distance(iX1,iY1,iX2,iY2);
}
static long FnObjectDistance(C4AulContext *cthr, C4Object *pObj2, C4Object *pObj)
{
if (!pObj) pObj=cthr->Obj; if (!pObj || !pObj2) return 0;
return Distance(pObj->GetX(),pObj->GetY(),pObj2->GetX(),pObj2->GetY());
}
static long FnObjectNumber(C4AulObjectContext *cthr)
{
return cthr->Obj->Number;
}
C4Object* FnObject(C4AulContext *cthr, long iNumber)
{
return ::Objects.SafeObjectPointer(iNumber);
}
static long FnShowInfo(C4AulObjectContext *cthr, C4Object *pObj)
{
if (!pObj) pObj=cthr->Obj; if (!pObj) return false;
return cthr->Obj->ActivateMenu(C4MN_Info,0,0,0,pObj);
}
static long FnBoundBy(C4AulContext *cthr, long iVal, long iRange1, long iRange2)
{
return BoundBy(iVal,iRange1,iRange2);
}
static bool FnInside(C4AulContext *cthr, long iVal, long iRange1, long iRange2)
{
return Inside(iVal,iRange1,iRange2);
}
static long FnRandom(C4AulContext *cthr, long iRange)
{
return Random(iRange);
}
static long FnAsyncRandom(C4AulContext *cthr, long iRange)
{
return SafeRandom(iRange);
}
static C4Value FnCall_C4V(C4AulContext *cthr, C4Value* szFunction_C4V,
C4Value* par0, C4Value* par1, C4Value* par2, C4Value* par3, C4Value* par4,
C4Value* par5, C4Value* par6, C4Value* par7, C4Value* par8/*, C4Value* par9*/)
{
// safety
C4String *szFunction = szFunction_C4V->getStr();
if (!szFunction || !cthr->Obj) return C4Value();
C4AulParSet Pars;
Copy2ParSet9(Pars, *par);
return cthr->Obj->Call(FnStringPar(szFunction),&Pars, true);
}
static C4Value FnDefinitionCall_C4V(C4AulContext *cthr,
C4Value* idID_C4V, C4Value* szFunction_C4V,
C4Value* par0, C4Value* par1, C4Value* par2, C4Value* par3, C4Value* par4,
C4Value* par5, C4Value* par6, C4Value* par7/*, C4Value* par8, C4Value* par9*/)
{
C4ID idID = idID_C4V->getC4ID();
C4String *szFunction = szFunction_C4V->getStr();
if (!idID || !szFunction) return C4Value();
// Make failsafe
char szFunc2[500+1]; sprintf(szFunc2,"~%s",FnStringPar(szFunction));
// Get definition
C4Def *pDef;
if (!(pDef=C4Id2Def(idID))) return C4Value();
// copy parameters
C4AulParSet Pars;
Copy2ParSet8(Pars, *par);
// Call
return pDef->Script.Call(szFunc2, 0, &Pars, true);
}
static C4Value FnGameCall_C4V(C4AulContext *cthr,
C4Value* szFunction_C4V,
C4Value* par0, C4Value* par1, C4Value* par2, C4Value* par3, C4Value* par4,
C4Value* par5, C4Value* par6, C4Value* par7, C4Value* par8/*, C4Value* par9*/)
{
C4String *szFunction = szFunction_C4V->getStr();
if (!szFunction) return C4Value();
// Make failsafe
char szFunc2[500+1]; sprintf(szFunc2,"~%s",FnStringPar(szFunction));
// copy parameters
C4AulParSet Pars;
Copy2ParSet9(Pars, *par);
// Call
return Game.Script.Call(szFunc2, 0, &Pars, true);
}
static C4Value FnGameCallEx_C4V(C4AulContext *cthr,
C4Value* szFunction_C4V,
C4Value* par0, C4Value* par1, C4Value* par2, C4Value* par3, C4Value* par4,
C4Value* par5, C4Value* par6, C4Value* par7, C4Value* par8/*, C4Value* par9*/)
{
C4String *szFunction = szFunction_C4V->getStr();
if (!szFunction) return C4Value();
// Make failsafe
char szFunc2[500+1]; sprintf(szFunc2,"~%s",FnStringPar(szFunction));
// copy parameters
C4AulParSet Pars;
Copy2ParSet9(Pars, *par);
// Call
return Game.Script.GRBroadcast(szFunc2,&Pars, true);
}
static C4Value FnProtectedCall_C4V(C4AulContext *cthr,
C4Value* pObj_C4V, C4Value* szFunction_C4V,
C4Value* par0, C4Value* par1, C4Value* par2, C4Value* par3, C4Value* par4,
C4Value* par5, C4Value* par6, C4Value* par7/*, C4Value* par8, C4Value* par9*/)
{
C4Object *pObj = pObj_C4V->getObj();
C4String *szFunction = szFunction_C4V->getStr();
if (!pObj || !szFunction) return C4Value();
if (!pObj->Def) return C4Value();
// get func
C4AulScriptFunc *f;
if (!(f = pObj->Def->Script.GetSFunc(FnStringPar(szFunction), AA_PROTECTED, true))) return C4Value();
// copy parameters
C4AulParSet Pars;
Copy2ParSet8(Pars, *par);
// exec
return f->Exec(pObj,&Pars, true);
}
static C4Value FnPrivateCall_C4V(C4AulContext *cthr,
C4Value* pObj_C4V, C4Value* szFunction_C4V,
C4Value* par0, C4Value* par1, C4Value* par2, C4Value* par3, C4Value* par4,
C4Value* par5, C4Value* par6, C4Value* par7/*, C4Value* par8, C4Value* par9*/)
{
C4Object *pObj = pObj_C4V->getObj();
C4String *szFunction = szFunction_C4V->getStr();
if (!pObj || !szFunction) return C4Value();
if (!pObj->Def) return C4Value();
// get func
C4AulScriptFunc *f;
if (!(f = pObj->Def->Script.GetSFunc(FnStringPar(szFunction), AA_PRIVATE, true))) return C4Value();
// copy parameters
C4AulParSet Pars;
Copy2ParSet8(Pars, *par);
// exec
return f->Exec(pObj,&Pars, true);
}
static C4Value FnEditCursor(C4AulContext *cth, C4Value *pPars)
{
if (::Control.SyncMode()) return C4VNull;
return C4VObj(Console.EditCursor.GetTarget());
}
static bool FnResort(C4AulContext *cthr, C4Object *pObj)
{
if (!pObj) pObj=cthr->Obj;
// Resort single object
if (pObj)
pObj->Resort();
// Resort object list
else
::Objects.SortByCategory();
return true;
}
static bool FnIsNetwork(C4AulContext *cthr) { return Game.Parameters.IsNetworkGame; }
static C4String *FnGetLeague(C4AulContext *cthr, long idx)
{
// get indexed league
StdStrBuf sIdxLeague;
if (!Game.Parameters.League.GetSection(idx, &sIdxLeague)) return NULL;
return String(sIdxLeague.getData());
}
static bool FnTestMessageBoard(C4AulContext *cthr, long iForPlr, bool fTestIfInUse)
{
// multi-query-MessageBoard is always available if the player is valid =)
// (but it won't do anything in developer mode...)
C4Player *pPlr = ::Players.Get(iForPlr);
if (!pPlr) return false;
if (!fTestIfInUse) return true;
// single query only if no query is scheduled
return pPlr->HasMessageBoardQuery();
}
static bool FnCallMessageBoard(C4AulContext *cthr, C4Object *pObj, bool fUpperCase, C4String *szQueryString, long iForPlr)
{
if (!pObj) pObj=cthr->Obj;
if (pObj && !pObj->Status) return false;
// check player
C4Player *pPlr = ::Players.Get(iForPlr);
if (!pPlr) return false;
// remove any previous
pPlr->CallMessageBoard(pObj, StdStrBuf(FnStringPar(szQueryString)), !!fUpperCase);
return true;
}
static bool FnAbortMessageBoard(C4AulContext *cthr, C4Object *pObj, long iForPlr)
{
if (!pObj) pObj=cthr->Obj;
// check player
C4Player *pPlr = ::Players.Get(iForPlr);
if (!pPlr) return false;
// close TypeIn if active
::MessageInput.AbortMsgBoardQuery(pObj, iForPlr);
// abort for it
return pPlr->RemoveMessageBoardQuery(pObj);
}
static bool FnOnMessageBoardAnswer(C4AulContext *cthr, C4Object *pObj, long iForPlr, C4String *szAnswerString)
{
// remove query
// fail if query doesn't exist to prevent any doubled answers
C4Player *pPlr = ::Players.Get(iForPlr);
if (!pPlr) return false;
if (!pPlr->RemoveMessageBoardQuery(pObj)) return false;
// if no answer string is provided, the user did not answer anything
// just remove the query
if (!szAnswerString || !szAnswerString->GetCStr()) return true;
// get script
C4ScriptHost *scr;
if (pObj) scr = &pObj->Def->Script; else scr = &Game.Script;
// exec func
return !!scr->Call(PSF_InputCallback, pObj, &C4AulParSet(C4VString(FnStringPar(szAnswerString)), C4VInt(iForPlr)));
}
static long FnScriptCounter(C4AulContext *cthr)
{
return Game.Script.Counter;
}
static C4Void FnSetMass(C4AulObjectContext *cthr, long iValue)
{
cthr->Obj->OwnMass=iValue-cthr->Obj->Def->Mass;
cthr->Obj->UpdateMass();
return C4VNull;
}
static long FnGetColor(C4AulObjectContext *cthr)
{
return cthr->Obj->Color;
}
static Nillable<long> FnGetPlrColor(C4AulContext *cthr, long iPlr)
{
// get player
C4Player *pPlr = ::Players.Get(iPlr);
// safety
if (!pPlr) return C4VNull;
// return player color
return pPlr->ColorDw;
}
static C4Void FnSetColor(C4AulObjectContext *cthr, long iValue)
{
cthr->Obj->Color=iValue;
cthr->Obj->UpdateGraphics(false);
cthr->Obj->UpdateFace(false);
return C4VNull;
}
static C4Void FnSetFoW(C4AulContext *cthr, bool fEnabled, long iPlr)
{
// safety
if (!ValidPlr(iPlr)) return C4VNull;
// set enabled
::Players.Get(iPlr)->SetFoW(!!fEnabled);
// success
return C4VNull;
}
static C4Void FnSetPlrViewRange(C4AulObjectContext *cthr, long iRange)
{
// set range
cthr->Obj->SetPlrViewRange(iRange);
// success
return C4VNull;
}
static long FnSetMaxPlayer(C4AulContext *cthr, long iTo)
{
// think positive! :)
if (iTo < 0) return false;
// script functions don't need to pass ControlQueue!
Game.Parameters.MaxPlayers = iTo;
// success
return true;
}
static C4Void FnSetPicture(C4AulObjectContext *cthr, long iX, long iY, long iWdt, long iHgt)
{
// set new picture rect
cthr->Obj->PictureRect.Set(iX, iY, iWdt, iHgt);
// success
return C4VNull;
}
static C4String *FnGetProcedure(C4AulObjectContext *cthr)
{
// no action?
if (!cthr->Obj->Action.pActionDef) return NULL;
// get proc
long iProc = cthr->Obj->Action.pActionDef->GetPropertyInt(P_Procedure);
// NONE?
if (iProc <= DFA_NONE) return NULL;
// return procedure name
return String(ProcedureName[iProc]);
}
static C4Object *FnBuy(C4AulContext *cthr, C4ID idBuyObj, long iForPlr, long iPayPlr, C4Object *pToBase, bool fShowErrors)
{
// safety
if (!ValidPlr(iForPlr) || !ValidPlr(iPayPlr)) return NULL;
// buy
C4Object *pThing;
if (!(pThing=::Players.Get(iPayPlr)->Buy(idBuyObj, fShowErrors, iForPlr, pToBase ? pToBase : cthr->Obj))) return NULL;
// enter object, if supplied
if (pToBase)
{
pThing->Enter(pToBase, true);
}
else
{
// no target object? get local pos
if (cthr->Obj) pThing->ForcePosition(cthr->Obj->GetX(), cthr->Obj->GetY());
}
// done
return pThing;
}
static bool FnSell(C4AulObjectContext *cthr, long iToPlr)
{
// safety
if (!ValidPlr(iToPlr)) return false;
// sell
return !!::Players.Get(iToPlr)->Sell2Home(cthr->Obj);
}
static C4Value FnIsRef(C4AulContext *cthr, C4Value* Value)
{
return C4VBool(Value->IsRef());
}
static C4Value FnGetType(C4AulContext *cthr, C4Value* Value)
{
return C4VInt(Value->GetType());
}
static C4Value FnCreateArray(C4AulContext *cthr, C4Value *pPars)
{
PAR(int, iSize);
return C4VArray(new C4ValueArray(iSize));
}
static C4Value FnGetLength(C4AulContext *cthr, C4Value *pPars)
{
// support GetLength() etc.
if (!pPars[0]) return C4VNull;
C4ValueArray * pArray = pPars->getArray();
if (pArray)
return C4VInt(pArray->GetSize());
C4String * pStr = pPars->getStr();
if (pStr)
return C4VInt(pStr->GetData().getLength());
throw new C4AulExecError(cthr->Obj, "func \"GetLength\" par 0 cannot be converted to string or array");
}
static C4Value FnGetIndexOf(C4AulContext *cthr, C4Value *pPars)
{
// find first occurance of first parameter in array
// support GetIndexOf(x, 0)
if (!pPars[1]) return C4VInt(-1);
// if the second param is nonzero, it must be an array
const C4ValueArray * pArray = pPars[1].getArray();
if (!pArray)
throw new C4AulExecError(cthr->Obj, "func \"GetIndexOf\" par 1 cannot be converted to array");
// find the element by comparing data only - this may result in bogus results if an object ptr array is searched for an int
// however, that's rather unlikely and strange scripting style
int32_t iSize = pArray->GetSize();
long cmp = pPars[0].GetData().Int;
for (int32_t i = 0; i<iSize; ++i)
if (cmp == pArray->GetItem(i).GetData().Int)
// element found
return C4VInt(i);
// element not found
return C4VInt(-1);
}
static C4Value FnSetLength(C4AulContext *cthr, C4Value *pPars)
{
PAR(ref, pArrayRef);
PAR(int, iNewSize);
// safety
if (iNewSize<0 || iNewSize > C4ValueArray::MaxSize)
throw new C4AulExecError(cthr->Obj, FormatString("SetLength: invalid array size (%d)", iNewSize).getData());
// set new size
pArrayRef.SetArrayLength(iNewSize, cthr);
// yeah, done!
return C4VBool(true);
}
static bool FnSetClrModulation(C4AulObjectContext *cthr, long dwClr, long iOverlayID)
{
// overlay?
if (iOverlayID)
{
C4GraphicsOverlay *pOverlay = cthr->Obj->GetGraphicsOverlay(iOverlayID, false);
if (!pOverlay)
{
DebugLogF("SetClrModulation: Overlay %d not defined for object %d (%s)", (int) iOverlayID, (int) cthr->Obj->Number, cthr->Obj->GetName());
return false;
}
pOverlay->SetClrModulation(dwClr);
}
else
{
// set it
cthr->Obj->ColorMod=dwClr;
}
// success
return true;
}
static Nillable<long> FnGetClrModulation(C4AulObjectContext *cthr, long iOverlayID)
{
// overlay?
if (iOverlayID)
{
C4GraphicsOverlay *pOverlay = cthr->Obj->GetGraphicsOverlay(iOverlayID, false);
if (!pOverlay)
{
DebugLogF("GetClrModulation: Overlay %d not defined for object %d (%s)", (int) iOverlayID, (int) cthr->Obj->Number, cthr->Obj->GetName());
return C4VNull;
}
return pOverlay->GetClrModulation();
}
else
// get it
return cthr->Obj->ColorMod;
}
static bool FnGetMissionAccess(C4AulContext *cthr, C4String *strMissionAccess)
{
// safety
if (!strMissionAccess) return false;
// non-sync mode: warn
if(::Control.SyncMode())
Log("Warning: using GetMissionAccess may cause desyncs when playing records!");
if (!Config.General.MissionAccess) return false;
return SIsModule(Config.General.MissionAccess, FnStringPar(strMissionAccess));
}
// Helper to read or write a value from/to a structure. Must be two
class C4ValueCompiler : public StdCompiler
{
public:
C4ValueCompiler(const char **pszNames, int iNameCnt, int iEntryNr)
: pszNames(pszNames), iNameCnt(iNameCnt), iEntryNr(iEntryNr)
{ }
virtual bool isCompiler() { return false; }
virtual bool hasNaming() { return true; }
virtual bool isVerbose() { return false; }
virtual bool Name(const char *szName)
{
// match possible? (no match yet / continued match)
if(!iMatchStart || haveCurrentMatch())
// already got all names?
if(!haveCompleteMatch())
// check name
if(SEqual(pszNames[iMatchCount], szName))
{
// got match
if(!iMatchCount) iMatchStart = iDepth + 1;
iMatchCount++;
}
iDepth++;
return true;
}
virtual bool Default(const char *szName)
{
// Always process values even if they are default!
return false;
}
virtual void NameEnd(bool fBreak = false)
{
// end of matched name section?
if(haveCurrentMatch())
{
iMatchCount--;
if(!iMatchCount) iMatchStart = 0;
}
iDepth--;
}
virtual void Begin()
{
// set up
iDepth = iMatchStart = iMatchCount = 0;
}
protected:
// value function forward to be overwritten by get or set compiler
virtual void ProcessInt(int32_t &rInt) = 0;
virtual void ProcessBool(bool &rBool) = 0;
virtual void ProcessChar(char &rChar) = 0;
virtual void ProcessString(char *szString, size_t iMaxLength, bool fIsID) = 0;
virtual void ProcessString(char **pszString, bool fIsID) = 0;
public:
// value functions
virtual void DWord(int32_t &rInt) { if(haveCompleteMatch()) if(!iEntryNr--) ProcessInt(rInt); }
virtual void DWord(uint32_t &rInt) { if(haveCompleteMatch()) if(!iEntryNr--) { int32_t i=rInt; ProcessInt(i); rInt =i; } }
virtual void Word(int16_t &rShort) { if(haveCompleteMatch()) if(!iEntryNr--) { int32_t i=rShort; ProcessInt(i); rShort=i; } }
virtual void Word(uint16_t &rShort) { if(haveCompleteMatch()) if(!iEntryNr--) { int32_t i=rShort; ProcessInt(i); rShort=i; } }
virtual void Byte(int8_t &rByte) { if(haveCompleteMatch()) if(!iEntryNr--) { int32_t i=rByte; ProcessInt(i); rByte =i; } }
virtual void Byte(uint8_t &rByte) { if(haveCompleteMatch()) if(!iEntryNr--) { int32_t i=rByte; ProcessInt(i); rByte =i; } }
virtual void Boolean(bool &rBool) { if(haveCompleteMatch()) if(!iEntryNr--) ProcessBool(rBool); }
virtual void Character(char &rChar) { if(haveCompleteMatch()) if(!iEntryNr--) ProcessChar(rChar); }
// The C4ID-Adaptor will set RCT_ID for it's strings (see C4Id.h), so we don't have to guess the type.
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType)
{ if(haveCompleteMatch()) if(!iEntryNr--) ProcessString(szString, iMaxLength, eType == StdCompiler::RCT_ID); }
virtual void String(char **pszString, RawCompileType eType)
{ if(haveCompleteMatch()) if(!iEntryNr--) ProcessString(pszString, eType == StdCompiler::RCT_ID); }
virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped)
{ /* C4Script can't handle this */ }
private:
// Name(s) of the entry to read
const char **pszNames;
int iNameCnt;
// Number of the element that is to be read
int iEntryNr;
// current depth
int iDepth;
// match start (where did the first name match?),
// match count (how many names did match, from that point?)
int iMatchStart, iMatchCount;
private:
// match active?
bool haveCurrentMatch() const { return iDepth + 1 == iMatchStart + iMatchCount; }
// match complete?
bool haveCompleteMatch() const { return haveCurrentMatch() && iMatchCount == iNameCnt; }
};
class C4ValueGetCompiler : public C4ValueCompiler
{
private:
// Result
C4Value Res;
public:
C4ValueGetCompiler(const char **pszNames, int iNameCnt, int iEntryNr)
: C4ValueCompiler(pszNames, iNameCnt, iEntryNr)
{ }
// Result-getter
const C4Value &getResult() const { return Res; }
protected:
// get values as C4Value
virtual void ProcessInt(int32_t &rInt) { Res = C4VInt(rInt); }
virtual void ProcessBool(bool &rBool) { Res = C4VBool(rBool); }
virtual void ProcessChar(char &rChar) { Res = C4VString(FormatString("%c", rChar)); }
virtual void ProcessString(char *szString, size_t iMaxLength, bool fIsID)
{ Res = (fIsID ? C4VID(C4Id(szString)) : C4VString(szString)); }
virtual void ProcessString(char **pszString, bool fIsID)
{ Res = (fIsID ? C4VID(C4Id(*pszString)) : C4VString(*pszString)); }
};
// Use the compiler to find a named value in a structure
template <class T>
C4Value GetValByStdCompiler(const char *strEntry, const char *strSection, int iEntryNr, const T &rFrom)
{
// Set up name array, create compiler
const char *szNames[2] = { strSection ? strSection : strEntry, strSection ? strEntry : NULL };
C4ValueGetCompiler Comp(szNames, strSection ? 2 : 1, iEntryNr);
// Compile
try
{
Comp.Decompile(rFrom);
return Comp.getResult();
}
// Should not happen, catch it anyway.
catch(StdCompiler::Exception *)
{
return C4VNull;
}
}
static C4Value FnGetDefCoreVal(C4AulContext* cthr, C4Value* strEntry_C4V, C4Value* strSection_C4V, C4Value *iEntryNr_C4V)
{
if (!cthr->Def)
throw new NeedNonGlobalContext("GetDefCoreVal");
const char *strEntry = FnStringPar(strEntry_C4V->getStr());
const char *strSection = FnStringPar(strSection_C4V->getStr());
if (strSection && !*strSection) strSection = NULL;
long iEntryNr = iEntryNr_C4V->getInt();
return GetValByStdCompiler(strEntry, strSection, iEntryNr, mkNamingAdapt(*cthr->Def, "DefCore"));
}
static C4Value FnGetObjectVal(C4AulObjectContext* cthr, C4Value* strEntry_C4V, C4Value* strSection_C4V, C4Value *iEntryNr_C4V)
{
const char *strEntry = FnStringPar(strEntry_C4V->getStr());
const char *strSection = FnStringPar(strSection_C4V->getStr());
if (!*strSection) strSection = NULL;
long iEntryNr = iEntryNr_C4V->getInt();
// get value
return GetValByStdCompiler(strEntry, strSection, iEntryNr, mkNamingAdapt(*cthr->Obj, "Object"));
}
static C4Value FnGetObjectInfoCoreVal(C4AulObjectContext* cthr, C4Value* strEntry_C4V, C4Value* strSection_C4V, C4Value *iEntryNr_C4V)
{
const char *strEntry = FnStringPar(strEntry_C4V->getStr());
const char *strSection = FnStringPar(strSection_C4V->getStr());
if (strSection && !*strSection) strSection = NULL;
long iEntryNr = iEntryNr_C4V->getInt();
// get obj info
C4ObjectInfo* pObjInfo = cthr->Obj->Info;
if(!pObjInfo) return C4VNull;
// get obj info core
C4ObjectInfoCore* pObjInfoCore = (C4ObjectInfoCore*) pObjInfo;
// get value
return GetValByStdCompiler(strEntry, strSection, iEntryNr, mkNamingAdapt(*pObjInfoCore, "ObjectInfo"));
}
static C4Value FnGetScenarioVal(C4AulContext* cthr, C4Value* strEntry_C4V, C4Value* strSection_C4V, C4Value *iEntryNr_C4V)
{
const char *strEntry = FnStringPar(strEntry_C4V->getStr());
const char *strSection = FnStringPar(strSection_C4V->getStr());
long iEntryNr = iEntryNr_C4V->getInt();
if(strSection && !*strSection) strSection = NULL;
return GetValByStdCompiler(strEntry, strSection, iEntryNr, mkParAdapt(Game.C4S, false));
}
static C4Value FnGetPlayerVal(C4AulContext* cthr, C4Value* strEntry_C4V, C4Value* strSection_C4V, C4Value* iPlayer_C4V, C4Value *iEntryNr_C4V)
{
const char *strEntry = FnStringPar(strEntry_C4V->getStr());
const char *strSection = FnStringPar(strSection_C4V->getStr());
if(strSection && !*strSection) strSection = NULL;
long iPlr = iPlayer_C4V->getInt();
long iEntryNr = iEntryNr_C4V->getInt();
if(!ValidPlr(iPlr)) return C4Value();
// get player
C4Player* pPlayer = ::Players.Get(iPlr);
// get value
return GetValByStdCompiler(strEntry, strSection, iEntryNr, mkNamingAdapt(mkParAdapt(*pPlayer, true), "Player"));
}
static C4Value FnGetPlayerInfoCoreVal(C4AulContext* cthr, C4Value* strEntry_C4V, C4Value* strSection_C4V, C4Value* iPlayer_C4V, C4Value *iEntryNr_C4V)
{
const char *strEntry = FnStringPar(strEntry_C4V->getStr());
const char *strSection = FnStringPar(strSection_C4V->getStr());
if(strSection && !*strSection) strSection = NULL;
long iPlr = iPlayer_C4V->getInt();
long iEntryNr = iEntryNr_C4V->getInt();
if(!ValidPlr(iPlr)) return C4Value();
// get player
C4Player* pPlayer = ::Players.Get(iPlr);
// get plr info core
C4PlayerInfoCore* pPlayerInfoCore = (C4PlayerInfoCore*) pPlayer;
// get value
return GetValByStdCompiler(strEntry, strSection, iEntryNr, *pPlayerInfoCore);
}
static C4Value FnGetMaterialVal(C4AulContext* cthr, C4Value* strEntry_C4V, C4Value* strSection_C4V, C4Value* iMat_C4V, C4Value *iEntryNr_C4V)
{
const char *strEntry = FnStringPar(strEntry_C4V->getStr());
const char *strSection = FnStringPar(strSection_C4V->getStr());
if(strSection && !*strSection) strSection = NULL;
long iMat = iMat_C4V->getInt();
long iEntryNr = iEntryNr_C4V->getInt();
if(iMat < 0 || iMat >= ::MaterialMap.Num) return C4Value();
// get material
C4Material *pMaterial = &::MaterialMap.Map[iMat];
// get plr info core
C4MaterialCore* pMaterialCore = static_cast<C4MaterialCore*>(pMaterial);
// material core implicates section "Material"
if (!SEqual(strSection, "Material")) return C4Value();
// get value
return GetValByStdCompiler(strEntry, NULL, iEntryNr, *pMaterialCore);
}
static bool FnCloseMenu(C4AulObjectContext *cthr)
{
return !!cthr->Obj->CloseMenu(true);
}
static Nillable<long> FnGetMenuSelection(C4AulObjectContext *cthr)
{
if(!cthr->Obj->Menu || !cthr->Obj->Menu->IsActive()) return C4VNull;
return cthr->Obj->Menu->GetSelection();
}
static bool FnResortObjects(C4AulContext* cthr, C4String *szFunc, long Category)
{
// safety
if (!szFunc) return false;
if (!cthr->Caller) return false;
// default category
if (!Category) Category=C4D_SortLimit;
// get function
C4AulFunc *pFn = cthr->Caller->Func->GetLocalSFunc(FnStringPar(szFunc));
if (!pFn)
throw new C4AulExecError(cthr->Obj, FormatString("ResortObjects: Resort function %s not found", FnStringPar(szFunc)).getData());
// create object resort
C4ObjResort *pObjRes = new C4ObjResort();
pObjRes->Category=Category;
pObjRes->OrderFunc=pFn;
// insert into game resort proc list
pObjRes->Next = ::Objects.ResortProc;
::Objects.ResortProc = pObjRes;
// success, so far
return true;
}
static bool FnResortObject(C4AulObjectContext* cthr, C4String *szFunc)
{
// safety
if (!szFunc) return false;
if (!cthr->Caller) return false;
// get function
C4AulFunc *pFn = cthr->Caller->Func->GetLocalSFunc(FnStringPar(szFunc));
if (!pFn)
throw new C4AulExecError(cthr->Obj, FormatString("ResortObjects: Resort function %s not found", FnStringPar(szFunc)).getData());
// create object resort
C4ObjResort *pObjRes = new C4ObjResort();
pObjRes->OrderFunc=pFn;
pObjRes->pSortObj=cthr->Obj;
// insert into game resort proc list
pObjRes->Next = ::Objects.ResortProc;
::Objects.ResortProc = pObjRes;
// success, so far
return true;
}
static long FnGetChar(C4AulContext* cthr, C4String *pString, long iIndex)
{
const char *szText = FnStringPar(pString);
if (!szText) return 0;
// loop and check for end of string
for (int i=0; i<iIndex; i++, szText++)
if (!*szText) return 0;
// return indiced character value
return (unsigned char) *szText;
}
static bool FnSetGraphics(C4AulObjectContext *pCtx, C4String *pGfxName, C4ID idSrcGfx, long iOverlayID, long iOverlayMode, C4String *pAction, long dwBlitMode, C4Object *pOverlayObject)
{
// safety
if (!pCtx->Obj->Status) return false;
// get def for source graphics
C4Def *pSrcDef=NULL;
if (idSrcGfx) if (!(pSrcDef=C4Id2Def(idSrcGfx))) return false;
// setting overlay?
if (iOverlayID)
{
// any overlays must be positive for now
if (iOverlayID<0) { Log("SetGraphics: Background overlays not implemented!"); return false; }
// deleting overlay?
C4DefGraphics *pGrp;
if (iOverlayMode == C4GraphicsOverlay::MODE_Object)
{
if (!pOverlayObject) return pCtx->Obj->RemoveGraphicsOverlay(iOverlayID);
}
else
{
if (!pSrcDef) return pCtx->Obj->RemoveGraphicsOverlay(iOverlayID);
pGrp = pSrcDef->Graphics.Get(FnStringPar(pGfxName));
if (!pGrp) return false;
}
// adding/setting
C4GraphicsOverlay *pOverlay = pCtx->Obj->GetGraphicsOverlay(iOverlayID, true);
switch (iOverlayMode)
{
case C4GraphicsOverlay::MODE_Base:
pOverlay->SetAsBase(pGrp, dwBlitMode);
break;
case C4GraphicsOverlay::MODE_Action:
pOverlay->SetAsAction(pGrp, FnStringPar(pAction), dwBlitMode);
break;
case C4GraphicsOverlay::MODE_IngamePicture:
pOverlay->SetAsIngamePicture(pGrp, dwBlitMode);
break;
case C4GraphicsOverlay::MODE_Picture:
pOverlay->SetAsPicture(pGrp, dwBlitMode);
break;
case C4GraphicsOverlay::MODE_Object:
if (pOverlayObject && !pOverlayObject->Status) pOverlayObject = NULL;
pOverlay->SetAsObject(pOverlayObject, dwBlitMode);
break;
case C4GraphicsOverlay::MODE_ExtraGraphics:
pOverlay->SetAsExtraGraphics(pGrp, dwBlitMode);
break;
default:
DebugLog("SetGraphics: Invalid overlay mode");
pOverlay->SetAsBase(NULL, 0); // make invalid, so it will be removed
break;
}
// remove if invalid
if (!pOverlay->IsValid(pCtx->Obj))
{
pCtx->Obj->RemoveGraphicsOverlay(iOverlayID);
return false;
}
// Okay, valid overlay set!
return true;
}
// no overlay: Base graphics
// set graphics - pSrcDef==NULL defaults to pObj->pDef
return pCtx->Obj->SetGraphics(FnStringPar(pGfxName), pSrcDef);
}
static long FnGetDefBottom(C4AulContext* cthr)
{
if (!cthr->Obj)
if (!cthr->Def)
throw new NeedNonGlobalContext("GetDefBottom");
assert(!cthr->Obj || cthr->Obj->Def == cthr->Def);
return cthr->Def->Shape.y+cthr->Def->Shape.Hgt + (cthr->Obj ? cthr->Obj->GetY() : 0);
}
static C4String *FnMaterialName(C4AulContext* cthr, long iMat)
{
// mat valid?
if (!MatValid(iMat)) return NULL;
// return mat name
return String(::MaterialMap.Map[iMat].Name);
}
static bool FnSetMenuSize(C4AulObjectContext* cthr, long iCols, long iRows)
{
// get menu
C4Menu *pMnu=cthr->Obj->Menu;
if (!pMnu || !pMnu->IsActive()) return false;
pMnu->SetSize(BoundBy<long>(iCols, 0, 50), BoundBy<long>(iRows, 0, 50));
return true;
}
char NeededMat[C4MaxMessage];
static C4String *FnGetNeededMatStr(C4AulContext* cthr, C4Object *pObj)
{
// local/safety
if (!pObj) if (!(pObj=cthr->Obj)) return NULL;
return String(pObj->GetNeededMatStr(cthr->Obj).getData());
}
static C4Value FnEval(C4AulContext *cthr, C4Value *strScript_C4V)
{
// execute script in the same object
enum C4AulScript::Strict Strict = C4AulScript::MAXSTRICT;
if (cthr->Caller)
Strict = cthr->Caller->Func->pOrgScript->Strict;
if (cthr->Obj)
return cthr->Obj->Def->Script.DirectExec(cthr->Obj, FnStringPar(strScript_C4V->getStr()), "eval", true, Strict);
else if (cthr->Def)
return cthr->Def->Script.DirectExec(0, FnStringPar(strScript_C4V->getStr()), "eval", true, Strict);
else
return Game.Script.DirectExec(0, FnStringPar(strScript_C4V->getStr()), "eval", true, Strict);
}
static bool FnLocateFunc(C4AulContext *cthr, C4String *funcname, C4Object *pObj, C4ID idDef)
{
// safety
if (!funcname || !funcname->GetCStr())
{
Log("No func name");
return false;
}
// determine script context
C4AulScript *pCheckScript;
if (pObj)
{
pCheckScript = &pObj->Def->Script;
}
else if (idDef)
{
C4Def *pDef = C4Id2Def(idDef);
if (!pDef) { Log("Invalid or unloaded def"); return false; }
pCheckScript = &pDef->Script;
}
else
{
if (!cthr || !cthr->Caller || !cthr->Caller->Func || !cthr->Caller->Func->Owner)
{
Log("No valid script context");
return false;
}
pCheckScript = cthr->Caller->Func->Owner;
}
// get function by name
C4AulFunc *pFunc = pCheckScript->GetFuncRecursive(funcname->GetCStr());
if (!pFunc)
{
LogF("Func %s not found", funcname->GetCStr());
}
else
{
const char *szPrefix = "";
while (pFunc)
{
C4AulScriptFunc *pSFunc = pFunc->SFunc();
if (!pSFunc)
{
LogF("%s%s (engine)", szPrefix, pFunc->Name);
}
else if (!pSFunc->pOrgScript)
{
LogF("%s%s (no owner)", szPrefix, pSFunc->Name);
}
else
{
int32_t iLine = SGetLine(pSFunc->pOrgScript->GetScript(), pSFunc->Script);
LogF("%s%s (%s:%d)", szPrefix, pFunc->Name, pSFunc->pOrgScript->ScriptName.getData(), (int)iLine);
}
// next func in overload chain
pFunc = pSFunc ? pSFunc->OwnerOverloaded : NULL;
szPrefix = "overloads ";
}
}
return true;
}
static C4Value FnVarN(C4AulContext *cthr, C4Value *strName_C4V)
{
const char *strName = FnStringPar(strName_C4V->getStr());
if(!cthr->Caller) return C4VNull;
// find variable
int32_t iID = cthr->Caller->Func->VarNamed.GetItemNr(strName);
if(iID < 0)
return C4VNull;
// return reference on variable
return cthr->Caller->Vars[iID].GetRef();
}
static C4Value FnLocalN(C4AulContext* cthr, C4Value* strName_C4V)
{
if (!cthr->Obj)
throw new NeedObjectContext("LocalN");
const char* strName = FnStringPar(strName_C4V->getStr());
// find variable
C4Value* pVarN = cthr->Obj->LocalNamed.GetItem(strName);
if(!pVarN) return C4VNull;
// return reference on variable
return pVarN->GetRef();
}
static C4Value FnGlobalN(C4AulContext* cthr, C4Value* strName_C4V)
{
const char* strName = FnStringPar(strName_C4V->getStr());
// find variable
C4Value* pVarN = ::ScriptEngine.GlobalNamed.GetItem(strName);
if(!pVarN) return C4Value();
// return reference on variable
return pVarN->GetRef();
}
static bool FnSetSkyAdjust(C4AulContext* cthr, long dwAdjust, long dwBackClr)
{
// set adjust
::Landscape.Sky.SetModulation(dwAdjust, dwBackClr);
// success
return true;
}
static bool FnSetMatAdjust(C4AulContext* cthr, long dwAdjust)
{
// set adjust
::Landscape.SetModulation(dwAdjust);
// success
return true;
}
static long FnGetSkyAdjust(C4AulContext* cthr, bool fBackColor)
{
// get adjust
return ::Landscape.Sky.GetModulation(!!fBackColor);
}
static long FnGetMatAdjust(C4AulContext* cthr)
{
// get adjust
return ::Landscape.GetModulation();
}
static long FnAnyContainer(C4AulContext*) { return ANY_CONTAINER; }
static long FnNoContainer(C4AulContext*) { return NO_CONTAINER; }
static long FnGetTime(C4AulContext *)
{
// check network, record, etc
if (::Control.SyncMode()) return 0;
return timeGetTime();
}
static long FnGetSystemTime(C4AulContext *cthr, long iWhat)
{
#ifdef _WIN32
// check network, record, etc
if (::Control.SyncMode()) return 0;
// check bounds
if (!Inside<long>(iWhat, 0, 7)) return 0;
SYSTEMTIME time;
GetLocalTime(&time);
// return queried value
return *(((WORD *) &time) + iWhat);
#else
return 0;
#endif
}
static C4Value FnSetPlrExtraData(C4AulContext *cthr, C4Value *iPlayer_C4V, C4Value *strDataName_C4V, C4Value *Data)
{
long iPlayer = iPlayer_C4V->getInt();
const char *strDataName = FnStringPar(strDataName_C4V->getStr());
// valid player? (for great nullpointer prevention)
if(!ValidPlr(iPlayer)) return C4Value();
// do not allow data type C4V_String or C4V_C4Object
if(Data->GetType() != C4V_Any &&
Data->GetType() != C4V_Int &&
Data->GetType() != C4V_Bool) return C4VNull;
// get pointer on player...
C4Player* pPlayer = ::Players.Get(iPlayer);
// no name list created yet?
if(!pPlayer->ExtraData.pNames)
// create name list
pPlayer->ExtraData.CreateTempNameList();
// data name already exists?
long ival;
if((ival = pPlayer->ExtraData.pNames->GetItemNr(strDataName)) != -1)
pPlayer->ExtraData[ival] = *Data;
else
{
// add name
pPlayer->ExtraData.pNames->AddName(strDataName);
// get val id & set
if((ival = pPlayer->ExtraData.pNames->GetItemNr(strDataName)) == -1) return C4Value();
pPlayer->ExtraData[ival] = *Data;
}
// ok, return the value that has been set
return *Data;
}
static C4Value FnGetPlrExtraData(C4AulContext *cthr, C4Value *iPlayer_C4V, C4Value *strDataName_C4V)
{
long iPlayer = iPlayer_C4V->getInt();
const char *strDataName = FnStringPar(strDataName_C4V->getStr());
// valid player?
if(!ValidPlr(iPlayer)) return C4Value();
// get pointer on player...
C4Player* pPlayer = ::Players.Get(iPlayer);
// no name list?
if(!pPlayer->ExtraData.pNames) return C4Value();
long ival;
if((ival = pPlayer->ExtraData.pNames->GetItemNr(strDataName)) == -1) return C4Value();
// return data
return pPlayer->ExtraData[ival];
}
static C4Value FnSetCrewExtraData(C4AulContext *cthr, C4Value *strDataName_C4V, C4Value *Data)
{
if (!cthr->Obj)
throw NeedObjectContext("SetCrewExtraData");
const char *strDataName = FnStringPar(strDataName_C4V->getStr());
// valid crew with info? (for great nullpointer prevention)
if(!cthr->Obj->Info) return C4Value();
// do not allow data type C4V_String or C4V_C4Object
if(Data->GetType() != C4V_Any &&
Data->GetType() != C4V_Int &&
Data->GetType() != C4V_Bool) return C4VNull;
// get pointer on info...
C4ObjectInfo *pInfo = cthr->Obj->Info;
// no name list created yet?
if(!pInfo->ExtraData.pNames)
// create name list
pInfo->ExtraData.CreateTempNameList();
// data name already exists?
long ival;
if((ival = pInfo->ExtraData.pNames->GetItemNr(strDataName)) != -1)
pInfo->ExtraData[ival] = *Data;
else
{
// add name
pInfo->ExtraData.pNames->AddName(strDataName);
// get val id & set
if((ival = pInfo->ExtraData.pNames->GetItemNr(strDataName)) == -1) return C4Value();
pInfo->ExtraData[ival] = *Data;
}
// ok, return the value that has been set
return *Data;
}
static C4Value FnGetCrewExtraData(C4AulContext *cthr, C4Value *strDataName_C4V)
{
if (!cthr->Obj)
throw NeedObjectContext("GetCrewExtraData");
const char *strDataName = FnStringPar(strDataName_C4V->getStr());
// valid crew with info?
if(!cthr->Obj->Info) return C4Value();
// get pointer on info...
C4ObjectInfo *pInfo = cthr->Obj->Info;
// no name list?
if(!pInfo->ExtraData.pNames) return C4Value();
long ival;
if((ival = pInfo->ExtraData.pNames->GetItemNr(strDataName)) == -1) return C4Value();
// return data
return pInfo->ExtraData[ival];
}
static long FnDrawMatChunks(C4AulContext *cctx, long tx, long ty, long twdt, long thgt, long icntx, long icnty, C4String *strMaterial, C4String *strTexture, bool bIFT)
{
return ::Landscape.DrawChunks(tx, ty, twdt, thgt, icntx, icnty, FnStringPar(strMaterial), FnStringPar(strTexture), bIFT != 0);
}
static bool FnGetCrewEnabled(C4AulObjectContext *cctx)
{
// return status
return !cctx->Obj->CrewDisabled;
}
static C4Void FnSetCrewEnabled(C4AulObjectContext *cctx, bool fEnabled)
{
// set status
cctx->Obj->CrewDisabled=!fEnabled;
// deselect
if (!fEnabled)
{
cctx->Obj->Select=false;
C4Player *pOwner;
if (pOwner=::Players.Get(cctx->Obj->Owner))
{
// if viewed player cursor gets deactivated and no new cursor is found, follow the old in target mode
bool fWasCursorMode = (pOwner->ViewMode == C4PVM_Cursor);
if (pOwner->Cursor==cctx->Obj)
pOwner->AdjustCursorCommand();
if (!pOwner->ViewCursor && !pOwner->Cursor && fWasCursorMode)
pOwner->SetViewMode(C4PVM_Target, cctx->Obj);
}
}
// success
return C4VNull;
}
static bool FnUnselectCrew(C4AulContext *cctx, long iPlayer)
{
// get player
C4Player *pPlr=::Players.Get(iPlayer);
if (!pPlr) return false;
// unselect crew
pPlr->UnselectCrew();
// success
return true;
}
static long FnDrawMap(C4AulContext *cctx, long iX, long iY, long iWdt, long iHgt, C4String *szMapDef)
{
// draw it!
return ::Landscape.DrawMap(iX, iY, iWdt, iHgt, FnStringPar(szMapDef));
}
static long FnDrawDefMap(C4AulContext *cctx, long iX, long iY, long iWdt, long iHgt, C4String *szMapDef)
{
// draw it!
return ::Landscape.DrawDefMap(iX, iY, iWdt, iHgt, FnStringPar(szMapDef));
}
struct C4ModLandscapeMatRec
{
long iMode, iClr1, iClr2;
};
DWORD FadeClr(DWORD dwClr1, DWORD dwClr2, BYTE byA1)
{
// darken colors and add them
DarkenClrBy(dwClr1, 255-byA1); DarkenClrBy(dwClr2, byA1);
return dwClr1+dwClr2;
}
void SmoothChars(signed char &r1, signed char &r2)
{
// lower the difference between two numbers
signed char d=(r2-r1)/4;
r1+=d; r2-=d;
}
static bool FnCreateParticle(C4AulContext *cthr, C4String *szName, long iX, long iY, long iXDir, long iYDir, long a, long b, C4Object *pObj, bool fBack)
{
// safety
if (pObj && !pObj->Status) return false;
// local offset
if (cthr->Obj)
{
iX+=cthr->Obj->GetX();
iY+=cthr->Obj->GetY();
}
// get particle
C4ParticleDef *pDef=::Particles.GetDef(FnStringPar(szName));
if (!pDef) return false;
// create
::Particles.Create(pDef, (float) iX, (float) iY, (float) iXDir/10.0f, (float) iYDir/10.0f, (float) a/10.0f, b, pObj ? (fBack ? &pObj->BackParticles : &pObj->FrontParticles) : NULL, pObj);
// success, even if not created
return true;
}
static bool FnCastAParticles(C4AulContext *cthr, C4String *szName, long iAmount, long iLevel, long iX, long iY, long a0, long a1, long b0, long b1, C4Object *pObj, bool fBack)
{
// safety
if (pObj && !pObj->Status) return false;
// local offset
if (cthr->Obj)
{
iX+=cthr->Obj->GetX();
iY+=cthr->Obj->GetY();
}
// get particle
C4ParticleDef *pDef=::Particles.GetDef(FnStringPar(szName));
if (!pDef) return false;
// cast
::Particles.Cast(pDef, iAmount, (float) iX, (float) iY, iLevel, (float) a0/10.0f, b0, (float) a1/10.0f, b1, pObj ? (fBack ? &pObj->BackParticles : &pObj->FrontParticles) : NULL, pObj);
// success, even if not created
return true;
}
static bool FnCastParticles(C4AulContext *cthr, C4String *szName, long iAmount, long iLevel, long iX, long iY, long a0, long a1, long b0, long b1, C4Object *pObj)
{
return FnCastAParticles(cthr, szName, iAmount, iLevel, iX, iY, a0, a1, b0, b1, pObj, false);
}
static bool FnCastBackParticles(C4AulContext *cthr, C4String *szName, long iAmount, long iLevel, long iX, long iY, long a0, long a1, long b0, long b1, C4Object *pObj)
{
return FnCastAParticles(cthr, szName, iAmount, iLevel, iX, iY, a0, a1, b0, b1, pObj, true);
}
static bool FnPushParticles(C4AulContext *cthr, C4String *szName, long iAX, long iAY)
{
// particle given?
C4ParticleDef *pDef=NULL;
if (szName)
{
pDef=::Particles.GetDef(FnStringPar(szName));
if (!pDef) return false;
}
// push them
::Particles.Push(pDef, (float) iAX/10.0f, (float)iAY/10.0f);
// success
return true;
}
static bool FnClearParticles(C4AulContext *cthr, C4String *szName, C4Object *pObj)
{
// particle given?
C4ParticleDef *pDef=NULL;
if (szName)
{
pDef=::Particles.GetDef(FnStringPar(szName));
if (!pDef) return false;
}
// delete them
if (pObj)
{
pObj->FrontParticles.Remove(pDef);
pObj->BackParticles.Remove(pDef);
}
else
::Particles.GlobalParticles.Remove(pDef);
// success
return true;
}
#define SkyPar_KEEP -163764
static bool FnSetSkyParallax(C4AulContext* ctx, long iMode, long iParX, long iParY, long iXDir, long iYDir, long iX, long iY)
{
// set all parameters that aren't SkyPar_KEEP
if (iMode != SkyPar_KEEP)
if (Inside<long>(iMode, 0, 1)) ::Landscape.Sky.ParallaxMode = iMode;
if (iParX != SkyPar_KEEP && iParX) ::Landscape.Sky.ParX = iParX;
if (iParY != SkyPar_KEEP && iParY) ::Landscape.Sky.ParY = iParY;
if (iXDir != SkyPar_KEEP) ::Landscape.Sky.xdir = itofix(iXDir);
if (iYDir != SkyPar_KEEP) ::Landscape.Sky.ydir = itofix(iYDir);
if (iX != SkyPar_KEEP) ::Landscape.Sky.x = itofix(iX);
if (iY != SkyPar_KEEP) ::Landscape.Sky.y = itofix(iY);
// success
return true;
}
static C4Void FnDoCrewExp(C4AulObjectContext* ctx, long iChange)
{
// do exp
ctx->Obj->DoExperience(iChange);
// success
return C4VNull;
}
static long FnReloadDef(C4AulContext* ctx, C4ID idDef, long iReloadWhat)
{
// get def
C4Def *pDef=NULL;
if (!idDef)
{
// no def given: local def
if (ctx->Obj) pDef=ctx->Obj->Def;
}
else
// def by ID
pDef=::Definitions.ID2Def(idDef);
// safety
if (!pDef) return false;
// reload everything if nothing has been specified
if (!iReloadWhat) iReloadWhat=C4D_Load_RX;
// perform reload
return Game.ReloadDef(pDef->id);
}
static long FnReloadParticle(C4AulContext* ctx, C4String *szParticleName)
{
// perform reload
return Game.ReloadParticle(FnStringPar(szParticleName));
}
static bool FnSetGamma(C4AulContext* ctx, long dwClr1, long dwClr2, long dwClr3, long iRampIndex)
{
::GraphicsSystem.SetGamma(dwClr1, dwClr2, dwClr3, iRampIndex);
return true;
}
static bool FnResetGamma(C4AulContext* ctx, long iRampIndex)
{
::GraphicsSystem.SetGamma(0x000000, 0x808080, 0xffffff, iRampIndex);
return true;
}
static long FnFrameCounter(C4AulContext*) { return Game.FrameCounter; }
struct PathInfo
{
long ilx, ily;
long ilen;
};
static bool SumPathLength(int32_t iX, int32_t iY, intptr_t iTransferTarget, intptr_t ipPathInfo)
{
PathInfo *pPathInfo = (PathInfo*) ipPathInfo;
pPathInfo->ilen += Distance(pPathInfo->ilx, pPathInfo->ily, iX, iY);
pPathInfo->ilx = iX;
pPathInfo->ily = iY;
return true;
}
static long FnGetPathLength(C4AulContext* ctx, long iFromX, long iFromY, long iToX, long iToY)
{
PathInfo PathInfo;
PathInfo.ilx = iFromX;
PathInfo.ily = iFromY;
PathInfo.ilen = 0;
if(!Game.PathFinder.Find(iFromX, iFromY, iToX, iToY, &SumPathLength, (long) &PathInfo))
return 0;
return PathInfo.ilen + Distance(PathInfo.ilx, PathInfo.ily, iToX, iToY);
}
static long FnSetTextureIndex(C4AulContext *ctx, C4String *psMatTex, long iNewIndex, bool fInsert)
{
if(!Inside(iNewIndex, 0l, 255l)) return false;
return ::Landscape.SetTextureIndex(FnStringPar(psMatTex), BYTE(iNewIndex), !!fInsert);
}
static long FnRemoveUnusedTexMapEntries(C4AulContext *ctx)
{
::Landscape.RemoveUnusedTexMapEntries();
return true;
}
static bool FnSetLandscapePixel(C4AulContext* ctx, long iX, long iY, long dwValue)
{
// local call
if (ctx->Obj) { iX+=ctx->Obj->GetX(); iY+=ctx->Obj->GetY(); }
// set pixel in 32bit-sfc only
// TODO: ::Landscape.SetPixDw(iX, iY, dwValue);
// success
return true;
}
static bool FnSetObjectOrder(C4AulContext* ctx, C4Object *pObjBeforeOrAfter, C4Object *pSortObj, bool fSortAfter)
{
// local call/safety
if (!pSortObj) pSortObj=ctx->Obj; if (!pSortObj) return false;
if (!pObjBeforeOrAfter) return false;
// note that no category check is done, so this call might corrupt the main list!
// the scripter must be wise enough not to call it for objects with different categories
// create object resort
C4ObjResort *pObjRes = new C4ObjResort();
pObjRes->pSortObj = pSortObj;
pObjRes->pObjBefore = pObjBeforeOrAfter;
pObjRes->fSortAfter = fSortAfter;
// insert into game resort proc list
pObjRes->Next = ::Objects.ResortProc;
::Objects.ResortProc = pObjRes;
// done, success so far
return true;
}
static bool FnDrawMaterialQuad(C4AulContext* ctx, C4String *szMaterial, long iX1, long iY1, long iX2, long iY2, long iX3, long iY3, long iX4, long iY4, bool fSub)
{
const char *szMat = FnStringPar(szMaterial);
return !! ::Landscape.DrawQuad(iX1, iY1, iX2, iY2, iX3, iY3, iX4, iY4, szMat, fSub);
}
static bool FnFightWith(C4AulObjectContext *ctx, C4Object *pTarget)
{
// safety
if (!pTarget) return false;
C4Object *pClonk = ctx->Obj;
// check OCF
if (~(pTarget->OCF & pClonk->OCF) & OCF_FightReady) return false;
// RejectFight callback
C4AulParSet parset1(C4VObj(pTarget) );
C4AulParSet parset2(C4VObj(pClonk) );
if(pTarget->Call(PSF_RejectFight, &parset1).getBool() ) return false;
if(pClonk->Call(PSF_RejectFight, &parset2).getBool() ) return false;
// begin fighting
ObjectActionFight(pClonk,pTarget);
ObjectActionFight(pTarget,pClonk);
// success
return true;
}
static bool FnSetFilmView(C4AulContext *ctx, long iToPlr)
{
// check player
if (!ValidPlr(iToPlr) && iToPlr != NO_OWNER) return false;
// real switch in replays only
if (!::Control.isReplay()) return true;
// set new target plr
if (C4Viewport *vp = ::GraphicsSystem.GetFirstViewport()) vp->Init(iToPlr, true);
// done, always success (sync)
return true;
}
static bool FnClearMenuItems(C4AulObjectContext *ctx)
{
// check menu
if (!ctx->Obj->Menu) return false;
// clear the items
ctx->Obj->Menu->ClearItems(true);
// success
return true;
}
static C4Object *FnGetObjectLayer(C4AulObjectContext *ctx)
{
// get layer object
return ctx->Obj->pLayer;
}
static C4Void FnSetObjectLayer(C4AulObjectContext *ctx, C4Object *pNewLayer)
{
// set layer object
ctx->Obj->pLayer = pNewLayer;
// set for all contents as well
for (C4ObjectLink *pLnk=ctx->Obj->Contents.First; pLnk; pLnk=pLnk->Next)
if ((ctx->Obj=pLnk->Obj) && ctx->Obj->Status)
ctx->Obj->pLayer = pNewLayer;
// success
return C4VNull;
}
static C4Void FnSetShape(C4AulObjectContext *ctx, long iX, long iY, long iWdt, long iHgt)
{
// update shape
ctx->Obj->Shape.x = iX;
ctx->Obj->Shape.y = iY;
ctx->Obj->Shape.Wdt = iWdt;
ctx->Obj->Shape.Hgt = iHgt;
// section list needs refresh
ctx->Obj->UpdatePos();
// done, success
return C4VNull;
}
static bool FnAddMsgBoardCmd(C4AulContext *ctx, C4String *pstrCommand, C4String *pstrScript, long iRestriction)
{
// safety
if(!pstrCommand || !pstrScript) return false;
// unrestricted commands cannot be set by direct-exec script (like /script).
if(iRestriction != C4MessageBoardCommand::C4MSGCMDR_Identifier)
if(!ctx->Caller || !*ctx->Caller->Func->Name)
return false;
C4MessageBoardCommand::Restriction eRestriction;
switch (iRestriction)
{
case C4MessageBoardCommand::C4MSGCMDR_Escaped: eRestriction = C4MessageBoardCommand::C4MSGCMDR_Escaped; break;
case C4MessageBoardCommand::C4MSGCMDR_Plain: eRestriction = C4MessageBoardCommand::C4MSGCMDR_Plain; break;
case C4MessageBoardCommand::C4MSGCMDR_Identifier: eRestriction = C4MessageBoardCommand::C4MSGCMDR_Identifier; break;
default: return false;
}
// add command
::MessageInput.AddCommand(FnStringPar(pstrCommand), FnStringPar(pstrScript), eRestriction);
return true;
}
static bool FnSetGameSpeed(C4AulContext *ctx, long iSpeed)
{
// safety
if(iSpeed) if(!Inside<long>(iSpeed, 0, 1000)) return false;
if(!iSpeed) iSpeed = 38;
// set speed, restart timer
Application.SetGameTickDelay(1000 / iSpeed);
return true;
}
static bool FnSetObjDrawTransform(C4AulObjectContext *ctx, long iA, long iB, long iC, long iD, long iE, long iF, long iOverlayID)
{
C4DrawTransform *pTransform;
// overlay?
if (iOverlayID)
{
// set overlay transform
C4GraphicsOverlay *pOverlay = ctx->Obj->GetGraphicsOverlay(iOverlayID, false);
if (!pOverlay) return false;
pTransform = pOverlay->GetTransform();
}
else
{
// set base transform
pTransform = ctx->Obj->pDrawTransform;
// del transform?
if (!iB && !iC && !iD && !iF && iA==iE && (!iA || iA==1000))
{
// identity/0 and no transform defined: nothing to do
if (!pTransform) return true;
// transform has no flipdir?
if (pTransform->FlipDir == 1)
{
// kill identity-transform, then
delete pTransform;
ctx->Obj->pDrawTransform=NULL;
return true;
}
// flipdir must remain: set identity
pTransform->Set(1,0,0,0,1,0,0,0,1);
return true;
}
// create draw transform if not already present
if (!pTransform) pTransform = ctx->Obj->pDrawTransform = new C4DrawTransform();
}
// assign values
pTransform->Set((float) iA/1000, (float) iB/1000, (float) iC/1000, (float) iD/1000, (float) iE/1000, (float) iF/1000, 0, 0, 1);
// done, success
return true;
}
static bool FnSetObjDrawTransform2(C4AulObjectContext *ctx, long iA, long iB, long iC, long iD, long iE, long iF, long iG, long iH, long iI, long iOverlayID)
{
// local call / safety
C4Object * pObj = ctx->Obj;
C4DrawTransform *pTransform;
// overlay?
if (iOverlayID)
{
// set overlay transform
C4GraphicsOverlay *pOverlay = pObj->GetGraphicsOverlay(iOverlayID, false);
if (!pOverlay) return false;
pTransform = pOverlay->GetTransform();
}
else
{
// set base transform
pTransform = pObj->pDrawTransform;
// create draw transform if not already present
if (!pTransform) pTransform = pObj->pDrawTransform = new C4DrawTransform(1);
}
// assign values
#define L2F(l) ((float)l/1000)
CBltTransform matrix;
matrix.Set(L2F(iA), L2F(iB), L2F(iC), L2F(iD), L2F(iE), L2F(iF), L2F(iG), L2F(iH), L2F(iI));
*pTransform *= matrix;
#undef L2F
// done, success
return true;
}
#define COPY_C4V_PAR(Var, Par, ParType, Std) \
Var = (Par && Par->GetType() == ParType \
? Par->GetData().Int \
: Std)
bool SimFlight(FIXED &x, FIXED &y, FIXED &xdir, FIXED &ydir, int32_t iDensityMin, int32_t iDensityMax, int32_t iIter);
static C4Value FnSimFlight(C4AulContext *ctx, C4Value *pvrX, C4Value *pvrY, C4Value *pvrXDir, C4Value *pvrYDir, C4Value *pviDensityMin, C4Value *pviDensityMax, C4Value *pviIter, C4Value *pviPrec)
{
// check and copy parameters
if(!pvrX || !pvrY || !pvrXDir || !pvrYDir) return C4VFalse;
COPY_C4V_PAR(int iDensityMin, pviDensityMin, C4V_Int, C4M_Solid);
COPY_C4V_PAR(int iDensityMax, pviDensityMax, C4V_Int, 100);
COPY_C4V_PAR(int iIter, pviIter, C4V_Int, -1);
COPY_C4V_PAR(int iPrec, pviPrec, C4V_Int, 10);
// convert to FIXED
FIXED x = itofix(pvrX->GetData().Int), y = itofix(pvrY->GetData().Int),
xdir = itofix(pvrXDir->GetData().Int, iPrec), ydir = itofix(pvrYDir->GetData().Int, iPrec);
// simulate
if(!SimFlight(x, y, xdir, ydir, iDensityMin, iDensityMax, iIter))
return C4VFalse;
// write results back
*pvrX = C4VInt(fixtoi(x)); *pvrY = C4VInt(fixtoi(y));
*pvrXDir = C4VInt(fixtoi(xdir * iPrec)); *pvrYDir = C4VInt(fixtoi(ydir * iPrec));
return C4VTrue;
}
#undef COPY_C4V_PAR
static bool FnSetPortrait(C4AulObjectContext *ctx, C4String *pstrPortrait, C4ID idSourceDef, bool fPermanent, bool fCopyGfx)
{
// safety
const char *szPortrait;
if (!pstrPortrait || !*(szPortrait=FnStringPar(pstrPortrait))) return false;
C4Object *pTarget = ctx->Obj;
if (!pTarget->Status || !pTarget->Info) return false;
// special case: clear portrait
if (SEqual(szPortrait, C4Portrait_None)) return pTarget->Info->ClearPortrait(!!fPermanent);
// get source def for portrait
C4Def *pSourceDef;
if (idSourceDef) pSourceDef = ::Definitions.ID2Def(idSourceDef); else pSourceDef=pTarget->Def;
if (!pSourceDef) return false;
// special case: random portrait
if (SEqual(szPortrait, C4Portrait_Random)) return pTarget->Info->SetRandomPortrait(pSourceDef->id, !!fPermanent, !!fCopyGfx);
// try to set portrait
return pTarget->Info->SetPortrait(szPortrait, pSourceDef, !!fPermanent, !!fCopyGfx);
}
static C4Value FnGetPortrait(C4AulContext *ctx, C4Value *pvfGetID, C4Value *pvfGetPermanent)
{
// get parameters
C4Object *pObj = ctx->Obj; bool fGetID = pvfGetID->getBool(); bool fGetPermanent = pvfGetPermanent->getBool();
// check valid object with info section
if (!pObj)
throw new NeedObjectContext("GetPortrait");
if (!pObj->Status || !pObj->Info) return C4Value();
// get portrait to examine
C4Portrait *pPortrait;
if (fGetPermanent)
{
// permanent: new portrait assigned?
if (!(pPortrait=pObj->Info->pNewPortrait))
{
// custom portrait?
if (pObj->Info->pCustomPortrait)
if (fGetID) return C4Value();
else
return C4VString(C4Portrait_Custom);
// portrait string from info?
const char *szPortrait = pObj->Info->PortraitFile;
// no portrait string: portrait undefined ("none" would mean no portrait)
if (!*szPortrait) return C4Value();
// evaluate portrait string
C4ID idPortraitSource=0;
szPortrait = C4Portrait::EvaluatePortraitString(szPortrait, idPortraitSource, pObj->Info->id, NULL);
// return desired value
if (fGetID)
return idPortraitSource ? C4VID(idPortraitSource) : C4Value();
else
return szPortrait ? C4VString(szPortrait) : C4Value();
}
}
else
// get current portrait
pPortrait = &(pObj->Info->Portrait);
// get portrait graphics
C4DefGraphics *pPortraitGfx = pPortrait->GetGfx();
// no portrait?
if (!pPortraitGfx) return C4Value();
// get def or name
if (fGetID)
return (pPortraitGfx->pDef ? C4VID(pPortraitGfx->pDef->id) : C4Value());
else
{
const char *szPortraitName = pPortraitGfx->GetName();
return C4VString(szPortraitName ? szPortraitName : C4Portrait_Custom);
}
}
static long FnLoadScenarioSection(C4AulContext *ctx, C4String *pstrSection, long dwFlags)
{
// safety
const char *szSection;
if (!pstrSection || !*(szSection=FnStringPar(pstrSection))) return false;
// try to load it
return Game.LoadScenarioSection(szSection, dwFlags);
}
static bool FnSetObjectStatus(C4AulObjectContext *ctx, long iNewStatus, bool fClearPointers)
{
// local call / safety
if (!ctx->Obj->Status) return false;
// no change
if (ctx->Obj->Status == iNewStatus) return true;
// set new status
switch (iNewStatus)
{
case C4OS_NORMAL:
return ctx->Obj->StatusActivate();
case C4OS_INACTIVE:
return ctx->Obj->StatusDeactivate(fClearPointers);
default:
return false; // status unknown
}
}
static long FnGetObjectStatus(C4AulObjectContext *ctx)
{
return ctx->Obj->Status;
}
static bool FnAdjustWalkRotation(C4AulObjectContext *ctx, long iRangeX, long iRangeY, long iSpeed)
{
// must be rotateable and attached to solid ground
if (!ctx->Obj->Def->Rotateable || ~ctx->Obj->Action.t_attach&CNAT_Bottom || ctx->Obj->Shape.AttachMat == MNone)
return false;
// adjust rotation
return ctx->Obj->AdjustWalkRotation(iRangeX, iRangeY, iSpeed);
}
static C4Value FnAddEffect_C4V(C4AulContext *ctx, C4Value *pvsEffectName, C4Value *pvpTarget, C4Value *pviPrio, C4Value *pviTimerIntervall, C4Value *pvpCmdTarget, C4Value *pvidCmdTarget, C4Value *pvVal1, C4Value *pvVal2, C4Value *pvVal3, C4Value *pvVal4)
{
// evaluate parameters
C4String *psEffectName = pvsEffectName->getStr();
C4Object *pTarget = pvpTarget->getObj();
long iPrio = pviPrio->getInt(), iTimerIntervall = pviTimerIntervall->getInt();
C4Object *pCmdTarget = pvpCmdTarget->getObj();
C4ID idCmdTarget = pvidCmdTarget->getC4ID();
const char *szEffect = FnStringPar(psEffectName);
// safety
if (pTarget && !pTarget->Status) return C4Value();
if (!szEffect || !*szEffect || !iPrio) return C4Value();
// create effect
int32_t iEffectNumber;
new C4Effect(pTarget, szEffect, iPrio, iTimerIntervall, pCmdTarget, idCmdTarget, *pvVal1, *pvVal2, *pvVal3, *pvVal4, true, iEffectNumber);
// return assigned effect number - may be 0 if he effect has been denied by another effect
// may also be the number of another effect
return C4VInt(iEffectNumber);
}
static C4Value FnGetEffect_C4V(C4AulContext *ctx, C4Value *pvsEffectName, C4Value *pvpTarget, C4Value *pviIndex, C4Value *pviQueryValue, C4Value *pviMaxPriority)
{
// evaluate parameters
C4String *psEffectName = pvsEffectName->getStr();
C4Object *pTarget = pvpTarget->getObj();
long iIndex = pviIndex->getInt(), iQueryValue = pviQueryValue->getInt(), iMaxPriority = pviMaxPriority->getInt();
const char *szEffect = FnStringPar(psEffectName);
// get effects
C4Effect *pEffect = pTarget ? pTarget->pEffects : Game.pGlobalEffects;
if (!pEffect) return C4Value();
// name/wildcard given: find effect by name and index
if (szEffect && *szEffect)
pEffect = pEffect->Get(szEffect, iIndex, iMaxPriority);
else
// otherwise, get by number
pEffect = pEffect->Get(iIndex, true, iMaxPriority);
// effect found?
if (!pEffect) return C4Value();
// evaluate desired value
switch (iQueryValue)
{
case 0: return C4VInt(pEffect->iNumber); // 0: number
case 1: return C4VString(pEffect->Name); // 1: name
case 2: return C4VInt(Abs(pEffect->iPriority)); // 2: priority (may be negative for deactivated effects)
case 3: return C4VInt(pEffect->iIntervall); // 3: timer intervall
case 4: return C4VObj(pEffect->pCommandTarget); // 4: command target
case 5: return C4VID(pEffect->idCommandTarget); // 5: command target ID
case 6: return C4VInt(pEffect->iTime); // 6: effect time
}
// invalid data queried
return C4Value();
}
static bool FnRemoveEffect(C4AulContext *ctx, C4String *psEffectName, C4Object *pTarget, long iIndex, bool fDoNoCalls)
{
// evaluate parameters
const char *szEffect = FnStringPar(psEffectName);
// get effects
C4Effect *pEffect = pTarget ? pTarget->pEffects : Game.pGlobalEffects;
if (!pEffect) return 0;
// name/wildcard given: find effect by name and index
if (szEffect && *szEffect)
pEffect = pEffect->Get(szEffect, iIndex);
else
// otherwise, get by number
pEffect = pEffect->Get(iIndex, false);
// effect found?
if (!pEffect) return 0;
// kill it
if (fDoNoCalls)
pEffect->SetDead();
else
pEffect->Kill(pTarget);
// done, success
return true;
}
static bool FnChangeEffect(C4AulContext *ctx, C4String *psEffectName, C4Object *pTarget, long iIndex, C4String *psNewEffectName, long iNewTimer)
{
// evaluate parameters
const char *szEffect = FnStringPar(psEffectName);
const char *szNewEffect = FnStringPar(psNewEffectName);
if (!szNewEffect || !*szNewEffect) return false;
// get effects
C4Effect *pEffect = pTarget ? pTarget->pEffects : Game.pGlobalEffects;
if (!pEffect) return false;
// name/wildcard given: find effect by name and index
if (szEffect && *szEffect)
pEffect = pEffect->Get(szEffect, iIndex);
else
// otherwise, get by number
pEffect = pEffect->Get(iIndex, false);
// effect found?
if (!pEffect) return false;
// set new name
SCopy(szNewEffect, pEffect->Name, C4MaxName);
pEffect->ReAssignCallbackFunctions();
// set new timer
if (iNewTimer>=0)
{
pEffect->iIntervall = iNewTimer;
pEffect->iTime = 0;
}
// done, success
return true;
}
static C4Value FnCheckEffect_C4V(C4AulContext *ctx, C4Value *pvsEffectName, C4Value *pvpTarget, C4Value *pviPrio, C4Value *pviTimerIntervall, C4Value *pvVal1, C4Value *pvVal2, C4Value *pvVal3, C4Value *pvVal4)
{
// evaluate parameters
C4String *psEffectName = pvsEffectName->getStr();
C4Object *pTarget = pvpTarget->getObj();
long iPrio = pviPrio->getInt(), iTimerIntervall = pviTimerIntervall->getInt();
const char *szEffect = FnStringPar(psEffectName);
// safety
if (pTarget && !pTarget->Status) return C4Value();
if (!szEffect || !*szEffect) return C4Value();
// get effects
C4Effect *pEffect = pTarget ? pTarget->pEffects : Game.pGlobalEffects;
if (!pEffect) return C4Value();
// let them check
return C4VInt(pEffect->Check(pTarget, szEffect, iPrio, iTimerIntervall, *pvVal1, *pvVal2, *pvVal3, *pvVal4));
}
static long FnGetEffectCount(C4AulContext *ctx, C4String *psEffectName, C4Object *pTarget, long iMaxPriority)
{
// evaluate parameters
const char *szEffect = FnStringPar(psEffectName);
// get effects
C4Effect *pEffect = pTarget ? pTarget->pEffects : Game.pGlobalEffects;
if (!pEffect) return false;
// count effects
if (!*szEffect) szEffect = 0;
return pEffect->GetCount(szEffect, iMaxPriority);
}
static C4Value FnEffectVar_C4V(C4AulContext *cthr, C4Value *pviVarIndex, C4Value *pvpObj, C4Value *pviEffectNumber)
{
// get parameters
C4Object *pObj = pvpObj->getObj();
long iVarIndex = pviVarIndex->getInt(), iEffectNumber = pviEffectNumber->getInt();
// safety
if (iVarIndex<0) return C4Value();
// get effect
C4Effect *pEffect = pObj ? pObj->pEffects : Game.pGlobalEffects;
if (!pEffect) return C4Value();
if (!(pEffect = pEffect->Get(iEffectNumber, true))) return C4Value();
// return ref to var
return pEffect->EffectVars[iVarIndex].GetRef();
}
static C4Value FnEffectCall_C4V(C4AulContext *ctx, C4Value *pvpTarget, C4Value *pviNumber, C4Value *pvsCallFn, C4Value *pvVal1, C4Value *pvVal2, C4Value *pvVal3, C4Value *pvVal4, C4Value *pvVal5, C4Value *pvVal6, C4Value *pvVal7)
{
// evaluate parameters
C4String *psCallFn = pvsCallFn->getStr();
C4Object *pTarget = pvpTarget->getObj();
long iNumber = pviNumber->getInt();
const char *szCallFn = FnStringPar(psCallFn);
// safety
if (pTarget && !pTarget->Status) return C4Value();
if (!szCallFn || !*szCallFn) return C4Value();
// get effect
C4Effect *pEffect = pTarget ? pTarget->pEffects : Game.pGlobalEffects;
if (!pEffect) return C4Value();
if (!(pEffect = pEffect->Get(iNumber, true))) return C4Value();
// do call
return pEffect->DoCall(pTarget, szCallFn, *pvVal1, *pvVal2, *pvVal3, *pvVal4, *pvVal5, *pvVal6, *pvVal7);
}
static long FnModulateColor(C4AulContext *cthr, long iClr1, long iClr2)
{
DWORD dwClr1 = iClr1;
DWORD dwClr2 = iClr2;
// default color
if (!dwClr1) dwClr1 = 0xffffff;
// get alpha
long iA1=dwClr1>>24, iA2=dwClr2>>24;
// modulate color values; mod alpha upwards
DWORD r = ((dwClr1 & 0xff) * (dwClr2 & 0xff)) >> 8 | // blue
((dwClr1>> 8 & 0xff) * (dwClr2>>8 & 0xff)) & 0xff00 | // green
((dwClr1>>16 & 0xff) * (dwClr2>>8 & 0xff00)) & 0xff0000 | // red
Min<long>(iA1+iA2 - ((iA1*iA2)>>8), 255) << 24 ; // alpha
return r;
}
static long FnWildcardMatch(C4AulContext *ctx, C4String *psString, C4String *psWildcard)
{
return SWildcardMatchEx(FnStringPar(psString), FnStringPar(psWildcard));
}
static long FnGetContact(C4AulObjectContext *ctx, long iVertex, long dwCheck)
{
// vertex not specified: check all
if (iVertex == -1)
{
long iResult = 0;
for (int i=0; i<ctx->Obj->Shape.VtxNum; ++i)
iResult |= ctx->Obj->Shape.GetVertexContact(i, dwCheck, ctx->Obj->GetX(), ctx->Obj->GetY());
return iResult;
}
// vertex specified: check it
if (!Inside<long>(iVertex, 0, ctx->Obj->Shape.VtxNum-1)) return 0;
return ctx->Obj->Shape.GetVertexContact(iVertex, dwCheck, ctx->Obj->GetX(), ctx->Obj->GetY());
}
static long FnSetObjectBlitMode(C4AulObjectContext *ctx, long dwNewBlitMode, long iOverlayID)
{
// overlay?
if (iOverlayID)
{
C4GraphicsOverlay *pOverlay = ctx->Obj->GetGraphicsOverlay(iOverlayID, false);
if (!pOverlay)
{
DebugLogF("SetObjectBlitMode: Overlay %d not defined for object %d (%s)", (int) iOverlayID, (int) ctx->Obj->Number, ctx->Obj->GetName());
return false;
}
pOverlay->SetBlitMode(dwNewBlitMode);
return true;
}
// get prev blit mode
DWORD dwPrevMode = ctx->Obj->BlitMode;
// iNewBlitMode = 0: reset to definition default
if (!dwNewBlitMode)
ctx->Obj->BlitMode = ctx->Obj->Def->BlitMode;
else
// otherwise, set the desired value
// also ensure that the custom flag is set
ctx->Obj->BlitMode = dwNewBlitMode | C4GFXBLIT_CUSTOM;
// return previous value
return dwPrevMode;
}
static Nillable<long> FnGetObjectBlitMode(C4AulObjectContext *ctx, long iOverlayID)
{
// overlay?
if (iOverlayID)
{
C4GraphicsOverlay *pOverlay = ctx->Obj->GetGraphicsOverlay(iOverlayID, false);
if (!pOverlay)
{
DebugLogF("SetObjectBlitMode: Overlay %d not defined for object %d (%s)", (int) iOverlayID, (int) ctx->Obj->Number, ctx->Obj->GetName());
return C4VNull;
}
return pOverlay->GetBlitMode();
}
// get blitting mode
return ctx->Obj->BlitMode;
}
static bool FnSetViewOffset(C4AulContext *ctx, long iPlayer, long iX, long iY)
{
if(!ValidPlr(iPlayer)) return 0;
// get player viewport
C4Viewport *pView = ::GraphicsSystem.GetViewport(iPlayer);
if(!pView) return 1; // sync safety
// set
pView->ViewOffsX = iX;
pView->ViewOffsY = iY;
// ok
return 1;
}
static bool FnSetPreSend(C4AulContext *cthr, long iToVal, C4String *pNewName)
{
if (!::Control.isNetwork()) return true;
// dbg: manual presend
const char *szClient = FnStringPar(pNewName);
if (!szClient || !*szClient || WildcardMatch(szClient, Game.Clients.getLocalName()))
{
::Control.Network.setTargetFPS(iToVal);
::GraphicsSystem.FlashMessage(FormatString("TargetFPS: %ld", iToVal).getData());
}
return true;
}
static long FnGetPlayerID(C4AulContext *cthr, long iPlayer)
{
C4Player *pPlr = ::Players.Get(iPlayer);
return pPlr ? pPlr->ID : 0;
}
static long FnGetPlayerTeam(C4AulContext *cthr, long iPlayer)
{
// get player
C4Player *pPlr = ::Players.Get(iPlayer);
if (!pPlr) return 0;
// search team containing this player
C4Team *pTeam = Game.Teams.GetTeamByPlayerID(pPlr->ID);
if (pTeam) return pTeam->GetID();
// special value of -1 indicating that the team is still to be chosen
if (pPlr->IsChosingTeam()) return -1;
// No team.
return 0;
}
static bool FnSetPlayerTeam(C4AulContext *cthr, long iPlayer, long idNewTeam, bool fNoCalls)
{
// no team changing in league games
if (Game.Parameters.isLeague()) return false;
// get player
C4Player *pPlr = ::Players.Get(iPlayer);
if (!pPlr) return false;
C4PlayerInfo *pPlrInfo = pPlr->GetInfo();
if (!pPlrInfo) return false;
// already in that team?
if (pPlr->Team == idNewTeam) return true;
// ask team setting if it's allowed (also checks for valid team)
if (!Game.Teams.IsJoin2TeamAllowed(idNewTeam)) return false;
// ask script if it's allowed
if (!fNoCalls)
{
if (!!Game.Script.GRBroadcast(PSF_RejectTeamSwitch, &C4AulParSet(C4VInt(iPlayer), C4VInt(idNewTeam)), true, true))
return false;
}
// exit previous team
C4Team *pOldTeam = Game.Teams.GetTeamByPlayerID(pPlr->ID);
int32_t idOldTeam = 0;
if (pOldTeam)
{
idOldTeam = pOldTeam->GetID();
pOldTeam->RemovePlayerByID(pPlr->ID);
}
// enter new team
if (idNewTeam)
{
C4Team *pNewTeam = Game.Teams.GetGenerateTeamByID(idNewTeam);
if (pNewTeam)
{
pNewTeam->AddPlayer(*pPlrInfo, true);
idNewTeam = pNewTeam->GetID();
}
else
{
// unknown error
pPlr->Team = idNewTeam = 0;
}
}
// update hositlities if this is not a "silent" change
if (!fNoCalls)
{
pPlr->SetTeamHostility();
}
// do callback to reflect change in scenario
if (!fNoCalls)
Game.Script.GRBroadcast(PSF_OnTeamSwitch, &C4AulParSet(C4VInt(iPlayer), C4VInt(idNewTeam), C4VInt(idOldTeam)), true);
return true;
}
static long FnGetTeamConfig(C4AulContext *cthr, long iConfigValue)
{
// query value
switch (iConfigValue)
{
case C4TeamList::TEAM_Custom: return Game.Teams.IsCustom();
case C4TeamList::TEAM_Active: return Game.Teams.IsMultiTeams();
case C4TeamList::TEAM_AllowHostilityChange: return Game.Teams.IsHostilityChangeAllowed();
case C4TeamList::TEAM_Dist: return Game.Teams.GetTeamDist();
case C4TeamList::TEAM_AllowTeamSwitch: return Game.Teams.IsTeamSwitchAllowed();
case C4TeamList::TEAM_AutoGenerateTeams: return Game.Teams.IsAutoGenerateTeams();
case C4TeamList::TEAM_TeamColors: return Game.Teams.IsTeamColors();
}
// undefined value
DebugLogF("GetTeamConfig: Unknown config value: %ld", iConfigValue);
return 0;
}
static C4String *FnGetTeamName(C4AulContext *cthr, long iTeam)
{
C4Team *pTeam = Game.Teams.GetTeamByID(iTeam);
if (!pTeam) return NULL;
return String(pTeam->GetName());
}
static long FnGetTeamColor(C4AulContext *cthr, long iTeam)
{
C4Team *pTeam = Game.Teams.GetTeamByID(iTeam);
return pTeam ? pTeam->GetColor() : 0u;
}
static long FnGetTeamByIndex(C4AulContext *cthr, long iIndex)
{
C4Team *pTeam = Game.Teams.GetTeamByIndex(iIndex);
return pTeam ? pTeam->GetID() : 0;
}
static long FnGetTeamCount(C4AulContext *cthr)
{
return Game.Teams.GetTeamCount();
}
static bool FnInitScenarioPlayer(C4AulContext *cthr, long iPlayer, long idTeam)
{
C4Player *pPlr = ::Players.Get(iPlayer);
if (!pPlr) return false;
return pPlr->ScenarioAndTeamInit(idTeam);
}
static bool FnOnOwnerRemoved(C4AulObjectContext *cthr)
{
// safety
C4Object *pObj = cthr->Obj;
C4Player *pPlr = ::Players.Get(pObj->Owner); if (!pPlr) return false;
if (pPlr->Crew.IsContained(pObj))
{
// crew members: Those are removed later (AFTER the player has been removed, for backwards compatiblity with relaunch scripting)
}
else if ((~pObj->Category & C4D_StaticBack) || (pObj->id == C4ID_Flag))
{
// Regular objects: Try to find a new, suitable owner from the same team
// Ignore StaticBack, because this would not be backwards compatible with many internal objects such as team account
// Do not ignore flags which might be StaticBack if being attached to castle parts
int32_t iNewOwner = NO_OWNER;
C4Team *pTeam;
if (pPlr->Team) if (pTeam = Game.Teams.GetTeamByID(pPlr->Team))
{
for (int32_t i=0; i<pTeam->GetPlayerCount(); ++i)
{
int32_t iPlrID = pTeam->GetIndexedPlayer(i);
if (iPlrID && iPlrID != pPlr->ID)
{
C4PlayerInfo *pPlrInfo = Game.PlayerInfos.GetPlayerInfoByID(iPlrID);
if (pPlrInfo) if (pPlrInfo->IsJoined())
{
// this looks like a good new owner
iNewOwner = pPlrInfo->GetInGameNumber();
break;
}
}
}
}
// if noone from the same team was found, try to find another non-hostile player
// (necessary for cooperative rounds without teams)
if (iNewOwner == NO_OWNER)
for (C4Player *pOtherPlr = ::Players.First; pOtherPlr; pOtherPlr = pOtherPlr->Next)
if (pOtherPlr != pPlr) if (!pOtherPlr->Eliminated)
if (!::Players.Hostile(pOtherPlr->Number, pPlr->Number))
iNewOwner = pOtherPlr->Number;
// set this owner
pObj->SetOwner(iNewOwner);
}
return true;
}
static bool FnSetScoreboardData(C4AulContext *cthr, long iRowID, long iColID, C4String *pText, long iData)
{
Game.Scoreboard.SetCell(iColID, iRowID, pText ? pText->GetCStr() : NULL, iData);
return true;
}
static C4String *FnGetScoreboardString(C4AulContext *cthr, long iRowID, long iColID)
{
return String(Game.Scoreboard.GetCellString(iColID, iRowID));
}
static int32_t FnGetScoreboardData(C4AulContext *cthr, long iRowID, long iColID)
{
return Game.Scoreboard.GetCellData(iColID, iRowID);
}
static bool FnDoScoreboardShow(C4AulContext *cthr, long iChange, long iForPlr)
{
C4Player *pPlr;
if (iForPlr)
{
// abort if the specified player is not local - but always return if the player exists,
// to ensure sync safety
if (!(pPlr = ::Players.Get(iForPlr-1))) return false;
if (!pPlr->LocalControl) return true;
}
Game.Scoreboard.DoDlgShow(iChange, false);
return true; //Game.Scoreboard.ShouldBeShown();
}
static bool FnSortScoreboard(C4AulContext *cthr, long iByColID, bool fReverse)
{
return Game.Scoreboard.SortBy(iByColID, !!fReverse);
}
static bool FnAddEvaluationData(C4AulContext *cthr, C4String *pText, long idPlayer)
{
// safety
if (!pText) return false;
if (!pText->GetCStr()) return false;
if (idPlayer && !Game.PlayerInfos.GetPlayerInfoByID(idPlayer)) return false;
// add data
Game.RoundResults.AddCustomEvaluationString(pText->GetCStr(), idPlayer);
return true;
}
static long FnGetUnusedOverlayID(C4AulObjectContext *ctx, long iBaseIndex)
{
// safety
if (!iBaseIndex) return 0;
// find search first unused index from there on
int iSearchDir = (iBaseIndex < 0) ? -1 : 1;
while (ctx->Obj->GetGraphicsOverlay(iBaseIndex, false)) iBaseIndex += iSearchDir;
return iBaseIndex;
}
static long FnActivateGameGoalMenu(C4AulContext *ctx, long iPlayer)
{
// get target player
C4Player *pPlr = ::Players.Get(iPlayer);
if (!pPlr) return false;
// open menu
return pPlr->Menu.ActivateGoals(pPlr->Number, pPlr->LocalControl && !::Control.isReplay());
}
static bool FnFatalError(C4AulContext *ctx, C4String *pErrorMsg)
{
throw new C4AulExecError(ctx->Obj, FormatString("User error: %s", pErrorMsg ? pErrorMsg->GetCStr() : "(no error)").getData());
}
static bool FnPlayVideo(C4AulContext *ctx, C4String *pFilename)
{
// filename must be valid
if (!pFilename || !pFilename->GetCStr()) return false;
// play it!
return Game.VideoPlayer.PlayVideo(pFilename->GetCStr());
}
static bool FnStartCallTrace(C4AulContext *ctx)
{
extern void C4AulStartTrace();
C4AulStartTrace();
return true;
}
static bool FnStartScriptProfiler(C4AulContext *ctx, C4ID idScript)
{
// get script to profile
C4AulScript *pScript;
if (idScript)
{
C4Def *pDef = C4Id2Def(idScript);
if (!pDef) return false;
pScript = &pDef->Script;
}
else
pScript = &::ScriptEngine;
// profile it
C4AulProfiler::StartProfiling(pScript);
return true;
}
static bool FnStopScriptProfiler(C4AulContext *ctx)
{
C4AulProfiler::StopProfiling();
return true;
}
static bool FnCustomMessage(C4AulContext *ctx, C4String *pMsg, C4Object *pObj, long iOwner, long iOffX, long iOffY, long dwClr, C4ID idDeco, C4String *sPortrait, long dwFlags, long iHSize)
{
// safeties
if (!pMsg) return false;
if (pObj && !pObj->Status) return false;
const char *szMsg = pMsg->GetCStr();
if (!szMsg) return false;
if (idDeco && !C4Id2Def(idDeco)) return false;
// only one positioning flag per direction allowed
uint32_t hpos = dwFlags & (C4GM_Left | C4GM_HCenter | C4GM_Right);
uint32_t vpos = dwFlags & (C4GM_Top | C4GM_VCenter | C4GM_Bottom);
if (((hpos | hpos-1) + 1)>>1 != hpos)
{
throw new C4AulExecError(ctx->Obj, "CustomMessage: Only one horizontal positioning flag allowed!");
}
if (((vpos | vpos-1) + 1)>>1 != vpos)
{
throw new C4AulExecError(ctx->Obj, "CustomMessage: Only one vertical positioning flag allowed!");
}
// message color
if (!dwClr) dwClr = 0xffffff;
dwClr = InvertRGBAAlpha(dwClr);
// message type
int32_t iType;
if (pObj)
if (iOwner != NO_OWNER)
iType = C4GM_TargetPlayer;
else
iType = C4GM_Target;
else
if (iOwner != NO_OWNER)
iType = C4GM_GlobalPlayer;
else
iType = C4GM_Global;
// remove speech?
StdStrBuf sMsg;
sMsg.Ref(szMsg);
if (dwFlags & C4GM_DropSpeech) sMsg.SplitAtChar('$', NULL);
// create it!
return ::Messages.New(iType,sMsg,pObj,iOwner,iOffX,iOffY,(uint32_t)dwClr, idDeco, sPortrait ? sPortrait->GetCStr() : NULL, dwFlags, iHSize);
}
/*static long FnSetSaturation(C4AulContext *ctx, long s)
{
return lpDDraw->SetSaturation(BoundBy(s,0l,255l));
}*/
static bool FnPauseGame(C4AulContext *ctx, bool fToggle)
{
// not in replay (film)
if (::Control.isReplay()) return true;
// script method for halting game (for films)
if (fToggle)
Console.TogglePause();
else
Console.DoHalt();
return true;
}
static bool FnSetNextMission(C4AulContext *ctx, C4String *szNextMission, C4String *szNextMissionText, C4String *szNextMissionDesc)
{
if (!szNextMission || !szNextMission->GetData().getLength())
{
// param empty: clear next mission
Game.NextMission.Clear();
Game.NextMissionText.Clear();
}
else
{
// set next mission, button and button desc if given
Game.NextMission.Copy(szNextMission->GetData());
if (szNextMissionText && szNextMissionText->GetCStr())
{
Game.NextMissionText.Copy(szNextMissionText->GetData());
}
else
{
Game.NextMissionText.Copy(LoadResStr("IDS_BTN_NEXTMISSION"));
}
if (szNextMissionDesc && szNextMissionDesc->GetCStr())
{
Game.NextMissionDesc.Copy(szNextMissionDesc->GetData());
}
else
{
Game.NextMissionDesc.Copy(LoadResStr("IDS_DESC_NEXTMISSION"));
}
}
return true;
}
static long FnGetPlayerControlState(C4AulContext *ctx, long iPlr, long iControl)
{
// get control set to check
C4PlayerControl *pCheckCtrl = NULL;
if (iPlr == NO_OWNER)
{
//pCheckCtrl = Game.GlobalPlayerControls;
}
else
{
C4Player *pPlr = ::Players.Get(iPlr);
if (pPlr)
{
pCheckCtrl = &(pPlr->Control);
}
}
// invalid player or no controls
if (!pCheckCtrl) return 0;
// query control
const C4PlayerControl::CSync::ControlDownState *pControlState = pCheckCtrl->GetControlDownState(iControl);
// no state means not down
if (!pControlState) return 0;
// otherwise take down-value
return pControlState->DownState.iStrength;
}
//=========================== C4Script Function Map ===================================
// defined function class
class C4AulDefFuncHelper: public C4AulFunc
{
public:
C4AulDefFuncHelper(C4AulScript *pOwner, const char *pName, bool Public,
C4V_Type pt0 = C4V_Any, C4V_Type pt1 = C4V_Any, C4V_Type pt2 = C4V_Any, C4V_Type pt3 = C4V_Any, C4V_Type pt4 = C4V_Any,
C4V_Type pt5 = C4V_Any, C4V_Type pt6 = C4V_Any, C4V_Type pt7 = C4V_Any, C4V_Type pt8 = C4V_Any, C4V_Type pt9 = C4V_Any):
C4AulFunc(pOwner, pName),
Public(Public)
{
ParType[0] = pt0;
ParType[1] = pt1;
ParType[2] = pt2;
ParType[3] = pt3;
ParType[4] = pt4;
ParType[5] = pt5;
ParType[6] = pt6;
ParType[7] = pt7;
ParType[8] = pt8;
ParType[9] = pt9;
}
virtual C4V_Type* GetParType() { return ParType; }
virtual bool GetPublic() { return Public; }
protected:
C4V_Type ParType[10];// type of the parameters
bool Public;
};
// A macro to create lists with some helper macros
// LIST(2, foo) would create ", foo(0), foo(1)
// TEXT can be a macro
#define LIST(N, TEXT) LIST##N(TEXT)
// The lists are used in a context where a leading comma is needed when the list is not empty
#define LIST0(TEXT)
#define LIST1(TEXT) LIST0(TEXT), TEXT(0)
#define LIST2(TEXT) LIST1(TEXT), TEXT(1)
#define LIST3(TEXT) LIST2(TEXT), TEXT(2)
#define LIST4(TEXT) LIST3(TEXT), TEXT(3)
#define LIST5(TEXT) LIST4(TEXT), TEXT(4)
#define LIST6(TEXT) LIST5(TEXT), TEXT(5)
#define LIST7(TEXT) LIST6(TEXT), TEXT(6)
#define LIST8(TEXT) LIST7(TEXT), TEXT(7)
#define LIST9(TEXT) LIST8(TEXT), TEXT(8)
#define LIST10(TEXT) LIST9(TEXT), TEXT(9)
// Macros which are passed to LIST
#define TYPENAMES(N) typename Par##N##_t
#define PARS(N) Par##N##_t
#define CONV_TYPE(N) C4ValueConv<Par##N##_t>::Type()
#define CONV_FROM_C4V(N) C4ValueConv<Par##N##_t>::_FromC4V(pPars[N])
// N is the number of parameters pFunc needs. Templates can only have a fixed number of arguments,
// so eleven templates are needed
#define TEMPLATE(N) \
template <typename RType LIST(N, TYPENAMES)> \
class C4AulDefFunc##N: \
public C4AulDefFuncHelper { \
public: \
/* A pointer to the function which this class wraps */ \
typedef RType (*Func)(C4AulContext * LIST(N, PARS)); \
virtual int GetParCount() { return N; } \
virtual C4V_Type GetRetType() \
{ return C4ValueConv<RType>::Type(); } \
/* Constructor, using the base class to create the ParType array */ \
C4AulDefFunc##N(C4AulScript *pOwner, const char *pName, Func pFunc, bool Public): \
C4AulDefFuncHelper(pOwner, pName, Public LIST(N, CONV_TYPE)), pFunc(pFunc) { } \
/* Extracts the parameters from C4Values and wraps the return value in a C4Value */ \
virtual C4Value Exec(C4AulContext *pContext, C4Value pPars[], bool fPassErrors=false) \
{ return C4ValueConv<RType>::ToC4V(pFunc(pContext LIST(N, CONV_FROM_C4V))); } \
protected: \
Func pFunc; \
}; \
template <typename RType LIST(N, TYPENAMES)> \
class C4AulDefObjectFunc##N: \
public C4AulDefFuncHelper { \
public: \
/* A pointer to the function which this class wraps */ \
typedef RType (*Func)(C4AulObjectContext * LIST(N, PARS)); \
virtual int GetParCount() { return N; } \
virtual C4V_Type GetRetType() \
{ return C4ValueConv<RType>::Type(); } \
/* Constructor, using the base class to create the ParType array */ \
C4AulDefObjectFunc##N(C4AulScript *pOwner, const char *pName, Func pFunc, bool Public): \
C4AulDefFuncHelper(pOwner, pName, Public LIST(N, CONV_TYPE)), pFunc(pFunc) { } \
/* Extracts the parameters from C4Values and wraps the return value in a C4Value */ \
virtual C4Value Exec(C4AulContext *pContext, C4Value pPars[], bool fPassErrors=false) \
{ \
if (!pContext->Obj) throw new NeedObjectContext(Name); \
return C4ValueConv<RType>::ToC4V(pFunc(static_cast<C4AulObjectContext*>(pContext) LIST(N, CONV_FROM_C4V))); \
} \
protected: \
Func pFunc; \
}; \
template <typename RType LIST(N, TYPENAMES)> \
static void AddFunc(C4AulScript * pOwner, const char * Name, RType (*pFunc)(C4AulContext * LIST(N, PARS)), bool Public=true) \
{ \
new C4AulDefFunc##N<RType LIST(N, PARS)>(pOwner, Name, pFunc, Public); \
} \
template <typename RType LIST(N, TYPENAMES)> \
static void AddFunc(C4AulScript * pOwner, const char * Name, RType (*pFunc)(C4AulObjectContext * LIST(N, PARS)), bool Public=true) \
{ \
new C4AulDefObjectFunc##N<RType LIST(N, PARS)>(pOwner, Name, pFunc, Public); \
}
TEMPLATE(0)
TEMPLATE(1)
TEMPLATE(2)
TEMPLATE(3)
TEMPLATE(4)
TEMPLATE(5)
TEMPLATE(6)
TEMPLATE(7)
TEMPLATE(8)
TEMPLATE(9)
TEMPLATE(10)
#undef LIST
#undef LIST0
#undef LIST1
#undef LIST2
#undef LIST3
#undef LIST4
#undef LIST5
#undef LIST6
#undef LIST7
#undef LIST8
#undef LIST9
#undef LIST10
#undef TYPENAMES
#undef PARS
#undef CONV_TYPE
#undef CONV_FROM_C4V
#undef TEMPLATE
void InitFunctionMap(C4AulScriptEngine *pEngine)
{
// add all def constants (all Int)
for (C4ScriptConstDef *pCDef = &C4ScriptConstMap[0]; pCDef->Identifier; pCDef++)
{
assert(pCDef->ValType == C4V_Int); // only int supported currently
::ScriptEngine.RegisterGlobalConstant(pCDef->Identifier, C4VInt(pCDef->Data));
}
// add all def script funcs
for (C4ScriptFnDef *pDef = &C4ScriptFnMap[0]; pDef->Identifier; pDef++)
pEngine->AddFunc(pDef->Identifier, pDef);
// AddFunc(pEngine, "SetSaturation", FnSetSaturation); //public: 0
AddFunc(pEngine, "Abs", FnAbs);
AddFunc(pEngine, "Min", FnMin);
AddFunc(pEngine, "Max", FnMax);
AddFunc(pEngine, "Sin", FnSin);
AddFunc(pEngine, "Cos", FnCos);
AddFunc(pEngine, "Sqrt", FnSqrt);
AddFunc(pEngine, "ArcSin", FnArcSin);
AddFunc(pEngine, "ArcCos", FnArcCos);
AddFunc(pEngine, "BoundBy", FnBoundBy);
AddFunc(pEngine, "Inside", FnInside);
AddFunc(pEngine, "Random", FnRandom);
AddFunc(pEngine, "AsyncRandom", FnAsyncRandom);
AddFunc(pEngine, "DoCon", FnDoCon);
AddFunc(pEngine, "GetCon", FnGetCon);
AddFunc(pEngine, "DoDamage", FnDoDamage);
AddFunc(pEngine, "DoEnergy", FnDoEnergy);
AddFunc(pEngine, "DoBreath", FnDoBreath);
AddFunc(pEngine, "DoMagicEnergy", FnDoMagicEnergy);
AddFunc(pEngine, "GetMagicEnergy", FnGetMagicEnergy);
AddFunc(pEngine, "EnergyCheck", FnEnergyCheck);
AddFunc(pEngine, "CheckEnergyNeedChain", FnCheckEnergyNeedChain);
AddFunc(pEngine, "GetEnergy", FnGetEnergy);
AddFunc(pEngine, "OnFire", FnOnFire);
AddFunc(pEngine, "Smoke", FnSmoke);
AddFunc(pEngine, "Stuck", FnStuck);
AddFunc(pEngine, "InLiquid", FnInLiquid);
AddFunc(pEngine, "Bubble", FnBubble);
AddFunc(pEngine, "SetAction", FnSetAction);
AddFunc(pEngine, "SetActionData", FnSetActionData);
AddFunc(pEngine, "GetActionData", FnGetActionData);
AddFunc(pEngine, "SetBridgeActionData", FnSetBridgeActionData);
AddFunc(pEngine, "GetAction", FnGetAction);
AddFunc(pEngine, "GetActTime", FnGetActTime);
AddFunc(pEngine, "GetOwner", FnGetOwner);
AddFunc(pEngine, "GetMass", FnGetMass);
AddFunc(pEngine, "GetBreath", FnGetBreath);
AddFunc(pEngine, "GetX", FnGetX);
AddFunc(pEngine, "GetY", FnGetY);
AddFunc(pEngine, "GetBase", FnGetBase);
AddFunc(pEngine, "GetMenu", FnGetMenu);
AddFunc(pEngine, "GetVertexNum", FnGetVertexNum);
AddFunc(pEngine, "GetVertex", FnGetVertex);
AddFunc(pEngine, "SetVertex", FnSetVertex);
AddFunc(pEngine, "AddVertex", FnAddVertex);
AddFunc(pEngine, "RemoveVertex", FnRemoveVertex);
AddFunc(pEngine, "SetContactDensity", FnSetContactDensity, false);
AddFunc(pEngine, "AnyContainer", FnAnyContainer);
AddFunc(pEngine, "NoContainer", FnNoContainer);
AddFunc(pEngine, "GetController", FnGetController);
AddFunc(pEngine, "SetController", FnSetController);
AddFunc(pEngine, "GetKiller", FnGetKiller);
AddFunc(pEngine, "SetKiller", FnSetKiller);
AddFunc(pEngine, "GetPhase", FnGetPhase);
AddFunc(pEngine, "SetPhase", FnSetPhase);
AddFunc(pEngine, "GetCategory", FnGetCategory);
AddFunc(pEngine, "GetOCF", FnGetOCF);
AddFunc(pEngine, "SetAlive", FnSetAlive);
AddFunc(pEngine, "GetAlive", FnGetAlive);
AddFunc(pEngine, "GetDamage", FnGetDamage);
AddFunc(pEngine, "ComponentAll", FnComponentAll);
AddFunc(pEngine, "SetComDir", FnSetComDir);
AddFunc(pEngine, "GetComDir", FnGetComDir);
AddFunc(pEngine, "SetDir", FnSetDir);
AddFunc(pEngine, "GetDir", FnGetDir);
AddFunc(pEngine, "SetEntrance", FnSetEntrance);
AddFunc(pEngine, "GetEntrance", FnGetEntrance);
AddFunc(pEngine, "SetCategory", FnSetCategory);
AddFunc(pEngine, "FinishCommand", FnFinishCommand);
AddFunc(pEngine, "GetDefinition", FnGetDefinition);
AddFunc(pEngine, "ActIdle", FnActIdle);
AddFunc(pEngine, "SetRDir", FnSetRDir);
AddFunc(pEngine, "GetRDir", FnGetRDir);
AddFunc(pEngine, "GetXDir", FnGetXDir);
AddFunc(pEngine, "GetYDir", FnGetYDir);
AddFunc(pEngine, "GetR", FnGetR);
AddFunc(pEngine, "GetName", FnGetName);
AddFunc(pEngine, "SetName", FnSetName);
AddFunc(pEngine, "GetDesc", FnGetDesc);
AddFunc(pEngine, "GetPlayerName", FnGetPlayerName);
AddFunc(pEngine, "GetTaggedPlayerName", FnGetTaggedPlayerName);
AddFunc(pEngine, "GetPlayerType", FnGetPlayerType);
AddFunc(pEngine, "SetXDir", FnSetXDir);
AddFunc(pEngine, "SetYDir", FnSetYDir);
AddFunc(pEngine, "SetR", FnSetR);
AddFunc(pEngine, "SetOwner", FnSetOwner);
AddFunc(pEngine, "CreatePropList", FnCreatePropList);
AddFunc(pEngine, "CreateObject", FnCreateObject);
AddFunc(pEngine, "MakeCrewMember", FnMakeCrewMember);
AddFunc(pEngine, "GrabObjectInfo", FnGrabObjectInfo);
AddFunc(pEngine, "CreateContents", FnCreateContents);
AddFunc(pEngine, "ShiftContents", FnShiftContents);
AddFunc(pEngine, "ComposeContents", FnComposeContents);
AddFunc(pEngine, "CreateConstruction", FnCreateConstruction);
AddFunc(pEngine, "GetID", FnGetID);
AddFunc(pEngine, "Contents", FnContents);
AddFunc(pEngine, "ScrollContents", FnScrollContents);
AddFunc(pEngine, "Contained", FnContained);
AddFunc(pEngine, "ContentsCount", FnContentsCount);
AddFunc(pEngine, "FindContents", FnFindContents);
AddFunc(pEngine, "FindConstructionSite", FnFindConstructionSite);
AddFunc(pEngine, "FindOtherContents", FnFindOtherContents);
AddFunc(pEngine, "FindBase", FnFindBase);
AddFunc(pEngine, "Sound", FnSound);
AddFunc(pEngine, "Music", FnMusic);
AddFunc(pEngine, "MusicLevel", FnMusicLevel);
AddFunc(pEngine, "SetPlayList", FnSetPlayList);
AddFunc(pEngine, "RemoveObject", FnRemoveObject);
AddFunc(pEngine, "GetActionTarget", FnGetActionTarget);
AddFunc(pEngine, "SetActionTargets", FnSetActionTargets);
AddFunc(pEngine, "SetPlrView", FnSetPlrView);
AddFunc(pEngine, "SetPlrKnowledge", FnSetPlrKnowledge);
AddFunc(pEngine, "SetPlrMagic", FnSetPlrMagic);
AddFunc(pEngine, "GetPlrViewMode", FnGetPlrViewMode);
AddFunc(pEngine, "GetPlrView", FnGetPlrView);
AddFunc(pEngine, "GetWealth", FnGetWealth);
AddFunc(pEngine, "SetWealth", FnSetWealth);
AddFunc(pEngine, "SetComponent", FnSetComponent);
AddFunc(pEngine, "DoScore", FnDoScore);
AddFunc(pEngine, "GetScore", FnGetScore);
AddFunc(pEngine, "GetPlrValue", FnGetPlrValue);
AddFunc(pEngine, "GetPlrValueGain", FnGetPlrValueGain);
AddFunc(pEngine, "SetPlrShowControl", FnSetPlrShowControl);
AddFunc(pEngine, "SetPlrShowControlPos", FnSetPlrShowControlPos);
AddFunc(pEngine, "GetPlrControlName", FnGetPlrControlName);
AddFunc(pEngine, "SetPlrShowCommand", FnSetPlrShowCommand);
AddFunc(pEngine, "GetWind", FnGetWind);
AddFunc(pEngine, "SetWind", FnSetWind);
AddFunc(pEngine, "GetTemperature", FnGetTemperature);
AddFunc(pEngine, "SetTemperature", FnSetTemperature);
AddFunc(pEngine, "ShakeFree", FnShakeFree);
AddFunc(pEngine, "ShakeObjects", FnShakeObjects);
AddFunc(pEngine, "DigFree", FnDigFree);
AddFunc(pEngine, "FreeRect", FnFreeRect);
AddFunc(pEngine, "DigFreeRect", FnDigFreeRect);
AddFunc(pEngine, "Hostile", FnHostile);
AddFunc(pEngine, "SetHostility", FnSetHostility);
AddFunc(pEngine, "PlaceVegetation", FnPlaceVegetation);
AddFunc(pEngine, "PlaceAnimal", FnPlaceAnimal);
AddFunc(pEngine, "GameOver", FnGameOver);
AddFunc(pEngine, "C4Id", FnC4Id);
AddFunc(pEngine, "ScriptGo", FnScriptGo);
AddFunc(pEngine, "GetHiRank", FnGetHiRank);
AddFunc(pEngine, "GetCrew", FnGetCrew);
AddFunc(pEngine, "GetCrewCount", FnGetCrewCount);
AddFunc(pEngine, "GetPlayerCount", FnGetPlayerCount);
AddFunc(pEngine, "GetPlayerByIndex", FnGetPlayerByIndex);
AddFunc(pEngine, "EliminatePlayer", FnEliminatePlayer);
AddFunc(pEngine, "SurrenderPlayer", FnSurrenderPlayer);
AddFunc(pEngine, "SetLeaguePerformance", FnSetLeaguePerformance);
AddFunc(pEngine, "CreateScriptPlayer", FnCreateScriptPlayer);
AddFunc(pEngine, "GetCursor", FnGetCursor);
AddFunc(pEngine, "GetViewCursor", FnGetViewCursor);
AddFunc(pEngine, "GetCaptain", FnGetCaptain);
AddFunc(pEngine, "SetCursor", FnSetCursor);
AddFunc(pEngine, "SetViewCursor", FnSetViewCursor);
AddFunc(pEngine, "SelectCrew", FnSelectCrew);
AddFunc(pEngine, "GetSelectCount", FnGetSelectCount);
AddFunc(pEngine, "SetCrewStatus", FnSetCrewStatus, false);
AddFunc(pEngine, "SetPosition", FnSetPosition);
AddFunc(pEngine, "GetMaterial", FnGetMaterial);
AddFunc(pEngine, "GetTexture", FnGetTexture);
AddFunc(pEngine, "GetMaterialCount", FnGetMaterialCount);
AddFunc(pEngine, "GBackSolid", FnGBackSolid);
AddFunc(pEngine, "GBackSemiSolid", FnGBackSemiSolid);
AddFunc(pEngine, "GBackLiquid", FnGBackLiquid);
AddFunc(pEngine, "GBackSky", FnGBackSky);
AddFunc(pEngine, "Material", FnMaterial);
AddFunc(pEngine, "BlastObjects", FnBlastObjects);
AddFunc(pEngine, "BlastObject", FnBlastObject);
AddFunc(pEngine, "BlastFree", FnBlastFree);
AddFunc(pEngine, "InsertMaterial", FnInsertMaterial);
AddFunc(pEngine, "DrawVolcanoBranch", FnDrawVolcanoBranch, false);
AddFunc(pEngine, "LandscapeWidth", FnLandscapeWidth);
AddFunc(pEngine, "LandscapeHeight", FnLandscapeHeight);
AddFunc(pEngine, "Resort", FnResort);
AddFunc(pEngine, "CreateMenu", FnCreateMenu);
AddFunc(pEngine, "SelectMenuItem", FnSelectMenuItem);
AddFunc(pEngine, "SetMenuDecoration", FnSetMenuDecoration);
AddFunc(pEngine, "SetMenuTextProgress", FnSetMenuTextProgress);
AddFunc(pEngine, "SetSeason", FnSetSeason);
AddFunc(pEngine, "GetSeason", FnGetSeason);
AddFunc(pEngine, "SetClimate", FnSetClimate);
AddFunc(pEngine, "GetClimate", FnGetClimate);
AddFunc(pEngine, "Distance", FnDistance);
AddFunc(pEngine, "ObjectDistance", FnObjectDistance);
AddFunc(pEngine, "GetValue", FnGetValue);
AddFunc(pEngine, "GetRank", FnGetRank);
AddFunc(pEngine, "Angle", FnAngle);
AddFunc(pEngine, "DoHomebaseMaterial", FnDoHomebaseMaterial);
AddFunc(pEngine, "DoHomebaseProduction", FnDoHomebaseProduction);
AddFunc(pEngine, "GainMissionAccess", FnGainMissionAccess);
AddFunc(pEngine, "SetPhysical", FnSetPhysical);
AddFunc(pEngine, "TrainPhysical", FnTrainPhysical);
AddFunc(pEngine, "GetPhysical", FnGetPhysical);
AddFunc(pEngine, "ResetPhysical", FnResetPhysical);
AddFunc(pEngine, "SetTransferZone", FnSetTransferZone);
AddFunc(pEngine, "IsNetwork", FnIsNetwork);
AddFunc(pEngine, "GetLeague", FnGetLeague);
AddFunc(pEngine, "TestMessageBoard", FnTestMessageBoard, false);
AddFunc(pEngine, "CallMessageBoard", FnCallMessageBoard, false);
AddFunc(pEngine, "AbortMessageBoard", FnAbortMessageBoard, false);
AddFunc(pEngine, "OnMessageBoardAnswer", FnOnMessageBoardAnswer, false);
AddFunc(pEngine, "ScriptCounter", FnScriptCounter);
AddFunc(pEngine, "SetMass", FnSetMass);
AddFunc(pEngine, "GetColor", FnGetColor);
AddFunc(pEngine, "SetColor", FnSetColor);
AddFunc(pEngine, "SetFoW", FnSetFoW);
AddFunc(pEngine, "SetPlrViewRange", FnSetPlrViewRange);
AddFunc(pEngine, "SetMaxPlayer", FnSetMaxPlayer);
AddFunc(pEngine, "SetPicture", FnSetPicture);
AddFunc(pEngine, "Buy", FnBuy);
AddFunc(pEngine, "Sell", FnSell);
AddFunc(pEngine, "GetProcedure", FnGetProcedure);
AddFunc(pEngine, "GetChar", FnGetChar);
AddFunc(pEngine, "ActivateGameGoalMenu", FnActivateGameGoalMenu);
AddFunc(pEngine, "SetGraphics", FnSetGraphics);
AddFunc(pEngine, "Object", FnObject);
AddFunc(pEngine, "ObjectNumber", FnObjectNumber);
AddFunc(pEngine, "ShowInfo", FnShowInfo);
AddFunc(pEngine, "GetTime", FnGetTime);
AddFunc(pEngine, "GetSystemTime", FnGetSystemTime, false);
AddFunc(pEngine, "SetClrModulation", FnSetClrModulation);
AddFunc(pEngine, "GetClrModulation", FnGetClrModulation);
AddFunc(pEngine, "GetMissionAccess", FnGetMissionAccess);
AddFunc(pEngine, "CloseMenu", FnCloseMenu);
AddFunc(pEngine, "GetMenuSelection", FnGetMenuSelection);
AddFunc(pEngine, "ResortObjects", FnResortObjects);
AddFunc(pEngine, "ResortObject", FnResortObject);
AddFunc(pEngine, "GetDefBottom", FnGetDefBottom);
AddFunc(pEngine, "MaterialName", FnMaterialName);
AddFunc(pEngine, "SetMenuSize", FnSetMenuSize);
AddFunc(pEngine, "GetNeededMatStr", FnGetNeededMatStr);
AddFunc(pEngine, "GetCrewEnabled", FnGetCrewEnabled);
AddFunc(pEngine, "SetCrewEnabled", FnSetCrewEnabled);
AddFunc(pEngine, "UnselectCrew", FnUnselectCrew);
AddFunc(pEngine, "DrawMap", FnDrawMap);
AddFunc(pEngine, "DrawDefMap", FnDrawDefMap);
AddFunc(pEngine, "CreateParticle", FnCreateParticle);
AddFunc(pEngine, "CastParticles", FnCastParticles);
AddFunc(pEngine, "CastBackParticles", FnCastBackParticles);
AddFunc(pEngine, "PushParticles", FnPushParticles);
AddFunc(pEngine, "ClearParticles", FnClearParticles);
AddFunc(pEngine, "SetSkyAdjust", FnSetSkyAdjust);
AddFunc(pEngine, "SetMatAdjust", FnSetMatAdjust);
AddFunc(pEngine, "GetSkyAdjust", FnGetSkyAdjust);
AddFunc(pEngine, "GetMatAdjust", FnGetMatAdjust);
AddFunc(pEngine, "SetSkyParallax", FnSetSkyParallax);
AddFunc(pEngine, "DoCrewExp", FnDoCrewExp);
AddFunc(pEngine, "ReloadDef", FnReloadDef);
AddFunc(pEngine, "ReloadParticle", FnReloadParticle);
AddFunc(pEngine, "SetGamma", FnSetGamma);
AddFunc(pEngine, "ResetGamma", FnResetGamma);
AddFunc(pEngine, "FrameCounter", FnFrameCounter);
AddFunc(pEngine, "SetLandscapePixel", FnSetLandscapePixel);
AddFunc(pEngine, "SetObjectOrder", FnSetObjectOrder);
AddFunc(pEngine, "GetPlrColor", FnGetPlrColor);
AddFunc(pEngine, "DrawMaterialQuad", FnDrawMaterialQuad);
AddFunc(pEngine, "FightWith", FnFightWith);
AddFunc(pEngine, "SetFilmView", FnSetFilmView);
AddFunc(pEngine, "ClearMenuItems", FnClearMenuItems);
AddFunc(pEngine, "GetObjectLayer", FnGetObjectLayer, false);
AddFunc(pEngine, "SetObjectLayer", FnSetObjectLayer, false);
AddFunc(pEngine, "SetShape", FnSetShape);
AddFunc(pEngine, "AddMsgBoardCmd", FnAddMsgBoardCmd);
AddFunc(pEngine, "SetGameSpeed", FnSetGameSpeed, false);
AddFunc(pEngine, "DrawMatChunks", FnDrawMatChunks, false);
AddFunc(pEngine, "GetPathLength", FnGetPathLength);
AddFunc(pEngine, "SetTextureIndex", FnSetTextureIndex, false);
AddFunc(pEngine, "RemoveUnusedTexMapEntries", FnRemoveUnusedTexMapEntries, false);
AddFunc(pEngine, "SetObjDrawTransform", FnSetObjDrawTransform);
AddFunc(pEngine, "SetObjDrawTransform2", FnSetObjDrawTransform2, false);
AddFunc(pEngine, "SetPortrait", FnSetPortrait);
AddFunc(pEngine, "LoadScenarioSection", FnLoadScenarioSection, false);
AddFunc(pEngine, "SetObjectStatus", FnSetObjectStatus, false);
AddFunc(pEngine, "GetObjectStatus", FnGetObjectStatus, false);
AddFunc(pEngine, "AdjustWalkRotation", FnAdjustWalkRotation, false);
AddFunc(pEngine, "FxFireStart", FnFxFireStart, false);
AddFunc(pEngine, "FxFireTimer", FnFxFireTimer, false);
AddFunc(pEngine, "FxFireStop", FnFxFireStop, false);
AddFunc(pEngine, "FxFireInfo", FnFxFireInfo, false);
AddFunc(pEngine, "RemoveEffect", FnRemoveEffect);
AddFunc(pEngine, "ChangeEffect", FnChangeEffect);
AddFunc(pEngine, "ModulateColor", FnModulateColor);
AddFunc(pEngine, "WildcardMatch", FnWildcardMatch);
AddFunc(pEngine, "GetContact", FnGetContact);
AddFunc(pEngine, "SetObjectBlitMode", FnSetObjectBlitMode);
AddFunc(pEngine, "GetObjectBlitMode", FnGetObjectBlitMode);
AddFunc(pEngine, "SetViewOffset", FnSetViewOffset);
AddFunc(pEngine, "SetPreSend", FnSetPreSend, false);
AddFunc(pEngine, "GetPlayerID", FnGetPlayerID, false);
AddFunc(pEngine, "GetPlayerTeam", FnGetPlayerTeam);
AddFunc(pEngine, "SetPlayerTeam", FnSetPlayerTeam);
AddFunc(pEngine, "GetTeamConfig", FnGetTeamConfig);
AddFunc(pEngine, "GetTeamName", FnGetTeamName);
AddFunc(pEngine, "GetTeamColor", FnGetTeamColor);
AddFunc(pEngine, "GetTeamByIndex", FnGetTeamByIndex);
AddFunc(pEngine, "GetTeamCount", FnGetTeamCount);
AddFunc(pEngine, "InitScenarioPlayer", FnInitScenarioPlayer, false);
AddFunc(pEngine, PSF_OnOwnerRemoved, FnOnOwnerRemoved, false);
AddFunc(pEngine, "SetScoreboardData", FnSetScoreboardData, false);
AddFunc(pEngine, "GetScoreboardString", FnGetScoreboardString, false);
AddFunc(pEngine, "GetScoreboardData", FnGetScoreboardData, false);
AddFunc(pEngine, "DoScoreboardShow", FnDoScoreboardShow, false);
AddFunc(pEngine, "SortScoreboard", FnSortScoreboard, false);
AddFunc(pEngine, "AddEvaluationData", FnAddEvaluationData, false);
AddFunc(pEngine, "GetUnusedOverlayID", FnGetUnusedOverlayID, false);
AddFunc(pEngine, "FatalError", FnFatalError, false);
AddFunc(pEngine, "ExtractMaterialAmount", FnExtractMaterialAmount);
AddFunc(pEngine, "GetEffectCount", FnGetEffectCount);
AddFunc(pEngine, "PlayVideo", FnPlayVideo);
AddFunc(pEngine, "StartCallTrace", FnStartCallTrace);
AddFunc(pEngine, "StartScriptProfiler", FnStartScriptProfiler);
AddFunc(pEngine, "StopScriptProfiler", FnStopScriptProfiler);
AddFunc(pEngine, "CustomMessage", FnCustomMessage);
AddFunc(pEngine, "PauseGame", FnPauseGame);
AddFunc(pEngine, "ExecuteCommand", FnExecuteCommand);
AddFunc(pEngine, "LocateFunc", FnLocateFunc);
AddFunc(pEngine, "PathFree", FnPathFree);
AddFunc(pEngine, "SetNextMission", FnSetNextMission);
AddFunc(pEngine, "GetPlayerControlState", FnGetPlayerControlState);
//FIXME new C4AulDefCastFunc(pEngine, "ScoreboardCol", C4V_C4ID, C4V_Int);
AddFunc(pEngine, "goto", Fn_goto);
AddFunc(pEngine, "this", Fn_this);
AddFunc(pEngine, "ChangeDef", FnChangeDef);
AddFunc(pEngine, "Explode", FnExplode);
AddFunc(pEngine, "Incinerate", FnIncinerate);
AddFunc(pEngine, "IncinerateLandscape", FnIncinerateLandscape);
AddFunc(pEngine, "Extinguish", FnExtinguish);
AddFunc(pEngine, "GrabContents", FnGrabContents);
AddFunc(pEngine, "Punch", FnPunch);
AddFunc(pEngine, "Kill", FnKill);
AddFunc(pEngine, "Fling", FnFling);
AddFunc(pEngine, "Jump", FnJump);
AddFunc(pEngine, "Enter", FnEnter);
AddFunc(pEngine, "DeathAnnounce", FnDeathAnnounce);
AddFunc(pEngine, "SetSolidMask", FnSetSolidMask);
AddFunc(pEngine, "GetGravity", FnGetGravity);
AddFunc(pEngine, "GetGravity", FnGetGravity);
AddFunc(pEngine, "Exit", FnExit);
AddFunc(pEngine, "Collect", FnCollect);
}
C4ScriptConstDef C4ScriptConstMap[]={
{ "C4D_All" ,C4V_Int, C4D_All},
{ "C4D_StaticBack" ,C4V_Int, C4D_StaticBack},
{ "C4D_Structure" ,C4V_Int, C4D_Structure},
{ "C4D_Vehicle" ,C4V_Int, C4D_Vehicle},
{ "C4D_Living" ,C4V_Int, C4D_Living},
{ "C4D_Object" ,C4V_Int, C4D_Object},
{ "C4D_Goal" ,C4V_Int, C4D_Goal},
{ "C4D_Environment" ,C4V_Int, C4D_Environment},
{ "C4D_Knowledge" ,C4V_Int, C4D_SelectKnowledge},
{ "C4D_Magic" ,C4V_Int, C4D_Magic},
{ "C4D_Rule" ,C4V_Int, C4D_Rule},
{ "C4D_Background" ,C4V_Int, C4D_Background},
{ "C4D_Parallax" ,C4V_Int, C4D_Parallax},
{ "C4D_MouseSelect" ,C4V_Int, C4D_MouseSelect},
{ "C4D_Foreground" ,C4V_Int, C4D_Foreground},
{ "C4D_MouseIgnore" ,C4V_Int, C4D_MouseIgnore},
{ "C4D_IgnoreFoW" ,C4V_Int, C4D_IgnoreFoW},
{ "C4D_GrabGet" ,C4V_Int, C4D_Grab_Get},
{ "C4D_GrabPut" ,C4V_Int, C4D_Grab_Put},
{ "C4D_LinePower" ,C4V_Int, C4D_Line_Power},
{ "C4D_LineSource" ,C4V_Int, C4D_Line_Source},
{ "C4D_LineDrain" ,C4V_Int, C4D_Line_Drain},
{ "C4D_LineLightning" ,C4V_Int, C4D_Line_Lightning},
{ "C4D_LineVolcano" ,C4V_Int, C4D_Line_Volcano},
{ "C4D_LineRope" ,C4V_Int, C4D_Line_Rope},
{ "C4D_LineColored" ,C4V_Int, C4D_Line_Colored},
{ "C4D_LineVertex" ,C4V_Int, C4D_Line_Vertex},
{ "C4D_PowerInput" ,C4V_Int, C4D_Power_Input},
{ "C4D_PowerOutput" ,C4V_Int, C4D_Power_Output},
{ "C4D_LiquidInput" ,C4V_Int, C4D_Liquid_Input},
{ "C4D_LiquidOutput" ,C4V_Int, C4D_Liquid_Output},
{ "C4D_PowerGenerator" ,C4V_Int, C4D_Power_Generator},
{ "C4D_PowerConsumer" ,C4V_Int, C4D_Power_Consumer},
{ "C4D_LiquidPump" ,C4V_Int, C4D_Liquid_Pump},
//{ "C4D_ConnectRope" ,C4V_Int, C4D_Connect_Rope},
{ "C4D_EnergyHolder" ,C4V_Int, C4D_EnergyHolder},
{ "C4V_Any" ,C4V_Int, C4V_Any},
{ "C4V_Int" ,C4V_Int, C4V_Int},
{ "C4V_Bool" ,C4V_Int, C4V_Bool},
{ "C4V_C4Object" ,C4V_Int, C4V_C4Object},
{ "C4V_String" ,C4V_Int, C4V_String},
{ "C4V_Array" ,C4V_Int, C4V_Array},
{ "C4V_PropList" ,C4V_Int, C4V_PropList},
{ "COMD_None" ,C4V_Int, COMD_None},
{ "COMD_Stop" ,C4V_Int, COMD_Stop},
{ "COMD_Up" ,C4V_Int, COMD_Up},
{ "COMD_UpRight" ,C4V_Int, COMD_UpRight},
{ "COMD_Right" ,C4V_Int, COMD_Right},
{ "COMD_DownRight" ,C4V_Int, COMD_DownRight},
{ "COMD_Down" ,C4V_Int, COMD_Down},
{ "COMD_DownLeft" ,C4V_Int, COMD_DownLeft},
{ "COMD_Left" ,C4V_Int, COMD_Left},
{ "COMD_UpLeft" ,C4V_Int, COMD_UpLeft},
{ "DIR_Left" ,C4V_Int, DIR_Left},
{ "DIR_Right" ,C4V_Int, DIR_Right},
{ "CON_CursorLeft" ,C4V_Int, CON_CursorLeft},
{ "CON_CursorToggle" ,C4V_Int, CON_CursorToggle},
{ "CON_CursorRight" ,C4V_Int, CON_CursorRight},
{ "CON_Throw" ,C4V_Int, CON_Throw},
{ "CON_Up" ,C4V_Int, CON_Up},
{ "CON_Dig" ,C4V_Int, CON_Dig},
{ "CON_Left" ,C4V_Int, CON_Left},
{ "CON_Down" ,C4V_Int, CON_Down},
{ "CON_Right" ,C4V_Int, CON_Right},
{ "CON_Menu" ,C4V_Int, CON_Menu},
{ "CON_Special" ,C4V_Int, CON_Special},
{ "CON_Special2" ,C4V_Int, CON_Special2},
{ "OCF_Construct" ,C4V_Int, OCF_Construct},
{ "OCF_Grab" ,C4V_Int, OCF_Grab},
{ "OCF_Collectible" ,C4V_Int, OCF_Carryable},
{ "OCF_OnFire" ,C4V_Int, OCF_OnFire},
{ "OCF_HitSpeed1" ,C4V_Int, OCF_HitSpeed1},
{ "OCF_Fullcon" ,C4V_Int, OCF_FullCon},
{ "OCF_Inflammable" ,C4V_Int, OCF_Inflammable},
{ "OCF_Chop" ,C4V_Int, OCF_Chop},
{ "OCF_Rotate" ,C4V_Int, OCF_Rotate},
{ "OCF_Exclusive" ,C4V_Int, OCF_Exclusive},
{ "OCF_Entrance" ,C4V_Int, OCF_Entrance},
{ "OCF_HitSpeed2" ,C4V_Int, OCF_HitSpeed2},
{ "OCF_HitSpeed3" ,C4V_Int, OCF_HitSpeed3},
{ "OCF_Collection" ,C4V_Int, OCF_Collection},
{ "OCF_Living" ,C4V_Int, OCF_Living},
{ "OCF_HitSpeed4" ,C4V_Int, OCF_HitSpeed4},
{ "OCF_FightReady" ,C4V_Int, OCF_FightReady},
{ "OCF_LineConstruct" ,C4V_Int, OCF_LineConstruct},
{ "OCF_Prey" ,C4V_Int, OCF_Prey},
{ "OCF_AttractLightning" ,C4V_Int, OCF_AttractLightning},
{ "OCF_NotContained" ,C4V_Int, OCF_NotContained},
{ "OCF_CrewMember" ,C4V_Int, OCF_CrewMember},
{ "OCF_Edible" ,C4V_Int, OCF_Edible},
{ "OCF_InLiquid" ,C4V_Int, OCF_InLiquid},
{ "OCF_InSolid" ,C4V_Int, OCF_InSolid},
{ "OCF_InFree" ,C4V_Int, OCF_InFree},
{ "OCF_Available" ,C4V_Int, OCF_Available},
{ "OCF_PowerConsumer" ,C4V_Int, OCF_PowerConsumer},
{ "OCF_PowerSupply" ,C4V_Int, OCF_PowerSupply},
{ "OCF_Container" ,C4V_Int, OCF_Container},
{ "OCF_Alive" ,C4V_Int, (int) OCF_Alive},
{ "VIS_All" ,C4V_Int, VIS_All},
{ "VIS_None" ,C4V_Int, VIS_None},
{ "VIS_Owner" ,C4V_Int, VIS_Owner},
{ "VIS_Allies" ,C4V_Int, VIS_Allies},
{ "VIS_Enemies" ,C4V_Int, VIS_Enemies},
{ "VIS_Select" ,C4V_Int, VIS_Select},
{ "VIS_God" ,C4V_Int, VIS_God},
{ "VIS_LayerToggle" ,C4V_Int, VIS_LayerToggle},
{ "VIS_OverlayOnly" ,C4V_Int, VIS_OverlayOnly},
{ "C4X_Ver1" ,C4V_Int, C4XVER1},
{ "C4X_Ver2" ,C4V_Int, C4XVER2},
{ "C4X_Ver3" ,C4V_Int, C4XVER3},
{ "C4X_Ver4" ,C4V_Int, C4XVER4},
{ "C4X_VerBuild" ,C4V_Int, C4XVERBUILD},
{ "SkyPar_Keep" ,C4V_Int, SkyPar_KEEP},
{ "C4MN_Style_Normal" ,C4V_Int, C4MN_Style_Normal},
{ "C4MN_Style_Context" ,C4V_Int, C4MN_Style_Context},
{ "C4MN_Style_Info" ,C4V_Int, C4MN_Style_Info},
{ "C4MN_Style_Dialog" ,C4V_Int, C4MN_Style_Dialog},
{ "C4MN_Style_EqualItemHeight",C4V_Int, C4MN_Style_EqualItemHeight},
{ "C4MN_Extra_None" ,C4V_Int, C4MN_Extra_None},
{ "C4MN_Extra_Components" ,C4V_Int, C4MN_Extra_Components},
{ "C4MN_Extra_Value" ,C4V_Int, C4MN_Extra_Value},
{ "C4MN_Extra_MagicValue" ,C4V_Int, C4MN_Extra_MagicValue},
{ "C4MN_Extra_Info" ,C4V_Int, C4MN_Extra_Info},
{ "C4MN_Extra_ComponentsMagic",C4V_Int, C4MN_Extra_ComponentsMagic},
{ "C4MN_Extra_LiveMagicValue" ,C4V_Int, C4MN_Extra_LiveMagicValue},
{ "C4MN_Extra_ComponentsLiveMagic",C4V_Int, C4MN_Extra_ComponentsLiveMagic},
{ "C4MN_Add_ImgRank" ,C4V_Int, C4MN_Add_ImgRank},
{ "C4MN_Add_ImgIndexed" ,C4V_Int, C4MN_Add_ImgIndexed},
{ "C4MN_Add_ImgObjRank" ,C4V_Int, C4MN_Add_ImgObjRank},
{ "C4MN_Add_ImgObject" ,C4V_Int, C4MN_Add_ImgObject},
{ "C4MN_Add_ImgTextSpec" ,C4V_Int, C4MN_Add_ImgTextSpec},
{ "C4MN_Add_ImgColor" ,C4V_Int, C4MN_Add_ImgColor},
{ "C4MN_Add_PassValue" ,C4V_Int, C4MN_Add_PassValue},
{ "C4MN_Add_ForceCount" ,C4V_Int, C4MN_Add_ForceCount},
{ "C4MN_Add_ForceNoDesc" ,C4V_Int, C4MN_Add_ForceNoDesc},
{ "FX_OK" ,C4V_Int, C4Fx_OK }, // generic standard behaviour for all effect callbacks
{ "FX_Effect_Deny" ,C4V_Int, C4Fx_Effect_Deny }, // delete effect
{ "FX_Effect_Annul" ,C4V_Int, C4Fx_Effect_Annul }, // delete effect, because it has annulled a countereffect
{ "FX_Effect_AnnulDoCalls" ,C4V_Int, C4Fx_Effect_AnnulCalls }, // delete effect, because it has annulled a countereffect; temp readd countereffect
{ "FX_Execute_Kill" ,C4V_Int, C4Fx_Execute_Kill }, // execute callback: Remove effect now
{ "FX_Stop_Deny" ,C4V_Int, C4Fx_Stop_Deny }, // deny effect removal
{ "FX_Start_Deny" ,C4V_Int, C4Fx_Start_Deny }, // deny effect start
{ "FX_Call_Normal" ,C4V_Int, C4FxCall_Normal }, // normal call; effect is being added or removed
{ "FX_Call_Temp" ,C4V_Int, C4FxCall_Temp }, // temp call; effect is being added or removed in responce to a lower-level effect change
{ "FX_Call_TempAddForRemoval" ,C4V_Int, C4FxCall_TempAddForRemoval }, // temp call; effect is being added because it had been temp removed and is now removed forever
{ "FX_Call_RemoveClear" ,C4V_Int, C4FxCall_RemoveClear }, // effect is being removed because object is being removed
{ "FX_Call_RemoveDeath" ,C4V_Int, C4FxCall_RemoveDeath }, // effect is being removed because object died - return -1 to avoid removal
{ "FX_Call_DmgScript" ,C4V_Int, C4FxCall_DmgScript }, // damage through script call
{ "FX_Call_DmgBlast" ,C4V_Int, C4FxCall_DmgBlast }, // damage through blast
{ "FX_Call_DmgFire" ,C4V_Int, C4FxCall_DmgFire }, // damage through fire
{ "FX_Call_DmgChop" ,C4V_Int, C4FxCall_DmgChop }, // damage through chopping
{ "FX_Call_Energy" ,C4V_Int, 32 }, // bitmask for generic energy loss
{ "FX_Call_EngScript" ,C4V_Int, C4FxCall_EngScript }, // energy loss through script call
{ "FX_Call_EngBlast" ,C4V_Int, C4FxCall_EngBlast }, // energy loss through blast
{ "FX_Call_EngObjHit" ,C4V_Int, C4FxCall_EngObjHit }, // energy loss through object hitting the living
{ "FX_Call_EngFire" ,C4V_Int, C4FxCall_EngFire }, // energy loss through fire
{ "FX_Call_EngBaseRefresh" ,C4V_Int, C4FxCall_EngBaseRefresh }, // energy reload in base (also by base object, but that's normally not called)
{ "FX_Call_EngAsphyxiation" ,C4V_Int, C4FxCall_EngAsphyxiation }, // energy loss through asphyxiaction
{ "FX_Call_EngCorrosion" ,C4V_Int, C4FxCall_EngCorrosion }, // energy loss through corrosion (acid)
{ "FX_Call_EngStruct" ,C4V_Int, C4FxCall_EngStruct }, // regular structure energy loss (normally not called)
{ "FX_Call_EngGetPunched" ,C4V_Int, C4FxCall_EngGetPunched }, // energy loss during fighting
{ "GFXOV_MODE_None" ,C4V_Int, C4GraphicsOverlay::MODE_None }, // gfx overlay modes
{ "GFXOV_MODE_Base" ,C4V_Int, C4GraphicsOverlay::MODE_Base }, //
{ "GFXOV_MODE_Action" ,C4V_Int, C4GraphicsOverlay::MODE_Action }, //
{ "GFXOV_MODE_Picture" ,C4V_Int, C4GraphicsOverlay::MODE_Picture }, //
{ "GFXOV_MODE_IngamePicture" ,C4V_Int, C4GraphicsOverlay::MODE_IngamePicture }, //
{ "GFXOV_MODE_Object" ,C4V_Int, C4GraphicsOverlay::MODE_Object }, //
{ "GFXOV_MODE_ExtraGraphics" ,C4V_Int, C4GraphicsOverlay::MODE_ExtraGraphics }, //
{ "GFX_Overlay" ,C4V_Int, 1}, // default overlay index
{ "GFXOV_Clothing" ,C4V_Int, 1000}, // overlay indices for clothes on Clonks, etc.
{ "GFXOV_Tools" ,C4V_Int, 2000}, // overlay indices for tools, weapons, etc.
{ "GFXOV_ProcessTarget" ,C4V_Int, 3000}, // overlay indices for objects processed by a Clonk
{ "GFXOV_Misc" ,C4V_Int, 5000}, // overlay indices for other stuff
{ "GFXOV_UI" ,C4V_Int, 6000}, // overlay indices for user interface
{ "GFX_BLIT_Additive" ,C4V_Int, C4GFXBLIT_ADDITIVE}, // blit modes
{ "GFX_BLIT_Mod2" ,C4V_Int, C4GFXBLIT_MOD2}, //
{ "GFX_BLIT_ClrSfc_OwnClr" ,C4V_Int, C4GFXBLIT_CLRSFC_OWNCLR}, //
{ "GFX_BLIT_ClrSfc_Mod2" ,C4V_Int, C4GFXBLIT_CLRSFC_MOD2}, //
{ "GFX_BLIT_Custom" ,C4V_Int, C4GFXBLIT_CUSTOM}, //
{ "GFX_BLIT_Parent" ,C4V_Int, C4GFXBLIT_PARENT}, //
{ "NO_OWNER" ,C4V_Int, NO_OWNER }, // invalid player number
// contact attachment
{ "CNAT_None" ,C4V_Int, CNAT_None },
{ "CNAT_Left" ,C4V_Int, CNAT_Left },
{ "CNAT_Right" ,C4V_Int, CNAT_Right },
{ "CNAT_Top" ,C4V_Int, CNAT_Top },
{ "CNAT_Bottom" ,C4V_Int, CNAT_Bottom },
{ "CNAT_Center" ,C4V_Int, CNAT_Center },
{ "CNAT_MultiAttach" ,C4V_Int, CNAT_MultiAttach },
{ "CNAT_NoCollision" ,C4V_Int, CNAT_NoCollision },
// vertex data
{ "VTX_X" ,C4V_Int, VTX_X },
{ "VTX_Y" ,C4V_Int, VTX_Y },
{ "VTX_CNAT" ,C4V_Int, VTX_CNAT },
{ "VTX_Friction" ,C4V_Int, VTX_Friction },
// vertex set mode
{ "VTX_SetPermanent" ,C4V_Int, VTX_SetPermanent },
{ "VTX_SetPermanentUpd" ,C4V_Int, VTX_SetPermanentUpd },
// material density
{ "C4M_Vehicle" ,C4V_Int, C4M_Vehicle },
{ "C4M_Solid" ,C4V_Int, C4M_Solid },
{ "C4M_SemiSolid" ,C4V_Int, C4M_SemiSolid },
{ "C4M_Liquid" ,C4V_Int, C4M_Liquid },
{ "C4M_Background" ,C4V_Int, C4M_Background },
// scoreboard
{ "SBRD_Caption" ,C4V_Int, C4Scoreboard::TitleKey }, // used to set row/coloumn headers
// teams - constants for GetTeamConfig
{ "TEAM_Custom" ,C4V_Int, C4TeamList::TEAM_Custom },
{ "TEAM_Active" ,C4V_Int, C4TeamList::TEAM_Active },
{ "TEAM_AllowHostilityChange" ,C4V_Int, C4TeamList::TEAM_AllowHostilityChange },
{ "TEAM_Dist" ,C4V_Int, C4TeamList::TEAM_Dist },
{ "TEAM_AllowTeamSwitch" ,C4V_Int, C4TeamList::TEAM_AllowTeamSwitch },
{ "TEAM_AutoGenerateTeams" ,C4V_Int, C4TeamList::TEAM_AutoGenerateTeams },
{ "TEAM_TeamColors" ,C4V_Int, C4TeamList::TEAM_TeamColors },
{ "C4OS_DELETED" ,C4V_Int, C4OS_DELETED },
{ "C4OS_NORMAL" ,C4V_Int, C4OS_NORMAL },
{ "C4OS_INACTIVE" ,C4V_Int, C4OS_INACTIVE },
{ "C4MSGCMDR_Escaped" ,C4V_Int, C4MessageBoardCommand::C4MSGCMDR_Escaped },
{ "C4MSGCMDR_Plain" ,C4V_Int, C4MessageBoardCommand::C4MSGCMDR_Plain },
{ "C4MSGCMDR_Identifier" ,C4V_Int, C4MessageBoardCommand::C4MSGCMDR_Identifier },
{ "BASEFUNC_Default" ,C4V_Int, BASEFUNC_Default },
{ "BASEFUNC_AutoSellContents" ,C4V_Int, BASEFUNC_AutoSellContents },
{ "BASEFUNC_RegenerateEnergy" ,C4V_Int, BASEFUNC_RegenerateEnergy },
{ "BASEFUNC_Buy" ,C4V_Int, BASEFUNC_Buy },
{ "BASEFUNC_Sell" ,C4V_Int, BASEFUNC_Sell },
{ "BASEFUNC_RejectEntrance" ,C4V_Int, BASEFUNC_RejectEntrance },
{ "BASEFUNC_Extinguish" ,C4V_Int, BASEFUNC_Extinguish },
{ "C4FO_Not" ,C4V_Int, C4FO_Not },
{ "C4FO_And" ,C4V_Int, C4FO_And },
{ "C4FO_Or" ,C4V_Int, C4FO_Or },
{ "C4FO_Exclude" ,C4V_Int, C4FO_Exclude },
{ "C4FO_InRect" ,C4V_Int, C4FO_InRect },
{ "C4FO_AtPoint" ,C4V_Int, C4FO_AtPoint },
{ "C4FO_AtRect" ,C4V_Int, C4FO_AtRect },
{ "C4FO_OnLine" ,C4V_Int, C4FO_OnLine },
{ "C4FO_Distance" ,C4V_Int, C4FO_Distance },
{ "C4FO_ID" ,C4V_Int, C4FO_ID },
{ "C4FO_OCF" ,C4V_Int, C4FO_OCF },
{ "C4FO_Category" ,C4V_Int, C4FO_Category },
{ "C4FO_Action" ,C4V_Int, C4FO_Action },
{ "C4FO_ActionTarget" ,C4V_Int, C4FO_ActionTarget },
{ "C4FO_Container" ,C4V_Int, C4FO_Container },
{ "C4FO_AnyContainer" ,C4V_Int, C4FO_AnyContainer },
{ "C4FO_Owner" ,C4V_Int, C4FO_Owner },
{ "C4FO_Func" ,C4V_Int, C4FO_Func },
{ "C4FO_Layer" ,C4V_Int, C4FO_Layer },
{ "C4SO_Reverse" ,C4V_Int, C4SO_Reverse },
{ "C4SO_Multiple" ,C4V_Int, C4SO_Multiple },
{ "C4SO_Distance" ,C4V_Int, C4SO_Distance },
{ "C4SO_Random" ,C4V_Int, C4SO_Random },
{ "C4SO_Speed" ,C4V_Int, C4SO_Speed },
{ "C4SO_Mass" ,C4V_Int, C4SO_Mass },
{ "C4SO_Value" ,C4V_Int, C4SO_Value },
{ "C4SO_Func" ,C4V_Int, C4SO_Func },
{ "PHYS_Current" ,C4V_Int, PHYS_Current },
{ "PHYS_Permanent" ,C4V_Int, PHYS_Permanent },
{ "PHYS_Temporary" ,C4V_Int, PHYS_Temporary },
{ "PHYS_StackTemporary" ,C4V_Int, PHYS_StackTemporary },
{ "C4CMD_Base" ,C4V_Int, C4CMD_Mode_Base },
{ "C4CMD_SilentBase" ,C4V_Int, C4CMD_Mode_SilentBase },
{ "C4CMD_Sub" ,C4V_Int, C4CMD_Mode_Sub },
{ "C4CMD_SilentSub" ,C4V_Int, C4CMD_Mode_SilentSub },
{ "C4CMD_MoveTo_NoPosAdjust" ,C4V_Int, C4CMD_MoveTo_NoPosAdjust },
{ "C4CMD_MoveTo_PushTarget" ,C4V_Int, C4CMD_MoveTo_PushTarget },
{ "C4CMD_Enter_PushTarget" ,C4V_Int, C4CMD_Enter_PushTarget },
{ "C4SECT_SaveLandscape" ,C4V_Int, C4S_SAVE_LANDSCAPE },
{ "C4SECT_SaveObjects" ,C4V_Int, C4S_SAVE_OBJECTS },
{ "C4SECT_KeepEffects" ,C4V_Int, C4S_KEEP_EFFECTS },
{ "TEAMID_New" ,C4V_Int, TEAMID_New },
{ "MSG_NoLinebreak" ,C4V_Int, C4GM_NoBreak },
{ "MSG_Bottom" ,C4V_Int, C4GM_Bottom },
{ "MSG_Multiple" ,C4V_Int, C4GM_Multiple },
{ "MSG_Top" ,C4V_Int, C4GM_Top },
{ "MSG_Left" ,C4V_Int, C4GM_Left },
{ "MSG_Right" ,C4V_Int, C4GM_Right },
{ "MSG_HCenter" ,C4V_Int, C4GM_HCenter },
{ "MSG_VCenter" ,C4V_Int, C4GM_VCenter },
{ "MSG_DropSpeech" ,C4V_Int, C4GM_DropSpeech },
{ "MSG_WidthRel" ,C4V_Int, C4GM_WidthRel },
{ "MSG_XRel" ,C4V_Int, C4GM_XRel },
{ "MSG_YRel" ,C4V_Int, C4GM_YRel },
{ "C4PT_User" ,C4V_Int, C4PT_User },
{ "C4PT_Script" ,C4V_Int, C4PT_Script },
{ "CSPF_FixedAttributes" ,C4V_Int, CSPF_FixedAttributes },
{ "CSPF_NoScenarioInit" ,C4V_Int, CSPF_NoScenarioInit },
{ "CSPF_NoEliminationCheck" ,C4V_Int, CSPF_NoEliminationCheck },
{ "CSPF_Invisible" ,C4V_Int, CSPF_Invisible },
{ NULL, C4V_Any, 0} };
#define MkFnC4V (C4Value (*)(C4AulContext *cthr, C4Value*, C4Value*, C4Value*, C4Value*, C4Value*,\
C4Value*, C4Value*, C4Value*, C4Value*, C4Value*))
C4ScriptFnDef C4ScriptFnMap[]={
{ "Equal", 1 ,C4V_Any ,{ C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnEqual_C4V , 0 },
{ "SetProperty", 1 ,C4V_Any ,{ C4V_String ,C4V_Any ,C4V_PropList,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnSetProperty_C4V , 0 },
{ "GetProperty", 1 ,C4V_Any ,{ C4V_String ,C4V_PropList,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnGetProperty_C4V , 0 },
{ "PlayerObjectCommand", 1 ,C4V_Bool ,{ C4V_Int ,C4V_String ,C4V_C4Object,C4V_Any ,C4V_Int ,C4V_C4Object,C4V_Any ,C4V_Int ,C4V_Any ,C4V_Any} ,0 , FnPlayerObjectCommand },
{ "SetCommand", 1 ,C4V_Bool ,{ C4V_String ,C4V_C4Object,C4V_Any ,C4V_Int ,C4V_C4Object,C4V_Any ,C4V_Int ,C4V_Any ,C4V_Any ,C4V_Any} ,0 , FnSetCommand },
{ "AddCommand", 1 ,C4V_Bool ,{ C4V_String ,C4V_C4Object,C4V_Any ,C4V_Int ,C4V_C4Object,C4V_Int ,C4V_Any ,C4V_Int ,C4V_Int ,C4V_Any} ,0 , FnAddCommand },
{ "AppendCommand", 1 ,C4V_Bool ,{ C4V_String ,C4V_C4Object,C4V_Any ,C4V_Int ,C4V_C4Object,C4V_Int ,C4V_Any ,C4V_Int ,C4V_Int ,C4V_Any} ,0 , FnAppendCommand },
{ "GetCommand", 1 ,C4V_Any ,{ C4V_Int ,C4V_Int ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,0 , FnGetCommand },
{ "PathFree2", 1 ,C4V_Bool ,{ C4V_pC4Value,C4V_pC4Value,C4V_Int ,C4V_Int ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnPathFree2_C4V , 0 },
{ "FindObject", 1 ,C4V_C4Object ,{ C4V_Array ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,0 , FnFindObject },
{ "FindObjects", 1 ,C4V_Array ,{ C4V_Array ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,0 , FnFindObjects },
{ "ObjectCount", 1 ,C4V_Int ,{ C4V_Array ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,0 , FnObjectCount },
{ "ProtectedCall", 1 ,C4V_Any ,{ C4V_C4Object,C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnProtectedCall_C4V , 0 },
{ "PrivateCall", 1 ,C4V_Any ,{ C4V_C4Object,C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnPrivateCall_C4V , 0 },
{ "GameCall", 1 ,C4V_Any ,{ C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnGameCall_C4V , 0 },
{ "GameCallEx", 1 ,C4V_Any ,{ C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnGameCallEx_C4V , 0 },
{ "DefinitionCall", 1 ,C4V_Any ,{ C4V_PropList,C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnDefinitionCall_C4V , 0 },
{ "Call", 0 ,C4V_Any ,{ C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnCall_C4V , 0 },
{ "GetPlrKnowledge", 1 ,C4V_Int ,{ C4V_Int ,C4V_PropList,C4V_Int ,C4V_Int ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnGetPlrKnowledge_C4V , 0 },
{ "GetPlrMagic", 1 ,C4V_Int ,{ C4V_Int ,C4V_PropList,C4V_Int ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnGetPlrMagic_C4V , 0 },
{ "GetComponent", 1 ,C4V_Int ,{ C4V_PropList,C4V_Int ,C4V_C4Object,C4V_PropList,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnGetComponent_C4V , 0 },
{ "PlayerMessage", 1 ,C4V_Int ,{ C4V_Int ,C4V_String ,C4V_C4Object,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V &FnPlayerMessage_C4V, 0 },
{ "Message", 1 ,C4V_Bool ,{ C4V_String ,C4V_C4Object,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V &FnMessage_C4V, 0 },
{ "AddMessage", 1 ,C4V_Bool ,{ C4V_String ,C4V_C4Object,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V &FnAddMessage_C4V, 0 },
{ "PlrMessage", 1 ,C4V_Bool ,{ C4V_String ,C4V_Int ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V &FnPlrMessage_C4V, 0 },
{ "Log", 1 ,C4V_Bool ,{ C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V &FnLog_C4V, 0 },
{ "DebugLog", 1 ,C4V_Bool ,{ C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V &FnDebugLog_C4V, 0 },
{ "Format", 1 ,C4V_String ,{ C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V &FnFormat_C4V, 0 },
{ "EditCursor", 1 ,C4V_C4Object ,{ C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,0 , FnEditCursor },
{ "AddMenuItem", 1 ,C4V_Bool ,{ C4V_String ,C4V_String ,C4V_PropList,C4V_Int ,C4V_Any ,C4V_String ,C4V_Int ,C4V_Any ,C4V_Any ,C4V_Any} ,0 , FnAddMenuItem },
{ "GetHomebaseMaterial", 1 ,C4V_Int ,{ C4V_Int ,C4V_PropList,C4V_Int ,C4V_Int ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnGetHomebaseMaterial_C4V , 0 },
{ "GetHomebaseProduction",1 ,C4V_Int ,{ C4V_Int ,C4V_PropList,C4V_Int ,C4V_Int ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnGetHomebaseProduction_C4V , 0 },
{ "IsRef", 1 ,C4V_Bool ,{ C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnIsRef, 0 },
{ "GetType", 1 ,C4V_Int ,{ C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnGetType, 0 },
{ "CreateArray", 1 ,C4V_Array ,{ C4V_Int ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,0, FnCreateArray },
{ "GetLength", 1 ,C4V_Int ,{ C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,0, FnGetLength },
{ "GetIndexOf", 1 ,C4V_Int ,{ C4V_Any ,C4V_Array ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,0, FnGetIndexOf },
{ "SetLength", 1 ,C4V_Bool ,{ C4V_pC4Value,C4V_Int ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,0, FnSetLength },
{ "GetDefCoreVal", 1 ,C4V_Any ,{ C4V_String ,C4V_String ,C4V_PropList,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnGetDefCoreVal, 0 },
{ "GetObjectVal", 1 ,C4V_Any ,{ C4V_String ,C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnGetObjectVal, 0 },
{ "GetObjectInfoCoreVal", 1 ,C4V_Any ,{ C4V_String ,C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnGetObjectInfoCoreVal, 0 },
{ "GetScenarioVal", 1 ,C4V_Any ,{ C4V_String ,C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnGetScenarioVal, 0 },
{ "GetPlayerVal", 1 ,C4V_Any ,{ C4V_String ,C4V_String ,C4V_Int ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnGetPlayerVal, 0 },
{ "GetPlayerInfoCoreVal", 1 ,C4V_Any ,{ C4V_String ,C4V_String ,C4V_Int ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnGetPlayerInfoCoreVal, 0 },
{ "GetMaterialVal", 1 ,C4V_Any ,{ C4V_String ,C4V_String ,C4V_Int ,C4V_Int ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnGetMaterialVal, 0 },
{ "SetPlrExtraData", 1 ,C4V_Any ,{ C4V_Int ,C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnSetPlrExtraData, 0 },
{ "GetPlrExtraData", 1 ,C4V_Any ,{ C4V_Int ,C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnGetPlrExtraData, 0 },
{ "SetCrewExtraData", 1 ,C4V_Any ,{ C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnSetCrewExtraData, 0 },
{ "GetCrewExtraData", 1 ,C4V_Any ,{ C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnGetCrewExtraData, 0 },
{ "SimFlight", 1 ,C4V_Bool ,{ C4V_pC4Value,C4V_pC4Value,C4V_pC4Value,C4V_pC4Value,C4V_Int ,C4V_Int ,C4V_Int ,C4V_Int ,C4V_Any ,C4V_Any} ,MkFnC4V FnSimFlight, 0 },
{ "GetPortrait", 1 ,C4V_Any ,{ C4V_C4Object,C4V_Bool ,C4V_Bool ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnGetPortrait, 0 },
{ "AddEffect", 1 ,C4V_Int ,{ C4V_String ,C4V_C4Object,C4V_Int ,C4V_Int ,C4V_C4Object,C4V_PropList,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnAddEffect_C4V, 0 },
{ "GetEffect", 1 ,C4V_Any ,{ C4V_String ,C4V_C4Object,C4V_Int ,C4V_Int ,C4V_Int ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnGetEffect_C4V, 0 },
{ "CheckEffect", 1 ,C4V_Int ,{ C4V_String ,C4V_C4Object,C4V_Int ,C4V_Int ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnCheckEffect_C4V, 0 },
{ "EffectCall", 1 ,C4V_Any ,{ C4V_C4Object,C4V_Int ,C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnEffectCall_C4V, 0 },
{ "EffectVar", 1 ,C4V_pC4Value ,{ C4V_Int ,C4V_C4Object,C4V_Int ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnEffectVar_C4V, 0 },
{ "eval", 1 ,C4V_Any ,{ C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnEval, 0 },
{ "VarN", 1 ,C4V_Any ,{ C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnVarN, 0 },
{ "LocalN", 1 ,C4V_Any ,{ C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnLocalN, 0 },
{ "GlobalN", 1 ,C4V_Any ,{ C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnGlobalN, 0 },
{ NULL, 0 ,C4V_Any ,{ C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,0, 0 }
};