diff --git a/projectfiles/VC14/wesnoth.vcxproj b/projectfiles/VC14/wesnoth.vcxproj index 7d56e95abea9..b29784718fce 100644 --- a/projectfiles/VC14/wesnoth.vcxproj +++ b/projectfiles/VC14/wesnoth.vcxproj @@ -2624,6 +2624,9 @@ $(IntDir)Scripting\ $(IntDir)Scripting\ + + $(IntDir)Scripting\ + $(IntDir)Scripting\ $(IntDir)Scripting\ diff --git a/projectfiles/VC16/wesnoth.vcxproj b/projectfiles/VC16/wesnoth.vcxproj index 94e3391281ce..4d85939345d5 100644 --- a/projectfiles/VC16/wesnoth.vcxproj +++ b/projectfiles/VC16/wesnoth.vcxproj @@ -2634,6 +2634,9 @@ $(IntDir)Scripting\ $(IntDir)Scripting\ + + $(IntDir)Scripting\ + $(IntDir)Scripting\ $(IntDir)Scripting\ @@ -3981,6 +3984,7 @@ + diff --git a/source_lists/wesnoth b/source_lists/wesnoth index 088e5c3bdc71..f9629aa70e00 100644 --- a/source_lists/wesnoth +++ b/source_lists/wesnoth @@ -310,6 +310,7 @@ scripting/application_lua_kernel.cpp scripting/debug_lua.cpp scripting/game_lua_kernel.cpp scripting/lua_audio.cpp +scripting/lua_color.cpp scripting/lua_common.cpp scripting/lua_cpp_function.cpp scripting/lua_fileops.cpp diff --git a/src/scripting/lua_color.cpp b/src/scripting/lua_color.cpp new file mode 100644 index 000000000000..f44ebb98eb0c --- /dev/null +++ b/src/scripting/lua_color.cpp @@ -0,0 +1,174 @@ +/* +Copyright (C) 2020-2020 by the Battle for Wesnoth Project https://www.wesnoth.org/ + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY. + +See the COPYING file for more details. +*/ + +#include "color_range.hpp" +#include "scripting/lua_color.hpp" +#include "scripting/lua_common.hpp" +#include "scripting/push_check.hpp" +#include "lua/lauxlib.h" +#include "lua/lua.h" // for lua_State, lua_settop, etc +#include "log.hpp" +#include "game_config.hpp" + +static lg::log_domain log_scripting_lua("scripting/lua"); +#define LOG_LUA LOG_STREAM(info, log_scripting_lua) +#define ERR_LUA LOG_STREAM(err, log_scripting_lua) + +static const char colorKey[] = "color range"; + +bool luaW_iscolor(lua_State* L, int index) +{ + return luaL_testudata(L, index, colorKey) != nullptr; +} + +static color_range& LuaW_checkcolor(lua_State *L, int index) +{ + if(!luaW_iscolor(L, index)) { + luaW_type_error(L, index, "color"); + throw "luaW_type_error returned"; + } + return *static_cast(lua_touserdata(L, index)); +} + + +color_range* luaW_pushcolor(lua_State *L, const color_range& color) +{ + color_range* res = new(L) color_range(color); + luaL_setmetatable(L, colorKey); + return res; +} + +int luaW_pushsinglecolor(lua_State *L, const color_t& color) +{ + lua_createtable(L, 0, 4); + luaW_table_set(L, -1, "r", color.r); + luaW_table_set(L, -1, "g", color.g); + luaW_table_set(L, -1, "b", color.b); + luaW_table_set(L, -1, "a", color.a); + return 1; +} + +static int impl_color_collect(lua_State *L) +{ + color_range *c = static_cast(lua_touserdata(L, 1)); + c->color_range::~color_range(); + return 0; +} + +/** + * Checks two color units for equality. (__eq metamethod) + */ +static int impl_color_equality(lua_State* L) +{ + color_range& left = LuaW_checkcolor(L, 1); + color_range& right = LuaW_checkcolor(L, 2); + const bool equal = left == right; + lua_pushboolean(L, equal); + return 1; +} + +/** + * Turns a lua color to string. (__tostring metamethod) + */ +static int impl_color_tostring(lua_State* L) +{ + color_range& c = LuaW_checkcolor(L, 1); + //TODO: is this the best way to call tostring? + lua_push(L, c.debug()); + return 1; +} + + +/** + * - Arg 1: userdata (ignored). + * - Arg 2: string containing the name of the color. + * - Ret 1: color_range containing the color. + */ +static int impl_get_color(lua_State *L) +{ + std::string color_id = luaL_checkstring(L, 2); + luaW_pushcolor(L, game_config::color_info(color_id)); + return 1; +} + +static int impl_color_get(lua_State *L) +{ + color_range& c = LuaW_checkcolor(L, 1); + char const *m = luaL_checkstring(L, 2); + + if(strcmp(m, "min") == 0) { + return luaW_pushsinglecolor(L, c.min()); + } + if(strcmp(m, "max") == 0) { + return luaW_pushsinglecolor(L, c.max()); + } + if(strcmp(m, "mid") == 0) { + return luaW_pushsinglecolor(L, c.mid()); + } + if(strcmp(m, "minimap") == 0) { + return luaW_pushsinglecolor(L, c.rep()); + } + // TODO: i think this shortcut would be useful, but im not sure yet on the best attribute name. + //if(strcmp(m, "pango_hex") == 0) { + // lua_push(L, c.mid().to_hex_string()); + // return 1; + //} + return 0; +} + +static int impl_color_set(lua_State *L) +{ + return luaL_argerror(L, 2, "color objects canot be modified"); +} + +namespace lua_colors { + std::string register_metatables(lua_State* L) + { + std::ostringstream cmd_out; + + // Create the getunit metatable. + cmd_out << "Adding color metatable...\n"; + + luaL_newmetatable(L, colorKey); + lua_pushcfunction(L, impl_color_collect); + lua_setfield(L, -2, "__gc"); + lua_pushcfunction(L, impl_color_equality); + lua_setfield(L, -2, "__eq"); + lua_pushcfunction(L, impl_color_tostring); + lua_setfield(L, -2, "__tostring"); + lua_pushcfunction(L, impl_color_get); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, impl_color_set); + lua_setfield(L, -2, "__newindex"); + lua_pushstring(L, "color range"); + lua_setfield(L, -2, "__metatable"); + + + // Create the current variable with its metatable. + cmd_out << "Adding wesnoth.colors table...\n"; + + lua_getglobal(L, "wesnoth"); + lua_newuserdata(L, 0); + lua_createtable(L, 0, 2); + lua_pushcfunction(L, impl_get_color); + lua_setfield(L, -2, "__index"); + lua_pushstring(L, "colors table"); + lua_setfield(L, -2, "__metatable"); + lua_setmetatable(L, -2); + lua_setfield(L, -2, "colors"); + lua_pop(L, 1); + + return cmd_out.str(); + } +} + diff --git a/src/scripting/lua_color.hpp b/src/scripting/lua_color.hpp new file mode 100644 index 000000000000..fe5c0a438bf2 --- /dev/null +++ b/src/scripting/lua_color.hpp @@ -0,0 +1,19 @@ +/* +Copyright (C) 2020-2020 by the Battle for Wesnoth Project https://www.wesnoth.org/ + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY. + +See the COPYING file for more details. +*/ + +#include +struct lua_State; + +namespace lua_colors { + std::string register_metatables(lua_State* L); +} \ No newline at end of file diff --git a/src/scripting/lua_kernel_base.cpp b/src/scripting/lua_kernel_base.cpp index 76ac91412b43..431c2566d4ee 100644 --- a/src/scripting/lua_kernel_base.cpp +++ b/src/scripting/lua_kernel_base.cpp @@ -28,6 +28,7 @@ #include "scripting/debug_lua.hpp" #endif +#include "scripting/lua_color.hpp" #include "scripting/lua_common.hpp" #include "scripting/lua_cpp_function.hpp" #include "scripting/lua_fileops.hpp" @@ -570,6 +571,8 @@ lua_kernel_base::lua_kernel_base() // Create formula bridge metatables cmd_log_ << lua_formula_bridge::register_metatables(L); + cmd_log_ << lua_colors::register_metatables(L); + // Create the Lua interpreter table cmd_log_ << "Sandboxing Lua interpreter...\nTo make variables visible outside the interpreter, assign to _G.variable.\n"; cmd_log_ << "The special variable _ holds the result of the last expression (if any).\n"; diff --git a/src/scripting/push_check.hpp b/src/scripting/push_check.hpp index 6c0f6a0bc6b3..5691bda9f476 100644 --- a/src/scripting/push_check.hpp +++ b/src/scripting/push_check.hpp @@ -397,3 +397,17 @@ lua_check_impl::remove_constref luaW_table_get_def(lua_State *L, int index, u lua_pop(L, 1); return res; } + + +template +void luaW_table_set(lua_State *L, int index, utils::string_view k, const T& value) +{ + if(!lua_istable(L, index)) { + luaL_argerror(L, index, "table expected"); + } + + index = lua_absindex(L, index); + lua_pushlstring(L, k.data(), k.size()); + lua_push(L, value); + lua_settable(L, index); +}