ResExsention's questions on the art of "Lua-ing"

Discussion of Lua and LuaWML support, development, and ideas.

Moderators: Forum Moderators, Developers

Post Reply
User avatar
ResExsention
Posts: 95
Joined: March 17th, 2018, 12:00 am
Location: Alberta, Canada

ResExsention's questions on the art of "Lua-ing"

Post by ResExsention » August 4th, 2018, 11:51 pm

Hi!

Lua is a very interesting and powerful language; ever since starting with wesnoth UMC development, it has always intrigued me, and I've always wanted to participate in the discussion on the Lua Labs forum... And I don't believe it; I'm here!

So I went into the LuaWML page, learned some basic syntax, noted a few important functions and keywords, and now feel prepared to join the Lua Labs forum. I am familiar with C++ and Python, so I soon got a hang of the syntax, but what different keywords and functions did still eluded me; and too bad that there's no ReferenceLUA page, so I got stuck. That's why this topic is here. So that I can ask questions related to Lua so that myself and others can learn more. So here we go.
I am a ranger and my WML knives will implant themselves in your back.

Creator of the abandoned campaign Royalties Forgotten and the work in progress campaign Purger of Evil.
Maintainer of Fate of a Princess.

gfgtdf
Developer
Posts: 1090
Joined: February 10th, 2013, 2:25 pm

Re: ResExsention's questions on the art of "Lua-ing"

Post by gfgtdf » August 5th, 2018, 12:01 am

lua is not a wesnoth specific langauge, so ther is little point in adding wesnothwiki page that explains the lua language itself when there are other pages that do that already, for example on www.lua.org
Scenario with Robots SP scenario (1.11/1.12), allows you to build your units with components, PYR No preperation turn 1.12 mp-mod that allows you to select your units immideately after the game begins.

User avatar
ResExsention
Posts: 95
Joined: March 17th, 2018, 12:00 am
Location: Alberta, Canada

Re: ResExsention's questions on the art of "Lua-ing"

Post by ResExsention » August 5th, 2018, 12:16 am

So my first question pertaining to Lua relates to setting up a Lua AI which is basically the standard RCA AI but with this added in somewhere:

1 - Evaluate and move units to potential targets.
2 - Evaluate if any enemy units are in range.
3 - If so, make units form a defensive line, facing the enemy units. Make them advance forward one hex at a time cohesively, meaning if one unit encounters an enemy unit, stop the entire line until that enemy unit is killed. Adjacent units to the one being attacked by the enemy can also break out of line and attack the assailing enemy unit.
4 - If more enemies encounter the line, repeat the step 3 response to assailing units; fight back, adjacent units to the one being attacked break line and help out.
5 - Replace any holes in the line with any reserve units. If there are no reserve units, shorten the line so the gap is filled.
6 - Once there are no longer any enemies in range, or if there were never any enemy units, break line and start moving units toward target normally.
7 - Evaluate if there are any enemy units with in a ten hex radius from the side's leader.
8 - If not, send reinforcements to all advancing lines.
9 - If there are enemies, don't send reinforcements this turn and use those troops to destroy destroy destroy the intruders!

For evaluating the enemies' range from the advancing force, I was thinking of using the ai.get_enemy_dst_src() function, because to me it looked like ai.get_enemy_distance_from_a_certain_filter(), but there was no documentation for it. And for the evaluation of whether there's an enemy near this side's leader, I was thinking using a conditional, but then, I would still need to evaluate ranges from the AI's leader to an enemy. Any ideas? And for filling in holes in a line, keeping the line in place, and making units fight back against enemies and also have adjacent units break line, well... Let's just say I have no idea how to do that. :oops:

If anyone could provide an entire lua AI script for this and walk me through it, that would be nice, and would be my most preferable answer, but just defining the right functions and their syntaxes is acceptable too.

Thank you all. ;)

EDIT: Yes. I am informed that Lua is not Wesnoth only. Though the lua.org website doesn't seem to show Wesnoth-specific functions and such. Is there like a Lua library that's loaded that contains the stuff for Wesnoth? That's what I meant this topic to be about.
I am a ranger and my WML knives will implant themselves in your back.

Creator of the abandoned campaign Royalties Forgotten and the work in progress campaign Purger of Evil.
Maintainer of Fate of a Princess.

gfgtdf
Developer
Posts: 1090
Joined: February 10th, 2013, 2:25 pm

Re: ResExsention's questions on the art of "Lua-ing"

Post by gfgtdf » August 5th, 2018, 2:56 am

well, the luawml page lists all wesnoth functions except the ai functions afaik. I don't know whether there is a documentation reference for lua ai scripting, mattsc or celmin might know.
Scenario with Robots SP scenario (1.11/1.12), allows you to build your units with components, PYR No preperation turn 1.12 mp-mod that allows you to select your units immideately after the game begins.

User avatar
ResExsention
Posts: 95
Joined: March 17th, 2018, 12:00 am
Location: Alberta, Canada

Re: ResExsention's questions on the art of "Lua-ing"

Post by ResExsention » August 5th, 2018, 3:11 am

Yeah, that is kind of sad... I mean, there is a LuaAI page, but it doesn't define functions and stuff very well, and there also is a Creating a custom AI with Lua page, which was more helpful, but still didn't give me the functions and stuff I was looking for. So I haven't gone anywhere with that AI I'm trying to make. :(
I am a ranger and my WML knives will implant themselves in your back.

Creator of the abandoned campaign Royalties Forgotten and the work in progress campaign Purger of Evil.
Maintainer of Fate of a Princess.

mattsc
Posts: 1062
Joined: October 13th, 2010, 6:14 pm
Location: Wandering, mostly aimlessly

Re: ResExsention's questions on the art of "Lua-ing"

Post by mattsc » August 5th, 2018, 2:53 pm

Hi ResExsention,

It's always good to have somebody else try to get their feet wet in the Wesnoth AI waters. :) However, what you are asking for there is a huge amount of rather complex work (we're probably talking hundreds of lines of code just for a first basic version). In particular something like "form a defensive line" is very difficult to do well for a computer. I think your chances of finding somebody to provide you with a complete Lua script, or even functions to do most of your numbered tasks, are very low.

Now, having said that, people here are generally very happy to help, but you need to come up with more specific questions. Your paragraph underneath the task list is a start in that direction, but the more specific the better. To get started, I'd say have a look at the mainline ai_helper.lua library. There's probably also some useful stuff in the lua directory of one of my add-ons, but quite honestly, that is currently such a mess that it is probably not worth your time trying to sift through. I might be able to point you to some functions on specific questions though.

Specifically on some of your questions, have a look at ai_helper.get_attackable_enemies(), ai_helper.get_closest_enemy(), ai_helper.can_reach() or ai_helper.get_attacks(). Those will not do exactly what you want done in the end, but you might be able to use them to accomplish some of your goals, and their code will tell you how (some of) this can be done.

Hope this helps to get started. AI is a pretty complex topic, it takes a while to get going on it, but hopefully that won't turn you away from it.

EDIT: I forgot, in that add-on I link to, there's a Lua AI Demo scenario that gives you a template for how to set up a functional (albeit not very useful) Lua AI.
SP campaigns: Galuldur's First Journey (1.12 & 1.14) & Grnk the Mighty (1.10 & 1.12)
AI experiments: Micro AIs (wiki, forum thread, known/fixed bugs), Fred, AI-demos add-on

#wesnoth-dev.2018-??-??.log:< c?????> mattsc, I think you broke Vultraz.

User avatar
Celtic_Minstrel
Developer
Posts: 1225
Joined: August 3rd, 2012, 11:26 pm
Contact:

Re: ResExsention's questions on the art of "Lua-ing"

Post by Celtic_Minstrel » August 5th, 2018, 8:12 pm

The LuaAI page is the official reference for the AI-specific Lua functions in the engine. It could use some improvement, sure, but I think it's basically complete. The only thing really missing is any explanation of how to use those move map functions, but normally they'll be replaced with different, simpler functions to do the same thing, so what we really need to do is document those instead. It doesn't list every possible aspect only because those are listed separately in AiWML.
Author of The Black Cross of Aleron campaign and Default++ era.
Maintainer of Steelhive.

User avatar
ResExsention
Posts: 95
Joined: March 17th, 2018, 12:00 am
Location: Alberta, Canada

Re: ResExsention's questions on the art of "Lua-ing"

Post by ResExsention » August 6th, 2018, 5:54 pm

Huh. Well, mattsc, thanks for pointing me in a direction that might help me out in my quest to make a complex AI, so thanks. I'll take a look at that file. Celtic_Minstrel, thanks for also pointing me also in another relatively correct direction. I'll certainly take a look at that, too.

EDIT: Well, mattsc, I checked out the ai helper file, and found that ai_helper.get_attackable_enemies() worked nicely, but I was wondering what kind of data it returned. An array/table? So I went like this:

Code: Select all

-- The Lance Defensive AI
-- Lances the units forward when there are no enemies in range, and then when the enemies come at the force, the ai groups them together defensively,

local ai_helper = wesnoth.require "ai/lua/ai_helper.lua"

local function get_unit(cfg)
	local filter = cfg.filter or {id = cfg.id}
	local unit = ai_helper.get_units_with_moves {
		side=wesnoth.current.side, {"and", filter}
	} [1]

	return unit
end

local ca_return_unit = {}

function ca_return_unit:evaluation(ai, cfg)
	local unit = get_unit(cfg)
	if unit then
		local attackable_enemies = ai_helper.get_attackable_enemies()
		-- evaluate if there are any enemies
		if attackable_enemies then
			return 99900
		else
			return 100010
		end
	end
	
	return 0
end

function ca_return_unit:execution(ai, cfg)
	local unit = get_unit(cfg)
	-- Uhhhhh. How do you make a line, or at least make the people group together defensively?
end
The code looks right to me. Is this code correct? :doh: And if anybody has the code for grouping units tightly together, that would be nice to provide as well.... I was thinking of making the AI move the units in that force that's getting attacked towards a single nearby hex, but I can't really figure out how to filter out the specific units in that force. Maybe creating an array/table that holds the units in each individual force, and then making all those units in the table/array go to one nearby hex when they get attacked?
I am a ranger and my WML knives will implant themselves in your back.

Creator of the abandoned campaign Royalties Forgotten and the work in progress campaign Purger of Evil.
Maintainer of Fate of a Princess.

mattsc
Posts: 1062
Joined: October 13th, 2010, 6:14 pm
Location: Wandering, mostly aimlessly

Re: ResExsention's questions on the art of "Lua-ing"

Post by mattsc » August 6th, 2018, 9:00 pm

ResExsention wrote:
August 6th, 2018, 5:54 pm
Well, mattsc, [...]
Well ...
ResExsention wrote:The code looks right to me. Is this code correct? :doh:
Whenever somebody writes something like that, I always think to myself: Why don't you try if it works? And I mean this completely non-cynical or anything. What you are trying to do here will require a lot of trial-and-error, and nobody will, in the end, be able to tell simply from looking at your code whether it does what you want. So you need to develop some way of testing and trouble-shooting your code piece by piece as you write it. Sorry for the "lecture", I am honestly just trying to be helpful, so here are some hopefully constructive pointers:

You don't actually need to have a working execution function to figure out whether the evaluation function works. Just put print(99900) or wesnoth.message(99900) or whatever into the if/else blocks to see if they get triggered correctly. Or put a print message at the beginning of the execution function to see if it is called, or ...
ResExsention wrote:I was wondering what kind of data it returned. An array/table?
I very strongly suggest that you get the Wesnoth Lua Pack (WLP) from the add-ons server and use its dbms function whenever you need to know what a function returns. (Alternatively, you can get a slightly modified version from here -- I don't know if WLP is on the 1.14 add-ons server.) For what you want to do, I assume that this will be invaluable. I know that it is for me.

Now, after all that, this is still simple enough that I can tell you that, no, it won't work like that. If you look here, you can see that the function returns an empty array when no enemies are found. So in that case, your conditional needs to look like this:

Code: Select all

if (#attackable_enemies > 0) then
Next, attackable_enemies() really returns what its name says, units that are attackable by what its arguments describe. In your code, there's no connection between unit and the return value of the function. So it's either insufficient (if you want there to be a connection) or unnecessary (if you just want to know if there are enemies without "connection" to a specific AI unit.
ResExsention wrote:And if anybody has the code for grouping units tightly together, that would be nice to provide as well.... I was thinking of making the AI move the units in that force that's getting attacked towards a single nearby hex, but I can't really figure out how to filter out the specific units in that force. Maybe creating an array/table that holds the units in each individual force, and then making all those units in the table/array go to one nearby hex when they get attacked?
That's the part (one of them) that I meant when I said that it's not that simple to do well. I don't think there's any preexisting code, and it depends strongly on what you want. You'll likely have to work on this yourself and just try it out. helper.adjacent_tiles() might be useful function for this.
SP campaigns: Galuldur's First Journey (1.12 & 1.14) & Grnk the Mighty (1.10 & 1.12)
AI experiments: Micro AIs (wiki, forum thread, known/fixed bugs), Fred, AI-demos add-on

#wesnoth-dev.2018-??-??.log:< c?????> mattsc, I think you broke Vultraz.

User avatar
ResExsention
Posts: 95
Joined: March 17th, 2018, 12:00 am
Location: Alberta, Canada

Re: ResExsention's questions on the art of "Lua-ing"

Post by ResExsention » August 7th, 2018, 8:16 pm

Oh. So get_attackable_enemies returns an array. I could probably utilize that. And the conditional you basically means if there are no enemies, then... And what of helper.adjacent_tiles()? Can I look at it under ai_helper.lua? Thx. I'll be getting the wesnoth lua pack in a few minutes; thanks for that. And thanks for pointing me towards using wesnoth.message(). I'll check it out.
I am a ranger and my WML knives will implant themselves in your back.

Creator of the abandoned campaign Royalties Forgotten and the work in progress campaign Purger of Evil.
Maintainer of Fate of a Princess.

User avatar
Celtic_Minstrel
Developer
Posts: 1225
Joined: August 3rd, 2012, 11:26 pm
Contact:

Re: ResExsention's questions on the art of "Lua-ing"

Post by Celtic_Minstrel » August 8th, 2018, 12:32 am

helper.adjacent_tiles() is part of the "helper" module, so you need to wesnoth.require "helper".
Author of The Black Cross of Aleron campaign and Default++ era.
Maintainer of Steelhive.

Post Reply