Squirrel questions ...

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
keoz
Transport Coordinator
Transport Coordinator
Posts: 321
Joined: 16 Jul 2009 10:04

Squirrel questions ...

Post by keoz »

Hi :D

I'm trying to tweak some gamescripts, and hence, I'm fighting with Squirrel. Yes, really fighting, because the great lack of documentation makes it really difficult to learn/discover that language. So, I'm gonna centralizing here all the little questions I have and about which I'm unable to find an answer in the official and pretty obscure/cryptic documentation or elsewhere by googling (anyway, when I Google about Squirrel problems, I mostly find pages about squirrels, about Squirrel SQL or about SquirrelMail, but not so much about Squirrel language).

So, It will be, at least to start, about really really really basic questions, mostly. And if somebody else has also little basic questions, feel free to post here. Reading other people simple problems is probably also a good way to learn.

First question: let's suppose I have a table, but I don't know the names of the possible keys in advance, how do I find them ? I can find all the values using table, but how do I know/find/print the name of the corresponding key of table ?

And actually, by the way: I would be interested if somebody has some basic documentation/tutorial/howto.
Last edited by keoz on 12 Mar 2013 10:05, edited 1 time in total.
Patch - Let's timetable depot waiting time with the Wait in depot patch.
GameScript - Searching a new way to make your cities growing ? Try the Renewed City Growth GameScript.
My screenshots thread.
User avatar
Lord Aro
Tycoon
Tycoon
Posts: 2369
Joined: 25 Jun 2009 16:42
Location: Location, Location
Contact:

Re: Squirrel questions ...

Post by Lord Aro »

Well, first off, the squirrel in OTTD is version 2.x, so the documentation link would be better suited as this one: http://www.squirrel-lang.org/doc/squirrel2.html

As for the rest of the questions, i haven't done any squirrel development in some time, so you're better off waiting for someone like Zuu or krinn for those answers :)
AroAI - A really feeble attempt at an AI

It is practically impossible to teach good programming to students that have had a prior exposure to BASIC: as potential programmers they are mentally mutilated beyond hope of regeneration. --Edsger Dijkstra
krinn
Transport Coordinator
Transport Coordinator
Posts: 339
Joined: 29 Dec 2010 19:36

Re: Squirrel questions ...

Post by krinn »

First, you should use this link : http://www.squirrel-lang.org/doc/squirrel2.html
because until someone contradict me, openttd use 2.x and not 3.x

for your problem the answer is

foreach (item, value in table) print("item="+item+" value="+value);
User avatar
keoz
Transport Coordinator
Transport Coordinator
Posts: 321
Joined: 16 Jul 2009 10:04

Re: Squirrel questions ...

Post by keoz »

Lord Aro wrote:Well, first off, the squirrel in OTTD is version 2.x, so the documentation link would be better suited as this one: http://www.squirrel-lang.org/doc/squirrel2.html
krinn wrote:First, you should use this link : http://www.squirrel-lang.org/doc/squirrel2.html
because until someone contradict me, openttd use 2.x and not 3.x
Oh. I didn't know that. I change the link in the OP, then.
krinn wrote:for your problem the answer is

foreach (item, value in table) print("item="+item+" value="+value);
Excellent. Thank you.
Patch - Let's timetable depot waiting time with the Wait in depot patch.
GameScript - Searching a new way to make your cities growing ? Try the Renewed City Growth GameScript.
My screenshots thread.
User avatar
keoz
Transport Coordinator
Transport Coordinator
Posts: 321
Joined: 16 Jul 2009 10:04

Re: Squirrel questions ...

Post by keoz »

Hello everybody.

Working back on the my script, I have another question, about data-saving. In the wiki, it is stated that we cannot save instances, but we can save arrays, tables, and so on ... So the question is: is it possible to save an array/table of instances ?

I have tried doing this by:

Code: Select all

function MainClass::Save()
{
	GSLog.Info("Saving data...");
	local table = {};
	table.town_array <- this.towns;
	return table;
}
In the code, "this.towns" is an array of instances of a class "GoalTown", which stores several datas about town goals. When I try to save, I have an error message: "You tried to save an unsupported type. No data saved".

That let me think that my idea of an array of instances was wrong. But maybee, it is just my code which is not fine. Any advices ?
Patch - Let's timetable depot waiting time with the Wait in depot patch.
GameScript - Searching a new way to make your cities growing ? Try the Renewed City Growth GameScript.
My screenshots thread.
User avatar
Zuu
OpenTTD Developer
OpenTTD Developer
Posts: 4553
Joined: 09 Jun 2003 18:21
Location: /home/sweden

Re: Squirrel questions ...

Post by Zuu »

It is not possible to store instances in saves. It doesn't matter if you save an instance directly or have it deep in an array tree.

For classes that need to store data, I usually have one member function that export the class instance data to a table. The class also have a static function that construct a new instance of that class based on table data (from a save). This way the conversion to/from table is kept together with the class.
My OpenTTD contributions (AIs, Game Scripts, patches, OpenTTD Auto Updater, and some sprites)
Junctioneer (a traffic intersection simulator)
User avatar
keoz
Transport Coordinator
Transport Coordinator
Posts: 321
Joined: 16 Jul 2009 10:04

Re: Squirrel questions ...

Post by keoz »

Zuu wrote:It is not possible to store instances in saves. It doesn't matter if you save an instance directly or have it deep in an array tree.
Ok. Thank you very much !
Zuu wrote:For classes that need to store data, I usually have one member function that export the class instance data to a table. The class also have a static function that construct a new instance of that class based on table data (from a save). This way the conversion to/from table is kept together with the class.
Eventually, do you have an example of such a construction ?
Patch - Let's timetable depot waiting time with the Wait in depot patch.
GameScript - Searching a new way to make your cities growing ? Try the Renewed City Growth GameScript.
My screenshots thread.
krinn
Transport Coordinator
Transport Coordinator
Posts: 339
Joined: 29 Dec 2010 19:36

Re: Squirrel questions ...

Post by krinn »

He means you have inside your class a function to save or restore datas needed.

On your example it would be something like that

Code: Select all

   local town_array = []
   foreach (towninstance, _ in this.towns) town_array.push(towninstance.GoalTownSavingFunction());

Code: Select all

function GoalTown::GoalTownSavingFunction()
{
local back = []
// add what datas you want to save for this class instance, say your class have ID, and population of town and an AIList of something
back.push(this.ID);
back.push(this.Population);
// back.push(this.anAIListInClass); * this to show error, you cannot save an AIList as it's an instance
back.push(this.anAIListInClass.Count()); // saving that list size to help yourself restoring it later if your class use more than one AIList, else it's not need as its end is just end of array
foreach (item, value in this.anAIListInClass) back.push(value); // saving only values of this one, so no more AIList instance
return back;
}
You endup with town_array holding values [ID value, Population value, AIListSize, ailistmember1, ailistmember2...] [ID value, Population value, AIListSize, ailistmember1...]... instead of [Memory ref to a Goald Instance] [Memory ref to Goal Instance]
User avatar
keoz
Transport Coordinator
Transport Coordinator
Posts: 321
Joined: 16 Jul 2009 10:04

Re: Squirrel questions ...

Post by keoz »

Ok ! Interesting. I get the point.

Until now, i did it in another way (using some global tables to hold data to save), but this looks far more elegant and effective. Thank you for the hints.
Patch - Let's timetable depot waiting time with the Wait in depot patch.
GameScript - Searching a new way to make your cities growing ? Try the Renewed City Growth GameScript.
My screenshots thread.
User avatar
keoz
Transport Coordinator
Transport Coordinator
Posts: 321
Joined: 16 Jul 2009 10:04

Re: Squirrel questions ...

Post by keoz »

New question:

Is it possible to do an array of arrays in squirrel ? (= a 2 dimensional array)
Patch - Let's timetable depot waiting time with the Wait in depot patch.
GameScript - Searching a new way to make your cities growing ? Try the Renewed City Growth GameScript.
My screenshots thread.
User avatar
Zuu
OpenTTD Developer
OpenTTD Developer
Posts: 4553
Joined: 09 Jun 2003 18:21
Location: /home/sweden

Re: Squirrel questions ...

Post by Zuu »

Yes, both arrays and tables can store any object types as content/value. The only exception is lists such as AIList/GSList which can only hold integer values.

This create a 10x10 nested array and fill it with some values. Last code line shows how to access values in the nested list.

Code: Select all

list = [];
for (local i = 0; i < 10; i++) {
  local inner_list = []
  for (local j = 0; j < 10; j++) {
    inner_list.append((i+1)*(j+1));
  }
  list.append(inner_list);
}
AILog.Info(list[3][3]); // => 4 * 4 => 16
My OpenTTD contributions (AIs, Game Scripts, patches, OpenTTD Auto Updater, and some sprites)
Junctioneer (a traffic intersection simulator)
User avatar
keoz
Transport Coordinator
Transport Coordinator
Posts: 321
Joined: 16 Jul 2009 10:04

Re: Squirrel questions ...

Post by keoz »

Zuu wrote:Yes, both arrays and tables can store any object types as content/value. The only exception is lists such as AIList/GSList which can only hold integer values.

This create a 10x10 nested array and fill it with some values. Last code line shows how to access values in the nested list.

Code: Select all

list = [];
for (local i = 0; i < 10; i++) {
  local inner_list = []
  for (local j = 0; j < 10; j++) {
    inner_list.append((i+1)*(j+1));
  }
  list.append(inner_list);
}
AILog.Info(list[3][3]); // => 4 * 4 => 16
This is very clear.

I was wondering how to access the inner elements and that gives me the answer (the official manual doesn't says anything about this). The further question would be if it is possible to create an array containing arrays of different sizes, but I suppose it is, since you can have different type of objects in arrays. I will just try.

btw, Thank you Zuu.
Patch - Let's timetable depot waiting time with the Wait in depot patch.
GameScript - Searching a new way to make your cities growing ? Try the Renewed City Growth GameScript.
My screenshots thread.
R2dical
Traffic Manager
Traffic Manager
Posts: 163
Joined: 18 Mar 2013 22:22

Re: Squirrel questions ...

Post by R2dical »

Ok so one of my own squirrel questions :)

I recently found the default parameter values feature in squirrel but can't resolve the following situation...

The squirrel docs have the following:
Squirrel's functions can have default parameters.
A function with default parameters is declared as follows:
With the example of:

Code: Select all

function test(a,b,c = 10, d = 20)
{
....
}
when the function test is invoked and the parameter c or d are not specified, the VM autometically assigns
the default value to the unspecified parameter.
But how would you call the above with a,b and d specified and leave c as the default? Calling with

Code: Select all

function test(x,y, ,z)
doesn't work :(
User avatar
Zuu
OpenTTD Developer
OpenTTD Developer
Posts: 4553
Joined: 09 Jun 2003 18:21
Location: /home/sweden

Re: Squirrel questions ...

Post by Zuu »

You cannot do that. It would require named parameters which as far as I know is not supported by Squirrel.

A workaround if you do not want to include the default value of parameter c in a lot of places in your code, you can make c and d default to null and document that if those parameters are null a value of 10 and 20 will be used. This way code that need to specify d but not c can pass null for c and still allow you to change the default value of c by only changing it at one place of the code. However, this solution only works if it is possible to declare a such special value (using null or a constant that give some special value not used otherwise). Also it is not really pretty and if you use code completion it will show "null" as default and not the actual value.

Another workaround is to only accept one parameter which should be a table with named parameters. This is used commonly in some PHP libraries. (which also have to deal with a language that lack named parameters also has its share of language quirks)
My OpenTTD contributions (AIs, Game Scripts, patches, OpenTTD Auto Updater, and some sprites)
Junctioneer (a traffic intersection simulator)
R2dical
Traffic Manager
Traffic Manager
Posts: 163
Joined: 18 Mar 2013 22:22

Re: Squirrel questions ...

Post by R2dical »

Ahh ok, thanks Zuu.

Looks like Squirrel checks from left to right also, so for the above calling "test(x,y,z)" would work for variables "a, b, c". So "d" would be the default param value.

I guess overloading is also off the menu? I get an error trying it.

Some good tips for workarounds but I think for my case null could cause some confusion in future since I use that for "no parameter" in many other places. Parameter tables are nice, may use that if this function will get called often enough :)
User avatar
Zuu
OpenTTD Developer
OpenTTD Developer
Posts: 4553
Joined: 09 Jun 2003 18:21
Location: /home/sweden

Re: Squirrel questions ...

Post by Zuu »

IIRC overloading methods is not supported in Squirrel. So you have to use a different method name if you want to have two variants.
My OpenTTD contributions (AIs, Game Scripts, patches, OpenTTD Auto Updater, and some sprites)
Junctioneer (a traffic intersection simulator)
krinn
Transport Coordinator
Transport Coordinator
Posts: 339
Joined: 29 Dec 2010 19:36

Re: Squirrel questions ...

Post by krinn »

Getting complex for nothing...

Why can't you just call it :
function test(x,y,10,z)

It's not like you didn't know the default param of c :)
R2dical
Traffic Manager
Traffic Manager
Posts: 163
Joined: 18 Mar 2013 22:22

Re: Squirrel questions ...

Post by R2dical »

Zuu wrote:IIRC overloading methods is not supported in Squirrel. So you have to use a different method name if you want to have two variants.
Thanks, I guess I could also have a different function name as a wrapper for the original which only passes in the values along with the defaults.
krinn wrote:It's not like you didn't know the default param of c :)
Sure, but I was more interested in not dealing with this bad boy:

Code: Select all

function RoadBuilder::DesignPath(ignored_tiles = [], demolish = false, feature_list = [], pathfinder_preset = null, max_length_multiplier = 0, max_length_offset = 10000, no_bridge_over = [],cost_mode = false, bridge_sort = [AIBridge.GetMaxSpeed, AIList.SORT_DESCENDING], pause_functions = {})
My pathfinder call :shock:
User avatar
Zuu
OpenTTD Developer
OpenTTD Developer
Posts: 4553
Joined: 09 Jun 2003 18:21
Location: /home/sweden

Re: Squirrel questions ...

Post by Zuu »

krinn wrote:It's not like you didn't know the default param of c :)
However, there is a sometimes quite significant difference between "use the default" or hard coding the current default value all over the place in your application.

If you later want to change the default value and have just blindly copied the default value you need to figure out all these places if they want exactly that value or is just using the default value.


Edit: And of course there are also situations where the opposite is true. Eg. when you want to explicitly state optional parameters to use the value that is currently default to ensure that that value will be used even if the method default value change.
My OpenTTD contributions (AIs, Game Scripts, patches, OpenTTD Auto Updater, and some sprites)
Junctioneer (a traffic intersection simulator)
krinn
Transport Coordinator
Transport Coordinator
Posts: 339
Joined: 29 Dec 2010 19:36

Re: Squirrel questions ...

Post by krinn »

R2dical:
better go with a function RoadBuilder::DesignPath(options)
where options is an array(10,null). And to pass demolish state i would options[1] = true; and any null index means default value.

Zuu: yes, better goes with a const DEFAULT_VALUE = "I'm something that really could never be a parameter value"; function (a, b, c = DEFAULT_VALUE, d = DEFAULT_VALUE) and a set of <if (c == DEFAULT_VALUE) c = 10; if (d == DEFAULT_VALUE...> in functions with multi default parameters.
Post Reply

Return to “OpenTTD AIs and Game Scripts”

Who is online

Users browsing this forum: No registered users and 8 guests