[[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