problem with lua learning

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

Moderator: Forum Moderators

Post Reply
User avatar
hermestrismi
Posts: 626
Joined: February 6th, 2016, 11:28 pm
Location: Tunisia
Contact:

problem with lua learning

Post by hermestrismi »

Hi,
this is my first attempt to learn and use Lua coding
I used the Ei event (found a boss at a random village and I tried to make it 6 bosses at 6 random villages (other villages will give you bandits)
now,
1- I turned

Code: Select all

	vars.boss_found = false
to

Code: Select all

	vars.boss_found = 0
(from boolean to numerical)
2- I replaced

Code: Select all

if not boss_found and visited > 2 then
to

Code: Select all

if  boss_found < 6 and visited > 2 then
, and

Code: Select all

vars.boss_found = true
to

Code: Select all

			vars.boss_found > 6
"the original code"

Code: Select all

-- Used for the bandit villages in S5. Much more specific than the village spawn implementations elsewhere,
-- since there are a lot more specific things needed (mostly the boss mechanics and village spreading)

local helper = wesnoth.require "helper"
local wml_actions = wesnoth.wml_actions
local _ = wesnoth.textdomain "wesnoth-ei"
local T = wml.tag
local vars = wml.variables

function wml_actions.spread_bandit_villages(cfg)
	local x = cfg.x or wml.error("[spread_bandit_villages] missing required x= attribute.")
	local y = cfg.y or wml.error("[spread_bandit_villages] missing required y= attribute.")
	local count = cfg.count or wml.error("[spread_bandit_villages] missing required count= attribute.")
	local types = cfg.types or wml.error("[spread_bandit_villages] missing required types= attribute.")

	vars.villages_visited = 0
	vars.boss_found = false
	vars.bandit_types = types

	local villages = wesnoth.map.find{gives_income = true, wml.tag['and'](cfg)}

	-- Shouldn't happen in the scenario, but a failsafe is always nice.
	if count > #villages then count = #villages end

	local village_i

	for i = 0, (count - 1) do
		village_i = mathx.random_choice("1.."..#villages)

		vars[string.format("bandit_villages[%d].x", i)] = villages[village_i][1]
		vars[string.format("bandit_villages[%d].y", i)] = villages[village_i][2]
		table.remove(villages, village_i)
	end
end

local function bandits_found(x,y)
	local bandit_types = vars.bandit_types
	local bandit_villages = wml.array_variables["bandit_villages"]
	local boss_found = vars.boss_found
	local visited = vars.villages_visited
	local rand1 = mathx.random_choice("3,4")
	local rand2 = mathx.random_choice("2.."..rand1)

	for i=1,rand2 do
		local radius = 1
		local locs
		repeat
			locs = wesnoth.map.find({T["not"] { T.filter {} } , T["and"] { x = x, y = y, radius = radius } })
			radius = radius + 1
		until locs[1]

		local bandit = mathx.random_choice(bandit_types)
		local loc_i = mathx.random_choice("1.."..#locs)

		wml_actions.move_unit_fake({x = string.format("%d,%d", x, locs[loc_i][1]), y = string.format("%d,%d", y, locs[loc_i][2]), type = bandit, side = "4"})
		wesnoth.units.to_map({ type = bandit, side = "4", random_traits = "yes", generate_name = "yes", upkeep = "loyal" }, locs[loc_i][1], locs[loc_i][2])
	end

	if not boss_found and visited > 2 then
		local boss_chance = (100 / #bandit_villages)
		local rand3 = mathx.random_choice("1..100")

		if rand3 <= boss_chance or #bandit_villages < 3 then
			vars.boss_found = true
			local loc = wesnoth.map.find({T["not"] { T.filter {} } , T["and"] { x = x, y = y, radius = 2 } })[1]
			wesnoth.fire_event("boss_found", x, y, loc[1], loc[2])
		end
	end
end

function wml_actions.bandit_village_capture(cfg)
	local bandit_villages = wml.array_access.get_proxy("bandit_villages")
	local x = cfg.x or wml.error("[bandit_village_capture] missing required x= attribute.")
	local y = cfg.y or wml.error("[bandit_village_capture] missing required y= attribute.")

	for i=1,#bandit_villages do
		if bandit_villages[i].x == x and bandit_villages[i].y == y then
			vars[string.format("bandit_villages[%d]", i - 1)] = nil

			local visited = vars.villages_visited
			vars.villages_visited = visited + 1

			wml.fire("message" , { x = x , y = y , message = _"They're here!"})

			bandits_found(x,y)
			return
		end
	end

	wml.fire("message" , { x = x , y = y , message = _"No outlaws in this village."})
end
the error I get is that

Code: Select all

spread_bandit_villages
and

Code: Select all

bandit_village_capture
are missing.
any ideas?
PS: BfW 1.16.2
the events are here
events

Code: Select all

    [event]
        name=prestart
        {VARIABLE bandits_leader_killed 0}
        {VARIABLE killed_by_1 0}
        [store_villages]
            y=1-40
        [/store_villages]
        [spread_bandit_villages]
            x=1-40
            y=1-40
            count=$($location.length / 2)
#ifdef EASY
            types="Footpad,Footpad,Poacher,Poacher,Thug,Thug,Thug,Thug,Thief,Thief,Thief,Thief"
#else
            types="Ruffian,Highwayman,Thug,Bandit,Thief,Rogue,Footpad,Outlaw,Poacher,Trapper,Thief,Thief,Thief,Thief,Rogue,Bandit,Outlaw"
#endif
        [/spread_bandit_villages]
        {CLEAR_VARIABLE location}
    [/event]
	
    [event]
        name=capture
        first_time_only=no
        [filter]
            side=1,3
        [/filter]
        [filter_condition]
            {VARIABLE_CONDITIONAL bandits_leader_killed less_than 6}
        [/filter_condition]
        [bandit_village_capture]
            x,y=$x1,$y1
        [/bandit_village_capture]
    [/event]
    [event]
        name=boss_found
        [move_unit_fake]
            x=$x1,$x2
            y=$y1,$y2
            type=Assassin
            side=4
        [/move_unit_fake]
        [unit]
            x,y=$x2,$y2
            type=Assassin
            side=4
            canrecruit=yes
        [/unit]
        {INCIDENTAL_MUSIC battle-epic.ogg}
        [message]
            speaker=Jolietateau
            message= _ "That’s a bandit leader! Kill him!"
        [/message]
    [/event]
    [event]
        name=die
        [filter]
            side=4
			canrecruit=yes
        [/filter]
		[filter_second]
			side=1
		[/filter_second]

        {VARIABLE_OP killed_by_1 add 1}
    [/event]
    [event]
        name=die
        [filter]
            side=4
			canrecruit=yes
        [/filter]

        {VARIABLE_OP bandits_leader_killed add 1}

        [if]
            [variable]
                name=bandits_leader_killed
				less_than=5
            [/variable]
            [then]
            [/then]
            [else]
        [if]
            [variable]
                name=killed_by_1
				greater_than_equal_to=3
            [/variable]
            [then]
			[/then]
			[else]
			[/else]
		[/if]
            [/else]
        [/if]
    [/event]
    [event]
        name=victory
        [message]
            speaker=Nelayin
            message= _ "We was walking for days now. We need to rest anyway. So, you have time to tell us everything."
        [/message]
        {CLEAR_VARIABLE ,bandit_villages,bandit_types,villages_visited,boss_found,bandits_leader_killed,killed_by_1}
    [/event]
User avatar
hermestrismi
Posts: 626
Joined: February 6th, 2016, 11:28 pm
Location: Tunisia
Contact:

Re: problem with lua learning

Post by hermestrismi »

edit
Horray

Code: Select all

	if  visited > 2 then

Code: Select all

if rand3 <= boss_chance or #bandit_villages < 6 then
vars.boss_found = 1
it works
my first ever lua manipulation lol
but still, can I prevent more than 6 bosses by

Code: Select all

		if rand3 <= boss_chance or #bandit_villages < 6 or 6 <= boss_found then
			vars.boss_found = 1
?
edit

Code: Select all

		if rand3 <= boss_chance or #bandit_villages < 6 and 6 <= boss_found then
tested and so far worked.
still, I really want to know the background of the first error :/
User avatar
Celtic_Minstrel
Developer
Posts: 2211
Joined: August 3rd, 2012, 11:26 pm
Location: Canada
Contact:

Re: problem with lua learning

Post by Celtic_Minstrel »

hermestrismi wrote: June 14th, 2022, 5:52 pm

Code: Select all

vars.boss_found = true
to

Code: Select all

			vars.boss_found > 6
Uhhh… how on earth does that make any sense? I don't think it's even valid code? You can't just replace an assignment with an expression. Probably what you actually want there is vars.boss_found = vars.boss_found + 1.

I think that would explain the error you mention, as using an expression where a statement is expected is a syntax error, and a syntax error in a Lua file will prevent everything in that file from being loaded.
Author of The Black Cross of Aleron campaign and Default++ era.
Former maintainer of Steelhive.
User avatar
hermestrismi
Posts: 626
Joined: February 6th, 2016, 11:28 pm
Location: Tunisia
Contact:

Re: problem with lua learning

Post by hermestrismi »

Celtic_Minstrel wrote: June 15th, 2022, 12:50 pm
hermestrismi wrote: June 14th, 2022, 5:52 pm

Code: Select all

vars.boss_found = true
to

Code: Select all

			vars.boss_found > 6
Uhhh… how on earth does that make any sense? I don't think it's even valid code? You can't just replace an assignment with an expression. Probably what you actually want there is vars.boss_found = vars.boss_found + 1.

I think that would explain the error you mention, as using an expression where a statement is expected is a syntax error, and a syntax error in a Lua file will prevent everything in that file from being loaded.
I said this my first ever try on lua so 'stupid' errors are normal I suppose :D
anyway, I understand now the nature of the mistake (from statement to number) and while fixing it , i figured out many new thing (how or, and, for, for not works, how equals =, less than <, greater than > , less than greater <= -the variable ... works, ..., the things that must be defined before working like nature of variables' values... ).
Now, it works fine except my fear that, under some circumstances , the player may encounter more than 6 bosses but i tested it and that never happen actually
User avatar
hermestrismi
Posts: 626
Joined: February 6th, 2016, 11:28 pm
Location: Tunisia
Contact:

Re: problem with lua learning

Post by hermestrismi »

the full new code

Code: Select all

local helper = wesnoth.require "helper"
local wml_actions = wesnoth.wml_actions
local _ = wesnoth.textdomain "wesnoth-Return_of_the_Legions"
local T = wml.tag
local vars = wml.variables

function wml_actions.spread_bandit_villages(cfg)
	local x = cfg.x or wml.error("[spread_bandit_villages] missing required x= attribute.")
	local y = cfg.y or wml.error("[spread_bandit_villages] missing required y= attribute.")
	local count = cfg.count or wml.error("[spread_bandit_villages] missing required count= attribute.")
	local types = cfg.types or wml.error("[spread_bandit_villages] missing required types= attribute.")

	vars.villages_visited = 0
	vars.boss_found = 0
	vars.bandit_types = types

	local villages = wesnoth.map.find{gives_income = true, wml.tag['and'](cfg)}

	-- Shouldn't happen in the scenario, but a failsafe is always nice.
	if count > #villages then count = #villages end

	local village_i

	for i = 0, (count - 1) do
		village_i = mathx.random_choice("1.."..#villages)

		vars[string.format("bandit_villages[%d].x", i)] = villages[village_i][1]
		vars[string.format("bandit_villages[%d].y", i)] = villages[village_i][2]
		table.remove(villages, village_i)
	end
end

local function bandits_found(x,y)
	local bandit_types = vars.bandit_types
	local bandit_villages = wml.array_variables["bandit_villages"]
	local boss_found = vars.boss_found
	local visited = vars.villages_visited
	local rand1 = mathx.random_choice("3,4")
	local rand2 = mathx.random_choice("2.."..rand1)

	for i=1,rand2 do
		local radius = 1
		local locs
		repeat
			locs = wesnoth.map.find({T["not"] { T.filter {} } , T["and"] { x = x, y = y, radius = radius } })
			radius = radius + 1
		until locs[1]

		local bandit = mathx.random_choice(bandit_types)
		local loc_i = mathx.random_choice("1.."..#locs)

		wml_actions.move_unit_fake({x = string.format("%d,%d", x, locs[loc_i][1]), y = string.format("%d,%d", y, locs[loc_i][2]), type = bandit, side = "4"})
		wesnoth.units.to_map({ type = bandit, side = "4", random_traits = "yes", generate_name = "yes", upkeep = "loyal" }, locs[loc_i][1], locs[loc_i][2])
	end

	if  visited > 2 then
		local boss_chance = (100 / #bandit_villages)
		local rand3 = mathx.random_choice("1..100")

		if rand3 <= boss_chance or #bandit_villages < 6 and 6 <= boss_found then
			vars.boss_found = 1
			local loc = wesnoth.map.find({T["not"] { T.filter {} } , T["and"] { x = x, y = y, radius = 2 } })[1]
			wesnoth.fire_event("boss_found", x, y, loc[1], loc[2])
		end
	end
end

function wml_actions.bandit_village_capture(cfg)
	local bandit_villages = wml.array_access.get_proxy("bandit_villages")
	local x = cfg.x or wml.error("[bandit_village_capture] missing required x= attribute.")
	local y = cfg.y or wml.error("[bandit_village_capture] missing required y= attribute.")

	for i=1,#bandit_villages do
		if bandit_villages[i].x == x and bandit_villages[i].y == y then
			vars[string.format("bandit_villages[%d]", i - 1)] = nil

			local visited = vars.villages_visited
			vars.villages_visited = visited + 1

			wml.fire("message" , { x = x , y = y , message = _"They're here!"})

			bandits_found(x,y)
			return
		end
	end

	wml.fire("message" , { x = x , y = y , message = _"No outlaws in this village."})
end
User avatar
hermestrismi
Posts: 626
Joined: February 6th, 2016, 11:28 pm
Location: Tunisia
Contact:

Re: problem with lua learning

Post by hermestrismi »

and, for information, i did some campaigns before but real variables and other wml manipulation was really began on last april as for lua learning (my first ever encounter with programming ) began 2 days ago. otherwise , i usually learn by mistakes and searching, and this is hard for me. so, be easy on me
Post Reply