forked from github/server
Merge pull request #687 from ennorehling/develop
refactor buildings: taxes, names, tests
This commit is contained in:
commit
3d13cb8968
|
@ -1,23 +1,21 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<building name="castle" capacity="1" fort="yes">
|
<building name="castle" capacity="1" fort="yes" taxes="100">
|
||||||
<function name="name" value="castle_name_2"/>
|
<construction skill="building" minskill="1" maxsize="10" name="site">
|
||||||
<function name="taxes" value="lua_building_taxes"/>
|
|
||||||
<construction skill="building" minskill="1" maxsize="10">
|
|
||||||
<requirement type="stone" quantity="1"/>
|
<requirement type="stone" quantity="1"/>
|
||||||
</construction>
|
</construction>
|
||||||
<construction skill="building" minskill="2" maxsize="40">
|
<construction skill="building" minskill="2" maxsize="40" name="fortification">
|
||||||
<requirement type="stone" quantity="1"/>
|
<requirement type="stone" quantity="1"/>
|
||||||
</construction>
|
</construction>
|
||||||
<construction skill="building" minskill="3" maxsize="200">
|
<construction skill="building" minskill="3" maxsize="200" name="tower">
|
||||||
<requirement type="stone" quantity="1"/>
|
<requirement type="stone" quantity="1"/>
|
||||||
</construction>
|
</construction>
|
||||||
<construction skill="building" minskill="4" maxsize="1000">
|
<construction skill="building" minskill="4" maxsize="1000" name="castle">
|
||||||
<requirement type="stone" quantity="1"/>
|
<requirement type="stone" quantity="1"/>
|
||||||
</construction>
|
</construction>
|
||||||
<construction skill="building" minskill="5" maxsize="5000">
|
<construction skill="building" minskill="5" maxsize="5000" name="fortress">
|
||||||
<requirement type="stone" quantity="1"/>
|
<requirement type="stone" quantity="1"/>
|
||||||
</construction>
|
</construction>
|
||||||
<construction skill="building" minskill="6">
|
<construction skill="building" minskill="6" name="citadel">
|
||||||
<requirement type="stone" quantity="1"/>
|
<requirement type="stone" quantity="1"/>
|
||||||
</construction>
|
</construction>
|
||||||
</building>
|
</building>
|
||||||
|
|
|
@ -1,25 +1,24 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<building name="castle" capacity="1" fort="yes">
|
<building name="castle" capacity="1" fort="yes">
|
||||||
<function name="name" value="castle_name"/>
|
<construction skill="building" minskill="1" maxsize="2" name="site">
|
||||||
<construction skill="building" minskill="1" maxsize="2">
|
|
||||||
<requirement type="stone" quantity="1"/>
|
<requirement type="stone" quantity="1"/>
|
||||||
</construction>
|
</construction>
|
||||||
<construction skill="building" minskill="1" maxsize="8">
|
<construction skill="building" minskill="1" maxsize="8" name="tradepost">
|
||||||
<requirement type="stone" quantity="1"/>
|
<requirement type="stone" quantity="1"/>
|
||||||
</construction>
|
</construction>
|
||||||
<construction skill="building" minskill="2" maxsize="40">
|
<construction skill="building" minskill="2" maxsize="40" name="fortification">
|
||||||
<requirement type="stone" quantity="1"/>
|
<requirement type="stone" quantity="1"/>
|
||||||
</construction>
|
</construction>
|
||||||
<construction skill="building" minskill="3" maxsize="200">
|
<construction skill="building" minskill="3" maxsize="200" name="tower">
|
||||||
<requirement type="stone" quantity="1"/>
|
<requirement type="stone" quantity="1"/>
|
||||||
</construction>
|
</construction>
|
||||||
<construction skill="building" minskill="4" maxsize="1000">
|
<construction skill="building" minskill="4" maxsize="1000" name="castle">
|
||||||
<requirement type="stone" quantity="1"/>
|
<requirement type="stone" quantity="1"/>
|
||||||
</construction>
|
</construction>
|
||||||
<construction skill="building" minskill="5" maxsize="5000">
|
<construction skill="building" minskill="5" maxsize="5000" name="fortress">
|
||||||
<requirement type="stone" quantity="1"/>
|
<requirement type="stone" quantity="1"/>
|
||||||
</construction>
|
</construction>
|
||||||
<construction skill="building" minskill="6">
|
<construction skill="building" minskill="6" name="citadel">
|
||||||
<requirement type="stone" quantity="1"/>
|
<requirement type="stone" quantity="1"/>
|
||||||
</construction>
|
</construction>
|
||||||
</building>
|
</building>
|
||||||
|
|
|
@ -3,16 +3,14 @@
|
||||||
|
|
||||||
<xi:include href="config://default/buildings/castle-2.xml" />
|
<xi:include href="config://default/buildings/castle-2.xml" />
|
||||||
|
|
||||||
<building name="watch" maxsize="10" capacity="1" fort="yes">
|
<building name="watch" maxsize="10" capacity="1" fort="yes" taxes="200">
|
||||||
<function name="name" value="fort_name"/>
|
<construction skill="building" minskill="1" maxsize="5" name="scaffolding">
|
||||||
<function name="taxes" value="lua_building_taxes"/>
|
|
||||||
<construction skill="building" minskill="1" maxsize="5">
|
|
||||||
<requirement type="log" quantity="1"/>
|
<requirement type="log" quantity="1"/>
|
||||||
</construction>
|
</construction>
|
||||||
<construction skill="building" minskill="2" maxsize="5">
|
<construction skill="building" minskill="2" maxsize="5" name="guardhouse">
|
||||||
<requirement type="log" quantity="1"/>
|
<requirement type="log" quantity="1"/>
|
||||||
</construction>
|
</construction>
|
||||||
<construction skill="building" minskill="2">
|
<construction skill="building" minskill="2" name="guardtower">
|
||||||
<requirement type="log" quantity="1"/>
|
<requirement type="log" quantity="1"/>
|
||||||
</construction>
|
</construction>
|
||||||
</building>
|
</building>
|
||||||
|
|
|
@ -1,13 +1,3 @@
|
||||||
function building_taxes(b, blevel)
|
|
||||||
btype = b.type
|
|
||||||
if btype=="castle" then
|
|
||||||
return blevel * 0.01
|
|
||||||
elseif btype=="watch" then
|
|
||||||
return blevel * 0.005
|
|
||||||
end
|
|
||||||
return 0.0
|
|
||||||
end
|
|
||||||
|
|
||||||
-- the "raindance" spell
|
-- the "raindance" spell
|
||||||
function raindance(r, mage, level, force)
|
function raindance(r, mage, level, force)
|
||||||
if (create_curse(mage, r, "blessedharvest", force, 1+force*2, 100 * force)) then
|
if (create_curse(mage, r, "blessedharvest", force, 1+force*2, 100 * force)) then
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
require "lunit"
|
||||||
|
|
||||||
|
module("tests.e2.buildings", package.seeall, lunit.testcase )
|
||||||
|
|
||||||
|
function setup()
|
||||||
|
eressea.game.reset()
|
||||||
|
eressea.settings.set("rules.food.flags", "4")
|
||||||
|
end
|
||||||
|
|
||||||
|
function teardown()
|
||||||
|
eressea.settings.set("rules.food.flags", "0")
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_castle_names()
|
||||||
|
local r = region.create(0, 0, "plain")
|
||||||
|
local b = building.create(r, "castle")
|
||||||
|
|
||||||
|
assert_equal("site", b:get_typename(1))
|
||||||
|
assert_equal("tradepost", b:get_typename(2))
|
||||||
|
assert_equal("tradepost", b:get_typename(9))
|
||||||
|
assert_equal("fortification", b:get_typename(10))
|
||||||
|
assert_equal("fortification", b:get_typename(49))
|
||||||
|
assert_equal("tower", b:get_typename(50))
|
||||||
|
assert_equal("tower", b:get_typename(249))
|
||||||
|
assert_equal("castle", b:get_typename(250))
|
||||||
|
assert_equal("castle", b:get_typename(1249))
|
||||||
|
assert_equal("fortress", b:get_typename(1250))
|
||||||
|
assert_equal("fortress", b:get_typename(6249))
|
||||||
|
assert_equal("citadel", b:get_typename(6250))
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_build_castle_stages()
|
||||||
|
local r = region.create(0,0, "plain")
|
||||||
|
local f = faction.create("human")
|
||||||
|
local u = unit.create(f, r, 1000)
|
||||||
|
local b = building.create(r, "castle")
|
||||||
|
|
||||||
|
u:add_item("stone", 1000)
|
||||||
|
|
||||||
|
u:set_skill("building", 1)
|
||||||
|
u:clear_orders()
|
||||||
|
|
||||||
|
u:add_order("MACHE BURG " .. itoa36(b.id))
|
||||||
|
process_orders()
|
||||||
|
assert_equal(10, b.size)
|
||||||
|
|
||||||
|
u:set_skill("building", 3)
|
||||||
|
u:clear_orders()
|
||||||
|
|
||||||
|
u:add_order("MACHE BURG " .. itoa36(b.id))
|
||||||
|
process_orders()
|
||||||
|
assert_equal(250, b.size)
|
||||||
|
end
|
|
@ -1,3 +1,4 @@
|
||||||
|
require 'tests.e2.buildings'
|
||||||
require 'tests.e2.production'
|
require 'tests.e2.production'
|
||||||
require 'tests.e2.adamantium'
|
require 'tests.e2.adamantium'
|
||||||
require 'tests.e2.undead'
|
require 'tests.e2.undead'
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
require "lunit"
|
require "lunit"
|
||||||
|
|
||||||
module("tests.e3.castles", package.seeall, lunit.testcase )
|
module("tests.e3.buildings", package.seeall, lunit.testcase )
|
||||||
|
|
||||||
function setup()
|
function setup()
|
||||||
eressea.game.reset()
|
eressea.game.reset()
|
||||||
|
@ -11,6 +11,23 @@ function teardown()
|
||||||
eressea.settings.set("rules.food.flags", "0")
|
eressea.settings.set("rules.food.flags", "0")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function test_castle_names()
|
||||||
|
local r = region.create(0, 0, "plain")
|
||||||
|
local b = building.create(r, "castle")
|
||||||
|
|
||||||
|
assert_equal("site", b:get_typename(1))
|
||||||
|
assert_equal("site", b:get_typename(9))
|
||||||
|
assert_equal("fortification", b:get_typename(10))
|
||||||
|
assert_equal("fortification", b:get_typename(49))
|
||||||
|
assert_equal("tower", b:get_typename(50))
|
||||||
|
assert_equal("tower", b:get_typename(249))
|
||||||
|
assert_equal("castle", b:get_typename(250))
|
||||||
|
assert_equal("castle", b:get_typename(1249))
|
||||||
|
assert_equal("fortress", b:get_typename(1250))
|
||||||
|
assert_equal("fortress", b:get_typename(6249))
|
||||||
|
assert_equal("citadel", b:get_typename(6250))
|
||||||
|
end
|
||||||
|
|
||||||
function test_build_watch()
|
function test_build_watch()
|
||||||
local r = region.create(0, 0, "plain")
|
local r = region.create(0, 0, "plain")
|
||||||
local f = faction.create("human", "e3build@eressea.de", "de")
|
local f = faction.create("human", "e3build@eressea.de", "de")
|
||||||
|
@ -33,7 +50,7 @@ function test_build_watch()
|
||||||
assert_equal(10, u.building.size)
|
assert_equal(10, u.building.size)
|
||||||
end
|
end
|
||||||
|
|
||||||
function test_watch()
|
function test_watch_names()
|
||||||
local r = region.create(0, 0, "plain")
|
local r = region.create(0, 0, "plain")
|
||||||
local b = building.create(r, "watch")
|
local b = building.create(r, "watch")
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
-- require 'tests.e3.castles'
|
require 'tests.e3.buildings'
|
||||||
-- require 'tests.e3.stealth'
|
require 'tests.e3.stealth'
|
||||||
-- require 'tests.e3.spells'
|
require 'tests.e3.spells'
|
||||||
require 'tests.e3.rules'
|
require 'tests.e3.rules'
|
||||||
-- require 'tests.e3.parser'
|
require 'tests.e3.parser'
|
||||||
-- require 'tests.e3.morale'
|
require 'tests.e3.morale'
|
||||||
-- require 'tests.e3.items'
|
require 'tests.e3.items'
|
||||||
-- require 'tests.economy'
|
require 'tests.economy'
|
||||||
-- require 'tests.orders'
|
require 'tests.orders'
|
||||||
-- require 'tests.common'
|
require 'tests.common'
|
||||||
-- require 'tests.items'
|
require 'tests.items'
|
||||||
-- require 'tests.magicbag'
|
require 'tests.magicbag'
|
||||||
-- require 'tests.process'
|
require 'tests.process'
|
||||||
-- require 'tests.e3.production'
|
require 'tests.e3.production'
|
||||||
-- require 'tests.production'
|
require 'tests.production'
|
||||||
|
|
|
@ -575,7 +575,7 @@ void give_control(unit * u, unit * u2)
|
||||||
|
|
||||||
assert(u->building == u2->building);
|
assert(u->building == u2->building);
|
||||||
if (f == u->faction) {
|
if (f == u->faction) {
|
||||||
building *b = largestbuilding(r, &cmp_current_owner, false);
|
building *b = largestbuilding(r, cmp_current_owner, false);
|
||||||
if (b == u->building) {
|
if (b == u->building) {
|
||||||
friendly_takeover(r, u2->faction);
|
friendly_takeover(r, u2->faction);
|
||||||
}
|
}
|
||||||
|
@ -888,7 +888,7 @@ static void manufacture(unit * u, const item_type * itype, int want)
|
||||||
case EBUILDINGREQ:
|
case EBUILDINGREQ:
|
||||||
ADDMSG(&u->faction->msgs,
|
ADDMSG(&u->faction->msgs,
|
||||||
msg_feedback(u, u->thisorder, "building_needed", "building",
|
msg_feedback(u, u->thisorder, "building_needed", "building",
|
||||||
itype->construction->btype->_name));
|
itype->construction->extra.btype->_name));
|
||||||
return;
|
return;
|
||||||
case ELOWSKILL:
|
case ELOWSKILL:
|
||||||
ADDMSG(&u->faction->msgs,
|
ADDMSG(&u->faction->msgs,
|
||||||
|
@ -1239,7 +1239,7 @@ static void create_potion(unit * u, const potion_type * ptype, int want)
|
||||||
case EBUILDINGREQ:
|
case EBUILDINGREQ:
|
||||||
ADDMSG(&u->faction->msgs,
|
ADDMSG(&u->faction->msgs,
|
||||||
msg_feedback(u, u->thisorder, "building_needed", "building",
|
msg_feedback(u, u->thisorder, "building_needed", "building",
|
||||||
ptype->itype->construction->btype->_name));
|
ptype->itype->construction->extra.btype->_name));
|
||||||
break;
|
break;
|
||||||
case ECOMPLETE:
|
case ECOMPLETE:
|
||||||
assert(0);
|
assert(0);
|
||||||
|
@ -2929,7 +2929,7 @@ static void peasant_taxes(region * r)
|
||||||
unit *u;
|
unit *u;
|
||||||
building *b;
|
building *b;
|
||||||
int money;
|
int money;
|
||||||
int maxsize;
|
int level;
|
||||||
|
|
||||||
f = region_get_owner(r);
|
f = region_get_owner(r);
|
||||||
if (f == NULL || is_mourning(r, turn)) {
|
if (f == NULL || is_mourning(r, turn)) {
|
||||||
|
@ -2947,10 +2947,10 @@ static void peasant_taxes(region * r)
|
||||||
if (u == NULL || u->faction != f)
|
if (u == NULL || u->faction != f)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
maxsize = buildingeffsize(b, false);
|
level = buildingeffsize(b, false);
|
||||||
if (maxsize > 0) {
|
if (level > 0) {
|
||||||
double taxfactor = money * b->type->taxes(b, maxsize);
|
double taxfactor = money * level / building_taxes(b);
|
||||||
double morale = MORALE_TAX_FACTOR * money * region_get_morale(r);
|
double morale = money * region_get_morale(r) / MORALE_TAX_FACTOR;
|
||||||
if (taxfactor > morale) {
|
if (taxfactor > morale) {
|
||||||
taxfactor = morale;
|
taxfactor = morale;
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,6 @@ void game_init(void)
|
||||||
register_spells();
|
register_spells();
|
||||||
register_names();
|
register_names();
|
||||||
register_resources();
|
register_resources();
|
||||||
register_buildings();
|
|
||||||
register_itemfunctions();
|
register_itemfunctions();
|
||||||
#if MUSEUM_MODULE
|
#if MUSEUM_MODULE
|
||||||
register_museum();
|
register_museum();
|
||||||
|
|
|
@ -112,7 +112,7 @@ static bool is_guardian_r(const unit * guard)
|
||||||
if (guard->building && rule_region_owners() && guard == building_owner(guard->building)) {
|
if (guard->building && rule_region_owners() && guard == building_owner(guard->building)) {
|
||||||
faction *owner = region_get_owner(guard->region);
|
faction *owner = region_get_owner(guard->region);
|
||||||
if (owner == guard->faction) {
|
if (owner == guard->faction) {
|
||||||
building *bowner = largestbuilding(guard->region, &cmp_taxes, false);
|
building *bowner = largestbuilding(guard->region, cmp_taxes, false);
|
||||||
if (bowner == guard->building) {
|
if (bowner == guard->building) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -352,58 +352,6 @@ lua_wage(const region * r, const faction * f, const race * rc, int in_turn)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lua_agebuilding(building * b)
|
|
||||||
{
|
|
||||||
lua_State *L = (lua_State *)global.vm_state;
|
|
||||||
char fname[64];
|
|
||||||
|
|
||||||
strlcpy(fname, "age_", sizeof(fname));
|
|
||||||
strlcat(fname, b->type->_name, sizeof(fname));
|
|
||||||
|
|
||||||
lua_getglobal(L, fname);
|
|
||||||
if (lua_isfunction(L, -1)) {
|
|
||||||
tolua_pushusertype(L, (void *)b, TOLUA_CAST "building");
|
|
||||||
|
|
||||||
if (lua_pcall(L, 1, 0, 0) != 0) {
|
|
||||||
const char *error = lua_tostring(L, -1);
|
|
||||||
log_error("agebuilding(%s) calling '%s': %s.\n", buildingname(b), fname, error);
|
|
||||||
lua_pop(L, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log_error("agebuilding(%s) calling '%s': not a function.\n", buildingname(b), fname);
|
|
||||||
lua_pop(L, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static double lua_building_taxes(building * b, int level)
|
|
||||||
{
|
|
||||||
lua_State *L = (lua_State *)global.vm_state;
|
|
||||||
const char *fname = "building_taxes";
|
|
||||||
double result = 0.0F;
|
|
||||||
|
|
||||||
lua_getglobal(L, fname);
|
|
||||||
if (lua_isfunction(L, -1)) {
|
|
||||||
tolua_pushusertype(L, (void *)b, TOLUA_CAST "building");
|
|
||||||
lua_pushinteger(L, level);
|
|
||||||
|
|
||||||
if (lua_pcall(L, 2, 1, 0) != 0) {
|
|
||||||
const char *error = lua_tostring(L, -1);
|
|
||||||
log_error("building_taxes(%s) calling '%s': %s.\n", buildingname(b), fname, error);
|
|
||||||
lua_pop(L, 1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
result = (double)lua_tonumber(L, -1);
|
|
||||||
lua_pop(L, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log_error("building_taxes(%s) calling '%s': not a function.\n", buildingname(b), fname);
|
|
||||||
lua_pop(L, 1);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lua_maintenance(const unit * u)
|
static int lua_maintenance(const unit * u)
|
||||||
{
|
{
|
||||||
lua_State *L = (lua_State *)global.vm_state;
|
lua_State *L = (lua_State *)global.vm_state;
|
||||||
|
@ -526,10 +474,6 @@ void register_tolua_helpers(void)
|
||||||
at_register(&at_direction);
|
at_register(&at_direction);
|
||||||
at_register(&at_building_action);
|
at_register(&at_building_action);
|
||||||
|
|
||||||
register_function((pf_generic)lua_building_taxes,
|
|
||||||
TOLUA_CAST "lua_building_taxes");
|
|
||||||
register_function((pf_generic)lua_agebuilding,
|
|
||||||
TOLUA_CAST "lua_agebuilding");
|
|
||||||
register_function((pf_generic)lua_callspell, TOLUA_CAST "lua_castspell");
|
register_function((pf_generic)lua_callspell, TOLUA_CAST "lua_castspell");
|
||||||
register_function((pf_generic)lua_initfamiliar,
|
register_function((pf_generic)lua_initfamiliar,
|
||||||
TOLUA_CAST "lua_initfamiliar");
|
TOLUA_CAST "lua_initfamiliar");
|
||||||
|
|
|
@ -502,20 +502,20 @@ static int count_materials(unit *u, const construction *type, int n, int complet
|
||||||
*/
|
*/
|
||||||
int build(unit * u, const construction * ctype, int completed, int want, int skill_mod)
|
int build(unit * u, const construction * ctype, int completed, int want, int skill_mod)
|
||||||
{
|
{
|
||||||
const construction *type = ctype;
|
const construction *con = ctype;
|
||||||
int skills = INT_MAX; /* number of skill points remainig */
|
int skills = INT_MAX; /* number of skill points remainig */
|
||||||
int basesk = 0;
|
int basesk = 0;
|
||||||
int made = 0;
|
int made = 0;
|
||||||
|
|
||||||
if (want <= 0)
|
if (want <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
if (type == NULL)
|
if (con == NULL)
|
||||||
return ENOMATERIALS;
|
return ENOMATERIALS;
|
||||||
if (type->improvement == NULL && completed == type->maxsize)
|
if (con->improvement == NULL && completed == con->maxsize)
|
||||||
return ECOMPLETE;
|
return ECOMPLETE;
|
||||||
if (type->btype != NULL) {
|
if (con->type==CONS_ITEM && con->extra.btype) {
|
||||||
building *b;
|
building *b;
|
||||||
if (!u->building || u->building->type != type->btype) {
|
if (!u->building || u->building->type != con->extra.btype) {
|
||||||
return EBUILDINGREQ;
|
return EBUILDINGREQ;
|
||||||
}
|
}
|
||||||
b = inside_building(u);
|
b = inside_building(u);
|
||||||
|
@ -524,12 +524,12 @@ int build(unit * u, const construction * ctype, int completed, int want, int ski
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type->skill != NOSKILL) {
|
if (con->skill != NOSKILL) {
|
||||||
int effsk;
|
int effsk;
|
||||||
int dm = get_effect(u, oldpotiontype[P_DOMORE]);
|
int dm = get_effect(u, oldpotiontype[P_DOMORE]);
|
||||||
|
|
||||||
assert(u->number);
|
assert(u->number);
|
||||||
basesk = effskill(u, type->skill, 0);
|
basesk = effskill(u, con->skill, 0);
|
||||||
if (basesk == 0)
|
if (basesk == 0)
|
||||||
return ENEEDSKILL;
|
return ENEEDSKILL;
|
||||||
|
|
||||||
|
@ -557,13 +557,13 @@ int build(unit * u, const construction * ctype, int completed, int want, int ski
|
||||||
* type->improvement==type means build another object of the same time
|
* type->improvement==type means build another object of the same time
|
||||||
* while material lasts type->improvement==x means build x when type
|
* while material lasts type->improvement==x means build x when type
|
||||||
* is finished */
|
* is finished */
|
||||||
while (type && type->improvement &&
|
while (con && con->improvement &&
|
||||||
type->improvement != type &&
|
con->improvement != con &&
|
||||||
type->maxsize > 0 && type->maxsize <= completed) {
|
con->maxsize > 0 && con->maxsize <= completed) {
|
||||||
completed -= type->maxsize;
|
completed -= con->maxsize;
|
||||||
type = type->improvement;
|
con = con->improvement;
|
||||||
}
|
}
|
||||||
if (type == NULL) {
|
if (con == NULL) {
|
||||||
if (made == 0)
|
if (made == 0)
|
||||||
return ECOMPLETE;
|
return ECOMPLETE;
|
||||||
break; /* completed */
|
break; /* completed */
|
||||||
|
@ -574,15 +574,15 @@ int build(unit * u, const construction * ctype, int completed, int want, int ski
|
||||||
* (enno): Nein, das ist f<EFBFBD>r Dinge, bei denen die n<EFBFBD>chste Ausbaustufe
|
* (enno): Nein, das ist f<EFBFBD>r Dinge, bei denen die n<EFBFBD>chste Ausbaustufe
|
||||||
* die gleiche wie die vorherige ist. z.b. gegenst<EFBFBD>nde.
|
* die gleiche wie die vorherige ist. z.b. gegenst<EFBFBD>nde.
|
||||||
*/
|
*/
|
||||||
if (type->maxsize > 0) {
|
if (con->maxsize > 0) {
|
||||||
completed = completed % type->maxsize;
|
completed = completed % con->maxsize;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
completed = 0;
|
completed = 0;
|
||||||
assert(type->reqsize >= 1);
|
assert(con->reqsize >= 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (basesk < type->minskill) {
|
if (basesk < con->minskill) {
|
||||||
if (made == 0)
|
if (made == 0)
|
||||||
return ELOWSKILL;
|
return ELOWSKILL;
|
||||||
else
|
else
|
||||||
|
@ -590,15 +590,15 @@ int build(unit * u, const construction * ctype, int completed, int want, int ski
|
||||||
}
|
}
|
||||||
|
|
||||||
/* n = maximum buildable size */
|
/* n = maximum buildable size */
|
||||||
if (type->minskill > 1) {
|
if (con->minskill > 1) {
|
||||||
n = skills / type->minskill;
|
n = skills / con->minskill;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
n = skills;
|
n = skills;
|
||||||
}
|
}
|
||||||
/* Flinkfingerring wirkt nicht auf Mengenbegrenzte (magische)
|
/* Flinkfingerring wirkt nicht auf Mengenbegrenzte (magische)
|
||||||
* Talente */
|
* Talente */
|
||||||
if (skill_limit(u->faction, type->skill) == INT_MAX) {
|
if (skill_limit(u->faction, con->skill) == INT_MAX) {
|
||||||
const resource_type *ring = get_resourcetype(R_RING_OF_NIMBLEFINGER);
|
const resource_type *ring = get_resourcetype(R_RING_OF_NIMBLEFINGER);
|
||||||
item *itm = ring ? *i_find(&u->items, ring->itype) : 0;
|
item *itm = ring ? *i_find(&u->items, ring->itype) : 0;
|
||||||
int i = itm ? itm->number : 0;
|
int i = itm ? itm->number : 0;
|
||||||
|
@ -610,26 +610,26 @@ int build(unit * u, const construction * ctype, int completed, int want, int ski
|
||||||
|
|
||||||
if (want < n) n = want;
|
if (want < n) n = want;
|
||||||
|
|
||||||
if (type->maxsize > 0) {
|
if (con->maxsize > 0) {
|
||||||
n = MIN(type->maxsize - completed, n);
|
n = MIN(con->maxsize - completed, n);
|
||||||
if (type->improvement == NULL) {
|
if (con->improvement == NULL) {
|
||||||
want = n;
|
want = n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
n = count_materials(u, type, n, completed);
|
n = count_materials(u, con, n, completed);
|
||||||
if (n <= 0) {
|
if (n <= 0) {
|
||||||
if (made == 0)
|
if (made == 0)
|
||||||
return ENOMATERIALS;
|
return ENOMATERIALS;
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
err = use_materials(u, type, n, completed);
|
err = use_materials(u, con, n, completed);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
made += n;
|
made += n;
|
||||||
skills -= n * type->minskill;
|
skills -= n * con->minskill;
|
||||||
want -= n;
|
want -= n;
|
||||||
completed = completed + n;
|
completed = completed + n;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,15 +37,27 @@ extern "C" {
|
||||||
int number;
|
int number;
|
||||||
} requirement;
|
} requirement;
|
||||||
|
|
||||||
|
typedef enum construct_t {
|
||||||
|
CONS_OTHER,
|
||||||
|
CONS_ITEM,
|
||||||
|
CONS_BUILDING
|
||||||
|
} construct_t;
|
||||||
|
|
||||||
typedef struct construction {
|
typedef struct construction {
|
||||||
|
construct_t type;
|
||||||
skill_t skill; /* skill req'd per point of size */
|
skill_t skill; /* skill req'd per point of size */
|
||||||
int minskill; /* skill req'd per point of size */
|
int minskill; /* skill req'd per point of size */
|
||||||
|
|
||||||
int maxsize; /* maximum size of this type */
|
int maxsize; /* maximum size of this type */
|
||||||
int reqsize; /* size of object using up 1 set of requirement. */
|
int reqsize; /* size of object using up 1 set of requirement. */
|
||||||
requirement *materials; /* material req'd to build one object */
|
requirement *materials; /* material req'd to build one object */
|
||||||
const struct building_type *btype;
|
|
||||||
/* building type required to make this thing */
|
union {
|
||||||
|
/* CONS_BUILDING: */
|
||||||
|
char * name; /* building level name */
|
||||||
|
/* CONS_ITEM: */
|
||||||
|
const struct building_type *btype; /* building required to build item */
|
||||||
|
} extra;
|
||||||
|
|
||||||
struct construction *improvement;
|
struct construction *improvement;
|
||||||
/* next level, if upgradable. if more than one of these items
|
/* next level, if upgradable. if more than one of these items
|
||||||
|
|
|
@ -81,7 +81,8 @@ static void test_build_requires_building(CuTest *tc) {
|
||||||
rtype = bf.cons.materials[0].rtype;
|
rtype = bf.cons.materials[0].rtype;
|
||||||
i_change(&u->items, rtype->itype, 1);
|
i_change(&u->items, rtype->itype, 1);
|
||||||
set_level(u, SK_ARMORER, 2);
|
set_level(u, SK_ARMORER, 2);
|
||||||
bf.cons.btype = btype = bt_get_or_create("hodor");
|
bf.cons.type = CONS_ITEM;
|
||||||
|
bf.cons.extra.btype = btype = bt_get_or_create("hodor");
|
||||||
btype->maxcapacity = 1;
|
btype->maxcapacity = 1;
|
||||||
btype->capacity = 1;
|
btype->capacity = 1;
|
||||||
CuAssertIntEquals_Msg(tc, "must be inside a production building", EBUILDINGREQ, build(u, &bf.cons, 0, 1, 0));
|
CuAssertIntEquals_Msg(tc, "must be inside a production building", EBUILDINGREQ, build(u, &bf.cons, 0, 1, 0));
|
||||||
|
|
|
@ -157,27 +157,52 @@ attrib_type at_building_generic_type = {
|
||||||
ATF_UNIQUE
|
ATF_UNIQUE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* TECH DEBT: simplest thing that works for E3 dwarf/halfling faction rules */
|
||||||
|
static int adjust_size(const building *b, int bsize) {
|
||||||
|
assert(b);
|
||||||
|
if (config_get_int("rules.dwarf_castles", 0)
|
||||||
|
&& strcmp(b->type->_name, "castle") == 0) {
|
||||||
|
unit *u = building_owner(b);
|
||||||
|
if (u && u->faction->race == get_race(RC_HALFLING)) {
|
||||||
|
return bsize * 5 / 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bsize;
|
||||||
|
}
|
||||||
|
|
||||||
/* Returns the (internal) name for a building of given size and type. Especially, returns the correct
|
/* Returns the (internal) name for a building of given size and type. Especially, returns the correct
|
||||||
* name if it depends on the size (as for Eressea castles).
|
* name if it depends on the size (as for Eressea castles).
|
||||||
*/
|
*/
|
||||||
const char *buildingtype(const building_type * btype, const building * b, int bsize)
|
const char *buildingtype(const building_type * btype, const building * b, int bsize)
|
||||||
{
|
{
|
||||||
const char *s;
|
const construction *con;
|
||||||
|
|
||||||
assert(btype);
|
assert(btype);
|
||||||
|
|
||||||
s = btype->_name;
|
|
||||||
if (btype->name) {
|
|
||||||
s = btype->name(btype, b, bsize);
|
|
||||||
}
|
|
||||||
if (b && b->attribs) {
|
if (b && b->attribs) {
|
||||||
if (is_building_type(btype, "generic")) {
|
if (is_building_type(btype, "generic")) {
|
||||||
const attrib *a = a_find(b->attribs, &at_building_generic_type);
|
const attrib *a = a_find(b->attribs, &at_building_generic_type);
|
||||||
if (a) {
|
if (a) {
|
||||||
s = (const char *)a->data.v;
|
return (const char *)a->data.v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return s;
|
if (btype->name) {
|
||||||
|
return btype->name(btype, b, bsize);
|
||||||
|
}
|
||||||
|
if (btype->construction->extra.name) {
|
||||||
|
if (b) {
|
||||||
|
assert(b->type == btype);
|
||||||
|
bsize = adjust_size(b, bsize);
|
||||||
|
}
|
||||||
|
for (con = btype->construction; con; con = con->improvement) {
|
||||||
|
bsize -= con->maxsize;
|
||||||
|
if (!con->improvement || bsize <0) {
|
||||||
|
return con->extra.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return btype->_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BMAXHASH 7919
|
#define BMAXHASH 7919
|
||||||
|
@ -219,55 +244,6 @@ building *findbuilding(int i)
|
||||||
{
|
{
|
||||||
return bfindhash(i);
|
return bfindhash(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *castle_name_i(const struct building_type *btype,
|
|
||||||
const struct building *b, int bsize, const char *fname[])
|
|
||||||
{
|
|
||||||
int i = bt_effsize(btype, b, bsize);
|
|
||||||
|
|
||||||
return fname[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *castle_name_2(const struct building_type *btype,
|
|
||||||
const struct building *b, int bsize)
|
|
||||||
{
|
|
||||||
const char *fname[] = {
|
|
||||||
"site",
|
|
||||||
"fortification",
|
|
||||||
"tower",
|
|
||||||
"castle",
|
|
||||||
"fortress",
|
|
||||||
"citadel"
|
|
||||||
};
|
|
||||||
return castle_name_i(btype, b, bsize, fname);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *castle_name(const struct building_type *btype,
|
|
||||||
const struct building *b, int bsize)
|
|
||||||
{
|
|
||||||
const char *fname[] = {
|
|
||||||
"site",
|
|
||||||
"tradepost",
|
|
||||||
"fortification",
|
|
||||||
"tower",
|
|
||||||
"castle",
|
|
||||||
"fortress",
|
|
||||||
"citadel"
|
|
||||||
};
|
|
||||||
return castle_name_i(btype, b, bsize, fname);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *fort_name(const struct building_type *btype,
|
|
||||||
const struct building *b, int bsize)
|
|
||||||
{
|
|
||||||
const char *fname[] = {
|
|
||||||
"scaffolding",
|
|
||||||
"guardhouse",
|
|
||||||
"guardtower",
|
|
||||||
};
|
|
||||||
return castle_name_i(btype, b, bsize, fname);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* for finding out what was meant by a particular building string */
|
/* for finding out what was meant by a particular building string */
|
||||||
|
|
||||||
static local_names *bnames;
|
static local_names *bnames;
|
||||||
|
@ -486,24 +462,19 @@ int buildingeffsize(const building * b, int img)
|
||||||
|
|
||||||
int bt_effsize(const building_type * btype, const building * b, int bsize)
|
int bt_effsize(const building_type * btype, const building * b, int bsize)
|
||||||
{
|
{
|
||||||
int i = bsize, n = 0;
|
int n = 0;
|
||||||
const construction *cons = btype->construction;
|
const construction *cons = btype->construction;
|
||||||
|
|
||||||
/* TECH DEBT: simplest thing that works for E3 dwarf/halfling faction rules */
|
if (b) {
|
||||||
if (b && config_get_int("rules.dwarf_castles", 0)
|
bsize = adjust_size(b, bsize);
|
||||||
&& strcmp(btype->_name, "castle") == 0) {
|
|
||||||
unit *u = building_owner(b);
|
|
||||||
if (u && u->faction->race == get_race(RC_HALFLING)) {
|
|
||||||
i = bsize * 10 / 8;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cons || !cons->improvement) {
|
if (!cons) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (cons && cons->maxsize != -1 && i >= cons->maxsize) {
|
while (cons && cons->maxsize != -1 && bsize >= cons->maxsize) {
|
||||||
i -= cons->maxsize;
|
bsize -= cons->maxsize;
|
||||||
cons = cons->improvement;
|
cons = cons->improvement;
|
||||||
++n;
|
++n;
|
||||||
}
|
}
|
||||||
|
@ -552,10 +523,10 @@ static unit *building_owner_ex(const building * bld, const struct faction * last
|
||||||
}
|
}
|
||||||
if (!heir && config_token("rules.region_owner_pay_building", bld->type->_name)) {
|
if (!heir && config_token("rules.region_owner_pay_building", bld->type->_name)) {
|
||||||
if (rule_region_owners()) {
|
if (rule_region_owners()) {
|
||||||
u = building_owner(largestbuilding(bld->region, &cmp_taxes, false));
|
u = building_owner(largestbuilding(bld->region, cmp_taxes, false));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
u = building_owner(largestbuilding(bld->region, &cmp_wage, false));
|
u = building_owner(largestbuilding(bld->region, cmp_wage, false));
|
||||||
}
|
}
|
||||||
if (u) {
|
if (u) {
|
||||||
heir = u;
|
heir = u;
|
||||||
|
@ -674,7 +645,7 @@ building *largestbuilding(const region * r, cmp_building_cb cmp_gt,
|
||||||
{
|
{
|
||||||
building *b, *best = NULL;
|
building *b, *best = NULL;
|
||||||
|
|
||||||
for (b = rbuildings(r); b; b = b->next) {
|
for (b = r->buildings; b; b = b->next) {
|
||||||
if (cmp_gt(b, best) <= 0)
|
if (cmp_gt(b, best) <= 0)
|
||||||
continue;
|
continue;
|
||||||
if (!imaginary) {
|
if (!imaginary) {
|
||||||
|
@ -702,7 +673,7 @@ static const int wagetable[7][4] = {
|
||||||
static int
|
static int
|
||||||
default_wage(const region * r, const faction * f, const race * rc, int in_turn)
|
default_wage(const region * r, const faction * f, const race * rc, int in_turn)
|
||||||
{
|
{
|
||||||
building *b = largestbuilding(r, &cmp_wage, false);
|
building *b = largestbuilding(r, cmp_wage, false);
|
||||||
int esize = 0;
|
int esize = 0;
|
||||||
double wage;
|
double wage;
|
||||||
static int ct_cache;
|
static int ct_cache;
|
||||||
|
@ -813,6 +784,12 @@ bool is_owner_building(const struct building * b)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int building_taxes(const building *b) {
|
||||||
|
assert(b);
|
||||||
|
return b->type->taxes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int cmp_taxes(const building * b, const building * a)
|
int cmp_taxes(const building * b, const building * a)
|
||||||
{
|
{
|
||||||
faction *f = region_get_owner(b->region);
|
faction *f = region_get_owner(b->region);
|
||||||
|
@ -822,14 +799,12 @@ int cmp_taxes(const building * b, const building * a)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else if (a) {
|
else if (a) {
|
||||||
int newsize = buildingeffsize(b, false);
|
int newtaxes = building_taxes(b);
|
||||||
double newtaxes = b->type->taxes(b, newsize);
|
int oldtaxes = building_taxes(a);
|
||||||
int oldsize = buildingeffsize(a, false);
|
|
||||||
double oldtaxes = a->type->taxes(a, oldsize);
|
|
||||||
|
|
||||||
if (newtaxes < oldtaxes)
|
if (newtaxes > oldtaxes)
|
||||||
return -1;
|
return -1;
|
||||||
else if (newtaxes > oldtaxes)
|
else if (newtaxes < oldtaxes)
|
||||||
return 1;
|
return 1;
|
||||||
else if (b->size < a->size)
|
else if (b->size < a->size)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -838,8 +813,9 @@ int cmp_taxes(const building * b, const building * a)
|
||||||
else {
|
else {
|
||||||
if (u && u->faction == f) {
|
if (u && u->faction == f) {
|
||||||
u = building_owner(a);
|
u = building_owner(a);
|
||||||
if (u && u->faction == f)
|
if (u && u->faction == f) {
|
||||||
return -1;
|
return 0;
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -848,7 +824,7 @@ int cmp_taxes(const building * b, const building * a)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmp_current_owner(const building * b, const building * a)
|
int cmp_current_owner(const building * b, const building * a)
|
||||||
|
@ -861,10 +837,8 @@ int cmp_current_owner(const building * b, const building * a)
|
||||||
if (!u || u->faction != f)
|
if (!u || u->faction != f)
|
||||||
return -1;
|
return -1;
|
||||||
if (a) {
|
if (a) {
|
||||||
int newsize = buildingeffsize(b, false);
|
int newtaxes = building_taxes(b);
|
||||||
double newtaxes = b->type->taxes(b, newsize);
|
int oldtaxes = building_taxes(a);
|
||||||
int oldsize = buildingeffsize(a, false);
|
|
||||||
double oldtaxes = a->type->taxes(a, oldsize);
|
|
||||||
|
|
||||||
if (newtaxes > oldtaxes) {
|
if (newtaxes > oldtaxes) {
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -872,21 +846,11 @@ int cmp_current_owner(const building * b, const building * a)
|
||||||
if (newtaxes < oldtaxes) {
|
if (newtaxes < oldtaxes) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (newsize != oldsize) {
|
|
||||||
return newsize - oldsize;
|
|
||||||
}
|
|
||||||
return (b->size - a->size);
|
return (b->size - a->size);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
void register_buildings(void)
|
|
||||||
{
|
|
||||||
register_function((pf_generic)castle_name, "castle_name");
|
|
||||||
register_function((pf_generic)castle_name_2, "castle_name_2");
|
|
||||||
register_function((pf_generic)fort_name, "fort_name");
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,7 @@ extern "C" {
|
||||||
variant magres; /* how well it resists against spells */
|
variant magres; /* how well it resists against spells */
|
||||||
int magresbonus; /* bonus it gives the target against spells */
|
int magresbonus; /* bonus it gives the target against spells */
|
||||||
int fumblebonus; /* bonus that reduces fumbling */
|
int fumblebonus; /* bonus that reduces fumbling */
|
||||||
|
int taxes; /* receive $1 tax per `taxes` in region */
|
||||||
double auraregen; /* modifier for aura regeneration inside building */
|
double auraregen; /* modifier for aura regeneration inside building */
|
||||||
struct maintenance *maintenance; /* array of requirements */
|
struct maintenance *maintenance; /* array of requirements */
|
||||||
struct construction *construction; /* construction of 1 building-level */
|
struct construction *construction; /* construction of 1 building-level */
|
||||||
|
@ -70,8 +71,6 @@ extern "C" {
|
||||||
|
|
||||||
const char *(*name) (const struct building_type *,
|
const char *(*name) (const struct building_type *,
|
||||||
const struct building * b, int size);
|
const struct building * b, int size);
|
||||||
void(*age) (struct building *);
|
|
||||||
double(*taxes) (const struct building *, int size);
|
|
||||||
struct attrib *attribs;
|
struct attrib *attribs;
|
||||||
} building_type;
|
} building_type;
|
||||||
|
|
||||||
|
@ -84,7 +83,6 @@ extern "C" {
|
||||||
bool bt_changed(int *cache);
|
bool bt_changed(int *cache);
|
||||||
const building_type *bt_find(const char *name);
|
const building_type *bt_find(const char *name);
|
||||||
void free_buildingtypes(void);
|
void free_buildingtypes(void);
|
||||||
void register_buildings(void);
|
|
||||||
void bt_register(struct building_type *type);
|
void bt_register(struct building_type *type);
|
||||||
int bt_effsize(const struct building_type *btype,
|
int bt_effsize(const struct building_type *btype,
|
||||||
const struct building *b, int bsize);
|
const struct building *b, int bsize);
|
||||||
|
@ -140,6 +138,7 @@ extern "C" {
|
||||||
int cmp_taxes(const struct building *b, const struct building *bother);
|
int cmp_taxes(const struct building *b, const struct building *bother);
|
||||||
int cmp_current_owner(const struct building *b,
|
int cmp_current_owner(const struct building *b,
|
||||||
const struct building *bother);
|
const struct building *bother);
|
||||||
|
int building_taxes(const building *b);
|
||||||
|
|
||||||
/* old functions, still in build.c: */
|
/* old functions, still in build.c: */
|
||||||
int buildingeffsize(const building * b, int imaginary);
|
int buildingeffsize(const building * b, int imaginary);
|
||||||
|
|
|
@ -296,7 +296,6 @@ static void test_btype_defaults(CuTest *tc) {
|
||||||
CuAssertPtrEquals(tc, 0, btype->maintenance);
|
CuAssertPtrEquals(tc, 0, btype->maintenance);
|
||||||
CuAssertPtrEquals(tc, 0, btype->construction);
|
CuAssertPtrEquals(tc, 0, btype->construction);
|
||||||
CuAssertTrue(tc, !btype->name);
|
CuAssertTrue(tc, !btype->name);
|
||||||
CuAssertTrue(tc, !btype->age);
|
|
||||||
CuAssertTrue(tc, !btype->taxes);
|
CuAssertTrue(tc, !btype->taxes);
|
||||||
CuAssertDblEquals(tc, 1.0, btype->auraregen, 0.0);
|
CuAssertDblEquals(tc, 1.0, btype->auraregen, 0.0);
|
||||||
CuAssertIntEquals(tc, -1, btype->maxsize);
|
CuAssertIntEquals(tc, -1, btype->maxsize);
|
||||||
|
@ -427,10 +426,87 @@ static void test_cmp_castle_size(CuTest *tc) {
|
||||||
u_set_building(u2, b2);
|
u_set_building(u2, b2);
|
||||||
b1->size = 5;
|
b1->size = 5;
|
||||||
b2->size = 10;
|
b2->size = 10;
|
||||||
CuAssertTrue(tc, cmp_castle_size(b1, b2)<0);
|
CuAssertTrue(tc, cmp_castle_size(b1, b2) < 0);
|
||||||
CuAssertTrue(tc, cmp_castle_size(b2, b1)>0);
|
CuAssertTrue(tc, cmp_castle_size(b2, b1) > 0);
|
||||||
CuAssertTrue(tc, cmp_castle_size(b1, NULL)>0);
|
CuAssertTrue(tc, cmp_castle_size(b1, b1) == 0);
|
||||||
CuAssertTrue(tc, cmp_castle_size(NULL, b1)<0);
|
test_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_cmp_wage(CuTest *tc) {
|
||||||
|
region *r;
|
||||||
|
building *b1, *b2;
|
||||||
|
building_type *btype;
|
||||||
|
|
||||||
|
test_setup();
|
||||||
|
btype = test_create_buildingtype("castle");
|
||||||
|
btype->taxes = 100;
|
||||||
|
r = test_create_region(0, 0, 0);
|
||||||
|
b1 = test_create_building(r, btype);
|
||||||
|
b2 = test_create_building(r, btype);
|
||||||
|
b1->size = 5;
|
||||||
|
b2->size = 10;
|
||||||
|
CuAssertPtrEquals(tc, b2, largestbuilding(r, cmp_wage, false));
|
||||||
|
CuAssertTrue(tc, cmp_wage(b1, b2) < 0);
|
||||||
|
CuAssertTrue(tc, cmp_wage(b2, b1) > 0);
|
||||||
|
CuAssertTrue(tc, cmp_wage(b1, b1) == 0);
|
||||||
|
test_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_cmp_taxes(CuTest *tc) {
|
||||||
|
region *r;
|
||||||
|
building *b1, *b2;
|
||||||
|
building_type *btype;
|
||||||
|
unit *u1, *u2;
|
||||||
|
|
||||||
|
test_setup();
|
||||||
|
btype = test_create_buildingtype("castle");
|
||||||
|
btype->taxes = 100;
|
||||||
|
r = test_create_region(0, 0, 0);
|
||||||
|
b1 = test_create_building(r, btype);
|
||||||
|
b2 = test_create_building(r, btype);
|
||||||
|
b1->size = 5;
|
||||||
|
b2->size = 10;
|
||||||
|
u1 = test_create_unit(test_create_faction(0), r);
|
||||||
|
u_set_building(u1, b1);
|
||||||
|
u2 = test_create_unit(test_create_faction(0), r);
|
||||||
|
u_set_building(u2, b2);
|
||||||
|
CuAssertPtrEquals(tc, b2, largestbuilding(r, cmp_taxes, false));
|
||||||
|
CuAssertTrue(tc, cmp_taxes(b1, b2) < 0);
|
||||||
|
CuAssertTrue(tc, cmp_taxes(b2, b1) > 0);
|
||||||
|
CuAssertTrue(tc, cmp_taxes(b1, b1) == 0);
|
||||||
|
test_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_cmp_current_owner(CuTest *tc) {
|
||||||
|
region *r;
|
||||||
|
building *b1, *b2;
|
||||||
|
building_type *btype;
|
||||||
|
unit *u1, *u2;
|
||||||
|
|
||||||
|
test_setup();
|
||||||
|
config_set("rules.region_owners", "1");
|
||||||
|
r = test_create_region(0, 0, 0);
|
||||||
|
btype = test_create_buildingtype("watch");
|
||||||
|
btype->construction->maxsize = 1;
|
||||||
|
btype->taxes = 200;
|
||||||
|
b1 = test_create_building(r, btype);
|
||||||
|
btype = test_create_buildingtype("castle");
|
||||||
|
btype->construction->maxsize = 1;
|
||||||
|
btype->taxes = 100;
|
||||||
|
b2 = test_create_building(r, btype);
|
||||||
|
b1->size = 1;
|
||||||
|
CuAssertIntEquals(tc, 1, buildingeffsize(b1, false));
|
||||||
|
b2->size = 1;
|
||||||
|
CuAssertIntEquals(tc, 1, buildingeffsize(b2, false));
|
||||||
|
u1 = test_create_unit(test_create_faction(0), r);
|
||||||
|
u_set_building(u1, b1);
|
||||||
|
u2 = test_create_unit(test_create_faction(0), r);
|
||||||
|
u_set_building(u2, b2);
|
||||||
|
region_set_owner(r, u1->faction, turn);
|
||||||
|
CuAssertPtrEquals(tc, b1, largestbuilding(r, cmp_current_owner, false));
|
||||||
|
CuAssertTrue(tc, cmp_current_owner(b2, b1) < 0);
|
||||||
|
CuAssertTrue(tc, cmp_current_owner(b1, b2) > 0);
|
||||||
|
CuAssertTrue(tc, cmp_current_owner(b1, b1) == 0);
|
||||||
test_cleanup();
|
test_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -459,10 +535,37 @@ static void test_building_effsize(CuTest *tc) {
|
||||||
test_cleanup();
|
test_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cmp_size(const building *lhs, const building *rhs) {
|
||||||
|
assert(lhs);
|
||||||
|
return rhs ? lhs->size - rhs->size : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_largestbuilding(CuTest *tc) {
|
||||||
|
region *r;
|
||||||
|
building *b1, *b2;
|
||||||
|
test_setup();
|
||||||
|
r = test_create_region(0, 0, NULL);
|
||||||
|
CuAssertPtrEquals(tc, NULL, largestbuilding(r, cmp_size, false));
|
||||||
|
b1 = test_create_building(r, NULL);
|
||||||
|
b2 = test_create_building(r, NULL);
|
||||||
|
b1->size = 1;
|
||||||
|
b2->size = 1;
|
||||||
|
CuAssertPtrEquals(tc, b1, largestbuilding(r, cmp_size, false));
|
||||||
|
b1->size = 2;
|
||||||
|
CuAssertPtrEquals(tc, b1, largestbuilding(r, cmp_size, false));
|
||||||
|
b2->size = 3;
|
||||||
|
CuAssertPtrEquals(tc, b2, largestbuilding(r, cmp_size, false));
|
||||||
|
test_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
CuSuite *get_building_suite(void)
|
CuSuite *get_building_suite(void)
|
||||||
{
|
{
|
||||||
CuSuite *suite = CuSuiteNew();
|
CuSuite *suite = CuSuiteNew();
|
||||||
|
SUITE_ADD_TEST(suite, test_largestbuilding);
|
||||||
SUITE_ADD_TEST(suite, test_cmp_castle_size);
|
SUITE_ADD_TEST(suite, test_cmp_castle_size);
|
||||||
|
SUITE_ADD_TEST(suite, test_cmp_taxes);
|
||||||
|
SUITE_ADD_TEST(suite, test_cmp_wage);
|
||||||
|
SUITE_ADD_TEST(suite, test_cmp_current_owner);
|
||||||
SUITE_ADD_TEST(suite, test_register_building);
|
SUITE_ADD_TEST(suite, test_register_building);
|
||||||
SUITE_ADD_TEST(suite, test_btype_defaults);
|
SUITE_ADD_TEST(suite, test_btype_defaults);
|
||||||
SUITE_ADD_TEST(suite, test_building_set_owner);
|
SUITE_ADD_TEST(suite, test_building_set_owner);
|
||||||
|
|
|
@ -1398,8 +1398,8 @@ faction *update_owners(region * r)
|
||||||
faction *f = NULL;
|
faction *f = NULL;
|
||||||
assert(rule_region_owners());
|
assert(rule_region_owners());
|
||||||
if (r->land) {
|
if (r->land) {
|
||||||
building *bowner = largestbuilding(r, &cmp_current_owner, false);
|
building *bowner = largestbuilding(r, cmp_current_owner, false);
|
||||||
building *blargest = largestbuilding(r, &cmp_taxes, false);
|
building *blargest = largestbuilding(r, cmp_taxes, false);
|
||||||
if (blargest) {
|
if (blargest) {
|
||||||
if (!bowner || bowner->size < blargest->size) {
|
if (!bowner || bowner->size < blargest->size) {
|
||||||
/* region owners update? */
|
/* region owners update? */
|
||||||
|
|
|
@ -66,7 +66,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
struct faction;
|
struct faction;
|
||||||
struct gamedata;
|
struct gamedata;
|
||||||
|
|
||||||
#define MORALE_TAX_FACTOR 0.005 /* 0.5% tax per point of morale */
|
#define MORALE_TAX_FACTOR 200 /* 0.5% tax per point of morale, 1 silver per 200 */
|
||||||
#define MORALE_MAX 10 /* Maximum morale allowed */
|
#define MORALE_MAX 10 /* Maximum morale allowed */
|
||||||
#define MORALE_DEFAULT 1 /* Morale of peasants when they are conquered for the first time */
|
#define MORALE_DEFAULT 1 /* Morale of peasants when they are conquered for the first time */
|
||||||
#define MORALE_TAKEOVER 0 /* Morale of peasants after they lose their lord */
|
#define MORALE_TAKEOVER 0 /* Morale of peasants after they lose their lord */
|
||||||
|
|
|
@ -214,7 +214,7 @@ xml_readrequirements(xmlNodePtr * nodeTab, int nodeNr, requirement ** reqArray)
|
||||||
|
|
||||||
void
|
void
|
||||||
xml_readconstruction(xmlXPathContextPtr xpath, xmlNodeSetPtr nodeSet,
|
xml_readconstruction(xmlXPathContextPtr xpath, xmlNodeSetPtr nodeSet,
|
||||||
construction ** consPtr)
|
construction ** consPtr, construct_t type)
|
||||||
{
|
{
|
||||||
xmlNodePtr pushNode = xpath->node;
|
xmlNodePtr pushNode = xpath->node;
|
||||||
int k;
|
int k;
|
||||||
|
@ -241,15 +241,25 @@ construction ** consPtr)
|
||||||
*consPtr = con = (construction *)calloc(sizeof(construction), 1);
|
*consPtr = con = (construction *)calloc(sizeof(construction), 1);
|
||||||
consPtr = &con->improvement;
|
consPtr = &con->improvement;
|
||||||
|
|
||||||
|
con->type = type;
|
||||||
con->skill = sk;
|
con->skill = sk;
|
||||||
con->maxsize = xml_ivalue(node, "maxsize", -1);
|
con->maxsize = xml_ivalue(node, "maxsize", -1);
|
||||||
con->minskill = xml_ivalue(node, "minskill", -1);
|
con->minskill = xml_ivalue(node, "minskill", -1);
|
||||||
con->reqsize = xml_ivalue(node, "reqsize", 1);
|
con->reqsize = xml_ivalue(node, "reqsize", 1);
|
||||||
|
|
||||||
propValue = xmlGetProp(node, BAD_CAST "building");
|
if (type == CONS_ITEM) {
|
||||||
if (propValue != NULL) {
|
propValue = xmlGetProp(node, BAD_CAST "building");
|
||||||
con->btype = bt_get_or_create((const char *)propValue);
|
if (propValue != NULL) {
|
||||||
xmlFree(propValue);
|
con->extra.btype = bt_get_or_create((const char *)propValue);
|
||||||
|
xmlFree(propValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (type == CONS_BUILDING) {
|
||||||
|
propValue = xmlGetProp(node, BAD_CAST "name");
|
||||||
|
if (propValue != NULL) {
|
||||||
|
con->extra.name = strdup((const char *)propValue);
|
||||||
|
xmlFree(propValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read construction/requirement */
|
/* read construction/requirement */
|
||||||
|
@ -310,6 +320,7 @@ static int parse_buildings(xmlDocPtr doc)
|
||||||
btype->magresbonus = xml_ivalue(node, "magresbonus", btype->magresbonus);
|
btype->magresbonus = xml_ivalue(node, "magresbonus", btype->magresbonus);
|
||||||
btype->fumblebonus = xml_ivalue(node, "fumblebonus", btype->fumblebonus);
|
btype->fumblebonus = xml_ivalue(node, "fumblebonus", btype->fumblebonus);
|
||||||
btype->auraregen = xml_fvalue(node, "auraregen", btype->auraregen);
|
btype->auraregen = xml_fvalue(node, "auraregen", btype->auraregen);
|
||||||
|
btype->taxes = xml_ivalue(node, "taxes", btype->taxes);
|
||||||
|
|
||||||
if (xml_bvalue(node, "nodestroy", false))
|
if (xml_bvalue(node, "nodestroy", false))
|
||||||
btype->flags |= BTF_INDESTRUCTIBLE;
|
btype->flags |= BTF_INDESTRUCTIBLE;
|
||||||
|
@ -337,7 +348,7 @@ static int parse_buildings(xmlDocPtr doc)
|
||||||
/* reading eressea/buildings/building/construction */
|
/* reading eressea/buildings/building/construction */
|
||||||
xpath->node = node;
|
xpath->node = node;
|
||||||
result = xmlXPathEvalExpression(BAD_CAST "construction", xpath);
|
result = xmlXPathEvalExpression(BAD_CAST "construction", xpath);
|
||||||
xml_readconstruction(xpath, result->nodesetval, &btype->construction);
|
xml_readconstruction(xpath, result->nodesetval, &btype->construction, CONS_BUILDING);
|
||||||
xmlXPathFreeObject(result);
|
xmlXPathFreeObject(result);
|
||||||
|
|
||||||
/* reading eressea/buildings/building/function */
|
/* reading eressea/buildings/building/function */
|
||||||
|
@ -359,12 +370,6 @@ static int parse_buildings(xmlDocPtr doc)
|
||||||
(const char *(*)(const struct building_type *,
|
(const char *(*)(const struct building_type *,
|
||||||
const struct building *, int))fun;
|
const struct building *, int))fun;
|
||||||
}
|
}
|
||||||
else if (strcmp((const char *)propValue, "age") == 0) {
|
|
||||||
btype->age = (void(*)(struct building *))fun;
|
|
||||||
}
|
|
||||||
else if (strcmp((const char *)propValue, "taxes") == 0) {
|
|
||||||
btype->taxes = (double(*)(const struct building *, int))fun;
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
log_error("unknown function type '%s' for building %s\n", (const char *)propValue, btype->_name);
|
log_error("unknown function type '%s' for building %s\n", (const char *)propValue, btype->_name);
|
||||||
}
|
}
|
||||||
|
@ -572,7 +577,7 @@ static int parse_ships(xmlDocPtr doc)
|
||||||
/* reading eressea/ships/ship/construction */
|
/* reading eressea/ships/ship/construction */
|
||||||
xpath->node = node;
|
xpath->node = node;
|
||||||
result = xmlXPathEvalExpression(BAD_CAST "construction", xpath);
|
result = xmlXPathEvalExpression(BAD_CAST "construction", xpath);
|
||||||
xml_readconstruction(xpath, result->nodesetval, &st->construction);
|
xml_readconstruction(xpath, result->nodesetval, &st->construction, CONS_OTHER);
|
||||||
xmlXPathFreeObject(result);
|
xmlXPathFreeObject(result);
|
||||||
|
|
||||||
for (child = node->children; child; child = child->next) {
|
for (child = node->children; child; child = child->next) {
|
||||||
|
@ -858,7 +863,7 @@ static item_type *xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype)
|
||||||
/* reading item/construction */
|
/* reading item/construction */
|
||||||
xpath->node = node;
|
xpath->node = node;
|
||||||
result = xmlXPathEvalExpression(BAD_CAST "construction", xpath);
|
result = xmlXPathEvalExpression(BAD_CAST "construction", xpath);
|
||||||
xml_readconstruction(xpath, result->nodesetval, &itype->construction);
|
xml_readconstruction(xpath, result->nodesetval, &itype->construction, CONS_ITEM);
|
||||||
xmlXPathFreeObject(result);
|
xmlXPathFreeObject(result);
|
||||||
|
|
||||||
/* reading item/weapon */
|
/* reading item/weapon */
|
||||||
|
|
|
@ -2883,10 +2883,6 @@ static building *age_building(building * b)
|
||||||
a_age(&b->attribs, b);
|
a_age(&b->attribs, b);
|
||||||
handle_event(b->attribs, "timer", b);
|
handle_event(b->attribs, "timer", b);
|
||||||
|
|
||||||
if (b->type->age) {
|
|
||||||
b->type->age(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -525,10 +525,6 @@ struct pay_fixture {
|
||||||
unit *u2;
|
unit *u2;
|
||||||
};
|
};
|
||||||
|
|
||||||
static double level_taxes(const building * b, int level) {
|
|
||||||
return b->size * level * 2.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setup_pay_cmd(struct pay_fixture *fix) {
|
static void setup_pay_cmd(struct pay_fixture *fix) {
|
||||||
faction *f;
|
faction *f;
|
||||||
region *r;
|
region *r;
|
||||||
|
@ -540,7 +536,7 @@ static void setup_pay_cmd(struct pay_fixture *fix) {
|
||||||
r = findregion(0, 0);
|
r = findregion(0, 0);
|
||||||
assert(r && f);
|
assert(r && f);
|
||||||
btcastle = test_create_buildingtype("castle");
|
btcastle = test_create_buildingtype("castle");
|
||||||
btcastle->taxes = level_taxes;
|
btcastle->taxes = 100;
|
||||||
b = test_create_building(r, btcastle);
|
b = test_create_building(r, btcastle);
|
||||||
assert(b);
|
assert(b);
|
||||||
fix->u1 = test_create_unit(f, r);
|
fix->u1 = test_create_unit(f, r);
|
||||||
|
|
32
src/magic.c
32
src/magic.c
|
@ -231,26 +231,6 @@ bool FactionSpells(void)
|
||||||
return rule != 0;
|
return rule != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void read_spells(struct selist **slistp, magic_t mtype,
|
|
||||||
struct storage *store)
|
|
||||||
{
|
|
||||||
for (;;) {
|
|
||||||
spell *sp;
|
|
||||||
char spname[64];
|
|
||||||
|
|
||||||
READ_TOK(store, spname, sizeof(spname));
|
|
||||||
if (strcmp(spname, "end") == 0)
|
|
||||||
break;
|
|
||||||
sp = find_spell(spname);
|
|
||||||
if (!sp) {
|
|
||||||
log_error("read_spells: could not find spell '%s' in school '%s'\n", spname, magic_school[mtype]);
|
|
||||||
}
|
|
||||||
if (sp) {
|
|
||||||
add_spell(slistp, sp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int get_spell_level_mage(const spell * sp, void * cbdata)
|
int get_spell_level_mage(const spell * sp, void * cbdata)
|
||||||
{
|
{
|
||||||
sc_mage *mage = (sc_mage *)cbdata;
|
sc_mage *mage = (sc_mage *)cbdata;
|
||||||
|
@ -305,18 +285,6 @@ static int read_mage(attrib * a, void *owner, struct gamedata *data)
|
||||||
return AT_READ_OK;
|
return AT_READ_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_spells(struct selist *slist, struct storage *store)
|
|
||||||
{
|
|
||||||
selist *ql;
|
|
||||||
int qi;
|
|
||||||
|
|
||||||
for (ql = slist, qi = 0; ql; selist_advance(&ql, &qi, 1)) {
|
|
||||||
spell *sp = (spell *)selist_get(ql, qi);
|
|
||||||
WRITE_TOK(store, sp->sname);
|
|
||||||
}
|
|
||||||
WRITE_TOK(store, "end");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
write_mage(const attrib * a, const void *owner, struct storage *store)
|
write_mage(const attrib * a, const void *owner, struct storage *store)
|
||||||
{
|
{
|
||||||
|
|
|
@ -244,10 +244,6 @@ extern "C" {
|
||||||
/* prüft, ob der Spruch in der Spruchliste der Einheit steht. */
|
/* prüft, ob der Spruch in der Spruchliste der Einheit steht. */
|
||||||
void pick_random_spells(struct faction *f, int level, struct spellbook * book, int num_spells);
|
void pick_random_spells(struct faction *f, int level, struct spellbook * book, int num_spells);
|
||||||
void show_new_spells(struct faction * f, int level, const struct spellbook *book);
|
void show_new_spells(struct faction * f, int level, const struct spellbook *book);
|
||||||
void updatespelllist(struct unit *u);
|
|
||||||
/* fügt alle Zauber des Magiegebietes der Einheit, deren Stufe kleiner
|
|
||||||
* als das aktuelle Magietalent ist, in die Spruchliste der Einheit
|
|
||||||
* ein */
|
|
||||||
bool knowsspell(const struct region *r, const struct unit *u,
|
bool knowsspell(const struct region *r, const struct unit *u,
|
||||||
const struct spell * sp);
|
const struct spell * sp);
|
||||||
/* prüft, ob die Einheit diesen Spruch gerade beherrscht, dh
|
/* prüft, ob die Einheit diesen Spruch gerade beherrscht, dh
|
||||||
|
@ -349,10 +345,6 @@ extern "C" {
|
||||||
struct order *ord, const struct spllprm *spobj);
|
struct order *ord, const struct spllprm *spobj);
|
||||||
bool FactionSpells(void);
|
bool FactionSpells(void);
|
||||||
|
|
||||||
void write_spells(struct selist *slist, struct storage *store);
|
|
||||||
void read_spells(struct selist **slistp, magic_t mtype,
|
|
||||||
struct storage *store);
|
|
||||||
|
|
||||||
struct spellbook * get_spellbook(const char * name);
|
struct spellbook * get_spellbook(const char * name);
|
||||||
void free_spellbooks(void);
|
void free_spellbooks(void);
|
||||||
void free_spellbook(struct spellbook *sb);
|
void free_spellbook(struct spellbook *sb);
|
||||||
|
|
|
@ -43,10 +43,11 @@ void morale_update(region *r) {
|
||||||
if (r->land->ownership && r->land->ownership->owner) {
|
if (r->land->ownership && r->land->ownership->owner) {
|
||||||
int stability = turn - r->land->ownership->morale_turn;
|
int stability = turn - r->land->ownership->morale_turn;
|
||||||
int maxmorale = MORALE_DEFAULT;
|
int maxmorale = MORALE_DEFAULT;
|
||||||
building *b = largestbuilding(r, &cmp_taxes, false);
|
building *b = largestbuilding(r, cmp_taxes, false);
|
||||||
if (b) {
|
if (b) {
|
||||||
int bsize = buildingeffsize(b, false);
|
int bsize = buildingeffsize(b, false);
|
||||||
maxmorale = (int)(0.5 + b->type->taxes(b, bsize + 1) / MORALE_TAX_FACTOR);
|
assert(b->type->taxes>0);
|
||||||
|
maxmorale = (bsize + 1) * MORALE_TAX_FACTOR / b->type->taxes;
|
||||||
}
|
}
|
||||||
if (morale < maxmorale) {
|
if (morale < maxmorale) {
|
||||||
if (stability > MORALE_COOLDOWN && r->land->ownership->owner
|
if (stability > MORALE_COOLDOWN && r->land->ownership->owner
|
||||||
|
|
Loading…
Reference in New Issue