--Prevent standalone execution: if not TRAINSPORTED then print("To prevent players from harm, this file may only be executed by the trAInsported game.") return end --AI by Ingix: -- mapTime() not yet in exe, approximate with os.time function mapTime() return os.time() end --+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ function ai.init (map, money,maximumTrains) DeltaX = {N = 0; S = 0; E = 1; W =-1} DeltaY = {N =-1; S = 1; E = 0; W = 0} OppositeDir = {N = "S", S = "N", E = "W", W = "E"} MyMap = map print (getNumberOfLines()) print (maximumTrains) -- list of trains I got -- indexed by train ID -- each entry contains a name, possibly a passenger and possibly a dest(ination), which contains a tile and possibly a dir and possibly a passenger name MyTrains ={} -- list if passengers waiting for trains -- each passenger has a name, start(ing tile), dest(ination tile) and goalMapTime -- EarlyBirds (passengers that were added before ai.init) must be added WaitingPassengers = {} if EarlyBirds ~= nil then for i=1,#EarlyBirds do table.insert (WaitingPassengers, { name = EarlyBirds[i].name, start = MyMap.height*EarlyBirds[i].startX+EarlyBirds[i].startY, goalMapTime = EarlyBirds[i].goalMapTime, dest = MyMap.height*EarlyBirds[i].destX +EarlyBirds[i].destY }) end end EarlyBirds=nil -- buy trains while (money >= 25) do buyTrain(random(MyMap.width), random(MyMap.height)) money=money-25 end -- contains the directions you can go from each tile DirMap = {} -- list of weichen WeichenListe = {} -- start MainInit that works as a coroutine DistancesCalculated=false -- true only after coroutine has finished MainInit_Co = coroutine.create (MainInit_CoRoutine) coroutine.resume (MainInit_Co) end -- ai.init --+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ function CheckReturn (keepRemainingLines) local used_l, max_l = getNumberOfLines() -- print (used_l, max_l) if used_l + keepRemainingLines + 5> max_l then coroutine.yield() end end -- CheckReturn --+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ function RemainingLines() local used_l, max_l = getNumberOfLines() -- print (used_l, max_l) return max_l - used_l - 5 end -- CheckReturn --+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ function MainInit_CoRoutine() print ("MapInit_CoRoutine started") -- walk trough map and create DirMap and WeichenListe -- a weiche has 3 or more neighbors for y=1, MyMap.height,1 do for x=1,MyMap.width,1 do CheckReturn (25) if MyMap[x][y] == "C" then DirMap[MyMap.height*x+y]={dest={}} if MyMap[x+1][y] == "C" then table.insert (DirMap[MyMap.height*x+y],"E") end if MyMap[x-1][y] == "C" then table.insert (DirMap[MyMap.height*x+y],"W") end if MyMap[x][y+1] == "C" then table.insert (DirMap[MyMap.height*x+y],"S") end if MyMap[x][y-1] == "C" then table.insert (DirMap[MyMap.height*x+y],"N") end if #DirMap[MyMap.height*x+y] >= 3 then table.insert (WeichenListe, MyMap.height*x+y) -- easy way to find index in WeichenListe later DirMap[MyMap.height*x+y].WI = #WeichenListe end end end end -- find out how long each part between weichen is -- result ist stored in DirMap[].dest[] when leaving in direction indicated by for wlIdx = 1,#WeichenListe,1 do for dirIdx = 1,#DirMap[WeichenListe[wlIdx]],1 do CheckReturn (10) if DirMap[WeichenListe[wlIdx]].dest[dirIdx] == nil then -- if not yet calculated local x=math.floor ((WeichenListe[wlIdx]-1) / MyMap.height) local y=(WeichenListe[wlIdx]-1) % MyMap.height+1 local dir = DirMap[WeichenListe[wlIdx]][dirIdx] local steps=0 local Strecke={} repeat --follow the path until next weiche CheckReturn (15) x=x+DeltaX[dir] y=y+DeltaY[dir] steps=steps+1 if #DirMap[MyMap.height*x+y] == 1 then steps=steps+1 -- end tiles take almost 2 steps normal time DirMap[MyMap.height*x+y].dest[1]={steps= steps, weiche= wlIdx, dir= DirMap[WeichenListe[wlIdx]][dirIdx]} dir = DirMap[MyMap.height*x+y][1] elseif #DirMap[MyMap.height*x+y] == 2 then if DirMap[MyMap.height*x+y][1] == OppositeDir[dir] then dir = DirMap[MyMap.height*x+y][2] DirMap[MyMap.height*x+y].dest[1]={steps= steps, weiche= wlIdx, dir= DirMap[WeichenListe[wlIdx]][dirIdx]} table.insert (Strecke,{tile=MyMap.height*x+y, dirIdx=2}) else dir = DirMap[MyMap.height*x+y][1] DirMap[MyMap.height*x+y].dest[2]={steps= steps, weiche= wlIdx, dir= DirMap[WeichenListe[wlIdx]][dirIdx]} table.insert (Strecke,{tile=MyMap.height*x+y, dirIdx=1}) end end until #DirMap[MyMap.height*x+y] >= 3 CheckReturn (20) -- add info to DirMap to show where a path leads to, how long it is and -- in which direction it will enter the other weiche ("N" means it enters from north) DirMap[WeichenListe[wlIdx]].dest[dirIdx]={steps=steps, weiche= DirMap[MyMap.height*x+y].WI, dir = OppositeDir[dir]} -- opposite direction can be entered as well for ZielDirIdx = 1, #DirMap[MyMap.height*x+y],1 do if DirMap[MyMap.height*x+y][ZielDirIdx] == OppositeDir[dir] then DirMap[MyMap.height*x+y].dest[ZielDirIdx] = {steps=steps, weiche= wlIdx, dir = DirMap[WeichenListe[wlIdx]][dirIdx]} break end end -- set opposite destination data CheckReturn (5+5*#Strecke) for stIdx = 1, #Strecke, 1 do DirMap[Strecke[stIdx].tile].dest[Strecke[stIdx].dirIdx] = {steps = steps - DirMap[Strecke[stIdx].tile].dest[3-Strecke[stIdx].dirIdx].steps, weiche = DirMap[MyMap.height*x+y].WI, dir = OppositeDir[dir]} end end end end -- find shortest routes between weichen CheckReturn (10) DistMatrix = {} for StartWeiche = 1,#WeichenListe,1 do DistMatrix [StartWeiche]={} for StartDirIdx = 1,#DirMap[WeichenListe[StartWeiche]],1 do local ShortestPath = {} CheckReturn (2*#WeichenListe + 10) for i=1,#WeichenListe,1 do ShortestPath[i]={N=10000, S=10000, E=10000, W=10000} end local CurrentWeiche=DirMap[WeichenListe[StartWeiche]].dest[StartDirIdx] ShortestPath [CurrentWeiche.weiche][CurrentWeiche.dir] = - CurrentWeiche.steps repeat local NextWeiche=0 local NewIteration=false for i=1,#ShortestPath,1 do CheckReturn (30) if ShortestPath[i].N < 0 then ShortestPath[i].N = math.abs (ShortestPath[i].N) for dirIdx = 1,#DirMap[WeichenListe[i]],1 do if DirMap[WeichenListe[i]][dirIdx] ~= "N" then NextWeiche = DirMap[WeichenListe[i]].dest[dirIdx] if ShortestPath[i].N + NextWeiche.steps < math.abs (ShortestPath[NextWeiche.weiche][NextWeiche.dir]) then NewIteration=true ShortestPath[NextWeiche.weiche][NextWeiche.dir] = - (ShortestPath[i].N + NextWeiche.steps) end end end end CheckReturn (30) if ShortestPath[i].S < 0 then ShortestPath[i].S = math.abs (ShortestPath[i].S) for dirIdx = 1,#DirMap[WeichenListe[i]],1 do if DirMap[WeichenListe[i]][dirIdx] ~= "S" then NextWeiche = DirMap[WeichenListe[i]].dest[dirIdx] if ShortestPath[i].S + NextWeiche.steps < math.abs (ShortestPath[NextWeiche.weiche][NextWeiche.dir]) then NewIteration=true ShortestPath[NextWeiche.weiche][NextWeiche.dir] = - (ShortestPath[i].S + NextWeiche.steps) end end end end CheckReturn (30) if ShortestPath[i].E < 0 then ShortestPath[i].E = math.abs (ShortestPath[i].E) for dirIdx = 1,#DirMap[WeichenListe[i]],1 do if DirMap[WeichenListe[i]][dirIdx] ~= "E" then NextWeiche = DirMap[WeichenListe[i]].dest[dirIdx] if ShortestPath[i].E + NextWeiche.steps < math.abs (ShortestPath[NextWeiche.weiche][NextWeiche.dir]) then NewIteration=true ShortestPath[NextWeiche.weiche][NextWeiche.dir] = - (ShortestPath[i].E + NextWeiche.steps) end end end end CheckReturn (40) if ShortestPath[i].W < 0 then ShortestPath[i].W = math.abs (ShortestPath[i].W) for dirIdx = 1,#DirMap[WeichenListe[i]],1 do if DirMap[WeichenListe[i]][dirIdx] ~= "W" then NextWeiche = DirMap[WeichenListe[i]].dest[dirIdx] if ShortestPath[i].W + NextWeiche.steps < math.abs (ShortestPath[NextWeiche.weiche][NextWeiche.dir]) then NewIteration=true ShortestPath[NextWeiche.weiche][NextWeiche.dir] = - (ShortestPath[i].W + NextWeiche.steps) end end end end end until not NewIteration DistMatrix[StartWeiche][DirMap[WeichenListe[StartWeiche]][StartDirIdx]]=ShortestPath end end CheckReturn (120) print ("Abstaende berechnet!") --++++ Ausgabe Abstände --for i=1,#WeichenListe,1 do -- for dirIdx = 1,#DirMap[WeichenListe[i]],1 do -- CheckReturn (keepRemainingLines + 120) -- print (i, DirMap[WeichenListe[i]][dirIdx]) -- for TargetWeiche = 1, #WeichenListe,1 do -- CheckReturn (keepRemainingLines + 200) -- print (TargetWeiche,DistMatrix[i][DirMap[WeichenListe[i]][dirIdx]][TargetWeiche].N,DistMatrix[i][DirMap[WeichenListe[i]][dirIdx]][TargetWeiche].S,DistMatrix[i][DirMap[WeichenListe[i]][dirIdx]][TargetWeiche].E,DistMatrix[i][DirMap[WeichenListe[i]][dirIdx]][TargetWeiche].W); -- end -- end -- end DistancesCalculated=true end -- MainInit_CoRoutine --+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ function printDest (tile) local x=math.floor ((tile-1) / MyMap.height) local y=(tile-1) % MyMap.height+1 print ("Gleis",x,y) for i=1,#DirMap[tile],1 do print (DirMap[tile][i], DirMap[tile].dest[i].weiche, DirMap[tile].dest[i].dir, DirMap[tile].dest[i].steps) end end --+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ function printDist (StartX, StartY, StartDir, EndX, EndY, EndArriveDir) local dist = PathLength (MyMap.height*StartX + StartY, StartDir, MyMap.height*EndX + EndY, EndArriveDir) print ("Start:", StartX, StartY, StartDir) print ("Ziel :", EndX, EndY, EndArriveDir) print ("Entf.:",dist) end --+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ function PathLength (StartTile, LeaveDirIdx, EndTile, ArriveDirIdx) -- convert the DirIdx's from direction ("N", "E") to index if necessary if type (LeaveDirIdx) ~= "number" then for i=1,#DirMap[StartTile],1 do if DirMap[StartTile][i] == LeaveDirIdx then LeaveDirIdx=i break end end end if type (ArriveDirIdx) ~= "number" then for i=1,#DirMap[EndTile],1 do if DirMap[EndTile][i] == ArriveDirIdx then ArriveDirIdx=i break end end end local StartWeiche = DirMap[StartTile].dest[LeaveDirIdx].weiche local StartWeicheArriveDir = DirMap[StartTile].dest[LeaveDirIdx].dir -- print (StartWeiche, StartWeicheArriveDir) -- find out if path leads directly to EndTile as the next Weiche with the current direction if (EndTile == WeichenListe[StartWeiche]) and (DirMap[EndTile][ArriveDirIdx] == StartWeicheArriveDir) then return DirMap[StartTile].dest[LeaveDirIdx].steps end -- find out if path leads directly to EndTile bevore next Weiche is reached if #DirMap[EndTile] < 3 then local OtherDirIdx = 1 if #DirMap[EndTile] == 2 then OtherDirIdx = 3 - ArriveDirIdx end if (DirMap[EndTile].dest[OtherDirIdx].weiche == StartWeiche) and (DirMap[EndTile].dest[OtherDirIdx].dir == StartWeicheArriveDir) then local diff = DirMap[StartTile].dest[LeaveDirIdx].steps - DirMap[EndTile].dest[OtherDirIdx].steps if diff >= 0 then return diff end end end local EndWeiche = DirMap[EndTile].dest[ArriveDirIdx].weiche local EndWeicheLeaveDir = DirMap[EndTile].dest[ArriveDirIdx].dir -- print (EndWeiche, EndWeicheLeaveDir) if (StartWeiche == EndWeiche) and (StartWeicheArriveDir ~= EndWeicheLeaveDir) then return DirMap[StartTile].dest[LeaveDirIdx].steps + DirMap[EndTile].dest[ArriveDirIdx].steps end local ShortLength = 10000 for i=1,#DirMap[WeichenListe[StartWeiche]],1 do if DirMap[WeichenListe[StartWeiche]][i] ~= StartWeicheArriveDir then for j=1,#DirMap[WeichenListe[EndWeiche]],1 do if DirMap[WeichenListe[EndWeiche]][j] ~= EndWeicheLeaveDir then if DistMatrix [StartWeiche][DirMap[WeichenListe[StartWeiche]][i]][EndWeiche][DirMap[WeichenListe[EndWeiche]][j]] < ShortLength then ShortLength = DistMatrix [StartWeiche][DirMap[WeichenListe[StartWeiche]][i]][EndWeiche][DirMap[WeichenListe[EndWeiche]][j]] end end end end end return ShortLength + DirMap[StartTile].dest[LeaveDirIdx].steps + DirMap[EndTile].dest[ArriveDirIdx].steps end --+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ function UpdateTrainGoal (trainID, x, y, dir) if MyTrains[trainID].dest == nil then local tile = MyMap.height*x+y -- print ("UpdateTrainGoal",trainID,x,y,dir) if MyTrains[trainID].passenger == nil then -- no destination and no passenger, lets find the nearest passenger and go for it local NearestPassengerDist = 10000 -- step through all waiting passengers for wpIdx = 1, #WaitingPassengers,1 do if tile == WaitingPassengers[wpIdx].start then -- we have a new passenger right here MyTrains[trainID].dest = {tile = tile} print ("Ziel fuer",MyTrains[trainID].name,"auf der Stelle gefunden: ",x,y) return end -- step though all possible arrival direction on passanger start tile and find the distance for dirIdx = 1, #DirMap[WaitingPassengers[wpIdx].start],1 do if RemainingLines() <= 500 then print (" Zug",MyTrains[trainID].name,"faehrt jetzt nach: ", math.floor ((MyTrains[trainID].dest.tile-1) / MyMap.height), (MyTrains[trainID].dest.tile-1) % MyMap.height+1) return end local pd = PathLength (tile, dir, WaitingPassengers[wpIdx].start, dirIdx) if pd < NearestPassengerDist then NearestPassengerDist = pd MyTrains[trainID].dest = {tile = WaitingPassengers[wpIdx].start} end end end else -- set destination to passengers destination MyTrains[trainID].dest = {tile = MyTrains[trainID].passenger.dest} end if MyTrains[trainID].dest ~= nil then -- nil means no possible update, like no waiting passengers in beginning print ("Zug",MyTrains[trainID].name,"faehrt jetzt nach: ",math.floor ((MyTrains[trainID].dest.tile-1) / MyMap.height), (MyTrains[trainID].dest.tile-1) % MyMap.height+1) end end end --+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ function ai.newTrain(train) print ("New train: ", train.name) table.insert (MyTrains,train.ID,{name=train.name}) if DistancesCalculated then -- do intelligent work once initialization is complete else coroutine.resume (MainInit_Co) end end -- ai.newTrain --+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ function ai.chooseDirection (train, possibleDirections) -- print ("Weichenentscheidung: ", train.name) if train.name ~= MyTrains[train.ID].name then print ("MyTrains hat anderen Namen:",MyTrains[train.ID].name) end if DistancesCalculated then UpdateTrainGoal (train.ID, train.x, train.y, train.dir) if MyTrains[train.ID].dest == nil then -- no destination, so we return nothing and let the game choose return end if MyTrains[train.ID].dest.tile == MyMap.height*train.nextX + train.nextY then -- we will arrive at dest anyway (it's the Weiche we are moving onto) return end local StartTile = MyMap.height*train.nextX + train.nextY local BestDirIdx = -1 local NearestDist = 10000 for startDirIdx = 1, #DirMap[StartTile],1 do if DirMap[StartTile][startDirIdx] ~= OppositeDir[train.dir] then for destDirIdx = 1, #DirMap[MyTrains[train.ID].dest.tile],1 do if RemainingLines () < 130 then if BestDirIdx == -1 then return DirMap[StartTile][startDirIdx] else return DirMap[StartTile][BestDirIdx] end end local pd = PathLength (StartTile, startDirIdx, MyTrains[train.ID].dest.tile, destDirIdx) if pd < NearestDist then NearestDist = pd BestDirIdx = startDirIdx end end end end local Result = DirMap[StartTile][BestDirIdx] if not possibleDirections[Result] then print ("chooseDirection erzeugt ungueltige Richtung: ",Result) end return Result else local DirList={} if possibleDirections.N then table.insert (DirList,"N") end if possibleDirections.S then table.insert (DirList,"S") end if possibleDirections.E then table.insert (DirList,"E") end if possibleDirections.W then table.insert (DirList,"W") end local Result = DirList[math.random(#DirList)] -- if not possibleDirections[Result] then -- print ("chooseDirection erzeugt ungueltige Richtung: ",Result) -- end coroutine.resume (MainInit_Co) return Result end end -- ai.chooseDirection --+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ function ai.blocked(train, possibleDirections, prevDirection) print ("geblockt!: ", train.name) if train.name ~= MyTrains[train.ID].name then print ("MyTrains hat anderen Namen:",MyTrains[train.ID].name) end if DistancesCalculated and false then -- do intelligent work once initialization is complete print (getNumberOfLines()) else coroutine.resume (MainInit_Co) end end -- ai.blocked --+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ function MyDropPassenger (train) if train.passenger ~= nil then if MyTrains[train.ID].passenger == nil then print ("train",train.name,"has a passenger, but MyTrain has not!") end MyTrains[train.ID].passenger = nil print ("Passagier",train.passenger.name,"aus",train.name,"ausgestiegen!") if (train.x ~= train.passenger.destX) or (train.y ~= train.passenger.destY) then print ("bzw. rausgeschmissen") end end dropPassenger (train) end --+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ function ai.foundPassengers(train, passengers) -- return the passenger from the index into passengers -- updates WaitingPassengers and MyTrains local function Idx2Pass (PassIdx) if PassIdx == nil then return nil end if (PassIdx < 1) or (PassIdx > #passengers) or (MyTrains[train.ID].passenger ~= nil) then return nil end for wpIdx = 1,#WaitingPassengers,1 do if (WaitingPassengers[wpIdx].name == passengers[PassIdx].name) and (MyMap.height*train.x+train.y == WaitingPassengers[wpIdx].start) and (MyMap.height*passengers[PassIdx].destX+passengers[PassIdx].destY == WaitingPassengers[wpIdx].dest) then MyTrains[train.ID].passenger = WaitingPassengers[wpIdx] MyTrains[train.ID].dest = {tile = MyTrains[train.ID].passenger.dest} table.remove (WaitingPassengers, wpIdx) print ("Zug",MyTrains[train.ID].name,"faehrt jetzt nach: ",math.floor ((MyTrains[train.ID].dest.tile-1) / MyMap.height), (MyTrains[train.ID].dest.tile-1) % MyMap.height+1) break end end -- if passenger was not found in WaitingPassengers if MyTrains[train.ID].passenger == nil then print (passengers[PassIdx].name,"not found in Waitingpassenger!") MyTrains[train.ID].passenger = {name = passengers[PassIdx].name, start = MyMap.height*train.x+train.y, dest = MyMap.height*passengers[PassIdx].destX+passengers[PassIdx].destY, goalMapTime = mapTime()-1} Mytrains[train.ID].dest = {tile = MyTrains[train.ID].passenger.dest} end print ("Passagier aufgenommen:", passengers[PassIdx].name) PassengerLeftMap (train.x, train.y) return passengers[PassIdx] end ---------- main ai.foundPassengers if train.name ~= MyTrains[train.ID].name then print ("MyTrains hat anderen Namen:",MyTrains[train.ID].name) end if DistancesCalculated then -- do intelligent work once initialization is complete -- only do something if train does not currently have passenger if train.passenger == nil then UpdateTrainGoal (train.ID, train.x, train.y, train.dir) if MyTrains[train.ID].dest.tile == MyMap.height*train.x + train.y then local NearestDest=10000 local BestPassIdx= -1 for passIdx = 1, #passengers,1 do for dirIdx = 1, #DirMap[MyMap.height*passengers[passIdx].destX+passengers[passIdx].destY],1 do if RemainingLines() < 130 then if BestPassIdx == -1 then return Idx2Pass(1) else return Idx2Pass (BestPassIdx) end end local pd = PathLength (MyMap.height*train.x+train.y, train.dir, MyMap.height*passengers[passIdx].destX+passengers[passIdx].destY, dirIdx) if pd < NearestDest then NearestDest = pd BestPassIdx = passIdx end end end return Idx2Pass (BestPassIdx) else if RemainingLines() > 200 then print ("FoundPassengers: UpdateTrainGoal will hier keine Passagiere mitnehmen: ",train.x, train.y) end end end else coroutine.resume (MainInit_Co) return Idx2Pass(1) end end -- ai.foundPassengers --+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ function ai.foundDestination(train) if train.name ~= MyTrains[train.ID].name then print ("MyTrains hat anderen Namen:",MyTrains[train.ID].name) end if DistancesCalculated then -- do intelligent work once initialization is complete MyDropPassenger (train) if MyTrains[train.ID].passenger == nil then -- should be after MyDropPassenger MyTrains[train.ID].dest = nil UpdateTrainGoal (train.ID, train.x, train.y, train.dir) end else MyDropPassenger (train) coroutine.resume (MainInit_Co) end end -- ai.foundDestination --+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ function ai.enoughMoney(money) print ("Geld fuer Zug da: ", money) if DistancesCalculated and false then -- do intelligent work once initialization is complete print (getNumberOfLines()) else while (money >= 25) do buyTrain(random(MyMap.width), random(MyMap.height)) money=money-25 end coroutine.resume (MainInit_Co) end end -- ai.enoughMoney --+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ function ai.newPassenger(name, x, y, destX, destY, vipTime) print ("neuer Passagier: ", name, "auf",x,y) if not (vipTime) then vipTime = -1 end if MyMap == nil then -- function illegally called before map.init if EarlyBirds == nil then EarlyBirds = {} end table.insert (EarlyBirds, {name = name, startX = x, startY = y, destX = destX, destY = destY, goalMapTime = mapTime() + vipTime}) else table.insert (WaitingPassengers,{ name = name, start = MyMap.height*x+y, dest = MyMap.height*destX+destY, goalMapTime = mapTime() + vipTime}) end if DistancesCalculated and false then -- do intelligent work once initialization is complete print (getNumberOfLines()) else if MyMap ~= nil then coroutine.resume (MainInit_Co) end end end -- ai.newPassenger --+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ function PassengerLeftMap (x,y) print ("Passagier verliess Karte auf Feld", x,y) local tile = MyMap.height*x+y for i=1,#MyTrains do -- walk through all of my trains if (MyTrains[i].passenger == nil) and (MyTrains[i].dest ~= nil) then -- if train has no passenger but a destination if MyTrains[i].dest.tile == tile then -- if the destination is a tile from which a passenger has just boarded a train MyTrains[i].dest = nil -- set destination of train to nil, so at next Weiche or when passenger is found along the route, GoalTrainUpdate will calc new goal print ("Zug", MyTrains[i].name, "hat damit moeglicherweise sein Ziel verloren!") end end end end --+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ function ai.passengerBoarded(train, passenger) print ("Passagier wurde mitgenommen: ", passenger.name) local wpLength = #WaitingPassengers for wpIdx = 1, #WaitingPassengers,1 do if WaitingPassengers[wpIdx].name == passenger then table.remove (WaitingPassengers, wpIdx) break end end if wpLength == #WaitingPassengers then print ("Could not find just boarded passenger",passenger,"in WaitingPassengers!") end if DistancesCalculated then PassengerLeftMap (train.x, train.y); else coroutine.resume (MainInit_Co) end end -- ai.passengerBoarded --+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ function ai.mapEvent(train) print ("MapEvent!") if DistancesCalculated then else coroutine.resume (MainInit_Co) end end -- ai.mapEvent --+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++