Merge pull request #744 from lua_refactor

Refactor some Lua stuff and reduce const_cast usage

Conflicts:
	src/scripting/game_lua_kernel.cpp
	src/scripting/lua_unit.cpp
This commit is contained in:
Celtic Minstrel 2016-08-24 02:41:53 -04:00
commit e821e508c3
36 changed files with 1157 additions and 1153 deletions

View file

@ -164,6 +164,10 @@
9193FC7B1D5AE5B2004F6C07 /* name_generator_factory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 913D26751D3C9697002FF3AB /* name_generator_factory.cpp */; };
9193FC7E1D5BB64F004F6C07 /* advancement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9193FC7C1D5BB64E004F6C07 /* advancement.cpp */; };
9193FC7F1D5BB64F004F6C07 /* advancement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9193FC7C1D5BB64E004F6C07 /* advancement.cpp */; };
9193FC821D5C2CF8004F6C07 /* lua_unit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9193FC801D5C2CF7004F6C07 /* lua_unit.cpp */; };
9193FC831D5C2D00004F6C07 /* lua_unit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9193FC801D5C2CF7004F6C07 /* lua_unit.cpp */; };
9193FC861D5D7461004F6C07 /* lua_unit_attacks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9193FC841D5D7452004F6C07 /* lua_unit_attacks.cpp */; };
9193FC871D5D7461004F6C07 /* lua_unit_attacks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9193FC841D5D7452004F6C07 /* lua_unit_attacks.cpp */; };
919B37F81BAF789E00E0094C /* synced_user_choice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 919B37F71BAF789D00E0094C /* synced_user_choice.cpp */; };
919B37FC1BAF7A9D00E0094C /* synced_choice_wait.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 919B37FA1BAF7A9D00E0094C /* synced_choice_wait.cpp */; };
91A214E51CAD666B00927AEA /* arrow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B52EE8A1121359A600CFBDAB /* arrow.cpp */; };
@ -268,7 +272,6 @@
91A215601CAD6A8B00927AEA /* lzio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EC89A1281879D17D00A3B0B1 /* lzio.cpp */; };
91A215621CAD6DA400927AEA /* application_lua_kernel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EC218E9A1A1064F4007C910C /* application_lua_kernel.cpp */; };
91A215631CAD6DA400927AEA /* game_lua_kernel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EC218EA21A106673007C910C /* game_lua_kernel.cpp */; };
91A215641CAD6DA400927AEA /* lua_api.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F4C02A0D182F1F64008525C6 /* lua_api.cpp */; };
91A215651CAD6DA400927AEA /* lua_common.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EC218E9E1A106648007C910C /* lua_common.cpp */; };
91A215661CAD6DA400927AEA /* lua_cpp_function.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ECD5D7BE1A22DC8600114175 /* lua_cpp_function.cpp */; };
91A215671CAD6DA400927AEA /* lua_fileops.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ECA4A6781A1EC319006BCCF2 /* lua_fileops.cpp */; };
@ -278,7 +281,6 @@
91A2156B1CAD6DA400927AEA /* lua_race.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ECC2FFF91A51A00900023AF4 /* lua_race.cpp */; };
91A2156C1CAD6DA500927AEA /* lua_rng.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ECA4A67A1A1EC319006BCCF2 /* lua_rng.cpp */; };
91A2156D1CAD6DA500927AEA /* lua_team.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EC5430211A4E6024006D206C /* lua_team.cpp */; };
91A2156E1CAD6DA500927AEA /* lua_types.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F4C02A0E182F1F64008525C6 /* lua_types.cpp */; };
91A2156F1CAD6DA500927AEA /* lua_unit_type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EC5430221A4E6024006D206C /* lua_unit_type.cpp */; };
91A215701CAD6E7500927AEA /* context.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EC59F25F1A4529D2001910CB /* context.cpp */; };
91A215711CAD6E7500927AEA /* manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EC59F2601A4529D2001910CB /* manager.cpp */; };
@ -1259,8 +1261,6 @@
F480CD4B14035038007175D6 /* sourceparser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F480CD3C14035038007175D6 /* sourceparser.cpp */; };
F480CD4C14035038007175D6 /* tag.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F480CD3E14035038007175D6 /* tag.cpp */; };
F49F134A15BC627C00B64B0B /* edit_label.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F49F134815BC627C00B64B0B /* edit_label.cpp */; };
F4C02A10182F1F64008525C6 /* lua_api.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F4C02A0D182F1F64008525C6 /* lua_api.cpp */; };
F4C02A11182F1F64008525C6 /* lua_types.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F4C02A0E182F1F64008525C6 /* lua_types.cpp */; };
F4C5DD68158CFD5E0044F754 /* point.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F4C5DD66158CFD5E0044F754 /* point.cpp */; };
F4D2A99614DAED0E00CAFF31 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F4D2A99514DAED0E00CAFF31 /* CoreFoundation.framework */; };
F4D2A9D514DAED4200CAFF31 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F4D2A99514DAED0E00CAFF31 /* CoreFoundation.framework */; };
@ -1594,6 +1594,10 @@
9193FC781D5AC2D8004F6C07 /* game_stats.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = game_stats.hpp; sourceTree = "<group>"; };
9193FC7C1D5BB64E004F6C07 /* advancement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = advancement.cpp; sourceTree = "<group>"; };
9193FC7D1D5BB64E004F6C07 /* advancement.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = advancement.hpp; sourceTree = "<group>"; };
9193FC801D5C2CF7004F6C07 /* lua_unit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lua_unit.cpp; sourceTree = "<group>"; };
9193FC811D5C2CF8004F6C07 /* lua_unit.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = lua_unit.hpp; sourceTree = "<group>"; };
9193FC841D5D7452004F6C07 /* lua_unit_attacks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lua_unit_attacks.cpp; sourceTree = "<group>"; };
9193FC851D5D745D004F6C07 /* lua_unit_attacks.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = lua_unit_attacks.hpp; sourceTree = "<group>"; };
919B37F71BAF789D00E0094C /* synced_user_choice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = synced_user_choice.cpp; sourceTree = "<group>"; };
919B37F91BAF78AB00E0094C /* synced_user_choice.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = synced_user_choice.hpp; sourceTree = "<group>"; };
919B37FA1BAF7A9D00E0094C /* synced_choice_wait.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = synced_choice_wait.cpp; sourceTree = "<group>"; };
@ -2245,7 +2249,6 @@
B5A5E3E012132C790047782D /* lundump.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lundump.h; sourceTree = "<group>"; };
B5A5E3E212132C790047782D /* lvm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lvm.h; sourceTree = "<group>"; };
B5A5E3E412132C790047782D /* lzio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lzio.h; sourceTree = "<group>"; };
B5A5E45012132DE30047782D /* lua_api.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = lua_api.hpp; sourceTree = "<group>"; };
B5A9914A0ECA4064002BE442 /* fonts */ = {isa = PBXFileReference; lastKnownFileType = folder; name = fonts; path = ../../fonts; sourceTree = SOURCE_ROOT; };
B5A9B0780ECA4074002BE442 /* images */ = {isa = PBXFileReference; lastKnownFileType = folder; name = images; path = ../../images; sourceTree = SOURCE_ROOT; };
B5A9B2140ECA4074002BE442 /* sounds */ = {isa = PBXFileReference; lastKnownFileType = folder; name = sounds; path = ../../sounds; sourceTree = SOURCE_ROOT; };
@ -2656,7 +2659,6 @@
F480CD3F14035038007175D6 /* tag.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = tag.hpp; sourceTree = "<group>"; };
F49F134815BC627C00B64B0B /* edit_label.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = edit_label.cpp; sourceTree = "<group>"; };
F49F134915BC627C00B64B0B /* edit_label.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = edit_label.hpp; sourceTree = "<group>"; };
F4C02A0D182F1F64008525C6 /* lua_api.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lua_api.cpp; sourceTree = "<group>"; };
F4C02A0E182F1F64008525C6 /* lua_types.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lua_types.cpp; sourceTree = "<group>"; };
F4C02A0F182F1F64008525C6 /* lua_types.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = lua_types.hpp; sourceTree = "<group>"; };
F4C5DD66158CFD5E0044F754 /* point.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = point.cpp; sourceTree = "<group>"; };
@ -4125,8 +4127,6 @@
91B621E21B76BAF300B00E0F /* context.hpp */,
EC218EA21A106673007C910C /* game_lua_kernel.cpp */,
91B621E41B76BB0100B00E0F /* game_lua_kernel.hpp */,
F4C02A0D182F1F64008525C6 /* lua_api.cpp */,
B5A5E45012132DE30047782D /* lua_api.hpp */,
EC218E9E1A106648007C910C /* lua_common.cpp */,
91B621E51B76BB0700B00E0F /* lua_common.hpp */,
ECD5D7BE1A22DC8600114175 /* lua_cpp_function.cpp */,
@ -4148,8 +4148,10 @@
91B621EC1B76BB2200B00E0F /* lua_rng.hpp */,
EC5430211A4E6024006D206C /* lua_team.cpp */,
91B621ED1B76BB2600B00E0F /* lua_team.hpp */,
F4C02A0E182F1F64008525C6 /* lua_types.cpp */,
F4C02A0F182F1F64008525C6 /* lua_types.hpp */,
9193FC801D5C2CF7004F6C07 /* lua_unit.cpp */,
9193FC811D5C2CF8004F6C07 /* lua_unit.hpp */,
9193FC841D5D7452004F6C07 /* lua_unit_attacks.cpp */,
9193FC851D5D745D004F6C07 /* lua_unit_attacks.hpp */,
EC5430221A4E6024006D206C /* lua_unit_type.cpp */,
91B621EE1B76BB2C00B00E0F /* lua_unit_type.hpp */,
EC59F2601A4529D2001910CB /* manager.cpp */,
@ -4940,7 +4942,6 @@
EC89A1431879D17D00A3B0B1 /* ltable.cpp in Sources */,
EC89A1441879D17D00A3B0B1 /* ltablib.cpp in Sources */,
EC89A1451879D17D00A3B0B1 /* ltm.cpp in Sources */,
F4C02A10182F1F64008525C6 /* lua_api.cpp in Sources */,
EC218EA01A106648007C910C /* lua_common.cpp in Sources */,
ECD5D7BF1A22DC8600114175 /* lua_cpp_function.cpp in Sources */,
ECA4A67B1A1EC319006BCCF2 /* lua_fileops.cpp in Sources */,
@ -4954,7 +4955,6 @@
ECC2FFFA1A51A00900023AF4 /* lua_race.cpp in Sources */,
ECA4A67D1A1EC319006BCCF2 /* lua_rng.cpp in Sources */,
EC5430231A4E6024006D206C /* lua_team.cpp in Sources */,
F4C02A11182F1F64008525C6 /* lua_types.cpp in Sources */,
EC5430241A4E6024006D206C /* lua_unit_type.cpp in Sources */,
EC89A1481879D17D00A3B0B1 /* lundump.cpp in Sources */,
EC89A1491879D17D00A3B0B1 /* lvm.cpp in Sources */,
@ -5237,6 +5237,8 @@
9193FC791D5AC2D8004F6C07 /* game_stats.cpp in Sources */,
9193FC7E1D5BB64F004F6C07 /* advancement.cpp in Sources */,
917746C11D680C7C00E8689A /* walker_tree_node.cpp in Sources */,
9193FC821D5C2CF8004F6C07 /* lua_unit.cpp in Sources */,
9193FC861D5D7461004F6C07 /* lua_unit_attacks.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -5603,7 +5605,6 @@
91A215601CAD6A8B00927AEA /* lzio.cpp in Sources */,
91A215621CAD6DA400927AEA /* application_lua_kernel.cpp in Sources */,
91A215631CAD6DA400927AEA /* game_lua_kernel.cpp in Sources */,
91A215641CAD6DA400927AEA /* lua_api.cpp in Sources */,
91A215651CAD6DA400927AEA /* lua_common.cpp in Sources */,
91A215661CAD6DA400927AEA /* lua_cpp_function.cpp in Sources */,
91A215671CAD6DA400927AEA /* lua_fileops.cpp in Sources */,
@ -5613,7 +5614,6 @@
91A2156B1CAD6DA400927AEA /* lua_race.cpp in Sources */,
91A2156C1CAD6DA500927AEA /* lua_rng.cpp in Sources */,
91A2156D1CAD6DA500927AEA /* lua_team.cpp in Sources */,
91A2156E1CAD6DA500927AEA /* lua_types.cpp in Sources */,
91A2156F1CAD6DA500927AEA /* lua_unit_type.cpp in Sources */,
91A215701CAD6E7500927AEA /* context.cpp in Sources */,
91A215711CAD6E7500927AEA /* manager.cpp in Sources */,
@ -5809,6 +5809,8 @@
9193FC7B1D5AE5B2004F6C07 /* name_generator_factory.cpp in Sources */,
9193FC7F1D5BB64F004F6C07 /* advancement.cpp in Sources */,
917746C21D680C7C00E8689A /* walker_tree_node.cpp in Sources */,
9193FC831D5C2D00004F6C07 /* lua_unit.cpp in Sources */,
9193FC871D5D7461004F6C07 /* lua_unit_attacks.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View file

@ -383,8 +383,7 @@ void readonly_context_impl::calculate_moves(const unit_map& units, std::map<map_
continue;
}
// If it's an enemy unit, reset its moves while we do the calculations.
unit* held_unit = const_cast<unit *>(&*un_it);
const unit_movement_resetter move_resetter(*held_unit,enemy || assume_full_movement);
const unit_movement_resetter move_resetter(*un_it,enemy || assume_full_movement);
// Insert the trivial moves of staying on the same map location.
if (un_it->movement_left() > 0) {

View file

@ -30,7 +30,7 @@
#include "units/unit.hpp"
#include "pathfind/pathfind.hpp"
#include "units/filter.hpp"
#include "scripting/lua_api.hpp"
#include "scripting/lua_unit.hpp"
#include "lua/lauxlib.h"
namespace ai {
@ -479,10 +479,7 @@ config aspect_attacks_lua::to_config() const
static bool call_lua_filter_fcn(lua_State* L, const unit& u, int idx)
{
lua_rawgeti(L, LUA_REGISTRYINDEX, idx);
new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(u.underlying_id());
lua_pushlightuserdata(L, getunitKey);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_setmetatable(L, -2);
luaW_pushunit(L, u.underlying_id());
luaW_pcall(L, 1, 1);
bool result = luaW_toboolean(L, -1);
lua_pop(L, 1);

View file

@ -24,7 +24,7 @@
#include "ai/lua/core.hpp"
#include "ai/composite/aspect.hpp"
#include "scripting/game_lua_kernel.hpp"
#include "scripting/lua_api.hpp"
#include "scripting/lua_unit.hpp"
#include "scripting/push_check.hpp"
#include "lua_object.hpp" // (Nephro)
@ -50,7 +50,7 @@ static lg::log_domain log_ai_engine_lua("ai/engine/lua");
#define LOG_LUA LOG_STREAM(info, log_ai_engine_lua)
#define ERR_LUA LOG_STREAM(err, log_ai_engine_lua)
static char const aisKey = 0;
static char const aisKey[] = "ai contexts";
namespace ai {
@ -59,17 +59,15 @@ static void push_attack_analysis(lua_State *L, const attack_analysis&);
void lua_ai_context::init(lua_State *L)
{
// Create the ai elements table.
lua_pushlightuserdata(L, static_cast<void *>(const_cast<char *>(&aisKey)));
lua_newtable(L);
lua_rawset(L, LUA_REGISTRYINDEX);
lua_setfield(L, LUA_REGISTRYINDEX, aisKey);
}
void lua_ai_context::get_arguments(config &cfg) const
{
int top = lua_gettop(L);
lua_pushlightuserdata(L, static_cast<void *>(const_cast<char *>(&aisKey)));
lua_rawget(L, LUA_REGISTRYINDEX);
lua_getfield(L, LUA_REGISTRYINDEX, aisKey);
lua_rawgeti(L, -1, num_);
lua_getfield(L, -1, "params");
@ -82,8 +80,7 @@ void lua_ai_context::set_arguments(const config &cfg)
{
int top = lua_gettop(L);
lua_pushlightuserdata(L, static_cast<void *>(const_cast<char *>(&aisKey)));
lua_rawget(L, LUA_REGISTRYINDEX);
lua_getfield(L, LUA_REGISTRYINDEX, aisKey);
lua_rawgeti(L, -1, num_);
luaW_pushconfig(L, cfg);
@ -96,8 +93,7 @@ void lua_ai_context::get_persistent_data(config &cfg) const
{
int top = lua_gettop(L);
lua_pushlightuserdata(L, static_cast<void *>(const_cast<char *>(&aisKey)));
lua_rawget(L, LUA_REGISTRYINDEX);
lua_getfield(L, LUA_REGISTRYINDEX, aisKey);
lua_rawgeti(L, -1, num_);
lua_getfield(L, -1, "data");
@ -110,8 +106,7 @@ void lua_ai_context::set_persistent_data(const config &cfg)
{
int top = lua_gettop(L);
lua_pushlightuserdata(L, static_cast<void *>(const_cast<char *>(&aisKey)));
lua_rawget(L, LUA_REGISTRYINDEX);
lua_getfield(L, LUA_REGISTRYINDEX, aisKey);
lua_rawgeti(L, -1, num_);
luaW_pushconfig(L, cfg);
@ -955,8 +950,7 @@ static void generate_and_push_ai_table(lua_State* L, ai::engine_lua* engine) {
static size_t generate_and_push_ai_state(lua_State* L, ai::engine_lua* engine)
{
// Retrieve the ai elements table from the registry.
lua_pushlightuserdata(L, static_cast<void *>(const_cast<char *>(&aisKey)));
lua_rawget(L, LUA_REGISTRYINDEX); // [-1: AIs registry table]
lua_getfield(L, LUA_REGISTRYINDEX, aisKey); // [-1: AIs registry table]
size_t length_ai = lua_rawlen(L, -1); // length of table
lua_newtable(L); // [-1: AI state table -2: AIs registry table]
generate_and_push_ai_table(L, engine); // [-1: AI routines -2: AI state -3: AIs registry]
@ -1022,8 +1016,7 @@ lua_ai_action_handler* lua_ai_action_handler::create(lua_State *L, char const *c
}
// Retrieve the ai elements table from the registry.
lua_pushlightuserdata(L, static_cast<void *>(const_cast<char *>(&aisKey)));
lua_rawget(L, LUA_REGISTRYINDEX); //stack size is now 2 [-1: ais_table -2: f]
lua_getfield(L, LUA_REGISTRYINDEX, aisKey); //stack size is now 2 [-1: ais_table -2: f]
// Push the function in the table so that it is not collected.
size_t length = lua_rawlen(L, -1);//length of ais_table
lua_pushvalue(L, -2); //stack size is now 3: [-1: f -2: ais_table -3: f]
@ -1054,8 +1047,7 @@ lua_ai_load::lua_ai_load(lua_ai_context& ctx, bool read_only) : L(ctx.L), was_re
return; // Leave the AI table on the stack, as requested
}
lua_pop(L, 1); // Pop the nil value off the stack
lua_pushlightuserdata(L, static_cast<void *>(const_cast<char *>(&aisKey))); // [-1: key]
lua_rawget(L, LUA_REGISTRYINDEX); // [-1: AI registry]
lua_getfield(L, LUA_REGISTRYINDEX, aisKey); // [-1: AI registry]
lua_rawgeti(L, -1, ctx.num_); // [-1: AI state -2: AI registry]
lua_remove(L,-2); // [-1: AI state]
@ -1087,8 +1079,7 @@ lua_ai_load::~lua_ai_load()
lua_ai_context::~lua_ai_context()
{
// Remove the ai context from the registry, so that it can be collected.
lua_pushlightuserdata(L, static_cast<void *>(const_cast<char *>(&aisKey)));
lua_rawget(L, LUA_REGISTRYINDEX);
lua_getfield(L, LUA_REGISTRYINDEX, aisKey);
lua_pushnil(L);
lua_rawseti(L, -2, num_);
lua_pop(L, 1);
@ -1102,8 +1093,7 @@ void lua_ai_action_handler::handle(const config &cfg, bool read_only, lua_object
lua_ai_load ctx(context_, read_only); // [-1: AI state table]
// Load the user function from the registry.
lua_pushlightuserdata(L, static_cast<void *>(const_cast<char *>(&aisKey))); // [-1: key -2: AI state]
lua_rawget(L, LUA_REGISTRYINDEX); // [-1: AI registry -2: AI state]
lua_getfield(L, LUA_REGISTRYINDEX, aisKey); // [-1: AI registry -2: AI state]
lua_rawgeti(L, -1, num_); // [-1: AI action -2: AI registry -3: AI state]
lua_remove(L, -2); // [-1: AI action -2: AI state]
@ -1125,8 +1115,7 @@ void lua_ai_action_handler::handle(const config &cfg, bool read_only, lua_object
lua_ai_action_handler::~lua_ai_action_handler()
{
// Remove the function from the registry, so that it can be collected.
lua_pushlightuserdata(L, static_cast<void *>(const_cast<char *>(&aisKey)));
lua_rawget(L, LUA_REGISTRYINDEX);
lua_getfield(L, LUA_REGISTRYINDEX, aisKey);
lua_pushnil(L);
lua_rawseti(L, -2, num_);
lua_pop(L, 1);

View file

@ -21,7 +21,6 @@
#include "ai/lua/lua_object.hpp"
#include "ai/lua/engine_lua.hpp"
#include "ai/default/aspect_attacks.hpp"
#include "scripting/lua_types.hpp"
#include "scripting/lua_common.hpp"
#include "resources.hpp"

View file

@ -25,7 +25,6 @@
#include "lua/lua.h"
#include "map/location.hpp"
#include "resources.hpp"
#include "scripting/lua_api.hpp"
#include "scripting/lua_common.hpp"
#include "terrain/filter.hpp"
#include "variable.hpp"

View file

@ -863,8 +863,10 @@ void config::recursive_clear_value(const std::string& key)
values.erase(key);
for (const any_child &value : all_children_range()) {
const_cast<config *>(&value.cfg)->recursive_clear_value(key);
for(std::pair<const std::string, child_list>& p : children) {
for(config* cfg : p.second) {
cfg->recursive_clear_value(key);
}
}
}
@ -1339,8 +1341,10 @@ void config::clear_diff_track(const config& diff)
itor->second[index]->clear_diff_track(item.cfg);
}
}
for (const any_child &value : all_children_range()) {
const_cast<config *>(&value.cfg)->remove_attribute(diff_track_attribute);
for(std::pair<const std::string, child_list>& p : children) {
for(config* cfg : p.second) {
cfg->remove_attribute(diff_track_attribute);
}
}
}

View file

@ -213,9 +213,9 @@ const config &manager::get_values()
config& manager::get_value_cfg(const std::string& id)
{
{
const config& value_cfg = get_value_cfg_or_empty(id);
if (!value_cfg.empty()) {
return const_cast<config&>(value_cfg);
config& value_cfg = values_.find_child("option", "id", id);
if(value_cfg) {
return value_cfg;
}
}
@ -237,16 +237,8 @@ config& manager::get_value_cfg(const std::string& id)
const config& manager::get_value_cfg_or_empty(const std::string& id) const
{
static const config empty;
for (const config::any_child& i : values_.all_children_range()) {
for (const config& j : i.cfg.child_range("option")) {
if (j["id"] == id) {
return j;
}
}
}
return empty;
const config& cfg = values_.find_child("option", "id", id);
return cfg ? cfg : empty;
}
config::any_child manager::get_option_parent(const std::string& id) const

View file

@ -94,7 +94,7 @@ void map_labels::read(const config &cfg)
recalculate_labels();
}
const terrain_label* map_labels::get_label(const map_location& loc, const std::string& team_name) const
terrain_label* map_labels::get_label_private(const map_location& loc, const std::string& team_name)
{
team_label_map::const_iterator label_map = labels_.find(team_name);
if (label_map != labels_.end()) {

View file

@ -41,7 +41,9 @@ public:
void write(config& res) const;
void read(const config &cfg);
const terrain_label* get_label(const map_location& loc, const std::string& team_name) const;
const terrain_label* get_label(const map_location& loc, const std::string& team_name) const {
return const_cast<map_labels*>(this)->get_label_private(loc, team_name);
}
// search a team-only label, if fails then try public labels
const terrain_label* get_label(const map_location& loc) const;
const terrain_label* set_label(const map_location& loc,
@ -81,10 +83,7 @@ private:
void add_label(const map_location &, terrain_label *);
void clear_map(label_map &, bool);
/// For our private use, a wrapper for get_label() that can return a pointer
/// to a non-const terrain_label.
terrain_label* get_label_private(const map_location& loc, const std::string& team_name)
{ return const_cast<terrain_label*>(get_label(loc, team_name)); }
terrain_label* get_label_private(const map_location& loc, const std::string& team_name);
// Note: this is not an overload of get_label() so that we do not block
// outsiders from calling get_label for a non-const map_labels object.

View file

@ -458,7 +458,7 @@ static void find_routes(
}
static paths::dest_vect::iterator lower_bound(paths::dest_vect &v, const map_location &loc)
static paths::dest_vect::const_iterator lower_bound(const paths::dest_vect &v, const map_location &loc)
{
size_t sz = v.size(), pos = 0;
while (sz)
@ -473,14 +473,14 @@ static paths::dest_vect::iterator lower_bound(paths::dest_vect &v, const map_loc
paths::dest_vect::const_iterator paths::dest_vect::find(const map_location &loc) const
{
const_iterator i = lower_bound(const_cast<dest_vect &>(*this), loc), i_end = end();
const_iterator i = lower_bound(*this, loc), i_end = end();
if (i != i_end && i->curr != loc) i = i_end;
return i;
}
void paths::dest_vect::insert(const map_location &loc)
{
iterator i = lower_bound(*this, loc), i_end = end();
const_iterator i = lower_bound(*this, loc), i_end = end();
if (i != i_end && i->curr == loc) return;
paths::step s = { loc, map_location(), 0 };
std::vector<step>::insert(i, s);

View file

@ -739,7 +739,7 @@ const mp_game_settings& play_controller::get_mp_settings()
return saved_game_.mp_settings();
}
const game_classification& play_controller::get_classification()
game_classification& play_controller::get_classification()
{
return saved_game_.classification();
}

View file

@ -198,7 +198,7 @@ public:
std::shared_ptr<wb::manager> get_whiteboard();
const mp_game_settings& get_mp_settings();
const game_classification& get_classification();
game_classification& get_classification();
int get_server_request_number() const { return gamestate().server_request_number_; }
void increase_server_request_number() { ++gamestate().server_request_number_; }

View file

@ -30,12 +30,10 @@
#include "config.hpp"
#include "game_errors.hpp"
#include "log.hpp"
#include "scripting/lua_api.hpp"
#include "scripting/lua_common.hpp"
#include "scripting/lua_cpp_function.hpp"
#include "scripting/lua_fileops.hpp"
#include "scripting/lua_kernel_base.hpp"
#include "scripting/lua_types.hpp"
#include "scripting/plugins/context.hpp"
#include "scripting/plugins/manager.hpp"

View file

@ -72,14 +72,14 @@
#include "recall_list_manager.hpp" // for recall_list_manager
#include "replay.hpp" // for get_user_choice, etc
#include "reports.hpp" // for register_generator, etc
#include "scripting/lua_api.hpp" // for luaW_toboolean, etc
#include "scripting/lua_unit.hpp"
#include "scripting/lua_unit_attacks.hpp"
#include "scripting/lua_common.hpp"
#include "scripting/lua_cpp_function.hpp"
#include "scripting/lua_gui2.hpp" // for show_gamestate_inspector
#include "scripting/lua_pathfind_cost_calculator.hpp"
#include "scripting/lua_race.hpp"
#include "scripting/lua_team.hpp"
#include "scripting/lua_types.hpp" // for getunitKey, dlgclbkKey, etc
#include "scripting/lua_unit_type.hpp"
#include "scripting/push_check.hpp"
#include "sdl/utils.hpp" // for surface
@ -327,497 +327,6 @@ namespace {
};
}//unnamed namespace for queued_event_context
/**
* Destroys a unit object before it is collected (__gc metamethod).
*/
static int impl_unit_collect(lua_State *L)
{
lua_unit *u = static_cast<lua_unit *>(lua_touserdata(L, 1));
u->lua_unit::~lua_unit();
return 0;
}
/**
* Checks two lua proxy units for equality. (__eq metamethod)
*/
static int impl_unit_equality(lua_State* L)
{
unit& left = luaW_checkunit(L, 1);
unit& right = luaW_checkunit(L, 2);
const bool equal = left.underlying_id() == right.underlying_id();
lua_pushboolean(L, equal);
return 1;
}
/**
* Gets some data on a unit (__index metamethod).
* - Arg 1: full userdata containing the unit id.
* - Arg 2: string containing the name of the property.
* - Ret 1: something containing the attribute.
*/
static int impl_unit_get(lua_State *L)
{
lua_unit *lu = static_cast<lua_unit *>(lua_touserdata(L, 1));
char const *m = luaL_checkstring(L, 2);
const unit* pu = lu->get();
if (strcmp(m, "valid") == 0)
{
if (!pu) return 0;
if (lu->on_map())
lua_pushstring(L, "map");
else if (lu->on_recall_list())
lua_pushstring(L, "recall");
else
lua_pushstring(L, "private");
return 1;
}
if (!pu) return luaL_argerror(L, 1, "unknown unit");
unit const &u = *pu;
// Find the corresponding attribute.
return_int_attrib("x", u.get_location().x + 1);
return_int_attrib("y", u.get_location().y + 1);
if (strcmp(m, "loc") == 0) {
lua_pushinteger(L, u.get_location().x + 1);
lua_pushinteger(L, u.get_location().y + 1);
return 2;
}
return_int_attrib("side", u.side());
return_string_attrib("id", u.id());
return_string_attrib("type", u.type_id());
return_string_attrib("image_mods", u.effect_image_mods());
return_string_attrib("usage", u.usage());
return_int_attrib("hitpoints", u.hitpoints());
return_int_attrib("max_hitpoints", u.max_hitpoints());
return_int_attrib("experience", u.experience());
return_int_attrib("max_experience", u.max_experience());
return_int_attrib("recall_cost", u.recall_cost());
return_int_attrib("moves", u.movement_left());
return_int_attrib("max_moves", u.total_movement());
return_int_attrib("max_attacks", u.max_attacks());
return_int_attrib("attacks_left", u.attacks_left());
return_tstring_attrib("name", u.name());
return_bool_attrib("canrecruit", u.can_recruit());
return_int_attrib("level", u.level());
return_int_attrib("cost", u.cost());
return_vector_string_attrib("extra_recruit", u.recruits());
return_vector_string_attrib("advances_to", u.advances_to());
if (strcmp(m, "alignment") == 0) {
lua_push(L, u.alignment());
return 1;
}
if (strcmp(m, "upkeep") == 0) {
unit::t_upkeep upkeep = u.upkeep_raw();
if(boost::get<unit::upkeep_full>(&upkeep) != nullptr){
lua_pushstring(L, "full");
}
else if(boost::get<unit::upkeep_loyal>(&upkeep) != nullptr){
lua_pushstring(L, "loyal");
}
else {
lua_push(L, boost::get<int>(upkeep));
}
return 1;
}
if (strcmp(m, "advancements") == 0) {
lua_push(L, u.modification_advancements());
return 1;
}
if (strcmp(m, "overlays") == 0) {
lua_push(L, u.overlays());
return 1;
}
if (strcmp(m, "traits") == 0) {
lua_push(L, u.get_traits_list());
return 1;
}
if (strcmp(m, "abilities") == 0) {
lua_push(L, u.get_ability_list());
return 1;
}
if (strcmp(m, "status") == 0) {
lua_createtable(L, 1, 0);
lua_pushvalue(L, 1);
lua_rawseti(L, -2, 1);
lua_pushlightuserdata(L
, ustatusKey);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_setmetatable(L, -2);
return 1;
}
if (strcmp(m, "variables") == 0) {
lua_createtable(L, 1, 0);
lua_pushvalue(L, 1);
lua_rawseti(L, -2, 1);
lua_pushlightuserdata(L
, unitvarKey);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_setmetatable(L, -2);
return 1;
}
if (strcmp(m, "attacks") == 0) {
lua_createtable(L, 1, 0);
lua_pushvalue(L, 1);
// hack: store the unit at -1 becasue we want positive indexes to refers to the attacks.
lua_rawseti(L, -2, -1);
lua_pushlightuserdata(L, uattacksKey);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_setmetatable(L, -2);
return 1;
}
return_cfg_attrib("recall_filter", cfg = u.recall_filter());
return_bool_attrib("hidden", u.get_hidden());
return_bool_attrib("petrified", u.incapacitated());
return_bool_attrib("resting", u.resting());
return_string_attrib("role", u.get_role());
return_string_attrib("race", u.race()->id());
return_string_attrib("gender", gender_string(u.gender()));
return_string_attrib("variation", u.variation());
return_bool_attrib("zoc", u.get_emit_zoc());
return_string_attrib("facing", map_location::write_direction(u.facing()));
return_string_attrib("portrait", u.big_profile() == u.absolute_image() ? u.absolute_image() + u.image_mods() : u.big_profile());
return_cfg_attrib("__cfg", u.write(cfg); u.get_location().write(cfg));
return lua_kernel_base::get_lua_kernel<game_lua_kernel>(L).return_unit_method(L, m);
}
/**
* Sets some data on a unit (__newindex metamethod).
* - Arg 1: full userdata containing the unit id.
* - Arg 2: string containing the name of the property.
* - Arg 3: something containing the attribute.
*/
static int impl_unit_set(lua_State *L)
{
lua_unit *lu = static_cast<lua_unit *>(lua_touserdata(L, 1));
char const *m = luaL_checkstring(L, 2);
unit* pu = lu->get();
if (!pu) return luaL_argerror(L, 1, "unknown unit");
unit &u = *pu;
// Find the corresponding attribute.
//modify_int_attrib_check_range("side", u.set_side(value), 1, static_cast<int>(teams().size())); TODO: Figure out if this is a good idea, to refer to teams() and make this depend on having a gamestate
modify_int_attrib("side", u.set_side(value));
modify_int_attrib("moves", u.set_movement(value));
modify_int_attrib("hitpoints", u.set_hitpoints(value));
modify_int_attrib("experience", u.set_experience(value));
modify_int_attrib("recall_cost", u.set_recall_cost(value));
modify_int_attrib("attacks_left", u.set_attacks(value));
modify_int_attrib("level", u.set_level(value));
modify_bool_attrib("resting", u.set_resting(value));
modify_tstring_attrib("name", u.set_name(value));
modify_string_attrib("role", u.set_role(value));
modify_string_attrib("facing", u.set_facing(map_location::parse_direction(value)));
modify_bool_attrib("hidden", u.set_hidden(value));
modify_bool_attrib("zoc", u.set_emit_zoc(value));
modify_bool_attrib("canrecruit", u.set_can_recruit(value));
modify_vector_string_attrib("extra_recruit", u.set_recruits(vector));
modify_vector_string_attrib("advances_to", u.set_advances_to(vector));
if (strcmp(m, "alignment") == 0) {
u.set_alignment(lua_check<unit_type::ALIGNMENT>(L, 3));
return 0;
}
if (strcmp(m, "advancements") == 0) {
u.set_advancements(lua_check<std::vector<config> >(L, 3));
return 0;
}
if (strcmp(m, "upkeep") == 0) {
if(lua_isnumber(L, 3)) {
u.set_upkeep(luaL_checkint(L, 3));
return 0;
}
const char* v = luaL_checkstring(L, 3);
if(strcmp(m, "loyal") == 0) {
u.set_upkeep(unit::upkeep_loyal());
}
else if(strcmp(m, "full") == 0) {
u.set_upkeep(unit::upkeep_full());
}
else {
std::string err_msg = "unknown upkeep value of unit: ";
err_msg += v;
return luaL_argerror(L, 2, err_msg.c_str());
}
return 0;
}
if (!lu->on_map()) {
map_location loc = u.get_location();
modify_int_attrib("x", loc.x = value - 1; u.set_location(loc));
modify_int_attrib("y", loc.y = value - 1; u.set_location(loc));
}
std::string err_msg = "unknown modifiable property of unit: ";
err_msg += m;
return luaL_argerror(L, 2, err_msg.c_str());
}
/**
* Gets the status of a unit (__index metamethod).
* - Arg 1: table containing the userdata containing the unit id.
* - Arg 2: string containing the name of the status.
* - Ret 1: boolean.
*/
static int impl_unit_status_get(lua_State *L)
{
if (!lua_istable(L, 1))
return luaL_typerror(L, 1, "unit status");
lua_rawgeti(L, 1, 1);
const unit* u = luaW_tounit(L, -1);
if (!u) return luaL_argerror(L, 1, "unknown unit");
char const *m = luaL_checkstring(L, 2);
lua_pushboolean(L, u->get_state(m));
return 1;
}
/**
* Sets the status of a unit (__newindex metamethod).
* - Arg 1: table containing the userdata containing the unit id.
* - Arg 2: string containing the name of the status.
* - Arg 3: boolean.
*/
static int impl_unit_status_set(lua_State *L)
{
if (!lua_istable(L, 1))
return luaL_typerror(L, 1, "unit status");
lua_rawgeti(L, 1, 1);
unit* u = luaW_tounit(L, -1);
if (!u) return luaL_argerror(L, 1, "unknown unit");
char const *m = luaL_checkstring(L, 2);
u->set_state(m, luaW_toboolean(L, 3));
return 0;
}
/**
* Gets the variable of a unit (__index metamethod).
* - Arg 1: table containing the userdata containing the unit id.
* - Arg 2: string containing the name of the status.
* - Ret 1: boolean.
*/
static int impl_unit_variables_get(lua_State *L)
{
if (!lua_istable(L, 1))
return luaL_typerror(L, 1, "unit variables");
lua_rawgeti(L, 1, 1);
const unit* u = luaW_tounit(L, -1);
if (!u) return luaL_argerror(L, 1, "unknown unit");
char const *m = luaL_checkstring(L, 2);
return_cfgref_attrib("__cfg", u->variables());
variable_access_const v(m, u->variables());
return luaW_pushvariable(L, v) ? 1 : 0;
}
/**
* Gets the attacks of a unit or unit type (__index metamethod).
* - Arg 1: table containing the userdata containing the unit or unit type.
* - Arg 2: index (int) or id (string) identifying a particular attack.
* - Ret 1: the unit's attacks.
*/
static int impl_unit_attacks_get(lua_State *L)
{
if (!lua_istable(L, 1)) {
return luaL_typerror(L, 1, "unit attacks");
}
lua_rawgeti(L, 1, -1);
const unit* u = luaW_tounit(L, -1);
const unit_type* ut = static_cast<const unit_type*>(luaL_testudata(L, -1, "unit type"));
if (!u && !ut) {
return luaL_argerror(L, 1, "unknown unit");
}
const attack_type* attack = nullptr;
const std::vector<attack_type>& attacks = u ? u->attacks() : ut->attacks();
if(!lua_isnumber(L,2)) {
std::string attack_id = luaL_checkstring(L, 2);
for (const attack_type& at : attacks) {
if(at.id() == attack_id) {
attack = &at;
break;
}
}
if (attack == nullptr) {
//return nil on invalid index, just like lua tables do.
return 0;
}
}
else
{
//
size_t index = luaL_checkinteger(L, 2) - 1;
if (index >= attacks.size()) {
//return nil on invalid index, just like lua tables do.
return 0;
}
attack = &attacks[index];
}
// stack { lua_unit }, id/index, lua_unit
lua_createtable(L, 2, 0);
// stack { lua_unit }, id/index, lua_unit, table
lua_pushvalue(L, -2);
// stack { lua_unit }, id/index, lua_unit, table, lua_unit
lua_rawseti(L, -2, 1);
// stack { lua_unit }, id/index, lua_unit, table
lua_pushstring(L, attack->id().c_str());
// stack { lua_unit }, id/index, lua_unit, table, attack id
lua_rawseti(L, -2, 2);
// stack { lua_unit }, id/index, lua_unit, table
lua_pushlightuserdata(L, uattackKey);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_setmetatable(L, -2);
return 1;
}
/**
* Counts the attacks of a unit (__len metamethod).
* - Arg 1: table containing the userdata containing the unit id.
* - Ret 1: size of unit attacks vector.
*/
static int impl_unit_attacks_len(lua_State *L)
{
if (!lua_istable(L, 1)) {
return luaL_typerror(L, 1, "unit attacks");
}
lua_rawgeti(L, 1, -1);
const unit* u = luaW_tounit(L, -1);
if (!u) {
return luaL_argerror(L, 1, "unknown unit");
}
lua_pushinteger(L, u->attacks().size());
return 1;
}
/**
* Gets a propoerty of a units attack (__index metamethod).
* - Arg 1: table containing the userdata containing the unit id. and a string identyfying the attack.
* - Arg 2: string
* - Ret 1:
*/
static int impl_unit_attack_get(lua_State *L)
{
if (!lua_istable(L, 1)) {
return luaL_typerror(L, 1, "unit attack");
}
lua_rawgeti(L, 1, 1);
const unit* u = luaW_tounit(L, -1);
if (!u) {
return luaL_argerror(L, 1, "unknown unit");
}
lua_rawgeti(L, 1, 2);
std::string attack_id = luaL_checkstring(L, -1);
char const *m = luaL_checkstring(L, 2);
for (const attack_type& attack : u->attacks())
{
if(attack.id() == attack_id)
{
return_string_attrib("description", attack.name());
return_string_attrib("name", attack.id());
return_string_attrib("type", attack.type());
return_string_attrib("icon", attack.icon());
return_string_attrib("range", attack.range());
// "min_range"
// "max_range"
return_int_attrib("damage", attack.damage());
return_int_attrib("number", attack.num_attacks());
return_int_attrib("attack_weight", attack.attack_weight());
return_int_attrib("defense_weight", attack.defense_weight());
return_int_attrib("accuracy", attack.accuracy());
return_int_attrib("movement_used", attack.movement_used());
return_int_attrib("parry", attack.parry());
return_cfgref_attrib("specials", attack.specials());
return_cfgref_attrib("__cfg", attack.to_config());
std::string err_msg = "unknown property of attack: ";
err_msg += m;
return luaL_argerror(L, 2, err_msg.c_str());
}
}
return luaL_argerror(L, 1, "invalid attack id");
}
/**
* Gets a propoerty of a units attack (__index metamethod).
* - Arg 1: table containing the userdata containing the unit id. and a string identyfying the attack.
* - Arg 2: string
* - Ret 1:
*/
static int impl_unit_attack_set(lua_State *L)
{
if (!lua_istable(L, 1)) {
return luaL_typerror(L, 1, "unit attack");
}
lua_rawgeti(L, 1, 1);
unit* u = luaW_tounit(L, -1);
if (!u) {
return luaL_argerror(L, 1, "unknown unit");
}
lua_rawgeti(L, 1, 2);
std::string attack_id = luaL_checkstring(L, -1);
char const *m = luaL_checkstring(L, 2);
for (attack_type& attack : u->attacks())
{
if(attack.id() == attack_id)
{
modify_tstring_attrib("description", attack.set_name(value));
// modify_string_attrib("name", attack.set_id(value));
modify_string_attrib("type", attack.set_type(value));
modify_string_attrib("icon", attack.set_icon(value));
modify_string_attrib("range", attack.set_range(value));
// "min_range"
// "max_range"
modify_int_attrib("damage", attack.set_damage(value));
modify_int_attrib("number", attack.set_num_attacks(value));
modify_int_attrib("attack_weight", attack.set_attack_weight(value));
modify_int_attrib("defense_weight", attack.set_defense_weight(value));
modify_int_attrib("accuracy", attack.set_accuracy(value));
modify_int_attrib("movement_used", attack.set_movement_used(value));
modify_int_attrib("parry", attack.set_parry(value));
if (strcmp(m, "specials") == 0) { \
attack.set_specials(luaW_checkconfig(L, 3));
return 0;
}
return_cfgref_attrib("specials", attack.specials());
std::string err_msg = "unknown modifyable property of attack: ";
err_msg += m;
return luaL_argerror(L, 2, err_msg.c_str());
}
}
return luaL_argerror(L, 1, "invalid attack id");
}
/**
* Sets the variable of a unit (__newindex metamethod).
* - Arg 1: table containing the userdata containing the unit id.
* - Arg 2: string containing the name of the status.
* - Arg 3: scalar.
*/
static int impl_unit_variables_set(lua_State *L)
{
if (!lua_istable(L, 1))
return luaL_typerror(L, 1, "unit variables");
lua_rawgeti(L, 1, 1);
unit* u = luaW_tounit(L, -1);
if (!u) return luaL_argerror(L, 1, "unknown unit");
char const *m = luaL_checkstring(L, 2);
if (strcmp(m, "__cfg") == 0) {
u->variables() = luaW_checkconfig(L, 3);
return 0;
}
variable_access_create v(m, u->variables());
luaW_checkvariable(L, v, 3);
return 0;
}
/**
* Gets currently viewing side.
* - Ret 1: integer specifying the currently viewing side
@ -868,10 +377,7 @@ int game_lua_kernel::intf_get_unit(lua_State *L)
std::string id = luaL_checkstring(L, 1);
for(const unit& u : units()) {
if(u.id() == id) {
new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(u.underlying_id());
lua_pushlightuserdata(L, getunitKey);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_setmetatable(L, -2);
luaW_pushunit(L, u.underlying_id());
return 1;
}
}
@ -884,11 +390,7 @@ int game_lua_kernel::intf_get_unit(lua_State *L)
if (!ui.valid()) return 0;
new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(ui->underlying_id());
lua_pushlightuserdata(L
, getunitKey);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_setmetatable(L, -2);
luaW_pushunit(L, ui->underlying_id());
return 1;
}
@ -909,11 +411,7 @@ int game_lua_kernel::intf_get_displayed_unit(lua_State *L)
game_display_->show_everything());
if (!ui.valid()) return 0;
new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(ui->underlying_id());
lua_pushlightuserdata(L
, getunitKey);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_setmetatable(L, -2);
luaW_pushunit(L, ui->underlying_id());
return 1;
}
@ -928,21 +426,16 @@ int game_lua_kernel::intf_get_units(lua_State *L)
vconfig filter = luaW_checkvconfig(L, 1, true);
// Go through all the units while keeping the following stack:
// 1: metatable, 2: return table, 3: userdata, 4: metatable copy
// 1: return table, 2: userdata
lua_settop(L, 0);
lua_pushlightuserdata(L
, getunitKey);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_newtable(L);
int i = 1;
// note that if filter is null, this yields a null filter matching everything (and doing no work)
filter_context & fc = game_state_;
for (const unit * ui : unit_filter(filter, &fc).all_matches_on_map()) {
new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(ui->underlying_id());
lua_pushvalue(L, 1);
lua_setmetatable(L, 3);
lua_rawseti(L, 2, i);
luaW_pushunit(L, ui->underlying_id());
lua_rawseti(L, 1, i);
++i;
}
return 1;
@ -957,12 +450,7 @@ int game_lua_kernel::intf_get_units(lua_State *L)
*/
int game_lua_kernel::intf_match_unit(lua_State *L)
{
if (!luaW_hasmetatable(L, 1, getunitKey))
return luaL_typerror(L, 1, "unit");
lua_unit *lu = static_cast<lua_unit *>(lua_touserdata(L, 1));
unit* u = lu->get();
if (!u) return luaL_argerror(L, 1, "unit not found");
lua_unit& u = *luaW_checkunit_ref(L, 1);
vconfig filter = luaW_checkvconfig(L, 2, true);
@ -973,8 +461,8 @@ int game_lua_kernel::intf_match_unit(lua_State *L)
filter_context & fc = game_state_;
if (luaW_hasmetatable(L, 3, getunitKey)) {
if (int side = lu->on_recall_list()) {
if(unit* u_adj = luaW_tounit(L, 3)) {
if(int side = u.on_recall_list()) {
WRN_LUA << "wesnoth.match_unit called with a secondary unit (3rd argument), ";
WRN_LUA << "but unit to match was on recall list. ";
WRN_LUA << "Thus the 3rd argument is ignored.\n";
@ -983,13 +471,11 @@ int game_lua_kernel::intf_match_unit(lua_State *L)
lua_pushboolean(L, unit_filter(filter, &fc).matches(*u, map_location()));
return 1;
}
lua_unit *lu_adj = static_cast<lua_unit *>(lua_touserdata(L, 1));
unit* u_adj = lu_adj->get();
if (!u_adj) {
return luaL_argerror(L, 3, "unit not found");
}
lua_pushboolean(L, unit_filter(filter, &fc).matches(*u, *u_adj));
} else if (int side = lu->on_recall_list()) {
} else if(int side = u.on_recall_list()) {
map_location loc;
luaW_tolocation(L, 3, loc); // If argument 3 isn't a location, loc is unchanged
team &t = (teams())[side - 1];
@ -1015,11 +501,8 @@ int game_lua_kernel::intf_get_recall_units(lua_State *L)
vconfig filter = luaW_checkvconfig(L, 1, true);
// Go through all the units while keeping the following stack:
// 1: metatable, 2: return table, 3: userdata, 4: metatable copy
// 1: return table, 2: userdata
lua_settop(L, 0);
lua_pushlightuserdata(L
, getunitKey);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_newtable(L);
int i = 1, s = 1;
filter_context & fc = game_state_;
@ -1034,10 +517,8 @@ int game_lua_kernel::intf_get_recall_units(lua_State *L)
if (!ufilt( *u, map_location() ))
continue;
}
new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(s, u->underlying_id());
lua_pushvalue(L, 1);
lua_setmetatable(L, 3);
lua_rawseti(L, 2, i);
luaW_pushunit(L, s, u->underlying_id());
lua_rawseti(L, 1, i);
++i;
}
++s;
@ -1232,14 +713,14 @@ int game_lua_kernel::intf_clear_menu_item(lua_State *L)
int game_lua_kernel::intf_set_end_campaign_credits(lua_State *L)
{
game_classification &classification = const_cast<game_classification &> (play_controller_.get_classification());
game_classification &classification = play_controller_.get_classification();
classification.end_credits = luaW_toboolean(L, 1);
return 0;
}
int game_lua_kernel::intf_set_end_campaign_text(lua_State *L)
{
game_classification &classification = const_cast<game_classification &> (play_controller_.get_classification());
game_classification &classification = play_controller_.get_classification();
classification.end_text = luaW_checktstring(L, 1);
if (lua_isnumber(L, 2)) {
classification.end_text_duration = static_cast<int> (lua_tonumber(L, 2));
@ -1884,7 +1365,7 @@ int game_lua_kernel::intf_get_end_level_data(lua_State* L)
return 0;
}
auto data = play_controller_.get_end_level_data_const();
new(lua_newuserdata(L, sizeof(end_level_data))) end_level_data();
new(L) end_level_data();
if(luaL_newmetatable(L, "end level data")) {
static luaL_Reg const callbacks[] = {
{ "__index", &impl_end_level_data_get},
@ -2463,6 +1944,15 @@ int game_lua_kernel::intf_print(lua_State *L) {
return 0;
}
void game_lua_kernel::put_unit_helper(const map_location& loc)
{
if(game_display_) {
game_display_->invalidate(loc);
}
units().erase(loc);
}
/**
* Places a unit on the map.
* - Arg 1: (optional) location.
@ -2479,8 +1969,6 @@ int game_lua_kernel::intf_put_unit(lua_State *L)
}
int unit_arg = 1;
lua_unit *lu = nullptr;
unit_ptr u = unit_ptr();
map_location loc;
if (lua_isnumber(L, 1)) {
// Since this form is deprecated, I didn't bother updating it to luaW_tolocation.
@ -2496,12 +1984,9 @@ int game_lua_kernel::intf_put_unit(lua_State *L)
}
}
if (luaW_hasmetatable(L, unit_arg, getunitKey))
{
lu = static_cast<lua_unit *>(lua_touserdata(L, unit_arg));
u = lu->get_shared();
if (!u) return luaL_argerror(L, unit_arg, "unit not found");
if (lu->on_map() && (unit_arg == 1 || u->get_location() == loc)) {
if((luaW_isunit(L, unit_arg))) {
lua_unit& u = *luaW_checkunit_ref(L, unit_arg);
if(u.on_map() && u->get_location() == loc) {
return 0;
}
if (!loc.valid()) {
@ -2511,9 +1996,10 @@ int game_lua_kernel::intf_put_unit(lua_State *L)
} else if (unit_arg != 1) {
WRN_LUA << "wesnoth.put_unit(x, y, unit) is deprecated. Use wesnoth.put_unit(unit, x, y) instead\n";
}
}
else if (!lua_isnoneornil(L, unit_arg))
{
put_unit_helper(loc);
u.put_map(loc);
u.get_shared()->anim_comp().set_standing();
} else if(!lua_isnoneornil(L, unit_arg)) {
const vconfig* vcfg = nullptr;
config cfg = luaW_checkconfig(L, unit_arg, vcfg);
if (unit_arg == 1 && !map().on_board(loc)) {
@ -2524,29 +2010,16 @@ int game_lua_kernel::intf_put_unit(lua_State *L)
} else if (unit_arg != 1) {
WRN_LUA << "wesnoth.put_unit(x, y, unit) is deprecated. Use wesnoth.put_unit(unit, x, y) instead\n";
}
u = unit_ptr (new unit(cfg, true, vcfg));
}
if (game_display_) {
game_display_->invalidate(loc);
}
if (!u) {
if (unit_arg == 3) {
WRN_LUA << "wesnoth.put_unit(x, y) is deprecated. Use wesnoth.erase_unit(x, y) instead\n";
units().erase(loc);
}
return 0;
}
units().erase(loc);
if (lu) {
lu->put_map(loc);
lu->get_shared()->anim_comp().set_standing();
} else {
unit_ptr u(new unit(cfg, true, vcfg));
put_unit_helper(loc);
u->set_location(loc);
units().insert(u);
} else {
WRN_LUA << "wesnoth.put_unit(x, y) is deprecated. Use wesnoth.erase_unit(x, y) instead\n";
put_unit_helper(loc);
return 0; // Don't fire event when unit is only erase
}
if(unit_arg != 1 || luaW_toboolean(L, 3)) {
play_controller_.pump().fire("unit_placed", loc);
}
@ -2564,18 +2037,14 @@ int game_lua_kernel::intf_erase_unit(lua_State *L)
}
map_location loc;
if (luaW_hasmetatable(L, 1, getunitKey)) {
lua_unit *lu = static_cast<lua_unit *>(lua_touserdata(L, 1));
unit_ptr u = lu->get_shared();
if (!lu->get()) {
return luaL_argerror(L, 1, "unit not found");
}
if (lu->on_map()) {
if(luaW_isunit(L, 1)) {
lua_unit& u = *luaW_checkunit_ref(L, 1);
if (u.on_map()) {
loc = u->get_location();
if (!map().on_board(loc)) {
return luaL_argerror(L, 1, "invalid location");
}
} else if (int side = lu->on_recall_list()) {
} else if (int side = u.on_recall_list()) {
team &t = teams()[side - 1];
// Should it use underlying ID instead?
t.recall_list().erase_if_matches_id(u->id());
@ -2616,21 +2085,23 @@ int game_lua_kernel::intf_put_recall_unit(lua_State *L)
int side = lua_tointeger(L, 2);
if (unsigned(side) > teams().size()) side = 0;
if (luaW_hasmetatable(L, 1, getunitKey))
{
lu = static_cast<lua_unit *>(lua_touserdata(L, 1));
if(luaW_isunit(L, 1)) {
lu = luaW_checkunit_ref(L, 1);
u = lu->get_shared();
if (!u || lu->on_recall_list())
return luaL_argerror(L, 1, "unit not found");
}
else
{
if(lu->on_recall_list() == side) {
return luaL_argerror(L, 1, "unit already on recall list");
}
} else {
const vconfig* vcfg = nullptr;
config cfg = luaW_checkconfig(L, 1, vcfg);
u = unit_ptr(new unit(cfg, true, vcfg));
}
if (!side) side = u->side();
if (!side) {
side = u->side();
} else {
u->set_side(side);
}
team &t = teams()[side - 1];
// Avoid duplicates in the recall list.
size_t uid = u->underlying_id();
@ -2655,11 +2126,8 @@ int game_lua_kernel::intf_extract_unit(lua_State *L)
if(map_locked_) {
return luaL_error(L, "Attempted to remove a unit while the map is locked");
}
if (!luaW_hasmetatable(L, 1, getunitKey))
return luaL_typerror(L, 1, "unit");
lua_unit *lu = static_cast<lua_unit *>(lua_touserdata(L, 1));
lua_unit* lu = luaW_checkunit_ref(L, 1);
unit_ptr u = lu->get_shared();
if (!u) return luaL_argerror(L, 1, "unit not found");
if (lu->on_map()) {
u = units().extract(u->get_location());
@ -2689,10 +2157,10 @@ int game_lua_kernel::intf_find_vacant_tile(lua_State *L)
{
map_location loc = luaW_checklocation(L, 1);
unit_ptr u = unit_ptr();
unit_ptr u;
if (!lua_isnoneornil(L, 2)) {
if (luaW_hasmetatable(L, 2, getunitKey)) {
u = static_cast<lua_unit *>(lua_touserdata(L, 2))->get_shared();
if(luaW_isunit(L, 2)) {
u = luaW_checkunit_ptr(L, 2, true);
} else {
const vconfig* vcfg = nullptr;
config cfg = luaW_checkconfig(L, 2, vcfg);
@ -2740,11 +2208,7 @@ static int intf_create_unit(lua_State *L)
const vconfig* vcfg = nullptr;
config cfg = luaW_checkconfig(L, 1, vcfg);
unit_ptr u = unit_ptr(new unit(cfg, true, vcfg));
new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(u);
lua_pushlightuserdata(L
, getunitKey);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_setmetatable(L, -2);
luaW_pushunit(L, u);
return 1;
}
@ -2756,11 +2220,7 @@ static int intf_create_unit(lua_State *L)
static int intf_copy_unit(lua_State *L)
{
unit& u = luaW_checkunit(L, 1);
new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(unit_ptr(new unit(u)));
lua_pushlightuserdata(L
, getunitKey);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_setmetatable(L, -2);
luaW_pushunit(L, unit_ptr(new unit(u)));
return 1;
}
@ -4765,75 +4225,9 @@ game_lua_kernel::game_lua_kernel(CVideo * video, game_state & gs, play_controlle
//Create the getrace metatable
cmd_log_ << lua_race::register_metatable(L);
// Create the getunit metatable.
cmd_log_ << "Adding getunit metatable...\n";
lua_pushlightuserdata(L
, getunitKey);
lua_createtable(L, 0, 5);
lua_pushcfunction(L, impl_unit_collect);
lua_setfield(L, -2, "__gc");
lua_pushcfunction(L, impl_unit_equality);
lua_setfield(L, -2, "__eq");
lua_pushcfunction(L, impl_unit_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, impl_unit_set);
lua_setfield(L, -2, "__newindex");
lua_pushstring(L, "unit");
lua_setfield(L, -2, "__metatable");
lua_rawset(L, LUA_REGISTRYINDEX);
// Create the unit status metatable.
cmd_log_ << "Adding unit status metatable...\n";
lua_pushlightuserdata(L
, ustatusKey);
lua_createtable(L, 0, 3);
lua_pushcfunction(L, impl_unit_status_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, impl_unit_status_set);
lua_setfield(L, -2, "__newindex");
lua_pushstring(L, "unit status");
lua_setfield(L, -2, "__metatable");
lua_rawset(L, LUA_REGISTRYINDEX);
// Create the unit attacks metatable.
cmd_log_ << "Adding unit attacks metatable...\n";
lua_pushlightuserdata(L, uattacksKey);
lua_createtable(L, 0, 3);
lua_pushcfunction(L, impl_unit_attacks_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, impl_unit_attacks_len);
lua_setfield(L, -2, "__len");
lua_pushstring(L, "unit attacks");
lua_setfield(L, -2, "__metatable");
lua_rawset(L, LUA_REGISTRYINDEX);
lua_pushlightuserdata(L, uattackKey);
lua_createtable(L, 0, 3);
lua_pushcfunction(L, impl_unit_attack_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, impl_unit_attack_set);
lua_setfield(L, -2, "__newindex");
lua_pushstring(L, "unit attack");
lua_setfield(L, -2, "__metatable");
lua_rawset(L, LUA_REGISTRYINDEX);
// Create the unit variables metatable.
cmd_log_ << "Adding unit variables metatable...\n";
lua_pushlightuserdata(L
, unitvarKey);
lua_createtable(L, 0, 3);
lua_pushcfunction(L, impl_unit_variables_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, impl_unit_variables_set);
lua_setfield(L, -2, "__newindex");
lua_pushstring(L, "unit variables");
lua_setfield(L, -2, "__metatable");
lua_rawset(L, LUA_REGISTRYINDEX);
//Create the unit metatables
cmd_log_ << lua_units::register_metatables(L);
cmd_log_ << lua_units::register_attacks_metatables(L);
// Create the vconfig metatable.
cmd_log_ << lua_common::register_vconfig_metatable(L);
@ -5320,10 +4714,7 @@ bool game_lua_kernel::run_filter(char const *name, unit const &u)
unit_map::const_unit_iterator ui = units().find(u.get_location());
if (!ui.valid()) return false;
// Pass the unit as argument.
new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(ui->underlying_id());
lua_pushlightuserdata(L, getunitKey);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_setmetatable(L, -2);
luaW_pushunit(L, ui->underlying_id());
return run_filter(name, 1);
}

View file

@ -117,6 +117,7 @@ class game_lua_kernel : public lua_kernel_base
int intf_open_help(lua_State *L);
int intf_play_sound(lua_State *L);
int intf_print(lua_State *L);
void put_unit_helper(const map_location& loc);
int intf_put_unit(lua_State *L);
int intf_erase_unit(lua_State *L);
int intf_put_recall_unit(lua_State *L);

View file

@ -1,220 +0,0 @@
/*
Copyright (C) 2009 - 2016 by Guillaume Melquiond <guillaume.melquiond@gmail.com>
Part of the Battle for Wesnoth Project http://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 "lua_api.hpp"
#include "lua_types.hpp"
#include "lua_jailbreak_exception.hpp" // for tlua_jailbreak_exception
#include "chat_events.hpp" // for chat_handler, etc
#include "config.hpp"
#include "display_chat_manager.hpp"
#include "game_board.hpp"
#include "game_display.hpp"
#include "log.hpp"
#include "map/location.hpp" // for map_location
#include "resources.hpp"
#include "scripting/lua_common.hpp"
#include "tstring.hpp"
#include "units/unit.hpp"
#include "units/map.hpp"
#include "variable.hpp"
#include <boost/variant/static_visitor.hpp>
#include <map> // for map<>::key_type
#include <new> // for operator new
#include <ostream> // for operator<<, basic_ostream, etc
#include <utility> // for pair
#include <string>
#include "lua/lauxlib.h"
#include "lua/lua.h" // for lua_State, lua_settop, etc
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)
void chat_message(std::string const &caption, std::string const &msg)
{
if (!resources::screen) return;
resources::screen->get_chat_manager().add_chat_message(time(nullptr), caption, 0, msg,
events::chat_handler::MESSAGE_PUBLIC, false);
}
#ifdef _MSC_VER
#pragma warning (push)
#pragma warning (disable: 4706)
#endif
bool luaW_pcall(lua_State *L
, int nArgs, int nRets, bool allow_wml_error)
{
// Load the error handler before the function and its arguments.
lua_pushlightuserdata(L
, executeKey);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_insert(L, -2 - nArgs);
int error_handler_index = lua_gettop(L) - nArgs - 1;
// Call the function.
int res = lua_pcall(L, nArgs, nRets, -2 - nArgs);
tlua_jailbreak_exception::rethrow();
if (res)
{
/*
* When an exception is thrown which doesn't derive from
* std::exception m will be nullptr pointer.
*/
char const *m = lua_tostring(L, -1);
if(m) {
if (allow_wml_error && strncmp(m, "~wml:", 5) == 0) {
m += 5;
char const *e = strstr(m, "stack traceback");
lg::wml_error() << std::string(m, e ? e - m : strlen(m));
} else if (allow_wml_error && strncmp(m, "~lua:", 5) == 0) {
m += 5;
char const *e = nullptr, *em = m;
while (em[0] && ((em = strstr(em + 1, "stack traceback"))))
#ifdef _MSC_VER
#pragma warning (pop)
#endif
e = em;
chat_message("Lua error", std::string(m, e ? e - m : strlen(m)));
} else {
ERR_LUA << m << '\n';
chat_message("Lua error", m);
}
} else {
chat_message("Lua caught unknown exception", "");
}
lua_pop(L, 2);
return false;
}
// Remove the error handler.
lua_remove(L, error_handler_index);
return true;
}
lua_unit::~lua_unit()
{
}
unit* lua_unit::get()
{
if (ptr) return ptr.get();
if (c_ptr) return c_ptr;
if (side) {
return resources::gameboard->teams()[side - 1].recall_list().find_if_matches_underlying_id(uid).get();
}
unit_map::unit_iterator ui = resources::units->find(uid);
if (!ui.valid()) return nullptr;
return ui.get_shared_ptr().get(); //&*ui would not be legal, must get new shared_ptr by copy ctor because the unit_map itself is holding a boost shared pointer.
}
unit_ptr lua_unit::get_shared()
{
if (ptr) return ptr;
if (side) {
return resources::gameboard->teams()[side - 1].recall_list().find_if_matches_underlying_id(uid);
}
unit_map::unit_iterator ui = resources::units->find(uid);
if (!ui.valid()) return unit_ptr();
return ui.get_shared_ptr(); //&*ui would not be legal, must get new shared_ptr by copy ctor because the unit_map itself is holding a boost shared pointer.
}
// Having this function here not only simplifies other code, it allows us to move
// pointers around from one structure to another.
// This makes bare pointer->map in particular about 2 orders of magnitude faster,
// as benchmarked from Lua code.
bool lua_unit::put_map(const map_location &loc)
{
if (ptr) {
ptr->set_location(loc);
resources::units->erase(loc);
std::pair<unit_map::unit_iterator, bool> res = resources::units->insert(ptr);
if (res.second) {
ptr.reset();
uid = res.first->underlying_id();
} else {
ERR_LUA << "Could not move unit " << ptr->underlying_id() << " onto map location " << loc << '\n';
return false;
}
} else if (side) { // recall list
unit_ptr it = resources::gameboard->teams()[side - 1].recall_list().extract_if_matches_underlying_id(uid);
if (it) {
side = 0;
// uid may be changed by unit_map on insertion
uid = resources::units->replace(loc, *it).first->underlying_id();
} else {
ERR_LUA << "Could not find unit " << uid << " on recall list of side " << side << '\n';
return false;
}
} else { // on map
unit_map::unit_iterator ui = resources::units->find(uid);
if (ui != resources::units->end()) {
map_location from = ui->get_location();
if (from != loc) { // This check is redundant in current usage
resources::units->erase(loc);
resources::units->move(from, loc);
}
// No need to change our contents
} else {
ERR_LUA << "Could not find unit " << uid << " on the map" << std::endl;
return false;
}
}
return true;
}
unit* luaW_tounit(lua_State *L, int index, bool only_on_map)
{
if (!luaW_hasmetatable(L, index, getunitKey)) return nullptr;
lua_unit *lu = static_cast<lua_unit *>(lua_touserdata(L, index));
if (only_on_map && !lu->on_map()) return nullptr;
return lu->get();
}
unit_ptr luaW_tounit_ptr(lua_State *L, int index, bool only_on_map)
{
if (!luaW_hasmetatable(L, index, getunitKey)) return unit_ptr();
lua_unit *lu = static_cast<lua_unit *>(lua_touserdata(L, index));
if (only_on_map && !lu->on_map()) return unit_ptr();
return lu->get_shared();
}
unit_ptr luaW_checkunit_ptr(lua_State *L, int index, bool only_on_map)
{
unit_ptr u = luaW_tounit(L, index, only_on_map);
if (!u) luaL_typerror(L, index, "unit");
return u;
}
unit& luaW_checkunit(lua_State *L, int index, bool only_on_map)
{
unit* u = luaW_tounit(L, index, only_on_map);
if (!u) luaL_typerror(L, index, "unit");
return *u;
}
lua_unit* luaW_pushlocalunit(lua_State *L, unit& u)
{
lua_unit* res = new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(u);
lua_pushlightuserdata(L, getunitKey);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_setmetatable(L, -2);
return res;
}

View file

@ -26,12 +26,14 @@
#include "global.hpp"
#include "config.hpp"
#include "scripting/lua_api.hpp"
#include "scripting/lua_types.hpp" // for gettextKey, tstringKey, etc
#include "scripting/lua_unit.hpp"
#include "tstring.hpp" // for t_string
#include "variable.hpp" // for vconfig
#include "log.hpp"
#include "gettext.hpp"
#include "resources.hpp"
#include "lua_jailbreak_exception.hpp"
#include "game_display.hpp"
#include <cstring>
#include <iterator> // for distance, advance
@ -41,11 +43,12 @@
#include "lua/lauxlib.h"
#include "lua/lua.h"
static const char * gettextKey = "gettext";
static const char * vconfigKey = "vconfig";
static const char * vconfigpairsKey = "vconfig pairs";
static const char * vconfigipairsKey = "vconfig ipairs";
const char * tstringKey = "translatable string";
static const char gettextKey[] = "gettext";
static const char vconfigKey[] = "vconfig";
static const char vconfigpairsKey[] = "vconfig pairs";
static const char vconfigipairsKey[] = "vconfig ipairs";
static const char tstringKey[] = "translatable string";
static const char executeKey[] = "err";
static lg::log_domain log_scripting_lua("scripting/lua");
#define LOG_LUA LOG_STREAM(info, log_scripting_lua)
@ -118,7 +121,7 @@ static void tstring_concat_aux(lua_State *L, t_string &dst, int src)
static int impl_tstring_concat(lua_State *L)
{
// Create a new t_string.
t_string *t = new(lua_newuserdata(L, sizeof(t_string))) t_string;
t_string *t = new(L) t_string;
luaL_setmetatable(L, tstringKey);
// Append both arguments to t.
@ -298,9 +301,8 @@ static int impl_vconfig_pairs_collect(lua_State *L)
*/
static int impl_vconfig_pairs(lua_State *L)
{
static const size_t sz = sizeof(config::const_attr_itors);
vconfig vcfg = luaW_checkvconfig(L, 1);
new(lua_newuserdata(L, sz)) config::const_attr_itors(vcfg.get_config().attribute_range());
new(L) config::const_attr_itors(vcfg.get_config().attribute_range());
luaL_newmetatable(L, vconfigpairsKey);
lua_setmetatable(L, -2);
lua_pushcclosure(L, &impl_vconfig_pairs_iter, 1);
@ -348,9 +350,8 @@ static int impl_vconfig_ipairs_collect(lua_State *L)
*/
static int impl_vconfig_ipairs(lua_State *L)
{
static const size_t sz = sizeof(vconfig_child_range);
vconfig cfg = luaW_checkvconfig(L, 1);
new(lua_newuserdata(L, sz)) vconfig_child_range(cfg.ordered_begin(), cfg.ordered_end());
new(L) vconfig_child_range(cfg.ordered_begin(), cfg.ordered_end());
luaL_newmetatable(L, vconfigipairsKey);
lua_setmetatable(L, -2);
lua_pushcclosure(L, &impl_vconfig_ipairs_iter, 1);
@ -454,15 +455,28 @@ std::string register_vconfig_metatable(lua_State *L)
} // end namespace lua_common
void* operator new(size_t sz, lua_State *L)
{
return lua_newuserdata(L, sz);
}
void operator delete(void*, lua_State *L)
{
// Not sure if this is needed since it's a no-op
// It's only called if a constructor throws while using the above operator new
// By removing the userdata from the stack, this should ensure that Lua frees it
lua_pop(L, 1);
}
void luaW_pushvconfig(lua_State *L, vconfig const &cfg)
{
new(lua_newuserdata(L, sizeof(vconfig))) vconfig(cfg);
new(L) vconfig(cfg);
luaL_setmetatable(L, vconfigKey);
}
void luaW_pushtstring(lua_State *L, t_string const &v)
{
new(lua_newuserdata(L, sizeof(t_string))) t_string(v);
new(L) t_string(v);
luaL_setmetatable(L, tstringKey);
}
@ -522,19 +536,6 @@ bool luaW_toscalar(lua_State *L, int index, config::attribute_value& v)
return true;
}
bool luaW_hasmetatable(lua_State *L
, int index
, luatypekey key)
{
if (!lua_getmetatable(L, index))
return false;
lua_pushlightuserdata(L, key);
lua_rawget(L, LUA_REGISTRYINDEX);
bool ok = lua_rawequal(L, -1, -2) == 1;
lua_pop(L, 2);
return ok;
}
bool luaW_totstring(lua_State *L, int index, t_string &str)
{
switch (lua_type(L, index)) {
@ -894,3 +895,82 @@ bool luaW_checkvariable(lua_State *L, variable_access_create& v, int n)
return false;
}
}
void chat_message(std::string const &caption, std::string const &msg)
{
if (!resources::screen) return;
resources::screen->get_chat_manager().add_chat_message(time(nullptr), caption, 0, msg,
events::chat_handler::MESSAGE_PUBLIC, false);
}
// To silence "no prototype" warnings
void push_error_handler(lua_State *L);
int luaW_pcall_internal(lua_State *L, int nArgs, int nRets);
void push_error_handler(lua_State *L)
{
luaW_getglobal(L, "debug", "traceback");
lua_setfield(L, LUA_REGISTRYINDEX, executeKey);
}
int luaW_pcall_internal(lua_State *L, int nArgs, int nRets)
{
// Load the error handler before the function and its arguments.
lua_getfield(L, LUA_REGISTRYINDEX, executeKey);
lua_insert(L, -2 - nArgs);
int error_handler_index = lua_gettop(L) - nArgs - 1;
// Call the function.
int errcode = lua_pcall(L, nArgs, nRets, -2 - nArgs);
// Remove the error handler.
lua_remove(L, error_handler_index);
tlua_jailbreak_exception::rethrow();
return errcode;
}
#ifdef _MSC_VER
#pragma warning (push)
#pragma warning (disable: 4706)
#endif
bool luaW_pcall(lua_State *L, int nArgs, int nRets, bool allow_wml_error)
{
int res = luaW_pcall_internal(L, nArgs, nRets);
if (res)
{
/*
* When an exception is thrown which doesn't derive from
* std::exception m will be nullptr pointer.
*/
char const *m = lua_tostring(L, -1);
if(m) {
if (allow_wml_error && strncmp(m, "~wml:", 5) == 0) {
m += 5;
char const *e = strstr(m, "stack traceback");
lg::wml_error() << std::string(m, e ? e - m : strlen(m));
} else if (allow_wml_error && strncmp(m, "~lua:", 5) == 0) {
m += 5;
char const *e = nullptr, *em = m;
while (em[0] && ((em = strstr(em + 1, "stack traceback"))))
#ifdef _MSC_VER
#pragma warning (pop)
#endif
e = em;
chat_message("Lua error", std::string(m, e ? e - m : strlen(m)));
} else {
ERR_LUA << m << '\n';
chat_message("Lua error", m);
}
} else {
chat_message("Lua caught unknown exception", "");
}
lua_pop(L, 2);
return false;
}
return true;
}

View file

@ -25,10 +25,10 @@ class t_string;
class vconfig;
#include "config.hpp"
#include "scripting/lua_types.hpp"
#include "variable_info.hpp"
#include "map/location.hpp"
#include <vector>
#include <string>
namespace lua_common {
int intf_textdomain(lua_State *L);
@ -39,7 +39,9 @@ namespace lua_common {
std::string register_vconfig_metatable(lua_State *L);
}
extern const char * tstringKey;
void* operator new(size_t sz, lua_State *L);
void operator delete(void* p, lua_State *L);
/**
* Pushes a vconfig on the top of the stack.
@ -61,12 +63,6 @@ void luaW_pushscalar(lua_State *L, config::attribute_value const &v);
*/
bool luaW_toscalar(lua_State *L, int index, config::attribute_value& v);
/**
* Returns true if the metatable of the object is the one found in the registry.
*/
bool luaW_hasmetatable(lua_State *L, int index, luatypekey key);
/**
* Converts a scalar to a translatable string.
*/
@ -165,6 +161,18 @@ bool luaW_pushvariable(lua_State *L, variable_access_const& v);
bool luaW_checkvariable(lua_State *L, variable_access_create& v, int n);
/**
* Displays a message in the chat window.
*/
void chat_message(std::string const &caption, std::string const &msg);
/**
* Calls a Lua function stored below its @a nArgs arguments at the top of the stack.
* @param nRets LUA_MULTRET for unbounded return values.
* @return true if the call was successful and @a nRets return values are available.
*/
bool luaW_pcall(lua_State *L, int nArgs, int nRets, bool allow_wml_error = false);
#define return_tstring_attrib(name, accessor) \
if (strcmp(m, name) == 0) { \

View file

@ -19,7 +19,6 @@
#include "game_config.hpp" //for game_config::debug_lua
#include "game_errors.hpp"
#include "log.hpp"
#include "scripting/lua_api.hpp" // for chat_message, luaW_pcall
#include "scripting/lua_common.hpp" // for chat_message, luaW_pcall
#include <exception>

View file

@ -16,7 +16,7 @@
#include "boost/variant/static_visitor.hpp"
#include "scripting/game_lua_kernel.hpp"
#include "scripting/lua_api.hpp"
#include "scripting/lua_unit.hpp"
#include "scripting/lua_common.hpp"
#include "lua/lauxlib.h"
#include "lua/lua.h"
@ -27,6 +27,8 @@
#include "resources.hpp"
#include "units/map.hpp"
static const char formulaKey[] = "formula";
void luaW_pushfaivariant(lua_State* L, variant val);
variant luaW_tofaivariant(lua_State* L, int i);
@ -141,13 +143,10 @@ void luaW_pushfaivariant(lua_State* L, variant val) {
const unit& u = u_ref->get_unit();
unit_map::iterator un_it = resources::units->find(u.get_location());
if(&*un_it == &u) {
new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(u.underlying_id());
luaW_pushunit(L, u.underlying_id());
} else {
new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(u.side(), u.underlying_id());
luaW_pushunit(L, u.side(), u.underlying_id());
}
lua_pushlightuserdata(L, getunitKey);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_setmetatable(L, -2);
} else if(location_callable* loc_ref = val.try_convert<location_callable>()) {
luaW_pushlocation(L, loc_ref->loc());
} else {
@ -208,8 +207,8 @@ int lua_formula_bridge::intf_eval_formula(lua_State *L)
{
bool need_delete = false;
fwrapper* form;
if(luaW_hasmetatable(L, 1, formulaKey)) {
form = static_cast<fwrapper*>(lua_touserdata(L, 1));
if(void* ud = luaL_testudata(L, 1, formulaKey)) {
form = static_cast<fwrapper*>(ud);
} else {
need_delete = true;
form = new fwrapper(luaL_checkstring(L, 1));
@ -235,10 +234,8 @@ int lua_formula_bridge::intf_compile_formula(lua_State* L)
if(!lua_isstring(L, 1)) {
luaL_typerror(L, 1, "string");
}
new(lua_newuserdata(L, sizeof(fwrapper))) fwrapper(lua_tostring(L, 1));
lua_pushlightuserdata(L, formulaKey);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_setmetatable(L, -2);
new(L) fwrapper(lua_tostring(L, 1));
luaL_setmetatable(L, formulaKey);
return 1;
}
@ -280,8 +277,7 @@ static int impl_formula_tostring(lua_State* L)
std::string lua_formula_bridge::register_metatables(lua_State* L)
{
lua_pushlightuserdata(L, formulaKey);
lua_createtable(L, 0, 4);
luaL_newmetatable(L, formulaKey);
lua_pushcfunction(L, impl_formula_collect);
lua_setfield(L, -2, "__gc");
lua_pushcfunction(L, impl_formula_tostring);
@ -290,7 +286,6 @@ std::string lua_formula_bridge::register_metatables(lua_State* L)
lua_setfield(L, -2, "__call");
lua_pushstring(L, "formula");
lua_setfield(L, -2, "__metatable");
lua_rawset(L, LUA_REGISTRYINDEX);
return "Adding formula metatable...\n";
}

View file

@ -41,9 +41,7 @@
#include "config.hpp"
#include "log.hpp"
#include "scripting/lua_api.hpp" // for luaW_toboolean, etc
#include "scripting/lua_common.hpp"
#include "scripting/lua_types.hpp" // for getunitKey, dlgclbkKey, etc
#include "serialization/string_utils.hpp"
#include "tstring.hpp"

View file

@ -34,7 +34,6 @@
#include "scripting/lua_gui2.hpp"
#include "scripting/lua_map_location_ops.hpp"
#include "scripting/lua_rng.hpp"
#include "scripting/lua_types.hpp"
#include "scripting/push_check.hpp"
#include "version.hpp" // for do_version_check, etc
@ -196,11 +195,10 @@ static int intf_name_generator(lua_State *L)
}
int chain_sz = luaL_optinteger(L, 3, 2);
int max_len = luaL_optinteger(L, 4, 12);
gen = new(lua_newuserdata(L, sizeof(markov_generator))) markov_generator(input, chain_sz, max_len);
gen = new(L) markov_generator(input, chain_sz, max_len);
// Ensure the pointer didn't change when cast
assert(static_cast<void*>(gen) == dynamic_cast<markov_generator*>(gen));
} else if(type == "context_free" || type == "cfg" || type == "CFG") {
void* buf = lua_newuserdata(L, sizeof(context_free_grammar_generator));
if(lua_istable(L, 2)) {
std::map<std::string, std::vector<std::string>> data;
for(lua_pushnil(L); lua_next(L, 2); lua_pop(L, 1)) {
@ -218,10 +216,10 @@ static int intf_name_generator(lua_State *L)
}
}
if(!data.empty()) {
gen = new(buf) context_free_grammar_generator(data);
gen = new(L) context_free_grammar_generator(data);
}
} else {
gen = new(buf) context_free_grammar_generator(luaL_checkstring(L, 2));
gen = new(L) context_free_grammar_generator(luaL_checkstring(L, 2));
}
if(gen) {
assert(static_cast<void*>(gen) == dynamic_cast<context_free_grammar_generator*>(gen));
@ -253,6 +251,8 @@ int dispatch(lua_State *L) {
return ((lua_kernel_base::get_lua_kernel<lua_kernel_base>(L)).*method)(L);
}
extern void push_error_handler(lua_State *L);
// Ctor, initialization
lua_kernel_base::lua_kernel_base(CVideo * video)
: mState(luaL_newstate())
@ -318,14 +318,7 @@ lua_kernel_base::lua_kernel_base(CVideo * video)
// Store the error handler.
cmd_log_ << "Adding error handler...\n";
lua_pushlightuserdata(L
, executeKey);
lua_getglobal(L, "debug");
lua_getfield(L, -1, "traceback");
lua_remove(L, -2);
lua_rawset(L, LUA_REGISTRYINDEX);
lua_pop(L, 1);
push_error_handler(L);
// Create the gettext metatable.
cmd_log_ << lua_common::register_gettext_metatable(L);
@ -493,23 +486,11 @@ bool lua_kernel_base::protected_call(int nArgs, int nRets, error_handler e_h)
return protected_call(mState, nArgs, nRets, e_h);
}
extern int luaW_pcall_internal(lua_State *L, int nArgs, int nRets);
bool lua_kernel_base::protected_call(lua_State * L, int nArgs, int nRets, error_handler e_h)
{
// Load the error handler before the function and its arguments.
lua_pushlightuserdata(L
, executeKey);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_insert(L, -2 - nArgs);
int error_handler_index = lua_gettop(L) - nArgs - 1;
// Call the function.
int errcode = lua_pcall(L, nArgs, nRets, -2 - nArgs);
tlua_jailbreak_exception::rethrow();
// Remove the error handler.
lua_remove(L, error_handler_index);
int errcode = luaW_pcall_internal(L, nArgs, nRets);
if (errcode != LUA_OK) {
char const * msg = lua_tostring(L, -1);

View file

@ -1,7 +1,6 @@
#pragma once
#include "lua/lua.h"
#include "map/location.hpp"
#include "scripting/lua_api.hpp"
#include "pathfind/pathfind.hpp"
/**

View file

@ -74,15 +74,13 @@ static int impl_race_get(lua_State* L)
return 1;
}
if (strcmp(m, "male_name_gen") == 0) {
new(lua_newuserdata(L, sizeof(proxy_name_generator)))
proxy_name_generator(race.generator(unit_race::MALE));
new(L) proxy_name_generator(race.generator(unit_race::MALE));
luaL_getmetatable(L, Gen);
lua_setmetatable(L, -2);
return 1;
}
if (strcmp(m, "female_name_gen") == 0) {
new(lua_newuserdata(L, sizeof(proxy_name_generator)))
proxy_name_generator(race.generator(unit_race::FEMALE));
new(L) proxy_name_generator(race.generator(unit_race::FEMALE));
luaL_getmetatable(L, Gen);
lua_setmetatable(L, -2);
return 1;

View file

@ -37,7 +37,7 @@ static const char * Rng = "Rng";
int impl_rng_create(lua_State* L)
{
uint32_t seed = lua_kernel_base::get_lua_kernel<lua_kernel_base>(L).get_random_seed();
new ( lua_newuserdata(L, sizeof(mt_rng)) ) mt_rng(seed);
new(L) mt_rng(seed);
luaL_setmetatable(L, Rng);
return 1;

View file

@ -1,33 +0,0 @@
/*
Copyright (C) 2014 - 2016 by David White <dave@whitevine.net>
Part of the Battle for Wesnoth Project http://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 "lua_types.hpp"
/* Dummy pointer for getting unique keys for Lua's registry. */
static char const v_executeKey = 0;
static char const v_getunitKey = 0;
static char const v_unitvarKey = 0;
static char const v_ustatusKey = 0;
static char const v_uattacksKey = 0;
static char const v_uattackKey = 0;
static char const v_formulaKey = 0;
luatypekey const executeKey = static_cast<void *>(const_cast<char *>(&v_executeKey));
luatypekey const getunitKey = static_cast<void *>(const_cast<char *>(&v_getunitKey));
luatypekey const unitvarKey = static_cast<void *>(const_cast<char *>(&v_unitvarKey));
luatypekey const ustatusKey = static_cast<void *>(const_cast<char *>(&v_ustatusKey));
luatypekey const uattacksKey = static_cast<void *>(const_cast<char *>(&v_uattacksKey));
luatypekey const uattackKey = static_cast<void *>(const_cast<char *>(&v_uattackKey));
luatypekey const formulaKey = static_cast<void *>(const_cast<char *>(&v_formulaKey));

View file

@ -1,30 +0,0 @@
/*
Copyright (C) 2014 - 2016 by David White <dave@whitevine.net>
Part of the Battle for Wesnoth Project http://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.
*/
#ifndef SCRIPTING_LUA_TYPES_HPP
#define SCRIPTING_LUA_TYPES_HPP
typedef void* luatypekey;
// i dont want to cast to void* each time ....
// a drawback is, that these are now normal static variables wich are initialised at initialisation time (so you shoudn't use these at/before initialisation time).
extern luatypekey const executeKey;
extern luatypekey const getunitKey;
extern luatypekey const unitvarKey;
extern luatypekey const ustatusKey;
extern luatypekey const uattacksKey;
extern luatypekey const uattackKey;
extern luatypekey const formulaKey;
#endif

568
src/scripting/lua_unit.cpp Normal file
View file

@ -0,0 +1,568 @@
/*
Copyright (C) 2009 - 2016 by Guillaume Melquiond <guillaume.melquiond@gmail.com>
Part of the Battle for Wesnoth Project http://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 "lua_unit.hpp"
#include "game_board.hpp"
#include "log.hpp"
#include "map/location.hpp" // for map_location
#include "resources.hpp"
#include "scripting/lua_common.hpp"
#include "scripting/lua_unit_attacks.hpp"
#include "scripting/push_check.hpp"
#include "scripting/game_lua_kernel.hpp"
#include "units/unit.hpp"
#include "units/map.hpp"
#include "lua/lauxlib.h"
#include "lua/lua.h" // for lua_State, lua_settop, etc
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 getunitKey[] = "unit";
static const char ustatusKey[] = "unit status";
static const char unitvarKey[] = "unit variables";
lua_unit::~lua_unit()
{
}
unit* lua_unit::get()
{
if (ptr) return ptr.get();
if (c_ptr) return c_ptr;
if (side) {
return resources::gameboard->teams()[side - 1].recall_list().find_if_matches_underlying_id(uid).get();
}
unit_map::unit_iterator ui = resources::units->find(uid);
if (!ui.valid()) return nullptr;
return ui.get_shared_ptr().get(); //&*ui would not be legal, must get new shared_ptr by copy ctor because the unit_map itself is holding a boost shared pointer.
}
unit_ptr lua_unit::get_shared()
{
if (ptr) return ptr;
if (side) {
return resources::gameboard->teams()[side - 1].recall_list().find_if_matches_underlying_id(uid);
}
unit_map::unit_iterator ui = resources::units->find(uid);
if (!ui.valid()) return unit_ptr();
return ui.get_shared_ptr(); //&*ui would not be legal, must get new shared_ptr by copy ctor because the unit_map itself is holding a boost shared pointer.
}
// Having this function here not only simplifies other code, it allows us to move
// pointers around from one structure to another.
// This makes bare pointer->map in particular about 2 orders of magnitude faster,
// as benchmarked from Lua code.
bool lua_unit::put_map(const map_location &loc)
{
if (ptr) {
ptr->set_location(loc);
resources::units->erase(loc);
std::pair<unit_map::unit_iterator, bool> res = resources::units->insert(ptr);
if (res.second) {
ptr.reset();
uid = res.first->underlying_id();
} else {
ERR_LUA << "Could not move unit " << ptr->underlying_id() << " onto map location " << loc << '\n';
return false;
}
} else if (side) { // recall list
unit_ptr it = resources::gameboard->teams()[side - 1].recall_list().extract_if_matches_underlying_id(uid);
if (it) {
side = 0;
// uid may be changed by unit_map on insertion
uid = resources::units->replace(loc, *it).first->underlying_id();
} else {
ERR_LUA << "Could not find unit " << uid << " on recall list of side " << side << '\n';
return false;
}
} else { // on map
unit_map::unit_iterator ui = resources::units->find(uid);
if (ui != resources::units->end()) {
map_location from = ui->get_location();
if (from != loc) { // This check is redundant in current usage
resources::units->erase(loc);
resources::units->move(from, loc);
}
// No need to change our contents
} else {
ERR_LUA << "Could not find unit " << uid << " on the map" << std::endl;
return false;
}
}
return true;
}
bool luaW_isunit(lua_State* L, int index)
{
return luaL_testudata(L, index,getunitKey);
}
enum {
LU_OK,
LU_NOT_UNIT,
LU_NOT_ON_MAP,
LU_NOT_VALID,
};
static lua_unit* internal_get_unit(lua_State *L, int index, bool only_on_map, int& error)
{
error = LU_OK;
if(!luaW_isunit(L, index)) {
error = LU_NOT_UNIT;
return nullptr;
}
lua_unit* lu = static_cast<lua_unit*>(lua_touserdata(L, index));
if(only_on_map && !lu->on_map()) {
error = LU_NOT_ON_MAP;
}
if(!lu->get()) {
error = LU_NOT_VALID;
}
return lu;
}
unit* luaW_tounit(lua_State *L, int index, bool only_on_map)
{
int error;
lua_unit* lu = internal_get_unit(L, index, only_on_map, error);
if(error != LU_OK) {
return nullptr;
}
return lu->get();
}
unit_ptr luaW_tounit_ptr(lua_State *L, int index, bool only_on_map)
{
int error;
lua_unit* lu = internal_get_unit(L, index, only_on_map, error);
if(error != LU_OK) {
return nullptr;
}
return lu->get_shared();
}
lua_unit* luaW_tounit_ref(lua_State *L, int index)
{
int error;
return internal_get_unit(L, index, false, error);
}
static void unit_show_error(lua_State *L, int index, int error)
{
switch(error) {
case LU_NOT_UNIT:
luaL_typerror(L, index, "unit");
case LU_NOT_VALID:
luaL_argerror(L, index, "unit not found");
case LU_NOT_ON_MAP:
luaL_argerror(L, index, "unit not found on map");
}
}
unit_ptr luaW_checkunit_ptr(lua_State *L, int index, bool only_on_map)
{
int error;
lua_unit* lu = internal_get_unit(L, index, only_on_map, error);
unit_show_error(L, index, error);
return lu->get_shared();
}
unit& luaW_checkunit(lua_State *L, int index, bool only_on_map)
{
int error;
lua_unit* lu = internal_get_unit(L, index, only_on_map, error);
unit_show_error(L, index, error);
return *lu->get();
}
lua_unit* luaW_checkunit_ref(lua_State *L, int index)
{
int error;
lua_unit* lu = internal_get_unit(L, index, false, error);
unit_show_error(L, index, error);
return lu;
}
void lua_unit::setmetatable(lua_State *L)
{
luaL_setmetatable(L, getunitKey);
}
lua_unit* luaW_pushlocalunit(lua_State *L, unit& u)
{
lua_unit* res = new(L) lua_unit(u);
lua_unit::setmetatable(L);
return res;
}
/**
* Destroys a unit object before it is collected (__gc metamethod).
*/
static int impl_unit_collect(lua_State *L)
{
lua_unit *u = static_cast<lua_unit *>(lua_touserdata(L, 1));
u->lua_unit::~lua_unit();
return 0;
}
/**
* Checks two lua proxy units for equality. (__eq metamethod)
*/
static int impl_unit_equality(lua_State* L)
{
unit& left = luaW_checkunit(L, 1);
unit& right = luaW_checkunit(L, 2);
const bool equal = left.underlying_id() == right.underlying_id();
lua_pushboolean(L, equal);
return 1;
}
/**
* Gets some data on a unit (__index metamethod).
* - Arg 1: full userdata containing the unit id.
* - Arg 2: string containing the name of the property.
* - Ret 1: something containing the attribute.
*/
static int impl_unit_get(lua_State *L)
{
lua_unit *lu = static_cast<lua_unit *>(lua_touserdata(L, 1));
char const *m = luaL_checkstring(L, 2);
const unit* pu = lu->get();
if(strcmp(m, "valid") == 0) {
if(!pu) {
return 0;
}
if(lu->on_map()) {
lua_pushstring(L, "map");
} else if(lu->on_recall_list()) {
lua_pushstring(L, "recall");
} else {
lua_pushstring(L, "private");
}
return 1;
}
if(!pu) {
return luaL_argerror(L, 1, "unknown unit");
}
unit const &u = *pu;
// Find the corresponding attribute.
return_int_attrib("x", u.get_location().x + 1);
return_int_attrib("y", u.get_location().y + 1);
if(strcmp(m, "loc") == 0) {
lua_pushinteger(L, u.get_location().x + 1);
lua_pushinteger(L, u.get_location().y + 1);
return 2;
}
return_int_attrib("side", u.side());
return_string_attrib("id", u.id());
return_string_attrib("type", u.type_id());
return_string_attrib("image_mods", u.effect_image_mods());
return_string_attrib("usage", u.usage());
return_int_attrib("hitpoints", u.hitpoints());
return_int_attrib("max_hitpoints", u.max_hitpoints());
return_int_attrib("experience", u.experience());
return_int_attrib("max_experience", u.max_experience());
return_int_attrib("recall_cost", u.recall_cost());
return_int_attrib("moves", u.movement_left());
return_int_attrib("max_moves", u.total_movement());
return_int_attrib("max_attacks", u.max_attacks());
return_int_attrib("attacks_left", u.attacks_left());
return_tstring_attrib("name", u.name());
return_bool_attrib("canrecruit", u.can_recruit());
return_int_attrib("level", u.level());
return_int_attrib("cost", u.cost());
return_vector_string_attrib("extra_recruit", u.recruits());
return_vector_string_attrib("advances_to", u.advances_to());
if(strcmp(m, "alignment") == 0) {
lua_push(L, u.alignment());
return 1;
}
if(strcmp(m, "upkeep") == 0) {
unit::t_upkeep upkeep = u.upkeep_raw();
if(boost::get<unit::upkeep_full>(&upkeep) != nullptr){
lua_pushstring(L, "full");
} else if(boost::get<unit::upkeep_loyal>(&upkeep) != nullptr){
lua_pushstring(L, "loyal");
} else {
lua_push(L, boost::get<int>(upkeep));
}
return 1;
}
if(strcmp(m, "advancements") == 0) {
lua_push(L, u.modification_advancements());
return 1;
}
if(strcmp(m, "overlays") == 0) {
lua_push(L, u.overlays());
return 1;
}
if(strcmp(m, "traits") == 0) {
lua_push(L, u.get_traits_list());
return 1;
}
if(strcmp(m, "abilities") == 0) {
lua_push(L, u.get_ability_list());
return 1;
}
if(strcmp(m, "status") == 0) {
lua_createtable(L, 1, 0);
lua_pushvalue(L, 1);
lua_rawseti(L, -2, 1);
luaL_setmetatable(L, ustatusKey);
return 1;
}
if(strcmp(m, "variables") == 0) {
lua_createtable(L, 1, 0);
lua_pushvalue(L, 1);
lua_rawseti(L, -2, 1);
luaL_setmetatable(L, unitvarKey);
return 1;
}
if(strcmp(m, "attacks") == 0) {
push_unit_attacks_table(L, 1);
return 1;
}
return_cfg_attrib("recall_filter", cfg = u.recall_filter());
return_bool_attrib("hidden", u.get_hidden());
return_bool_attrib("petrified", u.incapacitated());
return_bool_attrib("resting", u.resting());
return_string_attrib("role", u.get_role());
return_string_attrib("race", u.race()->id());
return_string_attrib("gender", gender_string(u.gender()));
return_string_attrib("variation", u.variation());
return_bool_attrib("zoc", u.get_emit_zoc());
return_string_attrib("facing", map_location::write_direction(u.facing()));
return_string_attrib("portrait", u.big_profile() == u.absolute_image() ? u.absolute_image() + u.image_mods() : u.big_profile());
return_cfg_attrib("__cfg", u.write(cfg); u.get_location().write(cfg));
return lua_kernel_base::get_lua_kernel<game_lua_kernel>(L).return_unit_method(L, m);
}
/**
* Sets some data on a unit (__newindex metamethod).
* - Arg 1: full userdata containing the unit id.
* - Arg 2: string containing the name of the property.
* - Arg 3: something containing the attribute.
*/
static int impl_unit_set(lua_State *L)
{
lua_unit *lu = static_cast<lua_unit *>(lua_touserdata(L, 1));
char const *m = luaL_checkstring(L, 2);
unit* pu = lu->get();
if (!pu) return luaL_argerror(L, 1, "unknown unit");
unit &u = *pu;
// Find the corresponding attribute.
//modify_int_attrib_check_range("side", u.set_side(value), 1, static_cast<int>(teams().size())); TODO: Figure out if this is a good idea, to refer to teams() and make this depend on having a gamestate
modify_int_attrib("side", u.set_side(value));
modify_int_attrib("moves", u.set_movement(value));
modify_int_attrib("hitpoints", u.set_hitpoints(value));
modify_int_attrib("experience", u.set_experience(value));
modify_int_attrib("recall_cost", u.set_recall_cost(value));
modify_int_attrib("attacks_left", u.set_attacks(value));
modify_int_attrib("level", u.set_level(value));
modify_bool_attrib("resting", u.set_resting(value));
modify_tstring_attrib("name", u.set_name(value));
modify_string_attrib("role", u.set_role(value));
modify_string_attrib("facing", u.set_facing(map_location::parse_direction(value)));
modify_bool_attrib("hidden", u.set_hidden(value));
modify_bool_attrib("zoc", u.set_emit_zoc(value));
modify_bool_attrib("canrecruit", u.set_can_recruit(value));
modify_vector_string_attrib("extra_recruit", u.set_recruits(vector));
modify_vector_string_attrib("advances_to", u.set_advances_to(vector));
if(strcmp(m, "alignment") == 0) {
u.set_alignment(lua_check<unit_type::ALIGNMENT>(L, 3));
return 0;
}
if(strcmp(m, "advancements") == 0) {
u.set_advancements(lua_check<std::vector<config> >(L, 3));
return 0;
}
if(strcmp(m, "upkeep") == 0) {
if(lua_isnumber(L, 3)) {
u.set_upkeep(luaL_checkint(L, 3));
return 0;
}
const char* v = luaL_checkstring(L, 3);
if(strcmp(m, "loyal") == 0) {
u.set_upkeep(unit::upkeep_loyal());
} else if(strcmp(m, "full") == 0) {
u.set_upkeep(unit::upkeep_full());
} else {
std::string err_msg = "unknown upkeep value of unit: ";
err_msg += v;
return luaL_argerror(L, 2, err_msg.c_str());
}
return 0;
}
if(!lu->on_map()) {
map_location loc = u.get_location();
modify_int_attrib("x", loc.x = value - 1; u.set_location(loc));
modify_int_attrib("y", loc.y = value - 1; u.set_location(loc));
}
std::string err_msg = "unknown modifiable property of unit: ";
err_msg += m;
return luaL_argerror(L, 2, err_msg.c_str());
}
/**
* Gets the status of a unit (__index metamethod).
* - Arg 1: table containing the userdata containing the unit id.
* - Arg 2: string containing the name of the status.
* - Ret 1: boolean.
*/
static int impl_unit_status_get(lua_State *L)
{
if(!lua_istable(L, 1)) {
return luaL_typerror(L, 1, "unit status");
}
lua_rawgeti(L, 1, 1);
const unit* u = luaW_tounit(L, -1);
if(!u) {
return luaL_argerror(L, 1, "unknown unit");
}
char const *m = luaL_checkstring(L, 2);
lua_pushboolean(L, u->get_state(m));
return 1;
}
/**
* Sets the status of a unit (__newindex metamethod).
* - Arg 1: table containing the userdata containing the unit id.
* - Arg 2: string containing the name of the status.
* - Arg 3: boolean.
*/
static int impl_unit_status_set(lua_State *L)
{
if(!lua_istable(L, 1)) {
return luaL_typerror(L, 1, "unit status");
}
lua_rawgeti(L, 1, 1);
unit* u = luaW_tounit(L, -1);
if(!u) {
return luaL_argerror(L, 1, "unknown unit");
}
char const *m = luaL_checkstring(L, 2);
u->set_state(m, luaW_toboolean(L, 3));
return 0;
}
/**
* Gets the variable of a unit (__index metamethod).
* - Arg 1: table containing the userdata containing the unit id.
* - Arg 2: string containing the name of the status.
* - Ret 1: boolean.
*/
static int impl_unit_variables_get(lua_State *L)
{
if(!lua_istable(L, 1)) {
return luaL_typerror(L, 1, "unit variables");
}
lua_rawgeti(L, 1, 1);
const unit* u = luaW_tounit(L, -1);
if(!u) {
return luaL_argerror(L, 1, "unknown unit");
}
char const *m = luaL_checkstring(L, 2);
return_cfgref_attrib("__cfg", u->variables());
variable_access_const v(m, u->variables());
return luaW_pushvariable(L, v) ? 1 : 0;
}
/**
* Sets the variable of a unit (__newindex metamethod).
* - Arg 1: table containing the userdata containing the unit id.
* - Arg 2: string containing the name of the status.
* - Arg 3: scalar.
*/
static int impl_unit_variables_set(lua_State *L)
{
if(!lua_istable(L, 1)) {
return luaL_typerror(L, 1, "unit variables");
}
lua_rawgeti(L, 1, 1);
unit* u = luaW_tounit(L, -1);
if(!u) {
return luaL_argerror(L, 1, "unknown unit");
}
char const *m = luaL_checkstring(L, 2);
if(strcmp(m, "__cfg") == 0) {
u->variables() = luaW_checkconfig(L, 3);
return 0;
}
variable_access_create v(m, u->variables());
luaW_checkvariable(L, v, 3);
return 0;
}
namespace lua_units {
std::string register_metatables(lua_State* L)
{
std::ostringstream cmd_out;
// Create the getunit metatable.
cmd_out << "Adding getunit metatable...\n";
luaL_newmetatable(L, getunitKey);
lua_pushcfunction(L, impl_unit_collect);
lua_setfield(L, -2, "__gc");
lua_pushcfunction(L, impl_unit_equality);
lua_setfield(L, -2, "__eq");
lua_pushcfunction(L, impl_unit_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, impl_unit_set);
lua_setfield(L, -2, "__newindex");
lua_pushstring(L, "unit");
lua_setfield(L, -2, "__metatable");
// Create the unit status metatable.
cmd_out << "Adding unit status metatable...\n";
luaL_newmetatable(L, ustatusKey);
lua_pushcfunction(L, impl_unit_status_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, impl_unit_status_set);
lua_setfield(L, -2, "__newindex");
lua_pushstring(L, "unit status");
lua_setfield(L, -2, "__metatable");
// Create the unit variables metatable.
cmd_out << "Adding unit variables metatable...\n";
luaL_newmetatable(L, unitvarKey);
lua_pushcfunction(L, impl_unit_variables_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, impl_unit_variables_set);
lua_setfield(L, -2, "__newindex");
lua_pushstring(L, "unit variables");
lua_setfield(L, -2, "__metatable");
return cmd_out.str();
}
}

View file

@ -17,42 +17,60 @@
#include <cstddef>
#include <string>
#include "lua_types.hpp" // the luatype typedef
#include "scripting/lua_common.hpp"
#include "units/ptr.hpp"
struct lua_State;
class lua_unit;
struct map_location;
/**
* Test if a Lua value is a unit
*/
bool luaW_isunit(lua_State *, int index);
/**
* Converts a Lua value to a unit pointer.
*/
unit* luaW_tounit(lua_State *L, int index, bool only_on_map = false);
/**
* Displays a message in the chat window.
*/
void chat_message(std::string const &caption, std::string const &msg);
/**
* Calls a Lua function stored below its @a nArgs arguments at the top of the stack.
* @param nRets LUA_MULTRET for unbounded return values.
* @return true if the call was successful and @a nRets return values are available.
*/
bool luaW_pcall(lua_State *L, int nArgs, int nRets, bool allow_wml_error = false);
/**
* Converts a Lua value to a unit pointer.
*/
unit& luaW_checkunit(lua_State *L, int index, bool only_on_map = false);
class lua_unit;
lua_unit* luaW_pushlocalunit(lua_State *L, unit& u);
/**
* Similar to luaW_checkunit/luaW_tounit but returns a unit_ptr, use this instead of
* luaW_checkunit/luaW_tounit when uasing an api that needs unit_ptr.
* Pushes a private unit on the stack.
*/
lua_unit* luaW_pushlocalunit(lua_State *L, unit& u);
/**
* Similar to luaW_tounit but returns a unit_ptr; use this instead of
* luaW_tounit when using an api that needs unit_ptr.
*/
unit_ptr luaW_tounit_ptr(lua_State *L, int index, bool only_on_map);
/**
* Similar to luaW_checkunit but returns a unit_ptr; use this instead of
* luaW_checkunit when using an api that needs unit_ptr.
*/
unit_ptr luaW_checkunit_ptr(lua_State *L, int index, bool only_on_map);
struct map_location;
/**
* Similar to luaW_tounit but returns a lua_unit; use this if you need
* to handle map and recall units differently, for example.
*
* Note that this only returns null if the element on the stack was not a unit,
* so it may be an invalid unit.
*/
lua_unit* luaW_tounit_ref(lua_State *L, int index);
/**
* Similar to luaW_checkunit but returns a lua_unit; use this if you need
* to handle map and recall units differently, for example.
*/
lua_unit* luaW_checkunit_ref(lua_State *L, int index);
/**
* Storage for a unit, either owned by the Lua code (#ptr != 0), a
@ -65,22 +83,43 @@ class lua_unit
unit_ptr ptr;
int side;
unit* c_ptr;
lua_unit(lua_unit const &);
lua_unit(lua_unit const &) = delete;
lua_unit& operator=(const lua_unit&) = delete;
template<typename... Args>
friend lua_unit* luaW_pushunit(lua_State *L, Args... args);
friend lua_unit* luaW_pushlocalunit(lua_State *L, unit& u);
static void setmetatable(lua_State *L);
public:
lua_unit(size_t u): uid(u), ptr(), side(0), c_ptr() {}
lua_unit(unit_ptr u): uid(0), ptr(u), side(0), c_ptr() {}
lua_unit(int s, size_t u): uid(u), ptr(), side(s), c_ptr() {}
lua_unit(unit& u): uid(0), ptr(), side(0), c_ptr(&u) {}
~lua_unit();
bool on_map() const { return !ptr && side == 0; }
int on_recall_list() const { return side; }
unit* get();
unit_ptr get_shared();
unit* operator->() {return get();}
unit& operator*() {return *get();}
void clear_ref() { uid = 0; ptr = unit_ptr(); side = 0; c_ptr = nullptr; }
// Clobbers loc
bool put_map(const map_location &loc);
};
template<typename... Args>
inline lua_unit* luaW_pushunit(lua_State *L, Args... args) {
lua_unit* lu = new(L) lua_unit(args...);
lua_unit::setmetatable(L);
return lu;
}
namespace lua_units {
std::string register_metatables(lua_State *L);
}
#endif

View file

@ -0,0 +1,230 @@
/*
Copyright (C) 2009 - 2016 by Guillaume Melquiond <guillaume.melquiond@gmail.com>
Part of the Battle for Wesnoth Project http://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 "lua_unit_attacks.hpp"
#include "scripting/lua_common.hpp"
#include "scripting/lua_unit.hpp"
#include "units/unit.hpp"
#include "lua/lauxlib.h"
#include "lua/lua.h" // for lua_State, lua_settop, etc
static const char uattacksKey[] = "unit attacks table";
static const char uattackKey[] = "unit attack";
void push_unit_attacks_table(lua_State* L, int idx)
{
lua_createtable(L, 1, 0);
lua_pushvalue(L, idx);
// hack: store the unit_type at -1 because we want positive indices to refer to the attacks.
lua_rawseti(L, -2, -1);
luaL_setmetatable(L, uattacksKey);
}
/**
* Gets the attacks of a unit or unit type (__index metamethod).
* - Arg 1: table containing the userdata containing the unit or unit type.
* - Arg 2: index (int) or id (string) identifying a particular attack.
* - Ret 1: the unit's attacks.
*/
static int impl_unit_attacks_get(lua_State *L)
{
if(!lua_istable(L, 1)) {
return luaL_typerror(L, 1, "unit attacks");
}
lua_rawgeti(L, 1, -1);
const unit* u = luaW_tounit(L, -1);
const unit_type* ut = static_cast<const unit_type*>(luaL_testudata(L, -1, "unit type"));
if(!u && !ut) {
return luaL_argerror(L, 1, "unknown unit");
}
const attack_type* attack = nullptr;
const std::vector<attack_type>& attacks = u ? u->attacks() : ut->attacks();
if(!lua_isnumber(L,2)) {
std::string attack_id = luaL_checkstring(L, 2);
for(const attack_type& at : attacks) {
if(at.id() == attack_id) {
attack = &at;
break;
}
}
if(attack == nullptr) {
//return nil on invalid index, just like lua tables do.
return 0;
}
} else {
size_t index = luaL_checkinteger(L, 2) - 1;
if(index >= attacks.size()) {
//return nil on invalid index, just like lua tables do.
return 0;
}
attack = &attacks[index];
}
// stack { lua_unit }, id/index, lua_unit
lua_createtable(L, 2, 0);
// stack { lua_unit }, id/index, lua_unit, table
lua_pushvalue(L, -2);
// stack { lua_unit }, id/index, lua_unit, table, lua_unit
lua_rawseti(L, -2, 1);
// stack { lua_unit }, id/index, lua_unit, table
lua_pushstring(L, attack->id().c_str());
// stack { lua_unit }, id/index, lua_unit, table, attack id
lua_rawseti(L, -2, 2);
// stack { lua_unit }, id/index, lua_unit, table
luaL_setmetatable(L, uattackKey);
return 1;
}
/**
* Counts the attacks of a unit (__len metamethod).
* - Arg 1: table containing the userdata containing the unit id.
* - Ret 1: size of unit attacks vector.
*/
static int impl_unit_attacks_len(lua_State *L)
{
if(!lua_istable(L, 1)) {
return luaL_typerror(L, 1, "unit attacks");
}
lua_rawgeti(L, 1, -1);
const unit* u = luaW_tounit(L, -1);
const unit_type* ut = static_cast<const unit_type*>(luaL_testudata(L, -1, "unit type"));
if(!u && !ut) {
return luaL_argerror(L, 1, "unknown unit");
}
lua_pushinteger(L, (u ? u->attacks() : ut->attacks()).size());
return 1;
}
/**
* Gets a propoerty of a units attack (__index metamethod).
* - Arg 1: table containing the userdata containing the unit id. and a string identyfying the attack.
* - Arg 2: string
* - Ret 1:
*/
static int impl_unit_attack_get(lua_State *L)
{
if(!lua_istable(L, 1)) {
return luaL_typerror(L, 1, "unit attack");
}
lua_rawgeti(L, 1, 1);
const unit* u = luaW_tounit(L, -1);
const unit_type* ut = static_cast<const unit_type*>(luaL_testudata(L, -1, "unit type"));
if(!u && !ut) {
return luaL_argerror(L, 1, "unknown unit");
}
lua_rawgeti(L, 1, 2);
std::string attack_id = luaL_checkstring(L, -1);
char const *m = luaL_checkstring(L, 2);
for(const attack_type& attack : u ? u->attacks() : ut->attacks()) {
if(attack.id() == attack_id) {
return_string_attrib("description", attack.name());
return_string_attrib("name", attack.id());
return_string_attrib("type", attack.type());
return_string_attrib("icon", attack.icon());
return_string_attrib("range", attack.range());
return_int_attrib("damage", attack.damage());
return_int_attrib("number", attack.num_attacks());
return_int_attrib("attack_weight", attack.attack_weight());
return_int_attrib("defense_weight", attack.defense_weight());
return_int_attrib("accuracy", attack.accuracy());
return_int_attrib("movement_used", attack.movement_used());
return_int_attrib("parry", attack.parry());
return_cfgref_attrib("specials", attack.specials());
return_cfgref_attrib("__cfg", attack.to_config());
std::string err_msg = "unknown property of attack: ";
err_msg += m;
return luaL_argerror(L, 2, err_msg.c_str());
}
}
return luaL_argerror(L, 1, "invalid attack id");
}
/**
* Gets a propoerty of a units attack (__index metamethod).
* - Arg 1: table containing the userdata containing the unit id. and a string identyfying the attack.
* - Arg 2: string
* - Ret 1:
*/
static int impl_unit_attack_set(lua_State *L)
{
if(!lua_istable(L, 1)) {
return luaL_typerror(L, 1, "unit attack");
}
lua_rawgeti(L, 1, 1);
unit* u = luaW_tounit(L, -1);
const unit_type* ut = static_cast<const unit_type*>(luaL_testudata(L, -1, "unit type"));
if(!u && !ut) {
return luaL_argerror(L, 1, "unknown unit");
}
lua_rawgeti(L, 1, 2);
std::string attack_id = luaL_checkstring(L, -1);
char const *m = luaL_checkstring(L, 2);
for(attack_type& attack : u ? u->attacks() : ut->attacks()) {
if(attack.id() == attack_id) {
modify_tstring_attrib("description", attack.set_name(value));
// modify_string_attrib("name", attack.set_id(value));
modify_string_attrib("type", attack.set_type(value));
modify_string_attrib("icon", attack.set_icon(value));
modify_string_attrib("range", attack.set_range(value));
modify_int_attrib("damage", attack.set_damage(value));
modify_int_attrib("number", attack.set_num_attacks(value));
modify_int_attrib("attack_weight", attack.set_attack_weight(value));
modify_int_attrib("defense_weight", attack.set_defense_weight(value));
modify_int_attrib("accuracy", attack.set_accuracy(value));
modify_int_attrib("movement_used", attack.set_movement_used(value));
modify_int_attrib("parry", attack.set_parry(value));
if(strcmp(m, "specials") == 0) {
attack.set_specials(luaW_checkconfig(L, 3));
return 0;
}
return_cfgref_attrib("specials", attack.specials());
std::string err_msg = "unknown modifyable property of attack: ";
err_msg += m;
return luaL_argerror(L, 2, err_msg.c_str());
}
}
return luaL_argerror(L, 1, "invalid attack id");
}
namespace lua_units {
std::string register_attacks_metatables(lua_State* L)
{
std::ostringstream cmd_out;
// Create the unit attacks metatable.
cmd_out << "Adding unit attacks metatable...\n";
luaL_newmetatable(L, uattacksKey);
lua_pushcfunction(L, impl_unit_attacks_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, impl_unit_attacks_len);
lua_setfield(L, -2, "__len");
lua_pushstring(L, "unit attacks");
lua_setfield(L, -2, "__metatable");
// Create the unit attack metatable
luaL_newmetatable(L, uattackKey);
lua_pushcfunction(L, impl_unit_attack_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, impl_unit_attack_set);
lua_setfield(L, -2, "__newindex");
lua_pushstring(L, "unit attack");
lua_setfield(L, -2, "__metatable");
return cmd_out.str();
}
}

View file

@ -0,0 +1,28 @@
/*
Copyright (C) 2009 - 2016 by Guillaume Melquiond <guillaume.melquiond@gmail.com>
Part of the Battle for Wesnoth Project http://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.
*/
#ifndef SCRIPTING_LUA_UNIT_ATTACKS_HPP
#define SCRIPTING_LUA_UNIT_ATTACKS_HPP
#include <string>
struct lua_State;
void push_unit_attacks_table(lua_State* L, int idx);
namespace lua_units {
std::string register_attacks_metatables(lua_State* L);
}
#endif

View file

@ -15,6 +15,7 @@
#include "scripting/lua_unit_type.hpp"
#include "scripting/lua_common.hpp"
#include "scripting/lua_unit_attacks.hpp"
#include "scripting/push_check.hpp"
#include "units/types.hpp"
@ -73,13 +74,7 @@ static int impl_unit_type_get(lua_State *L)
return 1;
}
if (strcmp(m, "attacks") == 0) {
lua_createtable(L, 1, 0);
lua_pushvalue(L, 1);
// hack: store the unit_type at -1 because we want positive indices to refer to the attacks.
lua_rawseti(L, -2, -1);
lua_pushlightuserdata(L, uattacksKey);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_setmetatable(L, -2);
push_unit_attacks_table(L, 1);
return 1;
}
return 0;

View file

@ -17,7 +17,6 @@
#include "config.hpp"
#include "game_errors.hpp"
#include "log.hpp"
#include "scripting/lua_api.hpp"
#include "scripting/lua_common.hpp"
#include "scripting/lua_rng.hpp"
#include "scripting/lua_pathfind_cost_calculator.hpp"

View file

@ -2380,11 +2380,11 @@ unit& unit::clone(bool is_temporary)
}
unit_movement_resetter::unit_movement_resetter(unit &u, bool operate) :
u_(u), moves_(u.movement_left(true))
unit_movement_resetter::unit_movement_resetter(const unit &u, bool operate) :
u_(const_cast<unit&>(u)), moves_(u.movement_left(true))
{
if (operate) {
u.set_movement(u.total_movement());
u_.set_movement(u_.total_movement());
}
}

View file

@ -548,7 +548,7 @@ private:
struct unit_movement_resetter
: private boost::noncopyable
{
unit_movement_resetter(unit& u, bool operate=true);
unit_movement_resetter(const unit& u, bool operate=true);
~unit_movement_resetter();
private: