Overloading lua functions

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

Moderator: Forum Moderators

Post Reply
User avatar
lhybrideur
Posts: 357
Joined: July 9th, 2019, 1:46 pm

Overloading lua functions

Post by lhybrideur »

Hi everyone,
I'm currently developing a campaign that an item management system written in lua from another add-on (LotI).
I am trying to overload a function to modify which unit can use what.
I have already succeeded for function that does not take an input parameter, but I cannot find how to do the same with a function that takes an input parameter.

Here are the function I want to overload and the function I want to use to overload it.
Original function

Code: Select all

-- Determine the list of item sorts (e.g. sword,staff,boots) that can be equipped by this unit.
-- Returns the Lua table { sword = 1, armour = 1, ... }.
function loti.util.list_equippable_sorts(unit)
	local unit_type = unit.type

	-- Doppelganger can't equip anything (but can drink potions).
	if unit_type:match( "doppelganger" ) then
		return { potion = 1 }
	end

	-- Everyone can equip rings/amulets/cloaks and use potions/books.
	local can_equip = { ring = 1, amulet = 1, cloak = 1, potion = 1, limited = 1 }

	-- All corporeal beings except bats can wear armour.
	if not ( unit_type == "Ghost" or unit_type == "Wraith" or unit_type == "Spectre"
		or unit_type == "Shadow" or unit_type == "Nightgaunt" or unit_type == "Dark Shade"
		or unit_type:match(" Bat$") )
	then
		can_equip.armour = 1
		can_equip.helm = 1
		can_equip.gauntlets = 1
		can_equip.boots = 1
	end

	-- Analyze the list of attacks. Allow weapons that are logical for this unit.
	for attack in pairs(loti.util.list_attacks(unit)) do
		if attack:match("sword$") or attack == "saber"
			or attack == "war talon" or attack == "war blade"
			or attack == "mberserk" or attack == "whirlwind"
			or attack == "spectral blades"
				then can_equip.sword = 1

		elseif attack:match("axe$") or attack == "berserker frenzy"
			then can_equip.axe = 1

		elseif attack:match("staff$")
			then can_equip.staff = 1

		elseif attack == "crossbow" or attack == "slurbow"
			then can_equip.xbow = 1

		elseif attack:match("bow$")
			then can_equip.bow = 1

		elseif attack == "dagger"
			then can_equip.dagger = 1

		elseif attack == "knife" or attack == "throwing knives"
			then can_equip.knife = 1

		elseif attack == "mace" or attack == "mace-spiked"
			or attack == "morning star" or attack == "club"
			or attack == "flail" or attack == "scourge"
			or attack == "mace_berserk" or attack == "hammer"
			or attack == "hammer_runic"
				then can_equip.mace = 1

		elseif attack == "halberd" or attack == "scythe"
			or attack == "scythe-whirlwind"
				then can_equip.polearm = 1

		elseif attack:match("claws$")
			then can_equip.claws = 1

		elseif attack == "sling" or attack == "bolas" or attack == "net"
			then can_equip.sling = 1

		elseif attack == "touch" or attack == "baneblade"
			or attack == "faerie touch" or attack == "vine"
			or attack == "torch"
				then can_equip.essence = 1

		elseif attack == "thunderstick" or attack == "dragonstaff"
			then can_equip.thunderstick = 1


		elseif attack == "spear" or attack == "javelin"
			or attack == "lance" or attack == "spike"
			or attack == "pike" or attack == "trident"
			or attack == "trident-blade" or attack == "pitchfork"
				then can_equip.spear = 1
		end
	end

	-- Some magician-like units can carry a staff (even if they don't attack with it).
	if unit_type == "Lich" or unit_type == "09 Ancient Lich" or unit_type == "Lich King"
		or unit_type == "Demilich" or unit_type == "Infernal Knight"
		or unit_type == "Dark Adept" or unit_type == "Elvish Shyde"
		or unit_type == "Elvish Seer" or unit_type == "Elvish Sylph"
		or unit_type == "Celestial Messenger" or unit_type == "Prophet"
		or unit_type == "Mage of Light" or unit_type == "Stormrider"
		or unit_type == "Sword Mage" or unit_type == "Knight of Magic"
		or unit_type == "Warlock" or unit_type == "Faerie Incarnation"
		or unit_type == "Elvish Overlord" or unit_type == "Lethalia_lich_weakened"
	then
		can_equip.staff = 1
	end

	-- Return the list of equippable item sorts for this unit
	return can_equip
end
Custom function in main.lua

Code: Select all

-- Determine the list of item sorts (e.g. sword,staff,boots) that can be equipped by this unit.
-- Returns the Lua table { sword = 1, armour = 1, ... }.
local function list_equippable_sorts_loi(unit)
	local list = loti.util.list_equippable_sorts(unit)
	local unit_type = unit.type

	-- Doppelganger can't equip anything (but can drink potions).
	if unit_type:match( "doppelganger" ) then
		return { potion = 1 }
	end

	-- Everyone can equip rings/amulets/cloaks and use potions/books.
	local can_equip_loi = { ring = 1, amulet = 1, potion = 1}

	-- All corporeal beings except bats can wear armour.
	if not ( unit_type == "Ghost" or unit_type == "Wraith" or unit_type == "Spectre"
		or unit_type == "Shadow" or unit_type == "Nightgaunt" or unit_type == "Dark Shade"
		or unit_type:match(" Bat$") )
	then
		can_equip_loi.armour = 1
		can_equip_loi.helm = 1
		can_equip_loi.gauntlets = 1
		can_equip_loi.boots = 1
	end

	if ( unit.type=="Dune Apothecary" or unit.type=="Young Man" or unit.type=="Dune Rover" or unit.type=="Dune Explorer" or unit.type=="Dune Ranger" or unit.type=="Dune Soldier" or unit.type=="Dune Spearguard" or unit.type=="Dune Spearmaster" or unit.type=="Dune Swordsman" or unit.type=="Dune Blademaster" or unit.type=="Dwarvish Arcanister" or unit.type=="Dwarvish Fighter" or unit.type=="Dwarvish Steelclad" or unit.type=="Dwarvish Lord" or unit.type=="Dwarvish Guardsman" or unit.type=="Dwarvish Stalwart" or unit.type=="Dwarvish Sentinel" or unit.type=="Dwarvish Runemaster" or unit.type=="Elvish Fighter" or unit.type=="Elvish Captain" or unit.type=="Elvish Marshal" or unit.type=="Cavalryman" or unit.type=="Dragoon" or unit.type=="Cavalier" or unit.type=="Heavy Infantryman" or unit.type=="Shock Trooper" or unit.type=="Iron Mauler" or unit.type=="Spearman" or unit.type=="Swordsman" or unit.type=="Royal Guard" or unit.type=="Royal Warrior" or unit.type=="Sergeant" or unit.type=="Lieutenant" or unit.type=="General" or unit.type=="Grand Marshal" or unit.type=="Merman Hoplite" or unit.type=="Naga Fighter" or unit.type=="Saurian Ambusher" or unit.type=="Saurian Flanker" or unit.type=="Chocobone" or unit.type=="Revenant" or unit.type=="Draug" or unit.type=="Silver Shield" or unit.type=="Pikeman" or unit.type=="Guardian" or unit.type=="Guard" or unit.type=="Shield Guard" or unit.type=="Legion Archer" or unit.type=="Legion Longbowman" or unit.type=="Legion Elite Longbowman" or unit.type=="Legion Horseman" or unit.type=="Legion Knight" or unit.type=="Legion Cavalier" or unit.type=="Legion Soldier" or unit.type=="Legion Swordsman" or unit.type=="Legion Champion" or unit.type=="Legion Spearman" or unit.type=="Legion Halberdier" or unit.type=="Legion Executioner" or unit.type=="Legion Trooper" or unit.type=="Legion Guardian" or unit.type=="Legion Sentinel" or unit.type=="Naga Guardian" or unit.type=="Naga Warden" or unit.type=="Naga Sentinel" or unit.type=="Chevalier" or unit.type=="Crusader" or unit.type=="Sentry" or unit.type=="Custodian" or unit.type=="Boar Rider" or unit.type=="Boar Knight" or unit.type=="Boar Cataphract" or unit.type=="Rouser" or unit.type=="Overlord" or unit.type=="Gallant Carapace" or unit.type=="Warrior Carapace" or unit.type=="Guard" or unit.type=="Protector" or unit.type=="Captain" or unit.type=="Chieftain" or unit.type=="Death Baron" or unit.type=="Skeleton Rider" or unit.type=="Bone Knight")
	then
		can_equip_loi.cloak = 1
	end

	if ( unit.type == "Elvish shaman" or unit.type == "Young Man" or unit.type == "Elvish Druid" or unit.type == "Elvish Shyde" or unit.type == "Elvish Sorceress" or unit.type == "Elvish Enchantress" or unit.type == "Elvish Sylph" or unit.type == "Dark Adept" or unit.type == "Dark Sorcerer" or unit.type == "Lich" or unit.type == "Necromancer" or unit.type == "Elder Mage" or unit.type == "Scholar" or unit.type == "Mage" or unit.type == "Red Mage" or unit.type == "Great Mage" or unit.type == "Silver Mage" or unit.type == "White Mage" or unit.type == "Mage of Light" or unit.type == "Mermaid Initiate" or unit.type == "Mermaid Enchantress" or unit.type == "Mermaid Siren" or unit.type == "Mermaid Priestess" or unit.type == "Mermaid Diviner" or unit.type == "Saurian Augur" or unit.type == "Saurian Oracle" or unit.type == "Saurian Soothsayer" or unit.type == "Troll Shaman" or unit.type == "Ancient Lich" or unit.type == "Adept" or unit.type == "Enchantress" or unit.type == "Sorceress" or unit.type == "Forest Mage" or unit.type == "Mage of Nature" or unit.type == "Tempest mage" or unit.type == "Mage of Storms" or unit.type == "Adept of Light" or unit.type == "Cleric" or unit.type == "Prophetess of Light" or unit.type == "Shaman" or unit.type == "Mystic" or unit.type == "Warlock" or unit.type == "Elder" or unit.type == "Orcish Shaman" or unit.type == "Orcish Warlock" or unit.type == "Orcish Sorcerer" or unit.type == "Shadow Initiate" or unit.type == "Shadow Mage" or unit.type == "Shadow Lord" or unit.type == "Wizard" or unit.type == "Sorcerer" or unit.type == "Empyrean Druid" or unit.type == "Moon Cleric" or unit.type == "Moon Enchantress" or unit.type == "Sun Priestess" or unit.type == "Sun Sorceress" or unit.type == "Elvish Acolyte" or unit.type == "Elvish Ascetic" or unit.type == "Elvish Mystic" or unit.type == "Elvish Avatar" or unit.type == "Sprite" or unit.type == "Fire Faerie" or unit.type == "Dryad" or unit.type == "Forest Spirit" or unit.type == "Initiate" or unit.type == "Deathmastere" or unit.type == "Lich Lord" or unit.type == "Elder Lich Lord" or unit.type == "Blood Apprentice" or unit.type == "Blood Manipulator" or unit.type == "Blood Apprentice" or unit.type == "Sangel" or unit.type == "Flesh Artisan" or unit.type == "Sire" or unit.type == "Methusalem" or unit.type == "Heretic" or unit.type == "Warmonger" or unit.type == "Scribe" or unit.type == "Savant" or unit.type == "Arbiter" or unit.type == "Rune Forger" or unit.type == "Seeker" or unit.type == "Pathfinder" or unit.type == "Skyrunner" or unit.type == "Strombringer" or unit.type == "Prophetess" or unit.type == "Ascendant" )
	then
		can_equip_loi.limited = 1
	end

	-- Analyze the list of attacks. Allow weapons that are logical for this unit.
	for attack in pairs(loti.util.list_attacks(unit)) do
		if attack:match("sword$") or attack == "saber"
			or attack == "war talon" or attack == "war blade"
			or attack == "mberserk" or attack == "whirlwind"
			or attack == "spectral blades"
				then can_equip_loi.sword = 1

		elseif attack:match("axe$") or attack == "berserker frenzy"
			then can_equip_loi.axe = 1

		elseif attack:match("staff$")
			then can_equip_loi.staff = 1

		elseif attack == "crossbow" or attack == "slurbow"
			then can_equip_loi.xbow = 1

		elseif attack:match("bow$") 
			then can_equip_loi.bow = 1

		elseif attack == "dagger"
			then can_equip_loi.dagger = 1

		elseif attack == "knife" or attack == "throwing knives"
			then can_equip_loi.knife = 1

		elseif attack == "mace" or attack == "mace-spiked"
			or attack == "morning star" or attack == "club"
			or attack == "flail" or attack == "scourge"
			or attack == "mace_berserk" or attack == "hammer"
			or attack == "hammer_runic"
				then can_equip_loi.mace = 1

		elseif attack == "halberd" or attack == "scythe"
			or attack == "scythe-whirlwind"
			then can_equip_loi.polearm = 1

		elseif attack:match("claws$")
			then can_equip_loi.claws = 1

		elseif attack == "sling" or attack == "bolas" or attack == "net"
			then can_equip_loi.sling = 1

		elseif attack == "touch" or attack == "baneblade"
			or attack == "faerie touch" or attack == "vine"
			or attack == "torch"
				then can_equip_loi.essence = 1

		elseif attack == "thunderstick" or attack == "dragonstaff"
			then can_equip_loi.thunderstick = 1


		elseif attack == "spear" or attack == "javelin"
			or attack == "lance" or attack == "spike"
			or attack == "pike" or attack == "trident"
			or attack == "trident-blade" or attack == "pitchfork"
				then can_equip_loi.spear = 1
		end
	end

	-- Some magician-like units can carry a staff (even if they don't attack with it).
	if unit_type == "Lich" or unit_type == "09 Ancient Lich" or unit_type == "Lich King"
		or unit_type == "Demilich" or unit_type == "Infernal Knight"
		or unit_type == "Dark Adept" or unit_type == "Elvish Shyde"
		or unit_type == "Elvish Seer" or unit_type == "Elvish Sylph"
		or unit_type == "Celestial Messenger" or unit_type == "Prophet"
		or unit_type == "Mage of Light" or unit_type == "Stormrider"
		or unit_type == "Sword Mage" or unit_type == "Knight of Magic"
		or unit_type == "Warlock" or unit_type == "Faerie Incarnation"
		or unit_type == "Elvish Overlord" or unit_type == "Lethalia_lich_weakened"
	then
		can_equip_loi.staff = 1
	end

	-- Return the list of equippable item sorts for this unit
	list.can_equip =  can_equip_loi
end

return { list_equippable_sorts_loi = list_equippable_sorts_loi}
Integration of the custom function in a start event

Code: Select all

[event]
name = start
	[lua]
				code = << wesnoth.require('~add-ons/Legends_of_Idaamub_beta/lua/main').list_equippable_sorts_loi() >>
			[/lua]
[/event]
The problem here is that I need to give the unit as an input but I don't understand how
Last edited by lhybrideur on July 22nd, 2020, 8:17 am, edited 2 times in total.
User avatar
Elvish_Hunter
Posts: 1575
Joined: September 4th, 2009, 2:39 pm
Location: Lintanir Forest...

Re: Overloading lua functions

Post by Elvish_Hunter »

lhybrideur wrote: July 15th, 2020, 1:47 pm The problem here is that I need to give the unit as an input but I don't understand how
So the problem isn't "how to override a Lua function", but "how to pass a unit as argument to a function called into a Lua tag".
The fact is that the start event doesn't have auto-stored primary and secondary units, otherwise you could've used the [args] sub-tag to pass its ID to a wesnoth.get_units() call and acquire the unit in this way.
Perhaps your best bet would be to assign the result of wesnoth.require to a variable (let's call it loi_helper), then acquire all the units you want with wesnoth.get_units(), iterate over them with an ipairs cycle and run your function on all of them.
Completely untested code:

Code: Select all

[event]
    name = start
    [lua]
        code = <<
local loi_helper = wesnoth.require('~add-ons/Legends_of_Idaamub_beta/lua/main')
for index, unit in ipairs(wesnoth.get_units({ side = 1 }) do
	loi_helper.list_equippable_sorts_loi(unit)
end
>>
    [/lua]
[/event]
Current maintainer of these add-ons, all on 1.16:
The Sojournings of Grog, Children of Dragons, A Rough Life, Wesnoth Lua Pack, The White Troll (co-author)
User avatar
lhybrideur
Posts: 357
Joined: July 9th, 2019, 1:46 pm

Re: Overloading lua functions

Post by lhybrideur »

Nice. I like it. Thank you very much. I will try that right now.
I only hope unit is not dynamically filled by another function somewhere.

P.S.: I changed the title.
User avatar
lhybrideur
Posts: 357
Joined: July 9th, 2019, 1:46 pm

Re: How to pass a unit as argument to a function called into a Lua tag

Post by lhybrideur »

It does not crash, but neither does it work. I think I need to find when list_equippable_sorts_loi(unit) is called so as to call my overloading function at the right time.

I will post when I have found.
User avatar
lhybrideur
Posts: 357
Joined: July 9th, 2019, 1:46 pm

Re: Overloading lua functions

Post by lhybrideur »

So, the function is called dynamically at the beginning of another function.

Code: Select all

local function onshow(unit)
	local equippable_sorts = loti.util.list_equippable_sorts(unit)
.
.
.
end
So I am back to trying to overload list_equippable_sorts(unit)
I can get loti.util from anywhere but I don't understand how to change what returns loti.util.list_equippable_sorts(unit)

If nothing else works, I will copy paste the whole file in my add-on, but that would be the ugly way around
Post Reply