Bauernhof mal anders.

Habe mir die Zeit genommen um einen Film im Spiel zu schreiben. Er ist zwar noch nicht gebrauchsfertig, aber da es im Moment wegen SpeicherProblemen bei Delayjobs so wie so nicht eingebaut werden kann, versuche ich einen Beitrag hier bei Wiki zu schreiben um das mal zu testen.

Ein Bauer baut sich eine Parzelle und bestellt diese. Zum Schuß kommt dann ein Händler und holt die Ware ab. Anschließend wird der Bauer bezahlt. Hört sich einfach an, aber anschauen lohnt sich sicher. Soll in der Endversion einstellbar sein ob und wieviel er bekommt. Als Mapschreiber könnte man das so benutzen, daß als Belohnung für irgendetwas der Bauernhof erlaubt wird. Natürlich muß dann der Platz vorhanden sein.

Aufgerufen wird der Hof einfach mit:

StartDelayFunc(BauernHof, Erstehungspunkt, Winkel) -- Soll noch Gold kommen. Geht aber noch nicht.

BauernHof heißt die Funktion.
Erstehungspunkt: Da wo der Hof hin soll.
Winkel: in welchem Winkel der Hof stehen soll 0-360°.

Sieht putzig aus. Ich empfehle aber zunächst die Variable lSchnell auf true zu lassen. Der erste Durchlauf dauert sonst etwa 30 Minuten. Diesen Code einfach in eine leere Karte, und ab die Post.

Habe übrigens viel gelernt wärend ich dies schrieb.

Als komplette Karte ist es hier leereversuchskarte.zip

Habe den Hof noch nicht in die Mitte gestellt. Drückt einfach auf den Serf oben.

Und daß mir ja niemand guckt was der Serf hinter dem Bauernhof macht.

--------------------------------------------------------------------------------
-- MapName: Bauernhof--
-- Author: Robert--
--------------------------------------------------------------------------------
 
-- Include main function
Script.Load( Folders.MapTools.."Main.lua" )
IncludeGlobals("MapEditorTools")
lSchnell=true
--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-- This function is called from main script to initialize the diplomacy states
function InitDiplomacy()
end
 
 
--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-- This function is called from main script to init all resources for player(s)
function InitResources()
    -- set some resources
    AddGold  (1000)
    AddSulfur(2000)
    AddIron  (3000)
    AddWood  (4000)	
    AddStone (5000)	
    AddClay  (0)	
end
 
--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-- This function is called to setup Technology states on mission start
function InitTechnologies()
end
 
--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-- This function is called on game start and after save game is loaded, setup your weather gfx
-- sets here
function InitWeatherGfxSets()
	SetupNormalWeatherGfxSet()
end
 
--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-- This function is called on game start you should setup your weather periods here
function InitWeather()
	AddPeriodicSummer(10)
end
 
--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-- This function is called on game start and after save game to initialize player colors
function InitPlayerColorMapping()
end
 
--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-- This function is called on game start after all initialization is done
function FirstMapAction()
 
	local VictoryConditionType = 1
 
	if VictoryConditionType == 1 then
		MapEditor_SetupResourceVictoryCondition()	
	elseif VictoryConditionType == 2 then
		MapEditor_SetupDestroyVictoryCondition(2)
	end
 
	-- Level 0 is deactivated...ignore
	MapEditor_SetupAI(2, 0, 0, 0, "", 0, 0)
	MapEditor_SetupAI(3, 0, 0, 0, "", 0, 0)
	MapEditor_SetupAI(4, 0, 0, 0, "", 0, 0)
	MapEditor_SetupAI(5, 0, 0, 0, "", 0, 0)
	MapEditor_SetupAI(6, 0, 0, 0, "", 0, 0)
	MapEditor_SetupAI(7, 0, 0, 0, "", 0, 0)
	MapEditor_SetupAI(8, 0, 0, 0, "", 0, 0)
	Tools.ExploreArea( -1, -1, 900 )
	MapEditor_CreateHQDefeatCondition()
	if lSchnell then
		SpeedUpGame()
		SpeedUpGame()
		SpeedUpGame()
		SpeedUpGame()
		SpeedUpGame()
	end
	tListe={}
	StartDelayFunc(BauernHof,{X=9500, Y=9500},45,55555)
end
-- Quest data
MapEditor_QuestTitle				= ""
MapEditor_QuestDescription 	= ""
 
function BauernHof(_pPos,_nAngle,_gold)
	if _gold== nil or not (type(_gold) == "number") then
		_gold=0
	end
	tHeu = {}
	nBHofID=Logic.CreateEntity( Entities.PB_Farm2,_pPos.X,_pPos.Y,_nAngle, 2 )
	nBHofWinkel=Logic.GetEntityOrientation(nBHofID)
	nSin=math.sin((math.rad(Logic.GetEntityOrientation(nBHofID))))
	nCos=math.cos((math.rad(Logic.GetEntityOrientation(nBHofID))))
	nDeltaY1=-60*nSin  --- Abstand Y für kleine Pflanzen
	nDeltaX1=-60*nCos   --- Abstand X für kleine Pflanzen
	nDeltaY2=-300*nSin   --- Abstand Y für große Pflanzen
	nDeltaX2=-300*nCos   --- Abstand X für große Pflanzen
	nAbstandX=-nCos*1000
	nAbstandY=-nSin*1000
	tRelPos=RelVonPos(nBHofID,{ rechts = 300, zur = 950 })
	nBauer=CreateEntity (1,Entities.PU_Serf,RelVonPos(nBHofID,{rechts=-500,zur=1200}),"Bauer")
	CreateEntity (1,Entities.XD_ScriptEntity,RelVonPos(nBHofID,{rechts=0,zur=500}),"RuhePunkt")
	DelayShort(3)
	aPflanzenKlein={}
	aPflanzenGross={}
	-- Jetzt werden die Positionen der Pflanzen in ein Table geschreiben, damit man es nachher nicht jedesmal ausrechnen muß
	for l = 0,20,3 do
		for k = 0,20,3 do
			for i = 0,2 do
				for j= 0,2 do
					table.insert( aPflanzenKlein,{	X=tRelPos.X+(k+i)*nDeltaX1+(l+j)*nDeltaY1,
													Y=tRelPos.Y+(k+i)*nDeltaY1-(l+j)*nDeltaX1} )
				end
			end
		end
	end
	-- Da die Pflanzen, die ich brauchte zwei verschiedene Größen haben muß das zweimal gemacht werden
	for j= 0,4 do
		for i = 0,4 do
			table.insert( aPflanzenGross,{	X=tRelPos.X+i*nDeltaX2+j*nDeltaY2,
											Y=tRelPos.Y+i*nDeltaY2-j*nDeltaX2} )
		end
	end
	tIron={}
	-- Hier werden die Positionen der einzelnen Gitter festgelegt und in das table tIron gepackt
	entry = {
			entity	= Entities.XD_IronGrid4,
			angle     = 0,	
			diffPosition={ rechts = 375, zur = 700 }}	-- relativ zum Bauernhof
	table.insert(tIron, entry)
	entry = {
			entity	= Entities.XD_IronGrid4,
			angle     = 0,
			diffPosition={ rechts = 375, zur = 1125 }}		
	table.insert(tIron,entry)
	entry = {
			entity	= Entities.XD_IronGrid4,
			angle     = 0,
			diffPosition={ rechts = 375, zur = 1575 }}		
 	table.insert(tIron,entry)
	entry = {
			entity	= Entities.XD_IronGrid4,
			angle     = 0,
			diffPosition={ rechts = 375, zur = 2025 }}		
 	table.insert(tIron,entry)  --Drehung
	entry = {
			entity	= Entities.XD_IronGrid4,
			angle     = 90,
			diffPosition={ rechts = 150, zur = 2250 }}		
 	table.insert(tIron,entry)
	entry = {
			entity	= Entities.XD_IronGrid4,
			angle     = 90,
			diffPosition={ rechts = -300, zur = 2250 }}		
 	table.insert(tIron,entry)
	entry = {
			entity	= Entities.XD_IronGrid4,
			angle     = 90,
			diffPosition={ rechts = -750, zur = 2250 }}		
 	table.insert(tIron,entry) -- Drehung
	entry = {
			entity	= Entities.XD_IronGrid4,
			angle     = 180,
			diffPosition={ rechts = -975, zur = 2025 }}		
 	table.insert(tIron,entry) 
	entry = {
			entity	= Entities.XD_IronGrid4,
			angle     = 180,
			diffPosition={ rechts = -975, zur = 1575 }}		
 	table.insert(tIron,entry) 
	entry = {
			entity	= Entities.XD_IronGrid4,
			angle     = 180,
			diffPosition={ rechts = -975, zur = 1125 }}		
 	table.insert(tIron,entry) 
	entry = {
			entity	= Entities.XD_IronGrid4,
			angle     = 180,
			diffPosition={ rechts = -975, zur = 700 }}		
 	table.insert(tIron,entry) 
	entry = {
			entity	= Entities.XD_MiscBank1,  -- noch ne Bank rein
			angle     = 180,
			diffPosition={ rechts = 300, zur = 700 }}		
 	table.insert(tIron,entry) 
	entry = {
			entity	= Entities.XD_MiscTable1, -- ein Tisch zum essen
			angle     = 90,
			diffPosition={ rechts = 150, zur = 700 }}		
 	table.insert(tIron,entry) 
	        entry = {
					entity	= Entities.XD_LargeCampFire, -- ein Lagerfeuer zum aufwärmen
					angle     = 270,
					diffPosition={ rechts = -550, zur = 700 }}		
 	table.insert(tIron,entry) 
	local zaehler = table.getn(tIron)  -- Ich wußte zwar nachher die Anzahl, nur wenn ich es anders machen wollte, 
	local tEntityPos                   -- brauchte ich hier nichts mehr zu ändern deshalb: table.getn(tIron)
	local bauerPos
	for i = 1, table.getn(tIron) do  -- je nachdem woh das Gitter stehl, muß der Bauer ja auch an eine andere Position
		tEntityPos=RelVonPos(nBHofID,tIron[i].diffPosition)
		if tIron[i].angle == 0 then  -- diese Position ist auch abhängig vom relativen Winkel zum Bauernhof
			bauerPos=RechtsVonPos(nBHofID,-100,tEntityPos)
		elseif tIron[i].angle == 90 then
			bauerPos=ZurEntity(nBHofID,-100,tEntityPos)
		elseif tIron[i].angle == 180 then
			bauerPos=RechtsVonPos(nBHofID,-100,tEntityPos)
		elseif tIron[i].angle == 270 then
			bauerPos=RechtsVonPos(nBHofID,100,tEntityPos)
		else
			return
		end
		Laufe("Bauer",bauerPos)  -- damit überwache ich, ob der Bauer noch läuft
		DrehEntity("Bauer",tEntityPos) -- Drehen, damit er auch in Richtung Eisen klopft
		Logic.SetTaskList( GetEntityId("Bauer"), TaskLists.TL_SERF_BUILD  )  -- klopfen
		Logic.CreateEffect( GGL_Effects.FXBuildingSmoke,tEntityPos.X ,tEntityPos.Y , 4);  -- Rauch
		Logic.CreateEffect( GGL_Effects.FXBuildingSmokeLarge,tEntityPos.X ,tEntityPos.Y , 4);
		Delay(3)
		Logic.CreateEffect( GGL_Effects.FXBuildingSmoke,tEntityPos.X ,tEntityPos.Y , 4);
		Logic.CreateEffect( GGL_Effects.FXBuildingSmokeMedium,tEntityPos.X ,tEntityPos.Y , 4);
		Delay(3)
		Logic.CreateEffect( GGL_Effects.FXBuildingSmoke,tEntityPos.X ,tEntityPos.Y , 4);
		Delay(3)
		if tIron[i].angle == 0 then
			bauerPos=RechtsVonPos(nBHofID,-200,tEntityPos)
		elseif tIron[i].angle == 90 then
			bauerPos=ZurEntity(nBHofID,-280,tEntityPos)
		elseif tIron[i].angle == 180 then
			bauerPos=RechtsVonPos(nBHofID,-280,tEntityPos)
		elseif tIron[i].angle == 270 then
			bauerPos=RechtsVonPos(nBHofID,280,tEntityPos)
		else   -- darf es nicht geben, also ende
			return
		end
		SetPosition(GetEntityId("Bauer"),bauerPos)  -- Bauer wegstellen, sonst hängt er fest wenn
		Logic.CreateEntity( tIron[i].entity, tEntityPos.X, tEntityPos.Y,nBHofWinkel+tIron[i].angle, 2 )
		-- wie vor das Gitter erzeugt wird
	end
	while true do
		DelayShort(3)
		PPause()  -- pinkeln gehen (hinter dem Bauernhof)
		Laufe("Bauer","RuhePunkt") -- kleine Pause
		Delay(5)
		for i = 5, table.getn(aPflanzenKlein),9 do  -- jetzt kommt das oben gemachte table zum Zug
			Laufe("Bauer",aPflanzenKlein[i]) -- Der Bauer läuft jetzt immer zu einer Position in der Mitte von 9 Pflanzen
			for k = 1, 9 do
				if not (k == 5) then  -- 5 muß augeklammert werden, da steht er drauf
					DrehEntity("Bauer",aPflanzenKlein[k+i-5]) -- er dreht sich zu einer Pflanzen-Position
					Logic.SetTaskList( GetEntityId("Bauer"), TaskLists.TL_SERF_EXTRACT_RESOURCE  )
					-- jetzt hackt er 
					Delay(1)			
				end
				Logic.CreateEntity( 297, aPflanzenKlein[k+i-5].X, aPflanzenKlein[k+i-5].Y  ) -- und ein haufen dreck entsteht
				_OP_CleanUp(aPflanzenKlein[k+i-5], 10,Entities.XD_PlantMoor2)-- die Pflanzen dort werden entfernt
			end
		end
		Bewaessern(aPflanzenKlein)  --fürs Bewässern eine eigene Funktion
		Move("Bauer","RuhePunkt") -- Pause
		Pflanzen(289)  -- jetzt wächst alles langsam
		Pflanzen(301)  -- hätte hier die Entity-Namen reinschreiben sollen
		Pflanzen(300)  -- für jede Pflanze Funktion laufen lassen
		Pflanzen(312)
		for i = 1 ,table.getn(aPflanzenKlein) do
			_OP_CleanUp(aPflanzenKlein[i], 1,300) --- letzte kleine Pflanzen entfernen, da ich das nicht in der Funktion gemacht habe
		end
		Pflanzen(315)
		PPause()  -- nochmal pinkeln
		StartDelayFunc(Salesman)  -- der Händler kommt
		for i = 5, table.getn(aPflanzenKlein),9 do  -- hier erntet der Bauer nach dem gleichen Schema wie das Hacken oben
			Laufe("Bauer",aPflanzenKlein[i])
			for k = 1, 9 do
				if not (k == 5) then
					DrehEntity("Bauer",aPflanzenKlein[k+i-5])
					Logic.SetTaskList( GetEntityId("Bauer"), TaskLists.TL_SERF_EXTRACT_WOOD  )
					Delay(1)			
				end
				Logic.CreateEntity( Entities.XD_PlantMoor2, aPflanzenKlein[k+i-5].X, aPflanzenKlein[k+i-5].Y  )
			end
				_OP_CleanUp(aPflanzenKlein[i], 100,315)
			if ((i-3) / 7) == math.floor ((i-3) / 7) and i > 5 then
				table.insert(tHeu,Logic.CreateEntity( Entities.XD_MiscHaybale1, aPflanzenKlein[i].X, aPflanzenKlein[i].Y  ))
				-- nur hier kommen noch Heuballen hin, wenn er eine Reihe fertig hat.
				SetPosition(GetEntityId("Bauer"),ZurEntity(nBHofID,-200,GetPosition("Bauer")))
			end
		end  
		while IsAlive("Haendler") do
			Delay(1)
		end
	end
end
 
 
function Salesman()   --- Das ist jetzt die Arbeit des Händlers
	local nWieOft=0
	CreateEntity(2, Entities.PU_Travelling_Salesman, ZurEntity(nBHofID,-800), "Haendler"  )
	-- erstmal hinter dem Hof enstehen
	while true do -- Mach die Schleife bis ich Stop sage
		while table.getn(tHeu) == 0 do -- Programm warted bis es Heuballen gibt
			Delay(1)
		end
		Laufe("Haendler",GetPosition(tHeu[1]) ) -- Händer läuft zum Heuballen
		DestroyEntity(tHeu[1]) -- Heuballen verschwindet
		tHeu={}
		nWieOft=nWieOft+1
		Laufe("Haendler", ZurEntity(nBHofID,-800) )-- Händer läuft hinter den Hof
		if nWieOft == 7 then -- Wenn alle Ballen geholt sind
			DestroyEntity("Haendler") -- Händler mit wagen weg
			CreateEntity(2, Entities.CU_Trader, ZurEntity(nBHofID,-800), "Haendler"  )-- Händler ohne Wagen her
			DelayShort(3)      
			Laufe("Haendler", RechtsVonPos(nBHofID,500) ) -- laufe vor den Hof
			CreateEntity(1, Entities.XD_MiscTrolley1, ZurEntity(nBHofID,-800), "Karren"  )
			-- Irgendwo muß der Karren ja sein
			Laufe("Bauer","RuhePunkt") --Bauer läuft zum Händler
			Laufe("Haendler", "RuhePunkt" )-- Händler läuft zum Bauern
			Sound.PlayGUISound(Sounds.VoicesMentor_HAPPY_Farmer) 
			DelayShort(25)-- jetzt wäre der Zeitpunkt für eine Bezahlung
			--Sound.PlayGUISound(Sounds.VoicesMentor_INFO_Payday_rnd_01)
			Delay(5)
			Laufe("Haendler", ZurEntity(nBHofID,-800) )
			DestroyEntity("Haendler")
			DestroyEntity("Karren")
			return
		end
	end
end
function Pflanzen(nWas)
	local aListe={}  -- hier kommt rein welche Position noch keine neue Pflanze hat
	if nWas==289 then  -- es wird getestet ob es eine kleine oder Große Pflanze ist
		nWas2=297  -- alte Pflanze merken
		lGross=false
	elseif nWas==301 then
		nWas2=289
		lGross=false
	elseif nWas==300 then
		nWas2=301
		lGross=false
	elseif nWas==312 then
		nWas2=300
		lGross=true
	elseif nWas==315 then
		nWas2=312
		lGross=true
	end
 
	if lGross then  -- ist es eine große Pflanze ?
		for i=1,table.getn(aPflanzenGross) do -- So lange noch nicht alle gepflanzt sind
			table.insert( aListe,aPflanzenGross[i] ) -- Table wird mit den Positionen der großen Pflanzen gefüllt
		end
		while table.getn(aListe) > 0 do -- So lange noch nicht alle gepflanzt sind
			nNummer=GetRandom(table.getn(aListe)) -- Durch Zufall einen aus der Liste auswählen
			if nNummer==0 then
				nNummer=1
			end
			_OP_CleanUp(aListe[nNummer], 1,nWas2)-- alte Pflanze weg
			pPos=aListe[nNummer]
			Logic.CreateEntity( nWas, pPos.X, pPos.Y  )-- neue Pflanze hin
			Delay(1)  -- warte etwas, damit es nach wachsen aussieht
			table.remove (aListe , nNummer) -- aus dem Table entfernen
		end
	else  -- kleine Pflanze ??
		for i=1,table.getn(aPflanzenKlein) do  -- Table wird mit den Positionen der kleinen Pflanzen gefüllt
			table.insert( aListe,aPflanzenKlein[i] )
		end
		while table.getn(aListe) > 0 do-- So lange noch nicht alle gepflanzt sind
			nNummer=GetRandom(table.getn(aListe))-- Durch Zufall einen aus der Liste auswählen
			if nNummer==0 then
				nNummer=1
			end
			_OP_CleanUp(aListe[nNummer], 1,nWas2)-- alte Pflanze weg
			pPos=aListe[nNummer]
			Logic.CreateEntity( nWas, pPos.X, pPos.Y  )-- neue Pflanze hin
			Delay(0.1) -- warte etwas, damit es nach Wachsen aussieht (weil hier wesendlich mehr Pflanzen sind, weniger)
			table.remove (aListe , nNummer)-- aus dem Table entfernen
		end
	end
end
 
 
 
 
function PPause()  -- Pinkel Pause
	local tPosBP;
	local nID;
	Laufe("Bauer",ZurEntity(nBHofID,-400)); -- Bauer läuft hinter den Hof
	tPosBP=ZurEntity("Bauer",150); -- Position etwas zum Bauern hin
	nID=Logic.CreateEntity( Entities.XD_Waterfall4, tPosBP.X, tPosBP.Y, Logic.GetEntityOrientation(GetEntityId("Bauer"))+90, 1 )
	-- Wasserfall wird erzeugt
	Delay(10); -- warten bis fertig 
	DestroyEntity(nID); -- Wasserfall weg
end
 
 
function Bewaessern(_tPflanzenKlein) -- fast wie die Pinkelpause
	local nIDBauer=GetEntityId("Bauer") -- hat ja immer eine andere
	local pPosBP
	local nID
	for i = 77, table.getn(_tPflanzenKlein)-70,18 do
		Laufe("Bauer",_tPflanzenKlein[i])-- wie beim Pflanzen
		pPosBP=ZurEntity("Bauer",-50); -- Abstand zum Bauern
 
		for i = 1,72 do  -- sieht dann fast so aus, als ob er sich flüssig dreht
			DrehEntity("Bauer",i*5)  -- Bauer immer drehen
			DestroyEntity(nID) -- alter wasserfall weg
			nID=Logic.CreateEntity( Entities.XD_Waterfall4, pPosBP.X, pPosBP.Y, Logic.GetEntityOrientation(nIDBauer)+90, 1 )
	´		-- neuer hin
		end
		DestroyEntity(nID)
	end
end
function Spraenkeln(_tPflanzenKlein) -- Die Funktion ist nicht drin, kann aber eingebaut werden.
	-- Gedanke war den, das der Bauer immer fortschritlicher wird und nacher nicht mehr selbst bewässern muß
	local nPos={}
	nAnfang=-9
	for k = -9,400,126 do
		for i = 1,4   do
			table.insert(nPos,k+i*18)
		end
	end
	local pPosBP;
	local nID={}
	for i = 1,144 do
		DelayShort(1)	
		for k = 1, table.getn(nPos) do
			DestroyEntity(nID[k])
			pPosBP=_tPflanzenKlein[nPos[k]]
			nID[k]=Logic.CreateEntity( Entities.XD_Waterfall4, pPosBP.X, pPosBP.Y, i*5, 1 )
		end
	end	
	for k = 1, table.getn(nPos) do
	DestroyEntity(nID[k])
	end
end
 
function ZurEntity(_entity, _range, _currPos)  -- neu geschrieben
	-- _entity  = die Entity zu deren Winkel  man sich bewegen will
	-- _currPos Die Position auf der man sich befindet
	-- _tRange= die Entfernung zur Entity (im Winkel der Entity) Weiter weg ist dann negativ
	if type (_entity) == "string" then
		_entity = GetEntityId(_entity);
	end
	local tPos = GetPosition(_entity)
	if _currPos == nil then
		_currPos = tPos
	elseif type (_currPos) == "string" or type (_currPos) == "number"  then
		_currPos = GetPosition(_currPos)
	end
	local nEntityAngle=Logic.GetEntityOrientation(_entity);
	local nSin=math.sin((math.rad(nEntityAngle)));
	local nCos=math.cos((math.rad(nEntityAngle)));
	local tPos = GetPosition(_entity)
	return {X=_currPos.X-nCos*_range,Y=_currPos.Y-nSin*_range}; -- Rückgabe=neue Position
end
--***********************************************************************************************************
function Winkel(_Pos1,_Pos2)
	local delta_X=0;
	local delta_Y=0;
	alpha=0
	if type (_Pos1) == "string" or type (_Pos1) == "number" then
		_Pos1 = GetPosition(GetEntityId(_Pos1));
	end
	if type (_Pos2) == "string" or type (_Pos2) == "number" then
		_Pos2 = GetPosition(GetEntityId(_Pos2));
	end
	delta_X=_Pos1.X-_Pos2.X
	delta_Y=_Pos1.Y-_Pos2.Y
	if delta_X == 0 and delta_Y == 0 then -- Steht auf dem Punkt
		return 0
	end
	alpha=math.deg(math.asin(math.abs(delta_X)/(math.sqrt(__pow(delta_X, 2)+__pow(delta_Y, 2)))))
	if delta_X >= 0 and delta_Y > 0 then
		alpha = 270 - alpha 
	elseif delta_X < 0 and delta_Y > 0 then
		alpha = 270 + alpha
	elseif delta_X < 0 and delta_Y <= 0 then
		alpha = 90 - alpha
	elseif delta_X >= 0 and delta_Y <= 0 then
		alpha = 90 + alpha
	end
	return alpha
end
--***********************************************************************************************************
function RechtsVonPos(_entity,_range,_currPos)  -- neu geschrieben
	-- _entity  = die Entity zu deren Winkel man nach rechts will
	-- _currPos Die Position auf der man sich befindet
	-- _tRange= die Entfernung nach rechts (im Winkel der Entity) Nach links ist dann negativ
	if type (_entity) == "string" then
		_entity = GetEntityId(_entity);
	end
	local tPos = GetPosition(_entity)
	if _currPos == nil then
		_currPos = tPos
	elseif type (_currPos) == "string" or type (_currPos) == "number"  then
		_currPos = GetPosition(_currPos)
	end
	local nEntityAngle=Logic.GetEntityOrientation(_entity);
	local nSin=math.sin((math.rad(nEntityAngle)));
	local nCos=math.cos((math.rad(nEntityAngle)));
	return {X=_currPos.X+nSin*_range,Y=_currPos.Y-nCos*_range};  -- Rückgabe=neue Position
end
--***********************************************************************************************************
function RelVonPos(_entity,_DiffPos)
	--- Diffpos = table mit .rechts und .zur
	local rueckPos={};
	rueckPos=RechtsVonPos( _entity, _DiffPos.rechts);
	rueckPos=ZurEntity( _entity, _DiffPos.zur, rueckPos );
	return rueckPos;  -- Rückgabe=neue Position
end
--***********************************************************************************************************
function _OP_CleanUp(_position, _range,_entity)
	local Data = { Logic.GetEntitiesInArea( _entity, _position.X, _position.Y, _range, 20)};
	local i;
	for i=2, Data[1]+1 do
		DestroyEntity(Data[i]);
	end
end
--***********************************************************************************************************
function DrehEntity(_entity, _angle)
---_angle kann auch Position oder Entity sein
	local currAngle;
	if type (_angle) == "table" or type (_angle) == "string" then
		_angle=Winkel(_entity, _angle);
	elseif type (_angle) == "number" then
		if _angle > 10 and IsAlive(_angle) then
		_angle=Winkel(_entity, _angle);
		end
	end
	while _angle >=  360 do
		_angle = _angle - 360;
	end
	_angle = math.floor(_angle+ 0.5 )
	RotateEntity(_entity, _angle);
    repeat
		DelayShort(1);
		currAngle=math.floor(Logic.GetEntityOrientation(GetEntityId(_entity))+ 0.5 );
    until currAngle == _angle
end
--***********************************************************************************************************
 
function Laufe(_entity,_tPos)
	local pEntityWarPos=GetPosition(_entity)
	if type (_tPos) == "string" or type (_tPos) == "number" then
		_tPos = GetPosition(_tPos);
	end
	Move(_entity,_tPos);
	DelayShort(2)
	local pEntityIstPos=GetPosition(_entity)
	while not (pEntityIstPos.X  == pEntityWarPos.X and pEntityIstPos.Y  == pEntityWarPos.Y) do  --er läuft noch
		pEntityWarPos=GetPosition(_entity)
		DelayShort(2)
		pEntityIstPos=GetPosition(_entity)
	end
end
--***********************************************************************************************************
function Laeuft(_entity)
	local pEntityWarPos=GetPosition(_entity)
	DelayShort(2)
	local pEntityIstPos=GetPosition(_entity)
	if (pEntityIstPos.X  == pEntityWarPos.X and pEntityIstPos.Y  == pEntityWarPos.Y) then
		return false  --er läuft nicht
	else
		return true   --er läuft
	end
end
 
--***********************************************************************************************************
function DrehEntityRel(_entity, _angle)
	local currAngle;
	if type (_angle) == "table" then
		_angle=Winkel(_entity, _angle);
	end
	currAngle=math.floor(Logic.GetEntityOrientation(GetEntityId(_entity))+ 0.5 );
	_angle = _angle + currAngle
	while _angle >=  360 do
		_angle = _angle - 360;
	end
	_angle = math.floor(_angle+ 0.5 )
	RotateEntity(_entity, _angle);
    repeat
		DelayShort(1);
		currAngle=math.floor(Logic.GetEntityOrientation(GetEntityId(_entity))+ 0.5 );
    until currAngle == _angle
end
 
 
-- Beginn DelayJob 3
--**********************************************************************************************************************
CxTools = CxTools or {};
 
--fix unpack() if needed
function unpack2(_table, _i)
	_i = _i or 1;
	assert(type(_table) == "table");
	if _i <= table.getn(_table) then
		return _table[_i], unpack2(_table, _i + 1);
	end
end
 
if not unpack( { true } ) then
    unpack = unpack2;
end
CxTools.tDelayFuncs = CxTools.tDelayFuncs or {};
CxTools.tDelayFuncsJob = false;
 
function CxTools:StartDelayFunc( _func, ... )
    assert( type(_func) == "function" );
    local thread = coroutine.create( _func );
    local fThread =
        function()
            local tRes = { coroutine.resume( thread, unpack( arg ) ) };
            local res = table.remove( tRes, 1 );
            if not res then
                if self.tDelayFuncsJob then EndJob( self.tDelayFuncsJob ); end
                assert( false, "DelayFunc error: " .. (retval or "unknown") );
            end
 
            local retval = table.remove( tRes, 1 );
 
            if type( retval ) == "function" then
                retval( unpack( tRes ) );
                retval = nil;
            end
 
            if not retval then
                return false;   -- function ends
            end
 
            assert( type( retval ) == "number" );
            assert( math.floor( retval ) == retval );
            assert( retval ~= 0 );
 
            return true, retval;    -- true, number of seconds to delay
        end
 
    local status, retval = fThread();
    if status then
        local entry = {};
        entry.func = fThread;
        entry.nextTime = Logic.GetCurrentTurn() + retval;
        table.insert( self.tDelayFuncs, entry );
 
        if not self.tDelayFuncsJob then
            self.tDelayFuncsJob = StartSimpleHiResJob( "DelayFuncsJob" );
 
            -- Workaround for broken savegame functionalitiy in 1.02 - 1.05
            XGUIEng.ShowWidget( gvGUI_WidgetID.MainMenuWindow_SaveGame, 0 );
            QuickSave = function() Message( "@color:255,0,0 Das Spiel kann momentan nicht gespeichert werden!" ); end
        end
    end    
end
 
function CxTools:DelayFuncsJob()
    assert( self.tDelayFuncsJob );
    local jobcount = table.getn( self.tDelayFuncs );
    if jobcount == 0 then
        self.tDelayFuncsJob = false;
 
        -- Workaround for broken savegame functionalitiy in 1.02 - 1.05
        XGUIEng.ShowWidget( gvGUI_WidgetID.MainMenuWindow_SaveGame, 1 );
        QuickSave = QuickSaveOrig;
 
        return true;
    end
 
    local currentTurn = Logic.GetCurrentTurn();
    for i = jobcount, 1, -1 do
        local entry = self.tDelayFuncs[i];
        assert( currentTurn <= entry.nextTime );
 
        if entry.nextTime == currentTurn then
            local status, retval = entry.func();
            if status then
                entry.nextTime = currentTurn + retval;
            else
                table.remove( self.tDelayFuncs, i );
            end
        end
    end
end
 
function CxTools.Delay( _seconds )
    assert( type( _seconds ) == "number" );
    coroutine.yield( _seconds * 10 );
end
 
function CxTools.DelayShort( _tenthseconds )
    assert( type( _tenthseconds ) == "number" );
    coroutine.yield( _tenthseconds );
end
 
StartDelayFunc = function( ... ) return CxTools:StartDelayFunc( unpack(arg) ); end;
DelayFuncsJob = function() return CxTools:DelayFuncsJob(); end;
Delay = CxTools.Delay;
DelayShort = CxTools.DelayShort;
-- Workaround for broken savegame functionalitiy in 1.02 - 1.05
QuickSaveOrig = QuickSave;