add lua terrainmap object
This commit is contained in:
parent
1671975859
commit
3d1e3b36df
9 changed files with 1539 additions and 0 deletions
|
@ -2710,6 +2710,12 @@
|
||||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Debug|Win32'">$(IntDir)Scripting\</ObjectFileName>
|
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Debug|Win32'">$(IntDir)Scripting\</ObjectFileName>
|
||||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|Win32'">$(IntDir)Scripting\</ObjectFileName>
|
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|Win32'">$(IntDir)Scripting\</ObjectFileName>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\scripting\lua_terrainfilter.cpp">
|
||||||
|
<ObjectFileName>$(IntDir)Scripting\</ObjectFileName>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\scripting\lua_terrainmap.cpp">
|
||||||
|
<ObjectFileName>$(IntDir)Scripting\</ObjectFileName>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\scripting\lua_unit.cpp">
|
<ClCompile Include="..\..\src\scripting\lua_unit.cpp">
|
||||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Scripting\</ObjectFileName>
|
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Scripting\</ObjectFileName>
|
||||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)Scripting\</ObjectFileName>
|
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)Scripting\</ObjectFileName>
|
||||||
|
@ -3945,6 +3951,8 @@
|
||||||
<ClInclude Include="..\..\src\scripting\lua_race.hpp" />
|
<ClInclude Include="..\..\src\scripting\lua_race.hpp" />
|
||||||
<ClInclude Include="..\..\src\scripting\lua_rng.hpp" />
|
<ClInclude Include="..\..\src\scripting\lua_rng.hpp" />
|
||||||
<ClInclude Include="..\..\src\scripting\lua_team.hpp" />
|
<ClInclude Include="..\..\src\scripting\lua_team.hpp" />
|
||||||
|
<ClInclude Include="..\..\src\scripting\lua_terrainfilter.hpp" />
|
||||||
|
<ClInclude Include="..\..\src\scripting\lua_terrainmap.hpp" />
|
||||||
<ClInclude Include="..\..\src\scripting\lua_unit.hpp" />
|
<ClInclude Include="..\..\src\scripting\lua_unit.hpp" />
|
||||||
<ClInclude Include="..\..\src\scripting\lua_unit_attacks.hpp" />
|
<ClInclude Include="..\..\src\scripting\lua_unit_attacks.hpp" />
|
||||||
<ClInclude Include="..\..\src\scripting\lua_unit_type.hpp" />
|
<ClInclude Include="..\..\src\scripting\lua_unit_type.hpp" />
|
||||||
|
|
|
@ -322,6 +322,8 @@ scripting/lua_preferences.cpp
|
||||||
scripting/lua_race.cpp
|
scripting/lua_race.cpp
|
||||||
scripting/lua_rng.cpp
|
scripting/lua_rng.cpp
|
||||||
scripting/lua_team.cpp
|
scripting/lua_team.cpp
|
||||||
|
scripting/lua_terrainmap.cpp
|
||||||
|
scripting/lua_terrainfilter.cpp
|
||||||
scripting/lua_unit.cpp
|
scripting/lua_unit.cpp
|
||||||
scripting/lua_unit_attacks.cpp
|
scripting/lua_unit_attacks.cpp
|
||||||
scripting/lua_unit_type.cpp
|
scripting/lua_unit_type.cpp
|
||||||
|
|
|
@ -943,6 +943,31 @@ bool luaW_checkvariable(lua_State *L, variable_access_create& v, int n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool luaW_tableget(lua_State *L, int index, const char* key)
|
||||||
|
{
|
||||||
|
if(index < 0) {
|
||||||
|
//with the next lua_pushstring negative indicies will no longer be correct.
|
||||||
|
--index;
|
||||||
|
}
|
||||||
|
lua_pushstring(L, key);
|
||||||
|
lua_gettable(L, index);
|
||||||
|
if(lua_isnoneornil(L, -1)) {
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::string_view luaW_tostring(lua_State *L, int index)
|
||||||
|
{
|
||||||
|
size_t len = 0;
|
||||||
|
const char* str = lua_tolstring(L, index, &len);
|
||||||
|
if(!str) {
|
||||||
|
throw luaL_error (L, "not a string");
|
||||||
|
}
|
||||||
|
return utils::string_view(str, len);
|
||||||
|
}
|
||||||
|
|
||||||
void chat_message(const std::string& caption, const std::string& msg)
|
void chat_message(const std::string& caption, const std::string& msg)
|
||||||
{
|
{
|
||||||
if (!game_display::get_singleton()) return;
|
if (!game_display::get_singleton()) return;
|
||||||
|
|
|
@ -26,6 +26,8 @@ class vconfig;
|
||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
#include "variable_info.hpp"
|
#include "variable_info.hpp"
|
||||||
#include "map/location.hpp"
|
#include "map/location.hpp"
|
||||||
|
#include "serialization/string_view.hpp"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
@ -172,6 +174,10 @@ bool luaW_pushvariable(lua_State *L, variable_access_const& v);
|
||||||
|
|
||||||
bool luaW_checkvariable(lua_State *L, variable_access_create& v, int n);
|
bool luaW_checkvariable(lua_State *L, variable_access_create& v, int n);
|
||||||
|
|
||||||
|
bool luaW_tableget(lua_State *L, int index, const char* key);
|
||||||
|
|
||||||
|
utils::string_view luaW_tostring(lua_State *L, int index);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays a message in the chat window.
|
* Displays a message in the chat window.
|
||||||
*/
|
*/
|
||||||
|
|
925
src/scripting/lua_terrainfilter.cpp
Normal file
925
src/scripting/lua_terrainfilter.cpp
Normal file
|
@ -0,0 +1,925 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2018 the Battle for Wesnoth Project https://www.wesnoth.org/
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY.
|
||||||
|
|
||||||
|
See the COPYING file for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "scripting/lua_terrainfilter.hpp"
|
||||||
|
#include "scripting/lua_terrainmap.hpp"
|
||||||
|
|
||||||
|
#include "formatter.hpp"
|
||||||
|
#include "log.hpp"
|
||||||
|
#include "map/location.hpp"
|
||||||
|
#include "map/map.hpp"
|
||||||
|
#include "scripting/lua_common.hpp"
|
||||||
|
#include "scripting/push_check.hpp"
|
||||||
|
#include "scripting/game_lua_kernel.hpp"
|
||||||
|
|
||||||
|
#include <boost/dynamic_bitset.hpp>
|
||||||
|
#include <boost/range/iterator_range.hpp>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include "lua/lauxlib.h"
|
||||||
|
#include "lua/lua.h"
|
||||||
|
|
||||||
|
static lg::log_domain log_scripting_lua_mapgen("scripting/lua/mapgen");
|
||||||
|
#define LOG_LMG LOG_STREAM(info, log_scripting_lua_mapgen)
|
||||||
|
#define ERR_LMG LOG_STREAM(err, log_scripting_lua_mapgen)
|
||||||
|
//general helper functions for parsing
|
||||||
|
|
||||||
|
struct inalid_lua_argument : public std::exception
|
||||||
|
{
|
||||||
|
explicit inalid_lua_argument(const std::string& msg) : errormessage_(msg) {}
|
||||||
|
const char* what() const noexcept { return errormessage_.c_str(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string errormessage_;
|
||||||
|
};
|
||||||
|
|
||||||
|
using knows_sets_t = std::map<std::string, std::set<map_location>>;
|
||||||
|
using offset_list_t = std::vector<std::pair<int, int>>;
|
||||||
|
using utils::string_view;
|
||||||
|
using dynamic_bitset = boost::dynamic_bitset<>;
|
||||||
|
using location_set = std::set<map_location>;
|
||||||
|
|
||||||
|
static const char terrinfilterKey[] = "terrainfilter";
|
||||||
|
#define LOG_MATCHES(NAME) \
|
||||||
|
LOG_LMG << #NAME << ":matches(" << l << ") line:" << __LINE__ << "\n";
|
||||||
|
namespace utils {
|
||||||
|
// todoc++14: use std::make_unique
|
||||||
|
template<typename T, typename... Args>
|
||||||
|
std::unique_ptr<T> make_unique(Args&&... args)
|
||||||
|
{
|
||||||
|
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
//helper functions for parsing
|
||||||
|
namespace {
|
||||||
|
bool iswhitespace(char c)
|
||||||
|
{
|
||||||
|
return c == ' ' || c == '\t' || c == '\n' || c == '\r';
|
||||||
|
}
|
||||||
|
|
||||||
|
void trim(string_view& s)
|
||||||
|
{
|
||||||
|
while(!s.empty() && iswhitespace(s.front())) {
|
||||||
|
s.remove_prefix(1);
|
||||||
|
}
|
||||||
|
while(!s.empty() && iswhitespace(s.back())) {
|
||||||
|
s.remove_suffix(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
void split_foreach(string_view s, char sep, const F& f)
|
||||||
|
{
|
||||||
|
if(s.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
int partend = s.find(sep);
|
||||||
|
if(partend == int(string_view::npos)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
f(s.substr(0, partend));
|
||||||
|
s.remove_prefix(partend + 1);
|
||||||
|
}
|
||||||
|
f(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
int atoi(string_view s)
|
||||||
|
{
|
||||||
|
if(s.empty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char** end = 0;
|
||||||
|
int res = strtol(&s[0], end, 10);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<int, int> parse_single_range(string_view s)
|
||||||
|
{
|
||||||
|
int dash_pos = s.find('-');
|
||||||
|
if(dash_pos == int(string_view::npos)) {
|
||||||
|
int res = atoi(s);
|
||||||
|
return {res, res};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
string_view first = s.substr(0, dash_pos);
|
||||||
|
string_view second = s.substr(dash_pos + 1);
|
||||||
|
return {atoi(first), atoi(second)};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic_bitset parse_range(string_view s)
|
||||||
|
{
|
||||||
|
dynamic_bitset res;
|
||||||
|
split_foreach(s, ',', [&](string_view part){
|
||||||
|
trim(part);
|
||||||
|
auto pair = parse_single_range(part);
|
||||||
|
int m = std::max(pair.first, pair.second);
|
||||||
|
if(m >= int(res.size())) {
|
||||||
|
res.resize(m + 1);
|
||||||
|
for(int i = pair.first; i <= pair.second; ++i) {
|
||||||
|
res[i] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
void parse_rel(string_view str, offset_list_t& even, offset_list_t& odd)
|
||||||
|
{
|
||||||
|
//sw = 1*s -1*se
|
||||||
|
//nw = -1*se
|
||||||
|
//ne = 1*se - 1*s
|
||||||
|
int s = 0;
|
||||||
|
int se = 0;
|
||||||
|
bool last_was_n = false;
|
||||||
|
while(!str.empty()) {
|
||||||
|
switch(str.front()) {
|
||||||
|
case 'n':
|
||||||
|
--s;
|
||||||
|
last_was_n = true;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
++s;
|
||||||
|
last_was_n = false;
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
++se;
|
||||||
|
if(!last_was_n) {
|
||||||
|
--s;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
--se;
|
||||||
|
if(last_was_n) {
|
||||||
|
++s;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
str.remove_prefix(1);
|
||||||
|
}
|
||||||
|
if((se & 2) == 0) {
|
||||||
|
odd.emplace_back(se, s + se/2);
|
||||||
|
even.emplace_back(se, s + se/2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
odd.emplace_back(se, s + (se - 1)/2);
|
||||||
|
even.emplace_back(se, s + (se + 1)/2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse_rel_sequence(string_view s, offset_list_t& even, offset_list_t& odd)
|
||||||
|
{
|
||||||
|
split_foreach(s, ',', [&](string_view part){
|
||||||
|
trim(part);
|
||||||
|
parse_rel(part, even, odd);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* TODO: move to a template header.
|
||||||
|
* Function that will add to @a result all elements of @a locs, plus all
|
||||||
|
* on-board locations matching @a pred that are connected to elements of
|
||||||
|
* locs by a chain of at most @a radius tiles, each of which matches @a pred.
|
||||||
|
* @a add_result a function that takes a location_range
|
||||||
|
* @pred1 a fast predicate (used before cachecheck).
|
||||||
|
* @pred2 a slow predicate (used after cachecheck).
|
||||||
|
*/
|
||||||
|
using location_range = boost::iterator_range<location_set::const_iterator>;
|
||||||
|
template<typename FPred1, typename FPred2>
|
||||||
|
void get_tiles_radius(location_set&& locs, size_t radius, location_set& result, const FPred1& pred1, const FPred2& pred2)
|
||||||
|
{
|
||||||
|
|
||||||
|
location_set must_visit, filtered_out;
|
||||||
|
location_set not_visited(locs.begin(), locs.end());
|
||||||
|
|
||||||
|
for ( ; radius != 0 && !not_visited.empty(); --radius )
|
||||||
|
{
|
||||||
|
location_set::const_iterator it = not_visited.begin();
|
||||||
|
location_set::const_iterator it_end = not_visited.end();
|
||||||
|
|
||||||
|
result.insert(it, it_end);
|
||||||
|
for(; it != it_end; ++it) {
|
||||||
|
adjacent_loc_array_t adj;
|
||||||
|
get_adjacent_tiles(*it, adj.data());
|
||||||
|
for(size_t i = 0; i < adj.size(); ++i) {
|
||||||
|
const map_location& loc = adj[i];
|
||||||
|
if( pred1(loc) ) {
|
||||||
|
if( !result.count(loc) && !filtered_out.count(loc) ) {
|
||||||
|
if( pred2(loc) ) {
|
||||||
|
must_visit.insert(loc);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
filtered_out.insert(loc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
not_visited.swap(must_visit);
|
||||||
|
must_visit.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
result.insert(not_visited.begin(), not_visited.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} //end namespace
|
||||||
|
|
||||||
|
static int luaW_push_locationset(lua_State* L, const std::set<map_location>& locs)
|
||||||
|
{
|
||||||
|
LOG_LMG << "push_locationset\n";
|
||||||
|
lua_createtable(L, locs.size(), 0);
|
||||||
|
int i = 1;
|
||||||
|
for (const map_location& loc : locs)
|
||||||
|
{
|
||||||
|
lua_createtable(L, 2, 0);
|
||||||
|
lua_pushinteger(L, loc.wml_x());
|
||||||
|
lua_rawseti(L, -2, 1);
|
||||||
|
lua_pushinteger(L, loc.wml_y());
|
||||||
|
lua_rawseti(L, -2, 2);
|
||||||
|
lua_rawseti(L, -2, i);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::set<map_location> luaW_to_locationset(lua_State* L, int index)
|
||||||
|
{
|
||||||
|
std::set<map_location> res;
|
||||||
|
lua_push(L, index);
|
||||||
|
size_t len = lua_rawlen(L, -1);
|
||||||
|
for(size_t i = 0; i != len; ++i) {
|
||||||
|
lua_geti(L, -1, i + 1);
|
||||||
|
res.insert(luaW_checklocation(L, -1));
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
class filter_impl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
filter_impl() {};
|
||||||
|
virtual bool matches(const mapgen_gamemap& m, map_location l) = 0;
|
||||||
|
virtual ~filter_impl() {};
|
||||||
|
};
|
||||||
|
|
||||||
|
//build_filter impl
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
std::unique_ptr<filter_impl> build_filter(lua_State* L, int res_index, knows_sets_t& ks);
|
||||||
|
|
||||||
|
class con_filter : public filter_impl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
con_filter(lua_State* L, int res_index, knows_sets_t& ks)
|
||||||
|
:list_()
|
||||||
|
{
|
||||||
|
LOG_LMG << "creating con filter\n";
|
||||||
|
size_t len = lua_rawlen(L, -1);
|
||||||
|
for(size_t i = 1; i != len; ++i) {
|
||||||
|
lua_geti(L, -1, i + 1);
|
||||||
|
list_.emplace_back(build_filter(L, res_index, ks));
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::vector<std::unique_ptr<filter_impl>> list_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class and_filter : public con_filter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
and_filter(lua_State* L, int res_index, knows_sets_t& ks)
|
||||||
|
: con_filter(L, res_index, ks)
|
||||||
|
{
|
||||||
|
LOG_LMG << "created and filter\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool matches(const mapgen_gamemap& m, map_location l) override
|
||||||
|
{
|
||||||
|
LOG_MATCHES(and);
|
||||||
|
for(const auto& pfilter : list_) {
|
||||||
|
if(!pfilter->matches(m, l)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class or_filter : public con_filter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
or_filter(lua_State* L, int res_index, knows_sets_t& ks)
|
||||||
|
: con_filter(L, res_index, ks)
|
||||||
|
{
|
||||||
|
LOG_LMG << "created or filter\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool matches(const mapgen_gamemap& m, map_location l) override
|
||||||
|
{
|
||||||
|
LOG_MATCHES(or);
|
||||||
|
for(const auto& pfilter : list_) {
|
||||||
|
if(pfilter->matches(m, l)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class nand_filter : public con_filter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
nand_filter(lua_State* L, int res_index, knows_sets_t& ks)
|
||||||
|
: con_filter(L, res_index, ks)
|
||||||
|
{
|
||||||
|
LOG_LMG << "created nand filter\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool matches(const mapgen_gamemap& m, map_location l) override
|
||||||
|
{
|
||||||
|
LOG_MATCHES(nand);
|
||||||
|
for(const auto& pfilter : list_) {
|
||||||
|
if(!pfilter->matches(m, l)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class nor_filter : public con_filter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
nor_filter(lua_State* L, int res_index, knows_sets_t& ks)
|
||||||
|
: con_filter(L, res_index, ks)
|
||||||
|
{
|
||||||
|
LOG_LMG << "created nor filter\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool matches(const mapgen_gamemap& m, map_location l) override
|
||||||
|
{
|
||||||
|
LOG_MATCHES(nor);
|
||||||
|
for(const auto& pfilter : list_) {
|
||||||
|
if(pfilter->matches(m, l)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class cached_filter : public filter_impl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cached_filter(lua_State* L, int res_index, knows_sets_t& ks)
|
||||||
|
: filter_()
|
||||||
|
, cache_()
|
||||||
|
{
|
||||||
|
LOG_LMG << "creating cached filter\n";
|
||||||
|
lua_geti(L, -1, 2);
|
||||||
|
filter_ = build_filter(L, res_index, ks);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool matches(const mapgen_gamemap& m, map_location l) override
|
||||||
|
{
|
||||||
|
LOG_MATCHES(cached);
|
||||||
|
int cache_size = 2 * m.total_width() * m.total_height();
|
||||||
|
int loc_index = 2 * (l.wml_x() + l.wml_y() * m.total_width());
|
||||||
|
|
||||||
|
if(int(cache_.size()) != cache_size) {
|
||||||
|
cache_ = dynamic_bitset(cache_size);
|
||||||
|
}
|
||||||
|
if(cache_[loc_index]) {
|
||||||
|
return cache_[loc_index + 1];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bool res = filter_->matches(m, l);
|
||||||
|
cache_[loc_index] = true;
|
||||||
|
cache_[loc_index + 1] = res;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<filter_impl> filter_;
|
||||||
|
mutable dynamic_bitset cache_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class x_filter : public filter_impl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
x_filter(lua_State* L, int /*res_index*/, knows_sets_t&)
|
||||||
|
: filter_()
|
||||||
|
{
|
||||||
|
LOG_LMG << "creating x filter\n";
|
||||||
|
lua_geti(L, -1, 2);
|
||||||
|
filter_ = parse_range(luaW_tostring(L, -1));
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
bool matches(const mapgen_gamemap&, map_location l) override
|
||||||
|
{
|
||||||
|
LOG_MATCHES(x);
|
||||||
|
return l.x >= 0 && l.x < int(filter_.size()) && filter_[l.x];
|
||||||
|
}
|
||||||
|
dynamic_bitset filter_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class y_filter : public filter_impl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
y_filter(lua_State* L, int /*res_index*/, knows_sets_t&)
|
||||||
|
: filter_()
|
||||||
|
{
|
||||||
|
LOG_LMG << "creating y filter\n";
|
||||||
|
lua_geti(L, -1, 2);
|
||||||
|
filter_ = parse_range(luaW_tostring(L, -1));
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool matches(const mapgen_gamemap&, map_location l) override
|
||||||
|
{
|
||||||
|
LOG_MATCHES(y);
|
||||||
|
return l.y >= 0 && l.y < int(filter_.size()) && filter_[l.y];
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic_bitset filter_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class onborder_filter : public filter_impl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
onborder_filter(lua_State*, int /*res_index*/, knows_sets_t&)
|
||||||
|
{
|
||||||
|
LOG_LMG << "creating onborder filter\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool matches(const mapgen_gamemap& m, map_location l) override
|
||||||
|
{
|
||||||
|
LOG_MATCHES(onborder);
|
||||||
|
return !m.on_map_noborder(l);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class terrain_filter : public filter_impl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
terrain_filter(lua_State* L, int /*res_index*/, knows_sets_t&)
|
||||||
|
: filter_()
|
||||||
|
{
|
||||||
|
LOG_LMG << "creating terrain filter\n";
|
||||||
|
lua_geti(L, -1, 2);
|
||||||
|
//fixme: use string_view
|
||||||
|
filter_ = t_translation::ter_match(luaW_tostring(L, -1));
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool matches(const mapgen_gamemap& m, map_location l) override
|
||||||
|
{
|
||||||
|
LOG_MATCHES(terrain);
|
||||||
|
const t_translation::terrain_code letter = m[l];
|
||||||
|
return t_translation::terrain_matches(letter, filter_);
|
||||||
|
}
|
||||||
|
|
||||||
|
t_translation::ter_match filter_;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const offset_list_t even_offsets_default = {{1 , 0}, {1 , 1}, {0 , 1}, {-1 , 1}, {-1 , 0}, {0, -1}};
|
||||||
|
static const offset_list_t odd_offsets_default = {{1 , -1}, {1 , 0}, {0 , 1}, {-1 , 0}, {-1 , -1}, {0, -1}};
|
||||||
|
|
||||||
|
class adjacent_filter : public filter_impl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
adjacent_filter(lua_State* L, int res_index, knows_sets_t& ks)
|
||||||
|
: filter_()
|
||||||
|
{
|
||||||
|
LOG_LMG << "creating adjacent filter\n";
|
||||||
|
if(luaW_tableget(L, -1, "adjacent")) {
|
||||||
|
parse_rel_sequence(luaW_tostring(L, -1), even_offsets_, odd_offsets_);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
even_offsets_ = even_offsets_default;
|
||||||
|
odd_offsets_ = odd_offsets_default;
|
||||||
|
}
|
||||||
|
if(luaW_tableget(L, -1, "count")) {
|
||||||
|
accepted_counts_ = parse_range(luaW_tostring(L, -1));
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
lua_geti(L, -1, 2);
|
||||||
|
filter_ = build_filter(L, res_index, ks);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool matches(const mapgen_gamemap& m, map_location l) override
|
||||||
|
{
|
||||||
|
LOG_MATCHES(adjacent);
|
||||||
|
int count = 0;
|
||||||
|
// is_odd == is_even in wml coordinates.
|
||||||
|
offset_list_t& offsets = (l.wml_x() & 1) ? odd_offsets_ : even_offsets_;
|
||||||
|
for(const auto& offset : offsets) {
|
||||||
|
map_location ad = {l.x + offset.first, l.y + offset.second};
|
||||||
|
if(m.on_map(ad) && filter_->matches(m, ad)) {
|
||||||
|
if(accepted_counts_.size() == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return int(accepted_counts_.size()) > count && accepted_counts_[count];
|
||||||
|
}
|
||||||
|
offset_list_t even_offsets_;
|
||||||
|
offset_list_t odd_offsets_;
|
||||||
|
dynamic_bitset accepted_counts_;
|
||||||
|
std::unique_ptr<filter_impl> filter_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class findin_filter : public filter_impl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
findin_filter(lua_State* L, int res_index, knows_sets_t& ks)
|
||||||
|
: set_(nullptr)
|
||||||
|
{
|
||||||
|
LOG_LMG << "creating findin filter\n";
|
||||||
|
lua_geti(L, -1, 2);
|
||||||
|
std::string id = std::string(luaW_tostring(L, -1));
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
//TODO: c++14: use heterogenous lookup.
|
||||||
|
auto insert_res = ks.insert(knows_sets_t::value_type{id, {}});
|
||||||
|
if(insert_res.second && res_index > 0) {
|
||||||
|
// istable(L, res_index) was already checked.
|
||||||
|
if(luaW_tableget(L, res_index, id.c_str())) {
|
||||||
|
insert_res.first->second = luaW_to_locationset(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set_ = &insert_res.first->second;
|
||||||
|
}
|
||||||
|
bool matches(const mapgen_gamemap&, map_location l) override
|
||||||
|
{
|
||||||
|
LOG_MATCHES(findin);
|
||||||
|
if(set_) {
|
||||||
|
return set_->find(l) != set_->end();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const location_set* set_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class radius_filter : public filter_impl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
radius_filter(lua_State* L, int res_index, knows_sets_t& ks)
|
||||||
|
: radius_()
|
||||||
|
, filter_radius_()
|
||||||
|
, filter_()
|
||||||
|
{
|
||||||
|
LOG_LMG << "creating radius filter\n";
|
||||||
|
if(luaW_tableget(L, -1, "filter_radius")) {
|
||||||
|
filter_radius_ = build_filter(L, res_index, ks);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
lua_geti(L, -1, 2);
|
||||||
|
radius_ = lua_tonumber(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
lua_geti(L, -1, 3);
|
||||||
|
filter_ = build_filter(L, res_index, ks);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool matches(const mapgen_gamemap& m, map_location l) override
|
||||||
|
{
|
||||||
|
LOG_MATCHES(radius);
|
||||||
|
std::set<map_location> result;
|
||||||
|
|
||||||
|
get_tiles_radius({{ l }}, radius_, result,
|
||||||
|
[&](const map_location& l) {
|
||||||
|
return m.on_map(l);
|
||||||
|
},
|
||||||
|
[&](const map_location& l) {
|
||||||
|
return !filter_radius_ || filter_radius_->matches(m, l);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
for (map_location lr : result) {
|
||||||
|
if(!filter_ || filter_->matches(m, lr)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int radius_;
|
||||||
|
std::unique_ptr<filter_impl> filter_radius_;
|
||||||
|
std::unique_ptr<filter_impl> filter_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// todo: maybe invent a gerneral macro for this string_switch implementation.
|
||||||
|
enum filter_keys { F_AND, F_OR, F_NAND, F_NOR, F_X, F_Y, F_FIND_IN, F_ADJACENT, F_TERRAIN, F_RADUIS, F_CACHED };
|
||||||
|
//todoc++14: std::unordered_map doesn'tsupport herterogrnous lookup.
|
||||||
|
//todo consider renaming and -> all ,or ->any, nor -> none, nand -> notall
|
||||||
|
static const std::unordered_map<std::string, filter_keys> keys {
|
||||||
|
{ "and", F_AND },
|
||||||
|
{ "or", F_OR },
|
||||||
|
{ "nand", F_NAND },
|
||||||
|
{ "or", F_NOR },
|
||||||
|
{ "x", F_X },
|
||||||
|
{ "y", F_Y },
|
||||||
|
{ "find_in", F_FIND_IN },
|
||||||
|
{ "adjacent", F_ADJACENT },
|
||||||
|
{ "terrain", F_TERRAIN },
|
||||||
|
{ "cached", F_CACHED },
|
||||||
|
{ "radius", F_RADUIS }
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<filter_impl> build_filter(lua_State* L, int res_index, knows_sets_t& ks)
|
||||||
|
{
|
||||||
|
LOG_LMG << "buildfilter: start\n";
|
||||||
|
if(!lua_istable(L, -1)) {
|
||||||
|
throw inalid_lua_argument("buildfilter: expected table");
|
||||||
|
}
|
||||||
|
lua_rawgeti(L, -1, 1);
|
||||||
|
std::string s = std::string(luaW_tostring(L, -1));
|
||||||
|
LOG_LMG << "buildfilter: got: " << s << "\n";
|
||||||
|
auto it = keys.find(s);
|
||||||
|
if(it == keys.end()) {
|
||||||
|
//fixme use proper exception type.
|
||||||
|
throw inalid_lua_argument(std::string("buildfilter: invalid filter type ") + s);
|
||||||
|
}
|
||||||
|
auto key = it->second;
|
||||||
|
lua_pop(L, 1);
|
||||||
|
switch(key)
|
||||||
|
{
|
||||||
|
case F_AND:
|
||||||
|
return utils::make_unique<and_filter>(L, res_index, ks);
|
||||||
|
case F_OR:
|
||||||
|
return utils::make_unique<or_filter>(L, res_index, ks);
|
||||||
|
case F_NAND:
|
||||||
|
return utils::make_unique<nand_filter>(L, res_index, ks);
|
||||||
|
case F_NOR:
|
||||||
|
return utils::make_unique<nor_filter>(L, res_index, ks);
|
||||||
|
case F_X:
|
||||||
|
return utils::make_unique<x_filter>(L, res_index, ks);
|
||||||
|
case F_Y:
|
||||||
|
return utils::make_unique<y_filter>(L, res_index, ks);
|
||||||
|
case F_FIND_IN:
|
||||||
|
return utils::make_unique<findin_filter>(L, res_index, ks);
|
||||||
|
case F_ADJACENT:
|
||||||
|
return utils::make_unique<adjacent_filter>(L, res_index, ks);
|
||||||
|
case F_TERRAIN:
|
||||||
|
return utils::make_unique<terrain_filter>(L, res_index, ks);
|
||||||
|
case F_RADUIS:
|
||||||
|
return utils::make_unique<radius_filter>(L, res_index, ks);
|
||||||
|
case F_CACHED:
|
||||||
|
return utils::make_unique<cached_filter>(L, res_index, ks);
|
||||||
|
default:
|
||||||
|
throw "invalid filter key enum";
|
||||||
|
}
|
||||||
|
throw "the compilter says control reaches end of non-void function";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////// PUBLIC API ////////////////
|
||||||
|
|
||||||
|
namespace lua_mapgen {
|
||||||
|
/// @a data_index a index to the lua stack pointing to the lua table that describes the filter.
|
||||||
|
/// @a res_index a _positive_ index to the lua stack pointing to the lua table that describes the filter resources.
|
||||||
|
filter::filter(lua_State* L, int data_index, int res_index)
|
||||||
|
{
|
||||||
|
LOG_LMG << "creating filter object\n";
|
||||||
|
lua_pushvalue (L, data_index);
|
||||||
|
impl_ = build_filter(L, res_index, known_sets_);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
LOG_LMG << "finished creating filter object\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool filter::matches(const mapgen_gamemap& m, map_location l)
|
||||||
|
{
|
||||||
|
log_scope("filter::matches");
|
||||||
|
return impl_->matches(m, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
filter::~filter()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int intf_mg_get_locations_part2(lua_State* L, mapgen_gamemap& m, lua_mapgen::filter& f)
|
||||||
|
{
|
||||||
|
location_set res;
|
||||||
|
LOG_LMG << "map:get_locations vaidargs\n";
|
||||||
|
if(lua_istable(L, 3)) {
|
||||||
|
LOG_LMG << "map:get_locations some locations\n";
|
||||||
|
location_set s = luaW_to_locationset(L, 3);
|
||||||
|
LOG_LMG << "map:get_locations #args = " << s.size() << "\n";
|
||||||
|
for (const map_location& l : s) {
|
||||||
|
if(f.matches(m, l)) {
|
||||||
|
res.insert(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG_LMG << "map:get_locations all locations\n";
|
||||||
|
m.for_each_loc([&](map_location l) {
|
||||||
|
if(f.matches(m, l)) {
|
||||||
|
res.insert(l);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
LOG_LMG << "map:get_locations #res = " << res.size() << "\n";
|
||||||
|
luaW_push_locationset(L, res);
|
||||||
|
LOG_LMG << "map:get_locations end\n";
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
int intf_mg_get_locations(lua_State* L)
|
||||||
|
{
|
||||||
|
//todo: create filter form table if needed
|
||||||
|
LOG_LMG << "map:get_locations\n";
|
||||||
|
mapgen_gamemap& m = luaW_checkterrainmap(L, 1);
|
||||||
|
if(luaW_is_mgfilter(L, 2)) {
|
||||||
|
lua_mapgen::filter& f = luaW_check_mgfilter(L, 2);
|
||||||
|
return intf_mg_get_locations_part2(L, m, f);
|
||||||
|
}
|
||||||
|
else if (lua_istable(L, 2)) {
|
||||||
|
lua_mapgen::filter f(L, 2, 0);
|
||||||
|
return intf_mg_get_locations_part2(L, m, f);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return luaW_type_error(L, 2, "terrainfilter");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int intf_mg_get_tiles_radius(lua_State* L)
|
||||||
|
{
|
||||||
|
mapgen_gamemap& m = luaW_checkterrainmap(L, 1);
|
||||||
|
lua_mapgen::filter& f = luaW_check_mgfilter(L, 3);
|
||||||
|
location_set s = luaW_to_locationset(L, 2);
|
||||||
|
location_set res;
|
||||||
|
int r = luaL_checkinteger(L, 4);
|
||||||
|
get_tiles_radius(std::move(s), r, res,
|
||||||
|
[&](const map_location& l) {
|
||||||
|
return m.on_map(l);
|
||||||
|
},
|
||||||
|
[&](const map_location& l) {
|
||||||
|
return f.matches(m, l);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
luaW_push_locationset(L, res);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool luaW_is_mgfilter(lua_State* L, int index)
|
||||||
|
{
|
||||||
|
return luaL_testudata(L, index, terrinfilterKey) != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
lua_mapgen::filter* luaW_to_mgfilter(lua_State *L, int index)
|
||||||
|
{
|
||||||
|
if(luaW_is_mgfilter(L, index)) {
|
||||||
|
return static_cast<lua_mapgen::filter*>(lua_touserdata(L, index));
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_mapgen::filter& luaW_check_mgfilter(lua_State *L, int index)
|
||||||
|
{
|
||||||
|
if(luaW_is_mgfilter(L, index)) {
|
||||||
|
return *static_cast<lua_mapgen::filter*>(lua_touserdata(L, index));
|
||||||
|
}
|
||||||
|
luaW_type_error(L, index, "terrainfilter");
|
||||||
|
throw "luaW_type_error didn't throw";
|
||||||
|
}
|
||||||
|
|
||||||
|
void lua_mgfilter_setmetatable(lua_State *L)
|
||||||
|
{
|
||||||
|
luaL_setmetatable(L, terrinfilterKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... T>
|
||||||
|
static lua_mapgen::filter* luaW_push_mgfilter(lua_State *L, T&&... params)
|
||||||
|
{
|
||||||
|
LOG_LMG << "luaW_push_mgfilter\n";
|
||||||
|
lua_mapgen::filter* res = new(L) lua_mapgen::filter(std::forward<T>(params)...);
|
||||||
|
lua_mgfilter_setmetatable(L);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a filter.
|
||||||
|
*/
|
||||||
|
int intf_terainfilter_create(lua_State *L)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
int res_index = 0;
|
||||||
|
if(!lua_istable(L, 1)) {
|
||||||
|
return luaL_argerror(L, 1, "table expected");
|
||||||
|
}
|
||||||
|
if(lua_istable(L, 2)) {
|
||||||
|
res_index = 2;
|
||||||
|
}
|
||||||
|
lua_mapgen::filter res(L, 1, res_index);
|
||||||
|
luaW_push_mgfilter(L, std::move(res));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
catch(const inalid_lua_argument& e) {
|
||||||
|
return luaL_argerror(L, 1, e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets some data on a filter (__index metamethod).
|
||||||
|
* - Arg 1: full userdata containing the filter.
|
||||||
|
* - Arg 2: string containing the name of the property.
|
||||||
|
* - Ret 1: something containing the attribute.
|
||||||
|
*/
|
||||||
|
static int impl_terainfilter_get(lua_State *L)
|
||||||
|
{
|
||||||
|
lua_mapgen::filter& f = luaW_check_mgfilter(L, 1);
|
||||||
|
UNUSED(f);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets some data on a filter (__newindex metamethod).
|
||||||
|
* - Arg 1: full userdata containing the filter.
|
||||||
|
* - Arg 2: string containing the name of the property.
|
||||||
|
* - Arg 3: something containing the attribute.
|
||||||
|
*/
|
||||||
|
static int impl_terainfilter_set(lua_State *L)
|
||||||
|
{
|
||||||
|
lua_mapgen::filter& f = luaW_check_mgfilter(L, 1);
|
||||||
|
UNUSED(f);
|
||||||
|
char const *m = luaL_checkstring(L, 2);
|
||||||
|
std::string err_msg = "unknown modifiable property of map: ";
|
||||||
|
err_msg += m;
|
||||||
|
return luaL_argerror(L, 2, err_msg.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the cache of a filter.
|
||||||
|
*/
|
||||||
|
static int intf_clearcache(lua_State *L)
|
||||||
|
{
|
||||||
|
lua_mapgen::filter& f = luaW_check_mgfilter(L, 1);
|
||||||
|
UNUSED(f);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Destroys a map object before it is collected (__gc metamethod).
|
||||||
|
*/
|
||||||
|
static int impl_terainfilter_collect(lua_State *L)
|
||||||
|
{
|
||||||
|
lua_mapgen::filter& f = luaW_check_mgfilter(L, 1);
|
||||||
|
f.~filter();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace lua_terrainfilter {
|
||||||
|
std::string register_metatables(lua_State* L)
|
||||||
|
{
|
||||||
|
std::ostringstream cmd_out;
|
||||||
|
|
||||||
|
cmd_out << "Adding terrainmamap metatable...\n";
|
||||||
|
|
||||||
|
luaL_newmetatable(L, terrinfilterKey);
|
||||||
|
lua_pushcfunction(L, impl_terainfilter_collect);
|
||||||
|
lua_setfield(L, -2, "__gc");
|
||||||
|
lua_pushcfunction(L, impl_terainfilter_get);
|
||||||
|
lua_setfield(L, -2, "__index");
|
||||||
|
lua_pushcfunction(L, impl_terainfilter_set);
|
||||||
|
lua_setfield(L, -2, "__newindex");
|
||||||
|
lua_pushstring(L, "terrain_filter");
|
||||||
|
lua_setfield(L, -2, "__metatable");
|
||||||
|
// terainmap methods
|
||||||
|
lua_pushcfunction(L, intf_clearcache);
|
||||||
|
lua_setfield(L, -2, "clear_cache");
|
||||||
|
|
||||||
|
return cmd_out.str();
|
||||||
|
}
|
||||||
|
}
|
71
src/scripting/lua_terrainfilter.hpp
Normal file
71
src/scripting/lua_terrainfilter.hpp
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2018 the Battle for Wesnoth Project https://www.wesnoth.org/
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY.
|
||||||
|
|
||||||
|
See the COPYING file for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include "scripting/lua_common.hpp"
|
||||||
|
struct lua_State;
|
||||||
|
struct map_location;
|
||||||
|
class mapgen_gamemap;
|
||||||
|
class filter_impl;
|
||||||
|
namespace lua_mapgen
|
||||||
|
{
|
||||||
|
class filter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// @a a lua table with the folllowing attributes
|
||||||
|
/// [1]: the filter table,
|
||||||
|
/// [2]: attributeslocation_sets
|
||||||
|
explicit filter(lua_State* L, int data_index, int res_index = 0);
|
||||||
|
|
||||||
|
//impl_ may contain pointers to known_sets_, copycontructing this will result in segfaults.
|
||||||
|
filter(const filter&) = delete;
|
||||||
|
filter& operator=(const filter&) = delete;
|
||||||
|
//moving is ok though.
|
||||||
|
filter(filter&&) = default;
|
||||||
|
filter& operator=(filter&&) = default;
|
||||||
|
|
||||||
|
~filter();
|
||||||
|
|
||||||
|
bool matches(const mapgen_gamemap& m, map_location l);
|
||||||
|
//todo: add a clear cache function.
|
||||||
|
private:
|
||||||
|
std::map<std::string, std::set<map_location>> known_sets_;
|
||||||
|
std::unique_ptr<filter_impl> impl_;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string register_filter_metatables(lua_State *L);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool luaW_is_mgfilter(lua_State* L, int index);
|
||||||
|
|
||||||
|
lua_mapgen::filter* luaW_to_mgfilter(lua_State *L, int index);
|
||||||
|
|
||||||
|
lua_mapgen::filter& luaW_check_mgfilter(lua_State *L, int index);
|
||||||
|
|
||||||
|
void lua_mgfilter_setmetatable(lua_State *L);
|
||||||
|
|
||||||
|
int intf_terainfilter_create(lua_State *L);
|
||||||
|
|
||||||
|
int intf_mg_get_locations(lua_State* L);
|
||||||
|
int intf_mg_get_tiles_radius(lua_State* L);
|
||||||
|
|
||||||
|
namespace lua_terrainfilter {
|
||||||
|
std::string register_metatables(lua_State *L);
|
||||||
|
}
|
382
src/scripting/lua_terrainmap.cpp
Normal file
382
src/scripting/lua_terrainmap.cpp
Normal file
|
@ -0,0 +1,382 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2018 the Battle for Wesnoth Project https://www.wesnoth.org/
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY.
|
||||||
|
|
||||||
|
See the COPYING file for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "scripting/lua_terrainmap.hpp"
|
||||||
|
#include "scripting/lua_terrainfilter.hpp"
|
||||||
|
|
||||||
|
#include "formatter.hpp"
|
||||||
|
#include "log.hpp"
|
||||||
|
#include "map/location.hpp"
|
||||||
|
#include "map/map.hpp"
|
||||||
|
#include "scripting/lua_common.hpp"
|
||||||
|
#include "scripting/push_check.hpp"
|
||||||
|
#include "scripting/game_lua_kernel.hpp"
|
||||||
|
|
||||||
|
#include "lua/lauxlib.h"
|
||||||
|
#include "lua/lua.h"
|
||||||
|
|
||||||
|
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 terrinmapKey[] = "terrainmap";
|
||||||
|
static const char maplocationKey[] = "special_locations";
|
||||||
|
|
||||||
|
using utils::string_view;
|
||||||
|
|
||||||
|
//////// SPECIAL LOCATION ////////
|
||||||
|
|
||||||
|
bool luaW_isslocs(lua_State* L, int index)
|
||||||
|
{
|
||||||
|
return luaL_testudata(L, index, maplocationKey) != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
mapgen_gamemap* luaW_toslocs(lua_State *L, int index)
|
||||||
|
{
|
||||||
|
if(luaW_isterrainmap(L, index)) {
|
||||||
|
lua_rawgeti(L, index, 1);
|
||||||
|
mapgen_gamemap* m = luaW_toterrainmap(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
mapgen_gamemap& luaW_check_slocs(lua_State *L, int index)
|
||||||
|
{
|
||||||
|
if(mapgen_gamemap* m = luaW_toslocs(L, index)) {
|
||||||
|
return *m;
|
||||||
|
}
|
||||||
|
luaW_type_error(L, index, "terrainmap");
|
||||||
|
throw "luaW_type_error didn't thow.";
|
||||||
|
}
|
||||||
|
|
||||||
|
void lua_slocs_setmetatable(lua_State *L)
|
||||||
|
{
|
||||||
|
luaL_setmetatable(L, maplocationKey);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @a index the index of the map object.
|
||||||
|
*/
|
||||||
|
void luaW_pushslocs(lua_State *L, int index)
|
||||||
|
{
|
||||||
|
lua_pushvalue(L, index);
|
||||||
|
//stack: map
|
||||||
|
lua_createtable(L, 1, 0);
|
||||||
|
//stack: map, slocs
|
||||||
|
lua_pushvalue(L, -2);
|
||||||
|
//stack: map, slocs, map
|
||||||
|
lua_rawseti(L, -2, 1);
|
||||||
|
//stack: map, slocs
|
||||||
|
luaL_setmetatable(L, maplocationKey);
|
||||||
|
//stack: map, slocs
|
||||||
|
lua_remove(L, -2);
|
||||||
|
//stack: slocs
|
||||||
|
}
|
||||||
|
|
||||||
|
int impl_slocs_get(lua_State* L)
|
||||||
|
{
|
||||||
|
mapgen_gamemap& m = luaW_check_slocs(L, 1);
|
||||||
|
string_view id = luaL_checkstring(L, 2);
|
||||||
|
auto res = m.special_location(std::string(id));
|
||||||
|
if(res.wml_x() >= 0) {
|
||||||
|
luaW_pushlocation(L, res);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//functions with variable return numbers have been causing problem in the past
|
||||||
|
lua_pushnil(L);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int impl_slocs_set(lua_State* L)
|
||||||
|
{
|
||||||
|
mapgen_gamemap& m = luaW_check_slocs(L, 1);
|
||||||
|
string_view id = luaL_checkstring(L, 2);
|
||||||
|
map_location loc = luaW_checklocation(L, 3);
|
||||||
|
|
||||||
|
m.set_special_location(std::string(id), loc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////// MAP ////////
|
||||||
|
|
||||||
|
mapgen_gamemap::mapgen_gamemap(string_view s)
|
||||||
|
: tiles_()
|
||||||
|
, starting_positions_()
|
||||||
|
{
|
||||||
|
if(s.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//throws t_translation::error
|
||||||
|
//todo: make read_game_map take a string_view
|
||||||
|
tiles_ = t_translation::read_game_map(s, starting_positions_, t_translation::coordinate{ 1, 1 });
|
||||||
|
}
|
||||||
|
|
||||||
|
mapgen_gamemap::mapgen_gamemap(int w, int h, terrain_code t)
|
||||||
|
: tiles_(w, h, t)
|
||||||
|
, starting_positions_()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string mapgen_gamemap::to_string() const
|
||||||
|
{
|
||||||
|
return t_translation::write_game_map(tiles_, starting_positions_, { 1, 1 }) + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void mapgen_gamemap::set_terrain(const map_location& loc, const terrain_code & terrain, const terrain_type_data::merge_mode mode)
|
||||||
|
{
|
||||||
|
terrain_code& t = (*this)[loc];
|
||||||
|
terrain_code old = t;
|
||||||
|
t = terrain;
|
||||||
|
simplemerge(old, t, mode);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void mapgen_gamemap::simplemerge(terrain_code old_t, terrain_code& new_t, const terrain_type_data::merge_mode mode)
|
||||||
|
{
|
||||||
|
if(mode == terrain_type_data::OVERLAY) {
|
||||||
|
new_t = t_translation::terrain_code(old_t.base, new_t.overlay);
|
||||||
|
}
|
||||||
|
if(mode == terrain_type_data::BASE) {
|
||||||
|
new_t = t_translation::terrain_code(new_t.base, old_t.overlay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mapgen_gamemap::set_special_location(const std::string& id, const map_location& loc)
|
||||||
|
{
|
||||||
|
bool valid = loc.valid();
|
||||||
|
auto it_left = starting_positions_.left.find(id);
|
||||||
|
if (it_left != starting_positions_.left.end()) {
|
||||||
|
if (valid) {
|
||||||
|
starting_positions_.left.replace_data(it_left, loc);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
starting_positions_.left.erase(it_left);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
starting_positions_.left.insert(it_left, std::make_pair(id, loc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
map_location mapgen_gamemap::special_location(const std::string& id) const
|
||||||
|
{
|
||||||
|
auto it = starting_positions_.left.find(id);
|
||||||
|
if (it != starting_positions_.left.end()) {
|
||||||
|
auto& coordinate = it->second;
|
||||||
|
return map_location(coordinate.x, coordinate.y);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return map_location();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool luaW_isterrainmap(lua_State* L, int index)
|
||||||
|
{
|
||||||
|
return luaL_testudata(L, index, terrinmapKey) != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
mapgen_gamemap* luaW_toterrainmap(lua_State *L, int index)
|
||||||
|
{
|
||||||
|
if(luaW_isterrainmap(L, index)) {
|
||||||
|
return static_cast<mapgen_gamemap*>(lua_touserdata(L, index));
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
mapgen_gamemap& luaW_checkterrainmap(lua_State *L, int index)
|
||||||
|
{
|
||||||
|
if(luaW_isterrainmap(L, index)) {
|
||||||
|
return *static_cast<mapgen_gamemap*>(lua_touserdata(L, index));
|
||||||
|
}
|
||||||
|
luaW_type_error(L, index, "terrainmap");
|
||||||
|
throw "luaW_type_error didn't throw";
|
||||||
|
}
|
||||||
|
|
||||||
|
void lua_terrainmap_setmetatable(lua_State *L)
|
||||||
|
{
|
||||||
|
luaL_setmetatable(L, terrinmapKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... T>
|
||||||
|
mapgen_gamemap* luaW_pushmap(lua_State *L, T&&... params)
|
||||||
|
{
|
||||||
|
mapgen_gamemap* res = new(L) mapgen_gamemap(std::forward<T>(params)...);
|
||||||
|
lua_terrainmap_setmetatable(L);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a map.
|
||||||
|
* - Arg 1: string descripbing the map data.
|
||||||
|
* - or:
|
||||||
|
* - Arg 1: int, width
|
||||||
|
* - Arg 2: int, height
|
||||||
|
* - Arg 3: string, terrain
|
||||||
|
*/
|
||||||
|
int intf_terainmap_create(lua_State *L)
|
||||||
|
{
|
||||||
|
if(lua_isnumber(L, 1) && lua_isnumber(L, 2)) {
|
||||||
|
int w = lua_tonumber(L, 1);
|
||||||
|
int h = lua_tonumber(L, 2);
|
||||||
|
auto terrain = t_translation::read_terrain_code(luaL_checkstring(L, 3));
|
||||||
|
luaW_pushmap(L, w, h, terrain);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
string_view data_str = luaL_checkstring(L, 1);
|
||||||
|
luaW_pushmap(L, data_str);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys a map object before it is collected (__gc metamethod).
|
||||||
|
*/
|
||||||
|
static int impl_terainmap_collect(lua_State *L)
|
||||||
|
{
|
||||||
|
mapgen_gamemap *u = static_cast<mapgen_gamemap*>(lua_touserdata(L, 1));
|
||||||
|
u->mapgen_gamemap::~mapgen_gamemap();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets some data on a map (__index metamethod).
|
||||||
|
* - Arg 1: full userdata containing the map.
|
||||||
|
* - Arg 2: string containing the name of the property.
|
||||||
|
* - Ret 1: something containing the attribute.
|
||||||
|
*/
|
||||||
|
static int impl_terainmap_get(lua_State *L)
|
||||||
|
{
|
||||||
|
mapgen_gamemap& tm = luaW_checkterrainmap(L, 1);
|
||||||
|
char const *m = luaL_checkstring(L, 2);
|
||||||
|
|
||||||
|
// Find the corresponding attribute.
|
||||||
|
return_int_attrib("width", tm.total_width());
|
||||||
|
return_int_attrib("height", tm.total_height());
|
||||||
|
return_string_attrib("data", tm.to_string());
|
||||||
|
|
||||||
|
if(strcmp(m, "special_locations") == 0) {
|
||||||
|
luaW_pushslocs(L, 1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(luaW_getmetafield(L, 1, m)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets some data on a map (__newindex metamethod).
|
||||||
|
* - Arg 1: full userdata containing the map.
|
||||||
|
* - Arg 2: string containing the name of the property.
|
||||||
|
* - Arg 3: something containing the attribute.
|
||||||
|
*/
|
||||||
|
static int impl_terainmap_set(lua_State *L)
|
||||||
|
{
|
||||||
|
mapgen_gamemap& tm = luaW_checkterrainmap(L, 1);
|
||||||
|
UNUSED(tm);
|
||||||
|
char const *m = luaL_checkstring(L, 2);
|
||||||
|
std::string err_msg = "unknown modifiable property of map: ";
|
||||||
|
err_msg += m;
|
||||||
|
return luaL_argerror(L, 2, err_msg.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a terrain code.
|
||||||
|
* - Arg 1: map location.
|
||||||
|
* - Arg 2: terrain code string.
|
||||||
|
* - Arg 3: layer: (overlay|base|both, default=both)
|
||||||
|
*/
|
||||||
|
static int intf_set_terrain(lua_State *L)
|
||||||
|
{
|
||||||
|
mapgen_gamemap& tm = luaW_checkterrainmap(L, 1);
|
||||||
|
map_location loc = luaW_checklocation(L, 2);
|
||||||
|
string_view t_str = luaL_checkstring(L, 3);
|
||||||
|
|
||||||
|
auto terrain = t_translation::read_terrain_code(t_str);
|
||||||
|
auto mode = terrain_type_data::BOTH;
|
||||||
|
|
||||||
|
if(!lua_isnoneornil(L, 4)) {
|
||||||
|
string_view mode_str = luaL_checkstring(L, 4);
|
||||||
|
if(mode_str == "base") {
|
||||||
|
mode = terrain_type_data::BASE;
|
||||||
|
}
|
||||||
|
else if(mode_str == "overlay") {
|
||||||
|
mode = terrain_type_data::OVERLAY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tm.set_terrain(loc, terrain, mode);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a terrain code.
|
||||||
|
* - Arg 1: map location.
|
||||||
|
* - Ret 1: string.
|
||||||
|
*/
|
||||||
|
static int intf_get_terrain(lua_State *L)
|
||||||
|
{
|
||||||
|
mapgen_gamemap& tm = luaW_checkterrainmap(L, 1);
|
||||||
|
map_location loc = luaW_checklocation(L, 2);
|
||||||
|
|
||||||
|
auto t = tm[loc];
|
||||||
|
lua_pushstring(L, t_translation::write_terrain_code(t).c_str());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace lua_terrainmap {
|
||||||
|
std::string register_metatables(lua_State* L)
|
||||||
|
{
|
||||||
|
std::ostringstream cmd_out;
|
||||||
|
|
||||||
|
cmd_out << "Adding terrainmamap metatable...\n";
|
||||||
|
|
||||||
|
luaL_newmetatable(L, terrinmapKey);
|
||||||
|
lua_pushcfunction(L, impl_terainmap_collect);
|
||||||
|
lua_setfield(L, -2, "__gc");
|
||||||
|
lua_pushcfunction(L, impl_terainmap_get);
|
||||||
|
lua_setfield(L, -2, "__index");
|
||||||
|
lua_pushcfunction(L, impl_terainmap_set);
|
||||||
|
lua_setfield(L, -2, "__newindex");
|
||||||
|
lua_pushstring(L, "terainmap");
|
||||||
|
lua_setfield(L, -2, "__metatable");
|
||||||
|
// terainmap methods
|
||||||
|
lua_pushcfunction(L, intf_set_terrain);
|
||||||
|
lua_setfield(L, -2, "set_terrain");
|
||||||
|
lua_pushcfunction(L, intf_get_terrain);
|
||||||
|
lua_setfield(L, -2, "get_terrain");
|
||||||
|
lua_pushcfunction(L, intf_mg_get_locations);
|
||||||
|
lua_setfield(L, -2, "get_locations");
|
||||||
|
lua_pushcfunction(L, intf_mg_get_tiles_radius);
|
||||||
|
lua_setfield(L, -2, "get_tiles_radius");
|
||||||
|
|
||||||
|
cmd_out << "Adding terrainmamap2 metatable...\n";
|
||||||
|
|
||||||
|
luaL_newmetatable(L, maplocationKey);
|
||||||
|
lua_pushcfunction(L, impl_slocs_get);
|
||||||
|
lua_setfield(L, -2, "__index");
|
||||||
|
lua_pushcfunction(L, impl_slocs_set);
|
||||||
|
lua_setfield(L, -2, "__newindex");
|
||||||
|
lua_pushstring(L, "special_locations");
|
||||||
|
lua_setfield(L, -2, "__metatable");
|
||||||
|
|
||||||
|
return cmd_out.str();
|
||||||
|
}
|
||||||
|
}
|
111
src/scripting/lua_terrainmap.hpp
Normal file
111
src/scripting/lua_terrainmap.hpp
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2018 the Battle for Wesnoth Project https://www.wesnoth.org/
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY.
|
||||||
|
|
||||||
|
See the COPYING file for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <string>
|
||||||
|
#include "scripting/lua_common.hpp"
|
||||||
|
#include "map/location.hpp"
|
||||||
|
#include "terrain/translation.hpp"
|
||||||
|
#include "terrain/type_data.hpp"
|
||||||
|
|
||||||
|
struct lua_State;
|
||||||
|
class lua_unit;
|
||||||
|
struct map_location;
|
||||||
|
|
||||||
|
// this clas is similar to the orginal gamemap class but they have no 'is' rlation:
|
||||||
|
// mapgen_gamemap, unlike gamemap offers 'raw' access to the data
|
||||||
|
// gamemap, unlike mapgen_gamemap uses terain type data.
|
||||||
|
class mapgen_gamemap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using terrain_code = t_translation::terrain_code;
|
||||||
|
using terrain_map = t_translation::ter_map;
|
||||||
|
using starting_positions = t_translation::starting_positions;
|
||||||
|
explicit mapgen_gamemap(utils::string_view data);
|
||||||
|
mapgen_gamemap(int w, int h, terrain_code);
|
||||||
|
|
||||||
|
std::string to_string() const;
|
||||||
|
|
||||||
|
/** Effective map width. */
|
||||||
|
int w() const { return total_width() - 2; }
|
||||||
|
|
||||||
|
/** Effective map height. */
|
||||||
|
int h() const { return total_height() - 2; }
|
||||||
|
|
||||||
|
/** Real width of the map, including borders. */
|
||||||
|
int total_width() const { return tiles_.w; }
|
||||||
|
|
||||||
|
/** Real height of the map, including borders */
|
||||||
|
int total_height() const { return tiles_.h; }
|
||||||
|
|
||||||
|
bool on_map(const map_location& loc) const
|
||||||
|
{
|
||||||
|
return loc.wml_x() >= 0 && loc.wml_x() < total_width() && loc.wml_y() >= 0 && loc.wml_y() < total_height();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool on_map_noborder(const map_location& loc) const
|
||||||
|
{
|
||||||
|
return loc.wml_x() > 0 && loc.wml_x() < total_width() - 1 && loc.wml_y() > 0 && loc.wml_y() < total_height() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
terrain_code& operator[](const map_location& loc)
|
||||||
|
{
|
||||||
|
return tiles_.get(loc.wml_x(), loc.wml_y());
|
||||||
|
}
|
||||||
|
|
||||||
|
const terrain_code& operator[](const map_location& loc) const
|
||||||
|
{
|
||||||
|
return tiles_.get(loc.wml_x(), loc.wml_y());
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_terrain(const map_location& loc, const terrain_code & terrain, const terrain_type_data::merge_mode mode);
|
||||||
|
static void simplemerge(terrain_code old, terrain_code& t, const terrain_type_data::merge_mode mode);
|
||||||
|
|
||||||
|
starting_positions& special_locations() { return starting_positions_; }
|
||||||
|
const starting_positions& special_locations() const { return starting_positions_; }
|
||||||
|
|
||||||
|
void set_special_location(const std::string& id, const map_location& loc);
|
||||||
|
map_location special_location(const std::string& id) const;
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
void for_each_loc(const F& f) const
|
||||||
|
{
|
||||||
|
for (int x = 0; x < total_width(); ++x) {
|
||||||
|
for (int y = 0; y < total_height(); ++y) {
|
||||||
|
f({ x, y , wml_loc()});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
t_translation::ter_map tiles_;
|
||||||
|
starting_positions starting_positions_;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool luaW_isterrainmap(lua_State* L, int index);
|
||||||
|
|
||||||
|
mapgen_gamemap* luaW_toterrainmap(lua_State *L, int index);
|
||||||
|
|
||||||
|
mapgen_gamemap& luaW_checkterrainmap(lua_State *L, int index);
|
||||||
|
|
||||||
|
void lua_terrainmap_setmetatable(lua_State *L);
|
||||||
|
|
||||||
|
mapgen_gamemap* luaW_pushmap(lua_State *L, mapgen_gamemap&& u);
|
||||||
|
|
||||||
|
int intf_terainmap_create(lua_State *L);
|
||||||
|
|
||||||
|
namespace lua_terrainmap {
|
||||||
|
std::string register_metatables(lua_State *L);
|
||||||
|
}
|
|
@ -20,6 +20,8 @@
|
||||||
#include "scripting/lua_common.hpp"
|
#include "scripting/lua_common.hpp"
|
||||||
#include "scripting/lua_rng.hpp"
|
#include "scripting/lua_rng.hpp"
|
||||||
#include "scripting/lua_pathfind_cost_calculator.hpp"
|
#include "scripting/lua_pathfind_cost_calculator.hpp"
|
||||||
|
#include "scripting/lua_terrainfilter.hpp"
|
||||||
|
#include "scripting/lua_terrainmap.hpp"
|
||||||
|
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -135,6 +137,8 @@ mapgen_lua_kernel::mapgen_lua_kernel()
|
||||||
static luaL_Reg const callbacks[] {
|
static luaL_Reg const callbacks[] {
|
||||||
{ "find_path", &intf_find_path },
|
{ "find_path", &intf_find_path },
|
||||||
{ "random", &intf_random },
|
{ "random", &intf_random },
|
||||||
|
{ "create_filter", &intf_terainfilter_create },
|
||||||
|
{ "create_map", &intf_terainmap_create },
|
||||||
{ nullptr, nullptr }
|
{ nullptr, nullptr }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -143,6 +147,10 @@ mapgen_lua_kernel::mapgen_lua_kernel()
|
||||||
luaL_setfuncs(L, callbacks, 0);
|
luaL_setfuncs(L, callbacks, 0);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
assert(lua_gettop(L) == 0);
|
assert(lua_gettop(L) == 0);
|
||||||
|
|
||||||
|
|
||||||
|
cmd_log_ << lua_terrainmap::register_metatables(L);
|
||||||
|
cmd_log_ << lua_terrainfilter::register_metatables(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mapgen_lua_kernel::run_generator(const char * prog, const config & generator)
|
void mapgen_lua_kernel::run_generator(const char * prog, const config & generator)
|
||||||
|
@ -193,6 +201,7 @@ config mapgen_lua_kernel::create_scenario(const char * prog, const config & gene
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t mapgen_lua_kernel::get_random_seed()
|
uint32_t mapgen_lua_kernel::get_random_seed()
|
||||||
{
|
{
|
||||||
if(uint32_t* pint = random_seed_.get_ptr()) {
|
if(uint32_t* pint = random_seed_.get_ptr()) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue