forked from Mirrors/openclonk
Merge branch 'master' into Controls
commit
9027544c37
|
@ -70,7 +70,6 @@ else()
|
|||
SET(INITIAL_USE_OPEN_AL OFF)
|
||||
endif()
|
||||
option(USE_OPEN_AL "Use OpenAL to play sounds" ${INITIAL_USE_OPEN_AL})
|
||||
option(DEBUGREC "Debug records" OFF)
|
||||
option(OC_BUILD_MULTIPROCESSOR "Use all processor cores to build" OFF)
|
||||
option(WITH_AUTOMATIC_UPDATE "Automatic updates are downloaded from the project website." OFF)
|
||||
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<!DOCTYPE funcs
|
||||
SYSTEM '../../../clonk.dtd'>
|
||||
<?xml-stylesheet type="text/xsl" href="../../../clonk.xsl"?>
|
||||
<funcs>
|
||||
<func>
|
||||
<title>CanInsertMaterial</title>
|
||||
<category>Landscape</category>
|
||||
<subcat>Material</subcat>
|
||||
<version>5.4 OC</version>
|
||||
<syntax>
|
||||
<rtype>bool</rtype>
|
||||
<params>
|
||||
<param>
|
||||
<type>int</type>
|
||||
<name>material_index</name>
|
||||
<desc>Material to test to be inserted (see <funclink>Material</funclink>()).</desc>
|
||||
</param>
|
||||
<param>
|
||||
<type>int</type>
|
||||
<name>x</name>
|
||||
<desc>X insert position or offset</desc>
|
||||
<optional />
|
||||
</param>
|
||||
<param>
|
||||
<type>int</type>
|
||||
<name>y</name>
|
||||
<desc>Y insert position or offset</desc>
|
||||
<optional />
|
||||
</param>
|
||||
<param>
|
||||
<type>proplist</type>
|
||||
<name>out_insertpos</name>
|
||||
<desc>If a writeable proplist is passed, members x and y are filled with the position at which the material would be inserted.</desc>
|
||||
<optional />
|
||||
</param>
|
||||
</params>
|
||||
</syntax>
|
||||
<desc>Tests if a material pixel at the given position can be inserted.</desc>
|
||||
<remark>If the target position already contains material of the same density as the inserted material, the engine will search upwards for a proper insertion position.</remark>
|
||||
<related>
|
||||
<funclink>Material</funclink>
|
||||
</related>
|
||||
</func>
|
||||
<author>Sven2</author><date>2001-11</date>
|
||||
</funcs>
|
|
@ -1,64 +1,58 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<!DOCTYPE funcs
|
||||
SYSTEM '../../../clonk.dtd'>
|
||||
<?xml-stylesheet type="text/xsl" href="../../../clonk.xsl"?>
|
||||
<funcs>
|
||||
<func>
|
||||
<title>InsertMaterial</title>
|
||||
<category>Landscape</category>
|
||||
<subcat>Material</subcat>
|
||||
<version>5.1 OC</version>
|
||||
<syntax>
|
||||
<rtype>bool</rtype>
|
||||
<params>
|
||||
<param>
|
||||
<type>int</type>
|
||||
<name>material_index</name>
|
||||
<desc>Material to be inserted (see <funclink>Material</funclink>()).</desc>
|
||||
</param>
|
||||
<param>
|
||||
<type>int</type>
|
||||
<name>x</name>
|
||||
<desc>X insert position or offset</desc>
|
||||
<optional />
|
||||
</param>
|
||||
<param>
|
||||
<type>int</type>
|
||||
<name>y</name>
|
||||
<desc>Y insert position or offset</desc>
|
||||
<optional />
|
||||
</param>
|
||||
<param>
|
||||
<type>int</type>
|
||||
<name>xdir</name>
|
||||
<desc>horizontal speed of material pixel to be inserted</desc>
|
||||
<optional />
|
||||
</param>
|
||||
<param>
|
||||
<type>int</type>
|
||||
<name>ydir</name>
|
||||
<desc>vertical speed of material pixel to be inserted</desc>
|
||||
<optional />
|
||||
</param>
|
||||
<param>
|
||||
<type>proplist</type>
|
||||
<name>out_insertpos</name>
|
||||
<desc>If a writeable proplist is passed, members x and y are filled with the actual insertion position.</desc>
|
||||
<optional />
|
||||
</param>
|
||||
<param>
|
||||
<type>bool</type>
|
||||
<name>query_only</name>
|
||||
<desc>If set, the material is not actually inserted. Use this if you are only interested if insertion would be possible and where it would take place.</desc>
|
||||
<optional />
|
||||
</param>
|
||||
</params>
|
||||
</syntax>
|
||||
<desc>Inserts a material pixel at the given position and given speed.</desc>
|
||||
<remark>If the target position already contains material of the same density as the inserted material, the engine will search upwards for a proper insertion position. Use the parameter out_insertpos to find out where material was actually inserted.</remark>
|
||||
<related>
|
||||
<funclink>Material</funclink>
|
||||
</related>
|
||||
</func>
|
||||
<author>Sven2</author><date>2001-11</date>
|
||||
</funcs>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<!DOCTYPE funcs
|
||||
SYSTEM '../../../clonk.dtd'>
|
||||
<?xml-stylesheet type="text/xsl" href="../../../clonk.xsl"?>
|
||||
<funcs>
|
||||
<func>
|
||||
<title>InsertMaterial</title>
|
||||
<category>Landscape</category>
|
||||
<subcat>Material</subcat>
|
||||
<version>5.1 OC</version>
|
||||
<syntax>
|
||||
<rtype>bool</rtype>
|
||||
<params>
|
||||
<param>
|
||||
<type>int</type>
|
||||
<name>material_index</name>
|
||||
<desc>Material to be inserted (see <funclink>Material</funclink>()).</desc>
|
||||
</param>
|
||||
<param>
|
||||
<type>int</type>
|
||||
<name>x</name>
|
||||
<desc>X insert position or offset</desc>
|
||||
<optional />
|
||||
</param>
|
||||
<param>
|
||||
<type>int</type>
|
||||
<name>y</name>
|
||||
<desc>Y insert position or offset</desc>
|
||||
<optional />
|
||||
</param>
|
||||
<param>
|
||||
<type>int</type>
|
||||
<name>xdir</name>
|
||||
<desc>horizontal speed of material pixel to be inserted</desc>
|
||||
<optional />
|
||||
</param>
|
||||
<param>
|
||||
<type>int</type>
|
||||
<name>ydir</name>
|
||||
<desc>vertical speed of material pixel to be inserted</desc>
|
||||
<optional />
|
||||
</param>
|
||||
<param>
|
||||
<type>proplist</type>
|
||||
<name>out_insertpos</name>
|
||||
<desc>If a writeable proplist is passed, members x and y are filled with the actual insertion position.</desc>
|
||||
<optional />
|
||||
</param>
|
||||
</params>
|
||||
</syntax>
|
||||
<desc>Inserts a material pixel at the given position and given speed.</desc>
|
||||
<remark>If the target position already contains material of the same density as the inserted material, the engine will search upwards for a proper insertion position.</remark>
|
||||
<related>
|
||||
<funclink>Material</funclink>
|
||||
</related>
|
||||
</func>
|
||||
<author>Sven2</author><date>2001-11</date>
|
||||
</funcs>
|
||||
|
|
|
@ -53,6 +53,7 @@ var swim_comb = swim_down + 1;</code>
|
|||
</example>
|
||||
</examples>
|
||||
<related>
|
||||
<funclink>TransformBone</funclink>
|
||||
<funclink>StopAnimation</funclink>
|
||||
<funclink>SetAnimationPosition</funclink>
|
||||
<funclink>SetAnimationWeight</funclink>
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<!DOCTYPE funcs
|
||||
SYSTEM '../../../clonk.dtd'>
|
||||
<?xml-stylesheet type="text/xsl" href="../../../clonk.xsl"?>
|
||||
<funcs>
|
||||
<func>
|
||||
<title>SetAnimationBoneTransform</title>
|
||||
<category>Animations</category>
|
||||
<version>5.4 OC</version>
|
||||
<syntax>
|
||||
<rtype>int</rtype>
|
||||
<params>
|
||||
<param>
|
||||
<type>int</type>
|
||||
<name>animation_number</name>
|
||||
<desc>Animation number of the animation whose bone transformation to change. The animation must have been created with <funclink>TransformBone</funclink>.</desc>
|
||||
</param>
|
||||
<param>
|
||||
<type>array</type>
|
||||
<name>transformation</name>
|
||||
<desc>An array with 12 entries representing a 3x4 transformation matrix in row-major order. These matrices can be created via <funclink>Trans_Identity</funclink>, <funclink>Trans_Translate</funclink>, <funclink>Trans_Rotate</funclink> and <funclink>Trans_Scale</funclink> or they can be combined via <funclink>Trans_Mul</funclink>.</desc>
|
||||
</param>
|
||||
<param>
|
||||
<type>int</type>
|
||||
<name>attach_number</name>
|
||||
<desc>If given, refers to the number of the attached mesh whose animation to change.</desc>
|
||||
<optional />
|
||||
</param>
|
||||
</params>
|
||||
</syntax>
|
||||
<desc>This function can be used to change the transformation of a bone set with <funclink>TransformBone</funclink>. This allows to create dynamic animations by script. Returns <code>true</code> if the new transformation was set or <code>false</code> if there is no such animation node or it was not created with <funclink>TransformBone</funclink>.</desc>
|
||||
<remark>See the <emlink href="definition/animations.html">animation documentation</emlink> for further explanations of the animation system.</remark>
|
||||
<remark>The transformation passed to this function is not completely arbitrary, in particular it must not have components which skew the mesh along one of the axes. Skewing is not supported by the animation blending system. Skew matrices cannot be produced with one of the Trans_* functions directly, but it can result of the multiplication of a rotation matrix with a rotated scale matrix, e.g. <code><funclink>Trans_Mul</funclink>(<funclink>Trans_Rotate</funclink>(...), <funclink>Trans_Scale(...)</funclink>, <funclink>Trans_Rotate</funclink>(...))</code>. Skewing cannot occur by combining translation and rotation matrices only.</remark>
|
||||
<examples>
|
||||
<example>
|
||||
<code><funclink>SetAnimationBoneTransform</funclink>(animation_number, <funclink>Trans_Rotate</funclink>(<funclink>FrameCounter</funclink>() % 360, 0, 1, 0));</code>
|
||||
<text>Script for a timer to be called each frame: The bone for which the animation with <code>animation_number</code> was started is turning with one revolution per 360 frames.</text>
|
||||
</example>
|
||||
</examples>
|
||||
<related>
|
||||
<funclink>TransformBone</funclink>
|
||||
<funclink>StopAnimation</funclink>
|
||||
</related>
|
||||
</func>
|
||||
<author>Clonk-Karl</author><date>2013-05</date>
|
||||
</funcs>
|
|
@ -20,6 +20,12 @@
|
|||
<name>position</name>
|
||||
<desc>Specifies how to compute the position of the animation. The value needs to be created with one of the "Anim_" animation functions.</desc>
|
||||
</param>
|
||||
<param>
|
||||
<type>int</type>
|
||||
<name>attach_number</name>
|
||||
<desc>If given, refers to the number of the attached mesh whose animation to change.</desc>
|
||||
<optional />
|
||||
</param>
|
||||
</params>
|
||||
</syntax>
|
||||
<desc>Sets a new position for the given animation. Returns <code>true</code> if the new AVP was set or <code>false</code> if there is no such animation with the given number or the number refers to a combination node.</desc>
|
||||
|
|
|
@ -20,6 +20,12 @@
|
|||
<name>weight</name>
|
||||
<desc>Specifies how to compute the weight of the animation in case the animation is combined with another animation in the given slot. The value needs to be created with one of the "Anim_" animation functions.</desc>
|
||||
</param>
|
||||
<param>
|
||||
<type>int</type>
|
||||
<name>attach_number</name>
|
||||
<desc>If given, refers to the number of the attached mesh whose animation to change.</desc>
|
||||
<optional />
|
||||
</param>
|
||||
</params>
|
||||
</syntax>
|
||||
<desc>Sets a new weight for the given animation. Returns <code>true</code> if the new AVP was set or <code>false</code> if there is no such animation with the given number or the refernced node is an animation node.</desc>
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<!DOCTYPE funcs
|
||||
SYSTEM '../../../clonk.dtd'>
|
||||
<?xml-stylesheet type="text/xsl" href="../../../clonk.xsl"?>
|
||||
<funcs>
|
||||
<func>
|
||||
<title>TransformBone</title>
|
||||
<category>Animations</category>
|
||||
<version>5.4 OC</version>
|
||||
<syntax>
|
||||
<rtype>int</rtype>
|
||||
<params>
|
||||
<param>
|
||||
<type>string</type>
|
||||
<name>bone</name>
|
||||
<desc>Name of the bone to be transformed.</desc>
|
||||
</param>
|
||||
<param>
|
||||
<type>array</type>
|
||||
<name>transformation</name>
|
||||
<desc>An array with 12 entries representing a 3x4 transformation matrix in row-major order. These matrices can be created via <funclink>Trans_Identity</funclink>, <funclink>Trans_Translate</funclink>, <funclink>Trans_Rotate</funclink> and <funclink>Trans_Scale</funclink> or they can be combined via <funclink>Trans_Mul</funclink>.</desc>
|
||||
</param>
|
||||
<param>
|
||||
<type>int</type>
|
||||
<name>slot</name>
|
||||
<desc>Slot in the animation stack in which the animation should be inserted. See <emlink href="definition/animations.html">Animations</emlink>.</desc>
|
||||
</param>
|
||||
<param>
|
||||
<type>array</type>
|
||||
<name>weight</name>
|
||||
<desc>Specifies how to compute the weight of the bone transformation in case it is combined with another animation in the given slot. The value needs to be created with one of the "Anim_" animation functions.</desc>
|
||||
</param>
|
||||
<param>
|
||||
<type>int</type>
|
||||
<name>sibling</name>
|
||||
<desc>If the bone transformation is combined with another animation then this refers to the node with which the new node is combined. If not given or <code>nil</code> then the animation is combined with the animation at the top of the slot as returned by <funclink>GetRootAnimation</funclink>.</desc>
|
||||
<optional />
|
||||
</param>
|
||||
</params>
|
||||
</syntax>
|
||||
<desc>This function is very similar to <funclink>PlayAnimation</funclink>. Instead of playing an animation which is pre-defined in the skeleton of the mesh, it allows individual bones to be transformed arbitrarily. The transformation is inserted as a leaf node into the animation tree for the given slot. The return value of this function is the animation number of the animation node inserted which can be used to manipulate or remove the animation later. If there are already animations in the given slot then additionally a combination node is created. This combination node is assigned the returned number plus 1.</desc>
|
||||
<remark>See the <emlink href="definition/animations.html">animation documentation</emlink> for further explanations of the animation system.</remark>
|
||||
<remark>The transformation passed to this function is not completely arbitrary, in particular it must not have components which skew the mesh along one of the axes. Skewing is not supported by the animation blending system. Skew matrices cannot be produced with one of the Trans_* functions directly, but it can result of the multiplication of a rotation matrix with a rotated scale matrix, e.g. <code><funclink>Trans_Mul</funclink>(<funclink>Trans_Rotate</funclink>(...), <funclink>Trans_Scale(...)</funclink>, <funclink>Trans_Rotate</funclink>(...))</code>. Skewing cannot occur by combining translation and rotation matrices only.</remark>
|
||||
<examples>
|
||||
<example>
|
||||
<code><funclink>TransformBone</funclink>("skeleton_arm_upper.R", Trans_Rotate(90, 0, 1, 0), 5, <funclink>Anim_Const</funclink>(1000));</code>
|
||||
<text>Rotates the right arm of a Clonk by 90 degrees around the Y axis (in bone coordinates).</text>
|
||||
</example>
|
||||
</examples>
|
||||
<related>
|
||||
<funclink>PlayAnimation</funclink>
|
||||
<funclink>StopAnimation</funclink>
|
||||
<funclink>SetAnimationBoneTransform</funclink>
|
||||
</related>
|
||||
</func>
|
||||
<author>Clonk-Karl</author><date>2013-05</date>
|
||||
</funcs>
|
|
@ -85,8 +85,8 @@ global func FxDryTimeTimer(object pTarget, effect, int timer)
|
|||
InsertMaterial(Material("Water"),Random(LandscapeWidth()-60)+30,1,Random(7)-3,100+Random(100));
|
||||
return 1;
|
||||
}
|
||||
for(var i=0; i<6+Random(4);i++)
|
||||
ExtractLiquid(310+Random(50),430+Random(10));
|
||||
ExtractLiquidAmount(310+Random(50),430+Random(10),6+Random(4));
|
||||
|
||||
if(!GBackLiquid(335,430))
|
||||
{
|
||||
AddEffect("Rain",nil,100,2);
|
||||
|
|
|
@ -108,8 +108,7 @@ protected func FxIntLiquidDrainStart(object target, proplist effect, int tempora
|
|||
|
||||
protected func FxIntLiquidDrainTimer(object target, proplist effect)
|
||||
{
|
||||
for (var i = 0; i < effect.Strength / 2; i++)
|
||||
ExtractLiquid(AbsX(effect.X), AbsY(effect.Y));
|
||||
ExtractLiquidAmount(AbsX(effect.X), AbsY(effect.Y),effect.Strength / 2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,12 +28,7 @@ private func Melt()
|
|||
private func Freeze()
|
||||
{
|
||||
DoCon(1);
|
||||
var i=2;
|
||||
while(i>0)
|
||||
{
|
||||
ExtractLiquid();
|
||||
i=--i;
|
||||
}
|
||||
ExtractMaterialAmount(0,0,Material("Water"),2);
|
||||
}
|
||||
|
||||
local Collectible = 1;
|
||||
|
|
|
@ -1,6 +1,18 @@
|
|||
/*-- Pipe line --*/
|
||||
/*-- Pipe line
|
||||
|
||||
//Author: ST-DDT
|
||||
Author: ST-DDT
|
||||
--*/
|
||||
|
||||
local Name = "$Name$";
|
||||
|
||||
local ActMap = {
|
||||
Connect = {
|
||||
Prototype = Action,
|
||||
Name = "Connect",
|
||||
Procedure = DFA_CONNECT,
|
||||
NextAction = "Connect"
|
||||
}
|
||||
};
|
||||
|
||||
protected func Initialize()
|
||||
{
|
||||
|
@ -11,19 +23,19 @@ protected func Initialize()
|
|||
return;
|
||||
}
|
||||
|
||||
// Returns true if this object is a functioning pipe.
|
||||
/** Returns true if this object is a functioning pipe. */
|
||||
public func IsPipeLine()
|
||||
{
|
||||
return GetAction() == "Connect";
|
||||
}
|
||||
|
||||
// Returns whether this pipe is connected to an object.
|
||||
/** Returns whether this pipe is connected to an object. */
|
||||
public func IsConnectedTo(object obj)
|
||||
{
|
||||
return GetActionTarget(0) == obj || GetActionTarget(1) == obj;
|
||||
}
|
||||
|
||||
// Returns the object which is connected to obj through this pipe.
|
||||
/** Returns the object which is connected to obj through this pipe. */
|
||||
public func GetConnectedObject(object obj)
|
||||
{
|
||||
if (GetActionTarget(0) == obj)
|
||||
|
@ -50,62 +62,3 @@ private func BreakMessage()
|
|||
line_end->Message("$TxtPipeBroke$");
|
||||
return;
|
||||
}
|
||||
|
||||
local ActMap = {
|
||||
Connect = {
|
||||
Prototype = Action,
|
||||
Name = "Connect",
|
||||
Procedure = DFA_CONNECT,
|
||||
NextAction = "Connect"
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
Extract liquid from barrel
|
||||
@param sznMaterial: Material to extract; Wildcardsupport
|
||||
@param inMaxAmount: Max Amount of Material being extracted
|
||||
@param pnTarget: Object which extracts the liquid
|
||||
@return [irMaterial,irAmount]
|
||||
-irMaterial: Material being extracted
|
||||
-irAmount: Amount being extracted
|
||||
*/
|
||||
public func GetLiquid(string sznMaterial, int inMaxAmount, object pnTarget, bool bWildcard)
|
||||
{
|
||||
var pConnected = GetConnectedObject(pnTarget);
|
||||
if (!pConnected)
|
||||
return ["", 0];
|
||||
var aMat = pConnected->~LiquidOutput(sznMaterial, inMaxAmount, pnTarget, this, bWildcard);
|
||||
//Bad script? Not needed.
|
||||
if (GetType(aMat) != C4V_Array)
|
||||
return [-1, 0];
|
||||
//Verify data
|
||||
if ((aMat[0] == "") || (GetLength(aMat) == 1))
|
||||
aMat[1] = 0;
|
||||
//Nothing is nothing
|
||||
if (aMat[1] <= 0)
|
||||
{
|
||||
aMat[0] = "";
|
||||
aMat[1] = 0;
|
||||
} //Bad script end
|
||||
return aMat;
|
||||
}
|
||||
|
||||
/**
|
||||
Insert liquid to barrel
|
||||
@param sznMaterial: Material to insert
|
||||
@param inMaxAmount: Max Amount of Material being inserted
|
||||
@param pnSource: Object which inserts the liquid
|
||||
@return inAmount: The inserted amount
|
||||
*/
|
||||
public func PutLiquid(string sznMaterial, int inMaxAmount, object pnSource)
|
||||
{
|
||||
var pConnected = GetConnectedObject(pnSource);
|
||||
if (!pConnected)
|
||||
return 0;
|
||||
if (sznMaterial == "")
|
||||
return 0;
|
||||
return BoundBy(pConnected->~LiquidInput(sznMaterial, inMaxAmount, pnSource, this), 0, inMaxAmount);
|
||||
}
|
||||
|
||||
local Name = "$Name$";
|
||||
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
/*-- Pipe --*/
|
||||
/*-- Pipe
|
||||
|
||||
//Author: ST-DDT
|
||||
Author: ST-DDT
|
||||
--*/
|
||||
|
||||
local Name = "$Name$";
|
||||
local Description = "$Description$";
|
||||
local UsageHelp = "$UsageHelp$";
|
||||
local Collectible = 1;
|
||||
local Rebuy = true;
|
||||
|
||||
protected func Hit()
|
||||
{
|
||||
|
@ -11,17 +18,13 @@ public func IsToolProduct() { return true; }
|
|||
|
||||
/*-- Line connection --*/
|
||||
|
||||
// Called with double dig: will connect power line to building at the clonk's position.
|
||||
/** Will connect power line to building at the clonk's position. */
|
||||
protected func ControlUse(object clonk, int x, int y)
|
||||
{
|
||||
// Is this already connected to a liquid pump?
|
||||
if (FindObject(Find_PipeLine()))
|
||||
if (FindObject(Find_Func("IsConnectedTo",this)))
|
||||
return false;
|
||||
// Only use if clonk is walking.
|
||||
if (!clonk->IsWalking())
|
||||
return true;
|
||||
// Clonk should stand still.
|
||||
clonk->SetComDir(COMD_Stop);
|
||||
|
||||
// Is there an object which accepts power lines?
|
||||
var liquid_pump = FindObject(Find_AtPoint(), Find_Func("IsLiquidPump"));
|
||||
// No liquid pump, display message.
|
||||
|
@ -30,96 +33,33 @@ protected func ControlUse(object clonk, int x, int y)
|
|||
clonk->Message("$MsgNoNewPipe$");
|
||||
return true;
|
||||
}
|
||||
|
||||
// already two pipes connected
|
||||
if(liquid_pump->GetSource() && liquid_pump->GetDrain())
|
||||
{
|
||||
clonk->Message("$MsgHasPipes$");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create and connect pipe.
|
||||
var pipe;
|
||||
var pipe = CreateObject(PipeLine, 0, 0, NO_OWNER);
|
||||
pipe->SetActionTargets(this, liquid_pump);
|
||||
Sound("Connect");
|
||||
|
||||
// If liquid pump has no source yet, create one.
|
||||
if (!liquid_pump->GetSource())
|
||||
{
|
||||
pipe = CreateObject(PipeLine, 0, 0, NO_OWNER);
|
||||
pipe->SetActionTargets(this, liquid_pump);
|
||||
liquid_pump->SetSource(pipe);
|
||||
Sound("Connect");
|
||||
clonk->Message("$MsgCreatedSource$");
|
||||
return true;
|
||||
}
|
||||
// Otherwise if liquid pump has no drain, create one.
|
||||
if (!liquid_pump->GetDrain())
|
||||
else
|
||||
{
|
||||
pipe = CreateObject(PipeLine, 0, 0, NO_OWNER);
|
||||
pipe->SetActionTargets(this, liquid_pump);
|
||||
liquid_pump->SetDrain(pipe);
|
||||
Sound("Connect");
|
||||
clonk->Message("$MsgCreatedDrain$");
|
||||
return true;
|
||||
}
|
||||
// Otherwise do nothing and notify player.
|
||||
clonk->Message("MsgHasPipes");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Finds all pipe lines connected to obj (can be nil in local calls).
|
||||
private func Find_PipeLine(object obj)
|
||||
{
|
||||
if (!obj)
|
||||
obj = this;
|
||||
return [C4FO_Func, "IsConnectedTo", obj];
|
||||
}
|
||||
|
||||
/**
|
||||
Extract liquid from this
|
||||
@param sznMaterial: Material to extract. 0 or "*" for any material.
|
||||
@param inMaxAmount: Max Amount of Material being extracted
|
||||
@param pnPump: Object which extracts the liquid
|
||||
@param pnPipe: Pipe which extracts the liquid (connected to pnPump)
|
||||
@param bnWildcard: Usefull to extract random liquids; use '*' for sznMaterial for all Materials
|
||||
@return [irMaterial,irAmount]
|
||||
-irMaterial: Material being extracted
|
||||
-irAmount: Amount being extracted
|
||||
*/
|
||||
public func LiquidOutput(string sznMaterial, int inMaxAmount, object pnPump, object pnPipe, bool bnWildcard)
|
||||
{
|
||||
var itMaterial;
|
||||
//Search liquid to pump
|
||||
if (bnWildcard)
|
||||
{
|
||||
itMaterial = GetMaterial();
|
||||
//nothing?
|
||||
if (itMaterial == -1)
|
||||
return ["", 0];
|
||||
//no liquid?
|
||||
if (GetMaterialVal("Density", "Material", itMaterial) != 25)
|
||||
return ["", 0];
|
||||
//wrong liquid?
|
||||
if (sznMaterial)
|
||||
if (!WildcardMatch(MaterialName(itMaterial),sznMaterial))
|
||||
return ["", 0];
|
||||
sznMaterial = MaterialName(itMaterial);
|
||||
}
|
||||
else
|
||||
itMaterial = Material(sznMaterial);
|
||||
if (GetMaterial() != itMaterial)
|
||||
return ["", 0];
|
||||
var itFound = ExtractMaterialAmount(0, 0, itMaterial, 5);
|
||||
return [sznMaterial, itFound];
|
||||
}
|
||||
|
||||
/**
|
||||
Insert liquid to this
|
||||
@param sznMaterial: Material to insert
|
||||
@param inMaxAmount: Max Amount of Material being inserted
|
||||
@param pnPump: Object which inserts the liquid
|
||||
@param pnPipe: Pipe which inserts the liquid (connected to pnPump)
|
||||
@return irAmount: The inserted amount
|
||||
*/
|
||||
public func LiquidInput(string sznMaterial, int inMaxAmount, object pnPump, object pnPipe)
|
||||
{
|
||||
var i=Max(0,inMaxAmount),itMaterial=Material(sznMaterial), n_inserted;
|
||||
while (i--) if (InsertMaterial(itMaterial)) ++n_inserted; else break;
|
||||
return n_inserted;
|
||||
}
|
||||
|
||||
local Name = "$Name$";
|
||||
local Description = "$Description$";
|
||||
local UsageHelp = "$UsageHelp$";
|
||||
local Collectible = 1;
|
||||
local Rebuy = true;
|
||||
|
|
|
@ -450,6 +450,12 @@ global func MakePowerProducer(int amount /* the amount of power to produce const
|
|||
return (Library_Power->GetPowerHelperForObject(this))->AddPowerProducer(this, amount);
|
||||
}
|
||||
|
||||
/** Turns the power producer into an object that does not produce power */
|
||||
global func UnmakePowerProducer()
|
||||
{
|
||||
MakePowerProducer(0);
|
||||
}
|
||||
|
||||
// returns true if the current power balance is bigger or equal amount
|
||||
global func IsPowerAvailable(int amount)
|
||||
{
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 286 KiB |
Binary file not shown.
|
@ -0,0 +1,25 @@
|
|||
// pumpJack genrated by blender2ogre 0.6.0
|
||||
|
||||
material pumpJack
|
||||
{
|
||||
receive_shadows on
|
||||
|
||||
technique
|
||||
{
|
||||
pass pumpJack
|
||||
{
|
||||
ambient 0.5 0.5 0.5 1.0
|
||||
diffuse 1 1 1 1.0
|
||||
specular 0.5 0.5 0.5 1.0 12.5
|
||||
emissive 0.0 0.0 0.0 1.0
|
||||
|
||||
texture_unit
|
||||
{
|
||||
texture pumpjack.png
|
||||
tex_address_mode wrap
|
||||
scale 1.0 1.0
|
||||
colour_op modulate
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,12 @@
|
|||
/*--
|
||||
Pump
|
||||
Author: Maikel, ST-DDT, Sven2
|
||||
Author: Maikel, ST-DDT, Sven2, Newton
|
||||
|
||||
Pumps liquids using drain and source pipes. Features include:
|
||||
+ switch on and off
|
||||
+ consume/produce a variable amount of power depending on the height of
|
||||
source and drain
|
||||
|
||||
Pumps liquids using drain and source pipes.
|
||||
--*/
|
||||
|
||||
#include Library_Structure
|
||||
|
@ -10,51 +14,114 @@
|
|||
#include Library_PowerConsumer
|
||||
#include Library_PowerProducer
|
||||
|
||||
local current_pump_power; // Current power needed for pumping. Negative if power is being produced.
|
||||
local Name = "$Name$";
|
||||
local Description = "$Description$";
|
||||
local BlastIncinerate = 50;
|
||||
local HitPoints = 70;
|
||||
|
||||
// This object is a liquid pump, thus pipes can be connected.
|
||||
/*
|
||||
States
|
||||
"Wait": turned off or source pipe not connected
|
||||
"WaitForPower": turned on but no power (does consume power)
|
||||
"WaitForLiquid": turned on but no liquid (does not consume power)
|
||||
"Pump": currently working and consuming/producing power
|
||||
|
||||
*/
|
||||
local ActMap = {
|
||||
Pump = {
|
||||
Prototype = Action,
|
||||
Name = "Pump",
|
||||
Length = 30,
|
||||
Delay = 3,
|
||||
NextAction = "Pump",
|
||||
StartCall = "CheckState",
|
||||
PhaseCall = "Pumping"
|
||||
},
|
||||
Wait = {
|
||||
Prototype = Action,
|
||||
Name = "Wait",
|
||||
Delay = 90,
|
||||
NextAction = "Wait",
|
||||
EndCall = "CheckState"
|
||||
},
|
||||
WaitForPower = {
|
||||
Prototype = Action,
|
||||
Name = "WaitForPower",
|
||||
Delay = 30,
|
||||
NextAction = "WaitForPower",
|
||||
EndCall = "CheckState"
|
||||
},
|
||||
WaitForLiquid = {
|
||||
Prototype = Action,
|
||||
Name = "WaitForLiquid",
|
||||
Delay = 30,
|
||||
NextAction = "WaitForLiquid",
|
||||
EndCall = "CheckState"
|
||||
}
|
||||
};
|
||||
|
||||
local animation; // animation handle
|
||||
|
||||
local switched_on; // controlled by Interaction. Indicates whether the user wants to pump or not
|
||||
|
||||
local powered; // whether the pump has enough power as a consumer, always true if producing
|
||||
local power_used; // the amount of power currently consumed or (if negative) produced
|
||||
|
||||
local stored_material_index; //contained liquid
|
||||
local stored_material_amount;
|
||||
|
||||
local source_pipe;
|
||||
local drain_pipe;
|
||||
|
||||
/** This object is a liquid pump, thus pipes can be connected. */
|
||||
public func IsLiquidPump() { return true; }
|
||||
|
||||
public func Construction(object creator)
|
||||
func Definition(def)
|
||||
{
|
||||
return _inherited(creator, ...);
|
||||
// for title image
|
||||
SetProperty("PictureTransformation",Trans_Rotate(50,0,1,0),def);
|
||||
// for building preview
|
||||
SetProperty("MeshTransformation",Trans_Rotate(50,0,1,0),def);
|
||||
}
|
||||
|
||||
protected func Initialize()
|
||||
func Construction()
|
||||
{
|
||||
turned_on = true;
|
||||
SetAction("Wait");
|
||||
CheckCurrentState();
|
||||
return;
|
||||
// Rotate at a 45 degree angle towards viewer and add a litte bit of Random
|
||||
this.MeshTransformation = Trans_Rotate(50 + RandomX(-10,10),0,1,0);
|
||||
}
|
||||
|
||||
func Initialize()
|
||||
{
|
||||
switched_on = true;
|
||||
var start = 0;
|
||||
var end = GetAnimationLength("pump");
|
||||
animation = PlayAnimation("pump", 5, Anim_Linear(GetAnimationPosition(animation), start, end, 35, ANIM_Loop), Anim_Const(1000));
|
||||
SetState("Wait");
|
||||
}
|
||||
|
||||
/*-- Interaction --*/
|
||||
|
||||
local turned_on;
|
||||
|
||||
public func IsInteractable() { return GetCon() >= 100; }
|
||||
|
||||
public func GetInteractionMetaInfo(object clonk)
|
||||
{
|
||||
if (turned_on)
|
||||
if (switched_on)
|
||||
return { Description = "$MsgTurnOff$", IconName = nil, IconID = Icon_Stop };
|
||||
return { Description = "$MsgTurnOn$", IconName = nil, IconID = Icon_Play };
|
||||
else
|
||||
return { Description = "$MsgTurnOn$", IconName = nil, IconID = Icon_Play };
|
||||
}
|
||||
|
||||
// On interaction the pump can be turned on or off.
|
||||
/** Turn on or off. */
|
||||
public func Interact(object clonk)
|
||||
{
|
||||
turned_on = !turned_on;
|
||||
CheckCurrentState();
|
||||
switched_on = !switched_on;
|
||||
CheckState();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*-- Pipe connection --*/
|
||||
|
||||
local source_pipe;
|
||||
local drain_pipe;
|
||||
|
||||
// Set-Getters for source and drain pipe.
|
||||
public func GetSource() { return source_pipe; }
|
||||
public func SetDrain(object pipe) { drain_pipe = pipe; }
|
||||
public func GetDrain() { return drain_pipe; }
|
||||
|
@ -62,9 +129,11 @@ public func GetDrain() { return drain_pipe; }
|
|||
public func SetSource(object pipe)
|
||||
{
|
||||
source_pipe = pipe;
|
||||
CheckCurrentState();
|
||||
CheckState();
|
||||
}
|
||||
|
||||
/*-- Power stuff --*/
|
||||
|
||||
func QueryWaivePowerRequest()
|
||||
{
|
||||
// has less priority than other objects, but not too low
|
||||
|
@ -73,333 +142,256 @@ func QueryWaivePowerRequest()
|
|||
|
||||
func OnNotEnoughPower()
|
||||
{
|
||||
// assert: current action is "Pump" or "PumpWaitLiquid"
|
||||
SetActionKeepPhase("PumpWaitPower");
|
||||
return _inherited(...);
|
||||
_inherited(...);
|
||||
powered = false;
|
||||
CheckState();
|
||||
}
|
||||
|
||||
func OnEnoughPower()
|
||||
{
|
||||
// assert: current action is either PumpWaitPower or Wait
|
||||
SetActionKeepPhase("Pump");
|
||||
return _inherited(...);
|
||||
}
|
||||
|
||||
func PumpWaitPowerStart() { return AddTimer(this.PumpingWaitForPower, 60); }
|
||||
func PumpWaitPowerStop() { return RemoveTimer(this.PumpingWaitForPower); }
|
||||
|
||||
func PumpingWaitForPower()
|
||||
{
|
||||
// Waiting for power: Check pump height, because we might become a producer
|
||||
if (!source_pipe) return CheckCurrentState();
|
||||
if (last_source_y != (source_pipe->GetConnectedObject(this) ?? this)->GetY() || last_drain_y != GetDrainObject()->GetY()) UpdatePumpHeight(true);
|
||||
}
|
||||
|
||||
local aMaterials=["", 0]; //contained liquids
|
||||
local pumpable_materials; // materials that can be pumped
|
||||
local last_source_y, last_drain_y;
|
||||
local pump_amount; // mat amount pumped since last height check
|
||||
|
||||
protected func PumpingWaitForLiquid()
|
||||
{
|
||||
// Pump is ready; check for liquids to pump
|
||||
if (!source_pipe) return CheckCurrentState();
|
||||
if(!HasLiquidToPump()) return;
|
||||
// Check stuck drain
|
||||
if (aMaterials[1] && (aMaterials[0] != "")) if (!InsertMaterial(Material(aMaterials[0]), 0,0,0,0, nil, true)) return;
|
||||
// OK; let's pump
|
||||
SetActionKeepPhase("Pump");
|
||||
UpdatePumpHeight();
|
||||
_inherited(...);
|
||||
powered = true;
|
||||
CheckState();
|
||||
}
|
||||
|
||||
/** Returns object to which the liquid is pumped */
|
||||
private func GetDrainObject()
|
||||
{
|
||||
if (drain_pipe) return drain_pipe->GetConnectedObject(this) ?? this;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Re turns object to which the liquid is pumped */
|
||||
private func GetSourceObject()
|
||||
{
|
||||
if (source_pipe) return source_pipe->GetConnectedObject(this) ?? this;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Returns amount of pixels to pump per 30 frames */
|
||||
public func GetPumpSpeed()
|
||||
{
|
||||
return 50;
|
||||
}
|
||||
|
||||
/** PhaseCall of Pump: Pump the liquid from the source to the drain pipe */
|
||||
protected func Pumping()
|
||||
{
|
||||
// at this point we can assert that we have power
|
||||
|
||||
// something went wrong in the meantime?
|
||||
// let the central function handle that
|
||||
if (!source_pipe)
|
||||
return CheckCurrentState();
|
||||
|
||||
// nothing to pump right now?
|
||||
if(!HasLiquidToPump())
|
||||
{
|
||||
UnmakePowerActuator();
|
||||
SetActionKeepPhase("PumpWaitLiquid");
|
||||
return;
|
||||
}
|
||||
|
||||
// Recheck pump height
|
||||
if (pump_amount > 200 || last_source_y != (source_pipe->GetConnectedObject(this) ?? this)->GetY() || last_drain_y != GetDrainObject()->GetY())
|
||||
{
|
||||
UpdatePumpHeight(true);
|
||||
if (GetAction() != "Pump") return;
|
||||
}
|
||||
// let the central function handle that on next check
|
||||
if (!source_pipe) return;
|
||||
|
||||
var pump_ok = true;
|
||||
|
||||
// is empty?
|
||||
if ((aMaterials[1] == 0) || (aMaterials[0] == ""))
|
||||
// is empty? -> try to get liquid
|
||||
if (!stored_material_amount)
|
||||
{
|
||||
|
||||
// get new materials
|
||||
aMaterials = source_pipe->GetLiquid(pumpable_materials, 5, this, true);
|
||||
var aMat = GetSourceObject()->ExtractLiquidAmount(0,0, GetPumpSpeed()/10);
|
||||
|
||||
// no material to pump?
|
||||
if ((aMaterials[0] == "") || (aMaterials[1] == 0))
|
||||
pump_ok = false;
|
||||
if (aMat)
|
||||
{
|
||||
stored_material_index = aMat[0];
|
||||
stored_material_amount = aMat[1];
|
||||
}
|
||||
else
|
||||
pump_amount += aMaterials[1];
|
||||
{
|
||||
pump_ok = false;
|
||||
}
|
||||
}
|
||||
if (pump_ok)
|
||||
{
|
||||
if (drain_pipe)
|
||||
var i = stored_material_amount;
|
||||
while (i > 0)
|
||||
{
|
||||
var pumped = BoundBy(drain_pipe->PutLiquid(aMaterials[0], aMaterials[1], this), 0, aMaterials[1]);
|
||||
aMaterials[1] -= pumped;
|
||||
// Drain is stuck?
|
||||
if (!pumped) pump_ok = false;
|
||||
if (GetDrainObject()->InsertMaterial(stored_material_index))
|
||||
{
|
||||
i--;
|
||||
}
|
||||
// Drain is stuck.
|
||||
else
|
||||
{
|
||||
pump_ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
stored_material_amount = i;
|
||||
if (stored_material_amount <= 0)
|
||||
stored_material_index = nil;
|
||||
}
|
||||
|
||||
if(!pump_ok)
|
||||
{
|
||||
SetState("WaitForLiquid");
|
||||
}
|
||||
}
|
||||
|
||||
/** Re check state and change the state if needed */
|
||||
func CheckState()
|
||||
{
|
||||
var is_fullcon = GetCon() >= 100;
|
||||
var can_pump = source_pipe && is_fullcon && switched_on;
|
||||
|
||||
// can't pump at all -> wait
|
||||
if (!can_pump)
|
||||
{
|
||||
SetState("Wait");
|
||||
}
|
||||
else
|
||||
{
|
||||
// can pump but has no liquid -> wait for liquid
|
||||
if (!HasLiquidToPump())
|
||||
{
|
||||
SetState("WaitForLiquid");
|
||||
}
|
||||
else
|
||||
{
|
||||
var i = Max(0, aMaterials[1]), itMaterial = Material(aMaterials[0]);
|
||||
while (i)
|
||||
if (InsertMaterial(itMaterial))
|
||||
i--;
|
||||
else
|
||||
{
|
||||
// Drain is stuck.
|
||||
pump_ok = false;
|
||||
break;
|
||||
}
|
||||
aMaterials[1] = i;
|
||||
if (!i) aMaterials[0] = "";
|
||||
// can pump, has liquid but has no power -> wait for power
|
||||
if (!powered)
|
||||
{
|
||||
SetState("WaitForPower");
|
||||
}
|
||||
// otherwise, pump! :-)
|
||||
else
|
||||
{
|
||||
SetState("Pump");
|
||||
}
|
||||
|
||||
// regularly update the power usage while pumping or waiting for power
|
||||
UpdatePowerUsage();
|
||||
}
|
||||
}
|
||||
if (!pump_ok)
|
||||
{
|
||||
// Couldn't pump. Probably drain stuck.
|
||||
UnmakePowerActuator();
|
||||
SetActionKeepPhase("PumpWaitLiquid");
|
||||
}
|
||||
// maybe add the possebility to empty pump (invaild mats?)
|
||||
return;
|
||||
}
|
||||
|
||||
// Get current height the pump has to push liquids upwards (input.y - output.y)
|
||||
func GetPumpHeight()
|
||||
/** Get current height the pump has to push liquids upwards (input.y - output.y) */
|
||||
private func GetPumpHeight()
|
||||
{
|
||||
var src = source_pipe->GetConnectedObject(this) ?? this, dst = GetDrainObject();
|
||||
var out_pos = {X=dst->GetX(), Y=dst->GetY()};
|
||||
dst->InsertMaterial(Material("Water"), 0,0,0,0, out_pos, true); // TODO assumes water material is loaded
|
||||
var src_x = src->GetX(), src_y = src->GetY();
|
||||
if (Global->GBackLiquid(src_x, src_y))
|
||||
// compare each the surfaces of the bodies of liquid pumped
|
||||
|
||||
// find Y position of surface of liquid that is pumped to target
|
||||
var source_y = 0;
|
||||
if (GetSourceObject()->GBackLiquid())
|
||||
{
|
||||
var src_mat = Global->GetMaterial(src_x, src_y);
|
||||
while (src_y>0 && src_mat == Global->GetMaterial(src_x, src_y-1)) --src_y;
|
||||
var src_mat = GetSourceObject()->GetMaterial();
|
||||
while (src_mat == GetSourceObject()->GetMaterial(0, source_y-1))
|
||||
--source_y;
|
||||
}
|
||||
return src_y - out_pos.Y;
|
||||
// same for target (use same function as if inserting)
|
||||
var target_pos = {X=0, Y=0};
|
||||
GetDrainObject()->CanInsertMaterial(Material("Water"),0,0,target_pos);
|
||||
return (GetSourceObject()->GetY() + source_y) - target_pos.Y;
|
||||
}
|
||||
|
||||
// Recheck power usage/production for current pump height
|
||||
func UpdatePumpHeight(bool unmake_actuator)
|
||||
/** Recheck power usage/production for current pump height
|
||||
and make the pump a producer / consumer for the power system */
|
||||
private func UpdatePowerUsage()
|
||||
{
|
||||
pump_amount = 0;
|
||||
last_source_y = (source_pipe->GetConnectedObject(this) ?? this)->GetY();
|
||||
last_drain_y = GetDrainObject()->GetY();
|
||||
var new_power = PumpHeight2Power(GetPumpHeight());
|
||||
if (unmake_actuator)
|
||||
UnmakePowerActuator();
|
||||
var new_power;
|
||||
if(IsUsingPower())
|
||||
new_power = PumpHeight2Power(GetPumpHeight());
|
||||
else
|
||||
if (new_power == current_pump_power) return true;
|
||||
return MakePowerActuator(new_power);
|
||||
}
|
||||
|
||||
// Makes this a power consumer or producer and sets appropriate waiting actions
|
||||
func MakePowerActuator(int new_power)
|
||||
{
|
||||
new_power = 0;
|
||||
|
||||
// do nothing if not necessary
|
||||
if (new_power == power_used)
|
||||
return;
|
||||
|
||||
// and update energy system
|
||||
if (new_power > 0)
|
||||
{
|
||||
SetActionKeepPhase("PumpWaitPower");
|
||||
if (power_used < 0)
|
||||
{
|
||||
powered = false; // needed since the flag was set manually
|
||||
UnmakePowerProducer();
|
||||
}
|
||||
MakePowerConsumer(new_power);
|
||||
|
||||
}
|
||||
else if (new_power < 0)
|
||||
{
|
||||
if (power_used > 0)
|
||||
UnmakePowerConsumer();
|
||||
MakePowerProducer(-new_power);
|
||||
powered = true; // when producing, we always have power
|
||||
}
|
||||
else // new_power == 0
|
||||
{
|
||||
if (power_used < 0) UnmakePowerProducer();
|
||||
else if (power_used > 0) UnmakePowerConsumer();
|
||||
powered = true;
|
||||
}
|
||||
|
||||
power_used = new_power;
|
||||
}
|
||||
|
||||
/** Return whether the pump should be using power in the current state */
|
||||
private func IsUsingPower()
|
||||
{
|
||||
return switched_on && (GetAction() == "Pump" || GetAction() == "WaitForPower");
|
||||
}
|
||||
|
||||
/** Transform pump height (input.y - output.y) to required power */
|
||||
private func PumpHeight2Power(int pump_height)
|
||||
{
|
||||
// pumping downwards will only produce energy after an offset
|
||||
var power_offset = 40;
|
||||
// max power consumed/produced
|
||||
var max_power = 150;
|
||||
|
||||
return BoundBy((pump_height + power_offset)/15*5, -max_power,max_power+power_offset);
|
||||
}
|
||||
|
||||
/** Returns whether there is liquid at the source pipe to pump */
|
||||
private func HasLiquidToPump()
|
||||
{
|
||||
if (!source_pipe)
|
||||
return false;
|
||||
|
||||
// source
|
||||
if(!GetSourceObject()->GBackLiquid())
|
||||
return false;
|
||||
|
||||
// target (test with the very popular liquid "water")
|
||||
if(!GetDrainObject()->CanInsertMaterial(Material("Water"),0,0))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Set the state of the pump, retaining the animation position and updating the power usage */
|
||||
func SetState(string act)
|
||||
{
|
||||
if(act == GetAction()) return;
|
||||
|
||||
var start = 0;
|
||||
var end = GetAnimationLength("pump");
|
||||
var anim_pos = GetAnimationPosition(animation);
|
||||
if (act == "Pump")
|
||||
{
|
||||
SetAnimationPosition(animation, Anim_Linear(anim_pos, start, end, 35, ANIM_Loop));
|
||||
}
|
||||
else if(act == "WaitForLiquid")
|
||||
{
|
||||
SetAnimationPosition(animation, Anim_Linear(anim_pos, start, end, 350, ANIM_Loop));
|
||||
}
|
||||
else
|
||||
{
|
||||
SetActionKeepPhase("Pump");
|
||||
if (new_power < 0) MakePowerProducer(-new_power);
|
||||
SetAnimationPosition(animation, Anim_Const(anim_pos));
|
||||
}
|
||||
current_pump_power = new_power;
|
||||
return true;
|
||||
}
|
||||
|
||||
func UnmakePowerActuator()
|
||||
{
|
||||
if (current_pump_power > 0)
|
||||
UnmakePowerConsumer();
|
||||
else if (current_pump_power < 0)
|
||||
MakePowerProducer(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Transform pump height (input.y - output.y) to required power
|
||||
func PumpHeight2Power(int pump_height)
|
||||
{
|
||||
return BoundBy((pump_height + 35)/30*10, -150,150);
|
||||
}
|
||||
|
||||
func CheckCurrentState()
|
||||
{
|
||||
if(turned_on)
|
||||
|
||||
// deactivate power usage when not pumping
|
||||
if (powered && (act == "Wait" || act == "WaitForLiquid"))
|
||||
{
|
||||
var has_source_pipe = !!source_pipe;
|
||||
var is_fullcon = GetCon() >= 100;
|
||||
|
||||
if(GetAction() == "Wait") // waiting: not consuming power
|
||||
{
|
||||
if(has_source_pipe && is_fullcon)
|
||||
{
|
||||
UpdatePumpHeight();
|
||||
return;
|
||||
}
|
||||
else return; // waiting and no source pipe, keep waiting
|
||||
}
|
||||
else // not waiting: consuming power
|
||||
{
|
||||
if(!has_source_pipe || !is_fullcon)
|
||||
{
|
||||
UnmakePowerActuator();
|
||||
SetAction("Wait");
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// this point should not be reached
|
||||
if (power_used < 0) UnmakePowerProducer();
|
||||
else if(power_used > 0) UnmakePowerConsumer();
|
||||
power_used = 0;
|
||||
powered = false;
|
||||
}
|
||||
else // turned off
|
||||
{
|
||||
if(GetAction() != "Wait") // consuming power (except in PumpWaitLiquid condition)
|
||||
{
|
||||
UnmakePowerActuator();
|
||||
SetAction("Wait");
|
||||
return;
|
||||
}
|
||||
else // already waiting
|
||||
return;
|
||||
}
|
||||
FatalError("Not every case handled in Pump::CheckCurrentState");
|
||||
}
|
||||
|
||||
// Returns whether the pump can pump some liquid.
|
||||
private func HasLiquidToPump()
|
||||
{
|
||||
// If there is no source pipe, return false.
|
||||
if (!source_pipe)
|
||||
return false;
|
||||
// If there is nothing to pump at the source return false.
|
||||
var source = source_pipe->GetConnectedObject(this);
|
||||
if (!source)
|
||||
return false;
|
||||
if (!source->GBackLiquid())
|
||||
return false;
|
||||
// TODO: Account for pumping into buildings.
|
||||
// Pumping is okay.
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
Set name or wildcard string of materials this pump can pump
|
||||
@param to_val: Material that can be pumped. 0 or "*" for any material.
|
||||
*/
|
||||
public func SetPumpableMaterials(string to_val)
|
||||
{
|
||||
pumpable_materials = to_val;
|
||||
return true;
|
||||
}
|
||||
|
||||
local Name = "$Name$";
|
||||
local Description = "$Description$";
|
||||
local BlastIncinerate = 50;
|
||||
local HitPoints = 70;
|
||||
|
||||
/*
|
||||
"Pump": the pump is currently working and consuming power
|
||||
"WillPump": the pump wants to work as soon as there is power
|
||||
"Wait": the pump has been turned off or some other need is not fulfilled (f.e. connected pipe)
|
||||
*/
|
||||
local ActMap = {
|
||||
Pump = {
|
||||
Prototype = Action,
|
||||
Name = "Pump",
|
||||
Procedure = DFA_NONE,
|
||||
Length = 30,
|
||||
Delay = 3,
|
||||
Directions = 2,
|
||||
FlipDir = 1,
|
||||
X = 0,
|
||||
Y = 0,
|
||||
Wdt = 28,
|
||||
Hgt = 32,
|
||||
NextAction = "Pump",
|
||||
StartCall = "CheckCurrentState",
|
||||
PhaseCall = "Pumping"
|
||||
},
|
||||
Wait = {
|
||||
Prototype = Action,
|
||||
Name = "Wait",
|
||||
Procedure = DFA_NONE,
|
||||
Length = 1,
|
||||
Delay = 60,
|
||||
Directions = 2,
|
||||
FlipDir = 1,
|
||||
X = 0,
|
||||
Y = 0,
|
||||
Wdt = 28,
|
||||
Hgt = 32,
|
||||
NextAction = "Wait",
|
||||
StartCall = "CheckCurrentState"
|
||||
},
|
||||
PumpWaitPower = {
|
||||
Prototype = Action,
|
||||
Name = "PumpWaitPower",
|
||||
Procedure = DFA_NONE,
|
||||
Length = 30,
|
||||
Delay = 0,
|
||||
Directions = 2,
|
||||
FlipDir = 1,
|
||||
X = 0,
|
||||
Y = 0,
|
||||
Wdt = 28,
|
||||
Hgt = 32,
|
||||
StartCall = "PumpWaitPowerStart",
|
||||
AbortCall = "PumpWaitPowerStop",
|
||||
NextAction = "PumpWaitPower"
|
||||
},
|
||||
PumpWaitLiquid = { // Pump waiting for liquid: Move slowly to indicate we're turned on
|
||||
Prototype = Action,
|
||||
Name = "PumpWaitLiquid",
|
||||
Procedure = DFA_NONE,
|
||||
Length = 30,
|
||||
Delay = 10,
|
||||
Directions = 2,
|
||||
FlipDir = 1,
|
||||
X = 0,
|
||||
Y = 0,
|
||||
Wdt = 28,
|
||||
Hgt = 32,
|
||||
NextAction = "PumpWaitLiquid",
|
||||
PhaseCall = "PumpingWaitForLiquid"
|
||||
}
|
||||
};
|
||||
|
||||
// Set action while retaining phase from last action
|
||||
func SetActionKeepPhase(string act)
|
||||
{
|
||||
var phase = GetPhase();
|
||||
if (!SetAction(act)) return false;
|
||||
SetPhase(phase);
|
||||
return true;
|
||||
// finally, set the action
|
||||
SetAction(act);
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
Name=Pumpe
|
||||
Description=Die Pumpe kann beliebige Flüssigkeiten von A nach B pumpen.
|
||||
Description=Die Pumpe kann beliebige Flüssigkeiten von A nach B pumpen. Pumpt sie Flüssigkeiten abwärts, erzeugt sie dabei sogar ein wenig Strom.
|
||||
MsgTurnOff=Pumpe abschalten
|
||||
MsgTurnOn=Pumpe anschalten
|
|
@ -1,4 +1,4 @@
|
|||
Name=Pump
|
||||
Description=The pump can transport liquid from A to B.
|
||||
Description=The pump can transport liquid from A to B. If it pumps liquids downwards, it even generates a bit of power.
|
||||
MsgTurnOff=Turn off pump
|
||||
MsgTurnOn=Turn on pump
|
Binary file not shown.
After Width: | Height: | Size: 116 KiB |
Binary file not shown.
|
@ -8,7 +8,7 @@ Difficulty=50
|
|||
Definition1=Objects.ocd
|
||||
|
||||
[Game]
|
||||
Goals=Goal_SellGems=1;
|
||||
Goals=Goal_RepairStatue=1;
|
||||
Rules=Rule_TeamAccount=1;Rule_BuyAtFlagpole=1;
|
||||
|
||||
[Player1]
|
||||
|
|
|
@ -51,24 +51,42 @@ global func FindPosInMat(string sMat, int iXStart, int iYStart, int iWidth, int
|
|||
return 0; // No location found.
|
||||
}
|
||||
|
||||
// Removes a material pixel from the specified location, if the material is a liquid.
|
||||
// \par x X coordinate. Offset if called in object context.
|
||||
// \par y Y coordinate. Offset if called in object context.
|
||||
// \returns The material index of the removed pixel, or -1 if no liquid was found.
|
||||
/** Removes a material pixel from the specified location, if the material is a liquid.
|
||||
@param x X coordinate
|
||||
@param y Y coordinate
|
||||
@return The material index of the removed pixel, or -1 if no liquid was found. */
|
||||
global func ExtractLiquid(int x, int y)
|
||||
{
|
||||
var mat = GetMaterial(x, y);
|
||||
var density = GetMaterialVal("Density", "Material", mat);
|
||||
if (density < C4M_Liquid || density >= C4M_Solid)
|
||||
return -1;
|
||||
ExtractMaterialAmount(x, y, mat, 1);
|
||||
return mat;
|
||||
var result = ExtractLiquidAmount(x, y, 1);
|
||||
if(!result) return -1;
|
||||
|
||||
return result[0];
|
||||
}
|
||||
|
||||
// Removes a material pixel from the specified location, if the material is flammable.
|
||||
// \par x X coordinate. Offset if called in object context.
|
||||
// \par y Y coordinate. Offset if called in object context.
|
||||
// \returns \c true if material was removed, \c false otherwise.
|
||||
/** Tries to remove amount material pixels from the specified location if the material is a liquid.
|
||||
@param x X coordinate
|
||||
@param y Y coordinate
|
||||
@param amount amount of liquid that should be extracted
|
||||
@return an array with the first position being the material index being extracted and the second the
|
||||
actual amount of pixels extracted OR nil if there was no liquid at all */
|
||||
global func ExtractLiquidAmount(int x, int y, int amount)
|
||||
{
|
||||
var mat = GetMaterial(x, y);
|
||||
if(mat == -1)
|
||||
return nil;
|
||||
var density = GetMaterialVal("Density", "Material", mat);
|
||||
if (density < C4M_Liquid || density >= C4M_Solid)
|
||||
return nil;
|
||||
var amount = ExtractMaterialAmount(x, y, mat, amount);
|
||||
if (amount <= 0)
|
||||
return nil;
|
||||
return [mat, amount];
|
||||
}
|
||||
|
||||
/** Removes a material pixel from the specified location, if the material is flammable
|
||||
@param x X coordinate. Offset if called in object context.
|
||||
@param y Y coordinate. Offset if called in object context.
|
||||
@return true if material was removed, false otherwise. */
|
||||
global func FlameConsumeMaterial(int x, int y)
|
||||
{
|
||||
var mat = GetMaterial(x, y);
|
||||
|
|
|
@ -36,16 +36,13 @@ don't need to include this file or any of the files it includes. */
|
|||
#include <boost/function.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
#ifdef DEBUGREC
|
||||
#define DEBUGREC_SCRIPT
|
||||
#define DEBUGREC_START_FRAME 0
|
||||
#define DEBUGREC_PXS
|
||||
#define DEBUGREC_OBJCOM
|
||||
#define DEBUGREC_MATSCAN
|
||||
//#define DEBUGREC_RECRUITMENT
|
||||
#define DEBUGREC_MENU
|
||||
#define DEBUGREC_OCF
|
||||
#endif
|
||||
|
||||
// solidmask debugging
|
||||
//#define SOLIDMASK_DEBUG
|
||||
|
|
|
@ -62,6 +62,11 @@ public:
|
|||
char ScreenshotPath[CFG_MaxString+1];
|
||||
bool GamepadEnabled;
|
||||
bool FirstStart;
|
||||
int32_t DebugRec;
|
||||
// if defined, the external file is used for debugrec writing. Otherwise read/check
|
||||
int32_t DebugRecWrite;
|
||||
// if defined, an external file is used for debugrec writing (replays only)
|
||||
char DebugRecExternalFile[_MAX_PATH+1];
|
||||
|
||||
public:
|
||||
static int GetLanguageSequence(const char *strSource, char *strTarget);
|
||||
|
|
|
@ -184,9 +184,8 @@ void C4GameControl::RequestRuntimeRecord()
|
|||
fRecordNeeded = true;
|
||||
// request through a synchronize-call
|
||||
// currnetly do not request, but start record with next gamesync, so network runtime join can be debugged
|
||||
#ifndef DEBUGREC
|
||||
::Control.DoInput(CID_Synchronize, new C4ControlSynchronize(false, true), CDT_Queue);
|
||||
#endif
|
||||
if (Config.General.DebugRec)
|
||||
::Control.DoInput(CID_Synchronize, new C4ControlSynchronize(false, true), CDT_Queue);
|
||||
}
|
||||
|
||||
bool C4GameControl::IsRuntimeRecordPossible() const
|
||||
|
@ -422,18 +421,19 @@ void C4GameControl::DoInput(C4PacketType eCtrlType, C4ControlPacket *pPkt, C4Con
|
|||
|
||||
void C4GameControl::DbgRec(C4RecordChunkType eType, const uint8_t *pData, size_t iSize)
|
||||
{
|
||||
#ifdef DEBUGREC
|
||||
if (DoNoDebugRec>0) return;
|
||||
// record data
|
||||
if (pRecord)
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
C4PktDebugRec dr(eType, StdBuf(pData, iSize));
|
||||
pRecord->Rec(Game.FrameCounter, DecompileToBuf<StdCompilerBinWrite>(dr), eType);
|
||||
if (DoNoDebugRec>0) return;
|
||||
// record data
|
||||
if (pRecord)
|
||||
{
|
||||
C4PktDebugRec dr(eType, StdBuf(pData, iSize));
|
||||
pRecord->Rec(Game.FrameCounter, DecompileToBuf<StdCompilerBinWrite>(dr), eType);
|
||||
}
|
||||
// check against playback
|
||||
if (pPlayback)
|
||||
pPlayback->Check(eType, pData, iSize);
|
||||
}
|
||||
// check against playback
|
||||
if (pPlayback)
|
||||
pPlayback->Check(eType, pData, iSize);
|
||||
#endif // DEBUGREC
|
||||
}
|
||||
|
||||
C4ControlDeliveryType C4GameControl::DecideControlDelivery()
|
||||
|
|
|
@ -39,9 +39,7 @@
|
|||
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef DEBUGREC
|
||||
#include "C4Record.h"
|
||||
#endif
|
||||
|
||||
/* C4PlayerControlDef */
|
||||
|
||||
|
@ -1073,12 +1071,13 @@ void C4PlayerControl::ExecuteControlPacket(const class C4ControlPlayerControl *p
|
|||
const C4PlayerControlDef *pCtrlDef = ControlDefs.GetControlByIndex(rItem.iControl);
|
||||
if (pCtrlDef)
|
||||
{
|
||||
#ifdef DEBUGREC
|
||||
if (pCtrlDef->IsSync())
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
AddDbgRec(RCT_PlrCom, &rItem.iControl, sizeof(rItem.iControl));
|
||||
if (pCtrlDef->IsSync())
|
||||
{
|
||||
AddDbgRec(RCT_PlrCom, &rItem.iControl, sizeof(rItem.iControl));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (ExecuteControl(rItem.iControl, pCtrl->IsReleaseControl(), pCtrl->GetExtraData(), rItem.iTriggerMode, false, fHandleDownStateOnly))
|
||||
if (pCtrlDef->IsSync())
|
||||
{
|
||||
|
|
|
@ -37,20 +37,13 @@
|
|||
|
||||
#define IMMEDIATEREC
|
||||
|
||||
//#define DEBUGREC_EXTFILE "DbgRec.ocb" // if defined, an external file is used for debugrec writing (replays only)
|
||||
//#define DEBUGREC_EXTFILE_WRITE // if defined, the external file is used for debugrec writing. Otherwise read/check
|
||||
|
||||
#ifdef DEBUGREC
|
||||
#ifdef DEBUGREC_EXTFILE
|
||||
CStdFile DbgRecFile;
|
||||
#endif
|
||||
int DoNoDebugRec=0; // debugrec disable counter
|
||||
|
||||
void AddDbgRec(C4RecordChunkType eType, const void *pData, int iSize)
|
||||
{
|
||||
::Control.DbgRec(eType, (const uint8_t *) pData, iSize);
|
||||
}
|
||||
#endif
|
||||
|
||||
C4DebugRecOff::C4DebugRecOff() : fDoOff(true)
|
||||
{
|
||||
|
@ -216,9 +209,8 @@ bool C4Record::Stop(StdStrBuf *pRecordName, BYTE *pRecordSHA1)
|
|||
LogRec.Close();
|
||||
|
||||
// pack group
|
||||
#ifndef DEBUGREC
|
||||
if (!C4Group_PackDirectory(sFilename.getData())) return false;
|
||||
#endif
|
||||
if (!Config.General.DebugRec)
|
||||
if (!C4Group_PackDirectory(sFilename.getData())) return false;
|
||||
|
||||
// return record data
|
||||
if (pRecordName)
|
||||
|
@ -501,23 +493,27 @@ bool C4Playback::Open(C4Group &rGrp)
|
|||
currChunk = chunks.begin();
|
||||
Finished = false;
|
||||
// external debugrec file
|
||||
#if defined(DEBUGREC_EXTFILE) && defined(DEBUGREC)
|
||||
#ifdef DEBUGREC_EXTFILE_WRITE
|
||||
if (!DbgRecFile.Create(DEBUGREC_EXTFILE))
|
||||
if (Config.General.DebugRecExternalFile[0] && Config.General.DebugRec)
|
||||
{
|
||||
LogFatal("DbgRec: Creation of external file \"" DEBUGREC_EXTFILE "\" failed!");
|
||||
return false;
|
||||
if (Config.General.DebugRecWrite)
|
||||
{
|
||||
if (!DbgRecFile.Create(Config.General.DebugRecExternalFile))
|
||||
{
|
||||
LogFatal(FormatString("DbgRec: Creation of external file \"%s\" failed!", Config.General.DebugRecExternalFile).getData());
|
||||
return false;
|
||||
}
|
||||
else LogF("DbgRec: Writing to \"%s\"...", Config.General.DebugRecExternalFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!DbgRecFile.Open(Config.General.DebugRecExternalFile))
|
||||
{
|
||||
LogFatal(FormatString("DbgRec: Opening of external file \"%s\" failed!", Config.General.DebugRecExternalFile).getData());
|
||||
return false;
|
||||
}
|
||||
else LogF("DbgRec: Checking against \"%s\"...", Config.General.DebugRecExternalFile);
|
||||
}
|
||||
}
|
||||
else Log("DbgRec: Writing to \"" DEBUGREC_EXTFILE "\"...");
|
||||
#else
|
||||
if (!DbgRecFile.Open(DEBUGREC_EXTFILE))
|
||||
{
|
||||
LogFatal("DbgRec: Opening of external file \"" DEBUGREC_EXTFILE "\" failed!");
|
||||
return false;
|
||||
}
|
||||
else Log("DbgRec: Checking against \"" DEBUGREC_EXTFILE "\"...");
|
||||
#endif
|
||||
#endif
|
||||
// ok
|
||||
return true;
|
||||
}
|
||||
|
@ -860,11 +856,12 @@ bool C4Playback::ExecuteControl(C4Control *pCtrl, int iFrame)
|
|||
// still playbacking?
|
||||
if (currChunk == chunks.end()) return false;
|
||||
if (Finished) { Finish(); return false; }
|
||||
#ifdef DEBUGREC
|
||||
if (DebugRec.firstPkt())
|
||||
DebugRecError("Debug rec overflow!");
|
||||
DebugRec.Clear();
|
||||
#endif
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
if (DebugRec.firstPkt())
|
||||
DebugRecError("Debug rec overflow!");
|
||||
DebugRec.Clear();
|
||||
}
|
||||
// return all control until this frame
|
||||
while (currChunk != chunks.end() && currChunk->Frame <= iFrame)
|
||||
{
|
||||
|
@ -887,28 +884,22 @@ bool C4Playback::ExecuteControl(C4Control *pCtrl, int iFrame)
|
|||
Finished=true;
|
||||
break;
|
||||
|
||||
#ifdef DEBUGREC
|
||||
default: // expect it to be debug rec
|
||||
// append to debug rec buffer
|
||||
if (currChunk->pDbg)
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
DebugRec.Add(CID_DebugRec, currChunk->pDbg);
|
||||
// the debugrec buffer is now responsible for deleting the packet
|
||||
currChunk->pDbg = NULL;
|
||||
// append to debug rec buffer
|
||||
if (currChunk->pDbg)
|
||||
{
|
||||
DebugRec.Add(CID_DebugRec, currChunk->pDbg);
|
||||
// the debugrec buffer is now responsible for deleting the packet
|
||||
currChunk->pDbg = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
}
|
||||
// next chunk
|
||||
NextChunk();
|
||||
}
|
||||
// Debug log
|
||||
#ifdef DEBUGREC
|
||||
//sprintf(OSTR, "-- Frame %d:", Game.FrameCounter); Log(OSTR);
|
||||
//char Indent[256+1]; strcpy(Indent, "");
|
||||
//pCtrl->deb_print(Indent);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -937,13 +928,13 @@ void C4Playback::Clear()
|
|||
playbackFile.Close();
|
||||
sequentialBuffer.Clear();
|
||||
fLoadSequential = false;
|
||||
#ifdef DEBUGREC
|
||||
C4IDPacket *pkt;
|
||||
while (pkt = DebugRec.firstPkt()) DebugRec.Delete(pkt);
|
||||
#ifdef DEBUGREC_EXTFILE
|
||||
DbgRecFile.Close();
|
||||
#endif
|
||||
#endif
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
C4IDPacket *pkt;
|
||||
while (pkt = DebugRec.firstPkt()) DebugRec.Delete(pkt);
|
||||
if (Config.General.DebugRecExternalFile[0])
|
||||
DbgRecFile.Close();
|
||||
}
|
||||
// done
|
||||
Finished = true;
|
||||
}
|
||||
|
@ -1012,7 +1003,6 @@ StdStrBuf GetDbgRecPktData(C4RecordChunkType eType, const StdBuf & RawData)
|
|||
return r;
|
||||
}
|
||||
|
||||
#ifdef DEBUGREC
|
||||
void C4Playback::Check(C4RecordChunkType eType, const uint8_t *pData, int iSize)
|
||||
{
|
||||
// only if enabled
|
||||
|
@ -1021,66 +1011,72 @@ void C4Playback::Check(C4RecordChunkType eType, const uint8_t *pData, int iSize)
|
|||
|
||||
C4PktDebugRec PktInReplay;
|
||||
bool fHasPacketFromHead = false;
|
||||
#ifdef DEBUGREC_EXTFILE
|
||||
#ifdef DEBUGREC_EXTFILE_WRITE
|
||||
// writing of external debugrec file
|
||||
DbgRecFile.Write(&eType, sizeof eType);
|
||||
int32_t iSize32 = iSize;
|
||||
DbgRecFile.Write(&iSize32, sizeof iSize32);
|
||||
DbgRecFile.Write(pData, iSize);
|
||||
return;
|
||||
#else
|
||||
int32_t iSize32 = 0;
|
||||
C4RecordChunkType eTypeRec = RCT_Undefined;
|
||||
DbgRecFile.Read(&eTypeRec, sizeof eTypeRec);
|
||||
DbgRecFile.Read(&iSize32, sizeof iSize32);
|
||||
if (iSize32)
|
||||
if (Config.General.DebugRecExternalFile[0])
|
||||
{
|
||||
StdBuf buf;
|
||||
buf.SetSize(iSize32);
|
||||
DbgRecFile.Read(buf.getMData(), iSize32);
|
||||
PktInReplay = C4PktDebugRec(eTypeRec, buf);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
// check debug rec in list
|
||||
C4IDPacket *pkt;
|
||||
if (pkt = DebugRec.firstPkt())
|
||||
{
|
||||
// copy from list
|
||||
PktInReplay = *static_cast<C4PktDebugRec *>(pkt->getPkt());
|
||||
DebugRec.Delete(pkt);
|
||||
if (Config.General.DebugRecWrite)
|
||||
{
|
||||
// writing of external debugrec file
|
||||
DbgRecFile.Write(&eType, sizeof eType);
|
||||
int32_t iSize32 = iSize;
|
||||
DbgRecFile.Write(&iSize32, sizeof iSize32);
|
||||
DbgRecFile.Write(pData, iSize);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
int32_t iSize32 = 0;
|
||||
C4RecordChunkType eTypeRec = RCT_Undefined;
|
||||
DbgRecFile.Read(&eTypeRec, sizeof eTypeRec);
|
||||
DbgRecFile.Read(&iSize32, sizeof iSize32);
|
||||
if (iSize32)
|
||||
{
|
||||
StdBuf buf;
|
||||
buf.SetSize(iSize32);
|
||||
DbgRecFile.Read(buf.getMData(), iSize32);
|
||||
PktInReplay = C4PktDebugRec(eTypeRec, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// special sync check skip...
|
||||
while (currChunk != chunks.end() && currChunk->Type == RCT_CtrlPkt)
|
||||
// check debug rec in list
|
||||
C4IDPacket *pkt;
|
||||
if (pkt = DebugRec.firstPkt())
|
||||
{
|
||||
C4IDPacket Packet(*currChunk->pPkt);
|
||||
C4ControlPacket *pCtrlPck = static_cast<C4ControlPacket *>(Packet.getPkt());
|
||||
assert(!pCtrlPck->Sync());
|
||||
::Control.ExecControlPacket(Packet.getPktType(), pCtrlPck);
|
||||
NextChunk();
|
||||
// copy from list
|
||||
PktInReplay = *static_cast<C4PktDebugRec *>(pkt->getPkt());
|
||||
DebugRec.Delete(pkt);
|
||||
}
|
||||
// record end?
|
||||
if (currChunk == chunks.end() || currChunk->Type == RCT_End || Finished)
|
||||
else
|
||||
{
|
||||
Log("DebugRec end: All in sync!");
|
||||
++DoNoDebugRec;
|
||||
return;
|
||||
}
|
||||
// unpack directly from head
|
||||
if (currChunk->Type != eType)
|
||||
{
|
||||
DebugRecError(FormatString("Playback type %x, this type %x", currChunk->Type, eType).getData());
|
||||
return;
|
||||
}
|
||||
if (currChunk->pDbg)
|
||||
PktInReplay = *currChunk->pDbg;
|
||||
// special sync check skip...
|
||||
while (currChunk != chunks.end() && currChunk->Type == RCT_CtrlPkt)
|
||||
{
|
||||
C4IDPacket Packet(*currChunk->pPkt);
|
||||
C4ControlPacket *pCtrlPck = static_cast<C4ControlPacket *>(Packet.getPkt());
|
||||
assert(!pCtrlPck->Sync());
|
||||
::Control.ExecControlPacket(Packet.getPktType(), pCtrlPck);
|
||||
NextChunk();
|
||||
}
|
||||
// record end?
|
||||
if (currChunk == chunks.end() || currChunk->Type == RCT_End || Finished)
|
||||
{
|
||||
Log("DebugRec end: All in sync!");
|
||||
++DoNoDebugRec;
|
||||
return;
|
||||
}
|
||||
// unpack directly from head
|
||||
if (currChunk->Type != eType)
|
||||
{
|
||||
DebugRecError(FormatString("Playback type %x, this type %x", currChunk->Type, eType).getData());
|
||||
return;
|
||||
}
|
||||
if (currChunk->pDbg)
|
||||
PktInReplay = *currChunk->pDbg;
|
||||
|
||||
fHasPacketFromHead = true;
|
||||
fHasPacketFromHead = true;
|
||||
}
|
||||
}
|
||||
#endif // DEBUGREC_EXTFILE
|
||||
// record end?
|
||||
if (PktInReplay.getType() == RCT_End)
|
||||
{
|
||||
|
@ -1121,7 +1117,6 @@ void C4Playback::DebugRecError(const char *szError)
|
|||
LogF("Playback error: %s", szError);
|
||||
BREAKPOINT_HERE;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool C4Playback::StreamToRecord(const char *szStream, StdStrBuf *pRecordFile)
|
||||
{
|
||||
|
|
|
@ -27,17 +27,11 @@ class C4Record;
|
|||
#include "C4Group.h"
|
||||
#include "C4Control.h"
|
||||
|
||||
#ifdef DEBUGREC
|
||||
extern int DoNoDebugRec; // debugrec disable counter in C4Record.cpp
|
||||
|
||||
#define DEBUGREC_OFF ++DoNoDebugRec;
|
||||
#define DEBUGREC_ON --DoNoDebugRec;
|
||||
|
||||
#else
|
||||
#define DEBUGREC_OFF
|
||||
#define DEBUGREC_ON
|
||||
#endif
|
||||
|
||||
// turn off debugrecs in current block
|
||||
class C4DebugRecOff
|
||||
{
|
||||
|
@ -100,9 +94,7 @@ enum C4RecordChunkType // record file chunk type
|
|||
RCT_Undefined = 0xff
|
||||
};
|
||||
|
||||
#ifdef DEBUGREC
|
||||
void AddDbgRec(C4RecordChunkType eType, const void *pData=NULL, int iSize=0); // record debug stuff
|
||||
#endif
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
|
@ -306,9 +298,7 @@ private:
|
|||
StdBuf sequentialBuffer; // buffer to manage sequential reads
|
||||
uint32_t iLastSequentialFrame; // frame number of last chunk read
|
||||
void Finish(); // end playback
|
||||
#ifdef DEBUGREC
|
||||
C4PacketList DebugRec;
|
||||
#endif
|
||||
public:
|
||||
C4Playback(); // constructor; init playback
|
||||
~C4Playback(); // destructor; deinit playback
|
||||
|
@ -324,11 +314,9 @@ public:
|
|||
bool ExecuteControl(C4Control *pCtrl, int iFrame); // assign control
|
||||
bool IsFinished() { return Finished; }
|
||||
void Clear();
|
||||
#ifdef DEBUGREC
|
||||
void Check(C4RecordChunkType eType, const uint8_t *pData, int iSize); // compare with debugrec
|
||||
void DebugRecError(const char *szError);
|
||||
#endif
|
||||
static bool StreamToRecord(const char *szStream, StdStrBuf *pRecord);
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -227,6 +227,9 @@ void C4Application::ParseCommandLine(int argc, char * argv[])
|
|||
{"league", no_argument, &Config.Network.LeagueServerSignUp, 1},
|
||||
{"nosignup", no_argument, &Config.Network.MasterServerSignUp, 0},
|
||||
{"signup", no_argument, &Config.Network.MasterServerSignUp, 1},
|
||||
|
||||
{"debugrecread", required_argument, 0, 'K'},
|
||||
{"debugrecwrite", required_argument, 0, 'w'},
|
||||
|
||||
{"client", required_argument, 0, 'c'},
|
||||
{"host", no_argument, 0, 'h'},
|
||||
|
@ -289,6 +292,28 @@ void C4Application::ParseCommandLine(int argc, char * argv[])
|
|||
Game.NetworkActive = true;
|
||||
SCopy(optarg, Game.DirectJoinAddress, _MAX_PATH);
|
||||
break;
|
||||
case 'K':
|
||||
if (optarg && optarg[0])
|
||||
{
|
||||
LogF("Reading from DebugRec file '%s'", optarg);
|
||||
SCopy(optarg, Config.General.DebugRecExternalFile, _MAX_PATH);
|
||||
}
|
||||
else
|
||||
Log("Reading DebugRec from CtrlRec file in scenario record");
|
||||
Config.General.DebugRec = 1;
|
||||
Config.General.DebugRecWrite = 0;
|
||||
break;
|
||||
case 'w':
|
||||
if (optarg && optarg[0])
|
||||
{
|
||||
LogF("Writing to DebugRec file '%s'", optarg);
|
||||
SCopy(optarg, Config.General.DebugRecExternalFile, _MAX_PATH);
|
||||
}
|
||||
else
|
||||
Log("Writing DebugRec to CtrlRec file in scenario record");
|
||||
Config.General.DebugRec = 1;
|
||||
Config.General.DebugRecWrite = 1;
|
||||
break;
|
||||
case 'r': Game.Record = true; break;
|
||||
case 'n': Game.NetworkActive = true; break;
|
||||
case 'N': Game.NetworkActive = false; break;
|
||||
|
|
|
@ -700,13 +700,8 @@ C4ST_NEW(MessagesStat, "C4Game::Execute Messages.Execute")
|
|||
#define EXEC_S(Expressions, Stat) \
|
||||
{ C4ST_START(Stat) Expressions C4ST_STOP(Stat) }
|
||||
|
||||
#ifdef DEBUGREC
|
||||
#define EXEC_S_DR(Expressions, Stat, DebugRecName) { AddDbgRec(RCT_Block, DebugRecName, 6); EXEC_S(Expressions, Stat) }
|
||||
#define EXEC_DR(Expressions, DebugRecName) { AddDbgRec(RCT_Block, DebugRecName, 6); Expressions }
|
||||
#else
|
||||
#define EXEC_S_DR(Expressions, Stat, DebugRecName) EXEC_S(Expressions, Stat)
|
||||
#define EXEC_DR(Expressions, DebugRecName) Expressions
|
||||
#endif
|
||||
#define EXEC_S_DR(Expressions, Stat, DebugRecName) { if (Config.General.DebugRec) AddDbgRec(RCT_Block, DebugRecName, 6); EXEC_S(Expressions, Stat) }
|
||||
#define EXEC_DR(Expressions, DebugRecName) { if (Config.General.DebugRec) AddDbgRec(RCT_Block, DebugRecName, 6); Expressions }
|
||||
|
||||
bool C4Game::Execute() // Returns true if the game is over
|
||||
{
|
||||
|
@ -725,9 +720,8 @@ bool C4Game::Execute() // Returns true if the game is over
|
|||
// Halt
|
||||
if (HaltCount) return false;
|
||||
|
||||
#ifdef DEBUGREC
|
||||
Landscape.DoRelights();
|
||||
#endif
|
||||
if (Config.General.DebugRec)
|
||||
Landscape.DoRelights();
|
||||
|
||||
// Execute the control
|
||||
Control.Execute();
|
||||
|
@ -736,10 +730,9 @@ bool C4Game::Execute() // Returns true if the game is over
|
|||
// Ticks
|
||||
EXEC_DR( Ticks(); , "Ticks")
|
||||
|
||||
#ifdef DEBUGREC
|
||||
// debugrec
|
||||
AddDbgRec(RCT_DbgFrame, &FrameCounter, sizeof(int32_t));
|
||||
#endif
|
||||
if (Config.General.DebugRec)
|
||||
// debugrec
|
||||
AddDbgRec(RCT_DbgFrame, &FrameCounter, sizeof(int32_t));
|
||||
|
||||
// Game
|
||||
|
||||
|
@ -777,11 +770,11 @@ bool C4Game::Execute() // Returns true if the game is over
|
|||
C4ST_RESETPART
|
||||
}
|
||||
|
||||
#ifdef DEBUGREC
|
||||
AddDbgRec(RCT_Block, "eGame", 6);
|
||||
|
||||
Landscape.DoRelights();
|
||||
#endif
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
AddDbgRec(RCT_Block, "eGame", 6);
|
||||
Landscape.DoRelights();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1004,14 +997,15 @@ C4Object* C4Game::NewObject( C4PropList *pDef, C4Object *pCreator,
|
|||
{
|
||||
// Safety
|
||||
if (!pDef) return NULL;
|
||||
#ifdef DEBUGREC
|
||||
C4RCCreateObj rc;
|
||||
memset(&rc, '\0', sizeof(rc));
|
||||
strncpy(rc.id, pDef->GetName(), 32+1);
|
||||
rc.oei=C4PropListNumbered::GetEnumerationIndex()+1;
|
||||
rc.x=iX; rc.y=iY; rc.ownr=iOwner;
|
||||
AddDbgRec(RCT_CrObj, &rc, sizeof(rc));
|
||||
#endif
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
C4RCCreateObj rc;
|
||||
memset(&rc, '\0', sizeof(rc));
|
||||
strncpy(rc.id, pDef->GetName(), 32+1);
|
||||
rc.oei=C4PropListNumbered::GetEnumerationIndex()+1;
|
||||
rc.x=iX; rc.y=iY; rc.ownr=iOwner;
|
||||
AddDbgRec(RCT_CrObj, &rc, sizeof(rc));
|
||||
}
|
||||
// Create object
|
||||
C4Object *pObj;
|
||||
if (!(pObj=new C4Object)) return NULL;
|
||||
|
@ -1319,9 +1313,8 @@ void C4Game::ObjectRemovalCheck() // Every ::Game.iTick255 by ExecObjects
|
|||
|
||||
void C4Game::ExecObjects() // Every Tick1 by Execute
|
||||
{
|
||||
#ifdef DEBUGREC
|
||||
AddDbgRec(RCT_Block, "ObjEx", 6);
|
||||
#endif
|
||||
if (Config.General.DebugRec)
|
||||
AddDbgRec(RCT_Block, "ObjEx", 6);
|
||||
|
||||
// Execute objects - reverse order to ensure
|
||||
C4Object *cObj; C4ObjectLink *clnk;
|
||||
|
@ -1333,9 +1326,8 @@ void C4Game::ExecObjects() // Every Tick1 by Execute
|
|||
// Status reset: process removal delay
|
||||
if (cObj->RemovalDelay>0) cObj->RemovalDelay--;
|
||||
|
||||
#ifdef DEBUGREC
|
||||
AddDbgRec(RCT_Block, "ObjCC", 6);
|
||||
#endif
|
||||
if (Config.General.DebugRec)
|
||||
AddDbgRec(RCT_Block, "ObjCC", 6);
|
||||
|
||||
// Can savely reset object marker here
|
||||
Objects.LastUsedMarker = 0;
|
||||
|
@ -1343,9 +1335,8 @@ void C4Game::ExecObjects() // Every Tick1 by Execute
|
|||
// Cross check objects
|
||||
Objects.CrossCheck();
|
||||
|
||||
#ifdef DEBUGREC
|
||||
AddDbgRec(RCT_Block, "ObjRs", 6);
|
||||
#endif
|
||||
if (Config.General.DebugRec)
|
||||
AddDbgRec(RCT_Block, "ObjRs", 6);
|
||||
|
||||
// Resort
|
||||
if (fResortAnyObject)
|
||||
|
@ -1354,9 +1345,8 @@ void C4Game::ExecObjects() // Every Tick1 by Execute
|
|||
Objects.ResortUnsorted();
|
||||
}
|
||||
|
||||
#ifdef DEBUGREC
|
||||
AddDbgRec(RCT_Block, "ObjRm", 6);
|
||||
#endif
|
||||
if (Config.General.DebugRec)
|
||||
AddDbgRec(RCT_Block, "ObjRm", 6);
|
||||
|
||||
// Removal
|
||||
if (!::Game.iTick255) ObjectRemovalCheck();
|
||||
|
|
|
@ -333,20 +333,35 @@ static bool FnSmoke(C4PropList * _this, long tx, long ty, long level, long dwClr
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool FnInsertMaterial(C4PropList * _this, long mat, long x, long y, long vx, long vy, C4PropList *insert_position, bool query_only)
|
||||
static bool FnInsertMaterial(C4PropList * _this, long mat, long x, long y, long vx, long vy, C4PropList *insert_position)
|
||||
{
|
||||
if (Object(_this)) { x+=Object(_this)->GetX(); y+=Object(_this)->GetY(); }
|
||||
int32_t insert_x=x, insert_y=y;
|
||||
if (!::Landscape.InsertMaterial(mat,&insert_x,&insert_y,vx,vy,query_only)) return false;
|
||||
// output insertion position if desired
|
||||
if (insert_position && !insert_position->IsFrozen())
|
||||
{
|
||||
insert_position->SetProperty(P_X, C4VInt(insert_x));
|
||||
insert_position->SetProperty(P_Y, C4VInt(insert_y));
|
||||
if (!::Landscape.InsertMaterial(mat,&insert_x,&insert_y,vx,vy)) return false;
|
||||
// output insertion position if desired
|
||||
if (insert_position && !insert_position->IsFrozen())
|
||||
{
|
||||
insert_position->SetProperty(P_X, C4VInt(insert_x));
|
||||
insert_position->SetProperty(P_Y, C4VInt(insert_y));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool FnCanInsertMaterial(C4PropList * _this, long mat, long x, long y, C4PropList *insert_position)
|
||||
{
|
||||
if (Object(_this)) { x+=Object(_this)->GetX(); y+=Object(_this)->GetY(); }
|
||||
int32_t insert_x=x, insert_y=y;
|
||||
if (!::Landscape.InsertMaterial(mat,&insert_x,&insert_y,0,0,true)) return false;
|
||||
// output insertion position if desired
|
||||
if (insert_position && !insert_position->IsFrozen())
|
||||
{
|
||||
insert_position->SetProperty(P_X, C4VInt(insert_x));
|
||||
insert_position->SetProperty(P_Y, C4VInt(insert_y));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static long FnGetMaterialCount(C4PropList * _this, long iMaterial, bool fReal)
|
||||
{
|
||||
if (!MatValid(iMaterial)) return -1;
|
||||
|
@ -2411,6 +2426,7 @@ void InitGameFunctionMap(C4AulScriptEngine *pEngine)
|
|||
AddFunc(pEngine, "Material", FnMaterial);
|
||||
AddFunc(pEngine, "BlastFree", FnBlastFree);
|
||||
AddFunc(pEngine, "InsertMaterial", FnInsertMaterial);
|
||||
AddFunc(pEngine, "CanInsertMaterial", FnCanInsertMaterial);
|
||||
AddFunc(pEngine, "LandscapeWidth", FnLandscapeWidth);
|
||||
AddFunc(pEngine, "LandscapeHeight", FnLandscapeHeight);
|
||||
AddFunc(pEngine, "SetSeason", FnSetSeason);
|
||||
|
|
|
@ -404,13 +404,14 @@ bool C4Menu::AddItem(C4MenuItem *pNew, const char *szCaption, const char *szComm
|
|||
C4ID idID, const char *szCommand2, bool fOwnValue, int32_t iValue, bool fIsSelectable)
|
||||
{
|
||||
#ifdef DEBUGREC_MENU
|
||||
if (pObject)
|
||||
{
|
||||
C4RCMenuAdd rc = { pObject ? pObject->Number : -1, iCount, idID, fOwnValue, iValue, fIsSelectable };
|
||||
AddDbgRec(RCT_MenuAdd, &rc, sizeof(C4RCMenuAdd));
|
||||
if (szCommand) AddDbgRec(RCT_MenuAddC, szCommand, strlen(szCommand)+1);
|
||||
if (szCommand2) AddDbgRec(RCT_MenuAddC, szCommand2, strlen(szCommand2)+1);
|
||||
}
|
||||
if (Config.General.DebugRec)
|
||||
if (pObject)
|
||||
{
|
||||
C4RCMenuAdd rc = { pObject ? pObject->Number : -1, iCount, idID, fOwnValue, iValue, fIsSelectable };
|
||||
AddDbgRec(RCT_MenuAdd, &rc, sizeof(C4RCMenuAdd));
|
||||
if (szCommand) AddDbgRec(RCT_MenuAddC, szCommand, strlen(szCommand)+1);
|
||||
if (szCommand2) AddDbgRec(RCT_MenuAddC, szCommand2, strlen(szCommand2)+1);
|
||||
}
|
||||
#endif
|
||||
// Add it to the list
|
||||
pClientWindow->AddElement(pNew);
|
||||
|
|
|
@ -135,7 +135,8 @@ void C4Landscape::ExecuteScan()
|
|||
return;
|
||||
|
||||
#ifdef DEBUGREC_MATSCAN
|
||||
AddDbgRec(RCT_MatScan, &ScanX, sizeof(ScanX));
|
||||
if (Config.General.DebugRec)
|
||||
AddDbgRec(RCT_MatScan, &ScanX, sizeof(ScanX));
|
||||
#endif
|
||||
|
||||
for (int32_t cnt=0; cnt<ScanSpeed; cnt++)
|
||||
|
@ -192,8 +193,11 @@ int32_t C4Landscape::DoScan(int32_t cx, int32_t cy, int32_t mat, int32_t dir)
|
|||
int32_t mconv = ::MaterialMap.Map[mat].TempConvStrength,
|
||||
mconvs = mconv;
|
||||
#ifdef DEBUGREC_MATSCAN
|
||||
C4RCMatScan rc = { cx, cy, mat, conv_to, dir, mconvs };
|
||||
AddDbgRec(RCT_MatScanDo, &rc, sizeof(C4RCMatScan));
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
C4RCMatScan rc = { cx, cy, mat, conv_to, dir, mconvs };
|
||||
AddDbgRec(RCT_MatScanDo, &rc, sizeof(C4RCMatScan));
|
||||
}
|
||||
#endif
|
||||
int32_t ydir = (dir == 0 ? +1 : -1), cy2;
|
||||
#ifdef PRETTY_TEMP_CONV
|
||||
|
@ -634,11 +638,12 @@ bool C4Landscape::ClearPix(int32_t tx, int32_t ty)
|
|||
}
|
||||
bool C4Landscape::SetPix(int32_t x, int32_t y, BYTE npix)
|
||||
{
|
||||
#ifdef DEBUGREC
|
||||
C4RCSetPix rc;
|
||||
rc.x=x; rc.y=y; rc.clr=npix;
|
||||
AddDbgRec(RCT_SetPix, &rc, sizeof(rc));
|
||||
#endif
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
C4RCSetPix rc;
|
||||
rc.x=x; rc.y=y; rc.clr=npix;
|
||||
AddDbgRec(RCT_SetPix, &rc, sizeof(rc));
|
||||
}
|
||||
// check bounds
|
||||
if (x < 0 || y < 0 || x >= Width || y >= Height)
|
||||
return false;
|
||||
|
@ -662,11 +667,12 @@ bool C4Landscape::SetPix(int32_t x, int32_t y, BYTE npix)
|
|||
|
||||
bool C4Landscape::_SetPix(int32_t x, int32_t y, BYTE npix)
|
||||
{
|
||||
#ifdef DEBUGREC
|
||||
C4RCSetPix rc;
|
||||
rc.x=x; rc.y=y; rc.clr=npix;
|
||||
AddDbgRec(RCT_SetPix, &rc, sizeof(rc));
|
||||
#endif
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
C4RCSetPix rc;
|
||||
rc.x=x; rc.y=y; rc.clr=npix;
|
||||
AddDbgRec(RCT_SetPix, &rc, sizeof(rc));
|
||||
}
|
||||
assert(x >= 0 && y >= 0 && x < Width && y < Height);
|
||||
// get and check pixel
|
||||
BYTE opix = _GetPix(x, y);
|
||||
|
@ -843,8 +849,13 @@ bool C4Landscape::InsertMaterial(int32_t mat, int32_t *tx, int32_t *ty, int32_t
|
|||
if (GetDensity(*tx,*ty+1)<mdens)
|
||||
{ if (!query_only) ::PXS.Create(mat,itofix(*tx),itofix(*ty),C4REAL10(vx),C4REAL10(vy)); return true; }
|
||||
|
||||
// Insertion OK here
|
||||
if (query_only) return true;
|
||||
if (query_only)
|
||||
{
|
||||
// since tx and ty changed, we need to re-check the bounds here
|
||||
// if we really inserted it, the check is made again in InsertDeadMaterial
|
||||
if (!Inside<int32_t>(*tx,0,Width-1) || !Inside<int32_t>(*ty,0,Height)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try reaction with material below and at insertion position
|
||||
C4MaterialReaction *pReact; int32_t tmat;
|
||||
|
@ -1223,10 +1234,11 @@ bool C4Landscape::Init(C4Group &hGroup, bool fOverloadCurrent, bool fLoadSky, bo
|
|||
return true;
|
||||
}
|
||||
|
||||
#ifdef DEBUGREC
|
||||
AddDbgRec(RCT_Block, "|---MAP---|", 12);
|
||||
AddDbgRec(RCT_Map, sfcMap->Bits, sfcMap->Pitch*sfcMap->Hgt);
|
||||
#endif
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
AddDbgRec(RCT_Block, "|---MAP---|", 12);
|
||||
AddDbgRec(RCT_Map, sfcMap->Bits, sfcMap->Pitch*sfcMap->Hgt);
|
||||
}
|
||||
|
||||
// Store map size and calculate map zoom
|
||||
int iWdt, iHgt;
|
||||
|
@ -1301,10 +1313,11 @@ bool C4Landscape::Init(C4Group &hGroup, bool fOverloadCurrent, bool fLoadSky, bo
|
|||
|
||||
Game.SetInitProgress(84);
|
||||
|
||||
#ifdef DEBUGREC
|
||||
AddDbgRec(RCT_Block, "|---LANDSCAPE---|", 18);
|
||||
AddDbgRec(RCT_Map, Surface8->Bits, Surface8->Pitch*Surface8->Hgt);
|
||||
#endif
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
AddDbgRec(RCT_Block, "|---LANDSCAPE---|", 18);
|
||||
AddDbgRec(RCT_Map, Surface8->Bits, Surface8->Pitch*Surface8->Hgt);
|
||||
}
|
||||
|
||||
// Create renderer
|
||||
pLandscapeRender = NULL;
|
||||
|
@ -1327,10 +1340,11 @@ bool C4Landscape::Init(C4Group &hGroup, bool fOverloadCurrent, bool fLoadSky, bo
|
|||
pLandscapeRender->Update(C4Rect(0, 0, Width, Height), this);
|
||||
Game.SetInitProgress(87);
|
||||
}
|
||||
#ifdef DEBUGREC
|
||||
AddDbgRec(RCT_Block, "|---LS---|", 11);
|
||||
AddDbgRec(RCT_Ls, Surface8->Bits, Surface8->Pitch*Surface8->Hgt);
|
||||
#endif
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
AddDbgRec(RCT_Block, "|---LS---|", 11);
|
||||
AddDbgRec(RCT_Ls, Surface8->Bits, Surface8->Pitch*Surface8->Hgt);
|
||||
}
|
||||
|
||||
|
||||
// Create pixel count array
|
||||
|
|
|
@ -516,11 +516,12 @@ bool C4MCOverlay::CheckMask(int32_t iX, int32_t iY)
|
|||
{
|
||||
// bounds match?
|
||||
if (!LooseBounds) if (iX<X || iY<Y || iX>=X+Wdt || iY>=Y+Hgt) return false;
|
||||
#ifdef DEBUGREC
|
||||
C4RCTrf rc;
|
||||
rc.x=iX; rc.y=iY; rc.Rotate=Rotate; rc.Turbulence=Turbulence;
|
||||
AddDbgRec(RCT_MCT1, &rc, sizeof(rc));
|
||||
#endif
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
C4RCTrf rc;
|
||||
rc.x=iX; rc.y=iY; rc.Rotate=Rotate; rc.Turbulence=Turbulence;
|
||||
AddDbgRec(RCT_MCT1, &rc, sizeof(rc));
|
||||
}
|
||||
C4Real dX=itofix(iX); C4Real dY=itofix(iY);
|
||||
// apply turbulence
|
||||
if (Turbulence)
|
||||
|
@ -558,11 +559,12 @@ bool C4MCOverlay::CheckMask(int32_t iX, int32_t iY)
|
|||
{ iX=fixtoi(dX, ZoomX); iY=fixtoi(dY, ZoomY); }
|
||||
else
|
||||
{ iX*=ZoomX; iY*=ZoomY; }
|
||||
#ifdef DEBUGREC
|
||||
C4RCPos rc2;
|
||||
rc2.x=iX; rc2.y=iY;
|
||||
AddDbgRec(RCT_MCT2, &rc2, sizeof(rc2));
|
||||
#endif
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
C4RCPos rc2;
|
||||
rc2.x=iX; rc2.y=iY;
|
||||
AddDbgRec(RCT_MCT2, &rc2, sizeof(rc2));
|
||||
}
|
||||
// apply offset
|
||||
iX-=OffX*ZoomX; iY-=OffY*ZoomY;
|
||||
// check bounds, if loose
|
||||
|
|
|
@ -75,11 +75,12 @@ void C4MassMoverSet::Execute()
|
|||
bool C4MassMoverSet::Create(int32_t x, int32_t y, bool fExecute)
|
||||
{
|
||||
if (Count == C4MassMoverChunk) return false;
|
||||
#ifdef DEBUGREC
|
||||
C4RCMassMover rc;
|
||||
rc.x=x; rc.y=y;
|
||||
AddDbgRec(RCT_MMC, &rc, sizeof(rc));
|
||||
#endif
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
C4RCMassMover rc;
|
||||
rc.x=x; rc.y=y;
|
||||
AddDbgRec(RCT_MMC, &rc, sizeof(rc));
|
||||
}
|
||||
int32_t cptr=CreatePtr;
|
||||
do
|
||||
{
|
||||
|
@ -118,11 +119,12 @@ bool C4MassMover::Init(int32_t tx, int32_t ty)
|
|||
|
||||
void C4MassMover::Cease()
|
||||
{
|
||||
#ifdef DEBUGREC
|
||||
C4RCMassMover rc;
|
||||
rc.x=x; rc.y=y;
|
||||
AddDbgRec(RCT_MMD, &rc, sizeof(rc));
|
||||
#endif
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
C4RCMassMover rc;
|
||||
rc.x=x; rc.y=y;
|
||||
AddDbgRec(RCT_MMD, &rc, sizeof(rc));
|
||||
}
|
||||
::MassMover.Count--;
|
||||
Mat=MNone;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ static const C4Real WindDrift_Factor = itofix(1, 800);
|
|||
void C4PXS::Execute()
|
||||
{
|
||||
#ifdef DEBUGREC_PXS
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
C4RCExecPXS rc;
|
||||
rc.x=x; rc.y=y; rc.iMat=Mat;
|
||||
|
@ -127,6 +128,7 @@ void C4PXS::Execute()
|
|||
// No contact? Free movement
|
||||
x=ctcox; y=ctcoy;
|
||||
#ifdef DEBUGREC_PXS
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
C4RCExecPXS rc;
|
||||
rc.x=x; rc.y=y; rc.iMat=Mat;
|
||||
|
@ -140,10 +142,13 @@ void C4PXS::Execute()
|
|||
void C4PXS::Deactivate()
|
||||
{
|
||||
#ifdef DEBUGREC_PXS
|
||||
C4RCExecPXS rc;
|
||||
rc.x=x; rc.y=y; rc.iMat=Mat;
|
||||
rc.pos = 2;
|
||||
AddDbgRec(RCT_ExecPXS, &rc, sizeof(rc));
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
C4RCExecPXS rc;
|
||||
rc.x=x; rc.y=y; rc.iMat=Mat;
|
||||
rc.pos = 2;
|
||||
AddDbgRec(RCT_ExecPXS, &rc, sizeof(rc));
|
||||
}
|
||||
#endif
|
||||
Mat=MNone;
|
||||
::PXS.Delete(this);
|
||||
|
|
|
@ -26,23 +26,30 @@
|
|||
int RandomCount = 0;
|
||||
unsigned int RandomHold = 0;
|
||||
|
||||
#ifdef DEBUGREC
|
||||
int Random(int iRange)
|
||||
{
|
||||
// next pseudorandom value
|
||||
RandomCount++;
|
||||
C4RCRandom rc;
|
||||
rc.Cnt=RandomCount;
|
||||
rc.Range=iRange;
|
||||
if (iRange==0)
|
||||
rc.Val=0;
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
// next pseudorandom value
|
||||
RandomCount++;
|
||||
C4RCRandom rc;
|
||||
rc.Cnt=RandomCount;
|
||||
rc.Range=iRange;
|
||||
if (iRange==0)
|
||||
rc.Val=0;
|
||||
else
|
||||
{
|
||||
RandomHold = ((uint64_t)RandomHold * 16807) % 2147483647;
|
||||
rc.Val = RandomHold % iRange;
|
||||
}
|
||||
AddDbgRec(RCT_Random, &rc, sizeof(rc));
|
||||
return rc.Val;
|
||||
}
|
||||
else
|
||||
{
|
||||
RandomCount++;
|
||||
if (iRange==0) return 0;
|
||||
RandomHold = ((uint64_t)RandomHold * 16807) % 2147483647;
|
||||
rc.Val = RandomHold % iRange;
|
||||
return RandomHold % iRange;
|
||||
}
|
||||
AddDbgRec(RCT_Random, &rc, sizeof(rc));
|
||||
return rc.Val;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -37,17 +37,7 @@ inline void FixedRandom(DWORD dwSeed)
|
|||
RandomCount=0;
|
||||
}
|
||||
|
||||
#ifdef DEBUGREC
|
||||
int Random(int iRange);
|
||||
#else
|
||||
inline int Random(int iRange)
|
||||
{
|
||||
RandomCount++;
|
||||
if (iRange==0) return 0;
|
||||
RandomHold = ((uint64_t)RandomHold * 16807) % 2147483647;
|
||||
return RandomHold % iRange;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline unsigned int SeededRandom(unsigned int iSeed, unsigned int iRange)
|
||||
{
|
||||
|
|
|
@ -153,11 +153,27 @@ namespace
|
|||
|
||||
ValueProviderAdapt mkValueProviderAdapt(StdMeshInstance::ValueProvider** ValueProvider) { return ValueProviderAdapt(ValueProvider); }
|
||||
|
||||
// Serialize a bone index by name with StdCompiler
|
||||
struct TransformAdapt
|
||||
void CompileFloat(StdCompiler* pComp, float& f)
|
||||
{
|
||||
// TODO: Teach StdCompiler how to handle float
|
||||
if(pComp->isCompiler())
|
||||
{
|
||||
C4Real r;
|
||||
pComp->Value(r);
|
||||
f = fixtof(r);
|
||||
}
|
||||
else
|
||||
{
|
||||
C4Real r = ftofix(f);
|
||||
pComp->Value(r);
|
||||
}
|
||||
}
|
||||
|
||||
// Serialize a transformation matrix by name with StdCompiler
|
||||
struct MatrixAdapt
|
||||
{
|
||||
StdMeshMatrix& Matrix;
|
||||
TransformAdapt(StdMeshMatrix& matrix): Matrix(matrix) {}
|
||||
MatrixAdapt(StdMeshMatrix& matrix): Matrix(matrix) {}
|
||||
|
||||
void CompileFunc(StdCompiler* pComp)
|
||||
{
|
||||
|
@ -167,30 +183,42 @@ namespace
|
|||
for(unsigned int j = 0; j < 4; ++j)
|
||||
{
|
||||
if(i != 0 || j != 0) pComp->Separator();
|
||||
// TODO: Teach StdCompiler how to handle float
|
||||
// pComp->Value(Matrix(i, j));
|
||||
|
||||
if(pComp->isCompiler())
|
||||
{
|
||||
C4Real f;
|
||||
pComp->Value(f);
|
||||
Matrix(i,j) = fixtof(f);
|
||||
}
|
||||
else
|
||||
{
|
||||
C4Real f = ftofix(Matrix(i,j));
|
||||
pComp->Value(f);
|
||||
}
|
||||
CompileFloat(pComp, Matrix(i, j));
|
||||
}
|
||||
}
|
||||
|
||||
pComp->Separator(StdCompiler::SEP_END);
|
||||
}
|
||||
|
||||
ALLOW_TEMP_TO_REF(TransformAdapt)
|
||||
ALLOW_TEMP_TO_REF(MatrixAdapt)
|
||||
};
|
||||
|
||||
TransformAdapt mkTransformAdapt(StdMeshMatrix& Matrix) { return TransformAdapt(Matrix); }
|
||||
|
||||
struct TransformAdapt
|
||||
{
|
||||
StdMeshTransformation& Trans;
|
||||
TransformAdapt(StdMeshTransformation& trans): Trans(trans) {}
|
||||
|
||||
void CompileFunc(StdCompiler* pComp)
|
||||
{
|
||||
pComp->Separator(StdCompiler::SEP_START);
|
||||
CompileFloat(pComp, Trans.translate.x);
|
||||
CompileFloat(pComp, Trans.translate.y);
|
||||
CompileFloat(pComp, Trans.translate.z);
|
||||
CompileFloat(pComp, Trans.rotate.w);
|
||||
CompileFloat(pComp, Trans.rotate.x);
|
||||
CompileFloat(pComp, Trans.rotate.y);
|
||||
CompileFloat(pComp, Trans.rotate.z);
|
||||
CompileFloat(pComp, Trans.scale.x);
|
||||
CompileFloat(pComp, Trans.scale.y);
|
||||
CompileFloat(pComp, Trans.scale.z);
|
||||
pComp->Separator(StdCompiler::SEP_END);
|
||||
}
|
||||
|
||||
ALLOW_TEMP_TO_REF(TransformAdapt);
|
||||
};
|
||||
|
||||
MatrixAdapt mkMatrixAdapt(StdMeshMatrix& Matrix) { return MatrixAdapt(Matrix); }
|
||||
TransformAdapt mkTransformAdapt(StdMeshTransformation& Trans) { return TransformAdapt(Trans); }
|
||||
|
||||
// Reset all animation list entries corresponding to node or its children
|
||||
void ClearAnimationListRecursively(std::vector<StdMeshInstance::AnimationNode*>& list, StdMeshInstance::AnimationNode* node)
|
||||
|
@ -530,6 +558,13 @@ StdMeshInstance::AnimationNode::AnimationNode(const StdMeshAnimation* animation,
|
|||
Leaf.Position = position;
|
||||
}
|
||||
|
||||
StdMeshInstance::AnimationNode::AnimationNode(const StdMeshBone* bone, const StdMeshTransformation& trans):
|
||||
Type(CustomNode), Parent(NULL)
|
||||
{
|
||||
Custom.BoneIndex = bone->Index;
|
||||
Custom.Transformation = new StdMeshTransformation(trans);
|
||||
}
|
||||
|
||||
StdMeshInstance::AnimationNode::AnimationNode(AnimationNode* child_left, AnimationNode* child_right, ValueProvider* weight):
|
||||
Type(LinearInterpolationNode), Parent(NULL)
|
||||
{
|
||||
|
@ -545,6 +580,9 @@ StdMeshInstance::AnimationNode::~AnimationNode()
|
|||
case LeafNode:
|
||||
delete Leaf.Position;
|
||||
break;
|
||||
case CustomNode:
|
||||
delete Custom.Transformation;
|
||||
break;
|
||||
case LinearInterpolationNode:
|
||||
delete LinearInterpolation.ChildLeft;
|
||||
delete LinearInterpolation.ChildRight;
|
||||
|
@ -566,6 +604,12 @@ bool StdMeshInstance::AnimationNode::GetBoneTransform(unsigned int bone, StdMesh
|
|||
if (!track) return false;
|
||||
transformation = track->GetTransformAt(fixtof(Leaf.Position->Value));
|
||||
return true;
|
||||
case CustomNode:
|
||||
if(bone == Custom.BoneIndex)
|
||||
transformation = *Custom.Transformation;
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
case LinearInterpolationNode:
|
||||
if (!LinearInterpolation.ChildLeft->GetBoneTransform(bone, transformation))
|
||||
return LinearInterpolation.ChildRight->GetBoneTransform(bone, transformation);
|
||||
|
@ -585,6 +629,7 @@ void StdMeshInstance::AnimationNode::CompileFunc(StdCompiler* pComp, const StdMe
|
|||
static const StdEnumEntry<NodeType> NodeTypes[] =
|
||||
{
|
||||
{ "Leaf", LeafNode },
|
||||
{ "Custom", CustomNode },
|
||||
{ "LinearInterpolation", LinearInterpolationNode },
|
||||
|
||||
{ NULL, static_cast<NodeType>(0) }
|
||||
|
@ -611,6 +656,22 @@ void StdMeshInstance::AnimationNode::CompileFunc(StdCompiler* pComp, const StdMe
|
|||
|
||||
pComp->Value(mkNamingAdapt(mkValueProviderAdapt(&Leaf.Position), "Position"));
|
||||
break;
|
||||
case CustomNode:
|
||||
if(pComp->isCompiler())
|
||||
{
|
||||
StdCopyStrBuf bone_name;
|
||||
pComp->Value(mkNamingAdapt(toC4CStrBuf(bone_name), "Bone"));
|
||||
const StdMeshBone* bone = Mesh->GetBoneByName(bone_name);
|
||||
if(!bone) pComp->excCorrupt("No such bone: \"%s\"", bone_name.getData());
|
||||
Custom.BoneIndex = bone->Index;
|
||||
}
|
||||
else
|
||||
{
|
||||
pComp->Value(mkNamingAdapt(mkParAdapt(mkDecompileAdapt(Mesh->GetBone(Custom.BoneIndex).Name), StdCompiler::RCT_All), "Bone"));
|
||||
}
|
||||
|
||||
pComp->Value(mkNamingAdapt(mkTransformAdapt(*Custom.Transformation), "Transformation"));
|
||||
break;
|
||||
case LinearInterpolationNode:
|
||||
pComp->Value(mkParAdapt(mkNamingPtrAdapt(LinearInterpolation.ChildLeft, "ChildLeft"), Mesh));
|
||||
pComp->Value(mkParAdapt(mkNamingPtrAdapt(LinearInterpolation.ChildRight, "ChildRight"), Mesh));
|
||||
|
@ -639,14 +700,38 @@ void StdMeshInstance::AnimationNode::DenumeratePointers()
|
|||
case LeafNode:
|
||||
value_provider = dynamic_cast<SerializableValueProvider*>(Leaf.Position);
|
||||
break;
|
||||
case CustomNode:
|
||||
value_provider = NULL;
|
||||
break;
|
||||
case LinearInterpolationNode:
|
||||
value_provider = dynamic_cast<SerializableValueProvider*>(LinearInterpolation.Weight);
|
||||
// non-recursive, StdMeshInstance::DenumeratePointers walks over all nodes
|
||||
break;
|
||||
}
|
||||
|
||||
if(value_provider) value_provider->DenumeratePointers();
|
||||
}
|
||||
|
||||
void StdMeshInstance::AnimationNode::ClearPointers(class C4Object* pObj)
|
||||
{
|
||||
SerializableValueProvider* value_provider = NULL;
|
||||
switch(Type)
|
||||
{
|
||||
case LeafNode:
|
||||
value_provider = dynamic_cast<SerializableValueProvider*>(Leaf.Position);
|
||||
break;
|
||||
case CustomNode:
|
||||
value_provider = NULL;
|
||||
break;
|
||||
case LinearInterpolationNode:
|
||||
value_provider = dynamic_cast<SerializableValueProvider*>(LinearInterpolation.Weight);
|
||||
// non-recursive, StdMeshInstance::ClearPointers walks over all nodes
|
||||
break;
|
||||
}
|
||||
|
||||
if(value_provider) value_provider->ClearPointers(pObj);
|
||||
}
|
||||
|
||||
StdMeshInstance::AttachedMesh::AttachedMesh():
|
||||
Number(0), Parent(NULL), Child(NULL), OwnChild(true), ChildDenumerator(NULL), ParentBone(0), ChildBone(0), FinalTransformDirty(false)
|
||||
{
|
||||
|
@ -711,8 +796,8 @@ void StdMeshInstance::AttachedMesh::CompileFunc(StdCompiler* pComp, DenumeratorF
|
|||
pComp->Value(mkNamingAdapt(Number, "Number"));
|
||||
pComp->Value(mkNamingAdapt(ParentBone, "ParentBone")); // TODO: Save as string
|
||||
pComp->Value(mkNamingAdapt(ChildBone, "ChildBone")); // TODO: Save as string (note we can only resolve this in DenumeratePointers then!)
|
||||
pComp->Value(mkNamingAdapt(mkTransformAdapt(AttachTrans), "AttachTransformation"));
|
||||
|
||||
pComp->Value(mkNamingAdapt(mkMatrixAdapt(AttachTrans), "AttachTransformation"));
|
||||
|
||||
uint8_t dwSyncFlags = static_cast<uint8_t>(Flags);
|
||||
pComp->Value(mkNamingAdapt(mkBitfieldAdapt(dwSyncFlags, AM_Entries), "Flags", 0u));
|
||||
if(pComp->isCompiler()) Flags = dwSyncFlags;
|
||||
|
@ -725,6 +810,11 @@ void StdMeshInstance::AttachedMesh::DenumeratePointers()
|
|||
ChildDenumerator->DenumeratePointers(this);
|
||||
}
|
||||
|
||||
bool StdMeshInstance::AttachedMesh::ClearPointers(class C4Object* pObj)
|
||||
{
|
||||
return ChildDenumerator->ClearPointers(pObj);
|
||||
}
|
||||
|
||||
StdMeshInstance::StdMeshInstance(const StdMesh& mesh, float completion):
|
||||
Mesh(&mesh), SharedVertices(mesh.GetSharedVertices().size()), Completion(completion),
|
||||
BoneTransforms(Mesh->GetNumBones(), StdMeshMatrix::Identity()),
|
||||
|
@ -806,70 +896,16 @@ StdMeshInstance::AnimationNode* StdMeshInstance::PlayAnimation(const StdStrBuf&
|
|||
|
||||
StdMeshInstance::AnimationNode* StdMeshInstance::PlayAnimation(const StdMeshAnimation& animation, int slot, AnimationNode* sibling, ValueProvider* position, ValueProvider* weight)
|
||||
{
|
||||
// Default
|
||||
if (!sibling) sibling = GetRootAnimationForSlot(slot);
|
||||
assert(!sibling || sibling->Slot == slot);
|
||||
|
||||
// Find two subsequent numbers in case we need to create two nodes, so
|
||||
// script can deduce the second node.
|
||||
unsigned int Number1, Number2;
|
||||
for (Number1 = 0; Number1 < AnimationNodes.size(); ++Number1)
|
||||
if (AnimationNodes[Number1] == NULL && (!sibling || Number1+1 == AnimationNodes.size() || AnimationNodes[Number1+1] == NULL))
|
||||
break;
|
||||
/* for(Number2 = Number1+1; Number2 < AnimationNodes.size(); ++Number2)
|
||||
if(AnimationNodes[Number2] == NULL)
|
||||
break;*/
|
||||
Number2 = Number1 + 1;
|
||||
|
||||
position->Value = BoundBy(position->Value, Fix0, ftofix(animation.Length));
|
||||
weight->Value = BoundBy(weight->Value, Fix0, itofix(1));
|
||||
|
||||
if (Number1 == AnimationNodes.size()) AnimationNodes.push_back( (StdMeshInstance::AnimationNode*) NULL);
|
||||
if (sibling && Number2 == AnimationNodes.size()) AnimationNodes.push_back( (StdMeshInstance::AnimationNode*) NULL);
|
||||
|
||||
AnimationNode* child = new AnimationNode(&animation, position);
|
||||
AnimationNodes[Number1] = child;
|
||||
child->Number = Number1;
|
||||
child->Slot = slot;
|
||||
InsertAnimationNode(child, slot, sibling, weight);
|
||||
return child;
|
||||
}
|
||||
|
||||
if (sibling)
|
||||
{
|
||||
AnimationNode* parent = new AnimationNode(child, sibling, weight);
|
||||
AnimationNodes[Number2] = parent;
|
||||
parent->Number = Number2;
|
||||
parent->Slot = slot;
|
||||
|
||||
child->Parent = parent;
|
||||
parent->Parent = sibling->Parent;
|
||||
parent->LinearInterpolation.ChildLeft = sibling;
|
||||
parent->LinearInterpolation.ChildRight = child;
|
||||
if (sibling->Parent)
|
||||
{
|
||||
if (sibling->Parent->LinearInterpolation.ChildLeft == sibling)
|
||||
sibling->Parent->LinearInterpolation.ChildLeft = parent;
|
||||
else
|
||||
sibling->Parent->LinearInterpolation.ChildRight = parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
// set new parent
|
||||
AnimationNodeList::iterator iter = GetStackIterForSlot(slot, false);
|
||||
// slot must not be empty, since sibling uses same slot
|
||||
assert(iter != AnimationStack.end() && *iter != NULL);
|
||||
*iter = parent;
|
||||
}
|
||||
|
||||
sibling->Parent = parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete weight;
|
||||
AnimationNodeList::iterator iter = GetStackIterForSlot(slot, true);
|
||||
assert(!*iter); // we have a sibling if slot is not empty
|
||||
*iter = child;
|
||||
}
|
||||
|
||||
BoneTransformsDirty = true;
|
||||
StdMeshInstance::AnimationNode* StdMeshInstance::PlayAnimation(const StdMeshBone* bone, const StdMeshTransformation& trans, int slot, AnimationNode* sibling, ValueProvider* weight)
|
||||
{
|
||||
AnimationNode* child = new AnimationNode(bone, trans);
|
||||
InsertAnimationNode(child, slot, sibling, weight);
|
||||
return child;
|
||||
}
|
||||
|
||||
|
@ -954,6 +990,13 @@ void StdMeshInstance::SetAnimationPosition(AnimationNode* node, ValueProvider* p
|
|||
BoneTransformsDirty = true;
|
||||
}
|
||||
|
||||
void StdMeshInstance::SetAnimationBoneTransform(AnimationNode* node, const StdMeshTransformation& trans)
|
||||
{
|
||||
assert(node->GetType() == AnimationNode::CustomNode);
|
||||
*node->Custom.Transformation = trans;
|
||||
BoneTransformsDirty = true;
|
||||
}
|
||||
|
||||
void StdMeshInstance::SetAnimationWeight(AnimationNode* node, ValueProvider* weight)
|
||||
{
|
||||
assert(node->GetType() == AnimationNode::LinearInterpolationNode);
|
||||
|
@ -1294,6 +1337,21 @@ void StdMeshInstance::DenumeratePointers()
|
|||
AttachChildren[i]->DenumeratePointers();
|
||||
}
|
||||
|
||||
void StdMeshInstance::ClearPointers(class C4Object* pObj)
|
||||
{
|
||||
for(unsigned int i = 0; i < AnimationNodes.size(); ++i)
|
||||
if(AnimationNodes[i])
|
||||
AnimationNodes[i]->ClearPointers(pObj);
|
||||
|
||||
std::vector<unsigned int> Removal;
|
||||
for(unsigned int i = 0; i < AttachChildren.size(); ++i)
|
||||
if(!AttachChildren[i]->ClearPointers(pObj))
|
||||
Removal.push_back(AttachChildren[i]->Number);
|
||||
|
||||
for(unsigned int i = 0; i < Removal.size(); ++i)
|
||||
DetachMesh(Removal[i]);
|
||||
}
|
||||
|
||||
StdMeshInstance::AnimationNodeList::iterator StdMeshInstance::GetStackIterForSlot(int slot, bool create)
|
||||
{
|
||||
// TODO: bsearch
|
||||
|
@ -1318,6 +1376,72 @@ StdMeshInstance::AnimationNodeList::iterator StdMeshInstance::GetStackIterForSlo
|
|||
return AnimationStack.insert(AnimationStack.end(), NULL);
|
||||
}
|
||||
|
||||
void StdMeshInstance::InsertAnimationNode(AnimationNode* node, int slot, AnimationNode* sibling, ValueProvider* weight)
|
||||
{
|
||||
// Default
|
||||
if (!sibling) sibling = GetRootAnimationForSlot(slot);
|
||||
assert(!sibling || sibling->Slot == slot);
|
||||
|
||||
// Find two subsequent numbers in case we need to create two nodes, so
|
||||
// script can deduce the second node.
|
||||
unsigned int Number1, Number2;
|
||||
for (Number1 = 0; Number1 < AnimationNodes.size(); ++Number1)
|
||||
if (AnimationNodes[Number1] == NULL && (!sibling || Number1+1 == AnimationNodes.size() || AnimationNodes[Number1+1] == NULL))
|
||||
break;
|
||||
/* for(Number2 = Number1+1; Number2 < AnimationNodes.size(); ++Number2)
|
||||
if(AnimationNodes[Number2] == NULL)
|
||||
break;*/
|
||||
Number2 = Number1 + 1;
|
||||
|
||||
weight->Value = BoundBy(weight->Value, Fix0, itofix(1));
|
||||
|
||||
if (Number1 == AnimationNodes.size()) AnimationNodes.push_back( (StdMeshInstance::AnimationNode*) NULL);
|
||||
if (sibling && Number2 == AnimationNodes.size()) AnimationNodes.push_back( (StdMeshInstance::AnimationNode*) NULL);
|
||||
|
||||
AnimationNodes[Number1] = node;
|
||||
node->Number = Number1;
|
||||
node->Slot = slot;
|
||||
|
||||
if (sibling)
|
||||
{
|
||||
AnimationNode* parent = new AnimationNode(node, sibling, weight);
|
||||
AnimationNodes[Number2] = parent;
|
||||
parent->Number = Number2;
|
||||
parent->Slot = slot;
|
||||
|
||||
node->Parent = parent;
|
||||
parent->Parent = sibling->Parent;
|
||||
parent->LinearInterpolation.ChildLeft = sibling;
|
||||
parent->LinearInterpolation.ChildRight = node;
|
||||
if (sibling->Parent)
|
||||
{
|
||||
if (sibling->Parent->LinearInterpolation.ChildLeft == sibling)
|
||||
sibling->Parent->LinearInterpolation.ChildLeft = parent;
|
||||
else
|
||||
sibling->Parent->LinearInterpolation.ChildRight = parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
// set new parent
|
||||
AnimationNodeList::iterator iter = GetStackIterForSlot(slot, false);
|
||||
// slot must not be empty, since sibling uses same slot
|
||||
assert(iter != AnimationStack.end() && *iter != NULL);
|
||||
*iter = parent;
|
||||
}
|
||||
|
||||
sibling->Parent = parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete weight;
|
||||
AnimationNodeList::iterator iter = GetStackIterForSlot(slot, true);
|
||||
assert(!*iter); // we have a sibling if slot is not empty
|
||||
*iter = node;
|
||||
}
|
||||
|
||||
BoneTransformsDirty = true;
|
||||
}
|
||||
|
||||
bool StdMeshInstance::ExecuteAnimationNode(AnimationNode* node)
|
||||
{
|
||||
ValueProvider* provider = NULL;
|
||||
|
@ -1331,6 +1455,9 @@ bool StdMeshInstance::ExecuteAnimationNode(AnimationNode* node)
|
|||
min = Fix0;
|
||||
max = ftofix(node->GetAnimation()->Length);
|
||||
break;
|
||||
case AnimationNode::CustomNode:
|
||||
// No execution necessary
|
||||
return true;
|
||||
case AnimationNode::LinearInterpolationNode:
|
||||
provider = node->GetWeightProvider();
|
||||
min = Fix0;
|
||||
|
@ -1340,6 +1467,8 @@ bool StdMeshInstance::ExecuteAnimationNode(AnimationNode* node)
|
|||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
assert(provider);
|
||||
const C4Real old_value = provider->Value;
|
||||
|
||||
if (!provider->Execute())
|
||||
|
|
|
@ -361,6 +361,7 @@ public:
|
|||
|
||||
virtual void CompileFunc(StdCompiler* pComp);
|
||||
virtual void DenumeratePointers() {}
|
||||
virtual void ClearPointers(class C4Object* pObj) {}
|
||||
};
|
||||
|
||||
// A node in the animation tree
|
||||
|
@ -370,10 +371,11 @@ public:
|
|||
friend class StdMeshInstance;
|
||||
friend class StdMeshUpdate;
|
||||
public:
|
||||
enum NodeType { LeafNode, LinearInterpolationNode };
|
||||
enum NodeType { LeafNode, CustomNode, LinearInterpolationNode };
|
||||
|
||||
AnimationNode();
|
||||
AnimationNode(const StdMeshAnimation* animation, ValueProvider* position);
|
||||
AnimationNode(const StdMeshBone* bone, const StdMeshTransformation& trans);
|
||||
AnimationNode(AnimationNode* child_left, AnimationNode* child_right, ValueProvider* weight);
|
||||
~AnimationNode();
|
||||
|
||||
|
@ -395,6 +397,7 @@ public:
|
|||
|
||||
void CompileFunc(StdCompiler* pComp, const StdMesh* Mesh);
|
||||
void DenumeratePointers();
|
||||
void ClearPointers(class C4Object* pObj);
|
||||
|
||||
protected:
|
||||
int Slot;
|
||||
|
@ -410,6 +413,12 @@ public:
|
|||
ValueProvider* Position;
|
||||
} Leaf;
|
||||
|
||||
struct
|
||||
{
|
||||
unsigned int BoneIndex;
|
||||
StdMeshTransformation* Transformation;
|
||||
} Custom;
|
||||
|
||||
struct
|
||||
{
|
||||
AnimationNode* ChildLeft;
|
||||
|
@ -432,6 +441,7 @@ public:
|
|||
|
||||
virtual void CompileFunc(StdCompiler* pComp, AttachedMesh* attach) = 0;
|
||||
virtual void DenumeratePointers(AttachedMesh* attach) {}
|
||||
virtual bool ClearPointers(class C4Object* pObj) { return true; }
|
||||
};
|
||||
|
||||
typedef Denumerator*(*DenumeratorFactoryFunc)();
|
||||
|
@ -458,6 +468,7 @@ public:
|
|||
|
||||
void CompileFunc(StdCompiler* pComp, DenumeratorFactoryFunc Factory);
|
||||
void DenumeratePointers();
|
||||
bool ClearPointers(class C4Object* pObj);
|
||||
|
||||
private:
|
||||
unsigned int ParentBone;
|
||||
|
@ -486,6 +497,7 @@ public:
|
|||
|
||||
AnimationNode* PlayAnimation(const StdStrBuf& animation_name, int slot, AnimationNode* sibling, ValueProvider* position, ValueProvider* weight);
|
||||
AnimationNode* PlayAnimation(const StdMeshAnimation& animation, int slot, AnimationNode* sibling, ValueProvider* position, ValueProvider* weight);
|
||||
AnimationNode* PlayAnimation(const StdMeshBone* bone, const StdMeshTransformation& trans, int slot, AnimationNode* sibling, ValueProvider* weight);
|
||||
void StopAnimation(AnimationNode* node);
|
||||
|
||||
AnimationNode* GetAnimationNodeByNumber(unsigned int number);
|
||||
|
@ -494,6 +506,7 @@ public:
|
|||
// Set new value providers for a node's position or weight - cannot be in
|
||||
// class AnimationNode since we need to mark BoneTransforms dirty.
|
||||
void SetAnimationPosition(AnimationNode* node, ValueProvider* position);
|
||||
void SetAnimationBoneTransform(AnimationNode* node, const StdMeshTransformation& trans);
|
||||
void SetAnimationWeight(AnimationNode* node, ValueProvider* weight);
|
||||
|
||||
// Update animations; call once a frame
|
||||
|
@ -541,6 +554,7 @@ public:
|
|||
|
||||
void CompileFunc(StdCompiler* pComp, AttachedMesh::DenumeratorFactoryFunc Factory);
|
||||
void DenumeratePointers();
|
||||
void ClearPointers(class C4Object* pObj);
|
||||
|
||||
const StdMesh& GetMesh() const { assert(Mesh != NULL); return *Mesh; }
|
||||
|
||||
|
@ -548,6 +562,7 @@ protected:
|
|||
typedef std::vector<AnimationNode*> AnimationNodeList;
|
||||
|
||||
AnimationNodeList::iterator GetStackIterForSlot(int slot, bool create);
|
||||
void InsertAnimationNode(AnimationNode* node, int slot, AnimationNode* sibling, ValueProvider* weight);
|
||||
bool ExecuteAnimationNode(AnimationNode* node);
|
||||
void ApplyBoneTransformToVertices(const std::vector<StdSubMesh::Vertex>& mesh_vertices, std::vector<StdMeshVertex>& instance_vertices);
|
||||
|
||||
|
|
|
@ -348,6 +348,53 @@ float StdMeshMatrix::Determinant() const
|
|||
- a[0][0]*a[1][2]*a[2][1] - a[0][1]*a[1][0]*a[2][2] - a[0][2]*a[1][1]*a[2][0];
|
||||
}
|
||||
|
||||
StdMeshTransformation StdMeshMatrix::Decompose() const
|
||||
{
|
||||
// Extract the scale part of the matrix
|
||||
const float sx = sqrt(a[0][0]*a[0][0] + a[1][0]*a[1][0] + a[2][0]*a[2][0]);
|
||||
const float sy = sqrt(a[0][1]*a[0][1] + a[1][1]*a[1][1] + a[2][1]*a[2][1]);
|
||||
const float sz = sqrt(a[0][2]*a[0][2] + a[1][2]*a[1][2] + a[2][2]*a[2][2]);
|
||||
|
||||
// What remains is the rotation part
|
||||
// TODO: This can be optimized by not doing the full matrix multiplication
|
||||
StdMeshMatrix rot = Scale(1.0f/sx, 1.0f/sy, 1.0f/sz) * *this;
|
||||
|
||||
// Note that this does not work for skew matrices -- we cannot
|
||||
// represent skews in StdMeshTransformation
|
||||
const float cos_angle = 0.5f * (rot.a[0][0] + rot.a[1][1] + rot.a[2][2] - 1.0f);
|
||||
|
||||
const float rdx = rot.a[2][1] - rot.a[1][2];
|
||||
const float rdy = rot.a[0][2] - rot.a[2][0];
|
||||
const float rdz = rot.a[1][0] - rot.a[0][1];
|
||||
const float det = sqrt(rdx*rdx + rdy*rdy + rdz*rdz);
|
||||
|
||||
const float rx = (rot.a[2][1] - rot.a[1][2]) / det;
|
||||
const float ry = (rot.a[0][2] - rot.a[2][0]) / det;
|
||||
const float rz = (rot.a[1][0] - rot.a[0][1]) / det;
|
||||
|
||||
const float angle = acos(cos_angle);
|
||||
|
||||
StdMeshTransformation trans;
|
||||
trans.scale.x = sx;
|
||||
trans.scale.y = sy;
|
||||
trans.scale.z = sz;
|
||||
trans.rotate = StdMeshQuaternion::AngleAxis(acos(cos_angle), StdMeshVector::Translate(rx, ry, rz));
|
||||
trans.translate.x = a[0][3];
|
||||
trans.translate.y = a[1][3];
|
||||
trans.translate.z = a[2][3];
|
||||
|
||||
#if 0
|
||||
// Double check that the result is correct. This check will fail if
|
||||
// the original matrix has skew components.
|
||||
StdMeshMatrix mat2 = StdMeshMatrix::Transform(trans);
|
||||
for(unsigned int i = 0; i < 3; ++i)
|
||||
for(unsigned int j = 0; j < 4; ++j)
|
||||
assert( fabs(mat2.a[i][j] - a[i][j]) < 1e-3);
|
||||
#endif
|
||||
|
||||
return trans;
|
||||
}
|
||||
|
||||
StdMeshMatrix operator*(const StdMeshMatrix& lhs, const StdMeshMatrix& rhs)
|
||||
{
|
||||
StdMeshMatrix m;
|
||||
|
|
|
@ -95,6 +95,7 @@ public:
|
|||
float operator()(int i, int j) const { return a[i][j]; }
|
||||
|
||||
float Determinant() const;
|
||||
StdMeshTransformation Decompose() const;
|
||||
|
||||
private:
|
||||
// 3x3 orthogonal + translation in last column
|
||||
|
|
|
@ -82,13 +82,13 @@ void StdMeshMaterialUpdate::Add(const StdMeshMaterial* material)
|
|||
}
|
||||
|
||||
StdMeshUpdate::StdMeshUpdate(const StdMesh& old_mesh):
|
||||
OldMesh(&old_mesh), BoneNames(OldMesh->GetNumBones())
|
||||
OldMesh(&old_mesh), BoneNamesByIndex(OldMesh->GetNumBones())
|
||||
{
|
||||
for(std::map<StdCopyStrBuf, StdMeshAnimation>::const_iterator iter = OldMesh->Animations.begin(); iter != OldMesh->Animations.end(); ++iter)
|
||||
AnimationNames[&iter->second] = iter->first;
|
||||
|
||||
for(unsigned int i = 0; i < OldMesh->GetNumBones(); ++i)
|
||||
BoneNames[i] = OldMesh->GetBone(i).Name;
|
||||
BoneNamesByIndex[i] = OldMesh->GetBone(i).Name;
|
||||
}
|
||||
|
||||
void StdMeshUpdate::Update(StdMeshInstance* instance, const StdMesh& new_mesh) const
|
||||
|
@ -110,7 +110,7 @@ void StdMeshUpdate::Update(StdMeshInstance* instance, const StdMesh& new_mesh) c
|
|||
// in the updated mesh, then detach the mesh from its parent
|
||||
if(instance->AttachParent)
|
||||
{
|
||||
if(!instance->AttachParent->SetChildBone(BoneNames[instance->AttachParent->ChildBone]))
|
||||
if(!instance->AttachParent->SetChildBone(BoneNamesByIndex[instance->AttachParent->ChildBone]))
|
||||
{
|
||||
bool OwnChild = instance->AttachParent->OwnChild;
|
||||
instance->AttachParent->Parent->DetachMesh(instance->AttachParent->Number);
|
||||
|
@ -127,7 +127,7 @@ void StdMeshUpdate::Update(StdMeshInstance* instance, const StdMesh& new_mesh) c
|
|||
std::vector<unsigned int> Removal;
|
||||
for(StdMeshInstance::AttachedMeshIter iter = instance->AttachedMeshesBegin(); iter != instance->AttachedMeshesEnd(); ++iter)
|
||||
{
|
||||
if(!(*iter)->SetParentBone(BoneNames[(*iter)->ParentBone]))
|
||||
if(!(*iter)->SetParentBone(BoneNamesByIndex[(*iter)->ParentBone]))
|
||||
{
|
||||
// Do not detach the mesh right here so we can finish iterating over
|
||||
// all attached meshes first.
|
||||
|
@ -166,6 +166,15 @@ bool StdMeshUpdate::UpdateAnimationNode(StdMeshInstance* instance, const StdMesh
|
|||
provider->Value = BoundBy(provider->Value, min, max);
|
||||
return true;
|
||||
}
|
||||
case StdMeshInstance::AnimationNode::CustomNode:
|
||||
{
|
||||
// Update bone index by bone name
|
||||
StdCopyStrBuf bone_name = BoneNamesByIndex[node->Custom.BoneIndex];
|
||||
const StdMeshBone* bone = new_mesh.GetBoneByName(bone_name);
|
||||
if(!bone) return false;
|
||||
node->Custom.BoneIndex = bone->Index;
|
||||
return true;
|
||||
}
|
||||
case StdMeshInstance::AnimationNode::LinearInterpolationNode:
|
||||
{
|
||||
const bool left_result = UpdateAnimationNode(instance, new_mesh, node->GetLeftChild());
|
||||
|
|
|
@ -64,7 +64,7 @@ private:
|
|||
const StdMesh* OldMesh;
|
||||
|
||||
std::map<const StdMeshAnimation*, StdCopyStrBuf> AnimationNames;
|
||||
std::vector<StdCopyStrBuf> BoneNames;
|
||||
std::vector<StdCopyStrBuf> BoneNamesByIndex;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -34,9 +34,7 @@
|
|||
#include <C4GameVersion.h>
|
||||
#include <C4Language.h>
|
||||
|
||||
#ifdef DEBUGREC
|
||||
#include <C4Record.h>
|
||||
#endif
|
||||
|
||||
C4DefList::C4DefList()
|
||||
{
|
||||
|
@ -396,13 +394,14 @@ void C4DefList::CallEveryDefinition()
|
|||
{
|
||||
for (Table::iterator it = table.begin(); it != table.end(); ++it)
|
||||
{
|
||||
#ifdef DEBUGREC
|
||||
// TODO: Might not be synchronous on runtime join since is run by joining
|
||||
// client but not by host. Might need to go to Synchronize().
|
||||
char sz[32+1];
|
||||
strncpy(sz, it->first.ToString(), 32+1);
|
||||
AddDbgRec(RCT_Definition, sz, 32);
|
||||
#endif
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
// TODO: Might not be synchronous on runtime join since is run by joining
|
||||
// client but not by host. Might need to go to Synchronize().
|
||||
char sz[32+1];
|
||||
strncpy(sz, it->first.ToString(), 32+1);
|
||||
AddDbgRec(RCT_Definition, sz, 32);
|
||||
}
|
||||
C4AulParSet Pars(C4VPropList(it->second));
|
||||
it->second->Call(PSF_Definition, &Pars);
|
||||
}
|
||||
|
|
|
@ -201,6 +201,9 @@ C4ValueProviderX::C4ValueProviderX(C4Object* object, C4Real pos, C4Real begin, C
|
|||
|
||||
bool C4ValueProviderX::Execute()
|
||||
{
|
||||
// Object might have been removed
|
||||
if(!Object) return false;
|
||||
|
||||
Value += (End - Begin) * (Object->xdir) / Length;
|
||||
|
||||
if (End > Begin)
|
||||
|
@ -242,6 +245,9 @@ C4ValueProviderY::C4ValueProviderY(C4Object* object, C4Real pos, C4Real begin, C
|
|||
|
||||
bool C4ValueProviderY::Execute()
|
||||
{
|
||||
// Object might have been removed
|
||||
if(!Object) return false;
|
||||
|
||||
Value += (End - Begin) * (Object->ydir) / Length;
|
||||
|
||||
if (End > Begin)
|
||||
|
@ -283,6 +289,9 @@ C4ValueProviderR::C4ValueProviderR(C4Object* object, C4Real begin, C4Real end):
|
|||
|
||||
bool C4ValueProviderR::Execute()
|
||||
{
|
||||
// Object might have been removed
|
||||
if(!Object) return false;
|
||||
|
||||
C4Real r = Object->fix_r;
|
||||
if(r < 0) r += 360;
|
||||
|
||||
|
@ -309,6 +318,9 @@ C4ValueProviderAbsX::C4ValueProviderAbsX(C4Object* object, C4Real pos, C4Real be
|
|||
|
||||
bool C4ValueProviderAbsX::Execute()
|
||||
{
|
||||
// Object might have been removed
|
||||
if(!Object) return false;
|
||||
|
||||
Value += (End - Begin) * Abs(Object->xdir) / Length;
|
||||
|
||||
assert( (End >= Begin && Value >= Begin) || (End <= Begin && Value <= Begin));
|
||||
|
@ -339,6 +351,9 @@ C4ValueProviderAbsY::C4ValueProviderAbsY(C4Object* object, C4Real pos, C4Real be
|
|||
|
||||
bool C4ValueProviderAbsY::Execute()
|
||||
{
|
||||
// Object might have been removed
|
||||
if(!Object) return false;
|
||||
|
||||
Value += (End - Begin) * Abs(Object->ydir) / Length;
|
||||
|
||||
assert( (End >= Begin && Value >= Begin) || (End <= Begin && Value <= Begin));
|
||||
|
@ -369,6 +384,9 @@ C4ValueProviderXDir::C4ValueProviderXDir(C4Object* object, C4Real begin, C4Real
|
|||
|
||||
bool C4ValueProviderXDir::Execute()
|
||||
{
|
||||
// Object might have been removed
|
||||
if(!Object) return false;
|
||||
|
||||
Value = Begin + (End - Begin) * Min<C4Real>(Abs(Object->xdir/MaxXDir), itofix(1));
|
||||
return true;
|
||||
}
|
||||
|
@ -394,6 +412,9 @@ C4ValueProviderYDir::C4ValueProviderYDir(C4Object* object, C4Real begin, C4Real
|
|||
|
||||
bool C4ValueProviderYDir::Execute()
|
||||
{
|
||||
// Object might have been removed
|
||||
if(!Object) return false;
|
||||
|
||||
Value = Begin + (End - Begin) * Min<C4Real>(Abs(Object->ydir/MaxYDir), itofix(1));
|
||||
return true;
|
||||
}
|
||||
|
@ -419,6 +440,9 @@ C4ValueProviderRDir::C4ValueProviderRDir(C4Object* object, C4Real begin, C4Real
|
|||
|
||||
bool C4ValueProviderRDir::Execute()
|
||||
{
|
||||
// Object might have been removed
|
||||
if(!Object) return false;
|
||||
|
||||
Value = Begin + (End - Begin) * Min<C4Real>(Abs(Object->rdir/MaxRDir), itofix(1));
|
||||
return true;
|
||||
}
|
||||
|
@ -444,6 +468,9 @@ C4ValueProviderCosR::C4ValueProviderCosR(C4Object* object, C4Real begin, C4Real
|
|||
|
||||
bool C4ValueProviderCosR::Execute()
|
||||
{
|
||||
// Object might have been removed
|
||||
if(!Object) return false;
|
||||
|
||||
Value = Begin + (End - Begin) * Cos(Object->fix_r + Offset);
|
||||
return true;
|
||||
}
|
||||
|
@ -469,6 +496,9 @@ C4ValueProviderSinR::C4ValueProviderSinR(C4Object* object, C4Real begin, C4Real
|
|||
|
||||
bool C4ValueProviderSinR::Execute()
|
||||
{
|
||||
// Object might have been removed
|
||||
if(!Object) return false;
|
||||
|
||||
Value = Begin + (End - Begin) * Sin(Object->fix_r + Offset);
|
||||
return true;
|
||||
}
|
||||
|
@ -494,6 +524,9 @@ C4ValueProviderCosV::C4ValueProviderCosV(C4Object* object, C4Real begin, C4Real
|
|||
|
||||
bool C4ValueProviderCosV::Execute()
|
||||
{
|
||||
// Object might have been removed
|
||||
if(!Object) return false;
|
||||
|
||||
// TODO: Maybe we can optimize this by using cos(r) = x/sqrt(x*x+y*y), sin(r)=y/sqrt(x*x+y*y)
|
||||
// plus addition theorems for sin or cos.
|
||||
|
||||
|
@ -523,6 +556,9 @@ C4ValueProviderSinV::C4ValueProviderSinV(C4Object* object, C4Real begin, C4Real
|
|||
|
||||
bool C4ValueProviderSinV::Execute()
|
||||
{
|
||||
// Object might have been removed
|
||||
if(!Object) return false;
|
||||
|
||||
// TODO: Maybe we can optimize this by using cos(r) = x/sqrt(x*x+y*y), sin(r)=y/sqrt(x*x+y*y),
|
||||
// plus addition theorems for sin or cos.
|
||||
|
||||
|
@ -551,6 +587,9 @@ C4ValueProviderAction::C4ValueProviderAction(C4Object* object):
|
|||
|
||||
bool C4ValueProviderAction::Execute()
|
||||
{
|
||||
// Object might have been removed
|
||||
if(!Object) return false;
|
||||
|
||||
const C4Action& Action = Object->Action;
|
||||
C4PropList* pActionDef = Object->GetAction();
|
||||
|
||||
|
|
|
@ -87,6 +87,7 @@ public:
|
|||
|
||||
virtual void CompileFunc(StdCompiler* pComp);
|
||||
virtual void DenumeratePointers() { Object.DenumeratePointers(); }
|
||||
virtual void ClearPointers(C4Object* pObj) { if(Object == pObj) Object = NULL; }
|
||||
private:
|
||||
C4ObjectPtr Object;
|
||||
C4Real Begin;
|
||||
|
@ -103,6 +104,7 @@ public:
|
|||
|
||||
virtual void CompileFunc(StdCompiler* pComp);
|
||||
virtual void DenumeratePointers() { Object.DenumeratePointers(); }
|
||||
virtual void ClearPointers(C4Object* pObj) { if(Object == pObj) Object = NULL; }
|
||||
private:
|
||||
C4ObjectPtr Object;
|
||||
C4Real Begin;
|
||||
|
@ -119,6 +121,7 @@ public:
|
|||
|
||||
virtual void CompileFunc(StdCompiler* pComp);
|
||||
virtual void DenumeratePointers() { Object.DenumeratePointers(); }
|
||||
virtual void ClearPointers(C4Object* pObj) { if(Object == pObj) Object = NULL; }
|
||||
private:
|
||||
C4ObjectPtr Object;
|
||||
C4Real Begin;
|
||||
|
@ -134,6 +137,7 @@ public:
|
|||
|
||||
virtual void CompileFunc(StdCompiler* pComp);
|
||||
virtual void DenumeratePointers() { Object.DenumeratePointers(); }
|
||||
virtual void ClearPointers(C4Object* pObj) { if(Object == pObj) Object = NULL; }
|
||||
private:
|
||||
C4ObjectPtr Object;
|
||||
C4Real Begin;
|
||||
|
@ -150,6 +154,7 @@ public:
|
|||
|
||||
virtual void CompileFunc(StdCompiler* pComp);
|
||||
virtual void DenumeratePointers() { Object.DenumeratePointers(); }
|
||||
virtual void ClearPointers(C4Object* pObj) { if(Object == pObj) Object = NULL; }
|
||||
private:
|
||||
C4ObjectPtr Object;
|
||||
C4Real Begin;
|
||||
|
@ -166,6 +171,7 @@ public:
|
|||
|
||||
virtual void CompileFunc(StdCompiler* pComp);
|
||||
virtual void DenumeratePointers() { Object.DenumeratePointers(); }
|
||||
virtual void ClearPointers(C4Object* pObj) { if(Object == pObj) Object = NULL; }
|
||||
private:
|
||||
C4ObjectPtr Object;
|
||||
C4Real Begin;
|
||||
|
@ -182,6 +188,7 @@ public:
|
|||
|
||||
virtual void CompileFunc(StdCompiler* pComp);
|
||||
virtual void DenumeratePointers() { Object.DenumeratePointers(); }
|
||||
virtual void ClearPointers(C4Object* pObj) { if(Object == pObj) Object = NULL; }
|
||||
private:
|
||||
C4ObjectPtr Object;
|
||||
C4Real Begin;
|
||||
|
@ -198,6 +205,7 @@ public:
|
|||
|
||||
virtual void CompileFunc(StdCompiler* pComp);
|
||||
virtual void DenumeratePointers() { Object.DenumeratePointers(); }
|
||||
virtual void ClearPointers(C4Object* pObj) { if(Object == pObj) Object = NULL; }
|
||||
private:
|
||||
C4ObjectPtr Object;
|
||||
C4Real Begin;
|
||||
|
@ -214,6 +222,7 @@ public:
|
|||
|
||||
virtual void CompileFunc(StdCompiler* pComp);
|
||||
virtual void DenumeratePointers() { Object.DenumeratePointers(); }
|
||||
virtual void ClearPointers(C4Object* pObj) { if(Object == pObj) Object = NULL; }
|
||||
private:
|
||||
C4ObjectPtr Object;
|
||||
C4Real Begin;
|
||||
|
@ -230,6 +239,7 @@ public:
|
|||
|
||||
virtual void CompileFunc(StdCompiler* pComp);
|
||||
virtual void DenumeratePointers() { Object.DenumeratePointers(); }
|
||||
virtual void ClearPointers(C4Object* pObj) { if(Object == pObj) Object = NULL; }
|
||||
private:
|
||||
C4ObjectPtr Object;
|
||||
C4Real Begin;
|
||||
|
@ -246,6 +256,7 @@ public:
|
|||
|
||||
virtual void CompileFunc(StdCompiler* pComp);
|
||||
virtual void DenumeratePointers() { Object.DenumeratePointers(); }
|
||||
virtual void ClearPointers(C4Object* pObj) { if(Object == pObj) Object = NULL; }
|
||||
private:
|
||||
C4ObjectPtr Object;
|
||||
C4Real Begin;
|
||||
|
@ -262,6 +273,7 @@ public:
|
|||
|
||||
virtual void CompileFunc(StdCompiler* pComp);
|
||||
virtual void DenumeratePointers() { Object.DenumeratePointers(); }
|
||||
virtual void ClearPointers(C4Object* pObj) { if(Object == pObj) Object = NULL; }
|
||||
private:
|
||||
C4ObjectPtr Object;
|
||||
C4Real Begin;
|
||||
|
@ -278,6 +290,7 @@ public:
|
|||
|
||||
virtual void CompileFunc(StdCompiler* pComp);
|
||||
virtual void DenumeratePointers() { Object.DenumeratePointers(); }
|
||||
virtual void ClearPointers(C4Object* pObj) { if(Object == pObj) Object = NULL; }
|
||||
private:
|
||||
C4ObjectPtr Object;
|
||||
};
|
||||
|
|
|
@ -40,9 +40,7 @@
|
|||
#include <C4Command.h>
|
||||
#include <C4Viewport.h>
|
||||
#include <C4MaterialList.h>
|
||||
#ifdef DEBUGREC
|
||||
#include <C4Record.h>
|
||||
#endif
|
||||
#include <C4SolidMask.h>
|
||||
#include <C4Random.h>
|
||||
#include <C4Log.h>
|
||||
|
@ -127,6 +125,18 @@ void C4MeshDenumerator::DenumeratePointers(StdMeshInstance::AttachedMesh* attach
|
|||
}
|
||||
}
|
||||
|
||||
bool C4MeshDenumerator::ClearPointers(C4Object* pObj)
|
||||
{
|
||||
if(Object == pObj)
|
||||
{
|
||||
Object = NULL;
|
||||
// Return false causes the attached mesh to be deleted by StdMeshInstance
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void DrawVertex(C4Facet &cgo, float tx, float ty, int32_t col, int32_t contact)
|
||||
{
|
||||
if (Inside<int32_t>(tx,cgo.X,cgo.X+cgo.Wdt) && Inside<int32_t>(ty,cgo.Y,cgo.Y+cgo.Hgt))
|
||||
|
@ -322,14 +332,15 @@ void C4Object::AssignRemoval(bool fExitContents)
|
|||
{
|
||||
// check status
|
||||
if (!Status) return;
|
||||
#ifdef DEBUGREC
|
||||
C4RCCreateObj rc;
|
||||
memset(&rc, '\0', sizeof(rc));
|
||||
rc.oei=Number;
|
||||
if (Def && Def->GetName()) strncpy(rc.id, Def->GetName(), 32+1);
|
||||
rc.x=GetX(); rc.y=GetY(); rc.ownr=Owner;
|
||||
AddDbgRec(RCT_DsObj, &rc, sizeof(rc));
|
||||
#endif
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
C4RCCreateObj rc;
|
||||
memset(&rc, '\0', sizeof(rc));
|
||||
rc.oei=Number;
|
||||
if (Def && Def->GetName()) strncpy(rc.id, Def->GetName(), 32+1);
|
||||
rc.x=GetX(); rc.y=GetY(); rc.ownr=Owner;
|
||||
AddDbgRec(RCT_DsObj, &rc, sizeof(rc));
|
||||
}
|
||||
// Destruction call in container
|
||||
if (Contained)
|
||||
{
|
||||
|
@ -479,10 +490,19 @@ void C4Object::UpdateGraphics(bool fGraphicsChanged, bool fTemp)
|
|||
}
|
||||
|
||||
// Keep mesh instance if it uses the same underlying mesh
|
||||
if(!pMeshInstance || !pGraphics->Type == C4DefGraphics::TYPE_Mesh ||
|
||||
if(!pMeshInstance || pGraphics->Type != C4DefGraphics::TYPE_Mesh ||
|
||||
&pMeshInstance->GetMesh() != pGraphics->Mesh)
|
||||
{
|
||||
// If this mesh is attached somewhere, detach it before deletion
|
||||
if(pMeshInstance && pMeshInstance->GetAttachParent() != NULL)
|
||||
{
|
||||
// TODO: If the new mesh has a bone with the same name, we could try updating...
|
||||
StdMeshInstance::AttachedMesh* attach_parent = pMeshInstance->GetAttachParent();
|
||||
attach_parent->Parent->DetachMesh(attach_parent->Number);
|
||||
}
|
||||
|
||||
delete pMeshInstance;
|
||||
|
||||
if (pGraphics->Type == C4DefGraphics::TYPE_Mesh)
|
||||
{
|
||||
pMeshInstance = new StdMeshInstance(*pGraphics->Mesh, Def->GrowthType ? 1.0f : static_cast<float>(Con)/static_cast<float>(FullCon));
|
||||
|
@ -840,8 +860,11 @@ void C4Object::SetOCF()
|
|||
if ((Def->GrabPutGet & C4D_Grab_Put) || (Def->GrabPutGet & C4D_Grab_Get) || (OCF & OCF_Entrance))
|
||||
OCF|=OCF_Container;
|
||||
#ifdef DEBUGREC_OCF
|
||||
C4RCOCF rc = { dwOCFOld, OCF, false };
|
||||
AddDbgRec(RCT_OCF, &rc, sizeof(rc));
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
C4RCOCF rc = { dwOCFOld, OCF, false };
|
||||
AddDbgRec(RCT_OCF, &rc, sizeof(rc));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -908,8 +931,11 @@ void C4Object::UpdateOCF()
|
|||
if ((Def->GrabPutGet & C4D_Grab_Put) || (Def->GrabPutGet & C4D_Grab_Get) || (OCF & OCF_Entrance))
|
||||
OCF|=OCF_Container;
|
||||
#ifdef DEBUGREC_OCF
|
||||
C4RCOCF rc = { dwOCFOld, OCF, true };
|
||||
AddDbgRec(RCT_OCF, &rc, sizeof(rc));
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
C4RCOCF rc = { dwOCFOld, OCF, true };
|
||||
AddDbgRec(RCT_OCF, &rc, sizeof(rc));
|
||||
}
|
||||
#endif
|
||||
#ifdef _DEBUG
|
||||
DEBUGREC_OFF
|
||||
|
@ -1000,15 +1026,16 @@ bool C4Object::ExecLife()
|
|||
|
||||
void C4Object::Execute()
|
||||
{
|
||||
#ifdef DEBUGREC
|
||||
// record debug
|
||||
C4RCExecObj rc;
|
||||
rc.Number=Number;
|
||||
rc.fx=fix_x;
|
||||
rc.fy=fix_y;
|
||||
rc.fr=fix_r;
|
||||
AddDbgRec(RCT_ExecObj, &rc, sizeof(rc));
|
||||
#endif
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
// record debug
|
||||
C4RCExecObj rc;
|
||||
rc.Number=Number;
|
||||
rc.fx=fix_x;
|
||||
rc.fy=fix_y;
|
||||
rc.fr=fix_r;
|
||||
AddDbgRec(RCT_ExecObj, &rc, sizeof(rc));
|
||||
}
|
||||
// reset temporary marker
|
||||
Marker = 0;
|
||||
// OCF
|
||||
|
@ -1815,10 +1842,8 @@ bool C4Object::Promote(int32_t torank, bool exception, bool fForceRankName)
|
|||
|
||||
void C4Object::ClearPointers(C4Object *pObj)
|
||||
{
|
||||
// TODO: Clear pointers on mesh instance:
|
||||
// Check for attach children using pObj's mesh instance
|
||||
// Check for animation nodes refering to pObj (Anim_X, ...).
|
||||
|
||||
// mesh attachments and animation nodes
|
||||
if(pMeshInstance) pMeshInstance->ClearPointers(pObj);
|
||||
// effects
|
||||
if (pEffects) pEffects->ClearPointers(pObj);
|
||||
// contents/contained: not necessary, because it's done in AssignRemoval and StatusDeactivate
|
||||
|
|
|
@ -90,6 +90,7 @@ public:
|
|||
|
||||
virtual void CompileFunc(StdCompiler* pComp, StdMeshInstance::AttachedMesh* attach);
|
||||
virtual void DenumeratePointers(StdMeshInstance::AttachedMesh* attach);
|
||||
virtual bool ClearPointers(C4Object* pObj);
|
||||
};
|
||||
|
||||
class C4Action
|
||||
|
|
|
@ -1830,6 +1830,56 @@ static Nillable<int> FnPlayAnimation(C4Object *Obj, C4String *szAnimation, int i
|
|||
return n_node->GetNumber();
|
||||
}
|
||||
|
||||
static Nillable<int> FnTransformBone(C4Object *Obj, C4String *szBoneName, C4ValueArray* Transformation, int iSlot, C4ValueArray* WeightProvider, Nillable<int> iSibling, Nillable<int> iAttachNumber)
|
||||
{
|
||||
if (!Obj) return C4Void();
|
||||
if (!Obj->pMeshInstance) return C4Void();
|
||||
if (iSlot == 0) return C4Void(); // Reserved for ActMap animations
|
||||
if (!Transformation) return C4Void();
|
||||
if (!WeightProvider) return C4Void();
|
||||
|
||||
StdMeshInstance* Instance = Obj->pMeshInstance;
|
||||
if (!iAttachNumber.IsNil())
|
||||
{
|
||||
const StdMeshInstance::AttachedMesh* Attached = Instance->GetAttachedMeshByNumber(iAttachNumber);
|
||||
// OwnChild is set if an object's instance is attached. In that case the animation should be set directly on that object.
|
||||
if (!Attached || !Attached->OwnChild) return C4Void();
|
||||
Instance = Attached->Child;
|
||||
}
|
||||
|
||||
StdMeshInstance::AnimationNode* s_node = NULL;
|
||||
if (!iSibling.IsNil())
|
||||
{
|
||||
s_node = Instance->GetAnimationNodeByNumber(iSibling);
|
||||
if (!s_node || s_node->GetSlot() != iSlot) return C4Void();
|
||||
}
|
||||
|
||||
const StdMeshBone* bone = Instance->GetMesh().GetBoneByName(szBoneName->GetData());
|
||||
if(!bone) return C4Void();
|
||||
|
||||
StdMeshInstance::ValueProvider* w_provider = CreateValueProviderFromArray(Obj, *WeightProvider);
|
||||
if (!w_provider) return C4Void();
|
||||
|
||||
StdMeshMatrix matrix;
|
||||
if (!C4ValueToMatrix(*Transformation, &matrix))
|
||||
throw new C4AulExecError("TransformBone: Transformation is not a valid 3x4 matrix");
|
||||
|
||||
// For bone transformations we cannot use general matrix transformations, but we use decomposed
|
||||
// translate, scale and rotation components (represented by the StdMeshTransformation class). This
|
||||
// is less generic since it does not support skewing.
|
||||
// Still, in the script API we want to expose a matrix parameter so that the convenient Trans_*
|
||||
// functions can be used. We decompose the passed matrix at this point. If the matrix indeed has
|
||||
// skewing components, the results will probably look strange since the decomposition would yield
|
||||
// bogus values, however I don't think that's a practical use case. In the worst case we could add
|
||||
// a check here and return nil if the matrix cannot be decomposed.
|
||||
StdMeshTransformation trans = matrix.Decompose();
|
||||
|
||||
StdMeshInstance::AnimationNode* n_node = Instance->PlayAnimation(bone, trans, iSlot, s_node, w_provider);
|
||||
if (!n_node) return C4Void();
|
||||
|
||||
return n_node->GetNumber();
|
||||
}
|
||||
|
||||
static bool FnStopAnimation(C4Object *Obj, Nillable<int> iAnimationNumber, Nillable<int> iAttachNumber)
|
||||
{
|
||||
if (!Obj) return false;
|
||||
|
@ -1974,6 +2024,35 @@ static bool FnSetAnimationPosition(C4Object *Obj, Nillable<int> iAnimationNumber
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool FnSetAnimationBoneTransform(C4Object *Obj, Nillable<int> iAnimationNumber, C4ValueArray* Transformation, Nillable<int> iAttachNumber)
|
||||
{
|
||||
if (!Obj) return false;
|
||||
if (!Obj->pMeshInstance) return false;
|
||||
if (iAnimationNumber.IsNil()) return false; // distinguish nil from 0
|
||||
|
||||
StdMeshInstance* Instance = Obj->pMeshInstance;
|
||||
if (!iAttachNumber.IsNil())
|
||||
{
|
||||
const StdMeshInstance::AttachedMesh* Attached = Instance->GetAttachedMeshByNumber(iAttachNumber);
|
||||
// OwnChild is set if an object's instance is attached. In that case the animation should be set directly on that object.
|
||||
if (!Attached || !Attached->OwnChild) return false;
|
||||
Instance = Attached->Child;
|
||||
}
|
||||
|
||||
StdMeshInstance::AnimationNode* node = Instance->GetAnimationNodeByNumber(iAnimationNumber);
|
||||
// slot 0 is reserved for ActMap animations
|
||||
if (!node || node->GetSlot() == 0 || node->GetType() != StdMeshInstance::AnimationNode::CustomNode) return false;
|
||||
|
||||
StdMeshMatrix matrix;
|
||||
if (!C4ValueToMatrix(*Transformation, &matrix))
|
||||
throw new C4AulExecError("TransformBone: Transformation is not a valid 3x4 matrix");
|
||||
// Here the same remark applies as in FnTransformBone
|
||||
StdMeshTransformation trans = matrix.Decompose();
|
||||
|
||||
Instance->SetAnimationBoneTransform(node, trans);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool FnSetAnimationWeight(C4Object *Obj, Nillable<int> iAnimationNumber, C4ValueArray* WeightProvider, Nillable<int> iAttachNumber)
|
||||
{
|
||||
if (!Obj) return false;
|
||||
|
@ -2513,6 +2592,7 @@ void InitObjectFunctionMap(C4AulScriptEngine *pEngine)
|
|||
AddFunc(pEngine, "ExecuteCommand", FnExecuteCommand);
|
||||
|
||||
AddFunc(pEngine, "PlayAnimation", FnPlayAnimation);
|
||||
AddFunc(pEngine, "TransformBone", FnTransformBone);
|
||||
AddFunc(pEngine, "StopAnimation", FnStopAnimation);
|
||||
AddFunc(pEngine, "GetRootAnimation", FnGetRootAnimation);
|
||||
AddFunc(pEngine, "GetAnimationLength", FnGetAnimationLength);
|
||||
|
@ -2520,6 +2600,7 @@ void InitObjectFunctionMap(C4AulScriptEngine *pEngine)
|
|||
AddFunc(pEngine, "GetAnimationPosition", FnGetAnimationPosition);
|
||||
AddFunc(pEngine, "GetAnimationWeight", FnGetAnimationWeight);
|
||||
AddFunc(pEngine, "SetAnimationPosition", FnSetAnimationPosition);
|
||||
AddFunc(pEngine, "SetAnimationBoneTransform", FnSetAnimationBoneTransform);
|
||||
AddFunc(pEngine, "SetAnimationWeight", FnSetAnimationWeight);
|
||||
AddFunc(pEngine, "AttachMesh", FnAttachMesh);
|
||||
AddFunc(pEngine, "DetachMesh", FnDetachMesh);
|
||||
|
|
|
@ -109,9 +109,8 @@ void C4LSectors::Add(C4Object *pObj, C4ObjectList *pMainList)
|
|||
{
|
||||
pSct->ObjectShapes.Add(pObj, C4ObjectList::stMain, pMainList);
|
||||
}
|
||||
#ifdef DEBUGREC
|
||||
pObj->Area.DebugRec(pObj, 'A');
|
||||
#endif
|
||||
if (Config.General.DebugRec)
|
||||
pObj->Area.DebugRec(pObj, 'A');
|
||||
}
|
||||
|
||||
void C4LSectors::Update(C4Object *pObj, C4ObjectList *pMainList)
|
||||
|
@ -152,9 +151,8 @@ void C4LSectors::Update(C4Object *pObj, C4ObjectList *pMainList)
|
|||
}
|
||||
// Update area
|
||||
pObj->Area = NewArea;
|
||||
#ifdef DEBUGREC
|
||||
pObj->Area.DebugRec(pObj, 'U');
|
||||
#endif
|
||||
if (Config.General.DebugRec)
|
||||
pObj->Area.DebugRec(pObj, 'U');
|
||||
}
|
||||
|
||||
void C4LSectors::Remove(C4Object *pObj)
|
||||
|
@ -187,9 +185,8 @@ void C4LSectors::Remove(C4Object *pObj)
|
|||
// Remove from all sectors in shape area
|
||||
for (pSct = pObj->Area.First(); pSct; pSct = pObj->Area.Next(pSct))
|
||||
pSct->ObjectShapes.Remove(pObj);
|
||||
#ifdef DEBUGREC
|
||||
pObj->Area.DebugRec(pObj, 'R');
|
||||
#endif
|
||||
if (Config.General.DebugRec)
|
||||
pObj->Area.DebugRec(pObj, 'R');
|
||||
}
|
||||
|
||||
void C4LSectors::AssertObjectNotInList(C4Object *pObj)
|
||||
|
@ -338,7 +335,6 @@ C4ObjectList *C4LArea::NextObjectShapes(C4ObjectList *pPrev, C4LSector **ppSct)
|
|||
return &(*ppSct)->ObjectShapes;
|
||||
}
|
||||
|
||||
#ifdef DEBUGREC
|
||||
void C4LArea::DebugRec(class C4Object *pObj, char cMarker)
|
||||
{
|
||||
C4RCArea rc;
|
||||
|
@ -352,4 +348,3 @@ void C4LArea::DebugRec(class C4Object *pObj, char cMarker)
|
|||
rc.out = !!pOut;
|
||||
AddDbgRec(RCT_Area, &rc, sizeof(C4RCArea));
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -126,9 +126,7 @@ public:
|
|||
{ *ppSct=NULL; return NextObjectShapes(NULL, ppSct); }
|
||||
C4ObjectList *NextObjectShapes(C4ObjectList *pPrev, C4LSector **ppSct); // get next object shapes list of this area
|
||||
|
||||
#ifdef DEBUGREC
|
||||
void DebugRec(class C4Object *pObj, char cMarker);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -57,14 +57,15 @@ void C4Shape::Clear()
|
|||
|
||||
void C4Shape::Rotate(C4Real Angle, bool bUpdateVertices)
|
||||
{
|
||||
#ifdef DEBUGREC
|
||||
C4RCRotVtx rc;
|
||||
rc.x=x; rc.y=y; rc.wdt=Wdt; rc.hgt=Hgt; rc.r=Angle;
|
||||
int32_t i = 0;
|
||||
for (; i<4; ++i)
|
||||
{ rc.VtxX[i]=VtxX[i]; rc.VtxY[i]=VtxY[i]; }
|
||||
AddDbgRec(RCT_RotVtx1, &rc, sizeof(rc));
|
||||
#endif
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
rc.x=x; rc.y=y; rc.wdt=Wdt; rc.hgt=Hgt; rc.r=Angle;
|
||||
for (; i<4; ++i)
|
||||
{ rc.VtxX[i]=VtxX[i]; rc.VtxY[i]=VtxY[i]; }
|
||||
AddDbgRec(RCT_RotVtx1, &rc, sizeof(rc));
|
||||
}
|
||||
int32_t cnt,nvtx,nvty,nwdt,nhgt;
|
||||
|
||||
C4Real mtx[4];
|
||||
|
@ -123,12 +124,13 @@ void C4Shape::Rotate(C4Real Angle, bool bUpdateVertices)
|
|||
}
|
||||
Wdt = nwdt;
|
||||
Hgt = nhgt;
|
||||
#ifdef DEBUGREC
|
||||
rc.x=x; rc.y=y; rc.wdt=Wdt; rc.hgt=Hgt;
|
||||
for (i=0; i<4; ++i)
|
||||
{ rc.VtxX[i]=VtxX[i]; rc.VtxY[i]=VtxY[i]; }
|
||||
AddDbgRec(RCT_RotVtx2, &rc, sizeof(rc));
|
||||
#endif
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
rc.x=x; rc.y=y; rc.wdt=Wdt; rc.hgt=Hgt;
|
||||
for (i=0; i<4; ++i)
|
||||
{ rc.VtxX[i]=VtxX[i]; rc.VtxY[i]=VtxY[i]; }
|
||||
AddDbgRec(RCT_RotVtx2, &rc, sizeof(rc));
|
||||
}
|
||||
}
|
||||
|
||||
void C4Shape::Stretch(int32_t iCon, bool bUpdateVertices)
|
||||
|
|
|
@ -258,6 +258,7 @@ LRESULT APIENTRY ViewportWinProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPa
|
|||
|
||||
// compute scancode
|
||||
C4KeyCode scancode = (((unsigned int)lParam) >> 16) & 0xFF;
|
||||
ConvertToUnixScancode(wParam, &scancode);
|
||||
|
||||
// Process message
|
||||
switch (uMsg)
|
||||
|
@ -472,6 +473,7 @@ LRESULT APIENTRY DialogWinProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPara
|
|||
|
||||
// compute scancode
|
||||
C4KeyCode scancode = (((unsigned int)lParam) >> 16) & 0xFF;
|
||||
ConvertToUnixScancode(wParam, &scancode);
|
||||
|
||||
// Process message
|
||||
switch (uMsg)
|
||||
|
|
|
@ -887,33 +887,36 @@ C4AulBCC *C4AulExec::Call(C4AulFunc *pFunc, C4Value *pReturn, C4Value *pPars, C4
|
|||
throw new C4AulExecError("using removed object");
|
||||
|
||||
#ifdef DEBUGREC_SCRIPT
|
||||
StdStrBuf sCallText;
|
||||
if (pContext && pContext->GetObject())
|
||||
sCallText.AppendFormat("Object(%d): ", pContext->GetObject()->Number);
|
||||
sCallText.Append(pFunc->GetName());
|
||||
sCallText.AppendChar('(');
|
||||
for (int i=0; i<C4AUL_MAX_Par; ++i)
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
if (i) sCallText.AppendChar(',');
|
||||
C4Value &rV = pPars[i];
|
||||
if (rV.GetType() == C4V_String)
|
||||
StdStrBuf sCallText;
|
||||
if (pContext && pContext->GetObject())
|
||||
sCallText.AppendFormat("Object(%d): ", pContext->GetObject()->Number);
|
||||
sCallText.Append(pFunc->GetName());
|
||||
sCallText.AppendChar('(');
|
||||
for (int i=0; i<C4AUL_MAX_Par; ++i)
|
||||
{
|
||||
C4String *s = rV.getStr();
|
||||
if (!s)
|
||||
sCallText.Append("(Snull)");
|
||||
else
|
||||
if (i) sCallText.AppendChar(',');
|
||||
C4Value &rV = pPars[i];
|
||||
if (rV.GetType() == C4V_String)
|
||||
{
|
||||
sCallText.Append("\"");
|
||||
sCallText.Append(s->GetData());
|
||||
sCallText.Append("\"");
|
||||
C4String *s = rV.getStr();
|
||||
if (!s)
|
||||
sCallText.Append("(Snull)");
|
||||
else
|
||||
{
|
||||
sCallText.Append("\"");
|
||||
sCallText.Append(s->GetData());
|
||||
sCallText.Append("\"");
|
||||
}
|
||||
}
|
||||
else
|
||||
sCallText.Append(rV.GetDataString());
|
||||
}
|
||||
else
|
||||
sCallText.Append(rV.GetDataString());
|
||||
sCallText.AppendChar(')');
|
||||
sCallText.AppendChar(';');
|
||||
AddDbgRec(RCT_AulFunc, sCallText.getData(), sCallText.getLength()+1);
|
||||
}
|
||||
sCallText.AppendChar(')');
|
||||
sCallText.AppendChar(';');
|
||||
AddDbgRec(RCT_AulFunc, sCallText.getData(), sCallText.getLength()+1);
|
||||
#endif
|
||||
|
||||
// Execute
|
||||
|
@ -1076,9 +1079,12 @@ C4Value C4AulScriptFunc::Exec(C4PropList * p, C4Value pPars[], bool fPassErrors)
|
|||
C4Value C4AulScript::DirectExec(C4Object *pObj, const char *szScript, const char *szContext, bool fPassErrors, C4AulScriptContext* context)
|
||||
{
|
||||
#ifdef DEBUGREC_SCRIPT
|
||||
AddDbgRec(RCT_DirectExec, szScript, strlen(szScript)+1);
|
||||
int32_t iObjNumber = pObj ? pObj->Number : -1;
|
||||
AddDbgRec(RCT_DirectExec, &iObjNumber, sizeof(int32_t));
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
AddDbgRec(RCT_DirectExec, szScript, strlen(szScript)+1);
|
||||
int32_t iObjNumber = pObj ? pObj->Number : -1;
|
||||
AddDbgRec(RCT_DirectExec, &iObjNumber, sizeof(int32_t));
|
||||
}
|
||||
#endif
|
||||
// profiler
|
||||
AulExec.StartDirectExec();
|
||||
|
|
|
@ -26,9 +26,7 @@
|
|||
#include <C4GameObjects.h>
|
||||
#include <C4Game.h>
|
||||
#include <C4Object.h>
|
||||
#ifdef DEBUGREC
|
||||
#include <C4Record.h>
|
||||
#endif
|
||||
|
||||
void C4PropList::AddRef(C4Value *pRef)
|
||||
{
|
||||
|
@ -609,9 +607,12 @@ void C4PropList::SetPropertyByS(C4String * k, const C4Value & to)
|
|||
//C4Property p(k, to);
|
||||
//Properties.Add(p);
|
||||
#ifdef DEBUGREC_SCRIPT
|
||||
// deactivate this debugrec for now, because property orders seem to be out of sync
|
||||
// after loading at the moment. might need to invastigate the cause later...
|
||||
//if (k->GetCStr()) AddDbgRec(RCT_SetProperty, k->GetCStr(), strlen(k->GetCStr())+1);
|
||||
if (Config.General.DebugRec)
|
||||
{
|
||||
// deactivate this debugrec for now, because property orders seem to be out of sync
|
||||
// after loading at the moment. might need to invastigate the cause later...
|
||||
//if (k->GetCStr()) AddDbgRec(RCT_SetProperty, k->GetCStr(), strlen(k->GetCStr())+1);
|
||||
}
|
||||
#endif
|
||||
Properties.Add(C4Property(k, to));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue