forked from github/server
fixed two bugs: harbours were not unique and multiple instances of unique buildings could still be built
This commit is contained in:
parent
d65d03db9c
commit
8714957a61
|
@ -128,7 +128,7 @@
|
||||||
</construction>
|
</construction>
|
||||||
</building>
|
</building>
|
||||||
|
|
||||||
<building name="harbour" capacity="1" maxcapacity="25" maxsize="25">
|
<building name="harbour" capacity="1" maxcapacity="25" maxsize="25" unique="yes">
|
||||||
<maintenance type="money" amount="250" vital="yes"/>
|
<maintenance type="money" amount="250" vital="yes"/>
|
||||||
<construction skill="building" minskill="3" reqsize="25" maxsize="25">
|
<construction skill="building" minskill="3" reqsize="25" maxsize="25">
|
||||||
<requirement type="log" quantity="125"/>
|
<requirement type="log" quantity="125"/>
|
||||||
|
|
|
@ -5,6 +5,19 @@ local function _test_create_ship(r)
|
||||||
return s
|
return s
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function _test_unique_btype()
|
||||||
|
local utype = nil
|
||||||
|
for i = 1, #config.buildings do
|
||||||
|
bt = config.buildings[i]
|
||||||
|
if (((config.get_building(bt).flags / 4) % 2) ~= 0) then -- #define BTF_UNIQUE 0x04
|
||||||
|
if (((config.get_building(bt).flags / 2) % 2) == 0) then -- #define BTF_NOBUILD 0x02
|
||||||
|
utype = bt
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return utype
|
||||||
|
end
|
||||||
|
|
||||||
local function one_unit(r, f)
|
local function one_unit(r, f)
|
||||||
local u = unit.create(f, r, 1)
|
local u = unit.create(f, r, 1)
|
||||||
u:add_item("money", u.number * 100)
|
u:add_item("money", u.number * 100)
|
||||||
|
@ -943,3 +956,97 @@ function test_bson_with_multiple_attribs()
|
||||||
end
|
end
|
||||||
assert_equal(6, total)
|
assert_equal(6, total)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function test_building_unique0()
|
||||||
|
local r = region.create(0, 0, "mountain")
|
||||||
|
local f = faction.create("noreply@eressea.de", "human", "de")
|
||||||
|
local u = unit.create(f, r, 20)
|
||||||
|
local f2 = faction.create("noreply@eressea.de", "human", "de")
|
||||||
|
local u2 = unit.create(f2, r, 20)
|
||||||
|
local utype = _test_unique_btype()
|
||||||
|
|
||||||
|
if (utype ~= nil) then
|
||||||
|
assert_equal("harbour", utype)
|
||||||
|
u:set_skill("building", 20)
|
||||||
|
u:add_item("log", 10000)
|
||||||
|
u:add_item("iron", 10000)
|
||||||
|
u:add_item("stone", 10000)
|
||||||
|
u:add_item("money", 10000)
|
||||||
|
u2:set_skill("building", 20)
|
||||||
|
u2:add_item("log", 10000)
|
||||||
|
u2:add_item("iron", 10000)
|
||||||
|
u2:add_item("stone", 10000)
|
||||||
|
u2:add_item("money", 10000)
|
||||||
|
|
||||||
|
-- build two harbours in one go
|
||||||
|
u:clear_orders()
|
||||||
|
u:add_order("MACHEN ".. translate(utype))
|
||||||
|
u2:clear_orders()
|
||||||
|
u2:add_order("MACHEN ".. translate(utype))
|
||||||
|
process_orders()
|
||||||
|
assert_not_nil(r.buildings)
|
||||||
|
bcount = 0
|
||||||
|
for bs in r.buildings do
|
||||||
|
assert_equal(1, string.find(bs.name, translate(utype)))
|
||||||
|
if (bs.size >= config.get_building(utype).maxsize) then
|
||||||
|
bcount = bcount + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert_equal(1, bcount) -- only one should be completed
|
||||||
|
else
|
||||||
|
-- fail() -- no unique building in rules
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_building_unique()
|
||||||
|
local r = region.create(0, 0, "mountain")
|
||||||
|
local f = faction.create("noreply@eressea.de", "human", "de")
|
||||||
|
local u = unit.create(f, r, 20)
|
||||||
|
local f2 = faction.create("noreply@eressea.de", "human", "de")
|
||||||
|
local u2 = unit.create(f2, r, 20)
|
||||||
|
local utype = _test_unique_btype()
|
||||||
|
|
||||||
|
if (utype ~= nil) then
|
||||||
|
u:set_skill("building", 20)
|
||||||
|
u:add_item("log", 10000)
|
||||||
|
u:add_item("iron", 10000)
|
||||||
|
u:add_item("stone", 10000)
|
||||||
|
u:add_item("money", 10000)
|
||||||
|
u2:set_skill("building", 20)
|
||||||
|
u2:add_item("log", 10000)
|
||||||
|
u2:add_item("iron", 10000)
|
||||||
|
u2:add_item("stone", 10000)
|
||||||
|
u2:add_item("money", 10000)
|
||||||
|
|
||||||
|
-- start building two harbours
|
||||||
|
u:clear_orders()
|
||||||
|
u:add_order("MACHEN 1 Hafen")
|
||||||
|
u2:clear_orders()
|
||||||
|
u2:add_order("MACHEN 1 Hafen")
|
||||||
|
process_orders()
|
||||||
|
-- finish building partial harbours
|
||||||
|
u:clear_orders()
|
||||||
|
u:add_order("MACHEN ".. translate("harbour"))
|
||||||
|
u2:clear_orders()
|
||||||
|
u2:add_order("MACHEN Hafen")
|
||||||
|
process_orders()
|
||||||
|
if (r.buildings() == nil) then
|
||||||
|
process_orders()
|
||||||
|
end
|
||||||
|
assert_not_nil(r.buildings)
|
||||||
|
bcount = 0
|
||||||
|
local h1 = nil
|
||||||
|
for bs in r.buildings do
|
||||||
|
if (h1 == nil) then
|
||||||
|
h1 = bs.name
|
||||||
|
else
|
||||||
|
assert_equal(h1, bs.name)
|
||||||
|
end
|
||||||
|
assert_equal(1, string.find(bs.name, "Hafen"))
|
||||||
|
if (bs.size >= 25) then
|
||||||
|
bcount = bcount + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert_equal(1, bcount) -- only one should be completed
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -20,6 +20,7 @@ without prior permission by the authors of Eressea.
|
||||||
#include <kernel/config.h>
|
#include <kernel/config.h>
|
||||||
|
|
||||||
#include <kernel/alliance.h>
|
#include <kernel/alliance.h>
|
||||||
|
#include <kernel/building.h>
|
||||||
#include <kernel/skill.h>
|
#include <kernel/skill.h>
|
||||||
#include <kernel/equipment.h>
|
#include <kernel/equipment.h>
|
||||||
#include <kernel/calendar.h>
|
#include <kernel/calendar.h>
|
||||||
|
@ -768,6 +769,19 @@ static int config_get_ships(lua_State * L)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int config_get_buildings(lua_State * L)
|
||||||
|
{
|
||||||
|
quicklist *ql;
|
||||||
|
int qi, i = 0;
|
||||||
|
lua_createtable(L, ql_length(buildingtypes), 0);
|
||||||
|
for (qi = 0, ql = buildingtypes; ql; ql_advance(&ql, &qi, 1)) {
|
||||||
|
building_type *btype = (building_type *) ql_get(ql, qi);
|
||||||
|
tolua_pushstring(L, TOLUA_CAST btype->_name);
|
||||||
|
lua_rawseti(L, -2, ++i);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int config_get_locales(lua_State * L)
|
static int config_get_locales(lua_State * L)
|
||||||
{
|
{
|
||||||
const struct locale *lang;
|
const struct locale *lang;
|
||||||
|
@ -823,6 +837,136 @@ static int config_get_resource(lua_State * L)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int config_get_btype(lua_State * L)
|
||||||
|
{
|
||||||
|
const char *name = tolua_tostring(L, 1, 0);
|
||||||
|
|
||||||
|
if (name) {
|
||||||
|
const struct building_type *btype = bt_find(name);
|
||||||
|
if (btype) {
|
||||||
|
lua_newtable(L);
|
||||||
|
lua_pushstring(L, "flags");
|
||||||
|
lua_pushinteger(L, btype->flags);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
if (btype->capacity > 0) {
|
||||||
|
lua_pushstring(L, "capacity");
|
||||||
|
lua_pushinteger(L, btype->capacity);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
}
|
||||||
|
if (btype->maxcapacity > 0) {
|
||||||
|
lua_pushstring(L, "maxcapacity");
|
||||||
|
lua_pushinteger(L, btype->maxcapacity);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
}
|
||||||
|
if (btype->maxsize > 0) {
|
||||||
|
lua_pushstring(L, "maxsize");
|
||||||
|
lua_pushinteger(L, btype->maxsize);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
}
|
||||||
|
if (btype->maintenance) {
|
||||||
|
int i;
|
||||||
|
lua_pushstring(L, "maintenance");
|
||||||
|
lua_newtable(L);
|
||||||
|
for (i = 0; btype->maintenance[i].number; ++i) {
|
||||||
|
lua_pushstring(L,
|
||||||
|
btype->maintenance[i].rtype->_name[0]);
|
||||||
|
lua_pushinteger(L, btype->maintenance[i].number);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
}
|
||||||
|
lua_settable(L, -3);
|
||||||
|
}
|
||||||
|
if (btype->construction) {
|
||||||
|
int i;
|
||||||
|
lua_pushstring(L, "build_skill_min");
|
||||||
|
lua_pushinteger(L, btype->construction->minskill);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
lua_pushstring(L, "build_skill_name");
|
||||||
|
lua_pushstring(L, skillnames[btype->construction->skill]);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
if (btype->construction->materials) {
|
||||||
|
lua_pushstring(L, "materials");
|
||||||
|
lua_newtable(L);
|
||||||
|
for (i = 0; btype->construction->materials[i].number; ++i) {
|
||||||
|
lua_pushstring(L,
|
||||||
|
btype->construction->materials[i].rtype->_name[0]);
|
||||||
|
lua_pushinteger(L, btype->construction->materials[i].number);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
}
|
||||||
|
lua_settable(L, -3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int config_get_stype(lua_State * L)
|
||||||
|
{
|
||||||
|
const char *name = tolua_tostring(L, 1, 0);
|
||||||
|
|
||||||
|
if (name) {
|
||||||
|
const struct ship_type *stype = st_find(name);
|
||||||
|
if (stype) {
|
||||||
|
lua_newtable(L);
|
||||||
|
lua_pushstring(L, "range");
|
||||||
|
lua_pushinteger(L, stype->range);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
lua_pushstring(L, "cabins");
|
||||||
|
lua_pushinteger(L, stype->cabins);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
lua_pushstring(L, "cargo");
|
||||||
|
lua_pushinteger(L, stype->cargo);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
lua_pushstring(L, "cptskill");
|
||||||
|
lua_pushinteger(L, stype->cptskill);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
lua_pushstring(L, "minskill");
|
||||||
|
lua_pushinteger(L, stype->minskill);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
lua_pushstring(L, "sumskill");
|
||||||
|
lua_pushinteger(L, stype->sumskill);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
lua_pushstring(L, "fishing");
|
||||||
|
lua_pushinteger(L, stype->fishing);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
if (stype->coasts) {
|
||||||
|
const terrain_type *coast = *stype->coasts;
|
||||||
|
lua_pushstring(L, "coasts");
|
||||||
|
lua_newtable(L);
|
||||||
|
while(coast) {
|
||||||
|
lua_pushstring(L, coast->_name);
|
||||||
|
lua_pushinteger(L, 1);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
coast = coast->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (stype->construction) {
|
||||||
|
int i;
|
||||||
|
lua_pushstring(L, "build_skill_min");
|
||||||
|
lua_pushinteger(L, stype->construction->minskill);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
lua_pushstring(L, "build_skill_name");
|
||||||
|
lua_pushstring(L, skillnames[stype->construction->skill]);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
if (stype->construction->materials) {
|
||||||
|
lua_pushstring(L, "materials");
|
||||||
|
lua_newtable(L);
|
||||||
|
for (i = 0; stype->construction->materials[i].number; ++i) {
|
||||||
|
lua_pushstring(L,
|
||||||
|
stype->construction->materials[i].rtype->_name[0]);
|
||||||
|
lua_pushinteger(L, stype->construction->materials[i].number);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
}
|
||||||
|
lua_settable(L, -3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int tolua_get_spell_text(lua_State * L)
|
static int tolua_get_spell_text(lua_State * L)
|
||||||
{
|
{
|
||||||
const struct locale *loc = default_locale;
|
const struct locale *loc = default_locale;
|
||||||
|
@ -1060,7 +1204,10 @@ int tolua_eressea_open(lua_State * L)
|
||||||
parse_inifile(L, global.inifile, "config");
|
parse_inifile(L, global.inifile, "config");
|
||||||
tolua_variable(L, TOLUA_CAST "locales", &config_get_locales, 0);
|
tolua_variable(L, TOLUA_CAST "locales", &config_get_locales, 0);
|
||||||
tolua_function(L, TOLUA_CAST "get_resource", &config_get_resource);
|
tolua_function(L, TOLUA_CAST "get_resource", &config_get_resource);
|
||||||
|
tolua_variable(L, TOLUA_CAST "buildings", &config_get_buildings, 0);
|
||||||
|
tolua_function(L, TOLUA_CAST "get_building", &config_get_btype);
|
||||||
tolua_variable(L, TOLUA_CAST "ships", &config_get_ships, 0);
|
tolua_variable(L, TOLUA_CAST "ships", &config_get_ships, 0);
|
||||||
|
tolua_function(L, TOLUA_CAST "get_ship", &config_get_stype);
|
||||||
} tolua_endmodule(L);
|
} tolua_endmodule(L);
|
||||||
tolua_function(L, TOLUA_CAST "get_region_by_id", tolua_get_region_byid);
|
tolua_function(L, TOLUA_CAST "get_region_by_id", tolua_get_region_byid);
|
||||||
tolua_function(L, TOLUA_CAST "get_faction", tolua_get_faction);
|
tolua_function(L, TOLUA_CAST "get_faction", tolua_get_faction);
|
||||||
|
|
|
@ -890,7 +890,7 @@ build_building(unit * u, const building_type * btype, int want, order * ord)
|
||||||
if (b)
|
if (b)
|
||||||
btype = b->type;
|
btype = b->type;
|
||||||
|
|
||||||
if (b && fval(btype, BTF_UNIQUE) && buildingtype_exists(r, btype, false)) {
|
if (fval(btype, BTF_UNIQUE) && buildingtype_exists(r, btype, false)) {
|
||||||
/* only one of these per region */
|
/* only one of these per region */
|
||||||
cmistake(u, ord, 93, MSG_PRODUCE);
|
cmistake(u, ord, 93, MSG_PRODUCE);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -124,28 +124,28 @@ typedef struct building_typelist {
|
||||||
building_type *type;
|
building_type *type;
|
||||||
} building_typelist;
|
} building_typelist;
|
||||||
|
|
||||||
static building_typelist *buildingtypes;
|
quicklist *buildingtypes = NULL;
|
||||||
|
|
||||||
building_type *bt_find(const char *name)
|
building_type *bt_find(const char *name)
|
||||||
{
|
{
|
||||||
const struct building_typelist *btl = buildingtypes;
|
quicklist *ql;
|
||||||
|
int qi;
|
||||||
|
|
||||||
assert(name);
|
assert(name);
|
||||||
while (btl && strcmp(btl->type->_name, name))
|
|
||||||
btl = btl->next;
|
for (qi = 0, ql = buildingtypes; ql; ql_advance(&ql, &qi, 1)) {
|
||||||
if (btl == NULL) {
|
building_type *btype = (building_type *) ql_get(ql, qi);
|
||||||
return NULL;
|
if (strcmp(btype->_name, name) == 0)
|
||||||
|
return btype;
|
||||||
}
|
}
|
||||||
return btl->type;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bt_register(building_type * type)
|
void bt_register(building_type * type)
|
||||||
{
|
{
|
||||||
struct building_typelist *btl = malloc(sizeof(building_type));
|
|
||||||
if (type->init)
|
if (type->init)
|
||||||
type->init(type);
|
type->init(type);
|
||||||
btl->type = type;
|
ql_push(&buildingtypes, (void *)type);
|
||||||
btl->next = buildingtypes;
|
|
||||||
buildingtypes = btl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int buildingcapacity(const building * b)
|
int buildingcapacity(const building * b)
|
||||||
|
@ -362,15 +362,19 @@ const building_type *findbuildingtype(const char *name,
|
||||||
bn = bn->next;
|
bn = bn->next;
|
||||||
}
|
}
|
||||||
if (!bn) {
|
if (!bn) {
|
||||||
struct building_typelist *btl = buildingtypes;
|
quicklist *ql = buildingtypes;
|
||||||
|
int qi;
|
||||||
|
|
||||||
bn = calloc(sizeof(local_names), 1);
|
bn = calloc(sizeof(local_names), 1);
|
||||||
bn->next = bnames;
|
bn->next = bnames;
|
||||||
bn->lang = lang;
|
bn->lang = lang;
|
||||||
while (btl) {
|
|
||||||
const char *n = locale_string(lang, btl->type->_name);
|
for (qi = 0, ql = buildingtypes; ql; ql_advance(&ql, &qi, 1)) {
|
||||||
type.v = (void *)btl->type;
|
building_type *btype = (building_type *) ql_get(ql, qi);
|
||||||
|
|
||||||
|
const char *n = locale_string(lang, btype->_name);
|
||||||
|
type.v = (void *)btype;
|
||||||
addtoken(&bn->names, n, type);
|
addtoken(&bn->names, n, type);
|
||||||
btl = btl->next;
|
|
||||||
}
|
}
|
||||||
bnames = bn;
|
bnames = bn;
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,8 @@ extern "C" {
|
||||||
struct attrib *attribs;
|
struct attrib *attribs;
|
||||||
} building_type;
|
} building_type;
|
||||||
|
|
||||||
|
extern struct quicklist *buildingtypes;
|
||||||
|
|
||||||
extern building_type *bt_find(const char *name);
|
extern building_type *bt_find(const char *name);
|
||||||
extern void register_buildings(void);
|
extern void register_buildings(void);
|
||||||
extern void bt_register(struct building_type *type);
|
extern void bt_register(struct building_type *type);
|
||||||
|
|
|
@ -2715,3 +2715,7 @@ void follow_unit(unit * u)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef DISABLE_TESTS
|
||||||
|
#include "move_test.c"
|
||||||
|
#endif
|
||||||
|
|
|
@ -69,10 +69,10 @@ const ship_type *findshiptype(const char *name, const struct locale *lang)
|
||||||
|
|
||||||
for (qi = 0, ql = shiptypes; ql; ql_advance(&ql, &qi, 1)) {
|
for (qi = 0, ql = shiptypes; ql; ql_advance(&ql, &qi, 1)) {
|
||||||
ship_type *stype = (ship_type *) ql_get(ql, qi);
|
ship_type *stype = (ship_type *) ql_get(ql, qi);
|
||||||
variant var;
|
variant var2;
|
||||||
const char *n = locale_string(lang, stype->name[0]);
|
const char *n = locale_string(lang, stype->name[0]);
|
||||||
var.v = (void *)stype;
|
var2.v = (void *)stype;
|
||||||
addtoken(&sn->names, n, var);
|
addtoken(&sn->names, n, var2);
|
||||||
}
|
}
|
||||||
snames = sn;
|
snames = sn;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
CuSuite *get_curse_suite(void);
|
CuSuite *get_curse_suite(void);
|
||||||
CuSuite *get_market_suite(void);
|
CuSuite *get_market_suite(void);
|
||||||
|
CuSuite *get_move_suite(void);
|
||||||
CuSuite *get_laws_suite(void);
|
CuSuite *get_laws_suite(void);
|
||||||
|
|
||||||
#include <kernel/region.h>
|
#include <kernel/region.h>
|
||||||
|
@ -34,6 +35,7 @@ int RunAllTests(void)
|
||||||
CuSuiteAddSuite(suite, get_quicklist_suite());
|
CuSuiteAddSuite(suite, get_quicklist_suite());
|
||||||
CuSuiteAddSuite(suite, get_curse_suite());
|
CuSuiteAddSuite(suite, get_curse_suite());
|
||||||
CuSuiteAddSuite(suite, get_market_suite());
|
CuSuiteAddSuite(suite, get_market_suite());
|
||||||
|
CuSuiteAddSuite(suite, get_move_suite());
|
||||||
CuSuiteAddSuite(suite, get_laws_suite());
|
CuSuiteAddSuite(suite, get_laws_suite());
|
||||||
|
|
||||||
CuSuiteRun(suite);
|
CuSuiteRun(suite);
|
||||||
|
|
Loading…
Reference in New Issue