[[http://www.siedler-games.de|{{:sg-link.jpg|}}]]
====== Förster ======
Der Förster an sich ist so angelegt, das er lustig Bäume vor sich hinplanzt.
Man kann ihn gut gebrauchen, wenn auf einer Map viele "Wüsten-" oder Steppengebiete sind.
Er schafft jedenfalls eine unerschöpflichen Vorrat an der Resource **Holz**.
Man muss auf der Map lediglich eine Entity mit Namen: **"gaertner1"** setzen und eine ScriptEntity mit Namen: **"WaldEntity"**. Und Dario darf auch nicht fehlen **"dario"**.
function DarioIsNeargaertner1()
if IsNear(GetEntityId("dario"), GetEntityId("gaertner1"), 1000) then
EndJob(DarioIsNeargaertner1ID)
_OP_Forests_addTreeGrowth()
MyForest = _OP_Forests_setupForest(GetPosition("WaldEntity"), 500, 1800, "gaertner1")
end
end
Aufgerufen wird das Ganze mit
DarioIsNeargaertner1ID=StartSimpleJob("DarioIsNeargaertner1");
entweder in der **FirstMapAction** oder als "Belohnung" in einem **Briefing.Finished**.
Falls der Förster pausieren soll, wenn 20 Bäume gepflanzt wurden, kann folgendes verwendet werden:
function PauseForester()
if _OP_Forests_getNumberOfExistingSeededTrees(MyForest) >= 20 then
_OP_Forests_disableForester(MyForest)
else
_OP_Forests_enableForester(MyForest)
end
end
Die Bäume wachsen aber trotzdem weiter.
====Code====
Der folgende Code wird benötigt, damit der Förster funktioniert:
--########################################################################
--###
--### Forest Script
--### Created by Opeter
--### Updated by Old McDonald
--###
--the forests table
_OP_Forests = {};
--set it local for better handling (the name is too long :))
local f = _OP_Forests;
--here you can add some tree entities
--don't forget to add at least one group of trees
f.Grow = {
};
--handling triggers...
--some dummy functions
function _OP_Forests_growTrees(_index)
return _OP_Forests:growTrees(_index);
end
function _OP_Forests_plantTrees(_index)
return _OP_Forests:plantTrees(_index);
end
function _OP_Forests_moveForester(_index)
return _OP_Forests:moveForester(_index);
end
--########################################################################
--###
--### Forest Functions
--###
--these two functions create forests
function f:createForest(_position, _distance, _range)
local forest = {};
local funcAdd = function( _n1, _n2 ) return _n1 + _n2; end;
local funcSub = function( _n1, _n2 ) return _n1 - _n2; end;
self:createSegment( forest, _position, _distance, _range, funcAdd, funcAdd );
self:createSegment( forest, _position, _distance, _range, funcSub, funcAdd );
self:createSegment( forest, _position, _distance, _range, funcAdd, funcSub );
self:createSegment( forest, _position, _distance, _range, funcSub, funcSub );
return forest;
end
function f:createSegment(_forest, _position, _distance, _range, _opX, _opY)
local distance2 = math.sqrt( _distance * _distance - (_distance/2) * (_distance / 2) );
local forestPos = {
X = _position.X,
Y = _position.Y
};
local x = 0;
for y = 0, _range / distance2, 1 do
while self:getRange(_position, forestPos) <= _range do
local entry = {
name = string.format( "_OP_Tree%d%d", table.getn( self ) + 1, table.getn( _forest ) + 1 ),
status = 0,
type = 0
};
entry.position = {
X = forestPos.X + math.random(100) - 50,
Y = forestPos.Y + math.random(100) - 50
};
entry.posF = {
X = 0,
Y = 0
};
if self:testPos(entry.position) then
entry.ID = CreateEntity( 1, Entities.XD_ScriptEntity, entry.position, entry.name );
table.insert( _forest, entry );
end
forestPos.X = _opX( forestPos.X, distance2 );
end
forestPos.X = _opX( _position.X, _distance / 2 * x );
forestPos.Y = _opY( forestPos.Y, distance2 );
x = 1 - x;
end
end
--this function let the trees grow
function f:growTrees(_index)
local forest = self[_index];
if forest == nil then
--return
return true;
elseif IsDestroyed(forest.forester) then
--destroy jobs
if forest.plantTreesJobId ~= 0 then
Trigger.UnrequestTrigger(forest.plantTreesJobId);
else
Trigger.UnrequestTrigger(forest.moveForesterJobId);
end
Trigger.UnrequestTrigger(forest.growTreesJobId);
--delete forest table
self[_index] = nil;
--return
return true;
end
forest.counterGrow = forest.counterGrow - 1;
if forest.counterGrow == 0 then
for i = 1, table.getn(forest), 1 do
local doFlag, eName = true, forest[i].name;
local eResource = 0;
if forest[i].status > 1 and forest[i].status < table.getn(self.Grow[forest[i].type]) + 1 then
eResource = Logic.GetResourceDoodadGoodAmount(GetEntityId(eName));
if eResource > 0 then
doFlag = false;
end
if Logic.GetEntitiesInArea( 0, forest[i].position.X, forest[i].position.Y, 150, 1 ) > 0 then
doFlag = false;
end
local newEntityType = self.Grow[forest[i].type][forest[i].status];
if newEntityType and not IsDead(eName) and math.random(forest.ProbabilityOfGrowing) == 1 and doFlag then
forest[i].status = forest[i].status + 1;
ReplaceEntity(eName, newEntityType);
end
end
end
forest.counterGrow = 4;
end
end
--this function controls the planting of trees
function f:plantTrees(_index)
local forest = self[_index];
if forest == nil then
--return
return true;
elseif IsDestroyed(forest.forester) then
--destroy jobs
if forest.plantTreesJobId ~= 0 then
Trigger.UnrequestTrigger(forest.plantTreesJobId);
else
Trigger.UnrequestTrigger(forest.moveForesterJobId);
end
Trigger.UnrequestTrigger(forest.growTreesJobId);
--delete forest table
self[_index] = nil;
--return
return true;
elseif not forest.Enabled then
return false;
end
forest.WaitTime = (forest.WaitTime or 0) + 1;
if forest.WaitTime < forest.Delay then
--delay not reached
return false;
end
forest.counterForester = forest.counterForester - 1;
if forest.counterForester <= 0 then
for i = 1, table.getn(forest), 1 do
local eName, ePos = forest[i].name, { X = forest[i].position.X, Y = forest[i].position.Y };
if forest[i].status == 1 then
if forest.OKTree then
if Logic.GetEntitiesInArea(0, ePos.X, ePos.Y, 100, 1) == 0 then
forest.nextTree = true;
if ReplaceEntity(eName, Entities.XD_Bush4) > 0 then
forest[i].status = 2;
forest[i].type = math.random( table.getn( self.Grow ) );
else
forest[i].status = -1;
end
else
if forest[i].posF.X == GetPosition(forest.forester).X and forest[i].posF.Y == GetPosition(forest.forester).Y then
forest[i].status = 0;
forest.nextTree = true;
else
forest[i].posF.X = GetPosition(forest.forester).X;
forest[i].posF.Y = GetPosition(forest.forester).Y;
end
forest.counterForester = 1;
end
else
forest[i].status = 0;
forest.nextTree = true;
forest.counterForester = 1;
end
end
if forest[i].status > 1 and IsDead(eName) then
forest[i].status = 0;
self:cleanUp(ePos, 200);
CreateEntity(1, Entities.XD_ScriptEntity, ePos, eName);
end
end
if forest.counterForester == 0 then
forest.counterForester = 2;
end
if not forest.nextTree then
return;
end
local array = {};
for i = 1, table.getn(forest), 1 do
if forest[i].status == 0 then
table.insert( array, i );
end
end
if table.getn( array ) == 0 then
forest.counterForester = 5;
return;
end
local i = array[math.random(table.getn(array))];
local eName = forest[i].name;
local posF = {
X = forest[i].position.X - 1,
Y = forest[i].position.Y - 1
};
forest.nextTree = false;
forest[i].status = 1;
forest.NTree = GetEntityId(eName);
Move(forest.forester, posF);
forest[i].posF = {
X = GetPosition(forest.forester).X,
Y = GetPosition(forest.forester).Y
};
forest.OKTree = true;
forest.foresterPos = forest[i].posF;
forest.oldForesterPos = forest[i].posF;
forest.moveForesterJobId = Trigger.RequestTrigger( Events.LOGIC_EVENT_EVERY_SECOND, nil, "_OP_Forests_moveForester", 1, {}, {_index} );
forest.plantTreesJobId = 0;
return true;
end
end
--this function controls whether the forester still walks
function f:moveForester(_index)
local forest = self[_index];
if forest == nil then
--return
return true;
elseif IsDestroyed(forest.forester) then
--destroy jobs
if forest.plantTreesJobId ~= 0 then
Trigger.UnrequestTrigger(forest.plantTreesJobId);
else
Trigger.UnrequestTrigger(forest.moveForesterJobId);
end
Trigger.UnrequestTrigger(forest.growTreesJobId);
--delete forest table
self[_index] = nil;
--return
return true;
elseif not forest.Enabled then
return false;
end
if IsNear(forest.forester, forest.NTree, 50) then
Move(forest.forester, forest.oldForesterPos);
forest.plantTreesJobId = Trigger.RequestTrigger( Events.LOGIC_EVENT_EVERY_SECOND, nil, "_OP_Forests_plantTrees", 1, {}, {_index} );
forest.moveForesterJobId = 0;
forest.counterForester = 3;
return true;
elseif forest.foresterPos.X == GetPosition(forest.forester).X and forest.foresterPos.Y == GetPosition(forest.forester).Y then
forest.OKTree = false;
forest.plantTreesJobId = Trigger.RequestTrigger( Events.LOGIC_EVENT_EVERY_SECOND, nil, "_OP_Forests_plantTrees", 1, {}, {_index} );
forest.moveForesterJobId = 0;
forest.counterForester = 1;
forest.WaitTime = 0;
return true;
else
forest.oldForesterPos = forest.foresterPos;
forest.foresterPos = GetPosition(forest.forester);
end
end
--########################################################################
--###
--### Utility Functions
--###
function f:getRange(_pos1, _pos2)
local x, y = _pos2.X - _pos1.X, _pos2.Y - _pos1.Y;
return math.sqrt( x * x + y * y );
end
function f:testPos(_pos)
if Logic.GetEntitiesInArea( Entities.XD_ScriptEntity, _pos.X, _pos.Y, 200, 1 ) == 0 then
return true;
end
end
function f:cleanUp(_position, _range)
local data = { Logic.GetEntitiesInArea( Entities.XD_TreeStump1, _position.X, _position.Y, _range, 16 ) };
for i = 1, table.remove(data, 1), 1 do
DestroyEntity(data[i]);
end
end
--########################################################################
--###
--### Comfort Functions
--###
--comfort wrapper
function _OP_Forests_setupForest(_position, _distance, _range, _forester, _delay, _probabilityOfGrowing)
return _OP_Forests:setupForest(_position, _distance, _range, _forester, _delay, _probabilityOfGrowing);
end
--this comfort function creates a new forest, setups the values of the indices in the forest table and starts the jobs
function f:setupForest(_position, _distance, _range, _forester, _delay, _probabilityOfGrowing)
assert(table.getn(self.Grow) > 0, "at least one growth plan must exist");
assert(IsValid(_forester), "the forester must be alive");
local forest = self:createForest(_position, _distance, _range);
forest.counterForester = 2;
forest.counterGrow = 4;
forest.NTree = 0;
forest.nextTree = true;
forest.OKTree = true;
forest.foresterPos = {};
forest.oldForesterPos = {};
forest.forester = _forester;
forest.moveForesterJobId = 0;
forest.Enabled = true;
forest.Delay = forest.Delay or 0;
forest.ProbabilityOfGrowing = _probabilityOfGrowing or 5;
local indexPos = table.getn(self) + 1;
table.insert(self, forest);
forest.plantTreesJobId = Trigger.RequestTrigger(Events.LOGIC_EVENT_EVERY_SECOND, nil, "_OP_Forests_plantTrees", 1, {}, {indexPos});
forest.growTreesJobId = Trigger.RequestTrigger(Events.LOGIC_EVENT_EVERY_SECOND, nil, "_OP_Forests_growTrees", 1, {}, {indexPos});
return forest;
end
--comfort wrapper
function _OP_Forests_addTreeGrowth( _description )
return _OP_Forests:addTreeGrowth( _description );
end
--this function adds a new tree growth "tree". if _description is nil, the standard table will be used
function f:addTreeGrowth( _description )
if _description == nil then
_description = {
Entities.XD_Pine3,
Entities.XD_Pine4,
Entities.XD_Pine6,
Entities.XD_Pine2
};
end
assert(type(_description) == "table", "_description must be a table");
assert(table.getn(_description) > 0, "one tree type must exist");
table.insert(_description, 1, nil);
_description.n = table.getn(_description);
table.insert(self.Grow, _description);
end
--comfort wrapper
function _OP_Forests_disableForester( _forest )
return _OP_Forests:disableForester(_forest);
end
--this function disables the forester
function f:disableForester( _forest )
_forest.Enabled = false;
end
--comfort wrapper
function _OP_Forests_enableForester( _forest )
return _OP_Forests:enableForester(_forest);
end
--this function enables the forester
function f:enableForester( _forest )
_forest.Enabled = true;
end
function _OP_Forests_getNumberOfExistingSeededTrees( _forest )
return _OP_Forests:getNumberOfExistingSeededTrees(_forest);
end
function _OP_Forests:getNumberOfExistingSeededTrees( _forest )
local n = 0;
for i = 1, table.getn(_forest), 1 do
if _forest[i].status > 1 and not IsDead(_forest[i].name) then
n = n + 1;
end
end
return n;
end