Merge script branch

qteditor
Günther Brammer 2016-05-15 19:21:26 +02:00
commit d23ffde361
26 changed files with 300 additions and 263 deletions

View File

@ -336,7 +336,7 @@
</xsl:if>
<xsl:if test="position() mod 2=0"><xsl:attribute name="class">dark</xsl:attribute></xsl:if>
<xsl:for-each select="col|literal_col">
<td><xsl:apply-templates select="@colspan|node()"/></td>
<td><xsl:apply-templates select="@colspan|@id|node()"/></td>
</xsl:for-each>
</tr>
</xsl:for-each>

View File

@ -131,14 +131,21 @@
<![CDATA[
(function() {
function navigate(url) {
var urlsplit = url.split("#");
var xhr = new XMLHttpRequest();
xhr.open('GET', url.split("#")[0]);
xhr.open('GET', urlsplit[0]);
xhr.onreadystatechange = function (e) {
if (xhr.readyState === 4) {
var d = parent.document;
var r = xhr.responseText;
d.getElementById("content").innerHTML = r.split('<div id="content">')[1];
d.title = r.slice(r.indexOf("<title>")+7, r.indexOf("</title>"));
if (urlsplit.length > 1) {
var scrolltarget = d.getElementById(urlsplit[1]);
if (scrolltarget) {
scrolltarget.scrollIntoView();
}
}
}
};
xhr.send();

View File

@ -70,23 +70,20 @@ func Activate(object caster, object caster2)
return true;
}
local InvisPSpell =
{
Start = func(object target)
{
local InvisPSpell = new Effect {
Start = func() {
// Save the casters previous visibility
this.visibility = target.Visibility;
this.old_mod = target-&gt;<funclink>GetClrModulation</funclink>();
this.visibility = Target.Visibility;
this.old_mod = Target-&gt;<funclink>GetClrModulation</funclink>();
// Make the caster invisible
target.Visibility = <funclink>VIS_Owner</funclink> | <funclink>VIS_Allies</funclink> | <funclink>VIS_God</funclink>;
Target.Visibility = <funclink>VIS_Owner</funclink> | <funclink>VIS_Allies</funclink> | <funclink>VIS_God</funclink>;
// Semitransparent and slightly blue for owner and allies
target-&gt;SetClrModulation(<funclink>ModulateColor</funclink>(this.old_mod, RGBa(127,127,255,127)));
Target-&gt;SetClrModulation(<funclink>ModulateColor</funclink>(this.old_mod, RGBa(127,127,255,127)));
},
Stop = func(object target)
{
Stop = func() {
// restore previous values
target-&gt;<funclink>SetClrModulation</funclink>(this.old_mod);
target.Visibility = this.visibility;
Target-&gt;<funclink>SetClrModulation</funclink>(this.old_mod);
Target.Visibility = this.visibility;
}
}</code>
<text>In this case, the magic spell object only starts the effect, then deletes itself immediately. The engine ensures that there are no conflicts with multiple effects modifying the visibility: effects are stored in a stack which ensures that effects are always removed in the opposite order of their addition. For this, there are a couple of extra Start and Stop calls to be made which are explained in detail later.</text>
@ -115,11 +112,11 @@ func Activate(object caster, object caster2)
return true;
}
local BanBurnPSpell = {
Construction = func(object target)
local BanBurnPSpell = new Effect {
Construction = func()
{
// On start of the effect: extinguish clonk
target-&gt;<funclink>Extinguish</funclink>();
Target-&gt;<funclink>Extinguish</funclink>();
},
Effect = func(string new_name)
{
@ -131,7 +128,7 @@ local BanBurnPSpell = {
};</code>
<text>This effect makes the clonk fire-proof for 30 seconds. The effect is implemented without any Timer or Stop callbacks as the complete functionality is achieved by simply blocking other effects which might have "Fire" as part of their name. This especially applies to the engine internal fire which has exactly the name "Fire". Of course, you could still add a Timer callback for graphic effects so the player can see that his clonk is immune. Also, you could create special visual effects when preventing incineration in <code>Effect</code>. For the like:</text>
<code>[...]
Effect = func(string new_name, object target, var1, var2, var3, var4)
Effect = func(string new_name, var1, var2, var3, var4)
{
// only handle fire
if (!<funclink>WildcardMatch</funclink>(new_name, &quot;*Fire*&quot;)) return 0;
@ -219,27 +216,25 @@ func Activate(object caster, object caster2)
return true;
}
local ReincarnationPSpell = {
Construction = func(object target)
{
local ReincarnationPSpell = new Effect {
Construction = func() {
// Only at the first start: message
target-&gt;<funclink>Message</funclink>(&quot;%s gets an extra life&quot;, target-&gt;<funclink>GetName</funclink>());
Target-&gt;<funclink>Message</funclink>(&quot;%s gets an extra life&quot;, Target-&gt;<funclink>GetName</funclink>());
return true;
},
func Stop(object target, int reason, bool temporary)
{
func Stop(int reason, bool temporary) {
// only when the clonk died
if (reason != 4) return true;
// the clonk has already been resurrected
if (target-&gt;<funclink>GetAlive</funclink>()) return -1;
if (Target-&gt;<funclink>GetAlive</funclink>()) return -1;
// resurrect clonk
target-&gt;<funclink>SetAlive</funclink>(true);
Target-&gt;<funclink>SetAlive</funclink>(true);
// give energy
target-&gt;<funclink>DoEnergy</funclink>(100);
Target-&gt;<funclink>DoEnergy</funclink>(100);
// message
target-&gt;<funclink>Message</funclink>(&quot;%s has been resurrected.&quot;, target-&gt;<funclink>GetName</funclink>());
Target-&gt;<funclink>Message</funclink>(&quot;%s has been resurrected.&quot;, Target-&gt;<funclink>GetName</funclink>());
// remove
return true;
@ -333,34 +328,39 @@ func FxGravChangeUSpellAdd(object target, proplist effect, string new_name, int
<table>
<caption id="PropertiesTable">Effect Properties</caption>
<rowh>
<col>Data type</col>
<col>Name</col>
<col>Data type</col>
<col>Description</col>
</rowh>
<row>
<col>string</col>
<col><code>Name</code></col>
<col>string</col>
<col>Can be changed.</col>
</row>
<row>
<col>int</col>
<col><code>Priority</code></col>
<col>int</col>
<col>See <a href="Priorities">Priorities</a></col>
</row>
<row>
<col>int</col>
<col><code>Interval</code></col>
<col>int</col>
<col>Of the <a href="#TimerCallback">Timer callback</a>.</col>
</row>
<row>
<col>int</col>
<col><code>Time</code></col>
<col>int</col>
<col>The age of the effect in frames, used for the <a href="#TimerCallback">Timer callback</a>. Can be changed.</col>
</row>
<row>
<col>proplist</col>
<col><code>CommandTarget</code></col>
<col>Either the command object or the command definition, depending on which is used.</col>
<col>proplist</col>
<col><code>nil</code> when created by <funclink>CreateEffect</funclink>, as the effect gets the callbacks itself. When created by <funclink>AddEffect</funclink> either the command object or the command definition, depending on which is used.</col>
</row>
<row>
<col><code>Target</code></col>
<col>proplist</col>
<col>The object the effect belongs to, or the proplists <code>Scenario</code> or <code>Global</code> for scenario and global effects.</col>
</row>
</table>
<h id="UserCallbacks">User Defined Properties</h>
@ -492,16 +492,15 @@ global func FxExplodeOnDeathCurseStop(object target, proplist effect, int reason
<h id="CBRef">Callback Reference</h>
<part>
<text>The following callbacks are made by the engine and should be implemented in your effect prototype as necessary.</text>
<text>All parameters receive the target as their first or second parameter. This is either an object, the <code>Global</code> or the <code>Scenario</code> proplist.</text>
<h>Start</h>
<text><code>int Start (object target, int temporary, any var1, any var2, any var3, any var4);</code></text>
<text>Called at the start of the effect. <code>target</code> is the target object of the effect. <code>this</code> is the effect itself. It can be used to manipulate the effect, for example with <code>this.Interval=newinterval</code>.</text>
<text><code>int Start (int temporary, any var1, any var2, any var3, any var4);</code></text>
<text>Called at the start of the effect. <code>this</code> is the effect itself. It can be used to manipulate the effect, for example with <code>this.Interval=newinterval</code>.</text>
<text>In normal operation the parameter temporary is 0. It is 1 if the effect is re-added after having been temporarily removed and 2 if the effect was temporarily removed and is now to be deleted (in this case a Remove call will follow).</text>
<text>If temporary is 0, var1 to var4 are the additional parameters passed to <funclink>CreateEffect</funclink>().</text>
<text>If temporary is 0 and this callback returns -1 the effect is not created and the corrsponding <funclink>CreateEffect</funclink>() call returns <code>nil</code>.</text>
<h>Stop</h>
<text><code>int Stop (object target, int reason, bool temporary);</code></text>
<text>When the effect is temporarily or permanently removed. target again is the target object and <code>this</code> the effect itself.</text>
<text><code>int Stop (int reason, bool temporary);</code></text>
<text>When the effect is temporarily or permanently removed. <code>this</code> is the effect itself.</text>
<text>reason contains the cause of the removal and can be one of the following values:</text>
<text>
<table>
@ -539,32 +538,32 @@ global func FxExplodeOnDeathCurseStop(object target, proplist effect, int reason
</text>
<text>The effect can prevent removal by returning -1. This will not help, however, in temporary removals or if the target object has been deleted.</text>
<h id="FxConstructionCallback">Construction</h>
<text><code>int Construction (object target, any var1, any var2, any var3, any var4);</code></text>
<text><code>int Construction (any var1, any var2, any var3, any var4);</code></text>
<text>Called when the effect is first created, before it is started. The parameters <code>var1</code> to <code>var4</code> are passed through from <funclink>CreateEffect</funclink>.</text>
<text>The return value is ignored.</text>
<h id="FxDestructionCallback">Destruction</h>
<text><code>nil Destruction (object target, int reason);</code></text>
<text><code>nil Destruction (int reason);</code></text>
<text>Callback when the effect is removed. <code>reason</code> is the same as in the preceding <code>Stop</code> call, see above.</text>
<text>The return value is ignored.</text>
<h id="TimerCallback">Timer</h>
<text><code>int Timer (object target, int time);</code></text>
<text><code>int Timer (int time);</code></text>
<text>Periodic timer call, if a timer interval has been specified at effect creation.</text>
<text>time specifies how long the effect has now been active. This might alternatively be determined using effect.Time.</text>
<text>If this function is not implemented or returns -1, the effect will be deleted after this call.</text>
<h>Effect</h>
<text><code>int Effect (string new_name, object target, any var1, any var2, any var3, any var4);</code></text>
<text><code>int Effect (string new_name, any var1, any var2, any var3, any var4);</code></text>
<text>A call to all effects of higher priority if a new effect is to be added to the same target object. new_name is the name of the new effect; <code>this</code> is the effect being called.</text>
<text>Warning: the new effect is not yet properly initialized and should not be manipulated in any way. Especially the priority field might not yet have been set.</text>
<text>This function can return -1 to reject the new effect. As the new effect might also be rejected by other effects, this callback should not try to add effects or similar (see gravitation spell). Generally you should not try to manipulate any effects during this callback.</text>
<text>Return -2 or -3 to accept the new effect. As long as the new effect is not rejected by any other effect, the <code>Add</code> call is then made to the accepting effect, the new effect is not actually created, and the calling <funclink>CreateEffect</funclink> function returns the accepting effect. The return value -3 will also temporarily remove all higher prioriy effects just before the <code>Add</code> callback and re-add them later.</text>
<text>var1 bis var4 are the parameters passed to <funclink>CreateEffect</funclink>()</text>
<h>Add</h>
<text><code>int Add (object target, string new_name, int new_timer, any var1, any var2, any var3, any var4);</code></text>
<text>Callback to the accepting effect if that has returned -2 or -3 to a prior <code>Effect</code> call. <code>this</code> identifies the accepting effect to which the consequences of the new effect will be added; <code>target</code> is the target object (0 for global effects).</text>
<text><code>int Add (string new_name, int new_timer, any var1, any var2, any var3, any var4);</code></text>
<text>Callback to the accepting effect if that has returned -2 or -3 to a prior <code>Effect</code> call. <code>this</code> identifies the accepting effect to which the consequences of the new effect will be added.</text>
<text>new_timer is the timer interval of the new effect; var1 to var4 are the parameters from AddEffect. Notice: in temporary calls, these parameters are not available - here they will be 0.</text>
<text>If -1 is returned, the accepting effect is deleted also. Logically, the calling <funclink>CreateEffect</funclink> function will then return <code>nil</code>.</text>
<h>Damage</h>
<text><code>int Damage (object target, int damage, int cause, int by_player);</code></text>
<text><code>int Damage (int damage, int cause, int by_player);</code></text>
<text>Every effect receives this callback whenever the energy or damage value of the target object is to change. If the function is defined, it should then return the damage to be done to the target.</text>
<text id="damagecause">This callback is made upon life energy changes in living beings and damage value changes in non-livings - but not vice versa. cause contains the value change and reason:</text>
<text>

View File

@ -6,7 +6,7 @@
<func>
<title>CreateEffect</title>
<category>Effects</category>
<version>5.5 OC</version>
<version>8.0 OC</version>
<syntax>
<rtype>proplist</rtype>
<params>

View File

@ -1,7 +1,7 @@
/*--
Action.c
Authors: Günther
Authors: Günther
Stuff for the proplist changes.
--*/

View File

@ -0,0 +1,19 @@
/*--
Effect.c
Authors: Günther
Prototype for effect prototypes.
--*/
static const Effect = new Global {
Remove = func(bool no_calls) {
return RemoveEffect(nil, nil, this, no_calls);
},
// These properties are set on all effects by the engine.
// They are declared here so that functions on proplists inheriting from this one can use them easily.
Name = nil,
Priority = 0,
Interval = 0,
Target = nil,
Time = 0
};

View File

@ -238,7 +238,7 @@ void C4ControlScript::Execute() const
// execute
C4PropList *pPropList = NULL;
if (iTargetObj == SCOPE_Console)
pPropList = ::GameScript.GetPropList();
pPropList = ::GameScript.ScenPropList.getPropList();
else if (iTargetObj == SCOPE_Global)
pPropList = ::ScriptEngine.GetPropList();
else if (!(pPropList = ::Objects.SafeObjectPointer(iTargetObj)))

View File

@ -725,8 +725,8 @@ bool C4Game::Execute() // Returns true if the game is over
// Game
EXEC_S( ExecObjects(); , ExecObjectsStat )
EXEC_S_DR( C4Effect::Execute(ScriptEngine.GetPropList(), &ScriptEngine.pGlobalEffects);
C4Effect::Execute(GameScript.GetPropList(), &GameScript.pScenarioEffects);
EXEC_S_DR( C4Effect::Execute(&ScriptEngine.pGlobalEffects);
C4Effect::Execute(&GameScript.pScenarioEffects);
, GEStats , "GEEx\0");
EXEC_S_DR( PXS.Execute(); , PXSStat , "PXSEx")
EXEC_S_DR( MassMover.Execute(); , MassMoverStat , "MMvEx")
@ -3487,12 +3487,12 @@ bool C4Game::LoadScenarioSection(const char *szSection, DWORD dwFlags)
// remove global effects
if (::ScriptEngine.pGlobalEffects && !(dwFlags & C4S_KEEP_EFFECTS))
{
::ScriptEngine.pGlobalEffects->ClearAll(NULL, C4FxCall_RemoveClear);
::ScriptEngine.pGlobalEffects->ClearAll(C4FxCall_RemoveClear);
// scenario section call might have been done from a global effect
// rely on dead effect removal for actually removing the effects; do not clear the array here!
}
if (::GameScript.pScenarioEffects && !(dwFlags & C4S_KEEP_EFFECTS))
::GameScript.pScenarioEffects->ClearAll(NULL, C4FxCall_RemoveClear);
::GameScript.pScenarioEffects->ClearAll(C4FxCall_RemoveClear);
// del particles as well
Particles.ClearAllParticles();
// clear transfer zones

View File

@ -53,7 +53,7 @@ C4Effect ** FnGetEffectsFor(C4PropList * pTarget)
{
if (pTarget == ScriptEngine.GetPropList())
return &ScriptEngine.pGlobalEffects;
if (pTarget == GameScript.ScenPrototype.getPropList() || pTarget == GameScript.ScenPropList.getPropList())
if (pTarget == GameScript.ScenPropList.getPropList())
return &GameScript.pScenarioEffects;
C4Object * Obj = pTarget->GetObject();
if (!Obj)

View File

@ -143,11 +143,11 @@ struct StdDecompileAdapt
}
// make this work with in combination with StdParameterAdapt
template<class P>
inline void CompileFunc(StdCompiler* pComp, const P& par) const
template<typename ... P>
inline void CompileFunc(StdCompiler* pComp, P && ... pars) const
{
assert(pComp->isDecompiler());
pComp->Value(mkParAdapt(const_cast<T &>(rValue), par));
pComp->Value(mkParAdapt(const_cast<T &>(rValue), std::forward<P>(pars)...));
}
};
template <class T>
@ -264,10 +264,10 @@ struct _IdFuncClass
template <class T, class M = _IdFuncClass<T> >
struct StdArrayAdapt
{
StdArrayAdapt(T *pArray, int iSize, M map = M())
: pArray(pArray), iSize(iSize), map(map)
StdArrayAdapt(T *pArray, int iSize, M && map = M())
: pArray(pArray), iSize(iSize), map(std::forward<M>(map))
{ }
T *pArray; int iSize; M map;
T *pArray; int iSize; M && map;
inline void CompileFunc(StdCompiler *pComp) const
{
for (int i = 0; i < iSize; i++)
@ -308,7 +308,7 @@ template <class T>
inline StdArrayAdapt<T> mkArrayAdapt(T *pArray, int iSize) { return StdArrayAdapt<T>(pArray, iSize); }
#define mkArrayAdaptM(A) mkArrayAdapt(A, sizeof(A) / sizeof(*(A)))
template <class T, class M>
inline StdArrayAdapt<T, M> mkArrayAdaptMap(T *pArray, int iSize, M map) { return StdArrayAdapt<T, M>(pArray, iSize, map); }
inline StdArrayAdapt<T, M> mkArrayAdaptMap(T *pArray, int iSize, M && map) { return StdArrayAdapt<T, M>(pArray, iSize, std::forward<M>(map)); }
#define mkArrayAdaptMapM(A, M) mkArrayAdaptMap(A, sizeof(A) / sizeof(*(A)), M)
// * Array Adaptor (defaulting)
@ -439,51 +439,54 @@ inline StdInsertAdapt<T, I> mkInsertAdapt(T &&rObj, I &&rIns, bool fBefore = tru
template <class T, class P>
struct StdParameterAdapt
{
StdParameterAdapt(T &rObj, const P &rPar) : rObj(rObj), Par(rPar) { }
T &rObj; const P Par;
StdParameterAdapt(T && rObj, P && rPar) : rObj(std::forward<T>(rObj)), Par(std::forward<P>(rPar)) { }
T && rObj; P && Par;
void CompileFunc(StdCompiler *pComp) const
{
rObj.CompileFunc(pComp, Par);
std::forward<T>(rObj).CompileFunc(pComp, std::forward<P>(Par));
}
// Operators for default checking/setting
template <class D> inline bool operator == (const D &nValue) const { return rObj == nValue; }
template <class D> inline StdParameterAdapt &operator = (const D &nValue) { rObj = nValue; return *this; }
// getting value
inline T &GetObj() { return rObj; }
inline T && GetObj() { return std::forward<T>(rObj); }
};
template <class T, class P>
inline StdParameterAdapt<T, P> mkParAdapt(T &&rObj, const P &rPar) { return StdParameterAdapt<T, P>(rObj, rPar); }
inline StdParameterAdapt<T, P> mkParAdapt(T && rObj, P && rPar)
{ return StdParameterAdapt<T, P>(std::forward<T>(rObj), std::forward<P>(rPar)); }
// for mkArrayAdaptMap
template <class P>
struct StdParameterAdaptMaker
{
const P Par;
StdParameterAdaptMaker(const P &rPar) : Par(rPar) { }
P && Par;
StdParameterAdaptMaker(P && rPar) : Par(std::forward<P>(rPar)) { }
template <class T>
StdParameterAdapt<T, P> operator ()(T &rObj) const { return StdParameterAdapt<T, P>(rObj, Par); }
StdParameterAdapt<T, P> operator ()(T && rObj) const { return StdParameterAdapt<T, P>(std::forward<T>(rObj), std::forward<P>(Par)); }
};
template <class P>
inline StdParameterAdaptMaker<P> mkParAdaptMaker(const P &rPar) { return StdParameterAdaptMaker<P>(rPar); }
inline StdParameterAdaptMaker<P> mkParAdaptMaker(P && rPar) { return StdParameterAdaptMaker<P>(std::forward<P>(rPar)); }
// * Parameter Adaptor 2
// Specify a second and a third parameter for the CompileFunc
template <class T, class P1, class P2>
struct StdParameter2Adapt
{
StdParameter2Adapt(T &rObj, const P1 &rPar1, const P2 &rPar2) : rObj(rObj), rPar1(rPar1), rPar2(rPar2) { }
T &rObj; const P1 &rPar1; const P2 &rPar2;
StdParameter2Adapt(T && rObj, P1 && rPar1, P2 && rPar2) :
rObj(std::forward<T>(rObj)), rPar1(std::forward<P1>(rPar1)), rPar2(std::forward<P2>(rPar2)) { }
T && rObj; P1 && rPar1; P2 && rPar2;
void CompileFunc(StdCompiler *pComp) const
{
rObj.CompileFunc(pComp, rPar1, rPar2);
std::forward<T>(rObj).CompileFunc(pComp, std::forward<P1>(rPar1), std::forward<P2>(rPar2));
}
// Operators for default checking/setting
template <class D> inline bool operator == (const D &nValue) const { return rObj == nValue; }
template <class D> inline StdParameter2Adapt &operator = (const D &nValue) { rObj = nValue; return *this; }
};
template <class T, class P1, class P2>
inline StdParameter2Adapt<T, P1, P2> mkParAdapt(T &rObj, const P1 &rPar1, const P2 &rPar2) { return StdParameter2Adapt<T, P1, P2>(rObj, rPar1, rPar2); }
inline StdParameter2Adapt<T, P1, P2> mkParAdapt(T && rObj, P1 && rPar1, P2 && rPar2)
{ return StdParameter2Adapt<T, P1, P2>(std::forward<T>(rObj), std::forward<P1>(rPar1), std::forward<P2>(rPar2)); }
template <class T>
struct StdBasicPtrAdapt
@ -514,10 +517,10 @@ struct StdPtrAdapt: StdBasicPtrAdapt<T>
}
// For use with StdParAdapt
template<class P>
void CompileFunc(StdCompiler *pComp, const P& p)
template<typename ... P>
void CompileFunc(StdCompiler *pComp, P && ...pars)
{
StdPtrAdaptCompileFunc(pComp, *this, p);
StdPtrAdaptCompileFunc(pComp, *this, std::forward<P>(pars)...);
}
};
@ -543,8 +546,8 @@ struct StdContextPtrAdapt: StdBasicPtrAdapt<T>
}
};
template <class T>
void StdPtrAdaptCompileFunc(StdCompiler* pComp, const T& adapt)
template <class T, typename ... P>
void StdPtrAdaptCompileFunc(StdCompiler* pComp, const T& adapt, P && ...pars)
{
bool fCompiler = pComp->isCompiler(),
fNaming = pComp->hasNaming();
@ -570,68 +573,28 @@ void StdPtrAdaptCompileFunc(StdCompiler* pComp, const T& adapt)
assert(adapt.rpObj);
// Compile value
if(fCompiler)
StdPtrAdaptCompileNewFunc(adapt, pComp);
StdPtrAdaptCompileNewFunc(adapt, pComp, std::forward<P>(pars)...);
else
StdPtrAdaptDecompileNewFunc(adapt, pComp);
StdPtrAdaptDecompileNewFunc(adapt, pComp, std::forward<P>(pars)...);
// Close naming
if(adapt.fAllowNull && fNaming) pComp->NameEnd();
}
// TODO: Avoid code duplication with the above function
template <class T, class P>
void StdPtrAdaptCompileFunc(StdCompiler* pComp, const T& adapt, const P& par)
{
bool fCompiler = pComp->isCompiler(),
fNaming = pComp->hasNaming();
// Compiling? Clear object before
if(fCompiler) { delete adapt.rpObj; adapt.rpObj = NULL; }
// Null checks - different with naming support.
if(adapt.fAllowNull)
if(fNaming)
{
// Null check: just omit when writing
if(!fCompiler && !adapt.rpObj) return;
// Set up naming
if(!pComp->Name(adapt.szNaming)) { assert(fCompiler); pComp->NameEnd(); return; }
}
else
{
bool fNull = !! adapt.rpObj;
pComp->Value(fNull);
// Null? Nothing further to do
if(fNull) return;
}
else if(!fCompiler)
assert(adapt.rpObj);
// Compile value
if(fCompiler)
StdPtrAdaptCompileNewFunc(adapt, pComp, par);
else
StdPtrAdaptDecompileNewFunc(adapt, pComp, par);
// Close naming
if(adapt.fAllowNull && fNaming) pComp->NameEnd();
}
template <class T>
void StdPtrAdaptCompileNewFunc(const StdPtrAdapt<T>& adapt, StdCompiler* pComp) { CompileNewFunc(adapt.rpObj, pComp); }
template <class T, class ContextT>
void StdPtrAdaptCompileNewFunc(const StdContextPtrAdapt<T, ContextT>& adapt, StdCompiler* pComp) { CompileNewFuncCtx(adapt.rpObj, pComp, *adapt.pCtx); }
template <class T, class P>
void StdPtrAdaptCompileNewFunc(const StdPtrAdapt<T>& adapt, StdCompiler* pComp, const P& par) { CompileNewFunc(adapt.rpObj, pComp, par); }
template <class T, class ContextT, class P>
void StdPtrAdaptCompileNewFunc(const StdContextPtrAdapt<T, ContextT>& adapt, StdCompiler* pComp, const P& par) { CompileNewFuncCtx(adapt.rpObj, pComp, *adapt.pCtx, par); }
template <class T, typename ... P>
void StdPtrAdaptCompileNewFunc(const StdPtrAdapt<T>& adapt, StdCompiler* pComp, P && ...pars) { CompileNewFunc(adapt.rpObj, pComp, std::forward<P>(pars)...); }
template <class T, class ContextT, typename ... P>
void StdPtrAdaptCompileNewFunc(const StdContextPtrAdapt<T, ContextT>& adapt, StdCompiler* pComp, P && ...pars) { CompileNewFuncCtx(adapt.rpObj, pComp, *adapt.pCtx, std::forward<P>(pars)...); }
template <class T>
void StdPtrAdaptDecompileNewFunc(const StdPtrAdapt<T>& adapt, StdCompiler* pComp) { pComp->Value(mkDecompileAdapt(*adapt.rpObj)); }
template <class T, class ContextT>
void StdPtrAdaptDecompileNewFunc(const StdContextPtrAdapt<T, ContextT>& adapt, StdCompiler* pComp) { pComp->Value(mkDecompileAdapt(*adapt.rpObj)); }
template <class T, class P>
void StdPtrAdaptDecompileNewFunc(const StdPtrAdapt<T>& adapt, StdCompiler* pComp, const P& par) { pComp->Value(mkParAdapt(mkDecompileAdapt(*adapt.rpObj), par)); }
template <class T, class ContextT, class P>
void StdPtrAdaptDecompileNewFunc(const StdContextPtrAdapt<T, ContextT>& adapt, StdCompiler* pComp, const P& par) { pComp->Value(mkParAdapt(mkDecompileAdapt(*adapt.rpObj), par)); }
template <class T, typename ... P>
void StdPtrAdaptDecompileNewFunc(const StdPtrAdapt<T>& adapt, StdCompiler* pComp, P && ...pars) { pComp->Value(mkParAdapt(mkDecompileAdapt(*adapt.rpObj), std::forward<P>(pars)...)); }
template <class T, class ContextT, typename ... P>
void StdPtrAdaptDecompileNewFunc(const StdContextPtrAdapt<T, ContextT>& adapt, StdCompiler* pComp, P && ...pars) { pComp->Value(mkParAdapt(mkDecompileAdapt(*adapt.rpObj), std::forward<P>(pars)...)); }
template <class T>
inline StdPtrAdapt<T> mkPtrAdapt(T *&rpObj, bool fAllowNull = true) { return StdPtrAdapt<T>(rpObj, fAllowNull); }

View File

@ -63,12 +63,10 @@ public:
else
Ref(Buf2);
}
StdBuf(StdBuf &&Buf2, bool fCopy = false)
StdBuf(StdBuf && Buf2) noexcept
: fRef(true), pData(NULL), iSize(0)
{
if (fCopy)
Copy(Buf2);
else if (!Buf2.isRef())
if (!Buf2.isRef())
Take(std::move(Buf2));
else
Ref(Buf2);
@ -373,11 +371,11 @@ public:
StdCopyBuf(const StdCopyBuf &Buf2, bool fCopy = true)
: StdBuf(Buf2.getRef(), fCopy)
{ }
StdCopyBuf(StdBuf &&Buf2, bool fCopy = false)
: StdBuf(std::move(Buf2), fCopy)
StdCopyBuf(StdBuf & Buf2) noexcept
: StdBuf(std::move(Buf2))
{ }
StdCopyBuf(StdCopyBuf &&Buf2, bool fCopy = false)
: StdBuf(std::move(Buf2), fCopy)
StdCopyBuf(StdCopyBuf &&Buf2) noexcept
: StdBuf(std::move(Buf2))
{ }
// Set by constant data. Copies data by default.
@ -414,8 +412,8 @@ public:
StdStrBuf(const StdStrBuf & Buf2, bool fCopy = true)
: StdBuf(Buf2, fCopy)
{ }
StdStrBuf(StdStrBuf &&Buf2, bool fCopy = false)
: StdBuf(std::move(Buf2), fCopy)
StdStrBuf(StdStrBuf && Buf2) noexcept
: StdBuf(std::move(Buf2))
{ }
// Set by constant data. References data by default, copies if specified.
@ -692,11 +690,11 @@ public:
StdCopyStrBuf(const StdCopyStrBuf &Buf2, bool fCopy = true)
: StdStrBuf(Buf2.getRef(), fCopy)
{ }
StdCopyStrBuf(StdStrBuf &&Buf2, bool fCopy = false)
: StdStrBuf(std::move(Buf2), fCopy)
StdCopyStrBuf(StdStrBuf && Buf2) noexcept
: StdStrBuf(std::move(Buf2))
{ }
StdCopyStrBuf(StdCopyStrBuf &&Buf2, bool fCopy = false)
: StdStrBuf(std::move(Buf2), fCopy)
StdCopyStrBuf(StdCopyStrBuf && Buf2) noexcept
: StdStrBuf(std::move(Buf2))
{ }
// Set by constant data. Copies data if desired.

View File

@ -333,8 +333,8 @@ void CompileNewFunc(T *&pStruct, StdCompiler *pComp)
pStruct = temp.release();
}
template <class T, class P>
void CompileNewFunc(T *&pStruct, StdCompiler *pComp, const P& rPar)
template <class T, typename ... P>
void CompileNewFunc(T *&pStruct, StdCompiler *pComp, P && ... pars)
{
// Create new object.
// If this line doesn't compile, you either have to
@ -343,7 +343,7 @@ void CompileNewFunc(T *&pStruct, StdCompiler *pComp, const P& rPar)
// behaviour is to construct the object from compiler data
std::unique_ptr<T> temp(new T); // exception-safety
// Compile
pComp->Value(mkParAdapt(*temp, rPar));
pComp->Value(mkParAdapt(*temp, std::forward<P>(pars)...));
pStruct = temp.release();
}

View File

@ -363,7 +363,7 @@ void C4Object::AssignRemoval(bool fExitContents)
// remove all effects (extinguishes as well)
if (pEffects)
{
pEffects->ClearAll(this, C4FxCall_RemoveClear);
pEffects->ClearAll(C4FxCall_RemoveClear);
// Effect-callback might actually have deleted the object already
if (!Status) return;
}
@ -1047,7 +1047,7 @@ void C4Object::Execute()
// effects
if (pEffects)
{
C4Effect::Execute(this, &pEffects);
C4Effect::Execute(&pEffects);
if (!Status) return;
}
// Life
@ -1110,7 +1110,7 @@ void C4Object::AssignDeath(bool fForced)
// get death causing player before doing effect calls, because those might meddle around with the flags
int32_t iDeathCausingPlayer = LastEnergyLossCausePlayer;
Alive=0;
if (pEffects) pEffects->ClearAll(this, C4FxCall_RemoveDeath);
if (pEffects) pEffects->ClearAll(C4FxCall_RemoveDeath);
// if the object is alive again, abort here if the kill is not forced
if (Alive && !fForced) return;
// Action
@ -1206,7 +1206,7 @@ void C4Object::DoDamage(int32_t iChange, int32_t iCausedBy, int32_t iCause)
// non-living: ask effects first
if (pEffects && !Alive)
{
pEffects->DoDamage(this, iChange, iCause, iCausedBy);
pEffects->DoDamage(iChange, iCause, iCausedBy);
if (!iChange) return;
}
// Change value
@ -1231,7 +1231,7 @@ void C4Object::DoEnergy(int32_t iChange, bool fExact, int32_t iCause, int32_t iC
if (iChange < 0) UpdatLastEnergyLossCause(iCausedByPlr);
// Living things: ask effects for change first
if (pEffects && Alive)
pEffects->DoDamage(this, iChange, iCause, iCausedByPlr);
pEffects->DoDamage(iChange, iCause, iCausedByPlr);
// Do change
iChange = Clamp<int32_t>(iChange, -Energy, GetPropertyInt(P_MaxEnergy) - Energy);
Energy += iChange;
@ -2326,7 +2326,7 @@ void C4Object::CompileFunc(StdCompiler *pComp, C4ValueNumbers * numbers)
pComp->Value(mkNamingAdapt( Layer, "Layer", C4ObjectPtr::Null ));
pComp->Value(mkNamingAdapt( C4DefGraphicsAdapt(pGraphics), "Graphics", &Def->Graphics ));
pComp->Value(mkNamingPtrAdapt( pDrawTransform, "DrawTransform" ));
pComp->Value(mkParAdapt(mkNamingPtrAdapt( pEffects, "Effects" ), numbers));
pComp->Value(mkParAdapt(mkNamingPtrAdapt( pEffects, "Effects" ), this, numbers));
pComp->Value(mkNamingAdapt( C4GraphicsOverlayListAdapt(pGfxOverlay),"GfxOverlay", (C4GraphicsOverlay *)NULL));
// Serialize mesh instance if we have a mesh graphics

View File

@ -2262,9 +2262,9 @@ static bool FnCreateParticleAtBone(C4Object* Obj, C4String* szName, C4String* sz
{
if(Pos->GetSize() != 3)
throw C4AulExecError("CreateParticleAtBone: Pos is not a three-vector");
x.x = (*Pos)[0].getInt();
x.y = (*Pos)[1].getInt();
x.z = (*Pos)[2].getInt();
x.x = (*Pos).GetItem(0).getInt();
x.y = (*Pos).GetItem(1).getInt();
x.z = (*Pos).GetItem(2).getInt();
}
else { x.x = x.y = x.z = 0.0f; }
@ -2272,9 +2272,9 @@ static bool FnCreateParticleAtBone(C4Object* Obj, C4String* szName, C4String* sz
{
if(Dir->GetSize() != 3)
throw C4AulExecError("CreateParticleAtBone: Dir is not a three-vector");
dir.x = (*Dir)[0].getInt() / 10.0f;
dir.y = (*Dir)[1].getInt() / 10.0f;
dir.z = (*Dir)[2].getInt() / 10.0f;
dir.x = (*Dir).GetItem(0).getInt() / 10.0f;
dir.y = (*Dir).GetItem(1).getInt() / 10.0f;
dir.z = (*Dir).GetItem(2).getInt() / 10.0f;
}
else { dir.x = dir.y = dir.z = 0.0f; }
// Apply the bone transformation to them, to go from bone coordinates

View File

@ -119,13 +119,13 @@ void C4AulScriptEngine::Denumerate(C4ValueNumbers * numbers)
if (pGlobalEffects) pGlobalEffects->Denumerate(numbers);
}
static void GlobalEffectsMergeCompileFunc(StdCompiler *pComp, C4Effect * & pEffects, const char * name, C4ValueNumbers * numbers)
static void GlobalEffectsMergeCompileFunc(StdCompiler *pComp, C4Effect * & pEffects, const char * name, C4PropList * pForObj, C4ValueNumbers * numbers)
{
C4Effect *pOldEffect, *pNextOldEffect=pEffects;
pEffects = NULL;
try
{
pComp->Value(mkParAdapt(mkNamingPtrAdapt(pEffects, name), numbers));
pComp->Value(mkParAdapt(mkNamingPtrAdapt(pEffects, name), pForObj, numbers));
}
catch (...)
{
@ -154,14 +154,14 @@ void C4AulScriptEngine::CompileFunc(StdCompiler *pComp, bool fScenarioSection, C
// loading scenario section: Merge effects
// Must keep old effects here even if they're dead, because the LoadScenarioSection call typically came from execution of a global effect
// and otherwise dead pointers would remain on the stack
GlobalEffectsMergeCompileFunc(pComp, pGlobalEffects, "Effects", numbers);
GlobalEffectsMergeCompileFunc(pComp, GameScript.pScenarioEffects, "ScenarioEffects", numbers);
GlobalEffectsMergeCompileFunc(pComp, pGlobalEffects, "Effects", this, numbers);
GlobalEffectsMergeCompileFunc(pComp, GameScript.pScenarioEffects, "ScenarioEffects", GameScript.ScenPropList._getPropList(), numbers);
}
else
{
// Otherwise, just compile effects
pComp->Value(mkParAdapt(mkNamingPtrAdapt(pGlobalEffects, "Effects"), numbers));
pComp->Value(mkParAdapt(mkNamingPtrAdapt(GameScript.pScenarioEffects, "ScenarioEffects"), numbers));
pComp->Value(mkParAdapt(mkNamingPtrAdapt(pGlobalEffects, "Effects"), this, numbers));
pComp->Value(mkParAdapt(mkNamingPtrAdapt(GameScript.pScenarioEffects, "ScenarioEffects"), GameScript.ScenPropList._getPropList(), numbers));
}
pComp->Value(mkNamingAdapt(*numbers, "Values"));
}

View File

@ -514,6 +514,8 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos)
// Typcheck to determine whether it's an array or a proplist
if(CheckArrayAccess(pStruct, pIndex) == C4V_Array)
{
if (pStruct->_getArray()->IsFrozen())
throw C4AulExecError("array write: array is readonly");
pStruct->_getArray()->SetItem(pIndex->_getInt(), *pValue);
}
else
@ -566,6 +568,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos)
throw C4AulExecError(FormatString("array slice: end index of type %s, int expected", EndIndex.GetTypeName()).getData());
C4ValueArray *pArray = Array._getArray();
if (pArray->IsFrozen()) throw C4AulExecError("array write: array is readonly");
pArray->SetSlice(StartIndex._getInt(), EndIndex._getInt(), Value);
// Set value as result, remove both indices and first copy of value

View File

@ -661,7 +661,7 @@ void C4AulScriptFunc::DumpByteCode()
const StdStrBuf &s = bcc.Par.s->GetData();
std::string es;
std::for_each(s.getData(), s.getData() + s.getLength(), [&es](char c) {
if (std::isgraph((unsigned char)c))
if (std::isprint((unsigned char)c))
{
es += c;
}
@ -2051,8 +2051,7 @@ void C4AulParse::Parse_Expression(int iParentPrio)
C4AulBCCType eCallType = (TokenType == ATT_CALL) ? AB_CALL : AB_CALLFS;
Shift();
// expect identifier of called function now
if (TokenType != ATT_IDTF)
throw C4AulParseError(this, "expecting func name after '->'");
Check(ATT_IDTF, "function name after '->'");
if (Type == PARSER)
{
pName = ::Strings.RegString(Idtf);
@ -2239,6 +2238,8 @@ C4Value C4AulParse::Parse_ConstExpression(C4PropListStatic * parent, C4String *
++size;
}
}
if (Type == PARSER)
r._getArray()->Freeze();
Shift();
break;
}

View File

@ -27,6 +27,7 @@
void C4Effect::AssignCallbackFunctions()
{
C4PropList *p = GetCallbackScript();
if (!p) return;
// compose function names and search them
char fn[C4AUL_MAX_Identifier+1];
sprintf(fn, PSF_FxStart, GetName()); pFnStart = p->GetFunc(fn);
@ -64,6 +65,7 @@ C4Effect::C4Effect(C4Effect **ppEffectList, C4PropList * prototype, int32_t iPri
CommandTarget.Set0();
AcquireNumber();
Register(ppEffectList, iPrio);
SetProperty(P_Name, C4VString(prototype->GetName()));
}
void C4Effect::Register(C4Effect **ppEffectList, int32_t iPrio)
@ -100,6 +102,7 @@ C4Effect * C4Effect::New(C4PropList *pForObj, C4Effect **ppEffectList, C4PropLis
C4Effect * C4Effect::Init(C4PropList *pForObj, int32_t iPrio, const C4Value &rVal1, const C4Value &rVal2, const C4Value &rVal3, const C4Value &rVal4)
{
Target = pForObj;
// ask all effects with higher priority first - except for prio 1 effects, which are considered out of the priority call chain (as per doc)
bool fRemoveUpper = (iPrio != 1);
// note that apart from denying the creation of this effect, higher priority effects may also remove themselves
@ -108,7 +111,7 @@ C4Effect * C4Effect::Init(C4PropList *pForObj, int32_t iPrio, const C4Value &rVa
// so the priority is assigned after this call, marking this effect dead before it's definitely valid
if (fRemoveUpper && pNext)
{
C4Effect * pEffect2 = pNext->Check(pForObj, GetName(), iPrio, iInterval, rVal1, rVal2, rVal3, rVal4);
C4Effect * pEffect2 = pNext->Check(GetName(), iPrio, iInterval, rVal1, rVal2, rVal3, rVal4);
if (pEffect2)
{
// effect denied (iResult = -1), added to an effect (iResult = Number of that effect)
@ -127,22 +130,22 @@ C4Effect * C4Effect::Init(C4PropList *pForObj, int32_t iPrio, const C4Value &rVa
C4AulFunc * pFn;
if (!GetCallbackScript())
{
Call(P_Construction, &C4AulParSet(pForObj, rVal1, rVal2, rVal3, rVal4)).getInt();
Call(P_Construction, &C4AulParSet(rVal1, rVal2, rVal3, rVal4)).getInt();
if (pForObj && !pForObj->Status) return 0;
pFn = GetFunc(P_Start);
}
else
pFn = pFnStart;
if (fRemoveUpper && pNext && pFn)
TempRemoveUpperEffects(pForObj, false, &pLastRemovedEffect);
TempRemoveUpperEffects(false, &pLastRemovedEffect);
// bad things may happen
if (pForObj && !pForObj->Status) return 0; // this will be invalid!
iPriority = iPrio; // validate effect now
if (CallStart(pForObj, 0, rVal1, rVal2, rVal3, rVal4) == C4Fx_Start_Deny)
if (CallStart(0, rVal1, rVal2, rVal3, rVal4) == C4Fx_Start_Deny)
// the effect denied to start: assume it hasn't, and mark it dead
SetDead();
if (fRemoveUpper && pNext && pFn)
TempReaddUpperEffects(pForObj, pLastRemovedEffect);
TempReaddUpperEffects(pLastRemovedEffect);
if (pForObj && !pForObj->Status) return 0; // this will be invalid!
// Update OnFire cache
if (!IsDead() && pForObj && WildcardMatch(C4Fx_AnyFire, GetName()))
@ -238,7 +241,7 @@ int32_t C4Effect::GetCount(const char *szMask, int32_t iMaxPriority)
return iCnt;
}
C4Effect* C4Effect::Check(C4PropList *pForObj, const char *szCheckEffect, int32_t iPrio, int32_t iTimer, const C4Value &rVal1, const C4Value &rVal2, const C4Value &rVal3, const C4Value &rVal4)
C4Effect* C4Effect::Check(const char *szCheckEffect, int32_t iPrio, int32_t iTimer, const C4Value &rVal1, const C4Value &rVal2, const C4Value &rVal3, const C4Value &rVal4)
{
// priority=1: always OK; no callbacks
if (iPrio == 1) return 0;
@ -249,7 +252,7 @@ C4Effect* C4Effect::Check(C4PropList *pForObj, const char *szCheckEffect, int32_
{
if (!pCheck->IsDead() && pCheck->iPriority >= iPrio)
{
int32_t iResult = pCheck->CallEffect(szCheckEffect, pForObj, rVal1, rVal2, rVal3, rVal4);
int32_t iResult = pCheck->CallEffect(szCheckEffect, rVal1, rVal2, rVal3, rVal4);
if (iResult == C4Fx_Effect_Deny)
// effect denied
return (C4Effect*)C4Fx_Effect_Deny;
@ -266,16 +269,16 @@ C4Effect* C4Effect::Check(C4PropList *pForObj, const char *szCheckEffect, int32_
{
// do temp remove calls if desired
if (pAddToEffect->pNext && fDoTempCallsForAdd)
pAddToEffect->TempRemoveUpperEffects(pForObj, false, &pLastRemovedEffect);
pAddToEffect->TempRemoveUpperEffects(false, &pLastRemovedEffect);
C4Value Par1 = C4VString(szCheckEffect), Par2 = C4VInt(iTimer), Par8;
int32_t iResult = pAddToEffect->DoCall(pForObj, PSFS_FxAdd, Par1, Par2, rVal1, rVal2, rVal3, rVal4, Par8).getInt();
int32_t iResult = pAddToEffect->DoCall(Target, PSFS_FxAdd, Par1, Par2, rVal1, rVal2, rVal3, rVal4, Par8).getInt();
// do temp readd calls if desired
if (pAddToEffect->pNext && fDoTempCallsForAdd)
pAddToEffect->TempReaddUpperEffects(pForObj, pLastRemovedEffect);
pAddToEffect->TempReaddUpperEffects(pLastRemovedEffect);
// effect removed by this call?
if (iResult == C4Fx_Start_Deny)
{
pAddToEffect->Kill(pForObj);
pAddToEffect->Kill();
return (C4Effect*)C4Fx_Effect_Annul;
}
else
@ -286,7 +289,7 @@ C4Effect* C4Effect::Check(C4PropList *pForObj, const char *szCheckEffect, int32_
return 0;
}
void C4Effect::Execute(C4PropList *pObj, C4Effect **ppEffectList)
void C4Effect::Execute(C4Effect **ppEffectList)
{
// get effect list
// execute all effects not marked as dead
@ -310,15 +313,15 @@ void C4Effect::Execute(C4PropList *pObj, C4Effect **ppEffectList)
// check timer execution
if (pEffect->iInterval && !(pEffect->iTime % pEffect->iInterval))
{
if (pEffect->CallTimer(pObj, pEffect->iTime) == C4Fx_Execute_Kill)
if (pEffect->CallTimer(pEffect->iTime) == C4Fx_Execute_Kill)
{
// safety: this class got deleted!
if (pObj && !pObj->Status) return;
if (pEffect->Target && !pEffect->Target->Status) return;
// timer function decided to finish it
pEffect->Kill(pObj);
pEffect->Kill();
}
// safety: this class got deleted!
if (pObj && !pObj->Status) return;
if (pEffect->Target && !pEffect->Target->Status) return;
}
// next effect
ppPrevEffect = &pEffect->pNext;
@ -327,66 +330,66 @@ void C4Effect::Execute(C4PropList *pObj, C4Effect **ppEffectList)
}
}
void C4Effect::Kill(C4PropList *pObj)
void C4Effect::Kill()
{
// active?
C4Effect *pLastRemovedEffect=NULL;
if (IsActive())
// then temp remove all higher priority effects
TempRemoveUpperEffects(pObj, false, &pLastRemovedEffect);
TempRemoveUpperEffects(false, &pLastRemovedEffect);
else
// otherwise: temp reactivate before real removal
// this happens only if a lower priority effect removes an upper priority effect in its add- or removal-call
if (iPriority!=1) CallStart(pObj, C4FxCall_TempAddForRemoval, C4Value(), C4Value(), C4Value(), C4Value());
if (iPriority!=1) CallStart(C4FxCall_TempAddForRemoval, C4Value(), C4Value(), C4Value(), C4Value());
// remove this effect
int32_t iPrevPrio = iPriority; SetDead();
if (CallStop(pObj, C4FxCall_Normal, false) == C4Fx_Stop_Deny)
if (CallStop(C4FxCall_Normal, false) == C4Fx_Stop_Deny)
// effect denied to be removed: recover
iPriority = iPrevPrio;
// reactivate other effects
TempReaddUpperEffects(pObj, pLastRemovedEffect);
TempReaddUpperEffects(pLastRemovedEffect);
// Update OnFire cache
if (pObj && WildcardMatch(C4Fx_AnyFire, GetName()))
if (Target && WildcardMatch(C4Fx_AnyFire, GetName()))
if (!Get(C4Fx_AnyFire))
pObj->SetOnFire(false);
Target->SetOnFire(false);
if (IsDead() && !GetCallbackScript())
Call(P_Destruction, &C4AulParSet(pObj, C4FxCall_Normal));
Call(P_Destruction, &C4AulParSet(C4FxCall_Normal));
}
void C4Effect::ClearAll(C4PropList *pObj, int32_t iClearFlag)
void C4Effect::ClearAll(int32_t iClearFlag)
{
// simply remove access all effects recursively, and do removal calls
// this does not regard lower-level effects being added in the removal calls,
// because this could hang the engine with poorly coded effects
if (pNext) pNext->ClearAll(pObj, iClearFlag);
if ((pObj && !pObj->Status) || IsDead()) return;
if (pNext) pNext->ClearAll(iClearFlag);
if ((Target && !Target->Status) || IsDead()) return;
int32_t iPrevPrio = iPriority;
SetDead();
if (CallStop(pObj, iClearFlag, false) == C4Fx_Stop_Deny)
if (CallStop(iClearFlag, false) == C4Fx_Stop_Deny)
{
// this stop-callback might have deleted the object and then denied its own removal
// must not modify self in this case...
if (pObj && !pObj->Status) return;
if (Target && !Target->Status) return;
// effect denied to be removed: recover it
iPriority = iPrevPrio;
}
// Update OnFire cache
if (pObj && WildcardMatch(C4Fx_AnyFire, GetName()) && IsDead())
if (Target && WildcardMatch(C4Fx_AnyFire, GetName()) && IsDead())
if (!Get(C4Fx_AnyFire))
pObj->SetOnFire(false);
Target->SetOnFire(false);
if (IsDead() && !GetCallbackScript())
Call(P_Destruction, &C4AulParSet(pObj, iClearFlag));
Call(P_Destruction, &C4AulParSet(iClearFlag));
}
void C4Effect::DoDamage(C4PropList *pObj, int32_t &riDamage, int32_t iDamageType, int32_t iCausePlr)
void C4Effect::DoDamage(int32_t &riDamage, int32_t iDamageType, int32_t iCausePlr)
{
// ask all effects for damage adjustments
C4Effect *pEff = this;
do
{
if (!pEff->IsDead())
pEff->CallDamage(pObj, riDamage, iDamageType, iCausePlr);
if (pObj && !pObj->Status) return;
pEff->CallDamage(riDamage, iDamageType, iCausePlr);
if (Target && !Target->Status) return;
}
while ((pEff = pEff->pNext) && riDamage);
}
@ -395,56 +398,63 @@ static C4Object * Obj(C4PropList * p) { return p ? p->GetObject() : NULL; }
C4Value C4Effect::DoCall(C4PropList *pObj, const char *szFn, const C4Value &rVal1, const C4Value &rVal2, const C4Value &rVal3, const C4Value &rVal4, const C4Value &rVal5, const C4Value &rVal6, const C4Value &rVal7)
{
C4PropList *p = GetCallbackScript();
if (!p) return Call(szFn, &C4AulParSet(pObj, rVal1, rVal2, rVal3, rVal4, rVal5, rVal6, rVal7));
// old variant
// compose function name
char fn[C4AUL_MAX_Identifier+1];
sprintf(fn, PSF_FxCustom, GetName(), szFn);
return p->Call(fn, &C4AulParSet(Obj(pObj), this, rVal1, rVal2, rVal3, rVal4, rVal5, rVal6, rVal7));
C4PropList * p = GetCallbackScript();
if (!p)
{
C4AulFunc * fn = GetFunc(szFn);
if (fn) return fn->Exec(this, &C4AulParSet(rVal1, rVal2, rVal3, rVal4, rVal5, rVal6, rVal7));
}
else
{
// old variant
// compose function name
C4AulFunc * fn = p->GetFunc(FormatString(PSF_FxCustom, GetName(), szFn).getData());
if (fn) return fn->Exec(p, &C4AulParSet(Obj(pObj), this, rVal1, rVal2, rVal3, rVal4, rVal5, rVal6, rVal7));
}
return C4Value();
}
int C4Effect::CallStart(C4PropList * obj, int temporary, const C4Value &var1, const C4Value &var2, const C4Value &var3, const C4Value &var4)
int C4Effect::CallStart(int temporary, const C4Value &var1, const C4Value &var2, const C4Value &var3, const C4Value &var4)
{
if (!GetCallbackScript())
return Call(P_Start, &C4AulParSet(obj, temporary, var1, var2, var3, var4)).getInt();
return Call(P_Start, &C4AulParSet(temporary, var1, var2, var3, var4)).getInt();
if (pFnStart)
return pFnStart->Exec(GetCallbackScript(), &C4AulParSet(Obj(obj), this, temporary, var1, var2, var3, var4)).getInt();
return pFnStart->Exec(GetCallbackScript(), &C4AulParSet(Obj(Target), this, temporary, var1, var2, var3, var4)).getInt();
return C4Fx_OK;
}
int C4Effect::CallStop(C4PropList * obj, int reason, bool temporary)
int C4Effect::CallStop(int reason, bool temporary)
{
if (!GetCallbackScript())
return Call(P_Stop, &C4AulParSet(obj, reason, temporary)).getInt();
return Call(P_Stop, &C4AulParSet(reason, temporary)).getInt();
if (pFnStop)
return pFnStop->Exec(GetCallbackScript(), &C4AulParSet(Obj(obj), this, reason, temporary)).getInt();
return pFnStop->Exec(GetCallbackScript(), &C4AulParSet(Obj(Target), this, reason, temporary)).getInt();
return C4Fx_OK;
}
int C4Effect::CallTimer(C4PropList * obj, int time)
int C4Effect::CallTimer(int time)
{
if (!GetCallbackScript())
return Call(P_Timer, &C4AulParSet(obj, time)).getInt();
return Call(P_Timer, &C4AulParSet(time)).getInt();
if (pFnTimer)
return pFnTimer->Exec(GetCallbackScript(), &C4AulParSet(Obj(obj), this, time)).getInt();
return pFnTimer->Exec(GetCallbackScript(), &C4AulParSet(Obj(Target), this, time)).getInt();
return C4Fx_Execute_Kill;
}
void C4Effect::CallDamage(C4PropList * obj, int32_t & damage, int damagetype, int plr)
void C4Effect::CallDamage(int32_t & damage, int damagetype, int plr)
{
if (!GetCallbackScript())
{
C4AulFunc *pFn = GetFunc(P_Damage);
if (pFn)
damage = pFn->Exec(this, &C4AulParSet(obj, damage, damagetype, plr)).getInt();
damage = pFn->Exec(this, &C4AulParSet(damage, damagetype, plr)).getInt();
}
else if (pFnDamage)
damage = pFnDamage->Exec(GetCallbackScript(), &C4AulParSet(Obj(obj), this, damage, damagetype, plr)).getInt();
damage = pFnDamage->Exec(GetCallbackScript(), &C4AulParSet(Obj(Target), this, damage, damagetype, plr)).getInt();
}
int C4Effect::CallEffect(const char * effect, C4PropList * obj, const C4Value &var1, const C4Value &var2, const C4Value &var3, const C4Value &var4)
int C4Effect::CallEffect(const char * effect, const C4Value &var1, const C4Value &var2, const C4Value &var3, const C4Value &var4)
{
if (!GetCallbackScript())
return Call(P_Effect, &C4AulParSet(effect, obj, var1, var2, var3, var4)).getInt();
return Call(P_Effect, &C4AulParSet(effect, var1, var2, var3, var4)).getInt();
if (pFnEffect)
return pFnEffect->Exec(GetCallbackScript(), &C4AulParSet(effect, Obj(obj), this, var1, var2, var3, var4)).getInt();
return pFnEffect->Exec(GetCallbackScript(), &C4AulParSet(effect, Obj(Target), this, var1, var2, var3, var4)).getInt();
return C4Fx_OK;
}
@ -462,9 +472,9 @@ void C4Effect::OnObjectChangedDef(C4PropList *pObj)
}
}
void C4Effect::TempRemoveUpperEffects(C4PropList *pObj, bool fTempRemoveThis, C4Effect **ppLastRemovedEffect)
void C4Effect::TempRemoveUpperEffects(bool fTempRemoveThis, C4Effect **ppLastRemovedEffect)
{
if (pObj && !pObj->Status) return; // this will be invalid!
if (Target && !Target->Status) return; // this will be invalid!
// priority=1: no callbacks
if (iPriority == 1) return;
// remove from high to low priority
@ -472,43 +482,44 @@ void C4Effect::TempRemoveUpperEffects(C4PropList *pObj, bool fTempRemoveThis, C4
C4Effect *pEff = pNext;
while (pEff) if (pEff->IsActive()) break; else pEff = pEff->pNext;
// temp remove active effects with higher priority
if (pEff) pEff->TempRemoveUpperEffects(pObj, true, ppLastRemovedEffect);
if (pEff) pEff->TempRemoveUpperEffects(true, ppLastRemovedEffect);
// temp remove this
if (fTempRemoveThis)
{
FlipActive();
// Update OnFire cache
if (pObj && WildcardMatch(C4Fx_AnyFire, GetName()))
if (Target && WildcardMatch(C4Fx_AnyFire, GetName()))
if (!Get(C4Fx_AnyFire))
pObj->SetOnFire(false);
Target->SetOnFire(false);
// temp callbacks only for higher priority effects
if (iPriority!=1) CallStop(pObj, C4FxCall_Temp, true);
if (iPriority!=1) CallStop(C4FxCall_Temp, true);
if (!*ppLastRemovedEffect) *ppLastRemovedEffect = this;
}
}
void C4Effect::TempReaddUpperEffects(C4PropList *pObj, C4Effect *pLastReaddEffect)
void C4Effect::TempReaddUpperEffects(C4Effect *pLastReaddEffect)
{
// nothing to do? - this will also happen if TempRemoveUpperEffects did nothing due to priority==1
if (!pLastReaddEffect) return;
if (pObj && !pObj->Status) return; // this will be invalid!
if (Target && !Target->Status) return; // this will be invalid!
// simply activate all following, inactive effects
for (C4Effect *pEff = pNext; pEff; pEff = pEff->pNext)
{
if (pEff->IsInactiveAndNotDead())
{
pEff->FlipActive();
if (pEff->iPriority!=1) pEff->CallStart(pObj, C4FxCall_Temp, C4Value(), C4Value(), C4Value(), C4Value());
if (pObj && WildcardMatch(C4Fx_AnyFire, pEff->GetName()))
pObj->SetOnFire(true);
if (pEff->iPriority!=1) pEff->CallStart(C4FxCall_Temp, C4Value(), C4Value(), C4Value(), C4Value());
if (Target && WildcardMatch(C4Fx_AnyFire, pEff->GetName()))
Target->SetOnFire(true);
}
// done?
if (pEff == pLastReaddEffect) break;
}
}
void C4Effect::CompileFunc(StdCompiler *pComp, C4ValueNumbers * numbers)
void C4Effect::CompileFunc(StdCompiler *pComp, C4PropList * Owner, C4ValueNumbers * numbers)
{
if (pComp->isCompiler()) Target = Owner;
// read name
pComp->Separator(StdCompiler::SEP_START); // '('
// read priority
@ -559,7 +570,7 @@ void C4Effect::CompileFunc(StdCompiler *pComp, C4ValueNumbers * numbers)
pComp->Value(fNext);
if (!fNext) return;
// read next
pComp->Value(mkParAdapt(mkPtrAdaptNoNull(pNext), numbers));
pComp->Value(mkParAdapt(mkPtrAdaptNoNull(pNext), Owner, numbers));
// denumeration and callback assignment will be done later
}
@ -580,6 +591,8 @@ void C4Effect::SetPropertyByS(C4String * k, const C4Value & to)
case P_Interval: iInterval = to.getInt(); return;
case P_CommandTarget:
throw C4AulExecError("effect: CommandTarget is readonly");
case P_Target:
throw C4AulExecError("effect: Target is readonly");
case P_Time: iTime = to.getInt(); return;
case P_Prototype:
throw new C4AulExecError("effect: Prototype is readonly");
@ -601,6 +614,8 @@ void C4Effect::ResetProperty(C4String * k)
case P_Interval: iInterval = 0; return;
case P_CommandTarget:
throw C4AulExecError("effect: CommandTarget is readonly");
case P_Target:
throw C4AulExecError("effect: Target is readonly");
case P_Time: iTime = 0; return;
case P_Prototype:
throw new C4AulExecError("effect: Prototype is readonly");
@ -619,6 +634,7 @@ bool C4Effect::GetPropertyByS(C4String *k, C4Value *pResult) const
case P_Priority: *pResult = C4VInt(Abs(iPriority)); return true;
case P_Interval: *pResult = C4VInt(iInterval); return true;
case P_CommandTarget: *pResult = CommandTarget; return true;
case P_Target: *pResult = C4Value(Target); return true;
case P_Time: *pResult = C4VInt(iTime); return true;
}
}
@ -635,6 +651,7 @@ C4ValueArray * C4Effect::GetProperties() const
(*a)[i++] = C4VString(&::Strings.P[P_Priority]);
(*a)[i++] = C4VString(&::Strings.P[P_Interval]);
(*a)[i++] = C4VString(&::Strings.P[P_CommandTarget]);
(*a)[i++] = C4VString(&::Strings.P[P_Target]);
(*a)[i++] = C4VString(&::Strings.P[P_Time]);
return a;
}

View File

@ -76,6 +76,7 @@ public:
protected:
C4Value CommandTarget; // target object for script callbacks - if deleted, the effect is removed without callbacks
C4PropList * Target; // target the effect is contained in
// presearched callback functions for faster calling
C4AulFunc *pFnTimer; // timer function Fx%sTimer
C4AulFunc *pFnStart, *pFnStop; // init/deinit-functions Fx%sStart, Fx%sStop
@ -84,18 +85,18 @@ protected:
void AssignCallbackFunctions(); // resolve callback function names
int CallStart(C4PropList * obj, int temporary, const C4Value &var1, const C4Value &var2, const C4Value &var3, const C4Value &var4);
int CallStop(C4PropList * obj, int reason, bool temporary);
int CallTimer(C4PropList * obj, int time);
void CallDamage(C4PropList * obj, int32_t & damage, int damagetype, int plr);
int CallEffect(const char * effect, C4PropList * obj, const C4Value &var1, const C4Value &var2, const C4Value &var3, const C4Value &var4);
int CallStart(int temporary, const C4Value &var1, const C4Value &var2, const C4Value &var3, const C4Value &var4);
int CallStop(int reason, bool temporary);
int CallTimer(int time);
void CallDamage(int32_t & damage, int damagetype, int plr);
int CallEffect(const char * effect, const C4Value &var1, const C4Value &var2, const C4Value &var3, const C4Value &var4);
C4Effect(C4Effect **ppEffectList, C4String * szName, int32_t iPrio, int32_t iTimerInterval, C4PropList * pCmdTarget);
C4Effect(C4Effect **ppEffectList, C4PropList * prototype, int32_t iPrio, int32_t iTimerInterval);
C4Effect(const C4Effect &); // unimplemented, do not use
C4Effect(const C4Effect &) = delete;
C4Effect(); // for the StdCompiler
C4Effect * Init(C4PropList *pForObj, int32_t iPrio, const C4Value &rVal1, const C4Value &rVal2, const C4Value &rVal3, const C4Value &rVal4);
friend void CompileNewFunc<C4Effect, C4ValueNumbers *>(C4Effect *&, StdCompiler *, C4ValueNumbers * const &);
template <class T, typename ... P> friend void CompileNewFunc(T *&, StdCompiler *, P && ...);
public:
static C4Effect * New(C4PropList *pForObj, C4Effect **ppEffectList, C4String * szName, int32_t iPrio, int32_t iTimerInterval, C4PropList * pCmdTarget, const C4Value &rVal1, const C4Value &rVal2, const C4Value &rVal3, const C4Value &rVal4);
static C4Effect * New(C4PropList *pForObj, C4Effect **ppEffectList, C4PropList * prototype, int32_t iPrio, int32_t iTimerInterval, const C4Value &rVal1, const C4Value &rVal2, const C4Value &rVal3, const C4Value &rVal4);
@ -113,13 +114,13 @@ public:
C4Effect *Get(const char *szName, int32_t iIndex=0, int32_t iMaxPriority=0); // get effect by name
int32_t GetCount(const char *szMask, int32_t iMaxPriority=0); // count effects that match the mask
C4Effect *Check(C4PropList *pForObj, const char *szCheckEffect, int32_t iPrio, int32_t iTimer, const C4Value &rVal1, const C4Value &rVal2, const C4Value &rVal3, const C4Value &rVal4); // do some effect callbacks
C4Effect *Check(const char *szCheckEffect, int32_t iPrio, int32_t iTimer, const C4Value &rVal1, const C4Value &rVal2, const C4Value &rVal3, const C4Value &rVal4); // do some effect callbacks
C4PropList * GetCallbackScript(); // get script context for effect callbacks
static void Execute(C4PropList *pObj, C4Effect **ppEffectList); // execute all effects
void Kill(C4PropList *pObj); // mark this effect deleted and do approprioate calls
void ClearAll(C4PropList *pObj, int32_t iClearFlag);// kill all effects doing removal calls w/o reagard of inactive effects
void DoDamage(C4PropList *pObj, int32_t &riDamage, int32_t iDamageType, int32_t iCausePlr); // ask all effects for damage
static void Execute(C4Effect **ppEffectList); // execute all effects
void Kill(); // mark this effect deleted and do approprioate calls
void ClearAll(int32_t iClearFlag);// kill all effects doing removal calls w/o reagard of inactive effects
void DoDamage(int32_t &riDamage, int32_t iDamageType, int32_t iCausePlr); // ask all effects for damage
C4Value DoCall(C4PropList *pObj, const char *szFn, const C4Value &rVal1, const C4Value &rVal2, const C4Value &rVal3, const C4Value &rVal4, const C4Value &rVal5, const C4Value &rVal6, const C4Value &rVal7); // custom call
@ -132,7 +133,7 @@ public:
}
void OnObjectChangedDef(C4PropList *pObj);
void CompileFunc(StdCompiler *pComp, C4ValueNumbers *);
void CompileFunc(StdCompiler *pComp, C4PropList *Owner, C4ValueNumbers *);
virtual C4Effect * GetEffect() { return this; }
virtual void SetPropertyByS(C4String * k, const C4Value & to);
virtual void ResetProperty(C4String * k);
@ -140,8 +141,8 @@ public:
virtual C4ValueArray * GetProperties() const;
protected:
void TempRemoveUpperEffects(C4PropList *pObj, bool fTempRemoveThis, C4Effect **ppLastRemovedEffect); // temp remove all effects with higher priority
void TempReaddUpperEffects(C4PropList *pObj, C4Effect *pLastReaddEffect); // temp remove all effects with higher priority
void TempRemoveUpperEffects(bool fTempRemoveThis, C4Effect **ppLastRemovedEffect); // temp remove all effects with higher priority
void TempReaddUpperEffects(C4Effect *pLastReaddEffect); // temp remove all effects with higher priority
};
// fire effect constants

View File

@ -374,7 +374,7 @@ void C4PropList::RemoveCyclicPrototypes()
}
}
void CompileNewFunc(C4PropList *&pStruct, StdCompiler *pComp, C4ValueNumbers * const & rPar)
void CompileNewFunc(C4PropList *&pStruct, StdCompiler *pComp, C4ValueNumbers * && rPar)
{
std::unique_ptr<C4PropList> temp(C4PropList::New()); // exception-safety
pComp->Value(mkParAdapt(*temp, rPar));

View File

@ -195,7 +195,7 @@ public:
Iterator end() { return Iterator(); }
};
void CompileNewFunc(C4PropList *&pStruct, StdCompiler *pComp, C4ValueNumbers * const & rPar);
void CompileNewFunc(C4PropList *&pStruct, StdCompiler *pComp, C4ValueNumbers * && rPar);
// Proplists that are created during a game and get saved in a savegame
// Examples: Objects, Effects

View File

@ -419,7 +419,7 @@ static bool FnRemoveEffect(C4PropList * _this, C4String *psEffectName, C4PropLis
if (fDoNoCalls)
pEffect->SetDead();
else
pEffect->Kill(pTarget);
pEffect->Kill();
// done, success
return true;
}
@ -436,7 +436,7 @@ static C4Value FnCheckEffect(C4PropList * _this, C4String * psEffectName, C4Prop
C4Effect *pEffect = *FnGetEffectsFor(pTarget);
if (!pEffect) return C4Value();
// let them check
C4Effect * r = pEffect->Check(pTarget, szEffect, iPrio, iTimerInterval, Val1, Val2, Val3, Val4);
C4Effect * r = pEffect->Check(szEffect, iPrio, iTimerInterval, Val1, Val2, Val3, Val4);
if (r == (C4Effect *)C4Fx_Effect_Deny) return C4VInt(C4Fx_Effect_Deny);
if (r == (C4Effect *)C4Fx_Effect_Annul) return C4VInt(C4Fx_Effect_Annul);
return C4VPropList(r);
@ -837,6 +837,7 @@ static Nillable<C4String *> FnGetConstantNameByValue(C4PropList * _this, int val
static bool FnSortArray(C4PropList * _this, C4ValueArray *pArray, bool descending)
{
if (!pArray) throw C4AulExecError("SortArray: no array given");
if (pArray->IsFrozen()) throw C4AulExecError("array sort: array is readonly");
// sort array by its members
pArray->Sort(descending);
return true;
@ -846,6 +847,7 @@ static bool FnSortArrayByProperty(C4PropList * _this, C4ValueArray *pArray, C4St
{
if (!pArray) throw C4AulExecError("SortArrayByProperty: no array given");
if (!prop_name) throw C4AulExecError("SortArrayByProperty: no property name given");
if (pArray->IsFrozen()) throw C4AulExecError("array sort: array is readonly");
// sort array by property
if (!pArray->SortByProperty(prop_name, descending)) throw C4AulExecError("SortArrayByProperty: not all array elements are proplists");
return true;
@ -855,6 +857,7 @@ static bool FnSortArrayByArrayElement(C4PropList * _this, C4ValueArray *pArray,
{
if (!pArray) throw C4AulExecError("SortArrayByArrayElement: no array given");
if (element_index<0) throw C4AulExecError("SortArrayByArrayElement: element index must be >=0");
if (pArray->IsFrozen()) throw C4AulExecError("array sort: array is readonly");
// sort array by array element
if (!pArray->SortByArrayElement(element_index, descending)) throw C4AulExecError("SortArrayByArrayElement: not all array elements are arrays of sufficient length");
return true;

View File

@ -39,7 +39,7 @@ C4Effect ** FnGetEffectsFor(C4PropList * pTarget)
{
if (pTarget == ScriptEngine.GetPropList())
return &ScriptEngine.pGlobalEffects;
if (pTarget == GameScript.ScenPrototype.getPropList() || pTarget == GameScript.ScenPropList.getPropList())
if (pTarget == GameScript.ScenPropList.getPropList())
return &GameScript.pScenarioEffects;
if (pTarget) throw C4AulExecError("Only global and scenario effects are supported");
return &ScriptEngine.pGlobalEffects;

View File

@ -69,6 +69,7 @@ public:
C4Value(const C4Value &nValue) : Data(nValue.Data), NextRef(NULL), Type(nValue.Type)
{ AddDataRef(); }
C4Value(C4Value && nValue) noexcept;
explicit C4Value(bool data): NextRef(NULL), Type(C4V_Bool)
{ Data.Int = data; }
@ -335,5 +336,16 @@ ALWAYS_INLINE void C4Value::Set0()
DelDataRef(oData, oType, NextRef);
}
ALWAYS_INLINE C4Value::C4Value(C4Value && nValue) noexcept:
Data(nValue.Data), NextRef(NULL), Type(nValue.Type)
{
if (Type == C4V_PropList)
{
Data.PropList->AddRef(this);
Data.PropList->DelRef(&nValue, nValue.NextRef);
}
nValue.Type = C4V_Nil; nValue.Data = 0; nValue.NextRef = NULL;
}
#endif

View File

@ -22,18 +22,18 @@
#include "object/C4Object.h"
C4ValueArray::C4ValueArray()
: iSize(0), iCapacity(0), pData(NULL)
: pData(NULL), iSize(0), iCapacity(0), constant(false)
{
}
C4ValueArray::C4ValueArray(int32_t inSize)
: iSize(0), iCapacity(0), pData(NULL)
: pData(NULL), iSize(0), iCapacity(0), constant(false)
{
SetSize(inSize);
}
C4ValueArray::C4ValueArray(const C4ValueArray &ValueArray2)
: iSize(0), iCapacity(0), pData(NULL)
: pData(NULL), iSize(0), iCapacity(0), constant(false)
{
SetSize(ValueArray2.GetSize());
for (int32_t i = 0; i < iSize; i++)
@ -77,6 +77,7 @@ public:
void C4ValueArray::Sort(class C4SortObject &rSort)
{
assert(!constant);
if (rSort.PrepareCache(this))
{
// Initialize position array
@ -110,6 +111,7 @@ struct C4ValueArraySortStringscomp
void C4ValueArray::SortStrings()
{
assert(!constant);
std::stable_sort(pData, pData+iSize, C4ValueArraySortStringscomp());
}
@ -126,6 +128,7 @@ struct C4ValueArraySortcomp
void C4ValueArray::Sort(bool descending)
{
assert(!constant);
// sort by whatever type the values have
std::stable_sort(pData, pData+iSize, C4ValueArraySortcomp());
if (descending) std::reverse(pData, pData+iSize);
@ -146,6 +149,7 @@ struct C4ValueArraySortPropertycomp
bool C4ValueArray::SortByProperty(C4String *prop_name, bool descending)
{
assert(!constant);
// expect this to be an array of proplists and sort by given property
// make sure we're all proplists before
for (int32_t i=0; i<iSize; ++i)
@ -170,6 +174,7 @@ struct C4ValueArraySortArrayElementcomp
bool C4ValueArray::SortByArrayElement(int32_t element_idx, bool descending)
{
assert(element_idx>=0);
assert(!constant);
// expect this to be an array of arrays and sort by given element
// make sure we're all arrays before
for (int32_t i=0; i<iSize; ++i)
@ -189,6 +194,7 @@ C4Value &C4ValueArray::operator[](int32_t iElem)
{
assert(iElem < MaxSize);
assert(iElem >= 0);
assert(!constant);
if (iElem >= iSize && iElem < MaxSize) this->SetSize(iElem + 1);
// out-of-memory? This might not get caught, but it's better than a segfault
assert(iElem < iSize);
@ -198,6 +204,7 @@ C4Value &C4ValueArray::operator[](int32_t iElem)
void C4ValueArray::SetItem(int32_t iElem, const C4Value &Value)
{
assert(!constant);
// enlarge
if (iElem < -iSize)
throw C4AulExecError("array access: index out of range");
@ -214,6 +221,7 @@ void C4ValueArray::SetItem(int32_t iElem, const C4Value &Value)
void C4ValueArray::SetSize(int32_t inSize)
{
if(inSize == iSize) return;
assert(!constant);
// array not larger than allocated memory? Well, just ignore the additional allocated mem then
if (inSize <= iCapacity)

View File

@ -57,6 +57,11 @@ public:
void SetItem(int32_t iElemNr, const C4Value &Value); // interface for script
void SetSize(int32_t inSize); // (enlarge only!)
// for arrays declared in script constants
void Freeze() { constant = true; }
void Thaw() { constant = false; }
bool IsFrozen() const { return constant; }
void Denumerate(C4ValueNumbers *);
// comparison
@ -77,8 +82,9 @@ public:
bool SortByArrayElement(int32_t array_idx, bool descending=false); // checks that this is an array of all arrays and sorts by array elements at index. returns false if an element is not an array or smaller than array_idx+1
private:
int32_t iSize, iCapacity;
C4Value* pData;
int32_t iSize, iCapacity;
bool constant; // if true, this array is not changeable
};
#endif