Building stations - getting ID of my station, other issues

Discuss the new AI features ("NoAI") introduced into OpenTTD 0.7, allowing you to implement custom AIs, and the new Game Scripts available in OpenTTD 1.2 and higher.

Moderator: OpenTTD Developers

User avatar
Darker
Engineer
Engineer
Posts: 56
Joined: 07 Aug 2011 14:32
Skype: zergdarker
Contact:

Building stations - getting ID of my station, other issues

Post by Darker »

So, as recomended, I started AI with buses.
I'm now at building stations. I decided to build as many drive-thru station as possible in one city on 6*6 area. But I definitely need id of the first station to append another ones. I don't see a reason why this is not returned by the build function, but it isn't. I failed to do this via tile functions too.
Next problem is a bit more complicated. In order to build these stations I have three loops:
1.Rows. Do nothing.
2. Cells. Check whether tile has a road on it.
3. Station rotation. Tryes booth rotations of station. If booth fails, produces message that tile wont be used and tryes to check for error that occured.

But this do not work. When I forced bot to build on square filled with straight roads, it didn't fill it correctly:
[screenshot]
main.nut
AIs source.
(6.97 KiB) Downloaded 58 times

Code: Select all

     if(AIMap.IsValidTile(townloc)) {
        local stationID=AIStation.STATION_NEW;     //Station ID, which may be replaced by the real ID of station
        local center_x = AIMap.GetTileX(townloc);  //gettiong town coordinates
        local center_y = AIMap.GetTileY(townloc);
        local start_x = center_x-3;      //Gettiong the top corner
        local start_y = center_y-3;
        local x = start_x;        //Asigning to x and y
        local y = start_y;
        Caesar.sign(x,y,"start");    //Just putting signs on square
        Caesar.sign(x+6,y+6,"end");
        for(local i=0; i<7; i++){
         AILog.Info("Station loop - ROW #"+i);
         local station_built=false;
         this.Sleep(3);
         for(local j=0; j<7; j++) {
          AILog.Info("   - "+j);
          if(!AIRoad.IsRoadTile(AIMap.GetTileIndex(x+i,y+j))){   //If there is no road...
           AILog.Info("   Skipping - not road."+i);              //... we don't use this tile
           continue;          
          }
          Caesar.sign(x+i,y+j,"Done.");             //Else we sign this tile as already parsed road.
          this.Sleep(5);
          for(local m=0; m<2; m++){
           local s_offset=AIMap.GetTileIndex(x,y); //This is very strange and mentioned at post end
           if(m==0) {
            local s_offset = AIMap.GetTileIndex(x+1,y);     //selectiong square for station direction
            AILog.Info("Trying to build station in X direction.");
           }
           else {
            local s_offset = AIMap.GetTileIndex(x,y+1);
            AILog.Info("Trying to build station in Y direction.");
           }
           local station_location =  AIMap.GetTileIndex(x+i,y+j);   //Place for station itself
           
           if(AITile.IsStationTile 	(station_location)) {         //already a station
             AILog.Error("Already built.");
             stationID=AIStation.STATION_JOIN_ADJACENT;
             //stationID=AIStation.STATION_NEW;
             break;
           }
           station_built=AIRoad.BuildDriveThroughRoadStation 	(station_location, s_offset,AIRoad.ROADVEHTYPE_BUS,stationID);

           if(station_built)    //If returned true.
            {
             
             AILog.Warning("Build SUCCESS!");
             stationID=AIStation.STATION_JOIN_ADJACENT;
             //stationID=AIStation.STATION_NEW;
             m=4;
            }	
            if(!station_built&&m==1){    //If loop is over but wee still have no station.
             
             AILog.Info("This square is not to be used.");
             local er = AIError.GetLastError 	();              //I am not sure I I do this right
             switch(er){
               case AIError.ERR_OWNED_BY_ANOTHER_COMPANY : {AILog.Error("Used by another company!");break;}
               case AIError.ERR_NOT_ENOUGH_CASH          : {AILog.Error("Out of money!");break;}
               case AIError.ERR_LOCAL_AUTHORITY_REFUSES  : {AILog.Error("Local authority refuses to allow this!");break;}
               case AIError.ERR_AREA_NOT_CLEAR           : {AILog.Error("Area not clear!");break;}
               case AIError.ERR_FLAT_LAND_REQUIRED       : {AILog.Error("We need flat area!");break;}
               case AIError.ERR_VEHICLE_IN_THE_WAY       : {AILog.Error("Vehicle approaching!");break;}
               case AIError.ERR_GENERAL_BASE             : {AILog.Error("General error.");break;}
             
             }
            }
          }	
         }
        }

      townSelected++;
     } 
     }
Edit:
There is some strange thing fith IF statement. Does it really remove "locals" defined inside it as it removes locals from for loop? Does IF really hav its own space for variables? When I defined something local in IF, it didn't exist down the code in same loop.
Hacking is like sex - you get in, you get out. And then you hope that you didn't leave inside anything to track you.
Yexo
Tycoon
Tycoon
Posts: 3663
Joined: 20 Dec 2007 12:49

Re: Building stations - getting ID of my station, other issu

Post by Yexo »

Code: Select all

   /*TOWNS*/
   local TOWN_COUNT = AITown.GetTownCount ();
   local T_BIG = array(0);
   for(local i=0; i<TOWN_COUNT; i++) {
     if(AITown.IsValidTown(i))T_BIG.append(AITown.GetLocation(i));
      else AILog.Error(i+" is not valid town!");      
   }
This code is very wrong. There might be towns with an id bigger than TOWN_COUNT. Correct code would be like this:

Code: Select all

local T_BIG = AITownList();
T_BIG.Valuate(AITown.GetLocation);
See the wiki for how AI*List works and what you can do with the Valuate function.

Code: Select all

           local s_offset = 0;
           if(m==0) {
            s_offset = AIMap.GetTileIndex(x+1,y);     //selectiong square for station direction
            AILog.Info("Trying to build station in X direction.");
           }
           else {
            s_offset = AIMap.GetTileIndex(x,y+1);
            AILog.Info("Trying to build station in Y direction.");
           }
           local station_location =  AIMap.GetTileIndex(x+i,y+j);   //Place for station itself
First you have to create the local variable s_offset outside the scope of that if/else block, or you won't be able to use it later. I've already fixed that in the code above wrt your original code. Than the value in s_offset is wrong. It should be next to station_location, not next to (x, y), hint: station_location is actually (x+i, y+j).
Edit:
There is some strange thing fith IF statement. Does it really remove "locals" defined inside it as it removes locals from for loop? Does IF really hav its own space for variables? When I defined something local in IF, it didn't exist down the code in same loop.
Yes, exactly, even an if-block has it's own scope.

Code: Select all

             local er = AIError.GetLastError 	();              //I am not sure I I do this right
             switch(er){
               case AIError.ERR_OWNED_BY_ANOTHER_COMPANY : {AILog.Error("Used by another company!");break;}
               case AIError.ERR_NOT_ENOUGH_CASH          : {AILog.Error("Out of money!");break;}
               ....snip....
               case AIError.ERR_OWNED_BY_ANOTHER_COMPANY : {AILog.Error("Used by another company!");break;}
             }
Try this instead:

Code: Select all

AILog.Error(AIError.GetLastErrorString());break;
User avatar
Darker
Engineer
Engineer
Posts: 56
Joined: 07 Aug 2011 14:32
Skype: zergdarker
Contact:

Re: Building stations - getting ID of my station, other issu

Post by Darker »

Thank you for correcting my City list gathering method. How do I check that I am at the last town? Is there so .last() method or something like that?
T have already corrected the error of forgetten j and i offset for station rotation. Don't seem to help :(
I'm sending a screenshot of what happen.
Darth division, 3016-01-31.png
Darth division, 3016-01-31.png (37.02 KiB) Viewed 2679 times
Edit: And please, can you tell me how do I get the ID of station a have built?
Hacking is like sex - you get in, you get out. And then you hope that you didn't leave inside anything to track you.
Yexo
Tycoon
Tycoon
Posts: 3663
Joined: 20 Dec 2007 12:49

Re: Building stations - getting ID of my station, other issu

Post by Yexo »

Darker wrote:Thank you for correcting my City list gathering method. How do I check that I am at the last town? Is there so .last() method or something like that?
T have already corrected the error of forgetten j and i offset for station rotation. Don't seem to help :(
So apply also my last fix so you'll actually get to see the error messages.
Edit: And please, can you tell me how do I get the ID of station a have built?
By using AIStation.GetStationID.
User avatar
Darker
Engineer
Engineer
Posts: 56
Joined: 07 Aug 2011 14:32
Skype: zergdarker
Contact:

Re: Building stations - getting ID of my station, other issu

Post by Darker »

I've applyed your hint to check all errors.
For the road 0:3 it returns ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION for all four directions. But I was basically thinkink that when I ask for last error I get the same until another error occures...
Yexo wrote:AIStation.GetStationID
Thank you. I was looking in tile class for this :)
Last edited by Darker on 22 Aug 2011 11:34, edited 1 time in total.
Hacking is like sex - you get in, you get out. And then you hope that you didn't leave inside anything to track you.
Yexo
Tycoon
Tycoon
Posts: 3663
Joined: 20 Dec 2007 12:49

Re: Building stations - getting ID of my station, other issu

Post by Yexo »

Darker wrote:For the road 0:3 it returns ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION for all four directions. But I was basically thinkink that when I ask for last error I get the same until another error occures...
And for which tiles was that? You'll get that error if you try to build on a tile with some existing road in the wrong direction.
User avatar
Darker
Engineer
Engineer
Posts: 56
Joined: 07 Aug 2011 14:32
Skype: zergdarker
Contact:

Re: Building stations - getting ID of my station, other issu

Post by Darker »

It for for tile 3 on screenshot. I understand what that error means. But 2 directions should work.
Hacking is like sex - you get in, you get out. And then you hope that you didn't leave inside anything to track you.
User avatar
Darker
Engineer
Engineer
Posts: 56
Joined: 07 Aug 2011 14:32
Skype: zergdarker
Contact:

Re: Building stations - getting ID of my station, other issu

Post by Darker »

I got also Precondition failed error. And, again, four times no matter if road dirrection is correct or not. This error occured for tile next to tile marked as 5 on screenshot in next row.
Edit:
I've added a loop to check whether the current tile is near station, and change stationID to AIStation.STATION_JOIN_ADJACENT. This shouldn't change nothing and so it did.
Edit:
It seems that I get Precondition failed for all the tiles expect the first row and first cell in each row.
another_fail.png
another_fail.png (10.88 KiB) Viewed 2658 times
Hacking is like sex - you get in, you get out. And then you hope that you didn't leave inside anything to track you.
krinn
Transport Coordinator
Transport Coordinator
Posts: 342
Joined: 29 Dec 2010 19:36

Re: Building stations - getting ID of my station, other issu

Post by krinn »

such a complex code to build a station !

Code: Select all

local possibleplace=AITileList();
local townplace=AITown.GetLocation(yourtownID);
possibleplace.AddRectangle(townplace, townplace+10); // pickup a 10x10 square inside your town
possibleplace.Valuate(AIRoad.IsRoadTile); // look for roads
possibleplace.KeepValue(1); // keep only road tiles
local directions=[AIMap.GetTileIndex(0, 1), AIMap.GetTileIndex(1, 0), AIMap.GetTileIndex(-1, 0), AIMap.GetTileIndex(0, -1)];
local yourstationID=null;
foreach (tile, dummy in possibleplace)
    {
    local success=false;
    foreach (voisin, dummy2 in directions)
        {
        if (AIRoad.IsRoadTile(tile+voisin)) // nice, the neighbourg is also a road
             {
             success=AIRoad.BuildDriveThroughRoadStation(tile, tile+voisin, AIRoad.ROADVEHTYPE_BUS, AIStation.STATION_NEW);
             if (success) { yourstationID=AIStation.GetStationID(tile); break; }
        }
    if (!success) {} // some error handling
                  else break;
   }
if (yourstationID==null) {} // you fail to build one, handle that by checking why, and yes "success" variable is lost now you are here
This is not really good as you just build a station inside the town without any other considerations than just finding a road+another_road_next_to_it, but this should show you how to build a station without the pain you seems to get.
didn't test it, just wrote that down as i don't use drivethrustation, but this should more or less be valid code :)
User avatar
Darker
Engineer
Engineer
Posts: 56
Joined: 07 Aug 2011 14:32
Skype: zergdarker
Contact:

Re: Building stations - getting ID of my station, other issu

Post by Darker »

Well, thank you for the code, but still...
I've done something wrong, I want to know what is wrong to do it correct next time. And I want also do my bot from my code not parts of code by others. This is not way I create software :)
Mainly I guess I know how to find a road to append a station on it. Once I can walk city squares, this may not be a problem.

Edit:Your code works, or seems to work, but you've used wrong way to select the area. I can guess that TileID is just row*col number. When you do +10 you are ne next 10 col.
Last edited by Darker on 22 Aug 2011 13:54, edited 1 time in total.
Hacking is like sex - you get in, you get out. And then you hope that you didn't leave inside anything to track you.
Yexo
Tycoon
Tycoon
Posts: 3663
Joined: 20 Dec 2007 12:49

Re: Building stations - getting ID of my station, other issu

Post by Yexo »

Darker wrote:It seems that I get Precondition failed for all the tiles expect the first row and first cell in each row.
My guess: you're still doing something wrong with s_offset.
User avatar
Darker
Engineer
Engineer
Posts: 56
Joined: 07 Aug 2011 14:32
Skype: zergdarker
Contact:

Source updated !

Post by Darker »

I have debugged it well. Try it yourself please.
The krinns code builded stations in only one direction.
main.nut
New source
(10.79 KiB) Downloaded 63 times
Edit:
Hey, I have a very strong susspition that calling last error without replacing it from memory is a very bad idea.
Last edited by Darker on 22 Aug 2011 14:49, edited 1 time in total.
Hacking is like sex - you get in, you get out. And then you hope that you didn't leave inside anything to track you.
Yexo
Tycoon
Tycoon
Posts: 3663
Joined: 20 Dec 2007 12:49

Re: Building stations - getting ID of my station, other issu

Post by Yexo »

Darker wrote:I have debugged it well. Try it yourself please.
Debugging your code is your task. Anyway, I've taken a look at it and my guess was correct: you're still not doing it correctly with s_offset. By putting "local" in front of s_offset in the if/else-if blocks you're defining a new variable with the same name. The original s_offset never changes and is still AIMap.GetTileIndex(x,y).

Next time when debugging print the values at the place where you use them, that means directly before this line:

Code: Select all

station_built=AIRoad.BuildDriveThroughRoadStation 	(station_location, s_offset,AIRoad.ROADVEHTYPE_BUS,stationID);
Modifying it to this would have easily revealed your problem.

Code: Select all

AILog.Info("Building station, station_location: ["+AIMap.GetTileX(station_location)+"-"+AIMap.GetTileY(station_location)+"], s_offset: ["+AIMap.GetTileX(s_offset)+"-"+AIMap.GetTileY(s_offset)+"]");
station_built=AIRoad.BuildDriveThroughRoadStation 	(station_location, s_offset,AIRoad.ROADVEHTYPE_BUS,stationID);

Code: Select all

if(AIStation.IsValidStation(AIMap.GetTileIndex(x+i,y+j))){
This line is incorrect, AIStation.IsValidStation accepts a StationID, not a TileIndex
User avatar
Darker
Engineer
Engineer
Posts: 56
Joined: 07 Aug 2011 14:32
Skype: zergdarker
Contact:

Re: Building stations - getting ID of my station, other issu

Post by Darker »

Yexo wrote:Debugging your code is your task.
Thats why I asked you after spending a hour with it.
Yexo wrote:Next time when debugging print the values at the place where you use them, that means directly before this line
This is what I will do. Thank you very much.
Yexo wrote:This line is incorrect, AIStation.IsValidStation accepts a StationID, not a TileIndex
Fixed, thank you :)
Hacking is like sex - you get in, you get out. And then you hope that you didn't leave inside anything to track you.
User avatar
Darker
Engineer
Engineer
Posts: 56
Joined: 07 Aug 2011 14:32
Skype: zergdarker
Contact:

Re: Building stations - getting ID of my station, other issu

Post by Darker »

Hey, and how do I get the cost required to build the station? I can't see it whether I look for it.
Also I dont see anything how about to sort lists on both Wiki and NoAi list page.
Hacking is like sex - you get in, you get out. And then you hope that you didn't leave inside anything to track you.
User avatar
Darker
Engineer
Engineer
Posts: 56
Joined: 07 Aug 2011 14:32
Skype: zergdarker
Contact:

Re: Building stations - getting ID of my station, other issu

Post by Darker »

Thank you, especially for price conting which seems to be quite interesting.
I hope i can have another question :)
I have seen for-looping through AIlists like this:
for (local town = town_list.Begin(); town_list.HasNext(); town = town_list.Next()) - from Wright AI
The red commands returns an error for me: The index HasNext doesn't exist. Quite confusing...

Another thing was finding near largest town. So long I think it should work as folows:
Get all town list.
Valuate it by location.
Create a tile list from this.So I need to be able to use FOR, or know how exactly foreach behaves (i have Squirells manual help)
Valuate by X axis. No problem I hope
Kick out tiles where abs(OriginalLocation-newX)>range. Do Abs() work?
Do same with Y.
Make town list from tile list somehow. Any ideas?
Hacking is like sex - you get in, you get out. And then you hope that you didn't leave inside anything to track you.
krinn
Transport Coordinator
Transport Coordinator
Posts: 342
Joined: 29 Dec 2010 19:36

Re: Building stations - getting ID of my station, other issu

Post by krinn »

in order

- local mytownlist=AITownList();
- mytownlist.Valuate(AITown.GetLocation);
- local mytilelist=AIList();
foreach (townid, tileloc in mytownlist) mytilelist.AddItem(tileloc,0); // because value of mytownlist is still set to AITown.GetLocation value
- mytilelist.Valuate(AIMap.GetTileX);
- ...GetTileY);
- i'm not sure of what you wish for that last one, if your mind is to have a kinda i want keep townID while playing with tiles location, i would do:
foreach (townid, tileloc in mytownlist) mytilelist.AddItem(tileloc,townid);
local saveref=AIList();
saveref.AddList(mytilelist); // before it get alter
mytilelist.Valuate(AIMap.GetTileX);
...
and to get the answer to whom is whom :
Find townID by location -> saveref.GetValue(anylocation); == the townid
User avatar
Darker
Engineer
Engineer
Posts: 56
Joined: 07 Aug 2011 14:32
Skype: zergdarker
Contact:

Re: Building stations - getting ID of my station, other issu

Post by Darker »

Thank you, mainly its coded. But I have one problem with it:
How do I remove single town from list? I must remove the town that defines the distance. The town in center. Maybe I can do a foreach loop.
What exactly is the first value in foreach supposed to be? Value id as int? The town/tile id?
foreach(one,two in AIList)
Edit: solved, I just used list instead of single town by mistake, that produced an error.
Hacking is like sex - you get in, you get out. And then you hope that you didn't leave inside anything to track you.
User avatar
Zuu
OpenTTD Developer
OpenTTD Developer
Posts: 4553
Joined: 09 Jun 2003 18:21
Location: /home/sweden

Re: Building stations - getting ID of my station, other issu

Post by Zuu »

Please don't use white text. It is invisible on the subsilver forum theme. Or maybe I should start to write in grey. ;-)
My OpenTTD contributions (AIs, Game Scripts, patches, OpenTTD Auto Updater, and some sprites)
Junctioneer (a traffic intersection simulator)
Post Reply

Return to “OpenTTD AIs and Game Scripts”

Who is online

Users browsing this forum: No registered users and 12 guests