Merge script branch

objectmenu
Günther Brammer 2016-01-24 12:25:52 +01:00
commit d0d27d25f1
28 changed files with 247 additions and 396 deletions

View File

@ -785,6 +785,7 @@ set(MAPE_BASE_SOURCES
src/lib/C4Rect.h
src/object/C4Id.cpp
src/object/C4Id.h
src/script/C4ScriptStandaloneStubs.cpp
)
set(MAPE_SOURCES

View File

@ -2021,9 +2021,9 @@ bool C4Game::ReloadFile(const char *szFile)
if ((pDef = ::Definitions.GetByPath(szRelativePath)))
return ReloadDef(pDef->id);
// script?
if (ScriptEngine.ReloadScript(szRelativePath, &::Definitions, Config.General.LanguageEx))
if (ScriptEngine.ReloadScript(szRelativePath, Config.General.LanguageEx))
{
return true;
ReLinkScriptEngine();
}
return true;
}
@ -2050,6 +2050,8 @@ bool C4Game::ReloadDef(C4ID id)
// Reload def
if (::Definitions.Reload(pDef,C4D_Load_RX,Config.General.LanguageEx,&Application.SoundSystem))
{
// update script engine - this will also do include callbacks and Freeze() pDef
ReLinkScriptEngine();
// Success, update all concerned object faces
// may have been done by graphics-update already - but not for objects using graphics of another def
// better update everything :)
@ -2422,6 +2424,9 @@ bool C4Game::LinkScriptEngine()
ScriptEngine.warnCnt, (ScriptEngine.warnCnt != 1 ? "s" : ""),
ScriptEngine.errCnt, (ScriptEngine.errCnt != 1 ? "s" : ""));
// update material pointers
::MaterialMap.UpdateScriptPointers();
// Set name list for globals
ScriptEngine.GlobalNamed.SetNameList(&ScriptEngine.GlobalNamedNames);
@ -2432,6 +2437,18 @@ bool C4Game::LinkScriptEngine()
return true;
}
bool C4Game::ReLinkScriptEngine()
{
::ScriptEngine.ReLink(&::Definitions);
// update effect pointers
::Objects.UpdateScriptPointers();
// update material pointers
::MaterialMap.UpdateScriptPointers();
return true;
}
bool C4Game::InitPlayers(C4ValueNumbers * numbers)
{
@ -3079,7 +3096,7 @@ bool C4Game::DoGameOver()
// Flag, log, call
GameOver=true;
Log(LoadResStr("IDS_PRC_GAMEOVER"));
::GameScript.GRBroadcast(PSF_OnGameOver);
GRBroadcast(PSF_OnGameOver);
// Flag all surviving players as winners
for (C4Player *pPlayer = Players.First; pPlayer; pPlayer = pPlayer->Next)
if (!pPlayer->Eliminated)
@ -3727,6 +3744,16 @@ bool C4Game::ToggleChat()
return C4ChatDlg::ToggleChat();
}
C4Value C4Game::GRBroadcast(const char *szFunction, C4AulParSet *pPars, bool fPassError, bool fRejectTest)
{
// call objects first - scenario script might overwrite hostility, etc...
C4Value vResult = ::Objects.GRBroadcast(szFunction, pPars, fPassError, fRejectTest);
// rejection tests abort on first nonzero result
if (fRejectTest) if (!!vResult) return vResult;
// scenario script call
return ::GameScript.Call(szFunction, pPars, fPassError);
}
void C4Game::SetDefaultGamma()
{
// Skip this if graphics haven't been initialized yet (happens when

View File

@ -205,6 +205,7 @@ public:
void CastObjects(C4ID id, C4Object *pCreator, int32_t num, int32_t level, int32_t tx, int32_t ty, int32_t iOwner=NO_OWNER, int32_t iController=NO_OWNER, C4ValueArray *out_objects=NULL);
C4Object *PlaceVegetation(C4PropList *def, int32_t iX, int32_t iY, int32_t iWdt, int32_t iHgt, int32_t iGrowth, C4PropList *shape_proplist, C4PropList * out_pos_proplist);
C4Object *PlaceAnimal(C4PropList *def);
C4Value GRBroadcast(const char *szFunction, C4AulParSet *pPars = 0, bool fPassError=false, bool fRejectTest=false); // call function in scenario script and all goals/rules/environment objects
bool LoadScenarioSection(const char *szSection, DWORD dwFlags);
@ -247,6 +248,7 @@ protected:
bool InitControl();
bool InitScriptEngine();
bool LinkScriptEngine();
bool ReLinkScriptEngine();
bool InitPlayers(C4ValueNumbers *);
bool OpenScenario();
bool InitDefs();

View File

@ -23,12 +23,7 @@
#include <C4DefList.h>
#include <C4Object.h>
#include <C4Random.h>
#include <C4Game.h>
#include <C4Landscape.h>
#include <C4PXS.h>
#include <C4GameObjects.h>
#include <C4SoundSystem.h>
void C4Effect::AssignCallbackFunctions()
{
@ -568,66 +563,3 @@ C4ValueArray * C4Effect::GetProperties() const
(*a)[i++] = C4VString(&::Strings.P[P_Time]);
return a;
}
// Some other, internal effects -------------------------------------------------------------
static int32_t GetSmokeLevel()
{
// just use fixed smoke level, smoke uses particles anyway
return 150;
}
static void BubbleOut(int32_t tx, int32_t ty)
{
// No bubbles from nowhere
if (!GBackSemiSolid(tx,ty)) return;
// User-defined smoke level
int32_t SmokeLevel = GetSmokeLevel();
// Enough bubbles out there already
if (::Objects.ObjectCount(C4ID::Bubble) >= SmokeLevel) return;
// Create bubble
Game.CreateObject(C4ID::Bubble,NULL,NO_OWNER,tx,ty);
}
void Splash(int32_t tx, int32_t ty, int32_t amt, C4Object *pByObj)
{
// Splash only if there is free space above
if (GBackSemiSolid(tx, ty - 15)) return;
// get back mat
int32_t iMat = GBackMat(tx, ty);
// check liquid
if (MatValid(iMat))
if (DensityLiquid(::MaterialMap.Map[iMat].Density) && ::MaterialMap.Map[iMat].Instable)
{
int32_t sy = ty;
while (GBackLiquid(tx, sy) && sy > ty - 20 && sy >= 0) sy--;
// Splash bubbles and liquid
for (int32_t cnt=0; cnt<amt; cnt++)
{
int32_t bubble_x = tx+Random(16)-8;
int32_t bubble_y = ty+Random(16)-6;
BubbleOut(bubble_x,bubble_y);
if (GBackLiquid(tx,ty) && !GBackSemiSolid(tx, sy))
{
C4Real xdir = C4REAL100(Random(151)-75);
C4Real ydir = C4REAL100(-Random(200));
::PXS.Create(::Landscape.ExtractMaterial(tx,ty,false),
itofix(tx),itofix(sy),
xdir,
ydir);
}
}
}
// Splash sound
if (amt>=20)
StartSoundEffect("Liquids::Splash2", false, 50, pByObj);
else if (amt>1) StartSoundEffect("Liquids::Splash1", false, 50, pByObj);
}
void Smoke(int32_t tx, int32_t ty, int32_t level, DWORD dwClr)
{
// Use scripted function (global func Smoke) to create smoke
// Caution: This makes engine internal smoking a synced call.
C4AulParSet pars(C4VInt(tx), C4VInt(ty), C4VInt(level), C4VInt(dwClr));
::ScriptEngine.GetPropList()->Call(P_Smoke, &pars);
}

View File

@ -146,8 +146,4 @@ protected:
#define C4Fx_FirePriority 100
#define C4Fx_FireTimer 1
// some other hardcoded engine effects
void Splash(int32_t tx, int32_t ty, int32_t amt, C4Object *pByObj);
void Smoke(int32_t tx, int32_t ty, int32_t level, DWORD dwClr=0);
#endif

View File

@ -790,14 +790,14 @@ static bool FnSetHostility(C4PropList * _this, long iPlr, long iPlr2, bool fHost
// do rejection test first
if (!fNoCalls)
{
if (!!::GameScript.GRBroadcast(PSF_RejectHostilityChange, &C4AulParSet(C4VInt(iPlr), C4VInt(iPlr2), C4VBool(fHostile)), true, true))
if (!!::Game.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
::GameScript.GRBroadcast(PSF_OnHostilityChange, &C4AulParSet(C4VInt(iPlr), C4VInt(iPlr2), C4VBool(fHostile), C4VBool(fOldHostility)), true);
::Game.GRBroadcast(PSF_OnHostilityChange, &C4AulParSet(C4VInt(iPlr), C4VInt(iPlr2), C4VBool(fHostile), C4VBool(fOldHostility)), true);
return true;
}
@ -1348,7 +1348,7 @@ static C4Value FnGameCallEx(C4PropList * _this, C4Value * Pars)
// copy parameters
C4AulParSet ParSet(&Pars[1], 9);
// Call
return ::GameScript.GRBroadcast(fn->GetCStr(), &ParSet, true);
return ::Game.GRBroadcast(fn->GetCStr(), &ParSet, true);
}
static C4Object * FnEditCursor(C4PropList * _this)
@ -2340,7 +2340,7 @@ static bool FnSetPlayerTeam(C4PropList * _this, long iPlayer, long idNewTeam, bo
// ask script if it's allowed
if (!fNoCalls)
{
if (!!::GameScript.GRBroadcast(PSF_RejectTeamSwitch, &C4AulParSet(C4VInt(iPlayer), C4VInt(idNewTeam)), true, true))
if (!!::Game.GRBroadcast(PSF_RejectTeamSwitch, &C4AulParSet(C4VInt(iPlayer), C4VInt(idNewTeam)), true, true))
return false;
}
// exit previous team
@ -2373,7 +2373,7 @@ static bool FnSetPlayerTeam(C4PropList * _this, long iPlayer, long idNewTeam, bo
}
// do callback to reflect change in scenario
if (!fNoCalls)
::GameScript.GRBroadcast(PSF_OnTeamSwitch, &C4AulParSet(C4VInt(iPlayer), C4VInt(idNewTeam), C4VInt(idOldTeam)), true);
::Game.GRBroadcast(PSF_OnTeamSwitch, &C4AulParSet(C4VInt(iPlayer), C4VInt(idNewTeam), C4VInt(idOldTeam)), true);
return true;
}

View File

@ -632,6 +632,13 @@ C4MaterialReaction *C4MaterialMap::GetReaction(int32_t iPXSMat, int32_t iLandsca
return GetReactionUnsafe(iPXSMat, iLandscapeMat);
}
static void Smoke(int32_t tx, int32_t ty, int32_t level)
{
// Use scripted function (global func Smoke) to create smoke
// Caution: This makes engine internal smoking a synced call.
C4AulParSet pars(C4VInt(tx), C4VInt(ty), C4VInt(level));
::ScriptEngine.GetPropList()->Call(P_Smoke, &pars);
}
bool mrfInsertCheck(int32_t &iX, int32_t &iY, C4Real &fXDir, C4Real &fYDir, int32_t &iPxsMat, int32_t iLsMat, bool *pfPosChanged)
{

View File

@ -118,3 +118,5 @@ bool C4Def::Load(C4Group& hGroup, StdMeshSkeletonLoader& loader, DWORD dwLoadWha
return true;
}
C4DefList Definitions;

View File

@ -31,45 +31,15 @@
#include "C4TextureShape.h"
/* This file implements stubs for the parts of the engine that are not used
* by mape. It also instantiates global variables required by mape that are
* not instantiated elsewhere. In particular, we avoid C4Globals.cpp. */
* by mape. */
/* These are actually used by mape: */
#ifdef _DEBUG
C4Set<C4PropList *> C4PropList::PropLists;
#endif
C4Set<C4PropListNumbered *> C4PropListNumbered::PropLists;
C4Set<C4PropListScript *> C4PropListScript::PropLists;
std::vector<C4PropListNumbered *> C4PropListNumbered::ShelvedPropLists;
int32_t C4PropListNumbered::EnumerationIndex = 0;
C4StringTable Strings;
C4AulScriptEngine ScriptEngine;
C4DefList Definitions;
/* These are just stubs used by dead code: */
C4Landscape Landscape;
C4PXSSystem PXS;
C4Config Config;
C4GameObjects Objects;
C4Reloc Reloc;
class C4Draw *pDraw = NULL;
bool EraseItemSafe(const char *szFilename) {return false;}
void Smoke(int32_t tx, int32_t ty, int32_t level, DWORD dwClr) {}
class C4SoundInstance *StartSoundEffectAt(const char *, int32_t, int32_t, int32_t, int32_t, int32_t, class C4SoundModifier *) { return NULL; }
C4Config::C4Config() {}
C4Config::~C4Config() {}
const char* C4Config::AtTempPath(const char *) { return NULL; }
const char* C4Config::AtRelativePath(char const* s) {return s;}
bool C4Reloc::Open(C4Group&, char const*) const {return false;}
bool C4Draw::TextOut(const char *, CStdFont &, float, C4Surface *, float, float, DWORD, BYTE, bool) { return false; }
C4Facet::C4Facet() {}
void C4Facet::Set(C4Surface*, float, float, float, float) {}
int32_t C4Facet::GetSectionCount() { return 0; }
C4Facet C4Facet::TruncateSection(int32_t) { return *this; }
C4Surface::C4Surface() {}
C4Surface::~C4Surface() {}
@ -101,9 +71,6 @@ C4IDListChunk::~C4IDListChunk() {}
C4DefGraphics::C4DefGraphics(C4Def*) {}
void C4DefGraphics::Clear() {}
void C4Def::IncludeDefinition(C4Def*) {}
void C4DefList::Draw(C4ID, C4Facet &, bool, int32_t) {}
void C4DefList::CallEveryDefinition() {}
void C4DefList::ResetIncludeDependencies() {}
bool C4DefList::DrawFontImage(const char* szImageTag, C4Facet& rTarget, C4DrawTransform* pTransform) { return false; }
@ -121,82 +88,11 @@ void C4Landscape::CheckInstabilityRange(int32_t, int32_t) {}
void C4Sky::Default() {}
C4Sky::~C4Sky() {}
void C4LSector::Clear() {}
C4ObjectList::C4ObjectList() {}
C4ObjectList::~C4ObjectList() {}
void C4ObjectList::Default() {}
void C4ObjectList::Clear() {}
void C4ObjectList::InsertLinkBefore(C4ObjectLink*, C4ObjectLink*) {}
void C4ObjectList::InsertLink(C4ObjectLink*, C4ObjectLink*) {}
void C4ObjectList::RemoveLink(C4ObjectLink*) {}
bool C4ObjectList::Add(C4Object*, C4ObjectList::SortType, C4ObjectList*) {return 0;}
bool C4ObjectList::Remove(C4Object*) {return 0;}
bool C4ObjectList::AssignInfo() {return 0;}
bool C4ObjectList::ValidateOwners() {return 0;}
void C4NotifyingObjectList::InsertLinkBefore(C4ObjectLink *pLink, C4ObjectLink *pBefore) {}
void C4NotifyingObjectList::InsertLink(C4ObjectLink*, C4ObjectLink*) {}
void C4NotifyingObjectList::RemoveLink(C4ObjectLink*) {}
C4GameObjects::C4GameObjects() {}
C4GameObjects::~C4GameObjects() {}
void C4GameObjects::Clear(bool) {}
void C4GameObjects::Default() {}
bool C4GameObjects::Remove(C4Object*) {return 0;}
bool C4GameObjects::AssignInfo() {return 0;}
bool C4GameObjects::ValidateOwners() {return 0;}
C4Object * C4GameObjects::ObjectPointer(int) {return 0;}
void C4GameObjects::UpdateScriptPointers() {}
C4Value C4GameObjects::GRBroadcast(char const*, C4AulParSet*, bool, bool) {return C4Value();}
C4PXSSystem::C4PXSSystem() {}
C4PXSSystem::~C4PXSSystem() {}
bool C4PXSSystem::Create(int, C4Real, C4Real, C4Real, C4Real) { return false; }
void AddDbgRec(C4RecordChunkType, const void *, int) {}
bool C4TextureShape::Load(C4Group &group, const char *filename, int32_t base_tex_wdt, int32_t base_tex_hgt) { return true; }
#if 0
/* Pulled in by C4Game... */
CStdFont::CStdFont() {}
C4PathFinder::C4PathFinder() {}
C4PathFinder::~C4PathFinder() {}
C4TransferZones::C4TransferZones() {}
C4TransferZones::~C4TransferZones() {}
C4PacketBase::C4PacketBase() {}
C4PacketList::C4PacketList() {}
C4PacketBase::~C4PacketBase() {}
C4PacketList::~C4PacketList() {}
C4Control::C4Control() {}
C4Control::~C4Control() {}
C4GameControl::C4GameControl(): Network(this) {}
C4GameControl::~C4GameControl() {}
C4GameControlNetwork::C4GameControlNetwork(C4GameControl*): pParent(NULL) {}
C4GameControlNetwork::~C4GameControlNetwork() {}
C4GraphicsResource::C4GraphicsResource(): CaptionFont(FontCaption), TitleFont(FontTitle), TextFont(FontRegular), MiniFont(FontTiny), TooltipFont(FontTooltip) {}
C4GraphicsResource::~C4GraphicsResource() {}
C4GameParameters::C4GameParameters() {}
C4GameParameters::~C4GameParameters() {}
//C4Extra::C4Extra() {}
//C4Extra::~C4Extra() {}
void C4Extra::Clear() {}
static C4KeyboardInput KeyboardInput;
void C4KeyboardInput::Clear() {}
bool C4KeyboardInput::IsValid = false;
C4KeyboardInput &C4KeyboardInput_Init() { return KeyboardInput; }
static C4GameParameters GameParameters;
static C4RoundResults GameRoundResults;
C4Game::C4Game(): Parameters(GameParameters), Clients(Parameters.Clients), Teams(Parameters.Teams), PlayerInfos(Parameters.PlayerInfos), RestorePlayerInfos(Parameters.RestorePlayerInfos), RoundResults(GameRoundResults), Input(Control.Input), KeyboardInput(C4KeyboardInput_Init()) {}
C4Game::~C4Game() {}
#endif
C4AulDebug *C4AulDebug::pDebug;
void C4AulDebug::DebugStep(C4AulBCC*, C4Value*) {}
C4Shader::C4Shader() {}
C4Shader::~C4Shader() {}

View File

@ -406,8 +406,6 @@ bool C4DefList::Reload(C4Def *pDef, DWORD dwLoadWhat, const char *szLanguage, C4
BuildTable();
// handle skeleton appends and includes
AppendAndIncludeSkeletons();
// update script engine - this will also do include callbacks and Freeze() this
::ScriptEngine.ReLink(this);
// restore graphics
GfxBackup.AssignUpdate();
// Success

View File

@ -435,8 +435,8 @@ void C4Object::DoMovement()
{
if (!InLiquid) // Enter liquid
{
if (OCF & OCF_HitSpeed2) if (Mass>3)
Splash(GetX(),GetY()+1,std::min(Shape.Wdt*Shape.Hgt/10,20),this);
if (OCF & OCF_HitSpeed2)
if (Mass>3) Splash();
fNoAttach=false;
InLiquid=1;
}

View File

@ -24,6 +24,7 @@
#include <C4Effect.h>
#include <C4ObjectInfo.h>
#include <C4Physics.h>
#include <C4PXS.h>
#include <C4ObjectCom.h>
#include <C4Command.h>
#include <C4Viewport.h>
@ -1151,7 +1152,7 @@ void C4Object::AssignDeath(bool fForced)
// Now, it is done for every crew member)
if(pPlr)
if(!pPlr->Crew.ObjectCount())
::GameScript.GRBroadcast(PSF_RelaunchPlayer,
::Game.GRBroadcast(PSF_RelaunchPlayer,
&C4AulParSet(C4VInt(Owner),C4VInt(iDeathCausingPlayer),Status ? C4VObj(this) : C4VNull));
if (pInfo)
pInfo->HasDied = false;
@ -4783,6 +4784,53 @@ bool C4Object::AdjustWalkRotation(int32_t iRangeX, int32_t iRangeY, int32_t iSpe
return true;
}
static void BubbleOut(int32_t tx, int32_t ty)
{
// No bubbles from nowhere
if (!GBackSemiSolid(tx,ty)) return;
// Enough bubbles out there already
if (::Objects.ObjectCount(C4ID::Bubble) >= 150) return;
// Create bubble
Game.CreateObject(C4ID::Bubble,NULL,NO_OWNER,tx,ty);
}
void C4Object::Splash()
{
int32_t tx = GetX(); int32_t ty = GetY()+1;
int32_t amt = std::min(Shape.Wdt*Shape.Hgt/10,20);
// Splash only if there is free space above
if (GBackSemiSolid(tx, ty - 15)) return;
// get back mat
int32_t iMat = GBackMat(tx, ty);
// check liquid
if (MatValid(iMat))
if (DensityLiquid(::MaterialMap.Map[iMat].Density) && ::MaterialMap.Map[iMat].Instable)
{
int32_t sy = ty;
while (GBackLiquid(tx, sy) && sy > ty - 20 && sy >= 0) sy--;
// Splash bubbles and liquid
for (int32_t cnt=0; cnt<amt; cnt++)
{
int32_t bubble_x = tx+Random(16)-8;
int32_t bubble_y = ty+Random(16)-6;
BubbleOut(bubble_x,bubble_y);
if (GBackLiquid(tx,ty) && !GBackSemiSolid(tx, sy))
{
C4Real xdir = C4REAL100(Random(151)-75);
C4Real ydir = C4REAL100(-Random(200));
::PXS.Create(::Landscape.ExtractMaterial(tx,ty,false),
itofix(tx),itofix(sy),
xdir,
ydir);
}
}
}
// Splash sound
if (amt>=20)
StartSoundEffect("Liquids::Splash2", false, 50, this);
else if (amt>1) StartSoundEffect("Liquids::Splash1", false, 50, this);
}
void C4Object::UpdateInLiquid()
{
// InLiquid check
@ -4790,8 +4838,8 @@ void C4Object::UpdateInLiquid()
{
if (!InLiquid) // Enter liquid
{
if (OCF & OCF_HitSpeed2) if (Mass>3)
Splash(GetX(),GetY()+1,std::min(Shape.Wdt*Shape.Hgt/10,20),this);
if (OCF & OCF_HitSpeed2)
if (Mass>3) Splash();
InLiquid=1;
}
}

View File

@ -119,6 +119,7 @@ class C4Object: public C4PropListNumbered
{
private:
void UpdateInMat();
void Splash();
public:
C4Object();
~C4Object();

View File

@ -328,7 +328,7 @@ bool C4Player::Init(int32_t iNumber, int32_t iAtClient, const char *szAtClientNa
{
// player preinit: In case a team needs to be chosen first, no InitializePlayer-broadcast is done
// this callback shall give scripters a chance to do stuff like starting an intro or enabling FoW, which might need to be done
::GameScript.GRBroadcast(PSF_PreInitializePlayer, &C4AulParSet(C4VInt(Number)));
::Game.GRBroadcast(PSF_PreInitializePlayer, &C4AulParSet(C4VInt(Number)));
// direct init
if (Status != PS_TeamSelection) if (!ScenarioInit()) return false;
}
@ -658,7 +658,7 @@ bool C4Player::ScenarioInit()
if (Team) SetTeamHostility();
// Scenario script initialization
::GameScript.GRBroadcast(PSF_InitializePlayer, &C4AulParSet(C4VInt(Number),
::Game.GRBroadcast(PSF_InitializePlayer, &C4AulParSet(C4VInt(Number),
C4VInt(ptx),
C4VInt(pty),
C4VObj(FirstBase),
@ -715,7 +715,7 @@ bool C4Player::SetWealth(int32_t iVal)
Wealth=Clamp<int32_t>(iVal,0,1000000000);
::GameScript.GRBroadcast(PSF_OnWealthChanged,&C4AulParSet(C4VInt(Number)));
::Game.GRBroadcast(PSF_OnWealthChanged,&C4AulParSet(C4VInt(Number)));
return true;
}

View File

@ -227,7 +227,7 @@ bool C4PlayerList::Remove(C4Player *pPlr, bool fDisconnect, bool fNoCalls)
// inform script
if (!fNoCalls)
::GameScript.GRBroadcast(PSF_RemovePlayer, &C4AulParSet(C4VInt(pPlr->Number), C4VInt(pPlr->Team)));
::Game.GRBroadcast(PSF_RemovePlayer, &C4AulParSet(C4VInt(pPlr->Number), C4VInt(pPlr->Team)));
// Transfer ownership of other objects to team members
if (!fNoCalls) pPlr->NotifyOwnedObjects();

View File

@ -371,10 +371,10 @@ public:
~C4AulScriptEngine(); // destructor
void Clear(); // clear data
void Link(C4DefList *rDefs); // link and parse all scripts
void ReLink(C4DefList *rDefs); // unlink + relink and parse all scripts
void ReLink(C4DefList *rDefs); // unlink, link and parse all scripts
virtual C4PropListStatic * GetPropList();
using C4AulScript::ReloadScript;
bool ReloadScript(const char *szScript, C4DefList *pDefs, const char *szLanguage); // search script and reload + relink, if found
bool ReloadScript(const char *szScript, const char *szLanguage); // search script and reload, if found
C4AulFunc * GetFirstFunc(C4String * Name)
{ return FuncLookUp.GetFirstFunc(Name); }
C4AulFunc * GetNextSNFunc(const C4AulFunc * After)

View File

@ -79,14 +79,6 @@ public:
inline bool IsNil() const { return true; }
};
// 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(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

View File

@ -136,14 +136,11 @@ bool C4AulExec::FnLogCallStack(C4PropList * _this)
void C4AulExec::ClearPointers(C4Object * obj)
{
#if 0
// FIXME: reactivate this code and remove the checks from Call once scripts are fixed
for (C4AulScriptContext *pCtx = pCurCtx; pCtx >= Contexts; pCtx--)
{
if (pCtx->Obj == obj)
pCtx->Obj = NULL;
}
#endif
}
C4Value C4AulExec::Exec(C4AulScriptFunc *pSFunc, C4PropList * p, C4Value *pnPars, bool fPassErrors)

View File

@ -42,9 +42,9 @@ bool C4ScriptHost::ResolveAppends(C4DefList *rDefs)
if (State != ASS_PREPARSED) return false;
for (std::list<StdCopyStrBuf>::iterator a = Appends.begin(); a != Appends.end(); ++a)
{
if (*a != "*")
if (*a != "*" || !rDefs)
{
C4Def *Def = rDefs->GetByName(*a);
C4Def *Def = rDefs ? rDefs->GetByName(*a) : NULL;
if (Def)
{
if (std::find(Def->Script.SourceScripts.begin(), Def->Script.SourceScripts.end(), GetScriptHost()) == Def->Script.SourceScripts.end())
@ -93,7 +93,7 @@ bool C4ScriptHost::ResolveIncludes(C4DefList *rDefs)
// append all includes to local script
for (std::list<StdCopyStrBuf>::reverse_iterator i = Includes.rbegin(); i != Includes.rend(); ++i)
{
C4Def *Def = rDefs->GetByName(*i);
C4Def *Def = rDefs ? rDefs->GetByName(*i) : NULL;
if (Def)
{
// resolve #includes in included script first (#include-chains :( )
@ -180,10 +180,8 @@ void C4AulScriptEngine::Link(C4DefList *rDefs)
// engine is always parsed (for global funcs)
State = ASS_PARSED;
// update material pointers
::MaterialMap.UpdateScriptPointers();
rDefs->CallEveryDefinition();
if (rDefs)
rDefs->CallEveryDefinition();
// Done modifying the proplists now
for (C4AulScript *s = Child0; s; s = s->Next)
@ -214,25 +212,14 @@ void C4AulScriptEngine::ReLink(C4DefList *rDefs)
// display state
LogF("C4AulScriptEngine linked - %d line%s, %d warning%s, %d error%s",
lineCnt, (lineCnt != 1 ? "s" : ""), warnCnt, (warnCnt != 1 ? "s" : ""), errCnt, (errCnt != 1 ? "s" : ""));
// update effect pointers
::Objects.UpdateScriptPointers();
// update material pointers
::MaterialMap.UpdateScriptPointers();
}
bool C4AulScriptEngine::ReloadScript(const char *szScript, C4DefList *pDefs, const char *szLanguage)
bool C4AulScriptEngine::ReloadScript(const char *szScript, const char *szLanguage)
{
C4AulScript * s;
for (s = Child0; s; s = s->Next)
if (s->ReloadScript(szScript, szLanguage))
break;
if (!s)
return false;
// relink
ReLink(pDefs);
// ok
return true;
return !!s;
}

View File

@ -199,6 +199,7 @@ private:
void DebugChunk();
void RemoveLastBCC();
C4V_Type GetLastRetType(C4V_Type to); // for warning purposes
void DumpByteCode();
C4AulBCC MakeSetter(bool fLeaveValue = false); // Prepares to generate a setter for the last value that was generated
@ -697,6 +698,89 @@ static const char * GetTTName(C4AulBCCType e)
}
}
void C4AulParse::DumpByteCode()
{
if (DEBUG_BYTECODE_DUMP && Type == PARSER)
{
fprintf(stderr, "%s:\n", Fn->GetName());
std::map<C4AulBCC *, int> labels;
int labeln = 0;
for (C4AulBCC *pBCC = Fn->GetCode(); pBCC->bccType != AB_EOFN; pBCC++)
{
switch (pBCC->bccType)
{
case AB_JUMP: case AB_JUMPAND: case AB_JUMPOR: case AB_JUMPNNIL: case AB_CONDN: case AB_COND:
labels[pBCC + pBCC->Par.i] = ++labeln; break;
default: break;
}
}
for (C4AulBCC *pBCC = Fn->GetCode();; pBCC++)
{
C4AulBCCType eType = pBCC->bccType;
if (labels.find(pBCC) != labels.end())
fprintf(stderr, "%d:\n", labels[pBCC]);
fprintf(stderr, "\t%d\t%s", Fn->GetLineOfCode(pBCC), GetTTName(eType));
if (strlen(GetTTName(eType)) < 8) fprintf(stderr, " ");
switch (eType)
{
case AB_FUNC:
fprintf(stderr, "\t%s\n", pBCC->Par.f->GetName()); break;
case AB_CALL: case AB_CALLFS: case AB_LOCALN: case AB_LOCALN_SET: case AB_PROP: case AB_PROP_SET:
fprintf(stderr, "\t%s\n", pBCC->Par.s->GetCStr()); break;
case AB_STRING:
{
const StdStrBuf &s = pBCC->Par.s->GetData();
std::string es;
std::for_each(s.getData(), s.getData() + s.getLength(), [&es](char c) {
if (std::isgraph((unsigned char)c))
{
es += c;
}
else
{
switch (c)
{
case '\'': es.append("\\'"); break;
case '\"': es.append("\\\""); break;
case '\\': es.append("\\\\"); break;
case '\a': es.append("\\a"); break;
case '\b': es.append("\\b"); break;
case '\f': es.append("\\f"); break;
case '\n': es.append("\\n"); break;
case '\r': es.append("\\r"); break;
case '\t': es.append("\\t"); break;
case '\v': es.append("\\v"); break;
default:
{
std::stringstream hex;
hex << "\\x" << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>((unsigned char)c);
es.append(hex.str());
break;
}
}
}
});
fprintf(stderr, "\t\"%s\"\n", es.c_str()); break;
}
case AB_DEBUG: case AB_NIL: case AB_RETURN:
case AB_PAR: case AB_THIS:
case AB_ARRAYA: case AB_ARRAYA_SET: case AB_ARRAY_SLICE: case AB_ARRAY_SLICE_SET:
case AB_ERR: case AB_EOFN:
assert(!pBCC->Par.X); fprintf(stderr, "\n"); break;
case AB_CARRAY:
fprintf(stderr, "\t%s\n", C4VArray(pBCC->Par.a).GetDataString().getData()); break;
case AB_CPROPLIST:
fprintf(stderr, "\t%s\n", C4VPropList(pBCC->Par.p).GetDataString().getData()); break;
case AB_JUMP: case AB_JUMPAND: case AB_JUMPOR: case AB_JUMPNNIL: case AB_CONDN: case AB_COND:
fprintf(stderr, "\t% -d\n", labels[pBCC + pBCC->Par.i]); break;
default:
fprintf(stderr, "\t% -d\n", pBCC->Par.i); break;
}
if (eType == AB_EOFN) break;
}
}
}
void C4AulScriptFunc::AddBCC(C4AulBCCType eType, intptr_t X, const char * SPos)
{
// store chunk
@ -1487,89 +1571,9 @@ void C4AulParse::Parse_Function()
DebugChunk();
AddBCC(AB_RETURN);
}
DumpByteCode();
// add separator
AddBCC(AB_EOFN);
// dump bytecode
if (DEBUG_BYTECODE_DUMP && Type == PARSER)
{
fprintf(stderr, "%s:\n", Fn->GetName());
std::map<C4AulBCC *, int> labels;
int labeln = 0;
for (C4AulBCC *pBCC = Fn->GetCode(); pBCC->bccType != AB_EOFN; pBCC++)
{
switch (pBCC->bccType)
{
case AB_JUMP: case AB_JUMPAND: case AB_JUMPOR: case AB_JUMPNNIL: case AB_CONDN: case AB_COND:
labels[pBCC + pBCC->Par.i] = ++labeln; break;
default: break;
}
}
for (C4AulBCC *pBCC = Fn->GetCode();; pBCC++)
{
C4AulBCCType eType = pBCC->bccType;
if (labels.find(pBCC) != labels.end())
fprintf(stderr, "%d:\n", labels[pBCC]);
fprintf(stderr, "\t%d\t%s", Fn->GetLineOfCode(pBCC), GetTTName(eType));
switch (eType)
{
case AB_FUNC:
fprintf(stderr, "\t%s\n", pBCC->Par.f->GetName()); break;
case AB_CALL: case AB_CALLFS: case AB_LOCALN: case AB_LOCALN_SET: case AB_PROP: case AB_PROP_SET:
fprintf(stderr, "\t%s\n", pBCC->Par.s->GetCStr()); break;
case AB_STRING:
{
const StdStrBuf &s = pBCC->Par.s->GetData();
std::string es;
std::for_each(s.getData(), s.getData() + s.getLength(), [&es](char c) {
if (std::isgraph((unsigned char)c))
{
es += c;
}
else
{
switch (c)
{
case '\'': es.append("\\'"); break;
case '\"': es.append("\\\""); break;
case '\\': es.append("\\\\"); break;
case '\a': es.append("\\a"); break;
case '\b': es.append("\\b"); break;
case '\f': es.append("\\f"); break;
case '\n': es.append("\\n"); break;
case '\r': es.append("\\r"); break;
case '\t': es.append("\\t"); break;
case '\v': es.append("\\v"); break;
default:
{
std::stringstream hex;
hex << "\\x" << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>((unsigned char)c);
es.append(hex.str());
break;
}
}
}
});
fprintf(stderr, "\t\"%s\"\n", es.c_str()); break;
}
case AB_DEBUG: case AB_NIL: case AB_RETURN:
case AB_PAR: case AB_THIS:
case AB_ARRAYA: case AB_ARRAYA_SET: case AB_ARRAY_SLICE: case AB_ARRAY_SLICE_SET:
case AB_ERR: case AB_EOFN:
assert(!pBCC->Par.X); fprintf(stderr, "\n"); break;
case AB_CARRAY:
fprintf(stderr, "\t%s\n", C4VArray(pBCC->Par.a).GetDataString().getData()); break;
case AB_CPROPLIST:
fprintf(stderr, "\t%s\n", C4VPropList(pBCC->Par.p).GetDataString().getData()); break;
case AB_JUMP: case AB_JUMPAND: case AB_JUMPOR: case AB_JUMPNNIL: case AB_CONDN: case AB_COND:
fprintf(stderr, "\t%d\n", labels[pBCC + pBCC->Par.i]); break;
default:
fprintf(stderr, "\t%d\n", pBCC->Par.i); break;
}
if (eType == AB_EOFN) break;
}
}
// Do not blame this function for script errors between functions
Fn = 0;
Shift();

View File

@ -21,7 +21,6 @@
#include <C4ScriptHost.h>
#include <C4Def.h>
#include <C4GameObjects.h>
/*--- C4ScriptHost ---*/
@ -280,14 +279,4 @@ C4Value C4GameScriptHost::Call(const char *szFunction, C4AulParSet *Pars, bool f
return ScenPropList._getPropList()->Call(szFunction, Pars, fPassError);
}
C4Value C4GameScriptHost::GRBroadcast(const char *szFunction, C4AulParSet *pPars, bool fPassError, bool fRejectTest)
{
// call objects first - scenario script might overwrite hostility, etc...
C4Value vResult = ::Objects.GRBroadcast(szFunction, pPars, fPassError, fRejectTest);
// rejection tests abort on first nonzero result
if (fRejectTest) if (!!vResult) return vResult;
// scenario script call
return Call(szFunction, pPars, fPassError);
}
C4GameScriptHost GameScript;

View File

@ -111,7 +111,6 @@ public:
void Clear();
virtual C4PropListStatic * GetPropList();
C4Value Call(const char *szFunction, C4AulParSet *pPars=0, bool fPassError=false);
C4Value GRBroadcast(const char *szFunction, C4AulParSet *pPars = 0, bool fPassError=false, bool fRejectTest=false); // call function in scenario script and all goals/rules/environment objects
C4Value ScenPropList;
C4Value ScenPrototype;
};

View File

@ -21,8 +21,15 @@
#include "c4group/C4Group.h"
#include "gamescript/C4Script.h"
#include "script/C4Aul.h"
#include "object/C4DefList.h"
#include "script/C4ScriptHost.h"
#include <C4DefList.h>
/* StandaloneStubs.cpp is shared with mape, which has a real implementation of these */
C4Def* C4DefList::GetByName(const StdStrBuf &) {return NULL;}
C4Def * C4DefList::GetDef(int) {return 0;}
int C4DefList::GetDefCount() {return 0;}
void C4DefList::CallEveryDefinition() {}
void C4DefList::ResetIncludeDependencies() {}
void InitializeC4Script()
{
@ -35,7 +42,7 @@ void InitializeC4Script()
C4Value RunLoadedC4Script()
{
// Link script engine (resolve includes/appends, generate code)
ScriptEngine.Link(&::Definitions);
ScriptEngine.Link(NULL);
// Set name list for globals
ScriptEngine.GlobalNamed.SetNameList(&ScriptEngine.GlobalNamedNames);

View File

@ -15,18 +15,15 @@
#include <C4Include.h>
#include <C4Config.h>
#include <C4DefList.h>
#include <C4GameObjects.h>
#include <C4MapScript.h>
#include <C4Material.h>
#include <C4Reloc.h>
#include <C4Aul.h>
#include <C4AulDebug.h>
#include <C4ScriptHost.h>
#include <C4Config.h>
#include <C4Def.h>
#include <C4Log.h>
#include <C4PropList.h>
#include <C4Record.h>
#include <C4Reloc.h>
/* Parts of the ScriptEngine that are normally in C4Globals for initialization order reasons. */
#ifdef _DEBUG
C4Set<C4PropList *> C4PropList::PropLists;
#endif
@ -37,70 +34,18 @@ int32_t C4PropListNumbered::EnumerationIndex = 0;
C4StringTable Strings;
C4AulScriptEngine ScriptEngine;
/* Stubs */
C4Config Config;
C4Config::C4Config() {}
C4Config::~C4Config() {}
const char * C4Config::AtRelativePath(char const*s) {return s;}
C4DefList Definitions;
C4DefList::C4DefList() {}
C4DefList::~C4DefList() {}
C4Def* C4DefList::GetByName(const StdStrBuf &) {return NULL;}
C4Def * C4DefList::GetDef(int) {return 0;}
int C4DefList::GetDefCount() {return 0;}
void C4DefList::CallEveryDefinition() {}
void C4DefList::ResetIncludeDependencies() {}
bool C4DefList::DrawFontImage(const char* szImageTag, C4Facet& rTarget, C4DrawTransform* pTransform) { return false; }
float C4DefList::GetFontImageAspect(const char* szImageTag) { return -1.0f; }
C4MaterialMap MaterialMap;
C4MaterialMap::C4MaterialMap() {}
C4MaterialMap::~C4MaterialMap() {}
void C4MaterialMap::UpdateScriptPointers() {}
C4AulDebug *C4AulDebug::pDebug;
void C4AulDebug::DebugStep(C4AulBCC*,C4Value*) {}
C4GameObjects Objects;
C4GameObjects::C4GameObjects() {}
C4GameObjects::~C4GameObjects() {}
void C4GameObjects::UpdateScriptPointers() {}
void C4GameObjects::Clear(bool) {}
void C4GameObjects::Default() {}
bool C4GameObjects::Remove(C4Object*) {return 0;}
bool C4GameObjects::AssignInfo() {return 0;}
bool C4GameObjects::ValidateOwners() {return 0;}
C4Value C4GameObjects::GRBroadcast(char const*, C4AulParSet*, bool, bool) {return C4Value();}
C4ObjectList::C4ObjectList() {}
C4ObjectList::~C4ObjectList() {}
void C4ObjectList::Default() {}
void C4ObjectList::Clear() {}
void C4ObjectList::InsertLinkBefore(C4ObjectLink*, C4ObjectLink*) {}
void C4ObjectList::InsertLink(C4ObjectLink*, C4ObjectLink*) {}
void C4ObjectList::RemoveLink(C4ObjectLink*) {}
bool C4ObjectList::Add(C4Object*, C4ObjectList::SortType, C4ObjectList*) {return 0;}
bool C4ObjectList::Remove(C4Object*) {return 0;}
bool C4ObjectList::AssignInfo() {return 0;}
bool C4ObjectList::ValidateOwners() {return 0;}
void C4NotifyingObjectList::InsertLinkBefore(C4ObjectLink *pLink, C4ObjectLink *pBefore) {}
void C4NotifyingObjectList::InsertLink(C4ObjectLink*, C4ObjectLink*) {}
void C4NotifyingObjectList::RemoveLink(C4ObjectLink*) {}
C4Reloc Reloc;
bool C4Reloc::Open(C4Group&, char const*) const { return false; }
void C4LSector::Clear() {}
void C4Def::IncludeDefinition(C4Def*) {}
bool EraseItemSafe(const char *szFilename) {return false;}
void AddDbgRec(C4RecordChunkType, const void *, int) {}
C4MapScriptHost MapScript;
C4MapScriptHost::C4MapScriptHost() {}
C4MapScriptHost::~C4MapScriptHost() {}
void C4MapScriptHost::Clear() {}
C4PropListStatic *C4MapScriptHost::GetPropList() {return NULL;}
bool C4MapScriptHost::Load(C4Group &, const char *, const char *, C4LangStringTable *) { return false; }
bool C4MapScriptHost::LoadData(const char *, const char *, C4LangStringTable *) { return false; }
void C4MapScriptHost::AddEngineFunctions() {}

View File

@ -16,7 +16,6 @@
#ifndef INC_C4Value
#define INC_C4Value
#include "C4Id.h"
#include "C4StringTable.h"
// C4Value type
@ -107,8 +106,6 @@ public:
C4AulFunc *_getFunction() const { return Data.Fn; }
C4PropList *_getPropList() const { return Data.PropList; }
// Template versions
bool operator ! () const { return !GetData(); }
inline operator const void* () const { return GetData() ? this : 0; } // To allow use of C4Value in conditions
@ -233,9 +230,6 @@ inline C4Value C4VFunction(C4AulFunc * pFn) { return C4Value(pFn); }
C4Value C4VString(StdStrBuf strString);
C4Value C4VString(const char *strString);
#define C4VFalse C4VBool(false)
#define C4VTrue C4VBool(true)
extern const C4Value C4VNull;
// C4Values can contain data structures that have to maintain their

View File

@ -121,6 +121,7 @@ if (GTEST_FOUND AND GMOCK_FOUND)
aul/AulMathTest.cpp
aul/AulPredefinedFunctionTest.cpp
../src/script/C4ScriptStandaloneStubs.cpp
../src/script/C4ScriptStandalone.cpp
LIBRARIES
libmisc
libc4script)

View File

@ -63,6 +63,6 @@ TEST_F(AulMathTest, Bug1389)
EXPECT_EQ(C4VINT_MAX, RunExpr("-2147483648 - 1"));
// x ± 1 ± 1 is handled differently from x ± 2, yet the result should be
// the same.
EXPECT_EQ(C4VTrue, RunExpr("2147483647 + 1 + 1 == 2147483647 + 2"));
EXPECT_EQ(C4VTrue, RunExpr("-2147483648 - 1 - 1 == -2147483648 - 2"));
EXPECT_EQ(C4Value(true), RunExpr("2147483647 + 1 + 1 == 2147483647 + 2"));
EXPECT_EQ(C4Value(true), RunExpr("-2147483648 - 1 - 1 == -2147483648 - 2"));
}

View File

@ -57,7 +57,7 @@ C4Value AulTest::RunCode(const char *code, bool wrap)
src += ">";
GameScript.LoadData(src.c_str(), wrapped.c_str(), NULL);
ScriptEngine.Link(&::Definitions);
ScriptEngine.Link(NULL);
ScriptEngine.GlobalNamed.SetNameList(&ScriptEngine.GlobalNamedNames);
return GameScript.Call("Main", nullptr, true);
@ -78,8 +78,8 @@ TEST_F(AulTest, ValueReturn)
// Make sure primitive value returns work.
EXPECT_EQ(C4VNull, RunCode("return;"));
EXPECT_EQ(C4VNull, RunExpr("nil"));
EXPECT_EQ(C4VTrue, RunExpr("true"));
EXPECT_EQ(C4VFalse, RunExpr("false"));
EXPECT_EQ(C4Value(true), RunExpr("true"));
EXPECT_EQ(C4Value(false), RunExpr("false"));
EXPECT_EQ(C4VInt(42), RunExpr("42"));
EXPECT_EQ(C4VString("Hello World!"), RunExpr("\"Hello World!\""));
@ -95,3 +95,29 @@ TEST_F(AulTest, ValueReturn)
C4VPropList("a", C4VInt(1), "b", C4VArray()),
RunExpr("{\"a\": 1, \"b\"=[]}"));
}
TEST_F(AulTest, Loops)
{
EXPECT_EQ(C4VInt(5), RunCode("var i = 0; do ++i; while (i < 5); return i;"));
EXPECT_EQ(C4VInt(5), RunCode("var i = 0; while (i < 5) ++i; return i;"));
EXPECT_EQ(C4VInt(5), RunCode("for(var i = 0; i < 5; ++i); return i;"));
EXPECT_EQ(C4VInt(6), RunCode("var i = 0, b; do { b = i++ >= 5; } while (!b); return i;"));
EXPECT_EQ(C4VInt(6), RunCode("var i = 0, b; while (!b) { b = i++ >= 5; } return i;"));
EXPECT_EQ(C4Value(), RunCode("var a = [], sum; for(var i in a) sum += i; return sum;"));
EXPECT_EQ(C4VInt(1), RunCode("var a = [1], sum; for(var i in a) sum += i; return sum;"));
EXPECT_EQ(C4VInt(6), RunCode("var a = [1,2,3], sum; for(var i in a) sum += i; return sum;"));
}
TEST_F(AulTest, Locals)
{
EXPECT_EQ(C4VInt(42), RunCode("local i = 42; func Main() { return i; }", false));
EXPECT_EQ(C4VInt(42), RunCode("local i; func Main() { i = 42; return i; }", false));
EXPECT_EQ(C4VInt(42), RunCode("func Main() { local i = 42; return i; }", false));
EXPECT_EQ(C4VInt(42), RunCode("local i = [42]; func Main() { return i[0]; }", false));
EXPECT_EQ(C4VInt(42), RunCode("local p = { i = 42 }; func Main() { return p.i; }", false));
}
TEST_F(AulTest, Eval)
{
EXPECT_EQ(C4VInt(42), RunExpr("eval(\"42\")"));
}