Merge default into rope

rope
Armin Burgmeier 2012-06-07 21:36:29 +02:00
commit cd67961aa6
102 changed files with 2138 additions and 1863 deletions

View File

@ -530,6 +530,7 @@ set(OC_CLONK_SOURCES
src/script/C4AulDefFunc.h
src/script/C4AulExec.cpp
src/script/C4AulExec.h
src/script/C4AulFunc.cpp
src/script/C4AulFunc.h
src/script/C4Aul.h
src/script/C4AulLink.cpp
@ -957,6 +958,7 @@ add_executable(c4script
src/lib/C4Random.cpp
src/script/C4Aul.cpp
src/script/C4AulExec.cpp
src/script/C4AulFunc.cpp
src/script/C4AulLink.cpp
src/script/C4AulParse.cpp
src/script/C4StringTable.cpp
@ -1093,9 +1095,6 @@ endforeach()
if(CMAKE_COMPILER_IS_GNUCXX)
include(GccPchSupport)
if(NOT DEFINED USE_GCC_PCH)
message("Using GCC precompiled headers! USE_GCC_PCH=Off to disable.")
endif()
option(USE_GCC_PCH "Use GCC precompiled headers" ON)
endif()
if(USE_GCC_PCH)

View File

@ -511,6 +511,7 @@ src/script/C4AulDebug.h \
src/script/C4AulDefFunc.h \
src/script/C4AulExec.cpp \
src/script/C4AulExec.h \
src/script/C4AulFunc.cpp \
src/script/C4AulFunc.h \
src/script/C4Aul.h \
src/script/C4AulLink.cpp \
@ -687,6 +688,7 @@ src/lib/C4Real.cpp \
src/lib/C4Random.cpp \
src/script/C4Aul.cpp \
src/script/C4AulExec.cpp \
src/script/C4AulFunc.cpp \
src/script/C4AulLink.cpp \
src/script/C4AulParse.cpp \
src/script/C4StringTable.cpp \

View File

@ -72,7 +72,6 @@
</examples>
<related>
<funclink>InsertMaterial</funclink>
<funclink>SetLandscapePixel</funclink>
</related>
</func>
<author>Sven2</author><date>2002-05</date>

View File

@ -0,0 +1,32 @@
<?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>GetProperties</title>
<category>Objects</category>
<subcat>Properties</subcat>
<version>5.3 OC</version>
<syntax>
<rtype>array</rtype>
<params>
<param>
<type>proplist</type>
<name>object</name>
<desc>Object to request property from, <code>nil</code> in local calls.</desc>
<optional />
</param>
</params>
</syntax>
<desc>Returns the names of all properties of <code>object</code>.</desc>
<related><funclink>SetProperty</funclink></related>
<related><funclink>GetProperty</funclink></related>
<examples>
<example>
<code>GetProperties({foo = 1, bar = 2}) == ["bar", "foo"]</code>
</example>
</examples>
</func>
<author>Günther</author><date>2012</date>
</funcs>

View File

@ -27,6 +27,7 @@
</syntax>
<desc>Returns the property <code>key</code> of <code>object</code>.</desc>
<related><funclink>SetProperty</funclink></related>
<related><funclink>GetProperties</funclink></related>
</func>
<author>Günther</author><date>2009-05</date>
</funcs>

View File

@ -1,40 +0,0 @@
<?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>SetLandscapePixel</title>
<category>Landscape</category>
<version>5.1 OC</version>
<syntax>
<rtype>bool</rtype>
<params>
<param>
<type>int</type>
<name>x</name>
<desc>X position of the pixel to be set; relative coordinates in local calls</desc>
</param>
<param>
<type>int</type>
<name>y</name>
<desc>Y position of the pixel to be set; relative coordinates in local calls</desc>
</param>
<param>
<type>int</type>
<name>dwValue</name>
<desc>32 bit color value of the pixel</desc>
</param>
</params>
</syntax>
<desc>Sets a pixel in the landscape. Not available in the old 8 bit graphics system.</desc>
<examples>
<example>
<code>SetLandscapePixel(0, 0, <funclink>RGB</funclink>(185, 127, 0));</code>
<text>Colors the landscape pixel directly behind the calling object brown.</text>
</example>
</examples>
<related><funclink>RGB</funclink></related>
</func>
<author>Sven2</author><date>2002-04</date>
</funcs>

View File

@ -1,42 +0,0 @@
/* larger dynamite explosion */
#appendto RelaunchContainer
private func OpenWeaponMenu(object clonk)
{
if (!menu)
{
var weapons = WeaponList();
if(weapons)
{
menu = clonk->CreateRingMenu(Clonk, this);
for (var weapon in weapons)
{
if(weapon == Firestone) menu->AddItem(weapon,2);
else if(weapon == Dynamite) menu->AddItem(weapon,2);
else menu->AddItem(weapon);
}
menu->Show();
}
}
}
public func Selected(object menu, object selector, bool alt)
{
if (!selector)
return false;
for (var i = 0; i < selector->GetAmount(); i++)
{
var newobj = CreateObject(selector->GetSymbol());
if (newobj->GetID() == Bow)
newobj->CreateContents(Arrow);
if (newobj->GetID() == Musket)
newobj->CreateContents(LeadShot);
Contents()->Collect(newobj);
}
menu->Show();
RelaunchClonk();
return true;
}

View File

@ -1,5 +1,3 @@
/* larger dynamite explosion */
#appendto RelaunchContainer
private func OpenWeaponMenu(object clonk)
@ -14,30 +12,10 @@ private func OpenWeaponMenu(object clonk)
{
if(weapon == Firestone) menu->AddItem(weapon,2);
else if(weapon == Dynamite) menu->AddItem(weapon,2);
else menu->AddItem(weapon);
else menu->AddItem(weapon, 1);
}
menu->Show();
menu->SetUncloseable();
}
}
}
public func Selected(object menu, object selector, bool alt)
{
if (!selector)
return false;
for (var i = 0; i < selector->GetAmount(); i++)
{
var newobj = CreateObject(selector->GetSymbol());
if (newobj->GetID() == Bow)
newobj->CreateContents(Arrow);
if (newobj->GetID() == Musket)
newobj->CreateContents(LeadShot);
Contents()->Collect(newobj);
}
menu->Show();
RelaunchClonk();
return true;
}

View File

@ -64,9 +64,9 @@ public func IsProjectileTarget(target,shooter)
public func OnProjectileHit(object shot)
{
DoFireworks();
var gol = FindObject(Find_ID(Goal_SaveTheWindmills));
if(gol) gol->IncShotScore(shot->GetController());
DoFireworks();
return 1;
}

View File

@ -12,22 +12,22 @@ Rules=Rule_TeamAccount=1
[Player1]
Wealth=0
Crew=Clonk=1
Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;Loam=1;
Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;ToolsWorkshop_SplitFirestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;Loam=1;
[Player2]
Wealth=0
Crew=Clonk=1
Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;Loam=1;
Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;ToolsWorkshop_SplitFirestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;Loam=1;
[Player3]
Wealth=0
Crew=Clonk=1
Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;Loam=1;
Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;ToolsWorkshop_SplitFirestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;Loam=1;
[Player4]
Wealth=0
Crew=Clonk=1
Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;Loam=1;
Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;ToolsWorkshop_SplitFirestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;Loam=1;
[Landscape]
Sky=Clouds2

View File

@ -14,26 +14,26 @@ Rules=Rule_TeamAccount=1;
[Player1]
Wealth=10
Crew=Clonk=2
Knowledge=Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Pump=1;Chest=1;Idol=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;Bucket=1;Pipe=1;
HomeBaseMaterial=Shovel=2;Pickaxe=2;Axe=2;Hammer=2;Dynamite=10;Loam=10;Wood=20;Metal=10;Clonk=2;Lorry=1;
Knowledge=Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Pump=1;Chest=1;Idol=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Barrel=1;Dynamite=1;DynamiteBox=1;Bucket=1;Pipe=1;
HomeBaseMaterial=Shovel=2;Pickaxe=2;Axe=2;Hammer=2;Dynamite=10;Loam=10;Wood=20;Metal=10;Clonk=2;Lorry=1;ToolsWorkshop_SplitFirestone=1;
[Player2]
Wealth=10
Crew=Clonk=2
Knowledge=Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Pump=1;Chest=1;Idol=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;Bucket=1;Pipe=1;
HomeBaseMaterial=Shovel=2;Pickaxe=2;Axe=2;Hammer=2;Dynamite=10;Loam=10;Wood=20;Metal=10;Clonk=2;Lorry=1;
Knowledge=Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Pump=1;Chest=1;Idol=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Barrel=1;Dynamite=1;DynamiteBox=1;Bucket=1;Pipe=1;
HomeBaseMaterial=Shovel=2;Pickaxe=2;Axe=2;Hammer=2;Dynamite=10;Loam=10;Wood=20;Metal=10;Clonk=2;Lorry=1;ToolsWorkshop_SplitFirestone=1;
[Player3]
Wealth=10
Crew=Clonk=2
Knowledge=Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Pump=1;Chest=1;Idol=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;Bucket=1;Pipe=1;
HomeBaseMaterial=Shovel=2;Pickaxe=2;Axe=2;Hammer=2;Dynamite=10;Loam=10;Wood=20;Metal=10;Clonk=2;Lorry=1;
Knowledge=Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Pump=1;Chest=1;Idol=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Barrel=1;Dynamite=1;DynamiteBox=1;Bucket=1;Pipe=1;
HomeBaseMaterial=Shovel=2;Pickaxe=2;Axe=2;Hammer=2;Dynamite=10;Loam=10;Wood=20;Metal=10;Clonk=2;Lorry=1;ToolsWorkshop_SplitFirestone=1;
[Player4]
Wealth=10
Crew=Clonk=2
Knowledge=Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Pump=1;Chest=1;Idol=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;Bucket=1;Pipe=1;
HomeBaseMaterial=Shovel=2;Pickaxe=2;Axe=2;Hammer=2;Dynamite=10;Loam=10;Wood=20;Metal=10;Clonk=2;Lorry=1;
Knowledge=Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Pump=1;Chest=1;Idol=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Barrel=1;Dynamite=1;DynamiteBox=1;Bucket=1;Pipe=1;
HomeBaseMaterial=Shovel=2;Pickaxe=2;Axe=2;Hammer=2;Dynamite=10;Loam=10;Wood=20;Metal=10;Clonk=2;Lorry=1;ToolsWorkshop_SplitFirestone=1;
[Landscape]
InEarth=Rock=1;Firestone=3;Loam=2

View File

@ -13,16 +13,13 @@ protected func Initialize()
goal->SetWealthGoal(400);
// Place some trees.
for (var i = 0; i < 16 + Random(4); i++)
PlaceVegetation(Tree_Coniferous, 0, LandscapeHeight() / 3, LandscapeWidth(), LandscapeHeight(), 1000 * (61 + Random(40)));
// place some sprout berries
var bush = PlaceVegetation(SproutBerryBush, 0, LandscapeHeight() / 3, LandscapeWidth(), LandscapeHeight(), 100000);
if(bush)
for (var i = 0; i < 2; i++)
PlaceVegetation(SproutBerryBush, bush->GetX() - 200, bush->GetY() - 200, 400, 400, 100000);
//Tree_Coniferous->Place(16+Random(4), Rectangle(0,LandscapeHeight()/3, LandscapeWidth(), LandscapeHeight()));
PlaceForest([Tree_Coniferous, SproutBerryBush],0, LandscapeHeight()/2+50,nil, true);
PlaceGrass(100);
CreateEnvironmentObjects("Temperate");
// Set time of day to evening and create some clouds and celestials.
Cloud->Place(10);
Cloud->SetPrecipitation("Water", 15);

View File

@ -14,25 +14,25 @@ Rules=Rule_TeamAccount=1;
[Player1]
Wealth=40
Crew=Clonk=2
Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;Bucket=1;
Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;ToolsWorkshop_SplitFirestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;Bucket=1;
HomeBaseMaterial=Shovel=2;Pickaxe=2;Axe=2;Hammer=2;Dynamite=10;Loam=10;Wood=20;Metal=10;Clonk=2;Lorry=1;
[Player2]
Wealth=40
Crew=Clonk=2
Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;Bucket=1;
Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;ToolsWorkshop_SplitFirestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;Bucket=1;
HomeBaseMaterial=Shovel=2;Pickaxe=2;Axe=2;Hammer=2;Dynamite=10;Loam=10;Wood=20;Metal=10;Clonk=2;Lorry=1;
[Player3]
Wealth=40
Crew=Clonk=2
Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;Bucket=1;
Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;ToolsWorkshop_SplitFirestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;Bucket=1;
HomeBaseMaterial=Shovel=2;Pickaxe=2;Axe=2;Hammer=2;Dynamite=10;Loam=10;Wood=20;Metal=10;Clonk=2;Lorry=1;
[Player4]
Wealth=40
Crew=Clonk=2
Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;Bucket=1;
Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;ToolsWorkshop_SplitFirestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;Bucket=1;
HomeBaseMaterial=Shovel=2;Pickaxe=2;Axe=2;Hammer=2;Dynamite=10;Loam=10;Wood=20;Metal=10;Clonk=2;Lorry=1;
[Landscape]

View File

@ -38,12 +38,10 @@ protected func Initialize()
// TODO: Make sure lorry stays on mountains.
// Place some coniferous trees, but only up to 2/3 of the mountain.
for (var i = 0; i < 16 + Random(5); i++)
PlaceVegetation(Tree_Coniferous, 0, LandscapeHeight() / 3, LandscapeWidth(), 2 * LandscapeHeight() / 3, 1000 * (61 + Random(40)));
Tree_Coniferous->Place(16+Random(5), Rectangle(0,LandscapeHeight()/3, LandscapeWidth(), 2*LandscapeHeight()/3));
// Some mushrooms as source of food.
for (var i = 0; i < 30 + Random(10); i++)
PlaceVegetation(Mushroom, 0, 0, LandscapeWidth(), LandscapeHeight());
Mushroom->Place(30+Random(10));
// Set time of day to evening and create some clouds and celestials.
Cloud->Place(20);

View File

@ -13,28 +13,28 @@ ValueOverloads=Nugget=10;GoldBar=50;
[Player1]
Wealth=50,0,0,250
Crew=Clonk=2
Knowledge=Plane_Engine=1;Foundry=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;LiftTower=1;Pump=1
Knowledge=Plane_Engine=1;Foundry=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;ToolsWorkshop_SplitFirestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;LiftTower=1;Pump=1
HomeBaseMaterial=Loam=99;Wood=5;Metal=3;Shovel=2;Axe=2;Hammer=2;Clonk=5;Bread=5
HomeBaseProduction=Loam=10;Wood=5;Metal=3;Shovel=2;Axe=2;Hammer=2;Clonk=5;Bread=5
[Player2]
Wealth=50,0,0,250
Crew=Clonk=2
Knowledge=Plane_Engine=1;Foundry=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;LiftTower=1;Pump=1
Knowledge=Plane_Engine=1;Foundry=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;ToolsWorkshop_SplitFirestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;LiftTower=1;Pump=1
HomeBaseMaterial=Loam=99;Wood=5;Metal=3;Shovel=2;Axe=2;Hammer=2;Clonk=5;Bread=5
HomeBaseProduction=Loam=10;Wood=5;Metal=3;Shovel=2;Axe=2;Hammer=2;Clonk=5;Bread=5
[Player3]
Wealth=50,0,0,250
Crew=Clonk=2
Knowledge=Plane_Engine=1;Foundry=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;LiftTower=1;Pump=1
Knowledge=Plane_Engine=1;Foundry=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;ToolsWorkshop_SplitFirestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;LiftTower=1;Pump=1
HomeBaseMaterial=Loam=99;Wood=5;Metal=3;Shovel=2;Axe=2;Hammer=2;Clonk=5;Bread=5
HomeBaseProduction=Loam=10;Wood=5;Metal=3;Shovel=2;Axe=2;Hammer=2;Clonk=5;Bread=5
[Player4]
Wealth=50,0,0,250
Crew=Clonk=2
Knowledge=Plane_Engine=1;Foundry=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;LiftTower=1;Pump=1
Knowledge=Plane_Engine=1;Foundry=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;ToolsWorkshop_SplitFirestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;LiftTower=1;Pump=1
HomeBaseMaterial=Loam=99;Wood=5;Metal=3;Shovel=2;Axe=2;Hammer=2;Clonk=5;Bread=5
HomeBaseProduction=Loam=10;Wood=5;Metal=3;Shovel=2;Axe=2;Hammer=2;Clonk=5;Bread=5

View File

@ -9,6 +9,12 @@ uniform sampler3D materialTex;
// Resolution of the landscape texture
uniform vec2 resolution;
// Use sampler if the GPU doesn't support enough uniforms to
// get the matMap as an array
#if MAX_FRAGMENT_UNIFORM_COMPONENTS < 259
#define BROKEN_ARRAYS_WORKAROUND
#endif
// Texture map
#ifdef BROKEN_ARRAYS_WORKAROUND
uniform sampler1D matMapTex;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 51 KiB

View File

@ -278,16 +278,31 @@ protected func Evaporation()
//Shades the clouds based on iSize: the water density value of the cloud.
private func ShadeCloud()
{
var shade = Min((rain+50)*425/1000, 255);
var cloudAlpha = Min((rain+50)*425/1000, 255);
if(rain > 600) cloudAlpha = 255;
//from RequestAlpha function
if(requestAlpha != nil){
cloudAlpha = cloudAlpha - (255 - requestAlpha);
if(cloudAlpha < 0) cloudAlpha = 0;
}
var shade2 = Min(rain-600, 255);
if (rain <= 600)
SetObjAlpha(shade);
if (rain > 600)
SetClrModulation(RGBa(255-shade2, 255-shade2, 255-shade2, 255));
if (rain <= 600)
SetObjAlpha(cloudAlpha);
if (rain > 600)
SetClrModulation(RGBa(255-shade2, 255-shade2, 255-shade2, cloudAlpha));
return;
}
//Utilized by time to make clouds invisible at night
local requestAlpha;
public func RequestAlpha(int alpha){
requestAlpha = alpha;
}
local ActMap = {
Fly = {
Prototype = Action,

View File

@ -1,4 +1,4 @@
/*--
/**--
Time Controller
Author:Ringwall
@ -122,37 +122,74 @@ protected func FxIntTimeCycleTimer(object target)
return 1;
}
// Adjusts the sky, celestial and others to the current time.
// Adjusts the sky, celestial and others to the current time. Use SetTime() at runtime, not this.
private func AdjustToTime()
{
var skyshade;
var skyshade = [0,0,0,0]; //R,G,B,A
var nightcolour = [10,25,40]; //default darkest-night colour
//Darkness of night dependant on moon-phase
var satellite = FindObject(Find_ID(Moon)); //pointer to the moon
if(satellite){
var phase = satellite->GetPhase();
if(phase == 1 || phase == 5) nightcolour = [4,7,9]; //super dark when moon is crescent
else if(phase == 2 || phase == 4) nightcolour = [5,15,25]; //somewhat dark when moon is half
else nightcolour = [10,25,40]; //deep-blue when moon is full
}
// Sunrise
if (Inside(time, time_set["SunriseStart"], time_set["SunriseEnd"]))
{
skyshade = Sin((GetTime() - 180) / 4, 255);
skyshade[0] = Sin((GetTime() - time_set["SunriseStart"]) / 4, 255 - nightcolour[0]) + nightcolour[0];
skyshade[1] = Sin((GetTime() - time_set["SunriseStart"]) / 4, 255 - nightcolour[1]) + nightcolour[1];
skyshade[2] = Sin((GetTime() - time_set["SunriseStart"]) / 4, 255 - nightcolour[2]) + nightcolour[2];
skyshade[3] = Sin((GetTime() - time_set["SunriseStart"]) / 4, 255);
if (time == 540)
if (FindObject(Find_ID(Moon)))
FindObject(Find_ID(Moon))->Phase();
if (satellite)
satellite->Phase();
}
// Day
else if (Inside(time, time_set["SunriseEnd"], time_set["SunsetStart"]))
skyshade = 255;
{
skyshade[0] = 255;
skyshade[1] = 255;
skyshade[2] = 255;
skyshade[3] = 255;
}
//Sunset
else if (Inside(time, time_set["SunsetStart"], time_set["SunsetEnd"]))
skyshade = 255 - Sin((GetTime() - 900) / 4, 255);
{
skyshade[0] = 255 - Sin((GetTime() - time_set["SunsetStart"]) / 4, 255 - nightcolour[0]);
skyshade[1] = 255 - Sin((GetTime() - time_set["SunsetStart"]) / 4, 255 - nightcolour[1]);
skyshade[2] = 255 - Sin((GetTime() - time_set["SunsetStart"]) / 4, 255 - nightcolour[2]);
skyshade[3] = 255 - Sin((GetTime() - time_set["SunsetStart"]) / 4, 255);
}
// Night
else if (time > time_set["SunsetEnd"] || time < time_set["SunriseStart"])
skyshade = 0;
{
skyshade[0] = nightcolour[0];
skyshade[1] = nightcolour[1];
skyshade[2] = nightcolour[2];
skyshade[3] = 0;
}
// Shade sky.
SetSkyAdjust(RGB(skyshade, skyshade, skyshade));
SetSkyAdjust(RGB(skyshade[0], skyshade[1], skyshade[2]));
// Adjust celestial objects.
for (var celestial in FindObjects(Find_Func("IsCelestial")))
celestial->SetObjAlpha(255 - skyshade);
celestial->SetObjAlpha(255 - skyshade[3]);
// Adjust clouds, TODO remedie this special case of white clouds on black sky.
// Adjust clouds
for(var cloud in FindObjects(Find_ID(Cloud))){
cloud->RequestAlpha(skyshade[3]);
}
return;
}

View File

@ -0,0 +1,8 @@
[DefCore]
id=Environment
Version=4,10,0,0
Category=C4D_StaticBack
Width=1
Height=1
Offset=-1,-1

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 B

View File

@ -0,0 +1,108 @@
/**
VisualEnvironment
Cares about the placement of purely visual objects.
The placement uses categories and thus is forward-compatible.
*/
// this proplist defines the selectable environment objects
// "ID" might be nil or a valid id
// "includes" specifies what objects are created when the selected object is created (no specific order)
// any entry of "Environment_Attributes" might be nil or false instead of a proplist
// nil will log a warning on creating that object and false will silently ignore it
// thus something like Environment_Attributes["Foobar"] = false; will work to disable certain features
static const Environment_Attributes =
{
All = {
ID = nil,
includes = ["Temperate", "Desert"],
},
Temperate = {
ID = nil,
includes = ["Zicadas", "Frogs", "BackgroundBirds"],
},
Desert = {
ID = nil,
includes = ["Zicadas"],
},
Zicadas = {
ID = Environment_Zicadas,
},
Frogs = {
ID = nil /* not yet implemented: Environment_Frogs */,
},
BackgroundBirds = {
ID = nil /* not yet implemented: Environment_BackgroundBirds */,
},
};
// provides a simple interface for creation of environment objects and decoration with standard values
// the objects are placed on a best-effort-basis. That means f.e. objects that rely on water will not be placed when there is no water in the landscape.
global func CreateEnvironmentObjects(
what /* array of strings or single string: what objects will be created, standard: "All" */
, proplist area /* area where objects will be created, format {x = ??, y = ??, w = ??, h = ??}, standard: whole landscape */
, int amount_percentage /* what percentage of the standard amount will be created, standard: 100 */
)
{
/*
// half desert, half temperate - but birds everywhere
CreateEnvironmentObjects(["Desert", "BackgroundBirds"], Rectangle(0, 0, LandscapeWidth()/2, LandscapeHeight()));
CreateEnvironmentObjects("Temperate", Rectangle(LandscapeWidth()/2, 0, LandscapeWidth()/2, LandscapeHeight()));
*/
what = what ?? "All";
area = area ?? Rectangle(0, 0, LandscapeWidth(), LandscapeHeight());
amount_percentage = amount_percentage ?? 100;
// might be a string to allow CreateEnvironmentObjects("All")
if(GetType(what) != C4V_Array)
what = [what];
// iteratively find all the objects that are included in the selection
while(true)
{
var changed = false;
var to_add = [];
// go through every object in the list
for(var obj in what)
{
var p = Environment_Attributes[obj];
if(p == nil) {Log("Warning: Environment object %s does not exist!", obj);}
else if(p == false) continue; // disabled by the scenario designer
// add all objects included to the temporary list if existing
if(!p["includes"]) continue;
to_add = Concatenate(to_add, p["includes"]);
}
// add every unique item from the temporary list to the object list
for(var obj in to_add)
{
if(IsValueInArray(what, obj)) continue;
if(!!Environment_Attributes[obj]["includes"])
changed = true; // found changes, need further checking
PushBack(what, obj);
}
if(!changed)
break;
}
// now create all the selected objects
for(var obj in what)
{
var p, p_id;
if(!(p = Environment_Attributes[obj])) continue;
if(!(p_id = p["ID"])) continue;
p_id->Place(amount_percentage, area);
}
}

View File

@ -0,0 +1,7 @@
[DefCore]
id=Environment_Zicadas
Version=4,10,0,0
Category=C4D_StaticBack
Width=1
Height=1
Offset=-1,-1

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 B

View File

@ -0,0 +1,26 @@
/**
Zicadas
Zicada sounds.
*/
local Name = "$Name$";
local Description = "$Description$";
func Place(int amount_percentage, proplist area)
{
area = area ?? Rectangle(0, 0, LandscapeWidth(), LandscapeHeight());
amount_percentage = amount_percentage ?? 100;
// calculate amount that has to be placed
var amount = LandscapeWidth() / 100;
amount = (amount_percentage * amount) / 100;
if(!amount) return;
while(--amount)
{
// search for zicada spot position
// ..
// place zicada spot
// ..
}
}

View File

@ -0,0 +1,2 @@
Name=Zikaden
Description=Zikadengeräusche.

View File

@ -0,0 +1,2 @@
Name=Zicadas
Description=Zicada sounds.

View File

@ -62,7 +62,7 @@ private func OpenWeaponMenu(object clonk)
{
menu = clonk->CreateRingMenu(Clonk, this);
for (var weapon in weapons)
menu->AddItem(weapon);
menu->AddItem(weapon, 1);
menu->Show();
menu->SetUncloseable();
}
@ -96,7 +96,11 @@ public func Selected(object menu, object selector, bool alt)
if (!selector)
return false;
for (var i = 0; i < selector->GetAmount(); i++)
var amount = selector->GetAmount();
if (amount > 1)
alt = nil;
for (var i = 0; i < amount; i++)
GiveWeapon(selector->GetSymbol(), alt);
has_selected = true;

View File

@ -21,12 +21,11 @@ public func Update()
// Display wealth via text.
CustomMessage(Format("@%d", wealth), this, plr, 0, 90);
// Display wealth via graphics.
var num;
if (wealth < 180) num = 4;
if (wealth < 120) num = 3;
if (wealth < 70) num = 2;
if (wealth < 30) num = 1;
if (wealth < 10) num = 0;
var num = 0;
if (wealth >= 10) num = 1;
if (wealth >= 30) num = 2;
if (wealth >= 70) num = 3;
if (wealth >= 120) num = 4;
SetGraphics(Format("%d", num));
return;
}

View File

@ -40,12 +40,8 @@ public func SetBG(bool newbg) {
public func SetNothing() // No item, no image, no whatever, just a plain button
{
SetAmount(0);
SetAmount(nil);
SetSymbol();
SetGraphics(nil,nil,9);
SetGraphics(nil,nil,10);
SetGraphics(nil,nil,11);
SetGraphics(nil,nil,12);
}
public func SetSize(int s) // in px *1000
@ -122,9 +118,15 @@ public func SetExtraData(extradata)
}
public func SetAmount(Amount)
{
amnt=Amount;
if(Amount==1) return ;
amnt = Amount;
if (Amount == nil)
{
SetGraphics(nil,nil,MI_AMOUNTX_LAYER);
SetGraphics(nil,nil,MI_AMOUNT1_LAYER);
SetGraphics(nil,nil,MI_AMOUNT10_LAYER);
SetGraphics(nil,nil,MI_AMOUNT100_LAYER);
return;
}
var one = Amount%10;
var ten = (Amount/10)%10;
var hun = (Amount/100)%10;

View File

@ -102,14 +102,7 @@ public func AddItem(new_item, int amount, extra)
menu_icons[index] = CreateObject(GUI_RingMenu_Icon,0,0,menu_object->GetOwner());
menu_icons[index]->SetSymbol(new_item);
menu_icons[index]->SetExtraData(extra);
if(amount == nil)
{
menu_icons[index]->SetAmount(1);
}
else
{
menu_icons[index]->SetAmount(amount);
}
menu_icons[index]->SetAmount(amount);
menu_icons[index].Visibility = VIS_None;
return index;
}

View File

@ -11,8 +11,7 @@ VertexY=1,-1
VertexFriction=20
Value=5
Mass=10
Components=Sulphur=1
Components=Sulphur=1;Coal=1
Projectile=1
Fragile=1
Explosive=1
Explosive=1

View File

@ -12,8 +12,6 @@ func Hit()
Explode(20);
}
public func IsToolProduct() { return true; }
local Collectible = 1;
local Name = "$Name$";
local Description = "$Description$";

View File

@ -77,7 +77,7 @@ func FxIntFusingTimer()
if( (fuse_vertex == 0 && fuse_dir == -1) || (fuse_vertex == GetVertexNum()-1 && fuse_dir == +1))
{
fuse_call->~OnFuseFinished(this);
RemoveObject();
if (fuse_call) RemoveObject();
return -1;
}
fuse_x = GetVertex(fuse_vertex, 0)*10;

View File

@ -82,6 +82,18 @@ public func GetItems()
return inv;
}
/** Returns how many items are in the clonks inventory
Does not have to be the same as ContentCounts() because of objects with special handling, like CarryHeavy */
public func GetItemCount()
{
var count = 0;
for(var i=0; i < GetLength(inventory); i++)
if(inventory[i])
count++;
return count;
}
/** Get the 'i'th item in hands.
These are the items that will be used with use-commands. (Left mouse click, etc...) */
public func GetHandItem(int i)
@ -494,7 +506,7 @@ protected func RejectCollect(id objid, object obj)
// collection of that object magically disabled?
if(GetEffect("NoCollection", obj)) return true;
// Carry heavy only gets picked up if non held already
// Carry heavy only gets picked up if none held already
if(obj->~IsCarryHeavy())
{
if(IsCarryingHeavy())
@ -540,7 +552,7 @@ protected func RejectCollect(id objid, object obj)
public func AllowTransfer(object obj)
{
// Only check max contents.
if (ContentsCount() >= MaxContentsCount())
if (GetItemCount() >= MaxContentsCount())
return false;
// don't allow picking up multiple carryheavy-objects

View File

@ -181,8 +181,6 @@ func CreateConstructionSite(object clonk, id structure_id, int x, int y, int dir
// Set owner for CreateConstruction
SetOwner(clonk->GetOwner());
// Save direction so the structure can ask for it
this.constructionDirection = dir;
// Create construction site
var site;
site = CreateObject(ConstructionSite, x, y, Contained()->GetOwner());
@ -229,9 +227,4 @@ func CreateConstructionSite(object clonk, id structure_id, int x, int y, int dir
// Message
clonk->Message("$TxtConstructions$", structure_id->GetName());
return true;
}
// Returns the desired direction for a construction
func GetConstructionDirection()
{
return this.constructionDirection;
}

View File

@ -11,21 +11,6 @@ public func IsPlant()
return true;
}
/** Chance to reproduce plant. Chances are one out of return value. Default is 500.
@return the chance, higher = less chance.
*/
private func SeedChance() { return 500; }
/** Distance the seeds may travel. Default is 250.
@return the maximum distance.
*/
private func SeedArea() { return 250; }
/** The amount of plants allowed within SeedAreaSize. Default is 10.
@return the maximum amount of plants.
*/
private func SeedAmount() { return 10; }
/** Automated positioning via RootSurface, make sure to call this if needed (in case Construction is overloaded)
*/
protected func Construction()
@ -35,6 +20,73 @@ protected func Construction()
_inherited(...);
}
/* Placement */
/** Places the given amount of plants inside the area. If no area is given, the whole landscape is used.
@param amount The amount of plants to be created (not necessarily every plant is created).
@param rectangle The area where to put the plants.
@param settings A proplist defining further setttings: { growth = 100000, keep_area = false }. Growth will get passed over to PlaceVegetation, keep_area will confine the plants and their offspring to rectangle.
@return Returns an array of all objects created.
*/
public func Place(int amount, proplist rectangle, proplist settings)
{
// No calls to objects, only definitions
if (GetType(this) == C4V_C4Object) return;
// Default parameters
if (!settings) settings = { growth = 100000, keep_area = false };
if (!settings.growth) settings.growth = 100000;
if (!rectangle)
rectangle = Rectangle(0,0, LandscapeWidth(), LandscapeHeight());
var plants = CreateArray(), plant;
for (var i = 0 ; i < amount ; i++)
{
plant = PlaceVegetation(this, rectangle.x, rectangle.y, rectangle.w, rectangle.h, settings.growth);
if (plant)
{
plants[GetLength(plants)] = plant;
if (settings.keep_area)
plant->KeepArea(rectangle);
}
plant = nil;
}
return plants;
}
/* Reproduction */
/** Will confine the the plant and its offspring to a certain area.
@params rectangle The confinement area.
*/
func KeepArea(proplist rectangle)
{
this.Confinement = rectangle;
}
/** Chance to reproduce plant. Chances are one out of return value. Default is 500.
@return the chance, higher = less chance.
*/
private func SeedChance()
{
return 500;
}
/** Distance the seeds may travel. Default is 250.
@return the maximum distance.
*/
private func SeedArea()
{
return 250;
}
/** The amount of plants allowed within SeedAreaSize. Default is 10.
@return the maximum amount of plants.
*/
private func SeedAmount()
{
return 10;
}
/** Reproduction of plants: Called every 2 seconds by a timer.
*/
public func Seed()
@ -42,8 +94,10 @@ public func Seed()
// Find number of plants in seed area.
var size = SeedArea();
var amount = SeedAmount();
var offset = size / -2;
var plant_cnt = ObjectCount(Find_ID(GetID()), Find_InRect(offset, offset, size, size));
var area = Rectangle(AbsX(size / -2), AbsY(size / -2), size, size);
if (this.Confinement)
area = RectangleEnsureWithin(area, this.Confinement);
var plant_cnt = ObjectCount(Find_ID(GetID()), Find_InRect(area.x - GetX(), area.y - GetY(), area.w, area.h));
// If there are not much plants in the seed area compared to seed amount
// the chance of seeding is improved, if there are much the chance is reduced.
var chance = SeedChance();
@ -52,7 +106,7 @@ public func Seed()
if (!Random(chance))
{
// Place the plant but check if it is not close to another one.
var plant = PlaceVegetation(GetID(), offset, offset, size, size, 3);
var plant = PlaceVegetation(GetID(), area.x - GetX(), area.y - GetY(), area.w, area.h, 3);
if (plant)
{
var neighbour = FindObject(Find_ID(GetID()), Find_Exclude(plant), Sort_Distance(plant->GetX() - GetX(), plant->GetY() - GetY()));
@ -60,6 +114,8 @@ public func Seed()
// Closeness determined by seedarea and amount.
if (!Random(distance / (size/amount)))
plant->RemoveObject();
else if (this.Confinement)
plant->KeepArea(this.Confinement);
}
}
return;
@ -106,7 +162,6 @@ protected func Damage()
_inherited(...);
}
// restarts the growing of the tree (for example after taking damage)
func RestartGrowth(int old_value)
{

View File

@ -16,16 +16,4 @@ public func Damage(int change, int cause, int cause_plr)
return RemoveObject();
}
return _inherited(change, cause, cause_plr);
}
public func Construction(object creator)
{
if (creator)
{
// Set dir according to the direction specified by the creator.
var dir = creator->~GetConstructionDirection();
if (dir)
SetDir(dir);
}
return _inherited(creator, ...);
}

View File

@ -15,6 +15,7 @@ Mass=30
Components=Wood=1
SolidMask=0,27,24,2,0,24
TopFace=0,0,24,26,0,0
Picture=24,0,152,128
HorizontalFix=1
NoPushEnter=1
ContactCalls=1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 316 B

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -91,8 +91,8 @@ local move_to, // Y-coordinate to move to on its own
func Movement()
{
// Move back and front
front->SetPosition(GetX(), GetY()-5);
back->SetPosition(GetX(), GetY()-7);
front->SetPosition(GetX(), GetY()-3);
back->SetPosition(GetX(), GetY()-5);
// No elevator?!
if (!elevator)

View File

@ -39,10 +39,10 @@ public func GetInteractionMetaInfo(object clonk)
public func Interact(object clonk)
{
var menu;
var i=0,item,player=clonk->GetOwner(), amount;
while (item = GetHomebaseMaterial(player, nil, i++))
var i = 0, item, amount;
while (item = GetHomebaseMaterial(GetOwner(), nil, i++))
{
amount = GetHomebaseMaterial(player, item);
amount = GetHomebaseMaterial(GetOwner(), item);
// Add even if amount==0
if (!menu) menu = clonk->CreateRingMenu(Flagpole, this);
if (!menu) return false;
@ -65,8 +65,11 @@ public func Selected(object menu, proplist menu_item, bool alt)
// Excess objects exit flag (can't get them out...)
var i = ContentsCount();
var obj;
while (i--) if (obj = Contents(i)) Contents(i)->Exit();
while (i--)
if (obj = Contents(i))
Contents(i)->Exit(0, GetDefHeight() / 2);
// Update available count
menu_item->SetAmount(GetHomebaseMaterial(clonk->GetOwner(), def));
menu_item->SetAmount(GetHomebaseMaterial(GetOwner(), def));
menu->Show();
return true;
}

View File

@ -15,13 +15,13 @@ public func IsLiquidPump() { return true; }
public func Construction(object creator)
{
SetAction("Wait");
return _inherited(creator, ...);
}
protected func Initialize()
{
MakePowerConsumer(100);
SetAction("Wait");
turned_on = true;
return;
}
@ -48,7 +48,10 @@ public func Interact(object clonk)
SetAction("Wait");
}
else
{
OnWaitStart();
turned_on = true;
}
return true;
}
@ -189,7 +192,7 @@ local ActMap = {
Name = "Wait",
Procedure = DFA_NONE,
Length = 1,
Delay = 50,
Delay = 10,
Directions = 2,
FlipDir = 1,
X = 0,

View File

@ -0,0 +1,8 @@
[DefCore]
id=ToolsWorkshop_SplitFirestone
Version=4,10,0,0
Category=C4D_Object
Width=1
Height=1
Components=Firestone=1
Picture=0,0,64,64

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

@ -0,0 +1,23 @@
/**
SplitFirestone
Split a firestone to get its natural components, coal and sulphur.
@author Clonkonaut
*/
local Name = "$Name$";
local Description = "$Description$";
func Initialize()
{
ScheduleCall(this, "Split", 1);
}
func Split()
{
if (!Contained()) return RemoveObject();
Contained()->CreateContents(Coal);
Contained()->CreateContents(Sulphur);
RemoveObject();
}
func IsToolProduct() { return true; }

View File

@ -0,0 +1,2 @@
Name=Feuerstein spalten
Description=Spaltet einen Feuerstein in dessen natürliche Komponenten, Kohle und Schwefel.

View File

@ -0,0 +1,2 @@
Name=Split firestone
Description=Split a firestone to get its natural components, coal and sulphur.

View File

@ -18,17 +18,6 @@ static const SproutBerryBush_water_per_berry = 10;
static const SproutBerryBush_max_sprouts = 8;
static const SproutBerryBush_evolve_steps_per_new_sprout = 2;
// static function
func Place(int amount)
{
// place some sprout berries
var bush = PlaceVegetation(SproutBerryBush, 0, LandscapeHeight() / 3, LandscapeWidth(), LandscapeHeight(), 100000);
if(bush)
for (var i = 1; i < amount; i++)
PlaceVegetation(SproutBerryBush, bush->GetX() - 200, bush->GetY() - 200, 400, 400, 100000);
return true;
}
func Construction()
{
SetCon(100);

View File

@ -2,6 +2,18 @@
#include Library_Plant
// Overloaded from the plant library to add the foreground parameter, foreground = true will roughly make every 3rd tree foreground (not the offspring though)
func Place(int amount, proplist rectangle, proplist settings, bool foreground)
{
// Default behaviour
var trees = inherited(amount, rectangle, settings);
if (GetLength(trees) < 1) return;
for (var tree in trees)
if (!Random(3))
tree.Plane = 510;
}
private func SeedChance() { return 500; }
private func SeedArea() { return 400; }
private func SeedAmount() { return 12; }

View File

@ -140,4 +140,75 @@ global func DrawParticleLine (string particle, int x0, int y0, int x1, int y1, i
}
// Succes, return number of created particles.
return prtnum;
}
/** Place a nice shaped forest. If no area is given, the whole landscape is used (which is not recommended!).
@param plants An array containing all plants that should be in the forest. plants[0] is the main plant, the others will be randomly scattered throughout the forest.
@param x The starting X-coordinate of the forest.
@param y The lowest line at which to start placing plants. Level ground is determined automatically, goind upwards.
@param width The width of the forest
@param foreground Will roughly make every third instance of plants[0] foreground
*/
global func PlaceForest(array plants, int x, int y, int width, bool foreground)
{
// Parameter check
if (GetLength(plants) == 0) return;
if (!x) x = 0;
if (!y) y = LandscapeHeight();
if (!width) width = LandscapeWidth();
if (this) { x = AbsX(x); y = AbsY(y); }
// Roughly 20% of the size (10% per side) are taken for 'forest ending zones'. Plants will be smaller there.
var end_zone = width * 10 / 100;
// The width of the standard plants will roughly be the measure for our plant size
var plant_size = plants[0]->GetDefWidth()/2;
var growth, y_pos, plant, x_variance, variance = 0, count, j, spot;
for (var i = plant_size ; i < width ; i += plant_size)
{
growth = 100;
y_pos = y;
x_variance = RandomX(-10,10);
// End zone check
if (i < end_zone)
growth = BoundBy(90 / ((end_zone * 100 / plant_size)/100) * (i/plant_size), 10,90);
else if (i > width - end_zone)
growth = BoundBy(90 / ((end_zone * 100 / plant_size)/100) * ((width-i)/plant_size), 10,90);
else if (!Random(10) && GetLength(plants) > 1)
{
variance = Random(GetLength(plants)-1)+1;
// Scatter some other plants
count = RandomX(2,4);
for (j = 0 ; j < count ; j++)
{
spot = (plant_size*2 / count) * j + RandomX(-5,5) - plant_size;
y_pos = y;
if (!GBackSolid(x + i + spot, y_pos)) continue;
while (!GBackSky(x + i + spot, y_pos) && y_pos > 0) y_pos--;
if (y_pos == 0) continue;
plant = CreateObject(plants[variance], x + i + spot, y_pos+5, NO_OWNER);
}
continue;
}
// No ground at y_pos?
if (!GBackSolid(x + i + x_variance, y_pos)) continue;
// Get level ground
while (!GBackSky(x + i + x_variance, y_pos) && y_pos > 0) y_pos--;
if (y_pos == 0) continue;
plant = CreateObject(plants[0], x + i + x_variance, y_pos+5, NO_OWNER);
plant->SetCon(growth);
if (foreground && !Random(3)) plant.Plane = 510;
// Every ~7th plant: double plant!
if (x_variance != 0 && !Random(7))
{
y_pos = y;
if (!GBackSolid(x + i - x_variance, y_pos)) continue;
while (!GBackSky(x + i - x_variance, y_pos) && y_pos > 0) y_pos--;
if (y_pos == 0) continue;
plant = CreateObject(plants[0], x + i - x_variance, y_pos+5, NO_OWNER);
plant->SetCon(growth);
if (foreground && !Random(3)) plant.Plane = 510;
}
}
}

View File

@ -28,7 +28,7 @@ global func OnFire()
}
// Extinguishes the calling object with specified strength.
global func Extinguish(strength)
global func Extinguish(strength /* strength between 0 and 100 */)
{
if (!this)
return false;
@ -47,7 +47,11 @@ global func Extinguish(strength)
}
// Incinerates the calling object with specified strength.
global func Incinerate(strength, int caused_by, blasted, incinerating_object)
global func Incinerate(
strength /* strength between 0 and 100 */
, int caused_by /* the player that caused the incineration */
, blasted /* whether the object was incinerated by an explosion */
, incinerating_object /* the object that caused the incineration */)
{
if (!this)
return false;

View File

@ -4,7 +4,10 @@
Authors: Zapper
--*/
global func GetFlagpoleForPosition(int x, int y)
// returns the flagpole that is currently holding ownership of a specific point in the landscape
global func GetFlagpoleForPosition(
int x /* x position in local coordinates */
, int y /* y position in local coordinates */)
{
if(GetType(LibraryFlag_flag_list) != C4V_Array) return nil;
@ -24,15 +27,19 @@ global func GetFlagpoleForPosition(int x, int y)
return oldest;
}
global func GetOwnerOfPosition(int x, int y)
// returns the current owner that controls a certain point with a flagpole or NO_OWNER
global func GetOwnerOfPosition(
int x /* x position in local coordinates */
, int y /* y position in local coordinates */)
{
var flag = GetFlagpoleForPosition(x, y);
if(!flag) return NO_OWNER;
return flag->GetOwner();
}
// redraws all flag radiuses
global func RedrawAllFlagRadiuses()
{
for(var f in LibraryFlag_flag_list)
f->RedrawFlagRadius();
}
}

View File

@ -79,8 +79,16 @@ global func ComDirLike(int comdir1, int comdir2)
// the shortest direction (left/right) to turn from one angle to another
// (for example for homing projectiles or aiming)
global func GetTurnDirection(int from, int to)
global func GetTurnDirection(
int from /* the angle at which the turning starts */
, int to /* the angle that should be turned towards */)
{
/*
// code for a homing missile
var dir = GetTurnDirection(my_angle, target_angle);
SetR(GetR() + dir / 10);
SetSpeed(Sin(GetR(), 10), -Cos(GetR(), 10));
*/
var dir;
/*if(to < from)*/dir=to-from;
//else dir=from-to;
@ -116,4 +124,21 @@ global func GetCalcDir()
{
if (!this) return 0;
return GetDir() * 2 - 1;
}
// Ensure that the first rectangle is fully with the second one and returns an adjusted rectangle. Both rectangles can be created with Rectangle()
global func RectangleEnsureWithin(proplist first, proplist second)
{
if (GetType(first) != C4V_PropList) return {};
if (GetType(second) != C4V_PropList) return {};
var adjusted = { x = first.x, y = first.y, w = first.w, h = first.h };
if (first.x < second.x) adjusted.x = second.x;
if (first.w > second.w) adjusted.w = second.w - (adjusted.x - second.x);
if (adjusted.x + adjusted.w > second.x + second.w) adjusted.w = second.w - (adjusted.x - second.x);
if (first.y < second.y) adjusted.y = second.y;
if (first.h > second.h) adjusted.h = second.h - (adjusted.y - second.y);
if (adjusted.y + adjusted.h > second.y + second.h) adjusted.h = second.h - (adjusted.y - second.y);
return adjusted;
}

View File

@ -148,7 +148,7 @@ global func GetMaxBreath()
}
// Makes an object gain Con until it is FullCon
global func StartGrowth(int value)
global func StartGrowth(int value /* the value the object grows approx. every second, in tenths of percent */)
{
var effect;
effect = AddEffect("IntGrowth", this, 1, 35, nil, nil, value);
@ -330,4 +330,4 @@ global func InFrontOf(object back)
return;
return front->FindObject(front->Find_AtPoint(), Find_Not(Find_Exclude(back))) != nil;
}
}

View File

@ -85,7 +85,8 @@ global func DoWealth(int plr, int value)
return SetWealth(plr, value + GetWealth(plr));
}
global func IsAllied(int plr1, int plr2, bool check_one_way_only)
// checks whether two players are allied - that means they are not hostile and neither of them is NO_OWNER
global func IsAllied(int plr1, int plr2, bool check_one_way_only /* whether to check the hostility only in one direction */)
{
if(plr1 == NO_OWNER) return false;
if(plr2 == NO_OWNER) return false;
@ -113,4 +114,4 @@ global func MessageWindow(string msg, int for_plr, id icon, string caption)
global func FindBase (int iPlr, int iIndex)
{
return FindObjects(Find_Owner(iPlr), Find_Func("IsBase"))[iIndex];
}
}

View File

@ -0,0 +1,27 @@
/*--
Proplists.c
General helper functions that create or work with proplists.
--*/
// creates a proplists with the properties x, y, w, h that represents a rectangle
// satisfies that the resulting rectangle's x|y point is in the top-left corner and the width and height are positive
global func Rectangle(int x2, int y2, int w2, int h2)
{
/*
// creates a rectangle representing the landscape
var rect = Rectangle(0, 0, LandscapeWidth(), LandscapeHeight());
*/
// normalize
if(w2 < 0)
{
x2 += w2;
w2 = -w2;
}
if(h2 < 0)
{
y2 += h2;
h2 = - h2;
}
return {x = x2, y = y2, w = w2, h = h2};
}

View File

@ -34,8 +34,24 @@ global func FxIntScheduleTimer(object obj, proplist effect)
}
// Adds a timed call to an object, replacement of DefCore TimerCall.
global func AddTimer(string function, int interval)
global func AddTimer(
string function /* function that will be called every time step */
, int interval /* interval in frames in which the function will be called */)
{
/*
// script for a mine that checks for enemies every second
func Initialize()
{
AddTimer("CheckForEnemies", 36);
}
func CheckForEnemies()
{
if(FindObject(Find_AtPoint(), Find_OCF(OCF_Alive)))
Explode(30);
}
*/
if (!this)
return false;
// Default to one second.

View File

@ -101,7 +101,7 @@ protected func FxRestoreStop(object target, effect, int reason, bool temporary)
else
to_restore->SetPosition(to_x, to_y);
// Restored object might have been removed on enter (Stackable).
if (to_restore)
if (to_restore && !to_restore->~IsStackable())
{
// Add new restore mode, either standard one or effect supplied in EffectVar 4.
if (ctrl_string)

View File

@ -50,8 +50,32 @@ don't need to include this file or any of the files it includes. */
// solidmask debugging
//#define SOLIDMASK_DEBUG
// debug memory management - must come after boost headers,
// because boost uses placement new
#include <algorithm>
#include <cassert>
#include <cctype>
#include <cerrno>
#include <climits>
#include <cmath>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iostream>
#include <list>
#include <map>
#include <memory>
#include <set>
#include <sstream>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
// debug memory management - must come after standard and boost headers,
// because those libraries use placement new
#ifndef NODEBUGMEM
#if defined(_DEBUG) && defined(_MSC_VER)
#if _MSC_VER <= 1200
@ -73,31 +97,7 @@ inline void operator delete(void *p, const char *, long)
#define new new(__FILE__, __LINE__)
#endif
#endif
#include <algorithm>
#include <cassert>
#include <cctype>
#include <cerrno>
#include <climits>
#include <cmath>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iostream>
#include <list>
#include <map>
#include <memory>
#include <new>
#include <set>
#include <sstream>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
#include "Standard.h"
#include "C4Prototypes.h"

View File

@ -63,6 +63,12 @@
#define C4XVERTOC4XVERS(s) C4XVERTOC4XVERS2(s)
#define C4XVERTOC4XVERS2(s) #s
// if C4XVER3 >= 90, this is a pre-release version; add VCS revision instead of build number
#if C4XVER3 >= 90
#define C4VERSION C4XVERTOC4XVERS(C4XVER1) "." C4XVERTOC4XVERS(C4XVER2) "." C4XVERTOC4XVERS(C4XVER3) " [" C4REVISION "]" C4VERSIONEXTRA C4BUILDOPT
#else
#define C4VERSION C4XVERTOC4XVERS(C4XVER1) "." C4XVERTOC4XVERS(C4XVER2) "." C4XVERTOC4XVERS(C4XVER3) " [" C4XVER4S "]" C4VERSIONEXTRA C4BUILDOPT
#endif
#endif

View File

@ -405,7 +405,7 @@ void C4Console::UpdateInputCtrl()
{
ClearInput();
// add global and standard functions
std::list <const char*> functions = ::ScriptEngine.GetFunctionNames(&::GameScript);
std::list <const char*> functions = ::ScriptEngine.GetFunctionNames(::GameScript.ScenPropList._getPropList());
SetInputFunctions(functions);
}

View File

@ -993,7 +993,7 @@ void C4ConsoleGUI::PropertyDlgUpdate(C4ObjectList &rSelection)
if (PropertyDlgObject == rSelection.GetObject()) return;
PropertyDlgObject = rSelection.GetObject();
std::list<const char *> functions = ::ScriptEngine.GetFunctionNames(PropertyDlgObject ? &PropertyDlgObject->Def->Script : 0);
std::list<const char *> functions = ::ScriptEngine.GetFunctionNames(PropertyDlgObject);
GtkEntryCompletion* completion = gtk_entry_get_completion(GTK_ENTRY(state->propertydlg_entry));
GtkListStore* store;

View File

@ -893,7 +893,7 @@ void C4ConsoleGUI::PropertyDlgUpdate(C4ObjectList &rSelection)
if (PropertyDlgObject == rSelection.GetObject()) return;
PropertyDlgObject = rSelection.GetObject();
std::list<const char *> functions = ::ScriptEngine.GetFunctionNames(PropertyDlgObject ? &PropertyDlgObject->Def->Script : 0);
std::list<const char *> functions = ::ScriptEngine.GetFunctionNames(PropertyDlgObject);
HWND hCombo = GetDlgItem(state->hPropertyDlg, IDC_COMBOINPUT);
wchar_t szLastText[500+1];
// Remember old window text

View File

@ -497,15 +497,15 @@ void C4Effect::SetPropertyByS(C4String * k, const C4Value & to)
{
case P_Name:
if (!to.getStr() || !*to.getStr()->GetCStr())
throw new C4AulExecError(0, "effect: Name has to be a nonempty string");
throw new C4AulExecError("effect: Name has to be a nonempty string");
C4PropListNumbered::SetPropertyByS(k, to);
ReAssignCallbackFunctions();
return;
case P_Priority:
throw new C4AulExecError(0, "effect: Priority is readonly");
throw new C4AulExecError("effect: Priority is readonly");
case P_Interval: iInterval = to.getInt(); return;
case P_CommandTarget:
throw new C4AulExecError(0, "effect: CommandTarget is readonly");
throw new C4AulExecError("effect: CommandTarget is readonly");
case P_Time: iTime = to.getInt(); return;
}
}
@ -519,12 +519,12 @@ void C4Effect::ResetProperty(C4String * k)
switch(k - &Strings.P[0])
{
case P_Name:
throw new C4AulExecError(0, "effect: Name has to be a nonempty string");
throw new C4AulExecError("effect: Name has to be a nonempty string");
case P_Priority:
throw new C4AulExecError(0, "effect: Priority is readonly");
throw new C4AulExecError("effect: Priority is readonly");
case P_Interval: iInterval = 0; return;
case P_CommandTarget:
throw new C4AulExecError(0, "effect: CommandTarget is readonly");
throw new C4AulExecError("effect: CommandTarget is readonly");
case P_Time: iTime = 0; return;
}
}
@ -556,6 +556,20 @@ bool C4Effect::GetPropertyByS(C4String *k, C4Value *pResult) const
return C4PropListNumbered::GetPropertyByS(k, pResult);
}
C4ValueArray * C4Effect::GetProperties() const
{
C4ValueArray * a = C4PropList::GetProperties();
int i;
i = a->GetSize();
a->SetSize(i + 5);
(*a)[i++] = C4VString(&::Strings.P[P_Name]);
(*a)[i++] = C4VString(&::Strings.P[P_Priority]);
(*a)[i++] = C4VString(&::Strings.P[P_Interval]);
(*a)[i++] = C4VString(&::Strings.P[P_CommandTarget]);
(*a)[i++] = C4VString(&::Strings.P[P_Time]);
return a;
}
// Some other, internal effects -------------------------------------------------------------
static int32_t GetSmokeLevel()

View File

@ -133,6 +133,7 @@ public:
virtual void SetPropertyByS(C4String * k, const C4Value & to);
virtual void ResetProperty(C4String * k);
virtual bool GetPropertyByS(C4String *k, C4Value *pResult) const;
virtual C4ValueArray * GetProperties() const;
protected:
void TempRemoveUpperEffects(C4Object *pObj, bool fTempRemoveThis, C4Effect **ppLastRemovedEffect); // temp remove all effects with higher priority

File diff suppressed because it is too large Load Diff

View File

@ -45,24 +45,6 @@ struct C4ScriptConstDef
long Data; // raw data
};
// ** a definition of a script-function.
// includes two versions of the Function to be called:
// * the first (C4V) takes 10 parameters
// * the second (C4V2) takes an array of 10 parameters
// only one may be set.
struct C4ScriptFnDef
{
const char* Identifier; // the name of the func in the script
bool Public;
C4V_Type RetType; // type returned. ignored when C4V
C4V_Type ParType[10];// type of the parameters. error when wrong parameter type.
C4Value (*FunctionC4V)(struct C4AulContext *cthr, C4Value*, C4Value*, C4Value*, C4Value*, C4Value*,
C4Value*, C4Value*, C4Value*, C4Value*, C4Value*);
C4Value (*FunctionC4V2)(struct C4AulContext *, C4Value *);
};
// add functions to engine
void InitGameFunctionMap(C4AulScriptEngine *pEngine);
void InitObjectFunctionMap(C4AulScriptEngine *pEngine);

View File

@ -2069,11 +2069,29 @@ void CStdGL::ResetTexture()
bool CStdGL::Error(const char *szMsg)
{
#ifdef USE_WIN32_WINDOWS
DWORD err = GetLastError();
#endif
bool r = C4Draw::Error(szMsg);
#ifdef USE_WIN32_WINDOWS
wchar_t * lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );
LogF(" gl: GetLastError() = %d - %s", err, StdStrBuf(lpMsgBuf).getData());
LocalFree(lpMsgBuf);
#endif
LogF(" gl: %s", glGetString(GL_VENDOR));
LogF(" gl: %s", glGetString(GL_RENDERER));
LogF(" gl: %s", glGetString(GL_VERSION));
LogF(" gl: %s", glGetString(GL_EXTENSIONS));
return C4Draw::Error(szMsg);
return r;
}
bool CStdGL::CheckGLError(const char *szAtOp)

View File

@ -939,7 +939,11 @@ bool C4ScenarioListLoader::SubFolder::LoadCustom(C4Group &rGrp, bool fNameLoaded
{
// default icon fallback
if (!fIconLoaded)
fctIcon.Set(C4Startup::Get()->Graphics.fctScenSelIcons.GetSection(C4StartupScenSel_DefaultIcon_Folder));
{
if(WildcardMatch(C4CFN_Savegames, GetFilename(sFilename.getData()))) iIconIndex = C4StartupScenSel_DefaultIcon_SavegamesFolder;
else iIconIndex = C4StartupScenSel_DefaultIcon_Folder;
fctIcon.Set(C4Startup::Get()->Graphics.fctScenSelIcons.GetSection(iIconIndex));
}
// folder index
iFolderIndex = C4F.Head.Index;
return true;

View File

@ -33,14 +33,15 @@
class C4StartupScenSelDlg;
const int32_t C4StartupScenSel_DefaultIcon_Scenario = 14,
C4StartupScenSel_DefaultIcon_Folder = 0,
C4StartupScenSel_DefaultIcon_WinFolder = 44,
C4StartupScenSel_DefaultIcon_OldIconBG = 18,
C4StartupScenSel_IconCount = 45,
C4StartupScenSel_TitlePictureWdt = 200,
C4StartupScenSel_TitlePictureHgt = 150,
C4StartupScenSel_TitlePicturePadding = 10,
C4StartupScenSel_TitleOverlayMargin = 10; // number of pixels to each side of title overlay picture
C4StartupScenSel_DefaultIcon_Folder = 0,
C4StartupScenSel_DefaultIcon_SavegamesFolder = 29,
C4StartupScenSel_DefaultIcon_WinFolder = 44,
C4StartupScenSel_DefaultIcon_OldIconBG = 18,
C4StartupScenSel_IconCount = 45,
C4StartupScenSel_TitlePictureWdt = 200,
C4StartupScenSel_TitlePictureHgt = 150,
C4StartupScenSel_TitlePicturePadding = 10,
C4StartupScenSel_TitleOverlayMargin = 10; // number of pixels to each side of title overlay picture
// a list of loaded scenarios
class C4ScenarioListLoader

View File

@ -547,6 +547,13 @@ GLhandleARB C4LandscapeRenderGL::CreateShader(GLenum iShaderType, const char *sz
szCodeRest = szVersion;
}
// Get number of available uniforms from driver
GLint max_uniforms = 0;
glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB, &max_uniforms);
Version.AppendFormat("#define MAX_FRAGMENT_UNIFORM_COMPONENTS %d\n", max_uniforms);
glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &max_uniforms);
Version.AppendFormat("#define MAX_VERTEX_UNIFORM_COMPONENTS %d\n", max_uniforms);
// Build code
const char *szCodes[C4LR_ShaderWorkaroundCount + 2];
szCodes[0] = Version.getData();

View File

@ -428,7 +428,7 @@ bool C4MCOverlay::SetField(C4MCParser *pParser, const char *szField, const char
case C4MCV_ScriptFunc:
{
// get script func of main script
C4AulFunc *pSFunc = ::GameScript.ScenPropList->GetFunc(StrPar);
C4AulFunc *pSFunc = ::GameScript.ScenPropList._getPropList()->GetFunc(StrPar);
if (!pSFunc) throw C4MCParserErr(pParser, C4MCErr_SFuncNotFound, StrPar);
// add to main
Target.As<C4MCCallbackArray*>() = new C4MCCallbackArray(pSFunc, MapCreator);

View File

@ -576,7 +576,7 @@ void SNewSegment(char *szStr, const char *szSepa)
int SGetLine(const char *szText, const char *cpPosition)
{
if (!szText || !cpPosition) return 0;
int iLines = 0;
int iLines = 1;
while (*szText && (szText<cpPosition))
{
if (*szText == 0x0A) iLines++;
@ -588,11 +588,16 @@ int SGetLine(const char *szText, const char *cpPosition)
int SLineGetCharacters(const char *szText, const char *cpPosition)
{
if (!szText || !cpPosition) return 0;
int iChars = 0;
int iChars = 1;
while (*szText && (szText<cpPosition))
{
if (*szText == 0x0A) iChars = 0;
iChars++;
if (*szText == 0x0A)
iChars = 1;
else if (*szText == '\t')
// assume a tab stop every 8 characters
iChars = ((iChars - 1 + 8) & ~7) + 1;
else
iChars++;
szText++;
}
return iChars;

View File

@ -252,7 +252,7 @@ void C4Def::CompileFunc(StdCompiler *pComp)
//-------------------------------- C4Def -------------------------------------------------------
C4Def::C4Def(): Script(this), C4PropList(ScriptEngine.GetPropList())
C4Def::C4Def(): Script(this), C4PropListStatic(ScriptEngine.GetPropList(), NULL, NULL)
{
assert(ScriptEngine.GetPropList());
Graphics.pDef = this;
@ -363,6 +363,7 @@ bool C4Def::Load(C4Group &hGroup,
// Register ID with script engine
::ScriptEngine.RegisterGlobalConstant(id.ToString(), C4VPropList(this));
ParentKeyName = ::Strings.RegString(id.ToString());
// Read script
if (dwLoadWhat & C4D_Load_Script)

View File

@ -102,7 +102,7 @@ C4D_Load_Temporary = 1024;
#define C4D_Blit_Additive 1
#define C4D_Blit_ModAdd 2
class C4Def: public C4PropList
class C4Def: public C4PropListStatic
{
public:
C4ID id;
@ -213,7 +213,7 @@ public:
void Synchronize();
virtual C4Def const * GetDef() const { return this; }
virtual C4Def * GetDef() { return this; }
virtual bool IsDef() const { return true; }
virtual bool Delete() { return false; }
protected:
bool LoadActMap(C4Group &hGroup);
void CrossMapActMap();

View File

@ -52,18 +52,18 @@ StdMeshInstance::ValueProvider* CreateValueProviderFromArray(C4Object* pForObj,
return new C4ValueProviderConst(itofix(Data[1].getInt(), 1000));
case C4AVP_Linear:
if (Data[4].getInt() == 0)
throw new C4AulExecError(pForObj, "Length cannot be zero");
throw new C4AulExecError("Length cannot be zero");
return new C4ValueProviderLinear(itofix(Data[1].getInt(), 1000), itofix(Data[2].getInt(), 1000), itofix(Data[3].getInt(), 1000), Data[4].getInt(), static_cast<C4AnimationEnding>(Data[5].getInt()));
case C4AVP_X:
if (!pForObj) return NULL;
if (Data[4].getInt() == 0)
throw new C4AulExecError(pForObj, "Length cannot be zero");
throw new C4AulExecError("Length cannot be zero");
return new C4ValueProviderX(pForObj, itofix(Data[1].getInt(), 1000), itofix(Data[2].getInt(), 1000), itofix(Data[3].getInt(), 1000), Data[4].getInt());
case C4AVP_Y:
if (!pForObj) return NULL;
if (Data[4].getInt() == 0)
throw new C4AulExecError(pForObj, "Length cannot be zero");
throw new C4AulExecError("Length cannot be zero");
return new C4ValueProviderY(pForObj, itofix(Data[1].getInt(), 1000), itofix(Data[2].getInt(), 1000), itofix(Data[3].getInt(), 1000), Data[4].getInt());
case C4AVP_R:
@ -74,27 +74,27 @@ StdMeshInstance::ValueProvider* CreateValueProviderFromArray(C4Object* pForObj,
case C4AVP_AbsX:
if (!pForObj) return NULL;
if (Data[4].getInt() == 0)
throw new C4AulExecError(pForObj, "Length cannot be zero");
throw new C4AulExecError("Length cannot be zero");
return new C4ValueProviderAbsX(pForObj, itofix(Data[1].getInt(), 1000), itofix(Data[2].getInt(), 1000), itofix(Data[3].getInt(), 1000), Data[4].getInt());
case C4AVP_AbsY:
if (!pForObj) return NULL;
if (Data[4].getInt() == 0)
throw new C4AulExecError(pForObj, "Length cannot be zero");
throw new C4AulExecError("Length cannot be zero");
return new C4ValueProviderAbsY(pForObj, itofix(Data[1].getInt(), 1000), itofix(Data[2].getInt(), 1000), itofix(Data[3].getInt(), 1000), Data[4].getInt());
case C4AVP_XDir:
if (!pForObj) return NULL;
if (Data[3].getInt() == 0)
throw new C4AulExecError(pForObj, "MaxXDir cannot be zero");
throw new C4AulExecError("MaxXDir cannot be zero");
return new C4ValueProviderXDir(pForObj, itofix(Data[1].getInt(), 1000), itofix(Data[2].getInt(), 1000), itofix(Data[3].getInt(),Data[4].getInt()));
case C4AVP_YDir:
if (!pForObj) return NULL;
if (Data[3].getInt() == 0)
throw new C4AulExecError(pForObj, "MaxYDir cannot be zero");
throw new C4AulExecError("MaxYDir cannot be zero");
return new C4ValueProviderYDir(pForObj, itofix(Data[1].getInt(), 1000), itofix(Data[2].getInt(), 1000), itofix(Data[3].getInt(),Data[4].getInt()));
case C4AVP_RDir:
if (!pForObj) return NULL;
if (Data[3].getInt() == 0)
throw new C4AulExecError(pForObj, "MaxRDir cannot be zero");
throw new C4AulExecError("MaxRDir cannot be zero");
return new C4ValueProviderRDir(pForObj, itofix(Data[1].getInt(), 1000), itofix(Data[2].getInt(), 1000), itofix(Data[3].getInt(),Data[4].getInt()));
case C4AVP_CosR:
if (!pForObj) return NULL;

View File

@ -4924,7 +4924,7 @@ void C4Object::SetPropertyByS(C4String * k, const C4Value & to)
switch(k - &Strings.P[0])
{
case P_Plane:
if (!to.getInt()) throw new C4AulExecError(this, "invalid Plane 0");
if (!to.getInt()) throw new C4AulExecError("invalid Plane 0");
SetPlane(to.getInt());
return;
}
@ -4957,3 +4957,13 @@ bool C4Object::GetPropertyByS(C4String *k, C4Value *pResult) const
}
return C4PropListNumbered::GetPropertyByS(k, pResult);
}
C4ValueArray * C4Object::GetProperties() const
{
C4ValueArray * a = C4PropList::GetProperties();
int i;
i = a->GetSize();
a->SetSize(i + 1);
(*a)[i++] = C4VString(&::Strings.P[P_Plane]);
return a;
}

View File

@ -409,6 +409,7 @@ public:
virtual void SetPropertyByS(C4String * k, const C4Value & to);
virtual void ResetProperty(C4String * k);
virtual bool GetPropertyByS(C4String *k, C4Value *pResult) const;
virtual C4ValueArray * GetProperties() const;
};
#endif

View File

@ -84,13 +84,13 @@ static bool FnPunch(C4Object *Obj, C4Object *target, long punch)
return !!ObjectComPunch(Obj,target,punch);
}
static bool FnKill(C4AulContext *cthr, C4Object *pObj, bool fForced)
static bool FnKill(C4PropList * _this, C4Object *pObj, bool fForced)
{
if (!pObj) pObj=cthr->Obj; if (!pObj) return false;
if (!pObj) pObj=Object(_this); if (!pObj) return false;
if (!pObj->GetAlive()) return false;
// Trace kills by player-owned objects
// Do not trace for NO_OWNER, because that would include e.g. the Suicide-rule
if (cthr->Obj && ValidPlr(cthr->Obj->Controller)) pObj->UpdatLastEnergyLossCause(cthr->Obj->Controller);
if (Object(_this) && ValidPlr(Object(_this)->Controller)) pObj->UpdatLastEnergyLossCause(Object(_this)->Controller);
// Do the kill
pObj->AssignDeath(!!fForced);
return true;
@ -174,24 +174,24 @@ static long FnGetCon(C4Object *Obj, long iPrec)
return iPrec*Obj->GetCon()/FullCon;
}
static C4String *FnGetName(C4AulContext *cthr)
static C4String *FnGetName(C4PropList * _this)
{
if (!cthr->Def)
if (!_this)
throw new NeedNonGlobalContext("GetName");
else
return String(cthr->Def->GetName());
return String(_this->GetName());
}
static bool FnSetName(C4AulContext *cthr, C4String *pNewName, bool fSetInInfo, bool fMakeValidIfExists)
static bool FnSetName(C4PropList * _this, C4String *pNewName, bool fSetInInfo, bool fMakeValidIfExists)
{
if (!cthr->Obj)
if (!Object(_this))
{
if (!cthr->Def)
if (!_this)
throw new NeedNonGlobalContext("SetName");
else if (fSetInInfo)
return false;
// Definition name
cthr->Def->SetName(FnStringPar(pNewName));
_this->SetName(FnStringPar(pNewName));
return true;
}
else
@ -200,7 +200,7 @@ static bool FnSetName(C4AulContext *cthr, C4String *pNewName, bool fSetInInfo, b
if (fSetInInfo)
{
// setting name in info
C4ObjectInfo *pInfo = cthr->Obj->Info;
C4ObjectInfo *pInfo = Object(_this)->Info;
if (!pInfo) return false;
const char *szName = pNewName->GetCStr();
// empty names are bad; e.g., could cause problems in savegames
@ -213,7 +213,7 @@ static bool FnSetName(C4AulContext *cthr, C4String *pNewName, bool fSetInInfo, b
// querying owner info list here isn't 100% accurate, as infos might have been stolen by other players
// however, there is no good way to track the original list ATM
C4ObjectInfoList *pInfoList = NULL;
C4Player *pOwner = ::Players.Get(cthr->Obj->Owner);
C4Player *pOwner = ::Players.Get(Object(_this)->Owner);
if (pOwner) pInfoList = &pOwner->CrewInfoList;
char NameBuf[C4MaxName+1];
if (pInfoList) if (pInfoList->NameExists(szName))
@ -224,14 +224,14 @@ static bool FnSetName(C4AulContext *cthr, C4String *pNewName, bool fSetInInfo, b
szName = NameBuf;
}
SCopy(szName, pInfo->Name, C4MaxName);
cthr->Obj->SetName(); // make sure object uses info name
cthr->Obj->Call(PSF_NameChange,&C4AulParSet(C4VBool(true)));
Object(_this)->SetName(); // make sure object uses info name
Object(_this)->Call(PSF_NameChange,&C4AulParSet(C4VBool(true)));
}
else
{
if (!pNewName) cthr->Obj->SetName();
else cthr->Obj->SetName(pNewName->GetCStr());
cthr->Obj->Call(PSF_NameChange,&C4AulParSet(C4VBool(false)));
if (!pNewName) Object(_this)->SetName();
else Object(_this)->SetName(pNewName->GetCStr());
Object(_this)->Call(PSF_NameChange,&C4AulParSet(C4VBool(false)));
}
}
return true;
@ -580,15 +580,15 @@ static long FnGetBreath(C4Object *Obj)
return Obj->Breath;
}
static long FnGetMass(C4AulContext *cthr)
static long FnGetMass(C4PropList * _this)
{
if (!cthr->Obj)
if (!cthr->Def || !cthr->Def->GetDef())
if (!Object(_this))
if (!_this || !_this->GetDef())
throw new NeedNonGlobalContext("GetMass");
else
return cthr->Def->GetDef()->Mass;
return _this->GetDef()->Mass;
else
return cthr->Obj->Mass;
return Object(_this)->Mass;
}
static long FnGetRDir(C4Object *Obj, long iPrec)
@ -749,15 +749,15 @@ static bool FnSetKiller(C4Object *Obj, long iNewKiller)
return true;
}
static long FnGetCategory(C4AulContext *cthr)
static long FnGetCategory(C4PropList * _this)
{
if (!cthr->Obj)
if (!cthr->Def || !cthr->Def->GetDef())
if (!Object(_this))
if (!_this || !_this->GetDef())
throw new NeedNonGlobalContext("GetCategory");
else
return cthr->Def->GetDef()->Category;
return _this->GetDef()->Category;
else
return cthr->Obj->Category;
return Object(_this)->Category;
}
static long FnGetOCF(C4Object *Obj)
@ -770,15 +770,15 @@ static long FnGetDamage(C4Object *Obj)
return Obj->Damage;
}
static long FnGetValue(C4AulContext *cthr, C4Object *pInBase, long iForPlayer)
static long FnGetValue(C4PropList * _this, C4Object *pInBase, long iForPlayer)
{
if (!cthr->Obj)
if (!cthr->Def || !cthr->Def->GetDef())
if (!Object(_this))
if (!_this || !_this->GetDef())
throw new NeedNonGlobalContext("GetValue");
else
return cthr->Def->GetDef()->GetValue(pInBase, iForPlayer);
return _this->GetDef()->GetValue(pInBase, iForPlayer);
else
return cthr->Obj->GetValue(pInBase, iForPlayer);
return Object(_this)->GetValue(pInBase, iForPlayer);
}
static long FnGetRank(C4Object *Obj)
@ -895,7 +895,7 @@ static bool FnAddMenuItem(C4Object *Obj, C4String * szCaption, C4String * szComm
else if (Parameter.getPropList()->GetDef())
sprintf(parameter, "C4Id(\"%s\")", Parameter.getPropList()->GetDef()->id.ToString());
else
throw new C4AulExecError(Obj, "proplist as parameter to AddMenuItem");
throw new C4AulExecError("proplist as parameter to AddMenuItem");
break;
case C4V_String:
// note this breaks if there is '"' in the string.
@ -908,7 +908,7 @@ static bool FnAddMenuItem(C4Object *Obj, C4String * szCaption, C4String * szComm
break;
case C4V_Array:
// Arrays were never allowed, so tell the scripter
throw new C4AulExecError(Obj, "array as parameter to AddMenuItem");
throw new C4AulExecError("array as parameter to AddMenuItem");
default:
return false;
}
@ -1053,8 +1053,7 @@ static bool FnAddMenuItem(C4Object *Obj, C4String * szCaption, C4String * szComm
{
// draw object picture
if (!XPar.CheckConversion(C4V_Object))
throw new C4AulExecError(Obj,
FormatString("call to \"%s\" parameter %d: got \"%s\", but expected \"%s\"!",
throw new C4AulExecError(FormatString("call to \"%s\" parameter %d: got \"%s\", but expected \"%s\"!",
"AddMenuItem", 8, XPar.GetTypeName(), GetC4VName(C4V_Object)
).getData());
pGfxObj = XPar.getObj();
@ -1294,9 +1293,9 @@ static long FnSetTransferZone(C4Object *Obj, long iX, long iY, long iWdt, long i
return Game.TransferZones.Set(iX,iY,iWdt,iHgt,Obj);
}
static long FnObjectDistance(C4AulContext *cthr, C4Object *pObj2, C4Object *pObj)
static long FnObjectDistance(C4PropList * _this, C4Object *pObj2, C4Object *pObj)
{
if (!pObj) pObj=cthr->Obj; if (!pObj || !pObj2) return 0;
if (!pObj) pObj=Object(_this); if (!pObj || !pObj2) return 0;
return Distance(pObj->GetX(),pObj->GetY(),pObj2->GetX(),pObj2->GetY());
}
@ -1506,13 +1505,13 @@ static bool FnSetGraphics(C4Object *Obj, C4String *pGfxName, C4Def *pSrcDef, lon
return Obj->SetGraphics(FnStringPar(pGfxName), pSrcDef);
}
static long FnGetDefBottom(C4AulContext* cthr)
static long FnGetDefBottom(C4PropList * _this)
{
if (!cthr->Def || !cthr->Def->GetDef())
if (!_this || !_this->GetDef())
throw new NeedNonGlobalContext("GetDefBottom");
assert(!cthr->Obj || cthr->Obj->Def == cthr->Def->GetDef());
return cthr->Def->GetDef()->Shape.y+cthr->Def->GetDef()->Shape.Hgt + (cthr->Obj ? cthr->Obj->GetY() : 0);
assert(!Object(_this) || Object(_this)->Def == _this->GetDef());
return _this->GetDef()->Shape.y+_this->GetDef()->Shape.Hgt + (Object(_this) ? Object(_this)->GetY() : 0);
}
static bool FnSetMenuSize(C4Object *Obj, long iCols, long iRows)
@ -2006,7 +2005,7 @@ static Nillable<int> FnAttachMesh(C4Object *Obj, C4PropList* Mesh, C4String * sz
StdMeshMatrix trans = StdMeshMatrix::Identity();
if (Transformation)
if (!C4ValueToMatrix(*Transformation, &trans))
throw new C4AulExecError(Obj, "AttachMesh: Transformation is not a valid 3x4 matrix");
throw new C4AulExecError("AttachMesh: Transformation is not a valid 3x4 matrix");
StdMeshInstance::AttachedMesh* attach;
C4Object* pObj = Mesh->GetObject();
@ -2064,7 +2063,7 @@ static bool FnSetAttachTransform(C4Object *Obj, long iAttachNumber, C4ValueArray
StdMeshMatrix trans;
if (!C4ValueToMatrix(*Transformation, &trans))
throw new C4AulExecError(Obj, "SetAttachTransform: Transformation is not a valid 3x4 matrix");
throw new C4AulExecError("SetAttachTransform: Transformation is not a valid 3x4 matrix");
attach->SetAttachTransformation(trans);
return true;
@ -2093,23 +2092,6 @@ static bool FnSetMeshMaterial(C4Object *Obj, C4String* Material, int iSubMesh)
return true;
}
static C4PropList* FnCreateRope(C4AulContext *cthr, C4Object* First, C4Object* Second, int SegmentLength, C4PropList* Graphics)
{
try
{
if(!Graphics) return false;
C4Def* Def = Graphics->GetDef();
if(!Def) return false;
return Game.Ropes.CreateRope(First, Second, itofix(SegmentLength), &Def->Graphics);
}
catch(const C4RopeError& err)
{
DebugLogF("Failed to create rope: %s", err.what());
return NULL;
}
}
//=========================== C4Script Function Map ===================================
C4ScriptConstDef C4ScriptObjectConstMap[]=
@ -2430,7 +2412,6 @@ void InitObjectFunctionMap(C4AulScriptEngine *pEngine)
AddFunc(pEngine, "SetAttachTransform", FnSetAttachTransform);
AddFunc(pEngine, "GetMeshMaterial", FnGetMeshMaterial);
AddFunc(pEngine, "SetMeshMaterial", FnSetMeshMaterial);
AddFunc(pEngine, "CreateRope", FnCreateRope);
AddFunc(pEngine, "ChangeDef", FnChangeDef);
AddFunc(pEngine, "GrabContents", FnGrabContents);
AddFunc(pEngine, "Punch", FnPunch);

View File

@ -19,67 +19,67 @@
#include <C4Rope.h>
#include <C4AulDefFunc.h>
static C4Void FnRemove(C4AulContext* Context)
static C4Void FnRemove(C4PropList* Rope)
{
Game.Ropes.RemoveRope(static_cast<C4Rope*>(Context->Def));
Game.Ropes.RemoveRope(static_cast<C4Rope*>(Rope));
return C4Void();
}
static C4Object* FnGetFront(C4AulContext* Context)
static C4Object* FnGetFront(C4PropList* Rope)
{
return static_cast<C4Rope*>(Context->Def)->GetFront()->GetObject();
return static_cast<C4Rope*>(Rope)->GetFront()->GetObject();
}
static C4Object* FnGetBack(C4AulContext* Context)
static C4Object* FnGetBack(C4PropList* Rope)
{
return static_cast<C4Rope*>(Context->Def)->GetBack()->GetObject();
return static_cast<C4Rope*>(Rope)->GetBack()->GetObject();
}
static C4Void FnSetFront(C4AulContext* Context, C4Object* obj, Nillable<int> x, Nillable<int> y)
static C4Void FnSetFront(C4PropList* Rope, C4Object* obj, Nillable<int> x, Nillable<int> y)
{
static_cast<C4Rope*>(Context->Def)->SetFront(obj, x.IsNil() ? Fix0 : itofix(x), y.IsNil() ? Fix0 : itofix(y));
static_cast<C4Rope*>(Rope)->SetFront(obj, x.IsNil() ? Fix0 : itofix(x), y.IsNil() ? Fix0 : itofix(y));
return C4Void();
}
static C4Void FnSetBack(C4AulContext* Context, C4Object* obj, Nillable<int> x, Nillable<int> y)
static C4Void FnSetBack(C4PropList* Rope, C4Object* obj, Nillable<int> x, Nillable<int> y)
{
static_cast<C4Rope*>(Context->Def)->SetBack(obj, x.IsNil() ? Fix0 : itofix(x), y.IsNil() ? Fix0 : itofix(y));
static_cast<C4Rope*>(Rope)->SetBack(obj, x.IsNil() ? Fix0 : itofix(x), y.IsNil() ? Fix0 : itofix(y));
return C4Void();
}
static C4Void FnSetFrontAutoSegmentation(C4AulContext* Context, int max)
static C4Void FnSetFrontAutoSegmentation(C4PropList* Rope, int max)
{
static_cast<C4Rope*>(Context->Def)->SetFrontAutoSegmentation(itofix(max));
static_cast<C4Rope*>(Rope)->SetFrontAutoSegmentation(itofix(max));
return C4Void();
}
static C4Void FnSetBackAutoSegmentation(C4AulContext* Context, int max)
static C4Void FnSetBackAutoSegmentation(C4PropList* Rope, int max)
{
static_cast<C4Rope*>(Context->Def)->SetBackAutoSegmentation(itofix(max));
static_cast<C4Rope*>(Rope)->SetBackAutoSegmentation(itofix(max));
return C4Void();
}
static C4Void FnSetFrontFixed(C4AulContext* Context, bool fixed)
static C4Void FnSetFrontFixed(C4PropList* Rope, bool fixed)
{
static_cast<C4Rope*>(Context->Def)->SetFrontFixed(fixed);
static_cast<C4Rope*>(Rope)->SetFrontFixed(fixed);
return C4Void();
}
static C4Void FnSetBackFixed(C4AulContext* Context, bool fixed)
static C4Void FnSetBackFixed(C4PropList* Rope, bool fixed)
{
static_cast<C4Rope*>(Context->Def)->SetBackFixed(fixed);
static_cast<C4Rope*>(Rope)->SetBackFixed(fixed);
return C4Void();
}
static C4Void FnPullFront(C4AulContext* Context, int force)
static C4Void FnPullFront(C4PropList* Rope, int force)
{
static_cast<C4Rope*>(Context->Def)->PullFront(itofix(force));
static_cast<C4Rope*>(Rope)->PullFront(itofix(force));
return C4Void();
}
static C4Void FnPullBack(C4AulContext* Context, int force)
static C4Void FnPullBack(C4PropList* Rope, int force)
{
static_cast<C4Rope*>(Context->Def)->PullBack(itofix(force));
static_cast<C4Rope*>(Rope)->PullBack(itofix(force));
return C4Void();
}
@ -96,8 +96,9 @@ C4RopeAul::~C4RopeAul()
void C4RopeAul::InitFunctionMap(C4AulScriptEngine* pEngine)
{
delete RopeDef;
RopeDef = C4PropList::NewScen();
RopeDef->SetName("C4Rope");
RopeDef = C4PropList::NewAnon(NULL, NULL, ::Strings.RegString("Rope"));
RopeDef->SetName("Rope");
pEngine->RegisterGlobalConstant("Rope", C4VPropList(RopeDef));
Reg2List(pEngine);

View File

@ -240,6 +240,9 @@ LRESULT APIENTRY ViewportWinProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPa
StoreWindowPosition(hwnd, FormatString("Viewport%i",cvp->Player+1).getData(), Config.GetSubkeyPath("Console"));
break;
//----------------------------------------------------------------------------------------------------------------------------------
case WM_CREATE:
DragAcceptFiles(hwnd, TRUE);
break;
case WM_CLOSE:
cvp->pWindow->Close();
break;
@ -252,11 +255,11 @@ LRESULT APIENTRY ViewportWinProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPa
int32_t iFileNum = DragQueryFile(hDrop,0xFFFFFFFF,NULL,0);
POINT pntPoint;
DragQueryPoint(hDrop,&pntPoint);
wchar_t szFilename[500+1];
for (int32_t cnt=0; cnt<iFileNum; cnt++)
{
DragQueryFileW(hDrop,cnt,szFilename,500);
DragQueryPoint(hDrop,&pntPoint);
cvp->DropFile(StdStrBuf(szFilename).getData(), (float)pntPoint.x, (float)pntPoint.y);
}
DragFinish(hDrop);

View File

@ -21,7 +21,7 @@
* "Clonk" is a registered trademark of Matthes Bender.
* See clonk_trademark_license.txt for full license.
*/
// C4Aul script engine CP conversion
// Miscellaneous script engine bits
#include <C4Include.h>
#include <C4Aul.h>
@ -44,127 +44,17 @@ void C4AulError::show()
DebugLog(sMessage.getData());
}
C4AulFunc::C4AulFunc(C4AulScript *pOwner, const char *pName):
iRefCnt(0),
Name(pName ? Strings.RegString(pName) : 0),
MapNext(NULL),
OverloadedBy (NULL)
{
AppendToScript(pOwner);
IncRef(); // see C4AulScript::Clear()
}
void C4AulFunc::AppendToScript(C4AulScript * pOwner)
{
Owner = pOwner;
if ((Prev = Owner->FuncL))
{
Prev->Next = this;
Owner->FuncL = this;
}
else
{
Owner->Func0 = this;
Owner->FuncL = this;
}
Next = NULL;
assert(GetName() || Owner->Temporary);
// add to global lookuptable with this name
if (GetName())
Owner->Engine->FuncLookUp.Add(this, true);
}
void C4AulFunc::RemoveFromScript()
{
if (Prev) Prev->Next = Next;
if (Next) Next->Prev = Prev;
if (Owner->Func0 == this) Owner->Func0 = Next;
if (Owner->FuncL == this) Owner->FuncL = Prev;
assert(Owner);
assert(Owner->Temporary || Name);
assert(!Owner->GetPropList() || Owner->GetPropList()->GetFunc(Name) != this);
if (GetName())
Owner->Engine->FuncLookUp.Remove(this);
Prev = 0;
Next = 0;
Owner = 0;
}
C4AulFunc::~C4AulFunc()
{
// remove from list
if (Prev) Prev->Next = Next;
if (Next) Next->Prev = Prev;
if (Owner)
{
if (Owner->Func0 == this) Owner->Func0 = Next;
if (Owner->FuncL == this) Owner->FuncL = Prev;
if (GetName())
Owner->Engine->FuncLookUp.Remove(this);
if (Owner->GetPropList() && Name)
{
C4Value v;
Owner->GetPropList()->GetPropertyByS(Name, &v);
assert(v.getFunction() != this);
}
}
}
StdStrBuf C4AulFunc::GetFullName()
{
// "lost" function?
StdStrBuf sOwner;
if (!Owner)
{
sOwner.Ref("(unknown) ");
}
else if (Owner->GetPropList() && Owner->GetPropList()->GetDef())
{
sOwner.Format("%s.", Owner->GetPropList()->GetDef()->id.ToString());
}
else if (Owner->Engine == Owner)
{
sOwner.Ref("global ");
}
else
{
sOwner.Ref("game ");
}
StdStrBuf sResult;
sResult.Format("%s%s", sOwner.getData(), GetName());
return sResult;
}
C4AulDefFunc::C4AulDefFunc(C4AulScript *pOwner, const char *pName, C4ScriptFnDef* pDef):
C4AulFunc(pOwner, pName) // constructor
{
Def = pDef;
Owner->GetPropList()->SetPropertyByS(Name, C4VFunction(this));
}
C4AulDefFunc::~C4AulDefFunc()
{
assert(!Owner);
}
C4AulScript::C4AulScript()
{
// not compiled
State = ASS_NONE;
IncludesResolved = false;
// defaults
Resolving=false;
Temporary = false;
LocalNamed.Reset();
// prepare lists
Prev = Next = NULL;
Engine = NULL;
Func0 = FuncL = NULL;
// prepare include list
Includes.clear();
Appends.clear();
}
C4AulScript::~C4AulScript()
@ -188,15 +78,6 @@ void C4AulScript::Unreg()
void C4AulScript::Clear()
{
// remove includes
Includes.clear();
Appends.clear();
while (Func0)
{
C4AulFunc * f = Func0;
f->RemoveFromScript();
f->DecRef(); // see C4AulFunc::C4AulFunc
}
// reset flags
State = ASS_NONE;
}
@ -263,13 +144,17 @@ C4AulScriptFunc::C4AulScriptFunc(C4AulScript *pOwner, const C4AulScriptFunc &Fro
ParType[i] = FromFunc.ParType[i];
}
void C4AulScript::AddFunc(const char *pIdtf, C4ScriptFnDef* Def)
C4AulScriptFunc::~C4AulScriptFunc()
{
// create def func
new C4AulDefFunc(this, pIdtf, Def);
if (OwnerOverloaded) OwnerOverloaded->DecRef();
}
void C4AulScriptFunc::SetOverloaded(C4AulFunc * f)
{
if (OwnerOverloaded) OwnerOverloaded->DecRef();
OwnerOverloaded = f;
if (f) f->IncRef();
}
/*--- C4AulScriptEngine ---*/
@ -293,7 +178,7 @@ C4PropList * C4AulScriptEngine::GetPropList()
{
if (!GlobalPropList)
{
GlobalPropList = C4PropList::NewScen();
GlobalPropList = C4PropList::NewAnon(NULL, NULL, ::Strings.RegString("Global"));
RegisterGlobalConstant("Global", C4VPropList(GlobalPropList));
}
return GlobalPropList;
@ -327,21 +212,6 @@ void C4AulScriptEngine::Clear()
GlobalNamed.SetNameList(&GlobalNamedNames);
}
void C4AulScriptEngine::UnLink()
{
// unlink scripts
for (C4AulScript *s = Child0; s; s = s->Next)
s->UnLink();
C4AulScript::UnLink();
// Do not clear global variables and constants, because they are registered by the
// preparser or other parts. Note that keeping those fields means that you cannot delete a global
// variable or constant at runtime by removing it from the script.
//GlobalNamedNames.Reset();
//GlobalConstNames.Reset();
}
void C4AulScriptEngine::RegisterGlobalConstant(const char *szName, const C4Value &rValue)
{
// Register name and set value.
@ -368,7 +238,7 @@ bool C4AulScriptEngine::Denumerate(C4ValueNumbers * numbers)
{
GlobalNamed.Denumerate(numbers);
// runtime data only: don't denumerate consts
GameScript.ScenPropList->Denumerate(numbers);
GameScript.ScenPropList.Denumerate(numbers);
return true;
}
@ -377,54 +247,45 @@ void C4AulScriptEngine::CompileFunc(StdCompiler *pComp, C4ValueNumbers * numbers
C4ValueMapData GlobalNamedDefault;
GlobalNamedDefault.SetNameList(&GlobalNamedNames);
pComp->Value(mkNamingAdapt(mkParAdapt(GlobalNamed, numbers), "StaticVariables", GlobalNamedDefault));
pComp->Value(mkNamingAdapt(mkParAdapt(*GameScript.ScenPropList, numbers), "Scenario"));
pComp->Value(mkNamingAdapt(mkParAdapt(*GameScript.ScenPropList._getPropList(), numbers), "Scenario"));
}
std::list<const char*> C4AulScriptEngine::GetFunctionNames(C4AulScript * script)
std::list<const char*> C4AulScriptEngine::GetFunctionNames(C4PropList * p)
{
std::list<const char*> functions;
for (C4AulFunc *pFn = Func0; pFn; pFn = pFn->Next)
std::list<const char*> global_functions;
if (!p) p = GetPropList();
const C4ValueArray * a = p->GetProperties();
for (int i = 0; i < a->GetSize(); ++i)
{
if (pFn->GetPublic())
{
functions.push_back(pFn->GetName());
}
}
// Add object or scenario script functions
if (script)
{
bool divider = false;
C4AulFunc *f = script->FuncL;
C4AulScriptFunc *pRef;
// Scan all functions
while (f)
{
if ((pRef = f->SFunc()))
{
// Insert divider if necessary
if (!divider)
functions.push_back(0);
divider = true;
// Add function
functions.push_back(pRef->GetName());
}
f = f->Prev;
}
C4String * key = (*a)[i].getStr();
if (!key) continue;
C4AulFunc * f = p->GetFunc(key);
if (!f) continue;
if (!f->GetPublic()) continue;
if (p->HasProperty(key))
functions.push_back(key->GetCStr());
else
global_functions.push_back(key->GetCStr());
}
delete a;
functions.sort();
functions.push_back(0);
global_functions.sort();
functions.splice(functions.end(), global_functions);
return functions;
}
/*--- C4AulFuncMap ---*/
static const size_t CapacityInc = 1024;
C4AulFuncMap::C4AulFuncMap(): Funcs(new C4AulFunc*[CapacityInc]), FuncCnt(0), Capacity(CapacityInc)
C4AulFuncMap::C4AulFuncMap(): FuncCnt(0)
{
memset(Funcs, 0, sizeof (C4AulFunc *) * Capacity);
memset(Funcs, 0, sizeof (C4AulFunc *) * HashSize);
}
C4AulFuncMap::~C4AulFuncMap()
{
delete[] Funcs;
assert(!FuncCnt);
}
unsigned int C4AulFuncMap::Hash(const char * name)
@ -436,11 +297,11 @@ unsigned int C4AulFuncMap::Hash(const char * name)
return h;
}
C4AulFunc * C4AulFuncMap::GetFirstFunc(const char * Name)
C4AulFunc * C4AulFuncMap::GetFirstFunc(C4String * Name)
{
if (!Name) return NULL;
C4AulFunc * Func = Funcs[Hash(Name) % Capacity];
while (Func && !SEqual(Name, Func->GetName()))
C4AulFunc * Func = Funcs[Hash(Name->GetCStr()) % HashSize];
while (Func && Name->GetCStr() != Func->GetName())
Func = Func->MapNext;
return Func;
}
@ -448,60 +309,25 @@ C4AulFunc * C4AulFuncMap::GetFirstFunc(const char * Name)
C4AulFunc * C4AulFuncMap::GetNextSNFunc(const C4AulFunc * After)
{
C4AulFunc * Func = After->MapNext;
while (Func && !SEqual(After->GetName(), Func->GetName()))
while (Func && After->GetName() != Func->GetName())
Func = Func->MapNext;
return Func;
}
void C4AulFuncMap::Add(C4AulFunc * func, bool bAtStart)
void C4AulFuncMap::Add(C4AulFunc * func)
{
if (++FuncCnt > Capacity)
{
int NCapacity = Capacity + CapacityInc;
C4AulFunc ** NFuncs = new C4AulFunc*[NCapacity];
memset(NFuncs, 0, sizeof (C4AulFunc *) * NCapacity);
for (int i = 0; i < Capacity; ++i)
{
while (Funcs[i])
{
// Get a pointer to the bucket
C4AulFunc ** pNFunc = &(NFuncs[Hash(Funcs[i]->GetName()) % NCapacity]);
// get a pointer to the end of the linked list
while (*pNFunc) pNFunc = &((*pNFunc)->MapNext);
// Move the func over
*pNFunc = Funcs[i];
// proceed with the next list member
Funcs[i] = Funcs[i]->MapNext;
// Terminate the linked list
(*pNFunc)->MapNext = 0;
}
}
Capacity = NCapacity;
delete [] Funcs;
Funcs = NFuncs;
}
++FuncCnt;
// Get a pointer to the bucket
C4AulFunc ** pFunc = &(Funcs[Hash(func->GetName()) % Capacity]);
if (bAtStart)
{
// move the current first to the second position
func->MapNext = *pFunc;
}
else
{
// get a pointer to the end of the linked list
while (*pFunc)
{
pFunc = &((*pFunc)->MapNext);
}
}
C4AulFunc ** pFunc = &(Funcs[Hash(func->GetName()) % HashSize]);
// move the current first to the second position
func->MapNext = *pFunc;
// Add the func
*pFunc = func;
}
void C4AulFuncMap::Remove(C4AulFunc * func)
{
C4AulFunc ** pFunc = &Funcs[Hash(func->GetName()) % Capacity];
C4AulFunc ** pFunc = &Funcs[Hash(func->GetName()) % HashSize];
while (*pFunc != func)
{
pFunc = &((*pFunc)->MapNext);

View File

@ -62,9 +62,8 @@ public:
// execution error
class C4AulExecError : public C4AulError
{
C4Object *cObj;
public:
C4AulExecError(C4Object *pObj, const char *szError); // constructor
C4AulExecError(const char *szError);
};
// function access
@ -76,25 +75,6 @@ enum C4AulAccess
AA_GLOBAL
};
struct C4AulParSet
{
C4Value Par[C4AUL_MAX_Par];
C4AulParSet() {} // standard-constructor
C4AulParSet(const C4Value &par0, const C4Value &par1 = C4Value(), const C4Value &par2 = C4Value(), const C4Value &par3 = C4Value(), const C4Value &par4 = C4Value(),
const C4Value &par5 = C4Value(), const C4Value &par6 = C4Value(), const C4Value &par7 = C4Value(), const C4Value &par8 = C4Value(), const C4Value &par9 = C4Value())
{
Par[0].Set(par0); Par[1].Set(par1); Par[2].Set(par2); Par[3].Set(par3); Par[4].Set(par4);
Par[5].Set(par5); Par[6].Set(par6); Par[7].Set(par7); Par[8].Set(par8); Par[9].Set(par9);
}
C4Value & operator[](int iIdx) { return Par[iIdx]; }
C4AulParSet * operator&() { return this; }
};
#define Copy2ParSet8(Pars, Vars) Pars[0].Set(Vars##0); Pars[1].Set(Vars##1); Pars[2].Set(Vars##2); Pars[3].Set(Vars##3); Pars[4].Set(Vars##4); Pars[5].Set(Vars##5); Pars[6].Set(Vars##6); Pars[7].Set(Vars##7);
#define Copy2ParSet9(Pars, Vars) Pars[0].Set(Vars##0); Pars[1].Set(Vars##1); Pars[2].Set(Vars##2); Pars[3].Set(Vars##3); Pars[4].Set(Vars##4); Pars[5].Set(Vars##5); Pars[6].Set(Vars##6); Pars[7].Set(Vars##7); Pars[8].Set(Vars##8);
#define Copy2ParSet10(Pars, Vars) Pars[0].Set(Vars##0); Pars[1].Set(Vars##1); Pars[2].Set(Vars##2); Pars[3].Set(Vars##3); Pars[4].Set(Vars##4); Pars[5].Set(Vars##5); Pars[6].Set(Vars##6); Pars[7].Set(Vars##7); Pars[8].Set(Vars##8); Pars[9].Set(Vars##9);
// byte code chunk type
// some special script functions defined hard-coded to reduce the exec context
enum C4AulBCCType
@ -185,16 +165,10 @@ struct C4AulBCC
} Par; // extra info
};
// call context
struct C4AulContext
{
C4Object *Obj;
C4PropList *Def;
};
// execution context
struct C4AulScriptContext : public C4AulContext
struct C4AulScriptContext
{
C4PropList *Obj;
C4Value *Return;
C4Value *Pars;
C4Value *Vars;
@ -212,6 +186,7 @@ class C4AulScriptFunc : public C4AulFunc
{
public:
C4AulFunc *OwnerOverloaded; // overloaded owner function; if present
void SetOverloaded(C4AulFunc *);
C4AulScriptFunc *SFunc() { return this; } // type check func...
protected:
int CodePos; // code pos
@ -227,18 +202,15 @@ public:
C4AulScriptFunc(C4AulScript *pOwner, C4ScriptHost *pOrgScript, const char *pName, const char *Script);
C4AulScriptFunc(C4AulScript *pOwner, const C4AulScriptFunc &FromFunc); // copy script/code, etc from given func
~C4AulScriptFunc();
void ParseFn(C4AulScriptContext* context = NULL);
virtual void UnLink();
virtual bool GetPublic() { return true; }
virtual int GetParCount() { return ParCount; }
virtual C4V_Type *GetParType() { return ParType; }
virtual C4V_Type GetRetType() { return C4V_Any; }
virtual C4Value Exec(C4AulContext *pCallerCtx, C4Value pPars[], bool fPassErrors=false); // execute func (script call, should not happen)
virtual C4Value Exec(C4PropList * p = NULL, C4AulParSet *pPars = NULL, bool fPassErrors=false); // execute func (engine call)
void SetError(C4AulContext *ctx, const char *szMessage); // set error message
virtual C4Value Exec(C4PropList * p, C4Value pPars[], bool fPassErrors=false); // execute func
int GetLineOfCode(C4AulBCC * bcc);
C4AulBCC * GetCode();
@ -250,37 +222,20 @@ public:
friend class C4ScriptHost;
};
// defined function class
class C4AulDefFunc : C4AulFunc
{
public:
C4ScriptFnDef* Def;
C4AulDefFunc(C4AulScript *pOwner, const char *pName, C4ScriptFnDef* pDef);
~C4AulDefFunc();
virtual bool GetPublic() { return !!Def->Public; }
virtual C4V_Type* GetParType() { return Def->ParType; }
virtual C4V_Type GetRetType() { return Def->RetType; }
using C4AulFunc::Exec;
virtual C4Value Exec(C4AulContext *pCallerCtx, C4Value pPars[], bool fPassErrors=false); // execute func (script call)
};
class C4AulFuncMap
{
public:
C4AulFuncMap();
~C4AulFuncMap();
C4AulFunc * GetFirstFunc(const char * Name);
C4AulFunc * GetFirstFunc(C4String * Name);
C4AulFunc * GetNextSNFunc(const C4AulFunc * After);
private:
C4AulFunc ** Funcs;
enum { HashSize = 1025 };
C4AulFunc * Funcs[HashSize];
int FuncCnt;
int Capacity;
static unsigned int Hash(const char * Name);
protected:
void Add(C4AulFunc * func, bool bAtEnd = true);
void Add(C4AulFunc * func);
void Remove(C4AulFunc * func);
friend class C4AulFunc;
friend class C4ScriptHost;
@ -336,22 +291,19 @@ public:
virtual bool Delete() { return true; } // allow deletion on pure class
StdCopyStrBuf ScriptName; // script name
C4ValueMapNames LocalNamed;
bool Temporary; // set for DirectExec-scripts; do not parse those
virtual C4PropList * GetPropList() { return 0; }
virtual C4ScriptHost * GetScriptHost() { return 0; }
void AddFunc(const char *pIdtf, C4ScriptFnDef* Def); // add def def func to table
C4Value DirectExec(C4Object *pObj, const char *szScript, const char *szContext, bool fPassErrors = false, C4AulScriptContext* context = NULL); // directly parse uncompiled script (WARG! CYCLES!)
void ResetProfilerTimes(); // zero all profiler times of owned functions
void CollectProfilerTimes(class C4AulProfiler &rProfiler);
virtual void ResetProfilerTimes(); // zero all profiler times of owned functions
virtual void CollectProfilerTimes(class C4AulProfiler &rProfiler);
bool IsReady() { return State == ASS_PARSED; } // whether script calls may be done
// helper functions
void Warn(const char *pMsg, const char *pIdtf);
void Warn(const char *pMsg, ...) GNUC_FORMAT_ATTRIBUTE_O;
friend class C4AulParseError;
friend class C4AulFunc;
@ -367,24 +319,16 @@ public:
protected:
C4LangStringTable *stringTable;
C4AulFunc *Func0, *FuncL; // owned functions
C4AulScriptEngine *Engine; //owning engine
C4AulScript *Prev, *Next; // tree structure
C4AulScriptState State; // script state
bool Resolving; // set while include-resolving, to catch circular includes
std::list<C4ID> Includes; // include list
std::list<C4ID> Appends; // append list
bool ResolveIncludes(C4DefList *rDefs); // resolve includes
bool ResolveAppends(C4DefList *rDefs); // resolve appends
void LinkFunctions();
bool IncludesResolved;
virtual void UnLink(); // reset to unlinked state
virtual bool ReloadScript(const char *szPath, const char *szLanguage); // reload given script
virtual bool Parse();
virtual bool ResolveIncludes(C4DefList *rDefs);
virtual bool ResolveAppends(C4DefList *rDefs);
virtual void UnLink();
};
// holds all C4AulScripts
@ -417,13 +361,13 @@ public:
virtual C4PropList * GetPropList();
using C4AulScript::ReloadScript;
bool ReloadScript(const char *szScript, C4DefList *pDefs, const char *szLanguage); // search script and reload + relink, if found
C4AulFunc * GetFirstFunc(const char * Name)
C4AulFunc * GetFirstFunc(C4String * Name)
{ return FuncLookUp.GetFirstFunc(Name); }
C4AulFunc * GetNextSNFunc(const C4AulFunc * After)
{ return FuncLookUp.GetNextSNFunc(After); }
// For the list of functions in the PropertyDlg
std::list<const char*> GetFunctionNames(C4AulScript *);
std::list<const char*> GetFunctionNames(C4PropList *);
void ResetProfilerTimes(); // zero all profiler times of owned functions
void CollectProfilerTimes(class C4AulProfiler &rProfiler);

View File

@ -229,7 +229,9 @@ void C4AulDebug::ProcessLine(const StdStrBuf &Line)
else if (SEqualNoCase(szCmd, "EXC") || SEqualNoCase(szCmd, "E"))
{
C4AulScriptContext* context = pExec->GetContext(pExec->GetContextDepth()-1);
int32_t objectNum = context && context->Obj ? context->Obj->Number : C4ControlScript::SCOPE_Global;
int32_t objectNum = C4ControlScript::SCOPE_Global;
if (context && context->Obj && context->Obj->GetObject())
objectNum = context->Obj->GetObject()->Number;
::Control.DoInput(CID_Script, new C4ControlScript(szData, objectNum, true, true), CDT_Decide);
}
else if (SEqualNoCase(szCmd, "PSE"))

View File

@ -26,24 +26,6 @@
#include <C4Effect.h>
#include <C4DefList.h>
typedef int32_t t_int;
typedef bool t_bool;
typedef C4ID t_id;
typedef C4Object *t_object;
typedef C4String *t_string;
typedef C4Value t_any;
typedef C4ValueArray *t_array;
inline t_int getPar_int(C4Value *pVal) { return pVal->getInt(); }
inline t_bool getPar_bool(C4Value *pVal) { return pVal->getBool(); }
inline t_id getPar_id(C4Value *pVal) { return pVal->getC4ID(); }
inline t_object getPar_object(C4Value *pVal) { return pVal->getObj(); }
inline t_string getPar_string(C4Value *pVal) { return pVal->getStr(); }
inline t_any getPar_any(C4Value *pVal) { return *pVal; }
inline t_array getPar_array(C4Value *pVal) { return pVal->getArray(); }
#define PAR(type, name) t_##type name = getPar_##type(pPars++)
inline const static char *FnStringPar(C4String *pString)
{
return pString ? pString->GetCStr() : "";
@ -52,9 +34,11 @@ inline C4String *String(const char * str)
{
return str ? ::Strings.RegString(str) : NULL;
}
StdStrBuf FnStringFormat(C4AulContext *cthr, const char *szFormatPar, C4Value * Par0=0, C4Value * Par1=0, C4Value * Par2=0, C4Value * Par3=0,
C4Value * Par4=0, C4Value * Par5=0, C4Value * Par6=0, C4Value * Par7=0, C4Value * Par8=0, C4Value * Par9=0);
enum { MaxFnStringParLen=500 };
inline C4Object * Object(C4PropList * _this)
{
return _this ? _this->GetObject() : NULL;
}
StdStrBuf FnStringFormat(C4PropList * _this, C4String *szFormatPar, C4Value * Pars, int ParCount);
template <typename T> struct C4ValueConv;
// Allow parameters to be nil
@ -102,7 +86,7 @@ public:
class NeedDefinitionContext : public C4AulExecError
{
public:
NeedDefinitionContext(const char *function) : C4AulExecError(NULL, FormatString("%s: must be called from definition context", function).getData()) {}
NeedDefinitionContext(const char *function) : C4AulExecError(FormatString("%s: must be called from definition context", function).getData()) {}
};
// Other functions are callable in object context only.
@ -110,7 +94,7 @@ public:
class NeedObjectContext : public C4AulExecError
{
public:
NeedObjectContext(const char *function) : C4AulExecError(NULL, FormatString("%s: must be called from object context", function).getData()) {}
NeedObjectContext(const char *function) : C4AulExecError(FormatString("%s: must be called from object context", function).getData()) {}
};
// Then there's functions that don't care, but need either defn or object context.
@ -118,7 +102,7 @@ public:
class NeedNonGlobalContext : public C4AulExecError
{
public:
NeedNonGlobalContext(const char *function) : C4AulExecError(NULL, FormatString("%s: call must not be from global context", function).getData()) {}
NeedNonGlobalContext(const char *function) : C4AulExecError(FormatString("%s: call must not be from global context", function).getData()) {}
};
// return type of functions returning nil
@ -254,7 +238,6 @@ public:
}
~C4AulDefFuncHelper()
{
assert(!Owner);
}
virtual C4V_Type* GetParType() { return ParType; }
virtual bool GetPublic() { return Public; }
@ -294,18 +277,16 @@ class C4AulDefFunc##N: \
public C4AulDefFuncHelper { \
public: \
/* A pointer to the function which this class wraps */ \
typedef RType (*Func)(C4AulContext * LIST(N, PARS)); \
typedef RType (*Func)(C4PropList * LIST(N, PARS)); \
virtual int GetParCount() { return N; } \
virtual C4V_Type GetRetType() \
{ return C4ValueConv<RType>::Type(); } \
/* Constructor, using the base class to create the ParType array */ \
C4AulDefFunc##N(C4AulScript *pOwner, const char *pName, Func pFunc, bool Public): \
C4AulDefFuncHelper(pOwner, pName, Public LIST(N, CONV_TYPE)), pFunc(pFunc) { } \
/* Avoid hiding base class function */ \
using C4AulFunc::Exec; \
/* Extracts the parameters from C4Values and wraps the return value in a C4Value */ \
virtual C4Value Exec(C4AulContext *pContext, C4Value pPars[], bool fPassErrors=false) \
{ return C4ValueConv<RType>::ToC4V(pFunc(pContext LIST(N, CONV_FROM_C4V))); } \
virtual C4Value Exec(C4PropList * _this, C4Value pPars[], bool fPassErrors) \
{ return C4ValueConv<RType>::ToC4V(pFunc(_this LIST(N, CONV_FROM_C4V))); } \
protected: \
Func pFunc; \
}; \
@ -321,19 +302,17 @@ public C4AulDefFuncHelper { \
/* Constructor, using the base class to create the ParType array */ \
C4AulDefObjectFunc##N(C4AulScript *pOwner, const char *pName, Func pFunc, bool Public): \
C4AulDefFuncHelper(pOwner, pName, Public LIST(N, CONV_TYPE)), pFunc(pFunc) { } \
/* Avoid hiding base class function */ \
using C4AulFunc::Exec; \
/* Extracts the parameters from C4Values and wraps the return value in a C4Value */ \
virtual C4Value Exec(C4AulContext *pContext, C4Value pPars[], bool fPassErrors=false) \
virtual C4Value Exec(C4PropList * _this, C4Value pPars[], bool fPassErrors) \
{ \
if (!pContext->Obj) throw new NeedObjectContext(GetName()); \
return C4ValueConv<RType>::ToC4V(pFunc(pContext->Obj LIST(N, CONV_FROM_C4V))); \
C4Object * Obj; if (!_this || !(Obj = _this->GetObject())) throw new NeedObjectContext(GetName()); \
return C4ValueConv<RType>::ToC4V(pFunc(Obj LIST(N, CONV_FROM_C4V))); \
} \
protected: \
Func pFunc; \
}; \
template <typename RType LIST(N, TYPENAMES)> \
inline void AddFunc(C4AulScript * pOwner, const char * Name, RType (*pFunc)(C4AulContext * LIST(N, PARS)), bool Public=true) \
template <typename RType LIST(N, TYPENAMES)> \
inline void AddFunc(C4AulScript * pOwner, const char * Name, RType (*pFunc)(C4PropList * LIST(N, PARS)), bool Public=true) \
{ \
new C4AulDefFunc##N<RType LIST(N, PARS)>(pOwner, Name, pFunc, Public); \
} \
@ -375,4 +354,31 @@ TEMPLATE(10)
#undef CONV_FROM_C4V
#undef TEMPLATE
// a definition of a function exported to script
struct C4ScriptFnDef
{
const char* Identifier; // the name of the func in the script
bool Public;
C4V_Type RetType; // type returned. ignored when C4V
C4V_Type ParType[10];// type of the parameters. error when wrong parameter type.
C4Value (*FunctionC4V)(C4PropList * _this, C4Value *);
};
// defined function class
class C4AulDefFunc : C4AulFunc
{
public:
C4ScriptFnDef* Def;
C4AulDefFunc(C4AulScript *pOwner, C4ScriptFnDef* pDef);
~C4AulDefFunc();
virtual bool GetPublic() { return !!Def->Public; }
virtual C4V_Type* GetParType() { return Def->ParType; }
virtual C4V_Type GetRetType() { return Def->RetType; }
virtual C4Value Exec(C4PropList * p, C4Value pPars[], bool fPassErrors=false);
};
#endif

View File

@ -36,7 +36,7 @@
C4AulExec AulExec;
C4AulExecError::C4AulExecError(C4Object *pObj, const char *szError) : cObj(pObj)
C4AulExecError::C4AulExecError(const char *szError)
{
// direct error message string
sMessage.Format("ERROR: %s.", szError ? szError : "(no error message)");
@ -46,6 +46,13 @@ StdStrBuf C4AulScriptContext::ReturnDump(StdStrBuf Dump)
{
if (!Func)
return StdStrBuf("");
// Context
if (Obj && Obj->Status)
{
C4Value ObjVal(Obj);
Dump.Append(ObjVal.GetDataString(0));
Dump.Append("->");
}
bool fDirectExec = !Func->GetName();
if (!fDirectExec)
{
@ -77,16 +84,6 @@ StdStrBuf C4AulScriptContext::ReturnDump(StdStrBuf Dump)
}
else
Dump.Append(Func->Owner->ScriptName);
// Context
if (Obj)
{
if (Obj->Status == C4OS_NORMAL)
Dump.AppendFormat(" (obj #%d)", Obj->Number);
else
Dump.AppendFormat(" (obj (#%d))", Obj->Number);
}
else if (Func->Owner->GetPropList())
Dump.AppendFormat(" (def %s)", Func->Owner->GetPropList()->GetName());
// Script
if (!fDirectExec && Func->pOrgScript)
Dump.AppendFormat(" (%s:%d)",
@ -108,13 +105,13 @@ void C4AulExec::LogCallStack()
pCtx->dump(StdStrBuf(" by: "));
}
C4String *C4AulExec::FnTranslate(C4AulContext *ctx, C4String *text)
C4String *C4AulExec::FnTranslate(C4PropList * _this, C4String *text)
{
if (!text || text->GetData().isNull()) return NULL;
// Find correct script: translations of the context if possible, containing script as fallback
C4AulScript *script = NULL;
if (ctx->Def && ctx->Def->GetDef())
script = &(ctx->Def->GetDef()->Script);
if (_this && _this->GetDef())
script = &(_this->GetDef()->Script);
else
script = AulExec.pCurCtx[-1].Func->pOrgScript;
assert(script);
@ -139,8 +136,6 @@ void C4AulExec::ClearPointers(C4Object * obj)
{
if (pCtx->Obj == obj)
pCtx->Obj = NULL;
if (pCtx->Def == obj)
pCtx->Def = NULL;
}
#endif
}
@ -160,8 +155,7 @@ C4Value C4AulExec::Exec(C4AulScriptFunc *pSFunc, C4PropList * p, C4Value *pnPars
// Push a new context
C4AulScriptContext ctx;
ctx.tTime = 0;
ctx.Obj = p ? p->GetObject() : NULL;
ctx.Def = p;
ctx.Obj = p;
ctx.Return = NULL;
ctx.Pars = pPars;
ctx.Vars = pCurVal + 1;
@ -236,10 +230,10 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
break;
case AB_EOF: case AB_EOFN:
throw new C4AulExecError(pCurCtx->Obj, "internal error: function didn't return");
throw new C4AulExecError("internal error: function didn't return");
case AB_ERR:
throw new C4AulExecError(pCurCtx->Obj, "syntax error: see above for details");
throw new C4AulExecError("syntax error: see above for details");
case AB_PARN_CONTEXT:
PushValue(AulExec.GetContext(AulExec.GetContextDepth()-2)->Pars[pCPos->Par.i]);
@ -250,24 +244,22 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
break;
case AB_LOCALN:
assert(!pCurCtx->Obj || pCurCtx->Def == pCurCtx->Obj);
if (!pCurCtx->Def)
throw new C4AulExecError(0, "can't access local variables without this");
if (!pCurCtx->Obj)
throw new C4AulExecError("can't access local variables without this");
PushNullVals(1);
pCurCtx->Def->GetPropertyByS(pCPos->Par.s, pCurVal);
pCurCtx->Obj->GetPropertyByS(pCPos->Par.s, pCurVal);
break;
case AB_LOCALN_SET:
assert(!pCurCtx->Obj || pCurCtx->Def == pCurCtx->Obj);
if (!pCurCtx->Def)
throw new C4AulExecError(0, "can't access local variables without this");
if (pCurCtx->Def->IsFrozen())
throw new C4AulExecError(pCurCtx->Obj, "local variable: this is readonly");
pCurCtx->Def->SetPropertyByS(pCPos->Par.s, pCurVal[0]);
if (!pCurCtx->Obj)
throw new C4AulExecError("can't access local variables without this");
if (pCurCtx->Obj->IsFrozen())
throw new C4AulExecError("local variable: this is readonly");
pCurCtx->Obj->SetPropertyByS(pCPos->Par.s, pCurVal[0]);
break;
case AB_PROP:
if (!pCurVal->CheckConversion(C4V_PropList))
throw new C4AulExecError(pCurCtx->Obj, FormatString("proplist access: proplist expected, got %s", pCurVal->GetTypeName()).getData());
throw new C4AulExecError(FormatString("proplist access: proplist expected, got %s", pCurVal->GetTypeName()).getData());
if (!pCurVal->_getPropList()->GetPropertyByS(pCPos->Par.s, pCurVal))
pCurVal->Set0();
break;
@ -275,9 +267,9 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
{
C4Value *pPropList = pCurVal - 1;
if (!pPropList->CheckConversion(C4V_PropList))
throw new C4AulExecError(pCurCtx->Obj, FormatString("proplist write: proplist expected, got %s", pPropList->GetTypeName()).getData());
throw new C4AulExecError(FormatString("proplist write: proplist expected, got %s", pPropList->GetTypeName()).getData());
if (pPropList->_getPropList()->IsFrozen())
throw new C4AulExecError(pCurCtx->Obj, "proplist write: proplist is readonly");
throw new C4AulExecError("proplist write: proplist is readonly");
pPropList->_getPropList()->SetPropertyByS(pCPos->Par.s, pCurVal[0]);
pPropList->Set(pCurVal[0]);
PopValue();
@ -325,7 +317,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
CheckOpPars(C4V_Int, C4V_Int, "/");
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
if (!pPar2->_getInt())
throw new C4AulExecError(pCurCtx->Obj, "division by zero");
throw new C4AulExecError("division by zero");
pPar1->SetInt(pPar1->_getInt() / pPar2->_getInt());
PopValue();
break;
@ -512,7 +504,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
assert(pStruct->GetType() == C4V_PropList);
C4PropList *pPropList = pStruct->_getPropList();
if (pPropList->IsFrozen())
throw new C4AulExecError(pCurCtx->Obj, "proplist write: proplist is readonly");
throw new C4AulExecError("proplist write: proplist is readonly");
pPropList->SetPropertyByS(pIndex->_getStr(), *pValue);
}
// Set result, remove array and index from stack
@ -528,11 +520,11 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
// Typcheck
if (!Array.CheckConversion(C4V_Array))
throw new C4AulExecError(pCurCtx->Obj, FormatString("array slice: can't access %s as an array", Array.GetTypeName()).getData());
throw new C4AulExecError(FormatString("array slice: can't access %s as an array", Array.GetTypeName()).getData());
if (!StartIndex.CheckConversion(C4V_Int))
throw new C4AulExecError(pCurCtx->Obj, FormatString("array slice: start index of type %s, int expected", StartIndex.GetTypeName()).getData());
throw new C4AulExecError(FormatString("array slice: start index of type %s, int expected", StartIndex.GetTypeName()).getData());
if (!EndIndex.CheckConversion(C4V_Int))
throw new C4AulExecError(pCurCtx->Obj, FormatString("array slice: end index of type %s, int expected", EndIndex.GetTypeName()).getData());
throw new C4AulExecError(FormatString("array slice: end index of type %s, int expected", EndIndex.GetTypeName()).getData());
Array.SetArray(Array.GetData().Array->GetSlice(StartIndex._getInt(), EndIndex._getInt()));
@ -550,11 +542,11 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
// Typcheck
if (!Array.CheckConversion(C4V_Array))
throw new C4AulExecError(pCurCtx->Obj, FormatString("array slice: can't access %s as an array", Array.GetTypeName()).getData());
throw new C4AulExecError(FormatString("array slice: can't access %s as an array", Array.GetTypeName()).getData());
if (!StartIndex.CheckConversion(C4V_Int))
throw new C4AulExecError(pCurCtx->Obj, FormatString("array slice: start index of type %s, int expected", StartIndex.GetTypeName()).getData());
throw new C4AulExecError(FormatString("array slice: start index of type %s, int expected", StartIndex.GetTypeName()).getData());
if (!EndIndex.CheckConversion(C4V_Int))
throw new C4AulExecError(pCurCtx->Obj, FormatString("array slice: end index of type %s, int expected", EndIndex.GetTypeName()).getData());
throw new C4AulExecError(FormatString("array slice: end index of type %s, int expected", EndIndex.GetTypeName()).getData());
C4ValueArray *pArray = Array._getArray();
pArray->SetSlice(StartIndex._getInt(), EndIndex._getInt(), Value);
@ -697,7 +689,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
case AB_PAR:
if (!pCurVal->CheckConversion(C4V_Int))
throw new C4AulExecError(pCurCtx->Obj, FormatString("Par: index of type %s, int expected", pCurVal->GetTypeName()).getData());
throw new C4AulExecError(FormatString("Par: index of type %s, int expected", pCurVal->GetTypeName()).getData());
// Push reference to parameter on the stack
if (pCurVal->_getInt() >= 0 && pCurVal->_getInt() < pCurCtx->Func->GetParCount())
pCurVal->Set(pCurCtx->Pars[pCurVal->_getInt()]);
@ -714,7 +706,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
if (!iItem)
{
if (!pCurVal[-1].CheckConversion(C4V_Array))
throw new C4AulExecError(pCurCtx->Obj, FormatString("for: array expected, but got %s", pCurVal[-1].GetTypeName()).getData());
throw new C4AulExecError(FormatString("for: array expected, but got %s", pCurVal[-1].GetTypeName()).getData());
}
C4ValueArray *pArray = pCurVal[-1]._getArray();
// No more entries?
@ -743,8 +735,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
pDest = pTargetVal->_getPropList();
}
else
throw new C4AulExecError(pCurCtx->Obj,
FormatString("'->': invalid target type %s, expected proplist", pTargetVal->GetTypeName()).getData());
throw new C4AulExecError(FormatString("'->': invalid target type %s, expected proplist", pTargetVal->GetTypeName()).getData());
// Search function for given context
C4AulFunc * pFunc = pDest->GetFunc(pCPos->Par.s);
@ -757,10 +748,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
// Function not found?
if (!pFunc)
throw new C4AulExecError(pCurCtx->Obj,
FormatString("'->': no function \"%s\" in object \"%s\"", pCPos->Par.s->GetCStr(), pTargetVal->GetDataString().getData()).getData());
assert(!pFunc->OverloadedBy);
throw new C4AulExecError(FormatString("'->': no function \"%s\" in object \"%s\"", pCPos->Par.s->GetCStr(), pTargetVal->GetDataString().getData()).getData());
// Save current position
pCurCtx->CPos = pCPos;
@ -832,15 +820,14 @@ C4AulBCC *C4AulExec::Call(C4AulFunc *pFunc, C4Value *pReturn, C4Value *pPars, C4
if (!pContext)
{
assert(pCurCtx >= Contexts);
pContext = pCurCtx->Def;
pContext = pCurCtx->Obj;
}
// Convert parameters (typecheck)
C4V_Type *pTypes = pFunc->GetParType();
for (int i = 0; i < pFunc->GetParCount(); i++)
if (!pPars[i].CheckParConversion(pTypes[i]))
throw new C4AulExecError(pCurCtx->Obj,
FormatString("call to \"%s\" parameter %d: passed %s, but expected %s",
throw new C4AulExecError(FormatString("call to \"%s\" parameter %d: passed %s, but expected %s",
pFunc->GetName(), i + 1, pPars[i].GetTypeName(), GetC4VName(pTypes[i])
).getData());
@ -850,10 +837,9 @@ C4AulBCC *C4AulExec::Call(C4AulFunc *pFunc, C4Value *pReturn, C4Value *pPars, C4
{
// Push a new context
C4AulScriptContext ctx;
ctx.Obj = pContext ? pContext->GetObject() : 0;
ctx.Obj = pContext;
if (ctx.Obj && !ctx.Obj->Status)
throw new C4AulExecError(ctx.Obj, "using removed object");
ctx.Def = pContext;
throw new C4AulExecError("using removed object");
ctx.Return = pReturn;
ctx.Pars = pPars;
ctx.Vars = pCurVal + 1;
@ -873,13 +859,8 @@ C4AulBCC *C4AulExec::Call(C4AulFunc *pFunc, C4Value *pReturn, C4Value *pPars, C4
}
else
{
// Create new context
C4AulContext ctx;
ctx.Obj = pContext ? pContext->GetObject() : 0;
if (ctx.Obj && !ctx.Obj->Status)
throw new C4AulExecError(ctx.Obj, "using removed object");
ctx.Def = pContext;
if (pContext && !pContext->Status)
throw new C4AulExecError("using removed object");
#ifdef DEBUGREC_SCRIPT
StdStrBuf sCallText;
@ -916,9 +897,9 @@ C4AulBCC *C4AulExec::Call(C4AulFunc *pFunc, C4Value *pReturn, C4Value *pPars, C4
C4AulScriptContext *pCtx = pCurCtx;
#endif
if (pReturn > pCurVal)
PushValue(pFunc->Exec(&ctx, pPars, true));
PushValue(pFunc->Exec(pContext, pPars, true));
else
pReturn->Set(pFunc->Exec(&ctx, pPars, true));
pReturn->Set(pFunc->Exec(pContext, pPars, true));
#ifdef _DEBUG
assert(pCtx == pCurCtx);
#endif
@ -927,16 +908,6 @@ C4AulBCC *C4AulExec::Call(C4AulFunc *pFunc, C4Value *pReturn, C4Value *pPars, C4
// Notify debugger
if (C4AulDebug *pDebug = C4AulDebug::GetDebugger())
{
// Make dummy context
C4AulScriptContext ctx;
ctx.Obj = pContext ? pContext->GetObject() : 0;
ctx.Def = pContext;
ctx.Return = pReturn;
ctx.Pars = pPars;
ctx.Vars = pPars + pFunc->GetParCount();
ctx.Func = pSFunc;
ctx.TemporaryScript = false;
ctx.CPos = NULL;
pDebug->DebugStepOut(pCurCtx->CPos + 1, pCurCtx, pReturn);
}
#endif
@ -991,7 +962,7 @@ void C4AulExec::StopProfiling()
void C4AulExec::PushContext(const C4AulScriptContext &rContext)
{
if (pCurCtx >= Contexts + MAX_CONTEXT_STACK - 1)
throw new C4AulExecError(pCurCtx->Obj, "context stack overflow");
throw new C4AulExecError("context stack overflow");
*++pCurCtx = rContext;
// Trace?
if (iTraceStart >= 0)
@ -1007,7 +978,7 @@ void C4AulExec::PushContext(const C4AulScriptContext &rContext)
void C4AulExec::PopContext()
{
if (pCurCtx < Contexts)
throw new C4AulExecError(pCurCtx->Obj, "internal error: context stack underflow");
throw new C4AulExecError("internal error: context stack underflow");
// Profiler adding up times
if (fProfiling)
{
@ -1071,57 +1042,15 @@ void C4AulProfiler::Show()
// done!
}
C4Value C4AulFunc::Exec(C4PropList * p, C4AulParSet* pPars, bool fPassErrors)
{
// construct a dummy caller context
C4AulContext ctx;
ctx.Obj = p ? p->GetObject() : NULL;
ctx.Def = p;
// execute
return Exec(&ctx, pPars ? pPars->Par : C4AulParSet().Par, fPassErrors);
}
C4Value C4AulScriptFunc::Exec(C4AulContext *pCtx, C4Value pPars[], bool fPassErrors)
C4Value C4AulScriptFunc::Exec(C4PropList * p, C4Value pPars[], bool fPassErrors)
{
// handle easiest case first
if (Owner->State != ASS_PARSED) return C4VNull;
if (Owner->State != ASS_PARSED) return C4Value();
// execute
return AulExec.Exec(this, pCtx->Obj ? pCtx->Obj : pCtx->Def, pPars, fPassErrors);
return AulExec.Exec(this, p, pPars, fPassErrors);
}
C4Value C4AulScriptFunc::Exec(C4PropList * p, C4AulParSet *pPars, bool fPassErrors)
{
// handle easiest case first
if (Owner->State != ASS_PARSED) return C4VNull;
// execute
return AulExec.Exec(this, p, pPars ? pPars->Par : C4AulParSet().Par, fPassErrors);
}
C4Value C4AulDefFunc::Exec(C4AulContext *pCallerCtx, C4Value pPars[], bool fPassErrors)
{
// Choose function call format to use
if (Def->FunctionC4V2 != 0)
// C4V function
return Def->FunctionC4V2(pCallerCtx, pPars);
if (Def->FunctionC4V != 0)
// C4V function
return Def->FunctionC4V(pCallerCtx, &pPars[0], &pPars[1], &pPars[2], &pPars[3], &pPars[4], &pPars[5], &pPars[6], &pPars[7], &pPars[8], &pPars[9]);
// should never happen...
return C4VNull;
}
class C4DirectExecScript: public C4ScriptHost
{
public:
@ -1135,8 +1064,6 @@ public:
p = pObj->Def;
LocalNamed = pObj->Def->Script.LocalNamed;
}
// FIXME: calls from definitions
ClearCode();
this->stringTable = stringTable;
}
bool Delete() { return true; }
@ -1186,8 +1113,8 @@ void C4AulScript::ResetProfilerTimes()
{
// zero all profiler times of owned functions
C4AulScriptFunc *pSFunc;
for (C4AulFunc *pFn = Func0; pFn; pFn = pFn->Next)
if ((pSFunc = pFn->SFunc()))
for (C4String *pFn = GetPropList()->EnumerateOwnFuncs(); pFn; pFn = GetPropList()->EnumerateOwnFuncs(pFn))
if ((pSFunc = GetPropList()->GetFunc(pFn)->SFunc()))
pSFunc->tProfileTime = 0;
}
@ -1195,8 +1122,8 @@ void C4AulScript::CollectProfilerTimes(C4AulProfiler &rProfiler)
{
// collect all profiler times of owned functions
C4AulScriptFunc *pSFunc;
for (C4AulFunc *pFn = Func0; pFn; pFn = pFn->Next)
if ((pSFunc = pFn->SFunc()))
for (C4String *pFn = GetPropList()->EnumerateOwnFuncs(); pFn; pFn = GetPropList()->EnumerateOwnFuncs(pFn))
if ((pSFunc = GetPropList()->GetFunc(pFn)->SFunc()))
rProfiler.CollectEntry(pSFunc, pSFunc->tProfileTime);
}

View File

@ -70,7 +70,7 @@ public:
int GetContextDepth() const { return pCurCtx - Contexts + 1; }
C4AulScriptContext *GetContext(int iLevel) { return iLevel >= 0 && iLevel < GetContextDepth() ? Contexts + iLevel : NULL; }
void LogCallStack();
static C4String *FnTranslate(C4AulContext *ctx, C4String *text);
static C4String *FnTranslate(C4PropList * _this, C4String *text);
void ClearPointers(C4Object *);
private:
@ -80,7 +80,7 @@ private:
void CheckOverflow(int iCnt)
{
if (pCurVal - Values >= MAX_VALUE_STACK - iCnt)
throw new C4AulExecError(pCurCtx->Obj, "value stack overflow, probably due to too deep recursion");
throw new C4AulExecError("value stack overflow, probably due to too deep recursion");
}
void PushInt(int32_t i)
@ -176,20 +176,17 @@ private:
// Typecheck parameters
if (!pPar1->CheckParConversion(Type1))
throw new C4AulExecError(pCurCtx->Obj,
FormatString("operator \"%s\" left side got %s, but expected %s",
throw new C4AulExecError(FormatString("operator \"%s\" left side got %s, but expected %s",
opname, pPar1->GetTypeName(), GetC4VName(Type1)).getData());
if (!pPar2->CheckParConversion(Type2))
throw new C4AulExecError(pCurCtx->Obj,
FormatString("operator \"%s\" right side got %s, but expected %s",
throw new C4AulExecError(FormatString("operator \"%s\" right side got %s, but expected %s",
opname, pPar2->GetTypeName(), GetC4VName(Type2)).getData());
}
ALWAYS_INLINE void CheckOpPar(C4V_Type Type1, const char * opname)
{
// Typecheck parameter
if (!pCurVal->CheckParConversion(Type1))
throw new C4AulExecError(pCurCtx->Obj,
FormatString("operator \"%s\": got %s, but expected %s",
throw new C4AulExecError(FormatString("operator \"%s\": got %s, but expected %s",
opname, pCurVal->GetTypeName(), GetC4VName(Type1)).getData());
}
@ -198,17 +195,17 @@ private:
if (pStructure->CheckConversion(C4V_Array))
{
if (!pIndex->CheckConversion(C4V_Int))
throw new C4AulExecError(pCurCtx->Obj, FormatString("array access: index of type %s, but expected int", pIndex->GetTypeName()).getData());
throw new C4AulExecError(FormatString("array access: index of type %s, but expected int", pIndex->GetTypeName()).getData());
return C4V_Array;
}
else if (pStructure->CheckConversion(C4V_PropList))
{
if (!pIndex->CheckConversion(C4V_String))
throw new C4AulExecError(pCurCtx->Obj, FormatString("proplist access: index of type %s, but expected string", pIndex->GetTypeName()).getData());
throw new C4AulExecError(FormatString("proplist access: index of type %s, but expected string", pIndex->GetTypeName()).getData());
return C4V_PropList;
}
else
throw new C4AulExecError(pCurCtx->Obj, FormatString("can't access %s as array or proplist", pStructure->GetTypeName()).getData());
throw new C4AulExecError(FormatString("can't access %s as array or proplist", pStructure->GetTypeName()).getData());
}
C4AulBCC *Call(C4AulFunc *pFunc, C4Value *pReturn, C4Value *pPars, C4PropList * pContext = NULL);
};

View File

@ -0,0 +1,82 @@
/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2001, 2007 Sven Eberhardt
* Copyright (c) 2011-2012 Günther Brammer
*
* Portions might be copyrighted by other authors who have contributed
* to OpenClonk.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
* See isc_license.txt for full license and disclaimer.
*
* "Clonk" is a registered trademark of Matthes Bender.
* See clonk_trademark_license.txt for full license.
*/
#include <C4Include.h>
#include <C4Value.h>
#include <C4AulFunc.h>
#include <C4Aul.h>
#include <C4ScriptHost.h>
C4AulFunc::C4AulFunc(C4AulScript *pOwner, const char *pName):
iRefCnt(0),
Name(pName ? Strings.RegString(pName) : 0),
MapNext(NULL)
{
Owner = pOwner;
assert(GetName() || Owner->Temporary);
// add to global lookuptable with this name
if (GetName())
Owner->Engine->FuncLookUp.Add(this);
}
C4AulFunc::~C4AulFunc()
{
if (Owner)
{
C4AulScriptEngine * Engine = Owner->Engine;
if (!Engine)
Engine = &::ScriptEngine;
if (GetName())
Engine->FuncLookUp.Remove(this);
if (Owner->GetPropList() && Name)
{
C4Value v;
Owner->GetPropList()->GetPropertyByS(Name, &v);
assert(v.getFunction() != this);
}
}
}
StdStrBuf C4AulFunc::GetFullName()
{
StdStrBuf r;
// "lost" function?
if (!Owner)
{
r.Ref("(unowned) ");
}
else if (Owner->GetPropList() && Owner->GetPropList()->IsStatic())
{
r.Take(Owner->GetPropList()->IsStatic()->GetDataString());
r.AppendChar('.');
}
else if (Owner == &GameScript)
{
r.Ref("Scenario.");
}
else if (Owner->Engine == Owner)
{
r.Ref("Global.");
}
else
{
r.Ref("(unknown) ");
}
r.Append(Name->GetData());
return r;
}

View File

@ -25,6 +25,26 @@
#define C4AUL_MAX_Par 10 // max number of parameters
struct C4AulParSet
{
C4Value Par[C4AUL_MAX_Par];
C4AulParSet() {} // standard-constructor
C4AulParSet(const C4Value &par0, const C4Value &par1 = C4Value(), const C4Value &par2 = C4Value(), const C4Value &par3 = C4Value(), const C4Value &par4 = C4Value(),
const C4Value &par5 = C4Value(), const C4Value &par6 = C4Value(), const C4Value &par7 = C4Value(), const C4Value &par8 = C4Value(), const C4Value &par9 = C4Value())
{
Par[0].Set(par0); Par[1].Set(par1); Par[2].Set(par2); Par[3].Set(par3); Par[4].Set(par4);
Par[5].Set(par5); Par[6].Set(par6); Par[7].Set(par7); Par[8].Set(par8); Par[9].Set(par9);
}
C4AulParSet(const C4Value * Pars, int ParCount)
{
for (int i = 0; i < ParCount; ++i)
Par[i].Set(Pars[i]);
}
C4Value & operator[](int iIdx) { return Par[iIdx]; }
C4AulParSet * operator&() { return this; }
};
// base function class
class C4AulFunc
{
@ -50,25 +70,22 @@ public:
protected:
C4RefCntPointer<C4String> Name; // function name
C4AulFunc *Prev, *Next; // linked list members
C4AulFunc *MapNext; // map member
void AppendToScript(C4AulScript *);
void RemoveFromScript();
virtual ~C4AulFunc();
public:
C4AulFunc *OverloadedBy; // function by which this one is overloaded
virtual C4AulScriptFunc *SFunc() { return NULL; } // type check func...
// Wether this function should be visible to players
virtual bool GetPublic() { return false; }
virtual int GetParCount() { return C4AUL_MAX_Par; }
virtual C4V_Type* GetParType() { return 0; }
virtual C4V_Type GetRetType() { return C4V_Any; }
virtual C4Value Exec(C4AulContext *pCallerCtx, C4Value pPars[], bool fPassErrors=false) { return C4Value(); } // execute func (script call)
virtual C4Value Exec(C4PropList * p = NULL, C4AulParSet *pPars = NULL, bool fPassErrors=false); // execute func (engine call)
virtual void UnLink() { OverloadedBy = NULL; }
virtual C4V_Type* GetParType() = 0;
virtual C4V_Type GetRetType() = 0;
C4Value Exec(C4PropList * p = NULL, C4AulParSet *pPars = NULL, bool fPassErrors=false)
{
return Exec(p, pPars->Par, fPassErrors);
}
virtual C4Value Exec(C4PropList * p, C4Value pPars[], bool fPassErrors=false) = 0;
};
#endif

View File

@ -28,9 +28,19 @@
#include <C4Game.h>
#include <C4GameObjects.h>
bool C4AulScript::ResolveIncludes(C4DefList *rDefs)
{
}
bool C4AulScript::ResolveAppends(C4DefList *rDefs)
{
}
// ResolveAppends and ResolveIncludes must be called both
// for each script. ResolveAppends has to be called first!
bool C4AulScript::ResolveAppends(C4DefList *rDefs)
bool C4ScriptHost::ResolveAppends(C4DefList *rDefs)
{
// resolve local appends
if (State != ASS_PREPARSED) return false;
@ -49,7 +59,7 @@ bool C4AulScript::ResolveAppends(C4DefList *rDefs)
// save id in buffer because AulWarn will use the buffer of C4IdText
// to get the id of the object in which the error occurs...
// (stupid static buffers...)
Warn("script to #appendto not found: ", a->ToString());
Warn("#appendto %s not found", a->ToString());
}
}
else
@ -69,7 +79,7 @@ bool C4AulScript::ResolveAppends(C4DefList *rDefs)
return true;
}
bool C4AulScript::ResolveIncludes(C4DefList *rDefs)
bool C4ScriptHost::ResolveIncludes(C4DefList *rDefs)
{
// Had been preparsed?
if (State != ASS_PREPARSED) return false;
@ -91,7 +101,7 @@ bool C4AulScript::ResolveIncludes(C4DefList *rDefs)
if (Def)
{
// resolve #includes in included script first (#include-chains :( )
if (!((C4AulScript &)Def->Script).IncludesResolved)
if (!Def->Script.IncludesResolved)
if (!Def->Script.ResolveIncludes(rDefs))
continue; // skip this #include
@ -106,7 +116,7 @@ bool C4AulScript::ResolveIncludes(C4DefList *rDefs)
// save id in buffer because AulWarn will use the buffer of C4IdText
// to get the id of the object in which the error occurs...
// (stupid static buffers...)
Warn("script to #include not found: ", i->ToString());
Warn("#include %s not found", i->ToString());
}
}
IncludesResolved = true;
@ -117,30 +127,20 @@ bool C4AulScript::ResolveIncludes(C4DefList *rDefs)
}
void C4AulScript::UnLink()
{
}
void C4ScriptHost::UnLink()
{
// do not unlink temporary (e.g., DirectExec-script in ReloadDef)
if (Temporary) return;
C4PropList * p = GetPropList();
if (p) p->C4PropList::Thaw();
// delete included/appended functions
C4AulFunc* pFunc = Func0;
while (pFunc)
if (p)
{
C4AulFunc* pNextFunc = pFunc->Next;
// clear stuff that's set in AfterLink
pFunc->UnLink();
if (pFunc->SFunc())
if (pFunc->Owner != pFunc->SFunc()->pOrgScript)
{
pFunc->RemoveFromScript();
pFunc->DecRef();
}
pFunc = pNextFunc;
p->C4PropList::Clear();
p->SetProperty(P_Prototype, C4VPropList(Engine->GetPropList()));
}
// includes will have to be re-resolved now
@ -149,11 +149,18 @@ void C4AulScript::UnLink()
if (State > ASS_PREPARSED) State = ASS_PREPARSED;
}
void C4AulScriptFunc::UnLink()
void C4AulScriptEngine::UnLink()
{
OwnerOverloaded = NULL;
C4AulFunc::UnLink();
// unlink scripts
for (C4AulScript *s = Child0; s; s = s->Next)
s->UnLink();
GetPropList()->Thaw();
if (State > ASS_PREPARSED) State = ASS_PREPARSED;
// Do not clear global variables and constants, because they are registered by the
// preparser or other parts. Note that keeping those fields means that you cannot delete a global
// variable or constant at runtime by removing it from the script.
//GlobalNamedNames.Reset();
//GlobalConstNames.Reset();
}
bool C4AulScript::ReloadScript(const char *szPath, const char *szLanguage)
@ -174,9 +181,6 @@ void C4AulScriptEngine::Link(C4DefList *rDefs)
for (C4AulScript *s = Child0; s; s = s->Next)
s->ResolveIncludes(rDefs);
// put script functions into the proplist
LinkFunctions();
// parse the scripts to byte code
for (C4AulScript *s = Child0; s; s = s->Next)
s->Parse();

View File

@ -128,7 +128,7 @@ class C4AulParse
public:
enum Type { PARSER, PREPARSER };
C4AulParse(C4ScriptHost * a, enum Type Type):
Fn(0), a(a), pOrgScript(a), SPos(a->Script.getData()),
Fn(0), a(a), pOrgScript(a), SPos(a->Script.getData()), TokenSPos(SPos),
TokenType(ATT_INVALID),
Done(false),
Type(Type),
@ -141,6 +141,7 @@ public:
{ while (pLoopStack) PopLoop(); ClearToken(); }
C4AulScriptFunc *Fn; C4ScriptHost * a; C4ScriptHost * pOrgScript;
const char *SPos; // current position in the script
const char *TokenSPos; // start of the current token in the script
char Idtf[C4AUL_MAX_Identifier]; // current identifier
C4AulTokenType TokenType; // current token type
int32_t cInt; // current int constant
@ -166,8 +167,8 @@ public:
void Parse_Local();
void Parse_Static();
void Parse_Const();
C4Value Parse_ConstExpression(bool really);
C4Value Parse_ConstPropList(bool really);
C4Value Parse_ConstExpression(C4PropListStatic * parent, C4String * Name);
C4Value Parse_ConstPropList(const C4PropListStatic * parent, C4String * Name);
bool AdvanceSpaces(); // skip whitespaces; return whether script ended
int GetOperator(const char* pScript);
@ -181,8 +182,8 @@ public:
void UnexpectedToken(const char * Expected) NORETURN;
static const char * GetTokenName(C4AulTokenType TokenType);
void Warn(const char *pMsg, const char *pIdtf=0);
void Error(const char *pMsg, const char *pIdtf=0);
void Warn(const char *pMsg, ...) GNUC_FORMAT_ATTRIBUTE_O;
void Error(const char *pMsg, ...) GNUC_FORMAT_ATTRIBUTE_O;
private:
@ -221,28 +222,26 @@ private:
void AddLoopControl(bool fBreak);
};
void C4AulScript::Warn(const char *pMsg, const char *pIdtf)
void C4AulScript::Warn(const char *pMsg, ...)
{
// display error
va_list args; va_start(args, pMsg);
StdStrBuf Buf;
Buf.FormatV(pMsg, args);
C4AulParseError warning(this, pMsg, pIdtf, true);
C4AulParseError warning(this, Buf.getData(), 0, true);
// display it
warning.show();
// count warnings
++::ScriptEngine.warnCnt;
}
void C4AulParse::Warn(const char *pMsg, const char *pIdtf)
void C4AulParse::Warn(const char *pMsg, ...)
{
// do not show errors for System.ocg scripts that appear to be pure #appendto scripts
if (Fn && !Fn->Owner->GetPropList() && !Fn->Owner->Appends.empty()) return;
// script doesn't own function -> skip
// (exception: global functions)
//if(pFunc) if(pFunc->pOrgScript != pScript && pScript != (C4AulScript *)&::ScriptEngine) return;
// display error
va_list args; va_start(args, pMsg);
StdStrBuf Buf;
Buf.FormatV(pMsg, args);
C4AulParseError warning(this, pMsg, pIdtf, true);
// display it
C4AulParseError warning(this, Buf.getData(), 0, true);
warning.show();
if (pOrgScript != a)
DebugLogF(" (as #appendto/#include to %s)", a->ScriptName.getData());
@ -250,9 +249,13 @@ void C4AulParse::Warn(const char *pMsg, const char *pIdtf)
++::ScriptEngine.warnCnt;
}
void C4AulParse::Error(const char *pMsg, const char *pIdtf)
void C4AulParse::Error(const char *pMsg, ...)
{
throw new C4AulParseError(this, pMsg, pIdtf);
va_list args; va_start(args, pMsg);
StdStrBuf Buf;
Buf.FormatV(pMsg, args);
throw new C4AulParseError(this, Buf.getData());
}
C4AulParseError::C4AulParseError(C4AulParse * state, const char *pMsg, const char *pIdtf, bool Warn)
@ -269,11 +272,11 @@ C4AulParseError::C4AulParseError(C4AulParse * state, const char *pMsg, const cha
sMessage.AppendFormat(" (in %s", state->Fn->GetName());
// Exact position
if (state->Fn->pOrgScript && state->SPos)
if (state->Fn->pOrgScript && state->TokenSPos)
sMessage.AppendFormat(", %s:%d:%d)",
state->Fn->pOrgScript->ScriptName.getData(),
SGetLine(state->Fn->pOrgScript->GetScript(), state->SPos),
SLineGetCharacters(state->Fn->pOrgScript->GetScript(), state->SPos));
SGetLine(state->Fn->pOrgScript->GetScript(), state->TokenSPos),
SLineGetCharacters(state->Fn->pOrgScript->GetScript(), state->TokenSPos));
else
sMessage.AppendChar(')');
}
@ -282,8 +285,8 @@ C4AulParseError::C4AulParseError(C4AulParse * state, const char *pMsg, const cha
// Script name
sMessage.AppendFormat(" (%s:%d:%d)",
state->pOrgScript->ScriptName.getData(),
SGetLine(state->pOrgScript->GetScript(), state->SPos),
SLineGetCharacters(state->pOrgScript->GetScript(), state->SPos));
SGetLine(state->pOrgScript->GetScript(), state->TokenSPos),
SLineGetCharacters(state->pOrgScript->GetScript(), state->TokenSPos));
}
}
@ -457,7 +460,7 @@ C4AulTokenType C4AulParse::GetNextToken(OperatorPolicy Operator)
// move to start of token
if (!AdvanceSpaces()) return ATT_EOF;
// store offset
const char *SPos0 = SPos;
TokenSPos = SPos;
// get char
char C = *(SPos++);
@ -476,7 +479,7 @@ C4AulTokenType C4AulParse::GetNextToken(OperatorPolicy Operator)
}
Len = Min(Len, C4AUL_MAX_Identifier);
SCopy(SPos0, Idtf, Len);
SCopy(TokenSPos, Idtf, Len);
return dir ? ATT_DIR : ATT_IDTF;
}
else if (C == '(') return ATT_BOPEN; // "("
@ -495,7 +498,7 @@ C4AulTokenType C4AulParse::GetNextToken(OperatorPolicy Operator)
else
{
// decimal
cInt = StrToI32(SPos0, 10, &SPos);
cInt = StrToI32(TokenSPos, 10, &SPos);
return ATT_INT;
}
}
@ -575,8 +578,7 @@ C4AulTokenType C4AulParse::GetNextToken(OperatorPolicy Operator)
// just insert "\"
strbuf.push_back('\\');
// show warning
char strEscape[2] = { *(SPos + 1), 0 };
Warn("unknown escape: ", strEscape);
Warn("unknown escape \"%c\"", *(SPos + 1));
}
}
else if (C == 0 || C == 10 || C == 13) // line break / feed
@ -730,11 +732,26 @@ void C4ScriptHost::ClearCode()
// add one empty chunk to init CPos and for functions without code.
// For example, leftovers from a previous version of a reloaded script
AddBCC(AB_ERR);
C4AulFunc * f = Func0;
while (f)
if (Engine) for (C4String *pFn = Engine->GetPropList()->EnumerateOwnFuncs(); pFn; pFn = Engine->GetPropList()->EnumerateOwnFuncs(pFn))
{
f->SFunc()->CodePos = 0;
f = f->Next;
C4AulScriptFunc *pSFunc = Engine->GetPropList()->GetFunc(pFn)->SFunc();
while (pSFunc)
{
if (pSFunc->pOrgScript == this)
pSFunc->CodePos = 0;
pSFunc = pSFunc->OwnerOverloaded ? pSFunc->OwnerOverloaded->SFunc() : 0;
}
}
if (!GetPropList()) return;
for (C4String *pFn = GetPropList()->EnumerateOwnFuncs(); pFn; pFn = GetPropList()->EnumerateOwnFuncs(pFn))
{
C4AulScriptFunc *pSFunc = GetPropList()->GetFunc(pFn)->SFunc();
while (pSFunc)
{
assert(pSFunc->Owner == this);
pSFunc->CodePos = 0;
pSFunc = pSFunc->OwnerOverloaded ? pSFunc->OwnerOverloaded->SFunc() : 0;
}
}
}
@ -768,11 +785,9 @@ bool C4ScriptHost::Preparse()
// clear stuff
Includes.clear(); Appends.clear();
if (GetPropList())
{
GetPropList()->C4PropList::Clear();
GetPropList()->SetProperty(P_Prototype, C4VPropList(Engine->GetPropList()));
}
GetPropList()->C4PropList::Clear();
GetPropList()->SetProperty(P_Prototype, C4VPropList(Engine->GetPropList()));
LocalValues.Clear();
// reset code
ClearCode();
@ -783,6 +798,9 @@ bool C4ScriptHost::Preparse()
// #include will have to be resolved now...
IncludesResolved = false;
// Parse will write the properties back after the ones from included scripts
GetPropList()->Properties.Swap(&LocalValues);
// return success
C4AulScript::State = ASS_PREPARSED;
return true;
@ -971,7 +989,7 @@ int C4AulParse::AddBCC(C4AulBCCType eType, intptr_t X)
}
// Add
a->AddBCC(eType, X, SPos);
a->AddBCC(eType, X, TokenSPos);
// Reset jump flag
fJump = false;
@ -1006,7 +1024,7 @@ C4V_Type C4AulParse::GetLastRetType(C4V_Type to)
case AB_CALL: case AB_CALLFS:
{
C4String * pName = a->GetLastCode()->Par.s;
C4AulFunc * pFunc2 = a->Engine->GetFirstFunc(pName->GetCStr());
C4AulFunc * pFunc2 = a->Engine->GetFirstFunc(pName);
bool allwarn = true;
from = C4V_Any;
while (pFunc2 && allwarn)
@ -1213,7 +1231,8 @@ void C4AulScriptFunc::ParseFn(C4AulScriptContext* context)
state.Shift();
state.Fn = this;
state.Parse_Expression();
GetCodeOwner()->AddBCC(AB_RETURN, 0, state.SPos);
state.Match(ATT_EOF);
GetCodeOwner()->AddBCC(AB_RETURN, 0, state.TokenSPos);
}
void C4AulParse::Parse_Script()
@ -1377,7 +1396,7 @@ void C4AulParse::Parse_Function()
if (a->Engine->GlobalNamedNames.GetItemNr(Idtf) != -1)
throw new C4AulParseError(this, "function definition: name already in use (global variable)");
if (a->Engine->GlobalConstNames.GetItemNr(Idtf) != -1)
Error("function definition: name already in use (global constant)", 0);
Error("function definition: name already in use (global constant)");
}
// get script fn
C4AulScript * owner;
@ -1386,22 +1405,24 @@ void C4AulParse::Parse_Function()
else
owner = a;
Fn = 0;
C4AulFunc * f = owner->Func0;
C4AulFunc * f = owner->GetPropList()->GetFunc(Idtf);
while (f)
{
if (SEqual(f->GetName(), Idtf) && f->SFunc() && f->SFunc()->pOrgScript == pOrgScript)
if (f->SFunc() && f->SFunc()->pOrgScript == pOrgScript && f->Owner == owner)
{
if (Fn)
//throw new C4AulParseError(this, "Duplicate function ", Idtf);
Warn("Duplicate function ", Idtf);
Warn("Duplicate function %s", Idtf);
Fn = f->SFunc();
}
f = f->Next;
f = f->SFunc() ? f->SFunc()->OwnerOverloaded : 0;
}
// first preparser run or a new func in a reloaded script
if (!Fn && Type == PREPARSER)
{
Fn = new C4AulScriptFunc(owner, pOrgScript, Idtf, SPos);
Fn->SetOverloaded(owner->GetPropList()->GetFunc(Fn->Name));
owner->GetPropList()->SetPropertyByS(Fn->Name, C4VFunction(Fn));
}
assert(Fn);
if (Type == PARSER)
@ -1489,6 +1510,52 @@ void C4AulParse::Parse_Function()
}
// add separator
AddBCC(AB_EOFN);
// dump bytecode
if (DEBUG_BYTECODE_DUMP && Type == PARSER)
{
fprintf(stderr, "%s:\n", Fn->GetName());
std::map<C4AulBCC *, int> labels;
int labeln = 0;
for (C4AulBCC *pBCC = Fn->GetCode(); pBCC->bccType != AB_EOFN; pBCC++)
{
switch (pBCC->bccType)
{
case AB_JUMP: case AB_JUMPAND: case AB_JUMPOR: case AB_JUMPNNIL: case AB_CONDN: case AB_COND:
labels[pBCC + pBCC->Par.i] = ++labeln; break;
default: break;
}
}
for (C4AulBCC *pBCC = Fn->GetCode();; pBCC++)
{
C4AulBCCType eType = pBCC->bccType;
if (labels.find(pBCC) != labels.end())
fprintf(stderr, "%d:\n", labels[pBCC]);
fprintf(stderr, "\t%d\t%s", Fn->GetLineOfCode(pBCC), GetTTName(eType));
switch (eType)
{
case AB_FUNC:
fprintf(stderr, "\t%s\n", pBCC->Par.f->GetName()); break;
case AB_CALL: case AB_CALLFS: case AB_LOCALN: case AB_LOCALN_SET: case AB_PROP: case AB_PROP_SET:
fprintf(stderr, "\t%s\n", pBCC->Par.s->GetCStr()); break;
case AB_STRING:
fprintf(stderr, "\t\"%s\"\n", pBCC->Par.s->GetCStr()); break;
case AB_DEBUG: case AB_NIL: case AB_RETURN:
case AB_PAR:
case AB_ARRAYA: case AB_ARRAYA_SET: case AB_ARRAY_SLICE: case AB_ARRAY_SLICE_SET:
case AB_ERR: case AB_EOFN: case AB_EOF:
assert(!pBCC->Par.X); fprintf(stderr, "\n"); break;
case AB_CARRAY: case AB_CPROPLIST:
fprintf(stderr, "\t%p\n", reinterpret_cast<void *>(pBCC->Par.X)); break;
case AB_JUMP: case AB_JUMPAND: case AB_JUMPOR: case AB_JUMPNNIL: case AB_CONDN: case AB_COND:
fprintf(stderr, "\t%d\n", labels[pBCC + pBCC->Par.i]); break;
default:
fprintf(stderr, "\t%d\n", pBCC->Par.i); break;
}
if (eType == AB_EOFN) break;
}
}
// Do not blame this function for script errors between functions
Fn = 0;
Shift();
@ -1757,7 +1824,7 @@ int C4AulParse::Parse_Params(int iMaxCnt, const char * sWarn, C4AulFunc * pFunc)
// too many parameters?
if (sWarn && size > iMaxCnt && Type == PARSER)
Warn(FormatString("call to %s gives %d parameters, but only %d are used", sWarn, size, iMaxCnt).getData(), NULL);
// Balance stack
// Balance stack// FIXME: not for CALL/FUNC
if (size != iMaxCnt)
AddBCC(AB_STACK, iMaxCnt - size);
return size;
@ -1867,19 +1934,50 @@ void C4AulParse::Parse_PropList()
Shift();
}
C4Value C4AulParse::Parse_ConstPropList(bool really)
C4Value C4AulParse::Parse_ConstPropList(const C4PropListStatic * parent, C4String * Name)
{
C4Value r;
if (!Name)
throw new C4AulParseError(this, "a static proplist is not allowed to be anonymous");
C4PropListStatic * p;
if (Type == PREPARSER)
{
p = C4PropList::NewAnon(NULL, parent, Name);
}
else
{
C4Value v;
bool r;
if (parent)
r = parent->GetPropertyByS(Name, &v);
else
r = a->Engine->GetGlobalConstant(Name->GetCStr(), &v);
if (!r || !v.getPropList())
{
// the proplist couldn't be parsed or was overwritten by a later constant.
// create a temporary replacement
v.SetPropList(C4PropList::NewAnon(NULL, parent, Name));
}
p = v.getPropList()->IsStatic();
if (!p)
throw new C4AulParseError(this, "internal error: constant proplist is not static");
if (p->GetParent() != parent || p->GetParentKeyName() != Name)
{
// the proplist is from another definition, so don't change it
// create a replacement for this defnition
// FIXME: shouldn't the copy be made in parse, like functions are handled?
v.SetPropList(C4PropList::NewAnon(NULL, parent, Name));
p = v.getPropList()->IsStatic();
}
// In case of script reloads
p->Thaw();
}
Shift();
if (really)
r.SetPropList(C4PropList::NewAnon());
while (TokenType != ATT_BLCLOSE)
{
C4String * pKey;
if (TokenType == ATT_IDTF)
{
if (really)
pKey = Strings.RegString(Idtf);
pKey = Strings.RegString(Idtf);
Shift();
}
else if (TokenType == ATT_STRING)
@ -1891,18 +1989,15 @@ C4Value C4AulParse::Parse_ConstPropList(bool really)
if (TokenType != ATT_COLON && TokenType != ATT_SET)
UnexpectedToken("':' or '='");
Shift();
if (really)
r._getPropList()->SetPropertyByS(pKey, Parse_ConstExpression(really));
else
Parse_ConstExpression(really);
Parse_ConstExpression(p, pKey);
if (TokenType == ATT_COMMA)
Shift();
else if (TokenType != ATT_BLCLOSE)
UnexpectedToken("'}' or ','");
}
if (really)
r._getPropList()->Freeze();
return r;
if (Type == PARSER)
p->Freeze();
return C4VPropList(p);
}
void C4AulParse::Parse_DoWhile()
@ -2195,7 +2290,7 @@ void C4AulParse::Parse_Expression(int iParentPrio)
throw new C4AulParseError(this, "'for' may not be used as a parameter");
else if (SEqual(Idtf, C4AUL_Return))
{
Error("return may not be used as a parameter", 0);
Error("return may not be used as a parameter");
}
else if (SEqual(Idtf, C4AUL_Par))
{
@ -2203,7 +2298,7 @@ void C4AulParse::Parse_Expression(int iParentPrio)
Fn->ParCount = C4AUL_MAX_Par;
// and for Par
Shift();
Parse_Params(1, C4AUL_Par);
Parse_Params(1, C4AUL_Par);//FIXME: don't use Parse_Params
AddBCC(AB_PAR);
}
else if (SEqual(Idtf, C4AUL_Inherited) || SEqual(Idtf, C4AUL_SafeInherited))
@ -2250,7 +2345,7 @@ void C4AulParse::Parse_Expression(int iParentPrio)
else if (FoundFn)
{
if (Config.Developer.ExtraWarnings && !FoundFn->GetPublic())
Warn("using deprecated function ", Idtf);
Warn("using deprecated function %s", Idtf);
Shift();
// Function parameters for all functions except "this", which can be used without
if (!SEqual(FoundFn->GetName(), C4AUL_this) || TokenType == ATT_BOPEN)
@ -2534,9 +2629,11 @@ void C4AulParse::Parse_Expression2(int iParentPrio)
Shift();
// expect identifier of called function now
if (TokenType != ATT_IDTF) throw new C4AulParseError(this, "expecting func name after '->'");
pFunc = a->Engine->GetFirstFunc(Idtf);
if (Type == PARSER)
{
pName = ::Strings.RegString(Idtf);
pFunc = a->Engine->GetFirstFunc(pName);
}
Shift();
Parse_Params(C4AUL_MAX_Par, pName ? pName->GetCStr() : Idtf, pFunc);
AddBCC(eCallType, reinterpret_cast<intptr_t>(pName));
@ -2611,11 +2708,9 @@ void C4AulParse::Parse_Local()
if (!a->GetPropList())
throw new C4AulParseError(this, "local variables can only be initialized on proplists");
Shift();
// register as constant
if (Type == PARSER)
a->GetPropList()->SetPropertyByS(Strings.RegString(Name), Parse_ConstExpression(true));
else
Parse_ConstExpression(false);
C4RefCntPointer<C4String> key = ::Strings.RegString(Name);
assert(a->GetPropList()->IsStatic());
Parse_ConstExpression(a->GetPropList()->IsStatic(), key);
}
switch (TokenType)
{
@ -2654,8 +2749,8 @@ void C4AulParse::Parse_Static()
UnexpectedToken("variable name");
// global variable definition
// check: symbol already in use?
if (a->Engine->GetPropList()->GetFunc(Idtf)) Error("function and variable with name ", Idtf);
if (a->Engine->GetGlobalConstant(Idtf, NULL)) Error("constant and variable with name ", Idtf);
if (a->Engine->GetPropList()->GetFunc(Idtf)) Error("function and variable with name %s", Idtf);
if (a->Engine->GetGlobalConstant(Idtf, NULL)) Error("constant and variable with name %s", Idtf);
// insert variable if not defined already
if (a->Engine->GlobalNamedNames.GetItemNr(Idtf) == -1)
{
@ -2682,7 +2777,7 @@ void C4AulParse::Parse_Static()
}
}
C4Value C4AulParse::Parse_ConstExpression(bool really)
C4Value C4AulParse::Parse_ConstExpression(C4PropListStatic * parent, C4String * Name)
{
C4Value r;
switch (TokenType)
@ -2698,15 +2793,18 @@ C4Value C4AulParse::Parse_ConstExpression(bool really)
else if (SEqual(Idtf, C4AUL_Nil))
r.Set0();
else if (SEqual(Idtf, C4AUL_New))
r = Parse_ConstPropList(really);
r = Parse_ConstPropList(parent, Name);
else if (a->LocalNamed.GetItemNr(Idtf) != -1)
a->GetPropList()->GetPropertyByS(::Strings.FindString(Idtf), &r);
else if (!a->Engine->GetGlobalConstant(Idtf, &r))
UnexpectedToken("constant value");
if (Type == PARSER)
UnexpectedToken("constant value");
break;
case ATT_BOPEN2:
{
Shift();
// Create an array
if (really)
if (Type == PARSER)
r.SetArray(new C4ValueArray());
int size = 0;
bool fDone = false;
@ -2718,7 +2816,7 @@ C4Value C4AulParse::Parse_ConstExpression(bool really)
// [] -> size 0, [*,] -> size 2, [*,*,] -> size 3
if (size > 0)
{
if (really)
if (Type == PARSER)
r._getArray()->SetItem(size, C4VNull);
++size;
}
@ -2728,7 +2826,7 @@ C4Value C4AulParse::Parse_ConstExpression(bool really)
case ATT_COMMA:
{
// got no parameter before a ","? then push nil
if (really)
if (Type == PARSER)
r._getArray()->SetItem(size, C4VNull);
Shift();
++size;
@ -2736,10 +2834,10 @@ C4Value C4AulParse::Parse_ConstExpression(bool really)
}
default:
{
if (really)
r._getArray()->SetItem(size, Parse_ConstExpression(really));
if (Type == PARSER)
r._getArray()->SetItem(size, Parse_ConstExpression(NULL, NULL));
else
Parse_ConstExpression(really);
Parse_ConstExpression(NULL, NULL);
++size;
if (TokenType == ATT_COMMA)
Shift();
@ -2757,7 +2855,7 @@ C4Value C4AulParse::Parse_ConstExpression(bool really)
}
case ATT_BLOPEN:
{
r = Parse_ConstPropList(really);
r = Parse_ConstPropList(parent, Name);
break;
}
case ATT_OPERATOR:
@ -2794,10 +2892,18 @@ C4Value C4AulParse::Parse_ConstExpression(bool really)
if (C4ScriptOpMap[OpID].Code == AB_BitOr)
{
Shift();
C4Value r2 = Parse_ConstExpression(really);
C4Value r2 = Parse_ConstExpression(NULL, NULL);
r.SetInt(r.getInt() | r2.getInt());
}
}
// store as constant or property
if (Name)
{
if (parent)
parent->SetPropertyByS(Name, r);
else
a->Engine->RegisterGlobalConstant(Name->GetCStr(), r);
}
return r;
}
@ -2814,9 +2920,9 @@ void C4AulParse::Parse_Const()
SCopy(Idtf, Name);
// check func lists - functions of same name are not allowed
if (a->Engine->GetPropList()->GetFunc(Idtf))
Error("definition of constant hidden by function ", Idtf);
Error("definition of constant hidden by function %s", Idtf);
if (a->Engine->GlobalNamedNames.GetItemNr(Idtf) != -1)
Error("constant and variable with name ", Idtf);
Error("constant and variable with name %s", Idtf);
Match(ATT_IDTF);
// expect '='
if (TokenType != ATT_SET)
@ -2828,11 +2934,8 @@ void C4AulParse::Parse_Const()
// So allow only simple constants for now.
Shift();
// register as constant
if (Type == PREPARSER)
a->Engine->RegisterGlobalConstant(Name, Parse_ConstExpression(true));
else
Parse_ConstExpression(false);
C4RefCntPointer<C4String> key = ::Strings.RegString(Name);
Parse_ConstExpression(NULL, key);
switch (TokenType)
{
@ -2858,25 +2961,8 @@ bool C4AulScript::Parse()
return true;
}
void C4AulScript::LinkFunctions()
{
for (C4AulFunc *f = Func0; f; f = f->Next)
{
C4AulScriptFunc *sf = f->SFunc();
if (!sf) continue;
sf->OwnerOverloaded = GetPropList()->GetFunc(sf->Name);
if (sf->OwnerOverloaded && sf->OwnerOverloaded->Owner == this)
sf->OwnerOverloaded->OverloadedBy = sf;
GetPropList()->SetPropertyByS(sf->Name, C4VFunction(sf));
}
}
bool C4ScriptHost::Parse()
{
if (DEBUG_BYTECODE_DUMP)
{
fprintf(stderr, "parsing %s...\n", ScriptName.getData());
}
// check state
if (State != ASS_LINKED) return false;
@ -2890,120 +2976,63 @@ bool C4ScriptHost::Parse()
return true;
}
C4AulFunc * thisfuncs = Func0;
for (C4AulFunc *f = thisfuncs; f; f = f->Next)
if (f->GetName() && f->SFunc())
{
Engine->FuncLookUp.Remove(f);
}
Func0 = FuncL = 0;
C4PropList * p = GetPropList();
for (std::list<C4ScriptHost *>::iterator s = SourceScripts.begin(); s != SourceScripts.end(); ++s)
{
if (*s == this)
// append all funcs and local variable initializations
const C4Property * prop = (*s)->LocalValues.First();
while (prop)
{
C4AulFunc *f = thisfuncs, *n;
while (f)
switch(prop->Value.GetType())
{
n = f->Next;
f->AppendToScript(this);
f = n;
case C4V_Function:
{
C4AulScriptFunc * sf = prop->Value.getFunction()->SFunc();
assert(sf->pOrgScript == *s);
C4AulScriptFunc *sfc;
if (sf->pOrgScript != this)
sfc = new C4AulScriptFunc(this, *sf);
else
sfc = sf;
sfc->SetOverloaded(p->GetFunc(sf->Name));
p->SetPropertyByS(prop->Key, C4VFunction(sfc));
}
break;
default:
p->SetPropertyByS(prop->Key, prop->Value);
}
continue;
prop = (*s)->LocalValues.Next(prop);
}
if (*s == this)
continue;
// definition appends
if (GetPropList() && GetPropList()->GetDef() && (*s)->GetPropList() && (*s)->GetPropList()->GetDef())
GetPropList()->GetDef()->IncludeDefinition((*s)->GetPropList()->GetDef());
// append all funcs
C4AulScriptFunc *sf;
for (C4AulFunc *f = (*s)->Func0; f; f = f->Next)
// funcs from other scripts get appended directly from their script
if ((sf = f->SFunc()) && sf->pOrgScript == *s)
{
// append: create copy
C4AulScriptFunc *sfc = new C4AulScriptFunc(this, *sf);
}
// copy local var definitions
for (int ivar = 0; ivar < (*s)->LocalNamed.iSize; ivar ++)
LocalNamed.AddName((*s)->LocalNamed.pNames[ivar]);
}
LinkFunctions();
// parse
C4AulParse state(this, C4AulParse::PARSER);
for (std::list<C4ScriptHost *>::iterator s = SourceScripts.begin(); s != SourceScripts.end(); ++s)
{
state.SPos = (*s)->Script.getData();
state.pOrgScript = *s;
if (DEBUG_BYTECODE_DUMP)
{
fprintf(stderr, "parsing %s...\n", state.pOrgScript->ScriptName.getData());
}
state.Parse_Script();
}
// add eof chunk
AddBCC(AB_EOF);
// calc absolute code addresses for script funcs
for (C4AulFunc * f = Func0; f; f = f->Next)
{
C4AulScriptFunc * Fn = f->SFunc();
assert(Fn);
if (Fn)
assert(Fn->GetCodeOwner() == this);
}
// save line count
Engine->lineCnt += SGetLine(Script.getData(), Script.getPtr(Script.getLength()));
// dump bytecode
if (DEBUG_BYTECODE_DUMP)
for (C4AulFunc * f = Func0; f; f = f->Next)
{
C4AulScriptFunc *Fn = f->SFunc();
assert(Fn);
if (!Fn)
continue;
fprintf(stderr, "%s:\n", Fn->GetName());
std::map<C4AulBCC *, int> labels;
int labeln = 0;
for (C4AulBCC *pBCC = Fn->GetCode(); pBCC->bccType != AB_EOFN; pBCC++)
{
switch (pBCC->bccType)
{
case AB_JUMP: case AB_JUMPAND: case AB_JUMPOR: case AB_JUMPNNIL: case AB_CONDN: case AB_COND:
labels[pBCC + pBCC->Par.i] = ++labeln; break;
default: break;
}
}
for (C4AulBCC *pBCC = Fn->GetCode();; pBCC++)
{
C4AulBCCType eType = pBCC->bccType;
if (labels.find(pBCC) != labels.end())
fprintf(stderr, "%d:\n", labels[pBCC]);
fprintf(stderr, "\t%d\t%s", Fn->GetLineOfCode(pBCC), GetTTName(eType));
switch (eType)
{
case AB_FUNC:
fprintf(stderr, "\t%s\n", pBCC->Par.f->GetName()); break;
case AB_CALL: case AB_CALLFS: case AB_LOCALN: case AB_LOCALN_SET: case AB_PROP: case AB_PROP_SET:
fprintf(stderr, "\t%s\n", pBCC->Par.s->GetCStr()); break;
case AB_STRING:
fprintf(stderr, "\t\"%s\"\n", pBCC->Par.s->GetCStr()); break;
case AB_DEBUG: case AB_NIL: case AB_RETURN:
case AB_PAR:
case AB_ARRAYA: case AB_ARRAYA_SET: case AB_ARRAY_SLICE: case AB_ARRAY_SLICE_SET:
case AB_ERR: case AB_EOFN: case AB_EOF:
assert(!pBCC->Par.X); fprintf(stderr, "\n"); break;
case AB_CARRAY: case AB_CPROPLIST:
fprintf(stderr, "\t%p\n", reinterpret_cast<void *>(pBCC->Par.X)); break;
case AB_JUMP: case AB_JUMPAND: case AB_JUMPOR: case AB_JUMPNNIL: case AB_CONDN: case AB_COND:
fprintf(stderr, "\t%d\n", labels[pBCC + pBCC->Par.i]); break;
default:
fprintf(stderr, "\t%d\n", pBCC->Par.i); break;
}
if (eType == AB_EOFN) break;
}
}
// finished
State = ASS_PARSED;

View File

@ -62,7 +62,7 @@ void C4PropList::DelRef(const C4Value * pRef, C4Value * pNextRef)
}
// Only pure script proplists are garbage collected here, host proplists
// like definitions and effects have their own memory management.
if (IsScriptPropList()) delete this;
if (Delete()) delete this;
}
C4PropList * C4PropList::New(C4PropList * prototype)
@ -71,15 +71,9 @@ C4PropList * C4PropList::New(C4PropList * prototype)
return r;
}
C4PropList * C4PropList::NewAnon(C4PropList * prototype)
C4PropListStatic * C4PropList::NewAnon(C4PropList * prototype, const C4PropListStatic * parent, C4String * key)
{
C4PropList * r = new C4PropListScript(prototype);
return r;
}
C4PropList * C4PropList::NewScen(C4PropList * prototype)
{
return new C4PropList(prototype);
return new C4PropListStatic(prototype, parent, key);
}
C4Set<C4PropListNumbered *> C4PropListNumbered::PropLists;
@ -157,6 +151,33 @@ C4PropListNumbered::~C4PropListNumbered()
Log("removing numbered proplist without number");
}
void C4PropListStatic::RefCompileFunc(StdCompiler *pComp, C4ValueNumbers * numbers) const
{
assert(!pComp->isCompiler());
if (Parent)
{
Parent->RefCompileFunc(pComp, numbers);
pComp->Separator(StdCompiler::SEP_PART);
}
if (!ParentKeyName)
pComp->excCorrupt("C4PropListStatic::RefCompileFunc without ParentKeyName");
pComp->Value(mkParAdapt(ParentKeyName->GetData(), StdCompiler::RCT_ID));
}
StdStrBuf C4PropListStatic::GetDataString() const
{
StdStrBuf r;
if (Parent)
{
r.Take(Parent->GetDataString());
r.AppendChar('.');
}
assert(ParentKeyName);
if (ParentKeyName)
r.Append(ParentKeyName->GetData());
return r;
}
#ifdef _DEBUG
C4Set<C4PropList *> C4PropList::PropLists;
#endif
@ -204,13 +225,18 @@ C4PropList::~C4PropList()
bool C4PropList::operator==(const C4PropList &b) const
{
// every numbered proplist has a unique number and is only identical to itself
if (this == &b) return true;
if (IsNumbered() || b.IsNumbered()) return false;
if (Properties.GetSize() != b.Properties.GetSize()) return false;
if (GetDef() != b.GetDef()) return false;
//if (GetObject() != b.GetObject()) return false;
const C4Property * p = Properties.First();
while (p)
{
if (*p != b.Properties.Get(p->Key)) return false;
const C4Property & bp = b.Properties.Get(p->Key);
if (!bp) return false;
if (p->Value != bp.Value) return false;
p = Properties.Next(p);
}
return true;
@ -476,8 +502,7 @@ C4Value C4PropList::CallOrThrow(const char * s, C4AulParSet *Pars)
{
if (s[0] == '~')
return C4Value();
throw new C4AulExecError(this->GetObject(),
FormatString("Call: no function \"%s\"", s).getData());
throw new C4AulExecError(FormatString("Call: no function \"%s\"", s).getData());
}
return pFn->Exec(this, Pars);
}
@ -513,6 +538,42 @@ int32_t C4PropList::GetPropertyInt(C4PropertyName n) const
return 0;
}
C4ValueArray * C4PropList::GetProperties() const
{
C4ValueArray * a;
int i;
if (prototype)
{
a = prototype->GetProperties();
i = a->GetSize();
a->SetSize(i + Properties.GetSize());
}
else
{
a = new C4ValueArray(Properties.GetSize());
i = 0;
}
const C4Property * p = Properties.First();
while (p)
{
(*a)[i++] = C4VString(p->Key);
p = Properties.Next(p);
}
return a;
}
C4String * C4PropList::EnumerateOwnFuncs(C4String * prev) const
{
const C4Property * p = prev ? Properties.Next(&Properties.Get(prev)) : Properties.First();
while (p)
{
if (p->Value.getFunction())
return p->Key;
p = Properties.Next(p);
}
return 0;
}
void C4PropList::SetPropertyByS(C4String * k, const C4Value & to)
{
assert(!constant);
@ -522,7 +583,7 @@ void C4PropList::SetPropertyByS(C4String * k, const C4Value & to)
C4PropList * newpt = to.GetData().PropList;
for(C4PropList * it = newpt; it; it = it->prototype)
if(it == this)
throw new C4AulExecError(NULL, "Trying to create cyclic prototype structure");
throw new C4AulExecError("Trying to create cyclic prototype structure");
prototype = newpt;
//return;
}

View File

@ -63,15 +63,17 @@ public:
virtual C4PropListNumbered * GetPropListNumbered();
C4PropList * GetPrototype() const { return prototype; }
// Whether this proplist should be saved as a reference to a C4Def/C4Object
virtual bool IsDef() const { return false; }
// saved as a reference to a global constant?
virtual class C4PropListStatic * IsStatic() { return NULL; }
// saved as a reference to separately saved objects?
virtual bool IsNumbered() const { return false; }
// Whether this proplist is a pure script proplist, not a host object
virtual bool IsScriptPropList() { return false; }
// some proplists have references that are not reference-counted
virtual bool Delete() { return false; }
// These three operate on properties as seen by script, which can be dynamic
// These four operate on properties as seen by script, which can be dynamic
// or reflect C++ variables
virtual bool GetPropertyByS(C4String *k, C4Value *pResult) const;
virtual C4ValueArray * GetProperties() const;
// not allowed on frozen proplists
virtual void SetPropertyByS(C4String * k, const C4Value & to);
virtual void ResetProperty(C4String * k);
@ -84,6 +86,7 @@ public:
{ return GetFunc(&Strings.P[k]); }
C4AulFunc * GetFunc(C4String * k) const;
C4AulFunc * GetFunc(const char * k) const;
C4String * EnumerateOwnFuncs(C4String * prev = 0) const;
C4Value Call(C4PropertyName k, C4AulParSet *pPars=0)
{ return Call(&Strings.P[k], pPars); }
C4Value Call(C4String * k, C4AulParSet *pPars=0);
@ -97,10 +100,10 @@ public:
{ SetPropertyByS(&Strings.P[k], to); }
static C4PropList * New(C4PropList * prototype = 0);
static C4PropList * NewAnon(C4PropList * prototype = 0);
static C4PropList * NewScen(C4PropList * prototype = 0);
static C4PropListStatic * NewAnon(C4PropList * prototype, const C4PropListStatic * parent, C4String * key);
// only freeze proplists which are not going to be modified
// FIXME: Only C4PropListStatic get frozen. Optimize accordingly.
void Freeze() { constant = true; }
void Thaw() { constant = false; }
bool IsFrozen() const { return constant; }
@ -108,7 +111,6 @@ public:
virtual void Denumerate(C4ValueNumbers *);
virtual ~C4PropList();
// Every proplist has to be initialized by either Init or CompileFunc.
void CompileFunc(StdCompiler *pComp, C4ValueNumbers *);
void AppendDataString(StdStrBuf * out, const char * delim, int depth = 3);
@ -125,6 +127,7 @@ private:
C4Set<C4Property> Properties;
C4PropList * prototype;
bool constant; // if true, this proplist is not changeable
friend class C4ScriptHost;
public:
int32_t Status;
};
@ -132,7 +135,7 @@ public:
void CompileNewFunc(C4PropList *&pStruct, StdCompiler *pComp, C4ValueNumbers * const & rPar);
// Proplists that are created during a game and get saved in a savegame
// Examples: Objects, Effects, scriptcreated proplists
// Examples: Objects, Effects
class C4PropListNumbered: public C4PropList
{
public:
@ -162,8 +165,26 @@ class C4PropListScript: public C4PropList
{
public:
C4PropListScript(C4PropList * prototype = 0): C4PropList(prototype) { }
bool IsScriptPropList() { return true; }
bool Delete() { return true; }
};
// PropLists declared in the game data
// examples: Definitions, local variable initializers
class C4PropListStatic: public C4PropList
{
public:
C4PropListStatic(C4PropList * prototype, const C4PropListStatic * parent, C4String * key):
C4PropList(prototype), Parent(parent), ParentKeyName(key) { }
virtual ~C4PropListStatic() { }
bool Delete() { return true; }
virtual C4PropListStatic * IsStatic() { return this; }
void RefCompileFunc(StdCompiler *pComp, C4ValueNumbers * numbers) const;
StdStrBuf GetDataString() const;
const C4PropListStatic * GetParent() { return Parent; }
const C4String * GetParentKeyName() { return ParentKeyName; }
protected:
const C4PropListStatic * Parent;
C4RefCntPointer<C4String> ParentKeyName; // property in parent this proplist was created in
};
#endif // C4PROPLIST_H

View File

@ -33,19 +33,14 @@
//========================== Some Support Functions =======================================
StdStrBuf FnStringFormat(C4AulContext *cthr, const char *szFormatPar, C4Value * Par0, C4Value * Par1, C4Value * Par2, C4Value * Par3,
C4Value * Par4, C4Value * Par5, C4Value * Par6, C4Value * Par7, C4Value * Par8, C4Value * Par9)
StdStrBuf FnStringFormat(C4PropList * _this, C4String *szFormatPar, C4Value * Pars, int ParCount)
{
C4Value * Par[11];
Par[0]=Par0; Par[1]=Par1; Par[2]=Par2; Par[3]=Par3; Par[4]=Par4;
Par[5]=Par5; Par[6]=Par6; Par[7]=Par7; Par[8]=Par8; Par[9]=Par9;
Par[10] = 0;
int cPar=0;
StdStrBuf StringBuf("", false);
const char * cpFormat = szFormatPar;
const char * cpFormat = FnStringPar(szFormatPar);
const char * cpType;
char szField[MaxFnStringParLen+1];
char szField[20];
while (*cpFormat)
{
// Copy normal stuff
@ -57,31 +52,31 @@ StdStrBuf FnStringFormat(C4AulContext *cthr, const char *szFormatPar, C4Value *
// Scan field type
for (cpType=cpFormat+1; *cpType && (*cpType=='.' || Inside(*cpType,'0','9')); cpType++) {}
// Copy field
SCopy(cpFormat,szField,cpType-cpFormat+1);
SCopy(cpFormat,szField,Min<unsigned int>(sizeof szField - 1, cpType - cpFormat + 1));
// Insert field by type
switch (*cpType)
{
// number
case 'd': case 'x': case 'X':
{
if (!Par[cPar]) throw new C4AulExecError(cthr->Obj, "format placeholder without parameter");
StringBuf.AppendFormat(szField, Par[cPar++]->getInt());
if (cPar >= ParCount) throw new C4AulExecError("format placeholder without parameter");
StringBuf.AppendFormat(szField, Pars[cPar++].getInt());
cpFormat+=SLen(szField);
break;
}
// character
case 'c':
{
if (!Par[cPar]) throw new C4AulExecError(cthr->Obj, "format placeholder without parameter");
StringBuf.AppendCharacter(Par[cPar++]->getInt());
if (cPar >= ParCount) throw new C4AulExecError("format placeholder without parameter");
StringBuf.AppendCharacter(Pars[cPar++].getInt());
cpFormat+=SLen(szField);
break;
}
// C4ID
case 'i':
{
if (!Par[cPar]) throw new C4AulExecError(cthr->Obj, "format placeholder without parameter");
C4ID id = Par[cPar++]->getC4ID();
if (cPar >= ParCount) throw new C4AulExecError("format placeholder without parameter");
C4ID id = Pars[cPar++].getC4ID();
StringBuf.Append(id.ToString());
cpFormat+=SLen(szField);
break;
@ -89,8 +84,8 @@ StdStrBuf FnStringFormat(C4AulContext *cthr, const char *szFormatPar, C4Value *
// C4Value
case 'v':
{
if (!Par[cPar]) throw new C4AulExecError(cthr->Obj, "format placeholder without parameter");
StringBuf.Append(static_cast<const StdStrBuf&>(Par[cPar++]->GetDataString(10)));
if (cPar >= ParCount) throw new C4AulExecError("format placeholder without parameter");
StringBuf.Append(static_cast<const StdStrBuf&>(Pars[cPar++].GetDataString(10)));
cpFormat+=SLen(szField);
break;
}
@ -98,14 +93,15 @@ StdStrBuf FnStringFormat(C4AulContext *cthr, const char *szFormatPar, C4Value *
case 's':
{
// get string
if (!Par[cPar]) throw new C4AulExecError(cthr->Obj, "format placeholder without parameter");
if (cPar >= ParCount) throw new C4AulExecError("format placeholder without parameter");
const char *szStr = "(null)";
if (Par[cPar]->GetData())
if (Pars[cPar].GetData())
{
C4String * pStr = Par[cPar++]->getStr();
if (!pStr) throw new C4AulExecError(cthr->Obj, "string format placeholder without string");
C4String * pStr = Pars[cPar].getStr();
if (!pStr) throw new C4AulExecError("string format placeholder without string");
szStr = pStr->GetCStr();
}
++cPar;
StringBuf.AppendFormat(szField, szStr);
cpFormat+=SLen(szField);
break;
@ -154,88 +150,104 @@ bool C4ValueToMatrix(const C4ValueArray& array, StdMeshMatrix* matrix)
return true;
}
//=============================== C4Script Functions ====================================
static C4PropList *Fn_this(C4AulContext *cthr)
C4AulDefFunc::C4AulDefFunc(C4AulScript *pOwner, C4ScriptFnDef* pDef):
C4AulFunc(pOwner, pDef->Identifier), Def(pDef)
{
return cthr->Def;
Owner->GetPropList()->SetPropertyByS(Name, C4VFunction(this));
}
static C4PropList * FnCreatePropList(C4AulContext *cthr, C4PropList * prototype)
C4AulDefFunc::~C4AulDefFunc()
{
}
C4Value C4AulDefFunc::Exec(C4PropList * p, C4Value pPars[], bool fPassErrors)
{
assert(Def->FunctionC4V);
return Def->FunctionC4V(p, pPars);
}
//=============================== C4Script Functions ====================================
static C4PropList *Fnthis(C4PropList * _this)
{
return _this;
}
static C4PropList * FnCreatePropList(C4PropList * _this, C4PropList * prototype)
{
return C4PropList::New(prototype);
}
static C4Value FnGetProperty_C4V(C4AulContext *cthr, C4Value * key_C4V, C4Value * pObj_C4V)
static C4Value FnGetProperty(C4PropList * _this, C4String * key, C4PropList * pObj)
{
C4PropList * pObj = pObj_C4V->_getPropList();
if (!pObj) pObj=cthr->Obj;
if (!pObj) pObj=cthr->Def;
if (!pObj) pObj = _this;
if (!pObj) return C4VNull;
C4String * key = key_C4V->_getStr();
if (!key) return C4VNull;
C4Value r;
pObj->GetPropertyByS(key, &r);
return r;
}
static C4Value FnSetProperty_C4V(C4AulContext *cthr, C4Value * key_C4V, C4Value * to, C4Value * pObj_C4V)
static bool FnSetProperty(C4PropList * _this, C4String * key, const C4Value & to, C4PropList * pObj)
{
C4PropList * pObj = pObj_C4V->_getPropList();
if (!pObj) pObj=cthr->Obj;
if (!pObj) pObj=cthr->Def;
if (!pObj) return C4VFalse;
C4String * key = key_C4V->_getStr();
if (!key) return C4VFalse;
if (!pObj) pObj = _this;
if (!pObj) return false;
if (!key) return false;
if (pObj->IsFrozen())
throw new C4AulExecError(cthr->Obj, "proplist write: proplist is readonly");
pObj->SetPropertyByS(key, *to);
return C4VTrue;
throw new C4AulExecError("proplist write: proplist is readonly");
pObj->SetPropertyByS(key, to);
return true;
}
static C4Value FnResetProperty_C4V(C4AulContext *cthr, C4Value * key_C4V, C4Value * pObj_C4V)
static bool FnResetProperty(C4PropList * _this, C4String * key, C4PropList * pObj)
{
C4PropList * pObj = pObj_C4V->_getPropList();
if (!pObj) pObj=cthr->Obj;
if (!pObj) pObj=cthr->Def;
if (!pObj) return C4VFalse;
C4String * key = key_C4V->_getStr();
if (!key) return C4VFalse;
if (!pObj->HasProperty(key)) return C4VFalse;
if (!pObj) pObj = _this;
if (!pObj) return false;
if (!key) return false;
if (!pObj->HasProperty(key)) return false;
if (pObj->IsFrozen())
throw new C4AulExecError(cthr->Obj, "proplist write: proplist is readonly");
throw new C4AulExecError("proplist write: proplist is readonly");
pObj->ResetProperty(key);
return C4VTrue;
return true;
}
static C4Value FnLog_C4V(C4AulContext *cthr, C4Value *szMessage, C4Value * iPar0, C4Value * iPar1, C4Value * iPar2, C4Value * iPar3, C4Value * iPar4, C4Value * iPar5, C4Value * iPar6, C4Value * iPar7, C4Value * iPar8)
static C4ValueArray * FnGetProperties(C4PropList * _this, C4PropList * p)
{
Log(FnStringFormat(cthr, FnStringPar(szMessage->getStr()),iPar0,iPar1,iPar2,iPar3,iPar4,iPar5,iPar6,iPar7,iPar8).getData());
if (!p) p = _this;
if (!p) throw new NeedNonGlobalContext("GetProperties");
C4ValueArray * r = p->GetProperties();
r->SortStrings();
return r;
}
static C4Value FnLog(C4PropList * _this, C4Value * Pars)
{
Log(FnStringFormat(_this, Pars[0].getStr(), &Pars[1], 9).getData());
return C4VBool(true);
}
static C4Value FnDebugLog_C4V(C4AulContext *cthr, C4Value *szMessage, C4Value * iPar0, C4Value * iPar1, C4Value * iPar2, C4Value * iPar3, C4Value * iPar4, C4Value * iPar5, C4Value * iPar6, C4Value * iPar7, C4Value * iPar8)
static C4Value FnDebugLog(C4PropList * _this, C4Value * Pars)
{
DebugLog(FnStringFormat(cthr, FnStringPar(szMessage->getStr()),iPar0,iPar1,iPar2,iPar3,iPar4,iPar5,iPar6,iPar7,iPar8).getData());
DebugLog(FnStringFormat(_this, Pars[0].getStr(), &Pars[1], 9).getData());
return C4VBool(true);
}
static C4Value FnFormat_C4V(C4AulContext *cthr, C4Value *szFormat, C4Value * iPar0, C4Value * iPar1, C4Value * iPar2, C4Value * iPar3, C4Value * iPar4, C4Value * iPar5, C4Value * iPar6, C4Value * iPar7, C4Value * iPar8)
static C4Value FnFormat(C4PropList * _this, C4Value * Pars)
{
return C4VString(FnStringFormat(cthr, FnStringPar(szFormat->getStr()),iPar0,iPar1,iPar2,iPar3,iPar4,iPar5,iPar6,iPar7,iPar8));
return C4VString(FnStringFormat(_this, Pars[0].getStr(), &Pars[1], 9));
}
static C4ID FnC4Id(C4AulContext *cthr, C4String *szID)
static C4ID FnC4Id(C4PropList * _this, C4String *szID)
{
return(C4ID(FnStringPar(szID)));
}
static long FnAbs(C4AulContext *cthr, long iVal)
static long FnAbs(C4PropList * _this, long iVal)
{
return Abs(iVal);
}
static long FnSin(C4AulContext *cthr, long iAngle, long iRadius, long iPrec)
static long FnSin(C4PropList * _this, long iAngle, long iRadius, long iPrec)
{
if (!iPrec) iPrec = 1;
// Precalculate the modulo operation so the C4Fixed argument to Sin does not overflow
@ -244,14 +256,14 @@ static long FnSin(C4AulContext *cthr, long iAngle, long iRadius, long iPrec)
return fixtoi(Sin(itofix(iAngle, iPrec)), iRadius);
}
static long FnCos(C4AulContext *cthr, long iAngle, long iRadius, long iPrec)
static long FnCos(C4PropList * _this, long iAngle, long iRadius, long iPrec)
{
if (!iPrec) iPrec = 1;
iAngle %= 360 * iPrec;
return fixtoi(Cos(itofix(iAngle, iPrec)), iRadius);
}
static long FnSqrt(C4AulContext *cthr, long iValue)
static long FnSqrt(C4PropList * _this, long iValue)
{
if (iValue<0) return 0;
long iSqrt = long(sqrt(double(iValue)));
@ -260,7 +272,7 @@ static long FnSqrt(C4AulContext *cthr, long iValue)
return iSqrt;
}
static long FnAngle(C4AulContext *cthr, long iX1, long iY1, long iX2, long iY2, long iPrec)
static long FnAngle(C4PropList * _this, long iX1, long iY1, long iX2, long iY2, long iPrec)
{
long iAngle;
@ -295,7 +307,7 @@ static long FnAngle(C4AulContext *cthr, long iX1, long iY1, long iX2, long iY2,
return iAngle;
}
static long FnArcSin(C4AulContext *cthr, long iVal, long iRadius)
static long FnArcSin(C4PropList * _this, long iVal, long iRadius)
{
// safety
if (!iRadius) return 0;
@ -307,7 +319,7 @@ static long FnArcSin(C4AulContext *cthr, long iVal, long iRadius)
return (long) floor(f1+0.5);
}
static long FnArcCos(C4AulContext *cthr, long iVal, long iRadius)
static long FnArcCos(C4PropList * _this, long iVal, long iRadius)
{
// safety
if (!iRadius) return 0;
@ -319,42 +331,42 @@ static long FnArcCos(C4AulContext *cthr, long iVal, long iRadius)
return (long) floor(f1+0.5);
}
static long FnMin(C4AulContext *cthr, long iVal1, long iVal2)
static long FnMin(C4PropList * _this, long iVal1, long iVal2)
{
return Min(iVal1,iVal2);
}
static long FnMax(C4AulContext *cthr, long iVal1, long iVal2)
static long FnMax(C4PropList * _this, long iVal1, long iVal2)
{
return Max(iVal1,iVal2);
}
static long FnDistance(C4AulContext *cthr, long iX1, long iY1, long iX2, long iY2)
static long FnDistance(C4PropList * _this, long iX1, long iY1, long iX2, long iY2)
{
return Distance(iX1,iY1,iX2,iY2);
}
static long FnBoundBy(C4AulContext *cthr, long iVal, long iRange1, long iRange2)
static long FnBoundBy(C4PropList * _this, long iVal, long iRange1, long iRange2)
{
return BoundBy(iVal,iRange1,iRange2);
}
static bool FnInside(C4AulContext *cthr, long iVal, long iRange1, long iRange2)
static bool FnInside(C4PropList * _this, long iVal, long iRange1, long iRange2)
{
return Inside(iVal,iRange1,iRange2);
}
static long FnRandom(C4AulContext *cthr, long iRange)
static long FnRandom(C4PropList * _this, long iRange)
{
return Random(iRange);
}
static long FnAsyncRandom(C4AulContext *cthr, long iRange)
static long FnAsyncRandom(C4PropList * _this, long iRange)
{
return SafeRandom(iRange);
}
static int FnGetType(C4AulContext *cthr, const C4Value & Value)
static int FnGetType(C4PropList * _this, const C4Value & Value)
{
// dynamic types
if (Value.CheckConversion(C4V_Object)) return C4V_Object;
@ -364,54 +376,49 @@ static int FnGetType(C4AulContext *cthr, const C4Value & Value)
return Value.GetType();
}
static C4ValueArray * FnCreateArray(C4AulContext *cthr, int iSize)
static C4ValueArray * FnCreateArray(C4PropList * _this, int iSize)
{
return new C4ValueArray(iSize);
}
static C4Value FnGetLength(C4AulContext *cthr, C4Value *pPars)
static int FnGetLength(C4PropList * _this, const C4Value & Par)
{
// support GetLength() etc.
if (!pPars[0]) return C4VNull;
C4ValueArray * pArray = pPars->getArray();
C4ValueArray * pArray = Par.getArray();
if (pArray)
return C4VInt(pArray->GetSize());
C4String * pStr = pPars->getStr();
return pArray->GetSize();
C4String * pStr = Par.getStr();
if (pStr)
return C4VInt(GetCharacterCount(pStr->GetData().getData()));
throw new C4AulExecError(cthr->Obj, "func \"GetLength\" par 0 cannot be converted to string or array");
return GetCharacterCount(pStr->GetData().getData());
throw new C4AulExecError("GetLength: parameter 0 cannot be converted to string or array");
}
static C4Value FnGetIndexOf(C4AulContext *cthr, C4Value *pPars)
static int FnGetIndexOf(C4PropList * _this, C4ValueArray * pArray, const C4Value & Needle)
{
// find first occurance of first parameter in array
// support GetIndexOf(0, x)
if (!pPars[0]) return C4VInt(-1);
// if the first param is nonzero, it must be an array
const C4ValueArray * pArray = pPars[0].getArray();
if (!pArray)
throw new C4AulExecError(cthr->Obj, "func \"GetIndexOf\" par 0 cannot be converted to array");
if (!pArray) return -1;
int32_t iSize = pArray->GetSize();
for (int32_t i = 0; i<iSize; ++i)
if (pPars[1] == pArray->GetItem(i))
for (int32_t i = 0; i < iSize; ++i)
if (Needle == pArray->GetItem(i))
// element found
return C4VInt(i);
return i;
// element not found
return C4VInt(-1);
return -1;
}
static C4Void FnSetLength(C4AulContext *cthr, C4ValueArray *pArray, int iNewSize)
static C4Void FnSetLength(C4PropList * _this, C4ValueArray *pArray, int iNewSize)
{
// safety
if (iNewSize<0 || iNewSize > C4ValueArray::MaxSize)
throw new C4AulExecError(cthr->Obj, FormatString("SetLength: invalid array size (%d)", iNewSize).getData());
throw new C4AulExecError(FormatString("SetLength: invalid array size (%d)", iNewSize).getData());
// set new size
pArray->SetSize(iNewSize);
return C4Void();
}
static Nillable<long> FnGetChar(C4AulContext* cthr, C4String *pString, long iIndex)
static Nillable<long> FnGetChar(C4PropList * _this, C4String *pString, long iIndex)
{
const char *szText = FnStringPar(pString);
if (!szText) return C4Void();
@ -425,18 +432,18 @@ static Nillable<long> FnGetChar(C4AulContext* cthr, C4String *pString, long iInd
return c;
}
static C4Value FnEval(C4AulContext *cthr, C4Value *strScript_C4V)
static C4Value Fneval(C4PropList * _this, C4String *strScript)
{
// execute script in the same object
if (cthr->Obj)
return cthr->Obj->Def->Script.DirectExec(cthr->Obj, FnStringPar(strScript_C4V->getStr()), "eval", true);
else if (cthr->Def && cthr->Def->GetDef())
return cthr->Def->GetDef()->Script.DirectExec(0, FnStringPar(strScript_C4V->getStr()), "eval", true);
if (Object(_this))
return Object(_this)->Def->Script.DirectExec(Object(_this), FnStringPar(strScript), "eval", true);
else if (_this && _this->GetDef())
return _this->GetDef()->Script.DirectExec(0, FnStringPar(strScript), "eval", true);
else
return ::GameScript.DirectExec(0, FnStringPar(strScript_C4V->getStr()), "eval", true);
return ::GameScript.DirectExec(0, FnStringPar(strScript), "eval", true);
}
static bool FnLocateFunc(C4AulContext *cthr, C4String *funcname, C4PropList * p)
static bool FnLocateFunc(C4PropList * _this, C4String *funcname, C4PropList * p)
{
// safety
if (!funcname || !funcname->GetCStr())
@ -444,7 +451,7 @@ static bool FnLocateFunc(C4AulContext *cthr, C4String *funcname, C4PropList * p)
Log("No func name");
return false;
}
if (!p) p = cthr->Def;
if (!p) p = _this;
// get function by name
C4AulFunc *pFunc = p->GetFunc(funcname);
if (!pFunc)
@ -478,7 +485,7 @@ static bool FnLocateFunc(C4AulContext *cthr, C4String *funcname, C4PropList * p)
return true;
}
static long FnModulateColor(C4AulContext *cthr, long iClr1, long iClr2)
static long FnModulateColor(C4PropList * _this, long iClr1, long iClr2)
{
DWORD dwClr1 = iClr1;
DWORD dwClr2 = iClr2;
@ -494,24 +501,24 @@ static long FnModulateColor(C4AulContext *cthr, long iClr1, long iClr2)
return r;
}
static long FnWildcardMatch(C4AulContext *ctx, C4String *psString, C4String *psWildcard)
static long FnWildcardMatch(C4PropList * _this, C4String *psString, C4String *psWildcard)
{
return SWildcardMatchEx(FnStringPar(psString), FnStringPar(psWildcard));
}
static bool FnFatalError(C4AulContext *ctx, C4String *pErrorMsg)
static bool FnFatalError(C4PropList * _this, C4String *pErrorMsg)
{
throw new C4AulExecError(ctx->Obj, FormatString("script: %s", pErrorMsg ? pErrorMsg->GetCStr() : "(no error)").getData());
throw new C4AulExecError(FormatString("script: %s", pErrorMsg ? pErrorMsg->GetCStr() : "(no error)").getData());
}
static bool FnStartCallTrace(C4AulContext *ctx)
static bool FnStartCallTrace(C4PropList * _this)
{
extern void C4AulStartTrace();
C4AulStartTrace();
return true;
}
static bool FnStartScriptProfiler(C4AulContext *ctx, C4ID idScript)
static bool FnStartScriptProfiler(C4PropList * _this, C4ID idScript)
{
// get script to profile
C4AulScript *pScript;
@ -528,13 +535,13 @@ static bool FnStartScriptProfiler(C4AulContext *ctx, C4ID idScript)
return true;
}
static bool FnStopScriptProfiler(C4AulContext *ctx)
static bool FnStopScriptProfiler(C4PropList * _this)
{
C4AulProfiler::StopProfiling();
return true;
}
static Nillable<C4String *> FnGetConstantNameByValue(C4AulContext *ctx, int value, Nillable<C4String *> name_prefix, int idx)
static Nillable<C4String *> FnGetConstantNameByValue(C4PropList * _this, int value, Nillable<C4String *> name_prefix, int idx)
{
C4String *name_prefix_s = name_prefix;
// find a constant that has the specified value and prefix
@ -576,26 +583,13 @@ C4ScriptConstDef C4ScriptConstMap[]=
{ NULL, C4V_Nil, 0}
};
#define MkFnC4V (C4Value (*)(C4AulContext *cthr, C4Value*, C4Value*, C4Value*, C4Value*, C4Value*,\
C4Value*, C4Value*, C4Value*, C4Value*, C4Value*))
C4ScriptFnDef C4ScriptFnMap[]=
{
{ "Log", 1, C4V_Bool, { C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any}, FnLog },
{ "DebugLog", 1, C4V_Bool, { C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any}, FnDebugLog },
{ "Format", 1, C4V_String, { C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any}, FnFormat },
{ "SetProperty", 1 ,C4V_Any ,{ C4V_String ,C4V_Any ,C4V_PropList,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnSetProperty_C4V , 0 },
{ "GetProperty", 1 ,C4V_Any ,{ C4V_String ,C4V_PropList,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnGetProperty_C4V , 0 },
{ "ResetProperty", 1 ,C4V_Any ,{ C4V_String ,C4V_PropList,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnResetProperty_C4V , 0 },
{ "Log", 1 ,C4V_Bool ,{ C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V &FnLog_C4V, 0 },
{ "DebugLog", 1 ,C4V_Bool ,{ C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V &FnDebugLog_C4V, 0 },
{ "Format", 1 ,C4V_String ,{ C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V &FnFormat_C4V, 0 },
{ "GetLength", 1 ,C4V_Int ,{ C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,0, FnGetLength },
{ "GetIndexOf", 1 ,C4V_Int ,{ C4V_Array ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,0, FnGetIndexOf },
{ "eval", 1 ,C4V_Any ,{ C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnEval, 0 },
{ NULL, 0 ,C4V_Nil ,{ C4V_Nil ,C4V_Nil ,C4V_Nil ,C4V_Nil ,C4V_Nil ,C4V_Nil ,C4V_Nil ,C4V_Nil ,C4V_Nil ,C4V_Nil} ,0, 0 }
{ NULL, 0, C4V_Nil, { C4V_Nil ,C4V_Nil ,C4V_Nil ,C4V_Nil ,C4V_Nil ,C4V_Nil ,C4V_Nil ,C4V_Nil ,C4V_Nil ,C4V_Nil}, 0 }
};
void InitCoreFunctionMap(C4AulScriptEngine *pEngine)
@ -609,39 +603,48 @@ void InitCoreFunctionMap(C4AulScriptEngine *pEngine)
// add all def script funcs
for (C4ScriptFnDef *pDef = &C4ScriptFnMap[0]; pDef->Identifier; pDef++)
pEngine->AddFunc(pDef->Identifier, pDef);
AddFunc(pEngine, "Abs", FnAbs);
AddFunc(pEngine, "Min", FnMin);
AddFunc(pEngine, "Max", FnMax);
AddFunc(pEngine, "Sin", FnSin);
AddFunc(pEngine, "Cos", FnCos);
AddFunc(pEngine, "Sqrt", FnSqrt);
AddFunc(pEngine, "ArcSin", FnArcSin);
AddFunc(pEngine, "ArcCos", FnArcCos);
AddFunc(pEngine, "BoundBy", FnBoundBy);
AddFunc(pEngine, "Inside", FnInside);
AddFunc(pEngine, "Random", FnRandom);
AddFunc(pEngine, "AsyncRandom", FnAsyncRandom);
new C4AulDefFunc(pEngine, pDef);
#define F(f) AddFunc(pEngine, #f, Fn##f)
F(Abs);
F(Min);
F(Max);
F(Sin);
F(Cos);
F(Sqrt);
F(ArcSin);
F(ArcCos);
F(BoundBy);
F(Inside);
F(Random);
F(AsyncRandom);
AddFunc(pEngine, "CreateArray", FnCreateArray);
AddFunc(pEngine, "CreatePropList", FnCreatePropList);
AddFunc(pEngine, "C4Id", FnC4Id, false);
AddFunc(pEngine, "Distance", FnDistance);
AddFunc(pEngine, "Angle", FnAngle);
AddFunc(pEngine, "GetChar", FnGetChar);
AddFunc(pEngine, "GetType", FnGetType);
AddFunc(pEngine, "ModulateColor", FnModulateColor);
AddFunc(pEngine, "WildcardMatch", FnWildcardMatch);
AddFunc(pEngine, "FatalError", FnFatalError);
AddFunc(pEngine, "StartCallTrace", FnStartCallTrace);
AddFunc(pEngine, "StartScriptProfiler", FnStartScriptProfiler);
AddFunc(pEngine, "StopScriptProfiler", FnStopScriptProfiler);
AddFunc(pEngine, "LocateFunc", FnLocateFunc);
F(CreateArray);
F(CreatePropList);
F(GetProperties);
F(GetProperty);
F(SetProperty);
F(ResetProperty);
F(C4Id);
F(Distance);
F(Angle);
F(GetChar);
F(GetType);
F(ModulateColor);
F(WildcardMatch);
F(GetLength);
F(SetLength);
F(GetIndexOf);
F(FatalError);
F(StartCallTrace);
F(StartScriptProfiler);
F(StopScriptProfiler);
F(LocateFunc);
AddFunc(pEngine, "SetLength", FnSetLength);
F(eval);
AddFunc(pEngine, "this", Fn_this);
AddFunc(pEngine, "GetConstantNameByValue", FnGetConstantNameByValue, false);
F(this);
F(GetConstantNameByValue);
AddFunc(pEngine, "Translate", C4AulExec::FnTranslate);
#undef F
}

View File

@ -38,8 +38,17 @@ C4ScriptHost::C4ScriptHost()
LastCode = NULL;
stringTable = 0;
SourceScripts.push_back(this);
LocalNamed.Reset();
// prepare include list
IncludesResolved = false;
Resolving=false;
Includes.clear();
Appends.clear();
}
C4ScriptHost::~C4ScriptHost()
{
Clear();
}
C4ScriptHost::~C4ScriptHost() { Clear(); }
void C4ScriptHost::Clear()
{
@ -49,6 +58,9 @@ void C4ScriptHost::Clear()
ClearCode();
SourceScripts.clear();
SourceScripts.push_back(this);
// remove includes
Includes.clear();
Appends.clear();
}
bool C4ScriptHost::Load(C4Group &hGroup, const char *szFilename,
@ -109,7 +121,7 @@ void C4ScriptHost::SetError(const char *szMessage)
/*--- C4ExtraScriptHost ---*/
C4ExtraScriptHost::C4ExtraScriptHost():
ParserPropList(C4PropList::NewAnon())
ParserPropList(C4PropList::NewAnon(NULL, NULL, NULL))
{
}
@ -125,9 +137,9 @@ C4PropList * C4ExtraScriptHost::GetPropList()
/*--- C4DefScriptHost ---*/
bool C4DefScriptHost::Load(C4Group & g, const char * f, const char * l, C4LangStringTable * t)
bool C4DefScriptHost::Parse()
{
bool r = C4ScriptHost::Load(g, f, l, t);
bool r = C4ScriptHost::Parse();
assert(Def);
// Check category
@ -152,7 +164,7 @@ bool C4DefScriptHost::Load(C4Group & g, const char * f, const char * l, C4LangSt
case C4D_Living | C4D_Foreground: Plane = 1400; break;
case C4D_Object | C4D_Foreground: Plane = 1500; break;
default:
DebugLogF("WARNING: Def %s (%s) at %s has invalid category!", Def->GetName(), Def->id.ToString(), g.GetFullName().getData());
Warn("Def %s (%s) has invalid category", Def->GetName(), Def->id.ToString());
gotplane = false;
break;
}
@ -160,7 +172,7 @@ bool C4DefScriptHost::Load(C4Group & g, const char * f, const char * l, C4LangSt
}
if (!Def->GetPlane())
{
DebugLogF("WARNING: Def %s (%s) at %s has invalid Plane!", Def->GetName(), Def->id.ToString(), g.GetFullName().getData());
Warn("Def %s (%s) has invalid Plane", Def->GetName(), Def->id.ToString());
Def->SetProperty(P_Plane, C4VInt(1));
}
return r;
@ -176,24 +188,26 @@ C4GameScriptHost::~C4GameScriptHost() { }
bool C4GameScriptHost::Load(C4Group & g, const char * f, const char * l, C4LangStringTable * t)
{
assert(ScriptEngine.GetPropList());
ScenPrototype = C4PropList::NewScen(ScriptEngine.GetPropList());
ScenPropList = C4PropList::NewScen(ScenPrototype);
::ScriptEngine.RegisterGlobalConstant("Scenario", C4VPropList(ScenPropList));
C4PropListStatic * pScen = C4PropList::NewAnon(NULL/*ScenPrototype*/, NULL, ::Strings.RegString("Scenario"));
ScenPropList.SetPropList(pScen);
::ScriptEngine.RegisterGlobalConstant("Scenario", ScenPropList);
ScenPrototype.SetPropList(C4PropList::NewAnon(ScriptEngine.GetPropList(), pScen, &::Strings.P[P_Prototype]));
ScenPropList._getPropList()->SetProperty(P_Prototype, ScenPrototype);
Reg2List(&ScriptEngine);
return C4ScriptHost::Load(g, f, l, t);
}
void C4GameScriptHost::Clear()
{
delete ScenPropList; ScenPropList = 0;
delete ScenPrototype; ScenPrototype = 0;
ScenPropList.Set0();
ScenPrototype.Set0();
C4ScriptHost::Clear();
}
C4Value C4GameScriptHost::Call(const char *szFunction, C4AulParSet *Pars, bool fPassError)
{
// FIXME: Does fPassError make sense?
return ScenPropList->Call(szFunction, Pars);
return ScenPropList._getPropList()->Call(szFunction, Pars);
}
C4Value C4GameScriptHost::GRBroadcast(const char *szFunction, C4AulParSet *pPars, bool fPassError, bool fRejectTest)

View File

@ -33,7 +33,7 @@ class C4ScriptHost : public C4AulScript
public:
~C4ScriptHost();
bool Delete() { return false; } // do NOT delete this - it's just a class member!
public:
void Clear();
virtual bool Load(C4Group &hGroup, const char *szFilename,
const char *szLanguage, C4LangStringTable *pLocalTable);
@ -52,18 +52,31 @@ protected:
void RemoveLastBCC();
void ClearCode();
bool Preparse(); // preparse script; return if successfull
bool Parse(); // parse preparsed script; return if successfull
virtual bool Parse(); // parse preparsed script; return if successfull
virtual void UnLink(); // reset to unlinked state
int GetCodePos() const { return Code.size(); }
C4AulBCC *GetCodeByPos(int iPos) { return &Code[iPos]; }
C4AulBCC *GetLastCode() { return LastCode; }
std::list<C4ID> Includes; // include list
std::list<C4ID> Appends; // append list
bool ResolveIncludes(C4DefList *rDefs); // resolve includes
bool ResolveAppends(C4DefList *rDefs); // resolve appends
bool Resolving; // set while include-resolving, to catch circular includes
bool IncludesResolved;
StdStrBuf Script; // script
std::vector<C4AulBCC> Code;
std::vector<const char *> PosForCode;
C4AulBCC * LastCode;
C4ValueMapNames LocalNamed;
C4Set<C4Property> LocalValues;
friend class C4AulParse;
friend class C4AulScriptFunc;
friend class C4AulDebug;
friend class C4DirectExecScript;
};
// script host for System.ocg scripts
@ -84,7 +97,7 @@ class C4DefScriptHost: public C4ScriptHost
public:
C4DefScriptHost(C4Def * Def) : C4ScriptHost(), Def(Def) { }
virtual bool Load(C4Group &, const char *, const char *, C4LangStringTable *);
virtual bool Parse();
virtual C4PropList * GetPropList();
protected:
C4Def *Def; // owning def file
@ -99,11 +112,11 @@ public:
~C4GameScriptHost();
virtual bool Load(C4Group &, const char *, const char *, C4LangStringTable *);
void Clear();
virtual C4PropList * GetPropList() { return ScenPrototype; }
virtual C4PropList * GetPropList() { return ScenPrototype._getPropList(); }
C4Value Call(const char *szFunction, C4AulParSet *pPars=0, bool fPassError=false);
C4Value GRBroadcast(const char *szFunction, C4AulParSet *pPars = 0, bool fPassError=false, bool fRejectTest=false); // call function in scenario script and all goals/rules/environment objects
C4PropList * ScenPropList;
C4PropList * ScenPrototype;
C4Value ScenPropList;
C4Value ScenPrototype;
};
extern C4GameScriptHost GameScript;

View File

@ -59,7 +59,7 @@ public:
template <class U> C4RefCntPointer(const C4RefCntPointer<U> & r): p(r.p) { IncRef(); }
#ifdef HAVE_RVALUE_REF
// Move constructor
template <class U> C4RefCntPointer(const C4RefCntPointer<U> RREF r): p(r.p) { r.p = 0; }
template <class U> C4RefCntPointer(C4RefCntPointer<U> RREF r): p(r.p) { r.p = 0; }
// Move assignment
template <class U> C4RefCntPointer& operator = (C4RefCntPointer<U> RREF r)
{
@ -215,6 +215,18 @@ public:
}
return 0;
}
void Swap(C4Set<T> * S2)
{
unsigned int Capacity2 = S2->Capacity;
unsigned int Size2 = S2->Size;
T * Table2 = S2->Table;
S2->Capacity = Capacity;
S2->Size = Size;
S2->Table = Table;
Capacity = Capacity2;
Size = Size2;
Table = Table2;
}
};
template<> template<>

View File

@ -136,17 +136,14 @@ StdStrBuf C4Value::GetDataString(int depth) const
{
if (Data.PropList == ScriptEngine.GetPropList())
return StdStrBuf("Global");
C4Object * Obj = Data.PropList->GetObject();
if (Obj == Data.PropList)
return FormatString("Object(%d)", Obj->Number);
const C4PropListStatic * Def = Data.PropList->IsStatic();
if (Def)
return Def->GetDataString();
StdStrBuf DataString;
DataString = "{";
if (Data.PropList->GetObject())
{
if (Data.PropList->GetObject()->Status == C4OS_NORMAL)
DataString.AppendFormat("#%d, ", Data.PropList->GetObject()->Number);
else
DataString.AppendFormat("(#%d), ", Data.PropList->GetObject()->Number);
}
else if (Data.PropList->GetDef())
DataString.AppendFormat("%s, ", Data.PropList->GetDef()->id.ToString());
Data.PropList->AppendDataString(&DataString, ", ", depth);
DataString.AppendChar('}');
return DataString;
@ -210,7 +207,7 @@ void C4Value::Denumerate(class C4ValueNumbers * numbers)
Data.Array->Denumerate(numbers); break;
case C4V_PropList:
// objects and effects are denumerated via the main object list
if (!Data.PropList->IsNumbered() && !Data.PropList->IsDef())
if (!Data.PropList->IsNumbered() && !Data.PropList->IsStatic())
Data.PropList->Denumerate(numbers);
break;
case C4V_C4ObjectEnum:
@ -266,23 +263,17 @@ void C4Value::CompileFunc(StdCompiler *pComp, C4ValueNumbers * numbers)
case C4V_Bool:
cC4VID = 'b'; break;
case C4V_PropList:
if (getPropList()->IsDef())
if (getPropList()->IsStatic())
cC4VID = 'D';
else if (getPropList()->IsNumbered())
cC4VID = 'O';
else if (getPropList() == GameScript.ScenPropList)
cC4VID = 'c';
else if (getPropList() == GameScript.ScenPrototype)
cC4VID = 't';
else if (getPropList() == ScriptEngine.GetPropList())
cC4VID = 'g';
else
cC4VID = 'E';
break;
case C4V_Array:
cC4VID = 'E'; break;
case C4V_Function:
cC4VID = 'f'; break;
cC4VID = 'D'; break;
case C4V_String:
cC4VID = 's'; break;
default:
@ -330,21 +321,38 @@ void C4Value::CompileFunc(StdCompiler *pComp, C4ValueNumbers * numbers)
case 'D':
{
C4ID id;
if (!fCompiler)
id = getPropList()->GetDef()->id;
pComp->Value(id);
if (fCompiler)
if (!pComp->isCompiler())
{
C4PropList * p = Definitions.ID2Def(id);
if (!p)
C4PropList * p = getPropList();
if (getFunction())
{
Set0();
pComp->Warn("ERROR: Definition %s is missing.", id.ToString());
p = Data.Fn->Owner->GetPropList();
assert(p);
assert(p->GetFunc(Data.Fn->GetName()) == Data.Fn);
assert(p->IsStatic());
}
else
p->IsStatic()->RefCompileFunc(pComp, numbers);
if (getFunction())
{
SetPropList(p);
pComp->Separator(StdCompiler::SEP_PART);
StdStrBuf s; s.Ref(Data.Fn->GetName());
pComp->Value(mkParAdapt(s, StdCompiler::RCT_ID));
}
}
else
{
StdStrBuf s;
pComp->Value(mkParAdapt(s, StdCompiler::RCT_ID));
if (!::ScriptEngine.GetGlobalConstant(s.getData(), this))
pComp->excNotFound("static proplist %s", s.getData());
while(pComp->Separator(StdCompiler::SEP_PART))
{
C4PropList * p = getPropList();
if (!p)
pComp->excNotFound("static proplist is not a proplist anymore", s.getData());
pComp->Value(mkParAdapt(s, StdCompiler::RCT_ID));
if (!p->GetPropertyByS(::Strings.RegString(s), this))
pComp->excNotFound("static proplist %s", s.getData());
}
}
break;
@ -361,14 +369,15 @@ void C4Value::CompileFunc(StdCompiler *pComp, C4ValueNumbers * numbers)
break;
}
// FIXME: remove these three once Game.txt were re-saved with current version
case 'c':
if (fCompiler)
SetPropList(GameScript.ScenPropList);
Set(GameScript.ScenPropList);
break;
case 't':
if (fCompiler)
SetPropList(GameScript.ScenPrototype);
Set(GameScript.ScenPrototype);
break;
case 'g':
@ -383,34 +392,6 @@ void C4Value::CompileFunc(StdCompiler *pComp, C4ValueNumbers * numbers)
// doesn't have a value, so nothing to store
break;
case 'f':
{
C4Value Owner;
if (!fCompiler)
{
Owner.SetPropList(Data.Fn->Owner->GetPropList());
assert(Owner._getPropList() && Owner._getPropList()->GetFunc(Data.Fn->GetName()) == Data.Fn);
}
pComp->Value(mkParAdapt(Owner, numbers));
pComp->Separator(StdCompiler::SEP_PART);
StdStrBuf s;
if (!fCompiler)
s = Data.Fn->GetName();
pComp->Value(s);
if (fCompiler)
{
// Owner was a definition or singleton, so shouldn't have to be denumerated
if (!Owner.getPropList())
{
Set0();
pComp->Warn("ERROR: Owner of function %s is missing.", s.getData());
}
else
SetFunction(Owner._getPropList()->GetFunc(s.getData()));
}
break;
}
default:
// shouldn't happen
pComp->excCorrupt("unknown C4Value type tag '%c'", cC4VID);
@ -508,30 +489,20 @@ bool C4Value::operator == (const C4Value& Value2) const
{
case C4V_Nil:
assert(!Data);
return Value2.Type == Type;
return Type == Value2.Type;
case C4V_Int:
case C4V_Bool:
return (Value2.Type == C4V_Int || Value2.Type == C4V_Bool) &&
Data == Value2.Data;
Data.Int == Value2.Data.Int;
case C4V_PropList:
if (Value2.Type == C4V_PropList)
{
// Compare as equal if and only if the proplists are indistinguishable
// If one or both are mutable, they have to be the same
// otherwise, they have to have the same contents
if (Data.PropList == Value2.Data.PropList) return true;
if (!Data.PropList->IsFrozen() || !Value2.Data.PropList->IsFrozen()) return false;
return (*Data.PropList == *Value2.Data.PropList);
}
return false;
return Type == Value2.Type && *Data.PropList == *Value2.Data.PropList;
case C4V_String:
return Type == Value2.Type && Data.Str == Value2.Data.Str;
case C4V_Array:
return Type == Value2.Type &&
(Data.Array == Value2.Data.Array || *(Data.Array) == *(Value2.Data.Array));
case C4V_Function:
return Type == Value2.Type &&
Data == Value2.Data;
return Type == Value2.Type && Data.Fn == Value2.Data.Fn;
default:
assert(!"Unexpected C4Value type (denumeration missing?)");
return Data == Value2.Data;

View File

@ -208,8 +208,6 @@ protected:
// data type
C4V_Type Type;
C4Value(C4V_Data nData, C4V_Type nType): Data(nData), NextRef(NULL)
{ Type = (nData || IsNullableType(nType) ? nType : C4V_Nil); AddDataRef(); }
void Set(C4V_Data nData, C4V_Type nType);

Some files were not shown because too many files have changed in this diff Show More