Ravana's Lua thread

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

Moderators: Forum Moderators, Developers

Post Reply
User avatar
Ravana
Moderator
Posts: 1839
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Ravana's Lua thread

Post by Ravana » January 8th, 2018, 8:02 am

I have been rewriting Orocia logic in Lua. When designing format for bonuses for enemy units, I reached solution that I think should be possible to do in more elegant way.

I want to hold bonus definitions in table, where combination of turn number and difficulty setting returns what modifications to apply that turn. However, those bonuses can refer to WML variables, which should be retrieved only once it is correct turn (local adaptive_multiplier = V.ORM_difficulty_setting). I solved it by having all effects return function which when called retrieves variable and returns function.

Any suggestions how to improve this?

Relevant code parts

Code: Select all

-- each turn bonus of current turn is applied
function ORM.fun.apply_wave_modifications()
	if ORM.unit_bonuses["t"..wesnoth.current.turn] == nil then return end
	
	local difficulty = V.ORM_difficulty_mode
	local units = wesnoth.get_units { side = 1 }
	local bonus = ORM.unit_bonuses["t"..wesnoth.current.turn][difficulty]
	for i,u in ipairs(units) do
		wesnoth.add_modification(u, "trait", ORM.bonus.evaluate(bonus))
	end
end

-- functions to initialize and evaluate bonuses
function ORM.bonus.evaluate(bonus)
	local name = bonus.name
	bonus = ORM.fun.map(function(e) return e() end, bonus)
	bonus.name = name
	return bonus
end

-- Usable for building trait that includes multiple bonuses
function ORM.bonus.build(name, effects)
	effects.name = name
	return effects
end

-- bonus definition
function ORM.bonus.swift(movement_modifier, strike_modifier)
	return ORM.bonus.build("swift", {ORM.effect.increase_movement(movement_modifier), ORM.effect.increase_strikes(strike_modifier)})
end

function ORM.effect.increase_movement(movement_modifier)
	return function()
		local adaptive_multiplier = V.ORM_difficulty_setting
		return T.effect{
			apply_to = "movement",
			increase=tostring(movement_modifier*adaptive_multiplier).."%"
		}
	end
end

function ORM.effect.increase_strikes(strike_modifier)
	return function()
		local adaptive_multiplier = V.ORM_difficulty_setting
		return T.effect{
			apply_to = "attack",
			increase_attacks=tostring(strike_modifier*adaptive_multiplier).."%"
		}
	end
end

-- data file, defines initial wave bonuses
ORM.unit_bonuses = {
	t2 = {
		ultrahardcore=ORM.bonus.swift(50, 0)
	}
}

-- https://en.wikibooks.org/wiki/Lua_Functional_Programming/Functions
function ORM.fun.map(func, array)
	local new_array = {}
	for i,v in ipairs(array) do
		new_array[i] = func(v)
	end
	return new_array
end

User avatar
Ravana
Moderator
Posts: 1839
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: Ravana's Lua thread

Post by Ravana » January 9th, 2018, 6:45 am

Spent an hour finding that this results in each further call of g having changed x available.

Code: Select all

y=2
function f(x)
	return function()
		x=2*x
		wesnoth.message(tostring(x))
	end
end
g = f(y)
g()
g()
Adding local keyword before assignment solved it.

User avatar
Ravana
Moderator
Posts: 1839
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: Ravana's Lua thread

Post by Ravana » January 10th, 2018, 2:55 am

Is there any easy way to call modify_unit including $this_unit from Lua?

User avatar
Ravana
Moderator
Posts: 1839
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: Ravana's Lua thread

Post by Ravana » January 14th, 2018, 8:35 am

Trying to find out why having this function active(with rush mod on) results in OOS. It is called on side 1 turn refresh.

Code: Select all

function ORM.fun.apply_rush_mod()
	if wesnoth.game_config.mp_settings.active_mods:find("EXI_Rush_Mod") then
		local movement_modifier
		if V.ORM_castledestruction_setting then
			movement_modifier = 1.3
		else
			movement_modifier = 1.8
		end
		if wesnoth.current.turn <= 1 then
			movement_modifier = 1
		end
		local units = wesnoth.get_units{
			side = 1,
			T["not"]{
				T.filter_wml{
					T.status{
						ORM_rush_mod="yes"
					}
				}
			}
		}

		for i,u in ipairs(units) do
			wesnoth.add_modification(u, "object", {
				ORM.effect.get(ORM.effect.add_status("ORM_rush_mod"))
			})
			u.moves = u.moves * movement_modifier
		end
	end
end
Is it safe to add object and change writable field of same unit reference?

Likely related

Code: Select all

20180116 09:27:55< vn971> UPD: was able to solve my task "+2 movement on turn 1"  on wesnoth-1.12.
20180116 09:27:55< vn971> It consists of these steps: 1. give an object with duration="turn" with a text-only ability/description 2. Add a object with duration="forever" to increase movement. 3. At start of turn 1 for each side (event), for each unit, set unit.moves = unit.max_moves  4. At start of turn 2, add an object with duration="forever" to decrease movement.
20180116 09:31:35< vn971> step 2 is needed because replays will break if I just set movement+2 from Lua. Somewhy, when I play a game, Lua works, but when a replay is happening, such changes are not respected, wesnoth says OOS. Step 3 is needed because wesnoth apparently has a bug of not really applying movement increase on turn 1. BUT, contrary to that, replays will _accept_ the movement then. So if you modify from Lua, then game works, replays don't. If you
20180116 09:31:35< vn971>  use duration="turn" then replays work, but the game itself won't. OK, and step 4 is needed to decrease the movement back, because it was previously set with duration="forever", as I already explained why.
20180116 09:45:10< vn971> I wonder if some of those steps reveal actual wesnoth bugs ^
20180116 09:46:35< vn971> For example, allowing writing legit Lua code that will work in game but will not work in replays feels like a bug. Object with duration=turn that increases movement and does not work feels like a bug too.
20180116 09:55:17< Ravana_> that should be the cause of my current oos then

User avatar
Ravana
Moderator
Posts: 1839
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: Ravana's Lua thread

Post by Ravana » January 30th, 2018, 10:44 pm

What is most sensible way to convert data between wml tables and normal tables?

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

Re: Ravana's Lua thread

Post by gfgtdf » February 10th, 2018, 7:07 pm

Ravana wrote:What is most sensible way to convert data between wml tables and normal tables?
it's unclear what you want here exactly, your do you want

a) an 'external' tool to convert your wml table to lua when porting your mod into lua
b) a lua code that cleans up your wml table code before processing them by lua
c) a lua code to write your lua tables into wml data when saving/loading savefiles?
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
Ravana
Moderator
Posts: 1839
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: Ravana's Lua thread

Post by Ravana » February 10th, 2018, 7:13 pm

c), I asked that for returning table from wesnoth.synchronise_choice. I have normal table that should be synced, so must be converted to wml table. And after it is synced, it is better to work with normal table again.

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

Re: Ravana's Lua thread

Post by gfgtdf » February 10th, 2018, 8:10 pm

for that id' use a serialize function that basicially converts lua table into strings, i do the same in my addo. https://github.com/gfgtdf/PYR_No_Preper ... er.lua#L49 , note that that function i use in my addon onyl works for simple tables, that is, no userdata, and no tables that contian themselves recursively.

EDIT: the code linked above no loner uses serialisation since the deseialize methoid i used had security issues.
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
Celtic_Minstrel
Developer
Posts: 1225
Joined: August 3rd, 2012, 11:26 pm
Contact:

Re: Ravana's Lua thread

Post by Celtic_Minstrel » February 18th, 2018, 5:38 pm

Ravana wrote:Is there any easy way to call modify_unit including $this_unit from Lua?
Well, you can call any WML tag from Lua, so there's that. (ie, using wesnoth.fire or wesnoth.wml_actions.tagname) I wouldn't really recommend this though. In the case of modify_unit, you can get the list of from the filter (with wesnoth.get_units) and loop over them in Lua to make whatever changes you need using the various accessors and mutators the API provides on the unit userdata.
Ravana wrote:c), I asked that for returning table from wesnoth.synchronise_choice. I have normal table that should be synced, so must be converted to wml table. And after it is synced, it is better to work with normal table again.
Personally, I think that using a table-to-string serializer as gfgtdf suggests is overkill. My recommendation for adding data to the save file would be to keep the Lua tables representing that data in a WML-compatible format (that is, use only non-integer keys that are valid identifiers, with values that are simple scalar values or simple arrays of scalar values).

Then you can simply use the on_load and on_save events to inject your data into the save file (under some custom tag name) and retrieve it, respectively. (Incidentally, I couldn't find the documentation for these events or even on_mouse_action via LuaWML...)
Author of The Black Cross of Aleron campaign and Default++ era.
Maintainer of Steelhive.

Post Reply