mirror of
https://github.com/wesnoth/wesnoth
synced 2025-05-20 18:46:19 +00:00
Lua: Add a new schedule module
The primary components of this are: - wesnoth.current.schedule - wesnoth.map.get_time_area() - wesnoth.schedule module
This commit is contained in:
parent
aadec0fe88
commit
a03d59d7eb
@ -95,8 +95,8 @@ function battle_calcs.strike_damage(attacker, defender, att_weapon, def_weapon,
|
||||
-- Set up a cache index. We use id+max_hitpoints+side for each unit, since the
|
||||
-- unit can level up.
|
||||
-- Also need to add the weapons and lawful_bonus values for each unit
|
||||
local att_lawful_bonus = wesnoth.get_time_of_day({ dst[1], dst[2], true }).lawful_bonus
|
||||
local def_lawful_bonus = wesnoth.get_time_of_day({ defender.x, defender.y, true }).lawful_bonus
|
||||
local att_lawful_bonus = wesnoth.schedule.get_illumination(dst).lawful_bonus
|
||||
local def_lawful_bonus = wesnoth.schedule.get_illumination(defender).lawful_bonus
|
||||
|
||||
local cind = 'SD-' .. attacker.id .. attacker.max_hitpoints .. attacker.side
|
||||
cind = cind .. 'x' .. defender.id .. defender.max_hitpoints .. defender.side
|
||||
@ -183,8 +183,8 @@ function battle_calcs.best_weapons(attacker, defender, dst, cache)
|
||||
-- Set up a cache index. We use id+max_hitpoints+side for each unit, since the
|
||||
-- unit can level up.
|
||||
-- Also need to add the weapons and lawful_bonus values for each unit
|
||||
local att_lawful_bonus = wesnoth.get_time_of_day({ dst[1], dst[2], true }).lawful_bonus
|
||||
local def_lawful_bonus = wesnoth.get_time_of_day({ defender.x, defender.y, true }).lawful_bonus
|
||||
local att_lawful_bonus = wesnoth.schedule.get_illumination(dst).lawful_bonus
|
||||
local def_lawful_bonus = wesnoth.schedule.get_illumination(defender).lawful_bonus
|
||||
|
||||
local cind = 'BW-' .. attacker.id .. attacker.max_hitpoints .. attacker.side
|
||||
cind = cind .. 'x' .. defender.id .. defender.max_hitpoints .. defender.side
|
||||
|
@ -757,7 +757,7 @@ return {
|
||||
local lawful_bonus = 0
|
||||
local eta_turn = wesnoth.current.turn + eta
|
||||
if eta_turn <= wesnoth.scenario.turns then
|
||||
lawful_bonus = wesnoth.get_time_of_day(wesnoth.current.turn + eta).lawful_bonus / eta^2
|
||||
lawful_bonus = wesnoth.schedule.get_time_of_day(nil, wesnoth.current.turn + eta).lawful_bonus / eta^2
|
||||
end
|
||||
local damage_bonus = AH.get_unit_time_of_day_bonus(recruit_unit.alignment, lawful_bonus)
|
||||
-- Estimate effectiveness on offense and defense
|
||||
|
@ -13,7 +13,7 @@ local _ = wesnoth.textdomain "wesnoth"
|
||||
---- level: deprecation level (1-4)
|
||||
---- version: the version at which the element may be removed (level 2 or 3 only)
|
||||
---- Set to nil if deprecation level is 1 or 4
|
||||
---- elem: The actual element being deprecated
|
||||
---- elem: The actual element being deprecated, ignored if level is 4
|
||||
---- detail_msg: An optional message to add to the deprecation message
|
||||
function wesnoth.deprecate_api(elem_name, replacement, level, version, elem, detail_msg)
|
||||
if wesnoth.game_config.strict_lua then return nil end
|
||||
@ -28,7 +28,20 @@ function wesnoth.deprecate_api(elem_name, replacement, level, version, elem, det
|
||||
error((_"Invalid deprecation level $level (should be 1-4)"):vformat(err_params))
|
||||
end
|
||||
local msg_shown = false
|
||||
if type(elem) == "function" or getmetatable(elem) == "function" then
|
||||
if level == 4 then
|
||||
local function show_msg(...)
|
||||
if not msg_shown then
|
||||
msg_shown = true
|
||||
wesnoth.deprecated_message(elem_name, level, version, message)
|
||||
end
|
||||
end
|
||||
return setmetatable({}, {
|
||||
__index = show_msg,
|
||||
__newindex = show_msg,
|
||||
__call = show_msg,
|
||||
__metatable = "removed API",
|
||||
})
|
||||
elseif type(elem) == "function" or getmetatable(elem) == "function" then
|
||||
return function(...)
|
||||
if not msg_shown then
|
||||
msg_shown = true
|
||||
@ -109,6 +122,43 @@ wesnoth.set_end_campaign_text = wesnoth.deprecate_api('wesnoth.set_end_campaign_
|
||||
end)
|
||||
|
||||
if wesnoth.kernel_type() == 'Game Lua Kernel' then
|
||||
local function get_time_of_day(...)
|
||||
local arg_i, turn = 1, nil
|
||||
if type(...) == 'number' then
|
||||
turn = ...
|
||||
arg_i = arg_i + 1
|
||||
end
|
||||
local loc, n = wesnoth.map.read_location(select(arg_i, ...))
|
||||
local illum = false
|
||||
if loc ~= nil then
|
||||
local actual_loc = type(select(arg_i, ...))
|
||||
if type(actual_loc) == 'table' and type(actual_loc[3]) == 'boolean' then
|
||||
illum = actual_loc[3]
|
||||
end
|
||||
arg_i = arg_i + n
|
||||
end
|
||||
local final_arg = select(arg_i, ...)
|
||||
if type(final_arg) == 'boolean' then
|
||||
illum = final_arg
|
||||
end
|
||||
local get_tod
|
||||
if illum then
|
||||
get_tod = wesnoth.schedule.get_illumination
|
||||
else
|
||||
get_tod = wesnoth.schedule.get_time_of_day
|
||||
end
|
||||
return get_tod(loc, turn)
|
||||
end
|
||||
|
||||
local function liminal_bonus(...)
|
||||
return wesnoth.current.schedule.liminal_bonus
|
||||
end
|
||||
|
||||
wesnoth.get_time_of_day = wesnoth.deprecate_api('wesnoth.get_time_of_day', 'wesnoth.schedule.get_time_of_day or wesnoth.schedule.get_illumination', 1, nil, get_time_of_day, 'The arguments have changed')
|
||||
wesnoth.set_time_of_day = wesnoth.deprecate_api('wesnoth.set_time_of_day', 'wesnoth.current.schedule.time_of_day', 4, nil, nil)
|
||||
wesnoth.get_max_liminal_bonus = wesnoth.deprecate_api('wesnoth.get_max_liminal_bonus', 'wesnoth.current.schedule.liminal_bonus', 1, nil, liminal_bonus, "It's now a read-write attribute")
|
||||
wesnoth.replace_schedule = wesnoth.deprecate_api('wesnoth.replace_schedule', 'wesnoth.schedule.replace', 1, nil, wesnoth.schedule.replace)
|
||||
|
||||
wesnoth.get_traits = wesnoth.deprecate_api('wesnoth.get_traits', 'wesnoth.game_config.global_traits', 1, nil, function() return wesnoth.game_config.global_traits end)
|
||||
wesnoth.end_level = wesnoth.deprecate_api('wesnoth.end_level', 'wesnoth.scenario.end_level_data assignment', 1, nil, function(cfg) wesnoth.scenario.end_level_data = cfg end)
|
||||
wesnoth.get_end_level_data = wesnoth.deprecate_api('wesnoth.get_end_level_data', 'wesnoth.scenario.end_level_data', 1, nil, function() return wesnoth.scenario.end_level_data end)
|
||||
|
@ -93,6 +93,10 @@ if wesnoth.kernel_type() == "Game Lua Kernel" then
|
||||
return self.terrain:split('^', {remove_empty=false})[2]
|
||||
elseif key == 'info' then
|
||||
return wesnoth.get_terrain_info(wesnoth.current.map[self])
|
||||
elseif key == 'time_of_day' then
|
||||
return wesnoth.schedule.get_time_of_day(self)
|
||||
elseif key == 'illuminated_time' then
|
||||
return wesnoth.schedule.get_illumination(self)
|
||||
elseif key == 1 then
|
||||
return self.x
|
||||
elseif key == 2 then
|
||||
@ -137,8 +141,8 @@ if wesnoth.kernel_type() == "Game Lua Kernel" then
|
||||
self.x = val
|
||||
elseif key == 2 then
|
||||
self.y = val
|
||||
elseif key == 'info' then
|
||||
error('hex.info is read-only', 1)
|
||||
elseif key == 'info' or key == 'time_of_day' or key == 'illuminated_time' then
|
||||
error(string.format('hex.%s is read-only', key), 1)
|
||||
else
|
||||
-- If it's not a known key, just set it
|
||||
rawset(self, key, val)
|
||||
|
@ -699,7 +699,7 @@ function wml_actions.remove_time_area(cfg)
|
||||
end
|
||||
|
||||
function wml_actions.replace_schedule(cfg)
|
||||
wesnoth.replace_schedule(cfg)
|
||||
wesnoth.schedule.replace(cfg)
|
||||
end
|
||||
|
||||
function wml_actions.scroll(cfg)
|
||||
|
@ -78,7 +78,7 @@ function wml_actions.harm_unit(cfg)
|
||||
elseif alignment == "chaotic" then
|
||||
damage_multiplier = damage_multiplier - tod_bonus
|
||||
elseif alignment == "liminal" then
|
||||
damage_multiplier = damage_multiplier + math.max(0, wesnoth.get_max_liminal_bonus() - math.abs(tod_bonus))
|
||||
damage_multiplier = damage_multiplier + math.max(0, wesnoth.current.schedule.liminal_bonus - math.abs(tod_bonus))
|
||||
else -- neutral, do nothing
|
||||
end
|
||||
local resistance_modified = resistance * modifier
|
||||
@ -90,7 +90,7 @@ function wml_actions.harm_unit(cfg)
|
||||
local damage = calculate_damage(
|
||||
amount,
|
||||
cfg.alignment or "neutral",
|
||||
wesnoth.get_time_of_day( { unit_to_harm.x, unit_to_harm.y, true } ).lawful_bonus,
|
||||
wesnoth.schedule.get_illumination(unit_to_harm).lawful_bonus,
|
||||
100 - unit_to_harm:resistance_against( cfg.damage_type or "dummy" ),
|
||||
resistance_multiplier
|
||||
)
|
||||
|
@ -17,7 +17,7 @@ local aspect = wml.variables['test_attribute']
|
||||
if ai.aspects[aspect] ~= expected[wesnoth.current.turn].value then
|
||||
wml.variables['is_valid'] = false
|
||||
local msg = 'Failed on turn ' .. tostring(wesnoth.current.turn)
|
||||
msg = msg .. ' (time: ' .. wesnoth.get_time_of_day().id .. ')'
|
||||
msg = msg .. ' (time: ' .. wesnoth.current.schedule.time_of_day .. ')'
|
||||
msg = msg .. '; ' .. aspect
|
||||
msg = msg .. ' was ' .. tostring(ai.aspects[aspect])
|
||||
msg = msg .. ' but expected to be '
|
||||
|
@ -839,6 +839,174 @@ int game_lua_kernel::intf_lock_view(lua_State *L)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void luaW_push_tod(lua_State* L, const time_of_day& tod)
|
||||
{
|
||||
lua_newtable(L);
|
||||
lua_pushstring(L, tod.id.c_str());
|
||||
lua_setfield(L, -2, "id");
|
||||
lua_pushinteger(L, tod.lawful_bonus);
|
||||
lua_setfield(L, -2, "lawful_bonus");
|
||||
lua_pushinteger(L, tod.bonus_modified);
|
||||
lua_setfield(L, -2, "bonus_modified");
|
||||
lua_pushstring(L, tod.image.c_str());
|
||||
lua_setfield(L, -2, "image");
|
||||
luaW_pushtstring(L, tod.name);
|
||||
lua_setfield(L, -2, "name");
|
||||
lua_pushstring(L, tod.sounds.c_str());
|
||||
lua_setfield(L, -2, "sound");
|
||||
lua_pushstring(L, tod.image_mask.c_str());
|
||||
lua_setfield(L, -2, "mask");
|
||||
|
||||
lua_pushinteger(L, tod.color.r);
|
||||
lua_setfield(L, -2, "red");
|
||||
lua_pushinteger(L, tod.color.g);
|
||||
lua_setfield(L, -2, "green");
|
||||
lua_pushinteger(L, tod.color.b);
|
||||
lua_setfield(L, -2, "blue");
|
||||
}
|
||||
|
||||
// A schedule object is just a location with a special metatable.
|
||||
// This is also valid for time area objects, which also have an "index" key identifying them.
|
||||
// The index is a secondary means of identification in case it has no locations.
|
||||
void game_lua_kernel::luaW_push_schedule(lua_State* L, int area_index)
|
||||
{
|
||||
lua_newuserdatauv(L, 0, 1);
|
||||
lua_pushinteger(L, area_index);
|
||||
lua_setiuservalue(L, -2, 1);
|
||||
if(luaL_newmetatable(L, "schedule")) {
|
||||
static luaL_Reg const schedule_meta[] {
|
||||
{"__index", &dispatch<&game_lua_kernel::impl_schedule_get>},
|
||||
{"__newindex", &dispatch<&game_lua_kernel::impl_schedule_set>},
|
||||
{"__len", &dispatch<&game_lua_kernel::impl_schedule_len>},
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
luaL_setfuncs(L, schedule_meta, 0);
|
||||
}
|
||||
lua_setmetatable(L, -2);
|
||||
}
|
||||
|
||||
static int luaW_check_schedule(lua_State* L, int idx)
|
||||
{
|
||||
int save_top = lua_gettop(L);
|
||||
luaL_checkudata(L, idx, "schedule");
|
||||
lua_getiuservalue(L, idx, 1);
|
||||
int i = luaL_checkinteger(L, -1);
|
||||
lua_settop(L, save_top);
|
||||
return i;
|
||||
}
|
||||
|
||||
int game_lua_kernel::impl_schedule_get(lua_State *L)
|
||||
{
|
||||
int area_index = luaW_check_schedule(L, 1);
|
||||
if(lua_isnumber(L, 2)) {
|
||||
const auto& times = area_index < 0 ? tod_man().times() : tod_man().times(area_index);
|
||||
int i = lua_tointeger(L, 2) - 1;
|
||||
if(i < 0 || i >= static_cast<int>(times.size())) {
|
||||
return luaL_argerror(L, 2, "invalid time of day index");
|
||||
}
|
||||
luaW_push_tod(L, times[i]);
|
||||
return 1;
|
||||
} else {
|
||||
const char* m = luaL_checkstring(L, 2);
|
||||
if(area_index >= 0) {
|
||||
return_string_attrib("time_of_day", tod_man().get_area_time_of_day(area_index).id);
|
||||
return_string_attrib("id", tod_man().get_area_id(area_index));
|
||||
if(strcmp(m, "hexes") == 0) {
|
||||
const auto& hexes = tod_man().get_area_by_index(area_index);
|
||||
luaW_push_locationset(L, hexes);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
return_string_attrib("time_of_day", tod_man().get_time_of_day().id);
|
||||
return_int_attrib("liminal_bonus", tod_man().get_max_liminal_bonus());
|
||||
}
|
||||
|
||||
if(luaW_getglobal(L, "wesnoth", "schedule", m)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int game_lua_kernel::impl_schedule_len(lua_State *L)
|
||||
{
|
||||
int area_index = luaW_check_schedule(L, 1);
|
||||
const auto& times = area_index < 0 ? tod_man().times() : tod_man().times(area_index);
|
||||
lua_pushinteger(L, times.size());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int game_lua_kernel::impl_schedule_set(lua_State *L)
|
||||
{
|
||||
int area_index = luaW_check_schedule(L, 1);
|
||||
if(lua_isnumber(L, 2)) {
|
||||
std::vector<time_of_day> times = area_index < 0 ? tod_man().times() : tod_man().times(area_index);
|
||||
int i = lua_tointeger(L, 2) - 1;
|
||||
if(i < 0 || i >= static_cast<int>(times.size())) {
|
||||
return luaL_argerror(L, 2, "invalid time of day index");
|
||||
}
|
||||
config time_cfg = luaW_checkconfig(L, 3);
|
||||
times[i] = time_of_day(time_cfg);
|
||||
if(area_index < 0) {
|
||||
tod_man().replace_schedule(times);
|
||||
} else {
|
||||
tod_man().replace_local_schedule(times, area_index);
|
||||
}
|
||||
} else {
|
||||
const char* m = luaL_checkstring(L, 2);
|
||||
if(strcmp(m, "time_of_day") == 0) {
|
||||
std::string value = luaL_checkstring(L, 3);
|
||||
const auto& times = area_index < 0 ? tod_man().times() : tod_man().times(area_index);
|
||||
auto iter = std::find_if(times.begin(), times.end(), [&value](const time_of_day& tod) {
|
||||
return tod.id == value;
|
||||
});
|
||||
if(iter == times.end()) {
|
||||
std::ostringstream err;
|
||||
err << "invalid time of day ID for ";
|
||||
if(area_index < 0) {
|
||||
err << "global schedule";
|
||||
} else {
|
||||
const std::string& id = tod_man().get_area_id(area_index);
|
||||
if(id.empty()) {
|
||||
const auto& hexes = tod_man().get_area_by_index(area_index);
|
||||
if(hexes.empty()) {
|
||||
err << "anonymous empty time area";
|
||||
} else {
|
||||
err << "anonymous time area at (" << hexes.begin()->wml_x() << ',' << hexes.begin()->wml_y() << ")";
|
||||
}
|
||||
} else {
|
||||
err << "time area with id=" << id;
|
||||
}
|
||||
}
|
||||
lua_push(L, err.str());
|
||||
return lua_error(L);
|
||||
}
|
||||
int n = std::distance(times.begin(), iter);
|
||||
if(area_index < 0) {
|
||||
tod_man().set_current_time(n);
|
||||
} else {
|
||||
tod_man().set_current_time(n, area_index);
|
||||
}
|
||||
}
|
||||
if(area_index >= 0) {
|
||||
modify_string_attrib("id", tod_man().set_area_id(area_index, value));
|
||||
if(strcmp(m, "hexes") == 0) {
|
||||
auto hexes = luaW_check_locationset(L, 3);
|
||||
tod_man().replace_area_locations(area_index, hexes);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
// Assign nil to reset the bonus to the default (best) value
|
||||
if(lua_isnil(L, 3) && strcmp(m, "liminal_bonus") == 0) {
|
||||
tod_man().reset_max_liminal_bonus();
|
||||
return 0;
|
||||
}
|
||||
modify_int_attrib("liminal_bonus", tod_man().set_max_liminal_bonus(value));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets details about a terrain.
|
||||
* - Arg 1: terrain code string.
|
||||
@ -880,79 +1048,49 @@ int game_lua_kernel::impl_get_terrain_info(lua_State *L)
|
||||
|
||||
/**
|
||||
* Gets time of day information.
|
||||
* - Arg 1: optional turn number
|
||||
* - Arg 2: optional location
|
||||
* - Arg 3: optional boolean (consider_illuminates)
|
||||
* - Arg 1: schedule object, location, time area ID, or nil
|
||||
* - Arg 2: optional turn number
|
||||
* - Ret 1: table.
|
||||
*/
|
||||
template<bool consider_illuminates>
|
||||
int game_lua_kernel::intf_get_time_of_day(lua_State *L)
|
||||
{
|
||||
unsigned arg = 1;
|
||||
|
||||
int for_turn = tod_man().turn();
|
||||
map_location loc = map_location();
|
||||
bool consider_illuminates = false;
|
||||
|
||||
if(lua_isnumber(L, arg)) {
|
||||
++arg;
|
||||
if(luaW_tolocation(L, 1, loc)) {
|
||||
if(!board().map().on_board_with_border(loc)) {
|
||||
return luaL_argerror(L, 1, "coordinates are not on board");
|
||||
}
|
||||
} else if(lua_isstring(L, 1)) {
|
||||
auto area = tod_man().get_area_by_id(lua_tostring(L, 1));
|
||||
if(area.empty()) {
|
||||
return luaL_error(L, "invalid or empty time_area ID");
|
||||
}
|
||||
// We just need SOME location in that area, it doesn't matter which one.
|
||||
loc = *area.begin();
|
||||
} else if(!lua_isnil(L, 1)) {
|
||||
auto area = tod_man().get_area_by_index(luaW_check_schedule(L, 1));
|
||||
if(area.empty()) {
|
||||
return luaL_error(L, "empty time_area");
|
||||
}
|
||||
// We just need SOME location in that area, it doesn't matter which one.
|
||||
loc = *area.begin();
|
||||
}
|
||||
|
||||
if(lua_isnumber(L, 2)) {
|
||||
for_turn = luaL_checkinteger(L, 1);
|
||||
int number_of_turns = tod_man().number_of_turns();
|
||||
if(for_turn < 1 || (number_of_turns != -1 && for_turn > number_of_turns)) {
|
||||
return luaL_argerror(L, 1, "turn number out of range");
|
||||
}
|
||||
}
|
||||
else if(lua_isnil(L, arg)) ++arg;
|
||||
|
||||
if(luaW_tolocation(L, arg, loc)) {
|
||||
if(!board().map().on_board(loc)) return luaL_argerror(L, arg, "coordinates are not on board");
|
||||
|
||||
if(lua_istable(L, arg)) {
|
||||
lua_rawgeti(L, arg, 3);
|
||||
consider_illuminates = luaW_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
} else if(lua_isboolean(L, arg + 1)) {
|
||||
consider_illuminates = luaW_toboolean(L, arg + 1);
|
||||
}
|
||||
}
|
||||
|
||||
const time_of_day& tod = consider_illuminates ?
|
||||
tod_man().get_illuminated_time_of_day(board().units(), board().map(), loc, for_turn) :
|
||||
tod_man().get_time_of_day(loc, for_turn);
|
||||
|
||||
lua_newtable(L);
|
||||
lua_pushstring(L, tod.id.c_str());
|
||||
lua_setfield(L, -2, "id");
|
||||
lua_pushinteger(L, tod.lawful_bonus);
|
||||
lua_setfield(L, -2, "lawful_bonus");
|
||||
lua_pushinteger(L, tod.bonus_modified);
|
||||
lua_setfield(L, -2, "bonus_modified");
|
||||
lua_pushstring(L, tod.image.c_str());
|
||||
lua_setfield(L, -2, "image");
|
||||
luaW_pushtstring(L, tod.name);
|
||||
lua_setfield(L, -2, "name");
|
||||
lua_pushstring(L, tod.sounds.c_str());
|
||||
lua_setfield(L, -2, "sound");
|
||||
lua_pushstring(L, tod.image_mask.c_str());
|
||||
lua_setfield(L, -2, "mask");
|
||||
|
||||
lua_pushinteger(L, tod.color.r);
|
||||
lua_setfield(L, -2, "red");
|
||||
lua_pushinteger(L, tod.color.g);
|
||||
lua_setfield(L, -2, "green");
|
||||
lua_pushinteger(L, tod.color.b);
|
||||
lua_setfield(L, -2, "blue");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the max liminal bonus
|
||||
* - Ret 1: integer.
|
||||
*/
|
||||
int game_lua_kernel::intf_get_max_liminal_bonus(lua_State *L)
|
||||
{
|
||||
int bonus = tod_man().get_max_liminal_bonus();
|
||||
lua_pushinteger(L, bonus);
|
||||
luaW_push_tod(L, tod);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -1400,6 +1538,10 @@ int game_lua_kernel::impl_current_get(lua_State *L)
|
||||
if(strcmp(m, "map") == 0) {
|
||||
return intf_terrainmap_get(L);
|
||||
}
|
||||
if(strcmp(m, "schedule") == 0) {
|
||||
luaW_push_schedule(L, -1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strcmp(m, "event_context") == 0)
|
||||
{
|
||||
@ -3620,70 +3762,51 @@ int game_lua_kernel::intf_remove_time_area(lua_State * L)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int game_lua_kernel::intf_get_time_area(lua_State* L)
|
||||
{
|
||||
map_location loc;
|
||||
if(luaW_tolocation(L, 1, loc)) {
|
||||
int area_index = tod_man().get_area_on_hex(loc).first;
|
||||
if(area_index < 0) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
luaW_push_schedule(L, area_index);
|
||||
return 1;
|
||||
} else {
|
||||
std::string area_id = luaL_checkstring(L, 1);
|
||||
const auto& area_ids = tod_man().get_area_ids();
|
||||
if(auto iter = std::find(area_ids.begin(), area_ids.end(), area_id); iter == area_ids.end()) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
} else {
|
||||
luaW_push_schedule(L, std::distance(area_ids.begin(), iter));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Replacing the current time of day schedule. */
|
||||
int game_lua_kernel::intf_replace_schedule(lua_State * L)
|
||||
{
|
||||
vconfig cfg = luaW_checkvconfig(L, 1);
|
||||
|
||||
if(cfg.get_children("time").empty()) {
|
||||
ERR_LUA << "attempted to to replace ToD schedule with empty schedule" << std::endl;
|
||||
map_location loc;
|
||||
if(luaW_tolocation(L, 1, loc)) {
|
||||
// Replace the global schedule with a time area's schedule
|
||||
// The expectation is that you call schedule.replace(time_area.schedule),
|
||||
// rather than passing a literal location.
|
||||
|
||||
} else {
|
||||
tod_man().replace_schedule(cfg.get_parsed_config());
|
||||
if (game_display_) {
|
||||
game_display_->new_turn();
|
||||
}
|
||||
LOG_LUA << "replaced ToD schedule\n";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
vconfig cfg = luaW_checkvconfig(L, 1);
|
||||
|
||||
int game_lua_kernel::intf_set_time_of_day(lua_State * L)
|
||||
{
|
||||
if(!game_display_) {
|
||||
return 0;
|
||||
}
|
||||
std::string area_id;
|
||||
std::size_t area_i = 0;
|
||||
if (lua_isstring(L, 2)) {
|
||||
area_id = lua_tostring(L, 1);
|
||||
std::vector<std::string> area_ids = tod_man().get_area_ids();
|
||||
area_i = std::distance(area_ids.begin(), std::find(area_ids.begin(), area_ids.end(), area_id));
|
||||
if(area_i >= area_ids.size()) {
|
||||
return luaL_argerror(L, 1, "invalid time area ID");
|
||||
}
|
||||
}
|
||||
int is_num = false;
|
||||
int new_time = lua_tonumberx(L, 1, &is_num) - 1;
|
||||
const std::vector<time_of_day>& times = area_id.empty()
|
||||
? tod_man().times()
|
||||
: tod_man().times(area_i);
|
||||
int num_times = times.size();
|
||||
if(!is_num) {
|
||||
std::string time_id = luaL_checkstring(L, 1);
|
||||
new_time = 0;
|
||||
for(const time_of_day& time : times) {
|
||||
if(time_id == time.id) {
|
||||
break;
|
||||
if(cfg.get_children("time").empty()) {
|
||||
ERR_LUA << "attempted to to replace ToD schedule with empty schedule" << std::endl;
|
||||
} else {
|
||||
tod_man().replace_schedule(cfg.get_parsed_config());
|
||||
if (game_display_) {
|
||||
game_display_->new_turn();
|
||||
}
|
||||
new_time++;
|
||||
LOG_LUA << "replaced ToD schedule\n";
|
||||
}
|
||||
if(new_time >= num_times) {
|
||||
return luaL_argerror(L, 1, "invalid time of day ID");
|
||||
}
|
||||
}
|
||||
|
||||
if(new_time == 0 && num_times == 0) {
|
||||
//ignore this case, because we don't want code like set_current_time(get_current_time()) to fail if num_times is 0.
|
||||
return 0;
|
||||
}
|
||||
if(new_time < 0 || new_time >= num_times) {
|
||||
return luaL_argerror(L, 1, "invalid time of day index");
|
||||
}
|
||||
|
||||
if(area_id.empty()) {
|
||||
tod_man().set_current_time(new_time);
|
||||
} else {
|
||||
tod_man().set_current_time(new_time, area_i);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -4020,16 +4143,12 @@ game_lua_kernel::game_lua_kernel(game_state & gs, play_controller & pc, reports
|
||||
{ "find_vision_range", &dispatch<&game_lua_kernel::intf_find_vision_range > },
|
||||
{ "fire_event", &dispatch2<&game_lua_kernel::intf_fire_event, false > },
|
||||
{ "fire_event_by_id", &dispatch2<&game_lua_kernel::intf_fire_event, true > },
|
||||
{ "get_time_of_day", &dispatch<&game_lua_kernel::intf_get_time_of_day > },
|
||||
{ "get_max_liminal_bonus", &dispatch<&game_lua_kernel::intf_get_max_liminal_bonus > },
|
||||
{ "log_replay", &dispatch<&game_lua_kernel::intf_log_replay > },
|
||||
{ "log", &dispatch<&game_lua_kernel::intf_log > },
|
||||
{ "message", &dispatch<&game_lua_kernel::intf_message > },
|
||||
{ "print", &dispatch<&game_lua_kernel::intf_print > },
|
||||
{ "redraw", &dispatch<&game_lua_kernel::intf_redraw > },
|
||||
{ "remove_event_handler", &dispatch<&game_lua_kernel::intf_remove_event > },
|
||||
{ "replace_schedule", &dispatch<&game_lua_kernel::intf_replace_schedule > },
|
||||
{ "set_time_of_day", &dispatch<&game_lua_kernel::intf_set_time_of_day > },
|
||||
{ "simulate_combat", &dispatch<&game_lua_kernel::intf_simulate_combat > },
|
||||
{ "synchronize_choice", &intf_synchronize_choice },
|
||||
{ "synchronize_choices", &intf_synchronize_choices },
|
||||
@ -4271,6 +4390,22 @@ game_lua_kernel::game_lua_kernel(game_state & gs, play_controller & pc, reports
|
||||
luaL_setfuncs(L, audio_callbacks, 0);
|
||||
lua_setfield(L, -2, "audio");
|
||||
lua_pop(L, 1);
|
||||
|
||||
// Create the schedule module
|
||||
cmd_log_ << "Adding schedule module...\n";
|
||||
static luaL_Reg const schedule_callbacks[] {
|
||||
{ "get_time_of_day", &dispatch<&game_lua_kernel::intf_get_time_of_day<false>>},
|
||||
{ "get_illumination", &dispatch<&game_lua_kernel::intf_get_time_of_day<true>>},
|
||||
{ "replace", &dispatch<&game_lua_kernel::intf_replace_schedule>},
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
lua_getglobal(L, "wesnoth");
|
||||
lua_newtable(L);
|
||||
luaL_setfuncs(L, schedule_callbacks, 0);
|
||||
lua_createtable(L, 0, 2);
|
||||
lua_setmetatable(L, -2);
|
||||
lua_setfield(L, -2, "schedule");
|
||||
lua_pop(L, 1);
|
||||
|
||||
// Create the playlist table with its metatable
|
||||
cmd_log_ << lua_audio::register_table(L);
|
||||
|
@ -74,6 +74,7 @@ class game_lua_kernel : public lua_kernel_base
|
||||
int intf_cancel_action(lua_State *);
|
||||
int intf_add_time_area(lua_State *);
|
||||
int intf_remove_time_area(lua_State *);
|
||||
int intf_get_time_area(lua_State *);
|
||||
int intf_animate_unit(lua_State *);
|
||||
int intf_gamestate_inspector(lua_State *);
|
||||
int impl_run_animation(lua_State *);
|
||||
@ -93,8 +94,11 @@ class game_lua_kernel : public lua_kernel_base
|
||||
int intf_view_locked(lua_State *L);
|
||||
int intf_lock_view(lua_State *L);
|
||||
int impl_get_terrain_info(lua_State *L);
|
||||
template<bool consider_illuminates>
|
||||
int intf_get_time_of_day(lua_State *L);
|
||||
int intf_get_max_liminal_bonus(lua_State *L);
|
||||
int impl_schedule_get(lua_State *L);
|
||||
int impl_schedule_len(lua_State *L);
|
||||
void luaW_push_schedule(lua_State* L, int area_index);
|
||||
int intf_get_village_owner(lua_State *L);
|
||||
int intf_set_village_owner(lua_State *L);
|
||||
int intf_get_map_size(lua_State *L);
|
||||
@ -154,7 +158,7 @@ class game_lua_kernel : public lua_kernel_base
|
||||
int intf_get_label(lua_State* L);
|
||||
int intf_redraw(lua_State *L);
|
||||
int intf_replace_schedule(lua_State *l);
|
||||
int intf_set_time_of_day(lua_State *L);
|
||||
int impl_schedule_set(lua_State *L);
|
||||
int intf_scroll(lua_State *L);
|
||||
int intf_get_all_vars(lua_State *L);
|
||||
int impl_theme_item(lua_State *L, std::string name);
|
||||
|
@ -730,6 +730,39 @@ map_location luaW_checklocation(lua_State *L, int index)
|
||||
return result;
|
||||
}
|
||||
|
||||
int luaW_push_locationset(lua_State* L, const std::set<map_location>& locs)
|
||||
{
|
||||
lua_createtable(L, locs.size(), 0);
|
||||
int i = 1;
|
||||
for(const map_location& loc : locs) {
|
||||
lua_createtable(L, 2, 0);
|
||||
lua_pushinteger(L, loc.wml_x());
|
||||
lua_rawseti(L, -2, 1);
|
||||
lua_pushinteger(L, loc.wml_y());
|
||||
lua_rawseti(L, -2, 2);
|
||||
lua_rawseti(L, -2, i);
|
||||
++i;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::set<map_location> luaW_check_locationset(lua_State* L, int idx)
|
||||
{
|
||||
std::set<map_location> locs;
|
||||
if(!lua_istable(L, idx)) {
|
||||
luaW_type_error(L, idx, "array of locations");
|
||||
}
|
||||
lua_len(L, idx);
|
||||
int len = luaL_checkinteger(L, -1);
|
||||
for(int i = 1; i < len; i++) {
|
||||
lua_geti(L, idx, i);
|
||||
locs.insert(luaW_checklocation(L, -1));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
return locs;
|
||||
|
||||
}
|
||||
|
||||
void luaW_pushconfig(lua_State *L, const config& cfg)
|
||||
{
|
||||
lua_newtable(L);
|
||||
|
@ -114,6 +114,16 @@ bool luaW_tolocation(lua_State *L, int index, map_location &loc);
|
||||
*/
|
||||
map_location luaW_checklocation(lua_State *L, int index);
|
||||
|
||||
/**
|
||||
* Converts a set of map locations to a Lua table pushed at the top of the stack.
|
||||
*/
|
||||
int luaW_push_locationset(lua_State* L, const std::set<map_location>& locs);
|
||||
|
||||
/**
|
||||
* Converts a table of integer pairs to a set of map location objects.
|
||||
*/
|
||||
std::set<map_location> luaW_check_locationset(lua_State* L, int idx);
|
||||
|
||||
/**
|
||||
* Converts a config object to a Lua table pushed at the top of the stack.
|
||||
*/
|
||||
|
@ -162,25 +162,6 @@ namespace {
|
||||
|
||||
} //end namespace
|
||||
|
||||
static int luaW_push_locationset(lua_State* L, const std::set<map_location>& locs)
|
||||
{
|
||||
LOG_LMG << "push_locationset\n";
|
||||
lua_createtable(L, locs.size(), 0);
|
||||
int i = 1;
|
||||
for (const map_location& loc : locs)
|
||||
{
|
||||
lua_createtable(L, 2, 0);
|
||||
lua_pushinteger(L, loc.wml_x());
|
||||
lua_rawseti(L, -2, 1);
|
||||
lua_pushinteger(L, loc.wml_y());
|
||||
lua_rawseti(L, -2, 2);
|
||||
lua_rawseti(L, -2, i);
|
||||
++i;
|
||||
}
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
static std::set<map_location> luaW_to_locationset(lua_State* L, int index)
|
||||
{
|
||||
std::set<map_location> res;
|
||||
|
@ -205,6 +205,15 @@ const time_of_day& tod_manager::get_time_of_day(const map_location& loc, int n_t
|
||||
return get_time_of_day_turn(times_, n_turn, currentTime_);
|
||||
}
|
||||
|
||||
const time_of_day& tod_manager::get_area_time_of_day(int area_i, int n_turn) const
|
||||
{
|
||||
assert(area_i < static_cast<int>(areas_.size()));
|
||||
if(n_turn == 0) {
|
||||
n_turn = turn_;
|
||||
}
|
||||
return get_time_of_day_turn(areas_[area_i].times, n_turn, areas_[area_i].currentTime);
|
||||
}
|
||||
|
||||
const time_of_day tod_manager::get_illuminated_time_of_day(
|
||||
const unit_map& units, const gamemap& map, const map_location& loc, int for_turn) const
|
||||
{
|
||||
@ -324,6 +333,12 @@ void tod_manager::set_area_id(int area_index, const std::string& id)
|
||||
areas_[area_index].id = id;
|
||||
}
|
||||
|
||||
const std::string& tod_manager::get_area_id(int area_index) const
|
||||
{
|
||||
assert(area_index < static_cast<int>(areas_.size()));
|
||||
return areas_[area_index].id;
|
||||
}
|
||||
|
||||
std::vector<std::string> tod_manager::get_area_ids() const
|
||||
{
|
||||
std::vector<std::string> areas;
|
||||
@ -351,6 +366,19 @@ const std::set<map_location>& tod_manager::get_area_by_index(int index) const
|
||||
return areas_[index].hexes;
|
||||
}
|
||||
|
||||
std::pair<int, std::string> tod_manager::get_area_on_hex(const map_location& loc) const
|
||||
{
|
||||
if(loc != map_location::null_location()) {
|
||||
for(auto i = areas_.rbegin(), i_end = areas_.rend();
|
||||
i != i_end; ++i) {
|
||||
if(i->hexes.find(loc) != i->hexes.end() && !i->times.empty())
|
||||
return {std::distance(areas_.rbegin(), i), i->id};
|
||||
}
|
||||
}
|
||||
|
||||
return {-1, ""};
|
||||
}
|
||||
|
||||
void tod_manager::add_time_area(const gamemap& map, const config& cfg)
|
||||
{
|
||||
areas_.emplace_back();
|
||||
|
@ -46,6 +46,7 @@ class tod_manager
|
||||
void set_current_time(int time, int area_index);
|
||||
void set_current_time(int time, const std::string& area_id);
|
||||
void set_area_id(int area_index, const std::string& id);
|
||||
const std::string& get_area_id(int area_index) const;
|
||||
|
||||
/**
|
||||
* Returns global time of day for the passed turn.
|
||||
@ -60,8 +61,12 @@ class tod_manager
|
||||
* tod areas matter, for_turn = 0 means current turn
|
||||
* ignoring illumination
|
||||
*/
|
||||
const time_of_day& get_time_of_day(const map_location& loc,
|
||||
int for_turn = 0) const;
|
||||
const time_of_day& get_time_of_day(const map_location& loc, int for_turn = 0) const;
|
||||
/**
|
||||
* Returns time of day for the passed turn in the specified tod area.
|
||||
* for_turn = 0 means current turn, ignoring illumination
|
||||
*/
|
||||
const time_of_day& get_area_time_of_day(int area_i, int for_turn = 0) const;
|
||||
|
||||
int get_current_area_time(int index) const;
|
||||
|
||||
@ -102,6 +107,11 @@ class tod_manager
|
||||
*/
|
||||
const std::set<map_location>& get_area_by_id(const std::string& id) const;
|
||||
|
||||
/**
|
||||
* @returns the area ID and index active on the given location.
|
||||
*/
|
||||
std::pair<int, std::string> get_area_on_hex(const map_location& loc) const;
|
||||
|
||||
/**
|
||||
* Adds a new local time area from config, making it follow its own
|
||||
* time-of-day sequence.
|
||||
@ -181,6 +191,14 @@ class tod_manager
|
||||
{ return has_tod_bonus_changed_; }
|
||||
int get_max_liminal_bonus() const
|
||||
{ return liminal_bonus_; }
|
||||
void set_max_liminal_bonus(int bonus) {
|
||||
liminal_bonus_ = bonus;
|
||||
has_cfg_liminal_bonus_ = true;
|
||||
}
|
||||
void reset_max_liminal_bonus() {
|
||||
liminal_bonus_ = calculate_best_liminal_bonus(times());
|
||||
has_cfg_liminal_bonus_ = false;
|
||||
}
|
||||
private:
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user